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);