diff options
author | rwatson <rwatson@FreeBSD.org> | 2004-12-05 22:08:37 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2004-12-05 22:08:37 +0000 |
commit | 338b787cfd398c95a913a9b05fa1cf75127562df (patch) | |
tree | 9b08c18aaf7221e87bdaa7522e7a0d830830206d | |
parent | f2988d54dee0ffdc5f894558569060c50692848d (diff) | |
download | FreeBSD-src-338b787cfd398c95a913a9b05fa1cf75127562df.zip FreeBSD-src-338b787cfd398c95a913a9b05fa1cf75127562df.tar.gz |
Pass the inpcb reference into ip_getmoptions() rather than just the
inp->inp_moptions pointer, so that ip_getmoptions() can perform
necessary locking when doing non-atomic reads.
Lock the inpcb by default to copy any data to local variables, then
unlock before performing sooptcopyout().
MFC after: 2 weeks
-rw-r--r-- | sys/netinet/ip_output.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 2e0a535..5baccf8 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -97,8 +97,7 @@ static struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *); static struct ifnet *ip_multicast_if(struct in_addr *, int *); static void ip_mloopback (struct ifnet *, struct mbuf *, struct sockaddr_in *, int); -static int ip_getmoptions - (struct sockopt *, struct ip_moptions *); +static int ip_getmoptions(struct inpcb *, struct sockopt *); static int ip_pcbopts(struct inpcb *, int, struct mbuf *); static int ip_setmoptions(struct inpcb *, struct sockopt *); @@ -1392,7 +1391,7 @@ ip_ctloutput(so, sopt) case IP_MULTICAST_LOOP: case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: - error = ip_getmoptions(sopt, inp->inp_moptions); + error = ip_getmoptions(inp, sopt); break; #if defined(IPSEC) || defined(FAST_IPSEC) @@ -1863,15 +1862,17 @@ ip_setmoptions(struct inpcb *inp, struct sockopt *sopt) * Return the IP multicast options in response to user getsockopt(). */ static int -ip_getmoptions(sopt, imo) - struct sockopt *sopt; - register struct ip_moptions *imo; +ip_getmoptions(struct inpcb *inp, struct sockopt *sopt) { + struct ip_moptions *imo; struct in_addr addr; struct in_ifaddr *ia; int error, optval; u_char coptval; + INP_LOCK(inp); + imo = inp->inp_moptions; + error = 0; switch (sopt->sopt_name) { case IP_MULTICAST_VIF: @@ -1879,6 +1880,7 @@ ip_getmoptions(sopt, imo) optval = imo->imo_multicast_vif; else optval = -1; + INP_UNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; @@ -1893,6 +1895,7 @@ ip_getmoptions(sopt, imo) addr.s_addr = (ia == NULL) ? INADDR_ANY : IA_SIN(ia)->sin_addr.s_addr; } + INP_UNLOCK(inp); error = sooptcopyout(sopt, &addr, sizeof addr); break; @@ -1901,6 +1904,7 @@ ip_getmoptions(sopt, imo) optval = coptval = IP_DEFAULT_MULTICAST_TTL; else optval = coptval = imo->imo_multicast_ttl; + INP_UNLOCK(inp); if (sopt->sopt_valsize == 1) error = sooptcopyout(sopt, &coptval, 1); else @@ -1912,6 +1916,7 @@ ip_getmoptions(sopt, imo) optval = coptval = IP_DEFAULT_MULTICAST_LOOP; else optval = coptval = imo->imo_multicast_loop; + INP_UNLOCK(inp); if (sopt->sopt_valsize == 1) error = sooptcopyout(sopt, &coptval, 1); else @@ -1919,9 +1924,12 @@ ip_getmoptions(sopt, imo) break; default: + INP_UNLOCK(inp); error = ENOPROTOOPT; break; } + INP_UNLOCK_ASSERT(inp); + return (error); } |