11db8d1f8SAna Kukec /*- 2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3fe267a55SPedro F. Giffuni * 41db8d1f8SAna Kukec * Copyright (c) 2009-2010 Ana Kukec <anchie@FreeBSD.org> 51db8d1f8SAna Kukec * All rights reserved. 61db8d1f8SAna Kukec * 71db8d1f8SAna Kukec * Redistribution and use in source and binary forms, with or without 81db8d1f8SAna Kukec * modification, are permitted provided that the following conditions 91db8d1f8SAna Kukec * are met: 101db8d1f8SAna Kukec * 1. Redistributions of source code must retain the above copyright 111db8d1f8SAna Kukec * notice, this list of conditions and the following disclaimer. 121db8d1f8SAna Kukec * 2. Redistributions in binary form must reproduce the above copyright 131db8d1f8SAna Kukec * notice, this list of conditions and the following disclaimer in the 141db8d1f8SAna Kukec * documentation and/or other materials provided with the distribution. 151db8d1f8SAna Kukec * 161db8d1f8SAna Kukec * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 171db8d1f8SAna Kukec * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181db8d1f8SAna Kukec * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191db8d1f8SAna Kukec * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 201db8d1f8SAna Kukec * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211db8d1f8SAna Kukec * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221db8d1f8SAna Kukec * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231db8d1f8SAna Kukec * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241db8d1f8SAna Kukec * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251db8d1f8SAna Kukec * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261db8d1f8SAna Kukec * SUCH DAMAGE. 271db8d1f8SAna Kukec */ 281db8d1f8SAna Kukec 291db8d1f8SAna Kukec #include <sys/cdefs.h> 301db8d1f8SAna Kukec __FBSDID("$FreeBSD$"); 311db8d1f8SAna Kukec 321db8d1f8SAna Kukec #include <sys/param.h> 331db8d1f8SAna Kukec #include <sys/kernel.h> 348ec07310SGleb Smirnoff #include <sys/malloc.h> 351db8d1f8SAna Kukec #include <sys/mbuf.h> 361db8d1f8SAna Kukec #include <sys/module.h> 371db8d1f8SAna Kukec #include <sys/priv.h> 381db8d1f8SAna Kukec #include <sys/protosw.h> 3957f60867SMark Johnston #include <sys/sdt.h> 401db8d1f8SAna Kukec #include <sys/systm.h> 411db8d1f8SAna Kukec #include <sys/socket.h> 421db8d1f8SAna Kukec #include <sys/sockbuf.h> 431db8d1f8SAna Kukec #include <sys/socketvar.h> 441db8d1f8SAna Kukec #include <sys/types.h> 451db8d1f8SAna Kukec 461db8d1f8SAna Kukec #include <net/route.h> 471db8d1f8SAna Kukec #include <net/if.h> 481db8d1f8SAna Kukec #include <net/if_var.h> 491db8d1f8SAna Kukec #include <net/vnet.h> 501db8d1f8SAna Kukec 511db8d1f8SAna Kukec #include <netinet/in.h> 5257f60867SMark Johnston #include <netinet/in_kdtrace.h> 531db8d1f8SAna Kukec #include <netinet/ip_var.h> 541db8d1f8SAna Kukec #include <netinet/ip6.h> 551db8d1f8SAna Kukec #include <netinet/icmp6.h> 561db8d1f8SAna Kukec 571db8d1f8SAna Kukec #include <netinet6/in6_var.h> 581db8d1f8SAna Kukec #include <netinet6/nd6.h> 591db8d1f8SAna Kukec #include <netinet6/scope6_var.h> 601db8d1f8SAna Kukec #include <netinet6/send.h> 611db8d1f8SAna Kukec 62d745c852SEd Schouten static MALLOC_DEFINE(M_SEND, "send", "Secure Neighbour Discovery"); 631db8d1f8SAna Kukec 641db8d1f8SAna Kukec /* 651db8d1f8SAna Kukec * The socket used to communicate with the SeND daemon. 661db8d1f8SAna Kukec */ 675f901c92SAndrew Turner VNET_DEFINE_STATIC(struct socket *, send_so); 681db8d1f8SAna Kukec #define V_send_so VNET(send_so) 691db8d1f8SAna Kukec 701db8d1f8SAna Kukec u_long send_sendspace = 8 * (1024 + sizeof(struct sockaddr_send)); 711db8d1f8SAna Kukec u_long send_recvspace = 9216; 721db8d1f8SAna Kukec 731db8d1f8SAna Kukec struct mtx send_mtx; 741db8d1f8SAna Kukec #define SEND_LOCK_INIT() mtx_init(&send_mtx, "send_mtx", NULL, MTX_DEF) 751db8d1f8SAna Kukec #define SEND_LOCK() mtx_lock(&send_mtx) 761db8d1f8SAna Kukec #define SEND_UNLOCK() mtx_unlock(&send_mtx) 771db8d1f8SAna Kukec #define SEND_LOCK_DESTROY() mtx_destroy(&send_mtx) 781db8d1f8SAna Kukec 791db8d1f8SAna Kukec static int 801db8d1f8SAna Kukec send_attach(struct socket *so, int proto, struct thread *td) 811db8d1f8SAna Kukec { 821db8d1f8SAna Kukec int error; 831db8d1f8SAna Kukec 841db8d1f8SAna Kukec SEND_LOCK(); 851db8d1f8SAna Kukec if (V_send_so != NULL) { 861db8d1f8SAna Kukec SEND_UNLOCK(); 871db8d1f8SAna Kukec return (EEXIST); 881db8d1f8SAna Kukec } 891db8d1f8SAna Kukec 901db8d1f8SAna Kukec error = priv_check(td, PRIV_NETINET_RAW); 911db8d1f8SAna Kukec if (error) { 921db8d1f8SAna Kukec SEND_UNLOCK(); 931db8d1f8SAna Kukec return(error); 941db8d1f8SAna Kukec } 951db8d1f8SAna Kukec 961db8d1f8SAna Kukec if (proto != IPPROTO_SEND) { 971db8d1f8SAna Kukec SEND_UNLOCK(); 981db8d1f8SAna Kukec return (EPROTONOSUPPORT); 991db8d1f8SAna Kukec } 1001db8d1f8SAna Kukec error = soreserve(so, send_sendspace, send_recvspace); 1011db8d1f8SAna Kukec if (error) { 1021db8d1f8SAna Kukec SEND_UNLOCK(); 1031db8d1f8SAna Kukec return(error); 1041db8d1f8SAna Kukec } 1051db8d1f8SAna Kukec 1061db8d1f8SAna Kukec V_send_so = so; 1071db8d1f8SAna Kukec SEND_UNLOCK(); 1081db8d1f8SAna Kukec 1091db8d1f8SAna Kukec return (0); 1101db8d1f8SAna Kukec } 1111db8d1f8SAna Kukec 1121db8d1f8SAna Kukec static int 1131db8d1f8SAna Kukec send_output(struct mbuf *m, struct ifnet *ifp, int direction) 1141db8d1f8SAna Kukec { 1151db8d1f8SAna Kukec struct ip6_hdr *ip6; 1161db8d1f8SAna Kukec struct sockaddr_in6 dst; 1171db8d1f8SAna Kukec struct icmp6_hdr *icmp6; 118605284b8SAlexander V. Chernikov struct epoch_tracker et; 1191db8d1f8SAna Kukec int icmp6len; 1208268d82cSAlexander V. Chernikov int error; 1211db8d1f8SAna Kukec 1221db8d1f8SAna Kukec /* 1231db8d1f8SAna Kukec * Receive incoming (SeND-protected) or outgoing traffic 1241db8d1f8SAna Kukec * (SeND-validated) from the SeND user space application. 1251db8d1f8SAna Kukec */ 1261db8d1f8SAna Kukec 1271db8d1f8SAna Kukec switch (direction) { 1281db8d1f8SAna Kukec case SND_IN: 1291db8d1f8SAna Kukec if (m->m_len < (sizeof(struct ip6_hdr) + 1301db8d1f8SAna Kukec sizeof(struct icmp6_hdr))) { 1311db8d1f8SAna Kukec m = m_pullup(m, sizeof(struct ip6_hdr) + 1321db8d1f8SAna Kukec sizeof(struct icmp6_hdr)); 1331db8d1f8SAna Kukec if (!m) 1341db8d1f8SAna Kukec return (ENOBUFS); 1351db8d1f8SAna Kukec } 1361db8d1f8SAna Kukec 1371db8d1f8SAna Kukec /* Before passing off the mbuf record the proper interface. */ 1381db8d1f8SAna Kukec m->m_pkthdr.rcvif = ifp; 1391db8d1f8SAna Kukec 1401db8d1f8SAna Kukec if (m->m_flags & M_PKTHDR) 1411db8d1f8SAna Kukec icmp6len = m->m_pkthdr.len - sizeof(struct ip6_hdr); 1421db8d1f8SAna Kukec else 1431db8d1f8SAna Kukec panic("Doh! not the first mbuf."); 1441db8d1f8SAna Kukec 1451db8d1f8SAna Kukec ip6 = mtod(m, struct ip6_hdr *); 1461db8d1f8SAna Kukec icmp6 = (struct icmp6_hdr *)(ip6 + 1); 1478268d82cSAlexander V. Chernikov error = 0; 1481db8d1f8SAna Kukec 1491db8d1f8SAna Kukec /* 1501db8d1f8SAna Kukec * Output the packet as icmp6.c:icpm6_input() would do. 1511db8d1f8SAna Kukec * The mbuf is always consumed, so we do not have to 1521db8d1f8SAna Kukec * care about that. 1531db8d1f8SAna Kukec */ 1548268d82cSAlexander V. Chernikov NET_EPOCH_ENTER(et); 1551db8d1f8SAna Kukec switch (icmp6->icmp6_type) { 1561db8d1f8SAna Kukec case ND_NEIGHBOR_SOLICIT: 1571db8d1f8SAna Kukec nd6_ns_input(m, sizeof(struct ip6_hdr), icmp6len); 1581db8d1f8SAna Kukec break; 1591db8d1f8SAna Kukec case ND_NEIGHBOR_ADVERT: 1601db8d1f8SAna Kukec nd6_na_input(m, sizeof(struct ip6_hdr), icmp6len); 1611db8d1f8SAna Kukec break; 1621db8d1f8SAna Kukec case ND_REDIRECT: 1631db8d1f8SAna Kukec icmp6_redirect_input(m, sizeof(struct ip6_hdr)); 1641db8d1f8SAna Kukec break; 1651db8d1f8SAna Kukec case ND_ROUTER_SOLICIT: 1661db8d1f8SAna Kukec nd6_rs_input(m, sizeof(struct ip6_hdr), icmp6len); 1671db8d1f8SAna Kukec break; 1681db8d1f8SAna Kukec case ND_ROUTER_ADVERT: 1691db8d1f8SAna Kukec nd6_ra_input(m, sizeof(struct ip6_hdr), icmp6len); 1701db8d1f8SAna Kukec break; 1711db8d1f8SAna Kukec default: 172569aad57SAndrey V. Elsukov m_freem(m); 1738268d82cSAlexander V. Chernikov error = ENOSYS; 1741db8d1f8SAna Kukec } 1758268d82cSAlexander V. Chernikov NET_EPOCH_EXIT(et); 1768268d82cSAlexander V. Chernikov 1778268d82cSAlexander V. Chernikov return (error); 1781db8d1f8SAna Kukec 1791db8d1f8SAna Kukec case SND_OUT: 1801db8d1f8SAna Kukec if (m->m_len < sizeof(struct ip6_hdr)) { 1811db8d1f8SAna Kukec m = m_pullup(m, sizeof(struct ip6_hdr)); 1821db8d1f8SAna Kukec if (!m) 1831db8d1f8SAna Kukec return (ENOBUFS); 1841db8d1f8SAna Kukec } 1851db8d1f8SAna Kukec ip6 = mtod(m, struct ip6_hdr *); 1861db8d1f8SAna Kukec if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 1871db8d1f8SAna Kukec m->m_flags |= M_MCAST; 1881db8d1f8SAna Kukec 1891db8d1f8SAna Kukec bzero(&dst, sizeof(dst)); 1901db8d1f8SAna Kukec dst.sin6_family = AF_INET6; 1911db8d1f8SAna Kukec dst.sin6_len = sizeof(dst); 1921db8d1f8SAna Kukec dst.sin6_addr = ip6->ip6_dst; 1931db8d1f8SAna Kukec 19486bd0491SAndre Oppermann m_clrprotoflags(m); /* Avoid confusing lower layers. */ 19586bd0491SAndre Oppermann 19657f60867SMark Johnston IP_PROBE(send, NULL, NULL, ip6, ifp, NULL, ip6); 19757f60867SMark Johnston 1981db8d1f8SAna Kukec /* 1991db8d1f8SAna Kukec * Output the packet as nd6.c:nd6_output_lle() would do. 2001db8d1f8SAna Kukec * The mbuf is always consumed, so we do not have to care 2011db8d1f8SAna Kukec * about that. 2021db8d1f8SAna Kukec * XXX-BZ as we added data, what about fragmenting, 2031db8d1f8SAna Kukec * if now needed? 2041db8d1f8SAna Kukec */ 2051db8d1f8SAna Kukec error = ((*ifp->if_output)(ifp, m, (struct sockaddr *)&dst, 2061db8d1f8SAna Kukec NULL)); 2071db8d1f8SAna Kukec if (error) 2081db8d1f8SAna Kukec error = ENOENT; 2091db8d1f8SAna Kukec return (error); 2101db8d1f8SAna Kukec 2111db8d1f8SAna Kukec default: 2121db8d1f8SAna Kukec panic("%s: direction %d neither SND_IN nor SND_OUT.", 2131db8d1f8SAna Kukec __func__, direction); 2141db8d1f8SAna Kukec } 2151db8d1f8SAna Kukec } 2161db8d1f8SAna Kukec 2171db8d1f8SAna Kukec /* 2181db8d1f8SAna Kukec * Receive a SeND message from user space to be either send out by the kernel 2191db8d1f8SAna Kukec * or, with SeND ICMPv6 options removed, to be further processed by the icmp6 2201db8d1f8SAna Kukec * input path. 2211db8d1f8SAna Kukec */ 2221db8d1f8SAna Kukec static int 2231db8d1f8SAna Kukec send_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 2241db8d1f8SAna Kukec struct mbuf *control, struct thread *td) 2251db8d1f8SAna Kukec { 2261db8d1f8SAna Kukec struct sockaddr_send *sendsrc; 2271db8d1f8SAna Kukec struct ifnet *ifp; 2281db8d1f8SAna Kukec int error; 2291db8d1f8SAna Kukec 2301db8d1f8SAna Kukec KASSERT(V_send_so == so, ("%s: socket %p not send socket %p", 2311db8d1f8SAna Kukec __func__, so, V_send_so)); 2321db8d1f8SAna Kukec 2331db8d1f8SAna Kukec sendsrc = (struct sockaddr_send *)nam; 234f161d294SMark Johnston if (sendsrc->send_family != AF_INET6) { 235f161d294SMark Johnston error = EAFNOSUPPORT; 236f161d294SMark Johnston goto err; 237f161d294SMark Johnston } 238f161d294SMark Johnston if (sendsrc->send_len != sizeof(*sendsrc)) { 239f161d294SMark Johnston error = EINVAL; 240f161d294SMark Johnston goto err; 241f161d294SMark Johnston } 2421db8d1f8SAna Kukec ifp = ifnet_byindex_ref(sendsrc->send_ifidx); 2431db8d1f8SAna Kukec if (ifp == NULL) { 2441db8d1f8SAna Kukec error = ENETUNREACH; 2451db8d1f8SAna Kukec goto err; 2461db8d1f8SAna Kukec } 2471db8d1f8SAna Kukec 2481db8d1f8SAna Kukec error = send_output(m, ifp, sendsrc->send_direction); 2491db8d1f8SAna Kukec if_rele(ifp); 2501db8d1f8SAna Kukec m = NULL; 2511db8d1f8SAna Kukec 2521db8d1f8SAna Kukec err: 253*d8acd268SMark Johnston if (control != NULL) 254*d8acd268SMark Johnston m_freem(control); 2551db8d1f8SAna Kukec if (m != NULL) 2561db8d1f8SAna Kukec m_freem(m); 257*d8acd268SMark Johnston 2581db8d1f8SAna Kukec return (error); 2591db8d1f8SAna Kukec } 2601db8d1f8SAna Kukec 2611db8d1f8SAna Kukec static void 2621db8d1f8SAna Kukec send_close(struct socket *so) 2631db8d1f8SAna Kukec { 2641db8d1f8SAna Kukec 2651db8d1f8SAna Kukec SEND_LOCK(); 2661db8d1f8SAna Kukec if (V_send_so) 2671db8d1f8SAna Kukec V_send_so = NULL; 2681db8d1f8SAna Kukec SEND_UNLOCK(); 2691db8d1f8SAna Kukec } 2701db8d1f8SAna Kukec 2711db8d1f8SAna Kukec /* 2721db8d1f8SAna Kukec * Send a SeND message to user space, that was either received and has to be 2731db8d1f8SAna Kukec * validated or was about to be send out and has to be handled by the SEND 2741db8d1f8SAna Kukec * daemon adding SeND ICMPv6 options. 2751db8d1f8SAna Kukec */ 2761db8d1f8SAna Kukec static int 2771db8d1f8SAna Kukec send_input(struct mbuf *m, struct ifnet *ifp, int direction, int msglen __unused) 2781db8d1f8SAna Kukec { 2791db8d1f8SAna Kukec struct ip6_hdr *ip6; 2801db8d1f8SAna Kukec struct sockaddr_send sendsrc; 2811db8d1f8SAna Kukec 2821db8d1f8SAna Kukec SEND_LOCK(); 2831db8d1f8SAna Kukec if (V_send_so == NULL) { 2841db8d1f8SAna Kukec SEND_UNLOCK(); 2851db8d1f8SAna Kukec return (-1); 2861db8d1f8SAna Kukec } 2871db8d1f8SAna Kukec 2881db8d1f8SAna Kukec /* 2891db8d1f8SAna Kukec * Make sure to clear any possible internally embedded scope before 2901db8d1f8SAna Kukec * passing the packet to user space for SeND cryptographic signature 2911db8d1f8SAna Kukec * validation to succeed. 2921db8d1f8SAna Kukec */ 2931db8d1f8SAna Kukec ip6 = mtod(m, struct ip6_hdr *); 2941db8d1f8SAna Kukec in6_clearscope(&ip6->ip6_src); 2951db8d1f8SAna Kukec in6_clearscope(&ip6->ip6_dst); 2961db8d1f8SAna Kukec 2971db8d1f8SAna Kukec bzero(&sendsrc, sizeof(sendsrc)); 2981db8d1f8SAna Kukec sendsrc.send_len = sizeof(sendsrc); 2991db8d1f8SAna Kukec sendsrc.send_family = AF_INET6; 3001db8d1f8SAna Kukec sendsrc.send_direction = direction; 3011db8d1f8SAna Kukec sendsrc.send_ifidx = ifp->if_index; 3021db8d1f8SAna Kukec 3031db8d1f8SAna Kukec /* 3041db8d1f8SAna Kukec * Send incoming or outgoing traffic to user space either to be 3051db8d1f8SAna Kukec * protected (outgoing) or validated (incoming) according to rfc3971. 3061db8d1f8SAna Kukec */ 3071db8d1f8SAna Kukec SOCKBUF_LOCK(&V_send_so->so_rcv); 3081db8d1f8SAna Kukec if (sbappendaddr_locked(&V_send_so->so_rcv, 3091db8d1f8SAna Kukec (struct sockaddr *)&sendsrc, m, NULL) == 0) { 310924d1c9aSAlexander V. Chernikov SOCKBUF_UNLOCK(&V_send_so->so_rcv); 3111db8d1f8SAna Kukec /* XXX stats. */ 3121db8d1f8SAna Kukec m_freem(m); 3131db8d1f8SAna Kukec } else { 3141db8d1f8SAna Kukec sorwakeup_locked(V_send_so); 3151db8d1f8SAna Kukec } 3161db8d1f8SAna Kukec 3171db8d1f8SAna Kukec SEND_UNLOCK(); 3181db8d1f8SAna Kukec return (0); 3191db8d1f8SAna Kukec } 3201db8d1f8SAna Kukec 3211db8d1f8SAna Kukec struct pr_usrreqs send_usrreqs = { 3221db8d1f8SAna Kukec .pru_attach = send_attach, 3231db8d1f8SAna Kukec .pru_send = send_send, 3241db8d1f8SAna Kukec .pru_detach = send_close 3251db8d1f8SAna Kukec }; 3261db8d1f8SAna Kukec struct protosw send_protosw = { 3271db8d1f8SAna Kukec .pr_type = SOCK_RAW, 3281db8d1f8SAna Kukec .pr_flags = PR_ATOMIC|PR_ADDR, 3291db8d1f8SAna Kukec .pr_protocol = IPPROTO_SEND, 3301db8d1f8SAna Kukec .pr_usrreqs = &send_usrreqs 3311db8d1f8SAna Kukec }; 3321db8d1f8SAna Kukec 3331db8d1f8SAna Kukec static int 3341db8d1f8SAna Kukec send_modevent(module_t mod, int type, void *unused) 3351db8d1f8SAna Kukec { 3361db8d1f8SAna Kukec #ifdef __notyet__ 3371db8d1f8SAna Kukec VNET_ITERATOR_DECL(vnet_iter); 3381db8d1f8SAna Kukec #endif 3391db8d1f8SAna Kukec int error; 3401db8d1f8SAna Kukec 3411db8d1f8SAna Kukec switch (type) { 3421db8d1f8SAna Kukec case MOD_LOAD: 3431db8d1f8SAna Kukec SEND_LOCK_INIT(); 3441db8d1f8SAna Kukec 3451db8d1f8SAna Kukec error = pf_proto_register(PF_INET6, &send_protosw); 3461db8d1f8SAna Kukec if (error != 0) { 3471db8d1f8SAna Kukec printf("%s:%d: MOD_LOAD pf_proto_register(): %d\n", 3481db8d1f8SAna Kukec __func__, __LINE__, error); 3491db8d1f8SAna Kukec SEND_LOCK_DESTROY(); 3501db8d1f8SAna Kukec break; 3511db8d1f8SAna Kukec } 3521db8d1f8SAna Kukec send_sendso_input_hook = send_input; 3531db8d1f8SAna Kukec break; 3541db8d1f8SAna Kukec case MOD_UNLOAD: 3551db8d1f8SAna Kukec /* Do not allow unloading w/o locking. */ 3561db8d1f8SAna Kukec return (EBUSY); 3571db8d1f8SAna Kukec #ifdef __notyet__ 3581db8d1f8SAna Kukec VNET_LIST_RLOCK_NOSLEEP(); 3591db8d1f8SAna Kukec SEND_LOCK(); 3601db8d1f8SAna Kukec VNET_FOREACH(vnet_iter) { 3611db8d1f8SAna Kukec CURVNET_SET(vnet_iter); 3621db8d1f8SAna Kukec if (V_send_so != NULL) { 3631db8d1f8SAna Kukec CURVNET_RESTORE(); 3641db8d1f8SAna Kukec SEND_UNLOCK(); 3651db8d1f8SAna Kukec VNET_LIST_RUNLOCK_NOSLEEP(); 3661db8d1f8SAna Kukec return (EBUSY); 3671db8d1f8SAna Kukec } 3681db8d1f8SAna Kukec CURVNET_RESTORE(); 3691db8d1f8SAna Kukec } 3701db8d1f8SAna Kukec SEND_UNLOCK(); 3711db8d1f8SAna Kukec VNET_LIST_RUNLOCK_NOSLEEP(); 3721db8d1f8SAna Kukec error = pf_proto_unregister(PF_INET6, IPPROTO_SEND, SOCK_RAW); 3731db8d1f8SAna Kukec if (error == 0) 3741db8d1f8SAna Kukec SEND_LOCK_DESTROY(); 3751db8d1f8SAna Kukec send_sendso_input_hook = NULL; 3761db8d1f8SAna Kukec break; 3771db8d1f8SAna Kukec #endif 3781db8d1f8SAna Kukec default: 3791db8d1f8SAna Kukec error = 0; 3801db8d1f8SAna Kukec break; 3811db8d1f8SAna Kukec } 3821db8d1f8SAna Kukec 3831db8d1f8SAna Kukec return (error); 3841db8d1f8SAna Kukec } 3851db8d1f8SAna Kukec 3861db8d1f8SAna Kukec static moduledata_t sendmod = { 3871db8d1f8SAna Kukec "send", 3881db8d1f8SAna Kukec send_modevent, 3899823d527SKevin Lo 0 3901db8d1f8SAna Kukec }; 3911db8d1f8SAna Kukec 3921db8d1f8SAna Kukec DECLARE_MODULE(send, sendmod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 393