Parcourir la source

Verify checksums on the RX datapath.

Simplify checksum generation on the TX datapath.
tags/v0.9.3
Michael Brown il y a 18 ans
Parent
révision
a0525a4ed3
8 fichiers modifiés avec 176 ajouts et 159 suppressions
  1. 1
    1
      src/include/gpxe/ip.h
  2. 20
    20
      src/include/gpxe/tcpip.h
  3. 1
    2
      src/net/icmpv6.c
  4. 110
    99
      src/net/ipv4.c
  5. 7
    9
      src/net/ipv6.c
  6. 16
    9
      src/net/tcp.c
  7. 13
    9
      src/net/tcpip.c
  8. 8
    10
      src/net/udp.c

+ 1
- 1
src/include/gpxe/ip.h Voir le fichier

@@ -12,7 +12,7 @@
12 12
 
13 13
 /* IP constants */
14 14
 
15
-#define IP_VER		4
15
+#define IP_VER		0x40
16 16
 #define IP_MASK_VER	0xf0
17 17
 #define IP_MASK_HLEN 	0x0f
18 18
 #define IP_MASK_OFFSET	0x1fff

+ 20
- 20
src/include/gpxe/tcpip.h Voir le fichier

@@ -14,6 +14,13 @@
14 14
 
15 15
 struct pk_buff;
16 16
 
17
+/** Empty checksum value
18
+ *
19
+ * This is the TCP/IP checksum over a zero-length block of data.
20
+ */
21
+#define TCPIP_EMPTY_CSUM 0xffff
22
+
23
+/** Length of a @c struct @c sockaddr_tcpip */
17 24
 #define SA_TCPIP_LEN 32
18 25
 
19 26
 /**
@@ -45,30 +52,22 @@ struct tcpip_protocol {
45 52
        	/**
46 53
          * Process received packet
47 54
          *
48
-         * @v pkb	Packet buffer
49
-	 * @v st_src	Partially-filled source address
50
-	 * @v st_dest	Partially-filled destination address
51
-	 * @ret rc	Return status code
55
+         * @v pkb		Packet buffer
56
+	 * @v st_src		Partially-filled source address
57
+	 * @v st_dest		Partially-filled destination address
58
+	 * @v pshdr_csum	Pseudo-header checksum
59
+	 * @ret rc		Return status code
52 60
          *
53 61
          * This method takes ownership of the packet buffer.
54 62
          */
55 63
         int ( * rx ) ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
56
-		       struct sockaddr_tcpip *st_dest );
64
+		       struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
57 65
         /** 
58 66
 	 * Transport-layer protocol number
59 67
 	 *
60 68
 	 * This is a constant of the type IP_XXX
61 69
          */
62 70
         uint8_t tcpip_proto;
63
-	/**
64
-	 * Checksum offset
65
-	 *
66
-	 * A negative number indicates that the protocol does not
67
-	 * require checksumming to be performed by the network layer.
68
-	 * A positive number is the offset of the checksum field in
69
-	 * the transport-layer header.
70
-	 */
71
-	int csum_offset;
72 71
 };
73 72
 
74 73
 /**
@@ -85,13 +84,14 @@ struct tcpip_net_protocol {
85 84
 	 * @v pkb		Packet buffer
86 85
 	 * @v tcpip_protocol	Transport-layer protocol
87 86
 	 * @v st_dest		Destination address
87
+	 * @v trans_csum	Transport-layer checksum to complete, or NULL
88 88
 	 * @ret rc		Return status code
89 89
 	 *
90 90
 	 * This function takes ownership of the packet buffer.
91 91
 	 */
92 92
 	int ( * tx ) ( struct pk_buff *pkb,
93 93
 		       struct tcpip_protocol *tcpip_protocol,
94
-		       struct sockaddr_tcpip *st_dest );
94
+		       struct sockaddr_tcpip *st_dest, uint16_t *trans_csum );
95 95
 };
96 96
 
97 97
 /** Declare a TCP/IP transport-layer protocol */
@@ -102,11 +102,11 @@ struct tcpip_net_protocol {
102 102
 
103 103
 extern int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto,
104 104
 		      struct sockaddr_tcpip *st_src,
105
-		      struct sockaddr_tcpip *st_dest );
105
+		      struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
106 106
 extern int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip, 
