Remove auxiliary data support and use in6ifa_ifwithaddr() function instead of ip6_getdstifaddr(). Rewrite scope zone checks, remove in6_clearscope/in6_setscope functions. Remove LLE lookup and route lookup from input path. --- sys/netinet6/ip6_input.c (svn+ssh://svn.freebsd.org/base/head) (revision 261548) +++ sys/netinet6/ip6_input.c (working copy) @@ -154,10 +154,6 @@ struct rwlock in6_ifaddr_lock; 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); @@ -427,19 +423,16 @@ out: void ip6_input(struct mbuf *m) { + struct in6_addr odst; struct ip6_hdr *ip6; + struct in6_ifaddr *ia; + int32_t plen; + int32_t rtalert = ~0; int off = sizeof(struct ip6_hdr), nest; - u_int32_t plen; - u_int32_t rtalert = ~0; + int srcscope, dstscope; int nxt, ours = 0; - struct ifnet *deliverifp = NULL, *ifp = NULL; - struct in6_addr odst; - struct route_in6 rin6; int srcrt = 0; - struct llentry *lle = NULL; - struct sockaddr_in6 dst6, *dst; - bzero(&rin6, sizeof(struct route_in6)); #ifdef IPSEC /* * should the inner packet be considered authentic? @@ -452,11 +445,6 @@ ip6_input(struct mbuf *m) #endif /* IPSEC */ - /* - * make sure we don't have onion peering information into m_tag. - */ - ip6_delaux(m); - if (m->m_flags & M_FASTFWD_OURS) { /* * Firewall changed destination to local. @@ -463,7 +451,6 @@ ip6_input(struct mbuf *m) */ m->m_flags &= ~M_FASTFWD_OURS; ours = 1; - deliverifp = m->m_pkthdr.rcvif; ip6 = mtod(m, struct ip6_hdr *); goto hbhcheck; } @@ -489,12 +476,6 @@ ip6_input(struct mbuf *m) IP6STAT_INC(ip6s_m1); } - /* drop the packet if IPv6 operation is disabled on the IF */ - if ((ND_IFINFO(m->m_pkthdr.rcvif)->flags & ND6_IFF_IFDISABLED)) { - m_freem(m); - return; - } - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); IP6STAT_INC(ip6s_total); @@ -643,7 +624,6 @@ ip6_input(struct mbuf *m) 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) && @@ -654,30 +634,22 @@ ip6_input(struct mbuf *m) * connected host. */ ip6_forward(m, 1); - goto out; + return; } passin: - /* - * Disambiguate address scope zones (if there is ambiguity). - * We first make sure that the original source or destination address - * is not in our internal form for scoped addresses. Such addresses - * are not necessarily invalid spec-wise, but we cannot accept them due - * to the usage conflict. - * in6_setscope() then also checks and rejects the cases where src or - * dst are the loopback address and the receiving interface - * is not loopback. - */ - if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) { - IP6STAT_INC(ip6s_badscope); /* XXX */ - goto bad; + srcscope = in6_addrscope(&ip6->ip6_src); + if (srcscope == IPV6_ADDR_SCOPE_LINKLOCAL && + IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) { + /* + * Packets with the loopback source address must be + * received on the loopback interface. + */ + if (m->m_pkthdr.rcvif != V_loif) { + IP6STAT_INC(ip6s_badscope); + goto bad; + } } - if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) || - in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) { - IP6STAT_INC(ip6s_badscope); - goto bad; - } - /* * Multicast check. Assume packet is for us to avoid * prematurely taking locks. @@ -685,7 +657,6 @@ passin: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { ours = 1; in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); - deliverifp = m->m_pkthdr.rcvif; goto hbhcheck; } @@ -692,162 +663,32 @@ passin: /* * Unicast check */ - - bzero(&dst6, sizeof(dst6)); - dst6.sin6_family = AF_INET6; - dst6.sin6_len = sizeof(struct sockaddr_in6); - dst6.sin6_addr = ip6->ip6_dst; - ifp = m->m_pkthdr.rcvif; - IF_AFDATA_RLOCK(ifp); - lle = lla_lookup(LLTABLE6(ifp), 0, - (struct sockaddr *)&dst6); - IF_AFDATA_RUNLOCK(ifp); - if ((lle != NULL) && (lle->la_flags & LLE_IFADDR)) { - struct ifaddr *ifa; - struct in6_ifaddr *ia6; - int bad; - - bad = 1; -#define sa_equal(a1, a2) \ - (bcmp((a1), (a2), ((a1))->sin6_len) == 0) - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != dst6.sin6_family) - continue; - if (sa_equal(&dst6, ifa->ifa_addr)) - break; - } - KASSERT(ifa != NULL, ("%s: ifa not found for lle %p", - __func__, lle)); -#undef sa_equal - - ia6 = (struct in6_ifaddr *)ifa; - if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { - /* Count the packet in the ip address stats */ - counter_u64_add(ia6->ia_ifa.ifa_ipackets, 1); - counter_u64_add(ia6->ia_ifa.ifa_ibytes, - m->m_pkthdr.len); - + dstscope = in6_addrscope(&ip6->ip6_dst); + ia = in6ifa_ifwithaddr(&ip6->ip6_dst, + in6_getscopezone(m->m_pkthdr.rcvif, dstscope)); + if (ia == NULL) { + /* + * This means that the receiving interface doesn't have this + * scoped (i.e. not global) address configured. + */ + if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { /* - * record address information into m_tag. + * Packets with the loopback destination address must + * be received on the loopback interface. */ - (void)ip6_setdstifaddr(m, ia6); - - bad = 0; - } else { - char ip6bufs[INET6_ADDRSTRLEN]; - char ip6bufd[INET6_ADDRSTRLEN]; - /* address is not ready, so discard the packet. */ - nd6log((LOG_INFO, - "ip6_input: packet to an unready address %s->%s\n", - ip6_sprintf(ip6bufs, &ip6->ip6_src), - ip6_sprintf(ip6bufd, &ip6->ip6_dst))); - } - IF_ADDR_RUNLOCK(ifp); - LLE_RUNLOCK(lle); - if (bad) + IP6STAT_INC(ip6s_badscope); goto bad; - else { - ours = 1; - deliverifp = ifp; - goto hbhcheck; } - } - if (lle != NULL) - LLE_RUNLOCK(lle); - - dst = &rin6.ro_dst; - dst->sin6_len = sizeof(struct sockaddr_in6); - dst->sin6_family = AF_INET6; - dst->sin6_addr = ip6->ip6_dst; - rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m)); - if (rin6.ro_rt) - RT_UNLOCK(rin6.ro_rt); - -#define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key)) - - /* - * Accept the packet if the forwarding interface to the destination - * according to the routing table is the loopback interface, - * unless the associated route has a gateway. - * Note that this approach causes to accept a packet if there is a - * route to the loopback interface for the destination of the packet. - * But we think it's even useful in some situations, e.g. when using - * a special daemon which wants to intercept the packet. - * - * XXX: some OSes automatically make a cloned route for the destination - * of an outgoing packet. If the outgoing interface of the packet - * is a loopback one, the kernel would consider the packet to be - * accepted, even if we have no such address assinged on the interface. - * We check the cloned flag of the route entry to reject such cases, - * assuming that route entries for our own addresses are not made by - * cloning (it should be true because in6_addloop explicitly installs - * the host route). However, we might have to do an explicit check - * while it would be less efficient. Or, should we rather install a - * reject route for such a case? - */ - if (rin6.ro_rt && - (rin6.ro_rt->rt_flags & - (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && -#ifdef RTF_WASCLONED - !(rin6.ro_rt->rt_flags & RTF_WASCLONED) && -#endif -#ifdef RTF_CLONED - !(rin6.ro_rt->rt_flags & RTF_CLONED) && -#endif -#if 0 - /* - * The check below is redundant since the comparison of - * the destination and the key of the rtentry has - * already done through looking up the routing table. - */ - IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, - &rt6_key(rin6.ro_rt)->sin6_addr) -#endif - rin6.ro_rt->rt_ifp->if_type == IFT_LOOP) { - int free_ia6 = 0; - struct in6_ifaddr *ia6; - /* - * found the loopback route to the interface address + * RFC 4007 p9: + * If a router receives a packet with a link-local destination + * address that is not one of the router's own link-local + * addresses on the arrival link, the router is expected to + * try to forward the packet to the destination on that link. */ - if (rin6.ro_rt->rt_gateway->sa_family == AF_LINK) { - struct sockaddr_in6 dest6; - - bzero(&dest6, sizeof(dest6)); - dest6.sin6_family = AF_INET6; - dest6.sin6_len = sizeof(dest6); - dest6.sin6_addr = ip6->ip6_dst; - ia6 = (struct in6_ifaddr *) - ifa_ifwithaddr((struct sockaddr *)&dest6); - if (ia6 == NULL) - goto bad; - free_ia6 = 1; - } - else - ia6 = (struct in6_ifaddr *)rin6.ro_rt->rt_ifa; - - /* - * record address information into m_tag. - */ - (void)ip6_setdstifaddr(m, ia6); - - /* - * packets to a tentative, duplicated, or somehow invalid - * address must not be accepted. - */ - if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { - /* this address is ready */ - ours = 1; - deliverifp = ia6->ia_ifp; /* correct? */ - /* Count the packet in the ip address stats */ - counter_u64_add(ia6->ia_ifa.ifa_ipackets, 1); - counter_u64_add(ia6->ia_ifa.ifa_ibytes, - m->m_pkthdr.len); - if (free_ia6) - ifa_free(&ia6->ia_ifa); - goto hbhcheck; - } else { + /* FALLTHROUGH */ + } else { + if (ia->ia6_flags & IN6_IFF_NOTREADY) { char ip6bufs[INET6_ADDRSTRLEN]; char ip6bufd[INET6_ADDRSTRLEN]; /* address is not ready, so discard the packet. */ @@ -855,27 +696,17 @@ passin: "ip6_input: packet to an unready address %s->%s\n", ip6_sprintf(ip6bufs, &ip6->ip6_src), ip6_sprintf(ip6bufd, &ip6->ip6_dst))); - - if (free_ia6) - ifa_free(&ia6->ia_ifa); + ifa_free(&ia->ia_ifa); goto bad; } + /* Count the packet in the ip address stats */ + counter_u64_add(ia->ia_ifa.ifa_ipackets, 1); + counter_u64_add(ia->ia_ifa.ifa_ibytes, m->m_pkthdr.len); + ifa_free(&ia->ia_ifa); + ours = 1; + goto hbhcheck; } - /* - * FAITH (Firewall Aided Internet Translator) - */ - if (V_ip6_keepfaith) { - if (rin6.ro_rt && rin6.ro_rt->rt_ifp && - rin6.ro_rt->rt_ifp->if_type == IFT_FAITH) { - /* XXX do we need more sanity checks? */ - ours = 1; - deliverifp = rin6.ro_rt->rt_ifp; /* faith */ - goto hbhcheck; - } - } - - /* * Now there is no reason to process the packet if it's not our own * and we're not a router. */ @@ -887,32 +718,6 @@ passin: hbhcheck: /* - * record address information into m_tag, if we don't have one yet. - * note that we are unable to record it, if the address is not listed - * as our interface address (e.g. multicast addresses, addresses - * within FAITH prefixes and such). - */ - if (deliverifp) { - struct in6_ifaddr *ia6; - - if ((ia6 = ip6_getdstifaddr(m)) != NULL) { - ifa_free(&ia6->ia_ifa); - } else { - ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); - if (ia6) { - if (!ip6_setdstifaddr(m, ia6)) { - /* - * XXX maybe we should drop the packet here, - * as we could not provide enough information - * to the upper layers. - */ - } - ifa_free(&ia6->ia_ifa); - } - } - } - - /* * Process Hop-by-Hop options header if it's contained. * m may be modified in ip6_hopopts_input(). * If a JumboPayload option is included, plen will also be modified. @@ -923,7 +728,7 @@ passin: error = ip6_input_hbh(m, &plen, &rtalert, &off, &nxt, &ours); if (error != 0) - goto out; + return; } else nxt = ip6->ip6_nxt; @@ -970,7 +775,7 @@ passin: } } else if (!ours) { ip6_forward(m, srcrt); - goto out; + return; } ip6 = mtod(m, struct ip6_hdr *); @@ -995,7 +800,7 @@ passin: * Tell launch routine the next header */ IP6STAT_INC(ip6s_delivered); - in6_ifstat_inc(deliverifp, ifs6_in_deliver); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_deliver); nest = 0; while (nxt != IPPROTO_DONE) { @@ -1033,50 +838,12 @@ passin: nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } - goto out; + return; bad: m_freem(m); -out: - if (rin6.ro_rt) - RTFREE(rin6.ro_rt); } /* - * set/grab in6_ifaddr correspond to IPv6 destination address. - * XXX backward compatibility wrapper - * - * XXXRW: We should bump the refcount on ia6 before sticking it in the m_tag, - * and then bump it when the tag is copied, and release it when the tag is - * freed. Unfortunately, m_tags don't support deep copies (yet), so instead - * we just bump the ia refcount when we receive it. This should be fixed. - */ -static struct ip6aux * -ip6_setdstifaddr(struct mbuf *m, struct in6_ifaddr *ia6) -{ - struct ip6aux *ip6a; - - ip6a = ip6_addaux(m); - if (ip6a) - ip6a->ip6a_dstia6 = ia6; - return ip6a; /* NULL if failed to set */ -} - -struct in6_ifaddr * -ip6_getdstifaddr(struct mbuf *m) -{ - struct ip6aux *ip6a; - struct in6_ifaddr *ia; - - ip6a = ip6_findaux(m); - if (ip6a) { - ia = ip6a->ip6a_dstia6; - ifa_ref(&ia->ia_ifa); - return ia; - } else - return NULL; -} - -/* * Hop-by-Hop options header processing. If a valid jumbo payload option is * included, the real payload length will be stored in plenp. * @@ -1354,7 +1121,6 @@ ip6_savecontrol_v4(struct inpcb *inp, struct mbuf #endif } else { bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); - in6_clearscope(&pi6.ipi6_addr); /* XXX */ } pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif) ? m->m_pkthdr.rcvif->if_index : 0; @@ -1629,9 +1395,6 @@ ip6_notify_pmtu(struct inpcb *in6p, struct sockadd bzero(&mtuctl, sizeof(mtuctl)); /* zero-clear for safety */ mtuctl.ip6m_mtu = *mtu; mtuctl.ip6m_addr = *dst; - if (sa6_recoverscope(&mtuctl.ip6m_addr)) - return; - if ((m_mtu = sbcreatecontrol((caddr_t)&mtuctl, sizeof(mtuctl), IPV6_PATHMTU, IPPROTO_IPV6)) == NULL) return; @@ -1839,46 +1602,9 @@ ip6_lasthdr(struct mbuf *m, int off, int proto, in } } -static struct ip6aux * -ip6_addaux(struct mbuf *m) -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); - if (!mtag) { - mtag = m_tag_get(PACKET_TAG_IPV6_INPUT, sizeof(struct ip6aux), - M_NOWAIT); - if (mtag) { - m_tag_prepend(m, mtag); - bzero(mtag + 1, sizeof(struct ip6aux)); - } - } - return mtag ? (struct ip6aux *)(mtag + 1) : NULL; -} - -static struct ip6aux * -ip6_findaux(struct mbuf *m) -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); - return mtag ? (struct ip6aux *)(mtag + 1) : NULL; -} - -static void -ip6_delaux(struct mbuf *m) -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); - if (mtag) - m_tag_delete(m, mtag); -} - /* * System control for IP6 */ - u_char inet6ctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,