Index: sys/netinet/ip_output.c =================================================================== --- sys/netinet/ip_output.c +++ sys/netinet/ip_output.c @@ -1076,17 +1076,23 @@ switch (sopt->sopt_name) { case IP_TOS: + INP_WLOCK(inp); inp->inp_ip_tos = optval; + INP_WUNLOCK(inp); break; case IP_TTL: + INP_WLOCK(inp); inp->inp_ip_ttl = optval; + INP_WUNLOCK(inp); break; case IP_MINTTL: - if (optval >= 0 && optval <= MAXTTL) + if (optval >= 0 && optval <= MAXTTL) { + INP_WLOCK(inp); inp->inp_ip_minttl = optval; - else + INP_WUNLOCK(inp); + } else error = EINVAL; break; @@ -1099,12 +1105,15 @@ INP_WUNLOCK(inp); \ } while (0) -#define OPTSET2(bit, val) do { \ - INP_WLOCK(inp); \ +#define OPTSET2_N(bit, val) do { \ if (val) \ inp->inp_flags2 |= bit; \ else \ inp->inp_flags2 &= ~bit; \ +} while (0) +#define OPTSET2(bit, val) do { \ + INP_WLOCK(inp); \ + OPTSET2_N(bit, val); \ INP_WUNLOCK(inp); \ } while (0) @@ -1154,8 +1163,10 @@ case IP_RSS_LISTEN_BUCKET: if ((optval >= 0) && (optval < rss_getnumbuckets())) { + INP_WLOCK(inp); inp->inp_rss_listen_bucket = optval; - OPTSET2(INP_RSS_BUCKET_SET, 1); + OPTSET2_N(INP_RSS_BUCKET_SET, 1); + INP_WUNLOCK(inp); } else { error = EINVAL; } @@ -1226,7 +1237,9 @@ #if defined(IPSEC) || defined(IPSEC_SUPPORT) case IP_IPSEC_POLICY: if (IPSEC_ENABLED(ipv4)) { + INP_WLOCK(inp); error = IPSEC_PCBCTL(ipv4, inp, sopt); + INP_WUNLOCK(inp); break; } /* FALLTHROUGH */ @@ -1242,6 +1255,7 @@ switch (sopt->sopt_name) { case IP_OPTIONS: case IP_RETOPTS: + INP_WLOCK(inp); if (inp->inp_options) error = sooptcopyout(sopt, mtod(inp->inp_options, @@ -1249,6 +1263,7 @@ inp->inp_options->m_len); else sopt->sopt_valsize = 0; + INP_WUNLOCK(inp); break; case IP_TOS: @@ -1273,6 +1288,7 @@ case IP_RSSBUCKETID: case IP_RECVRSSBUCKETID: #endif + INP_WLOCK(inp); switch (sopt->sopt_name) { case IP_TOS: @@ -1362,6 +1378,7 @@ optval = OPTBIT2(INP_BINDMULTI); break; } + INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; @@ -1380,7 +1397,9 @@ #if defined(IPSEC) || defined(IPSEC_SUPPORT) case IP_IPSEC_POLICY: if (IPSEC_ENABLED(ipv4)) { + INP_WLOCK(inp); error = IPSEC_PCBCTL(ipv4, inp, sopt); + INP_WUNLOCK(inp); break; } /* FALLTHROUGH */ Index: sys/netinet/raw_ip.c =================================================================== --- sys/netinet/raw_ip.c +++ sys/netinet/raw_ip.c @@ -569,7 +569,9 @@ if (sopt->sopt_level != IPPROTO_IP) { if ((sopt->sopt_level == SOL_SOCKET) && (sopt->sopt_name == SO_SETFIB)) { + INP_WLOCK(inp); inp->inp_inc.inc_fibnum = so->so_fibnum; + INP_WUNLOCK(inp); return (0); } return (EINVAL); @@ -580,7 +582,9 @@ case SOPT_GET: switch (sopt->sopt_name) { case IP_HDRINCL: + INP_WLOCK(inp); optval = inp->inp_flags & INP_HDRINCL; + INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; @@ -637,10 +641,12 @@ sizeof optval); if (error) break; + INP_WLOCK(inp); if (optval) inp->inp_flags |= INP_HDRINCL; else inp->inp_flags &= ~INP_HDRINCL; + INP_WUNLOCK(inp); break; case IP_FW3: /* generic ipfw v.3 functions */ Index: sys/netinet6/ip6_output.c =================================================================== --- sys/netinet6/ip6_output.c +++ sys/netinet6/ip6_output.c @@ -1496,8 +1496,10 @@ error = soopt_mcopyin(sopt, m); /* XXX */ if (error != 0) break; + INP_WLOCK(in6p); error = ip6_pcbopts(&in6p->in6p_outputopts, m, so, sopt); + INP_WUNLOCK(in6p); m_freem(m); /* XXX */ break; } @@ -1567,19 +1569,25 @@ error = EINVAL; else { /* -1 = kernel default */ + INP_WLOCK(in6p); in6p->in6p_hops = optval; if ((in6p->inp_vflag & INP_IPV4) != 0) in6p->inp_ip_ttl = optval; + INP_WUNLOCK(in6p); } break; -#define OPTSET(bit) \ +#define OPTSET_N(bit) \ do { \ - INP_WLOCK(in6p); \ if (optval) \ in6p->inp_flags |= (bit); \ else \ in6p->inp_flags &= ~(bit); \ +} while (/*CONSTCOND*/ 0) +#define OPTSET(bit) \ +do { \ + INP_WLOCK(in6p); \ + OPTSET_N(bit); \ INP_WUNLOCK(in6p); \ } while (/*CONSTCOND*/ 0) #define OPTSET2292(bit) \ @@ -1594,23 +1602,34 @@ } while (/*CONSTCOND*/ 0) #define OPTBIT(bit) (in6p->inp_flags & (bit) ? 1 : 0) -#define OPTSET2(bit, val) do { \ - INP_WLOCK(in6p); \ +#define OPTSET2_N(bit, val) do { \ if (val) \ in6p->inp_flags2 |= bit; \ else \ in6p->inp_flags2 &= ~bit; \ +} while (0) +#define OPTSET2(bit, val) do { \ + INP_WLOCK(in6p); \ + OPTSET2_N(bit, val); \ INP_WUNLOCK(in6p); \ } while (0) #define OPTBIT2(bit) (in6p->inp_flags2 & (bit) ? 1 : 0) +#define OPTSET2292_EXCLUSIVE(bit) \ +do { \ + INP_WLOCK(in6p); \ + if (OPTBIT(IN6P_RFC2292)) { \ + error = EINVAL; \ + } else { \ + if (optval) \ + in6p->inp_flags |= (bit); \ + else \ + in6p->inp_flags &= ~(bit); \ + } \ + INP_WUNLOCK(in6p); \ +} while (/*CONSTCOND*/ 0) case IPV6_RECVPKTINFO: - /* cannot mix with RFC2292 */ - if (OPTBIT(IN6P_RFC2292)) { - error = EINVAL; - break; - } - OPTSET(IN6P_PKTINFO); + OPTSET2292_EXCLUSIVE(IN6P_PKTINFO); break; case IPV6_HOPLIMIT: @@ -1622,57 +1641,34 @@ error = EINVAL; break; } + INP_WLOCK(in6p); optp = &in6p->in6p_outputopts; error = ip6_pcbopt(IPV6_HOPLIMIT, (u_char *)&optval, sizeof(optval), optp, (td != NULL) ? td->td_ucred : NULL, uproto); + INP_WUNLOCK(in6p); break; } case IPV6_RECVHOPLIMIT: - /* cannot mix with RFC2292 */ - if (OPTBIT(IN6P_RFC2292)) { - error = EINVAL; - break; - } - OPTSET(IN6P_HOPLIMIT); + OPTSET2292_EXCLUSIVE(IN6P_HOPLIMIT); break; case IPV6_RECVHOPOPTS: - /* cannot mix with RFC2292 */ - if (OPTBIT(IN6P_RFC2292)) { - error = EINVAL; - break; - } - OPTSET(IN6P_HOPOPTS); + OPTSET2292_EXCLUSIVE(IN6P_HOPOPTS); break; case IPV6_RECVDSTOPTS: - /* cannot mix with RFC2292 */ - if (OPTBIT(IN6P_RFC2292)) { - error = EINVAL; - break; - } - OPTSET(IN6P_DSTOPTS); + OPTSET2292_EXCLUSIVE(IN6P_DSTOPTS); break; case IPV6_RECVRTHDRDSTOPTS: - /* cannot mix with RFC2292 */ - if (OPTBIT(IN6P_RFC2292)) { - error = EINVAL; - break; - } - OPTSET(IN6P_RTHDRDSTOPTS); + OPTSET2292_EXCLUSIVE(IN6P_RTHDRDSTOPTS); break; case IPV6_RECVRTHDR: - /* cannot mix with RFC2292 */ - if (OPTBIT(IN6P_RFC2292)) { - error = EINVAL; - break; - } - OPTSET(IN6P_RTHDR); + OPTSET2292_EXCLUSIVE(IN6P_RTHDR); break; case IPV6_RECVPATHMTU: @@ -1702,24 +1698,24 @@ * available only prior to bind(2). * see ipng mailing list, Jun 22 2001. */ + INP_WLOCK(in6p); if (in6p->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { error = EINVAL; + INP_WUNLOCK(in6p); break; } - OPTSET(IN6P_IPV6_V6ONLY); + OPTSET_N(IN6P_IPV6_V6ONLY); + /* optclear vflag */ if (optval) in6p->inp_vflag &= ~INP_IPV4; else in6p->inp_vflag |= INP_IPV4; + INP_WUNLOCK(in6p); break; case IPV6_RECVTCLASS: /* cannot mix with RFC2292 XXX */ - if (OPTBIT(IN6P_RFC2292)) { - error = EINVAL; - break; - } - OPTSET(IN6P_TCLASS); + OPTSET2292_EXCLUSIVE(IN6P_TCLASS); break; case IPV6_AUTOFLOWLABEL: OPTSET(IN6P_AUTOFLOWLABEL); @@ -1739,8 +1735,10 @@ case IPV6_RSS_LISTEN_BUCKET: if ((optval >= 0) && (optval < rss_getnumbuckets())) { + INP_WLOCK(in6p); in6p->inp_rss_listen_bucket = optval; - OPTSET2(INP_RSS_BUCKET_SET, 1); + OPTSET2_N(INP_RSS_BUCKET_SET, 1); + INP_WUNLOCK(in6p); } else { error = EINVAL; } @@ -1763,11 +1761,13 @@ break; { struct ip6_pktopts **optp; + INP_WLOCK(in6p); optp = &in6p->in6p_outputopts; error = ip6_pcbopt(optname, (u_char *)&optval, sizeof(optval), optp, (td != NULL) ? td->td_ucred : NULL, uproto); + INP_WUNLOCK(in6p); break; } @@ -1832,12 +1832,6 @@ int optlen; struct ip6_pktopts **optp; - /* cannot mix with RFC2292 */ - if (OPTBIT(IN6P_RFC2292)) { - error = EINVAL; - break; - } - /* * We only ensure valsize is not too large * here. Further validation will be done @@ -1847,12 +1841,21 @@ sizeof(optbuf_storage), 0); if (error) break; + + INP_WLOCK(in6p); + /* cannot mix with RFC2292 */ + if (OPTBIT(IN6P_RFC2292)) { + error = EINVAL; + INP_WUNLOCK(in6p); + break; + } optlen = sopt->sopt_valsize; optbuf = optbuf_storage; optp = &in6p->in6p_outputopts; error = ip6_pcbopt(optname, optbuf, optlen, optp, (td != NULL) ? td->td_ucred : NULL, uproto); + INP_WUNLOCK(in6p); break; } #undef OPTSET @@ -1905,7 +1908,9 @@ #if defined(IPSEC) || defined(IPSEC_SUPPORT) case IPV6_IPSEC_POLICY: if (IPSEC_ENABLED(ipv6)) { + INP_WLOCK(in6p); error = IPSEC_PCBCTL(ipv6, in6p, sopt); + INP_WUNLOCK(in6p); break; } /* FALLTHROUGH */ @@ -1958,6 +1963,7 @@ case IPV6_RECVRSSBUCKETID: #endif case IPV6_BINDMULTI: + INP_WLOCK(in6p); switch (optname) { case IPV6_RECVHOPOPTS: @@ -2057,6 +2063,7 @@ break; } + INP_WUNLOCK(in6p); if (error) break; error = sooptcopyout(sopt, &optval, @@ -2067,6 +2074,7 @@ { u_long pmtu = 0; struct ip6_mtuinfo mtuinfo; + struct in6_addr addr; if (!(so->so_state & SS_ISCONNECTED)) return (ENOTCONN); @@ -2074,9 +2082,15 @@ * XXX: we dot not consider the case of source * routing, or optional information to specify * the outgoing interface. + * Copy faddr out of in6p to avoid holding lock + * on inp during route lookup. */ + INP_WLOCK(in6p); + bzero(&addr, sizeof(addr)); + bcopy(&in6p->in6p_faddr, &addr, sizeof(addr)); + INP_WUNLOCK(in6p); error = ip6_getpmtu_ctl(so->so_fibnum, - &in6p->in6p_faddr, &pmtu); + &addr, &pmtu); if (error) break; if (pmtu > IPV6_MAXPACKET) @@ -2096,6 +2110,7 @@ case IPV6_2292HOPOPTS: case IPV6_2292RTHDR: case IPV6_2292DSTOPTS: + INP_WLOCK(in6p); switch (optname) { case IPV6_2292PKTINFO: optval = OPTBIT(IN6P_PKTINFO); @@ -2113,6 +2128,7 @@ optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); break; } + INP_WUNLOCK(in6p); error = sooptcopyout(sopt, &optval, sizeof optval); break; @@ -2126,8 +2142,10 @@ case IPV6_DONTFRAG: case IPV6_USE_MIN_MTU: case IPV6_PREFER_TEMPADDR: + INP_WLOCK(in6p); error = ip6_getpcbopt(in6p->in6p_outputopts, optname, sopt); + INP_WUNLOCK(in6p); break; case IPV6_MULTICAST_IF: @@ -2140,7 +2158,9 @@ #if defined(IPSEC) || defined(IPSEC_SUPPORT) case IPV6_IPSEC_POLICY: if (IPSEC_ENABLED(ipv6)) { + INP_WLOCK(in6p); error = IPSEC_PCBCTL(ipv6, in6p, sopt); + INP_WUNLOCK(in6p); break; } /* FALLTHROUGH */ @@ -2199,15 +2219,21 @@ IPPROTO_ICMPV6) { if (optval != icmp6off) error = EINVAL; - } else + } else { + INP_WLOCK(in6p); in6p->in6p_cksum = optval; + INP_WUNLOCK(in6p); + } break; case SOPT_GET: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) optval = icmp6off; - else + else { + INP_WLOCK(in6p); optval = in6p->in6p_cksum; + INP_WUNLOCK(in6p); + } error = sooptcopyout(sopt, &optval, sizeof(optval)); break; @@ -2238,6 +2264,8 @@ int error = 0; struct thread *td = sopt->sopt_td; + INP_WLOCK_ASSERT(sotoinpcb(so)); + /* turn off any old options. */ if (opt) { #ifdef DIAGNOSTIC @@ -3082,6 +3110,8 @@ { int len; + INP_WLOCK_ASSERT(in6p); + if (!in6p->in6p_outputopts) return 0;