david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Verify checksums on the RX datapath.

Simplify checksum generation on the TX datapath.
This commit is contained in:
Michael Brown 2007-01-03 20:48:52 +00:00
parent 285beeff7c
commit a0525a4ed3
8 changed files with 176 additions and 159 deletions

View File

@ -12,7 +12,7 @@
/* IP constants */
#define IP_VER 4
#define IP_VER 0x40
#define IP_MASK_VER 0xf0
#define IP_MASK_HLEN 0x0f
#define IP_MASK_OFFSET 0x1fff

View File

@ -14,6 +14,13 @@
struct pk_buff;
/** Empty checksum value
*
* This is the TCP/IP checksum over a zero-length block of data.
*/
#define TCPIP_EMPTY_CSUM 0xffff
/** Length of a @c struct @c sockaddr_tcpip */
#define SA_TCPIP_LEN 32
/**
@ -45,30 +52,22 @@ struct tcpip_protocol {
/**
* Process received packet
*
* @v pkb Packet buffer
* @v st_src Partially-filled source address
* @v st_dest Partially-filled destination address
* @ret rc Return status code
* @v pkb Packet buffer
* @v st_src Partially-filled source address
* @v st_dest Partially-filled destination address
* @v pshdr_csum Pseudo-header checksum
* @ret rc Return status code
*
* This method takes ownership of the packet buffer.
*/
int ( * rx ) ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest );
struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
/**
* Transport-layer protocol number
*
* This is a constant of the type IP_XXX
*/
uint8_t tcpip_proto;
/**
* Checksum offset
*
* A negative number indicates that the protocol does not
* require checksumming to be performed by the network layer.
* A positive number is the offset of the checksum field in
* the transport-layer header.
*/
int csum_offset;
};
/**
@ -85,13 +84,14 @@ struct tcpip_net_protocol {
* @v pkb Packet buffer
* @v tcpip_protocol Transport-layer protocol
* @v st_dest Destination address
* @v trans_csum Transport-layer checksum to complete, or NULL
* @ret rc Return status code
*
* This function takes ownership of the packet buffer.
*/
int ( * tx ) ( struct pk_buff *pkb,
struct tcpip_protocol *tcpip_protocol,
struct sockaddr_tcpip *st_dest );
struct sockaddr_tcpip *st_dest, uint16_t *trans_csum );
};
/** Declare a TCP/IP transport-layer protocol */
@ -102,11 +102,11 @@ struct tcpip_net_protocol {
extern int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto,
struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest );
struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
extern int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip,
struct sockaddr_tcpip *st_dest );
extern unsigned int tcpip_continue_chksum ( unsigned int partial,
const void *data, size_t len );
extern unsigned int tcpip_chksum ( const void *data, size_t len );
struct sockaddr_tcpip *st_dest, uint16_t *trans_csum );
extern uint16_t tcpip_continue_chksum ( uint16_t partial,
const void *data, size_t len );
extern uint16_t tcpip_chksum ( const void *data, size_t len );
#endif /* _GPXE_TCPIP_H */

View File

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

View File

