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