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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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  */
49 static 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  */
68 static 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  */
101 static 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  */
128 void rndis_tx_complete_err ( struct rndis_device *rndis,
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  */
159 static int rndis_tx_data ( struct rndis_device *rndis,
160  struct io_buffer *iobuf ) {
161  struct rndis_packet_message *msg;
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  */
191 int rndis_tx_defer ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
192  struct net_device *netdev = rndis->netdev;
193  struct rndis_header *header;
194  struct rndis_packet_message *msg;
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  */
222 static void rndis_rx_data ( struct rndis_device *rndis,
223  struct io_buffer *iobuf ) {
224  struct net_device *netdev = rndis->netdev;
225  struct rndis_packet_message *msg;
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  */
274 static 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 */
290  msg->major = cpu_to_le32 ( RNDIS_VERSION_MAJOR );
291  msg->minor = cpu_to_le32 ( RNDIS_VERSION_MINOR );
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  */
313 static 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  */
361 static 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  */
381 static 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  */
415 static 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  */
434 static 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  */
476 static 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 );
529  break;
530 
532  if ( info_len > sizeof ( netdev->ll_addr ) )
533  info_len = sizeof ( netdev->ll_addr );
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  */
587 static 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  */
639 static 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  */
660 static 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 */
684  if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_CURRENT_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  */
717 static 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  */
781 static 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 
797  case RNDIS_QUERY_CMPLT:
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  */
830 void 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  */
867 void 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  */
882 static 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  */
903 static 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  */
947 static 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  */
967 static 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  */
980 static 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  */
1001 struct 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  */
1027 int 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  */
1055 void 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  */
1067 void free_rndis ( struct rndis_device *rndis ) {
1068  struct net_device *netdev = rndis->netdev;
1069 
1070  /* Free network device */
1071  netdev_nullify ( netdev );
1072  netdev_put ( netdev );
1073 }
struct rndis_device * alloc_rndis(size_t priv_len)
Allocate RNDIS device.
Definition: rndis.c:1001
#define iob_pull(iobuf, len)
Definition: iobuf.h:107
#define EINVAL
Invalid argument.
Definition: errno.h:429
Unknown start-of-day status code.
Definition: rndis.h:196
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define iob_put(iobuf, len)
Definition: iobuf.h:125
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition: netdevice.c:587
void netdev_tx_defer(struct net_device *netdev, struct io_buffer *iobuf)
Defer transmitted packet.
Definition: netdevice.c:413
u32 info
Definition: ar9003_mac.h:24
int(* open)(struct rndis_device *rndis)
Open RNDIS device.
Definition: rndis.h:290
#define RNDIS_INDICATE_STATUS_MSG
RNDIS indicate status message.
Definition: rndis.h:167
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition: message.c:62
const char * name
Device name.
Definition: rndis.h:322
static void rndis_rx_data(struct rndis_device *rndis, struct io_buffer *iobuf)
Receive data packet.
Definition: rndis.c:222
#define le32_to_cpu(value)
Definition: byteswap.h:114
void netdev_tx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard transmitted packet.
Definition: netdevice.c:441
uint32_t oid
Object ID.
Definition: rndis.h:111
UINT8_t filter
Receive packet filter.
Definition: pxe_api.h:68
Error codes.
#define iob_push(iobuf, len)
Definition: iobuf.h:89
Multicast packets.
Definition: rndis.h:262
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
RNDIS query OID completion.
Definition: rndis.h:124
uint32_t type
Operating system type.
Definition: ena.h:12
void unregister_rndis(struct rndis_device *rndis)
Unregister RNDIS device.
Definition: rndis.c:1055
Unicast packets.
Definition: rndis.h:260
#define DBGC(...)
Definition: compiler.h:505
RNDIS query or set OID message.
Definition: rndis.h:107
static void rndis_rx_query_oid(struct rndis_device *rndis, struct io_buffer *iobuf)
Receive query OID completion.
Definition: rndis.c:476
RNDIS initialise message.
Definition: rndis.h:35
char name[40]
Name.
Definition: device.h:79
void(* close)(struct rndis_device *rndis)
Close RNDIS device.
Definition: rndis.h:296
RNDIS initialise completion.
Definition: rndis.h:68
static int rndis_wait(struct rndis_device *rndis, unsigned int wait_id)
Wait for completion.
Definition: rndis.c:68
static int rndis_tx_halt(struct rndis_device *rndis)
Transmit halt message.
Definition: rndis.c:381
uint32_t id
Request ID.
Definition: rndis.h:70
#define RNDIS_QUERY_CMPLT
RNDIS query OID completion.
Definition: rndis.h:121
void netdev_link_down(struct net_device *netdev)
Mark network device as having link down.
Definition: netdevice.c:231
uint32_t data_len
Microcode data size (or 0 to indicate 2000 bytes)
Definition: ucode.h:26
#define RNDIS_OID_GEN_MEDIA_CONNECT_STATUS
OID for media status.
Definition: rndis.h:272
#define RNDIS_MAX_WAIT_MS
Maximum time to wait for a transaction to complete.
Definition: rndis.h:21
static void rndis_rx_status(struct rndis_device *rndis, struct io_buffer *iobuf)
Receive indicate status message.
Definition: rndis.c:717
Device is connected to a network medium.
Definition: rndis.h:192
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition: iobuf.c:131
#define RNDIS_INIT_ID
Request ID used for initialisation.
Definition: rndis.h:50
#define ENOTSUP
Operation not supported.
Definition: errno.h:590
static int rndis_filter(struct rndis_device *rndis, unsigned int filter)
Set receive filter.
Definition: rndis.c:882
static int rndis_tx_message(struct rndis_device *rndis, struct io_buffer *iobuf, unsigned int type)
Transmit message.
Definition: rndis.c:101
int(* transmit)(struct rndis_device *rndis, struct io_buffer *iobuf)
Transmit packet.
Definition: rndis.h:307
#define RNDIS_VERSION_MAJOR
RNDIS major version.
Definition: rndis.h:53
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition: netdevice.h:519
#define ENOMEM
Not enough space.
Definition: errno.h:535
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition: iobuf.h:217
void * memcpy(void *dest, const void *src, size_t len) __nonnull
uint32_t id
Request ID.
Definition: rndis.h:126
uint32_t status
Status.
Definition: rndis.h:128
#define RNDIS_MTU
RNDIS maximum transfer size.
Definition: rndis.h:62
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
uint8_t info_len
Reject information length.
Definition: ib_mad.h:19
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition: netdevice.h:576
static int rndis_open(struct net_device *netdev)
Open network device.
Definition: rndis.c:903
Ethernet protocol.
struct net_device * netdev
Network device.
Definition: rndis.h:320
unsigned int wait_id
Request ID for current blocking request.
Definition: rndis.h:329
void * priv
Driver private data.
Definition: netdevice.h:432
struct rndis_operations * op
RNDIS operations.
Definition: rndis.h:324
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
#define DBGC_HDA(...)
Definition: compiler.h:506
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
Definition: netdevice.h:789
ring len
Length.
Definition: dwmac.h:231
An RNDIS device.
Definition: rndis.h:318
static struct net_device * netdev
Definition: gdbudp.c:52
#define RNDIS_SET_CMPLT
RNDIS set OID completion.
Definition: rndis.h:136
void unregister_netdev(struct net_device *netdev)
Unregister network device.
Definition: netdevice.c:942
void rndis_rx_err(struct rndis_device *rndis, struct io_buffer *iobuf, int rc)
Discard packet from underlying transport layer.
Definition: rndis.c:867
#define cpu_to_le32(value)
Definition: byteswap.h:108
uint8_t id
Request identifier.
Definition: ena.h:12
#define EPROTO
Protocol error.
Definition: errno.h:625
#define iob_unput(iobuf, len)
Definition: iobuf.h:140
static int rndis_tx_initialise(struct rndis_device *rndis, unsigned int id)
Transmit initialisation message.
Definition: rndis.c:274
static int rndis_tx_data(struct rndis_device *rndis, struct io_buffer *iobuf)
Transmit data packet.
Definition: rndis.c:159
#define RNDIS_QUERY_MSG
RNDIS query OID message.
Definition: rndis.h:101
static int rndis_initialise(struct rndis_device *rndis)
Initialise RNDIS.
Definition: rndis.c:361
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
#define RNDIS_OID_802_3_PERMANENT_ADDRESS
OID for permanent MAC address.
Definition: rndis.h:275
RNDIS packet message.
Definition: rndis.h:231
All multicast packets.
Definition: rndis.h:264
int register_rndis(struct rndis_device *rndis)
Register RNDIS device.
Definition: rndis.c:1027
int register_netdev(struct net_device *netdev)
Register network device.
Definition: netdevice.c:760
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
static struct io_buffer * rndis_alloc_iob(size_t len)
Allocate I/O buffer.
Definition: rndis.c:49
A network device.
Definition: netdevice.h:353
uint32_t id
Request ID.
Definition: rndis.h:141
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition: netdevice.h:532
#define RNDIS_INITIALISE_MSG
RNDIS initialise message.
Definition: rndis.h:32
static void rndis_rx_message(struct rndis_device *rndis, struct io_buffer *iobuf, unsigned int type)
Receive RNDIS message.
Definition: rndis.c:781
void(* poll)(struct rndis_device *rndis)
Poll for completed and received packets.
Definition: rndis.h:314
uint32_t len
Information buffer length.
Definition: rndis.h:130
Remote Network Driver Interface Specification.
RNDIS device operations.
Definition: rndis.h:283
static void rndis_close(struct net_device *netdev)
Close network device.
Definition: rndis.c:947
void rndis_rx(struct rndis_device *rndis, struct io_buffer *iobuf)
Receive packet from underlying transport layer.
Definition: rndis.c:830
unsigned int uint32_t
Definition: stdint.h:12
static int rndis_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
Definition: rndis.c:967
#define RNDIS_OID_GEN_CURRENT_PACKET_FILTER
OID for packet filter.
Definition: rndis.h:255
uint8_t status
Status.
Definition: ena.h:16
int rndis_tx_defer(struct rndis_device *rndis, struct io_buffer *iobuf)
Defer transmitted packet.
Definition: rndis.c:191
Network device operations.
Definition: netdevice.h:214
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
Definition: netdevice.c:549
struct device * dev
Underlying hardware device.
Definition: netdevice.h:365
uint32_t offset
Information buffer offset.
Definition: rndis.h:132
Network device management.
RNDIS halt message.
Definition: rndis.h:95
#define RNDIS_SET_MSG
RNDIS set OID message.
Definition: rndis.h:104
static int rndis_halt(struct rndis_device *rndis)
Halt RNDIS.
Definition: rndis.c:415
RNDIS message header.
Definition: rndis.h:24
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:79
#define iob_reserve(iobuf, len)
Definition: iobuf.h:72
All packets.
Definition: rndis.h:268
void netdev_tx_complete_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Complete network transmission.
Definition: netdevice.c:471
#define RNDIS_OID_802_3_CURRENT_ADDRESS
OID for current MAC address.
Definition: rndis.h:278
static int rndis_describe(struct rndis_device *rndis)
Describe RNDIS device.
Definition: rndis.c:660
#define RNDIS_VERSION_MINOR
RNDIS minor version.
Definition: rndis.h:56
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 * data
Start of data.
Definition: iobuf.h:53
void * priv
Driver private data.
Definition: rndis.h:326
static void rndis_rx_set_oid(struct rndis_device *rndis, struct io_buffer *iobuf)
Receive set OID completion.
Definition: rndis.c:587
#define EIO
Input/output error.
Definition: errno.h:434
static void rndis_poll(struct net_device *netdev)
Poll for completed and received packets.
Definition: rndis.c:980
uint32_t status
Status.
Definition: rndis.h:72
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition: ethernet.c:265
struct ena_llq_option header
Header locations.
Definition: ena.h:16
#define RNDIS_PACKET_MSG
RNDIS packet message.
Definition: rndis.h:220
int wait_rc
Return status code for current blocking request.
Definition: rndis.h:331
uint8_t data[48]
Additional event data.
Definition: ena.h:22
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
Device model.
Broadcast packets.
Definition: rndis.h:266
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition: netdevice.h:388
FILE_SECBOOT(PERMITTED)
void free_rndis(struct rndis_device *rndis)
Free RNDIS device.
Definition: rndis.c:1067
void rndis_tx_complete_err(struct rndis_device *rndis, struct io_buffer *iobuf, int rc)
Complete message transmission.
Definition: rndis.c:128
uint8_t hw_addr[MAX_HW_ADDR_LEN]
Hardware address.
Definition: netdevice.h:382
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
static void rndis_rx_initialise(struct rndis_device *rndis, struct io_buffer *iobuf)
Receive initialisation completion.
Definition: rndis.c:313
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:670
String functions.
RNDIS set OID completion.
Definition: rndis.h:139
#define RNDIS_INITIALISE_CMPLT
RNDIS initialise completion.
Definition: rndis.h:65
Device is disconnected from the medium.
Definition: rndis.h:194
RNDIS indicate status message.
Definition: rndis.h:178
uint32_t status
Status.
Definition: rndis.h:143
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:38
#define RNDIS_HALT_MSG
RNDIS halt message.
Definition: rndis.h:92