summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-06 16:20:21 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-11 10:08:08 +0100
commit66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch)
tree48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/netinet6
parentDefine __GLOBL1() and __GLOBL() (diff)
downloadrtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/netinet6')
-rw-r--r--freebsd/sys/netinet6/dest6.c2
-rw-r--r--freebsd/sys/netinet6/frag6.c14
-rw-r--r--freebsd/sys/netinet6/icmp6.c190
-rw-r--r--freebsd/sys/netinet6/in6.c410
-rw-r--r--freebsd/sys/netinet6/in6.h144
-rw-r--r--freebsd/sys/netinet6/in6_cksum.c122
-rw-r--r--freebsd/sys/netinet6/in6_gif.c8
-rw-r--r--freebsd/sys/netinet6/in6_gif.h10
-rw-r--r--freebsd/sys/netinet6/in6_ifattach.c68
-rw-r--r--freebsd/sys/netinet6/in6_ifattach.h13
-rw-r--r--freebsd/sys/netinet6/in6_mcast.c5
-rw-r--r--freebsd/sys/netinet6/in6_pcb.c349
-rw-r--r--freebsd/sys/netinet6/in6_pcb.h64
-rw-r--r--freebsd/sys/netinet6/in6_proto.c57
-rw-r--r--freebsd/sys/netinet6/in6_src.c66
-rw-r--r--freebsd/sys/netinet6/in6_var.h55
-rw-r--r--freebsd/sys/netinet6/ip6_forward.c103
-rw-r--r--freebsd/sys/netinet6/ip6_input.c301
-rw-r--r--freebsd/sys/netinet6/ip6_ipsec.c9
-rw-r--r--freebsd/sys/netinet6/ip6_mroute.c90
-rw-r--r--freebsd/sys/netinet6/ip6_mroute.h1
-rw-r--r--freebsd/sys/netinet6/ip6_output.c262
-rw-r--r--freebsd/sys/netinet6/ip6_var.h138
-rw-r--r--freebsd/sys/netinet6/ip6protosw.h18
-rw-r--r--freebsd/sys/netinet6/mld6.c19
-rw-r--r--freebsd/sys/netinet6/nd6.c216
-rw-r--r--freebsd/sys/netinet6/nd6.h113
-rw-r--r--freebsd/sys/netinet6/nd6_nbr.c66
-rw-r--r--freebsd/sys/netinet6/nd6_rtr.c56
-rw-r--r--freebsd/sys/netinet6/pim6_var.h2
-rw-r--r--freebsd/sys/netinet6/raw_ip6.c44
-rw-r--r--freebsd/sys/netinet6/raw_ip6.h2
-rw-r--r--freebsd/sys/netinet6/route6.c8
-rw-r--r--freebsd/sys/netinet6/scope6_var.h24
-rw-r--r--freebsd/sys/netinet6/sctp6_usrreq.c29
-rw-r--r--freebsd/sys/netinet6/sctp6_var.h28
-rw-r--r--freebsd/sys/netinet6/send.h45
-rw-r--r--freebsd/sys/netinet6/tcp6_var.h6
-rw-r--r--freebsd/sys/netinet6/udp6_usrreq.c155
39 files changed, 2272 insertions, 1040 deletions
diff --git a/freebsd/sys/netinet6/dest6.c b/freebsd/sys/netinet6/dest6.c
index cb7bb73b..15240dfc 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)
for (optlen = 0; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) {
if (*opt != IP6OPT_PAD1 &&
(dstoptlen < IP6OPT_MINLEN || *(opt + 1) + 2 > dstoptlen)) {
- V_ip6stat.ip6s_toosmall++;
+ IP6STAT_INC(ip6s_toosmall);
goto bad;
}
diff --git a/freebsd/sys/netinet6/frag6.c b/freebsd/sys/netinet6/frag6.c
index 3a58a48e..8e6b0680 100644
--- a/freebsd/sys/netinet6/frag6.c
+++ b/freebsd/sys/netinet6/frag6.c
@@ -217,7 +217,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
return IPPROTO_DONE;
}
- V_ip6stat.ip6s_fragments++;
+ IP6STAT_INC(ip6s_fragments);
in6_ifstat_inc(dstifp, ifs6_reass_reqd);
/* offset now points to data portion */
@@ -230,7 +230,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
*/
if ((ip6f->ip6f_offlg & ~IP6F_RESERVED_MASK) == 0) {
/* XXX-BZ we want dedicated counters for this. */
- V_ip6stat.ip6s_reassembled++;
+ IP6STAT_INC(ip6s_reassembled);
in6_ifstat_inc(dstifp, ifs6_reass_ok);
*offp = offset;
return (ip6f->ip6f_nxt);
@@ -605,7 +605,7 @@ insert:
m->m_pkthdr.len = plen;
}
- V_ip6stat.ip6s_reassembled++;
+ IP6STAT_INC(ip6s_reassembled);
in6_ifstat_inc(dstifp, ifs6_reass_ok);
/*
@@ -621,7 +621,7 @@ insert:
dropfrag:
IP6Q_UNLOCK();
in6_ifstat_inc(dstifp, ifs6_reass_fail);
- V_ip6stat.ip6s_fragdropped++;
+ IP6STAT_INC(ip6s_fragdropped);
m_freem(m);
return IPPROTO_DONE;
}
@@ -745,7 +745,7 @@ frag6_slowtimo(void)
--q6->ip6q_ttl;
q6 = q6->ip6q_next;
if (q6->ip6q_prev->ip6q_ttl == 0) {
- V_ip6stat.ip6s_fragtimeout++;
+ IP6STAT_INC(ip6s_fragtimeout);
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
frag6_freef(q6->ip6q_prev);
}
@@ -757,7 +757,7 @@ frag6_slowtimo(void)
*/
while (V_frag6_nfragpackets > (u_int)V_ip6_maxfragpackets &&
V_ip6q.ip6q_prev) {
- V_ip6stat.ip6s_fragoverflow++;
+ IP6STAT_INC(ip6s_fragoverflow);
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
frag6_freef(V_ip6q.ip6q_prev);
}
@@ -783,7 +783,7 @@ frag6_drain(void)
VNET_FOREACH(vnet_iter) {
CURVNET_SET(vnet_iter);
while (V_ip6q.ip6q_next != &V_ip6q) {
- V_ip6stat.ip6s_fragdropped++;
+ IP6STAT_INC(ip6s_fragdropped);
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
frag6_freef(V_ip6q.ip6q_next);
}
diff --git a/freebsd/sys/netinet6/icmp6.c b/freebsd/sys/netinet6/icmp6.c
index 8c6bc0c5..32d50e94 100644
--- a/freebsd/sys/netinet6/icmp6.c
+++ b/freebsd/sys/netinet6/icmp6.c
@@ -107,6 +107,7 @@ __FBSDID("$FreeBSD$");
#include <netinet6/scope6_var.h>
#include <netinet6/mld6_var.h>
#include <netinet6/nd6.h>
+#include <netinet6/send.h>
#ifdef IPSEC
#include <netipsec/ipsec.h>
@@ -131,18 +132,18 @@ VNET_DECLARE(int, icmp6_nodeinfo);
#define V_icmp6errppslim_last VNET(icmp6errppslim_last)
#define V_icmp6_nodeinfo VNET(icmp6_nodeinfo)
-static void icmp6_errcount(struct icmp6errstat *, int, int);
+static void icmp6_errcount(int, int);
static int icmp6_rip6_input(struct mbuf **, int);
static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
-static const char *icmp6_redirect_diag __P((struct in6_addr *,
- struct in6_addr *, struct in6_addr *));
+static const char *icmp6_redirect_diag(struct in6_addr *,
+ struct in6_addr *, struct in6_addr *);
static struct mbuf *ni6_input(struct mbuf *, int);
static struct mbuf *ni6_nametodns(const char *, int, int);
static int ni6_dnsmatch(const char *, int, const char *, int);
-static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
- struct ifnet **, struct in6_addr *));
-static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
- struct ifnet *, int));
+static int ni6_addrs(struct icmp6_nodeinfo *, struct mbuf *,
+ struct ifnet **, struct in6_addr *);
+static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
+ struct ifnet *, int);
static int icmp6_notify_error(struct mbuf **, int, int, int);
/*
@@ -160,59 +161,59 @@ kmod_icmp6stat_inc(int statnum)
}
static void
-icmp6_errcount(struct icmp6errstat *stat, int type, int code)
+icmp6_errcount(int type, int code)
{
switch (type) {
case ICMP6_DST_UNREACH:
switch (code) {
case ICMP6_DST_UNREACH_NOROUTE:
- stat->icp6errs_dst_unreach_noroute++;
+ ICMP6STAT_INC(icp6s_odst_unreach_noroute);
return;
case ICMP6_DST_UNREACH_ADMIN:
- stat->icp6errs_dst_unreach_admin++;
+ ICMP6STAT_INC(icp6s_odst_unreach_admin);
return;
case ICMP6_DST_UNREACH_BEYONDSCOPE:
- stat->icp6errs_dst_unreach_beyondscope++;
+ ICMP6STAT_INC(icp6s_odst_unreach_beyondscope);
return;
case ICMP6_DST_UNREACH_ADDR:
- stat->icp6errs_dst_unreach_addr++;
+ ICMP6STAT_INC(icp6s_odst_unreach_addr);
return;
case ICMP6_DST_UNREACH_NOPORT:
- stat->icp6errs_dst_unreach_noport++;
+ ICMP6STAT_INC(icp6s_odst_unreach_noport);
return;
}
break;
case ICMP6_PACKET_TOO_BIG:
- stat->icp6errs_packet_too_big++;
+ ICMP6STAT_INC(icp6s_opacket_too_big);
return;
case ICMP6_TIME_EXCEEDED:
switch (code) {
case ICMP6_TIME_EXCEED_TRANSIT:
- stat->icp6errs_time_exceed_transit++;
+ ICMP6STAT_INC(icp6s_otime_exceed_transit);
return;
case ICMP6_TIME_EXCEED_REASSEMBLY:
- stat->icp6errs_time_exceed_reassembly++;
+ ICMP6STAT_INC(icp6s_otime_exceed_reassembly);
return;
}
break;
case ICMP6_PARAM_PROB:
switch (code) {
case ICMP6_PARAMPROB_HEADER:
- stat->icp6errs_paramprob_header++;
+ ICMP6STAT_INC(icp6s_oparamprob_header);
return;
case ICMP6_PARAMPROB_NEXTHEADER:
- stat->icp6errs_paramprob_nextheader++;
+ ICMP6STAT_INC(icp6s_oparamprob_nextheader);
return;
case ICMP6_PARAMPROB_OPTION:
- stat->icp6errs_paramprob_option++;
+ ICMP6STAT_INC(icp6s_oparamprob_option);
return;
}
break;
case ND_REDIRECT:
- stat->icp6errs_redirect++;
+ ICMP6STAT_INC(icp6s_oredirect);
return;
}
- stat->icp6errs_unknown++;
+ ICMP6STAT_INC(icp6s_ounknown);
}
/*
@@ -263,7 +264,7 @@ icmp6_error(struct mbuf *m, int type, int code, int param)
ICMP6STAT_INC(icp6s_error);
/* count per-type-code statistics */
- icmp6_errcount(&V_icmp6stat.icp6s_outerrhist, type, code);
+ icmp6_errcount(type, code);
#ifdef M_DECRYPTED /*not openbsd*/
if (m->m_flags & M_DECRYPTED) {
@@ -416,6 +417,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
int icmp6len = m->m_pkthdr.len - *offp;
int code, sum, noff;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
+ int ip6len, error;
ifp = m->m_pkthdr.rcvif;
@@ -430,6 +432,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
*/
ip6 = mtod(m, struct ip6_hdr *);
+ ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
if (icmp6len < sizeof(struct icmp6_hdr)) {
ICMP6STAT_INC(icp6s_tooshort);
goto freeit;
@@ -772,11 +775,33 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
goto badlen;
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
/* give up local */
- nd6_rs_input(m, off, icmp6len);
+
+ /* Send incoming SeND packet to user space. */
+ if (send_sendso_input_hook != NULL) {
+ IP6_EXTHDR_CHECK(m, off,
+ icmp6len, IPPROTO_DONE);
+ error = send_sendso_input_hook(m, ifp,
+ SND_IN, ip6len);
+ /* -1 == no app on SEND socket */
+ if (error == 0)
+ return (IPPROTO_DONE);
+ nd6_rs_input(m, off, icmp6len);
+ } else
+ nd6_rs_input(m, off, icmp6len);
m = NULL;
goto freeit;
}
- nd6_rs_input(n, off, icmp6len);
+ if (send_sendso_input_hook != NULL) {
+ IP6_EXTHDR_CHECK(n, off,
+ icmp6len, IPPROTO_DONE);
+ error = send_sendso_input_hook(n, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ goto freeit;
+ /* -1 == no app on SEND socket */
+ nd6_rs_input(n, off, icmp6len);
+ } else
+ nd6_rs_input(n, off, icmp6len);
/* m stays. */
break;
@@ -787,12 +812,27 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
if (icmp6len < sizeof(struct nd_router_advert))
goto badlen;
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
- /* give up local */
- nd6_ra_input(m, off, icmp6len);
+
+ /* Send incoming SeND-protected/ND packet to user space. */
+ if (send_sendso_input_hook != NULL) {
+ error = send_sendso_input_hook(m, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ return (IPPROTO_DONE);
+ nd6_ra_input(m, off, icmp6len);
+ } else
+ nd6_ra_input(m, off, icmp6len);
m = NULL;
goto freeit;
}
- nd6_ra_input(n, off, icmp6len);
+ if (send_sendso_input_hook != NULL) {
+ error = send_sendso_input_hook(n, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ goto freeit;
+ nd6_ra_input(n, off, icmp6len);
+ } else
+ nd6_ra_input(n, off, icmp6len);
/* m stays. */
break;
@@ -803,12 +843,25 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
if (icmp6len < sizeof(struct nd_neighbor_solicit))
goto badlen;
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
- /* give up local */
- nd6_ns_input(m, off, icmp6len);
+ if (send_sendso_input_hook != NULL) {
+ error = send_sendso_input_hook(m, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ return (IPPROTO_DONE);
+ nd6_ns_input(m, off, icmp6len);
+ } else
+ nd6_ns_input(m, off, icmp6len);
m = NULL;
goto freeit;
}
- nd6_ns_input(n, off, icmp6len);
+ if (send_sendso_input_hook != NULL) {
+ error = send_sendso_input_hook(n, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ goto freeit;
+ nd6_ns_input(n, off, icmp6len);
+ } else
+ nd6_ns_input(n, off, icmp6len);
/* m stays. */
break;
@@ -819,12 +872,27 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
if (icmp6len < sizeof(struct nd_neighbor_advert))
goto badlen;
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
- /* give up local */
- nd6_na_input(m, off, icmp6len);
+
+ /* Send incoming SeND-protected/ND packet to user space. */
+ if (send_sendso_input_hook != NULL) {
+ error = send_sendso_input_hook(m, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ return (IPPROTO_DONE);
+ nd6_na_input(m, off, icmp6len);
+ } else
+ nd6_na_input(m, off, icmp6len);
m = NULL;
goto freeit;
}
- nd6_na_input(n, off, icmp6len);
+ if (send_sendso_input_hook != NULL) {
+ error = send_sendso_input_hook(n, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ goto freeit;
+ nd6_na_input(n, off, icmp6len);
+ } else
+ nd6_na_input(n, off, icmp6len);
/* m stays. */
break;
@@ -835,12 +903,25 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
if (icmp6len < sizeof(struct nd_redirect))
goto badlen;
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
- /* give up local */
- icmp6_redirect_input(m, off);
+ if (send_sendso_input_hook != NULL) {
+ error = send_sendso_input_hook(m, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ return (IPPROTO_DONE);
+ icmp6_redirect_input(m, off);
+ } else
+ icmp6_redirect_input(m, off);
m = NULL;
goto freeit;
}
- icmp6_redirect_input(n, off);
+ if (send_sendso_input_hook != NULL) {
+ error = send_sendso_input_hook(n, ifp,
+ SND_IN, ip6len);
+ if (error == 0)
+ goto freeit;
+ icmp6_redirect_input(n, off);
+ } else
+ icmp6_redirect_input(n, off);
/* m stays. */
break;
@@ -1102,6 +1183,8 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code)
ip6cp.ip6c_src = &icmp6src;
ip6cp.ip6c_nxt = nxt;
+ m_addr_changed(m);
+
if (icmp6type == ICMP6_PACKET_TOO_BIG) {
notifymtu = ntohl(icmp6->icmp6_mtu);
ip6cp.ip6c_cmdarg = (void *)&notifymtu;
@@ -2229,6 +2312,8 @@ icmp6_reflect(struct mbuf *m, size_t off)
m->m_flags &= ~(M_BCAST|M_MCAST);
+ m_addr_changed(m);
+
ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL);
if (outif)
icmp6_ifoutstat_inc(outif, type, code);
@@ -2290,14 +2375,11 @@ icmp6_redirect_input(struct mbuf *m, int off)
union nd_opts ndopts;
char ip6buf[INET6_ADDRSTRLEN];
- if (!m)
- return;
+ M_ASSERTPKTHDR(m);
+ KASSERT(m->m_pkthdr.rcvif != NULL, ("%s: no rcvif", __func__));
ifp = m->m_pkthdr.rcvif;
- if (!ifp)
- return;
-
/* XXX if we are router, we don't update route by icmp6 redirect */
if (V_ip6_forwarding)
goto freeit;
@@ -2350,23 +2432,23 @@ icmp6_redirect_input(struct mbuf *m, int off)
if (rt) {
if (rt->rt_gateway == NULL ||
rt->rt_gateway->sa_family != AF_INET6) {
+ RTFREE_LOCKED(rt);
nd6log((LOG_ERR,
"ICMP6 redirect rejected; no route "
"with inet6 gateway found for redirect dst: %s\n",
icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
- RTFREE_LOCKED(rt);
goto bad;
}
gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
+ RTFREE_LOCKED(rt);
nd6log((LOG_ERR,
"ICMP6 redirect rejected; "
"not equal to gw-for-src=%s (must be same): "
"%s\n",
ip6_sprintf(ip6buf, gw6),
icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
- RTFREE_LOCKED(rt);
goto bad;
}
} else {
@@ -2404,9 +2486,8 @@ icmp6_redirect_input(struct mbuf *m, int off)
icmp6len -= sizeof(*nd_rd);
nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
if (nd6_options(&ndopts) < 0) {
- nd6log((LOG_INFO, "icmp6_redirect_input: "
- "invalid ND option, rejected: %s\n",
- icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
+ nd6log((LOG_INFO, "%s: invalid ND option, rejected: %s\n",
+ __func__, icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
/* nd6_options have incremented stats */
goto freeit;
}
@@ -2417,10 +2498,9 @@ icmp6_redirect_input(struct mbuf *m, int off)
}
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
- nd6log((LOG_INFO,
- "icmp6_redirect_input: lladdrlen mismatch for %s "
+ nd6log((LOG_INFO, "%s: lladdrlen mismatch for %s "
"(if %d, icmp6 packet %d): %s\n",
- ip6_sprintf(ip6buf, &redtgt6),
+ __func__, ip6_sprintf(ip6buf, &redtgt6),
ifp->if_addrlen, lladdrlen - 2,
icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
goto bad;
@@ -2483,6 +2563,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
struct in6_addr *router_ll6;
struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */
struct mbuf *m = NULL; /* newly allocated one */
+ struct m_tag *mtag;
struct ip6_hdr *ip6; /* m as struct ip6_hdr */
struct nd_redirect *nd_rd;
struct llentry *ln = NULL;
@@ -2491,7 +2572,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
struct ifnet *outif = NULL;
struct sockaddr_in6 src_sa;
- icmp6_errcount(&V_icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0);
+ icmp6_errcount(ND_REDIRECT, 0);
/* if we are not router, we don't send icmp6 redirect */
if (!V_ip6_forwarding)
@@ -2743,6 +2824,15 @@ noredhdropt:;
nd_rd->nd_rd_cksum = in6_cksum(m, IPPROTO_ICMPV6,
sizeof(*ip6), ntohs(ip6->ip6_plen));
+ if (send_sendso_input_hook != NULL) {
+ mtag = m_tag_get(PACKET_TAG_ND_OUTGOING, sizeof(unsigned short),
+ M_NOWAIT);
+ if (mtag == NULL)
+ goto fail;
+ *(unsigned short *)(mtag + 1) = nd_rd->nd_rd_type;
+ m_tag_prepend(m, mtag);
+ }
+
/* send the packet to outside... */
ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL);
if (outif) {
diff --git a/freebsd/sys/netinet6/in6.c b/freebsd/sys/netinet6/in6.c
index 1eed3901..eac5e11e 100644
--- a/freebsd/sys/netinet6/in6.c
+++ b/freebsd/sys/netinet6/in6.c
@@ -107,6 +107,9 @@ __FBSDID("$FreeBSD$");
#include <netinet6/scope6_var.h>
#include <netinet6/in6_pcb.h>
+VNET_DECLARE(int, icmp6_nodeinfo_oldmcprefix);
+#define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix)
+
/*
* Definitions of some costant IP6 addresses.
*/
@@ -130,15 +133,93 @@ const struct in6_addr in6mask128 = IN6MASK128;
const struct sockaddr_in6 sa6_any =
{ sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 };
-static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
- struct ifnet *, struct thread *));
-static int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *,
- struct sockaddr_in6 *, int));
+static int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t,
+ struct ifnet *, struct thread *);
+static int in6_ifinit(struct ifnet *, struct in6_ifaddr *,
+ struct sockaddr_in6 *, int);
static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
int (*faithprefix_p)(struct in6_addr *);
+#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa))
+#define ia62ifa(ia6) (&((ia6)->ia_ifa))
+
+void
+in6_ifaddloop(struct ifaddr *ifa)
+{
+ struct sockaddr_dl gateway;
+ struct sockaddr_in6 mask, addr;
+ struct rtentry rt;
+ struct in6_ifaddr *ia;
+ struct ifnet *ifp;
+ struct llentry *ln;
+
+ ia = ifa2ia6(ifa);
+ ifp = ifa->ifa_ifp;
+ IF_AFDATA_LOCK(ifp);
+ ifa->ifa_rtrequest = nd6_rtrequest;
+ ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR |
+ LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr);
+ IF_AFDATA_UNLOCK(ifp);
+ if (ln != NULL) {
+ ln->la_expire = 0; /* for IPv6 this means permanent */
+ ln->ln_state = ND6_LLINFO_REACHABLE;
+ /*
+ * initialize for rtmsg generation
+ */
+ bzero(&gateway, sizeof(gateway));
+ gateway.sdl_len = sizeof(gateway);
+ gateway.sdl_family = AF_LINK;
+ gateway.sdl_nlen = 0;
+ gateway.sdl_alen = 6;
+ memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned,
+ sizeof(ln->ll_addr));
+ LLE_WUNLOCK(ln);
+ }
+
+ bzero(&rt, sizeof(rt));
+ rt.rt_gateway = (struct sockaddr *)&gateway;
+ memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
+ memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
+ rt_mask(&rt) = (struct sockaddr *)&mask;
+ rt_key(&rt) = (struct sockaddr *)&addr;
+ rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
+ /* Announce arrival of local address to all FIBs. */
+ rt_newaddrmsg(RTM_ADD, ifa, 0, &rt);
+}
+
+void
+in6_ifremloop(struct ifaddr *ifa)
+{
+ struct sockaddr_dl gateway;
+ struct sockaddr_in6 mask, addr;
+ struct rtentry rt0;
+ struct in6_ifaddr *ia;
+ struct ifnet *ifp;
+ ia = ifa2ia6(ifa);
+ ifp = ifa->ifa_ifp;
+ memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
+ memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
+ lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr,
+ (struct sockaddr *)&mask, LLE_STATIC);
+
+ /*
+ * initialize for rtmsg generation
+ */
+ bzero(&gateway, sizeof(gateway));
+ gateway.sdl_len = sizeof(gateway);
+ gateway.sdl_family = AF_LINK;
+ gateway.sdl_nlen = 0;
+ gateway.sdl_alen = ifp->if_addrlen;
+ bzero(&rt0, sizeof(rt0));
+ rt0.rt_gateway = (struct sockaddr *)&gateway;
+ rt_mask(&rt0) = (struct sockaddr *)&mask;
+ rt_key(&rt0) = (struct sockaddr *)&addr;
+ rt0.rt_flags = RTF_HOST | RTF_STATIC;
+ /* Announce removal of local address to all FIBs. */
+ rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
+}
int
in6_mask2len(struct in6_addr *mask, u_char *lim0)
@@ -176,15 +257,12 @@ in6_mask2len(struct in6_addr *mask, u_char *lim0)
return x * 8 + y;
}
-#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa))
-#define ia62ifa(ia6) (&((ia6)->ia_ifa))
-
#ifdef COMPAT_FREEBSD32
struct in6_ndifreq32 {
- char ifname[IFNAMSIZ];
- uint32_t ifindex;
+ char ifname[IFNAMSIZ];
+ uint32_t ifindex;
};
-#define SIOCGDEFIFACE32_IN6 _IOWR('i', 86, struct in6_ndifreq32)
+#define SIOCGDEFIFACE32_IN6 _IOWR('i', 86, struct in6_ndifreq32)
#endif
int
@@ -200,7 +278,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
switch (cmd) {
case SIOCGETSGCNT_IN6:
case SIOCGETMIFCNT_IN6:
- /*
+ /*
* XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c.
* We cannot see how that would be needed, so do not adjust the
* KPI blindly; more likely should clean up the IPv4 variant.
@@ -413,7 +491,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
}
if (td != NULL) {
- error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ?
+ error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ?
PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR);
if (error)
goto out;
@@ -671,8 +749,32 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
* that is, this address might make other addresses detached.
*/
pfxlist_onlink_check();
- if (error == 0 && ia)
+ if (error == 0 && ia) {
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
+ /*
+ * Try to clear the flag when a new
+ * IPv6 address is added onto an
+ * IFDISABLED interface and it
+ * succeeds.
+ */
+ struct in6_ndireq nd;
+
+ memset(&nd, 0, sizeof(nd));
+ nd.ndi.flags = ND_IFINFO(ifp)->flags;
+ nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
+ if (nd6_ioctl(SIOCSIFINFO_FLAGS,
+ (caddr_t)&nd, ifp) < 0)
+ log(LOG_NOTICE, "SIOCAIFADDR_IN6: "
+ "SIOCSIFINFO_FLAGS for -ifdisabled "
+ "failed.");
+ /*
+ * Ignore failure of clearing the flag
+ * intentionally. The failure means
+ * address duplication was detected.
+ */
+ }
EVENTHANDLER_INVOKE(ifaddr_event, ifp);
+ }
break;
}
@@ -714,6 +816,7 @@ out:
return (error);
}
+
/*
* Join necessary multicast groups. Factored out from in6_update_ifa().
* This entire work should only be done once, for the default FIB.
@@ -835,6 +938,17 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
else
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
}
+ if (V_icmp6_nodeinfo_oldmcprefix &&
+ in6_nigroup_oldmcprefix(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
+ imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
+ if (imm == NULL)
+ nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+ "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+ &mltaddr.sin6_addr), if_name(ifp), error));
+ /* XXX not very fatal, go on... */
+ else
+ LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+ }
/*
* Join interface-local all-nodes address.
@@ -1123,6 +1237,10 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
if (hostIsNew && in6if_do_dad(ifp))
ia->ia6_flags |= IN6_IFF_TENTATIVE;
+ /* DAD should be performed after ND6_IFF_IFDISABLED is cleared. */
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
+ ia->ia6_flags |= IN6_IFF_TENTATIVE;
+
/*
* We are done if we have simply modified an existing address.
*/
@@ -1247,7 +1365,7 @@ in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
bzero(&sin6, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
- memcpy(&sin6.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
+ memcpy(&sin6.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
sizeof(sin6.sin6_addr));
error = in6_setscope(&sin6.sin6_addr, ifa0->ifa_ifp, NULL);
if (error != 0)
@@ -1256,16 +1374,17 @@ in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
if (rt != NULL && rt->rt_gateway != NULL &&
- (memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
+ (memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
&ia->ia_addr.sin6_addr,
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
- /*
+ /*
* If no more IPv6 address exists on this interface then
* remove the multicast address route.
*/
if (ifa0 == NULL) {
- memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
- sizeof(mltaddr.sin6_addr));
+ memcpy(&mltaddr.sin6_addr,
+ &satosin6(rt_key(rt))->sin6_addr,
+ sizeof(mltaddr.sin6_addr));
RTFREE_LOCKED(rt);
error = in6_rtrequest(RTM_DELETE,
(struct sockaddr *)&mltaddr,
@@ -1297,16 +1416,17 @@ in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
if (rt != NULL && rt->rt_gateway != NULL &&
- (memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
+ (memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
&ia->ia_addr.sin6_addr,
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
- /*
+ /*
* If no more IPv6 address exists on this interface then
* remove the multicast address route.
*/
if (ifa0 == NULL) {
- memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
- sizeof(mltaddr.sin6_addr));
+ memcpy(&mltaddr.sin6_addr,
+ &satosin6(rt_key(rt))->sin6_addr,
+ sizeof(mltaddr.sin6_addr));
RTFREE_LOCKED(rt);
error = in6_rtrequest(RTM_DELETE,
@@ -1338,9 +1458,6 @@ in6_purgeaddr(struct ifaddr *ifa)
{
struct ifnet *ifp = ifa->ifa_ifp;
struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
- struct sockaddr_dl gateway;
- struct sockaddr_in6 mask, addr;
- struct rtentry rt0;
int plen, error;
struct ifaddr *ifa0;
@@ -1353,8 +1470,7 @@ in6_purgeaddr(struct ifaddr *ifa)
TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) {
if ((ifa0->ifa_addr->sa_family != AF_INET6) ||
memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr,
- &ia->ia_addr.sin6_addr,
- sizeof(struct in6_addr)) == 0)
+ &ia->ia_addr.sin6_addr, sizeof(struct in6_addr)) == 0)
continue;
else
break;
@@ -1365,12 +1481,12 @@ in6_purgeaddr(struct ifaddr *ifa)
/*
* Remove the loopback route to the interface address.
- * The check for the current setting of "nd6_useloopback"
+ * The check for the current setting of "nd6_useloopback"
* is not needed.
*/
if (ia->ia_flags & IFA_RTSELF) {
error = ifa_del_loopback_route((struct ifaddr *)ia,
- (struct sockaddr *)&ia->ia_addr);
+ (struct sockaddr *)&ia->ia_addr);
if (error == 0)
ia->ia_flags &= ~IFA_RTSELF;
}
@@ -1379,28 +1495,7 @@ in6_purgeaddr(struct ifaddr *ifa)
nd6_dad_stop(ifa);
/* Remove local address entry from lltable. */
- IF_AFDATA_LOCK(ifp);
- lla_lookup(LLTABLE6(ifp), (LLE_DELETE | LLE_IFADDR),
- (struct sockaddr *)&ia->ia_addr);
- IF_AFDATA_UNLOCK(ifp);
-
- /*
- * initialize for rtmsg generation
- */
- bzero(&gateway, sizeof(gateway));
- gateway.sdl_len = sizeof(gateway);
- gateway.sdl_family = AF_LINK;
- gateway.sdl_nlen = 0;
- gateway.sdl_alen = ifp->if_addrlen;
- /* */
- bzero(&rt0, sizeof(rt0));
- rt0.rt_gateway = (struct sockaddr *)&gateway;
- memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
- memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
- rt_mask(&rt0) = (struct sockaddr *)&mask;
- rt_key(&rt0) = (struct sockaddr *)&addr;
- rt0.rt_flags = RTF_HOST | RTF_STATIC;
- rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
+ in6_ifremloop(ifa);
/* Leave multicast groups. */
error = in6_purgeaddr_mc(ifp, ia, ifa0);
@@ -1793,7 +1888,7 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
* Special case:
* If a new destination address is specified for a point-to-point
* interface, install a route to the destination as an interface
- * direct route.
+ * direct route.
* XXX: the logic below rejects assigning multiple addresses on a p2p
* interface that share the same destination.
*/
@@ -1817,49 +1912,14 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
*/
if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) {
error = ifa_add_loopback_route((struct ifaddr *)ia,
- (struct sockaddr *)&ia->ia_addr);
+ (struct sockaddr *)&ia->ia_addr);
if (error == 0)
ia->ia_flags |= IFA_RTSELF;
}
/* Add local address to lltable, if necessary (ex. on p2p link). */
- if (newhost) {
- struct llentry *ln;
- struct rtentry rt;
- struct sockaddr_dl gateway;
- struct sockaddr_in6 mask, addr;
-
- IF_AFDATA_LOCK(ifp);
- ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
- ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | LLE_EXCLUSIVE),
- (struct sockaddr *)&ia->ia_addr);
- IF_AFDATA_UNLOCK(ifp);
- if (ln != NULL) {
- ln->la_expire = 0; /* for IPv6 this means permanent */
- ln->ln_state = ND6_LLINFO_REACHABLE;
- /*
- * initialize for rtmsg generation
- */
- bzero(&gateway, sizeof(gateway));
- gateway.sdl_len = sizeof(gateway);
- gateway.sdl_family = AF_LINK;
- gateway.sdl_nlen = 0;
- gateway.sdl_alen = 6;
- memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned, sizeof(ln->ll_addr));
- /* */
- LLE_WUNLOCK(ln);
- }
-
- bzero(&rt, sizeof(rt));
- rt.rt_gateway = (struct sockaddr *)&gateway;
- memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
- memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
- rt_mask(&rt) = (struct sockaddr *)&mask;
- rt_key(&rt) = (struct sockaddr *)&addr;
- rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
- /* Announce arrival of local address to all FIBs. */
- rt_newaddrmsg(RTM_ADD, &ia->ia_ifa, 0, &rt);
- }
+ if (newhost)
+ in6_ifaddloop(&(ia->ia_ifa));
return (error);
}
@@ -1879,7 +1939,7 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
continue;
if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
if ((((struct in6_ifaddr *)ifa)->ia6_flags &
- ignoreflags) != 0)
+ ignoreflags) != 0)
continue;
ifa_ref(ifa);
break;
@@ -1915,6 +1975,32 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
}
/*
+ * Find a link-local scoped address on ifp and return it if any.
+ */
+struct in6_ifaddr *
+in6ifa_llaonifp(struct ifnet *ifp)
+{
+ struct sockaddr_in6 *sin6;
+ struct ifaddr *ifa;
+
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
+ return (NULL);
+ if_addr_rlock(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin6->sin6_addr))
+ break;
+ }
+ if_addr_runlock(ifp);
+
+ return ((struct in6_ifaddr *)ifa);
+}
+
+/*
* Convert IP6 address to printable (loggable) representation. Caller
* has to make sure that ip6buf is at least INET6_ADDRSTRLEN long.
*/
@@ -1922,7 +2008,7 @@ static char digits[] = "0123456789abcdef";
char *
ip6_sprintf(char *ip6buf, const struct in6_addr *addr)
{
- int i;
+ int i, cnt = 0, maxcnt = 0, idx = 0, index = 0;
char *cp;
const u_int16_t *a = (const u_int16_t *)addr;
const u_int8_t *d;
@@ -1931,6 +2017,23 @@ ip6_sprintf(char *ip6buf, const struct in6_addr *addr)
cp = ip6buf;
for (i = 0; i < 8; i++) {
+ if (*(a + i) == 0) {
+ cnt++;
+ if (cnt == 1)
+ idx = i;
+ }
+ else if (maxcnt < cnt) {
+ maxcnt = cnt;
+ index = idx;
+ cnt = 0;
+ }
+ }
+ if (maxcnt < cnt) {
+ maxcnt = cnt;
+ index = idx;
+ }
+
+ for (i = 0; i < 8; i++) {
if (dcolon == 1) {
if (*a == 0) {
if (i == 7)
@@ -1941,7 +2044,7 @@ ip6_sprintf(char *ip6buf, const struct in6_addr *addr)
dcolon = 2;
}
if (*a == 0) {
- if (dcolon == 0 && *(a + 1) == 0) {
+ if (dcolon == 0 && *(a + 1) == 0 && i == index) {
if (i == 0)
*cp++ = ':';
*cp++ = ':';
@@ -2000,6 +2103,27 @@ in6_localaddr(struct in6_addr *in6)
return (0);
}
+/*
+ * Return 1 if an internet address is for the local host and configured
+ * on one of its interfaces.
+ */
+int
+in6_localip(struct in6_addr *in6)
+{
+ struct in6_ifaddr *ia;
+
+ IN6_IFADDR_RLOCK();
+ TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
+ if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) {
+ IN6_IFADDR_RUNLOCK();
+ return (1);
+ }
+ }
+ IN6_IFADDR_RUNLOCK();
+ return (0);
+}
+
+
int
in6_is_addr_deprecated(struct sockaddr_in6 *sa6)
{
@@ -2008,7 +2132,7 @@ in6_is_addr_deprecated(struct sockaddr_in6 *sa6)
IN6_IFADDR_RLOCK();
TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
- &sa6->sin6_addr) &&
+ &sa6->sin6_addr) &&
(ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) {
IN6_IFADDR_RUNLOCK();
return (1); /* true */
@@ -2226,6 +2350,9 @@ in6if_do_dad(struct ifnet *ifp)
if ((ifp->if_flags & IFF_LOOPBACK) != 0)
return (0);
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
+ return (0);
+
switch (ifp->if_type) {
#ifdef IFT_DUMMY
case IFT_DUMMY:
@@ -2276,7 +2403,7 @@ in6_setmaxmtu(void)
maxmtu = IN6_LINKMTU(ifp);
}
IFNET_RUNLOCK_NOSLEEP();
- if (maxmtu) /* update only when maxmtu is positive */
+ if (maxmtu) /* update only when maxmtu is positive */
V_in6_maxmtu = maxmtu;
}
@@ -2305,6 +2432,7 @@ in6_if2idlen(struct ifnet *ifp)
#ifdef IFT_MIP
case IFT_MIP: /* ditto */
#endif
+ case IFT_INFINIBAND:
return (64);
case IFT_FDDI: /* RFC2467 */
return (64);
@@ -2346,76 +2474,73 @@ struct in6_llentry {
struct sockaddr_in6 l3_addr6;
};
+/*
+ * Deletes an address from the address table.
+ * This function is called by the timer functions
+ * such as arptimer() and nd6_llinfo_timer(), and
+ * the caller does the locking.
+ */
+static void
+in6_lltable_free(struct lltable *llt, struct llentry *lle)
+{
+ LLE_WUNLOCK(lle);
+ LLE_LOCK_DESTROY(lle);
+ free(lle, M_LLTABLE);
+}
+
static struct llentry *
in6_lltable_new(const struct sockaddr *l3addr, u_int flags)
{
struct in6_llentry *lle;
- lle = malloc(sizeof(struct in6_llentry), M_LLTABLE,
- M_DONTWAIT | M_ZERO);
+ lle = malloc(sizeof(struct in6_llentry), M_LLTABLE, M_NOWAIT | M_ZERO);
if (lle == NULL) /* NB: caller generates msg */
return NULL;
lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
lle->base.lle_refcnt = 1;
+ lle->base.lle_free = in6_lltable_free;
LLE_LOCK_INIT(&lle->base);
callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock,
CALLOUT_RETURNUNLOCKED);
- return &lle->base;
-}
-
-/*
- * Deletes an address from the address table.
- * This function is called by the timer functions
- * such as arptimer() and nd6_llinfo_timer(), and
- * the caller does the locking.
- */
-static void
-in6_lltable_free(struct lltable *llt, struct llentry *lle)
-{
- LLE_WUNLOCK(lle);
- LLE_LOCK_DESTROY(lle);
- free(lle, M_LLTABLE);
+ return (&lle->base);
}
static void
-in6_lltable_prefix_free(struct lltable *llt,
- const struct sockaddr *prefix,
- const struct sockaddr *mask,
- u_int flags)
+in6_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
+ const struct sockaddr *mask, u_int flags)
{
const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
struct llentry *lle, *next;
- register int i;
+ int i;
/*
- * (flags & LLE_STATIC) means deleting all entries
- * including static ND6 entries
+ * (flags & LLE_STATIC) means deleting all entries
+ * including static ND6 entries.
*/
- for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
+ IF_AFDATA_WLOCK(llt->llt_ifp);
+ for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
if (IN6_ARE_MASKED_ADDR_EQUAL(
- &((struct sockaddr_in6 *)L3_ADDR(lle))->sin6_addr,
- &pfx->sin6_addr,
- &msk->sin6_addr) &&
- ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))) {
- int canceled;
-
- canceled = callout_drain(&lle->la_timer);
+ &satosin6(L3_ADDR(lle))->sin6_addr,
+ &pfx->sin6_addr, &msk->sin6_addr) &&
+ ((flags & LLE_STATIC) ||
+ !(lle->la_flags & LLE_STATIC))) {
LLE_WLOCK(lle);
- if (canceled)
+ if (callout_stop(&lle->la_timer))
LLE_REMREF(lle);
llentry_free(lle);
}
}
}
+ IF_AFDATA_WUNLOCK(llt->llt_ifp);
}
static int
-in6_lltable_rtcheck(struct ifnet *ifp,
- u_int flags,
+in6_lltable_rtcheck(struct ifnet *ifp,
+ u_int flags,
const struct sockaddr *l3addr)
{
struct rtentry *rt;
@@ -2430,8 +2555,8 @@ in6_lltable_rtcheck(struct ifnet *ifp,
RT_DEFAULT_FIB);
if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
struct ifaddr *ifa;
- /*
- * Create an ND6 cache for an IPv6 neighbor
+ /*
+ * Create an ND6 cache for an IPv6 neighbor
* that is not covered by our own prefix.
*/
/* XXX ifaof_ifpforaddr should take a const param */
@@ -2472,8 +2597,8 @@ in6_lltable_lookup(struct lltable *llt, u_int flags,
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle);
if (lle->la_flags & LLE_DELETED)
continue;
- if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr,
- sizeof(struct in6_addr)) == 0)
+ if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr,
+ sizeof(struct in6_addr)) == 0)
break;
}
@@ -2502,15 +2627,20 @@ in6_lltable_lookup(struct lltable *llt, u_int flags,
lle->lle_tbl = llt;
lle->lle_head = lleh;
+ lle->la_flags |= LLE_LINKED;
LIST_INSERT_HEAD(lleh, lle, lle_next);
} else if (flags & LLE_DELETE) {
if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
LLE_WLOCK(lle);
- lle->la_flags = LLE_DELETED;
- LLE_WUNLOCK(lle);
+ lle->la_flags |= LLE_DELETED;
#ifdef DIAGNOSTIC
- log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
-#endif
+ log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
+#endif
+ if ((lle->la_flags &
+ (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
+ llentry_free(lle);
+ else
+ LLE_WUNLOCK(lle);
}
lle = (void *)-1;
}
@@ -2620,7 +2750,6 @@ in6_domifattach(struct ifnet *ifp)
ext->scope6_id = scope6_ifattach(ifp);
ext->lltable = lltable_init(ifp, AF_INET6);
if (ext->lltable != NULL) {
- ext->lltable->llt_free = in6_lltable_free;
ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
ext->lltable->llt_lookup = in6_lltable_lookup;
ext->lltable->llt_dump = in6_lltable_dump;
@@ -2697,8 +2826,7 @@ in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam)
struct sockaddr_in *sin_p;
struct sockaddr_in6 *sin6_p;
- sin6_p = malloc(sizeof *sin6_p, M_SONAME,
- M_WAITOK);
+ sin6_p = malloc(sizeof *sin6_p, M_SONAME, M_WAITOK);
sin_p = (struct sockaddr_in *)*nam;
in6_sin_2_v4mapsin6(sin_p, sin6_p);
free(*nam, M_SONAME);
diff --git a/freebsd/sys/netinet6/in6.h b/freebsd/sys/netinet6/in6.h
index 7abbfa40..616f1009 100644
--- a/freebsd/sys/netinet6/in6.h
+++ b/freebsd/sys/netinet6/in6.h
@@ -235,37 +235,37 @@ extern const struct in6_addr in6addr_linklocal_allv2routers;
* Unspecified
*/
#define IN6_IS_ADDR_UNSPECIFIED(a) \
- ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) == 0))
+ ((a)->__u6_addr.__u6_addr32[0] == 0 && \
+ (a)->__u6_addr.__u6_addr32[1] == 0 && \
+ (a)->__u6_addr.__u6_addr32[2] == 0 && \
+ (a)->__u6_addr.__u6_addr32[3] == 0)
/*
* Loopback
*/
#define IN6_IS_ADDR_LOOPBACK(a) \
- ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) == ntohl(1)))
+ ((a)->__u6_addr.__u6_addr32[0] == 0 && \
+ (a)->__u6_addr.__u6_addr32[1] == 0 && \
+ (a)->__u6_addr.__u6_addr32[2] == 0 && \
+ (a)->__u6_addr.__u6_addr32[3] == ntohl(1))
/*
* IPv4 compatible
*/
#define IN6_IS_ADDR_V4COMPAT(a) \
- ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) != 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) != ntohl(1)))
+ ((a)->__u6_addr.__u6_addr32[0] == 0 && \
+ (a)->__u6_addr.__u6_addr32[1] == 0 && \
+ (a)->__u6_addr.__u6_addr32[2] == 0 && \
+ (a)->__u6_addr.__u6_addr32[3] != 0 && \
+ (a)->__u6_addr.__u6_addr32[3] != ntohl(1))
/*
* Mapped
*/
#define IN6_IS_ADDR_V4MAPPED(a) \
- ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
- (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
+ ((a)->__u6_addr.__u6_addr32[0] == 0 && \
+ (a)->__u6_addr.__u6_addr32[1] == 0 && \
+ (a)->__u6_addr.__u6_addr32[2] == ntohl(0x0000ffff))
/*
* KAME Scope Values
@@ -376,6 +376,8 @@ extern const struct in6_addr in6addr_linklocal_allv2routers;
struct route_in6 {
struct rtentry *ro_rt;
struct llentry *ro_lle;
+ struct in6_addr *ro_ia6;
+ int ro_flags;
struct sockaddr_in6 ro_dst;
};
#endif
@@ -397,8 +399,8 @@ struct route_in6 {
#define IPV6_MULTICAST_IF 9 /* u_int; set/get IP6 multicast i/f */
#define IPV6_MULTICAST_HOPS 10 /* int; set/get IP6 multicast hops */
#define IPV6_MULTICAST_LOOP 11 /* u_int; set/get IP6 multicast loopback */
-#define IPV6_JOIN_GROUP 12 /* ip6_mreq; join a group membership */
-#define IPV6_LEAVE_GROUP 13 /* ip6_mreq; leave a group membership */
+#define IPV6_JOIN_GROUP 12 /* ipv6_mreq; join a group membership */
+#define IPV6_LEAVE_GROUP 13 /* ipv6_mreq; leave a group membership */
#define IPV6_PORTRANGE 14 /* int; range to choose for unspec port */
#define ICMP6_FILTER 18 /* icmp6_filter; icmp6 filter */
/* RFC2292 options */
@@ -611,7 +613,12 @@ struct ip6_mtuinfo {
#define IPV6CTL_STEALTH 45
#define ICMPV6CTL_ND6_ONLINKNSRFC4861 47
-#define IPV6CTL_MAXID 48
+#define IPV6CTL_NO_RADR 48 /* No defroute from RA */
+#define IPV6CTL_NORBIT_RAIF 49 /* Disable R-bit in NA on RA
+ * receiving IF. */
+#define IPV6CTL_RFC6204W3 50 /* Accept defroute even when forwarding
+ enabled */
+#define IPV6CTL_MAXID 51
#endif /* __BSD_VISIBLE */
/*
@@ -625,22 +632,25 @@ struct ip6_mtuinfo {
#ifdef _KERNEL
struct cmsghdr;
-
-int in6_cksum __P((struct mbuf *, u_int8_t, u_int32_t, u_int32_t));
-int in6_localaddr __P((struct in6_addr *));
-int in6_addrscope __P((struct in6_addr *));
-struct in6_ifaddr *in6_ifawithifp __P((struct ifnet *, struct in6_addr *));
-extern void in6_if_up __P((struct ifnet *));
+struct ip6_hdr;
+
+int in6_cksum_pseudo(struct ip6_hdr *, uint32_t, uint8_t, uint16_t);
+int in6_cksum(struct mbuf *, u_int8_t, u_int32_t, u_int32_t);
+int in6_localaddr(struct in6_addr *);
+int in6_localip(struct in6_addr *);
+int in6_addrscope(struct in6_addr *);
+struct in6_ifaddr *in6_ifawithifp(struct ifnet *, struct in6_addr *);
+extern void in6_if_up(struct ifnet *);
struct sockaddr;
extern u_char ip6_protox[];
-void in6_sin6_2_sin __P((struct sockaddr_in *sin,
- struct sockaddr_in6 *sin6));
-void in6_sin_2_v4mapsin6 __P((struct sockaddr_in *sin,
- struct sockaddr_in6 *sin6));
-void in6_sin6_2_sin_in_sock __P((struct sockaddr *nam));
-void in6_sin_2_v4mapsin6_in_sock __P((struct sockaddr **nam));
-extern void addrsel_policy_init __P((void));
+void in6_sin6_2_sin(struct sockaddr_in *sin,
+ struct sockaddr_in6 *sin6);
+void in6_sin_2_v4mapsin6(struct sockaddr_in *sin,
+ struct sockaddr_in6 *sin6);
+void in6_sin6_2_sin_in_sock(struct sockaddr *nam);
+void in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam);
+extern void addrsel_policy_init(void);
#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
#define sin6tosa(sin6) ((struct sockaddr *)(sin6))
@@ -664,43 +674,43 @@ typedef __socklen_t socklen_t;
__BEGIN_DECLS
struct cmsghdr;
-extern int inet6_option_space __P((int));
-extern int inet6_option_init __P((void *, struct cmsghdr **, int));
-extern int inet6_option_append __P((struct cmsghdr *, const uint8_t *,
- int, int));
-extern uint8_t *inet6_option_alloc __P((struct cmsghdr *, int, int, int));
-extern int inet6_option_next __P((const struct cmsghdr *, uint8_t **));
-extern int inet6_option_find __P((const struct cmsghdr *, uint8_t **, int));
-
-extern size_t inet6_rthdr_space __P((int, int));
-extern struct cmsghdr *inet6_rthdr_init __P((void *, int));
-extern int inet6_rthdr_add __P((struct cmsghdr *, const struct in6_addr *,
- unsigned int));
-extern int inet6_rthdr_lasthop __P((struct cmsghdr *, unsigned int));
+extern int inet6_option_space(int);
+extern int inet6_option_init(void *, struct cmsghdr **, int);
+extern int inet6_option_append(struct cmsghdr *, const uint8_t *,
+ int, int);
+extern uint8_t *inet6_option_alloc(struct cmsghdr *, int, int, int);
+extern int inet6_option_next(const struct cmsghdr *, uint8_t **);
+extern int inet6_option_find(const struct cmsghdr *, uint8_t **, int);
+
+extern size_t inet6_rthdr_space(int, int);
+extern struct cmsghdr *inet6_rthdr_init(void *, int);
+extern int inet6_rthdr_add(struct cmsghdr *, const struct in6_addr *,
+ unsigned int);
+extern int inet6_rthdr_lasthop(struct cmsghdr *, unsigned int);
#if 0 /* not implemented yet */
-extern int inet6_rthdr_reverse __P((const struct cmsghdr *, struct cmsghdr *));
+extern int inet6_rthdr_reverse(const struct cmsghdr *, struct cmsghdr *);
#endif
-extern int inet6_rthdr_segments __P((const struct cmsghdr *));
-extern struct in6_addr *inet6_rthdr_getaddr __P((struct cmsghdr *, int));
-extern int inet6_rthdr_getflags __P((const struct cmsghdr *, int));
-
-extern int inet6_opt_init __P((void *, socklen_t));
-extern int inet6_opt_append __P((void *, socklen_t, int, uint8_t, socklen_t,
- uint8_t, void **));
-extern int inet6_opt_finish __P((void *, socklen_t, int));
-extern int inet6_opt_set_val __P((void *, int, void *, socklen_t));
-
-extern int inet6_opt_next __P((void *, socklen_t, int, uint8_t *, socklen_t *,
- void **));
-extern int inet6_opt_find __P((void *, socklen_t, int, uint8_t, socklen_t *,
- void **));
-extern int inet6_opt_get_val __P((void *, int, void *, socklen_t));
-extern socklen_t inet6_rth_space __P((int, int));
-extern void *inet6_rth_init __P((void *, socklen_t, int, int));
-extern int inet6_rth_add __P((void *, const struct in6_addr *));
-extern int inet6_rth_reverse __P((const void *, void *));
-extern int inet6_rth_segments __P((const void *));
-extern struct in6_addr *inet6_rth_getaddr __P((const void *, int));
+extern int inet6_rthdr_segments(const struct cmsghdr *);
+extern struct in6_addr *inet6_rthdr_getaddr(struct cmsghdr *, int);
+extern int inet6_rthdr_getflags(const struct cmsghdr *, int);
+
+extern int inet6_opt_init(void *, socklen_t);
+extern int inet6_opt_append(void *, socklen_t, int, uint8_t, socklen_t,
+ uint8_t, void **);
+extern int inet6_opt_finish(void *, socklen_t, int);
+extern int inet6_opt_set_val(void *, int, void *, socklen_t);
+
+extern int inet6_opt_next(void *, socklen_t, int, uint8_t *, socklen_t *,
+ void **);
+extern int inet6_opt_find(void *, socklen_t, int, uint8_t, socklen_t *,
+ void **);
+extern int inet6_opt_get_val(void *, int, void *, socklen_t);
+extern socklen_t inet6_rth_space(int, int);
+extern void *inet6_rth_init(void *, socklen_t, int, int);
+extern int inet6_rth_add(void *, const struct in6_addr *);
+extern int inet6_rth_reverse(const void *, void *);
+extern int inet6_rth_segments(const void *);
+extern struct in6_addr *inet6_rth_getaddr(const void *, int);
__END_DECLS
#endif /* __BSD_VISIBLE */
diff --git a/freebsd/sys/netinet6/in6_cksum.c b/freebsd/sys/netinet6/in6_cksum.c
index e0e03f45..e129ca71 100644
--- a/freebsd/sys/netinet6/in6_cksum.c
+++ b/freebsd/sys/netinet6/in6_cksum.c
@@ -80,10 +80,70 @@ __FBSDID("$FreeBSD$");
*/
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
-#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
+#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; (void)ADDCARRY(sum);}
+
+static int
+_in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum)
+{
+ int sum;
+ uint16_t scope, *w;
+ union {
+ u_int16_t phs[4];
+ struct {
+ u_int32_t ph_len;
+ u_int8_t ph_zero[3];
+ u_int8_t ph_nxt;
+ } __packed ph;
+ } uph;
+
+ sum = csum;
+
+ /*
+ * First create IP6 pseudo header and calculate a summary.
+ */
+ uph.ph.ph_len = htonl(len);
+ uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
+ uph.ph.ph_nxt = nxt;
+
+ /* Payload length and upper layer identifier. */
+ sum += uph.phs[0]; sum += uph.phs[1];
+ sum += uph.phs[2]; sum += uph.phs[3];
+
+ /* IPv6 source address. */
+ scope = in6_getscope(&ip6->ip6_src);
+ w = (u_int16_t *)&ip6->ip6_src;
+ sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+ sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
+ if (scope != 0)
+ sum -= scope;
+
+ /* IPv6 destination address. */
+ scope = in6_getscope(&ip6->ip6_dst);
+ w = (u_int16_t *)&ip6->ip6_dst;
+ sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+ sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
+ if (scope != 0)
+ sum -= scope;
+
+ return (sum);
+}
+
+int
+in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum)
+{
+ int sum;
+ union {
+ u_int16_t s[2];
+ u_int32_t l;
+ } l_util;
+
+ sum = _in6_cksum_pseudo(ip6, len, nxt, csum);
+ REDUCE;
+ return (sum);
+}
/*
- * m MUST contain a continuous IP6 header.
+ * m MUST contain a contiguous IP6 header.
* off is an offset where TCP/UDP/ICMP6 header starts.
* len is a total length of a transport segment.
* (e.g. TCP header + TCP payload)
@@ -91,12 +151,10 @@ __FBSDID("$FreeBSD$");
int
in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len)
{
- u_int16_t *w;
- int sum = 0;
- int mlen = 0;
- int byte_swapped = 0;
struct ip6_hdr *ip6;
- struct in6_addr in6;
+ u_int16_t *w, scope;
+ int byte_swapped, mlen;
+ int sum;
union {
u_int16_t phs[4];
struct {
@@ -114,42 +172,38 @@ in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len)
u_int32_t l;
} l_util;
- /* sanity check */
- if (m->m_pkthdr.len < off + len) {
- panic("in6_cksum: mbuf len (%d) < off+len (%d+%d)",
- m->m_pkthdr.len, off, len);
- }
-
- bzero(&uph, sizeof(uph));
+ /* Sanity check. */
+ KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+"
+ "len(%d)", __func__, m->m_pkthdr.len, off, len));
/*
* First create IP6 pseudo header and calculate a summary.
*/
- ip6 = mtod(m, struct ip6_hdr *);
uph.ph.ph_len = htonl(len);
+ uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
uph.ph.ph_nxt = nxt;
- /*
- * IPv6 source address.
- * XXX: we'd like to avoid copying the address, but we can't due to
- * the possibly embedded scope zone ID.
- */
- in6 = ip6->ip6_src;
- in6_clearscope(&in6);
- w = (u_int16_t *)&in6;
+ /* Payload length and upper layer identifier. */
+ sum = uph.phs[0]; sum += uph.phs[1];
+ sum += uph.phs[2]; sum += uph.phs[3];
+
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ /* IPv6 source address. */
+ scope = in6_getscope(&ip6->ip6_src);
+ w = (u_int16_t *)&ip6->ip6_src;
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
+ if (scope != 0)
+ sum -= scope;
- /* IPv6 destination address */
- in6 = ip6->ip6_dst;
- in6_clearscope(&in6);
- w = (u_int16_t *)&in6;
+ /* IPv6 destination address. */
+ scope = in6_getscope(&ip6->ip6_dst);
+ w = (u_int16_t *)&ip6->ip6_dst;
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
-
- /* Payload length and upper layer identifier */
- sum += uph.phs[0]; sum += uph.phs[1];
- sum += uph.phs[2]; sum += uph.phs[3];
+ if (scope != 0)
+ sum -= scope;
/*
* Secondly calculate a summary of the first mbuf excluding offset.
@@ -169,14 +223,16 @@ in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len)
/*
* Force to even boundary.
*/
- if ((1 & (long) w) && (mlen > 0)) {
+ if ((1 & (long)w) && (mlen > 0)) {
REDUCE;
sum <<= 8;
s_util.c[0] = *(u_char *)w;
w = (u_int16_t *)((char *)w + 1);
mlen--;
byte_swapped = 1;
- }
+ } else
+ byte_swapped = 0;
+
/*
* Unroll the loop to make overhead from
* branches &c small.
diff --git a/freebsd/sys/netinet6/in6_gif.c b/freebsd/sys/netinet6/in6_gif.c
index bab07c38..9e0f37f0 100644
--- a/freebsd/sys/netinet6/in6_gif.c
+++ b/freebsd/sys/netinet6/in6_gif.c
@@ -266,6 +266,8 @@ in6_gif_output(struct ifnet *ifp,
#endif
}
+ m_addr_changed(m);
+
#ifdef IPV6_MINMTU
/*
* force fragmentation to minimum MTU, to avoid path MTU discovery.
@@ -301,14 +303,14 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto)
sc = (struct gif_softc *)encap_getarg(m);
if (sc == NULL) {
m_freem(m);
- V_ip6stat.ip6s_nogif++;
+ IP6STAT_INC(ip6s_nogif);
return IPPROTO_DONE;
}
gifp = GIF2IFP(sc);
if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
m_freem(m);
- V_ip6stat.ip6s_nogif++;
+ IP6STAT_INC(ip6s_nogif);
return IPPROTO_DONE;
}
@@ -363,7 +365,7 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto)
break;
default:
- V_ip6stat.ip6s_nogif++;
+ IP6STAT_INC(ip6s_nogif);
m_freem(m);
return IPPROTO_DONE;
}
diff --git a/freebsd/sys/netinet6/in6_gif.h b/freebsd/sys/netinet6/in6_gif.h
index f9520898..e1184175 100644
--- a/freebsd/sys/netinet6/in6_gif.h
+++ b/freebsd/sys/netinet6/in6_gif.h
@@ -36,10 +36,10 @@
#define GIF_HLIM 30
struct gif_softc;
-int in6_gif_input __P((struct mbuf **, int *, int));
-int in6_gif_output __P((struct ifnet *, int, struct mbuf *));
-int gif_encapcheck6 __P((const struct mbuf *, int, int, void *));
-int in6_gif_attach __P((struct gif_softc *));
-int in6_gif_detach __P((struct gif_softc *));
+int in6_gif_input(struct mbuf **, int *, int);
+int in6_gif_output(struct ifnet *, int, struct mbuf *);
+int gif_encapcheck6(const struct mbuf *, int, int, void *);
+int in6_gif_attach(struct gif_softc *);
+int in6_gif_detach(struct gif_softc *);
#endif /* _NETINET6_IN6_GIF_H_ */
diff --git a/freebsd/sys/netinet6/in6_ifattach.c b/freebsd/sys/netinet6/in6_ifattach.c
index 57a7efef..a8f03017 100644
--- a/freebsd/sys/netinet6/in6_ifattach.c
+++ b/freebsd/sys/netinet6/in6_ifattach.c
@@ -272,6 +272,7 @@ found:
/* get EUI64 */
switch (ifp->if_type) {
+ case IFT_BRIDGE:
case IFT_ETHER:
case IFT_L2VLAN:
case IFT_FDDI:
@@ -622,13 +623,16 @@ in6_ifattach_loopback(struct ifnet *ifp)
/*
* compute NI group address, based on the current hostname setting.
- * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
+ * see RFC 4620.
*
* when ifp == NULL, the caller is responsible for filling scopeid.
+ *
+ * If oldmcprefix == 1, FF02:0:0:0:0:2::/96 is used for NI group address
+ * while it is FF02:0:0:0:0:2:FF00::/104 in RFC 4620.
*/
-int
-in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
- struct in6_addr *in6)
+static int
+in6_nigroup0(struct ifnet *ifp, const char *name, int namelen,
+ struct in6_addr *in6, int oldmcprefix)
{
struct prison *pr;
const char *p;
@@ -677,7 +681,7 @@ in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
*q = *q - 'A' + 'a';
}
- /* generate 8 bytes of pseudo-random value. */
+ /* generate 16 bytes of pseudo-random value. */
bzero(&ctxt, sizeof(ctxt));
MD5Init(&ctxt);
MD5Update(&ctxt, &l, sizeof(l));
@@ -687,13 +691,36 @@ in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
bzero(in6, sizeof(*in6));
in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL;
in6->s6_addr8[11] = 2;
- bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
+ if (oldmcprefix == 0) {
+ in6->s6_addr8[12] = 0xff;
+ /* Copy the first 24 bits of 128-bit hash into the address. */
+ bcopy(digest, &in6->s6_addr8[13], 3);
+ } else {
+ /* Copy the first 32 bits of 128-bit hash into the address. */
+ bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
+ }
if (in6_setscope(in6, ifp, NULL))
return (-1); /* XXX: should not fail */
return 0;
}
+int
+in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
+ struct in6_addr *in6)
+{
+
+ return (in6_nigroup0(ifp, name, namelen, in6, 0));
+}
+
+int
+in6_nigroup_oldmcprefix(struct ifnet *ifp, const char *name, int namelen,
+ struct in6_addr *in6)
+{
+
+ return (in6_nigroup0(ifp, name, namelen, in6, 1));
+}
+
/*
* XXX multiple loopback interface needs more care. for instance,
* nodelocal address needs to be configured onto only one of them.
@@ -711,7 +738,8 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
switch (ifp->if_type) {
case IFT_PFLOG:
case IFT_PFSYNC:
- case IFT_CARP:
+ ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
+ ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
return;
}
@@ -719,7 +747,6 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
* quirks based on interface type
*/
switch (ifp->if_type) {
-#ifdef IFT_STF
case IFT_STF:
/*
* 6to4 interface is a very special kind of beast.
@@ -727,8 +754,8 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
* linklocals for 6to4 interface, but there's no use and
* it is rather harmful to have one.
*/
- goto statinit;
-#endif
+ ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
+ break;
default:
break;
}
@@ -762,22 +789,23 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
/*
* assign a link-local address, if there's none.
*/
- if (V_ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) {
+ if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
+ ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
+ int error;
+
ia = in6ifa_ifpforlinklocal(ifp, 0);
if (ia == NULL) {
- if (in6_ifattach_linklocal(ifp, altifp) == 0) {
- /* linklocal address assigned */
- } else {
- /* failed to assign linklocal address. bark? */
- }
+ error = in6_ifattach_linklocal(ifp, altifp);
+#if 0
+ if (error)
+ log(LOG_NOTICE, "in6_ifattach_linklocal: "
+ "failed to add a link-local addr to %s\n",
+ if_name(ifp));
+#endif
} else
ifa_free(&ia->ia_ifa);
}
-#ifdef IFT_STF /* XXX */
-statinit:
-#endif
-
/* update dynamically. */
if (V_in6_maxmtu < ifp->if_mtu)
V_in6_maxmtu = ifp->if_mtu;
diff --git a/freebsd/sys/netinet6/in6_ifattach.h b/freebsd/sys/netinet6/in6_ifattach.h
index 441eb755..af627313 100644
--- a/freebsd/sys/netinet6/in6_ifattach.h
+++ b/freebsd/sys/netinet6/in6_ifattach.h
@@ -34,12 +34,13 @@
#define _NETINET6_IN6_IFATTACH_H_
#ifdef _KERNEL
-void in6_ifattach __P((struct ifnet *, struct ifnet *));
-void in6_ifdetach __P((struct ifnet *));
-int in6_get_tmpifid __P((struct ifnet *, u_int8_t *, const u_int8_t *, int));
-void in6_tmpaddrtimer __P((void *));
-int in6_get_hw_ifid __P((struct ifnet *, struct in6_addr *));
-int in6_nigroup __P((struct ifnet *, const char *, int, struct in6_addr *));
+void in6_ifattach(struct ifnet *, struct ifnet *);
+void in6_ifdetach(struct ifnet *);
+int in6_get_tmpifid(struct ifnet *, u_int8_t *, const u_int8_t *, int);
+void in6_tmpaddrtimer(void *);
+int in6_get_hw_ifid(struct ifnet *, struct in6_addr *);
+int in6_nigroup(struct ifnet *, const char *, int, struct in6_addr *);
+int in6_nigroup_oldmcprefix(struct ifnet *, const char *, int, struct in6_addr *);
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_IFATTACH_H_ */
diff --git a/freebsd/sys/netinet6/in6_mcast.c b/freebsd/sys/netinet6/in6_mcast.c
index 67c85c37..55f2fab2 100644
--- a/freebsd/sys/netinet6/in6_mcast.c
+++ b/freebsd/sys/netinet6/in6_mcast.c
@@ -152,7 +152,8 @@ static int sysctl_ip6_mcast_filters(SYSCTL_HANDLER_ARGS);
SYSCTL_DECL(_net_inet6_ip6); /* XXX Not in any common header. */
-SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, mcast, CTLFLAG_RW, 0, "IPv6 multicast");
+static SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, mcast, CTLFLAG_RW, 0,
+ "IPv6 multicast");
static u_long in6_mcast_maxgrpsrc = IPV6_MAX_GROUP_SRC_FILTER;
SYSCTL_ULONG(_net_inet6_ip6_mcast, OID_AUTO, maxgrpsrc,
@@ -172,7 +173,7 @@ SYSCTL_INT(_net_inet6_ip6_mcast, OID_AUTO, loop, CTLFLAG_RW | CTLFLAG_TUN,
&in6_mcast_loop, 0, "Loopback multicast datagrams by default");
TUNABLE_INT("net.inet6.ip6.mcast.loop", &in6_mcast_loop);
-SYSCTL_NODE(_net_inet6_ip6_mcast, OID_AUTO, filters,
+static SYSCTL_NODE(_net_inet6_ip6_mcast, OID_AUTO, filters,
CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip6_mcast_filters,
"Per-interface stack-wide source filters");
diff --git a/freebsd/sys/netinet6/in6_pcb.c b/freebsd/sys/netinet6/in6_pcb.c
index 6446edeb..4d607f71 100644
--- a/freebsd/sys/netinet6/in6_pcb.c
+++ b/freebsd/sys/netinet6/in6_pcb.c
@@ -2,8 +2,12 @@
/*-
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (c) 2010-2011 Juniper Networks, Inc.
* All rights reserved.
*
+ * Portions of this software were developed by Robert N. M. Watson under
+ * contract to Juniper Networks, Inc.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -72,6 +76,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
#include <rtems/bsd/local/opt_ipsec.h>
+#include <rtems/bsd/local/opt_pcbgroup.h>
#include <rtems/bsd/sys/param.h>
#include <sys/systm.h>
@@ -107,8 +112,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/in6_pcb.h>
#include <netinet6/scope6_var.h>
-#include <security/mac/mac_framework.h>
-
struct in6_addr zeroin6_addr;
int
@@ -119,17 +122,18 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
u_short lport = 0;
- int error, wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
+ int error, lookupflags = 0;
+ int reuseport = (so->so_options & SO_REUSEPORT);
- INP_INFO_WLOCK_ASSERT(pcbinfo);
INP_WLOCK_ASSERT(inp);
+ INP_HASH_WLOCK_ASSERT(pcbinfo);
if (TAILQ_EMPTY(&V_in6_ifaddrhead)) /* XXX broken! */
return (EADDRNOTAVAIL);
if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
return (EINVAL);
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
- wild = INPLOOKUP_WILDCARD;
+ lookupflags = INPLOOKUP_WILDCARD;
if (nam == NULL) {
if ((error = prison_local_ip6(cred, &inp->in6p_laddr,
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
@@ -189,6 +193,7 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
}
if (lport) {
struct inpcb *t;
+ struct tcptw *tw;
/* GROSS */
if (ntohs(lport) <= V_ipport_reservedhigh &&
@@ -208,14 +213,15 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) &&
(!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
!IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
- (t->inp_socket->so_options & SO_REUSEPORT)
+ (t->inp_flags2 & INP_REUSEPORT) == 0) &&
#ifndef __rtems__
- == 0) && (inp->inp_cred->cr_uid !=
+ (inp->inp_cred->cr_uid !=
t->inp_cred->cr_uid))
#else /* __rtems__ */
- == 0))
+ 0)
#endif /* __rtems__ */
return (EADDRINUSE);
+#ifdef INET
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
@@ -238,36 +244,49 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
#endif /* __rtems__ */
return (EADDRINUSE);
}
+#endif
}
t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
- lport, wild, cred);
- if (t && (reuseport & ((t->inp_flags & INP_TIMEWAIT) ?
- intotw(t)->tw_so_options :
- t->inp_socket->so_options)) == 0)
+ lport, lookupflags, cred);
+ if (t && (t->inp_flags & INP_TIMEWAIT)) {
+ /*
+ * XXXRW: If an incpb has had its timewait
+ * state recycled, we treat the address as
+ * being in use (for now). This is better
+ * than a panic, but not desirable.
+ */
+ tw = intotw(t);
+ if (tw == NULL ||
+ (reuseport & tw->tw_so_options) == 0)
+ return (EADDRINUSE);
+ } else if (t && (reuseport & inp_so_options(t)) == 0) {
return (EADDRINUSE);
+ }
+#ifdef INET
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
in6_sin6_2_sin(&sin, sin6);
t = in_pcblookup_local(pcbinfo, sin.sin_addr,
- lport, wild, cred);
+ lport, lookupflags, cred);
if (t && t->inp_flags & INP_TIMEWAIT) {
- if ((reuseport &
- intotw(t)->tw_so_options) == 0 &&
- (ntohl(t->inp_laddr.s_addr) !=
+ tw = intotw(t);
+ if (tw == NULL)
+ return (EADDRINUSE);
+ if ((reuseport & tw->tw_so_options) == 0
+ && (ntohl(t->inp_laddr.s_addr) !=
INADDR_ANY || ((inp->inp_vflag &
INP_IPV6PROTO) ==
(t->inp_vflag & INP_IPV6PROTO))))
return (EADDRINUSE);
- }
- else if (t &&
- (reuseport & t->inp_socket->so_options)
- == 0 && (ntohl(t->inp_laddr.s_addr) !=
- INADDR_ANY || INP_SOCKAF(so) ==
- INP_SOCKAF(t->inp_socket)))
+ } else if (t &&
+ (reuseport & inp_so_options(t)) == 0 &&
+ (ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
+ (t->inp_vflag & INP_IPV6PROTO) != 0))
return (EADDRINUSE);
}
+#endif
}
inp->in6p_laddr = sin6->sin6_addr;
}
@@ -309,8 +328,8 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
int scope_ambiguous = 0;
struct in6_addr in6a;
- INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
INP_WLOCK_ASSERT(inp);
+ INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); /* XXXRW: why? */
if (nam->sa_len != sizeof (*sin6))
return (EINVAL);
@@ -371,15 +390,16 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
* then pick one.
*/
int
-in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
- struct ucred *cred)
+in6_pcbconnect_mbuf(register struct inpcb *inp, struct sockaddr *nam,
+ struct ucred *cred, struct mbuf *m)
{
+ struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
struct in6_addr addr6;
int error;
- INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
INP_WLOCK_ASSERT(inp);
+ INP_HASH_WLOCK_ASSERT(pcbinfo);
/*
* Call inner routine, to assign local interface address.
@@ -388,7 +408,7 @@ in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
if ((error = in6_pcbladdr(inp, nam, &addr6)) != 0)
return (error);
- if (in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr,
+ if (in6_pcblookup_hash_locked(pcbinfo, &sin6->sin6_addr,
sin6->sin6_port,
IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
? &addr6 : &inp->in6p_laddr,
@@ -411,17 +431,24 @@ in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
inp->inp_flow |=
(htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
- in_pcbrehash(inp);
+ in_pcbrehash_mbuf(inp, m);
return (0);
}
+int
+in6_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred)
+{
+
+ return (in6_pcbconnect_mbuf(inp, nam, cred, NULL));
+}
+
void
in6_pcbdisconnect(struct inpcb *inp)
{
- INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
INP_WLOCK_ASSERT(inp);
+ INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr));
inp->inp_fport = 0;
@@ -512,11 +539,14 @@ in6_mapped_sockaddr(struct socket *so, struct sockaddr **nam)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("in6_mapped_sockaddr: inp == NULL"));
+#ifdef INET
if ((inp->inp_vflag & (INP_IPV4 | INP_IPV6)) == INP_IPV4) {
error = in_getsockaddr(so, nam);
if (error == 0)
in6_sin_2_v4mapsin6_in_sock(nam);
- } else {
+ } else
+#endif
+ {
/* scope issues will be handled in in6_getsockaddr(). */
error = in6_getsockaddr(so, nam);
}
@@ -533,11 +563,13 @@ in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("in6_mapped_peeraddr: inp == NULL"));
+#ifdef INET
if ((inp->inp_vflag & (INP_IPV4 | INP_IPV6)) == INP_IPV4) {
error = in_getpeeraddr(so, nam);
if (error == 0)
in6_sin_2_v4mapsin6_in_sock(nam);
} else
+#endif
/* scope issues will be handled in in6_getpeeraddr(). */
error = in6_getpeeraddr(so, nam);
@@ -655,18 +687,22 @@ in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr *dst,
}
/*
- * Lookup a PCB based on the local address and port.
+ * Lookup a PCB based on the local address and port. Caller must hold the
+ * hash lock. No inpcb locks or references are acquired.
*/
struct inpcb *
in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
- u_short lport, int wild_okay, struct ucred *cred)
+ u_short lport, int lookupflags, struct ucred *cred)
{
register struct inpcb *inp;
int matchwild = 3, wildcard;
- INP_INFO_WLOCK_ASSERT(pcbinfo);
+ KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0,
+ ("%s: invalid lookup flags %d", __func__, lookupflags));
+
+ INP_HASH_WLOCK_ASSERT(pcbinfo);
- if (!wild_okay) {
+ if ((lookupflags & INPLOOKUP_WILDCARD) == 0) {
struct inpcbhead *head;
/*
* Look for an unconnected (wildcard foreign addr) PCB that
@@ -817,20 +853,158 @@ in6_rtchange(struct inpcb *inp, int errno)
return inp;
}
+#ifdef PCBGROUP
+/*
+ * Lookup PCB in hash list, using pcbgroup tables.
+ */
+static struct inpcb *
+in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
+ struct in6_addr *faddr, u_int fport_arg, struct in6_addr *laddr,
+ u_int lport_arg, int lookupflags, struct ifnet *ifp)
+{
+ struct inpcbhead *head;
+ struct inpcb *inp, *tmpinp;
+ u_short fport = fport_arg, lport = lport_arg;
+ int faith;
+
+ if (faithprefix_p != NULL)
+ faith = (*faithprefix_p)(laddr);
+ else
+ faith = 0;
+
+ /*
+ * First look for an exact match.
+ */
+ tmpinp = NULL;
+ INP_GROUP_LOCK(pcbgroup);
+ head = &pcbgroup->ipg_hashbase[
+ INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, lport, fport,
+ pcbgroup->ipg_hashmask)];
+ LIST_FOREACH(inp, head, inp_pcbgrouphash) {
+ /* XXX inp locking */
+ if ((inp->inp_vflag & INP_IPV6) == 0)
+ continue;
+ if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) &&
+ IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&
+ inp->inp_fport == fport &&
+ inp->inp_lport == lport) {
+ /*
+ * XXX We should be able to directly return
+ * the inp here, without any checks.
+ * Well unless both bound with SO_REUSEPORT?
+ */
+ if (prison_flag(inp->inp_cred, PR_IP6))
+ goto found;
+ if (tmpinp == NULL)
+ tmpinp = inp;
+ }
+ }
+ if (tmpinp != NULL) {
+ inp = tmpinp;
+ goto found;
+ }
+
+ /*
+ * Then look for a wildcard match, if requested.
+ */
+ if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {
+ struct inpcb *local_wild = NULL, *local_exact = NULL;
+ struct inpcb *jail_wild = NULL;
+ int injail;
+
+ /*
+ * Order of socket selection - we always prefer jails.
+ * 1. jailed, non-wild.
+ * 2. jailed, wild.
+ * 3. non-jailed, non-wild.
+ * 4. non-jailed, wild.
+ */
+ head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, lport,
+ 0, pcbinfo->ipi_wildmask)];
+ LIST_FOREACH(inp, head, inp_pcbgroup_wild) {
+ /* XXX inp locking */
+ if ((inp->inp_vflag & INP_IPV6) == 0)
+ continue;
+
+ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
+ inp->inp_lport != lport) {
+ continue;
+ }
+
+ /* XXX inp locking */
+ if (faith && (inp->inp_flags & INP_FAITH) == 0)
+ continue;
+
+ injail = prison_flag(inp->inp_cred, PR_IP6);
+ if (injail) {
+ if (prison_check_ip6(inp->inp_cred,
+ laddr) != 0)
+ continue;
+ } else {
+ if (local_exact != NULL)
+ continue;
+ }
+
+ if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) {
+ if (injail)
+ goto found;
+ else
+ local_exact = inp;
+ } else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
+ if (injail)
+ jail_wild = inp;
+ else
+ local_wild = inp;
+ }
+ } /* LIST_FOREACH */
+
+ inp = jail_wild;
+ if (inp == NULL)
+ inp = jail_wild;
+ if (inp == NULL)
+ inp = local_exact;
+ if (inp == NULL)
+ inp = local_wild;
+ if (inp != NULL)
+ goto found;
+ } /* if ((lookupflags & INPLOOKUP_WILDCARD) != 0) */
+ INP_GROUP_UNLOCK(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
+ panic("%s: locking buf", __func__);
+ return (inp);
+}
+#endif /* PCBGROUP */
+
/*
* Lookup PCB in hash list.
*/
struct inpcb *
-in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
- u_int fport_arg, struct in6_addr *laddr, u_int lport_arg, int wildcard,
- struct ifnet *ifp)
+in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
+ u_int fport_arg, struct in6_addr *laddr, u_int lport_arg,
+ int lookupflags, struct ifnet *ifp)
{
struct inpcbhead *head;
struct inpcb *inp, *tmpinp;
u_short fport = fport_arg, lport = lport_arg;
int faith;
- INP_INFO_LOCK_ASSERT(pcbinfo);
+ KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0,
+ ("%s: invalid lookup flags %d", __func__, lookupflags));
+
+ INP_HASH_LOCK_ASSERT(pcbinfo);
if (faithprefix_p != NULL)
faith = (*faithprefix_p)(laddr);
@@ -869,7 +1043,7 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
/*
* Then look for a wildcard match, if requested.
*/
- if (wildcard == INPLOOKUP_WILDCARD) {
+ if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {
struct inpcb *local_wild = NULL, *local_exact = NULL;
struct inpcb *jail_wild = NULL;
int injail;
@@ -926,7 +1100,7 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
return (local_exact);
if (local_wild != NULL)
return (local_wild);
- } /* if (wildcard == INPLOOKUP_WILDCARD) */
+ } /* if ((lookupflags & INPLOOKUP_WILDCARD) != 0) */
/*
* Not found.
@@ -934,6 +1108,101 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
return (NULL);
}
+/*
+ * Lookup PCB in hash list, using pcbinfo tables. This variation locks the
+ * hash list lock, and will return the inpcb locked (i.e., requires
+ * INPLOOKUP_LOCKPCB).
+ */
+static struct inpcb *
+in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
+ u_int fport, struct in6_addr *laddr, u_int lport, int lookupflags,
+ struct ifnet *ifp)
+{
+ struct inpcb *inp;
+
+ 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
+ panic("%s: locking bug", __func__);
+ } else
+ INP_HASH_RUNLOCK(pcbinfo);
+ return (inp);
+}
+
+/*
+ * Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf
+ * from which a pre-calculated hash value may be extracted.
+ *
+ * Possibly more of this logic should be in in6_pcbgroup.c.
+ */
+struct inpcb *
+in6_pcblookup(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, u_int fport,
+ struct in6_addr *laddr, u_int lport, int lookupflags, struct ifnet *ifp)
+{
+#if defined(PCBGROUP)
+ struct inpcbgroup *pcbgroup;
+#endif
+
+ KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
+ ("%s: invalid lookup flags %d", __func__, lookupflags));
+ KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
+ ("%s: LOCKPCB not set", __func__));
+
+#if defined(PCBGROUP)
+ if (in_pcbgroup_enabled(pcbinfo)) {
+ pcbgroup = in6_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
+ fport);
+ return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
+ laddr, lport, lookupflags, ifp));
+ }
+#endif
+ return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
+ lookupflags, ifp));
+}
+
+struct inpcb *
+in6_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
+ u_int fport, struct in6_addr *laddr, u_int lport, int lookupflags,
+ struct ifnet *ifp, struct mbuf *m)
+{
+#ifdef PCBGROUP
+ struct inpcbgroup *pcbgroup;
+#endif
+
+ KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
+ ("%s: invalid lookup flags %d", __func__, lookupflags));
+ KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
+ ("%s: LOCKPCB not set", __func__));
+
+#ifdef PCBGROUP
+ if (in_pcbgroup_enabled(pcbinfo)) {
+ pcbgroup = in6_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
+ m->m_pkthdr.flowid);
+ if (pcbgroup != NULL)
+ return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr,
+ fport, laddr, lport, lookupflags, ifp));
+ pcbgroup = in6_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
+ fport);
+ return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
+ laddr, lport, lookupflags, ifp));
+ }
+#endif
+ return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
+ lookupflags, ifp));
+}
+
void
init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m)
{
diff --git a/freebsd/sys/netinet6/in6_pcb.h b/freebsd/sys/netinet6/in6_pcb.h
index c54a8cf3..19d151b7 100644
--- a/freebsd/sys/netinet6/in6_pcb.h
+++ b/freebsd/sys/netinet6/in6_pcb.h
@@ -69,36 +69,56 @@
#define sin6tosa(sin6) ((struct sockaddr *)(sin6))
#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
-void in6_pcbpurgeif0 __P((struct inpcbinfo *, struct ifnet *));
-void in6_losing __P((struct inpcb *));
-int in6_pcbbind __P((struct inpcb *, struct sockaddr *, struct ucred *));
-int in6_pcbconnect __P((struct inpcb *, struct sockaddr *, struct ucred *));
-void in6_pcbdisconnect __P((struct inpcb *));
+struct inpcbgroup *
+ in6_pcbgroup_byhash(struct inpcbinfo *, u_int, uint32_t);
+struct inpcbgroup *
+ in6_pcbgroup_byinpcb(struct inpcb *);
+struct inpcbgroup *
+ in6_pcbgroup_bymbuf(struct inpcbinfo *, struct mbuf *);
+struct inpcbgroup *
+ in6_pcbgroup_bytuple(struct inpcbinfo *, const struct in6_addr *,
+ u_short, const struct in6_addr *, u_short);
+
+void in6_pcbpurgeif0(struct inpcbinfo *, struct ifnet *);
+void in6_losing(struct inpcb *);
+int in6_pcbbind(struct inpcb *, struct sockaddr *, struct ucred *);
+int in6_pcbconnect(struct inpcb *, struct sockaddr *, struct ucred *);
+int in6_pcbconnect_mbuf(struct inpcb *, struct sockaddr *,
+ struct ucred *, struct mbuf *);
+void in6_pcbdisconnect(struct inpcb *);
int in6_pcbladdr(struct inpcb *, struct sockaddr *, struct in6_addr *);
struct inpcb *
- in6_pcblookup_local __P((struct inpcbinfo *,
+ in6_pcblookup_local(struct inpcbinfo *,
struct in6_addr *, u_short, int,
- struct ucred *));
+ struct ucred *);
+struct inpcb *
+ in6_pcblookup(struct inpcbinfo *, struct in6_addr *,
+ u_int, struct in6_addr *, u_int, int,
+ struct ifnet *);
+struct inpcb *
+ in6_pcblookup_hash_locked(struct inpcbinfo *, struct in6_addr *,
+ u_int, struct in6_addr *, u_int, int,
+ struct ifnet *);
struct inpcb *
- in6_pcblookup_hash __P((struct inpcbinfo *,
- struct in6_addr *, u_int, struct in6_addr *,
- u_int, int, struct ifnet *));
-void in6_pcbnotify __P((struct inpcbinfo *, struct sockaddr *,
+ in6_pcblookup_mbuf(struct inpcbinfo *, struct in6_addr *,
+ u_int, struct in6_addr *, u_int, int,
+ struct ifnet *ifp, struct mbuf *);
+void in6_pcbnotify(struct inpcbinfo *, struct sockaddr *,
u_int, const struct sockaddr *, u_int, int, void *,
- struct inpcb *(*)(struct inpcb *, int)));
+ struct inpcb *(*)(struct inpcb *, int));
struct inpcb *
- in6_rtchange __P((struct inpcb *, int));
+ in6_rtchange(struct inpcb *, int);
struct sockaddr *
- in6_sockaddr __P((in_port_t port, struct in6_addr *addr_p));
+ in6_sockaddr(in_port_t port, struct in6_addr *addr_p);
struct sockaddr *
- in6_v4mapsin6_sockaddr __P((in_port_t port, struct in_addr *addr_p));
-int in6_getpeeraddr __P((struct socket *so, struct sockaddr **nam));
-int in6_getsockaddr __P((struct socket *so, struct sockaddr **nam));
-int in6_mapped_sockaddr __P((struct socket *so, struct sockaddr **nam));
-int in6_mapped_peeraddr __P((struct socket *so, struct sockaddr **nam));
-int in6_selecthlim __P((struct in6pcb *, struct ifnet *));
-int in6_pcbsetport __P((struct in6_addr *, struct inpcb *, struct ucred *));
-void init_sin6 __P((struct sockaddr_in6 *sin6, struct mbuf *m));
+ in6_v4mapsin6_sockaddr(in_port_t port, struct in_addr *addr_p);
+int in6_getpeeraddr(struct socket *so, struct sockaddr **nam);
+int in6_getsockaddr(struct socket *so, struct sockaddr **nam);
+int in6_mapped_sockaddr(struct socket *so, struct sockaddr **nam);
+int in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam);
+int in6_selecthlim(struct in6pcb *, struct ifnet *);
+int in6_pcbsetport(struct in6_addr *, struct inpcb *, struct ucred *);
+void init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m);
#endif /* _KERNEL */
#endif /* !_NETINET6_IN6_PCB_H_ */
diff --git a/freebsd/sys/netinet6/in6_proto.c b/freebsd/sys/netinet6/in6_proto.c
index df05febf..a6c3b4e8 100644
--- a/freebsd/sys/netinet6/in6_proto.c
+++ b/freebsd/sys/netinet6/in6_proto.c
@@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_ipstealth.h>
#include <rtems/bsd/local/opt_sctp.h>
#include <rtems/bsd/local/opt_mpath.h>
+#include <rtems/bsd/local/opt_route.h>
#include <rtems/bsd/sys/param.h>
#include <sys/socket.h>
@@ -127,6 +128,10 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6protosw.h>
+#ifdef FLOWTABLE
+#include <net/flowtable.h>
+#endif
+
/*
* TCP/IP protocol family: IP6, ICMP6, UDP, TCP.
*/
@@ -167,6 +172,9 @@ struct ip6protosw inet6sw[] = {
.pr_input = udp6_input,
.pr_ctlinput = udp6_ctlinput,
.pr_ctloutput = ip6_ctloutput,
+#ifndef INET /* Do not call initialization twice. */
+ .pr_init = udp_init,
+#endif
.pr_usrreqs = &udp6_usrreqs,
},
{
@@ -220,6 +228,9 @@ struct ip6protosw inet6sw[] = {
.pr_output = rip6_output,
.pr_ctlinput = rip6_ctlinput,
.pr_ctloutput = rip6_ctloutput,
+#ifndef INET /* Do not call initialization twice. */
+ .pr_init = rip_init,
+#endif
.pr_usrreqs = &rip6_usrreqs
},
{
@@ -388,6 +399,9 @@ VNET_DEFINE(int, ip6_sendredirects) = IPV6_SENDREDIRECTS;
VNET_DEFINE(int, ip6_defhlim) = IPV6_DEFHLIM;
VNET_DEFINE(int, ip6_defmcasthlim) = IPV6_DEFAULT_MULTICAST_HOPS;
VNET_DEFINE(int, ip6_accept_rtadv) = 0;
+VNET_DEFINE(int, ip6_no_radr) = 0;
+VNET_DEFINE(int, ip6_norbit_raif) = 0;
+VNET_DEFINE(int, ip6_rfc6204w3) = 0;
VNET_DEFINE(int, ip6_maxfragpackets); /* initialized in frag6.c:frag6_init() */
VNET_DEFINE(int, ip6_maxfrags); /* initialized in frag6.c:frag6_init() */
VNET_DEFINE(int, ip6_log_interval) = 5;
@@ -436,6 +450,7 @@ VNET_DEFINE(int, icmp6errppslim) = 100; /* 100pps */
/* control how to respond to NI queries */
VNET_DEFINE(int, icmp6_nodeinfo) =
(ICMP6_NODEINFO_FQDNOK|ICMP6_NODEINFO_NODEADDROK);
+VNET_DEFINE(int, icmp6_nodeinfo_oldmcprefix) = 1;
/* UDP on IP6 parameters */
VNET_DEFINE(int, udp6_sendspace) = 9216;/* really max datagram size */
@@ -508,12 +523,27 @@ SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
&VNET_NAME(ip6_sendredirects), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_DEFHLIM, hlim, CTLFLAG_RW,
&VNET_NAME(ip6_defhlim), 0, "");
-SYSCTL_VNET_STRUCT(_net_inet6_ip6, IPV6CTL_STATS, stats, CTLFLAG_RD,
+SYSCTL_VNET_STRUCT(_net_inet6_ip6, IPV6CTL_STATS, stats, CTLFLAG_RW,
&VNET_NAME(ip6stat), ip6stat, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGPACKETS, maxfragpackets,
CTLFLAG_RW, &VNET_NAME(ip6_maxfragpackets), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_ACCEPT_RTADV, accept_rtadv,
- CTLFLAG_RW, &VNET_NAME(ip6_accept_rtadv), 0, "");
+ CTLFLAG_RW, &VNET_NAME(ip6_accept_rtadv), 0,
+ "Default value of per-interface flag for accepting ICMPv6 Router"
+ "Advertisement messages");
+SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_NO_RADR, no_radr,
+ CTLFLAG_RW, &VNET_NAME(ip6_no_radr), 0,
+ "Default value of per-interface flag to control whether routers "
+ "sending ICMPv6 RA messages on that interface are added into the "
+ "default router list.");
+SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_NORBIT_RAIF, norbit_raif, CTLFLAG_RW,
+ &VNET_NAME(ip6_norbit_raif), 0,
+ "Always set 0 to R flag in ICMPv6 NA messages when accepting RA"
+ " on the interface.");
+SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_RFC6204W3, rfc6204w3,
+ CTLFLAG_RW, &VNET_NAME(ip6_rfc6204w3), 0,
+ "Accept the default router list from ICMPv6 RA messages even "
+ "when packet forwarding enabled.");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
&VNET_NAME(ip6_keepfaith), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_LOG_INTERVAL, log_interval,
@@ -543,8 +573,10 @@ SYSCTL_VNET_PROC(_net_inet6_ip6, IPV6CTL_TEMPVLTIME, tempvltime,
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_V6ONLY, v6only, CTLFLAG_RW,
&VNET_NAME(ip6_v6only), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_AUTO_LINKLOCAL, auto_linklocal,
- CTLFLAG_RW, &VNET_NAME(ip6_auto_linklocal), 0, "");
-SYSCTL_VNET_STRUCT(_net_inet6_ip6, IPV6CTL_RIP6STATS, rip6stats, CTLFLAG_RD,
+ CTLFLAG_RW, &VNET_NAME(ip6_auto_linklocal), 0,
+ "Default value of per-interface flag for automatically adding an IPv6"
+ " link-local address to interfaces when attached");
+SYSCTL_VNET_STRUCT(_net_inet6_ip6, IPV6CTL_RIP6STATS, rip6stats, CTLFLAG_RW,
&VNET_NAME(rip6stat), rip6stat, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_PREFER_TEMPADDR, prefer_tempaddr,
CTLFLAG_RW, &VNET_NAME(ip6_prefer_tempaddr), 0, "");
@@ -559,12 +591,22 @@ SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_STEALTH, stealth, CTLFLAG_RW,
&VNET_NAME(ip6stealth), 0, "");
#endif
+#ifdef FLOWTABLE
+VNET_DEFINE(int, ip6_output_flowtable_size) = 2048;
+VNET_DEFINE(struct flowtable *, ip6_ft);
+#define V_ip6_output_flowtable_size VNET(ip6_output_flowtable_size)
+
+SYSCTL_VNET_INT(_net_inet6_ip6, OID_AUTO, output_flowtable_size, CTLFLAG_RDTUN,
+ &VNET_NAME(ip6_output_flowtable_size), 2048,
+ "number of entries in the per-cpu output flow caches");
+#endif
+
/* net.inet6.icmp6 */
SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRACCEPT, rediraccept,
CTLFLAG_RW, &VNET_NAME(icmp6_rediraccept), 0, "");
SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRTIMEOUT, redirtimeout,
CTLFLAG_RW, &VNET_NAME(icmp6_redirtimeout), 0, "");
-SYSCTL_VNET_STRUCT(_net_inet6_icmp6, ICMPV6CTL_STATS, stats, CTLFLAG_RD,
+SYSCTL_VNET_STRUCT(_net_inet6_icmp6, ICMPV6CTL_STATS, stats, CTLFLAG_RW,
&VNET_NAME(icmp6stat), icmp6stat, "");
SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_PRUNE, nd6_prune, CTLFLAG_RW,
&VNET_NAME(nd6_prune), 0, "");
@@ -578,6 +620,11 @@ SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_USELOOPBACK, nd6_useloopback,
CTLFLAG_RW, &VNET_NAME(nd6_useloopback), 0, "");
SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_NODEINFO, nodeinfo, CTLFLAG_RW,
&VNET_NAME(icmp6_nodeinfo), 0, "");
+SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_NODEINFO_OLDMCPREFIX,
+ nodeinfo_oldmcprefix, CTLFLAG_RW,
+ &VNET_NAME(icmp6_nodeinfo_oldmcprefix), 0,
+ "Join old IPv6 NI group address in draft-ietf-ipngwg-icmp-name-lookup"
+ " for compatibility with KAME implememtation.");
SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_ERRPPSLIMIT, errppslimit,
CTLFLAG_RW, &VNET_NAME(icmp6errppslim), 0, "");
SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_MAXNUDHINT, nd6_maxnudhint,
diff --git a/freebsd/sys/netinet6/in6_src.c b/freebsd/sys/netinet6/in6_src.c
index 74577cbd..cc2f5ee5 100644
--- a/freebsd/sys/netinet6/in6_src.c
+++ b/freebsd/sys/netinet6/in6_src.c
@@ -129,20 +129,20 @@ static VNET_DEFINE(struct in6_addrpolicy, defaultaddrpolicy);
VNET_DEFINE(int, ip6_prefer_tempaddr) = 0;
-static int selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
+static int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
- struct rtentry **, int, u_int));
-static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
+ struct rtentry **, int, u_int);
+static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route_in6 *ro, struct ifnet **,
- struct ifnet *, u_int));
+ struct ifnet *, u_int);
static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
static void init_policy_queue(void);
static int add_addrsel_policyent(struct in6_addrpolicy *);
static int delete_addrsel_policyent(struct in6_addrpolicy *);
-static int walk_addrsel_policy __P((int (*)(struct in6_addrpolicy *, void *),
- void *));
+static int walk_addrsel_policy(int (*)(struct in6_addrpolicy *, void *),
+ void *);
static int dump_addrsel_policyent(struct in6_addrpolicy *, void *);
static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
@@ -153,9 +153,8 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
* an entry to the caller for later use.
*/
#define REPLACE(r) do {\
- if ((r) < sizeof(V_ip6stat.ip6s_sources_rule) / \
- sizeof(V_ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
- V_ip6stat.ip6s_sources_rule[(r)]++; \
+ IP6STAT_INC(ip6s_sources_rule[(r)]); \
+ rule = (r); \
/* { \
char ip6buf[INET6_ADDRSTRLEN], ip6b[INET6_ADDRSTRLEN]; \
printf("in6_selectsrc: replace %s with %s by %d\n", ia_best ? ip6_sprintf(ip6buf, &ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(ip6b, &ia->ia_addr.sin6_addr), (r)); \
@@ -163,9 +162,6 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
goto replace; \
} while(0)
#define NEXT(r) do {\
- if ((r) < sizeof(V_ip6stat.ip6s_sources_rule) / \
- sizeof(V_ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
- V_ip6stat.ip6s_sources_rule[(r)]++; \
/* { \
char ip6buf[INET6_ADDRSTRLEN], ip6b[INET6_ADDRSTRLEN]; \
printf("in6_selectsrc: keep %s against %s by %d\n", ia_best ? ip6_sprintf(ip6buf, &ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(ip6b, &ia->ia_addr.sin6_addr), (r)); \
@@ -173,9 +169,8 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
goto next; /* XXX: we can't use 'continue' here */ \
} while(0)
#define BREAK(r) do { \
- if ((r) < sizeof(V_ip6stat.ip6s_sources_rule) / \
- sizeof(V_ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
- V_ip6stat.ip6s_sources_rule[(r)]++; \
+ IP6STAT_INC(ip6s_sources_rule[(r)]); \
+ rule = (r); \
goto out; /* XXX: we can't use 'break' here */ \
} while(0)
@@ -192,7 +187,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct in6_addrpolicy *dst_policy = NULL, *best_policy = NULL;
u_int32_t odstzone;
int prefer_tempaddr;
- int error;
+ int error, rule;
struct ip6_moptions *mopts;
KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
@@ -308,6 +303,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
if (error)
return (error);
+ rule = 0;
IN6_IFADDR_RLOCK();
TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
int new_scope = -1, new_matchlen = -1;
@@ -385,10 +381,12 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
*/
/* Rule 5: Prefer outgoing interface */
- if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp)
- NEXT(5);
- if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp)
- REPLACE(5);
+ if (!(ND_IFINFO(ifp)->flags & ND6_IFF_NO_PREFER_IFACE)) {
+ if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp)
+ NEXT(5);
+ if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp)
+ REPLACE(5);
+ }
/*
* Rule 6: Prefer matching label
@@ -487,6 +485,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
if ((ia = ia_best) == NULL) {
IN6_IFADDR_RUNLOCK();
+ IP6STAT_INC(ip6s_sources_none);
return (EADDRNOTAVAIL);
}
@@ -503,6 +502,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
if (cred != NULL && prison_local_ip6(cred, &tmp, (inp != NULL &&
(inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0) {
IN6_IFADDR_RUNLOCK();
+ IP6STAT_INC(ip6s_sources_none);
return (EADDRNOTAVAIL);
}
@@ -510,6 +510,16 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
*ifpp = ifp;
bcopy(&tmp, srcp, sizeof(*srcp));
+ if (ia->ia_ifp == ifp)
+ IP6STAT_INC(ip6s_sources_sameif[best_scope]);
+ else
+ IP6STAT_INC(ip6s_sources_otherif[best_scope]);
+ if (dst_scope == best_scope)
+ IP6STAT_INC(ip6s_sources_samescope[best_scope]);
+ else
+ IP6STAT_INC(ip6s_sources_otherscope[best_scope]);
+ if (IFA6_IS_DEPRECATED(ia))
+ IP6STAT_INC(ip6s_sources_deprecated[best_scope]);
IN6_IFADDR_RUNLOCK();
return (0);
}
@@ -733,7 +743,7 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
error = EHOSTUNREACH;
}
if (error == EHOSTUNREACH)
- V_ip6stat.ip6s_noroute++;
+ IP6STAT_INC(ip6s_noroute);
if (retifp != NULL) {
*retifp = ifp;
@@ -875,8 +885,7 @@ in6_selecthlim(struct inpcb *in6p, struct ifnet *ifp)
RTFREE(ro6.ro_rt);
if (lifp)
return (ND_IFINFO(lifp)->chlim);
- } else
- return (V_ip6_defhlim);
+ }
}
return (V_ip6_defhlim);
}
@@ -890,13 +899,13 @@ in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred)
{
struct socket *so = inp->inp_socket;
u_int16_t lport = 0;
- int error, wild = 0;
+ int error, lookupflags = 0;
#ifdef INVARIANTS
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
#endif
- INP_INFO_WLOCK_ASSERT(pcbinfo);
INP_WLOCK_ASSERT(inp);
+ INP_HASH_WLOCK_ASSERT(pcbinfo);
error = prison_local_ip6(cred, laddr,
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0));
@@ -905,11 +914,11 @@ in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred)
/* XXX: this is redundant when called from in6_pcbbind */
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
- wild = INPLOOKUP_WILDCARD;
+ lookupflags = INPLOOKUP_WILDCARD;
inp->inp_flags |= INP_ANONPORT;
- error = in_pcb_lport(inp, NULL, &lport, cred, wild);
+ error = in_pcb_lport(inp, NULL, &lport, cred, lookupflags);
if (error != 0)
return (error);
@@ -966,7 +975,7 @@ struct walkarg {
static int in6_src_sysctl(SYSCTL_HANDLER_ARGS);
SYSCTL_DECL(_net_inet6_ip6);
-SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy,
+static SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy,
CTLFLAG_RD, in6_src_sysctl, "");
static int
@@ -1100,6 +1109,7 @@ delete_addrsel_policyent(struct in6_addrpolicy *key)
TAILQ_REMOVE(&V_addrsel_policytab, pol, ape_entry);
ADDRSEL_UNLOCK();
ADDRSEL_XUNLOCK();
+ free(pol, M_IFADDR);
return (0);
}
diff --git a/freebsd/sys/netinet6/in6_var.h b/freebsd/sys/netinet6/in6_var.h
index 793eb540..c7ebe523 100644
--- a/freebsd/sys/netinet6/in6_var.h
+++ b/freebsd/sys/netinet6/in6_var.h
@@ -750,36 +750,37 @@ int in6_leavegroup(struct in6_multi_mship *);
/* flags to in6_update_ifa */
#define IN6_IFAUPDATE_DADDELAY 0x1 /* first time to configure an address */
-int in6_mask2len __P((struct in6_addr *, u_char *));
-int in6_control __P((struct socket *, u_long, caddr_t, struct ifnet *,
- struct thread *));
-int in6_update_ifa __P((struct ifnet *, struct in6_aliasreq *,
- struct in6_ifaddr *, int));
-void in6_purgeaddr __P((struct ifaddr *));
-int in6if_do_dad __P((struct ifnet *));
-void in6_purgeif __P((struct ifnet *));
-void in6_savemkludge __P((struct in6_ifaddr *));
-void *in6_domifattach __P((struct ifnet *));
-void in6_domifdetach __P((struct ifnet *, void *));
-void in6_setmaxmtu __P((void));
-int in6_if2idlen __P((struct ifnet *));
-struct in6_ifaddr *in6ifa_ifpforlinklocal __P((struct ifnet *, int));
-struct in6_ifaddr *in6ifa_ifpwithaddr __P((struct ifnet *, struct in6_addr *));
-char *ip6_sprintf __P((char *, const struct in6_addr *));
-int in6_addr2zoneid __P((struct ifnet *, struct in6_addr *, u_int32_t *));
-int in6_matchlen __P((struct in6_addr *, struct in6_addr *));
-int in6_are_prefix_equal __P((struct in6_addr *, struct in6_addr *, int));
-void in6_prefixlen2mask __P((struct in6_addr *, int));
-int in6_prefix_ioctl __P((struct socket *, u_long, caddr_t,
- struct ifnet *));
-int in6_prefix_add_ifid __P((int, struct in6_ifaddr *));
-void in6_prefix_remove_ifid __P((int, struct in6_ifaddr *));
-void in6_purgeprefix __P((struct ifnet *));
+int in6_mask2len(struct in6_addr *, u_char *);
+int in6_control(struct socket *, u_long, caddr_t, struct ifnet *,
+ struct thread *);
+int in6_update_ifa(struct ifnet *, struct in6_aliasreq *,
+ struct in6_ifaddr *, int);
+void in6_purgeaddr(struct ifaddr *);
+int in6if_do_dad(struct ifnet *);
+void in6_purgeif(struct ifnet *);
+void in6_savemkludge(struct in6_ifaddr *);
+void *in6_domifattach(struct ifnet *);
+void in6_domifdetach(struct ifnet *, void *);
+void in6_setmaxmtu(void);
+int in6_if2idlen(struct ifnet *);
+struct in6_ifaddr *in6ifa_ifpforlinklocal(struct ifnet *, int);
+struct in6_ifaddr *in6ifa_ifpwithaddr(struct ifnet *, struct in6_addr *);
+struct in6_ifaddr *in6ifa_llaonifp(struct ifnet *);
+char *ip6_sprintf(char *, const struct in6_addr *);
+int in6_addr2zoneid(struct ifnet *, struct in6_addr *, u_int32_t *);
+int in6_matchlen(struct in6_addr *, struct in6_addr *);
+int in6_are_prefix_equal(struct in6_addr *, struct in6_addr *, int);
+void in6_prefixlen2mask(struct in6_addr *, int);
+int in6_prefix_ioctl(struct socket *, u_long, caddr_t,
+ struct ifnet *);
+int in6_prefix_add_ifid(int, struct in6_ifaddr *);
+void in6_prefix_remove_ifid(int, struct in6_ifaddr *);
+void in6_purgeprefix(struct ifnet *);
void in6_ifremloop(struct ifaddr *);
void in6_ifaddloop(struct ifaddr *);
-int in6_is_addr_deprecated __P((struct sockaddr_in6 *));
-int in6_src_ioctl __P((u_long, caddr_t));
+int in6_is_addr_deprecated(struct sockaddr_in6 *);
+int in6_src_ioctl(u_long, caddr_t);
/*
* Extended API for IPv6 FIB support.
diff --git a/freebsd/sys/netinet6/ip6_forward.c b/freebsd/sys/netinet6/ip6_forward.c
index fa5d373f..2b45804f 100644
--- a/freebsd/sys/netinet6/ip6_forward.c
+++ b/freebsd/sys/netinet6/ip6_forward.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
+#include <rtems/bsd/local/opt_ipfw.h>
#include <rtems/bsd/local/opt_ipsec.h>
#include <rtems/bsd/local/opt_ipstealth.h>
@@ -52,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syslog.h>
#include <net/if.h>
+#include <net/netisr.h>
#include <net/route.h>
#include <net/pfil.h>
@@ -100,11 +102,15 @@ ip6_forward(struct mbuf *m, int srcrt)
struct mbuf *mcopy = NULL;
struct ifnet *origifp; /* maybe unnecessary */
u_int32_t inzone, outzone;
- struct in6_addr src_in6, dst_in6;
+ struct in6_addr src_in6, dst_in6, odst;
#ifdef IPSEC
struct secpolicy *sp = NULL;
int ipsecrt = 0;
#endif
+#ifdef SCTP
+ int sw_csum;
+#endif
+ struct m_tag *fwd_tag;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
#ifdef IPSEC
@@ -116,7 +122,7 @@ ip6_forward(struct mbuf *m, int srcrt)
* before forwarding packet actually.
*/
if (ipsec6_in_reject(m, NULL)) {
- V_ipsec6stat.in_polvio++;
+ IPSEC6STAT_INC(in_polvio);
m_freem(m);
return;
}
@@ -131,7 +137,7 @@ ip6_forward(struct mbuf *m, int srcrt)
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
if (V_ip6_log_time + V_ip6_log_interval < time_second) {
V_ip6_log_time = time_second;
@@ -178,8 +184,8 @@ ip6_forward(struct mbuf *m, int srcrt)
sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND,
IP_FORWARDING, &error);
if (sp == NULL) {
- V_ipsec6stat.out_inval++;
- V_ip6stat.ip6s_cantforward++;
+ IPSEC6STAT_INC(out_inval);
+ IP6STAT_INC(ip6s_cantforward);
if (mcopy) {
#if 0
/* XXX: what icmp ? */
@@ -199,8 +205,8 @@ ip6_forward(struct mbuf *m, int srcrt)
/*
* This packet is just discarded.
*/
- V_ipsec6stat.out_polvio++;
- V_ip6stat.ip6s_cantforward++;
+ IPSEC6STAT_INC(out_polvio);
+ IP6STAT_INC(ip6s_cantforward);
KEY_FREESP(&sp);
if (mcopy) {
#if 0
@@ -222,7 +228,7 @@ ip6_forward(struct mbuf *m, int srcrt)
if (sp->req == NULL) {
/* XXX should be panic ? */
printf("ip6_forward: No IPsec request specified.\n");
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
KEY_FREESP(&sp);
if (mcopy) {
#if 0
@@ -306,7 +312,7 @@ ip6_forward(struct mbuf *m, int srcrt)
/* don't show these error codes to the user */
break;
}
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
if (mcopy) {
#if 0
/* XXX: what icmp ? */
@@ -347,18 +353,18 @@ ip6_forward(struct mbuf *m, int srcrt)
goto skip_routing;
skip_ipsec:
#endif
-
+again:
bzero(&rin6, sizeof(struct route_in6));
dst = (struct sockaddr_in6 *)&rin6.ro_dst;
dst->sin6_len = sizeof(struct sockaddr_in6);
dst->sin6_family = AF_INET6;
dst->sin6_addr = ip6->ip6_dst;
-
+again2:
rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
if (rin6.ro_rt != NULL)
RT_UNLOCK(rin6.ro_rt);
else {
- V_ip6stat.ip6s_noroute++;
+ IP6STAT_INC(ip6s_noroute);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
if (mcopy) {
icmp6_error(mcopy, ICMP6_DST_UNREACH,
@@ -383,13 +389,13 @@ skip_routing:
src_in6 = ip6->ip6_src;
if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) {
/* XXX: this should not happen */
- V_ip6stat.ip6s_cantforward++;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_cantforward);
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
- V_ip6stat.ip6s_cantforward++;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_cantforward);
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
if (inzone != outzone
@@ -397,8 +403,8 @@ skip_routing:
&& !ipsecrt
#endif
) {
- V_ip6stat.ip6s_cantforward++;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_cantforward);
+ IP6STAT_INC(ip6s_badscope);
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
if (V_ip6_log_time + V_ip6_log_interval < time_second) {
@@ -428,8 +434,8 @@ skip_routing:
if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
inzone != outzone) {
- V_ip6stat.ip6s_cantforward++;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_cantforward);
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
@@ -556,6 +562,7 @@ skip_routing:
if (!PFIL_HOOKED(&V_inet6_pfil_hook))
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);
if (error != 0)
@@ -564,16 +571,66 @@ skip_routing:
goto freecopy;
ip6 = mtod(m, struct ip6_hdr *);
+ /* See if destination IP address was changed by packet filter. */
+ if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) {
+ m->m_flags |= M_SKIP_FIREWALL;
+ /* If destination is now ourself drop to ip6_input(). */
+ if (in6_localip(&ip6->ip6_dst)) {
+ m->m_flags |= M_FASTFWD_OURS;
+ if (m->m_pkthdr.rcvif == NULL)
+ m->m_pkthdr.rcvif = V_loif;
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
+ m->m_pkthdr.csum_flags |=
+ CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+#ifdef SCTP
+ if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
+ m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
+#endif
+ error = netisr_queue(NETISR_IPV6, m);
+ goto out;
+ } else
+ goto again; /* Redo the routing table lookup. */
+ }
+
+ /* See if local, if yes, send it to netisr. */
+ if (m->m_flags & M_FASTFWD_OURS) {
+ if (m->m_pkthdr.rcvif == NULL)
+ m->m_pkthdr.rcvif = V_loif;
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
+ m->m_pkthdr.csum_flags |=
+ CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+#ifdef SCTP
+ if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
+ m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
+#endif
+ error = netisr_queue(NETISR_IPV6, m);
+ goto out;
+ }
+ /* Or forward to some other address? */
+ if ((m->m_flags & M_IP6_NEXTHOP) &&
+ (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
+ dst = (struct sockaddr_in6 *)&rin6.ro_dst;
+ bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in6));
+ m->m_flags |= M_SKIP_FIREWALL;
+ m->m_flags &= ~M_IP6_NEXTHOP;
+ m_tag_delete(m, fwd_tag);
+ goto again2;
+ }
+
pass:
error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
if (error) {
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
} else {
- V_ip6stat.ip6s_forward++;
+ IP6STAT_INC(ip6s_forward);
in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
if (type)
- V_ip6stat.ip6s_redirectsent++;
+ IP6STAT_INC(ip6s_redirectsent);
else {
if (mcopy)
goto freecopy;
diff --git a/freebsd/sys/netinet6/ip6_input.c b/freebsd/sys/netinet6/ip6_input.c
index ee537a52..aba38ecf 100644
--- a/freebsd/sys/netinet6/ip6_input.c
+++ b/freebsd/sys/netinet6/ip6_input.c
@@ -67,7 +67,9 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
+#include <rtems/bsd/local/opt_ipfw.h>
#include <rtems/bsd/local/opt_ipsec.h>
+#include <rtems/bsd/local/opt_route.h>
#include <rtems/bsd/sys/param.h>
#include <sys/systm.h>
@@ -92,6 +94,7 @@ __FBSDID("$FreeBSD$");
#include <net/vnet.h>
#include <netinet/in.h>
+#include <netinet/ip_var.h>
#include <netinet/in_systm.h>
#include <net/if_llatbl.h>
#ifdef INET
@@ -115,6 +118,12 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6protosw.h>
+#ifdef FLOWTABLE
+#include <net/flowtable.h>
+VNET_DECLARE(int, ip6_output_flowtable_size);
+#define V_ip6_output_flowtable_size VNET(ip6_output_flowtable_size)
+#endif
+
extern struct domain inet6domain;
u_char ip6_protox[IPPROTO_MAX];
@@ -139,6 +148,9 @@ RW_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock");
static void ip6_init2(void *);
static struct ip6aux *ip6_setdstifaddr(struct mbuf *, struct in6_ifaddr *);
+static struct ip6aux *ip6_addaux(struct mbuf *);
+static struct ip6aux *ip6_findaux(struct mbuf *m);
+static void ip6_delaux (struct mbuf *);
static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
#ifdef PULLDOWN_TEST
static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
@@ -156,6 +168,8 @@ ip6_init(void)
TUNABLE_INT_FETCH("net.inet6.ip6.auto_linklocal",
&V_ip6_auto_linklocal);
+ TUNABLE_INT_FETCH("net.inet6.ip6.accept_rtadv", &V_ip6_accept_rtadv);
+ TUNABLE_INT_FETCH("net.inet6.ip6.no_radr", &V_ip6_no_radr);
TAILQ_INIT(&V_in6_ifaddrhead);
@@ -171,6 +185,24 @@ ip6_init(void)
nd6_init();
frag6_init();
+#ifdef FLOWTABLE
+ if (TUNABLE_INT_FETCH("net.inet6.ip6.output_flowtable_size",
+ &V_ip6_output_flowtable_size)) {
+ if (V_ip6_output_flowtable_size < 256)
+ V_ip6_output_flowtable_size = 256;
+ if (!powerof2(V_ip6_output_flowtable_size)) {
+ printf("flowtable must be power of 2 size\n");
+ V_ip6_output_flowtable_size = 2048;
+ }
+ } else {
+ /*
+ * round up to the next power of 2
+ */
+ V_ip6_output_flowtable_size = 1 << fls((1024 + maxusers * 64)-1);
+ }
+ V_ip6_ft = flowtable_alloc("ipv6", V_ip6_output_flowtable_size, FL_IPV6|FL_PCPU);
+#endif
+
V_ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR;
/* Skip global initialization stuff for non-default instances. */
@@ -301,6 +333,83 @@ ip6_init2(void *dummy)
/* This must be after route_init(), which is now SI_ORDER_THIRD */
SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ip6_init2, NULL);
+static int
+ip6_input_hbh(struct mbuf *m, uint32_t *plen, uint32_t *rtalert, int *off,
+ int *nxt, int *ours)
+{
+ struct ip6_hdr *ip6;
+ struct ip6_hbh *hbh;
+
+ if (ip6_hopopts_input(plen, rtalert, &m, off)) {
+#if 0 /*touches NULL pointer*/
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
+#endif
+ goto out; /* m have already been freed */
+ }
+
+ /* adjust pointer */
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ /*
+ * if the payload length field is 0 and the next header field
+ * indicates Hop-by-Hop Options header, then a Jumbo Payload
+ * option MUST be included.
+ */
+ if (ip6->ip6_plen == 0 && *plen == 0) {
+ /*
+ * Note that if a valid jumbo payload option is
+ * contained, ip6_hopopts_input() must set a valid
+ * (non-zero) payload length to the variable plen.
+ */
+ IP6STAT_INC(ip6s_badoptions);
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
+ icmp6_error(m, ICMP6_PARAM_PROB,
+ ICMP6_PARAMPROB_HEADER,
+ (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
+ goto out;
+ }
+#ifndef PULLDOWN_TEST
+ /* ip6_hopopts_input() ensures that mbuf is contiguous */
+ hbh = (struct ip6_hbh *)(ip6 + 1);
+#else
+ IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
+ sizeof(struct ip6_hbh));
+ if (hbh == NULL) {
+ IP6STAT_INC(ip6s_tooshort);
+ goto out;
+ }
+#endif
+ *nxt = hbh->ip6h_nxt;
+
+ /*
+ * If we are acting as a router and the packet contains a
+ * router alert option, see if we know the option value.
+ * Currently, we only support the option value for MLD, in which
+ * case we should pass the packet to the multicast routing
+ * daemon.
+ */
+ if (*rtalert != ~0) {
+ switch (*rtalert) {
+ case IP6OPT_RTALERT_MLD:
+ if (V_ip6_forwarding)
+ *ours = 1;
+ break;
+ default:
+ /*
+ * RFC2711 requires unrecognized values must be
+ * silently ignored.
+ */
+ break;
+ }
+ }
+
+ return (0);
+
+out:
+ return (1);
+}
+
void
ip6_input(struct mbuf *m)
{
@@ -334,26 +443,36 @@ ip6_input(struct mbuf *m)
*/
ip6_delaux(m);
+ if (m->m_flags & M_FASTFWD_OURS) {
+ /*
+ * Firewall changed destination to local.
+ */
+ m->m_flags &= ~M_FASTFWD_OURS;
+ ours = 1;
+ deliverifp = m->m_pkthdr.rcvif;
+ ip6 = mtod(m, struct ip6_hdr *);
+ goto hbhcheck;
+ }
+
/*
* mbuf statistics
*/
if (m->m_flags & M_EXT) {
if (m->m_next)
- V_ip6stat.ip6s_mext2m++;
+ IP6STAT_INC(ip6s_mext2m);
else
- V_ip6stat.ip6s_mext1++;
+ IP6STAT_INC(ip6s_mext1);
} else {
-#define M2MMAX (sizeof(V_ip6stat.ip6s_m2m)/sizeof(V_ip6stat.ip6s_m2m[0]))
if (m->m_next) {
if (m->m_flags & M_LOOP) {
- V_ip6stat.ip6s_m2m[V_loif->if_index]++;
- } else if (m->m_pkthdr.rcvif->if_index < M2MMAX)
- V_ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++;
+ IP6STAT_INC(ip6s_m2m[V_loif->if_index]);
+ } else if (m->m_pkthdr.rcvif->if_index < IP6S_M2MMAX)
+ IP6STAT_INC(
+ ip6s_m2m[m->m_pkthdr.rcvif->if_index]);
else
- V_ip6stat.ip6s_m2m[0]++;
+ IP6STAT_INC(ip6s_m2m[0]);
} else
- V_ip6stat.ip6s_m1++;
-#undef M2MMAX
+ IP6STAT_INC(ip6s_m1);
}
/* drop the packet if IPv6 operation is disabled on the IF */
@@ -363,7 +482,7 @@ ip6_input(struct mbuf *m)
}
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive);
- V_ip6stat.ip6s_total++;
+ IP6STAT_INC(ip6s_total);
#ifndef PULLDOWN_TEST
/*
@@ -401,7 +520,7 @@ ip6_input(struct mbuf *m)
struct ifnet *inifp;
inifp = m->m_pkthdr.rcvif;
if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
- V_ip6stat.ip6s_toosmall++;
+ IP6STAT_INC(ip6s_toosmall);
in6_ifstat_inc(inifp, ifs6_in_hdrerr);
return;
}
@@ -410,12 +529,12 @@ ip6_input(struct mbuf *m)
ip6 = mtod(m, struct ip6_hdr *);
if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
- V_ip6stat.ip6s_badvers++;
+ IP6STAT_INC(ip6s_badvers);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
goto bad;
}
- V_ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
+ IP6STAT_INC(ip6s_nxthist[ip6->ip6_nxt]);
/*
* Check against address spoofing/corruption.
@@ -425,7 +544,7 @@ ip6_input(struct mbuf *m)
/*
* XXX: "badscope" is not very suitable for a multicast source.
*/
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
@@ -437,7 +556,7 @@ ip6_input(struct mbuf *m)
* because ip6_mloopback() passes the "actual" interface
* as the outgoing/incoming interface.
*/
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
@@ -462,7 +581,7 @@ ip6_input(struct mbuf *m)
*/
if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
@@ -476,11 +595,18 @@ ip6_input(struct mbuf *m)
*/
if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) ||
IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) {
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
#endif
+#ifdef IPSEC
+ /*
+ * Bypass packet filtering for packets previously handled by IPsec.
+ */
+ if (ip6_ipsec_filtertunnel(m))
+ goto passin;
+#endif /* IPSEC */
/*
* Run through list of hooks for input packets.
@@ -503,6 +629,23 @@ ip6_input(struct mbuf *m)
ip6 = mtod(m, struct ip6_hdr *);
srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst);
+ if (m->m_flags & M_FASTFWD_OURS) {
+ m->m_flags &= ~M_FASTFWD_OURS;
+ ours = 1;
+ deliverifp = m->m_pkthdr.rcvif;
+ goto hbhcheck;
+ }
+ if ((m->m_flags & M_IP6_NEXTHOP) &&
+ m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) {
+ /*
+ * Directly ship the packet on. This allows forwarding
+ * packets originally destined to us to some other directly
+ * connected host.
+ */
+ ip6_forward(m, 1);
+ goto out;
+ }
+
passin:
/*
* Disambiguate address scope zones (if there is ambiguity).
@@ -515,12 +658,12 @@ passin:
* is not loopback.
*/
if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) {
- V_ip6stat.ip6s_badscope++; /* XXX */
+ IP6STAT_INC(ip6s_badscope); /* XXX */
goto bad;
}
if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) ||
in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) {
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
@@ -724,7 +867,7 @@ passin:
* and we're not a router.
*/
if (!V_ip6_forwarding) {
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
goto bad;
}
@@ -763,71 +906,11 @@ passin:
*/
plen = (u_int32_t)ntohs(ip6->ip6_plen);
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
- struct ip6_hbh *hbh;
+ int error;
- if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) {
-#if 0 /*touches NULL pointer*/
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
-#endif
- goto out; /* m have already been freed */
- }
-
- /* adjust pointer */
- ip6 = mtod(m, struct ip6_hdr *);
-
- /*
- * if the payload length field is 0 and the next header field
- * indicates Hop-by-Hop Options header, then a Jumbo Payload
- * option MUST be included.
- */
- if (ip6->ip6_plen == 0 && plen == 0) {
- /*
- * Note that if a valid jumbo payload option is
- * contained, ip6_hopopts_input() must set a valid
- * (non-zero) payload length to the variable plen.
- */
- V_ip6stat.ip6s_badoptions++;
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
+ error = ip6_input_hbh(m, &plen, &rtalert, &off, &nxt, &ours);
+ if (error != 0)
goto out;
- }
-#ifndef PULLDOWN_TEST
- /* ip6_hopopts_input() ensures that mbuf is contiguous */
- hbh = (struct ip6_hbh *)(ip6 + 1);
-#else
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
- sizeof(struct ip6_hbh));
- if (hbh == NULL) {
- V_ip6stat.ip6s_tooshort++;
- goto out;
- }
-#endif
- nxt = hbh->ip6h_nxt;
-
- /*
- * If we are acting as a router and the packet contains a
- * router alert option, see if we know the option value.
- * Currently, we only support the option value for MLD, in which
- * case we should pass the packet to the multicast routing
- * daemon.
- */
- if (rtalert != ~0) {
- switch (rtalert) {
- case IP6OPT_RTALERT_MLD:
- if (V_ip6_forwarding)
- ours = 1;
- break;
- default:
- /*
- * RFC2711 requires unrecognized values must be
- * silently ignored.
- */
- break;
- }
- }
} else
nxt = ip6->ip6_nxt;
@@ -838,7 +921,7 @@ passin:
* Drop packet if shorter than we expect.
*/
if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
goto bad;
}
@@ -890,7 +973,7 @@ passin:
*/
if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
@@ -898,13 +981,13 @@ passin:
/*
* Tell launch routine the next header
*/
- V_ip6stat.ip6s_delivered++;
+ IP6STAT_INC(ip6s_delivered);
in6_ifstat_inc(deliverifp, ifs6_in_deliver);
nest = 0;
while (nxt != IPPROTO_DONE) {
if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) {
- V_ip6stat.ip6s_toomanyhdr++;
+ IP6STAT_INC(ip6s_toomanyhdr);
goto bad;
}
@@ -913,7 +996,7 @@ passin:
* more sanity checks in header chain processing.
*/
if (m->m_pkthdr.len < off) {
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
goto bad;
}
@@ -1007,14 +1090,14 @@ ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp,
IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
if (hbh == NULL) {
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
return -1;
}
hbhlen = (hbh->ip6h_len + 1) << 3;
IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
hbhlen);
if (hbh == NULL) {
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
return -1;
}
#endif
@@ -1039,7 +1122,7 @@ ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp,
*
* The function assumes that hbh header is located right after the IPv6 header
* (RFC2460 p7), opthead is pointer into data content in m, and opthead to
- * opthead + hbhlen is located in continuous memory region.
+ * opthead + hbhlen is located in contiguous memory region.
*/
int
ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
@@ -1059,7 +1142,7 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
break;
case IP6OPT_PADN:
if (hbhlen < IP6OPT_MINLEN) {
- V_ip6stat.ip6s_toosmall++;
+ IP6STAT_INC(ip6s_toosmall);
goto bad;
}
optlen = *(opt + 1) + 2;
@@ -1067,7 +1150,7 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
case IP6OPT_ROUTER_ALERT:
/* XXX may need check for alignment */
if (hbhlen < IP6OPT_RTALERT_LEN) {
- V_ip6stat.ip6s_toosmall++;
+ IP6STAT_INC(ip6s_toosmall);
goto bad;
}
if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) {
@@ -1084,7 +1167,7 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
case IP6OPT_JUMBO:
/* XXX may need check for alignment */
if (hbhlen < IP6OPT_JUMBO_LEN) {
- V_ip6stat.ip6s_toosmall++;
+ IP6STAT_INC(ip6s_toosmall);
goto bad;
}
if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) {
@@ -1102,7 +1185,7 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
*/
ip6 = mtod(m, struct ip6_hdr *);
if (ip6->ip6_plen) {
- V_ip6stat.ip6s_badoptions++;
+ IP6STAT_INC(ip6s_badoptions);
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
erroff + opt - opthead);
@@ -1126,7 +1209,7 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
* there's no explicit mention in specification.
*/
if (*plenp != 0) {
- V_ip6stat.ip6s_badoptions++;
+ IP6STAT_INC(ip6s_badoptions);
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
erroff + opt + 2 - opthead);
@@ -1138,7 +1221,7 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
* jumbo payload length must be larger than 65535.
*/
if (jumboplen <= IPV6_MAXPACKET) {
- V_ip6stat.ip6s_badoptions++;
+ IP6STAT_INC(ip6s_badoptions);
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
erroff + opt + 2 - opthead);
@@ -1149,7 +1232,7 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
break;
default: /* unknown option */
if (hbhlen < IP6OPT_MINLEN) {
- V_ip6stat.ip6s_toosmall++;
+ IP6STAT_INC(ip6s_toosmall);
goto bad;
}
optlen = ip6_unknown_opt(opt, m,
@@ -1172,7 +1255,7 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
* Unknown option processing.
* The third argument `off' is the offset from the IPv6 header to the option,
* which is necessary if the IPv6 header the and option header and IPv6 header
- * is not continuous in order to return an ICMPv6 error.
+ * is not contiguous in order to return an ICMPv6 error.
*/
int
ip6_unknown_opt(u_int8_t *optp, struct mbuf *m, int off)
@@ -1186,11 +1269,11 @@ ip6_unknown_opt(u_int8_t *optp, struct mbuf *m, int off)
m_freem(m);
return (-1);
case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */
- V_ip6stat.ip6s_badoptions++;
+ IP6STAT_INC(ip6s_badoptions);
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off);
return (-1);
case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */
- V_ip6stat.ip6s_badoptions++;
+ IP6STAT_INC(ip6s_badoptions);
ip6 = mtod(m, struct ip6_hdr *);
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
(m->m_flags & (M_BCAST|M_MCAST)))
@@ -1369,14 +1452,14 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr),
ip6->ip6_nxt);
if (ext == NULL) {
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
return;
}
hbh = mtod(ext, struct ip6_hbh *);
hbhlen = (hbh->ip6h_len + 1) << 3;
if (hbhlen != ext->m_len) {
m_freem(ext);
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
return;
}
#endif
@@ -1443,7 +1526,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
#else
ext = ip6_pullexthdr(m, off, nxt);
if (ext == NULL) {
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
return;
}
ip6e = mtod(ext, struct ip6_ext *);
@@ -1453,7 +1536,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
elen = (ip6e->ip6e_len + 1) << 3;
if (elen != ext->m_len) {
m_freem(ext);
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
return;
}
#endif
@@ -1471,7 +1554,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
mp = &(*mp)->m_next;
break;
case IPPROTO_ROUTING:
- if (!in6p->inp_flags & IN6P_RTHDR)
+ if (!(in6p->inp_flags & IN6P_RTHDR))
break;
*mp = sbcreatecontrol((caddr_t)ip6e, elen,
@@ -1753,7 +1836,7 @@ ip6_lasthdr(struct mbuf *m, int off, int proto, int *nxtp)
}
}
-struct ip6aux *
+static struct ip6aux *
ip6_addaux(struct mbuf *m)
{
struct m_tag *mtag;
@@ -1770,7 +1853,7 @@ ip6_addaux(struct mbuf *m)
return mtag ? (struct ip6aux *)(mtag + 1) : NULL;
}
-struct ip6aux *
+static struct ip6aux *
ip6_findaux(struct mbuf *m)
{
struct m_tag *mtag;
@@ -1779,7 +1862,7 @@ ip6_findaux(struct mbuf *m)
return mtag ? (struct ip6aux *)(mtag + 1) : NULL;
}
-void
+static void
ip6_delaux(struct mbuf *m)
{
struct m_tag *mtag;
diff --git a/freebsd/sys/netinet6/ip6_ipsec.c b/freebsd/sys/netinet6/ip6_ipsec.c
index d0b075da..fe61dab9 100644
--- a/freebsd/sys/netinet6/ip6_ipsec.c
+++ b/freebsd/sys/netinet6/ip6_ipsec.c
@@ -32,6 +32,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
#include <rtems/bsd/local/opt_ipsec.h>
@@ -45,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
+#include <sys/syslog.h>
#include <net/if.h>
#include <net/route.h>
@@ -152,7 +154,7 @@ ip6_ipsec_fwd(struct mbuf *m)
KEY_FREESP(&sp);
splx(s);
if (error) {
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
return 1;
}
#endif /* IPSEC */
@@ -291,11 +293,16 @@ ip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error,
/*
* Do delayed checksums now because we send before
* this is done in the normal processing path.
+ * For IPv6 we do delayed checksums in ip6_output.c.
*/
+#ifdef INET
if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+ ipseclog((LOG_DEBUG,
+ "%s: we do not support IPv4 over IPv6", __func__));
in_delayed_cksum(*m);
(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
}
+#endif
/*
* Preserve KAME behaviour: ENOENT can be returned
diff --git a/freebsd/sys/netinet6/ip6_mroute.c b/freebsd/sys/netinet6/ip6_mroute.c
index 3188a13e..00eab8ed 100644
--- a/freebsd/sys/netinet6/ip6_mroute.c
+++ b/freebsd/sys/netinet6/ip6_mroute.c
@@ -157,13 +157,14 @@ static VNET_DEFINE(int, ip6_mrouter_ver) = 0;
SYSCTL_DECL(_net_inet6);
SYSCTL_DECL(_net_inet6_ip6);
-SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM");
+static SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM");
static struct mrt6stat mrt6stat;
SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW,
&mrt6stat, mrt6stat,
"Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)");
+#define MRT6STAT_INC(name) mrt6stat.name += 1
#define NO_RTE_FOUND 0x1
#define RTE_FOUND 0x2
@@ -251,10 +252,11 @@ static mifi_t nummifs = 0;
static mifi_t reg_mif_num = (mifi_t)-1;
static struct pim6stat pim6stat;
-SYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RD,
+SYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RW,
&pim6stat, pim6stat,
- "PIM Statistics (struct pim6stat, netinet6/pim_var.h)");
+ "PIM Statistics (struct pim6stat, netinet6/pim6_var.h)");
+#define PIM6STAT_INC(name) pim6stat.name += 1
static VNET_DEFINE(int, pim6);
#define V_pim6 VNET(pim6)
@@ -272,7 +274,7 @@ static VNET_DEFINE(int, pim6);
#define MF6CFIND(o, g, rt) do { \
struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
rt = NULL; \
- mrt6stat.mrt6s_mfc_lookups++; \
+ MRT6STAT_INC(mrt6s_mfc_lookups); \
while (_rt) { \
if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \
IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \
@@ -283,7 +285,7 @@ static VNET_DEFINE(int, pim6);
_rt = _rt->mf6c_next; \
} \
if (rt == NULL) { \
- mrt6stat.mrt6s_mfc_misses++; \
+ MRT6STAT_INC(mrt6s_mfc_misses); \
} \
} while (/*CONSTCOND*/ 0)
@@ -718,7 +720,6 @@ add_m6if(struct mif6ctl *mifcp)
mifp->m6_pkt_out = 0;
mifp->m6_bytes_in = 0;
mifp->m6_bytes_out = 0;
- bzero(&mifp->m6_route, sizeof(mifp->m6_route));
/* Adjust nummifs up if the mifi is higher than nummifs */
if (nummifs <= mifcp->mif6c_mifi)
@@ -1103,7 +1104,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
* (although such packets must normally set 1 to the hop limit field).
*/
if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
- V_ip6stat.ip6s_cantforward++;
+ IP6STAT_INC(ip6s_cantforward);
if (V_ip6_log_time + V_ip6_log_interval < time_second) {
V_ip6_log_time = time_second;
log(LOG_DEBUG,
@@ -1145,7 +1146,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
GET_TIME(tp);
#endif /* UPCALL_TIMING */
- mrt6stat.mrt6s_no_route++;
+ MRT6STAT_INC(mrt6s_no_route);
#ifdef MRT6DEBUG
if (V_mrt6debug & (DEBUG_FORWARD | DEBUG_MFC))
log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n",
@@ -1272,7 +1273,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
"socket queue full\n");
- mrt6stat.mrt6s_upq_sockfull++;
+ MRT6STAT_INC(mrt6s_upq_sockfull);
free(rte, M_MRTABLE6);
m_freem(mb0);
free(rt, M_MRTABLE6);
@@ -1280,7 +1281,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
return (ENOBUFS);
}
- mrt6stat.mrt6s_upcalls++;
+ MRT6STAT_INC(mrt6s_upcalls);
/* insert new entry at head of hash chain */
bzero(rt, sizeof(*rt));
@@ -1306,7 +1307,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
if (++npkts > MAX_UPQ6) {
- mrt6stat.mrt6s_upq_ovflw++;
+ MRT6STAT_INC(mrt6s_upq_ovflw);
free(rte, M_MRTABLE6);
m_freem(mb0);
MFC6_UNLOCK();
@@ -1375,7 +1376,7 @@ expire_upcalls(void *unused)
free(rte, M_MRTABLE6);
rte = n;
} while (rte != NULL);
- mrt6stat.mrt6s_cache_cleanups++;
+ MRT6STAT_INC(mrt6s_cache_cleanups);
n6expire[i]--;
*nptr = mfc->mf6c_next;
@@ -1431,7 +1432,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
ifp->if_index, mifi,
mif6table[mifi].m6_ifp->if_index);
#endif
- mrt6stat.mrt6s_wrong_if++;
+ MRT6STAT_INC(mrt6s_wrong_if);
rt->mf6c_wrong_if++;
/*
* If we are doing PIM processing, and we are forwarding
@@ -1504,14 +1505,14 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
break;
}
- mrt6stat.mrt6s_upcalls++;
+ MRT6STAT_INC(mrt6s_upcalls);
if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
#ifdef MRT6DEBUG
if (V_mrt6debug)
log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
#endif
- ++mrt6stat.mrt6s_upq_sockfull;
+ MRT6STAT_INC(mrt6s_upq_sockfull);
return (ENOBUFS);
} /* if socket Q full */
} /* if PIM */
@@ -1538,7 +1539,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
dst0 = ip6->ip6_dst;
if ((error = in6_setscope(&src0, ifp, &iszone)) != 0 ||
(error = in6_setscope(&dst0, ifp, &idzone)) != 0) {
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
return (error);
}
for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) {
@@ -1558,7 +1559,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
&odzone) ||
iszone != oszone ||
idzone != odzone) {
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
continue;
}
}
@@ -1577,11 +1578,8 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
struct mbuf *mb_copy;
struct ifnet *ifp = mifp->m6_ifp;
int error = 0;
- struct sockaddr_in6 *dst6;
u_long linkmtu;
- dst6 = &mifp->m6_route.ro_dst;
-
/*
* Make a new reference to the packet; make sure that
* the IPv6 header is actually copied, not just referenced,
@@ -1611,8 +1609,8 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
/* XXX: ip6_output will override ip6->ip6_hlim */
im6o.im6o_multicast_hlim = ip6->ip6_hlim;
im6o.im6o_multicast_loop = 1;
- error = ip6_output(mb_copy, NULL, &mifp->m6_route,
- IPV6_FORWARDING, &im6o, NULL, NULL);
+ error = ip6_output(mb_copy, NULL, NULL, IPV6_FORWARDING, &im6o,
+ NULL, NULL);
#ifdef MRT6DEBUG
if (V_mrt6debug & DEBUG_XMIT)
@@ -1627,10 +1625,13 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
* loop back a copy now.
*/
if (in6_mcast_loop) {
- dst6->sin6_len = sizeof(struct sockaddr_in6);
- dst6->sin6_family = AF_INET6;
- dst6->sin6_addr = ip6->ip6_dst;
- ip6_mloopback(ifp, m, &mifp->m6_route.ro_dst);
+ struct sockaddr_in6 dst6;
+
+ bzero(&dst6, sizeof(dst6));
+ dst6.sin6_len = sizeof(struct sockaddr_in6);
+ dst6.sin6_family = AF_INET6;
+ dst6.sin6_addr = ip6->ip6_dst;
+ ip6_mloopback(ifp, m, &dst6);
}
/*
@@ -1639,15 +1640,18 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
*/
linkmtu = IN6_LINKMTU(ifp);
if (mb_copy->m_pkthdr.len <= linkmtu || linkmtu < IPV6_MMTU) {
- dst6->sin6_len = sizeof(struct sockaddr_in6);
- dst6->sin6_family = AF_INET6;
- dst6->sin6_addr = ip6->ip6_dst;
+ struct sockaddr_in6 dst6;
+
+ bzero(&dst6, sizeof(dst6));
+ dst6.sin6_len = sizeof(struct sockaddr_in6);
+ dst6.sin6_family = AF_INET6;
+ dst6.sin6_addr = ip6->ip6_dst;
/*
* We just call if_output instead of nd6_output here, since
* we need no ND for a multicast forwarded packet...right?
*/
error = (*ifp->if_output)(ifp, mb_copy,
- (struct sockaddr *)&mifp->m6_route.ro_dst, NULL);
+ (struct sockaddr *)&dst6, NULL);
#ifdef MRT6DEBUG
if (V_mrt6debug & DEBUG_XMIT)
log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
@@ -1696,7 +1700,7 @@ register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
ip6_sprintf(ip6bufd, &ip6->ip6_dst));
}
#endif
- ++pim6stat.pim6s_snd_registers;
+ PIM6STAT_INC(pim6s_snd_registers);
/* Make a copy of the packet to send to the user level process */
MGETHDR(mm, M_DONTWAIT, MT_HEADER);
@@ -1731,7 +1735,7 @@ register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
im6->im6_mif = mif - mif6table;
/* iif info is not given for reg. encap.n */
- mrt6stat.mrt6s_upcalls++;
+ MRT6STAT_INC(mrt6s_upcalls);
if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
#ifdef MRT6DEBUG
@@ -1739,7 +1743,7 @@ register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
log(LOG_WARNING,
"register_send: ip6_mrouter socket queue full\n");
#endif
- ++mrt6stat.mrt6s_upq_sockfull;
+ MRT6STAT_INC(mrt6s_upq_sockfull);
return (ENOBUFS);
}
return (0);
@@ -1780,7 +1784,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
int minlen;
int off = *offp;
- ++pim6stat.pim6s_rcv_total;
+ PIM6STAT_INC(pim6s_rcv_total);
ip6 = mtod(m, struct ip6_hdr *);
pimlen = m->m_pkthdr.len - *offp;
@@ -1789,7 +1793,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
* Validate lengths
*/
if (pimlen < PIM_MINLEN) {
- ++pim6stat.pim6s_rcv_tooshort;
+ PIM6STAT_INC(pim6s_rcv_tooshort);
#ifdef MRT6DEBUG
if (V_mrt6debug & DEBUG_PIM)
log(LOG_DEBUG,"pim6_input: PIM packet too short\n");
@@ -1822,7 +1826,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
#else
IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen);
if (pim == NULL) {
- pim6stat.pim6s_rcv_tooshort++;
+ PIM6STAT_INC(pim6s_rcv_tooshort);
return (IPPROTO_DONE);
}
#endif
@@ -1842,7 +1846,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
cksumlen = pimlen;
if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) {
- ++pim6stat.pim6s_rcv_badsum;
+ PIM6STAT_INC(pim6s_rcv_badsum);
#ifdef MRT6DEBUG
if (V_mrt6debug & DEBUG_PIM)
log(LOG_DEBUG,
@@ -1856,7 +1860,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
/* PIM version check */
if (pim->pim_ver != PIM_VERSION) {
- ++pim6stat.pim6s_rcv_badversion;
+ PIM6STAT_INC(pim6s_rcv_badversion);
#ifdef MRT6DEBUG
log(LOG_ERR,
"pim6_input: incorrect version %d, expecting %d\n",
@@ -1882,7 +1886,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
#endif
- ++pim6stat.pim6s_rcv_registers;
+ PIM6STAT_INC(pim6s_rcv_registers);
if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {
#ifdef MRT6DEBUG
@@ -1904,8 +1908,8 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
* Validate length
*/
if (pimlen < PIM6_REG_MINLEN) {
- ++pim6stat.pim6s_rcv_tooshort;
- ++pim6stat.pim6s_rcv_badregisters;
+ PIM6STAT_INC(pim6s_rcv_tooshort);
+ PIM6STAT_INC(pim6s_rcv_badregisters);
#ifdef MRT6DEBUG
log(LOG_ERR,
"pim6_input: register packet size too "
@@ -1929,7 +1933,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
/* verify the version number of the inner packet */
if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
- ++pim6stat.pim6s_rcv_badregisters;
+ PIM6STAT_INC(pim6s_rcv_badregisters);
#ifdef MRT6DEBUG
log(LOG_DEBUG, "pim6_input: invalid IP version (%d) "
"of the inner packet\n",
@@ -1941,7 +1945,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
/* verify the inner packet is destined to a mcast group */
if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
- ++pim6stat.pim6s_rcv_badregisters;
+ PIM6STAT_INC(pim6s_rcv_badregisters);
#ifdef MRT6DEBUG
if (V_mrt6debug & DEBUG_PIM)
log(LOG_DEBUG,
diff --git a/freebsd/sys/netinet6/ip6_mroute.h b/freebsd/sys/netinet6/ip6_mroute.h
index 701d5345..d2df0dbe 100644
--- a/freebsd/sys/netinet6/ip6_mroute.h
+++ b/freebsd/sys/netinet6/ip6_mroute.h
@@ -212,7 +212,6 @@ struct mif6 {
u_quad_t m6_pkt_out; /* # pkts out on interface */
u_quad_t m6_bytes_in; /* # bytes in on interface */
u_quad_t m6_bytes_out; /* # bytes out on interface */
- struct route_in6 m6_route; /* cached route */
#ifdef notyet
u_int m6_rsvp_on; /* RSVP listening on this vif */
struct socket *m6_rsvpd; /* RSVP daemon socket */
diff --git a/freebsd/sys/netinet6/ip6_output.c b/freebsd/sys/netinet6/ip6_output.c
index a92e68ec..06f1246a 100644
--- a/freebsd/sys/netinet6/ip6_output.c
+++ b/freebsd/sys/netinet6/ip6_output.c
@@ -67,8 +67,10 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
+#include <rtems/bsd/local/opt_ipfw.h>
#include <rtems/bsd/local/opt_ipsec.h>
#include <rtems/bsd/local/opt_sctp.h>
+#include <rtems/bsd/local/opt_route.h>
#include <rtems/bsd/sys/param.h>
#include <sys/kernel.h>
@@ -83,6 +85,8 @@ __FBSDID("$FreeBSD$");
#include <sys/syslog.h>
#include <sys/ucred.h>
+#include <machine/in_cksum.h>
+
#include <net/if.h>
#include <net/netisr.h>
#include <net/route.h>
@@ -91,6 +95,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
@@ -113,6 +118,10 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6protosw.h>
#include <netinet6/scope6_var.h>
+#ifdef FLOWTABLE
+#include <net/flowtable.h>
+#endif
+
extern int in6_mcast_loop;
struct ip6_exthdrs {
@@ -123,21 +132,21 @@ struct ip6_exthdrs {
struct mbuf *ip6e_dest2;
};
-static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **,
- struct ucred *, int));
-static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
- struct socket *, struct sockopt *));
+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_setpktopt __P((int, u_char *, int, struct ip6_pktopts *,
- struct ucred *, int, int, int));
+static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *,
+ struct ucred *, int, int, int);
static int ip6_copyexthdr(struct mbuf **, caddr_t, int);
-static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
- struct ip6_frag **));
+static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int,
+ struct ip6_frag **);
static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
-static int ip6_getpmtu __P((struct route_in6 *, struct route_in6 *,
- struct ifnet *, struct in6_addr *, u_long *, int *, u_int));
+static int ip6_getpmtu(struct route_in6 *, struct route_in6 *,
+ struct ifnet *, struct in6_addr *, u_long *, int *, u_int);
static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
@@ -177,12 +186,39 @@ static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
}\
} while (/*CONSTCOND*/ 0)
+static void
+in6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset)
+{
+ u_short csum;
+
+ csum = in_cksum_skip(m, offset + plen, offset);
+ if (m->m_pkthdr.csum_flags & CSUM_UDP_IPV6 && csum == 0)
+ csum = 0xffff;
+ offset += m->m_pkthdr.csum_data; /* checksum offset */
+
+ if (offset + sizeof(u_short) > m->m_len) {
+ printf("%s: delayed m_pullup, m->len: %d plen %u off %u "
+ "csum_flags=0x%04x\n", __func__, m->m_len, plen, offset,
+ m->m_pkthdr.csum_flags);
+ /*
+ * XXX this should not happen, but if it does, the correct
+ * behavior may be to insert the checksum in the appropriate
+ * next mbuf in the chain.
+ */
+ return;
+ }
+ *(u_short *)(m->m_data + offset) = csum;
+}
+
/*
* IP6 output. The packet in mbuf chain m contains a skeletal IP6
* header (with pri, len, nxt, hlim, src, dst).
* This function may modify ver and hlim only.
* The mbuf chain containing the packet will be freed.
* The mbuf opt, if present, will not be freed.
+ * If route_in6 ro is present and has ro_rt initialized, route lookup would be
+ * skipped and ro->ro_rt would be used. If ro is present but ro->ro_rt is NULL,
+ * then result of route lookup is stored in ro->ro_rt.
*
* type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and
* nd_ifinfo.linkmtu is u_int32_t. so we use u_long to hold largest one,
@@ -215,9 +251,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
struct route_in6 *ro_pmtu = NULL;
int hdrsplit = 0;
int needipsec = 0;
-#ifdef SCTP
- int sw_csum;
-#endif
+ int sw_csum, tso;
#ifdef IPSEC
struct ipsec_output_state state;
struct ip6_rthdr *rh = NULL;
@@ -225,6 +259,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
int segleft_org = 0;
struct secpolicy *sp = NULL;
#endif /* IPSEC */
+ struct m_tag *fwd_tag = NULL;
ip6 = mtod(m, struct ip6_hdr *);
if (ip6 == NULL) {
@@ -236,9 +271,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
M_SETFIB(m, inp->inp_inc.inc_fibnum);
finaldst = ip6->ip6_dst;
-
bzero(&exthdrs, sizeof(exthdrs));
-
if (opt) {
/* Hop-by-Hop options header */
MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
@@ -273,6 +306,20 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
goto freehdrs;
case -1: /* Do IPSec */
needipsec = 1;
+ /*
+ * Do delayed checksums now, as we may send before returning.
+ */
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
+ plen = m->m_pkthdr.len - sizeof(*ip6);
+ in6_delayed_cksum(m, plen, sizeof(struct ip6_hdr));
+ m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
+ }
+#ifdef SCTP
+ if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) {
+ sctp_delayed_cksum(m, sizeof(struct ip6_hdr));
+ m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6;
+ }
+#endif
case 0: /* No IPSec */
default:
break;
@@ -453,16 +500,16 @@ skip_ipsec2:;
if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) &&
(flags & IPV6_UNSPECSRC) == 0) {
error = EOPNOTSUPP;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
error = EOPNOTSUPP;
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
goto bad;
}
- V_ip6stat.ip6s_localout++;
+ IP6STAT_INC(ip6s_localout);
/*
* Route packet.
@@ -475,7 +522,21 @@ skip_ipsec2:;
if (opt && opt->ip6po_rthdr)
ro = &opt->ip6po_route;
dst = (struct sockaddr_in6 *)&ro->ro_dst;
+#ifdef FLOWTABLE
+ if (ro->ro_rt == NULL) {
+ struct flentry *fle;
+ /*
+ * The flow table returns route entries valid for up to 30
+ * seconds; we rely on the remainder of ip_output() taking no
+ * longer than that long for the stability of ro_rt. The
+ * flow ID assignment must have happened before this point.
+ */
+ fle = flowtable_lookup_mbuf(V_ip6_ft, m, AF_INET6);
+ if (fle != NULL)
+ flow_to_route_in6(fle, ro);
+ }
+#endif
again:
/*
* if specified, try to fill in the traffic class field.
@@ -577,23 +638,23 @@ again:
/* adjust pointer */
ip6 = mtod(m, struct ip6_hdr *);
- 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 ((error = in6_selectroute_fib(&dst_sa, opt, im6o, ro,
- &ifp, &rt, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m))) != 0) {
- switch (error) {
- case EHOSTUNREACH:
- V_ip6stat.ip6s_noroute++;
- break;
- case EADDRNOTAVAIL:
- default:
- break; /* XXX statistics? */
+ if (ro->ro_rt && fwd_tag == NULL) {
+ rt = ro->ro_rt;
+ ifp = ro->ro_rt->rt_ifp;
+ } else {
+ if (fwd_tag == NULL) {
+ 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;
+ }
+ error = in6_selectroute_fib(&dst_sa, opt, im6o, ro, &ifp,
+ &rt, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m));
+ if (error != 0) {
+ if (ifp != NULL)
+ in6_ifstat_inc(ifp, ifs6_out_discard);
+ goto bad;
}
- if (ifp != NULL)
- in6_ifstat_inc(ifp, ifs6_out_discard);
- goto bad;
}
if (rt == NULL) {
/*
@@ -618,7 +679,7 @@ again:
/*
* The outgoing interface must be in the zone of source and
- * destination addresses.
+ * destination addresses.
*/
origifp = ifp;
@@ -644,7 +705,7 @@ again:
goto badscope;
}
- /* We should use ia_ifp to support the case of
+ /* We should use ia_ifp to support the case of
* sending packets to an address of our own.
*/
if (ia != NULL && ia->ia_ifp)
@@ -654,7 +715,7 @@ again:
goto routefound;
badscope:
- V_ip6stat.ip6s_badscope++;
+ IP6STAT_INC(ip6s_badscope);
in6_ifstat_inc(origifp, ifs6_out_discard);
if (error == 0)
error = EHOSTUNREACH; /* XXX */
@@ -683,7 +744,7 @@ again:
* Confirm that the outgoing interface supports multicast.
*/
if (!(ifp->if_flags & IFF_MULTICAST)) {
- V_ip6stat.ip6s_noroute++;
+ IP6STAT_INC(ip6s_noroute);
in6_ifstat_inc(ifp, ifs6_out_discard);
error = ENETUNREACH;
goto bad;
@@ -796,13 +857,13 @@ again:
#ifdef DIAGNOSTIC
if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len)
- panic("ip6e_hbh is not continuous");
+ panic("ip6e_hbh is not contiguous");
#endif
/*
* XXX: if we have to send an ICMPv6 error to the sender,
* we need the M_LOOP flag since icmp6_error() expects
* the IPv6 and the hop-by-hop options header are
- * continuous unless the flag is set.
+ * contiguous unless the flag is set.
*/
m->m_flags |= M_LOOP;
m->m_pkthdr.rcvif = ifp;
@@ -832,18 +893,17 @@ again:
if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) {
m->m_flags |= M_SKIP_FIREWALL;
/* If destination is now ourself drop to ip6_input(). */
- if (in6_localaddr(&ip6->ip6_dst)) {
+ if (in6_localip(&ip6->ip6_dst)) {
+ m->m_flags |= M_FASTFWD_OURS;
if (m->m_pkthdr.rcvif == NULL)
m->m_pkthdr.rcvif = V_loif;
- if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
m->m_pkthdr.csum_flags |=
- CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+ CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
m->m_pkthdr.csum_data = 0xffff;
}
- m->m_pkthdr.csum_flags |=
- CSUM_IP_CHECKED | CSUM_IP_VALID;
#ifdef SCTP
- if (m->m_pkthdr.csum_flags & CSUM_SCTP)
+ if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
#endif
error = netisr_queue(NETISR_IPV6, m);
@@ -852,7 +912,32 @@ again:
goto again; /* Redo the routing table lookup. */
}
- /* XXX: IPFIREWALL_FORWARD */
+ /* See if local, if yes, send it to netisr. */
+ if (m->m_flags & M_FASTFWD_OURS) {
+ if (m->m_pkthdr.rcvif == NULL)
+ m->m_pkthdr.rcvif = V_loif;
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
+ m->m_pkthdr.csum_flags |=
+ CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+#ifdef SCTP
+ if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
+ m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
+#endif
+ error = netisr_queue(NETISR_IPV6, m);
+ goto done;
+ }
+ /* Or forward to some other address? */
+ if ((m->m_flags & M_IP6_NEXTHOP) &&
+ (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
+ dst = (struct sockaddr_in6 *)&ro->ro_dst;
+ bcopy((fwd_tag+1), &dst_sa, sizeof(struct sockaddr_in6));
+ m->m_flags |= M_SKIP_FIREWALL;
+ m->m_flags &= ~M_IP6_NEXTHOP;
+ m_tag_delete(m, fwd_tag);
+ goto again;
+ }
passout:
/*
@@ -874,16 +959,32 @@ passout:
* 4: if dontfrag == 1 && alwaysfrag == 1
* error, as we cannot handle this conflicting request
*/
+ sw_csum = m->m_pkthdr.csum_flags;
+ if (!hdrsplit) {
+ tso = ((sw_csum & ifp->if_hwassist & CSUM_TSO) != 0) ? 1 : 0;
+ sw_csum &= ~ifp->if_hwassist;
+ } else
+ tso = 0;
+ /*
+ * If we added extension headers, we will not do TSO and calculate the
+ * checksums ourselves for now.
+ * XXX-BZ Need a framework to know when the NIC can handle it, even
+ * with ext. hdrs.
+ */
+ if (sw_csum & CSUM_DELAY_DATA_IPV6) {
+ sw_csum &= ~CSUM_DELAY_DATA_IPV6;
+ in6_delayed_cksum(m, plen, sizeof(struct ip6_hdr));
+ }
#ifdef SCTP
- sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist;
- if (sw_csum & CSUM_SCTP) {
+ if (sw_csum & CSUM_SCTP_IPV6) {
+ sw_csum &= ~CSUM_SCTP_IPV6;
sctp_delayed_cksum(m, sizeof(struct ip6_hdr));
- sw_csum &= ~CSUM_SCTP;
}
#endif
+ m->m_pkthdr.csum_flags &= ifp->if_hwassist;
tlen = m->m_pkthdr.len;
- if (opt && (opt->ip6po_flags & IP6PO_DONTFRAG))
+ if ((opt && (opt->ip6po_flags & IP6PO_DONTFRAG)) || tso)
dontfrag = 1;
else
dontfrag = 0;
@@ -892,7 +993,7 @@ passout:
error = EMSGSIZE;
goto bad;
}
- if (dontfrag && tlen > IN6_LINKMTU(ifp)) { /* case 2-b */
+ if (dontfrag && tlen > IN6_LINKMTU(ifp) && !tso) { /* case 2-b */
/*
* Even if the DONTFRAG option is specified, we cannot send the
* packet when the data length is larger than the MTU of the
@@ -976,10 +1077,26 @@ passout:
if (qslots <= 0 || ((u_int)qslots * (mtu - hlen)
< tlen /* - hlen */)) {
error = ENOBUFS;
- V_ip6stat.ip6s_odropped++;
+ IP6STAT_INC(ip6s_odropped);
goto bad;
}
+
+ /*
+ * If the interface will not calculate checksums on
+ * fragmented packets, then do it here.
+ * XXX-BZ handle the hw offloading case. Need flags.
+ */
+ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
+ 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) {
+ sctp_delayed_cksum(m, hlen);
+ m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6;
+ }
+#endif
mnext = &m->m_nextpkt;
/*
@@ -1010,7 +1127,7 @@ passout:
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (!m) {
error = ENOBUFS;
- V_ip6stat.ip6s_odropped++;
+ IP6STAT_INC(ip6s_odropped);
goto sendorfree;
}
m->m_pkthdr.rcvif = NULL;
@@ -1023,7 +1140,7 @@ passout:
m->m_len = sizeof(*mhip6);
error = ip6_insertfraghdr(m0, m, hlen, &ip6f);
if (error) {
- V_ip6stat.ip6s_odropped++;
+ IP6STAT_INC(ip6s_odropped);
goto sendorfree;
}
ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7));
@@ -1035,7 +1152,7 @@ passout:
sizeof(*ip6f) - sizeof(struct ip6_hdr)));
if ((m_frgpart = m_copy(m0, off, len)) == 0) {
error = ENOBUFS;
- V_ip6stat.ip6s_odropped++;
+ IP6STAT_INC(ip6s_odropped);
goto sendorfree;
}
m_cat(m, m_frgpart);
@@ -1044,7 +1161,7 @@ passout:
ip6f->ip6f_reserved = 0;
ip6f->ip6f_ident = id;
ip6f->ip6f_nxt = nextproto;
- V_ip6stat.ip6s_ofragments++;
+ IP6STAT_INC(ip6s_ofragments);
in6_ifstat_inc(ifp, ifs6_out_fragcreat);
}
@@ -1073,14 +1190,13 @@ sendorfree:
}
if (error == 0)
- V_ip6stat.ip6s_fragmented++;
+ IP6STAT_INC(ip6s_fragmented);
done:
- if (ro == &ip6route && ro->ro_rt) { /* brace necessary for RTFREE */
- RTFREE(ro->ro_rt);
- } else if (ro_pmtu == &ip6route && ro_pmtu->ro_rt) {
- RTFREE(ro_pmtu->ro_rt);
- }
+ if (ro == &ip6route)
+ RO_RTFREE(ro);
+ if (ro_pmtu == &ip6route)
+ RO_RTFREE(ro_pmtu);
#ifdef IPSEC
if (sp != NULL)
KEY_FREESP(&sp);
@@ -1375,6 +1491,24 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
if (sopt->sopt_level == SOL_SOCKET &&
sopt->sopt_dir == SOPT_SET) {
switch (sopt->sopt_name) {
+ case SO_REUSEADDR:
+ INP_WLOCK(in6p);
+ if ((so->so_options & SO_REUSEADDR) != 0)
+ in6p->inp_flags2 |= INP_REUSEADDR;
+ else
+ in6p->inp_flags2 &= ~INP_REUSEADDR;
+ INP_WUNLOCK(in6p);
+ error = 0;
+ break;
+ case SO_REUSEPORT:
+ INP_WLOCK(in6p);
+ if ((so->so_options & SO_REUSEPORT) != 0)
+ in6p->inp_flags2 |= INP_REUSEPORT;
+ else
+ in6p->inp_flags2 &= ~INP_REUSEPORT;
+ INP_WUNLOCK(in6p);
+ error = 0;
+ break;
case SO_SETFIB:
INP_WLOCK(in6p);
in6p->inp_inc.inc_fibnum = so->so_fibnum;
@@ -1385,7 +1519,7 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
break;
}
}
- } else {
+ } else { /* level == IPPROTO_IPV6 */
switch (op) {
case SOPT_SET:
diff --git a/freebsd/sys/netinet6/ip6_var.h b/freebsd/sys/netinet6/ip6_var.h
index 9e210e2d..4a094d42 100644
--- a/freebsd/sys/netinet6/ip6_var.h
+++ b/freebsd/sys/netinet6/ip6_var.h
@@ -204,12 +204,14 @@ struct ip6stat {
u_quad_t ip6s_rawout; /* total raw ip packets generated */
u_quad_t ip6s_badscope; /* scope error */
u_quad_t ip6s_notmember; /* don't join this multicast group */
- u_quad_t ip6s_nxthist[256]; /* next header history */
+#define IP6S_HDRCNT 256 /* headers count */
+ u_quad_t ip6s_nxthist[IP6S_HDRCNT]; /* next header history */
u_quad_t ip6s_m1; /* one mbuf */
- u_quad_t ip6s_m2m[32]; /* two or more mbuf */
+#define IP6S_M2MMAX 32
+ u_quad_t ip6s_m2m[IP6S_M2MMAX]; /* two or more mbuf */
u_quad_t ip6s_mext1; /* one ext mbuf */
u_quad_t ip6s_mext2m; /* two or more ext mbuf */
- u_quad_t ip6s_exthdrtoolong; /* ext hdr are not continuous */
+ u_quad_t ip6s_exthdrtoolong; /* ext hdr are not contiguous */
u_quad_t ip6s_nogif; /* no match gif found */
u_quad_t ip6s_toomanyhdr; /* discarded due to too many headers */
@@ -218,27 +220,29 @@ struct ip6stat {
* algorithm:
* XXX: hardcoded 16 = # of ip6 multicast scope types + 1
*/
+#define IP6S_RULESMAX 16
+#define IP6S_SCOPECNT 16
/* number of times that address selection fails */
u_quad_t ip6s_sources_none;
/* number of times that an address on the outgoing I/F is chosen */
- u_quad_t ip6s_sources_sameif[16];
+ u_quad_t ip6s_sources_sameif[IP6S_SCOPECNT];
/* number of times that an address on a non-outgoing I/F is chosen */
- u_quad_t ip6s_sources_otherif[16];
+ u_quad_t ip6s_sources_otherif[IP6S_SCOPECNT];
/*
* number of times that an address that has the same scope
* from the destination is chosen.
*/
- u_quad_t ip6s_sources_samescope[16];
+ u_quad_t ip6s_sources_samescope[IP6S_SCOPECNT];
/*
* number of times that an address that has a different scope
* from the destination is chosen.
*/
- u_quad_t ip6s_sources_otherscope[16];
+ u_quad_t ip6s_sources_otherscope[IP6S_SCOPECNT];
/* number of times that a deprecated address is chosen */
- u_quad_t ip6s_sources_deprecated[16];
+ u_quad_t ip6s_sources_deprecated[IP6S_SCOPECNT];
/* number of times that each rule of source selection is applied. */
- u_quad_t ip6s_sources_rule[16];
+ u_quad_t ip6s_sources_rule[IP6S_RULESMAX];
};
#ifdef _KERNEL
@@ -285,6 +289,8 @@ struct ip6aux {
#define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */
#define IPV6_MINMTU 0x04 /* use minimum MTU (IPV6_USE_MIN_MTU) */
+#define M_IP6_NEXTHOP M_PROTO7 /* explicit ip nexthop */
+
#ifdef __NO_STRICT_ALIGNMENT
#define IP6_HDR_ALIGNED_P(ip) 1
#else
@@ -316,6 +322,11 @@ VNET_DECLARE(int, ip6_maxfragpackets); /* Maximum packets in reassembly
VNET_DECLARE(int, ip6_maxfrags); /* Maximum fragments in reassembly
* queue */
VNET_DECLARE(int, ip6_accept_rtadv); /* Acts as a host not a router */
+VNET_DECLARE(int, ip6_no_radr); /* No defroute from RA */
+VNET_DECLARE(int, ip6_norbit_raif); /* Disable R-bit in NA on RA
+ * receiving IF. */
+VNET_DECLARE(int, ip6_rfc6204w3); /* Accept defroute from RA even when
+ forwarding enabled */
VNET_DECLARE(int, ip6_keepfaith); /* Firewall Aided Internet Translator */
VNET_DECLARE(int, ip6_log_interval);
VNET_DECLARE(time_t, ip6_log_time);
@@ -327,6 +338,9 @@ VNET_DECLARE(int, ip6_dad_count); /* DupAddrDetectionTransmits */
#define V_ip6_maxfragpackets VNET(ip6_maxfragpackets)
#define V_ip6_maxfrags VNET(ip6_maxfrags)
#define V_ip6_accept_rtadv VNET(ip6_accept_rtadv)
+#define V_ip6_no_radr VNET(ip6_no_radr)
+#define V_ip6_norbit_raif VNET(ip6_norbit_raif)
+#define V_ip6_rfc6204w3 VNET(ip6_rfc6204w3)
#define V_ip6_keepfaith VNET(ip6_keepfaith)
#define V_ip6_log_interval VNET(ip6_log_interval)
#define V_ip6_log_time VNET(ip6_log_time)
@@ -361,87 +375,87 @@ struct sockopt;
struct inpcb;
-int icmp6_ctloutput __P((struct socket *, struct sockopt *sopt));
+int icmp6_ctloutput(struct socket *, struct sockopt *sopt);
struct in6_ifaddr;
-void ip6_init __P((void));
+void ip6_init(void);
#ifdef VIMAGE
-void ip6_destroy __P((void));
+void ip6_destroy(void);
#endif
int ip6proto_register(short);
int ip6proto_unregister(short);
-void ip6_input __P((struct mbuf *));
-struct in6_ifaddr *ip6_getdstifaddr __P((struct mbuf *));
-void ip6_freepcbopts __P((struct ip6_pktopts *));
+void ip6_input(struct mbuf *);
+struct in6_ifaddr *ip6_getdstifaddr(struct mbuf *);
+void ip6_freepcbopts(struct ip6_pktopts *);
-int ip6_unknown_opt __P((u_int8_t *, struct mbuf *, int));
-char * ip6_get_prevhdr __P((struct mbuf *, int));
-int ip6_nexthdr __P((struct mbuf *, int, int, int *));
-int ip6_lasthdr __P((struct mbuf *, int, int, int *));
+int ip6_unknown_opt(u_int8_t *, struct mbuf *, int);
+char * ip6_get_prevhdr(struct mbuf *, int);
+int ip6_nexthdr(struct mbuf *, int, int, int *);
+int ip6_lasthdr(struct mbuf *, int, int, int *);
-struct ip6aux *ip6_addaux __P((struct mbuf *));
-struct ip6aux *ip6_findaux __P((struct mbuf *));
-void ip6_delaux __P((struct mbuf *));
+#ifdef __notyet__
+struct ip6aux *ip6_findaux(struct mbuf *);
+#endif
extern int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *,
struct mbuf *);
-int ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *,
- u_int32_t *));
+int ip6_process_hopopts(struct mbuf *, u_int8_t *, int, u_int32_t *,
+ u_int32_t *);
struct mbuf **ip6_savecontrol_v4(struct inpcb *, struct mbuf *,
struct mbuf **, int *);
-void ip6_savecontrol __P((struct inpcb *, struct mbuf *, struct mbuf **));
-void ip6_notify_pmtu __P((struct inpcb *, struct sockaddr_in6 *,
- u_int32_t *));
-int ip6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
+void ip6_savecontrol(struct inpcb *, struct mbuf *, struct mbuf **);
+void ip6_notify_pmtu(struct inpcb *, struct sockaddr_in6 *,
+ u_int32_t *);
+int ip6_sysctl(int *, u_int, void *, size_t *, void *, size_t);
-void ip6_forward __P((struct mbuf *, int));
+void ip6_forward(struct mbuf *, int);
-void ip6_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in6 *));
-int ip6_output __P((struct mbuf *, struct ip6_pktopts *,
+void ip6_mloopback(struct ifnet *, struct mbuf *, struct sockaddr_in6 *);
+int ip6_output(struct mbuf *, struct ip6_pktopts *,
struct route_in6 *,
int,
struct ip6_moptions *, struct ifnet **,
- struct inpcb *));
-int ip6_ctloutput __P((struct socket *, struct sockopt *));
-int ip6_raw_ctloutput __P((struct socket *, struct sockopt *));
-void ip6_initpktopts __P((struct ip6_pktopts *));
-int ip6_setpktopts __P((struct mbuf *, struct ip6_pktopts *,
- struct ip6_pktopts *, struct ucred *, int));
-void ip6_clearpktopts __P((struct ip6_pktopts *, int));
-struct ip6_pktopts *ip6_copypktopts __P((struct ip6_pktopts *, int));
-int ip6_optlen __P((struct inpcb *));
-
-int route6_input __P((struct mbuf **, int *, int));
-
-void frag6_init __P((void));
-int frag6_input __P((struct mbuf **, int *, int));
-void frag6_slowtimo __P((void));
-void frag6_drain __P((void));
-
-void rip6_init __P((void));
-int rip6_input __P((struct mbuf **, int *, int));
-void rip6_ctlinput __P((int, struct sockaddr *, void *));
-int rip6_ctloutput __P((struct socket *, struct sockopt *));
-int rip6_output __P((struct mbuf *, ...));
-int rip6_usrreq __P((struct socket *,
- int, struct mbuf *, struct mbuf *, struct mbuf *, struct thread *));
-
-int dest6_input __P((struct mbuf **, int *, int));
-int none_input __P((struct mbuf **, int *, int));
+ struct inpcb *);
+int ip6_ctloutput(struct socket *, struct sockopt *);
+int ip6_raw_ctloutput(struct socket *, struct sockopt *);
+void ip6_initpktopts(struct ip6_pktopts *);
+int ip6_setpktopts(struct mbuf *, struct ip6_pktopts *,
+ struct ip6_pktopts *, struct ucred *, int);
+void ip6_clearpktopts(struct ip6_pktopts *, int);
+struct ip6_pktopts *ip6_copypktopts(struct ip6_pktopts *, int);
+int ip6_optlen(struct inpcb *);
+
+int route6_input(struct mbuf **, int *, int);
+
+void frag6_init(void);
+int frag6_input(struct mbuf **, int *, int);
+void frag6_slowtimo(void);
+void frag6_drain(void);
+
+void rip6_init(void);
+int rip6_input(struct mbuf **, int *, int);
+void rip6_ctlinput(int, struct sockaddr *, void *);
+int rip6_ctloutput(struct socket *, struct sockopt *);
+int rip6_output(struct mbuf *, ...);
+int rip6_usrreq(struct socket *,
+ int, struct mbuf *, struct mbuf *, struct mbuf *, struct thread *);
+
+int dest6_input(struct mbuf **, int *, int);
+int none_input(struct mbuf **, int *, int);
int in6_selectsrc(struct sockaddr_in6 *, struct ip6_pktopts *,
struct inpcb *inp, struct route_in6 *, struct ucred *cred,
struct ifnet **, struct in6_addr *);
-int in6_selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
+int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
- struct rtentry **));
+ struct rtentry **);
int in6_selectroute_fib(struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
struct rtentry **, u_int);
-u_int32_t ip6_randomid __P((void));
-u_int32_t ip6_randomflowlabel __P((void));
+u_int32_t ip6_randomid(void);
+u_int32_t ip6_randomflowlabel(void);
#endif /* _KERNEL */
#endif /* !_NETINET6_IP6_VAR_H_ */
diff --git a/freebsd/sys/netinet6/ip6protosw.h b/freebsd/sys/netinet6/ip6protosw.h
index 1fae44c8..ec802a51 100644
--- a/freebsd/sys/netinet6/ip6protosw.h
+++ b/freebsd/sys/netinet6/ip6protosw.h
@@ -118,26 +118,26 @@ struct ip6protosw {
/* protocol-protocol hooks */
int (*pr_input) /* input to protocol (from below) */
- __P((struct mbuf **, int *, int));
+ (struct mbuf **, int *, int);
int (*pr_output) /* output to protocol (from above) */
- __P((struct mbuf *, ...));
+ (struct mbuf *, ...);
void (*pr_ctlinput) /* control input (from below) */
- __P((int, struct sockaddr *, void *));
+ (int, struct sockaddr *, void *);
int (*pr_ctloutput) /* control output (from above) */
- __P((struct socket *, struct sockopt *));
+ (struct socket *, struct sockopt *);
/* utility hooks */
void (*pr_init) /* initialization hook */
- __P((void));
+ (void);
void (*pr_destroy) /* cleanup hook */
- __P((void));
+ (void);
void (*pr_fasttimo) /* fast timeout (200ms) */
- __P((void));
+ (void);
void (*pr_slowtimo) /* slow timeout (500ms) */
- __P((void));
+ (void);
void (*pr_drain) /* flush any excess space possible */
- __P((void));
+ (void);
struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */
};
diff --git a/freebsd/sys/netinet6/mld6.c b/freebsd/sys/netinet6/mld6.c
index d2fd82b7..25f03411 100644
--- a/freebsd/sys/netinet6/mld6.c
+++ b/freebsd/sys/netinet6/mld6.c
@@ -196,7 +196,7 @@ static int sysctl_mld_ifinfo(SYSCTL_HANDLER_ARGS);
* to a vnet in ifp->if_vnet.
*/
static struct mtx mld_mtx;
-MALLOC_DEFINE(M_MLD, "mld", "mld state");
+static MALLOC_DEFINE(M_MLD, "mld", "mld state");
#define MLD_EMBEDSCOPE(pin6, zoneid) \
if (IN6_IS_SCOPE_LINKLOCAL(pin6) || \
@@ -234,8 +234,9 @@ SYSCTL_VNET_PROC(_net_inet6_mld, OID_AUTO, gsrdelay,
/*
* Non-virtualized sysctls.
*/
-SYSCTL_NODE(_net_inet6_mld, OID_AUTO, ifinfo, CTLFLAG_RD | CTLFLAG_MPSAFE,
- sysctl_mld_ifinfo, "Per-interface MLDv2 state");
+static SYSCTL_NODE(_net_inet6_mld, OID_AUTO, ifinfo,
+ CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_mld_ifinfo,
+ "Per-interface MLDv2 state");
static int mld_v1enable = 1;
SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RW,
@@ -834,7 +835,7 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
mld = (struct mldv2_query *)(mtod(m, uint8_t *) + off);
maxdelay = ntohs(mld->mld_maxdelay); /* in 1/10ths of a second */
- if (maxdelay >= 32678) {
+ if (maxdelay >= 32768) {
maxdelay = (MLD_MRC_MANT(maxdelay) | 0x1000) <<
(MLD_MRC_EXP(maxdelay) + 3);
}
@@ -868,16 +869,10 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
*/
if (IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
/*
- * General Queries SHOULD be directed to ff02::1.
* A general query with a source list has undefined
* behaviour; discard it.
*/
- struct in6_addr dst;
-
- dst = ip6->ip6_dst;
- in6_clearscope(&dst);
- if (!IN6_ARE_ADDR_EQUAL(&dst, &in6addr_linklocal_allnodes) ||
- nsrc > 0)
+ if (nsrc > 0)
return (EINVAL);
is_general_query = 1;
} else {
@@ -2204,6 +2199,7 @@ mld_final_leave(struct in6_multi *inm, struct mld_ifinfo *mli)
#endif
mld_v1_transmit_report(inm, MLD_LISTENER_DONE);
inm->in6m_state = MLD_NOT_MEMBER;
+ V_current_state_timers_running6 = 1;
} else if (mli->mli_version == MLD_VERSION_2) {
/*
* Stop group timer and all pending reports.
@@ -3098,7 +3094,6 @@ mld_dispatch_packet(struct mbuf *m)
m0 = mld_v2_encap_report(ifp, m);
if (m0 == NULL) {
CTR2(KTR_MLD, "%s: dropped %p", __func__, m);
- m_freem(m);
IP6STAT_INC(ip6s_odropped);
goto out;
}
diff --git a/freebsd/sys/netinet6/nd6.c b/freebsd/sys/netinet6/nd6.c
index ead44620..b84baf18 100644
--- a/freebsd/sys/netinet6/nd6.c
+++ b/freebsd/sys/netinet6/nd6.c
@@ -72,7 +72,9 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6_var.h>
#include <netinet6/scope6_var.h>
#include <netinet6/nd6.h>
+#include <netinet6/in6_ifattach.h>
#include <netinet/icmp6.h>
+#include <netinet6/send.h>
#include <sys/limits.h>
@@ -122,8 +124,10 @@ VNET_DEFINE(int, nd6_recalc_reachtm_interval) = ND6_RECALC_REACHTM_INTERVAL;
static struct sockaddr_in6 all1_sa;
-static int nd6_is_new_addr_neighbor __P((struct sockaddr_in6 *,
- struct ifnet *));
+int (*send_sendso_input_hook)(struct mbuf *, struct ifnet *, int, int);
+
+static int nd6_is_new_addr_neighbor(struct sockaddr_in6 *,
+ struct ifnet *);
static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *);
static void nd6_slowtimo(void *);
static int regen_tmpaddr(struct in6_ifaddr *);
@@ -172,21 +176,37 @@ nd6_ifattach(struct ifnet *ifp)
{
struct nd_ifinfo *nd;
- nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK);
- bzero(nd, sizeof(*nd));
-
+ nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK|M_ZERO);
nd->initialized = 1;
nd->chlim = IPV6_DEFHLIM;
nd->basereachable = REACHABLE_TIME;
nd->reachable = ND_COMPUTE_RTIME(nd->basereachable);
nd->retrans = RETRANS_TIMER;
+
+ nd->flags = ND6_IFF_PERFORMNUD;
+
+ /* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL.
+ * XXXHRS: Clear ND6_IFF_AUTO_LINKLOCAL on an IFT_BRIDGE interface by
+ * default regardless of the V_ip6_auto_linklocal configuration to
+ * give a reasonable default behavior.
+ */
+ if ((V_ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) ||
+ (ifp->if_flags & IFF_LOOPBACK))
+ nd->flags |= ND6_IFF_AUTO_LINKLOCAL;
/*
- * Note that the default value of ip6_accept_rtadv is 0, which means
- * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV
- * here.
+ * A loopback interface does not need to accept RTADV.
+ * XXXHRS: Clear ND6_IFF_ACCEPT_RTADV on an IFT_BRIDGE interface by
+ * default regardless of the V_ip6_accept_rtadv configuration to
+ * prevent the interface from accepting RA messages arrived
+ * on one of the member interfaces with ND6_IFF_ACCEPT_RTADV.
*/
- nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV);
+ if (V_ip6_accept_rtadv &&
+ !(ifp->if_flags & IFF_LOOPBACK) &&
+ (ifp->if_type != IFT_BRIDGE))
+ nd->flags |= ND6_IFF_ACCEPT_RTADV;
+ if (V_ip6_no_radr && !(ifp->if_flags & IFF_LOOPBACK))
+ nd->flags |= ND6_IFF_NO_RADR;
/* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
nd6_setmtu0(ifp, nd);
@@ -276,10 +296,9 @@ nd6_option(union nd_opts *ndopts)
struct nd_opt_hdr *nd_opt;
int olen;
- if (ndopts == NULL)
- panic("ndopts == NULL in nd6_option");
- if (ndopts->nd_opts_last == NULL)
- panic("uninitialized ndopts in nd6_option");
+ KASSERT(ndopts != NULL, ("%s: ndopts == NULL", __func__));
+ KASSERT(ndopts->nd_opts_last != NULL, ("%s: uninitialized ndopts",
+ __func__));
if (ndopts->nd_opts_search == NULL)
return NULL;
if (ndopts->nd_opts_done)
@@ -327,10 +346,9 @@ nd6_options(union nd_opts *ndopts)
struct nd_opt_hdr *nd_opt;
int i = 0;
- if (ndopts == NULL)
- panic("ndopts == NULL in nd6_options");
- if (ndopts->nd_opts_last == NULL)
- panic("uninitialized ndopts in nd6_options");
+ KASSERT(ndopts != NULL, ("%s: ndopts == NULL", __func__));
+ KASSERT(ndopts->nd_opts_last != NULL, ("%s: uninitialized ndopts",
+ __func__));
if (ndopts->nd_opts_search == NULL)
return 0;
@@ -505,6 +523,7 @@ nd6_llinfo_timer(void *arg)
ln->la_hold = m0;
clear_llinfo_pqueue(ln);
}
+ EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_TIMEDOUT);
(void)nd6_free(ln, 0);
ln = NULL;
if (m != NULL)
@@ -522,6 +541,7 @@ nd6_llinfo_timer(void *arg)
case ND6_LLINFO_STALE:
/* Garbage Collection(RFC 2461 5.3) */
if (!ND6_LLINFO_PERMANENT(ln)) {
+ EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_EXPIRED);
(void)nd6_free(ln, 1);
ln = NULL;
}
@@ -549,6 +569,7 @@ nd6_llinfo_timer(void *arg)
nd6_ns_output(ifp, dst, dst, ln, 0);
LLE_WLOCK(ln);
} else {
+ EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_EXPIRED);
(void)nd6_free(ln, 0);
ln = NULL;
}
@@ -809,13 +830,9 @@ nd6_purge(struct ifnet *ifp)
if (V_nd6_defifindex == ifp->if_index)
nd6_setdefaultiface(0);
- if (!V_ip6_forwarding && V_ip6_accept_rtadv) { /* XXX: too restrictive? */
- /* refresh default router list
- *
- *
- */
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
+ /* Refresh default router list. */
defrouter_select();
-
}
/* XXXXX
@@ -949,10 +966,9 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
/*
* If the default router list is empty, all addresses are regarded
* as on-link, and thus, as a neighbor.
- * XXX: we restrict the condition to hosts, because routers usually do
- * not have the "default router list".
*/
- if (!V_ip6_forwarding && TAILQ_EMPTY(&V_nd_defrouter) &&
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV &&
+ TAILQ_EMPTY(&V_nd_defrouter) &&
V_nd6_defifindex == ifp->if_index) {
return (1);
}
@@ -1013,8 +1029,7 @@ nd6_free(struct llentry *ln, int gc)
ifp = ln->lle_tbl->llt_ifp;
- if (!V_ip6_forwarding) {
-
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
dr = defrouter_lookup(&L3_ADDR_SIN6(ln)->sin6_addr, ifp);
if (dr != NULL && dr->expire &&
@@ -1113,8 +1128,14 @@ nd6_free(struct llentry *ln, int gc)
LLE_WUNLOCK(ln);
IF_AFDATA_LOCK(ifp);
LLE_WLOCK(ln);
- LLE_REMREF(ln);
- llentry_free(ln);
+
+ /* Guard against race with other llentry_free(). */
+ if (ln->la_flags & LLE_LINKED) {
+ LLE_REMREF(ln);
+ llentry_free(ln);
+ } else
+ LLE_FREE_LOCKED(ln);
+
IF_AFDATA_UNLOCK(ifp);
return (next);
@@ -1172,11 +1193,13 @@ done:
void
nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
{
- struct sockaddr_in6 *gateway = (struct sockaddr_in6 *)rt->rt_gateway;
+ struct sockaddr_in6 *gateway;
struct nd_defrouter *dr;
- struct ifnet *ifp = rt->rt_ifp;
+ struct ifnet *ifp;
RT_LOCK_ASSERT(rt);
+ gateway = (struct sockaddr_in6 *)rt->rt_gateway;
+ ifp = rt->rt_ifp;
switch (req) {
case RTM_ADD:
@@ -1347,6 +1370,94 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
ND_IFINFO(ifp)->chlim = ND.chlim;
/* FALLTHROUGH */
case SIOCSIFINFO_FLAGS:
+ {
+ struct ifaddr *ifa;
+ struct in6_ifaddr *ia;
+
+ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
+ !(ND.flags & ND6_IFF_IFDISABLED)) {
+ /* ifdisabled 1->0 transision */
+
+ /*
+ * If the interface is marked as ND6_IFF_IFDISABLED and
+ * has an link-local address with IN6_IFF_DUPLICATED,
+ * do not clear ND6_IFF_IFDISABLED.
+ * See RFC 4862, Section 5.4.5.
+ */
+ int duplicated_linklocal = 0;
+
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ia = (struct in6_ifaddr *)ifa;
+ if ((ia->ia6_flags & IN6_IFF_DUPLICATED) &&
+ IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) {
+ duplicated_linklocal = 1;
+ break;
+ }
+ }
+ IF_ADDR_RUNLOCK(ifp);
+
+ if (duplicated_linklocal) {
+ ND.flags |= ND6_IFF_IFDISABLED;
+ log(LOG_ERR, "Cannot enable an interface"
+ " with a link-local address marked"
+ " duplicate.\n");
+ } else {
+ ND_IFINFO(ifp)->flags &= ~ND6_IFF_IFDISABLED;
+ if (ifp->if_flags & IFF_UP)
+ in6_if_up(ifp);
+ }
+ } else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
+ (ND.flags & ND6_IFF_IFDISABLED)) {
+ /* ifdisabled 0->1 transision */
+ /* Mark all IPv6 address as tentative. */
+
+ ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ia = (struct in6_ifaddr *)ifa;
+ ia->ia6_flags |= IN6_IFF_TENTATIVE;
+ }
+ IF_ADDR_RUNLOCK(ifp);
+ }
+
+ if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) {
+ if (!(ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)) {
+ /* auto_linklocal 0->1 transision */
+
+ /* If no link-local address on ifp, configure */
+ ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL;
+ in6_ifattach(ifp, NULL);
+ } else if (!(ND.flags & ND6_IFF_IFDISABLED) &&
+ ifp->if_flags & IFF_UP) {
+ /*
+ * When the IF already has
+ * ND6_IFF_AUTO_LINKLOCAL, no link-local
+ * address is assigned, and IFF_UP, try to
+ * assign one.
+ */
+ int haslinklocal = 0;
+
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ia = (struct in6_ifaddr *)ifa;
+ if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) {
+ haslinklocal = 1;
+ break;
+ }
+ }
+ IF_ADDR_RUNLOCK(ifp);
+ if (!haslinklocal)
+ in6_ifattach(ifp, NULL);
+ }
+ }
+ }
ND_IFINFO(ifp)->flags = ND.flags;
break;
#undef ND
@@ -1457,10 +1568,8 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
IF_AFDATA_UNLOCK_ASSERT(ifp);
- if (ifp == NULL)
- panic("ifp == NULL in nd6_cache_lladdr");
- if (from == NULL)
- panic("from == NULL in nd6_cache_lladdr");
+ KASSERT(ifp != NULL, ("%s: ifp == NULL", __func__));
+ KASSERT(from != NULL, ("%s: from == NULL", __func__));
/* nothing must be updated for unspecified address */
if (IN6_IS_ADDR_UNSPECIFIED(from))
@@ -1521,6 +1630,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
*/
bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen);
ln->la_flags |= LLE_VALID;
+ EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED);
}
if (!is_newentry) {
@@ -1681,7 +1791,8 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* for those are not autoconfigured hosts, we explicitly avoid such
* cases for safety.
*/
- if (do_update && router && !V_ip6_forwarding && V_ip6_accept_rtadv) {
+ if (do_update && router &&
+ ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/*
* guaranteed recursion
*/
@@ -1754,9 +1865,12 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
struct mbuf **chain)
{
struct mbuf *m = m0;
+ struct m_tag *mtag;
struct llentry *ln = lle;
+ struct ip6_hdr *ip6;
int error = 0;
int flags = 0;
+ int ip6len;
#ifdef INVARIANTS
if (lle != NULL) {
@@ -1935,6 +2049,28 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
#ifdef MAC
mac_netinet6_nd6_send(ifp, m);
#endif
+
+ /*
+ * If called from nd6_ns_output() (NS), nd6_na_output() (NA),
+ * icmp6_redirect_output() (REDIRECT) or from rip6_output() (RS, RA
+ * as handled by rtsol and rtadvd), mbufs will be tagged for SeND
+ * to be diverted to user space. When re-injected into the kernel,
+ * send_output() will directly dispatch them to the outgoing interface.
+ */
+ if (send_sendso_input_hook != NULL) {
+ mtag = m_tag_find(m, PACKET_TAG_ND_OUTGOING, NULL);
+ if (mtag != NULL) {
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
+ /* Use the SEND socket */
+ error = send_sendso_input_hook(m, ifp, SND_OUT,
+ ip6len);
+ /* -1 == no app on SEND socket */
+ if (error == 0 || error != -1)
+ return (error);
+ }
+ }
+
/*
* We were passed in a pointer to an lle with the lock held
* this means that we can't call if_output as we will
@@ -1958,6 +2094,8 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
}
return (error);
}
+ /* Reset layer specific mbuf flags to avoid confusing lower layers. */
+ m->m_flags &= ~(M_PROTOFLAGS);
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
return ((*ifp->if_output)(origifp, m, (struct sockaddr *)dst,
NULL));
@@ -2037,6 +2175,7 @@ nd6_need_cache(struct ifnet *ifp)
#ifdef IFT_CARP
case IFT_CARP:
#endif
+ case IFT_INFINIBAND:
case IFT_GIF: /* XXX need more cases? */
case IFT_PPP:
case IFT_TUNNEL:
@@ -2060,7 +2199,7 @@ nd6_storelladdr(struct ifnet *ifp, struct mbuf *m,
*lle = NULL;
IF_AFDATA_UNLOCK_ASSERT(ifp);
- if (m->m_flags & M_MCAST) {
+ if (m != NULL && m->m_flags & M_MCAST) {
int i;
switch (ifp->if_type) {
@@ -2125,7 +2264,6 @@ clear_llinfo_pqueue(struct llentry *ln)
for (m_hold = ln->la_hold; m_hold; m_hold = m_hold_next) {
m_hold_next = m_hold->m_nextpkt;
- m_hold->m_nextpkt = NULL;
m_freem(m_hold);
}
diff --git a/freebsd/sys/netinet6/nd6.h b/freebsd/sys/netinet6/nd6.h
index 0893065e..79e41e38 100644
--- a/freebsd/sys/netinet6/nd6.h
+++ b/freebsd/sys/netinet6/nd6.h
@@ -84,6 +84,9 @@ struct nd_ifinfo {
* DAD failure. (XXX: not ND-specific)
*/
#define ND6_IFF_DONT_SET_IFROUTE 0x10
+#define ND6_IFF_AUTO_LINKLOCAL 0x20
+#define ND6_IFF_NO_RADR 0x40
+#define ND6_IFF_NO_PREFER_IFACE 0x80 /* XXX: not related to ND. */
#define ND6_CREATE LLE_CREATE
#define ND6_EXCLUSIVE LLE_EXCLUSIVE
@@ -382,68 +385,68 @@ union nd_opts {
/* XXX: need nd6_var.h?? */
/* nd6.c */
-void nd6_init __P((void));
+void nd6_init(void);
#ifdef VIMAGE
-void nd6_destroy __P((void));
+void nd6_destroy(void);
#endif
-struct nd_ifinfo *nd6_ifattach __P((struct ifnet *));
-void nd6_ifdetach __P((struct nd_ifinfo *));
-int nd6_is_addr_neighbor __P((struct sockaddr_in6 *, struct ifnet *));
-void nd6_option_init __P((void *, int, union nd_opts *));
-struct nd_opt_hdr *nd6_option __P((union nd_opts *));
-int nd6_options __P((union nd_opts *));
-struct llentry *nd6_lookup __P((struct in6_addr *, int, struct ifnet *));
-void nd6_setmtu __P((struct ifnet *));
-void nd6_llinfo_settimer __P((struct llentry *, long));
-void nd6_llinfo_settimer_locked __P((struct llentry *, long));
-void nd6_timer __P((void *));
-void nd6_purge __P((struct ifnet *));
-void nd6_nud_hint __P((struct rtentry *, struct in6_addr *, int));
-int nd6_resolve __P((struct ifnet *, struct rtentry *, struct mbuf *,
- struct sockaddr *, u_char *));
-void nd6_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *));
-int nd6_ioctl __P((u_long, caddr_t, struct ifnet *));
-struct llentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *,
- char *, int, int, int));
-int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *,
- struct sockaddr_in6 *, struct rtentry *));
-int nd6_output_lle __P((struct ifnet *, struct ifnet *, struct mbuf *,
+struct nd_ifinfo *nd6_ifattach(struct ifnet *);
+void nd6_ifdetach(struct nd_ifinfo *);
+int nd6_is_addr_neighbor(struct sockaddr_in6 *, struct ifnet *);
+void nd6_option_init(void *, int, union nd_opts *);
+struct nd_opt_hdr *nd6_option(union nd_opts *);
+int nd6_options(union nd_opts *);
+struct llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *);
+void nd6_setmtu(struct ifnet *);
+void nd6_llinfo_settimer(struct llentry *, long);
+void nd6_llinfo_settimer_locked(struct llentry *, long);
+void nd6_timer(void *);
+void nd6_purge(struct ifnet *);
+void nd6_nud_hint(struct rtentry *, struct in6_addr *, int);
+int nd6_resolve(struct ifnet *, struct rtentry *, struct mbuf *,
+ struct sockaddr *, u_char *);
+void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
+int nd6_ioctl(u_long, caddr_t, struct ifnet *);
+struct llentry *nd6_cache_lladdr(struct ifnet *, struct in6_addr *,
+ char *, int, int, int);
+int nd6_output(struct ifnet *, struct ifnet *, struct mbuf *,
+ struct sockaddr_in6 *, struct rtentry *);
+int nd6_output_lle(struct ifnet *, struct ifnet *, struct mbuf *,
struct sockaddr_in6 *, struct rtentry *, struct llentry *,
- struct mbuf **));
-int nd6_output_flush __P((struct ifnet *, struct ifnet *, struct mbuf *,
- struct sockaddr_in6 *, struct route *));
-int nd6_need_cache __P((struct ifnet *));
-int nd6_storelladdr __P((struct ifnet *, struct mbuf *,
- struct sockaddr *, u_char *, struct llentry **));
+ struct mbuf **);
+int nd6_output_flush(struct ifnet *, struct ifnet *, struct mbuf *,
+ struct sockaddr_in6 *, struct route *);
+int nd6_need_cache(struct ifnet *);
+int nd6_storelladdr(struct ifnet *, struct mbuf *,
+ struct sockaddr *, u_char *, struct llentry **);
/* nd6_nbr.c */
-void nd6_na_input __P((struct mbuf *, int, int));
-void nd6_na_output __P((struct ifnet *, const struct in6_addr *,
- const struct in6_addr *, u_long, int, struct sockaddr *));
-void nd6_ns_input __P((struct mbuf *, int, int));
-void nd6_ns_output __P((struct ifnet *, const struct in6_addr *,
- const struct in6_addr *, struct llentry *, int));
-caddr_t nd6_ifptomac __P((struct ifnet *));
-void nd6_dad_start __P((struct ifaddr *, int));
-void nd6_dad_stop __P((struct ifaddr *));
-void nd6_dad_duplicated __P((struct ifaddr *));
+void nd6_na_input(struct mbuf *, int, int);
+void nd6_na_output(struct ifnet *, const struct in6_addr *,
+ const struct in6_addr *, u_long, int, struct sockaddr *);
+void nd6_ns_input(struct mbuf *, int, int);
+void nd6_ns_output(struct ifnet *, const struct in6_addr *,
+ const struct in6_addr *, struct llentry *, int);
+caddr_t nd6_ifptomac(struct ifnet *);
+void nd6_dad_start(struct ifaddr *, int);
+void nd6_dad_stop(struct ifaddr *);
+void nd6_dad_duplicated(struct ifaddr *);
/* nd6_rtr.c */
-void nd6_rs_input __P((struct mbuf *, int, int));
-void nd6_ra_input __P((struct mbuf *, int, int));
-void prelist_del __P((struct nd_prefix *));
-void defrouter_reset __P((void));
-void defrouter_select __P((void));
-void defrtrlist_del __P((struct nd_defrouter *));
-void prelist_remove __P((struct nd_prefix *));
-int nd6_prelist_add __P((struct nd_prefixctl *, struct nd_defrouter *,
- struct nd_prefix **));
-void pfxlist_onlink_check __P((void));
-struct nd_defrouter *defrouter_lookup __P((struct in6_addr *, struct ifnet *));
-struct nd_prefix *nd6_prefix_lookup __P((struct nd_prefixctl *));
-void rt6_flush __P((struct in6_addr *, struct ifnet *));
-int nd6_setdefaultiface __P((int));
-int in6_tmpifadd __P((const struct in6_ifaddr *, int, int));
+void nd6_rs_input(struct mbuf *, int, int);
+void nd6_ra_input(struct mbuf *, int, int);
+void prelist_del(struct nd_prefix *);
+void defrouter_reset(void);
+void defrouter_select(void);
+void defrtrlist_del(struct nd_defrouter *);
+void prelist_remove(struct nd_prefix *);
+int nd6_prelist_add(struct nd_prefixctl *, struct nd_defrouter *,
+ struct nd_prefix **);
+void pfxlist_onlink_check(void);
+struct nd_defrouter *defrouter_lookup(struct in6_addr *, struct ifnet *);
+struct nd_prefix *nd6_prefix_lookup(struct nd_prefixctl *);
+void rt6_flush(struct in6_addr *, struct ifnet *);
+int nd6_setdefaultiface(int);
+int in6_tmpifadd(const struct in6_ifaddr *, int, int);
#endif /* _KERNEL */
diff --git a/freebsd/sys/netinet6/nd6_nbr.c b/freebsd/sys/netinet6/nd6_nbr.c
index a67fc68f..4574145f 100644
--- a/freebsd/sys/netinet6/nd6_nbr.c
+++ b/freebsd/sys/netinet6/nd6_nbr.c
@@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
#include <netinet6/nd6.h>
#include <netinet/icmp6.h>
#include <netinet/ip_carp.h>
+#include <netinet6/send.h>
#define SDL(s) ((struct sockaddr_dl *)s)
@@ -115,10 +116,14 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
int lladdrlen = 0;
int anycast = 0, proxy = 0, tentative = 0;
int tlladdr;
+ int rflag;
union nd_opts ndopts;
struct sockaddr_dl proxydl;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
+ rflag = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0;
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && V_ip6_norbit_raif)
+ rflag = 0;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, icmp6len,);
nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
@@ -345,8 +350,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
goto bad;
nd6_na_output_fib(ifp, &in6_all, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
- tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
+ rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
M_GETFIB(m));
goto freeit;
}
@@ -356,8 +360,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
nd6_na_output_fib(ifp, &saddr6, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
- tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
+ rflag | ND_NA_FLAG_SOLICITED, tlladdr,
+ proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
freeit:
if (ifa != NULL)
ifa_free(ifa);
@@ -394,6 +398,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
const struct in6_addr *taddr6, struct llentry *ln, int dad)
{
struct mbuf *m;
+ struct m_tag *mtag;
struct ip6_hdr *ip6;
struct nd_neighbor_solicit *nd_ns;
struct ip6_moptions im6o;
@@ -578,14 +583,23 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
nd_ns->nd_ns_cksum =
in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
+ if (send_sendso_input_hook != NULL) {
+ mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
+ sizeof(unsigned short), M_NOWAIT);
+ if (mtag == NULL)
+ goto bad;
+ *(unsigned short *)(mtag + 1) = nd_ns->nd_ns_type;
+ m_tag_prepend(m, mtag);
+ }
+
ip6_output(m, NULL, &ro, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL, NULL);
icmp6_ifstat_inc(ifp, ifs6_out_msg);
icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
ICMP6STAT_INC(icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
- if (ro.ro_rt) { /* we don't cache this route. */
- RTFREE(ro.ro_rt);
- }
+ /* We don't cache this route. */
+ RO_RTFREE(&ro);
+
return;
bad:
@@ -625,6 +639,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
struct llentry *ln = NULL;
union nd_opts ndopts;
struct mbuf *chain = NULL;
+ struct m_tag *mtag;
struct sockaddr_in6 sin6;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
@@ -742,6 +757,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
*/
bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen);
ln->la_flags |= LLE_VALID;
+ EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED);
if (is_solicited) {
ln->ln_state = ND6_LLINFO_REACHABLE;
ln->ln_byhint = 0;
@@ -817,6 +833,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
if (lladdr != NULL) {
bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen);
ln->la_flags |= LLE_VALID;
+ EVENTHANDLER_INVOKE(lle_event, ln,
+ LLENTRY_RESOLVED);
}
/*
@@ -860,7 +878,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
dr = defrouter_lookup(in6, ln->lle_tbl->llt_ifp);
if (dr)
defrtrlist_del(dr);
- else if (!V_ip6_forwarding) {
+ else if (ND_IFINFO(ln->lle_tbl->llt_ifp)->flags &
+ ND6_IFF_ACCEPT_RTADV) {
/*
* Even if the neighbor is not in the default
* router list, the neighbor may be used
@@ -894,6 +913,15 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
* we assume ifp is not a loopback here, so just set
* the 2nd argument as the 1st one.
*/
+
+ if (send_sendso_input_hook != NULL) {
+ mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
+ sizeof(unsigned short), M_NOWAIT);
+ if (mtag == NULL)
+ goto bad;
+ m_tag_prepend(m, mtag);
+ }
+
nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain);
}
}
@@ -938,6 +966,7 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
struct sockaddr *sdl0, u_int fibnum)
{
struct mbuf *m;
+ struct m_tag *mtag;
struct ifnet *oifp;
struct ip6_hdr *ip6;
struct nd_neighbor_advert *nd_na;
@@ -1079,14 +1108,23 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
nd_na->nd_na_cksum =
in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
+ if (send_sendso_input_hook != NULL) {
+ mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
+ sizeof(unsigned short), M_NOWAIT);
+ if (mtag == NULL)
+ goto bad;
+ *(unsigned short *)(mtag + 1) = nd_na->nd_na_type;
+ m_tag_prepend(m, mtag);
+ }
+
ip6_output(m, NULL, &ro, 0, &im6o, NULL, NULL);
icmp6_ifstat_inc(ifp, ifs6_out_msg);
icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert);
ICMP6STAT_INC(icp6s_outhist[ND_NEIGHBOR_ADVERT]);
- if (ro.ro_rt) { /* we don't cache this route. */
- RTFREE(ro.ro_rt);
- }
+ /* We don't cache this route. */
+ RO_RTFREE(&ro);
+
return;
bad:
@@ -1126,6 +1164,7 @@ nd6_ifptomac(struct ifnet *ifp)
#ifdef IFT_CARP
case IFT_CARP:
#endif
+ case IFT_INFINIBAND:
case IFT_BRIDGE:
case IFT_ISO88025:
return IF_LLADDR(ifp);
@@ -1220,6 +1259,8 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
if (!(ifa->ifa_ifp->if_flags & IFF_UP)) {
return;
}
+ if (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED)
+ return;
if (nd6_dad_find(ifa) != NULL) {
/* DAD already in progress */
return;
@@ -1424,7 +1465,7 @@ nd6_dad_duplicated(struct ifaddr *ifa)
* identifier based on the hardware address which is supposed to be
* uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP
* operation on the interface SHOULD be disabled.
- * [rfc2462bis-03 Section 5.4.5]
+ * [RFC 4862, Section 5.4.5]
*/
if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
struct in6_addr in6;
@@ -1441,6 +1482,7 @@ nd6_dad_duplicated(struct ifaddr *ifa)
#ifdef IFT_IEEE80211
case IFT_IEEE80211:
#endif
+ case IFT_INFINIBAND:
in6 = ia->ia_addr.sin6_addr;
if (in6_get_hw_ifid(ifp, &in6) == 0 &&
IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) {
diff --git a/freebsd/sys/netinet6/nd6_rtr.c b/freebsd/sys/netinet6/nd6_rtr.c
index d73ac569..bd6fa33b 100644
--- a/freebsd/sys/netinet6/nd6_rtr.c
+++ b/freebsd/sys/netinet6/nd6_rtr.c
@@ -70,11 +70,11 @@ __FBSDID("$FreeBSD$");
static int rtpref(struct nd_defrouter *);
static struct nd_defrouter *defrtrlist_update(struct nd_defrouter *);
-static int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *,
- struct mbuf *, int));
-static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int);
-static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
- struct nd_defrouter *));
+static int prelist_update(struct nd_prefixctl *, struct nd_defrouter *,
+ struct mbuf *, int);
+static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int);
+static struct nd_pfxrouter *pfxrtr_lookup(struct nd_prefix *,
+ struct nd_defrouter *);
static void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *);
static void pfxrtr_del(struct nd_pfxrouter *);
static struct nd_pfxrouter *find_pfxlist_reachable_router
@@ -83,8 +83,8 @@ static void defrouter_delreq(struct nd_defrouter *);
static void nd6_rtmsg(int, struct rtentry *);
static int in6_init_prefix_ltimes(struct nd_prefix *);
-static void in6_init_address_ltimes __P((struct nd_prefix *,
- struct in6_addrlifetime *));
+static void in6_init_address_ltimes(struct nd_prefix *,
+ struct in6_addrlifetime *);
static int nd6_prefix_onlink(struct nd_prefix *);
static int nd6_prefix_offlink(struct nd_prefix *);
@@ -132,8 +132,11 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len)
union nd_opts ndopts;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
- /* If I'm not a router, ignore it. */
- if (V_ip6_accept_rtadv != 0 || V_ip6_forwarding != 1)
+ /*
+ * Accept RS only when V_ip6_forwarding=1 and the interface has
+ * no ND6_IFF_ACCEPT_RTADV.
+ */
+ if (!V_ip6_forwarding || ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV)
goto freeit;
/* Sanity checks */
@@ -218,12 +221,9 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
/*
- * We only accept RAs only when
- * the system-wide variable allows the acceptance, and
- * per-interface variable allows RAs on the receiving interface.
+ * We only accept RAs only when the per-interface flag
+ * ND6_IFF_ACCEPT_RTADV is on the receiving interface.
*/
- if (V_ip6_accept_rtadv == 0)
- goto freeit;
if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
goto freeit;
@@ -273,7 +273,17 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
bzero(&dr0, sizeof(dr0));
dr0.rtaddr = saddr6;
dr0.flags = nd_ra->nd_ra_flags_reserved;
- dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
+ /*
+ * Effectively-disable routes from RA messages when
+ * ND6_IFF_NO_RADR enabled on the receiving interface or
+ * (ip6.forwarding == 1 && ip6.rfc6204w3 != 1).
+ */
+ if (ndi->flags & ND6_IFF_NO_RADR)
+ dr0.rtlifetime = 0;
+ else if (V_ip6_forwarding && !V_ip6_rfc6204w3)
+ dr0.rtlifetime = 0;
+ else
+ dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
dr0.expire = time_second + dr0.rtlifetime;
dr0.ifp = ifp;
/* unspecified or not? (RFC 2461 6.3.4) */
@@ -562,7 +572,7 @@ defrtrlist_del(struct nd_defrouter *dr)
* Flush all the routing table entries that use the router
* as a next hop.
*/
- if (!V_ip6_forwarding && V_ip6_accept_rtadv) /* XXX: better condition? */
+ if (ND_IFINFO(dr->ifp)->flags & ND6_IFF_ACCEPT_RTADV)
rt6_flush(&dr->rtaddr, dr->ifp);
if (dr->installed) {
@@ -621,20 +631,6 @@ defrouter_select(void)
struct llentry *ln = NULL;
/*
- * This function should be called only when acting as an autoconfigured
- * host. Although the remaining part of this function is not effective
- * if the node is not an autoconfigured host, we explicitly exclude
- * such cases here for safety.
- */
- if (V_ip6_forwarding || !V_ip6_accept_rtadv) {
- nd6log((LOG_WARNING,
- "defrouter_select: called unexpectedly (forwarding=%d, "
- "accept_rtadv=%d)\n", V_ip6_forwarding, V_ip6_accept_rtadv));
- splx(s);
- return;
- }
-
- /*
* Let's handle easy case (3) first:
* If default router list is empty, there's nothing to be done.
*/
diff --git a/freebsd/sys/netinet6/pim6_var.h b/freebsd/sys/netinet6/pim6_var.h
index 19d0e900..060836ba 100644
--- a/freebsd/sys/netinet6/pim6_var.h
+++ b/freebsd/sys/netinet6/pim6_var.h
@@ -52,7 +52,7 @@ struct pim6stat {
};
#if (defined(KERNEL)) || (defined(_KERNEL))
-int pim6_input __P((struct mbuf **, int*, int));
+int pim6_input(struct mbuf **, int*, int);
#endif /* KERNEL */
/*
diff --git a/freebsd/sys/netinet6/raw_ip6.c b/freebsd/sys/netinet6/raw_ip6.c
index 06d16034..e2d6693a 100644
--- a/freebsd/sys/netinet6/raw_ip6.c
+++ b/freebsd/sys/netinet6/raw_ip6.c
@@ -94,6 +94,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/icmp6.h>
#include <netinet/ip6.h>
+#include <netinet/ip_var.h>
#include <netinet6/ip6protosw.h>
#include <netinet6/ip6_mroute.h>
#include <netinet6/in6_pcb.h>
@@ -101,6 +102,7 @@ __FBSDID("$FreeBSD$");
#include <netinet6/nd6.h>
#include <netinet6/raw_ip6.h>
#include <netinet6/scope6_var.h>
+#include <netinet6/send.h>
#ifdef IPSEC
#include <netipsec/ipsec.h>
@@ -160,7 +162,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
struct mbuf *opts = NULL;
struct sockaddr_in6 fromsa;
- V_rip6stat.rip6s_ipackets++;
+ RIP6STAT_INC(rip6s_ipackets);
if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
/* XXX Send icmp6 host/port unreach? */
@@ -199,11 +201,11 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
}
INP_RLOCK(in6p);
if (in6p->in6p_cksum != -1) {
- V_rip6stat.rip6s_isum++;
+ RIP6STAT_INC(rip6s_isum);
if (in6_cksum(m, proto, *offp,
m->m_pkthdr.len - *offp)) {
INP_RUNLOCK(in6p);
- V_rip6stat.rip6s_badsum++;
+ RIP6STAT_INC(rip6s_badsum);
continue;
}
}
@@ -263,7 +265,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
*/
if (n && ipsec6_in_reject(n, last)) {
m_freem(n);
- V_ipsec6stat.in_polvio++;
+ IPSEC6STAT_INC(in_polvio);
/* Do not inject data into pcb. */
} else
#endif /* IPSEC */
@@ -279,7 +281,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
m_freem(n);
if (opts)
m_freem(opts);
- V_rip6stat.rip6s_fullsock++;
+ RIP6STAT_INC(rip6s_fullsock);
} else
sorwakeup(last->inp_socket);
opts = NULL;
@@ -295,8 +297,8 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
*/
if ((last != NULL) && ipsec6_in_reject(m, last)) {
m_freem(m);
- V_ipsec6stat.in_polvio++;
- V_ip6stat.ip6s_delivered--;
+ IPSEC6STAT_INC(in_polvio);
+ IP6STAT_DEC(ip6s_delivered);
/* Do not inject data into pcb. */
INP_RUNLOCK(last);
} else
@@ -312,14 +314,14 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
m_freem(m);
if (opts)
m_freem(opts);
- V_rip6stat.rip6s_fullsock++;
+ RIP6STAT_INC(rip6s_fullsock);
} else
sorwakeup(last->inp_socket);
INP_RUNLOCK(last);
} else {
- V_rip6stat.rip6s_nosock++;
+ RIP6STAT_INC(rip6s_nosock);
if (m->m_flags & M_MCAST)
- V_rip6stat.rip6s_nosockmcast++;
+ RIP6STAT_INC(rip6s_nosockmcast);
if (proto == IPPROTO_NONE)
m_freem(m);
else {
@@ -328,7 +330,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
ICMP6_PARAMPROB_NEXTHEADER,
prvnxtp - mtod(m, char *));
}
- V_ip6stat.ip6s_delivered--;
+ IP6STAT_DEC(ip6s_delivered);
}
return (IPPROTO_DONE);
}
@@ -392,6 +394,7 @@ rip6_output(m, va_alist)
#endif
{
struct mbuf *control;
+ struct m_tag *mtag;
struct socket *so;
struct sockaddr_in6 *dstsock;
struct in6_addr *dst;
@@ -535,13 +538,30 @@ rip6_output(m, va_alist)
*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
}
+ /*
+ * Send RA/RS messages to user land for protection, before sending
+ * them to rtadvd/rtsol.
+ */
+ if ((send_sendso_input_hook != NULL) &&
+ so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
+ switch (type) {
+ case ND_ROUTER_ADVERT:
+ case ND_ROUTER_SOLICIT:
+ mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
+ sizeof(unsigned short), M_NOWAIT);
+ if (mtag == NULL)
+ goto bad;
+ m_tag_prepend(m, mtag);
+ }
+ }
+
error = ip6_output(m, optp, NULL, 0, in6p->in6p_moptions, &oifp, in6p);
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
if (oifp)
icmp6_ifoutstat_inc(oifp, type, code);
ICMP6STAT_INC(icp6s_outhist[type]);
} else
- V_rip6stat.rip6s_opackets++;
+ RIP6STAT_INC(rip6s_opackets);
goto freectl;
diff --git a/freebsd/sys/netinet6/raw_ip6.h b/freebsd/sys/netinet6/raw_ip6.h
index 23395a67..cc4bcdd0 100644
--- a/freebsd/sys/netinet6/raw_ip6.h
+++ b/freebsd/sys/netinet6/raw_ip6.h
@@ -48,6 +48,8 @@ struct rip6stat {
};
#ifdef _KERNEL
+#define RIP6STAT_ADD(name, val) V_rip6stat.name += (val)
+#define RIP6STAT_INC(name) RIP6STAT_ADD(name, 1)
VNET_DECLARE(struct rip6stat, rip6stat);
#define V_rip6stat VNET(rip6stat)
#endif
diff --git a/freebsd/sys/netinet6/route6.c b/freebsd/sys/netinet6/route6.c
index f91b9ea8..90738461 100644
--- a/freebsd/sys/netinet6/route6.c
+++ b/freebsd/sys/netinet6/route6.c
@@ -64,17 +64,19 @@ route6_input(struct mbuf **mp, int *offp, int proto)
struct mbuf *m = *mp;
struct ip6_rthdr *rh;
int off = *offp, rhlen;
+#ifdef __notyet__
struct ip6aux *ip6a;
ip6a = ip6_findaux(m);
if (ip6a) {
/* XXX reject home-address option before rthdr */
if (ip6a->ip6a_flags & IP6A_SWAP) {
- V_ip6stat.ip6s_badoptions++;
+ IP6STAT_INC(ip6s_badoptions);
m_freem(m);
return IPPROTO_DONE;
}
}
+#endif
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(*rh), IPPROTO_DONE);
@@ -84,7 +86,7 @@ route6_input(struct mbuf **mp, int *offp, int proto)
ip6 = mtod(m, struct ip6_hdr *);
IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, sizeof(*rh));
if (rh == NULL) {
- V_ip6stat.ip6s_tooshort++;
+ IP6STAT_INC(ip6s_tooshort);
return IPPROTO_DONE;
}
#endif
@@ -100,7 +102,7 @@ route6_input(struct mbuf **mp, int *offp, int proto)
rhlen = (rh->ip6r_len + 1) << 3;
break; /* Final dst. Just ignore the header. */
}
- V_ip6stat.ip6s_badoptions++;
+ IP6STAT_INC(ip6s_badoptions);
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
(caddr_t)&rh->ip6r_type - (caddr_t)ip6);
return (IPPROTO_DONE);
diff --git a/freebsd/sys/netinet6/scope6_var.h b/freebsd/sys/netinet6/scope6_var.h
index 2248037f..ae337b86 100644
--- a/freebsd/sys/netinet6/scope6_var.h
+++ b/freebsd/sys/netinet6/scope6_var.h
@@ -42,18 +42,18 @@ struct scope6_id {
u_int32_t s6id_list[16];
};
-void scope6_init __P((void));
-struct scope6_id *scope6_ifattach __P((struct ifnet *));
-void scope6_ifdetach __P((struct scope6_id *));
-int scope6_set __P((struct ifnet *, struct scope6_id *));
-int scope6_get __P((struct ifnet *, struct scope6_id *));
-void scope6_setdefault __P((struct ifnet *));
-int scope6_get_default __P((struct scope6_id *));
-u_int32_t scope6_addr2default __P((struct in6_addr *));
-int sa6_embedscope __P((struct sockaddr_in6 *, int));
-int sa6_recoverscope __P((struct sockaddr_in6 *));
-int in6_setscope __P((struct in6_addr *, struct ifnet *, u_int32_t *));
-int in6_clearscope __P((struct in6_addr *));
+void scope6_init(void);
+struct scope6_id *scope6_ifattach(struct ifnet *);
+void scope6_ifdetach(struct scope6_id *);
+int scope6_set(struct ifnet *, struct scope6_id *);
+int scope6_get(struct ifnet *, struct scope6_id *);
+void scope6_setdefault(struct ifnet *);
+int scope6_get_default(struct scope6_id *);
+u_int32_t scope6_addr2default(struct in6_addr *);
+int sa6_embedscope(struct sockaddr_in6 *, int);
+int sa6_recoverscope(struct sockaddr_in6 *);
+int in6_setscope(struct in6_addr *, struct ifnet *, u_int32_t *);
+int in6_clearscope(struct in6_addr *);
uint16_t in6_getscope(struct in6_addr *);
#endif /* _KERNEL */
diff --git a/freebsd/sys/netinet6/sctp6_usrreq.c b/freebsd/sys/netinet6/sctp6_usrreq.c
index 65253fbb..f4dfe819 100644
--- a/freebsd/sys/netinet6/sctp6_usrreq.c
+++ b/freebsd/sys/netinet6/sctp6_usrreq.c
@@ -791,18 +791,11 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
}
}
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- if (!MODULE_GLOBAL(ip6_v6only)) {
- struct sockaddr_in sin;
+ struct sockaddr_in sin;
- /* convert v4-mapped into v4 addr and send */
- in6_sin6_2_sin(&sin, sin6);
- return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin,
- control, p));
- } else {
- /* mapped addresses aren't enabled */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
- return (EINVAL);
- }
+ /* convert v4-mapped into v4 addr and send */
+ in6_sin6_2_sin(&sin, sin6);
+ return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p));
}
#endif /* INET */
connected_type:
@@ -936,17 +929,9 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
}
}
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- if (!MODULE_GLOBAL(ip6_v6only)) {
- /* convert v4-mapped into v4 addr */
- in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
- addr = (struct sockaddr *)&ss;
- } else {
- /* mapped addresses aren't enabled */
- SCTP_INP_RUNLOCK(inp);
- SCTP_ASOC_CREATE_UNLOCK(inp);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
- return (EINVAL);
- }
+ /* convert v4-mapped into v4 addr */
+ in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
+ addr = (struct sockaddr *)&ss;
}
#endif /* INET */
/* Now do we connect? */
diff --git a/freebsd/sys/netinet6/sctp6_var.h b/freebsd/sys/netinet6/sctp6_var.h
index 53d1d4c5..79d4c52b 100644
--- a/freebsd/sys/netinet6/sctp6_var.h
+++ b/freebsd/sys/netinet6/sctp6_var.h
@@ -41,22 +41,16 @@ __FBSDID("$FreeBSD$");
SYSCTL_DECL(_net_inet6_sctp6);
extern struct pr_usrreqs sctp6_usrreqs;
+int sctp6_input(struct mbuf **, int *, int);
+int sctp6_input_with_port(struct mbuf **, int *, uint16_t);
+int
+sctp6_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
+ struct mbuf *, struct proc *);
+void sctp6_ctlinput(int, struct sockaddr *, void *);
+extern void
+sctp6_notify(struct sctp_inpcb *, struct icmp6_hdr *,
+ struct sctphdr *, struct sockaddr *,
+ struct sctp_tcb *, struct sctp_nets *);
-int sctp6_input __P((struct mbuf **, int *, int));
-int sctp6_input_with_port __P((struct mbuf **, int *, uint16_t));
-int sctp6_output
-__P((struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
- struct mbuf *, struct proc *));
- void sctp6_ctlinput __P((int, struct sockaddr *, void *));
-
-
- extern void sctp6_notify(struct sctp_inpcb *inp,
- struct icmp6_hdr *icmph,
- struct sctphdr *sh,
- struct sockaddr *to,
- struct sctp_tcb *stcb,
- struct sctp_nets *net);
-
-
-#endif /* _KERNEL */
+#endif
#endif
diff --git a/freebsd/sys/netinet6/send.h b/freebsd/sys/netinet6/send.h
new file mode 100644
index 00000000..9795d142
--- /dev/null
+++ b/freebsd/sys/netinet6/send.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2009-2010 Ana Kukec <anchie@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NETINET6_SEND_H_
+#define _NETINET6_SEND_H_
+
+#define SND_OUT 0 /* Outgoing traffic */
+#define SND_IN 1 /* Incoming traffic. */
+
+struct sockaddr_send {
+ uint8_t send_len; /* total length */
+ sa_family_t send_family; /* address family */
+ int send_direction;
+ int send_ifidx;
+ char send_zero[8];
+};
+
+extern int (*send_sendso_input_hook)(struct mbuf *, struct ifnet *, int, int);
+
+#endif /* _NETINET6_SEND_H_ */
diff --git a/freebsd/sys/netinet6/tcp6_var.h b/freebsd/sys/netinet6/tcp6_var.h
index 7da325a1..5cb04f99 100644
--- a/freebsd/sys/netinet6/tcp6_var.h
+++ b/freebsd/sys/netinet6/tcp6_var.h
@@ -71,9 +71,9 @@ VNET_DECLARE(int, tcp_v6mssdflt); /* XXX */
#endif
struct ip6_hdr;
-void tcp6_ctlinput __P((int, struct sockaddr *, void *));
-void tcp6_init __P((void));
-int tcp6_input __P((struct mbuf **, int *, int));
+void tcp6_ctlinput(int, struct sockaddr *, void *);
+void tcp6_init(void);
+int tcp6_input(struct mbuf **, int *, int);
struct rtentry *tcp_rtlookup6(struct in_conninfo *);
extern struct pr_usrreqs tcp6_usrreqs;
diff --git a/freebsd/sys/netinet6/udp6_usrreq.c b/freebsd/sys/netinet6/udp6_usrreq.c
index 260aedf0..8342cf7c 100644
--- a/freebsd/sys/netinet6/udp6_usrreq.c
+++ b/freebsd/sys/netinet6/udp6_usrreq.c
@@ -2,8 +2,12 @@
/*-
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (c) 2010-2011 Juniper Networks, Inc.
* All rights reserved.
*
+ * Portions of this software were developed by Robert N. M. Watson under
+ * contract to Juniper Networks, Inc.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -69,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
+#include <rtems/bsd/local/opt_ipfw.h>
#include <rtems/bsd/local/opt_ipsec.h>
#include <rtems/bsd/sys/param.h>
@@ -138,7 +143,7 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
/* Check AH/ESP integrity. */
if (ipsec6_in_reject(n, inp)) {
m_freem(n);
- V_ipsec6stat.in_polvio++;
+ IPSEC6STAT_INC(in_polvio);
return;
}
#endif /* IPSEC */
@@ -179,6 +184,8 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
int off = *offp;
int plen, ulen;
struct sockaddr_in6 fromsa;
+ struct m_tag *fwd_tag;
+ uint16_t uh_sum;
ifp = m->m_pkthdr.rcvif;
ip6 = mtod(m, struct ip6_hdr *);
@@ -222,7 +229,18 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
UDPSTAT_INC(udps_nosum);
goto badunlocked;
}
- if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
+
+ if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) {
+ if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
+ uh_sum = m->m_pkthdr.csum_data;
+ else
+ uh_sum = in6_cksum_pseudo(ip6, ulen,
+ IPPROTO_UDP, m->m_pkthdr.csum_data);
+ uh_sum ^= 0xffff;
+ } else
+ uh_sum = in6_cksum(m, IPPROTO_UDP, off, ulen);
+
+ if (uh_sum != 0) {
UDPSTAT_INC(udps_badsum);
goto badunlocked;
}
@@ -233,11 +251,11 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
init_sin6(&fromsa, m);
fromsa.sin6_port = uh->uh_sport;
- INP_INFO_RLOCK(&V_udbinfo);
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
struct inpcb *last;
struct ip6_moptions *imo;
+ INP_INFO_RLOCK(&V_udbinfo);
/*
* In the event that laddr should be set to the link-local
* address (this happens in RIPng), the multicast address
@@ -275,11 +293,11 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
}
/*
- * Detached PCBs can linger in the list if someone
- * holds a reference. (e.g. udp_pcblist)
+ * XXXRW: Because we weren't holding either the inpcb
+ * or the hash lock when we checked for a match
+ * before, we should probably recheck now that the
+ * inpcb lock is (supposed to be) held.
*/
- if (inp->inp_socket == NULL)
- continue;
/*
* Handle socket delivery policy for any-source
@@ -375,8 +393,43 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
/*
* Locate pcb for datagram.
*/
- inp = in6_pcblookup_hash(&V_udbinfo, &ip6->ip6_src, uh->uh_sport,
- &ip6->ip6_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif);
+
+ /*
+ * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain.
+ */
+ if ((m->m_flags & M_IP6_NEXTHOP) &&
+ (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
+ struct sockaddr_in6 *next_hop6;
+
+ next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1);
+
+ /*
+ * Transparently forwarded. Pretend to be the destination.
+ * Already got one like this?
+ */
+ inp = in6_pcblookup_mbuf(&V_udbinfo,
+ &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport,
+ INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m);
+ if (!inp) {
+ /*
+ * It's new. Try to find the ambushing socket.
+ * Because we've rewritten the destination address,
+ * any hardware-generated hash is ignored.
+ */
+ inp = in6_pcblookup(&V_udbinfo, &ip6->ip6_src,
+ uh->uh_sport, &next_hop6->sin6_addr,
+ next_hop6->sin6_port ? htons(next_hop6->sin6_port) :
+ uh->uh_dport, INPLOOKUP_WILDCARD |
+ INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif);
+ }
+ /* Remove the tag from the packet. We don't need it anymore. */
+ m_tag_delete(m, fwd_tag);
+ m->m_flags &= ~M_IP6_NEXTHOP;
+ } else
+ inp = in6_pcblookup_mbuf(&V_udbinfo, &ip6->ip6_src,
+ uh->uh_sport, &ip6->ip6_dst, uh->uh_dport,
+ INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB,
+ m->m_pkthdr.rcvif, m);
if (inp == NULL) {
if (udp_log_in_vain) {
char ip6bufs[INET6_ADDRSTRLEN];
@@ -393,9 +446,8 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
if (m->m_flags & M_MCAST) {
printf("UDP6: M_MCAST is set in a unicast packet.\n");
UDPSTAT_INC(udps_noportmcast);
- goto badheadlocked;
+ goto badunlocked;
}
- INP_INFO_RUNLOCK(&V_udbinfo);
if (V_udp_blackhole)
goto badunlocked;
if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0)
@@ -403,17 +455,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
return (IPPROTO_DONE);
}
- INP_RLOCK(inp);
- INP_INFO_RUNLOCK(&V_udbinfo);
-
- /*
- * Detached PCBs can linger in the hash table if someone holds a
- * reference. (e.g. udp_pcblist)
- */
- if (inp->inp_socket == NULL) {
- INP_RUNLOCK(inp);
- goto badunlocked;
- }
+ INP_RLOCK_ASSERT(inp);
up = intoudpcb(inp);
if (up->u_tun_func == NULL) {
udp6_append(inp, m, off, &fromsa);
@@ -523,13 +565,11 @@ udp6_getcred(SYSCTL_HANDLER_ARGS)
(error = sa6_embedscope(&addrs[1], V_ip6_use_defzone)) != 0) {
return (error);
}
- INP_INFO_RLOCK(&V_udbinfo);
- inp = in6_pcblookup_hash(&V_udbinfo, &addrs[1].sin6_addr,
- addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 1,
- NULL);
+ inp = in6_pcblookup(&V_udbinfo, &addrs[1].sin6_addr,
+ addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port,
+ INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL);
if (inp != NULL) {
- INP_RLOCK(inp);
- INP_INFO_RUNLOCK(&V_udbinfo);
+ INP_RLOCK_ASSERT(inp);
if (inp->inp_socket == NULL)
error = ENOENT;
if (error == 0)
@@ -538,10 +578,8 @@ udp6_getcred(SYSCTL_HANDLER_ARGS)
if (error == 0)
cru2x(inp->inp_cred, &xuc);
INP_RUNLOCK(inp);
- } else {
- INP_INFO_RUNLOCK(&V_udbinfo);
+ } else
error = ENOENT;
- }
if (error == 0)
error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
return (error);
@@ -570,6 +608,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
struct sockaddr_in6 tmp;
INP_WLOCK_ASSERT(inp);
+ INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
if (addr6) {
/* addr6 has been validated in udp6_send(). */
@@ -744,10 +783,9 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
ip6->ip6_src = *laddr;
ip6->ip6_dst = *faddr;
- if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
- sizeof(struct ip6_hdr), plen)) == 0) {
- udp6->uh_sum = 0xffff;
- }
+ udp6->uh_sum = in6_cksum_pseudo(ip6, plen, IPPROTO_UDP, 0);
+ m->m_pkthdr.csum_flags = CSUM_UDP_IPV6;
+ m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
flags = 0;
@@ -790,15 +828,15 @@ udp6_abort(struct socket *so)
}
#endif
- INP_INFO_WLOCK(&V_udbinfo);
INP_WLOCK(inp);
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
+ INP_HASH_WLOCK(&V_udbinfo);
in6_pcbdisconnect(inp);
inp->in6p_laddr = in6addr_any;
+ INP_HASH_WUNLOCK(&V_udbinfo);
soisdisconnected(so);
}
INP_WUNLOCK(inp);
- INP_INFO_WUNLOCK(&V_udbinfo);
}
static int
@@ -856,8 +894,8 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));
- INP_INFO_WLOCK(&V_udbinfo);
INP_WLOCK(inp);
+ INP_HASH_WLOCK(&V_udbinfo);
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
@@ -867,6 +905,7 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
inp->inp_vflag |= INP_IPV4;
+#ifdef INET
else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
struct sockaddr_in sin;
@@ -877,12 +916,15 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
td->td_ucred);
goto out;
}
+#endif
}
error = in6_pcbbind(inp, nam, td->td_ucred);
+#ifdef INET
out:
+#endif
+ INP_HASH_WUNLOCK(&V_udbinfo);
INP_WUNLOCK(inp);
- INP_INFO_WUNLOCK(&V_udbinfo);
return (error);
}
@@ -903,15 +945,15 @@ udp6_close(struct socket *so)
return;
}
#endif
- INP_INFO_WLOCK(&V_udbinfo);
INP_WLOCK(inp);
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
+ INP_HASH_WLOCK(&V_udbinfo);
in6_pcbdisconnect(inp);
inp->in6p_laddr = in6addr_any;
+ INP_HASH_WUNLOCK(&V_udbinfo);
soisdisconnected(so);
}
INP_WUNLOCK(inp);
- INP_INFO_WUNLOCK(&V_udbinfo);
}
static int
@@ -925,8 +967,11 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
sin6 = (struct sockaddr_in6 *)nam;
KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
- INP_INFO_WLOCK(&V_udbinfo);
+ /*
+ * XXXRW: Need to clarify locking of v4/v6 flags.
+ */
INP_WLOCK(inp);
+#ifdef INET
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
@@ -944,12 +989,15 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
error = prison_remote_ip4(td->td_ucred, &sin.sin_addr);
if (error != 0)
goto out;
+ INP_HASH_WLOCK(&V_udbinfo);
error = in_pcbconnect(inp, (struct sockaddr *)&sin,
td->td_ucred);
+ INP_HASH_WUNLOCK(&V_udbinfo);
if (error == 0)
soisconnected(so);
goto out;
}
+#endif
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
error = EISCONN;
goto out;
@@ -959,12 +1007,13 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr);
if (error != 0)
goto out;
+ INP_HASH_WLOCK(&V_udbinfo);
error = in6_pcbconnect(inp, nam, td->td_ucred);
+ INP_HASH_WUNLOCK(&V_udbinfo);
if (error == 0)
soisconnected(so);
out:
INP_WUNLOCK(inp);
- INP_INFO_WUNLOCK(&V_udbinfo);
return (error);
}
@@ -996,32 +1045,32 @@ udp6_disconnect(struct socket *so)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL"));
- INP_INFO_WLOCK(&V_udbinfo);
- INP_WLOCK(inp);
-
#ifdef INET
if (inp->inp_vflag & INP_IPV4) {
struct pr_usrreqs *pru;
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
- error = (*pru->pru_disconnect)(so);
- goto out;
+ (void)(*pru->pru_disconnect)(so);
+ return (0);
}
#endif
+ INP_WLOCK(inp);
+
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
error = ENOTCONN;
goto out;
}
+ INP_HASH_WLOCK(&V_udbinfo);
in6_pcbdisconnect(inp);
inp->in6p_laddr = in6addr_any;
+ INP_HASH_WUNLOCK(&V_udbinfo);
SOCK_LOCK(so);
so->so_state &= ~SS_ISCONNECTED; /* XXX */
SOCK_UNLOCK(so);
out:
INP_WUNLOCK(inp);
- INP_INFO_WUNLOCK(&V_udbinfo);
return (0);
}
@@ -1035,7 +1084,6 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_send: inp == NULL"));
- INP_INFO_WLOCK(&V_udbinfo);
INP_WLOCK(inp);
if (addr) {
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
@@ -1072,7 +1120,6 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
* select the UDPv4 output routine are invalidated?
*/
INP_WUNLOCK(inp);
- INP_INFO_WUNLOCK(&V_udbinfo);
if (sin6)
in6_sin6_2_sin_in_sock(addr);
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
@@ -1085,14 +1132,16 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
#ifdef MAC
mac_inpcb_create_mbuf(inp, m);
#endif
+ INP_HASH_WLOCK(&V_udbinfo);
error = udp6_output(inp, m, addr, control, td);
+ INP_HASH_WUNLOCK(&V_udbinfo);
+#ifdef INET
+#endif
INP_WUNLOCK(inp);
- INP_INFO_WUNLOCK(&V_udbinfo);
return (error);
bad:
INP_WUNLOCK(inp);
- INP_INFO_WUNLOCK(&V_udbinfo);
m_freem(m);
return (error);
}