107
-		      struct sockaddr_tcpip *st_dest );
108
-extern unsigned int tcpip_continue_chksum ( unsigned int partial,
109
-					    const void *data, size_t len );
110
-extern unsigned int tcpip_chksum ( const void *data, size_t len );
107
+		      struct sockaddr_tcpip *st_dest, uint16_t *trans_csum );
108
+extern uint16_t tcpip_continue_chksum ( uint16_t partial,
109
+					const void *data, size_t len );
110
+extern uint16_t tcpip_chksum ( const void *data, size_t len );
111 111
 
112 112
 #endif /* _GPXE_TCPIP_H */

+ 1
- 2
src/net/icmpv6.c Voir le fichier

@@ -60,7 +60,7 @@ int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src __unuse
60 60
 	st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff;
61 61
 	
62 62
 	/* Send packet over IP6 */
63
-	return ( tcpip_tx ( pkb, &icmp6_protocol, &st_dest.st ) );
63
+	return tcpip_tx ( pkb, &icmp6_protocol, &st_dest.st, &nsolicit->csum );
64 64
 }
65 65
 
66 66
 /**
@@ -124,5 +124,4 @@ struct tcpip_protocol icmp6_protocol __tcpip_protocol = {
124 124
 	.name = "ICMP6",
125 125
 	.rx = icmp6_rx,
126 126
 	.tcpip_proto = IP_ICMP6, // 58
127
-	.csum_offset = 2,
128 127
 };

+ 110
- 99
src/net/ipv4.c Voir le fichier

@@ -230,44 +230,65 @@ static struct pk_buff * ipv4_reassemble ( struct pk_buff * pkb ) {
230 230
 	return NULL;
231 231
 }
232 232
 
233
-
234 233
 /**
235
- * Complete the transport-layer checksum
236
- *
237
- * @v pkb	Packet buffer
238
- * @v tcpip	Transport-layer protocol
234
+ * Add IPv4 pseudo-header checksum to existing checksum
239 235
  *
240
- * This function calculates the tcpip 
236
+ * @v pkb		Packet buffer
237
+ * @v csum		Existing checksum
238
+ * @ret csum		Updated checksum
241 239
  */
