Browse Source

[undi] Fill in ProtType correctly in PXENV_UNDI_ISR

Determine the network-layer packet type and fill it in for UNDI
clients.  This is required by some NBPs such as emBoot's winBoot/i.

This change requires refactoring the link-layer portions of the
gPXE netdevice API, so that it becomes possible to strip the
link-layer header without passing the packet up the network stack.
tags/v0.9.4
Michael Brown 16 years ago
parent
commit
30fb3b3810
5 changed files with 145 additions and 65 deletions
  1. 22
    21
      src/drivers/net/ipoib.c
  2. 15
    11
      src/include/gpxe/netdevice.h
  3. 61
    12
      src/interface/pxe/pxe_undi.c
  4. 21
    19
      src/net/ethernet.c
  5. 26
    2
      src/net/netdevice.c

+ 22
- 21
src/drivers/net/ipoib.c View File

@@ -153,18 +153,17 @@ static struct ipoib_mac ipoib_broadcast = {
153 153
 };
154 154
 
155 155
 /**
156
- * Transmit IPoIB packet
156
+ * Add IPoIB link-layer header
157 157
  *
158 158
  * @v iobuf		I/O buffer
159 159
  * @v netdev		Network device
160 160
  * @v net_protocol	Network-layer protocol
161 161
  * @v ll_dest		Link-layer destination address
162
- *
163
- * Prepends the IPoIB link-layer header and transmits the packet.
164 162
  */
