Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Apr 2009 10:12:01 +0000 (UTC)
From:      Bruce M Simpson <bms@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r191657 - head/sys/netinet
Message-ID:  <200904291012.n3TAC1rd076041@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bms
Date: Wed Apr 29 10:12:01 2009
New Revision: 191657
URL: http://svn.freebsd.org/changeset/base/191657

Log:
  Fix a problem whereby enqueued IGMPv3 filter list changes would be
  incorrectly output, if the RB-tree enumeration happened to reuse the
  same chain for a mode switch: that is, both ALLOW and BLOCK records
  were appended for the same group, in the same mbuf packet chain.
  
  This was introduced during an mbuf chain layout bug fix involving
  m_getptr(), which obviously cannot count from offset 0 on the
  second pass through the RB-tree when serializing the IGMPv3
  group records into the pending mbuf chain.
  
  Cut over to KTR_INET for IGMPv3 CTR usage.

Modified:
  head/sys/netinet/igmp.c

Modified: head/sys/netinet/igmp.c
==============================================================================
--- head/sys/netinet/igmp.c	Wed Apr 29 10:02:50 2009	(r191656)
+++ head/sys/netinet/igmp.c	Wed Apr 29 10:12:01 2009	(r191657)
@@ -86,7 +86,7 @@ __FBSDID("$FreeBSD$");
 #include <security/mac/mac_framework.h>
 
 #ifndef KTR_IGMPV3
-#define KTR_IGMPV3 KTR_SUBSYS
+#define KTR_IGMPV3 KTR_INET
 #endif
 
 static struct igmp_ifinfo *
@@ -2983,7 +2983,7 @@ igmp_v3_enqueue_filter_change(struct ifq
 	struct ip_msource	*ims, *nims;
 	struct mbuf		*m, *m0, *md;
 	in_addr_t		 naddr;
-	int			 m0srcs, nbytes, off, rsrcs, schanged;
+	int			 m0srcs, nbytes, npbytes, off, rsrcs, schanged;
 	int			 nallow, nblock;
 	uint8_t			 mode, now, then;
 	rectype_t		 crt, drt, nrt;
@@ -3001,6 +3001,7 @@ igmp_v3_enqueue_filter_change(struct ifq
 	nrt = REC_NONE;	/* record type for current node */
 	m0srcs = 0;	/* # source which will fit in current mbuf chain */
 	nbytes = 0;	/* # of bytes appended to group's state-change queue */
+	npbytes = 0;	/* # of bytes appended this packet */
 	rsrcs = 0;	/* # sources encoded in current record */
 	schanged = 0;	/* # nodes encoded in overall filter change */
 	nallow = 0;	/* # of source entries in ALLOW_NEW */
@@ -3047,6 +3048,7 @@ igmp_v3_enqueue_filter_change(struct ifq
 				m0srcs = (ifp->if_mtu - IGMP_LEADINGSPACE -
 				    sizeof(struct igmp_grouprec)) /
 				    sizeof(in_addr_t);
+				npbytes = 0;
 				CTR1(KTR_IGMPV3,
 				    "%s: allocated new packet", __func__);
 			}
@@ -3066,15 +3068,19 @@ igmp_v3_enqueue_filter_change(struct ifq
 				    "%s: m_append() failed", __func__);
 				return (-ENOMEM);
 			}
-			nbytes += sizeof(struct igmp_grouprec);
-			if (m == m0) {
-				md = m_last(m);
+			npbytes += sizeof(struct igmp_grouprec);
+			if (m != m0) {
+				/* new packet; offset in c hain */
+				md = m_getptr(m, npbytes -
+				    sizeof(struct igmp_grouprec), &off);
 				pig = (struct igmp_grouprec *)(mtod(md,
-				    uint8_t *) + md->m_len - nbytes);
+				    uint8_t *) + off);
 			} else {
-				md = m_getptr(m, 0, &off);
+				/* current packet; offset from last append */
+				md = m_last(m);
 				pig = (struct igmp_grouprec *)(mtod(md,
-				    uint8_t *) + off);
+				    uint8_t *) + md->m_len -
+				    sizeof(struct igmp_grouprec));
 			}
 			/*
 			 * Begin walking the tree for this record type
@@ -3133,7 +3139,7 @@ igmp_v3_enqueue_filter_change(struct ifq
 			 * pass, back out of allocations.
 			 */
 			if (rsrcs == 0) {
-				nbytes -= sizeof(struct igmp_grouprec);
+				npbytes -= sizeof(struct igmp_grouprec);
 				if (m != m0) {
 					CTR1(KTR_IGMPV3,
 					    "%s: m_free(m)", __func__);
@@ -3146,7 +3152,7 @@ igmp_v3_enqueue_filter_change(struct ifq
 				}
 				continue;
 			}
-			nbytes += (rsrcs * sizeof(in_addr_t));
+			npbytes += (rsrcs * sizeof(in_addr_t));
 			if (crt == REC_ALLOW)
 				pig->ig_type = IGMP_ALLOW_NEW_SOURCES;
 			else if (crt == REC_BLOCK)
@@ -3159,6 +3165,7 @@ igmp_v3_enqueue_filter_change(struct ifq
 			m->m_pkthdr.PH_vt.vt_nrecs++;
 			if (m != m0)
 				_IF_ENQUEUE(ifq, m);
+			nbytes += npbytes;
 		} while (nims != NULL);
 		drt |= crt;
 		crt = (~crt & REC_FULL);



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