242
-static void ipv4_tx_csum ( struct pk_buff *pkb,
243
-			   struct tcpip_protocol *tcpip ) {
244
-	struct iphdr *iphdr = pkb->data;
240
+static uint16_t ipv4_pshdr_chksum ( struct pk_buff *pkb, uint16_t csum ) {
245 241
 	struct ipv4_pseudo_header pshdr;
246
-	uint16_t *csum = ( ( ( void * ) iphdr ) + sizeof ( *iphdr )
247
-			   + tcpip->csum_offset );
242
+	struct iphdr *iphdr = pkb->data;
243
+	size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
248 244
 
249
-	/* Calculate pseudo header */
245
+	/* Build pseudo-header */
250 246
 	pshdr.src = iphdr->src;
251 247
 	pshdr.dest = iphdr->dest;
252 248
 	pshdr.zero_padding = 0x00;
253 249
 	pshdr.protocol = iphdr->protocol;
254
-	/* This is only valid when IPv4 does not have options */
255
-	pshdr.len = htons ( pkb_len ( pkb ) - sizeof ( *iphdr ) );
250
+	pshdr.len = htons ( pkb_len ( pkb ) - hdrlen );
256 251
 
257 252
 	/* Update the checksum value */
258
-	*csum = tcpip_continue_chksum ( *csum, &pshdr, sizeof ( pshdr ) );
253
+	return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
259 254
 }
260 255
 
261 256
 /**
262
- * Calculate the transport-layer checksum while processing packets
257
+ * Determine link-layer address
258
+ *
259
+ * @v dest		IPv4 destination address
260
+ * @v src		IPv4 source address
261
+ * @v netdev		Network device
262
+ * @v ll_dest		Link-layer destination address buffer
263
+ * @ret rc		Return status code
263 264
  */
264
-static uint16_t ipv4_rx_csum ( struct pk_buff *pkb __unused,
265
-			       uint8_t trans_proto __unused ) {
266
-	/** 
267
-	 * This function needs to be implemented. Until then, it will return
268
-	 * 0xffffffff every time
269
-	 */
270
-	return 0xffff;
265
+static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
266
+			  struct net_device *netdev, uint8_t *ll_dest ) {
267
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
268
+	uint8_t *dest_bytes = ( ( uint8_t * ) &dest );
269
+
270
+	if ( dest.s_addr == INADDR_BROADCAST ) {
271
+		/* Broadcast address */
272
+		memcpy ( ll_dest, ll_protocol->ll_broadcast,
273
+			 ll_protocol->ll_addr_len );
274
+		return 0;
275
+	} else if ( IN_MULTICAST ( dest.s_addr ) ) {
276
+		/* Special case: IPv4 multicast over Ethernet.	This
277
+		 * code may need to be generalised once we find out
278
+		 * what happens for other link layers.
279
+		 */
280
+		ll_dest[0] = 0x01;
281
+		ll_dest[1] = 0x00;
282
+		ll_dest[2] = 0x5e;
283
+		ll_dest[3] = dest_bytes[1] & 0x7f;
284
+		ll_dest[4] = dest_bytes[2];
285
+		ll_dest[5] = dest_bytes[3];
286
+		return 0;
287
+	} else {
288
+		/* Unicast address: resolve via ARP */
289
+		return arp_resolve ( netdev, &ipv4_protocol, &dest,
290
+				     &src, ll_dest );
291
+	}
271 292
 }
272 293
 
273 294
 /**
@@ -276,24 +297,23 @@ static uint16_t ipv4_rx_csum ( struct pk_buff *pkb __unused,
276 297
  * @v pkb		Packet buffer
277 298
  * @v tcpip		Transport-layer protocol
278 299
  * @v st_dest		Destination network-layer address
300
+ * @v trans_csum	Transport-layer checksum to complete, or NULL
279 301
  * @ret rc		Status
280 302
  *
281 303
  * This function expects a transport-layer segment and prepends the IP header
282 304
  */
283 305
 static int ipv4_tx ( struct pk_buff *pkb,
284 306
 		     struct tcpip_protocol *tcpip_protocol,
285
-		     struct sockaddr_tcpip *st_dest ) {
307
+		     struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ) {
286 308
 	struct iphdr *iphdr = pkb_push ( pkb, sizeof ( *iphdr ) );
287 309
 	struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
288 310
 	struct ipv4_miniroute *miniroute;
289
-	struct net_device *netdev = NULL;
290 311
 	struct in_addr next_hop;
291
-	uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
292
-	const uint8_t *ll_dest = ll_dest_buf;
312
+	uint8_t ll_dest[MAX_LL_ADDR_LEN];
293 313
 	int rc;
294 314
 
295 315
 	/* Fill up the IP header, except source address */
296
-	iphdr->verhdrlen = ( ( IP_VER << 4 ) | ( sizeof ( *iphdr ) / 4 ) );
316
+	iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
297 317
 	iphdr->service = IP_TOS;
298 318
 	iphdr->len = htons ( pkb_len ( pkb ) );	
299 319
 	iphdr->ident = htons ( ++next_ident );
@@ -307,18 +327,23 @@ static int ipv4_tx ( struct pk_buff *pkb,
307 327
 	next_hop = iphdr->dest;
308 328
 	miniroute = ipv4_route ( &next_hop );
309 329
 	if ( ! miniroute ) {
310
-		DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) );
330
+		DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
311 331
 		rc = -EHOSTUNREACH;
312 332
 		goto err;
313 333
 	}
314 334
 	iphdr->src = miniroute->address;
315
-	netdev = miniroute->netdev;
316 335
 
317
-	/* Calculate the transport layer checksum */
318
-	if ( tcpip_protocol->csum_offset > 0 )
319
-		ipv4_tx_csum ( pkb, tcpip_protocol );
336
+	/* Determine link-layer destination address */
337
+	if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, miniroute->netdev,
338
+				   ll_dest ) ) != 0 ) {
339
+		DBG ( "IPv4 has no link-layer address for %s\n",
340
+		      inet_ntoa ( iphdr->dest ) );
341
+		goto err;
342
+	}
320 343
 
