diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2019-09-24 11:05:03 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2019-11-13 10:47:04 +0100 |
commit | a5ddb0ea69f21c16b7697a935d7a0c16bb3cffcf (patch) | |
tree | db091fb0f7d091804482156c9f3f55879ac93d5b /freebsd/sys/netinet6/ip6_output.c | |
parent | test/syscalls01: Fix sporadic test failures (diff) | |
download | rtems-libbsd-a5ddb0ea69f21c16b7697a935d7a0c16bb3cffcf.tar.bz2 |
Update to FreeBSD head 2019-09-24
Git mirror commit 6b0307a0a5184339393f555d5d424190d8a8277a.
Diffstat (limited to '')
-rw-r--r-- | freebsd/sys/netinet6/ip6_output.c | 488 |
1 files changed, 304 insertions, 184 deletions
diff --git a/freebsd/sys/netinet6/ip6_output.c b/freebsd/sys/netinet6/ip6_output.c index 0851bef8..483f17f0 100644 --- a/freebsd/sys/netinet6/ip6_output.c +++ b/freebsd/sys/netinet6/ip6_output.c @@ -69,14 +69,16 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_inet6.h> -#include <rtems/bsd/local/opt_ratelimit.h> #include <rtems/bsd/local/opt_ipsec.h> -#include <rtems/bsd/local/opt_sctp.h> +#include <rtems/bsd/local/opt_kern_tls.h> +#include <rtems/bsd/local/opt_ratelimit.h> #include <rtems/bsd/local/opt_route.h> #include <rtems/bsd/local/opt_rss.h> +#include <rtems/bsd/local/opt_sctp.h> #include <sys/param.h> #include <sys/kernel.h> +#include <sys/ktls.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/errno.h> @@ -230,7 +232,20 @@ ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto, IP6STAT_INC(ip6s_odropped); return (ENOBUFS); } - m->m_flags = m0->m_flags & M_COPYFLAGS; + + /* + * Make sure the complete packet header gets copied + * from the originating mbuf to the newly created + * mbuf. This also ensures that existing firewall + * classification(s), VLAN tags and so on get copied + * to the resulting fragmented packet(s): + */ + if (m_dup_pkthdr(m, m0, M_NOWAIT) == 0) { + m_free(m); + IP6STAT_INC(ip6s_odropped); + return (ENOBUFS); + } + *mnext = m; mnext = &m->m_nextpkt; m->m_data += max_linkhdr; @@ -255,8 +270,6 @@ ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto, } m_cat(m, m_frgpart); m->m_pkthdr.len = fraglen + hlen + sizeof(*ip6f); - m->m_pkthdr.fibnum = m0->m_pkthdr.fibnum; - m->m_pkthdr.rcvif = NULL; ip6f->ip6f_reserved = 0; ip6f->ip6f_ident = id; ip6f->ip6f_nxt = nextproto; @@ -267,6 +280,83 @@ ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto, return (0); } +static int +ip6_output_send(struct inpcb *inp, struct ifnet *ifp, struct ifnet *origifp, + struct mbuf *m, struct sockaddr_in6 *dst, struct route_in6 *ro) +{ +#ifdef KERN_TLS + struct ktls_session *tls = NULL; +#endif + struct m_snd_tag *mst; + int error; + + MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0); + mst = NULL; + +#ifdef KERN_TLS + /* + * If this is an unencrypted TLS record, save a reference to + * the record. This local reference is used to call + * ktls_output_eagain after the mbuf has been freed (thus + * dropping the mbuf's reference) in if_output. + */ + if (m->m_next != NULL && mbuf_has_tls_session(m->m_next)) { + tls = ktls_hold(m->m_next->m_ext.ext_pgs->tls); + mst = tls->snd_tag; + + /* + * If a TLS session doesn't have a valid tag, it must + * have had an earlier ifp mismatch, so drop this + * packet. + */ + if (mst == NULL) { + error = EAGAIN; + goto done; + } + } +#endif +#ifdef RATELIMIT + if (inp != NULL && mst == NULL) { + if ((inp->inp_flags2 & INP_RATE_LIMIT_CHANGED) != 0 || + (inp->inp_snd_tag != NULL && + inp->inp_snd_tag->ifp != ifp)) + in_pcboutput_txrtlmt(inp, ifp, m); + + if (inp->inp_snd_tag != NULL) + mst = inp->inp_snd_tag; + } +#endif + if (mst != NULL) { + KASSERT(m->m_pkthdr.rcvif == NULL, + ("trying to add a send tag to a forwarded packet")); + if (mst->ifp != ifp) { + error = EAGAIN; + goto done; + } + + /* stamp send tag on mbuf */ + m->m_pkthdr.snd_tag = m_snd_tag_ref(mst); + m->m_pkthdr.csum_flags |= CSUM_SND_TAG; + } + + error = nd6_output_ifp(ifp, origifp, m, dst, (struct route *)ro); + +done: + /* Check for route change invalidating send tags. */ +#ifdef KERN_TLS + if (tls != NULL) { + if (error == EAGAIN) + error = ktls_output_eagain(inp, tls); + ktls_free(tls); + } +#endif +#ifdef RATELIMIT + if (error == EAGAIN) + in_pcboutput_eagain(inp); +#endif + return (error); +} + /* * IP6 output. The packet in mbuf chain m contains a skeletal IP6 * header (with pri, len, nxt, hlim, src, dst). @@ -324,6 +414,9 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, m->m_pkthdr.flowid = inp->inp_flowid; M_HASHTYPE_SET(m, inp->inp_flowtype); } +#ifdef NUMA + m->m_pkthdr.numa_domain = inp->inp_numa_domain; +#endif } #if defined(IPSEC) || defined(IPSEC_SUPPORT) @@ -573,52 +666,72 @@ again: counter_u64_add(rt->rt_pksent, 1); } - - /* - * The outgoing interface must be in the zone of source and - * destination addresses. - */ - origifp = ifp; - + /* Setup data structures for scope ID checks. */ src0 = ip6->ip6_src; - if (in6_setscope(&src0, origifp, &zone)) - goto badscope; bzero(&src_sa, sizeof(src_sa)); src_sa.sin6_family = AF_INET6; src_sa.sin6_len = sizeof(src_sa); src_sa.sin6_addr = ip6->ip6_src; - if (sa6_recoverscope(&src_sa) || zone != src_sa.sin6_scope_id) - goto badscope; dst0 = ip6->ip6_dst; - if (in6_setscope(&dst0, origifp, &zone)) - goto badscope; /* re-initialize to be sure */ bzero(&dst_sa, sizeof(dst_sa)); dst_sa.sin6_family = AF_INET6; dst_sa.sin6_len = sizeof(dst_sa); dst_sa.sin6_addr = ip6->ip6_dst; - if (sa6_recoverscope(&dst_sa) || zone != dst_sa.sin6_scope_id) { - goto badscope; - } - - /* We should use ia_ifp to support the case of - * sending packets to an address of our own. - */ - if (ia != NULL && ia->ia_ifp) - ifp = ia->ia_ifp; - /* scope check is done. */ - goto routefound; + /* Check for valid scope ID. */ + if (in6_setscope(&src0, ifp, &zone) == 0 && + sa6_recoverscope(&src_sa) == 0 && zone == src_sa.sin6_scope_id && + in6_setscope(&dst0, ifp, &zone) == 0 && + sa6_recoverscope(&dst_sa) == 0 && zone == dst_sa.sin6_scope_id) { + /* + * The outgoing interface is in the zone of the source + * and destination addresses. + * + * Because the loopback interface cannot receive + * packets with a different scope ID than its own, + * there is a trick is to pretend the outgoing packet + * was received by the real network interface, by + * setting "origifp" different from "ifp". This is + * only allowed when "ifp" is a loopback network + * interface. Refer to code in nd6_output_ifp() for + * more details. + */ + origifp = ifp; + + /* + * We should use ia_ifp to support the case of sending + * packets to an address of our own. + */ + if (ia != NULL && ia->ia_ifp) + ifp = ia->ia_ifp; + + } else if ((ifp->if_flags & IFF_LOOPBACK) == 0 || + sa6_recoverscope(&src_sa) != 0 || + sa6_recoverscope(&dst_sa) != 0 || + dst_sa.sin6_scope_id == 0 || + (src_sa.sin6_scope_id != 0 && + src_sa.sin6_scope_id != dst_sa.sin6_scope_id) || + (origifp = ifnet_byindex(dst_sa.sin6_scope_id)) == NULL) { + /* + * If the destination network interface is not a + * loopback interface, or the destination network + * address has no scope ID, or the source address has + * a scope ID set which is different from the + * destination address one, or there is no network + * interface representing this scope ID, the address + * pair is considered invalid. + */ + IP6STAT_INC(ip6s_badscope); + in6_ifstat_inc(ifp, ifs6_out_discard); + if (error == 0) + error = EHOSTUNREACH; /* XXX */ + goto bad; + } - badscope: - IP6STAT_INC(ip6s_badscope); - in6_ifstat_inc(origifp, ifs6_out_discard); - if (error == 0) - error = EHOSTUNREACH; /* XXX */ - goto bad; + /* All scope ID checks are successful. */ - routefound: if (rt && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { if (opt && opt->ip6po_nextroute.ro_rt) { /* @@ -774,16 +887,21 @@ again: } /* Jump over all PFIL processing if hooks are not active. */ - if (!PFIL_HOOKED(&V_inet6_pfil_hook)) + if (!PFIL_HOOKED_OUT(V_inet6_pfil_head)) goto passout; odst = ip6->ip6_dst; /* Run through list of hooks for output packets. */ - error = pfil_run_hooks(&V_inet6_pfil_hook, &m, ifp, PFIL_OUT, 0, inp); - if (error != 0 || m == NULL) + switch (pfil_run_hooks(V_inet6_pfil_head, &m, ifp, PFIL_OUT, inp)) { + case PFIL_PASS: + ip6 = mtod(m, struct ip6_hdr *); + break; + case PFIL_DROPPED: + error = EPERM; + /* FALLTHROUGH */ + case PFIL_CONSUMED: goto done; - /* adjust pointer */ - ip6 = mtod(m, struct ip6_hdr *); + } needfiblookup = 0; /* See if destination IP address was changed by packet filter. */ @@ -881,11 +999,30 @@ passout: */ if (sw_csum & CSUM_DELAY_DATA_IPV6) { sw_csum &= ~CSUM_DELAY_DATA_IPV6; + m = mb_unmapped_to_ext(m); + if (m == NULL) { + error = ENOBUFS; + IP6STAT_INC(ip6s_odropped); + goto bad; + } in6_delayed_cksum(m, plen, sizeof(struct ip6_hdr)); + } else if ((ifp->if_capenable & IFCAP_NOMAP) == 0) { + m = mb_unmapped_to_ext(m); + if (m == NULL) { + error = ENOBUFS; + IP6STAT_INC(ip6s_odropped); + goto bad; + } } #ifdef SCTP if (sw_csum & CSUM_SCTP_IPV6) { sw_csum &= ~CSUM_SCTP_IPV6; + m = mb_unmapped_to_ext(m); + if (m == NULL) { + error = ENOBUFS; + IP6STAT_INC(ip6s_odropped); + goto bad; + } sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); } #endif @@ -931,23 +1068,7 @@ passout: m->m_pkthdr.len); ifa_free(&ia6->ia_ifa); } -#ifdef RATELIMIT - if (inp != NULL) { - if (inp->inp_flags2 & INP_RATE_LIMIT_CHANGED) - in_pcboutput_txrtlmt(inp, ifp, m); - /* stamp send tag on mbuf */ - m->m_pkthdr.snd_tag = inp->inp_snd_tag; - } else { - m->m_pkthdr.snd_tag = NULL; - } -#endif - error = nd6_output_ifp(ifp, origifp, m, dst, - (struct route *)ro); -#ifdef RATELIMIT - /* check for route change */ - if (error == EAGAIN) - in_pcboutput_eagain(inp); -#endif + error = ip6_output_send(inp, ifp, origifp, m, dst, ro); goto done; } @@ -989,11 +1110,23 @@ passout: * XXX-BZ handle the hw offloading case. Need flags. */ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { + m = mb_unmapped_to_ext(m); + if (m == NULL) { + in6_ifstat_inc(ifp, ifs6_out_fragfail); + error = ENOBUFS; + goto bad; + } in6_delayed_cksum(m, plen, hlen); m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; } #ifdef SCTP if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { + m = mb_unmapped_to_ext(m); + if (m == NULL) { + in6_ifstat_inc(ifp, ifs6_out_fragfail); + error = ENOBUFS; + goto bad; + } sctp_delayed_cksum(m, hlen); m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; } @@ -1046,23 +1179,7 @@ sendorfree: counter_u64_add(ia->ia_ifa.ifa_obytes, m->m_pkthdr.len); } -#ifdef RATELIMIT - if (inp != NULL) { - if (inp->inp_flags2 & INP_RATE_LIMIT_CHANGED) - in_pcboutput_txrtlmt(inp, ifp, m); - /* stamp send tag on mbuf */ - m->m_pkthdr.snd_tag = inp->inp_snd_tag; - } else { - m->m_pkthdr.snd_tag = NULL; - } -#endif - error = nd6_output_ifp(ifp, origifp, m, dst, - (struct route *)ro); -#ifdef RATELIMIT - /* check for route change */ - if (error == EAGAIN) - in_pcboutput_eagain(inp); -#endif + error = ip6_output_send(inp, ifp, origifp, m, dst, ro); } else m_freem(m); } @@ -1390,7 +1507,7 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt) { int optdatalen, uproto; void *optdata; - struct inpcb *in6p = sotoinpcb(so); + struct inpcb *inp = sotoinpcb(so); int error, optval; int level, op, optname; int optlen; @@ -1425,43 +1542,43 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt) sopt->sopt_dir == SOPT_SET) { switch (sopt->sopt_name) { case SO_REUSEADDR: - INP_WLOCK(in6p); + INP_WLOCK(inp); if ((so->so_options & SO_REUSEADDR) != 0) - in6p->inp_flags2 |= INP_REUSEADDR; + inp->inp_flags2 |= INP_REUSEADDR; else - in6p->inp_flags2 &= ~INP_REUSEADDR; - INP_WUNLOCK(in6p); + inp->inp_flags2 &= ~INP_REUSEADDR; + INP_WUNLOCK(inp); error = 0; break; case SO_REUSEPORT: - INP_WLOCK(in6p); + INP_WLOCK(inp); if ((so->so_options & SO_REUSEPORT) != 0) - in6p->inp_flags2 |= INP_REUSEPORT; + inp->inp_flags2 |= INP_REUSEPORT; else - in6p->inp_flags2 &= ~INP_REUSEPORT; - INP_WUNLOCK(in6p); + inp->inp_flags2 &= ~INP_REUSEPORT; + INP_WUNLOCK(inp); error = 0; break; case SO_REUSEPORT_LB: - INP_WLOCK(in6p); + INP_WLOCK(inp); if ((so->so_options & SO_REUSEPORT_LB) != 0) - in6p->inp_flags2 |= INP_REUSEPORT_LB; + inp->inp_flags2 |= INP_REUSEPORT_LB; else - in6p->inp_flags2 &= ~INP_REUSEPORT_LB; - INP_WUNLOCK(in6p); + inp->inp_flags2 &= ~INP_REUSEPORT_LB; + INP_WUNLOCK(inp); error = 0; break; case SO_SETFIB: - INP_WLOCK(in6p); - in6p->inp_inc.inc_fibnum = so->so_fibnum; - INP_WUNLOCK(in6p); + INP_WLOCK(inp); + inp->inp_inc.inc_fibnum = so->so_fibnum; + INP_WUNLOCK(inp); error = 0; break; case SO_MAX_PACING_RATE: #ifdef RATELIMIT - INP_WLOCK(in6p); - in6p->inp_flags2 |= INP_RATE_LIMIT_CHANGED; - INP_WUNLOCK(in6p); + INP_WLOCK(inp); + inp->inp_flags2 |= INP_RATE_LIMIT_CHANGED; + INP_WUNLOCK(inp); error = 0; #else error = EOPNOTSUPP; @@ -1495,7 +1612,7 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt) error = soopt_mcopyin(sopt, m); /* XXX */ if (error != 0) break; - error = ip6_pcbopts(&in6p->in6p_outputopts, + error = ip6_pcbopts(&inp->in6p_outputopts, m, so, sopt); m_freem(m); /* XXX */ break; @@ -1566,57 +1683,57 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt) error = EINVAL; else { /* -1 = kernel default */ - in6p->in6p_hops = optval; - if ((in6p->inp_vflag & + inp->in6p_hops = optval; + if ((inp->inp_vflag & INP_IPV4) != 0) - in6p->inp_ip_ttl = optval; + inp->inp_ip_ttl = optval; } break; #define OPTSET(bit) \ do { \ - INP_WLOCK(in6p); \ + INP_WLOCK(inp); \ if (optval) \ - in6p->inp_flags |= (bit); \ + inp->inp_flags |= (bit); \ else \ - in6p->inp_flags &= ~(bit); \ - INP_WUNLOCK(in6p); \ + inp->inp_flags &= ~(bit); \ + INP_WUNLOCK(inp); \ } while (/*CONSTCOND*/ 0) #define OPTSET2292(bit) \ do { \ - INP_WLOCK(in6p); \ - in6p->inp_flags |= IN6P_RFC2292; \ + INP_WLOCK(inp); \ + inp->inp_flags |= IN6P_RFC2292; \ if (optval) \ - in6p->inp_flags |= (bit); \ + inp->inp_flags |= (bit); \ else \ - in6p->inp_flags &= ~(bit); \ - INP_WUNLOCK(in6p); \ + inp->inp_flags &= ~(bit); \ + INP_WUNLOCK(inp); \ } while (/*CONSTCOND*/ 0) -#define OPTBIT(bit) (in6p->inp_flags & (bit) ? 1 : 0) +#define OPTBIT(bit) (inp->inp_flags & (bit) ? 1 : 0) #define OPTSET2_N(bit, val) do { \ if (val) \ - in6p->inp_flags2 |= bit; \ + inp->inp_flags2 |= bit; \ else \ - in6p->inp_flags2 &= ~bit; \ + inp->inp_flags2 &= ~bit; \ } while (0) #define OPTSET2(bit, val) do { \ - INP_WLOCK(in6p); \ + INP_WLOCK(inp); \ OPTSET2_N(bit, val); \ - INP_WUNLOCK(in6p); \ + INP_WUNLOCK(inp); \ } while (0) -#define OPTBIT2(bit) (in6p->inp_flags2 & (bit) ? 1 : 0) +#define OPTBIT2(bit) (inp->inp_flags2 & (bit) ? 1 : 0) #define OPTSET2292_EXCLUSIVE(bit) \ do { \ - INP_WLOCK(in6p); \ + INP_WLOCK(inp); \ if (OPTBIT(IN6P_RFC2292)) { \ error = EINVAL; \ } else { \ if (optval) \ - in6p->inp_flags |= (bit); \ + inp->inp_flags |= (bit); \ else \ - in6p->inp_flags &= ~(bit); \ + inp->inp_flags &= ~(bit); \ } \ - INP_WUNLOCK(in6p); \ + INP_WUNLOCK(inp); \ } while (/*CONSTCOND*/ 0) case IPV6_RECVPKTINFO: @@ -1632,17 +1749,17 @@ do { \ error = EINVAL; break; } - INP_WLOCK(in6p); - if (in6p->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { - INP_WUNLOCK(in6p); + INP_WLOCK(inp); + if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { + INP_WUNLOCK(inp); return (ECONNRESET); } - optp = &in6p->in6p_outputopts; + optp = &inp->in6p_outputopts; error = ip6_pcbopt(IPV6_HOPLIMIT, (u_char *)&optval, sizeof(optval), optp, (td != NULL) ? td->td_ucred : NULL, uproto); - INP_WUNLOCK(in6p); + INP_WUNLOCK(inp); break; } @@ -1693,16 +1810,16 @@ do { \ * available only prior to bind(2). * see ipng mailing list, Jun 22 2001. */ - if (in6p->inp_lport || - !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { + if (inp->inp_lport || + !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { error = EINVAL; break; } OPTSET(IN6P_IPV6_V6ONLY); if (optval) - in6p->inp_vflag &= ~INP_IPV4; + inp->inp_vflag &= ~INP_IPV4; else - in6p->inp_vflag |= INP_IPV4; + inp->inp_vflag |= INP_IPV4; break; case IPV6_RECVTCLASS: /* cannot mix with RFC2292 XXX */ @@ -1726,10 +1843,10 @@ do { \ case IPV6_RSS_LISTEN_BUCKET: if ((optval >= 0) && (optval < rss_getnumbuckets())) { - INP_WLOCK(in6p); - in6p->inp_rss_listen_bucket = optval; + INP_WLOCK(inp); + inp->inp_rss_listen_bucket = optval; OPTSET2_N(INP_RSS_BUCKET_SET, 1); - INP_WUNLOCK(in6p); + INP_WUNLOCK(inp); } else { error = EINVAL; } @@ -1752,17 +1869,17 @@ do { \ break; { struct ip6_pktopts **optp; - INP_WLOCK(in6p); - if (in6p->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { - INP_WUNLOCK(in6p); + INP_WLOCK(inp); + if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { + INP_WUNLOCK(inp); return (ECONNRESET); } - optp = &in6p->in6p_outputopts; + optp = &inp->in6p_outputopts; error = ip6_pcbopt(optname, (u_char *)&optval, sizeof(optval), optp, (td != NULL) ? td->td_ucred : NULL, uproto); - INP_WUNLOCK(in6p); + INP_WUNLOCK(inp); break; } @@ -1844,16 +1961,16 @@ do { \ break; optlen = sopt->sopt_valsize; optbuf = optbuf_storage; - INP_WLOCK(in6p); - if (in6p->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { - INP_WUNLOCK(in6p); + INP_WLOCK(inp); + if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { + INP_WUNLOCK(inp); return (ECONNRESET); } - optp = &in6p->in6p_outputopts; + optp = &inp->in6p_outputopts; error = ip6_pcbopt(optname, optbuf, optlen, optp, (td != NULL) ? td->td_ucred : NULL, uproto); - INP_WUNLOCK(in6p); + INP_WUNLOCK(inp); break; } #undef OPTSET @@ -1870,7 +1987,7 @@ do { \ case MCAST_LEAVE_GROUP: case MCAST_JOIN_SOURCE_GROUP: case MCAST_LEAVE_SOURCE_GROUP: - error = ip6_setmoptions(in6p, sopt); + error = ip6_setmoptions(inp, sopt); break; case IPV6_PORTRANGE: @@ -1879,34 +1996,34 @@ do { \ if (error) break; - INP_WLOCK(in6p); + INP_WLOCK(inp); switch (optval) { case IPV6_PORTRANGE_DEFAULT: - in6p->inp_flags &= ~(INP_LOWPORT); - in6p->inp_flags &= ~(INP_HIGHPORT); + inp->inp_flags &= ~(INP_LOWPORT); + inp->inp_flags &= ~(INP_HIGHPORT); break; case IPV6_PORTRANGE_HIGH: - in6p->inp_flags &= ~(INP_LOWPORT); - in6p->inp_flags |= INP_HIGHPORT; + inp->inp_flags &= ~(INP_LOWPORT); + inp->inp_flags |= INP_HIGHPORT; break; case IPV6_PORTRANGE_LOW: - in6p->inp_flags &= ~(INP_HIGHPORT); - in6p->inp_flags |= INP_LOWPORT; + inp->inp_flags &= ~(INP_HIGHPORT); + inp->inp_flags |= INP_LOWPORT; break; default: error = EINVAL; break; } - INP_WUNLOCK(in6p); + INP_WUNLOCK(inp); break; #if defined(IPSEC) || defined(IPSEC_SUPPORT) case IPV6_IPSEC_POLICY: if (IPSEC_ENABLED(ipv6)) { - error = IPSEC_PCBCTL(ipv6, in6p, sopt); + error = IPSEC_PCBCTL(ipv6, inp, sopt); break; } /* FALLTHROUGH */ @@ -1974,7 +2091,7 @@ do { \ break; case IPV6_UNICAST_HOPS: - optval = in6p->in6p_hops; + optval = inp->in6p_hops; break; case IPV6_RECVPKTINFO: @@ -2000,7 +2117,7 @@ do { \ case IPV6_PORTRANGE: { int flags; - flags = in6p->inp_flags; + flags = inp->inp_flags; if (flags & INP_HIGHPORT) optval = IPV6_PORTRANGE_HIGH; else if (flags & INP_LOWPORT) @@ -2026,11 +2143,11 @@ do { \ break; case IPV6_FLOWID: - optval = in6p->inp_flowid; + optval = inp->inp_flowid; break; case IPV6_FLOWTYPE: - optval = in6p->inp_flowtype; + optval = inp->inp_flowtype; break; case IPV6_RECVFLOWID: @@ -2039,8 +2156,8 @@ do { \ #ifdef RSS case IPV6_RSSBUCKETID: retval = - rss_hash2bucket(in6p->inp_flowid, - in6p->inp_flowtype, + rss_hash2bucket(inp->inp_flowid, + inp->inp_flowtype, &rss_bucket); if (retval == 0) optval = rss_bucket; @@ -2076,12 +2193,12 @@ do { \ * 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 + * Copy faddr out of inp to avoid holding lock * on inp during route lookup. */ - INP_RLOCK(in6p); - bcopy(&in6p->in6p_faddr, &addr, sizeof(addr)); - INP_RUNLOCK(in6p); + INP_RLOCK(inp); + bcopy(&inp->in6p_faddr, &addr, sizeof(addr)); + INP_RUNLOCK(inp); error = ip6_getpmtu_ctl(so->so_fibnum, &addr, &pmtu); if (error) @@ -2133,20 +2250,20 @@ do { \ case IPV6_DONTFRAG: case IPV6_USE_MIN_MTU: case IPV6_PREFER_TEMPADDR: - error = ip6_getpcbopt(in6p, optname, sopt); + error = ip6_getpcbopt(inp, optname, sopt); break; case IPV6_MULTICAST_IF: case IPV6_MULTICAST_HOPS: case IPV6_MULTICAST_LOOP: case IPV6_MSFILTER: - error = ip6_getmoptions(in6p, sopt); + error = ip6_getmoptions(inp, sopt); break; #if defined(IPSEC) || defined(IPSEC_SUPPORT) case IPV6_IPSEC_POLICY: if (IPSEC_ENABLED(ipv6)) { - error = IPSEC_PCBCTL(ipv6, in6p, sopt); + error = IPSEC_PCBCTL(ipv6, inp, sopt); break; } /* FALLTHROUGH */ @@ -2166,7 +2283,7 @@ ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt) { int error = 0, optval, optlen; const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum); - struct inpcb *in6p = sotoinpcb(so); + struct inpcb *inp = sotoinpcb(so); int level, op, optname; level = sopt->sopt_level; @@ -2198,22 +2315,25 @@ ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt) sizeof(optval)); if (error) break; - if ((optval % 2) != 0) { - /* the API assumes even offset values */ + if (optval < -1 || (optval % 2) != 0) { + /* + * The API assumes non-negative even offset + * values or -1 as a special value. + */ error = EINVAL; } else if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { if (optval != icmp6off) error = EINVAL; } else - in6p->in6p_cksum = optval; + inp->in6p_cksum = optval; break; case SOPT_GET: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) optval = icmp6off; else - optval = in6p->in6p_cksum; + optval = inp->in6p_cksum; error = sooptcopyout(sopt, &optval, sizeof(optval)); break; @@ -2312,16 +2432,16 @@ ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt, #define GET_PKTOPT_VAR(field, lenexpr) do { \ if (pktopt && pktopt->field) { \ - INP_RUNLOCK(in6p); \ + INP_RUNLOCK(inp); \ optdata = malloc(sopt->sopt_valsize, M_TEMP, M_WAITOK); \ malloc_optdata = true; \ - INP_RLOCK(in6p); \ - if (in6p->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { \ - INP_RUNLOCK(in6p); \ + INP_RLOCK(inp); \ + if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { \ + INP_RUNLOCK(inp); \ free(optdata, M_TEMP); \ return (ECONNRESET); \ } \ - pktopt = in6p->in6p_outputopts; \ + pktopt = inp->in6p_outputopts; \ if (pktopt && pktopt->field) { \ optdatalen = min(lenexpr, sopt->sopt_valsize); \ bcopy(&pktopt->field, optdata, optdatalen); \ @@ -2340,7 +2460,7 @@ ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt, pktopt->field->sa_len) static int -ip6_getpcbopt(struct inpcb *in6p, int optname, struct sockopt *sopt) +ip6_getpcbopt(struct inpcb *inp, int optname, struct sockopt *sopt) { void *optdata = NULL; bool malloc_optdata = false; @@ -2352,8 +2472,8 @@ ip6_getpcbopt(struct inpcb *in6p, int optname, struct sockopt *sopt) int defpreftemp = IP6PO_TEMPADDR_SYSTEM; struct ip6_pktopts *pktopt; - INP_RLOCK(in6p); - pktopt = in6p->in6p_outputopts; + INP_RLOCK(inp); + pktopt = inp->in6p_outputopts; switch (optname) { case IPV6_PKTINFO: @@ -2413,10 +2533,10 @@ ip6_getpcbopt(struct inpcb *in6p, int optname, struct sockopt *sopt) #ifdef DIAGNOSTIC panic("ip6_getpcbopt: unexpected option\n"); #endif - INP_RUNLOCK(in6p); + INP_RUNLOCK(inp); return (ENOPROTOOPT); } - INP_RUNLOCK(in6p); + INP_RUNLOCK(inp); error = sooptcopyout(sopt, optdata, optdatalen); if (malloc_optdata) @@ -3098,23 +3218,23 @@ ip6_splithdr(struct mbuf *m, struct ip6_exthdrs *exthdrs) * Compute IPv6 extension header length. */ int -ip6_optlen(struct inpcb *in6p) +ip6_optlen(struct inpcb *inp) { int len; - if (!in6p->in6p_outputopts) + if (!inp->in6p_outputopts) return 0; len = 0; #define elen(x) \ (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0) - len += elen(in6p->in6p_outputopts->ip6po_hbh); - if (in6p->in6p_outputopts->ip6po_rthdr) + len += elen(inp->in6p_outputopts->ip6po_hbh); + if (inp->in6p_outputopts->ip6po_rthdr) /* dest1 is valid with rthdr only */ - len += elen(in6p->in6p_outputopts->ip6po_dest1); - len += elen(in6p->in6p_outputopts->ip6po_rthdr); - len += elen(in6p->in6p_outputopts->ip6po_dest2); + len += elen(inp->in6p_outputopts->ip6po_dest1); + len += elen(inp->in6p_outputopts->ip6po_rthdr); + len += elen(inp->in6p_outputopts->ip6po_dest2); return len; #undef elen } |