165
-static int ipoib_tx ( struct io_buffer *iobuf, struct net_device *netdev,
166
-		      struct net_protocol *net_protocol,
167
-		      const void *ll_dest ) {
163
+static int ipoib_push ( struct io_buffer *iobuf,
164
+			struct net_device *netdev __unused,
165
+			struct net_protocol *net_protocol,
166
+			const void *ll_dest ) {
168 167
 	struct ipoib_hdr *ipoib_hdr =
169 168
 		iob_push ( iobuf, sizeof ( *ipoib_hdr ) );
170 169
 
@@ -174,36 +173,38 @@ static int ipoib_tx ( struct io_buffer *iobuf, struct net_device *netdev,
174 173
 	ipoib_hdr->real.proto = net_protocol->net_proto;
175 174
 	ipoib_hdr->real.reserved = 0;
176 175
 
177
-	/* Hand off to network device */
178
-	return netdev_tx ( netdev, iobuf );
176
+	return 0;
179 177
 }
180 178
 
181 179
 /**
182
- * Process received IPoIB packet
183
- *
184
- * @v iobuf	I/O buffer
185
- * @v netdev	Network device
180
+ * Remove IPoIB link-layer header
186 181
  *
187
- * Strips off the IPoIB link-layer header and passes up to the
188
- * network-layer protocol.
182
+ * @v iobuf		I/O buffer
183
+ * @v netdev		Network device
184
+ * @v net_proto		Network-layer protocol, in network-byte order
185
+ * @v ll_source		Source link-layer address
186
+ * @ret rc		Return status code
189 187
  */
190
-static int ipoib_rx ( struct io_buffer *iobuf, struct net_device *netdev ) {
188
+static int ipoib_pull ( struct io_buffer *iobuf,
189
+			struct net_device *netdev __unused,
190
+			uint16_t *net_proto, const void **ll_source ) {
191 191
 	struct ipoib_hdr *ipoib_hdr = iobuf->data;
192 192
 
193 193
 	/* Sanity check */
194 194
 	if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
195 195
 		DBG ( "IPoIB packet too short for link-layer header\n" );
196 196
 		DBG_HD ( iobuf->data, iob_len ( iobuf ) );
197
-		free_iob ( iobuf );
198 197
 		return -EINVAL;
199 198
 	}
200 199
 
201 200
 	/* Strip off IPoIB header */
202 201
 	iob_pull ( iobuf, sizeof ( *ipoib_hdr ) );
203 202
 
204
-	/* Hand off to network-layer protocol */
205
-	return net_rx ( iobuf, netdev, ipoib_hdr->real.proto,
206
-			&ipoib_hdr->pseudo.peer );
203
+	/* Fill in required fields */
204
+	*net_proto = ipoib_hdr->real.proto;
205
+	*ll_source = &ipoib_hdr->pseudo.peer;
206
+
207
+	return 0;
207 208
 }
208 209
 
209 210
 /**
@@ -231,8 +232,8 @@ struct ll_protocol ipoib_protocol __ll_protocol = {
231 232
 	.ll_addr_len	= IPOIB_ALEN,
232 233
 	.ll_header_len	= IPOIB_HLEN,
233 234
 	.ll_broadcast	= ( uint8_t * ) &ipoib_broadcast,
234
-	.tx		= ipoib_tx,
235
-	.rx		= ipoib_rx,
235
+	.push		= ipoib_push,
236
+	.pull		= ipoib_pull,
236 237
 	.ntoa		= ipoib_ntoa,
237 238
 };
238 239
 

+ 15
- 11
src/include/gpxe/netdevice.h View File

@@ -76,7 +76,7 @@ struct ll_protocol {
76 76
 	/** Protocol name */
77 77
 	const char *name;
78 78
 	/**
79
-	 * Transmit network-layer packet via network device
79
+	 * Add link-layer header
80 80
 	 *
81 81
 	 * @v iobuf		I/O buffer
82 82
 	 * @v netdev		Network device
@@ -85,24 +85,28 @@ struct ll_protocol {
85 85
 	 * @ret rc		Return status code
86 86
 	 *
87 87
 	 * This method should prepend in the link-layer header
88
-	 * (e.g. the Ethernet DIX header) and transmit the packet.
89
-	 * This method takes ownership of the I/O buffer.
88
+	 * (e.g. the Ethernet DIX header).
90 89
 	 */
91
-	int ( * tx ) ( struct io_buffer *iobuf, struct net_device *netdev,
92
-		       struct net_protocol *net_protocol,
93
-		       const void *ll_dest );
90
+	int ( * push ) ( struct io_buffer *iobuf, struct net_device *netdev,
91
+			 struct net_protocol *net_protocol,
92
+			 const void *ll_dest );
94 93
 	/**
95
-	 * Handle received packet
94
+	 * Remove link-layer header
96 95
 	 *
97 96
 	 * @v iobuf	I/O buffer
98 97
 	 * @v netdev	Network device
98
+	 * @v net_proto	Network-layer protocol, in network-byte order
99
+	 * @v ll_source	Source link-layer address
100
+	 * @ret rc	Return status code
99 101
 	 *
100 102
 	 * This method should strip off the link-layer header
101
-	 * (e.g. the Ethernet DIX header) and pass the packet to
102
-	 * net_rx().  This method takes ownership of the packet
103
-	 * buffer.
103
+	 * (e.g. the Ethernet DIX header) and return the protocol and
104
+	 * source link-layer address.  The method must not alter the
105
+	 * packet content, and may return the link-layer address as a
106
+	 * pointer to data within the packet.
104 107
 	 */
105
-	int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev );
108
+	int ( * pull ) ( struct io_buffer *iobuf, struct net_device *netdev,
109
+			 uint16_t *net_proto, const void **ll_source );
106 110
 	/**
107 111
 	 * Transcribe link-layer address
108 112
 	 *

+ 61
- 12
src/interface/pxe/pxe_undi.c View File

@@ -251,11 +251,9 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
251 251
 				 datablk->TDDataLen );
252 252
 	}
253 253
 
254
-	/* Transmit packet */
255
-	if ( net_protocol == NULL ) {
256
-		/* Link-layer header already present */
257
-		rc = netdev_tx ( pxe_netdev, iobuf );
258
-	} else {
254
+	/* Add link-layer header, if required to do so */
255
+	if ( net_protocol != NULL ) {
256
+
259 257
 		/* Calculate destination address */
260 258
 		if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
261 259
 			copy_from_real ( destaddr,
@@ -267,14 +265,28 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
267 265
 			DBG ( " BCAST" );
268 266
 			ll_dest = pxe_netdev->ll_protocol->ll_broadcast;
269 267
 		}
270
-		rc = net_tx ( iobuf, pxe_netdev, net_protocol, ll_dest );
268
+
269
+		/* Add link-layer header */
270
+		if ( ( rc = pxe_netdev->ll_protocol->push ( iobuf, pxe_netdev,
271
+							    net_protocol,
272
+							    ll_dest )) != 0 ){
273
+			free_iob ( iobuf );
274
+			undi_transmit->Status = PXENV_STATUS ( rc );
275
+			return PXENV_EXIT_FAILURE;
276
+		}
277
+	}
278
+
279
+	/* Transmit packet */
280
+	if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
281
+		undi_transmit->Status = PXENV_STATUS ( rc );
282
+		return PXENV_EXIT_FAILURE;
271 283
 	}
272 284
 
273 285
 	/* Flag transmission as in-progress */
274 286
 	undi_tx_count++;
275 287
 
276
-	undi_transmit->Status = PXENV_STATUS ( rc );
277
-	return ( ( rc == 0 ) ? PXENV_EXIT_SUCCESS : PXENV_EXIT_FAILURE );
288
+	undi_transmit->Status = PXENV_STATUS_SUCCESS;
289
+	return PXENV_EXIT_SUCCESS;
278 290
 }