321
-	/* Calculate header checksum, in network byte order */
344
+	/* Fix up checksums */
345
+	if ( trans_csum )
346
+		*trans_csum = ipv4_pshdr_chksum ( pkb, *trans_csum );
322 347
 	iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
323 348
 
324 349
 	/* Print IP4 header for debugging */
@@ -327,34 +352,8 @@ static int ipv4_tx ( struct pk_buff *pkb,
327 352
 	      inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
328 353
 	      ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
329 354
 
330
-	/* Determine link-layer destination address */
331
-	if ( next_hop.s_addr == INADDR_BROADCAST ) {
332
-		/* Broadcast address */
333
-		ll_dest = netdev->ll_protocol->ll_broadcast;
334
-	} else if ( IN_MULTICAST ( next_hop.s_addr ) ) {
335
-		/* Special case: IPv4 multicast over Ethernet.	This
336
-		 * code may need to be generalised once we find out
337
-		 * what happens for other link layers.
338
-		 */
339
-		uint8_t *next_hop_bytes = ( uint8_t * ) &next_hop;
340
-		ll_dest_buf[0] = 0x01;
341
-		ll_dest_buf[0] = 0x00;
342
-		ll_dest_buf[0] = 0x5e;
343
-		ll_dest_buf[3] = next_hop_bytes[1] & 0x7f;
344
-		ll_dest_buf[4] = next_hop_bytes[2];
345
-		ll_dest_buf[5] = next_hop_bytes[3];
346
-	} else {
347
-		/* Unicast address: resolve via ARP */
348
-		if ( ( rc = arp_resolve ( netdev, &ipv4_protocol, &next_hop,
349
-					  &iphdr->src, ll_dest_buf ) ) != 0 ) {
350
-			DBG ( "No ARP entry for %s\n",
351
-			      inet_ntoa ( iphdr->dest ) );
352
-			goto err;
353
-		}
354
-	}
355
-
356 355
 	/* Hand off to link layer */
357
-	return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
356
+	return net_tx ( pkb, miniroute->netdev, &ipv4_protocol, ll_dest );
358 357
 
359 358
  err:
360 359
 	free_pkb ( pkb );
@@ -374,73 +373,85 @@ static int ipv4_tx ( struct pk_buff *pkb,
374 373
 static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
375 374
 		     const void *ll_source __unused ) {
376 375
 	struct iphdr *iphdr = pkb->data;
376
+	size_t hdrlen;
377
+	size_t len;
377 378
 	union {
378 379
 		struct sockaddr_in sin;
379 380
 		struct sockaddr_tcpip st;
380 381
 	} src, dest;
381
-	uint16_t chksum;
382
+	uint16_t csum;
383
+	uint16_t pshdr_csum;
382 384
 
383
-	/* Sanity check */
385
+	/* Sanity check the IPv4 header */
384 386
 	if ( pkb_len ( pkb ) < sizeof ( *iphdr ) ) {
385
-		DBG ( "IP datagram too short (%d bytes)\n", pkb_len ( pkb ) );
387
+		DBG ( "IPv4 packet too short at %d bytes (min %d bytes)\n",
388
+		      pkb_len ( pkb ), sizeof ( *iphdr ) );
389
+		goto err;
390
+	}
391
+	if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
392
+		DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
393
+		goto err;
394
+	}
395
+	hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
396
+	if ( hdrlen < sizeof ( *iphdr ) ) {
397
+		DBG ( "IPv4 header too short at %d bytes (min %d bytes)\n",
398
+		      hdrlen, sizeof ( *iphdr ) );
399
+		goto err;
400
+	}
401
+	if ( hdrlen > pkb_len ( pkb ) ) {
402
+		DBG ( "IPv4 header too long at %d bytes "
403
+		      "(packet is %d bytes)\n", hdrlen, pkb_len ( pkb ) );
404
+		goto err;
405
+	}
406
+	if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
407
+		DBG ( "IPv4 checksum incorrect (is %04x including checksum "
408
+		      "field, should be 0000)\n", csum );
409
+		goto err;
410
+	}
411
+	len = ntohs ( iphdr->len );
412
+	if ( len < hdrlen ) {
413
+		DBG ( "IPv4 length too short at %d bytes "
414
+		      "(header is %d bytes)\n", len, hdrlen );
415
+		goto err;
416
+	}
417
+	if ( len > pkb_len ( pkb ) ) {
418
+		DBG ( "IPv4 length too long at %d bytes "
419
+		      "(packet is %d bytes)\n", len, pkb_len ( pkb ) );
386 420
 		goto err;
387 421
 	}
