Преглед изворни кода

[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 пре 9 година
родитељ
комит
1d0ade42db
2 измењених фајлова са 181 додато и 24 уклоњено
  1. 20
    2
      src/include/ipxe/rndis.h
  2. 161
    22
      src/net/rndis.c

+ 20
- 2
src/include/ipxe/rndis.h Прегледај датотеку

28
 } __attribute__ (( packed ));
28
 } __attribute__ (( packed ));
29
 
29
 
30
 /** RNDIS initialise message */
30
 /** RNDIS initialise message */
31
-#define RNDIS_INITIALIZE_MSG 0x00000002UL
31
+#define RNDIS_INITIALISE_MSG 0x00000002UL
32
 
32
 
33
 /** RNDIS initialise message */
33
 /** RNDIS initialise message */
34
-struct rndis_initialize_message {
34
+struct rndis_initialise_message {
35
 	/** Request ID */
35
 	/** Request ID */
36
 	uint32_t id;
36
 	uint32_t id;
37
 	/** Major version */
37
 	/** Major version */
42
 	uint32_t mtu;
42
 	uint32_t mtu;
43
 } __attribute__ (( packed ));
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
 /** RNDIS initialise completion */
63
 /** RNDIS initialise completion */
46
 #define RNDIS_INITIALISE_CMPLT 0x80000002UL
64
 #define RNDIS_INITIALISE_CMPLT 0x80000002UL
47
 
65
 

+ 161
- 22
src/net/rndis.c Прегледај датотеку

53
 	return iobuf;
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
  * Transmit message
89
  * Transmit message
58
  *
90
  *
227
 	netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
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
  * Transmit OID message
371
  * Transmit OID message
232
  *
372
  *
443
  */
583
  */
444
 static int rndis_oid ( struct rndis_device *rndis, unsigned int oid,
584
 static int rndis_oid ( struct rndis_device *rndis, unsigned int oid,
445
 		       const void *data, size_t len ) {
585
 		       const void *data, size_t len ) {
446
-	unsigned int i;
447
 	int rc;
586
 	int rc;
448
 
587
 
449
 	/* Transmit query */
588
 	/* Transmit query */
450
 	if ( ( rc = rndis_tx_oid ( rndis, oid, data, len ) ) != 0 )
589
 	if ( ( rc = rndis_tx_oid ( rndis, oid, data, len ) ) != 0 )
451
 		return rc;
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
 		rndis_rx_data ( rndis, iob_disown ( iobuf ) );
674
 		rndis_rx_data ( rndis, iob_disown ( iobuf ) );
551
 		break;
675
 		break;
552
 
676
 
677
+	case RNDIS_INITIALISE_CMPLT:
678
+		rndis_rx_initialise ( rndis, iob_disown ( iobuf ) );
679
+		break;
680
+
553
 	case RNDIS_QUERY_CMPLT:
681
 	case RNDIS_QUERY_CMPLT:
554
 		rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) );
682
 		rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) );
555
 		break;
683
 		break;
615
 		/* Parse and check header */
743
 		/* Parse and check header */
616
 		type = le32_to_cpu ( header->type );
744
 		type = le32_to_cpu ( header->type );
617
 		len = le32_to_cpu ( header->len );
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
 			       rndis->name );
749
 			       rndis->name );
621
 			DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
750
 			DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
622
 			rc = -EINVAL;
751
 			rc = -EINVAL;
667
 		goto err_open;
796
 		goto err_open;
668
 	}
797
 	}
669
 
798
 
799
+	/* Initialise RNDIS */
800
+	if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
801
+		goto err_initialise;
802
+
670
 	/* Set receive filter */
803
 	/* Set receive filter */
671
 	filter = cpu_to_le32 ( RNDIS_FILTER_UNICAST |
804
 	filter = cpu_to_le32 ( RNDIS_FILTER_UNICAST |
672
 			       RNDIS_FILTER_MULTICAST |
805
 			       RNDIS_FILTER_MULTICAST |
689
 
822
 
690
  err_query_link:
823
  err_query_link:
691
  err_set_filter:
824
  err_set_filter:
825
+ err_initialise:
692
 	rndis->op->close ( rndis );
826
 	rndis->op->close ( rndis );
693
  err_open:
827
  err_open:
694
 	return rc;
828
 	return rc;
794
 		goto err_open;
928
 		goto err_open;
795
 	}
929
 	}
796
 
930
 
931
+	/* Initialise RNDIS */
932
+	if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
933
+		goto err_initialise;
934
+
797
 	/* Query permanent MAC address */
935
 	/* Query permanent MAC address */
798
 	if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
936
 	if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
799
 				NULL, 0 ) ) != 0 )
937
 				NULL, 0 ) ) != 0 )
817
  err_query_link:
955
  err_query_link:
818
  err_query_current:
956
  err_query_current:
819
  err_query_permanent:
957
  err_query_permanent:
958
+ err_initialise:
820
 	rndis->op->close ( rndis );
959
 	rndis->op->close ( rndis );
821
  err_open:
960
  err_open:
822
 	unregister_netdev ( netdev );
961
 	unregister_netdev ( netdev );

Loading…
Откажи
Сачувај