summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-08-21 09:39:55 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-21 10:29:40 +0200
commit2df56dbd60bb5d925d2ce0ddbdefdbe6107ea783 (patch)
treebd7bad558534db4a1f400bc38a2c9aa7ea4f411e /freebsd/sys/netinet6
parentUpdate to FreeBSD head 2018-02-01 (diff)
downloadrtems-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.c2
-rw-r--r--freebsd/sys/netinet6/frag6.c6
-rw-r--r--freebsd/sys/netinet6/icmp6.c9
-rw-r--r--freebsd/sys/netinet6/in6.c34
-rw-r--r--freebsd/sys/netinet6/in6_ifattach.c1
-rw-r--r--freebsd/sys/netinet6/in6_pcb.c74
-rw-r--r--freebsd/sys/netinet6/ip6_fastfwd.c4
-rw-r--r--freebsd/sys/netinet6/ip6_forward.c5
-rw-r--r--freebsd/sys/netinet6/ip6_input.c62
-rw-r--r--freebsd/sys/netinet6/ip6_mroute.c2
-rw-r--r--freebsd/sys/netinet6/ip6_output.c174
-rw-r--r--freebsd/sys/netinet6/ip6_var.h2
-rw-r--r--freebsd/sys/netinet6/nd6.c5
-rw-r--r--freebsd/sys/netinet6/nd6_nbr.c31
-rw-r--r--freebsd/sys/netinet6/nd6_rtr.c5
-rw-r--r--freebsd/sys/netinet6/raw_ip6.c6
-rw-r--r--freebsd/sys/netinet6/udp6_usrreq.c2
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);