388 422
 
389
-	/* Print IP4 header for debugging */
423
+	/* Print IPv4 header for debugging */
390 424
 	DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
391 425
 	DBG ( "%s len %d proto %d id %04x csum %04x\n",
392 426
 	      inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
393 427
 	      ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
394 428
 
395
-	/* Validate version and header length */
396
-	if ( iphdr->verhdrlen != 0x45 ) {
397
-		DBG ( "Bad version and header length %x\n", iphdr->verhdrlen );
398
-		goto err;
399
-	}
400
-
401
-	/* Validate length of IP packet */
402
-	if ( ntohs ( iphdr->len ) > pkb_len ( pkb ) ) {
403
-		DBG ( "Inconsistent packet length %d\n",
404
-		      ntohs ( iphdr->len ) );
405
-		goto err;
406
-	}
429
+	/* Truncate packet to correct length, calculate pseudo-header
430
+	 * checksum and then strip off the IPv4 header.
431
+	 */
432
+	pkb_unput ( pkb, ( pkb_len ( pkb ) - len ) );
433
+	pshdr_csum = ipv4_pshdr_chksum ( pkb, TCPIP_EMPTY_CSUM );
434
+	pkb_pull ( pkb, hdrlen );
407 435
 
408
-	/* Verify the checksum */
409
-	if ( ( chksum = ipv4_rx_csum ( pkb, iphdr->protocol ) )	!= 0xffff ) {
410
-		DBG ( "Bad checksum %x\n", chksum );
411
-	}
412 436
 	/* Fragment reassembly */
413 437
 	if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || 
414 438
 	     ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
415
-		/* Pass the fragment to the reassembler ipv4_ressable() which
416
-		 * either returns a fully reassembled packet buffer or NULL.
439
+		/* Pass the fragment to ipv4_reassemble() which either
440
+		 * returns a fully reassembled packet buffer or NULL.
417 441
 		 */
418 442
 		pkb = ipv4_reassemble ( pkb );
419
-		if ( !pkb ) {
443
+		if ( ! pkb )
420 444
 			return 0;
421
-		}
422 445
 	}
423 446
 
424
-	/* To reduce code size, the following functions are not implemented:
425
-	 * 1. Check the destination address
426
-	 * 2. Check the TTL field
427
-	 * 3. Check the service field
428
-	 */
429
-
430
-	/* Construct socket addresses */
447
+	/* Construct socket addresses and hand off to transport layer */
431 448
 	memset ( &src, 0, sizeof ( src ) );
432 449
 	src.sin.sin_family = AF_INET;
433 450
 	src.sin.sin_addr = iphdr->src;
434 451
 	memset ( &dest, 0, sizeof ( dest ) );
435 452
 	dest.sin.sin_family = AF_INET;
436 453
 	dest.sin.sin_addr = iphdr->dest;
437
-
438
-	/* Strip header */
439
-	pkb_unput ( pkb, pkb_len ( pkb ) - ntohs ( iphdr->len ) );
440
-	pkb_pull ( pkb, sizeof ( *iphdr ) );
441
-
442
-	/* Send it to the transport layer */
443
-	return tcpip_rx ( pkb, iphdr->protocol, &src.st, &dest.st );
454
+	return tcpip_rx ( pkb, iphdr->protocol, &src.st, &dest.st, pshdr_csum);
444 455
 
445 456
  err:
446 457
 	free_pkb ( pkb );

+ 7
- 9
src/net/ipv6.c Voir le fichier

