Browse Source

Verify checksums on the RX datapath.

Simplify checksum generation on the TX datapath.
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
a0525a4ed3
8 changed files with 176 additions and 159 deletions
  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 View File

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

+ 20
- 20
src/include/gpxe/tcpip.h View File

14
 
14
 
15
 struct pk_buff;
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
 #define SA_TCPIP_LEN 32
24
 #define SA_TCPIP_LEN 32
18
 
25
 
19
 /**
26
 /**
45
        	/**
52
        	/**
46
          * Process received packet
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
          * This method takes ownership of the packet buffer.
61
          * This method takes ownership of the packet buffer.
54
          */
62
          */
55
         int ( * rx ) ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
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
 	 * Transport-layer protocol number
66
 	 * Transport-layer protocol number
59
 	 *
67
 	 *
60
 	 * This is a constant of the type IP_XXX
68
 	 * This is a constant of the type IP_XXX
61
          */
69
          */
62
         uint8_t tcpip_proto;
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
 	 * @v pkb		Packet buffer
84
 	 * @v pkb		Packet buffer
86
 	 * @v tcpip_protocol	Transport-layer protocol
85
 	 * @v tcpip_protocol	Transport-layer protocol
87
 	 * @v st_dest		Destination address
86
 	 * @v st_dest		Destination address
87
+	 * @v trans_csum	Transport-layer checksum to complete, or NULL
88
 	 * @ret rc		Return status code
88
 	 * @ret rc		Return status code
89
 	 *
89
 	 *
90
 	 * This function takes ownership of the packet buffer.
90
 	 * This function takes ownership of the packet buffer.
91
 	 */
91
 	 */
92
 	int ( * tx ) ( struct pk_buff *pkb,
92
 	int ( * tx ) ( struct pk_buff *pkb,
93
 		       struct tcpip_protocol *tcpip_protocol,
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
 /** Declare a TCP/IP transport-layer protocol */
97
 /** Declare a TCP/IP transport-layer protocol */
102
 
102
 
103
 extern int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto,
103
 extern int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto,
104
 		      struct sockaddr_tcpip *st_src,
104
 		      struct sockaddr_tcpip *st_src,
105
-		      struct sockaddr_tcpip *st_dest );
105
+		      struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
106
 extern int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip, 
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
 #endif /* _GPXE_TCPIP_H */
112
 #endif /* _GPXE_TCPIP_H */

+ 1
- 2
src/net/icmpv6.c View File

60
 	st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff;
60
 	st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff;
61
 	
61
 	
62
 	/* Send packet over IP6 */
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
 	.name = "ICMP6",
124
 	.name = "ICMP6",
125
 	.rx = icmp6_rx,
125
 	.rx = icmp6_rx,
126
 	.tcpip_proto = IP_ICMP6, // 58
126
 	.tcpip_proto = IP_ICMP6, // 58
127
-	.csum_offset = 2,
128
 };
127
 };

+ 110
- 99
src/net/ipv4.c View File

230
 	return NULL;
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
 	struct ipv4_pseudo_header pshdr;
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
 	pshdr.src = iphdr->src;
246
 	pshdr.src = iphdr->src;
251
 	pshdr.dest = iphdr->dest;
247
 	pshdr.dest = iphdr->dest;
252
 	pshdr.zero_padding = 0x00;
248
 	pshdr.zero_padding = 0x00;
253
 	pshdr.protocol = iphdr->protocol;
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
 	/* Update the checksum value */
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
  * @v pkb		Packet buffer
297
  * @v pkb		Packet buffer
277
  * @v tcpip		Transport-layer protocol
298
  * @v tcpip		Transport-layer protocol
278
  * @v st_dest		Destination network-layer address
299
  * @v st_dest		Destination network-layer address
300
+ * @v trans_csum	Transport-layer checksum to complete, or NULL
279
  * @ret rc		Status
301
  * @ret rc		Status
280
  *
302
  *
281
  * This function expects a transport-layer segment and prepends the IP header
303
  * This function expects a transport-layer segment and prepends the IP header
282
  */
304
  */
