15a1842a2SAndrey V. Elsukov /*- 25a1842a2SAndrey V. Elsukov * Copyright (c) 2014-2016 Andrey V. Elsukov <ae@FreeBSD.org> 35a1842a2SAndrey V. Elsukov * All rights reserved. 45a1842a2SAndrey V. Elsukov * 55a1842a2SAndrey V. Elsukov * Redistribution and use in source and binary forms, with or without 65a1842a2SAndrey V. Elsukov * modification, are permitted provided that the following conditions 75a1842a2SAndrey V. Elsukov * are met: 85a1842a2SAndrey V. Elsukov * 95a1842a2SAndrey V. Elsukov * 1. Redistributions of source code must retain the above copyright 105a1842a2SAndrey V. Elsukov * notice, this list of conditions and the following disclaimer. 115a1842a2SAndrey V. Elsukov * 2. Redistributions in binary form must reproduce the above copyright 125a1842a2SAndrey V. Elsukov * notice, this list of conditions and the following disclaimer in the 135a1842a2SAndrey V. Elsukov * documentation and/or other materials provided with the distribution. 145a1842a2SAndrey V. Elsukov * 155a1842a2SAndrey V. Elsukov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 165a1842a2SAndrey V. Elsukov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 175a1842a2SAndrey V. Elsukov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 185a1842a2SAndrey V. Elsukov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 195a1842a2SAndrey V. Elsukov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 205a1842a2SAndrey V. Elsukov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 215a1842a2SAndrey V. Elsukov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 225a1842a2SAndrey V. Elsukov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 235a1842a2SAndrey V. Elsukov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 245a1842a2SAndrey V. Elsukov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 255a1842a2SAndrey V. Elsukov */ 265a1842a2SAndrey V. Elsukov 275a1842a2SAndrey V. Elsukov #include <sys/cdefs.h> 285a1842a2SAndrey V. Elsukov #include "opt_inet6.h" 295a1842a2SAndrey V. Elsukov #include "opt_ipstealth.h" 305a1842a2SAndrey V. Elsukov 315a1842a2SAndrey V. Elsukov #include <sys/param.h> 325a1842a2SAndrey V. Elsukov #include <sys/systm.h> 335a1842a2SAndrey V. Elsukov #include <sys/mbuf.h> 345a1842a2SAndrey V. Elsukov #include <sys/socket.h> 355a1842a2SAndrey V. Elsukov #include <sys/kernel.h> 365a1842a2SAndrey V. Elsukov #include <sys/sysctl.h> 375a1842a2SAndrey V. Elsukov 385a1842a2SAndrey V. Elsukov #include <net/if.h> 395a1842a2SAndrey V. Elsukov #include <net/if_var.h> 403d0d5b21SJustin Hibbits #include <net/if_private.h> 415a1842a2SAndrey V. Elsukov #include <net/route.h> 429ac7c6cfSAlexander V. Chernikov #include <net/route/nhop.h> 435a1842a2SAndrey V. Elsukov #include <net/pfil.h> 445a1842a2SAndrey V. Elsukov #include <net/vnet.h> 455a1842a2SAndrey V. Elsukov 465a1842a2SAndrey V. Elsukov #include <netinet/in.h> 475a1842a2SAndrey V. Elsukov #include <netinet/in_kdtrace.h> 485a1842a2SAndrey V. Elsukov #include <netinet/in_var.h> 495a1842a2SAndrey V. Elsukov #include <netinet/ip_var.h> 505a1842a2SAndrey V. Elsukov #include <netinet/ip6.h> 515a1842a2SAndrey V. Elsukov #include <netinet/icmp6.h> 525a1842a2SAndrey V. Elsukov #include <netinet6/in6_var.h> 535a1842a2SAndrey V. Elsukov #include <netinet6/in6_fib.h> 545a1842a2SAndrey V. Elsukov #include <netinet6/ip6_var.h> 555a1842a2SAndrey V. Elsukov #include <netinet6/nd6.h> 565a1842a2SAndrey V. Elsukov 575a1842a2SAndrey V. Elsukov static int 589ac7c6cfSAlexander V. Chernikov ip6_findroute(struct nhop_object **pnh, const struct sockaddr_in6 *dst, 595a1842a2SAndrey V. Elsukov struct mbuf *m) 605a1842a2SAndrey V. Elsukov { 619ac7c6cfSAlexander V. Chernikov struct nhop_object *nh; 625a1842a2SAndrey V. Elsukov 639ac7c6cfSAlexander V. Chernikov nh = fib6_lookup(M_GETFIB(m), &dst->sin6_addr, 649ac7c6cfSAlexander V. Chernikov dst->sin6_scope_id, NHR_NONE, m->m_pkthdr.flowid); 659ac7c6cfSAlexander V. Chernikov if (nh == NULL) { 665a1842a2SAndrey V. Elsukov IP6STAT_INC(ip6s_noroute); 675a1842a2SAndrey V. Elsukov IP6STAT_INC(ip6s_cantforward); 685a1842a2SAndrey V. Elsukov icmp6_error(m, ICMP6_DST_UNREACH, 695a1842a2SAndrey V. Elsukov ICMP6_DST_UNREACH_NOROUTE, 0); 705a1842a2SAndrey V. Elsukov return (EHOSTUNREACH); 715a1842a2SAndrey V. Elsukov } 729ac7c6cfSAlexander V. Chernikov if (nh->nh_flags & NHF_BLACKHOLE) { 735a1842a2SAndrey V. Elsukov IP6STAT_INC(ip6s_cantforward); 745a1842a2SAndrey V. Elsukov m_freem(m); 755a1842a2SAndrey V. Elsukov return (EHOSTUNREACH); 765a1842a2SAndrey V. Elsukov } 775a1842a2SAndrey V. Elsukov 789ac7c6cfSAlexander V. Chernikov if (nh->nh_flags & NHF_REJECT) { 795a1842a2SAndrey V. Elsukov IP6STAT_INC(ip6s_cantforward); 805a1842a2SAndrey V. Elsukov icmp6_error(m, ICMP6_DST_UNREACH, 815a1842a2SAndrey V. Elsukov ICMP6_DST_UNREACH_REJECT, 0); 825a1842a2SAndrey V. Elsukov return (EHOSTUNREACH); 835a1842a2SAndrey V. Elsukov } 849ac7c6cfSAlexander V. Chernikov 859ac7c6cfSAlexander V. Chernikov *pnh = nh; 869ac7c6cfSAlexander V. Chernikov 875a1842a2SAndrey V. Elsukov return (0); 885a1842a2SAndrey V. Elsukov } 895a1842a2SAndrey V. Elsukov 905a1842a2SAndrey V. Elsukov struct mbuf* 915a1842a2SAndrey V. Elsukov ip6_tryforward(struct mbuf *m) 925a1842a2SAndrey V. Elsukov { 935a1842a2SAndrey V. Elsukov struct sockaddr_in6 dst; 949ac7c6cfSAlexander V. Chernikov struct nhop_object *nh; 955a1842a2SAndrey V. Elsukov struct m_tag *fwd_tag; 965a1842a2SAndrey V. Elsukov struct ip6_hdr *ip6; 975a1842a2SAndrey V. Elsukov struct ifnet *rcvif; 985a1842a2SAndrey V. Elsukov uint32_t plen; 995a1842a2SAndrey V. Elsukov int error; 1005a1842a2SAndrey V. Elsukov 1015a1842a2SAndrey V. Elsukov /* 1025a1842a2SAndrey V. Elsukov * Fallback conditions to ip6_input for slow path processing. 1035a1842a2SAndrey V. Elsukov */ 1045a1842a2SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 10556c989dfSAndrey V. Elsukov if ((m->m_flags & (M_BCAST | M_MCAST)) != 0 || 10656c989dfSAndrey V. Elsukov ip6->ip6_nxt == IPPROTO_HOPOPTS || 1075a1842a2SAndrey V. Elsukov IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || 1085a1842a2SAndrey V. Elsukov IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) || 1095a1842a2SAndrey V. Elsukov IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src) || 110*40faf878SMark Johnston IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst) || 1115a1842a2SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) || 1125a1842a2SAndrey V. Elsukov in6_localip(&ip6->ip6_dst)) 1135a1842a2SAndrey V. Elsukov return (m); 1145a1842a2SAndrey V. Elsukov /* 1155a1842a2SAndrey V. Elsukov * Check that the amount of data in the buffers 1165a1842a2SAndrey V. Elsukov * is as at least much as the IPv6 header would have us expect. 1175a1842a2SAndrey V. Elsukov * Trim mbufs if longer than we expect. 1185a1842a2SAndrey V. Elsukov * Drop packet if shorter than we expect. 1195a1842a2SAndrey V. Elsukov */ 1205a1842a2SAndrey V. Elsukov rcvif = m->m_pkthdr.rcvif; 1215a1842a2SAndrey V. Elsukov plen = ntohs(ip6->ip6_plen); 1225a1842a2SAndrey V. Elsukov if (plen == 0) { 1235a1842a2SAndrey V. Elsukov /* 1245a1842a2SAndrey V. Elsukov * Jumbograms must have hop-by-hop header and go via 1255a1842a2SAndrey V. Elsukov * slow path. 1265a1842a2SAndrey V. Elsukov */ 1275a1842a2SAndrey V. Elsukov IP6STAT_INC(ip6s_badoptions); 1285a1842a2SAndrey V. Elsukov goto dropin; 1295a1842a2SAndrey V. Elsukov } 1305a1842a2SAndrey V. Elsukov if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { 1315a1842a2SAndrey V. Elsukov IP6STAT_INC(ip6s_tooshort); 1325a1842a2SAndrey V. Elsukov in6_ifstat_inc(rcvif, ifs6_in_truncated); 1335a1842a2SAndrey V. Elsukov goto dropin; 1345a1842a2SAndrey V. Elsukov } 1355a1842a2SAndrey V. Elsukov if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { 1365a1842a2SAndrey V. Elsukov if (m->m_len == m->m_pkthdr.len) { 1375a1842a2SAndrey V. Elsukov m->m_len = sizeof(struct ip6_hdr) + plen; 1385a1842a2SAndrey V. Elsukov m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; 1395a1842a2SAndrey V. Elsukov } else 1405a1842a2SAndrey V. Elsukov m_adj(m, sizeof(struct ip6_hdr) + plen - 1415a1842a2SAndrey V. Elsukov m->m_pkthdr.len); 1425a1842a2SAndrey V. Elsukov } 1435a1842a2SAndrey V. Elsukov 1445a1842a2SAndrey V. Elsukov /* 1455a1842a2SAndrey V. Elsukov * Hop limit. 1465a1842a2SAndrey V. Elsukov */ 1475a1842a2SAndrey V. Elsukov #ifdef IPSTEALTH 1485a1842a2SAndrey V. Elsukov if (!V_ip6stealth) 1495a1842a2SAndrey V. Elsukov #endif 1505a1842a2SAndrey V. Elsukov if (ip6->ip6_hlim <= IPV6_HLIMDEC) { 1515a1842a2SAndrey V. Elsukov icmp6_error(m, ICMP6_TIME_EXCEEDED, 1525a1842a2SAndrey V. Elsukov ICMP6_TIME_EXCEED_TRANSIT, 0); 1535a1842a2SAndrey V. Elsukov m = NULL; 1545a1842a2SAndrey V. Elsukov goto dropin; 1555a1842a2SAndrey V. Elsukov } 1565a1842a2SAndrey V. Elsukov 1575a1842a2SAndrey V. Elsukov bzero(&dst, sizeof(dst)); 1585a1842a2SAndrey V. Elsukov dst.sin6_family = AF_INET6; 1595a1842a2SAndrey V. Elsukov dst.sin6_len = sizeof(dst); 1605a1842a2SAndrey V. Elsukov dst.sin6_addr = ip6->ip6_dst; 1615a1842a2SAndrey V. Elsukov 1625a1842a2SAndrey V. Elsukov /* 1635a1842a2SAndrey V. Elsukov * Incoming packet firewall processing. 1645a1842a2SAndrey V. Elsukov */ 165b252313fSGleb Smirnoff if (!PFIL_HOOKED_IN(V_inet6_pfil_head)) 1665a1842a2SAndrey V. Elsukov goto passin; 167dda6376bSMateusz Guzik if (pfil_mbuf_in(V_inet6_pfil_head, &m, rcvif, NULL) != 168b252313fSGleb Smirnoff PFIL_PASS) 1695a1842a2SAndrey V. Elsukov goto dropin; 1705a1842a2SAndrey V. Elsukov /* 1715a1842a2SAndrey V. Elsukov * If packet filter sets the M_FASTFWD_OURS flag, this means 1725a1842a2SAndrey V. Elsukov * that new destination or next hop is our local address. 1735a1842a2SAndrey V. Elsukov * So, we can just go back to ip6_input. 1745a1842a2SAndrey V. Elsukov * XXX: should we decrement ip6_hlim in such case? 1755a1842a2SAndrey V. Elsukov * 1765a1842a2SAndrey V. Elsukov * Also it can forward packet to another destination, e.g. 1775a1842a2SAndrey V. Elsukov * M_IP6_NEXTHOP flag is set and fwd_tag is attached to mbuf. 1785a1842a2SAndrey V. Elsukov */ 1795a1842a2SAndrey V. Elsukov if (m->m_flags & M_FASTFWD_OURS) 1805a1842a2SAndrey V. Elsukov return (m); 1815a1842a2SAndrey V. Elsukov 1825a1842a2SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 1835a1842a2SAndrey V. Elsukov if ((m->m_flags & M_IP6_NEXTHOP) && 1845a1842a2SAndrey V. Elsukov (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { 1855a1842a2SAndrey V. Elsukov /* 1865a1842a2SAndrey V. Elsukov * Now we will find route to forwarded by pfil destination. 1875a1842a2SAndrey V. Elsukov */ 1885a1842a2SAndrey V. Elsukov bcopy((fwd_tag + 1), &dst, sizeof(dst)); 1895a1842a2SAndrey V. Elsukov m->m_flags &= ~M_IP6_NEXTHOP; 1905a1842a2SAndrey V. Elsukov m_tag_delete(m, fwd_tag); 1915a1842a2SAndrey V. Elsukov } else { 1925a1842a2SAndrey V. Elsukov /* Update dst since pfil could change it */ 1935a1842a2SAndrey V. Elsukov dst.sin6_addr = ip6->ip6_dst; 1945a1842a2SAndrey V. Elsukov } 1955a1842a2SAndrey V. Elsukov passin: 1965a1842a2SAndrey V. Elsukov /* 1975a1842a2SAndrey V. Elsukov * Find route to destination. 1985a1842a2SAndrey V. Elsukov */ 1995a1842a2SAndrey V. Elsukov if (ip6_findroute(&nh, &dst, m) != 0) { 2005a1842a2SAndrey V. Elsukov m = NULL; 2015a1842a2SAndrey V. Elsukov in6_ifstat_inc(rcvif, ifs6_in_noroute); 2025a1842a2SAndrey V. Elsukov goto dropin; 2035a1842a2SAndrey V. Elsukov } 204b252313fSGleb Smirnoff if (!PFIL_HOOKED_OUT(V_inet6_pfil_head)) { 2059ac7c6cfSAlexander V. Chernikov if (m->m_pkthdr.len > nh->nh_mtu) { 2069ac7c6cfSAlexander V. Chernikov in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig); 2079ac7c6cfSAlexander V. Chernikov icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh->nh_mtu); 208f9656ee6SMichael Tuexen m = NULL; 209f9656ee6SMichael Tuexen goto dropout; 210f9656ee6SMichael Tuexen } 211f9656ee6SMichael Tuexen goto passout; 212f9656ee6SMichael Tuexen } 213a0bf3ee4SKristof Provost 214a0bf3ee4SKristof Provost /* 215a0bf3ee4SKristof Provost * Outgoing packet firewall processing. 216a0bf3ee4SKristof Provost */ 217dda6376bSMateusz Guzik if (pfil_mbuf_out(V_inet6_pfil_head, &m, nh->nh_ifp, 21814c9a2dbSMateusz Guzik NULL) != PFIL_PASS) 219a0bf3ee4SKristof Provost goto dropout; 220a0bf3ee4SKristof Provost 2215a1842a2SAndrey V. Elsukov /* 2225a1842a2SAndrey V. Elsukov * We used slow path processing for packets with scoped addresses. 2235a1842a2SAndrey V. Elsukov * So, scope checks aren't needed here. 2245a1842a2SAndrey V. Elsukov */ 2259ac7c6cfSAlexander V. Chernikov if (m->m_pkthdr.len > nh->nh_mtu) { 2269ac7c6cfSAlexander V. Chernikov in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig); 2279ac7c6cfSAlexander V. Chernikov icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh->nh_mtu); 2285a1842a2SAndrey V. Elsukov m = NULL; 2295a1842a2SAndrey V. Elsukov goto dropout; 2305a1842a2SAndrey V. Elsukov } 2315a1842a2SAndrey V. Elsukov 2325a1842a2SAndrey V. Elsukov /* 2335a1842a2SAndrey V. Elsukov * If packet filter sets the M_FASTFWD_OURS flag, this means 2345a1842a2SAndrey V. Elsukov * that new destination or next hop is our local address. 2355a1842a2SAndrey V. Elsukov * So, we can just go back to ip6_input. 2365a1842a2SAndrey V. Elsukov * 2375a1842a2SAndrey V. Elsukov * Also it can forward packet to another destination, e.g. 2385a1842a2SAndrey V. Elsukov * M_IP6_NEXTHOP flag is set and fwd_tag is attached to mbuf. 2395a1842a2SAndrey V. Elsukov */ 2405a1842a2SAndrey V. Elsukov if (m->m_flags & M_FASTFWD_OURS) { 2415a1842a2SAndrey V. Elsukov /* 2425a1842a2SAndrey V. Elsukov * XXX: we did one hop and should decrement hop limit. But 2435a1842a2SAndrey V. Elsukov * now we are the destination and just don't pay attention. 2445a1842a2SAndrey V. Elsukov */ 2455a1842a2SAndrey V. Elsukov return (m); 2465a1842a2SAndrey V. Elsukov } 2475a1842a2SAndrey V. Elsukov /* 2485a1842a2SAndrey V. Elsukov * Again. A packet filter could change the destination address. 2495a1842a2SAndrey V. Elsukov */ 2505a1842a2SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 2515a1842a2SAndrey V. Elsukov if (m->m_flags & M_IP6_NEXTHOP) 2525a1842a2SAndrey V. Elsukov fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); 2535a1842a2SAndrey V. Elsukov else 2545a1842a2SAndrey V. Elsukov fwd_tag = NULL; 2555a1842a2SAndrey V. Elsukov 2565a1842a2SAndrey V. Elsukov if (fwd_tag != NULL || 2575a1842a2SAndrey V. Elsukov !IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &ip6->ip6_dst)) { 2585a1842a2SAndrey V. Elsukov if (fwd_tag != NULL) { 2595a1842a2SAndrey V. Elsukov bcopy((fwd_tag + 1), &dst, sizeof(dst)); 2605a1842a2SAndrey V. Elsukov m->m_flags &= ~M_IP6_NEXTHOP; 2615a1842a2SAndrey V. Elsukov m_tag_delete(m, fwd_tag); 2625a1842a2SAndrey V. Elsukov } else 2635a1842a2SAndrey V. Elsukov dst.sin6_addr = ip6->ip6_dst; 2645a1842a2SAndrey V. Elsukov /* 2655a1842a2SAndrey V. Elsukov * Redo route lookup with new destination address 2665a1842a2SAndrey V. Elsukov */ 2675a1842a2SAndrey V. Elsukov if (ip6_findroute(&nh, &dst, m) != 0) { 2685a1842a2SAndrey V. Elsukov m = NULL; 2695a1842a2SAndrey V. Elsukov goto dropout; 2705a1842a2SAndrey V. Elsukov } 2715a1842a2SAndrey V. Elsukov } 2725a1842a2SAndrey V. Elsukov passout: 2735a1842a2SAndrey V. Elsukov #ifdef IPSTEALTH 2745a1842a2SAndrey V. Elsukov if (!V_ip6stealth) 2755a1842a2SAndrey V. Elsukov #endif 2765a1842a2SAndrey V. Elsukov { 2775a1842a2SAndrey V. Elsukov ip6->ip6_hlim -= IPV6_HLIMDEC; 2785a1842a2SAndrey V. Elsukov } 2795a1842a2SAndrey V. Elsukov 2805a1842a2SAndrey V. Elsukov m_clrprotoflags(m); /* Avoid confusing lower layers. */ 2819ac7c6cfSAlexander V. Chernikov IP_PROBE(send, NULL, NULL, ip6, nh->nh_ifp, NULL, ip6); 2825a1842a2SAndrey V. Elsukov 2839ac7c6cfSAlexander V. Chernikov if (nh->nh_flags & NHF_GATEWAY) 2849ac7c6cfSAlexander V. Chernikov dst.sin6_addr = nh->gw6_sa.sin6_addr; 2859ac7c6cfSAlexander V. Chernikov error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m, 2865a1842a2SAndrey V. Elsukov (struct sockaddr *)&dst, NULL); 2875a1842a2SAndrey V. Elsukov if (error != 0) { 2889ac7c6cfSAlexander V. Chernikov in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard); 2895a1842a2SAndrey V. Elsukov IP6STAT_INC(ip6s_cantforward); 2905a1842a2SAndrey V. Elsukov } else { 2919ac7c6cfSAlexander V. Chernikov in6_ifstat_inc(nh->nh_ifp, ifs6_out_forward); 2925a1842a2SAndrey V. Elsukov IP6STAT_INC(ip6s_forward); 2935a1842a2SAndrey V. Elsukov } 2945a1842a2SAndrey V. Elsukov return (NULL); 2955a1842a2SAndrey V. Elsukov dropin: 2965a1842a2SAndrey V. Elsukov in6_ifstat_inc(rcvif, ifs6_in_discard); 2975a1842a2SAndrey V. Elsukov goto drop; 2985a1842a2SAndrey V. Elsukov dropout: 2999ac7c6cfSAlexander V. Chernikov in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard); 3005a1842a2SAndrey V. Elsukov drop: 3015a1842a2SAndrey V. Elsukov if (m != NULL) 3025a1842a2SAndrey V. Elsukov m_freem(m); 3035a1842a2SAndrey V. Elsukov return (NULL); 3045a1842a2SAndrey V. Elsukov } 305