Remove auxiliary data support and use in6ifa_ifwithaddr() function instead of ip6_getdstifaddr(). --- sys/netinet6/icmp6.c (svn+ssh://svn.freebsd.org/base/head) (revision 261548) +++ sys/netinet6/icmp6.c (working copy) @@ -228,28 +228,11 @@ void icmp6_error2(struct mbuf *m, int type, int code, int param, struct ifnet *ifp) { - struct ip6_hdr *ip6; if (ifp == NULL) return; -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), ); -#else - if (m->m_len < sizeof(struct ip6_hdr)) { - m = m_pullup(m, sizeof(struct ip6_hdr)); - if (m == NULL) - return; - } -#endif - - ip6 = mtod(m, struct ip6_hdr *); - - if (in6_setscope(&ip6->ip6_src, ifp, NULL) != 0) - return; - if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) - return; - + m->m_pkthdr.rcvif = ifp; icmp6_error(m, type, code, param); } @@ -378,26 +361,13 @@ icmp6_error(struct mbuf *m, int type, int code, in nip6->ip6_src = oip6->ip6_src; nip6->ip6_dst = oip6->ip6_dst; - in6_clearscope(&oip6->ip6_src); - in6_clearscope(&oip6->ip6_dst); - icmp6 = (struct icmp6_hdr *)(nip6 + 1); icmp6->icmp6_type = type; icmp6->icmp6_code = code; icmp6->icmp6_pptr = htonl((u_int32_t)param); - /* - * icmp6_reflect() is designed to be in the input path. - * icmp6_error() can be called from both input and output path, - * and if we are in output path rcvif could contain bogus value. - * clear m->m_pkthdr.rcvif for safety, we should have enough scope - * information in ip header (nip6). - */ - m->m_pkthdr.rcvif = NULL; - ICMP6STAT_INC(icp6s_outhist[type]); icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */ - return; freeit: @@ -958,11 +928,11 @@ icmp6_input(struct mbuf **mp, int *offp, int proto static int icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) { + struct sockaddr_in6 icmp6src, icmp6dst; struct mbuf *m = *mp; struct icmp6_hdr *icmp6; struct ip6_hdr *eip6; u_int32_t notifymtu; - struct sockaddr_in6 icmp6src, icmp6dst; if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { ICMP6STAT_INC(icp6s_tooshort); @@ -1144,14 +1114,15 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6dst.sin6_addr = eip6->ip6_dst; else icmp6dst.sin6_addr = *finaldst; - if (in6_setscope(&icmp6dst.sin6_addr, m->m_pkthdr.rcvif, NULL)) - goto freeit; + icmp6dst.sin6_scope_id = in6_getscopezone(m->m_pkthdr.rcvif, + in6_addrscope(&icmp6dst.sin6_addr)); + bzero(&icmp6src, sizeof(icmp6src)); icmp6src.sin6_len = sizeof(struct sockaddr_in6); icmp6src.sin6_family = AF_INET6; icmp6src.sin6_addr = eip6->ip6_src; - if (in6_setscope(&icmp6src.sin6_addr, m->m_pkthdr.rcvif, NULL)) - goto freeit; + icmp6src.sin6_scope_id = in6_getscopezone(m->m_pkthdr.rcvif, + in6_addrscope(&icmp6src.sin6_addr)); icmp6src.sin6_flowinfo = (eip6->ip6_flow & IPV6_FLOWLABEL_MASK); @@ -1189,11 +1160,10 @@ icmp6_notify_error(struct mbuf **mp, int off, int void icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated) { + struct in_conninfo inc; struct in6_addr *dst = ip6cp->ip6c_finaldst; struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6; - struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */ u_int mtu = ntohl(icmp6->icmp6_mtu); - struct in_conninfo inc; #if 0 /* @@ -1228,12 +1198,11 @@ icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, in mtu = IPV6_MMTU - 8; bzero(&inc, sizeof(inc)); - inc.inc_fibnum = M_GETFIB(m); + inc.inc_fibnum = M_GETFIB(ip6cp->ip6c_m); inc.inc_flags |= INC_ISIPV6; inc.inc6_faddr = *dst; - if (in6_setscope(&inc.inc6_faddr, m->m_pkthdr.rcvif, NULL)) - return; - + inc.inc6_zoneid = in6_getscopezone(ip6cp->ip6c_m->m_pkthdr.rcvif, + in6_addrscope(dst)); if (mtu < tcp_maxmtu6(&inc, NULL)) { tcp_hc_updatemtu(&inc, mtu); ICMP6STAT_INC(icp6s_pmtuchg); @@ -1263,7 +1232,6 @@ ni6_input(struct mbuf *m, int off) struct ni_reply_fqdn *fqdn; int addrs; /* for NI_QTYPE_NODEADDR */ struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */ - struct in6_addr in6_subj; /* subject address */ struct ip6_hdr *ip6; int oldfqdn = 0; /* if 1, return pascal string (03 draft) */ char *subj = NULL; @@ -1311,9 +1279,11 @@ ni6_input(struct mbuf *m, int off) goto bad; /* else it's a link-local multicast, fine */ } else { /* unicast or anycast */ - if ((ia6 = ip6_getdstifaddr(m)) == NULL) - goto bad; /* XXX impossible */ - + ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, + in6_getscopezone(m->m_pkthdr.rcvif, + in6_addrscope(&ip6->ip6_dst))); + if (ia6 == NULL) + goto bad; if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) && !(V_icmp6_nodeinfo & ICMP6_NODEINFO_TMPADDROK)) { ifa_free(&ia6->ia_ifa); @@ -1374,14 +1344,10 @@ ni6_input(struct mbuf *m, int off) * * We do not do proxy at this moment. */ - /* m_pulldown instead of copy? */ - m_copydata(m, off + sizeof(struct icmp6_nodeinfo), - subjlen, (caddr_t)&in6_subj); - if (in6_setscope(&in6_subj, m->m_pkthdr.rcvif, NULL)) - goto bad; - - subj = (char *)&in6_subj; - if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &in6_subj)) + subj = (char *)m_pulldown(m, off + + sizeof(struct icmp6_nodeinfo), subjlen, NULL); + if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, + (struct in6_addr *)subj)) break; /* @@ -1945,7 +1911,6 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct /* copy the address itself */ bcopy(&ifa6->ia_addr.sin6_addr, cp, sizeof(struct in6_addr)); - in6_clearscope((struct in6_addr *)cp); /* XXX */ cp += sizeof(struct in6_addr); resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t)); @@ -1992,20 +1957,12 @@ icmp6_rip6_input(struct mbuf **mp, int off) return (IPPROTO_DONE); } #endif - - /* - * XXX: the address may have embedded scope zone ID, which should be - * hidden from applications. - */ bzero(&fromsa, sizeof(fromsa)); fromsa.sin6_family = AF_INET6; fromsa.sin6_len = sizeof(struct sockaddr_in6); fromsa.sin6_addr = ip6->ip6_src; - if (sa6_recoverscope(&fromsa)) { - m_freem(m); - return (IPPROTO_DONE); - } - + fromsa.sin6_scope_id = in6_getscopezone(m->m_pkthdr.rcvif, + in6_addrscope(&ip6->ip6_src)); INP_INFO_RLOCK(&V_ripcbinfo); LIST_FOREACH(in6p, &V_ripcb, inp_list) { if ((in6p->inp_vflag & INP_IPV6) == 0) @@ -2134,13 +2091,14 @@ icmp6_rip6_input(struct mbuf **mp, int off) void icmp6_reflect(struct mbuf *m, size_t off) { + struct route_in6 *ro, ro6; + struct in6_addr src, *srcp = NULL; struct ip6_hdr *ip6; struct icmp6_hdr *icmp6; struct in6_ifaddr *ia = NULL; - int plen; - int type, code; struct ifnet *outif = NULL; - struct in6_addr origdst, src, *srcp = NULL; + uint32_t zoneid; + int type, code, plen, error; /* too short to reflect */ if (off < sizeof(struct ip6_hdr)) { @@ -2187,49 +2145,26 @@ icmp6_reflect(struct mbuf *m, size_t off) type = icmp6->icmp6_type; /* keep type for statistics */ code = icmp6->icmp6_code; /* ditto. */ - origdst = ip6->ip6_dst; /* - * ip6_input() drops a packet if its src is multicast. - * So, the src is never multicast. - */ - ip6->ip6_dst = ip6->ip6_src; - - /* * If the incoming packet was addressed directly to us (i.e. unicast), * use dst as the src for the reply. * The IN6_IFF_NOTREADY case should be VERY rare, but is possible * (for example) when we encounter an error while forwarding procedure * destined to a duplicated address of ours. - * Note that ip6_getdstifaddr() may fail if we are in an error handling - * procedure of an outgoing packet of our own, in which case we need - * to search in the ifaddr list. */ - if (!IN6_IS_ADDR_MULTICAST(&origdst)) { - if ((ia = ip6_getdstifaddr(m))) { - if (!(ia->ia6_flags & - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) - srcp = &ia->ia_addr.sin6_addr; - } else { - struct sockaddr_in6 d; - - bzero(&d, sizeof(d)); - d.sin6_family = AF_INET6; - d.sin6_len = sizeof(d); - d.sin6_addr = origdst; - ia = (struct in6_ifaddr *) - ifa_ifwithaddr((struct sockaddr *)&d); - if (ia && - !(ia->ia6_flags & - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) { - srcp = &ia->ia_addr.sin6_addr; - } + zoneid = in6_getscopezone(m->m_pkthdr.rcvif, + in6_addrscope(&ip6->ip6_dst)); + if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { + ia = in6ifa_ifwithaddr(&ip6->ip6_dst, zoneid); + if (ia != NULL && !(ia->ia6_flags & + (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) { + srcp = &ia->ia_addr.sin6_addr; + outif = ia->ia_ifp; /* XXX: is it correct? */ } } - + ro = NULL; if (srcp == NULL) { - int e; struct sockaddr_in6 sin6; - struct route_in6 ro; /* * This case matches to multicasts, our anycast, or unicasts @@ -2236,38 +2171,40 @@ icmp6_reflect(struct mbuf *m, size_t off) * that we do not own. Select a source address based on the * source address of the erroneous packet. */ + ro = &ro6; + bzero(&ro6, sizeof(ro6)); + outif = m->m_pkthdr.rcvif; + bzero(&sin6, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(sin6); - sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */ - - bzero(&ro, sizeof(ro)); - e = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &src); - if (ro.ro_rt) - RTFREE(ro.ro_rt); /* XXX: we could use this */ - if (e) { + sin6.sin6_addr = ip6->ip6_src; + sin6.sin6_scope_id = zoneid; + error = in6_selectsrc(&sin6, NULL, NULL, ro, NULL, + &outif, &src); + if (error != 0) { char ip6buf[INET6_ADDRSTRLEN]; nd6log((LOG_DEBUG, "icmp6_reflect: source can't be determined: " "dst=%s, error=%d\n", - ip6_sprintf(ip6buf, &sin6.sin6_addr), e)); + ip6_sprintf(ip6buf, &sin6.sin6_addr), error)); + RO_RTFREE(ro); goto bad; } srcp = &src; } - + KASSERT(outif != NULL, ("%s: outif is NULL", __func__)); + /* + * ip6_input() drops a packet if its src is multicast. + * So, the src is never multicast. + */ + ip6->ip6_dst = ip6->ip6_src; ip6->ip6_src = *srcp; ip6->ip6_flow = 0; ip6->ip6_vfc &= ~IPV6_VERSION_MASK; ip6->ip6_vfc |= IPV6_VERSION; ip6->ip6_nxt = IPPROTO_ICMPV6; - if (outif) - ip6->ip6_hlim = ND_IFINFO(outif)->chlim; - else if (m->m_pkthdr.rcvif) { - /* XXX: This may not be the outgoing interface */ - ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim; - } else - ip6->ip6_hlim = V_ip6_defhlim; + ip6->ip6_hlim = ND_IFINFO(outif)->chlim; icmp6->icmp6_cksum = 0; icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6, @@ -2279,12 +2216,12 @@ icmp6_reflect(struct mbuf *m, size_t off) m->m_flags &= ~(M_BCAST|M_MCAST); - ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL); - if (outif) - icmp6_ifoutstat_inc(outif, type, code); - + ip6_output(m, NULL, ro, IPV6_USEROIF, NULL, &outif, NULL); + icmp6_ifoutstat_inc(outif, type, code); if (ia != NULL) ifa_free(&ia->ia_ifa); + if (ro != NULL) + RO_RTFREE(ro); return; bad: @@ -2364,11 +2301,6 @@ icmp6_redirect_input(struct mbuf *m, int off) redtgt6 = nd_rd->nd_rd_target; reddst6 = nd_rd->nd_rd_dst; - if (in6_setscope(&redtgt6, m->m_pkthdr.rcvif, NULL) || - in6_setscope(&reddst6, m->m_pkthdr.rcvif, NULL)) { - goto freeit; - } - /* validation */ if (!IN6_IS_ADDR_LINKLOCAL(&src6)) { nd6log((LOG_ERR, @@ -2384,7 +2316,14 @@ icmp6_redirect_input(struct mbuf *m, int off) ip6_sprintf(ip6buf, &src6), ip6->ip6_hlim)); goto bad; } - { + if (IN6_IS_ADDR_MULTICAST(&reddst6)) { + nd6log((LOG_ERR, + "ICMP6 redirect rejected; " + "redirect dst must be unicast: %s\n", + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; + } + if (!IN6_IS_ADDR_LINKLOCAL(&reddst6)) { /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */ struct sockaddr_in6 sin6; struct in6_addr *gw6; @@ -2426,13 +2365,6 @@ icmp6_redirect_input(struct mbuf *m, int off) RTFREE_LOCKED(rt); rt = NULL; } - if (IN6_IS_ADDR_MULTICAST(&reddst6)) { - nd6log((LOG_ERR, - "ICMP6 redirect rejected; " - "redirect dst must be unicast: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); - goto bad; - } is_router = is_onlink = 0; if (IN6_IS_ADDR_LINKLOCAL(&redtgt6)) @@ -2505,6 +2437,7 @@ icmp6_redirect_input(struct mbuf *m, int off) sdst.sin6_family = AF_INET6; sdst.sin6_len = sizeof(struct sockaddr_in6); bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); + sdst.sin6_scope_id = in6_getscopezone(ifp, in6_addrscope(&reddst6)); pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst); #ifdef IPSEC key_sa_routechange((struct sockaddr *)&sdst); @@ -2534,8 +2467,6 @@ icmp6_redirect_output(struct mbuf *m0, struct rten struct llentry *ln = NULL; size_t maxlen; u_char *p; - struct ifnet *outif = NULL; - struct sockaddr_in6 src_sa; icmp6_errcount(ND_REDIRECT, 0); @@ -2554,11 +2485,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rten * [RFC 2461, sec 8.2] */ sip6 = mtod(m0, struct ip6_hdr *); - bzero(&src_sa, sizeof(src_sa)); - src_sa.sin6_family = AF_INET6; - src_sa.sin6_len = sizeof(src_sa); - src_sa.sin6_addr = sip6->ip6_src; - if (nd6_is_addr_neighbor(&src_sa, ifp) == 0) + if (nd6_is_addr_neighbor(&sip6->ip6_src, ifp) == 0) goto fail; if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) goto fail; /* what should we do here? */ @@ -2772,15 +2699,7 @@ noredhdropt:; m_freem(m0); m0 = NULL; } - - /* XXX: clear embedded link IDs in the inner header */ - in6_clearscope(&sip6->ip6_src); - in6_clearscope(&sip6->ip6_dst); - in6_clearscope(&nd_rd->nd_rd_target); - in6_clearscope(&nd_rd->nd_rd_dst); - ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); - nd_rd->nd_rd_cksum = 0; nd_rd->nd_rd_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen)); @@ -2795,13 +2714,11 @@ noredhdropt:; } /* send the packet to outside... */ - ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL); - if (outif) { - icmp6_ifstat_inc(outif, ifs6_out_msg); - icmp6_ifstat_inc(outif, ifs6_out_redirect); + if (ip6_output(m, NULL, NULL, IPV6_USEROIF, NULL, &ifp, NULL) == 0) { + icmp6_ifstat_inc(ifp, ifs6_out_msg); + icmp6_ifstat_inc(ifp, ifs6_out_redirect); } ICMP6STAT_INC(icp6s_outhist[ND_REDIRECT]); - return; fail: