|
@@ -53,6 +53,38 @@ static struct io_buffer * rndis_alloc_iob ( size_t len ) {
|
53
|
53
|
return iobuf;
|
54
|
54
|
}
|
55
|
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
|
+
|
56
|
88
|
/**
|
57
|
89
|
* Transmit message
|
58
|
90
|
*
|
|
@@ -227,6 +259,114 @@ static void rndis_rx_data ( struct rndis_device *rndis,
|
227
|
259
|
netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
|
228
|
260
|
}
|
229
|
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
|
+
|
230
|
370
|
/**
|
231
|
371
|
* Transmit OID message
|
232
|
372
|
*
|
|
@@ -443,33 +583,17 @@ static void rndis_rx_set_oid ( struct rndis_device *rndis,
|
443
|
583
|
*/
|
444
|
584
|
static int rndis_oid ( struct rndis_device *rndis, unsigned int oid,
|
445
|
585
|
const void *data, size_t len ) {
|
446
|
|
- unsigned int i;
|
447
|
586
|
int rc;
|
448
|
587
|
|
449
|
588
|
/* Transmit query */
|
450
|
589
|
if ( ( rc = rndis_tx_oid ( rndis, oid, data, len ) ) != 0 )
|
451
|
590
|
return rc;
|
452
|
591
|
|
453
|
|
- /* Record query ID */
|
454
|
|
- rndis->wait_id = oid;
|
455
|
|
-
|
456
|
|
- /* Wait for operation to complete */
|
457
|
|
- for ( i = 0 ; i < RNDIS_MAX_WAIT_MS ; i++ ) {
|
458
|
|
-
|
459
|
|
- /* Check for completion */
|
460
|
|
- if ( ! rndis->wait_id )
|
461
|
|
- return rndis->wait_rc;
|
462
|
|
-
|
463
|
|
- /* Poll RNDIS device */
|
464
|
|
- rndis->op->poll ( rndis );
|
465
|
|
-
|
466
|
|
- /* Delay for 1ms */
|
467
|
|
- mdelay ( 1 );
|
468
|
|
- }
|
|
592
|
+ /* Wait for response */
|
|
593
|
+ if ( ( rc = rndis_wait ( rndis, oid ) ) != 0 )
|
|
594
|
+ return rc;
|
469
|
595
|
|
470
|
|
- DBGC ( rndis, "RNDIS %s timed out waiting for OID %#08x\n",
|
471
|
|
- rndis->name, oid );
|
472
|
|
- return -ETIMEDOUT;
|
|
596
|
+ return 0;
|
473
|
597
|
}
|
474
|
598
|
|
475
|
599
|
/**
|
|
@@ -550,6 +674,10 @@ static void rndis_rx_message ( struct rndis_device *rndis,
|
550
|
674
|
rndis_rx_data ( rndis, iob_disown ( iobuf ) );
|
551
|
675
|
break;
|
552
|
676
|
|
|
677
|
+ case RNDIS_INITIALISE_CMPLT:
|
|
678
|
+ rndis_rx_initialise ( rndis, iob_disown ( iobuf ) );
|
|
679
|
+ break;
|
|
680
|
+
|
553
|
681
|
case RNDIS_QUERY_CMPLT:
|
554
|
682
|
rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) );
|
555
|
683
|
break;
|
|
@@ -615,8 +743,9 @@ void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
|
615
|
743
|
/* Parse and check header */
|
616
|
744
|
type = le32_to_cpu ( header->type );
|
617
|
745
|
len = le32_to_cpu ( header->len );
|
618
|
|
- if ( len > iob_len ( iobuf ) ) {
|
619
|
|
- DBGC ( rndis, "RNDIS %s received underlength packet:\n",
|
|
746
|
+ if ( ( len < sizeof ( *header ) ) ||
|
|
747
|
+ ( len > iob_len ( iobuf ) ) ) {
|
|
748
|
+ DBGC ( rndis, "RNDIS %s received malformed packet:\n",
|
620
|
749
|
rndis->name );
|
621
|
750
|
DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
|
622
|
751
|
rc = -EINVAL;
|
|
@@ -667,6 +796,10 @@ static int rndis_open ( struct net_device *netdev ) {
|
667
|
796
|
goto err_open;
|
668
|
797
|
}
|
669
|
798
|
|
|
799
|
+ /* Initialise RNDIS */
|
|
800
|
+ if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
|
|
801
|
+ goto err_initialise;
|
|
802
|
+
|
670
|
803
|
/* Set receive filter */
|
671
|
804
|
filter = cpu_to_le32 ( RNDIS_FILTER_UNICAST |
|
672
|
805
|
RNDIS_FILTER_MULTICAST |
|
|
@@ -689,6 +822,7 @@ static int rndis_open ( struct net_device *netdev ) {
|
689
|
822
|
|
690
|
823
|
err_query_link:
|
691
|
824
|
err_set_filter:
|
|
825
|
+ err_initialise:
|
692
|
826
|
rndis->op->close ( rndis );
|
693
|
827
|
err_open:
|
694
|
828
|
return rc;
|
|
@@ -794,6 +928,10 @@ int register_rndis ( struct rndis_device *rndis ) {
|
794
|
928
|
goto err_open;
|
795
|
929
|
}
|
796
|
930
|
|
|
931
|
+ /* Initialise RNDIS */
|
|
932
|
+ if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
|
|
933
|
+ goto err_initialise;
|
|
934
|
+
|
797
|
935
|
/* Query permanent MAC address */
|
798
|
936
|
if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
|
799
|
937
|
NULL, 0 ) ) != 0 )
|
|
@@ -817,6 +955,7 @@ int register_rndis ( struct rndis_device *rndis ) {
|
817
|
955
|
err_query_link:
|
818
|
956
|
err_query_current:
|
819
|
957
|
err_query_permanent:
|
|
958
|
+ err_initialise:
|
820
|
959
|
rndis->op->close ( rndis );
|
821
|
960
|
err_open:
|
822
|
961
|
unregister_netdev ( netdev );
|