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