@ -230,44 +230,65 @@ static struct pk_buff * ipv4_reassemble ( struct pk_buff * pkb ) {
return NULL;
}
/**
* Complete the transport-layer checksum
* Add IPv4 pseudo-header checksum to existing checksum
*
* @v pkb Packet buffer
* @v tcpip Transport-layer protocol
*
* This function calculates the tcpip
* @v pkb Packet buffer
* @v csum Existing checksum
* @ret csum Updated checksum
*/
static void ipv4_tx_csum ( struct pk_buff *pkb,
struct tcpip_protocol *tcpip ) {
struct iphdr *iphdr = pkb->data;
static uint16_t ipv4_pshdr_chksum ( struct pk_buff *pkb, uint16_t csum ) {
struct ipv4_pseudo_header pshdr;
uint16_t *csum = ( ( ( void * ) iphdr ) + sizeof ( *iphdr )
+ tcpip->csum_offset );
struct iphdr *iphdr = pkb->data;
size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
/* Calculate pseudo header */
/* Build pseudo-header */
pshdr.src = iphdr->src;
pshdr.dest = iphdr->dest;
pshdr.zero_padding = 0x00;
pshdr.protocol = iphdr->protocol;
/* This is only valid when IPv4 does not have options */
pshdr.len = htons ( pkb_len ( pkb ) - sizeof ( *iphdr ) );
pshdr.len = htons ( pkb_len ( pkb ) - hdrlen );
/* Update the checksum value */
*csum = tcpip_continue_chksum ( *csum, &pshdr, sizeof ( pshdr ) );
return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
}
/**
* Calculate the transport-layer checksum while processing packets
* Determine link-layer address
*
* @v dest IPv4 destination address
* @v src IPv4 source address
* @v netdev Network device
* @v ll_dest Link-layer destination address buffer
* @ret rc Return status code
*/
static uint16_t ipv4_rx_csum ( struct pk_buff *pkb __unused,
uint8_t trans_proto __unused ) {
/**
* This function needs to be implemented. Until then, it will return
* 0xffffffff every time
*/
return 0xffff;
static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
struct net_device *netdev, uint8_t *ll_dest ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
uint8_t *dest_bytes = ( ( uint8_t * ) &dest );
if ( dest.s_addr == INADDR_BROADCAST ) {
/* Broadcast address */
memcpy ( ll_dest, ll_protocol->ll_broadcast,
ll_protocol->ll_addr_len );
return 0;
} else if ( IN_MULTICAST ( dest.s_addr ) ) {
/* Special case: IPv4 multicast over Ethernet. This
* code may need to be generalised once we find out
* what happens for other link layers.
*/
ll_dest[0] = 0x01;
ll_dest[1] = 0x00;
ll_dest[2] = 0x5e;
ll_dest[3] = dest_bytes[1] & 0x7f;
ll_dest[4] = dest_bytes[2];
ll_dest[5] = dest_bytes[3];
return 0;
} else {
/* Unicast address: resolve via ARP */
return arp_resolve ( netdev, &ipv4_protocol, &dest,
&src, ll_dest );
}
}
/**
@ -276,24 +297,23 @@ static uint16_t ipv4_rx_csum ( struct pk_buff *pkb __unused,
* @v pkb Packet buffer
* @v tcpip Transport-layer protocol
* @v st_dest Destination network-layer address
* @v trans_csum Transport-layer checksum to complete, or NULL
* @ret rc Status
*
* This function expects a transport-layer segment and prepends the IP header
*/
static int ipv4_tx ( struct pk_buff *pkb,
struct tcpip_protocol *tcpip_protocol,
struct sockaddr_tcpip *st_dest ) {
struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ) {
struct iphdr *iphdr = pkb_push ( pkb, sizeof ( *iphdr ) );
struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
struct ipv4_miniroute *miniroute;
struct net_device *netdev = NULL;
struct in_addr next_hop;
uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
const uint8_t *ll_dest = ll_dest_buf;
uint8_t ll_dest[MAX_LL_ADDR_LEN];
int rc;
/* Fill up the IP header, except source address */
iphdr->verhdrlen = ( ( IP_VER << 4 ) | ( sizeof ( *iphdr ) / 4 ) );
iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
iphdr->service = IP_TOS;
iphdr->len = htons ( pkb_len ( pkb ) );
iphdr->ident = htons ( ++next_ident );
@ -307,18 +327,23 @@ static int ipv4_tx ( struct pk_buff *pkb,
next_hop = iphdr->dest;
miniroute = ipv4_route ( &next_hop );
if ( ! miniroute ) {
DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) );
DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
rc = -EHOSTUNREACH;
goto err;
}
iphdr->src = miniroute->address;
netdev = miniroute->netdev;
/* Calculate the transport layer checksum */
if ( tcpip_protocol->csum_offset > 0 )
ipv4_tx_csum ( pkb, tcpip_protocol );
/* Determine link-layer destination address */
if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, miniroute->netdev,
ll_dest ) ) != 0 ) {
DBG ( "IPv4 has no link-layer address for %s\n",
inet_ntoa ( iphdr->dest ) );
goto err;
}
/* Calculate header checksum, in network byte order */
/* Fix up checksums */
if ( trans_csum )
*trans_csum = ipv4_pshdr_chksum ( pkb, *trans_csum );
iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
/* Print IP4 header for debugging */
@ -327,34 +352,8 @@ static int ipv4_tx ( struct pk_buff *pkb,
inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
/* Determine link-layer destination address */
if ( next_hop.s_addr == INADDR_BROADCAST ) {
/* Broadcast address */
ll_dest = netdev->ll_protocol->ll_broadcast;
} else if ( IN_MULTICAST ( next_hop.s_addr ) ) {
/* Special case: IPv4 multicast over Ethernet. This
* code may need to be generalised once we find out
* what happens for other link layers.
*/
uint8_t *next_hop_bytes = ( uint8_t * ) &next_hop;
ll_dest_buf[0] = 0x01;
ll_dest_buf[0] = 0x00;
ll_dest_buf[0] = 0x5e;
ll_dest_buf[3] = next_hop_bytes[1] & 0x7f;
ll_dest_buf[4] = next_hop_bytes[2];
ll_dest_buf[5] = next_hop_bytes[3];
} else {
/* Unicast address: resolve via ARP */
if ( ( rc = arp_resolve ( netdev, &ipv4_protocol, &next_hop,
&iphdr->src, ll_dest_buf ) ) != 0 ) {
DBG ( "No ARP entry for %s\n",
inet_ntoa ( iphdr->dest ) );
goto err;
}
}
/* Hand off to link layer */
return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
return net_tx ( pkb, miniroute->netdev, &ipv4_protocol, ll_dest );
err:
free_pkb ( pkb );
@ -374,73 +373,85 @@ static int ipv4_tx ( struct pk_buff *pkb,
static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
const void *ll_source __unused ) {
struct iphdr *iphdr = pkb->data;
size_t hdrlen;
size_t len;
union {
struct sockaddr_in sin;
struct sockaddr_tcpip st;
} src, dest;
uint16_t chksum;
uint16_t csum;
uint16_t pshdr_csum;
/* Sanity check */
/* Sanity check the IPv4 header */
if ( pkb_len ( pkb ) < sizeof ( *iphdr ) ) {
DBG ( "IP datagram too short (%d bytes)\n", pkb_len ( pkb ) );
DBG ( "IPv4 packet too short at %d bytes (min %d bytes)\n",
pkb_len ( pkb ), sizeof ( *iphdr ) );
goto err;
}
if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
goto err;
}
hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
if ( hdrlen < sizeof ( *iphdr ) ) {
DBG ( "IPv4 header too short at %d bytes (min %d bytes)\n",
hdrlen, sizeof ( *iphdr ) );
goto err;
}
if ( hdrlen > pkb_len ( pkb ) ) {
DBG ( "IPv4 header too long at %d bytes "
"(packet is %d bytes)\n", hdrlen, pkb_len ( pkb ) );
goto err;
}
if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
DBG ( "IPv4 checksum incorrect (is %04x including checksum "
"field, should be 0000)\n", csum );
goto err;
}
len = ntohs ( iphdr->len );
if ( len < hdrlen ) {
DBG ( "IPv4 length too short at %d bytes "
"(header is %d bytes)\n", len, hdrlen );
goto err;
}
if ( len > pkb_len ( pkb ) ) {
DBG ( "IPv4 length too long at %d bytes "
"(packet is %d bytes)\n", len, pkb_len ( pkb ) );
goto err;
}
/* Print IP4 header for debugging */
/* Print IPv4 header for debugging */
DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
DBG ( "%s len %d proto %d id %04x csum %04x\n",
inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
/* Validate version and header length */
if ( iphdr->verhdrlen != 0x45 ) {
DBG ( "Bad version and header length %x\n", iphdr->verhdrlen );
goto err;
}
/* Truncate packet to correct length, calculate pseudo-header
* checksum and then strip off the IPv4 header.
*/
pkb_unput ( pkb, ( pkb_len ( pkb ) - len ) );
pshdr_csum = ipv4_pshdr_chksum ( pkb, TCPIP_EMPTY_CSUM );
pkb_pull ( pkb, hdrlen );
/* Validate length of IP packet */
if ( ntohs ( iphdr->len ) > pkb_len ( pkb ) ) {
DBG ( "Inconsistent packet length %d\n",
ntohs ( iphdr->len ) );
goto err;
}
/* Verify the checksum */
if ( ( chksum = ipv4_rx_csum ( pkb, iphdr->protocol ) ) != 0xffff ) {
DBG ( "Bad checksum %x\n", chksum );
}
/* Fragment reassembly */
if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) ||
( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
/* Pass the fragment to the reassembler ipv4_ressable() which
* either returns a fully reassembled packet buffer or NULL.
/* Pass the fragment to ipv4_reassemble() which either
* returns a fully reassembled packet buffer or NULL.
*/
pkb = ipv4_reassemble ( pkb );
if ( !pkb ) {
if ( ! pkb )
return 0;
}
}
/* To reduce code size, the following functions are not implemented:
* 1. Check the destination address
* 2. Check the TTL field
* 3. Check the service field
*/
/* Construct socket addresses */
/* Construct socket addresses and hand off to transport layer */
memset ( &src, 0, sizeof ( src ) );
src.sin.sin_family = AF_INET;
src.sin.sin_addr = iphdr->src;
memset ( &dest, 0, sizeof ( dest ) );
dest.sin.sin_family = AF_INET;
dest.sin.sin_addr = iphdr->dest;
/* Strip header */
pkb_unput ( pkb, pkb_len ( pkb ) - ntohs ( iphdr->len ) );
pkb_pull ( pkb, sizeof ( *iphdr ) );
/* Send it to the transport layer */
return tcpip_rx ( pkb, iphdr->protocol, &src.st, &dest.st );
return tcpip_rx ( pkb, iphdr->protocol, &src.st, &dest.st, pshdr_csum);
err:
free_pkb ( pkb );

