Module Name:    src
Committed By:   zoltan
Date:           Fri Nov  4 00:22:34 UTC 2011

Modified Files:
        src/sys/netinet6: frag6.c ip6_var.h

Log Message:
Change the IPv6 reassembly mechanism to use mutex(9).
Also add ip6_reass_packet() to be used by NPF.


To generate a diff of this commit:
cvs rdiff -u -r1.49 -r1.50 src/sys/netinet6/frag6.c
cvs rdiff -u -r1.55 -r1.56 src/sys/netinet6/ip6_var.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet6/frag6.c
diff -u src/sys/netinet6/frag6.c:1.49 src/sys/netinet6/frag6.c:1.50
--- src/sys/netinet6/frag6.c:1.49	Tue May  3 17:44:30 2011
+++ src/sys/netinet6/frag6.c	Fri Nov  4 00:22:33 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: frag6.c,v 1.49 2011/05/03 17:44:30 dyoung Exp $	*/
+/*	$NetBSD: frag6.c,v 1.50 2011/11/04 00:22:33 zoltan Exp $	*/
 /*	$KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.49 2011/05/03 17:44:30 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.50 2011/11/04 00:22:33 zoltan Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -64,66 +64,13 @@ static void frag6_insque(struct ip6q *, 
 static void frag6_remque(struct ip6q *);
 static void frag6_freef(struct ip6q *);
 
-static int ip6q_locked;
 static int frag6_drainwanted;
 
 u_int frag6_nfragpackets;
 u_int frag6_nfrags;
 struct	ip6q ip6q;	/* ip6 reassemble queue */
 
-static inline int ip6q_lock_try(void);
-static inline void ip6q_unlock(void);
-
-static inline int
-ip6q_lock_try(void)
-{
-	int s;
-
-	/*
-	 * Use splvm() -- we're bloking things that would cause
-	 * mbuf allocation.
-	 */
-	s = splvm();
-	if (ip6q_locked) {
-		splx(s);
-		return (0);
-	}
-	ip6q_locked = 1;
-	splx(s);
-	return (1);
-}
-
-static inline void
-ip6q_unlock(void)
-{
-	int s;
-
-	s = splvm();
-	ip6q_locked = 0;
-	splx(s);
-}
-
-#ifdef DIAGNOSTIC
-#define	IP6Q_LOCK()							\
-do {									\
-	if (ip6q_lock_try() == 0) {					\
-		printf("%s:%d: ip6q already locked\n", __FILE__, __LINE__); \
-		panic("ip6q_lock");					\
-	}								\
-} while (/*CONSTCOND*/ 0)
-#define	IP6Q_LOCK_CHECK()						\
-do {									\
-	if (ip6q_locked == 0) {						\
-		printf("%s:%d: ip6q lock not held\n", __FILE__, __LINE__); \
-		panic("ip6q lock check");				\
-	}								\
-} while (/*CONSTCOND*/ 0)
-#else
-#define	IP6Q_LOCK()		(void) ip6q_lock_try()
-#define	IP6Q_LOCK_CHECK()	/* nothing */
-#endif
-
-#define	IP6Q_UNLOCK()		ip6q_unlock()
+static kmutex_t	frag6_lock;
 
 #ifndef offsetof		/* XXX */
 #define	offsetof(type, member)	((size_t)(&((type *)0)->member))
@@ -137,6 +84,7 @@ frag6_init(void)
 {
 
 	ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
+	mutex_init(&frag6_lock, MUTEX_DEFAULT, IPL_NET);
 }
 
 /*
@@ -171,8 +119,8 @@ frag6_init(void)
 /*
  * Fragment input
  */
