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