summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/icmp6.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet6/icmp6.c')
-rw-r--r--freebsd/sys/netinet6/icmp6.c336
1 files changed, 134 insertions, 202 deletions
diff --git a/freebsd/sys/netinet6/icmp6.c b/freebsd/sys/netinet6/icmp6.c
index 569b5dfa..6e3a4873 100644
--- a/freebsd/sys/netinet6/icmp6.c
+++ b/freebsd/sys/netinet6/icmp6.c
@@ -65,9 +65,10 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#define MBUF_PRIVATE /* XXXRW: Optimisation tries to avoid M_EXT mbufs */
+
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
-#include <rtems/bsd/local/opt_ipsec.h>
#include <rtems/bsd/sys/param.h>
#include <sys/domain.h>
@@ -87,6 +88,7 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_llatbl.h>
#include <net/if_types.h>
@@ -100,6 +102,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/icmp6.h>
#include <netinet/tcp_var.h>
+#include <netinet6/in6_fib.h>
#include <netinet6/in6_ifattach.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/ip6protosw.h>
@@ -109,14 +112,14 @@ __FBSDID("$FreeBSD$");
#include <netinet6/nd6.h>
#include <netinet6/send.h>
-#ifdef IPSEC
-#include <netipsec/ipsec.h>
-#include <netipsec/key.h>
-#endif
-
extern struct domain inet6domain;
-VNET_DEFINE(struct icmp6stat, icmp6stat);
+VNET_PCPUSTAT_DEFINE(struct icmp6stat, icmp6stat);
+VNET_PCPUSTAT_SYSINIT(icmp6stat);
+
+#ifdef VIMAGE
+VNET_PCPUSTAT_SYSUNINIT(icmp6stat);
+#endif /* VIMAGE */
VNET_DECLARE(struct inpcbinfo, ripcbinfo);
VNET_DECLARE(struct inpcbhead, ripcb);
@@ -157,7 +160,7 @@ void
kmod_icmp6stat_inc(int statnum)
{
- (*((u_quad_t *)&V_icmp6stat + statnum))++;
+ counter_u64_add(VNET(icmp6stat)[statnum], 1);
}
static void
@@ -362,7 +365,7 @@ icmp6_error(struct mbuf *m, int type, int code, int param)
m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
- M_PREPEND(m, preplen, M_DONTWAIT); /* FIB is also copied over. */
+ M_PREPEND(m, preplen, M_NOWAIT); /* FIB is also copied over. */
if (m == NULL) {
nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
return;
@@ -474,22 +477,6 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
goto freeit;
}
- if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
- /*
- * Deliver very specific ICMP6 type only.
- * This is important to deliver TOOBIG. Otherwise PMTUD
- * will not work.
- */
- switch (icmp6->icmp6_type) {
- case ICMP6_DST_UNREACH:
- case ICMP6_PACKET_TOO_BIG:
- case ICMP6_TIME_EXCEEDED:
- break;
- default:
- goto freeit;
- }
- }
-
ICMP6STAT_INC(icp6s_inhist[icmp6->icmp6_type]);
icmp6_ifstat_inc(ifp, ifs6_in_msg);
if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
@@ -500,15 +487,13 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
icmp6_ifstat_inc(ifp, ifs6_in_dstunreach);
switch (code) {
case ICMP6_DST_UNREACH_NOROUTE:
+ case ICMP6_DST_UNREACH_ADDR: /* PRC_HOSTDEAD is a DOS */
code = PRC_UNREACH_NET;
break;
case ICMP6_DST_UNREACH_ADMIN:
icmp6_ifstat_inc(ifp, ifs6_in_adminprohib);
code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
break;
- case ICMP6_DST_UNREACH_ADDR:
- code = PRC_HOSTDEAD;
- break;
case ICMP6_DST_UNREACH_BEYONDSCOPE:
/* I mean "source address was incorrect." */
code = PRC_PARAMPROB;
@@ -575,28 +560,21 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
/* Give up remote */
break;
}
- if ((n->m_flags & M_EXT) != 0
+ if (!M_WRITABLE(n)
|| n->m_len < off + sizeof(struct icmp6_hdr)) {
struct mbuf *n0 = n;
- const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
int n0len;
- MGETHDR(n, M_DONTWAIT, n0->m_type);
- n0len = n0->m_pkthdr.len; /* save for use below */
- if (n)
- M_MOVE_PKTHDR(n, n0); /* FIB copied. */
- if (n && maxlen >= MHLEN) {
- MCLGET(n, M_DONTWAIT);
- if ((n->m_flags & M_EXT) == 0) {
- m_free(n);
- n = NULL;
- }
- }
+ CTASSERT(sizeof(*nip6) + sizeof(*nicmp6) <= MHLEN);
+ n = m_gethdr(M_NOWAIT, n0->m_type);
if (n == NULL) {
/* Give up remote */
m_freem(n0);
break;
}
+
+ m_move_pkthdr(n, n0); /* FIB copied. */
+ n0len = n0->m_pkthdr.len; /* save for use below */
/*
* Copy IPv6 and ICMPv6 only.
*/
@@ -683,31 +661,27 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
} else {
struct prison *pr;
u_char *p;
- int maxlen, maxhlen, hlen;
+ int maxhlen, hlen;
/*
* XXX: this combination of flags is pointless,
* but should we keep this for compatibility?
*/
- if ((V_icmp6_nodeinfo & 5) != 5)
+ if ((V_icmp6_nodeinfo & (ICMP6_NODEINFO_FQDNOK |
+ ICMP6_NODEINFO_TMPADDROK)) !=
+ (ICMP6_NODEINFO_FQDNOK | ICMP6_NODEINFO_TMPADDROK))
break;
if (code != 0)
goto badcode;
- maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
- if (maxlen >= MCLBYTES) {
+
+ CTASSERT(sizeof(*nip6) + sizeof(*nicmp6) + 4 <= MHLEN);
+ n = m_gethdr(M_NOWAIT, m->m_type);
+ if (n == NULL) {
/* Give up remote */
break;
}
- MGETHDR(n, M_DONTWAIT, m->m_type);
- if (n && maxlen > MHLEN) {
- MCLGET(n, M_DONTWAIT);
- if ((n->m_flags & M_EXT) == 0) {
- m_free(n);
- n = NULL;
- }
- }
- if (n && !m_dup_pkthdr(n, m, M_DONTWAIT)) {
+ if (!m_dup_pkthdr(n, m, M_NOWAIT)) {
/*
* Previous code did a blind M_COPY_PKTHDR
* and said "just for rcvif". If true, then
@@ -718,13 +692,8 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
m_free(n);
n = NULL;
}
- if (n == NULL) {
- /* Give up remote */
- break;
- }
- n->m_pkthdr.rcvif = NULL;
- n->m_len = 0;
- maxhlen = M_TRAILINGSPACE(n) - maxlen;
+ maxhlen = M_TRAILINGSPACE(n) -
+ (sizeof(*nip6) + sizeof(*nicmp6) + 4);
#ifndef __rtems__
pr = curthread->td_ucred->cr_prison;
#else /* __rtems__ */
@@ -771,7 +740,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
goto badcode;
if (icmp6len < sizeof(struct nd_router_solicit))
goto badlen;
- if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
/* give up local */
/* Send incoming SeND packet to user space. */
@@ -809,7 +778,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
goto badcode;
if (icmp6len < sizeof(struct nd_router_advert))
goto badlen;
- if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
/* Send incoming SeND-protected/ND packet to user space. */
if (send_sendso_input_hook != NULL) {
@@ -840,7 +809,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
goto badcode;
if (icmp6len < sizeof(struct nd_neighbor_solicit))
goto badlen;
- if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
if (send_sendso_input_hook != NULL) {
error = send_sendso_input_hook(m, ifp,
SND_IN, ip6len);
@@ -869,7 +838,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
goto badcode;
if (icmp6len < sizeof(struct nd_neighbor_advert))
goto badlen;
- if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
/* Send incoming SeND-protected/ND packet to user space. */
if (send_sendso_input_hook != NULL) {
@@ -900,7 +869,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
goto badcode;
if (icmp6len < sizeof(struct nd_redirect))
goto badlen;
- if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
+ if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
if (send_sendso_input_hook != NULL) {
error = send_sendso_input_hook(m, ifp,
SND_IN, ip6len);
@@ -1181,8 +1150,6 @@ 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;
@@ -1329,7 +1296,8 @@ ni6_input(struct mbuf *m, int off)
goto bad;
/* else it's a link-local multicast, fine */
} else { /* unicast or anycast */
- if ((ia6 = ip6_getdstifaddr(m)) == NULL)
+ ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+ if (ia6 == NULL)
goto bad; /* XXX impossible */
if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) &&
@@ -1505,26 +1473,23 @@ ni6_input(struct mbuf *m, int off)
break;
}
- /* allocate an mbuf to reply. */
- MGETHDR(n, M_DONTWAIT, m->m_type);
+ /* Allocate an mbuf to reply. */
+ if (replylen > MCLBYTES) {
+ /*
+ * XXX: should we try to allocate more? But MCLBYTES
+ * is probably much larger than IPV6_MMTU...
+ */
+ goto bad;
+ }
+ if (replylen > MHLEN)
+ n = m_getcl(M_NOWAIT, m->m_type, M_PKTHDR);
+ else
+ n = m_gethdr(M_NOWAIT, m->m_type);
if (n == NULL) {
m_freem(m);
return (NULL);
}
- M_MOVE_PKTHDR(n, m); /* just for recvif and FIB */
- if (replylen > MHLEN) {
- if (replylen > MCLBYTES) {
- /*
- * XXX: should we try to allocate more? But MCLBYTES
- * is probably much larger than IPV6_MMTU...
- */
- goto bad;
- }
- MCLGET(n, M_DONTWAIT);
- if ((n->m_flags & M_EXT) == 0) {
- goto bad;
- }
- }
+ m_move_pkthdr(n, m); /* just for recvif and FIB */
n->m_pkthdr.len = n->m_len = replylen;
/* copy mbuf header and IPv6 + Node Information base headers */
@@ -1623,16 +1588,13 @@ ni6_nametodns(const char *name, int namelen, int old)
else
len = MCLBYTES;
- /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */
- MGET(m, M_DONTWAIT, MT_DATA);
- if (m && len > MLEN) {
- MCLGET(m, M_DONTWAIT);
- if ((m->m_flags & M_EXT) == 0)
- goto fail;
- }
- if (!m)
+ /* Because MAXHOSTNAMELEN is usually 256, we use cluster mbuf. */
+ if (len > MLEN)
+ m = m_getcl(M_NOWAIT, MT_DATA, 0);
+ else
+ m = m_get(M_NOWAIT, MT_DATA);
+ if (m == NULL)
goto fail;
- m->m_next = NULL;
if (old) {
m->m_len = len;
@@ -1793,7 +1755,7 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m, struct ifnet **ifpp,
}
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
+ TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
addrsofif = 0;
IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
@@ -1880,7 +1842,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6,
ifp = ifp0 ? ifp0 : TAILQ_FIRST(&V_ifnet);
again:
- for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
+ for (; ifp; ifp = TAILQ_NEXT(ifp, if_link)) {
IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
@@ -1965,8 +1927,8 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6,
ltime = ND6_INFINITE_LIFETIME;
else {
if (ifa6->ia6_lifetime.ia6t_expire >
- time_second)
- ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_second);
+ time_uptime)
+ ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_uptime);
else
ltime = 0;
}
@@ -2078,7 +2040,7 @@ icmp6_rip6_input(struct mbuf **mp, int off)
*/
if ((m->m_flags & M_EXT) && m->m_next == NULL &&
m->m_len <= MHLEN) {
- MGET(n, M_DONTWAIT, m->m_type);
+ n = m_get(M_NOWAIT, m->m_type);
if (n != NULL) {
if (m_dup_pkthdr(n, m, M_NOWAIT)) {
bcopy(m->m_data, n->m_data,
@@ -2128,7 +2090,7 @@ icmp6_rip6_input(struct mbuf **mp, int off)
m->m_len <= MHLEN) {
struct mbuf *n;
- MGET(n, M_DONTWAIT, m->m_type);
+ n = m_get(M_NOWAIT, m->m_type);
if (n != NULL) {
if (m_dup_pkthdr(n, m, M_NOWAIT)) {
bcopy(m->m_data, n->m_data, m->m_len);
@@ -2166,13 +2128,13 @@ icmp6_rip6_input(struct mbuf **mp, int off)
void
icmp6_reflect(struct mbuf *m, size_t off)
{
+ struct in6_addr src6, *srcp;
struct ip6_hdr *ip6;
struct icmp6_hdr *icmp6;
struct in6_ifaddr *ia = NULL;
- int plen;
- int type, code;
struct ifnet *outif = NULL;
- struct in6_addr origdst, src, *srcp = NULL;
+ int plen;
+ int type, code, hlim;
/* too short to reflect */
if (off < sizeof(struct ip6_hdr)) {
@@ -2218,13 +2180,8 @@ icmp6_reflect(struct mbuf *m, size_t off)
icmp6 = (struct icmp6_hdr *)(ip6 + 1);
type = icmp6->icmp6_type; /* keep type for statistics */
code = icmp6->icmp6_code; /* ditto. */
-
- origdst = ip6->ip6_dst;
- /*
- * ip6_input() drops a packet if its src is multicast.
- * So, the src is never multicast.
- */
- ip6->ip6_dst = ip6->ip6_src;
+ hlim = 0;
+ srcp = NULL;
/*
* If the incoming packet was addressed directly to us (i.e. unicast),
@@ -2232,74 +2189,59 @@ icmp6_reflect(struct mbuf *m, size_t off)
* The IN6_IFF_NOTREADY case should be VERY rare, but is possible
* (for example) when we encounter an error while forwarding procedure
* destined to a duplicated address of ours.
- * Note that ip6_getdstifaddr() may fail if we are in an error handling
- * procedure of an outgoing packet of our own, in which case we need
- * to search in the ifaddr list.
*/
- if (!IN6_IS_ADDR_MULTICAST(&origdst)) {
- if ((ia = ip6_getdstifaddr(m))) {
- if (!(ia->ia6_flags &
- (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
- srcp = &ia->ia_addr.sin6_addr;
- } else {
- struct sockaddr_in6 d;
-
- bzero(&d, sizeof(d));
- d.sin6_family = AF_INET6;
- d.sin6_len = sizeof(d);
- d.sin6_addr = origdst;
- ia = (struct in6_ifaddr *)
- ifa_ifwithaddr((struct sockaddr *)&d);
- if (ia &&
- !(ia->ia6_flags &
- (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
- srcp = &ia->ia_addr.sin6_addr;
- }
+ if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+ ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+ if (ia != NULL && !(ia->ia6_flags &
+ (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
+ src6 = ia->ia_addr.sin6_addr;
+ srcp = &src6;
+
+ if (m->m_pkthdr.rcvif != NULL) {
+ /* XXX: This may not be the outgoing interface */
+ hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
+ } else
+ hlim = V_ip6_defhlim;
}
+ if (ia != NULL)
+ ifa_free(&ia->ia_ifa);
}
if (srcp == NULL) {
- int e;
- struct sockaddr_in6 sin6;
- struct route_in6 ro;
+ int error;
+ struct in6_addr dst6;
+ uint32_t scopeid;
/*
* This case matches to multicasts, our anycast, or unicasts
* that we do not own. Select a source address based on the
* source address of the erroneous packet.
*/
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(sin6);
- sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
-
- bzero(&ro, sizeof(ro));
- e = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &src);
- if (ro.ro_rt)
- RTFREE(ro.ro_rt); /* XXX: we could use this */
- if (e) {
+ in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid);
+ error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
+ scopeid, NULL, &src6, &hlim);
+
+ if (error) {
char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG,
"icmp6_reflect: source can't be determined: "
"dst=%s, error=%d\n",
- ip6_sprintf(ip6buf, &sin6.sin6_addr), e));
+ ip6_sprintf(ip6buf, &ip6->ip6_dst), error));
goto bad;
}
- srcp = &src;
+ srcp = &src6;
}
-
+ /*
+ * ip6_input() drops a packet if its src is multicast.
+ * So, the src is never multicast.
+ */
+ ip6->ip6_dst = ip6->ip6_src;
ip6->ip6_src = *srcp;
ip6->ip6_flow = 0;
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_ICMPV6;
- if (outif)
- ip6->ip6_hlim = ND_IFINFO(outif)->chlim;
- else if (m->m_pkthdr.rcvif) {
- /* XXX: This may not be the outgoing interface */
- ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
- } else
- ip6->ip6_hlim = V_ip6_defhlim;
+ ip6->ip6_hlim = hlim;
icmp6->icmp6_cksum = 0;
icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
@@ -2311,19 +2253,13 @@ 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);
- if (ia != NULL)
- ifa_free(&ia->ia_ifa);
return;
bad:
- if (ia != NULL)
- ifa_free(&ia->ia_ifa);
m_freem(m);
return;
}
@@ -2365,7 +2301,6 @@ icmp6_redirect_input(struct mbuf *m, int off)
int icmp6len = ntohs(ip6->ip6_plen);
char *lladdr = NULL;
int lladdrlen = 0;
- struct rtentry *rt = NULL;
int is_router;
int is_onlink;
struct in6_addr src6 = ip6->ip6_src;
@@ -2420,18 +2355,13 @@ icmp6_redirect_input(struct mbuf *m, int off)
}
{
/* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
- struct sockaddr_in6 sin6;
- struct in6_addr *gw6;
-
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
- rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
- if (rt) {
- if (rt->rt_gateway == NULL ||
- rt->rt_gateway->sa_family != AF_INET6) {
- RTFREE_LOCKED(rt);
+ struct nhop6_basic nh6;
+ struct in6_addr kdst;
+ uint32_t scopeid;
+
+ in6_splitscope(&reddst6, &kdst, &scopeid);
+ if (fib6_lookup_nh_basic(RT_DEFAULT_FIB, &kdst, scopeid, 0, 0,&nh6)==0){
+ if ((nh6.nh_flags & NHF_GATEWAY) == 0) {
nd6log((LOG_ERR,
"ICMP6 redirect rejected; no route "
"with inet6 gateway found for redirect dst: %s\n",
@@ -2439,14 +2369,12 @@ icmp6_redirect_input(struct mbuf *m, int off)
goto bad;
}
- gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
- if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
- RTFREE_LOCKED(rt);
+ if (IN6_ARE_ADDR_EQUAL(&src6, &nh6.nh_addr) == 0) {
nd6log((LOG_ERR,
"ICMP6 redirect rejected; "
"not equal to gw-for-src=%s (must be same): "
"%s\n",
- ip6_sprintf(ip6buf, gw6),
+ ip6_sprintf(ip6buf, &nh6.nh_addr),
icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
goto bad;
}
@@ -2457,8 +2385,6 @@ icmp6_redirect_input(struct mbuf *m, int off)
icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
goto bad;
}
- RTFREE_LOCKED(rt);
- rt = NULL;
}
if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
nd6log((LOG_ERR,
@@ -2480,7 +2406,6 @@ icmp6_redirect_input(struct mbuf *m, int off)
icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
goto bad;
}
- /* validation passed */
icmp6len -= sizeof(*nd_rd);
nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
@@ -2505,31 +2430,45 @@ icmp6_redirect_input(struct mbuf *m, int off)
goto bad;
}
+ /* Validation passed. */
+
/* RFC 2461 8.3 */
nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
- if (!is_onlink) { /* better router case. perform rtredirect. */
- /* perform rtredirect */
+ /*
+ * Install a gateway route in the better-router case or an interface
+ * route in the on-link-destination case.
+ */
+ {
struct sockaddr_in6 sdst;
struct sockaddr_in6 sgw;
struct sockaddr_in6 ssrc;
+ struct sockaddr *gw;
+ int rt_flags;
u_int fibnum;
bzero(&sdst, sizeof(sdst));
- bzero(&sgw, sizeof(sgw));
bzero(&ssrc, sizeof(ssrc));
- sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
- sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
- sizeof(struct sockaddr_in6);
- bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
+ sdst.sin6_family = ssrc.sin6_family = AF_INET6;
+ sdst.sin6_len = ssrc.sin6_len = sizeof(struct sockaddr_in6);
bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
+ rt_flags = RTF_HOST;
+ if (is_router) {
+ bzero(&sgw, sizeof(sgw));
+ sgw.sin6_family = AF_INET6;
+ sgw.sin6_len = sizeof(struct sockaddr_in6);
+ bcopy(&redtgt6, &sgw.sin6_addr,
+ sizeof(struct in6_addr));
+ gw = (struct sockaddr *)&sgw;
+ rt_flags |= RTF_GATEWAY;
+ } else
+ gw = ifp->if_addr->ifa_addr;
for (fibnum = 0; fibnum < rt_numfibs; fibnum++)
- in6_rtredirect((struct sockaddr *)&sdst,
- (struct sockaddr *)&sgw, (struct sockaddr *)NULL,
- RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&ssrc,
- fibnum);
+ in6_rtredirect((struct sockaddr *)&sdst, gw,
+ (struct sockaddr *)NULL, rt_flags,
+ (struct sockaddr *)&ssrc, fibnum);
}
/* finally update cached route in each socket via pfctlinput */
{
@@ -2540,9 +2479,6 @@ icmp6_redirect_input(struct mbuf *m, int off)
sdst.sin6_len = sizeof(struct sockaddr_in6);
bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
-#ifdef IPSEC
- key_sa_routechange((struct sockaddr *)&sdst);
-#endif /* IPSEC */
}
freeit:
@@ -2609,14 +2545,10 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
#if IPV6_MMTU >= MCLBYTES
# error assumption failed about IPV6_MMTU and MCLBYTES
#endif
- MGETHDR(m, M_DONTWAIT, MT_HEADER);
- if (m && IPV6_MMTU >= MHLEN)
- MCLGET(m, M_DONTWAIT);
- if (!m)
+ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
goto fail;
M_SETFIB(m, rt->rt_fibnum);
- m->m_pkthdr.rcvif = NULL;
- m->m_len = 0;
maxlen = M_TRAILINGSPACE(m);
maxlen = min(IPV6_MMTU, maxlen);
/* just for safety */
@@ -2711,7 +2643,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
nd_opt->nd_opt_len = len >> 3;
lladdr = (char *)(nd_opt + 1);
- bcopy(&ln->ll_addr, lladdr, ifp->if_addrlen);
+ bcopy(ln->ll_addr, lladdr, ifp->if_addrlen);
p += len;
}
}