279 291
 
280 292
 /* PXENV_UNDI_SET_MCAST_ADDRESS
@@ -532,6 +544,13 @@ PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
532 544
 PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
533 545
 	struct io_buffer *iobuf;
534 546
 	size_t len;
547
+	struct ll_protocol *ll_protocol;
548
+	const void *ll_source;
549
+	uint16_t net_proto;
550
+	size_t ll_hlen;
551
+	struct net_protocol *net_protocol;
552
+	unsigned int prottype;
553
+	int rc;
535 554
 
536 555
 	DBG ( "PXENV_UNDI_ISR" );
537 556
 
@@ -604,16 +623,46 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
604 623
 		}
605 624
 		memcpy ( basemem_packet, iobuf->data, len );
606 625
 
626
+		/* Strip link-layer header */
627
+		ll_protocol = pxe_netdev->ll_protocol;
628
+		if ( ( rc = ll_protocol->pull ( iobuf, pxe_netdev,
629
+						&net_proto,
630
+						&ll_source ) ) != 0 ) {
631
+			/* Assume unknown net_proto and no ll_source */
632
+			net_proto = 0;
633
+			ll_source = NULL;
634
+		}
635
+		ll_hlen = ( len - iob_len ( iobuf ) );
636
+
637
+		/* Determine network-layer protocol */
638
+		switch ( net_proto ) {
639
+		case htons ( ETH_P_IP ):
640
+			net_protocol = &ipv4_protocol;
641
+			prottype = P_IP;
642
+			break;
643
+		case htons ( ETH_P_ARP ):
644
+			net_protocol = &arp_protocol;
645
+			prottype = P_ARP;
646
+			break;
647
+		case htons ( ETH_P_RARP ):
648
+			net_protocol = &rarp_protocol;
649
+			prottype = P_RARP;
650
+			break;
651
+		default:
652
+			net_protocol = NULL;
653
+			prottype = P_UNKNOWN;
654
+			break;
655
+		}
656
+		DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
657
+
607 658
 		/* Fill in UNDI_ISR structure */
608 659
 		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
609 660
 		undi_isr->BufferLength = len;
610 661
 		undi_isr->FrameLength = len;
611
-		undi_isr->FrameHeaderLength =
612
-			pxe_netdev->ll_protocol->ll_header_len;
662
+		undi_isr->FrameHeaderLength = ll_hlen;
613 663
 		undi_isr->Frame.segment = rm_ds;
614 664
 		undi_isr->Frame.offset = __from_data16 ( basemem_packet );
615
-		/* Probably ought to fill in packet type */
616
-		undi_isr->ProtType = P_UNKNOWN;
665
+		undi_isr->ProtType = prottype;
617 666
 		undi_isr->PktType = XMT_DESTADDR;
618 667
 
619 668
 		/* Free packet */

+ 21
- 19
src/net/ethernet.c View File

@@ -38,17 +38,16 @@
38 38
 static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
39 39
 
40 40
 /**
41
- * Transmit Ethernet packet
41
+ * Add Ethernet link-layer header
42 42
  *
43 43
  * @v iobuf		I/O buffer
44 44
  * @v netdev		Network device
45 45
  * @v net_protocol	Network-layer protocol
46 46
  * @v ll_dest		Link-layer destination address
47
- *
48
- * Prepends the Ethernet link-layer header and transmits the packet.
49 47
  */
