diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-08-21 09:39:55 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-09-21 10:29:40 +0200 |
commit | 2df56dbd60bb5d925d2ce0ddbdefdbe6107ea783 (patch) | |
tree | bd7bad558534db4a1f400bc38a2c9aa7ea4f411e /freebsd/sys/netinet6 | |
parent | Update to FreeBSD head 2018-02-01 (diff) | |
download | rtems-libbsd-2df56dbd60bb5d925d2ce0ddbdefdbe6107ea783.tar.bz2 |
Update to FreeBSD head 2018-04-01
Git mirror commit 8dfb1ccc26d1cea7e2529303003ff61f9f1784c4.
Update #3472.
Diffstat (limited to 'freebsd/sys/netinet6')
-rw-r--r-- | freebsd/sys/netinet6/dest6.c | 2 | ||||
-rw-r--r-- | freebsd/sys/netinet6/frag6.c | 6 | ||||
-rw-r--r-- | freebsd/sys/netinet6/icmp6.c | 9 | ||||
-rw-r--r-- | freebsd/sys/netinet6/in6.c | 34 | ||||
-rw-r--r-- | freebsd/sys/netinet6/in6_ifattach.c | 1 | ||||
-rw-r--r-- | freebsd/sys/netinet6/in6_pcb.c | 74 | ||||
-rw-r--r-- | freebsd/sys/netinet6/ip6_fastfwd.c | 4 | ||||
-rw-r--r-- | freebsd/sys/netinet6/ip6_forward.c | 5 | ||||
-rw-r--r-- | freebsd/sys/netinet6/ip6_input.c | 62 | ||||
-rw-r--r-- | freebsd/sys/netinet6/ip6_mroute.c | 2 | ||||
-rw-r--r-- | freebsd/sys/netinet6/ip6_output.c | 174 | ||||
-rw-r--r-- | freebsd/sys/netinet6/ip6_var.h | 2 | ||||
-rw-r--r-- | freebsd/sys/netinet6/nd6.c | 5 | ||||
-rw-r--r-- | freebsd/sys/netinet6/nd6_nbr.c | 31 | ||||
-rw-r--r-- | freebsd/sys/netinet6/nd6_rtr.c | 5 | ||||
-rw-r--r-- | freebsd/sys/netinet6/raw_ip6.c | 6 | ||||
-rw-r--r-- | freebsd/sys/netinet6/udp6_usrreq.c | 2 |
17 files changed, 237 insertions, 187 deletions
diff --git a/freebsd/sys/netinet6/dest6.c b/freebsd/sys/netinet6/dest6.c index 1c9efc25..50a836ba 100644 --- a/freebsd/sys/netinet6/dest6.c +++ b/freebsd/sys/netinet6/dest6.c @@ -95,7 +95,7 @@ dest6_input(struct mbuf **mp, int *offp, int proto) opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest); /* search header for all options. */ - for (optlen = 0; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) { + for (; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) { if (*opt != IP6OPT_PAD1 && (dstoptlen < IP6OPT_MINLEN || *(opt + 1) + 2 > dstoptlen)) { IP6STAT_INC(ip6s_toosmall); diff --git a/freebsd/sys/netinet6/frag6.c b/freebsd/sys/netinet6/frag6.c index 5b405ebb..70103fe3 100644 --- a/freebsd/sys/netinet6/frag6.c +++ b/freebsd/sys/netinet6/frag6.c @@ -580,10 +580,8 @@ insert: /* * Store NXT to the original. */ - { - char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */ - *prvnxtp = nxt; - } + m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t), + (caddr_t)&nxt); frag6_remque(q6); V_frag6_nfrags -= q6->ip6q_nfrag; diff --git a/freebsd/sys/netinet6/icmp6.c b/freebsd/sys/netinet6/icmp6.c index 38f14461..77876599 100644 --- a/freebsd/sys/netinet6/icmp6.c +++ b/freebsd/sys/netinet6/icmp6.c @@ -596,7 +596,6 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) n->m_pkthdr.len = n0len + (noff - off); n->m_next = n0; } else { - nip6 = mtod(n, struct ip6_hdr *); IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off, sizeof(*nicmp6)); noff = off; @@ -2319,6 +2318,14 @@ icmp6_redirect_input(struct mbuf *m, int off) goto bad; } + /* + * Embed scope zone id into next hop address, since + * fib6_lookup_nh_basic() returns address without embedded + * scope zone id. + */ + if (in6_setscope(&nh6.nh_addr, m->m_pkthdr.rcvif, NULL)) + goto freeit; + if (IN6_ARE_ADDR_EQUAL(&src6, &nh6.nh_addr) == 0) { nd6log((LOG_ERR, "ICMP6 redirect rejected; " diff --git a/freebsd/sys/netinet6/in6.c b/freebsd/sys/netinet6/in6.c index 6fc29892..a5d84d85 100644 --- a/freebsd/sys/netinet6/in6.c +++ b/freebsd/sys/netinet6/in6.c @@ -114,6 +114,14 @@ __FBSDID("$FreeBSD$"); #include <netinet6/in6_fib.h> #include <netinet6/in6_pcb.h> +/* + * struct in6_ifreq and struct ifreq must be type punnable for common members + * of ifr_ifru to allow accessors to be shared. + */ +_Static_assert(offsetof(struct in6_ifreq, ifr_ifru) == + offsetof(struct ifreq, ifr_ifru), + "struct in6_ifreq and struct ifreq are not type punnable"); + VNET_DECLARE(int, icmp6_nodeinfo_oldmcprefix); #define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix) @@ -480,10 +488,6 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, error = EINVAL; goto out; } - /* - * XXX: should we check if ifa_dstaddr is NULL and return - * an error? - */ ifr->ifr_dstaddr = ia->ia_dstaddr; if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0) goto out; @@ -1975,8 +1979,6 @@ in6_if2idlen(struct ifnet *ifp) return (64); case IFT_FDDI: /* RFC2467 */ return (64); - case IFT_ISO88025: /* RFC2470 (IPv6 over Token Ring) */ - return (64); case IFT_PPP: /* RFC2472 */ return (64); case IFT_ARCNET: /* RFC2497 */ @@ -2152,6 +2154,25 @@ in6_lltable_rtcheck(struct ifnet *ifp, return 0; } +/* + * Called by the datapath to indicate that the entry was used. + */ +static void +in6_lltable_mark_used(struct llentry *lle) +{ + + LLE_REQ_LOCK(lle); + lle->r_skip_req = 0; + + /* + * Set the hit time so the callback function + * can determine the remaining time before + * transiting to the DELAY state. + */ + lle->lle_hittime = time_uptime; + LLE_REQ_UNLOCK(lle); +} + static inline uint32_t in6_lltable_hash_dst(const struct in6_addr *dst, uint32_t hsize) { @@ -2384,6 +2405,7 @@ in6_lltattach(struct ifnet *ifp) llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry; llt->llt_free_entry = in6_lltable_free_entry; llt->llt_match_prefix = in6_lltable_match_prefix; + llt->llt_mark_used = in6_lltable_mark_used; lltable_link(llt); return (llt); diff --git a/freebsd/sys/netinet6/in6_ifattach.c b/freebsd/sys/netinet6/in6_ifattach.c index 26a682ad..1ce489f5 100644 --- a/freebsd/sys/netinet6/in6_ifattach.c +++ b/freebsd/sys/netinet6/in6_ifattach.c @@ -281,7 +281,6 @@ found: case IFT_ETHER: case IFT_L2VLAN: case IFT_FDDI: - case IFT_ISO88025: case IFT_ATM: case IFT_IEEE1394: /* IEEE802/EUI64 cases - what others? */ diff --git a/freebsd/sys/netinet6/in6_pcb.c b/freebsd/sys/netinet6/in6_pcb.c index c9107260..a4bbd6a9 100644 --- a/freebsd/sys/netinet6/in6_pcb.c +++ b/freebsd/sys/netinet6/in6_pcb.c @@ -882,6 +882,7 @@ in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup, struct inpcbhead *head; struct inpcb *inp, *tmpinp; u_short fport = fport_arg, lport = lport_arg; + bool locked; /* * First look for an exact match. @@ -1040,18 +1041,32 @@ in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup, return (NULL); found: - in_pcbref(inp); - INP_GROUP_UNLOCK(pcbgroup); - if (lookupflags & INPLOOKUP_WLOCKPCB) { - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (NULL); - } else if (lookupflags & INPLOOKUP_RLOCKPCB) { - INP_RLOCK(inp); - if (in_pcbrele_rlocked(inp)) - return (NULL); - } else + if (lookupflags & INPLOOKUP_WLOCKPCB) + locked = INP_TRY_WLOCK(inp); + else if (lookupflags & INPLOOKUP_RLOCKPCB) + locked = INP_TRY_RLOCK(inp); + else panic("%s: locking buf", __func__); + if (!locked) + in_pcbref(inp); + INP_GROUP_UNLOCK(pcbgroup); + if (!locked) { + if (lookupflags & INPLOOKUP_WLOCKPCB) { + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (NULL); + } else { + INP_RLOCK(inp); + if (in_pcbrele_rlocked(inp)) + return (NULL); + } + } +#ifdef INVARIANTS + if (lookupflags & INPLOOKUP_WLOCKPCB) + INP_WLOCK_ASSERT(inp); + else + INP_RLOCK_ASSERT(inp); +#endif return (inp); } #endif /* PCBGROUP */ @@ -1177,23 +1192,38 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, struct ifnet *ifp) { struct inpcb *inp; + bool locked; INP_HASH_RLOCK(pcbinfo); inp = in6_pcblookup_hash_locked(pcbinfo, faddr, fport, laddr, lport, (lookupflags & ~(INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)), ifp); if (inp != NULL) { - in_pcbref(inp); - INP_HASH_RUNLOCK(pcbinfo); - if (lookupflags & INPLOOKUP_WLOCKPCB) { - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (NULL); - } else if (lookupflags & INPLOOKUP_RLOCKPCB) { - INP_RLOCK(inp); - if (in_pcbrele_rlocked(inp)) - return (NULL); - } else + if (lookupflags & INPLOOKUP_WLOCKPCB) + locked = INP_TRY_WLOCK(inp); + else if (lookupflags & INPLOOKUP_RLOCKPCB) + locked = INP_TRY_RLOCK(inp); + else panic("%s: locking bug", __func__); + if (!locked) + in_pcbref(inp); + INP_HASH_RUNLOCK(pcbinfo); + if (!locked) { + if (lookupflags & INPLOOKUP_WLOCKPCB) { + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (NULL); + } else { + INP_RLOCK(inp); + if (in_pcbrele_rlocked(inp)) + return (NULL); + } + } +#ifdef INVARIANTS + if (lookupflags & INPLOOKUP_WLOCKPCB) + INP_WLOCK_ASSERT(inp); + else + INP_RLOCK_ASSERT(inp); +#endif } else INP_HASH_RUNLOCK(pcbinfo); return (inp); diff --git a/freebsd/sys/netinet6/ip6_fastfwd.c b/freebsd/sys/netinet6/ip6_fastfwd.c index e11f612b..056f9315 100644 --- a/freebsd/sys/netinet6/ip6_fastfwd.c +++ b/freebsd/sys/netinet6/ip6_fastfwd.c @@ -159,7 +159,7 @@ ip6_tryforward(struct mbuf *m) */ if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto passin; - if (pfil_run_hooks(&V_inet6_pfil_hook, &m, rcvif, PFIL_IN, + if (pfil_run_hooks(&V_inet6_pfil_hook, &m, rcvif, PFIL_IN, 0, NULL) != 0 || m == NULL) goto dropin; /* @@ -203,7 +203,7 @@ passin: if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto passout; if (pfil_run_hooks(&V_inet6_pfil_hook, &m, nh.nh_ifp, PFIL_OUT, - NULL) != 0 || m == NULL) + PFIL_FWD, NULL) != 0 || m == NULL) goto dropout; /* diff --git a/freebsd/sys/netinet6/ip6_forward.c b/freebsd/sys/netinet6/ip6_forward.c index 3364dd05..80535efe 100644 --- a/freebsd/sys/netinet6/ip6_forward.c +++ b/freebsd/sys/netinet6/ip6_forward.c @@ -326,8 +326,9 @@ again2: goto pass; odst = ip6->ip6_dst; - /* Run through list of hooks for output packets. */ - error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL); + /* Run through list of hooks for forwarded packets. */ + error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, + PFIL_FWD, NULL); if (error != 0 || m == NULL) goto freecopy; /* consumed by filter */ ip6 = mtod(m, struct ip6_hdr *); diff --git a/freebsd/sys/netinet6/ip6_input.c b/freebsd/sys/netinet6/ip6_input.c index 78d941ae..7e1007e3 100644 --- a/freebsd/sys/netinet6/ip6_input.c +++ b/freebsd/sys/netinet6/ip6_input.c @@ -763,7 +763,7 @@ ip6_input(struct mbuf *m) odst = ip6->ip6_dst; if (pfil_run_hooks(&V_inet6_pfil_hook, &m, - m->m_pkthdr.rcvif, PFIL_IN, NULL)) + m->m_pkthdr.rcvif, PFIL_IN, 0, NULL)) return; if (m == NULL) /* consumed by filter */ return; @@ -1713,49 +1713,39 @@ ip6_pullexthdr(struct mbuf *m, size_t off, int nxt) /* * Get pointer to the previous header followed by the header * currently processed. - * XXX: This function supposes that - * M includes all headers, - * the next header field and the header length field of each header - * are valid, and - * the sum of each header length equals to OFF. - * Because of these assumptions, this function must be called very - * carefully. Moreover, it will not be used in the near future when - * we develop `neater' mechanism to process extension headers. */ -char * +int ip6_get_prevhdr(const struct mbuf *m, int off) { - struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct ip6_ext ip6e; + struct ip6_hdr *ip6; + int len, nlen, nxt; if (off == sizeof(struct ip6_hdr)) - return (&ip6->ip6_nxt); - else { - int len, nxt; - struct ip6_ext *ip6e = NULL; + return (offsetof(struct ip6_hdr, ip6_nxt)); + if (off < sizeof(struct ip6_hdr)) + panic("%s: off < sizeof(struct ip6_hdr)", __func__); - nxt = ip6->ip6_nxt; - len = sizeof(struct ip6_hdr); - while (len < off) { - ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len); - - switch (nxt) { - case IPPROTO_FRAGMENT: - len += sizeof(struct ip6_frag); - break; - case IPPROTO_AH: - len += (ip6e->ip6e_len + 2) << 2; - break; - default: - len += (ip6e->ip6e_len + 1) << 3; - break; - } - nxt = ip6e->ip6e_nxt; + ip6 = mtod(m, struct ip6_hdr *); + nxt = ip6->ip6_nxt; + len = sizeof(struct ip6_hdr); + nlen = 0; + while (len < off) { + m_copydata(m, len, sizeof(ip6e), (caddr_t)&ip6e); + switch (nxt) { + case IPPROTO_FRAGMENT: + nlen = sizeof(struct ip6_frag); + break; + case IPPROTO_AH: + nlen = (ip6e.ip6e_len + 2) << 2; + break; + default: + nlen = (ip6e.ip6e_len + 1) << 3; } - if (ip6e) - return (&ip6e->ip6e_nxt); - else - return NULL; + len += nlen; + nxt = ip6e.ip6e_nxt; } + return (len - nlen); } /* diff --git a/freebsd/sys/netinet6/ip6_mroute.c b/freebsd/sys/netinet6/ip6_mroute.c index 4959145d..a4a8cdf9 100644 --- a/freebsd/sys/netinet6/ip6_mroute.c +++ b/freebsd/sys/netinet6/ip6_mroute.c @@ -1859,7 +1859,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto) "of the inner packet", (eip6->ip6_vfc & IPV6_VERSION)); m_freem(m); - return (IPPROTO_NONE); + return (IPPROTO_DONE); } /* verify the inner packet is destined to a mcast group */ diff --git a/freebsd/sys/netinet6/ip6_output.c b/freebsd/sys/netinet6/ip6_output.c index 8dd71077..1841829a 100644 --- a/freebsd/sys/netinet6/ip6_output.c +++ b/freebsd/sys/netinet6/ip6_output.c @@ -137,7 +137,7 @@ static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **, struct ucred *, int); static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *, struct socket *, struct sockopt *); -static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *); +static int ip6_getpcbopt(struct inpcb *, int, struct sockopt *); static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, struct ucred *, int, int, int); @@ -787,7 +787,7 @@ again: odst = ip6->ip6_dst; /* Run through list of hooks for output packets. */ - error = pfil_run_hooks(&V_inet6_pfil_hook, &m, ifp, PFIL_OUT, inp); + error = pfil_run_hooks(&V_inet6_pfil_hook, &m, ifp, PFIL_OUT, 0, inp); if (error != 0 || m == NULL) goto done; /* adjust pointer */ @@ -1050,7 +1050,7 @@ sendorfree: m = m0->m_nextpkt; m0->m_nextpkt = 0; m_freem(m0); - for (m0 = m; m; m = m0) { + for (; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; if (error == 0) { @@ -1598,23 +1598,34 @@ do { \ } 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: @@ -1635,48 +1646,23 @@ do { \ } 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: @@ -1719,11 +1705,7 @@ do { \ 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); @@ -1743,8 +1725,10 @@ do { \ 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; } @@ -2071,6 +2055,7 @@ do { \ { u_long pmtu = 0; struct ip6_mtuinfo mtuinfo; + struct in6_addr addr; if (!(so->so_state & SS_ISCONNECTED)) return (ENOTCONN); @@ -2078,9 +2063,14 @@ 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 + * on inp during route lookup. */ + INP_RLOCK(in6p); + bcopy(&in6p->in6p_faddr, &addr, sizeof(addr)); + INP_RUNLOCK(in6p); error = ip6_getpmtu_ctl(so->so_fibnum, - &in6p->in6p_faddr, &pmtu); + &addr, &pmtu); if (error) break; if (pmtu > IPV6_MAXPACKET) @@ -2130,8 +2120,7 @@ do { \ case IPV6_DONTFRAG: case IPV6_USE_MIN_MTU: case IPV6_PREFER_TEMPADDR: - error = ip6_getpcbopt(in6p->in6p_outputopts, - optname, sopt); + error = ip6_getpcbopt(in6p, optname, sopt); break; case IPV6_MULTICAST_IF: @@ -2306,17 +2295,50 @@ ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt, return (ip6_setpktopt(optname, buf, len, opt, cred, 1, 0, uproto)); } +#define GET_PKTOPT_VAR(field, lenexpr) do { \ + if (pktopt && pktopt->field) { \ + INP_RUNLOCK(in6p); \ + 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); \ + free(optdata, M_TEMP); \ + return (ECONNRESET); \ + } \ + pktopt = in6p->in6p_outputopts; \ + if (pktopt && pktopt->field) { \ + optdatalen = min(lenexpr, sopt->sopt_valsize); \ + bcopy(&pktopt->field, optdata, optdatalen); \ + } else { \ + free(optdata, M_TEMP); \ + optdata = NULL; \ + malloc_optdata = false; \ + } \ + } \ +} while(0) + +#define GET_PKTOPT_EXT_HDR(field) GET_PKTOPT_VAR(field, \ + (((struct ip6_ext *)pktopt->field)->ip6e_len + 1) << 3) + +#define GET_PKTOPT_SOCKADDR(field) GET_PKTOPT_VAR(field, \ + pktopt->field->sa_len) + static int -ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt) +ip6_getpcbopt(struct inpcb *in6p, int optname, struct sockopt *sopt) { void *optdata = NULL; + bool malloc_optdata = false; int optdatalen = 0; - struct ip6_ext *ip6e; int error = 0; struct in6_pktinfo null_pktinfo; int deftclass = 0, on; int defminmtu = IP6PO_MINMTU_MCASTONLY; int defpreftemp = IP6PO_TEMPADDR_SYSTEM; + struct ip6_pktopts *pktopt; + + INP_RLOCK(in6p); + pktopt = in6p->in6p_outputopts; switch (optname) { case IPV6_PKTINFO: @@ -2333,50 +2355,29 @@ ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt) break; case IPV6_TCLASS: if (pktopt && pktopt->ip6po_tclass >= 0) - optdata = (void *)&pktopt->ip6po_tclass; - else - optdata = (void *)&deftclass; + deftclass = pktopt->ip6po_tclass; + optdata = (void *)&deftclass; optdatalen = sizeof(int); break; case IPV6_HOPOPTS: - if (pktopt && pktopt->ip6po_hbh) { - optdata = (void *)pktopt->ip6po_hbh; - ip6e = (struct ip6_ext *)pktopt->ip6po_hbh; - optdatalen = (ip6e->ip6e_len + 1) << 3; - } + GET_PKTOPT_EXT_HDR(ip6po_hbh); break; case IPV6_RTHDR: - if (pktopt && pktopt->ip6po_rthdr) { - optdata = (void *)pktopt->ip6po_rthdr; - ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr; - optdatalen = (ip6e->ip6e_len + 1) << 3; - } + GET_PKTOPT_EXT_HDR(ip6po_rthdr); break; case IPV6_RTHDRDSTOPTS: - if (pktopt && pktopt->ip6po_dest1) { - optdata = (void *)pktopt->ip6po_dest1; - ip6e = (struct ip6_ext *)pktopt->ip6po_dest1; - optdatalen = (ip6e->ip6e_len + 1) << 3; - } + GET_PKTOPT_EXT_HDR(ip6po_dest1); break; case IPV6_DSTOPTS: - if (pktopt && pktopt->ip6po_dest2) { - optdata = (void *)pktopt->ip6po_dest2; - ip6e = (struct ip6_ext *)pktopt->ip6po_dest2; - optdatalen = (ip6e->ip6e_len + 1) << 3; - } + GET_PKTOPT_EXT_HDR(ip6po_dest2); break; case IPV6_NEXTHOP: - if (pktopt && pktopt->ip6po_nexthop) { - optdata = (void *)pktopt->ip6po_nexthop; - optdatalen = pktopt->ip6po_nexthop->sa_len; - } + GET_PKTOPT_SOCKADDR(ip6po_nexthop); break; case IPV6_USE_MIN_MTU: if (pktopt) - optdata = (void *)&pktopt->ip6po_minmtu; - else - optdata = (void *)&defminmtu; + defminmtu = pktopt->ip6po_minmtu; + optdata = (void *)&defminmtu; optdatalen = sizeof(int); break; case IPV6_DONTFRAG: @@ -2389,19 +2390,22 @@ ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt) break; case IPV6_PREFER_TEMPADDR: if (pktopt) - optdata = (void *)&pktopt->ip6po_prefer_tempaddr; - else - optdata = (void *)&defpreftemp; + defpreftemp = pktopt->ip6po_prefer_tempaddr; + optdata = (void *)&defpreftemp; optdatalen = sizeof(int); break; default: /* should not happen */ #ifdef DIAGNOSTIC panic("ip6_getpcbopt: unexpected option\n"); #endif + INP_RUNLOCK(in6p); return (ENOPROTOOPT); } + INP_RUNLOCK(in6p); error = sooptcopyout(sopt, optdata, optdatalen); + if (malloc_optdata) + free(optdata, M_TEMP); return (error); } diff --git a/freebsd/sys/netinet6/ip6_var.h b/freebsd/sys/netinet6/ip6_var.h index 5c8997ca..42c235d1 100644 --- a/freebsd/sys/netinet6/ip6_var.h +++ b/freebsd/sys/netinet6/ip6_var.h @@ -364,7 +364,7 @@ void ip6_direct_input(struct mbuf *); void ip6_freepcbopts(struct ip6_pktopts *); int ip6_unknown_opt(u_int8_t *, struct mbuf *, int); -char * ip6_get_prevhdr(const struct mbuf *, int); +int ip6_get_prevhdr(const struct mbuf *, int); int ip6_nexthdr(const struct mbuf *, int, int, int *); int ip6_lasthdr(const struct mbuf *, int, int, int *); diff --git a/freebsd/sys/netinet6/nd6.c b/freebsd/sys/netinet6/nd6.c index 6235b808..a00d5421 100644 --- a/freebsd/sys/netinet6/nd6.c +++ b/freebsd/sys/netinet6/nd6.c @@ -63,7 +63,6 @@ __FBSDID("$FreeBSD$"); #include <net/if_arc.h> #include <net/if_dl.h> #include <net/if_types.h> -#include <net/iso88025.h> #include <net/fddi.h> #include <net/route.h> #include <net/vnet.h> @@ -346,9 +345,6 @@ nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) case IFT_FDDI: ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); /* RFC2467 */ break; - case IFT_ISO88025: - ndi->maxmtu = MIN(ISO88025_MAX_MTU, ifp->if_mtu); - break; default: ndi->maxmtu = ifp->if_mtu; break; @@ -2281,7 +2277,6 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, case IFT_FDDI: case IFT_L2VLAN: case IFT_BRIDGE: - case IFT_ISO88025: ETHER_MAP_IPV6_MULTICAST(&dst6->sin6_addr, desten); return (0); diff --git a/freebsd/sys/netinet6/nd6_nbr.c b/freebsd/sys/netinet6/nd6_nbr.c index 0c875324..e5b37877 100644 --- a/freebsd/sys/netinet6/nd6_nbr.c +++ b/freebsd/sys/netinet6/nd6_nbr.c @@ -1099,7 +1099,6 @@ nd6_ifptomac(struct ifnet *ifp) case IFT_L2VLAN: case IFT_INFINIBAND: case IFT_BRIDGE: - case IFT_ISO88025: return IF_LLADDR(ifp); default: return NULL; @@ -1122,6 +1121,7 @@ struct dadq { #define ND_OPT_NONCE_LEN32 \ ((ND_OPT_NONCE_LEN + sizeof(uint32_t) - 1)/sizeof(uint32_t)) uint32_t dad_nonce[ND_OPT_NONCE_LEN32]; + bool dad_ondadq; /* on dadq? Protected by DADQ_WLOCK. */ }; static VNET_DEFINE(TAILQ_HEAD(, dadq), dadq); @@ -1140,6 +1140,7 @@ nd6_dad_add(struct dadq *dp) DADQ_WLOCK(); TAILQ_INSERT_TAIL(&V_dadq, dp, dad_list); + dp->dad_ondadq = true; DADQ_WUNLOCK(); } @@ -1148,9 +1149,17 @@ nd6_dad_del(struct dadq *dp) { DADQ_WLOCK(); - TAILQ_REMOVE(&V_dadq, dp, dad_list); - DADQ_WUNLOCK(); - nd6_dad_rele(dp); + if (dp->dad_ondadq) { + /* + * Remove dp from the dadq and release the dadq's + * reference. + */ + TAILQ_REMOVE(&V_dadq, dp, dad_list); + dp->dad_ondadq = false; + DADQ_WUNLOCK(); + nd6_dad_rele(dp); + } else + DADQ_WUNLOCK(); } static struct dadq * @@ -1283,6 +1292,8 @@ nd6_dad_start(struct ifaddr *ifa, int delay) dp->dad_ns_icount = dp->dad_na_icount = 0; dp->dad_ns_ocount = dp->dad_ns_tcount = 0; dp->dad_ns_lcount = dp->dad_loopbackprobe = 0; + + /* Add this to the dadq and add a reference for the dadq. */ refcount_init(&dp->dad_refcnt, 1); nd6_dad_add(dp); nd6_dad_starttimer(dp, delay, 0); @@ -1303,17 +1314,9 @@ nd6_dad_stop(struct ifaddr *ifa) } nd6_dad_stoptimer(dp); - - /* - * The DAD queue entry may have been removed by nd6_dad_timer() while - * we were waiting for it to stop, so re-do the lookup. - */ - nd6_dad_rele(dp); - dp = nd6_dad_find(ifa, NULL); - if (dp == NULL) - return; - nd6_dad_del(dp); + + /* Release this function's reference, acquired by nd6_dad_find(). */ nd6_dad_rele(dp); } diff --git a/freebsd/sys/netinet6/nd6_rtr.c b/freebsd/sys/netinet6/nd6_rtr.c index 2affacbf..642faa1a 100644 --- a/freebsd/sys/netinet6/nd6_rtr.c +++ b/freebsd/sys/netinet6/nd6_rtr.c @@ -410,8 +410,11 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len) int change = (ndi->linkmtu != mtu); ndi->linkmtu = mtu; - if (change) /* in6_maxmtu may change */ + if (change) { + /* in6_maxmtu may change */ in6_setmaxmtu(); + rt_updatemtu(ifp); + } } else { nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " "mtu=%lu sent from %s; " diff --git a/freebsd/sys/netinet6/raw_ip6.c b/freebsd/sys/netinet6/raw_ip6.c index b68077ef..a4843380 100644 --- a/freebsd/sys/netinet6/raw_ip6.c +++ b/freebsd/sys/netinet6/raw_ip6.c @@ -327,12 +327,10 @@ rip6_input(struct mbuf **mp, int *offp, int proto) RIP6STAT_INC(rip6s_nosockmcast); if (proto == IPPROTO_NONE) m_freem(m); - else { - char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ + else icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER, - prvnxtp - mtod(m, char *)); - } + ip6_get_prevhdr(m, *offp)); IP6STAT_DEC(ip6s_delivered); } return (IPPROTO_DONE); diff --git a/freebsd/sys/netinet6/udp6_usrreq.c b/freebsd/sys/netinet6/udp6_usrreq.c index 98d097f7..c2b32eb1 100644 --- a/freebsd/sys/netinet6/udp6_usrreq.c +++ b/freebsd/sys/netinet6/udp6_usrreq.c @@ -222,7 +222,6 @@ udp6_input(struct mbuf **mp, int *offp, int proto) uint8_t nxt; ifp = m->m_pkthdr.rcvif; - ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); @@ -232,6 +231,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto) IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh)); if (!uh) return (IPPROTO_DONE); + ip6 = mtod(m, struct ip6_hdr *); #endif UDPSTAT_INC(udps_ipackets); |