summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authortanimura <tanimura@FreeBSD.org>2002-05-20 05:41:09 +0000
committertanimura <tanimura@FreeBSD.org>2002-05-20 05:41:09 +0000
commit92d8381dd544a8237b3fd68c4e7fce9bd0903fb2 (patch)
tree2465ddbcecac65f96c5c6d5cef1a4fe3f1ac03f8 /sys/netinet6
parent969293170b27461145f69a538d5abd15fea34ba1 (diff)
downloadFreeBSD-src-92d8381dd544a8237b3fd68c4e7fce9bd0903fb2.zip
FreeBSD-src-92d8381dd544a8237b3fd68c4e7fce9bd0903fb2.tar.gz
Lock down a socket, milestone 1.
o Add a mutex (sb_mtx) to struct sockbuf. This protects the data in a socket buffer. The mutex in the receive buffer also protects the data in struct socket. o Determine the lock strategy for each members in struct socket. o Lock down the following members: - so_count - so_options - so_linger - so_state o Remove *_locked() socket APIs. Make the following socket APIs touching the members above now require a locked socket: - sodisconnect() - soisconnected() - soisconnecting() - soisdisconnected() - soisdisconnecting() - sofree() - soref() - sorele() - sorwakeup() - sotryfree() - sowakeup() - sowwakeup() Reviewed by: alfred
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/icmp6.c10
-rw-r--r--sys/netinet6/in6_pcb.c68
-rw-r--r--sys/netinet6/in6_src.c2
-rw-r--r--sys/netinet6/ip6_input.c5
-rw-r--r--sys/netinet6/ip6_mroute.c2
-rw-r--r--sys/netinet6/raw_ip6.c45
-rw-r--r--sys/netinet6/udp6_usrreq.c57
7 files changed, 151 insertions, 38 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 38332b2..f9994c6 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1941,8 +1941,11 @@ icmp6_rip6_input(mp, off)
if (opts) {
m_freem(opts);
}
- } else
+ } else {
+ SOCK_LOCK(last->in6p_socket);
sorwakeup(last->in6p_socket);
+ SOCK_UNLOCK(last->in6p_socket);
+ }
opts = NULL;
}
}
@@ -1958,8 +1961,11 @@ icmp6_rip6_input(mp, off)
m_freem(m);
if (opts)
m_freem(opts);
- } else
+ } else {
+ SOCK_LOCK(last->in6p_socket);
sorwakeup(last->in6p_socket);
+ SOCK_UNLOCK(last->in6p_socket);
+ }
} else {
m_freem(m);
ip6stat.ip6s_delivered--;
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 09a5c29..ab37249 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -124,14 +124,19 @@ in6_pcbbind(inp, nam, td)
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
u_short lport = 0;
- int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
+ int wild = 0, reuseport;
+ SOCK_LOCK(so);
+ reuseport = (so->so_options & SO_REUSEPORT);
+ SOCK_UNLOCK(so);
if (!in6_ifaddr) /* XXX broken! */
return (EADDRNOTAVAIL);
if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
return(EINVAL);
+ SOCK_LOCK(so);
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
wild = 1;
+ SOCK_UNLOCK(so);
if (nam) {
sin6 = (struct sockaddr_in6 *)nam;
if (nam->sa_len != sizeof(*sin6))
@@ -157,8 +162,10 @@ in6_pcbbind(inp, nam, td)
* and a multicast address is bound on both
* new and duplicated sockets.
*/
+ SOCK_LOCK(so);
if (so->so_options & SO_REUSEADDR)
reuseport = SO_REUSEADDR|SO_REUSEPORT;
+ SOCK_UNLOCK(so);
} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct ifaddr *ia = NULL;
@@ -190,14 +197,19 @@ in6_pcbbind(inp, nam, td)
t = in6_pcblookup_local(pcbinfo,
&sin6->sin6_addr, lport,
INPLOOKUP_WILDCARD);
- if (t &&
- (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
- !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
- (t->inp_socket->so_options &
- SO_REUSEPORT) == 0) &&
- (so->so_cred->cr_uid !=
- t->inp_socket->so_cred->cr_uid))
- return (EADDRINUSE);
+ if (t != NULL) {
+ SOCK_LOCK(t->inp_socket);
+ if ((!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
+ !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
+ (t->inp_socket->so_options &
+ SO_REUSEPORT) == 0) &&
+ (so->so_cred->cr_uid !=
+ t->inp_socket->so_cred->cr_uid)) {
+ SOCK_UNLOCK(t->inp_socket);
+ return (EADDRINUSE);
+ }
+ SOCK_UNLOCK(t->inp_socket);
+ }
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
@@ -218,8 +230,14 @@ in6_pcbbind(inp, nam, td)
}
t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
lport, wild);
- if (t && (reuseport & t->inp_socket->so_options) == 0)
- return(EADDRINUSE);
+ if (t != NULL) {
+ SOCK_LOCK(t->inp_socket);
+ if ((reuseport & t->inp_socket->so_options) == 0) {
+ SOCK_UNLOCK(t->inp_socket);
+ return(EADDRINUSE);
+ }
+ SOCK_UNLOCK(t->inp_socket);
+ }
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
@@ -227,14 +245,19 @@ in6_pcbbind(inp, nam, td)
in6_sin6_2_sin(&sin, sin6);
t = in_pcblookup_local(pcbinfo, sin.sin_addr,
lport, wild);
- if (t &&
- (reuseport & t->inp_socket->so_options)
- == 0 &&
- (ntohl(t->inp_laddr.s_addr)
- != INADDR_ANY ||
- INP_SOCKAF(so) ==
- INP_SOCKAF(t->inp_socket)))
- return (EADDRINUSE);
+ if (t != NULL) {
+ SOCK_LOCK(t->inp_socket);
+ if ((reuseport & t->inp_socket->so_options)
+ == 0 &&
+ (ntohl(t->inp_laddr.s_addr)
+ != INADDR_ANY ||
+ INP_SOCKAF(so) ==
+ INP_SOCKAF(t->inp_socket))) {
+ SOCK_UNLOCK(t->inp_socket);
+ return (EADDRINUSE);
+ }
+ SOCK_UNLOCK(t->inp_socket);
+ }
}
}
inp->in6p_laddr = sin6->sin6_addr;
@@ -589,8 +612,12 @@ in6_pcbdisconnect(inp)
/* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
in_pcbrehash(inp);
- if (inp->inp_socket->so_state & SS_NOFDREF)
+ SOCK_LOCK(inp->inp_socket);
+ if (inp->inp_socket->so_state & SS_NOFDREF) {
+ SOCK_UNLOCK(inp->inp_socket);
in6_pcbdetach(inp);
+ } else
+ SOCK_UNLOCK(inp->inp_socket);
}
void
@@ -607,6 +634,7 @@ in6_pcbdetach(inp)
inp->inp_gencnt = ++ipi->ipi_gencnt;
in_pcbremlists(inp);
sotoinpcb(so) = 0;
+ SOCK_LOCK(so);
sotryfree(so);
if (inp->in6p_options)
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 3dd2212..910e66d 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -338,9 +338,11 @@ in6_pcbsetport(laddr, inp, td)
int count, error = 0, wild = 0;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
+ SOCK_LOCK(so);
/* XXX: this is redundant when called from in6_pcbbind */
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
wild = INPLOOKUP_WILDCARD;
+ SOCK_UNLOCK(so);
inp->inp_flags |= INP_ANONPORT;
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 16df5bb..f237cdf 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1147,16 +1147,19 @@ ip6_savecontrol(in6p, mp, ip6, m)
privileged++;
#ifdef SO_TIMESTAMP
+ SOCK_LOCK(in6p->in6p_socket);
if ((in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0) {
struct timeval tv;
+ SOCK_UNLOCK(in6p->in6p_socket);
microtime(&tv);
*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
SCM_TIMESTAMP, SOL_SOCKET);
if (*mp) {
mp = &(*mp)->m_next;
}
- }
+ } else
+ SOCK_UNLOCK(in6p->in6p_socket);
#endif
/* RFC 2292 sec. 5 */
diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
index 9af7e81..513e307 100644
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -892,7 +892,9 @@ socket_send(s, mm, src)
if (sbappendaddr(&s->so_rcv,
(struct sockaddr *)src,
mm, (struct mbuf *)0) != 0) {
+ SOCK_LOCK(s);
sorwakeup(s);
+ SOCK_UNLOCK(s);
return 0;
}
}
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 2dcec0c..5fbd7c9 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -182,9 +182,16 @@ rip6_input(mp, offp, proto)
} else
#endif /*IPSEC*/
if (n) {
- if (last->in6p_flags & IN6P_CONTROLOPTS ||
- last->in6p_socket->so_options & SO_TIMESTAMP)
+ if (last->in6p_flags & IN6P_CONTROLOPTS)
ip6_savecontrol(last, &opts, ip6, n);
+ else {
+ SOCK_LOCK(last->in6p_socket);
+ if (last->in6p_socket->so_options & SO_TIMESTAMP) {
+ SOCK_UNLOCK(last->in6p_socket);
+ ip6_savecontrol(last, &opts, ip6, n);
+ } else
+ SOCK_UNLOCK(last->in6p_socket);
+ }
/* strip intermediate headers */
m_adj(n, *offp);
if (sbappendaddr(&last->in6p_socket->so_rcv,
@@ -194,8 +201,11 @@ rip6_input(mp, offp, proto)
if (opts)
m_freem(opts);
rip6stat.rip6s_fullsock++;
- } else
+ } else {
+ SOCK_LOCK(last->in6p_socket);
sorwakeup(last->in6p_socket);
+ SOCK_UNLOCK(last->in6p_socket);
+ }
opts = NULL;
}
}
@@ -213,9 +223,16 @@ rip6_input(mp, offp, proto)
} else
#endif /*IPSEC*/
if (last) {
- if (last->in6p_flags & IN6P_CONTROLOPTS ||
- last->in6p_socket->so_options & SO_TIMESTAMP)
+ if (last->in6p_flags & IN6P_CONTROLOPTS)
ip6_savecontrol(last, &opts, ip6, m);
+ else {
+ SOCK_LOCK(last->in6p_socket);
+ if (last->in6p_socket->so_options & SO_TIMESTAMP) {
+ SOCK_UNLOCK(last->in6p_socket);
+ ip6_savecontrol(last, &opts, ip6, m);
+ } else
+ SOCK_UNLOCK(last->in6p_socket);
+ }
/* strip intermediate headers */
m_adj(m, *offp);
if (sbappendaddr(&last->in6p_socket->so_rcv,
@@ -224,8 +241,11 @@ rip6_input(mp, offp, proto)
if (opts)
m_freem(opts);
rip6stat.rip6s_fullsock++;
- } else
+ } else {
+ SOCK_LOCK(last->in6p_socket);
sorwakeup(last->in6p_socket);
+ SOCK_UNLOCK(last->in6p_socket);
+ }
} else {
rip6stat.rip6s_nosock++;
if (m->m_flags & M_MCAST)
@@ -591,7 +611,9 @@ rip6_detach(struct socket *so)
static int
rip6_abort(struct socket *so)
{
+ SOCK_LOCK(so);
soisdisconnected(so);
+ SOCK_UNLOCK(so);
return rip6_detach(so);
}
@@ -600,8 +622,12 @@ rip6_disconnect(struct socket *so)
{
struct inpcb *inp = sotoinpcb(so);
- if ((so->so_state & SS_ISCONNECTED) == 0)
+ SOCK_LOCK(so);
+ if ((so->so_state & SS_ISCONNECTED) == 0) {
+ SOCK_UNLOCK(so);
return ENOTCONN;
+ }
+ SOCK_UNLOCK(so);
inp->in6p_faddr = in6addr_any;
return rip6_abort(so);
}
@@ -669,7 +695,9 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
return (error ? error : EADDRNOTAVAIL);
inp->in6p_laddr = *in6a;
inp->in6p_faddr = addr->sin6_addr;
+ SOCK_LOCK(so);
soisconnected(so);
+ SOCK_UNLOCK(so);
return 0;
}
@@ -689,7 +717,9 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
struct sockaddr_in6 *dst;
/* always copy sockaddr to avoid overwrites */
+ SOCK_LOCK(so);
if (so->so_state & SS_ISCONNECTED) {
+ SOCK_UNLOCK(so);
if (nam) {
m_freem(m);
return EISCONN;
@@ -702,6 +732,7 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
sizeof(struct in6_addr));
dst = &tmp;
} else {
+ SOCK_UNLOCK(so);
if (nam == NULL) {
m_freem(m);
return ENOTCONN;
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 20913e6..0e58be5 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -269,10 +269,18 @@ udp6_input(mp, offp, proto)
* and m_copy() will copy M_PKTHDR
* only if offset is 0.
*/
- if (last->in6p_flags & IN6P_CONTROLOPTS
- || last->in6p_socket->so_options & SO_TIMESTAMP)
+ if (last->in6p_flags & IN6P_CONTROLOPTS)
ip6_savecontrol(last, &opts,
ip6, n);
+ else {
+ SOCK_LOCK(last->in6p_socket);
+ if (last->in6p_socket->so_options & SO_TIMESTAMP) {
+ SOCK_UNLOCK(last->in6p_socket);
+ ip6_savecontrol(last, &opts,
+ ip6, n);
+ } else
+ SOCK_UNLOCK(last->in6p_socket);
+ }
m_adj(n, off + sizeof(struct udphdr));
if (sbappendaddr(&last->in6p_socket->so_rcv,
@@ -282,8 +290,11 @@ udp6_input(mp, offp, proto)
if (opts)
m_freem(opts);
udpstat.udps_fullsock++;
- } else
+ } else {
+ SOCK_LOCK(last->in6p_socket);
sorwakeup(last->in6p_socket);
+ SOCK_UNLOCK(last->in6p_socket);
+ }
opts = NULL;
}
}
@@ -296,9 +307,13 @@ udp6_input(mp, offp, proto)
* port. It assumes that an application will never
* clear these options after setting them.
*/
+ SOCK_LOCK(last->in6p_socket);
if ((last->in6p_socket->so_options &
- (SO_REUSEPORT|SO_REUSEADDR)) == 0)
+ (SO_REUSEPORT|SO_REUSEADDR)) == 0) {
+ SOCK_UNLOCK(last->in6p_socket);
break;
+ } else
+ SOCK_UNLOCK(last->in6p_socket);
}
if (last == NULL) {
@@ -320,9 +335,16 @@ udp6_input(mp, offp, proto)
goto bad;
}
#endif /* IPSEC */
- if (last->in6p_flags & IN6P_CONTROLOPTS
- || last->in6p_socket->so_options & SO_TIMESTAMP)
+ if (last->in6p_flags & IN6P_CONTROLOPTS)
ip6_savecontrol(last, &opts, ip6, m);
+ else {
+ SOCK_LOCK(last->in6p_socket);
+ if (last->in6p_socket->so_options & SO_TIMESTAMP) {
+ SOCK_UNLOCK(last->in6p_socket);
+ ip6_savecontrol(last, &opts, ip6, m);
+ } else
+ SOCK_UNLOCK(last->in6p_socket);
+ }
m_adj(m, off + sizeof(struct udphdr));
if (sbappendaddr(&last->in6p_socket->so_rcv,
@@ -331,7 +353,9 @@ udp6_input(mp, offp, proto)
udpstat.udps_fullsock++;
goto bad;
}
+ SOCK_LOCK(last->in6p_socket);
sorwakeup(last->in6p_socket);
+ SOCK_UNLOCK(last->in6p_socket);
return IPPROTO_DONE;
}
/*
@@ -375,9 +399,16 @@ udp6_input(mp, offp, proto)
*/
init_sin6(&udp_in6, m); /* general init */
udp_in6.sin6_port = uh->uh_sport;
- if (in6p->in6p_flags & IN6P_CONTROLOPTS
- || in6p->in6p_socket->so_options & SO_TIMESTAMP)
+ if (in6p->in6p_flags & IN6P_CONTROLOPTS)
ip6_savecontrol(in6p, &opts, ip6, m);
+ else {
+ SOCK_LOCK(in6p->in6p_socket);
+ if (in6p->in6p_socket->so_options & SO_TIMESTAMP) {
+ SOCK_UNLOCK(in6p->in6p_socket);
+ ip6_savecontrol(in6p, &opts, ip6, m);
+ } else
+ SOCK_UNLOCK(in6p->in6p_socket);
+ }
m_adj(m, off + sizeof(struct udphdr));
if (sbappendaddr(&in6p->in6p_socket->so_rcv,
(struct sockaddr *)&udp_in6,
@@ -385,7 +416,9 @@ udp6_input(mp, offp, proto)
udpstat.udps_fullsock++;
goto bad;
}
+ SOCK_LOCK(in6p->in6p_socket);
sorwakeup(in6p->in6p_socket);
+ SOCK_UNLOCK(in6p->in6p_socket);
return IPPROTO_DONE;
bad:
if (m)
@@ -509,7 +542,9 @@ udp6_abort(struct socket *so)
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL; /* ??? possible? panic instead? */
+ SOCK_LOCK(so);
soisdisconnected(so);
+ SOCK_UNLOCK(so);
s = splnet();
in6_pcbdetach(inp);
splx(s);
@@ -614,7 +649,9 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
if (error == 0) {
inp->inp_vflag |= INP_IPV4;
inp->inp_vflag &= ~INP_IPV6;
+ SOCK_LOCK(so);
soisconnected(so);
+ SOCK_UNLOCK(so);
}
return error;
}
@@ -629,7 +666,9 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
}
+ SOCK_LOCK(so);
soisconnected(so);
+ SOCK_UNLOCK(so);
}
return error;
}
@@ -673,7 +712,9 @@ udp6_disconnect(struct socket *so)
in6_pcbdisconnect(inp);
inp->in6p_laddr = in6addr_any;
splx(s);
+ SOCK_LOCK(so);
so->so_state &= ~SS_ISCONNECTED; /* XXX */
+ SOCK_UNLOCK(so);
return 0;
}
OpenPOWER on IntegriCloud