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 */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to