283
 static int ipv4_tx ( struct pk_buff *pkb,
305
 static int ipv4_tx ( struct pk_buff *pkb,
284
 		     struct tcpip_protocol *tcpip_protocol,
306
 		     struct tcpip_protocol *tcpip_protocol,
285
-		     struct sockaddr_tcpip *st_dest ) {
307
+		     struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ) {
286
 	struct iphdr *iphdr = pkb_push ( pkb, sizeof ( *iphdr ) );
308
 	struct iphdr *iphdr = pkb_push ( pkb, sizeof ( *iphdr ) );
287
 	struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
309
 	struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
288
 	struct ipv4_miniroute *miniroute;
310
 	struct ipv4_miniroute *miniroute;
289
-	struct net_device *netdev = NULL;
290
 	struct in_addr next_hop;
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
 	int rc;
313
 	int rc;
294
 
314
 
295
 	/* Fill up the IP header, except source address */
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
 	iphdr->service = IP_TOS;
317
 	iphdr->service = IP_TOS;
298
 	iphdr->len = htons ( pkb_len ( pkb ) );	
318
 	iphdr->len = htons ( pkb_len ( pkb ) );	
299
 	iphdr->ident = htons ( ++next_ident );
319
 	iphdr->ident = htons ( ++next_ident );
307
 	next_hop = iphdr->dest;
327
 	next_hop = iphdr->dest;
308
 	miniroute = ipv4_route ( &next_hop );
328
 	miniroute = ipv4_route ( &next_hop );
309
 	if ( ! miniroute ) {
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
 		rc = -EHOSTUNREACH;
331
 		rc = -EHOSTUNREACH;
312
 		goto err;
332
 		goto err;
313
 	}
333
 	}
314
 	iphdr->src = miniroute->address;
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
 	iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
347
 	iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
323
 
348
 
324
 	/* Print IP4 header for debugging */
349
 	/* Print IP4 header for debugging */
327
 	      inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
352
 	      inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
328
 	      ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
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
 	/* Hand off to link layer */
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
  err:
358
  err:
360
 	free_pkb ( pkb );
359
 	free_pkb ( pkb );
374
 static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
373
 static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
375
 		     const void *ll_source __unused ) {
374
 		     const void *ll_source __unused ) {
376
 	struct iphdr *iphdr = pkb->data;
375
 	struct iphdr *iphdr = pkb->data;
376
+	size_t hdrlen;
377
+	size_t len;
377
 	union {
378
 	union {
378
 		struct sockaddr_in sin;
379
 		struct sockaddr_in sin;
379
 		struct sockaddr_tcpip st;
380
 		struct sockaddr_tcpip st;
380
 	} src, dest;
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
 	if ( pkb_len ( pkb ) < sizeof ( *iphdr ) ) {
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
 		goto err;
420
 		goto err;
387
 	}
421
 	}
388
 
422
 
389
-	/* Print IP4 header for debugging */
423
+	/* Print IPv4 header for debugging */
390
 	DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
424
 	DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
391
 	DBG ( "%s len %d proto %d id %04x csum %04x\n",
425
 	DBG ( "%s len %d proto %d id %04x csum %04x\n",
392
 	      inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
426
 	      inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
393
 	      ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
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
 	/* Fragment reassembly */
436
 	/* Fragment reassembly */
413
 	if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || 
437
 	if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || 
414
 	     ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
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
 		pkb = ipv4_reassemble ( pkb );
442
 		pkb = ipv4_reassemble ( pkb );
419
-		if ( !pkb ) {
443
+		if ( ! pkb )
420
 			return 0;
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
 	memset ( &src, 0, sizeof ( src ) );
448
 	memset ( &src, 0, sizeof ( src ) );
432
 	src.sin.sin_family = AF_INET;
449
 	src.sin.sin_family = AF_INET;
433
 	src.sin.sin_addr = iphdr->src;
450
 	src.sin.sin_addr = iphdr->src;
434
 	memset ( &dest, 0, sizeof ( dest ) );
451
 	memset ( &dest, 0, sizeof ( dest ) );
435
 	dest.sin.sin_family = AF_INET;
452
 	dest.sin.sin_family = AF_INET;
436
 	dest.sin.sin_addr = iphdr->dest;
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
  err:
456
  err:
446
 	free_pkb ( pkb );
457
 	free_pkb ( pkb );

+ 7
- 9
src/net/ipv6.c View File

103
  * This function constructs the pseudo header and completes the checksum in the
103
  * This function constructs the pseudo header and completes the checksum in the
104
  * upper layer header.
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
 	struct ip6_header *ip6hdr = pkb->data;
107
 	struct ip6_header *ip6hdr = pkb->data;
108
 	struct ipv6_pseudo_header pshdr;
108
 	struct ipv6_pseudo_header pshdr;
109
-	uint16_t *csum = ( ( ( void * ) ip6hdr ) + sizeof ( *ip6hdr ) +
110
-			tcpip->csum_offset );
111
 
109
 
112
 	/* Calculate pseudo header */
110
 	/* Calculate pseudo header */
113
 	memset ( &pshdr, 0, sizeof ( pshdr ) );
111
 	memset ( &pshdr, 0, sizeof ( pshdr ) );
117
 	pshdr.nxt_hdr = ip6hdr->nxt_hdr;
115
 	pshdr.nxt_hdr = ip6hdr->nxt_hdr;
118
 
116
 
119
 	/* Update checksum value */
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
  */
140
  */
143
 static int ipv6_tx ( struct pk_buff *pkb,
141
 static int ipv6_tx ( struct pk_buff *pkb,
144
 		     struct tcpip_protocol *tcpip,
142
 		     struct tcpip_protocol *tcpip,
145
-		     struct sockaddr_tcpip *st_dest ) {
143
+		     struct sockaddr_tcpip *st_dest,
144
+		     uint16_t *trans_csum ) {
146
 	struct sockaddr_in6 *dest = ( struct sockaddr_in6* ) st_dest;
145
 	struct sockaddr_in6 *dest = ( struct sockaddr_in6* ) st_dest;
147
 	struct in6_addr next_hop;
146
 	struct in6_addr next_hop;
148
 	struct ipv6_miniroute *miniroute;
147
 	struct ipv6_miniroute *miniroute;
184
 	}
183
 	}
185
 
184
 
186
 	/* Complete the transport layer checksum */
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
 	/* Print IPv6 header */
189
 	/* Print IPv6 header */
192
 	ipv6_dump ( ip6hdr );
190
 	ipv6_dump ( ip6hdr );
244
 		return 0;
242
 		return 0;
245
 	}
243
 	}
246
 	/* Next header is not a IPv6 extension header */
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 View File

309
 	DBGC ( conn, "\n" );
309
 	DBGC ( conn, "\n" );
310
 
310
 
311
 	/* Transmit packet */
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
  * Process received packet
591
  * Process received packet
592
  *
592
  *
593
  * @v pkb		Packet buffer
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
 static int tcp_rx ( struct pk_buff *pkb,
599
 static int tcp_rx ( struct pk_buff *pkb,
597
 		    struct sockaddr_tcpip *st_src __unused,
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
 	struct tcp_header *tcphdr;
603
 	struct tcp_header *tcphdr;
600
 	struct tcp_connection *conn;
604
 	struct tcp_connection *conn;
601
 	unsigned int hlen;
605
 	unsigned int hlen;
606
+	uint16_t csum;
602
 	uint32_t start_seq;
607
 	uint32_t start_seq;
603
 	uint32_t seq;
608
 	uint32_t seq;
604
 	uint32_t ack;
609
 	uint32_t ack;
608
 	size_t len;
613
 	size_t len;
609
 	int rc = 0;
614
 	int rc = 0;
610
 
615
 
611
-	/* Sanity check packet and strip TCP header */
616
+	/* Sanity check packet */
612
 	if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
617
 	if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
613
 		DBG ( "TCP packet too short at %d bytes (min %d bytes)\n",
618
 		DBG ( "TCP packet too short at %d bytes (min %d bytes)\n",
614
 		      pkb_len ( pkb ), sizeof ( *tcphdr ) );
619
 		      pkb_len ( pkb ), sizeof ( *tcphdr ) );
629
 		rc = -EINVAL;
634
 		rc = -EINVAL;
630
 		goto err;
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
 	/* Parse parameters from header and strip header */
644
 	/* Parse parameters from header and strip header */
637
 	conn = tcp_demux ( tcphdr->dest );
645
 	conn = tcp_demux ( tcphdr->dest );
845
 	.name = "TCP",
853
 	.name = "TCP",
846
 	.rx = tcp_rx,
854
 	.rx = tcp_rx,
847
 	.tcpip_proto = IP_TCP,
855
 	.tcpip_proto = IP_TCP,
848
-	.csum_offset = 16,
849
 };
856
 };

+ 13
- 9
src/net/tcpip.c View File

32
  * @v tcpip_proto	Transport-layer protocol number
32
  * @v tcpip_proto	Transport-layer protocol number
33
  * @v st_src		Partially-filled source address
33
  * @v st_src		Partially-filled source address
34
  * @v st_dest		Partially-filled destination address
34
  * @v st_dest		Partially-filled destination address
35
+ * @v pshdr_csum	Pseudo-header checksum
35
  * @ret rc		Return status code
36
  * @ret rc		Return status code
36
  *
37
  *
37
  * This function expects a transport-layer segment from the network
38
  * This function expects a transport-layer segment from the network
42
  */
43
  */
43
 int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto, 
44
 int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto, 
44
 	       struct sockaddr_tcpip *st_src,
45
 	       struct sockaddr_tcpip *st_src,
45
-	       struct sockaddr_tcpip *st_dest ) {
46
+	       struct sockaddr_tcpip *st_dest,
47
+	       uint16_t pshdr_csum ) {
46
 	struct tcpip_protocol *tcpip;
48
 	struct tcpip_protocol *tcpip;
47
 
49
 
48
 	/* Hand off packet to the appropriate transport-layer protocol */
50
 	/* Hand off packet to the appropriate transport-layer protocol */
49
 	for ( tcpip = tcpip_protocols; tcpip < tcpip_protocols_end; tcpip++ ) {
51
 	for ( tcpip = tcpip_protocols; tcpip < tcpip_protocols_end; tcpip++ ) {
50
 		if ( tcpip->tcpip_proto == tcpip_proto ) {
52
 		if ( tcpip->tcpip_proto == tcpip_proto ) {
51
 			DBG ( "TCP/IP received %s packet\n", tcpip->name );
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
  * @v pkb		Packet buffer
65
  * @v pkb		Packet buffer
64
  * @v tcpip_protocol	Transport-layer protocol
66
  * @v tcpip_protocol	Transport-layer protocol
65
  * @v st_dest		Destination address
67
  * @v st_dest		Destination address
68
+ * @v trans_csum	Transport-layer checksum to complete, or NULL
66
  * @ret rc		Return status code
69
  * @ret rc		Return status code
67
  */
70
  */
68
 int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol,
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
 	struct tcpip_net_protocol *tcpip_net;
73
 	struct tcpip_net_protocol *tcpip_net;
71
 
74
 
72
 	/* Hand off packet to the appropriate network-layer protocol */
75
 	/* Hand off packet to the appropriate network-layer protocol */
74
 	      tcpip_net < tcpip_net_protocols_end ; tcpip_net++ ) {
77
 	      tcpip_net < tcpip_net_protocols_end ; tcpip_net++ ) {
75
 		if ( tcpip_net->sa_family == st_dest->st_family ) {
78
 		if ( tcpip_net->sa_family == st_dest->st_family ) {
76
 			DBG ( "TCP/IP sending %s packet\n", tcpip_net->name );
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
  * or both.  Deciding which to swap is left as an exercise for the
105
  * or both.  Deciding which to swap is left as an exercise for the
102
  * interested reader.
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
 	unsigned int cksum = ( ( ~partial ) & 0xffff );
110
 	unsigned int cksum = ( ( ~partial ) & 0xffff );
107
 	unsigned int value;
111
 	unsigned int value;
108
 	unsigned int i;
112
 	unsigned int i;
121
 			cksum -= 0xffff;
125
 			cksum -= 0xffff;
122
 	}
126
 	}
123
 	
127
 	
124
-	return ( ( ~cksum ) & 0xffff );
128
+	return ( ~cksum );
125
 }
129
 }
126
 
130
 
127
 /**
131
 /**
134
  * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
138
  * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
135
  * checksum is returned in network byte order.
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 View File

163
 	      ntohs ( udphdr->chksum ) );
163
 	      ntohs ( udphdr->chksum ) );
164
 
164
 
165
 	/* Send it to the next layer for processing */
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
  * @v pkb		Packet buffer
190
  * @v pkb		Packet buffer
191
  * @v st_src		Partially-filled source address
191
  * @v st_src		Partially-filled source address
192
  * @v st_dest		Partially-filled destination address
192
  * @v st_dest		Partially-filled destination address
193
+ * @v pshdr_csum	Pseudo-header checksum
193
  * @ret rc		Return status code
194
  * @ret rc		Return status code
194
  */
195
  */
195
 static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
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
 	struct udp_header *udphdr = pkb->data;
198
 	struct udp_header *udphdr = pkb->data;
198
 	struct udp_connection *conn;
199
 	struct udp_connection *conn;
199
 	unsigned int ulen;
200
 	unsigned int ulen;
200
-	uint16_t chksum;
201
+	uint16_t csum;
201
 	int rc;
202
 	int rc;
202
 
203
 
203
 	/* Sanity check */
204
 	/* Sanity check */
225
 	pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
226
 	pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
226
 
227
 
227
 	/* Verify the checksum */
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
 		rc = -EINVAL;
233
 		rc = -EINVAL;
234
 		goto done;
234
 		goto done;
235
 	}
235
 	}
236
-#endif
237
 
236
 
238
 	/* Complete the socket addresses */
237
 	/* Complete the socket addresses */
239
 	st_src->st_port = udphdr->source_port;
238
 	st_src->st_port = udphdr->source_port;
271
 	.name = "UDP",
270
 	.name = "UDP",
272
 	.rx = udp_rx,
271
 	.rx = udp_rx,
273
 	.tcpip_proto = IP_UDP,
272
 	.tcpip_proto = IP_UDP,
274
-	.csum_offset = 6,
275
 };
273
 };

Loading…
Cancel
Save