@@ -103,11 +103,9 @@ void del_ipv6_address ( struct net_device *netdev ) {
103 103
  * This function constructs the pseudo header and completes the checksum in the
104 104
  * upper layer header.
105 105
  */
106
-static void ipv6_tx_csum ( struct pk_buff *pkb, struct tcpip_protocol *tcpip ) {
106
+static uint16_t ipv6_tx_csum ( struct pk_buff *pkb, uint16_t csum ) {
107 107
 	struct ip6_header *ip6hdr = pkb->data;
108 108
 	struct ipv6_pseudo_header pshdr;
109
-	uint16_t *csum = ( ( ( void * ) ip6hdr ) + sizeof ( *ip6hdr ) +
110
-			tcpip->csum_offset );
111 109
 
112 110
 	/* Calculate pseudo header */
113 111
 	memset ( &pshdr, 0, sizeof ( pshdr ) );
@@ -117,7 +115,7 @@ static void ipv6_tx_csum ( struct pk_buff *pkb, struct tcpip_protocol *tcpip ) {
117 115
 	pshdr.nxt_hdr = ip6hdr->nxt_hdr;
118 116
 
119 117
 	/* Update checksum value */
120
-	*csum = tcpip_continue_chksum ( *csum, &pshdr, sizeof ( pshdr ) );
118
+	return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
121 119
 }
122 120
 
123 121
 /**
@@ -142,7 +140,8 @@ void ipv6_dump ( struct ip6_header *ip6hdr ) {
142 140
  */
143 141
 static int ipv6_tx ( struct pk_buff *pkb,
144 142
 		     struct tcpip_protocol *tcpip,
145
-		     struct sockaddr_tcpip *st_dest ) {
143
+		     struct sockaddr_tcpip *st_dest,
144
+		     uint16_t *trans_csum ) {
146 145
 	struct sockaddr_in6 *dest = ( struct sockaddr_in6* ) st_dest;
147 146
 	struct in6_addr next_hop;
148 147
 	struct ipv6_miniroute *miniroute;
@@ -184,9 +183,8 @@ static int ipv6_tx ( struct pk_buff *pkb,
184 183
 	}
185 184
 
186 185
 	/* Complete the transport layer checksum */
187
-	if ( tcpip->csum_offset > 0 ) {
188
-		ipv6_tx_csum ( pkb, tcpip );
189
-	}
186
+	if ( trans_csum )
187
+		*trans_csum = ipv6_tx_csum ( pkb, *trans_csum );
190 188
 
191 189
 	/* Print IPv6 header */
192 190
 	ipv6_dump ( ip6hdr );
@@ -244,7 +242,7 @@ static int ipv6_process_nxt_hdr ( struct pk_buff *pkb, uint8_t nxt_hdr,
244 242
 		return 0;
245 243
 	}
246 244
 	/* Next header is not a IPv6 extension header */
247
-	return tcpip_rx ( pkb, nxt_hdr, src, dest );
245
+	return tcpip_rx ( pkb, nxt_hdr, src, dest, 0 /* fixme */ );
248 246
 }
249 247
 
250 248
 /**

+ 16
- 9
src/net/tcp.c Voir le fichier

@@ -309,7 +309,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
309 309
 	DBGC ( conn, "\n" );
310 310
 
311 311
 	/* Transmit packet */
312
-	return tcpip_tx ( pkb, &tcp_protocol, &conn->peer );
312
+	return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, &tcphdr->csum );
313 313
 }
314 314
 
315 315
 /**
@@ -591,14 +591,19 @@ static int tcp_rx_fin ( struct tcp_connection *conn, uint32_t seq ) {
591 591
  * Process received packet
592 592
  *
593 593
  * @v pkb		Packet buffer
594
- * @v partial		Partial checksum
595
- */
594
+ * @v st_src		Partially-filled source address
595
+ * @v st_dest		Partially-filled destination address
596
+ * @v pshdr_csum	Pseudo-header checksum
597
+ * @ret rc		Return status code
598
+  */
596 599
 static int tcp_rx ( struct pk_buff *pkb,
597 600
 		    struct sockaddr_tcpip *st_src __unused,
598
-		    struct sockaddr_tcpip *st_dest __unused ) {
601
+		    struct sockaddr_tcpip *st_dest __unused,
602
+		    uint16_t pshdr_csum ) {
599 603
 	struct tcp_header *tcphdr;
600 604
 	struct tcp_connection *conn;
601 605
 	unsigned int hlen;
606
+	uint16_t csum;
602 607
 	uint32_t start_seq;
603 608
 	uint32_t seq;
604 609
 	uint32_t ack;
@@ -608,7 +613,7 @@ static int tcp_rx ( struct pk_buff *pkb,
608 613
 	size_t len;
609 614
 	int rc = 0;
610 615
 
611
-	/* Sanity check packet and strip TCP header */
616
+	/* Sanity check packet */
612 617
 	if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
613 618
 		DBG ( "TCP packet too short at %d bytes (min %d bytes)\n",
614 619
 		      pkb_len ( pkb ), sizeof ( *tcphdr ) );
@@ -629,9 +634,12 @@ static int tcp_rx ( struct pk_buff *pkb,
629 634
 		rc = -EINVAL;
630 635
 		goto err;
631 636
 	}
632
-
633
-	/* TODO: Verify checksum */
634
-#warning "Verify checksum"
637
+	csum = tcpip_continue_chksum ( pshdr_csum, pkb->data, pkb_len ( pkb ));
638
+	if ( csum != 0 ) {
639
+		DBG ( "TCP checksum incorrect (is %04x including checksum "
640
+		      "field, should be 0000)\n", csum );
641
+		goto err;
642
+	}
635 643
 	
636 644
 	/* Parse parameters from header and strip header */
637 645
 	conn = tcp_demux ( tcphdr->dest );
@@ -845,5 +853,4 @@ struct tcpip_protocol tcp_protocol __tcpip_protocol = {
845 853
 	.name = "TCP",
846 854
 	.rx = tcp_rx,
847 855
 	.tcpip_proto = IP_TCP,
848
-	.csum_offset = 16,
849 856
 };

+ 13
- 9
src/net/tcpip.c Voir le fichier

@@ -32,6 +32,7 @@ tcpip_protocols_end[0] __table_end ( tcpip_protocols );
32 32
  * @v tcpip_proto	Transport-layer protocol number
33 33
  * @v st_src		Partially-filled source address
34 34
  * @v st_dest		Partially-filled destination address
35
+ * @v pshdr_csum	Pseudo-header checksum
35 36
  * @ret rc		Return status code
36 37
  *
37 38
  * This function expects a transport-layer segment from the network
@@ -42,14 +43,15 @@ tcpip_protocols_end[0] __table_end ( tcpip_protocols );
42 43
  */
43 44
 int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto, 
44 45
 	       struct sockaddr_tcpip *st_src,
45
-	       struct sockaddr_tcpip *st_dest ) {
46
+	       struct sockaddr_tcpip *st_dest,
47
+	       uint16_t pshdr_csum ) {
46 48
 	struct tcpip_protocol *tcpip;
47 49
 
48 50
 	/* Hand off packet to the appropriate transport-layer protocol */
49 51
 	for ( tcpip = tcpip_protocols; tcpip < tcpip_protocols_end; tcpip++ ) {
50 52
 		if ( tcpip->tcpip_proto == tcpip_proto ) {
51 53
 			DBG ( "TCP/IP received %s packet\n", tcpip->name );
52
-			return tcpip->rx ( pkb, st_src, st_dest );
54
+			return tcpip->rx ( pkb, st_src, st_dest, pshdr_csum );
53 55
 		}
54 56
 	}
55 57
 
@@ -63,10 +65,11 @@ int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto,
63 65
  * @v pkb		Packet buffer
64 66
  * @v tcpip_protocol	Transport-layer protocol
65 67
  * @v st_dest		Destination address
68
+ * @v trans_csum	Transport-layer checksum to complete, or NULL
66 69
  * @ret rc		Return status code
67 70
  */
68 71
 int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol,
69
-	       struct sockaddr_tcpip *st_dest ) {
72
+	       struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ) {
70 73
 	struct tcpip_net_protocol *tcpip_net;
71 74
 
72 75
 	/* Hand off packet to the appropriate network-layer protocol */
@@ -74,7 +77,8 @@ int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol,
74 77
 	      tcpip_net < tcpip_net_protocols_end ; tcpip_net++ ) {
75 78
 		if ( tcpip_net->sa_family == st_dest->st_family ) {
76 79
 			DBG ( "TCP/IP sending %s packet\n", tcpip_net->name );
77
-			return tcpip_net->tx ( pkb, tcpip_protocol, st_dest );
80
+			return tcpip_net->tx ( pkb, tcpip_protocol, st_dest,
81
+					       trans_csum );
78 82
 		}
79 83
 	}
80 84
 	
@@ -101,8 +105,8 @@ int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol,
101 105
  * or both.  Deciding which to swap is left as an exercise for the
102 106
  * interested reader.
103 107
  */
104
-unsigned int tcpip_continue_chksum ( unsigned int partial, const void *data,
105
-				     size_t len ) {
108
+uint16_t tcpip_continue_chksum ( uint16_t partial, const void *data,
109
+				 size_t len ) {
106 110
 	unsigned int cksum = ( ( ~partial ) & 0xffff );
107 111
 	unsigned int value;
108 112
 	unsigned int i;
@@ -121,7 +125,7 @@ unsigned int tcpip_continue_chksum ( unsigned int partial, const void *data,
121 125
 			cksum -= 0xffff;
122 126
 	}
123 127
 	
124
-	return ( ( ~cksum ) & 0xffff );
128
+	return ( ~cksum );
125 129
 }
126 130
 
127 131
 /**
@@ -134,6 +138,6 @@ unsigned int tcpip_continue_chksum ( unsigned int partial, const void *data,
134 138
  * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
135 139
  * checksum is returned in network byte order.
136 140
  */
137
-unsigned int tcpip_chksum ( const void *data, size_t len ) {
138
-	return tcpip_continue_chksum ( 0xffff, data, len );
141
+uint16_t tcpip_chksum ( const void *data, size_t len ) {
142
+	return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, len );
139 143
 }

+ 8
- 10
src/net/udp.c Voir le fichier

@@ -163,7 +163,7 @@ int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
163 163
 	      ntohs ( udphdr->chksum ) );
164 164
 
165 165
 	/* Send it to the next layer for processing */
166
-	return tcpip_tx ( pkb, &udp_protocol, peer );
166
+	return tcpip_tx ( pkb, &udp_protocol, peer, &udphdr->chksum );
167 167
 }
168 168
 
169 169
 /**
@@ -190,14 +190,15 @@ int udp_send ( struct udp_connection *conn, const void *data, size_t len ) {
190 190
  * @v pkb		Packet buffer
191 191
  * @v st_src		Partially-filled source address
192 192
  * @v st_dest		Partially-filled destination address
193
+ * @v pshdr_csum	Pseudo-header checksum
193 194
  * @ret rc		Return status code
194 195
  */
195 196
 static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
196
-		    struct sockaddr_tcpip *st_dest ) {
197
+		    struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
197 198
 	struct udp_header *udphdr = pkb->data;
198 199
 	struct udp_connection *conn;
199 200
 	unsigned int ulen;
200
-	uint16_t chksum;
201
+	uint16_t csum;
201 202
 	int rc;
202 203
 
203 204
 	/* Sanity check */
@@ -225,15 +226,13 @@ static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
225 226
 	pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
226 227
 
227 228
 	/* Verify the checksum */
228
-#warning "Don't we need to take the pseudo-header into account here?"
229
-#if 0
230
-	chksum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
231
-	if ( chksum != 0xffff ) {
232
-		DBG ( "Bad checksum %#x\n", chksum );
229
+	csum = tcpip_continue_chksum ( pshdr_csum, pkb->data, pkb_len ( pkb ));
230
+	if ( csum != 0 ) {
231
+		DBG ( "UDP checksum incorrect (is %04x including checksum "
232
+		      "field, should be 0000)\n", csum );
233 233
 		rc = -EINVAL;
234 234
 		goto done;
235 235
 	}
236
-#endif
237 236
 
238 237
 	/* Complete the socket addresses */
239 238
 	st_src->st_port = udphdr->source_port;
@@ -271,5 +270,4 @@ struct tcpip_protocol udp_protocol __tcpip_protocol = {
271 270
 	.name = "UDP",
272 271
 	.rx = udp_rx,
273 272
 	.tcpip_proto = IP_UDP,
274
-	.csum_offset = 6,
275 273
 };

Chargement…
Annuler
Enregistrer