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