These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / net / rndis.c
1 /*
2  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 /** @file
27  *
28  * Remote Network Driver Interface Specification
29  *
30  */
31
32 #include <unistd.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <byteswap.h>
36 #include <ipxe/iobuf.h>
37 #include <ipxe/netdevice.h>
38 #include <ipxe/ethernet.h>
39 #include <ipxe/device.h>
40 #include <ipxe/rndis.h>
41
42 /**
43  * Allocate I/O buffer
44  *
45  * @v len               Length
46  * @ret iobuf           I/O buffer, or NULL
47  */
48 static struct io_buffer * rndis_alloc_iob ( size_t len ) {
49         struct rndis_header *header;
50         struct io_buffer *iobuf;
51
52         /* Allocate I/O buffer and reserve space */
53         iobuf = alloc_iob ( sizeof ( *header ) + len );
54         if ( iobuf )
55                 iob_reserve ( iobuf, sizeof ( *header ) );
56
57         return iobuf;
58 }
59
60 /**
61  * Wait for completion
62  *
63  * @v rndis             RNDIS device
64  * @v wait_id           Request ID
65  * @ret rc              Return status code
66  */
67 static int rndis_wait ( struct rndis_device *rndis, unsigned int wait_id ) {
68         unsigned int i;
69
70         /* Record query ID */
71         rndis->wait_id = wait_id;
72
73         /* Wait for operation to complete */
74         for ( i = 0 ; i < RNDIS_MAX_WAIT_MS ; i++ ) {
75
76                 /* Check for completion */
77                 if ( ! rndis->wait_id )
78                         return rndis->wait_rc;
79
80                 /* Poll RNDIS device */
81                 rndis->op->poll ( rndis );
82
83                 /* Delay for 1ms */
84                 mdelay ( 1 );
85         }
86
87         DBGC ( rndis, "RNDIS %s timed out waiting for ID %#08x\n",
88                rndis->name, wait_id );
89         return -ETIMEDOUT;
90 }
91
92 /**
93  * Transmit message
94  *
95  * @v rndis             RNDIS device
96  * @v iobuf             I/O buffer
97  * @v type              Message type
98  * @ret rc              Return status code
99  */
100 static int rndis_tx_message ( struct rndis_device *rndis,
101                               struct io_buffer *iobuf, unsigned int type ) {
102         struct rndis_header *header;
103         int rc;
104
105         /* Prepend RNDIS header */
106         header = iob_push ( iobuf, sizeof ( *header ) );
107         header->type = cpu_to_le32 ( type );
108         header->len = cpu_to_le32 ( iob_len ( iobuf ) );
109
110         /* Transmit message */
111         if ( ( rc = rndis->op->transmit ( rndis, iobuf ) ) != 0 ) {
112                 DBGC ( rndis, "RNDIS %s could not transmit: %s\n",
113                        rndis->name, strerror ( rc ) );
114                 return rc;
115         }
116
117         return 0;
118 }
119
120 /**
121  * Complete message transmission
122  *
123  * @v rndis             RNDIS device
124  * @v iobuf             I/O buffer
125  * @v rc                Packet status code
126  */
127 void rndis_tx_complete_err ( struct rndis_device *rndis,
128                              struct io_buffer *iobuf, int rc ) {
129         struct net_device *netdev = rndis->netdev;
130         struct rndis_header *header;
131         size_t len = iob_len ( iobuf );
132
133         /* Sanity check */
134         if ( len < sizeof ( *header ) ) {
135                 DBGC ( rndis, "RNDIS %s completed underlength transmission:\n",
136                        rndis->name );
137                 DBGC_HDA ( rndis, 0, iobuf->data, len );
138                 netdev_tx_err ( netdev, NULL, -EINVAL );
139                 return;
140         }
141         header = iobuf->data;
142
143         /* Complete buffer */
144         if ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) {
145                 netdev_tx_complete_err ( netdev, iobuf, rc );
146         } else {
147                 free_iob ( iobuf );
148         }
149 }
150
151 /**
152  * Transmit data packet
153  *
154  * @v rndis             RNDIS device
155  * @v iobuf             I/O buffer
156  * @ret rc              Return status code
157  */
158 static int rndis_tx_data ( struct rndis_device *rndis,
159                            struct io_buffer *iobuf ) {
160         struct rndis_packet_message *msg;
161         size_t len = iob_len ( iobuf );
162         int rc;
163
164         /* Prepend packet message header */
165         msg = iob_push ( iobuf, sizeof ( *msg ) );
166         memset ( msg, 0, sizeof ( *msg ) );
167         msg->data.offset = cpu_to_le32 ( sizeof ( *msg ) );
168         msg->data.len = cpu_to_le32 ( len );
169
170         /* Transmit message */
171         if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_PACKET_MSG ) ) != 0 )
172                 return rc;
173
174         return 0;
175 }
176
177 /**
178  * Defer transmitted packet
179  *
180  * @v rndis             RNDIS device
181  * @v iobuf             I/O buffer
182  * @ret rc              Return status code
183  *
184  * As with netdev_tx_defer(), the caller must ensure that space in the
185  * transmit descriptor ring is freed up before calling
186  * rndis_tx_complete().
187  *
188  * Unlike netdev_tx_defer(), this call may fail.
189  */
190 int rndis_tx_defer ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
191         struct net_device *netdev = rndis->netdev;
192         struct rndis_header *header;
193         struct rndis_packet_message *msg;
194
195         /* Fail unless this was a packet message.  Only packet
196          * messages correspond to I/O buffers in the network device's
197          * TX queue; other messages cannot be deferred in this way.
198          */
199         assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
200         header = iobuf->data;
201         if ( header->type != cpu_to_le32 ( RNDIS_PACKET_MSG ) )
202                 return -ENOTSUP;
203
204         /* Strip RNDIS header and packet message header, to return
205          * this packet to the state in which we received it.
206          */
207         iob_pull ( iobuf, ( sizeof ( *header ) + sizeof ( *msg ) ) );
208
209         /* Defer packet */
210         netdev_tx_defer ( netdev, iobuf );
211
212         return 0;
213 }
214
215 /**
216  * Receive data packet
217  *
218  * @v rndis             RNDIS device
219  * @v iobuf             I/O buffer
220  */
221 static void rndis_rx_data ( struct rndis_device *rndis,
222                             struct io_buffer *iobuf ) {
223         struct net_device *netdev = rndis->netdev;
224         struct rndis_packet_message *msg;
225         size_t len = iob_len ( iobuf );
226         size_t data_offset;
227         size_t data_len;
228         int rc;
229
230         /* Sanity check */
231         if ( len < sizeof ( *msg ) ) {
232                 DBGC ( rndis, "RNDIS %s received underlength data packet:\n",
233                        rndis->name );
234                 DBGC_HDA ( rndis, 0, iobuf->data, len );
235                 rc = -EINVAL;
236                 goto err_len;
237         }
238         msg = iobuf->data;
239
240         /* Locate and sanity check data buffer */
241         data_offset = le32_to_cpu ( msg->data.offset );
242         data_len = le32_to_cpu ( msg->data.len );
243         if ( ( data_offset > len ) || ( data_len > ( len - data_offset ) ) ) {
244                 DBGC ( rndis, "RNDIS %s data packet data exceeds packet:\n",
245                        rndis->name );
246                 DBGC_HDA ( rndis, 0, iobuf->data, len );
247                 rc = -EINVAL;
248                 goto err_data;
249         }
250
251         /* Strip non-data portions */
252         iob_pull ( iobuf, data_offset );
253         iob_unput ( iobuf, ( iob_len ( iobuf ) - data_len ) );
254
255         /* Hand off to network stack */
256         netdev_rx ( netdev, iob_disown ( iobuf ) );
257
258         return;
259
260  err_data:
261  err_len:
262         /* Report error to network stack */
263         netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
264 }
265
266 /**
267  * Transmit initialisation message
268  *
269  * @v rndis             RNDIS device
270  * @v id                Request ID
271  * @ret rc              Return status code
272  */
273 static int rndis_tx_initialise ( struct rndis_device *rndis, unsigned int id ) {
274         struct io_buffer *iobuf;
275         struct rndis_initialise_message *msg;
276         int rc;
277
278         /* Allocate I/O buffer */
279         iobuf = rndis_alloc_iob ( sizeof ( *msg ) );
280         if ( ! iobuf ) {
281                 rc = -ENOMEM;
282                 goto err_alloc;
283         }
284
285         /* Construct message */
286         msg = iob_put ( iobuf, sizeof ( *msg ) );
287         memset ( msg, 0, sizeof ( *msg ) );
288         msg->id = id; /* Non-endian */
289         msg->major = cpu_to_le32 ( RNDIS_VERSION_MAJOR );
290         msg->minor = cpu_to_le32 ( RNDIS_VERSION_MINOR );
291         msg->mtu = cpu_to_le32 ( RNDIS_MTU );
292
293         /* Transmit message */
294         if ( ( rc = rndis_tx_message ( rndis, iobuf,
295                                        RNDIS_INITIALISE_MSG ) ) != 0 )
296                 goto err_tx;
297
298         return 0;
299
300  err_tx:
301         free_iob ( iobuf );
302  err_alloc:
303         return rc;
304 }
305
306 /**
307  * Receive initialisation completion
308  *
309  * @v rndis             RNDIS device
310  * @v iobuf             I/O buffer
311  */
312 static void rndis_rx_initialise ( struct rndis_device *rndis,
313                                   struct io_buffer *iobuf ) {
314         struct rndis_initialise_completion *cmplt;
315         size_t len = iob_len ( iobuf );
316         unsigned int id;
317         int rc;
318
319         /* Sanity check */
320         if ( len < sizeof ( *cmplt ) ) {
321                 DBGC ( rndis, "RNDIS %s received underlength initialisation "
322                        "completion:\n", rndis->name );
323                 DBGC_HDA ( rndis, 0, iobuf->data, len );
324                 rc = -EINVAL;
325                 goto err_len;
326         }
327         cmplt = iobuf->data;
328
329         /* Extract request ID */
330         id = cmplt->id; /* Non-endian */
331
332         /* Check status */
333         if ( cmplt->status ) {
334                 DBGC ( rndis, "RNDIS %s received initialisation completion "
335                        "failure %#08x\n", rndis->name,
336                        le32_to_cpu ( cmplt->status ) );
337                 rc = -EIO;
338                 goto err_status;
339         }
340
341         /* Success */
342         rc = 0;
343
344  err_status:
345         /* Record completion result if applicable */
346         if ( id == rndis->wait_id ) {
347                 rndis->wait_id = 0;
348                 rndis->wait_rc = rc;
349         }
350  err_len:
351         free_iob ( iobuf );
352 }
353
354 /**
355  * Initialise RNDIS
356  *
357  * @v rndis             RNDIS device
358  * @ret rc              Return status code
359  */
360 static int rndis_initialise ( struct rndis_device *rndis ) {
361         int rc;
362
363         /* Transmit initialisation message */
364         if ( ( rc = rndis_tx_initialise ( rndis, RNDIS_INIT_ID ) ) != 0 )
365                 return rc;
366
367         /* Wait for response */
368         if ( ( rc = rndis_wait ( rndis, RNDIS_INIT_ID ) ) != 0 )
369                 return rc;
370
371         return 0;
372 }
373
374 /**
375  * Transmit halt message
376  *
377  * @v rndis             RNDIS device
378  * @ret rc              Return status code
379  */
380 static int rndis_tx_halt ( struct rndis_device *rndis ) {
381         struct io_buffer *iobuf;
382         struct rndis_halt_message *msg;
383         int rc;
384
385         /* Allocate I/O buffer */
386         iobuf = rndis_alloc_iob ( sizeof ( *msg ) );
387         if ( ! iobuf ) {
388                 rc = -ENOMEM;
389                 goto err_alloc;
390         }
391
392         /* Construct message */
393         msg = iob_put ( iobuf, sizeof ( *msg ) );
394         memset ( msg, 0, sizeof ( *msg ) );
395
396         /* Transmit message */
397         if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_HALT_MSG ) ) != 0 )
398                 goto err_tx;
399
400         return 0;
401
402  err_tx:
403         free_iob ( iobuf );
404  err_alloc:
405         return rc;
406 }
407
408 /**
409  * Halt RNDIS
410  *
411  * @v rndis             RNDIS device
412  * @ret rc              Return status code
413  */
414 static int rndis_halt ( struct rndis_device *rndis ) {
415         int rc;
416
417         /* Transmit halt message */
418         if ( ( rc = rndis_tx_halt ( rndis ) ) != 0 )
419                 return rc;
420
421         return 0;
422 }
423
424 /**
425  * Transmit OID message
426  *
427  * @v rndis             RNDIS device
428  * @v oid               Object ID
429  * @v data              New OID value (or NULL to query current value)
430  * @v len               Length of new OID value
431  * @ret rc              Return status code
432  */
433 static int rndis_tx_oid ( struct rndis_device *rndis, unsigned int oid,
434                           const void *data, size_t len ) {
435         struct io_buffer *iobuf;
436         struct rndis_oid_message *msg;
437         unsigned int type;
438         int rc;
439
440         /* Allocate I/O buffer */
441         iobuf = rndis_alloc_iob ( sizeof ( *msg ) + len );
442         if ( ! iobuf ) {
443                 rc = -ENOMEM;
444                 goto err_alloc;
445         }
446
447         /* Construct message.  We use the OID as the request ID. */
448         msg = iob_put ( iobuf, sizeof ( *msg ) );
449         memset ( msg, 0, sizeof ( *msg ) );
450         msg->id = oid; /* Non-endian */
451         msg->oid = cpu_to_le32 ( oid );
452         msg->offset = cpu_to_le32 ( sizeof ( *msg ) );
453         msg->len = cpu_to_le32 ( len );
454         memcpy ( iob_put ( iobuf, len ), data, len );
455
456         /* Transmit message */
457         type = ( data ? RNDIS_SET_MSG : RNDIS_QUERY_MSG );
458         if ( ( rc = rndis_tx_message ( rndis, iobuf, type ) ) != 0 )
459                 goto err_tx;
460
461         return 0;
462
463  err_tx:
464         free_iob ( iobuf );
465  err_alloc:
466         return rc;
467 }
468
469 /**
470  * Receive query OID completion
471  *
472  * @v rndis             RNDIS device
473  * @v iobuf             I/O buffer
474  */
475 static void rndis_rx_query_oid ( struct rndis_device *rndis,
476                                  struct io_buffer *iobuf ) {
477         struct net_device *netdev = rndis->netdev;
478         struct rndis_query_completion *cmplt;
479         size_t len = iob_len ( iobuf );
480         size_t info_offset;
481         size_t info_len;
482         unsigned int id;
483         void *info;
484         uint32_t *link_status;
485         int rc;
486
487         /* Sanity check */
488         if ( len < sizeof ( *cmplt ) ) {
489                 DBGC ( rndis, "RNDIS %s received underlength query "
490                        "completion:\n", rndis->name );
491                 DBGC_HDA ( rndis, 0, iobuf->data, len );
492                 rc = -EINVAL;
493                 goto err_len;
494         }
495         cmplt = iobuf->data;
496
497         /* Extract request ID */
498         id = cmplt->id; /* Non-endian */
499
500         /* Check status */
501         if ( cmplt->status ) {
502                 DBGC ( rndis, "RNDIS %s received query completion failure "
503                        "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) );
504                 DBGC_HDA ( rndis, 0, iobuf->data, len );
505                 rc = -EIO;
506                 goto err_status;
507         }
508
509         /* Locate and sanity check information buffer */
510         info_offset = le32_to_cpu ( cmplt->offset );
511         info_len = le32_to_cpu ( cmplt->len );
512         if ( ( info_offset > len ) || ( info_len > ( len - info_offset ) ) ) {
513                 DBGC ( rndis, "RNDIS %s query completion information exceeds "
514                        "packet:\n", rndis->name );
515                 DBGC_HDA ( rndis, 0, iobuf->data, len );
516                 rc = -EINVAL;
517                 goto err_info;
518         }
519         info = ( ( ( void * ) cmplt ) + info_offset );
520
521         /* Handle OID */
522         switch ( id ) {
523
524         case RNDIS_OID_802_3_PERMANENT_ADDRESS:
525                 if ( info_len > sizeof ( netdev->hw_addr ) )
526                         info_len = sizeof ( netdev->hw_addr );
527                 memcpy ( netdev->hw_addr, info, info_len );
528                 break;
529
530         case RNDIS_OID_802_3_CURRENT_ADDRESS:
531                 if ( info_len > sizeof ( netdev->ll_addr ) )
532                         info_len = sizeof ( netdev->ll_addr );
533                 memcpy ( netdev->ll_addr, info, info_len );
534                 break;
535
536         case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
537                 if ( info_len != sizeof ( *link_status ) ) {
538                         DBGC ( rndis, "RNDIS %s invalid link status:\n",
539                                rndis->name );
540                         DBGC_HDA ( rndis, 0, iobuf->data, len );
541                         rc = -EPROTO;
542                         goto err_link_status;
543                 }
544                 link_status = info;
545                 if ( *link_status == 0 ) {
546                         DBGC ( rndis, "RNDIS %s link is up\n", rndis->name );
547                         netdev_link_up ( netdev );
548                 } else {
549                         DBGC ( rndis, "RNDIS %s link is down: %#08x\n",
550                                rndis->name, le32_to_cpu ( *link_status ) );
551                         netdev_link_down ( netdev );
552                 }
553                 break;
554
555         default:
556                 DBGC ( rndis, "RNDIS %s unexpected query completion ID %#08x\n",
557                        rndis->name, id );
558                 DBGC_HDA ( rndis, 0, iobuf->data, len );
559                 rc = -EPROTO;
560                 goto err_id;
561         }
562
563         /* Success */
564         rc = 0;
565
566  err_id:
567  err_link_status:
568  err_info:
569  err_status:
570         /* Record completion result if applicable */
571         if ( id == rndis->wait_id ) {
572                 rndis->wait_id = 0;
573                 rndis->wait_rc = rc;
574         }
575  err_len:
576         /* Free I/O buffer */
577         free_iob ( iobuf );
578 }
579
580 /**
581  * Receive set OID completion
582  *
583  * @v rndis             RNDIS device
584  * @v iobuf             I/O buffer
585  */
586 static void rndis_rx_set_oid ( struct rndis_device *rndis,
587                                struct io_buffer *iobuf ) {
588         struct rndis_set_completion *cmplt;
589         size_t len = iob_len ( iobuf );
590         unsigned int id;
591         int rc;
592
593         /* Sanity check */
594         if ( len < sizeof ( *cmplt ) ) {
595                 DBGC ( rndis, "RNDIS %s received underlength set completion:\n",
596                        rndis->name );
597                 DBGC_HDA ( rndis, 0, iobuf->data, len );
598                 rc = -EINVAL;
599                 goto err_len;
600         }
601         cmplt = iobuf->data;
602
603         /* Extract request ID */
604         id = cmplt->id; /* Non-endian */
605
606         /* Check status */
607         if ( cmplt->status ) {
608                 DBGC ( rndis, "RNDIS %s received set completion failure "
609                        "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) );
610                 DBGC_HDA ( rndis, 0, iobuf->data, len );
611                 rc = -EIO;
612                 goto err_status;
613         }
614
615         /* Success */
616         rc = 0;
617
618  err_status:
619         /* Record completion result if applicable */
620         if ( id == rndis->wait_id ) {
621                 rndis->wait_id = 0;
622                 rndis->wait_rc = rc;
623         }
624  err_len:
625         /* Free I/O buffer */
626         free_iob ( iobuf );
627 }
628
629 /**
630  * Query or set OID
631  *
632  * @v rndis             RNDIS device
633  * @v oid               Object ID
634  * @v data              New OID value (or NULL to query current value)
635  * @v len               Length of new OID value
636  * @ret rc              Return status code
637  */
638 static int rndis_oid ( struct rndis_device *rndis, unsigned int oid,
639                        const void *data, size_t len ) {
640         int rc;
641
642         /* Transmit query */
643         if ( ( rc = rndis_tx_oid ( rndis, oid, data, len ) ) != 0 )
644                 return rc;
645
646         /* Wait for response */
647         if ( ( rc = rndis_wait ( rndis, oid ) ) != 0 )
648                 return rc;
649
650         return 0;
651 }
652
653 /**
654  * Receive indicate status message
655  *
656  * @v rndis             RNDIS device
657  * @v iobuf             I/O buffer
658  */
659 static void rndis_rx_status ( struct rndis_device *rndis,
660                               struct io_buffer *iobuf ) {
661         struct net_device *netdev = rndis->netdev;
662         struct rndis_indicate_status_message *msg;
663         size_t len = iob_len ( iobuf );
664         unsigned int status;
665         int rc;
666
667         /* Sanity check */
668         if ( len < sizeof ( *msg ) ) {
669                 DBGC ( rndis, "RNDIS %s received underlength status message:\n",
670                        rndis->name );
671                 DBGC_HDA ( rndis, 0, iobuf->data, len );
672                 rc = -EINVAL;
673                 goto err_len;
674         }
675         msg = iobuf->data;
676
677         /* Extract status */
678         status = le32_to_cpu ( msg->status );
679
680         /* Handle status */
681         switch ( msg->status ) {
682
683         case RNDIS_STATUS_MEDIA_CONNECT:
684                 DBGC ( rndis, "RNDIS %s link is up\n", rndis->name );
685                 netdev_link_up ( netdev );
686                 break;
687
688         case RNDIS_STATUS_MEDIA_DISCONNECT:
689                 DBGC ( rndis, "RNDIS %s link is down\n", rndis->name );
690                 netdev_link_down ( netdev );
691                 break;
692
693         case RNDIS_STATUS_WTF_WORLD:
694                 /* Ignore */
695                 break;
696
697         default:
698                 DBGC ( rndis, "RNDIS %s unexpected status %#08x:\n",
699                        rndis->name, status );
700                 DBGC_HDA ( rndis, 0, iobuf->data, len );
701                 rc = -ENOTSUP;
702                 goto err_status;
703         }
704
705         /* Free I/O buffer */
706         free_iob ( iobuf );
707
708         return;
709
710  err_status:
711  err_len:
712         /* Report error via network device statistics */
713         netdev_rx_err ( netdev, iobuf, rc );
714 }
715
716 /**
717  * Receive RNDIS message
718  *
719  * @v rndis             RNDIS device
720  * @v iobuf             I/O buffer
721  * @v type              Message type
722  */
723 static void rndis_rx_message ( struct rndis_device *rndis,
724                                struct io_buffer *iobuf, unsigned int type ) {
725         struct net_device *netdev = rndis->netdev;
726         int rc;
727
728         /* Handle packet */
729         switch ( type ) {
730
731         case RNDIS_PACKET_MSG:
732                 rndis_rx_data ( rndis, iob_disown ( iobuf ) );
733                 break;
734
735         case RNDIS_INITIALISE_CMPLT:
736                 rndis_rx_initialise ( rndis, iob_disown ( iobuf ) );
737                 break;
738
739         case RNDIS_QUERY_CMPLT:
740                 rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) );
741                 break;
742
743         case RNDIS_SET_CMPLT:
744                 rndis_rx_set_oid ( rndis, iob_disown ( iobuf ) );
745                 break;
746
747         case RNDIS_INDICATE_STATUS_MSG:
748                 rndis_rx_status ( rndis, iob_disown ( iobuf ) );
749                 break;
750
751         default:
752                 DBGC ( rndis, "RNDIS %s received unexpected type %#08x\n",
753                        rndis->name, type );
754                 DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
755                 rc = -EPROTO;
756                 goto err_type;
757         }
758
759         return;
760
761  err_type:
762         /* Report error via network device statistics */
763         netdev_rx_err ( netdev, iobuf, rc );
764 }
765
766 /**
767  * Receive packet from underlying transport layer
768  *
769  * @v rndis             RNDIS device
770  * @v iobuf             I/O buffer
771  */
772 void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
773         struct net_device *netdev = rndis->netdev;
774         struct rndis_header *header;
775         unsigned int type;
776         int rc;
777
778         /* Sanity check */
779         if ( iob_len ( iobuf ) < sizeof ( *header ) ) {
780                 DBGC ( rndis, "RNDIS %s received underlength packet:\n",
781                        rndis->name );
782                 DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
783                 rc = -EINVAL;
784                 goto drop;
785         }
786         header = iobuf->data;
787
788         /* Parse and strip header */
789         type = le32_to_cpu ( header->type );
790         iob_pull ( iobuf, sizeof ( *header ) );
791
792         /* Handle message */
793         rndis_rx_message ( rndis, iob_disown ( iobuf ), type );
794
795         return;
796
797  drop:
798         /* Record error */
799         netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
800 }
801
802 /**
803  * Discard packet from underlying transport layer
804  *
805  * @v rndis             RNDIS device
806  * @v iobuf             I/O buffer
807  * @v rc                Packet status code
808  */
809 void rndis_rx_err ( struct rndis_device *rndis, struct io_buffer *iobuf,
810                     int rc ) {
811         struct net_device *netdev = rndis->netdev;
812
813         /* Record error */
814         netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
815 }
816
817 /**
818  * Set receive filter
819  *
820  * @v rndis             RNDIS device
821  * @v filter            Receive filter
822  * @ret rc              Return status code
823  */
824 static int rndis_filter ( struct rndis_device *rndis, unsigned int filter ) {
825         uint32_t value = cpu_to_le32 ( filter );
826         int rc;
827
828         /* Set receive filter */
829         if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
830                                 &value, sizeof ( value ) ) ) != 0 ) {
831                 DBGC ( rndis, "RNDIS %s could not set receive filter to %#08x: "
832                        "%s\n", rndis->name, filter, strerror ( rc ) );
833                 return rc;
834         }
835
836         return 0;
837 }
838
839 /**
840  * Open network device
841  *
842  * @v netdev            Network device
843  * @ret rc              Return status code
844  */
845 static int rndis_open ( struct net_device *netdev ) {
846         struct rndis_device *rndis = netdev->priv;
847         int rc;
848
849         /* Open RNDIS device */
850         if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
851                 DBGC ( rndis, "RNDIS %s could not open: %s\n",
852                        rndis->name, strerror ( rc ) );
853                 goto err_open;
854         }
855
856         /* Initialise RNDIS */
857         if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
858                 goto err_initialise;
859
860         /* Set receive filter */
861         if ( ( rc = rndis_filter ( rndis, ( RNDIS_FILTER_UNICAST |
862                                             RNDIS_FILTER_MULTICAST |
863                                             RNDIS_FILTER_ALL_MULTICAST |
864                                             RNDIS_FILTER_BROADCAST |
865                                             RNDIS_FILTER_PROMISCUOUS ) ) ) != 0)
866                 goto err_set_filter;
867
868         /* Update link status */
869         if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
870                                 NULL, 0 ) ) != 0 )
871                 goto err_query_link;
872
873         return 0;
874
875  err_query_link:
876  err_set_filter:
877         rndis_halt ( rndis );
878  err_initialise:
879         rndis->op->close ( rndis );
880  err_open:
881         return rc;
882 }
883
884 /**
885  * Close network device
886  *
887  * @v netdev            Network device
888  */
889 static void rndis_close ( struct net_device *netdev ) {
890         struct rndis_device *rndis = netdev->priv;
891
892         /* Clear receive filter */
893         rndis_filter ( rndis, 0 );
894
895         /* Halt RNDIS device */
896         rndis_halt ( rndis );
897
898         /* Close RNDIS device */
899         rndis->op->close ( rndis );
900 }
901
902 /**
903  * Transmit packet
904  *
905  * @v netdev            Network device
906  * @v iobuf             I/O buffer
907  * @ret rc              Return status code
908  */
909 static int rndis_transmit ( struct net_device *netdev,
910                             struct io_buffer *iobuf ) {
911         struct rndis_device *rndis = netdev->priv;
912
913         /* Transmit data packet */
914         return rndis_tx_data ( rndis, iobuf );
915 }
916
917 /**
918  * Poll for completed and received packets
919  *
920  * @v netdev            Network device
921  */
922 static void rndis_poll ( struct net_device *netdev ) {
923         struct rndis_device *rndis = netdev->priv;
924
925         /* Poll RNDIS device */
926         rndis->op->poll ( rndis );
927 }
928
929 /** Network device operations */
930 static struct net_device_operations rndis_operations = {
931         .open           = rndis_open,
932         .close          = rndis_close,
933         .transmit       = rndis_transmit,
934         .poll           = rndis_poll,
935 };
936
937 /**
938  * Allocate RNDIS device
939  *
940  * @v priv_len          Length of private data
941  * @ret rndis           RNDIS device, or NULL on allocation failure
942  */
943 struct rndis_device * alloc_rndis ( size_t priv_len ) {
944         struct net_device *netdev;
945         struct rndis_device *rndis;
946
947         /* Allocate and initialise structure */
948         netdev = alloc_etherdev ( sizeof ( *rndis ) + priv_len );
949         if ( ! netdev )
950                 return NULL;
951         netdev_init ( netdev, &rndis_operations );
952         rndis = netdev->priv;
953         rndis->netdev = netdev;
954         rndis->priv = ( ( ( void * ) rndis ) + sizeof ( *rndis ) );
955
956         return rndis;
957 }
958
959 /**
960  * Register RNDIS device
961  *
962  * @v rndis             RNDIS device
963  * @ret rc              Return status code
964  *
965  * Note that this routine will open and use the RNDIS device in order
966  * to query the MAC address.  The device must be immediately ready for
967  * use prior to registration.
968  */
969 int register_rndis ( struct rndis_device *rndis ) {
970         struct net_device *netdev = rndis->netdev;
971         int rc;
972
973         /* Assign device name (for debugging) */
974         rndis->name = netdev->dev->name;
975
976         /* Register network device */
977         if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
978                 DBGC ( rndis, "RNDIS %s could not register: %s\n",
979                        rndis->name, strerror ( rc ) );
980                 goto err_register;
981         }
982
983         /* Open RNDIS device to read MAC addresses */
984         if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
985                 DBGC ( rndis, "RNDIS %s could not open: %s\n",
986                        rndis->name, strerror ( rc ) );
987                 goto err_open;
988         }
989
990         /* Initialise RNDIS */
991         if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
992                 goto err_initialise;
993
994         /* Query permanent MAC address */
995         if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
996                                 NULL, 0 ) ) != 0 )
997                 goto err_query_permanent;
998
999         /* Query current MAC address */
1000         if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_CURRENT_ADDRESS,
1001                                 NULL, 0 ) ) != 0 )
1002                 goto err_query_current;
1003
1004         /* Get link status */
1005         if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
1006                                 NULL, 0 ) ) != 0 )
1007                 goto err_query_link;
1008
1009         /* Halt RNDIS device */
1010         rndis_halt ( rndis );
1011
1012         /* Close RNDIS device */
1013         rndis->op->close ( rndis );
1014
1015         return 0;
1016
1017  err_query_link:
1018  err_query_current:
1019  err_query_permanent:
1020         rndis_halt ( rndis );
1021  err_initialise:
1022         rndis->op->close ( rndis );
1023  err_open:
1024         unregister_netdev ( netdev );
1025  err_register:
1026         return rc;
1027 }
1028
1029 /**
1030  * Unregister RNDIS device
1031  *
1032  * @v rndis             RNDIS device
1033  */
1034 void unregister_rndis ( struct rndis_device *rndis ) {
1035         struct net_device *netdev = rndis->netdev;
1036
1037         /* Unregister network device */
1038         unregister_netdev ( netdev );
1039 }
1040
1041 /**
1042  * Free RNDIS device
1043  *
1044  * @v rndis             RNDIS device
1045  */
1046 void free_rndis ( struct rndis_device *rndis ) {
1047         struct net_device *netdev = rndis->netdev;
1048
1049         /* Free network device */
1050         netdev_nullify ( netdev );
1051         netdev_put ( netdev );
1052 }