mirror of
https://github.com/xcat2/xNBA.git
synced 2024-12-14 23:31:39 +00:00
Correct TCP/IP checksum generation.
This commit is contained in:
parent
0768670fd8
commit
2c0eb6eb1d
@ -83,7 +83,9 @@ extern void trans_rx ( struct pk_buff *pkb, uint8_t trans_proto,
|
||||
extern int trans_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip,
|
||||
struct sockaddr *dest );
|
||||
|
||||
extern uint16_t calc_chksum ( void *b, int len );
|
||||
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 );
|
||||
|
||||
extern struct tcpip_protocol * find_tcpip_protocol ( uint8_t trans_proto );
|
||||
extern struct tcpip_net_protocol * find_tcpip_net_protocol ( sa_family_t sa_family );
|
||||
|
@ -238,9 +238,8 @@ void ipv4_tx_csum ( struct pk_buff *pkb, struct tcpip_protocol *tcpip ) {
|
||||
|
||||
struct iphdr *iphdr = pkb->data;
|
||||
struct ipv4_pseudo_header pshdr;
|
||||
void *csum_offset = iphdr + sizeof ( *iphdr ) + tcpip->csum_offset;
|
||||
uint16_t partial_csum = *( ( uint16_t* ) csum_offset );
|
||||
uint16_t csum;
|
||||
uint16_t *csum = ( ( ( void * ) iphdr ) + sizeof ( *iphdr )
|
||||
+ tcpip->csum_offset );
|
||||
|
||||
/* Calculate pseudo header */
|
||||
pshdr.src = iphdr->src;
|
||||
@ -250,8 +249,7 @@ void ipv4_tx_csum ( struct pk_buff *pkb, struct tcpip_protocol *tcpip ) {
|
||||
pshdr.len = htons ( pkb_len ( pkb ) - sizeof ( *iphdr ) );
|
||||
|
||||
/* Update the checksum value */
|
||||
csum = partial_csum + calc_chksum ( &pshdr, sizeof ( pshdr ) );
|
||||
memcpy ( csum_offset, &csum, 2 );
|
||||
*csum = tcpip_continue_chksum ( *csum, &pshdr, sizeof ( pshdr ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -407,7 +405,7 @@ int ipv4_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip,
|
||||
|
||||
/* Calculate header checksum, in network byte order */
|
||||
iphdr->chksum = 0;
|
||||
iphdr->chksum = htons ( calc_chksum ( iphdr, sizeof ( *iphdr ) ) );
|
||||
iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
|
||||
|
||||
/* Print IP4 header for debugging */
|
||||
ipv4_dump ( iphdr );
|
||||
|
@ -105,21 +105,56 @@ int trans_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip,
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate internet checksum
|
||||
* Calculate continued TCP/IP checkum
|
||||
*
|
||||
* @v b Pointer to the data
|
||||
* @v len Length of data to be checksummed
|
||||
* @ret result 16 bit internet checksum
|
||||
* @v partial Checksum of already-summed data, in network byte order
|
||||
* @v data Data buffer
|
||||
* @v len Length of data buffer
|
||||
* @ret cksum Updated checksum, in network byte order
|
||||
*
|
||||
* Calculates a TCP/IP-style 16-bit checksum over the data block. The
|
||||
* checksum is returned in network byte order.
|
||||
*
|
||||
* This function may be used to add new data to an existing checksum.
|
||||
* The function assumes that both the old data and the new data start
|
||||
* on even byte offsets; if this is not the case then you will need to
|
||||
* byte-swap either the input partial checksum, the output checksum,
|
||||
* or both. Deciding which to swap is left as an exercise for the
|
||||
* interested reader.
|
||||
*/
|
||||
uint16_t calc_chksum(void *b, int len) {
|
||||
uint16_t *buf = b, result;
|
||||
uint16_t sum=0;
|
||||
for ( sum = 0; len > 1; len -= 2 ) /* Sum all 16b words */
|
||||
sum += *buf++;
|
||||
if ( len == 1 ) /* If any stray bytes, */
|
||||
sum += *(unsigned char*)buf; /* add to sum */
|
||||
sum = (sum >> 16) + (sum & 0xffff); /* Add the carry */
|
||||
sum += (sum >> 16); /* (again) */
|
||||
result = ~sum; /* Take the one's complement */
|
||||
return result; /* Return 16b value */
|
||||
unsigned int tcpip_continue_chksum ( unsigned int partial, const void *data,
|
||||
size_t len ) {
|
||||
unsigned int cksum = ( ( ~partial ) & 0xffff );
|
||||
unsigned int value;
|
||||
unsigned int i;
|
||||
|
||||
for ( i = 0 ; i < len ; i++ ) {
|
||||
value = * ( ( uint8_t * ) data + i );
|
||||
if ( i & 1 ) {
|
||||
/* Odd bytes: swap on little-endian systems */
|
||||
value = be16_to_cpu ( value );
|
||||
} else {
|
||||
/* Even bytes: swap on big-endian systems */
|
||||
value = le16_to_cpu ( value );
|
||||
}
|
||||
cksum += value;
|
||||
if ( cksum > 0xffff )
|
||||
cksum -= 0xffff;
|
||||
}
|
||||
|
||||
return ( ( ~cksum ) & 0xffff );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate TCP/IP checkum
|
||||
*
|
||||
* @v data Data buffer
|
||||
* @v len Length of data buffer
|
||||
* @ret cksum Checksum, in network byte order
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
@ -142,11 +142,8 @@ int udp_sendto ( struct udp_connection *conn, struct sockaddr *peer,
|
||||
udphdr->dest_port = *dest;
|
||||
udphdr->source_port = conn->local_port;
|
||||
udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
|
||||
/**
|
||||
* Calculate the partial checksum. Note this is stored in host byte
|
||||
* order.
|
||||
*/
|
||||
udphdr->chksum = calc_chksum ( udphdr, sizeof ( *udphdr ) + len );
|
||||
udphdr->chksum = 0;
|
||||
udphdr->chksum = tcpip_chksum ( udphdr, sizeof ( *udphdr ) + len );
|
||||
|
||||
/**
|
||||
* Dump the contents of the UDP header
|
||||
@ -238,7 +235,7 @@ void udp_rx ( struct pk_buff *pkb, struct in_addr *src_net_addr __unused,
|
||||
}
|
||||
|
||||
/* Verify the checksum */
|
||||
chksum = calc_chksum ( pkb->data, pkb_len ( pkb ) );
|
||||
chksum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
|
||||
if ( chksum != 0xffff ) {
|
||||
DBG ( "Bad checksum %d\n", chksum );
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user