View File

@ -103,11 +103,9 @@ void del_ipv6_address ( struct net_device *netdev ) {
* This function constructs the pseudo header and completes the checksum in the
* upper layer header.
*/
static void ipv6_tx_csum ( struct pk_buff *pkb, struct tcpip_protocol *tcpip ) {
static uint16_t ipv6_tx_csum ( struct pk_buff *pkb, uint16_t csum ) {
struct ip6_header *ip6hdr = pkb->data;
struct ipv6_pseudo_header pshdr;
uint16_t *csum = ( ( ( void * ) ip6hdr ) + sizeof ( *ip6hdr ) +
tcpip->csum_offset );
/* Calculate pseudo header */
memset ( &pshdr, 0, sizeof ( pshdr ) );
@ -117,7 +115,7 @@ static void ipv6_tx_csum ( struct pk_buff *pkb, struct tcpip_protocol *tcpip ) {
pshdr.nxt_hdr = ip6hdr->nxt_hdr;
/* Update checksum value */
*csum = tcpip_continue_chksum ( *csum, &pshdr, sizeof ( pshdr ) );
return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
}
/**
@ -142,7 +140,8 @@ void ipv6_dump ( struct ip6_header *ip6hdr ) {
*/
static int ipv6_tx ( struct pk_buff *pkb,
struct tcpip_protocol *tcpip,
struct sockaddr_tcpip *st_dest ) {
struct sockaddr_tcpip *st_dest,
uint16_t *trans_csum ) {
struct sockaddr_in6 *dest = ( struct sockaddr_in6* ) st_dest;
struct in6_addr next_hop;
struct ipv6_miniroute *miniroute;
@ -184,9 +183,8 @@ static int ipv6_tx ( struct pk_buff *pkb,
}
/* Complete the transport layer checksum */
if ( tcpip->csum_offset > 0 ) {
ipv6_tx_csum ( pkb, tcpip );
}
if ( trans_csum )
*trans_csum = ipv6_tx_csum ( pkb, *trans_csum );
/* Print IPv6 header */
ipv6_dump ( ip6hdr );
@ -244,7 +242,7 @@ static int ipv6_process_nxt_hdr ( struct pk_buff *pkb, uint8_t nxt_hdr,
return 0;
}
/* Next header is not a IPv6 extension header */
return tcpip_rx ( pkb, nxt_hdr, src, dest );
return tcpip_rx ( pkb, nxt_hdr, src, dest, 0 /* fixme */ );
}
/**

View File

@ -309,7 +309,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
DBGC ( conn, "\n" );
/* Transmit packet */
return tcpip_tx ( pkb, &tcp_protocol, &conn->peer );
return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, &tcphdr->csum );
}
/**
@ -591,14 +591,19 @@ static int tcp_rx_fin ( struct tcp_connection *conn, uint32_t seq ) {
* Process received packet
*
* @v pkb Packet buffer
* @v partial Partial checksum
*/
* @v st_src Partially-filled source address
* @v st_dest Partially-filled destination address
* @v pshdr_csum Pseudo-header checksum
* @ret rc Return status code
*/
static int tcp_rx ( struct pk_buff *pkb,
struct sockaddr_tcpip *st_src __unused,
struct sockaddr_tcpip *st_dest __unused ) {
struct sockaddr_tcpip *st_dest __unused,
uint16_t pshdr_csum ) {
struct tcp_header *tcphdr;
struct tcp_connection *conn;
unsigned int hlen;
uint16_t csum;
uint32_t start_seq;
uint32_t seq;
uint32_t ack;
@ -608,7 +613,7 @@ static int tcp_rx ( struct pk_buff *pkb,
size_t len;
int rc = 0;
/* Sanity check packet and strip TCP header */
/* Sanity check packet */
if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
DBG ( "TCP packet too short at %d bytes (min %d bytes)\n",
pkb_len ( pkb ), sizeof ( *tcphdr ) );
@ -629,9 +634,12 @@ static int tcp_rx ( struct pk_buff *pkb,
rc = -EINVAL;
goto err;
}
/* TODO: Verify checksum */
#warning "Verify checksum"
csum = tcpip_continue_chksum ( pshdr_csum, pkb->data, pkb_len ( pkb ));
if ( csum != 0 ) {
DBG ( "TCP checksum incorrect (is %04x including checksum "
"field, should be 0000)\n", csum );
goto err;
}
/* Parse parameters from header and strip header */
conn = tcp_demux ( tcphdr->dest );
@ -845,5 +853,4 @@ struct tcpip_protocol tcp_protocol __tcpip_protocol = {
.name = "TCP",
.rx = tcp_rx,
.tcpip_proto = IP_TCP,
.csum_offset = 16,
};

View File

@ -32,6 +32,7 @@ tcpip_protocols_end[0] __table_end ( tcpip_protocols );
* @v tcpip_proto Transport-layer protocol number
* @v st_src Partially-filled source address
* @v st_dest Partially-filled destination address
* @v pshdr_csum Pseudo-header checksum
* @ret rc Return status code
*
* This function expects a transport-layer segment from the network
@ -42,14 +43,15 @@ tcpip_protocols_end[0] __table_end ( tcpip_protocols );
*/
int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto,
struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest ) {
struct sockaddr_tcpip *st_dest,
uint16_t pshdr_csum ) {
struct tcpip_protocol *tcpip;
/* Hand off packet to the appropriate transport-layer protocol */
for ( tcpip = tcpip_protocols; tcpip < tcpip_protocols_end; tcpip++ ) {
if ( tcpip->tcpip_proto == tcpip_proto ) {
DBG ( "TCP/IP received %s packet\n", tcpip->name );
return tcpip->rx ( pkb, st_src, st_dest );
return tcpip->rx ( pkb, st_src, st_dest, pshdr_csum );
}
}
@ -63,10 +65,11 @@ int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto,
* @v pkb Packet buffer
* @v tcpip_protocol Transport-layer protocol
* @v st_dest Destination address
* @v trans_csum Transport-layer checksum to complete, or NULL
* @ret rc Return status code
*/
int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol,
struct sockaddr_tcpip *st_dest ) {
struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ) {
struct tcpip_net_protocol *tcpip_net;
/* 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,
tcpip_net < tcpip_net_protocols_end ; tcpip_net++ ) {
if ( tcpip_net->sa_family == st_dest->st_family ) {
DBG ( "TCP/IP sending %s packet\n", tcpip_net->name );
return tcpip_net->tx ( pkb, tcpip_protocol, st_dest );
return tcpip_net->tx ( pkb, tcpip_protocol, st_dest,
trans_csum );
}
}
@ -101,8 +105,8 @@ int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol,
* or both. Deciding which to swap is left as an exercise for the
* interested reader.
*/
unsigned int tcpip_continue_chksum ( unsigned int partial, const void *data,
size_t len ) {
uint16_t tcpip_continue_chksum ( uint16_t partial, const void *data,
size_t len ) {
unsigned int cksum = ( ( ~partial ) & 0xffff );
unsigned int value;
unsigned int i;
@ -121,7 +125,7 @@ unsigned int tcpip_continue_chksum ( unsigned int partial, const void *data,
cksum -= 0xffff;
}
return ( ( ~cksum ) & 0xffff );
return ( ~cksum );
}
/**
@ -134,6 +138,6 @@ unsigned int tcpip_continue_chksum ( unsigned int partial, const void *data,
* Calculates a TCP/IP-style 16-bit checksum over the data block. The
* checksum is returned in network byte order.
*/
unsigned int tcpip_chksum ( const void *data, size_t len ) {
return tcpip_continue_chksum ( 0xffff, data, len );
uint16_t tcpip_chksum ( const void *data, size_t len ) {
return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, len );
}

View File

@ -163,7 +163,7 @@ int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
ntohs ( udphdr->chksum ) );
/* Send it to the next layer for processing */
return tcpip_tx ( pkb, &udp_protocol, peer );
return tcpip_tx ( pkb, &udp_protocol, peer, &udphdr->chksum );
}
/**
@ -190,14 +190,15 @@ int udp_send ( struct udp_connection *conn, const void *data, size_t len ) {
* @v pkb Packet buffer
* @v st_src Partially-filled source address
* @v st_dest Partially-filled destination address
* @v pshdr_csum Pseudo-header checksum
* @ret rc Return status code
*/
static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest ) {
struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
struct udp_header *udphdr = pkb->data;
struct udp_connection *conn;
unsigned int ulen;
uint16_t chksum;
uint16_t csum;
int rc;
/* Sanity check */
@ -225,15 +226,13 @@ static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
/* Verify the checksum */
#warning "Don't we need to take the pseudo-header into account here?"
#if 0
chksum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
if ( chksum != 0xffff ) {
DBG ( "Bad checksum %#x\n", chksum );
csum = tcpip_continue_chksum ( pshdr_csum, pkb->data, pkb_len ( pkb ));
if ( csum != 0 ) {
DBG ( "UDP checksum incorrect (is %04x including checksum "
"field, should be 0000)\n", csum );
rc = -EINVAL;
goto done;
}
#endif
/* Complete the socket addresses */
st_src->st_port = udphdr->source_port;
@ -271,5 +270,4 @@ struct tcpip_protocol udp_protocol __tcpip_protocol = {
.name = "UDP",
.rx = udp_rx,
.tcpip_proto = IP_UDP,
.csum_offset = 6,
};