1*84d9c64aSbluhm /* $OpenBSD: ip6_forward.c,v 1.125 2025/01/03 21:27:40 bluhm Exp $ */ 29fd6ccffSitojun /* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */ 3287546eaSitojun 4287546eaSitojun /* 5287546eaSitojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6287546eaSitojun * All rights reserved. 7287546eaSitojun * 8287546eaSitojun * Redistribution and use in source and binary forms, with or without 9287546eaSitojun * modification, are permitted provided that the following conditions 10287546eaSitojun * are met: 11287546eaSitojun * 1. Redistributions of source code must retain the above copyright 12287546eaSitojun * notice, this list of conditions and the following disclaimer. 13287546eaSitojun * 2. Redistributions in binary form must reproduce the above copyright 14287546eaSitojun * notice, this list of conditions and the following disclaimer in the 15287546eaSitojun * documentation and/or other materials provided with the distribution. 16287546eaSitojun * 3. Neither the name of the project nor the names of its contributors 17287546eaSitojun * may be used to endorse or promote products derived from this software 18287546eaSitojun * without specific prior written permission. 19287546eaSitojun * 20287546eaSitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21287546eaSitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22287546eaSitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23287546eaSitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24287546eaSitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25287546eaSitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26287546eaSitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27287546eaSitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28287546eaSitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29287546eaSitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30287546eaSitojun * SUCH DAMAGE. 31287546eaSitojun */ 32287546eaSitojun 330f2babb4Sjasoni #include "pf.h" 340f2babb4Sjasoni 35287546eaSitojun #include <sys/param.h> 36287546eaSitojun #include <sys/systm.h> 37287546eaSitojun #include <sys/mbuf.h> 38287546eaSitojun #include <sys/socket.h> 39287546eaSitojun #include <sys/errno.h> 40287546eaSitojun #include <sys/time.h> 41287546eaSitojun #include <sys/kernel.h> 42287546eaSitojun #include <sys/syslog.h> 43287546eaSitojun 44287546eaSitojun #include <net/if.h> 450deb6685Smpi #include <net/if_var.h> 46ba8b7f53Smarkus #include <net/if_enc.h> 47287546eaSitojun #include <net/route.h> 482ab93df7Sbluhm #if NPF > 0 492ab93df7Sbluhm #include <net/pfvar.h> 502ab93df7Sbluhm #endif 51287546eaSitojun 52287546eaSitojun #include <netinet/in.h> 53f4f4d166Sitojun #include <netinet/ip_var.h> 54dc572864Sbluhm #include <netinet6/in6_var.h> 55fa86ee14Sitojun #include <netinet/ip6.h> 56287546eaSitojun #include <netinet6/ip6_var.h> 57fa86ee14Sitojun #include <netinet/icmp6.h> 58287546eaSitojun #include <netinet6/nd6.h> 592ab93df7Sbluhm #include <netinet/udp.h> 602ab93df7Sbluhm #include <netinet/tcp.h> 612ab93df7Sbluhm #include <netinet/tcp_timer.h> 622ab93df7Sbluhm #include <netinet/tcp_var.h> 636f8ff7e4Stodd #ifdef IPSEC 64537b0e2dScedric #include <netinet/ip_ipsp.h> 656f8ff7e4Stodd #include <netinet/ip_ah.h> 666f8ff7e4Stodd #include <netinet/ip_esp.h> 676f8ff7e4Stodd #endif 68287546eaSitojun 69287546eaSitojun /* 70287546eaSitojun * Forward a packet. If some error occurs return the sender 71287546eaSitojun * an icmp packet. Note we can't always generate a meaningful 72287546eaSitojun * icmp message because icmp doesn't have a large enough repertoire 73287546eaSitojun * of codes and types. 74287546eaSitojun * 75287546eaSitojun * If not forwarding, just drop the packet. This could be confusing 7684b2c343Sbluhm * if ip6_forwarding was zero but some routing protocol was advancing 77287546eaSitojun * us as a gateway to somewhere. However, we must let the routing 78287546eaSitojun * protocol deal with that. 79287546eaSitojun * 80287546eaSitojun */ 81287546eaSitojun 82287546eaSitojun void 83ab457133Sbluhm ip6_forward(struct mbuf *m, struct route *ro, int flags) 84287546eaSitojun { 85287546eaSitojun struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 8600dd3069Sbluhm struct route iproute; 8700dd3069Sbluhm struct rtentry *rt; 8822723314Sbluhm struct sockaddr *dst; 89c4e3ba2aSmpi struct ifnet *ifp = NULL; 90dd7e0821Sbluhm u_int rtableid = m->m_pkthdr.ph_rtableid; 91dd7e0821Sbluhm u_int ifidx = m->m_pkthdr.ph_ifidx; 92dd7e0821Sbluhm u_int8_t loopcnt = m->m_pkthdr.ph_loopcnt; 93dd7e0821Sbluhm u_int icmp_len; 94dd7e0821Sbluhm char icmp_buf[MHLEN]; 95dd7e0821Sbluhm CTASSERT(sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + 96dd7e0821Sbluhm MAX_TCPOPTLEN <= sizeof(icmp_buf)); 97dd7e0821Sbluhm u_short mflags, pfflags; 982136a888Sbluhm struct mbuf *mcopy; 99dd7e0821Sbluhm int error = 0, type = 0, code = 0, destmtu = 0; 1006f8ff7e4Stodd #ifdef IPSEC 1014a931851Smarkus struct tdb *tdb = NULL; 1026f8ff7e4Stodd #endif /* IPSEC */ 103bbcf0337Smpi char src6[INET6_ADDRSTRLEN], dst6[INET6_ADDRSTRLEN]; 104287546eaSitojun 1055a4be39aSitojun /* 1065a4be39aSitojun * Do not forward packets to multicast destination (should be handled 1075a4be39aSitojun * by ip6_mforward(). 1085a4be39aSitojun * Do not forward packets with unspecified source. It was discussed 1095a4be39aSitojun * in July 2000, on ipngwg mailing list. 1105a4be39aSitojun */ 111f4f4d166Sitojun if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || 1125a4be39aSitojun IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || 1135a4be39aSitojun IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { 114d0968898Skn time_t uptime; 115d0968898Skn 11631e14cacSjca ip6stat_inc(ip6s_cantforward); 117d0968898Skn uptime = getuptime(); 118d0968898Skn 119d0968898Skn if (ip6_log_time + ip6_log_interval < uptime) { 120d0968898Skn ip6_log_time = uptime; 121bbcf0337Smpi inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6)); 122bbcf0337Smpi inet_ntop(AF_INET6, &ip6->ip6_dst, dst6, sizeof(dst6)); 123287546eaSitojun log(LOG_DEBUG, 124287546eaSitojun "cannot forward " 125ef0d94f6Stb "from %s to %s nxt %d received on interface %u\n", 126dd7e0821Sbluhm src6, dst6, ip6->ip6_nxt, ifidx); 127287546eaSitojun } 128287546eaSitojun m_freem(m); 1292136a888Sbluhm goto done; 130287546eaSitojun } 131287546eaSitojun 132287546eaSitojun if (ip6->ip6_hlim <= IPV6_HLIMDEC) { 133287546eaSitojun icmp6_error(m, ICMP6_TIME_EXCEEDED, 134287546eaSitojun ICMP6_TIME_EXCEED_TRANSIT, 0); 1352136a888Sbluhm goto done; 136287546eaSitojun } 137287546eaSitojun ip6->ip6_hlim -= IPV6_HLIMDEC; 138287546eaSitojun 139e38fb131Sdlg /* 140e38fb131Sdlg * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU - 141e38fb131Sdlg * size of IPv6 + ICMPv6 headers) bytes of the packet in case 142e38fb131Sdlg * we need to generate an ICMP6 message to the src. 143e38fb131Sdlg * Thanks to M_EXT, in most cases copy will not occur. 144dd7e0821Sbluhm * For small packets copy original onto stack instead of mbuf. 145e38fb131Sdlg * 146cf045b76Sbluhm * For final protocol header like TCP or UDP, full header chain in 147cf045b76Sbluhm * ICMP6 packet is not necessary. In this case only copy small 148cf045b76Sbluhm * part of original packet and save it on stack instead of mbuf. 149cf045b76Sbluhm * Although this violates RFC 4443 2.4. (c), it avoids additional 150cf045b76Sbluhm * mbuf allocations. Also pf nat and rdr do not affect the shared 151cf045b76Sbluhm * mbuf cluster. 152cf045b76Sbluhm * 153e38fb131Sdlg * It is important to save it before IPsec processing as IPsec 154e38fb131Sdlg * processing may modify the mbuf. 155e38fb131Sdlg */ 156cf045b76Sbluhm switch (ip6->ip6_nxt) { 157cf045b76Sbluhm case IPPROTO_TCP: 158cf045b76Sbluhm icmp_len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + 159cf045b76Sbluhm MAX_TCPOPTLEN; 160cf045b76Sbluhm break; 161cf045b76Sbluhm case IPPROTO_UDP: 162cf045b76Sbluhm icmp_len = sizeof(struct ip6_hdr) + sizeof(struct udphdr); 163cf045b76Sbluhm break; 164cf045b76Sbluhm case IPPROTO_ESP: 165cf045b76Sbluhm icmp_len = sizeof(struct ip6_hdr) + 2 * sizeof(u_int32_t); 166cf045b76Sbluhm break; 167cf045b76Sbluhm default: 168cf045b76Sbluhm icmp_len = ICMPV6_PLD_MAXLEN; 169cf045b76Sbluhm break; 170cf045b76Sbluhm } 171cf045b76Sbluhm if (icmp_len > m->m_pkthdr.len) 172cf045b76Sbluhm icmp_len = m->m_pkthdr.len; 173dd7e0821Sbluhm if (icmp_len <= sizeof(icmp_buf)) { 174dd7e0821Sbluhm mflags = m->m_flags; 175dd7e0821Sbluhm pfflags = m->m_pkthdr.pf.flags; 176dd7e0821Sbluhm m_copydata(m, 0, icmp_len, icmp_buf); 177dd7e0821Sbluhm mcopy = NULL; 178dd7e0821Sbluhm } else { 179dd7e0821Sbluhm mcopy = m_copym(m, 0, icmp_len, M_NOWAIT); 180dd7e0821Sbluhm icmp_len = 0; 181dd7e0821Sbluhm } 182e38fb131Sdlg 183f1638404Sclaudio #if NPF > 0 184f1638404Sclaudio reroute: 185f1638404Sclaudio #endif 186f1638404Sclaudio 1876f8ff7e4Stodd #ifdef IPSEC 1884a931851Smarkus if (ipsec_in_use) { 189e7111b64Sbluhm error = ip6_output_ipsec_lookup(m, NULL, &tdb); 190e7111b64Sbluhm if (error) { 1916f8ff7e4Stodd /* 1926f8ff7e4Stodd * -EINVAL is used to indicate that the packet should 1936f8ff7e4Stodd * be silently dropped, typically because we've asked 1946f8ff7e4Stodd * key management for an SA. 1956f8ff7e4Stodd */ 1966f8ff7e4Stodd if (error == -EINVAL) /* Should silently drop packet */ 1976f8ff7e4Stodd error = 0; 1986f8ff7e4Stodd 1998e48d76aSgerhard m_freem(m); 2006f8ff7e4Stodd goto freecopy; 2016f8ff7e4Stodd } 2026f8ff7e4Stodd } 2036f8ff7e4Stodd #endif /* IPSEC */ 2046f8ff7e4Stodd 20500dd3069Sbluhm if (ro == NULL) { 20600dd3069Sbluhm ro = &iproute; 20700dd3069Sbluhm ro->ro_rt = NULL; 20800dd3069Sbluhm } 20900dd3069Sbluhm rt = route6_mpath(ro, &ip6->ip6_dst, &ip6->ip6_src, 210d1e0275eSmpi m->m_pkthdr.ph_rtableid); 211d1e0275eSmpi if (rt == NULL) { 21231e14cacSjca ip6stat_inc(ip6s_noroute); 213dd7e0821Sbluhm type = ICMP6_DST_UNREACH; 214dd7e0821Sbluhm code = ICMP6_DST_UNREACH_NOROUTE; 215287546eaSitojun m_freem(m); 216dd7e0821Sbluhm goto icmperror; 217287546eaSitojun } 21800dd3069Sbluhm dst = &ro->ro_dstsa; 219f4f4d166Sitojun 220f4f4d166Sitojun /* 221f4f4d166Sitojun * Scope check: if a packet can't be delivered to its destination 222f4f4d166Sitojun * for the reason that the destination is beyond the scope of the 223f4f4d166Sitojun * source address, discard the packet and return an icmp6 destination 224f4f4d166Sitojun * unreachable error with Code 2 (beyond scope of source address). 225f4f4d166Sitojun * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1] 226f4f4d166Sitojun */ 227dd7e0821Sbluhm if (in6_addr2scopeid(ifidx, &ip6->ip6_src) != 22828112c65Smpi in6_addr2scopeid(rt->rt_ifidx, &ip6->ip6_src)) { 229d0968898Skn time_t uptime; 230d0968898Skn 23131e14cacSjca ip6stat_inc(ip6s_cantforward); 23231e14cacSjca ip6stat_inc(ip6s_badscope); 233d0968898Skn uptime = getuptime(); 234f4f4d166Sitojun 235d0968898Skn if (ip6_log_time + ip6_log_interval < uptime) { 236d0968898Skn ip6_log_time = uptime; 237bbcf0337Smpi inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6)); 238bbcf0337Smpi inet_ntop(AF_INET6, &ip6->ip6_dst, dst6, sizeof(dst6)); 239f4f4d166Sitojun log(LOG_DEBUG, 240f4f4d166Sitojun "cannot forward " 241fb492c37Smpi "src %s, dst %s, nxt %d, rcvif %u, outif %u\n", 242dd7e0821Sbluhm src6, dst6, ip6->ip6_nxt, ifidx, rt->rt_ifidx); 243f4f4d166Sitojun } 244dd7e0821Sbluhm type = ICMP6_DST_UNREACH; 245dd7e0821Sbluhm code = ICMP6_DST_UNREACH_BEYONDSCOPE; 246f4f4d166Sitojun m_freem(m); 247dd7e0821Sbluhm goto icmperror; 248f4f4d166Sitojun } 249f4f4d166Sitojun 2506f8ff7e4Stodd #ifdef IPSEC 2516f8ff7e4Stodd /* 2526f8ff7e4Stodd * Check if the packet needs encapsulation. 2536f8ff7e4Stodd * ipsp_process_packet will never come back to here. 2546f8ff7e4Stodd */ 2554a931851Smarkus if (tdb != NULL) { 2566f8ff7e4Stodd /* Callee frees mbuf */ 25700dd3069Sbluhm error = ip6_output_ipsec_send(tdb, m, ro, 0, 1); 25800dd3069Sbluhm rt = ro->ro_rt; 2594a931851Smarkus if (error) 2604a931851Smarkus goto senderr; 2614a931851Smarkus goto freecopy; 2626f8ff7e4Stodd } 2636f8ff7e4Stodd #endif /* IPSEC */ 2646f8ff7e4Stodd 265287546eaSitojun if (rt->rt_flags & RTF_GATEWAY) 26622723314Sbluhm dst = rt->rt_gateway; 267287546eaSitojun 268287546eaSitojun /* 269287546eaSitojun * If we are to forward the packet using the same interface 270287546eaSitojun * as one we got the packet from, perhaps we should send a redirect 271287546eaSitojun * to sender to shortcut a hop. 272287546eaSitojun * Only send redirect if source is sending directly to us, 273287546eaSitojun * and if packet was not source routed (or has any options). 274287546eaSitojun * Also, don't send redirect if forwarding using a route 275287546eaSitojun * modified by a redirect. 276287546eaSitojun */ 277c4e3ba2aSmpi ifp = if_get(rt->rt_ifidx); 2782e310992Smpi if (ifp == NULL) { 2792e310992Smpi m_freem(m); 280c0384984Smpi goto freecopy; 2812e310992Smpi } 282dd7e0821Sbluhm if (rt->rt_ifidx == ifidx && 2839c4c1a6fSbluhm !ISSET(rt->rt_flags, RTF_DYNAMIC|RTF_MODIFIED) && 2849c4c1a6fSbluhm !ISSET(flags, IPV6_REDIRECT) && 2859c4c1a6fSbluhm atomic_load_int(&ip6_sendredirects)) { 286c4e3ba2aSmpi if ((ifp->if_flags & IFF_POINTOPOINT) && 28700dd3069Sbluhm nd6_is_addr_neighbor(&ro->ro_dstsin6, ifp)) { 2886b28ab66Sitojun /* 2896b28ab66Sitojun * If the incoming interface is equal to the outgoing 2909fd6ccffSitojun * one, the link attached to the interface is 2919fd6ccffSitojun * point-to-point, and the IPv6 destination is 2929fd6ccffSitojun * regarded as on-link on the link, then it will be 2939fd6ccffSitojun * highly probable that the destination address does 2949fd6ccffSitojun * not exist on the link and that the packet is going 2959fd6ccffSitojun * to loop. Thus, we immediately drop the packet and 2969fd6ccffSitojun * send an ICMPv6 error message. 2979fd6ccffSitojun * For other routing loops, we dare to let the packet 2989fd6ccffSitojun * go to the loop, so that a remote diagnosing host 2999fd6ccffSitojun * can detect the loop by traceroute. 3006b28ab66Sitojun * type/code is based on suggestion by Rich Draves. 3016b28ab66Sitojun * not sure if it is the best pick. 3026b28ab66Sitojun */ 303dd7e0821Sbluhm type = ICMP6_DST_UNREACH; 304dd7e0821Sbluhm code = ICMP6_DST_UNREACH_ADDR; 3056b28ab66Sitojun m_freem(m); 306dd7e0821Sbluhm goto icmperror; 3076b28ab66Sitojun } 308287546eaSitojun type = ND_REDIRECT; 3096b28ab66Sitojun } 310287546eaSitojun 3116afad192Sitojun /* 3126afad192Sitojun * Fake scoped addresses. Note that even link-local source or 313df8d9afdSjsg * destination can appear, if the originating node just sends the 3146afad192Sitojun * packet to us (without address resolution for the destination). 3156afad192Sitojun * Since both icmp6_error and icmp6_redirect_output fill the embedded 316841d7adbSitojun * link identifiers, we can do this stuff after making a copy for 317841d7adbSitojun * returning an error. 3186afad192Sitojun */ 319d4070096Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) 3206afad192Sitojun ip6->ip6_src.s6_addr16[1] = 0; 321d4070096Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) 3226afad192Sitojun ip6->ip6_dst.s6_addr16[1] = 0; 3236afad192Sitojun 3240f2babb4Sjasoni #if NPF > 0 325c4e3ba2aSmpi if (pf_test(AF_INET6, PF_FWD, ifp, &m) != PF_PASS) { 3260f2babb4Sjasoni m_freem(m); 3270f2babb4Sjasoni goto senderr; 3280f2babb4Sjasoni } 329cb3a4e31Sjasoni if (m == NULL) 330cb3a4e31Sjasoni goto senderr; 331261474c2Sdhartmei ip6 = mtod(m, struct ip6_hdr *); 332f1638404Sclaudio if ((m->m_pkthdr.pf.flags & (PF_TAG_REROUTE | PF_TAG_GENERATED)) == 333f1638404Sclaudio (PF_TAG_REROUTE | PF_TAG_GENERATED)) { 334f1638404Sclaudio /* already rerun the route lookup, go on */ 335f1638404Sclaudio m->m_pkthdr.pf.flags &= ~(PF_TAG_GENERATED | PF_TAG_REROUTE); 336f1638404Sclaudio } else if (m->m_pkthdr.pf.flags & PF_TAG_REROUTE) { 337f1638404Sclaudio /* tag as generated to skip over pf_test on rerun */ 338f1638404Sclaudio m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 339ab457133Sbluhm SET(flags, IPV6_REDIRECT); 34000dd3069Sbluhm if (ro == &iproute) 34100dd3069Sbluhm rtfree(ro->ro_rt); 34200dd3069Sbluhm ro = NULL; 343c4e3ba2aSmpi if_put(ifp); 344c4e3ba2aSmpi ifp = NULL; 345f1638404Sclaudio goto reroute; 346f1638404Sclaudio } 3470f2babb4Sjasoni #endif 348f3378d78Sjan 34928c60e63Sbluhm #ifdef IPSEC 35028c60e63Sbluhm if (ISSET(flags, IPV6_FORWARDING) && 35128c60e63Sbluhm ISSET(flags, IPV6_FORWARDING_IPSEC) && 35228c60e63Sbluhm !ISSET(m->m_pkthdr.ph_tagsset, PACKET_TAG_IPSEC_IN_DONE)) { 35328c60e63Sbluhm error = EHOSTUNREACH; 35428c60e63Sbluhm goto senderr; 35528c60e63Sbluhm } 35628c60e63Sbluhm #endif 35728c60e63Sbluhm 35822723314Sbluhm error = if_output_tso(ifp, &m, dst, rt, ifp->if_mtu); 3594d7caa4bSbluhm if (error) 3604d7caa4bSbluhm ip6stat_inc(ip6s_cantforward); 3614d7caa4bSbluhm else if (m == NULL) 3624d7caa4bSbluhm ip6stat_inc(ip6s_forward); 363f3378d78Sjan if (error || m == NULL) 3644d7caa4bSbluhm goto senderr; 3650f2babb4Sjasoni 366dd7e0821Sbluhm type = ICMP6_PACKET_TOO_BIG; 367dd7e0821Sbluhm destmtu = ifp->if_mtu; 3684d7caa4bSbluhm m_freem(m); 369dd7e0821Sbluhm goto icmperror; 3704d7caa4bSbluhm 3710f2babb4Sjasoni senderr: 372dd7e0821Sbluhm if (mcopy == NULL && icmp_len == 0) 3732136a888Sbluhm goto done; 374a380976cSbluhm 375287546eaSitojun switch (error) { 376287546eaSitojun case 0: 377287546eaSitojun if (type == ND_REDIRECT) { 378dd7e0821Sbluhm if (icmp_len != 0) { 379dd7e0821Sbluhm mcopy = m_gethdr(M_DONTWAIT, MT_DATA); 380dd7e0821Sbluhm if (mcopy == NULL) 381dd7e0821Sbluhm goto done; 382dd7e0821Sbluhm mcopy->m_len = mcopy->m_pkthdr.len = icmp_len; 383dd7e0821Sbluhm mcopy->m_flags |= (mflags & M_COPYFLAGS); 384dd7e0821Sbluhm mcopy->m_pkthdr.ph_rtableid = rtableid; 385dd7e0821Sbluhm mcopy->m_pkthdr.ph_ifidx = ifidx; 386dd7e0821Sbluhm mcopy->m_pkthdr.ph_loopcnt = loopcnt; 387dd7e0821Sbluhm mcopy->m_pkthdr.pf.flags |= 388dd7e0821Sbluhm (pfflags & PF_TAG_GENERATED); 389dd7e0821Sbluhm memcpy(mcopy->m_data, icmp_buf, icmp_len); 390dd7e0821Sbluhm } 391dd7e0821Sbluhm if (mcopy != NULL) { 392287546eaSitojun icmp6_redirect_output(mcopy, rt); 3934d7caa4bSbluhm ip6stat_inc(ip6s_redirectsent); 394dd7e0821Sbluhm } 3952136a888Sbluhm goto done; 396287546eaSitojun } 397287546eaSitojun goto freecopy; 398287546eaSitojun 399287546eaSitojun case EMSGSIZE: 400a380976cSbluhm type = ICMP6_PACKET_TOO_BIG; 401a380976cSbluhm if (rt != NULL) { 402*84d9c64aSbluhm u_int rtmtu; 403*84d9c64aSbluhm 404*84d9c64aSbluhm rtmtu = atomic_load_int(&rt->rt_mtu); 405*84d9c64aSbluhm if (rtmtu != 0) { 406*84d9c64aSbluhm destmtu = rtmtu; 407a380976cSbluhm } else { 408a380976cSbluhm struct ifnet *destifp; 409a380976cSbluhm 410a380976cSbluhm destifp = if_get(rt->rt_ifidx); 411a380976cSbluhm if (destifp != NULL) 412a380976cSbluhm destmtu = destifp->if_mtu; 413a380976cSbluhm if_put(destifp); 414a380976cSbluhm } 415a380976cSbluhm } 416a380976cSbluhm ip6stat_inc(ip6s_cantfrag); 417a380976cSbluhm if (destmtu == 0) 418a380976cSbluhm goto freecopy; 419a380976cSbluhm break; 420a380976cSbluhm 421a380976cSbluhm case EACCES: 422a380976cSbluhm /* 423a380976cSbluhm * pf(4) blocked the packet. There is no need to send an ICMP 424a380976cSbluhm * packet back since pf(4) takes care of it. 425a380976cSbluhm */ 426287546eaSitojun goto freecopy; 427287546eaSitojun 428287546eaSitojun case ENOBUFS: 429287546eaSitojun /* Tell source to slow down like source quench in IP? */ 430287546eaSitojun goto freecopy; 431287546eaSitojun 432287546eaSitojun case ENETUNREACH: /* shouldn't happen, checked above */ 433287546eaSitojun case EHOSTUNREACH: 434287546eaSitojun case ENETDOWN: 435287546eaSitojun case EHOSTDOWN: 436287546eaSitojun default: 437287546eaSitojun type = ICMP6_DST_UNREACH; 438287546eaSitojun code = ICMP6_DST_UNREACH_ADDR; 439287546eaSitojun break; 440287546eaSitojun } 441dd7e0821Sbluhm icmperror: 442dd7e0821Sbluhm if (icmp_len != 0) { 443dd7e0821Sbluhm mcopy = m_gethdr(M_DONTWAIT, MT_DATA); 444dd7e0821Sbluhm if (mcopy == NULL) 445dd7e0821Sbluhm goto done; 446dd7e0821Sbluhm mcopy->m_len = mcopy->m_pkthdr.len = icmp_len; 447dd7e0821Sbluhm mcopy->m_flags |= (mflags & M_COPYFLAGS); 448dd7e0821Sbluhm mcopy->m_pkthdr.ph_rtableid = rtableid; 449dd7e0821Sbluhm mcopy->m_pkthdr.ph_ifidx = ifidx; 450dd7e0821Sbluhm mcopy->m_pkthdr.ph_loopcnt = loopcnt; 451dd7e0821Sbluhm mcopy->m_pkthdr.pf.flags |= (pfflags & PF_TAG_GENERATED); 452dd7e0821Sbluhm memcpy(mcopy->m_data, icmp_buf, icmp_len); 453dd7e0821Sbluhm } 454dd7e0821Sbluhm if (mcopy != NULL) 455a380976cSbluhm icmp6_error(mcopy, type, code, destmtu); 4562136a888Sbluhm goto done; 457287546eaSitojun 458287546eaSitojun freecopy: 459287546eaSitojun m_freem(mcopy); 4602136a888Sbluhm done: 46100dd3069Sbluhm if (ro == &iproute) 46200dd3069Sbluhm rtfree(ro->ro_rt); 463c4e3ba2aSmpi if_put(ifp); 46431a6915fSbluhm #ifdef IPSEC 46531a6915fSbluhm tdb_unref(tdb); 46631a6915fSbluhm #endif /* IPSEC */ 467287546eaSitojun } 468