svn commit: r285712 - head/sys/netpfil/ipfw
Andrey V. Elsukov
ae at FreeBSD.org
Mon Jul 20 07:26:33 UTC 2015
Author: ae
Date: Mon Jul 20 07:26:31 2015
New Revision: 285712
URL: https://svnweb.freebsd.org/changeset/base/285712
Log:
Add helper functions for IP checksum adjusting. Use these functions in
dummynet code and for setdscp. This fixes wrong checksums in some cases.
Obtained from: Yandex LLC
MFC after: 2 weeks
Sponsored by: Yandex LLC
Modified:
head/sys/netpfil/ipfw/ip_dn_io.c
head/sys/netpfil/ipfw/ip_fw2.c
head/sys/netpfil/ipfw/ip_fw_private.h
Modified: head/sys/netpfil/ipfw/ip_dn_io.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_dn_io.c Mon Jul 20 06:58:32 2015 (r285711)
+++ head/sys/netpfil/ipfw/ip_dn_io.c Mon Jul 20 07:26:31 2015 (r285712)
@@ -429,8 +429,7 @@ ecn_mark(struct mbuf* m)
switch (ip->ip_v) {
case IPVERSION:
{
- u_int8_t otos;
- int sum;
+ uint16_t old;
if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
return (0); /* not-ECT */
@@ -441,17 +440,9 @@ ecn_mark(struct mbuf* m)
* ecn-capable but not marked,
* mark CE and update checksum
*/
- otos = ip->ip_tos;
+ old = *(uint16_t *)ip;
ip->ip_tos |= IPTOS_ECN_CE;
- /*
- * update checksum (from RFC1624)
- * HC' = ~(~HC + ~m + m')
- */
- sum = ~ntohs(ip->ip_sum) & 0xffff;
- sum += (~otos & 0xffff) + ip->ip_tos;
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16); /* add carry */
- ip->ip_sum = htons(~sum & 0xffff);
+ ip->ip_sum = cksum_adjust(ip->ip_sum, old, *(uint16_t *)ip);
return (1);
}
#ifdef INET6
Modified: head/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw2.c Mon Jul 20 06:58:32 2015 (r285711)
+++ head/sys/netpfil/ipfw/ip_fw2.c Mon Jul 20 07:26:31 2015 (r285712)
@@ -2487,12 +2487,13 @@ do { \
code = TARG(cmd->arg1, dscp) & 0x3F;
l = 0; /* exit inner loop */
if (is_ipv4) {
- uint16_t a;
+ uint16_t old;
- a = ip->ip_tos;
- ip->ip_tos = (code << 2) | (ip->ip_tos & 0x03);
- a += ntohs(ip->ip_sum) - ip->ip_tos;
- ip->ip_sum = htons(a);
+ old = *(uint16_t *)ip;
+ ip->ip_tos = (code << 2) |
+ (ip->ip_tos & 0x03);
+ ip->ip_sum = cksum_adjust(ip->ip_sum,
+ old, *(uint16_t *)ip);
} else if (is_ipv6) {
uint8_t *v;
Modified: head/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_private.h Mon Jul 20 06:58:32 2015 (r285711)
+++ head/sys/netpfil/ipfw/ip_fw_private.h Mon Jul 20 07:26:31 2015 (r285712)
@@ -725,5 +725,22 @@ extern ipfw_nat_cfg_t *ipfw_nat_del_ptr;
extern ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
extern ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
+/* Helper functions for IP checksum adjustment */
+static __inline uint16_t
+cksum_add(uint16_t sum, uint16_t a)
+{
+ uint16_t res;
+
+ res = sum + a;
+ return (res + (res < a));
+}
+
+static __inline uint16_t
+cksum_adjust(uint16_t oldsum, uint16_t old, uint16_t new)
+{
+
+ return (~cksum_add(cksum_add(~oldsum, ~old), new));
+}
+
#endif /* _KERNEL */
#endif /* _IPFW2_PRIVATE_H */
More information about the svn-src-head
mailing list