-int
-frag6_input(struct mbuf **mp, int *offp, int proto)
+static int
+frag6_in(struct mbuf **mp, int *offp)
 {
 	struct rtentry *rt;
 	struct mbuf *m = *mp, *t;
@@ -193,7 +141,7 @@ frag6_input(struct mbuf **mp, int *offp,
 	ip6 = mtod(m, struct ip6_hdr *);
 	IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
 	if (ip6f == NULL)
-		return IPPROTO_DONE;
+		return -1;
 
 	dstifp = NULL;
 	/* find the destination interface of the packet. */
@@ -205,7 +153,7 @@ frag6_input(struct mbuf **mp, int *offp,
 	if (ip6->ip6_plen == 0) {
 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
 		in6_ifstat_inc(dstifp, ifs6_reass_fail);
-		return IPPROTO_DONE;
+		return -1;
 	}
 
 	/*
@@ -219,7 +167,7 @@ frag6_input(struct mbuf **mp, int *offp,
 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
 		    offsetof(struct ip6_hdr, ip6_plen));
 		in6_ifstat_inc(dstifp, ifs6_reass_fail);
-		return IPPROTO_DONE;
+		return -1;
 	}
 
 	IP6_STATINC(IP6_STAT_FRAGMENTS);
@@ -228,7 +176,7 @@ frag6_input(struct mbuf **mp, int *offp,
 	/* offset now points to data portion */
 	offset += sizeof(struct ip6_frag);
 
-	IP6Q_LOCK();
+	mutex_enter(&frag6_lock);
 
 	/*
 	 * Enforce upper bound on number of fragments.
@@ -269,7 +217,6 @@ frag6_input(struct mbuf **mp, int *offp,
 		if (q6 == NULL)
 			goto dropfrag;
 		memset(q6, 0, sizeof(*q6));
-
 		frag6_insque(q6, &ip6q);
 
 		/* ip6q_nxt will be filled afterwards, from 1st fragment */
@@ -307,18 +254,18 @@ frag6_input(struct mbuf **mp, int *offp,
 	if (q6->ip6q_unfrglen >= 0) {
 		/* The 1st fragment has already arrived. */
 		if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
+			mutex_exit(&frag6_lock);
 			icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
 			    offset - sizeof(struct ip6_frag) +
 			    offsetof(struct ip6_frag, ip6f_offlg));
-			IP6Q_UNLOCK();
-			return (IPPROTO_DONE);
+			return -1;
 		}
 	} else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
+		mutex_exit(&frag6_lock);
 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
 			    offset - sizeof(struct ip6_frag) +
 				offsetof(struct ip6_frag, ip6f_offlg));
-		IP6Q_UNLOCK();
-		return (IPPROTO_DONE);
+		return -1;
 	}
 	/*
 	 * If it's the first fragment, do the above check for each
@@ -476,14 +423,14 @@ insert:
 	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
 	     af6 = af6->ip6af_down) {
 		if (af6->ip6af_off != next) {
-			IP6Q_UNLOCK();
-			return IPPROTO_DONE;
+			mutex_exit(&frag6_lock);
+			return 0;
 		}
 		next += af6->ip6af_frglen;
 	}
 	if (af6->ip6af_up->ip6af_mff) {
-		IP6Q_UNLOCK();
-		return IPPROTO_DONE;
+		mutex_exit(&frag6_lock);
+		return 0;
 	}
 
 	/*
@@ -566,17 +513,39 @@ insert:
 	*mp = m;
 	*offp = offset;
 
-	IP6Q_UNLOCK();
+	mutex_exit(&frag6_lock);
 	return nxt;
 
  dropfrag:
+	mutex_exit(&frag6_lock);
 	in6_ifstat_inc(dstifp, ifs6_reass_fail);
 	IP6_STATINC(IP6_STAT_FRAGDROPPED);
 	m_freem(m);
-	IP6Q_UNLOCK();
+	return -1;
+}
+
+int
+frag6_input(struct mbuf **mp, int *offp, int proto)
+{
+	int ret = frag6_in(mp, offp);
+
+	if (ret > 0) {
+		return ret;
+	}
 	return IPPROTO_DONE;
 }
 
+int
+ip6_reass_packet(struct mbuf **mp, int offset)
+{
+	int ret = frag6_in(mp, &offset);
+
+	if (ret <= 0) {
+		*mp = NULL;
+	}
+	return ret < 0 ? ret : 0;
+}
+
 /*
  * Free a fragment reassembly header and all
  * associated datagrams.
@@ -586,7 +555,7 @@ frag6_freef(struct ip6q *q6)
 {
 	struct ip6asfrag *af6, *down6;
 
-	IP6Q_LOCK_CHECK();
+	KASSERT(mutex_owned(&frag6_lock));
 
 	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
 	     af6 = down6) {
@@ -629,7 +598,7 @@ void
 frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6)
 {
 
-	IP6Q_LOCK_CHECK();
+	KASSERT(mutex_owned(&frag6_lock));
 
 	af6->ip6af_up = up6;
 	af6->ip6af_down = up6->ip6af_down;
@@ -644,7 +613,7 @@ void
 frag6_deq(struct ip6asfrag *af6)
 {
 
-	IP6Q_LOCK_CHECK();
+	KASSERT(mutex_owned(&frag6_lock));
 
 	af6->ip6af_up->ip6af_down = af6->ip6af_down;
 	af6->ip6af_down->ip6af_up = af6->ip6af_up;
@@ -654,7 +623,7 @@ void
 frag6_insque(struct ip6q *new, struct ip6q *old)
 {
 
-	IP6Q_LOCK_CHECK();
+	KASSERT(mutex_owned(&frag6_lock));
 
 	new->ip6q_prev = old;
 	new->ip6q_next = old->ip6q_next;
@@ -666,7 +635,7 @@ void
 frag6_remque(struct ip6q *p6)
 {
 
-	IP6Q_LOCK_CHECK();
+	KASSERT(mutex_owned(&frag6_lock));
 
 	p6->ip6q_prev->ip6q_next = p6->ip6q_next;
 	p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
@@ -691,10 +660,7 @@ frag6_slowtimo(void)
 {
 	struct ip6q *q6;
 
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-
-	IP6Q_LOCK();
+	mutex_enter(&frag6_lock);
 	q6 = ip6q.ip6q_next;
 	if (q6)
 		while (q6 != &ip6q) {
@@ -717,7 +683,7 @@ frag6_slowtimo(void)
 		/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
 		frag6_freef(ip6q.ip6q_prev);
 	}
-	IP6Q_UNLOCK();
+	mutex_exit(&frag6_lock);
 
 #if 0
 	/*
@@ -729,8 +695,6 @@ frag6_slowtimo(void)
 	rtcache_free(&ipsrcchk_rt);
 #endif
 
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
 }
 
 void
@@ -746,14 +710,12 @@ void
 frag6_drain(void)
 {
 
-	KERNEL_LOCK(1, NULL);
-	if (ip6q_lock_try() != 0) {
+	if (mutex_tryenter(&frag6_lock)) {
 		while (ip6q.ip6q_next != &ip6q) {
 			IP6_STATINC(IP6_STAT_FRAGDROPPED);
 			/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
 			frag6_freef(ip6q.ip6q_next);
 		}
-		IP6Q_UNLOCK();
+		mutex_exit(&frag6_lock);
 	}
-	KERNEL_UNLOCK_ONE(NULL);
 }

Index: src/sys/netinet6/ip6_var.h
diff -u src/sys/netinet6/ip6_var.h:1.55 src/sys/netinet6/ip6_var.h:1.56
--- src/sys/netinet6/ip6_var.h:1.55	Tue May 24 18:07:11 2011
+++ src/sys/netinet6/ip6_var.h	Fri Nov  4 00:22:33 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_var.h,v 1.55 2011/05/24 18:07:11 spz Exp $	*/
+/*	$NetBSD: ip6_var.h,v 1.56 2011/11/04 00:22:33 zoltan Exp $	*/
 /*	$KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $	*/
 
 /*
@@ -358,6 +358,7 @@ int	route6_input(struct mbuf **, int *, 
 
 void	frag6_init(void);
 int	frag6_input(struct mbuf **, int *, int);
+int	ip6_reass_packet(struct mbuf **, int);
 void	frag6_slowtimo(void);
 void	frag6_fasttimo(void);
 void	frag6_drain(void);

Reply via email to