[rndis] Register netdev with MAC filled
[ipxe.git] / 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 /* Open RNDIS device to read MAC addresses */
977 if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
978 DBGC ( rndis, "RNDIS %s could not open: %s\n",
979 rndis->name, strerror ( rc ) );
980 goto err_open;
981 }
982
983 /* Initialise RNDIS */
984 if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
985 goto err_initialise;
986
987 /* Query permanent MAC address */
988 if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
989 NULL, 0 ) ) != 0 )
990 goto err_query_permanent;
991
992 /* Query current MAC address */
993 if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_CURRENT_ADDRESS,
994 NULL, 0 ) ) != 0 )
995 goto err_query_current;
996
997 /* Get link status */
998 if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
999 NULL, 0 ) ) != 0 )
1000 goto err_query_link;
1001
1002 /* Halt RNDIS device */
1003 rndis_halt ( rndis );
1004
1005 /* Close RNDIS device */
1006 rndis->op->close ( rndis );
1007
1008 /* Register network device */
1009 if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
1010 DBGC ( rndis, "RNDIS %s could not register: %s\n",
1011 rndis->name, strerror ( rc ) );
1012 goto err_register;
1013 }
1014
1015 return 0;
1016
1017 unregister_netdev ( netdev );
1018 err_register:
1019 err_query_link:
1020 err_query_current:
1021 err_query_permanent:
1022 rndis_halt ( rndis );
1023 err_initialise:
1024 rndis->op->close ( rndis );
1025 err_open:
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 }