Index: frag6.c =================================================================== RCS file: /home/ncvs/src/sys/netinet6/frag6.c,v retrieving revision 1.16 diff -u -r1.16 frag6.c --- frag6.c 7 Oct 2003 17:46:18 -0000 1.16 +++ frag6.c 19 Oct 2003 19:54:36 -0000 @@ -34,8 +34,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -68,10 +70,18 @@ static void frag6_remque __P((struct ip6q *)); static void frag6_freef __P((struct ip6q *)); -/* XXX we eventually need splreass6, or some real semaphore */ -int frag6_doing_reass; -u_int frag6_nfragpackets; -struct ip6q ip6q; /* ip6 reassemble queue */ +static struct mtx ip6qlock; +#define IP6Q_LOCK_INIT() mtx_init(&ip6qlock, "ip6qlock", NULL, MTX_DEF); +#define IP6Q_LOCK() mtx_lock(&ip6qlock); +#define IP6Q_UNLOCK() mtx_unlock(&ip6qlock); +#define IP6Q_LOCK_ASSERT() mtx_assert(&ip6qlock, MA_OWNED); + +/* + * These fields all protected by ip6qlock. + */ +static int frag6_doing_reass; +static u_int frag6_nfragpackets; +static struct ip6q ip6q; /* ip6 reassemble queue */ /* FreeBSD tweak */ static MALLOC_DEFINE(M_FTABLE, "fragment", "fragment reassembly header"); @@ -84,7 +94,7 @@ { ip6_maxfragpackets = nmbclusters / 4; - + IP6Q_LOCK_INIT(); #ifndef RANDOM_IP_ID ip6_id = arc4random(); #endif @@ -204,6 +214,7 @@ /* offset now points to data portion */ offset += sizeof(struct ip6_frag); + IP6Q_LOCK(); frag6_doing_reass = 1; for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next) @@ -274,6 +285,7 @@ offset - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); frag6_doing_reass = 0; + IP6Q_UNLOCK(); return (IPPROTO_DONE); } } else if (fragoff + frgpartlen > IPV6_MAXPACKET) { @@ -281,6 +293,7 @@ offset - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); frag6_doing_reass = 0; + IP6Q_UNLOCK(); return (IPPROTO_DONE); } /* @@ -436,12 +449,14 @@ af6 = af6->ip6af_down) { if (af6->ip6af_off != next) { frag6_doing_reass = 0; + IP6Q_UNLOCK(); return IPPROTO_DONE; } next += af6->ip6af_frglen; } if (af6->ip6af_up->ip6af_mff) { frag6_doing_reass = 0; + IP6Q_UNLOCK(); return IPPROTO_DONE; } @@ -525,13 +540,15 @@ *offp = offset; frag6_doing_reass = 0; + IP6Q_UNLOCK(); return nxt; dropfrag: + frag6_doing_reass = 0; + IP6Q_UNLOCK(); in6_ifstat_inc(dstifp, ifs6_reass_fail); ip6stat.ip6s_fragdropped++; m_freem(m); - frag6_doing_reass = 0; return IPPROTO_DONE; } @@ -545,6 +562,7 @@ { struct ip6asfrag *af6, *down6; + IP6Q_LOCK_ASSERT(); for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; af6 = down6) { struct mbuf *m = IP6_REASS_MBUF(af6); @@ -585,6 +603,8 @@ frag6_enq(af6, up6) struct ip6asfrag *af6, *up6; { + + IP6Q_LOCK_ASSERT(); af6->ip6af_up = up6; af6->ip6af_down = up6->ip6af_down; up6->ip6af_down->ip6af_up = af6; @@ -598,6 +618,8 @@ frag6_deq(af6) struct ip6asfrag *af6; { + + IP6Q_LOCK_ASSERT(); af6->ip6af_up->ip6af_down = af6->ip6af_down; af6->ip6af_down->ip6af_up = af6->ip6af_up; } @@ -606,6 +628,8 @@ frag6_insque(new, old) struct ip6q *new, *old; { + + IP6Q_LOCK_ASSERT(); new->ip6q_prev = old; new->ip6q_next = old->ip6q_next; old->ip6q_next->ip6q_prev= new; @@ -616,6 +640,8 @@ frag6_remque(p6) struct ip6q *p6; { + + IP6Q_LOCK_ASSERT(); p6->ip6q_prev->ip6q_next = p6->ip6q_next; p6->ip6q_next->ip6q_prev = p6->ip6q_prev; } @@ -631,6 +657,7 @@ struct ip6q *q6; int s = splnet(); + IP6Q_LOCK(); frag6_doing_reass = 1; q6 = ip6q.ip6q_next; if (q6) @@ -655,6 +682,7 @@ frag6_freef(ip6q.ip6q_prev); } frag6_doing_reass = 0; + IP6Q_UNLOCK(); #if 0 /* @@ -681,11 +709,16 @@ void frag6_drain() { - if (frag6_doing_reass) + + IP6Q_LOCK(); + if (frag6_doing_reass) { + IP6Q_UNLOCK(); return; + } while (ip6q.ip6q_next != &ip6q) { ip6stat.ip6s_fragdropped++; /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(ip6q.ip6q_next); } + IP6Q_UNLOCK(); } Index: scope6.c =================================================================== RCS file: /home/ncvs/src/sys/netinet6/scope6.c,v retrieving revision 1.8 diff -u -r1.8 scope6.c --- scope6.c 17 Oct 2003 15:46:31 -0000 1.8 +++ scope6.c 19 Oct 2003 20:28:51 -0000 @@ -45,6 +45,16 @@ #include #include +/* + * The scope6_lock protects both the global sid default stored in + * sid_default below, but also per-interface sid data. + */ +static struct mtx scope6_lock; +#define SCOPE6_LOCK_INIT() mtx_init(&scope6_lock, "scope6_lock", NULL, MTX_DEF); +#define SCOPE6_LOCK() mtx_lock(&scope6_lock); +#define SCOPE6_UNLOCK() mtx_unlock(&scope6_lock); +#define SCOPE6_LOCK_ASSERT() mtx_assert(&scope7_lock, MA_OWNED); + static struct scope6_id sid_default; #define SID(ifp) \ (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id) @@ -53,6 +63,7 @@ scope6_init() { + SCOPE6_LOCK_INIT(); bzero(&sid_default, sizeof(sid_default)); } @@ -113,7 +124,7 @@ */ s = splnet(); - + SCOPE6_LOCK(); for (i = 0; i < 16; i++) { if (idlist->s6id_list[i] && idlist->s6id_list[i] != sid->s6id_list[i]) { @@ -137,6 +148,7 @@ sid->s6id_list[i] = idlist->s6id_list[i]; } } + SCOPE6_UNLOCK(); splx(s); return (error); @@ -151,9 +163,9 @@ if (sid == NULL) /* paranoid? */ return (EINVAL); - + SCOPE6_LOCK(); *idlist = *sid; - + SCOPE6_UNLOCK(); return (0); } @@ -224,6 +236,7 @@ { int scope; struct scope6_id *sid = SID(ifp); + u_int32_t retval; #ifdef DIAGNOSTIC if (sid == NULL) { /* should not happen */ @@ -245,22 +258,32 @@ scope = in6_addrscope(addr); + /* + * XXX: These are all u_int32_t reads, so may not require locking. + */ + SCOPE6_LOCK(); switch(scope) { case IPV6_ADDR_SCOPE_NODELOCAL: - return (-1); /* XXX: is this an appropriate value? */ + retval = -1; /* XXX: is this an appropriate value? */ + break; case IPV6_ADDR_SCOPE_LINKLOCAL: - return (sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]); + retval = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]; + break; case IPV6_ADDR_SCOPE_SITELOCAL: - return (sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]); + retval = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]; + break; case IPV6_ADDR_SCOPE_ORGLOCAL: - return (sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]); + retval = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]; + break; default: - return (0); /* XXX: treat as global. */ + retval = 0; /* XXX: treat as global. */ } + SCOPE6_UNLOCK(); + return (retval); } void @@ -273,6 +296,7 @@ * We might eventually have to separate the notion of "link" from * "interface" and provide a user interface to set the default. */ + SCOPE6_LOCK(); if (ifp) { sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = ifp->if_index; @@ -282,13 +306,17 @@ sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = 0; sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0; } + SCOPE6_UNLOCK(); } int scope6_get_default(idlist) struct scope6_id *idlist; { + + SCOPE6_LOCK(); *idlist = sid_default; + SCOPE6_UNLOCK(); return (0); } @@ -297,6 +325,8 @@ scope6_addr2default(addr) struct in6_addr *addr; { + u_int32_t id; + /* * special case: The loopback address should be considered as * link-local, but there's no ambiguity in the syntax. @@ -304,5 +334,13 @@ if (IN6_IS_ADDR_LOOPBACK(addr)) return (0); - return (sid_default.s6id_list[in6_addrscope(addr)]); + /* + * XXX: 32-bit read is atomic on all our platforms, is it OK + * not to lock here? + */ + SCOPE6_LOCK(); + id = sid_default.s6id_list[in6_addrscope(addr)]; + SCOPE6_UNLOCK(); + + return (id); }