diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2014-02-10 09:20:05 +0900 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2014-02-14 13:33:04 +0900 |
commit | 5a50c0283346a197cda7af19e68f611f14b8fe57 (patch) | |
tree | 1cccafeba5bbd41374daa0aed35379faa4c26a88 /checksum.c | |
parent | a33592bd08a20c6a521b8508975b7a74ecdf4f03 (diff) | |
download | android_external_android-clat-5a50c0283346a197cda7af19e68f611f14b8fe57.tar.gz android_external_android-clat-5a50c0283346a197cda7af19e68f611f14b8fe57.tar.bz2 android_external_android-clat-5a50c0283346a197cda7af19e68f611f14b8fe57.zip |
Fix up checksums instead of recalculating them.
Currently the checksums of translated packets are calculated
from scratch by checksumming the translated packet. This is slow
and does not work in the case of fragments, because the whole
packet is not available. Instead, calculate the checksum by
adjusting the checksum of the original packet.
Bug: 11542311
Bug: 12116252
Change-Id: I6b78a94ca5bd96b13ee2653b6200551193b3dcc1
Diffstat (limited to 'checksum.c')
-rw-r--r-- | checksum.c | 38 |
1 files changed, 33 insertions, 5 deletions
@@ -49,19 +49,27 @@ uint32_t ip_checksum_add(uint32_t current, const void *data, int len) { return checksum; } -/* function: ip_checksum_finish - * close the checksum +/* function: ip_checksum_fold + * folds a 32-bit partial checksum into 16 bits * temp_sum - sum from ip_checksum_add + * returns: the folded checksum in network byte order */ -uint16_t ip_checksum_finish(uint32_t temp_sum) { +uint16_t ip_checksum_fold(uint32_t temp_sum) { while(temp_sum > 0xffff) temp_sum = (temp_sum >> 16) + (temp_sum & 0xFFFF); - temp_sum = (~temp_sum) & 0xffff; - return temp_sum; } +/* function: ip_checksum_finish + * folds and closes the checksum + * temp_sum - sum from ip_checksum_add + * returns: a header checksum value in network byte order + */ +uint16_t ip_checksum_finish(uint32_t temp_sum) { + return ~ip_checksum_fold(temp_sum); +} + /* function: ip_checksum * combined ip_checksum_add and ip_checksum_finish * data - data to checksum @@ -113,3 +121,23 @@ uint32_t ipv4_pseudo_header_checksum(uint32_t current, const struct iphdr *ip, u return current; } + +/* function: ip_checksum_adjust + * calculates a new checksum given a previous checksum and the old and new pseudo-header checksums + * checksum - the header checksum in the original packet in network byte order + * old_hdr_sum - the pseudo-header checksum of the original packet + * new_hdr_sum - the pseudo-header checksum of the translated packet + * returns: the new header checksum in network byte order + */ +uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum) { + // Algorithm suggested in RFC 1624. + // http://tools.ietf.org/html/rfc1624#section-3 + checksum = ~checksum; + uint16_t folded_sum = ip_checksum_fold(checksum + new_hdr_sum); + uint16_t folded_old = ip_checksum_fold(old_hdr_sum); + if (folded_sum > folded_old) { + return ~(folded_sum - folded_old); + } else { + return ~(folded_sum - folded_old - 1); // end-around borrow + } +} |