diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-06 16:20:21 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-11 10:08:08 +0100 |
commit | 66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch) | |
tree | 48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/netinet6 | |
parent | Define __GLOBL1() and __GLOBL() (diff) | |
download | rtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2 |
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/netinet6')
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 *)¬ifymtu; @@ -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); } |