Browse Source

[rndis] Send RNDIS_INITIALISE_MSG

The Hyper-V RNDIS implementation on Windows Server 2012 R2 requires
that we send an explicit RNDIS initialisation message in order to get
a working RX datapath.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
1d0ade42db
2 changed files with 181 additions and 24 deletions
  1. 20
    2
      src/include/ipxe/rndis.h
  2. 161
    22
      src/net/rndis.c

+ 20
- 2
src/include/ipxe/rndis.h View File

@@ -28,10 +28,10 @@ struct rndis_header {
28 28
 } __attribute__ (( packed ));
29 29
 
30 30
 /** RNDIS initialise message */
31
-#define RNDIS_INITIALIZE_MSG 0x00000002UL
31
+#define RNDIS_INITIALISE_MSG 0x00000002UL
32 32
 
33 33
 /** RNDIS initialise message */
34
-struct rndis_initialize_message {
34
+struct rndis_initialise_message {
35 35
 	/** Request ID */
36 36
 	uint32_t id;
37 37
 	/** Major version */
@@ -42,6 +42,24 @@ struct rndis_initialize_message {
42 42
 	uint32_t mtu;
43 43
 } __attribute__ (( packed ));
44 44
 
45
+/** Request ID used for initialisation
46
+ *
47
+ * This is a policy decision.
48
+ */
49
+#define RNDIS_INIT_ID 0xe110e110UL
50
+
51
+/** RNDIS major version */
52
+#define RNDIS_VERSION_MAJOR 1
53
+
54
+/** RNDIS minor version */
55
+#define RNDIS_VERSION_MINOR 0
56
+
57
+/** RNDIS maximum transfer size
58
+ *
59
+ * This is a policy decision.
60
+ */
61
+#define RNDIS_MTU 2048
62
+
45 63
 /** RNDIS initialise completion */
46 64
 #define RNDIS_INITIALISE_CMPLT 0x80000002UL
47 65
 

+ 161
- 22
src/net/rndis.c View File

@@ -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 );

Loading…
Cancel
Save