50
-static int eth_tx ( struct io_buffer *iobuf, struct net_device *netdev,
51
-		    struct net_protocol *net_protocol, const void *ll_dest ) {
48
+static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev,
49
+		      struct net_protocol *net_protocol,
50
+		      const void *ll_dest ) {
52 51
 	struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
53 52
 
54 53
 	/* Build Ethernet header */
@@ -56,35 +55,38 @@ static int eth_tx ( struct io_buffer *iobuf, struct net_device *netdev,
56 55
 	memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
57 56
 	ethhdr->h_protocol = net_protocol->net_proto;
58 57
 
59
-	/* Hand off to network device */
60
-	return netdev_tx ( netdev, iobuf );
58
+	return 0;
61 59
 }
62 60
 
63 61
 /**
64
- * Process received Ethernet packet
65
- *
66
- * @v iobuf	I/O buffer
67
- * @v netdev	Network device
62
+ * Remove Ethernet link-layer header
68 63
  *
69
- * Strips off the Ethernet link-layer header and passes up to the
70
- * network-layer protocol.
64
+ * @v iobuf		I/O buffer
65
+ * @v netdev		Network device
66
+ * @v net_proto		Network-layer protocol, in network-byte order
67
+ * @v ll_source		Source link-layer address
68
+ * @ret rc		Return status code
71 69
  */
72
-static int eth_rx ( struct io_buffer *iobuf, struct net_device *netdev ) {
70
+static int eth_pull ( struct io_buffer *iobuf,
71
+		      struct net_device *netdev __unused,
72
+		      uint16_t *net_proto, const void **ll_source ) {
73 73
 	struct ethhdr *ethhdr = iobuf->data;
74 74
 
75 75
 	/* Sanity check */
76 76
 	if ( iob_len ( iobuf ) < sizeof ( *ethhdr ) ) {
77 77
 		DBG ( "Ethernet packet too short (%zd bytes)\n",
78 78
 		      iob_len ( iobuf ) );
79
-		free_iob ( iobuf );
80 79
 		return -EINVAL;
81 80
 	}
82 81
 
83 82
 	/* Strip off Ethernet header */
84 83
 	iob_pull ( iobuf, sizeof ( *ethhdr ) );
85 84
 
86
-	/* Hand off to network-layer protocol */
87
-	return net_rx ( iobuf, netdev, ethhdr->h_protocol, ethhdr->h_source );
85
+	/* Fill in required fields */
86
+	*net_proto = ethhdr->h_protocol;
87
+	*ll_source = ethhdr->h_source;
88
+
89
+	return 0;
88 90
 }
89 91
 
90 92
 /**
@@ -110,7 +112,7 @@ struct ll_protocol ethernet_protocol __ll_protocol = {
110 112
 	.ll_addr_len	= ETH_ALEN,
111 113
 	.ll_header_len	= ETH_HLEN,
112 114
 	.ll_broadcast	= eth_broadcast,
113
-	.tx		= eth_tx,
114
-	.rx		= eth_rx,
115
+	.push		= eth_push,
116
+	.pull		= eth_pull,
115 117
 	.ntoa		= eth_ntoa,
116 118
 };

+ 26
- 2
src/net/netdevice.c View File

@@ -439,6 +439,7 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
439 439
  */
440 440
 int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
441 441
 	     struct net_protocol *net_protocol, const void *ll_dest ) {
442
+	int rc;
442 443
 
443 444
 	/* Force a poll on the netdevice to (potentially) clear any
444 445
 	 * backed-up TX completions.  This is needed on some network
@@ -447,7 +448,15 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
447 448
 	 */
448 449
 	netdev_poll ( netdev );
449 450
 
450
-	return netdev->ll_protocol->tx ( iobuf, netdev, net_protocol, ll_dest );
451
+	/* Add link-layer header */
452
+	if ( ( rc = netdev->ll_protocol->push ( iobuf, netdev, net_protocol,
453
+						ll_dest ) ) != 0 ) {
454
+		free_iob ( iobuf );
455
+		return rc;
456
+	}
457
+
458
+	/* Transmit packet */
459
+	return netdev_tx ( netdev, iobuf );
451 460
 }
452 461
 
453 462
 /**
@@ -485,6 +494,10 @@ int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
485 494
 static void net_step ( struct process *process __unused ) {
486 495
 	struct net_device *netdev;
487 496
 	struct io_buffer *iobuf;
497
+	struct ll_protocol *ll_protocol;
498
+	uint16_t net_proto;
499
+	const void *ll_source;
500
+	int rc;
488 501
 
489 502
 	/* Poll and process each network device */
490 503
 	list_for_each_entry ( netdev, &net_devices, list ) {
@@ -499,10 +512,21 @@ static void net_step ( struct process *process __unused ) {
499 512
 		 * NIC faster than they arrive.
500 513
 		 */
501 514
 		if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
515
+
502 516
 			DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n",
503 517
 			       netdev, iobuf, iobuf->data,
504 518
 			       iob_len ( iobuf ) );
505
-			netdev->ll_protocol->rx ( iobuf, netdev );
519
+
520
+			/* Remove link-layer header */
521
+			ll_protocol = netdev->ll_protocol;
522
+			if ( ( rc = ll_protocol->pull ( iobuf, netdev,
523
+							&net_proto,
524
+							&ll_source ) ) != 0 ) {
525
+				free_iob ( iobuf );
526
+				continue;
527
+			}
528
+
529
+			net_rx ( iobuf, netdev, net_proto, ll_source );
506 530
 		}
507 531
 	}
508 532
 }

Loading…
Cancel
Save