apf_checksum: fix infinite loop problem
Since we no longer check the len is sufficient,
we can no longer guarantee len-X doesn't underflow.
However switching to using signed length avoids the problem,
and actually slightly reduces compiled program size.
Test: ./mk; atest apf_dns_test apf_checksum_test
Signed-off-by: Maciej Żenczykowski <[email protected]>
Change-Id: Id9a1ee626f999c42c5bd2e9c74a637dd5b915c27
diff --git a/apf_checksum.h b/apf_checksum.h
index 0bb14bb..f6adfe5 100644
--- a/apf_checksum.h
+++ b/apf_checksum.h
@@ -2,8 +2,8 @@
* Calculate big endian 16-bit sum of a buffer (max 128kB),
* then fold and negate it, producing a 16-bit result in [0..FFFE].
*/
-u16 calc_csum(u32 sum, const u8* const buf, const u32 len) {
- u32 i;
+u16 calc_csum(u32 sum, const u8* const buf, const s32 len) {
+ s32 i;
for (i = 0; i < len; ++i) sum += buf[i] * ((i & 1) ? 1 : 256);
sum = (sum & 0xFFFF) + (sum >> 16); /* max after this is 1FFFE */
@@ -23,7 +23,7 @@
* Warning: first IPV4_HLEN + TCP_HLEN == 40 bytes of ip4_pkt must be writable!
* Returns 6-bit DSCP value [0..63], garbage on parse error.
*/
-static int calc_ipv4_csum(u8* const ip4_pkt, const u32 len) {
+static int calc_ipv4_csum(u8* const ip4_pkt, const s32 len) {
store_be16(ip4_pkt + 10, calc_csum(0xFFFF, ip4_pkt, IPV4_HLEN));
u8 proto = ip4_pkt[9];
@@ -45,7 +45,7 @@
* Warning: first IPV6_HLEN + TCP_HLEN == 60 bytes of ip6_pkt must be writable!
* Returns 6-bit DSCP value [0..63], garbage on parse error.
*/
-static int calc_ipv6_csum(u8* const ip6_pkt, const u32 len) {
+static int calc_ipv6_csum(u8* const ip6_pkt, const s32 len) {
u8 proto = ip6_pkt[6];
u16 csum = calc_csum(proto, ip6_pkt + 8, len - 8);
switch (proto) {
@@ -72,7 +72,7 @@
*
* @return 6-bit DSCP value [0..63], garbage on parse error.
*/
-int calculate_checksum_and_return_dscp(u8* const pkt, const u32 len) {
+int calculate_checksum_and_return_dscp(u8* const pkt, const s32 len) {
switch (read_be16(pkt + 12)) { /* ethertype */
case ETH_P_IP: return calc_ipv4_csum(pkt + ETH_HLEN, len - ETH_HLEN);
case ETH_P_IPV6: return calc_ipv6_csum(pkt + ETH_HLEN, len - ETH_HLEN);