Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 20 Jul 2015 07:26:32 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r285712 - head/sys/netpfil/ipfw
Message-ID:  <201507200726.t6K7QW7J023955@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507200726.t6K7QW7J023955>