1c398230bSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1993 50ae76120SRobert Watson * The Regents of the University of California. 60ae76120SRobert Watson * All rights reserved. 7df8bae1dSRodney W. Grimes * 8df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 9df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 10df8bae1dSRodney W. Grimes * are met: 11df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 12df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 13df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 15df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 16fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 17df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 18df8bae1dSRodney W. Grimes * without specific prior written permission. 19df8bae1dSRodney W. Grimes * 20df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30df8bae1dSRodney W. Grimes * SUCH DAMAGE. 31df8bae1dSRodney W. Grimes * 3225f26ad8SGarrett Wollman * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 33df8bae1dSRodney W. Grimes */ 34df8bae1dSRodney W. Grimes 354b421e2dSMike Silbersack #include <sys/cdefs.h> 364b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 374b421e2dSMike Silbersack 3800c081e9SBjoern A. Zeeb #include "opt_inet.h" 396a800098SYoshinobu Inoue #include "opt_inet6.h" 406a800098SYoshinobu Inoue #include "opt_ipsec.h" 410c325f53SAlexander V. Chernikov #include "opt_route.h" 426a800098SYoshinobu Inoue 43df8bae1dSRodney W. Grimes #include <sys/param.h> 445a59cefcSBosko Milekic #include <sys/jail.h> 45117bcae7SGarrett Wollman #include <sys/kernel.h> 46ea8d1492SAlexander V. Chernikov #include <sys/eventhandler.h> 47960ed29cSSeigo Tanimura #include <sys/lock.h> 48df8bae1dSRodney W. Grimes #include <sys/malloc.h> 49df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 50acd3428bSRobert Watson #include <sys/priv.h> 514787fd37SPaul Saab #include <sys/proc.h> 52df8bae1dSRodney W. Grimes #include <sys/protosw.h> 53cc0a3c8cSAndrey V. Elsukov #include <sys/rmlock.h> 54385195c0SMarko Zec #include <sys/rwlock.h> 55960ed29cSSeigo Tanimura #include <sys/signalvar.h> 56117bcae7SGarrett Wollman #include <sys/socket.h> 57df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 58960ed29cSSeigo Tanimura #include <sys/sx.h> 59117bcae7SGarrett Wollman #include <sys/sysctl.h> 60960ed29cSSeigo Tanimura #include <sys/systm.h> 618781d8e9SBruce Evans 6269c2d429SJeff Roberson #include <vm/uma.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #include <net/if.h> 6576039bc8SGleb Smirnoff #include <net/if_var.h> 66df8bae1dSRodney W. Grimes #include <net/route.h> 67*81728a53SAlexander V. Chernikov #include <net/route/route_ctl.h> 684b79449eSBjoern A. Zeeb #include <net/vnet.h> 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes #include <netinet/in.h> 71df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 720c325f53SAlexander V. Chernikov #include <netinet/in_fib.h> 73c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h> 74c1f8a6ceSDavid Greenman #include <netinet/in_var.h> 755b84dc78SQing Li #include <netinet/if_ether.h> 76960ed29cSSeigo Tanimura #include <netinet/ip.h> 77df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 78df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h> 796d7270a5SMichael Tuexen #include <netinet/ip_icmp.h> 80df8bae1dSRodney W. Grimes 81fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h> 82b9234fafSSam Leffler 8373d76e77SKevin Lo #include <machine/stdarg.h> 84aed55708SRobert Watson #include <security/mac/mac_framework.h> 85aed55708SRobert Watson 8674e9dcf7SBjoern A. Zeeb VNET_DEFINE(int, ip_defttl) = IPDEFTTL; 876df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_VNET | CTLFLAG_RW, 8874e9dcf7SBjoern A. Zeeb &VNET_NAME(ip_defttl), 0, 8974e9dcf7SBjoern A. Zeeb "Maximum TTL on IP packets"); 9074e9dcf7SBjoern A. Zeeb 91eddfbb76SRobert Watson VNET_DEFINE(struct inpcbhead, ripcb); 92eddfbb76SRobert Watson VNET_DEFINE(struct inpcbinfo, ripcbinfo); 93eddfbb76SRobert Watson 941e77c105SRobert Watson #define V_ripcb VNET(ripcb) 951e77c105SRobert Watson #define V_ripcbinfo VNET(ripcbinfo) 96df8bae1dSRodney W. Grimes 97115a40c7SLuigi Rizzo /* 98b2019e17SLuigi Rizzo * Control and data hooks for ipfw, dummynet, divert and so on. 99115a40c7SLuigi Rizzo * The data hooks are not used here but it is convenient 100115a40c7SLuigi Rizzo * to keep them all in one place. 101115a40c7SLuigi Rizzo */ 1020b4b0b0fSJulian Elischer VNET_DEFINE(ip_fw_chk_ptr_t, ip_fw_chk_ptr) = NULL; 1030b4b0b0fSJulian Elischer VNET_DEFINE(ip_fw_ctl_ptr_t, ip_fw_ctl_ptr) = NULL; 104b2019e17SLuigi Rizzo 105b2019e17SLuigi Rizzo int (*ip_dn_ctl_ptr)(struct sockopt *); 106dc0fa4f7SGleb Smirnoff int (*ip_dn_io_ptr)(struct mbuf **, struct ip_fw_args *); 1071830dae3SGleb Smirnoff void (*ip_divert_ptr)(struct mbuf *, bool); 108cef9f220SGleb Smirnoff int (*ng_ipfw_input_p)(struct mbuf **, struct ip_fw_args *, bool); 109db69a05dSPaul Saab 11000c081e9SBjoern A. Zeeb #ifdef INET 111df8bae1dSRodney W. Grimes /* 1120ae76120SRobert Watson * Hooks for multicast routing. They all default to NULL, so leave them not 1130ae76120SRobert Watson * initialized and rely on BSS being set to 0. 114bbb4330bSLuigi Rizzo */ 115bbb4330bSLuigi Rizzo 1160ae76120SRobert Watson /* 1170ae76120SRobert Watson * The socket used to communicate with the multicast routing daemon. 1180ae76120SRobert Watson */ 119eddfbb76SRobert Watson VNET_DEFINE(struct socket *, ip_mrouter); 120bbb4330bSLuigi Rizzo 1210ae76120SRobert Watson /* 1220ae76120SRobert Watson * The various mrouter and rsvp functions. 1230ae76120SRobert Watson */ 124bbb4330bSLuigi Rizzo int (*ip_mrouter_set)(struct socket *, struct sockopt *); 125bbb4330bSLuigi Rizzo int (*ip_mrouter_get)(struct socket *, struct sockopt *); 126bbb4330bSLuigi Rizzo int (*ip_mrouter_done)(void); 127bbb4330bSLuigi Rizzo int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, 128bbb4330bSLuigi Rizzo struct ip_moptions *); 129e40bae9aSRoman Divacky int (*mrt_ioctl)(u_long, caddr_t, int); 130bbb4330bSLuigi Rizzo int (*legal_vif_num)(int); 131bbb4330bSLuigi Rizzo u_long (*ip_mcast_src)(int); 132bbb4330bSLuigi Rizzo 1338f5a8818SKevin Lo int (*rsvp_input_p)(struct mbuf **, int *, int); 134bbb4330bSLuigi Rizzo int (*ip_rsvp_vif)(struct socket *, struct sockopt *); 135bbb4330bSLuigi Rizzo void (*ip_rsvp_force_done)(struct socket *); 13600c081e9SBjoern A. Zeeb #endif /* INET */ 13700c081e9SBjoern A. Zeeb 138ad2cbb09SMichael Tuexen extern struct protosw inetsw[]; 139ad2cbb09SMichael Tuexen 14000c081e9SBjoern A. Zeeb u_long rip_sendspace = 9216; 14100c081e9SBjoern A. Zeeb SYSCTL_ULONG(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, 14200c081e9SBjoern A. Zeeb &rip_sendspace, 0, "Maximum outgoing raw IP datagram size"); 14300c081e9SBjoern A. Zeeb 14400c081e9SBjoern A. Zeeb u_long rip_recvspace = 9216; 14500c081e9SBjoern A. Zeeb SYSCTL_ULONG(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW, 14600c081e9SBjoern A. Zeeb &rip_recvspace, 0, "Maximum space for incoming raw IP datagrams"); 147bbb4330bSLuigi Rizzo 148bbb4330bSLuigi Rizzo /* 1499ed324c9SAlexander Motin * Hash functions 1509ed324c9SAlexander Motin */ 1519ed324c9SAlexander Motin 1529ed324c9SAlexander Motin #define INP_PCBHASH_RAW_SIZE 256 1539ed324c9SAlexander Motin #define INP_PCBHASH_RAW(proto, laddr, faddr, mask) \ 1549ed324c9SAlexander Motin (((proto) + (laddr) + (faddr)) % (mask) + 1) 1559ed324c9SAlexander Motin 15600c081e9SBjoern A. Zeeb #ifdef INET 1579ed324c9SAlexander Motin static void 1589ed324c9SAlexander Motin rip_inshash(struct inpcb *inp) 1599ed324c9SAlexander Motin { 1609ed324c9SAlexander Motin struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 1619ed324c9SAlexander Motin struct inpcbhead *pcbhash; 1629ed324c9SAlexander Motin int hash; 1639ed324c9SAlexander Motin 1649ed324c9SAlexander Motin INP_INFO_WLOCK_ASSERT(pcbinfo); 1659ed324c9SAlexander Motin INP_WLOCK_ASSERT(inp); 1669ed324c9SAlexander Motin 16718f401c6SAlexander Motin if (inp->inp_ip_p != 0 && 16818f401c6SAlexander Motin inp->inp_laddr.s_addr != INADDR_ANY && 16918f401c6SAlexander Motin inp->inp_faddr.s_addr != INADDR_ANY) { 1709ed324c9SAlexander Motin hash = INP_PCBHASH_RAW(inp->inp_ip_p, inp->inp_laddr.s_addr, 1719ed324c9SAlexander Motin inp->inp_faddr.s_addr, pcbinfo->ipi_hashmask); 17218f401c6SAlexander Motin } else 1739ed324c9SAlexander Motin hash = 0; 1749ed324c9SAlexander Motin pcbhash = &pcbinfo->ipi_hashbase[hash]; 175b872626dSMatt Macy CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 1769ed324c9SAlexander Motin } 1779ed324c9SAlexander Motin 1789ed324c9SAlexander Motin static void 1799ed324c9SAlexander Motin rip_delhash(struct inpcb *inp) 1809ed324c9SAlexander Motin { 18118f401c6SAlexander Motin 18218f401c6SAlexander Motin INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 1839ed324c9SAlexander Motin INP_WLOCK_ASSERT(inp); 18418f401c6SAlexander Motin 185b872626dSMatt Macy CK_LIST_REMOVE(inp, inp_hash); 1869ed324c9SAlexander Motin } 18700c081e9SBjoern A. Zeeb #endif /* INET */ 1889ed324c9SAlexander Motin 1899ed324c9SAlexander Motin /* 190df8bae1dSRodney W. Grimes * Raw interface to IP protocol. 191df8bae1dSRodney W. Grimes */ 192df8bae1dSRodney W. Grimes 193df8bae1dSRodney W. Grimes /* 194032dcc76SLuigi Rizzo * Initialize raw connection block q. 195df8bae1dSRodney W. Grimes */ 1964f590175SPaul Saab static void 1974f590175SPaul Saab rip_zone_change(void *tag) 1984f590175SPaul Saab { 1994f590175SPaul Saab 200603724d3SBjoern A. Zeeb uma_zone_set_max(V_ripcbinfo.ipi_zone, maxsockets); 2014f590175SPaul Saab } 2024f590175SPaul Saab 203d915b280SStephan Uphoff static int 204d915b280SStephan Uphoff rip_inpcb_init(void *mem, int size, int flags) 205d915b280SStephan Uphoff { 20608651e1fSJohn Baldwin struct inpcb *inp = mem; 20708651e1fSJohn Baldwin 208d915b280SStephan Uphoff INP_LOCK_INIT(inp, "inp", "rawinp"); 209d915b280SStephan Uphoff return (0); 210d915b280SStephan Uphoff } 211d915b280SStephan Uphoff 212df8bae1dSRodney W. Grimes void 213f2565d68SRobert Watson rip_init(void) 214df8bae1dSRodney W. Grimes { 215f2565d68SRobert Watson 2169bcd427bSRobert Watson in_pcbinfo_init(&V_ripcbinfo, "rip", &V_ripcb, INP_PCBHASH_RAW_SIZE, 217cc487c16SGleb Smirnoff 1, "ripcb", rip_inpcb_init, IPI_HASHFIELDS_NONE); 2180ae76120SRobert Watson EVENTHANDLER_REGISTER(maxsockets_change, rip_zone_change, NULL, 2190ae76120SRobert Watson EVENTHANDLER_PRI_ANY); 220df8bae1dSRodney W. Grimes } 221df8bae1dSRodney W. Grimes 222bc29160dSMarko Zec #ifdef VIMAGE 2233f58662dSBjoern A. Zeeb static void 2243f58662dSBjoern A. Zeeb rip_destroy(void *unused __unused) 225bc29160dSMarko Zec { 226bc29160dSMarko Zec 2279bcd427bSRobert Watson in_pcbinfo_destroy(&V_ripcbinfo); 228bc29160dSMarko Zec } 2293f58662dSBjoern A. Zeeb VNET_SYSUNINIT(raw_ip, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, rip_destroy, NULL); 230bc29160dSMarko Zec #endif 231bc29160dSMarko Zec 23200c081e9SBjoern A. Zeeb #ifdef INET 2333b6dd5a9SSam Leffler static int 2343b19fa35SRobert Watson rip_append(struct inpcb *last, struct ip *ip, struct mbuf *n, 2353b19fa35SRobert Watson struct sockaddr_in *ripsrc) 2363b6dd5a9SSam Leffler { 2374ea889c6SRobert Watson int policyfail = 0; 23833841545SHajimu UMEMOTO 239fa046d87SRobert Watson INP_LOCK_ASSERT(last); 240cbe42d48SRobert Watson 241fcf59617SAndrey V. Elsukov #if defined(IPSEC) || defined(IPSEC_SUPPORT) 242da0f4099SHajimu UMEMOTO /* check AH/ESP integrity. */ 243fcf59617SAndrey V. Elsukov if (IPSEC_ENABLED(ipv4)) { 244fcf59617SAndrey V. Elsukov if (IPSEC_CHECK_POLICY(ipv4, n, last) != 0) 245da0f4099SHajimu UMEMOTO policyfail = 1; 246b9234fafSSam Leffler } 247b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */ 2484ea889c6SRobert Watson #ifdef MAC 24930d239bcSRobert Watson if (!policyfail && mac_inpcb_check_deliver(last, n) != 0) 2504ea889c6SRobert Watson policyfail = 1; 2514ea889c6SRobert Watson #endif 252936cd18dSAndre Oppermann /* Check the minimum TTL for socket. */ 253936cd18dSAndre Oppermann if (last->inp_ip_minttl && last->inp_ip_minttl > ip->ip_ttl) 254936cd18dSAndre Oppermann policyfail = 1; 2553b6dd5a9SSam Leffler if (!policyfail) { 2563b6dd5a9SSam Leffler struct mbuf *opts = NULL; 2571e4d7da7SRobert Watson struct socket *so; 2583b6dd5a9SSam Leffler 2591e4d7da7SRobert Watson so = last->inp_socket; 2603b6dd5a9SSam Leffler if ((last->inp_flags & INP_CONTROLOPTS) || 2611fd7af26SAndre Oppermann (so->so_options & (SO_TIMESTAMP | SO_BINTIME))) 26282c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, n); 2631e4d7da7SRobert Watson SOCKBUF_LOCK(&so->so_rcv); 2641e4d7da7SRobert Watson if (sbappendaddr_locked(&so->so_rcv, 2653b19fa35SRobert Watson (struct sockaddr *)ripsrc, n, opts) == 0) { 266df8bae1dSRodney W. Grimes /* should notify about lost packet */ 267df8bae1dSRodney W. Grimes m_freem(n); 26882c23ebaSBill Fenner if (opts) 26982c23ebaSBill Fenner m_freem(opts); 2701e4d7da7SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 2714cc20ab1SSeigo Tanimura } else 2721e4d7da7SRobert Watson sorwakeup_locked(so); 2733b6dd5a9SSam Leffler } else 2743b6dd5a9SSam Leffler m_freem(n); 2750ae76120SRobert Watson return (policyfail); 276df8bae1dSRodney W. Grimes } 2773b6dd5a9SSam Leffler 2783b6dd5a9SSam Leffler /* 2790ae76120SRobert Watson * Setup generic address and protocol structures for raw_input routine, then 2800ae76120SRobert Watson * pass them along with mbuf chain. 2813b6dd5a9SSam Leffler */ 2828f5a8818SKevin Lo int 2838f5a8818SKevin Lo rip_input(struct mbuf **mp, int *offp, int proto) 2843b6dd5a9SSam Leffler { 285d10910e6SBruce M Simpson struct ifnet *ifp; 2868f5a8818SKevin Lo struct mbuf *m = *mp; 2873b6dd5a9SSam Leffler struct ip *ip = mtod(m, struct ip *); 2883b6dd5a9SSam Leffler struct inpcb *inp, *last; 2893b19fa35SRobert Watson struct sockaddr_in ripsrc; 2909ed324c9SAlexander Motin int hash; 2913b6dd5a9SSam Leffler 292f42347c3SGleb Smirnoff NET_EPOCH_ASSERT(); 293f42347c3SGleb Smirnoff 2948f5a8818SKevin Lo *mp = NULL; 2958f5a8818SKevin Lo 2963b19fa35SRobert Watson bzero(&ripsrc, sizeof(ripsrc)); 2973b19fa35SRobert Watson ripsrc.sin_len = sizeof(ripsrc); 2983b19fa35SRobert Watson ripsrc.sin_family = AF_INET; 2993b6dd5a9SSam Leffler ripsrc.sin_addr = ip->ip_src; 3003b6dd5a9SSam Leffler last = NULL; 301d10910e6SBruce M Simpson 302d10910e6SBruce M Simpson ifp = m->m_pkthdr.rcvif; 303d10910e6SBruce M Simpson 3049ed324c9SAlexander Motin hash = INP_PCBHASH_RAW(proto, ip->ip_src.s_addr, 305603724d3SBjoern A. Zeeb ip->ip_dst.s_addr, V_ripcbinfo.ipi_hashmask); 306b872626dSMatt Macy CK_LIST_FOREACH(inp, &V_ripcbinfo.ipi_hashbase[hash], inp_hash) { 3070ca3b096SAlexander Motin if (inp->inp_ip_p != proto) 3080ca3b096SAlexander Motin continue; 3090ca3b096SAlexander Motin #ifdef INET6 31086d02c5cSBjoern A. Zeeb /* XXX inp locking */ 3110ca3b096SAlexander Motin if ((inp->inp_vflag & INP_IPV4) == 0) 3120ca3b096SAlexander Motin continue; 3130ca3b096SAlexander Motin #endif 3140ca3b096SAlexander Motin if (inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 3150ca3b096SAlexander Motin continue; 3160ca3b096SAlexander Motin if (inp->inp_faddr.s_addr != ip->ip_src.s_addr) 3170ca3b096SAlexander Motin continue; 3183bb87a6cSKip Macy if (last != NULL) { 3199ed324c9SAlexander Motin struct mbuf *n; 3209ed324c9SAlexander Motin 321c3bef61eSKevin Lo n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 3229ed324c9SAlexander Motin if (n != NULL) 3239ed324c9SAlexander Motin (void) rip_append(last, ip, n, &ripsrc); 3249ed324c9SAlexander Motin /* XXX count dropped packet */ 3259ed324c9SAlexander Motin INP_RUNLOCK(last); 326e93fdbe2SMatt Macy last = NULL; 3279ed324c9SAlexander Motin } 32886d02c5cSBjoern A. Zeeb INP_RLOCK(inp); 329e93fdbe2SMatt Macy if (__predict_false(inp->inp_flags2 & INP_FREED)) 330e93fdbe2SMatt Macy goto skip_1; 331e93fdbe2SMatt Macy if (jailed_without_vnet(inp->inp_cred)) { 332e93fdbe2SMatt Macy /* 333e93fdbe2SMatt Macy * XXX: If faddr was bound to multicast group, 334e93fdbe2SMatt Macy * jailed raw socket will drop datagram. 335e93fdbe2SMatt Macy */ 336e93fdbe2SMatt Macy if (prison_check_ip4(inp->inp_cred, &ip->ip_dst) != 0) 337e93fdbe2SMatt Macy goto skip_1; 338e5c331cfSMatt Macy } 339e93fdbe2SMatt Macy last = inp; 340e93fdbe2SMatt Macy continue; 341e93fdbe2SMatt Macy skip_1: 342e93fdbe2SMatt Macy INP_RUNLOCK(inp); 3439ed324c9SAlexander Motin } 344b872626dSMatt Macy CK_LIST_FOREACH(inp, &V_ripcbinfo.ipi_hashbase[0], inp_hash) { 3450ca3b096SAlexander Motin if (inp->inp_ip_p && inp->inp_ip_p != proto) 3463b6dd5a9SSam Leffler continue; 3473b6dd5a9SSam Leffler #ifdef INET6 34886d02c5cSBjoern A. Zeeb /* XXX inp locking */ 3493b6dd5a9SSam Leffler if ((inp->inp_vflag & INP_IPV4) == 0) 3500ca3b096SAlexander Motin continue; 3513b6dd5a9SSam Leffler #endif 352d10910e6SBruce M Simpson if (!in_nullhost(inp->inp_laddr) && 353d10910e6SBruce M Simpson !in_hosteq(inp->inp_laddr, ip->ip_dst)) 3540ca3b096SAlexander Motin continue; 355d10910e6SBruce M Simpson if (!in_nullhost(inp->inp_faddr) && 356d10910e6SBruce M Simpson !in_hosteq(inp->inp_faddr, ip->ip_src)) 3570ca3b096SAlexander Motin continue; 358e93fdbe2SMatt Macy if (last != NULL) { 359e93fdbe2SMatt Macy struct mbuf *n; 360e93fdbe2SMatt Macy 361e93fdbe2SMatt Macy n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 362e93fdbe2SMatt Macy if (n != NULL) 363e93fdbe2SMatt Macy (void) rip_append(last, ip, n, &ripsrc); 364e93fdbe2SMatt Macy /* XXX count dropped packet */ 365e93fdbe2SMatt Macy INP_RUNLOCK(last); 366e93fdbe2SMatt Macy last = NULL; 367e93fdbe2SMatt Macy } 368e93fdbe2SMatt Macy INP_RLOCK(inp); 369e93fdbe2SMatt Macy if (__predict_false(inp->inp_flags2 & INP_FREED)) 370e93fdbe2SMatt Macy goto skip_2; 371de0bd6f7SBjoern A. Zeeb if (jailed_without_vnet(inp->inp_cred)) { 372d10910e6SBruce M Simpson /* 373d10910e6SBruce M Simpson * Allow raw socket in jail to receive multicast; 374d10910e6SBruce M Simpson * assume process had PRIV_NETINET_RAW at attach, 375d10910e6SBruce M Simpson * and fall through into normal filter path if so. 376d10910e6SBruce M Simpson */ 377d10910e6SBruce M Simpson if (!IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && 378d10910e6SBruce M Simpson prison_check_ip4(inp->inp_cred, &ip->ip_dst) != 0) 379e93fdbe2SMatt Macy goto skip_2; 380d10910e6SBruce M Simpson } 381d10910e6SBruce M Simpson /* 382d10910e6SBruce M Simpson * If this raw socket has multicast state, and we 383d10910e6SBruce M Simpson * have received a multicast, check if this socket 384d10910e6SBruce M Simpson * should receive it, as multicast filtering is now 385d10910e6SBruce M Simpson * the responsibility of the transport layer. 386d10910e6SBruce M Simpson */ 387d10910e6SBruce M Simpson if (inp->inp_moptions != NULL && 388d10910e6SBruce M Simpson IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 389793c7042SBruce M Simpson /* 390793c7042SBruce M Simpson * If the incoming datagram is for IGMP, allow it 391793c7042SBruce M Simpson * through unconditionally to the raw socket. 392793c7042SBruce M Simpson * 393793c7042SBruce M Simpson * In the case of IGMPv2, we may not have explicitly 394793c7042SBruce M Simpson * joined the group, and may have set IFF_ALLMULTI 395793c7042SBruce M Simpson * on the interface. imo_multi_filter() may discard 396793c7042SBruce M Simpson * control traffic we actually need to see. 397793c7042SBruce M Simpson * 398793c7042SBruce M Simpson * Userland multicast routing daemons should continue 399793c7042SBruce M Simpson * filter the control traffic appropriately. 400793c7042SBruce M Simpson */ 401d10910e6SBruce M Simpson int blocked; 402d10910e6SBruce M Simpson 403793c7042SBruce M Simpson blocked = MCAST_PASS; 404793c7042SBruce M Simpson if (proto != IPPROTO_IGMP) { 405793c7042SBruce M Simpson struct sockaddr_in group; 406793c7042SBruce M Simpson 407d10910e6SBruce M Simpson bzero(&group, sizeof(struct sockaddr_in)); 408d10910e6SBruce M Simpson group.sin_len = sizeof(struct sockaddr_in); 409d10910e6SBruce M Simpson group.sin_family = AF_INET; 410d10910e6SBruce M Simpson group.sin_addr = ip->ip_dst; 411d10910e6SBruce M Simpson 412793c7042SBruce M Simpson blocked = imo_multi_filter(inp->inp_moptions, 413793c7042SBruce M Simpson ifp, 414d10910e6SBruce M Simpson (struct sockaddr *)&group, 415d10910e6SBruce M Simpson (struct sockaddr *)&ripsrc); 416793c7042SBruce M Simpson } 417793c7042SBruce M Simpson 418d10910e6SBruce M Simpson if (blocked != MCAST_PASS) { 41986425c62SRobert Watson IPSTAT_INC(ips_notmember); 420e93fdbe2SMatt Macy goto skip_2; 421d10910e6SBruce M Simpson } 422d10910e6SBruce M Simpson } 42382c23ebaSBill Fenner last = inp; 424e93fdbe2SMatt Macy continue; 425e93fdbe2SMatt Macy skip_2: 426e93fdbe2SMatt Macy INP_RUNLOCK(inp); 427df8bae1dSRodney W. Grimes } 4283b6dd5a9SSam Leffler if (last != NULL) { 4293b19fa35SRobert Watson if (rip_append(last, ip, m, &ripsrc) != 0) 43086425c62SRobert Watson IPSTAT_INC(ips_delivered); 4319ad11dd8SRobert Watson INP_RUNLOCK(last); 432df8bae1dSRodney W. Grimes } else { 433ad2cbb09SMichael Tuexen if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { 43486425c62SRobert Watson IPSTAT_INC(ips_noproto); 43586425c62SRobert Watson IPSTAT_DEC(ips_delivered); 4366d7270a5SMichael Tuexen icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0); 4376d7270a5SMichael Tuexen } else { 438ad2cbb09SMichael Tuexen m_freem(m); 439ad2cbb09SMichael Tuexen } 4406d7270a5SMichael Tuexen } 4418f5a8818SKevin Lo return (IPPROTO_DONE); 442df8bae1dSRodney W. Grimes } 443df8bae1dSRodney W. Grimes 444df8bae1dSRodney W. Grimes /* 4450ae76120SRobert Watson * Generate IP header and pass packet to ip_output. Tack on options user may 4460ae76120SRobert Watson * have setup with control call. 447df8bae1dSRodney W. Grimes */ 448df8bae1dSRodney W. Grimes int 44973d76e77SKevin Lo rip_output(struct mbuf *m, struct socket *so, ...) 450df8bae1dSRodney W. Grimes { 451b9555453SGleb Smirnoff struct epoch_tracker et; 4523b6dd5a9SSam Leffler struct ip *ip; 453ac830b58SBosko Milekic int error; 4543b6dd5a9SSam Leffler struct inpcb *inp = sotoinpcb(so); 45573d76e77SKevin Lo va_list ap; 45673d76e77SKevin Lo u_long dst; 457b5d47ff5SJohn-Mark Gurney int flags = ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) | 458b5d47ff5SJohn-Mark Gurney IP_ALLOWBROADCAST; 45920a6a3a7SMichael Tuexen int cnt, hlen; 460aef06417SMichael Tuexen u_char opttype, optlen, *cp; 461df8bae1dSRodney W. Grimes 46273d76e77SKevin Lo va_start(ap, so); 46373d76e77SKevin Lo dst = va_arg(ap, u_long); 46473d76e77SKevin Lo va_end(ap); 46573d76e77SKevin Lo 466df8bae1dSRodney W. Grimes /* 4670ae76120SRobert Watson * If the user handed us a complete IP packet, use it. Otherwise, 4680ae76120SRobert Watson * allocate an mbuf for a header and fill it in. 469df8bae1dSRodney W. Grimes */ 470df8bae1dSRodney W. Grimes if ((inp->inp_flags & INP_HDRINCL) == 0) { 471430d30d8SBill Fenner if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { 472430d30d8SBill Fenner m_freem(m); 473430d30d8SBill Fenner return(EMSGSIZE); 474430d30d8SBill Fenner } 475eb1b1807SGleb Smirnoff M_PREPEND(m, sizeof(struct ip), M_NOWAIT); 4766b48911bSRobert Watson if (m == NULL) 4776b48911bSRobert Watson return(ENOBUFS); 478ac830b58SBosko Milekic 4799ad11dd8SRobert Watson INP_RLOCK(inp); 480df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 4818ce3f3ddSRuslan Ermilov ip->ip_tos = inp->inp_ip_tos; 482b2828ad2SAndre Oppermann if (inp->inp_flags & INP_DONTFRAG) 4838f134647SGleb Smirnoff ip->ip_off = htons(IP_DF); 484b2828ad2SAndre Oppermann else 4858f134647SGleb Smirnoff ip->ip_off = htons(0); 486ca98b82cSDavid Greenman ip->ip_p = inp->inp_ip_p; 4878f134647SGleb Smirnoff ip->ip_len = htons(m->m_pkthdr.len); 488b89e82ddSJamie Gritton ip->ip_src = inp->inp_laddr; 489ae190832SSteven Hartland ip->ip_dst.s_addr = dst; 4900c325f53SAlexander V. Chernikov #ifdef ROUTE_MPATH 4910c325f53SAlexander V. Chernikov if (CALC_FLOWID_OUTBOUND) { 4920c325f53SAlexander V. Chernikov uint32_t hash_type, hash_val; 4930c325f53SAlexander V. Chernikov 4940c325f53SAlexander V. Chernikov hash_val = fib4_calc_software_hash(ip->ip_src, 4950c325f53SAlexander V. Chernikov ip->ip_dst, 0, 0, ip->ip_p, &hash_type); 4960c325f53SAlexander V. Chernikov m->m_pkthdr.flowid = hash_val; 4970c325f53SAlexander V. Chernikov M_HASHTYPE_SET(m, hash_type); 4980c325f53SAlexander V. Chernikov flags |= IP_NODEFAULTFLOWID; 4990c325f53SAlexander V. Chernikov } 5000c325f53SAlexander V. Chernikov #endif 5017a657e63SBjoern A. Zeeb if (jailed(inp->inp_cred)) { 5027a657e63SBjoern A. Zeeb /* 5037a657e63SBjoern A. Zeeb * prison_local_ip4() would be good enough but would 5047a657e63SBjoern A. Zeeb * let a source of INADDR_ANY pass, which we do not 505ae190832SSteven Hartland * want to see from jails. 5067a657e63SBjoern A. Zeeb */ 507ae190832SSteven Hartland if (ip->ip_src.s_addr == INADDR_ANY) { 508c1604fe4SGleb Smirnoff NET_EPOCH_ENTER(et); 509c1604fe4SGleb Smirnoff error = in_pcbladdr(inp, &ip->ip_dst, 510c1604fe4SGleb Smirnoff &ip->ip_src, inp->inp_cred); 511c1604fe4SGleb Smirnoff NET_EPOCH_EXIT(et); 512ae190832SSteven Hartland } else { 5137a657e63SBjoern A. Zeeb error = prison_local_ip4(inp->inp_cred, 5147a657e63SBjoern A. Zeeb &ip->ip_src); 515ae190832SSteven Hartland } 516b89e82ddSJamie Gritton if (error != 0) { 517413628a7SBjoern A. Zeeb INP_RUNLOCK(inp); 518413628a7SBjoern A. Zeeb m_freem(m); 519b89e82ddSJamie Gritton return (error); 520413628a7SBjoern A. Zeeb } 5217a657e63SBjoern A. Zeeb } 5228ce3f3ddSRuslan Ermilov ip->ip_ttl = inp->inp_ip_ttl; 523df8bae1dSRodney W. Grimes } else { 524430d30d8SBill Fenner if (m->m_pkthdr.len > IP_MAXPACKET) { 525430d30d8SBill Fenner m_freem(m); 526430d30d8SBill Fenner return(EMSGSIZE); 527430d30d8SBill Fenner } 528df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 52920a6a3a7SMichael Tuexen hlen = ip->ip_hl << 2; 53020a6a3a7SMichael Tuexen if (m->m_len < hlen) { 53120a6a3a7SMichael Tuexen m = m_pullup(m, hlen); 53220a6a3a7SMichael Tuexen if (m == NULL) 53320a6a3a7SMichael Tuexen return (EINVAL); 53420a6a3a7SMichael Tuexen ip = mtod(m, struct ip *); 53520a6a3a7SMichael Tuexen } 5360c325f53SAlexander V. Chernikov #ifdef ROUTE_MPATH 5370c325f53SAlexander V. Chernikov if (CALC_FLOWID_OUTBOUND) { 5380c325f53SAlexander V. Chernikov uint32_t hash_type, hash_val; 53920a6a3a7SMichael Tuexen 5400c325f53SAlexander V. Chernikov hash_val = fib4_calc_software_hash(ip->ip_dst, 5410c325f53SAlexander V. Chernikov ip->ip_src, 0, 0, ip->ip_p, &hash_type); 5420c325f53SAlexander V. Chernikov m->m_pkthdr.flowid = hash_val; 5430c325f53SAlexander V. Chernikov M_HASHTYPE_SET(m, hash_type); 5440c325f53SAlexander V. Chernikov flags |= IP_NODEFAULTFLOWID; 5450c325f53SAlexander V. Chernikov } 5460c325f53SAlexander V. Chernikov #endif 54720a6a3a7SMichael Tuexen INP_RLOCK(inp); 54820a6a3a7SMichael Tuexen /* 54920a6a3a7SMichael Tuexen * Don't allow both user specified and setsockopt options, 55020a6a3a7SMichael Tuexen * and don't allow packet length sizes that will crash. 55120a6a3a7SMichael Tuexen */ 55220a6a3a7SMichael Tuexen if ((hlen < sizeof (*ip)) 55320a6a3a7SMichael Tuexen || ((hlen > sizeof (*ip)) && inp->inp_options) 55420a6a3a7SMichael Tuexen || (ntohs(ip->ip_len) != m->m_pkthdr.len)) { 55520a6a3a7SMichael Tuexen INP_RUNLOCK(inp); 55620a6a3a7SMichael Tuexen m_freem(m); 55720a6a3a7SMichael Tuexen return (EINVAL); 55820a6a3a7SMichael Tuexen } 559b89e82ddSJamie Gritton error = prison_check_ip4(inp->inp_cred, &ip->ip_src); 560b89e82ddSJamie Gritton if (error != 0) { 5619ad11dd8SRobert Watson INP_RUNLOCK(inp); 5625a59cefcSBosko Milekic m_freem(m); 563b89e82ddSJamie Gritton return (error); 5645a59cefcSBosko Milekic } 5656d947416SGleb Smirnoff /* 566aef06417SMichael Tuexen * Don't allow IP options which do not have the required 567aef06417SMichael Tuexen * structure as specified in section 3.1 of RFC 791 on 568aef06417SMichael Tuexen * pages 15-23. 569aef06417SMichael Tuexen */ 570aef06417SMichael Tuexen cp = (u_char *)(ip + 1); 57120a6a3a7SMichael Tuexen cnt = hlen - sizeof (struct ip); 572aef06417SMichael Tuexen for (; cnt > 0; cnt -= optlen, cp += optlen) { 573aef06417SMichael Tuexen opttype = cp[IPOPT_OPTVAL]; 574aef06417SMichael Tuexen if (opttype == IPOPT_EOL) 575aef06417SMichael Tuexen break; 576aef06417SMichael Tuexen if (opttype == IPOPT_NOP) { 577aef06417SMichael Tuexen optlen = 1; 578aef06417SMichael Tuexen continue; 579aef06417SMichael Tuexen } 580aef06417SMichael Tuexen if (cnt < IPOPT_OLEN + sizeof(u_char)) { 581aef06417SMichael Tuexen INP_RUNLOCK(inp); 582aef06417SMichael Tuexen m_freem(m); 583aef06417SMichael Tuexen return (EINVAL); 584aef06417SMichael Tuexen } 585aef06417SMichael Tuexen optlen = cp[IPOPT_OLEN]; 586aef06417SMichael Tuexen if (optlen < IPOPT_OLEN + sizeof(u_char) || 587aef06417SMichael Tuexen optlen > cnt) { 588aef06417SMichael Tuexen INP_RUNLOCK(inp); 589aef06417SMichael Tuexen m_freem(m); 590aef06417SMichael Tuexen return (EINVAL); 591aef06417SMichael Tuexen } 592aef06417SMichael Tuexen } 593aef06417SMichael Tuexen /* 5946d947416SGleb Smirnoff * This doesn't allow application to specify ID of zero, 5956d947416SGleb Smirnoff * but we got this limitation from the beginning of history. 5966d947416SGleb Smirnoff */ 597df8bae1dSRodney W. Grimes if (ip->ip_id == 0) 5986d947416SGleb Smirnoff ip_fillid(ip); 5990ae76120SRobert Watson 6000ae76120SRobert Watson /* 6010ae76120SRobert Watson * XXX prevent ip_output from overwriting header fields. 6020ae76120SRobert Watson */ 603df8bae1dSRodney W. Grimes flags |= IP_RAWOUTPUT; 60486425c62SRobert Watson IPSTAT_INC(ips_rawout); 605df8bae1dSRodney W. Grimes } 6066a800098SYoshinobu Inoue 6076fbfd582SAndre Oppermann if (inp->inp_flags & INP_ONESBCAST) 6088afa2304SBruce M Simpson flags |= IP_SENDONES; 6098afa2304SBruce M Simpson 610ac830b58SBosko Milekic #ifdef MAC 61130d239bcSRobert Watson mac_inpcb_create_mbuf(inp, m); 612ac830b58SBosko Milekic #endif 613ac830b58SBosko Milekic 614b9555453SGleb Smirnoff NET_EPOCH_ENTER(et); 615ac830b58SBosko Milekic error = ip_output(m, inp->inp_options, NULL, flags, 616ac830b58SBosko Milekic inp->inp_moptions, inp); 617b9555453SGleb Smirnoff NET_EPOCH_EXIT(et); 6189ad11dd8SRobert Watson INP_RUNLOCK(inp); 6190ae76120SRobert Watson return (error); 620df8bae1dSRodney W. Grimes } 621df8bae1dSRodney W. Grimes 622df8bae1dSRodney W. Grimes /* 623df8bae1dSRodney W. Grimes * Raw IP socket option processing. 62483503a92SRobert Watson * 6256c67b8b6SRobert Watson * IMPORTANT NOTE regarding access control: Traditionally, raw sockets could 6266c67b8b6SRobert Watson * only be created by a privileged process, and as such, socket option 6276c67b8b6SRobert Watson * operations to manage system properties on any raw socket were allowed to 6286c67b8b6SRobert Watson * take place without explicit additional access control checks. However, 6296c67b8b6SRobert Watson * raw sockets can now also be created in jail(), and therefore explicit 6306c67b8b6SRobert Watson * checks are now required. Likewise, raw sockets can be used by a process 6316c67b8b6SRobert Watson * after it gives up privilege, so some caution is required. For options 6326c67b8b6SRobert Watson * passed down to the IP layer via ip_ctloutput(), checks are assumed to be 6336c67b8b6SRobert Watson * performed in ip_ctloutput() and therefore no check occurs here. 63402dd4b5cSRobert Watson * Unilaterally checking priv_check() here breaks normal IP socket option 6356c67b8b6SRobert Watson * operations on raw sockets. 6366c67b8b6SRobert Watson * 6376c67b8b6SRobert Watson * When adding new socket options here, make sure to add access control 6386c67b8b6SRobert Watson * checks here as necessary. 639762ad1d6SBjoern A. Zeeb * 640762ad1d6SBjoern A. Zeeb * XXX-BZ inp locking? 641df8bae1dSRodney W. Grimes */ 642df8bae1dSRodney W. Grimes int 6433b6dd5a9SSam Leffler rip_ctloutput(struct socket *so, struct sockopt *sopt) 644df8bae1dSRodney W. Grimes { 645cfe8b629SGarrett Wollman struct inpcb *inp = sotoinpcb(so); 646cfe8b629SGarrett Wollman int error, optval; 647df8bae1dSRodney W. Grimes 648bc97ba51SJulian Elischer if (sopt->sopt_level != IPPROTO_IP) { 649bc97ba51SJulian Elischer if ((sopt->sopt_level == SOL_SOCKET) && 650bc97ba51SJulian Elischer (sopt->sopt_name == SO_SETFIB)) { 651bc97ba51SJulian Elischer inp->inp_inc.inc_fibnum = so->so_fibnum; 652bc97ba51SJulian Elischer return (0); 653bc97ba51SJulian Elischer } 654df8bae1dSRodney W. Grimes return (EINVAL); 655bc97ba51SJulian Elischer } 656df8bae1dSRodney W. Grimes 65725f26ad8SGarrett Wollman error = 0; 658cfe8b629SGarrett Wollman switch (sopt->sopt_dir) { 659cfe8b629SGarrett Wollman case SOPT_GET: 660cfe8b629SGarrett Wollman switch (sopt->sopt_name) { 661cfe8b629SGarrett Wollman case IP_HDRINCL: 662cfe8b629SGarrett Wollman optval = inp->inp_flags & INP_HDRINCL; 663cfe8b629SGarrett Wollman error = sooptcopyout(sopt, &optval, sizeof optval); 664cfe8b629SGarrett Wollman break; 665df8bae1dSRodney W. Grimes 6663429911dSLuigi Rizzo case IP_FW3: /* generic ipfw v.3 functions */ 6677b109fa4SLuigi Rizzo case IP_FW_ADD: /* ADD actually returns the body... */ 66809bb5f75SPoul-Henning Kamp case IP_FW_GET: 669cd8b5ae0SRuslan Ermilov case IP_FW_TABLE_GETSIZE: 670cd8b5ae0SRuslan Ermilov case IP_FW_TABLE_LIST: 671ff2f6fe8SPaolo Pisati case IP_FW_NAT_GET_CONFIG: 672ff2f6fe8SPaolo Pisati case IP_FW_NAT_GET_LOG: 6730b4b0b0fSJulian Elischer if (V_ip_fw_ctl_ptr != NULL) 6740b4b0b0fSJulian Elischer error = V_ip_fw_ctl_ptr(sopt); 6757b109fa4SLuigi Rizzo else 6767b109fa4SLuigi Rizzo error = ENOPROTOOPT; 677cfe8b629SGarrett Wollman break; 6784dd1662bSUgen J.S. Antsilevich 6793429911dSLuigi Rizzo case IP_DUMMYNET3: /* generic dummynet v.3 functions */ 680b715f178SLuigi Rizzo case IP_DUMMYNET_GET: 6819b932e9eSAndre Oppermann if (ip_dn_ctl_ptr != NULL) 682b715f178SLuigi Rizzo error = ip_dn_ctl_ptr(sopt); 6837b109fa4SLuigi Rizzo else 6847b109fa4SLuigi Rizzo error = ENOPROTOOPT; 685b715f178SLuigi Rizzo break ; 6861c5de19aSGarrett Wollman 6871c5de19aSGarrett Wollman case MRT_INIT: 6881c5de19aSGarrett Wollman case MRT_DONE: 6891c5de19aSGarrett Wollman case MRT_ADD_VIF: 6901c5de19aSGarrett Wollman case MRT_DEL_VIF: 6911c5de19aSGarrett Wollman case MRT_ADD_MFC: 6921c5de19aSGarrett Wollman case MRT_DEL_MFC: 6931c5de19aSGarrett Wollman case MRT_VERSION: 6941c5de19aSGarrett Wollman case MRT_ASSERT: 6951e78ac21SJeffrey Hsu case MRT_API_SUPPORT: 6961e78ac21SJeffrey Hsu case MRT_API_CONFIG: 6971e78ac21SJeffrey Hsu case MRT_ADD_BW_UPCALL: 6981e78ac21SJeffrey Hsu case MRT_DEL_BW_UPCALL: 699acd3428bSRobert Watson error = priv_check(curthread, PRIV_NETINET_MROUTE); 7006c67b8b6SRobert Watson if (error != 0) 7016c67b8b6SRobert Watson return (error); 702bbb4330bSLuigi Rizzo error = ip_mrouter_get ? ip_mrouter_get(so, sopt) : 703bbb4330bSLuigi Rizzo EOPNOTSUPP; 704cfe8b629SGarrett Wollman break; 705cfe8b629SGarrett Wollman 706cfe8b629SGarrett Wollman default: 707cfe8b629SGarrett Wollman error = ip_ctloutput(so, sopt); 708cfe8b629SGarrett Wollman break; 709df8bae1dSRodney W. Grimes } 710cfe8b629SGarrett Wollman break; 711cfe8b629SGarrett Wollman 712cfe8b629SGarrett Wollman case SOPT_SET: 713cfe8b629SGarrett Wollman switch (sopt->sopt_name) { 714cfe8b629SGarrett Wollman case IP_HDRINCL: 715cfe8b629SGarrett Wollman error = sooptcopyin(sopt, &optval, sizeof optval, 716cfe8b629SGarrett Wollman sizeof optval); 717cfe8b629SGarrett Wollman if (error) 718cfe8b629SGarrett Wollman break; 719cfe8b629SGarrett Wollman if (optval) 720cfe8b629SGarrett Wollman inp->inp_flags |= INP_HDRINCL; 721cfe8b629SGarrett Wollman else 722cfe8b629SGarrett Wollman inp->inp_flags &= ~INP_HDRINCL; 723cfe8b629SGarrett Wollman break; 724cfe8b629SGarrett Wollman 7253429911dSLuigi Rizzo case IP_FW3: /* generic ipfw v.3 functions */ 7268ba03966SRuslan Ermilov case IP_FW_ADD: 727cfe8b629SGarrett Wollman case IP_FW_DEL: 728cfe8b629SGarrett Wollman case IP_FW_FLUSH: 729cfe8b629SGarrett Wollman case IP_FW_ZERO: 7300b6c1a83SBrian Feldman case IP_FW_RESETLOG: 731cd8b5ae0SRuslan Ermilov case IP_FW_TABLE_ADD: 732cd8b5ae0SRuslan Ermilov case IP_FW_TABLE_DEL: 733cd8b5ae0SRuslan Ermilov case IP_FW_TABLE_FLUSH: 734ff2f6fe8SPaolo Pisati case IP_FW_NAT_CFG: 735ff2f6fe8SPaolo Pisati case IP_FW_NAT_DEL: 7360b4b0b0fSJulian Elischer if (V_ip_fw_ctl_ptr != NULL) 7370b4b0b0fSJulian Elischer error = V_ip_fw_ctl_ptr(sopt); 7387b109fa4SLuigi Rizzo else 7397b109fa4SLuigi Rizzo error = ENOPROTOOPT; 740cfe8b629SGarrett Wollman break; 741cfe8b629SGarrett Wollman 7423429911dSLuigi Rizzo case IP_DUMMYNET3: /* generic dummynet v.3 functions */ 743b715f178SLuigi Rizzo case IP_DUMMYNET_CONFIGURE: 744b715f178SLuigi Rizzo case IP_DUMMYNET_DEL: 745b715f178SLuigi Rizzo case IP_DUMMYNET_FLUSH: 7469b932e9eSAndre Oppermann if (ip_dn_ctl_ptr != NULL) 747b715f178SLuigi Rizzo error = ip_dn_ctl_ptr(sopt); 7487b109fa4SLuigi Rizzo else 7497b109fa4SLuigi Rizzo error = ENOPROTOOPT ; 750b715f178SLuigi Rizzo break ; 751cfe8b629SGarrett Wollman 752cfe8b629SGarrett Wollman case IP_RSVP_ON: 753acd3428bSRobert Watson error = priv_check(curthread, PRIV_NETINET_MROUTE); 7546c67b8b6SRobert Watson if (error != 0) 7556c67b8b6SRobert Watson return (error); 756cfe8b629SGarrett Wollman error = ip_rsvp_init(so); 757cfe8b629SGarrett Wollman break; 758cfe8b629SGarrett Wollman 759cfe8b629SGarrett Wollman case IP_RSVP_OFF: 760acd3428bSRobert Watson error = priv_check(curthread, PRIV_NETINET_MROUTE); 7616c67b8b6SRobert Watson if (error != 0) 7626c67b8b6SRobert Watson return (error); 763cfe8b629SGarrett Wollman error = ip_rsvp_done(); 764cfe8b629SGarrett Wollman break; 765cfe8b629SGarrett Wollman 766cfe8b629SGarrett Wollman case IP_RSVP_VIF_ON: 767cfe8b629SGarrett Wollman case IP_RSVP_VIF_OFF: 768acd3428bSRobert Watson error = priv_check(curthread, PRIV_NETINET_MROUTE); 7696c67b8b6SRobert Watson if (error != 0) 7706c67b8b6SRobert Watson return (error); 771bbb4330bSLuigi Rizzo error = ip_rsvp_vif ? 772bbb4330bSLuigi Rizzo ip_rsvp_vif(so, sopt) : EINVAL; 773cfe8b629SGarrett Wollman break; 774cfe8b629SGarrett Wollman 775cfe8b629SGarrett Wollman case MRT_INIT: 776cfe8b629SGarrett Wollman case MRT_DONE: 777cfe8b629SGarrett Wollman case MRT_ADD_VIF: 778cfe8b629SGarrett Wollman case MRT_DEL_VIF: 779cfe8b629SGarrett Wollman case MRT_ADD_MFC: 780cfe8b629SGarrett Wollman case MRT_DEL_MFC: 781cfe8b629SGarrett Wollman case MRT_VERSION: 782cfe8b629SGarrett Wollman case MRT_ASSERT: 7831e78ac21SJeffrey Hsu case MRT_API_SUPPORT: 7841e78ac21SJeffrey Hsu case MRT_API_CONFIG: 7851e78ac21SJeffrey Hsu case MRT_ADD_BW_UPCALL: 7861e78ac21SJeffrey Hsu case MRT_DEL_BW_UPCALL: 787acd3428bSRobert Watson error = priv_check(curthread, PRIV_NETINET_MROUTE); 7886c67b8b6SRobert Watson if (error != 0) 7896c67b8b6SRobert Watson return (error); 790bbb4330bSLuigi Rizzo error = ip_mrouter_set ? ip_mrouter_set(so, sopt) : 791bbb4330bSLuigi Rizzo EOPNOTSUPP; 792cfe8b629SGarrett Wollman break; 793cfe8b629SGarrett Wollman 794cfe8b629SGarrett Wollman default: 795cfe8b629SGarrett Wollman error = ip_ctloutput(so, sopt); 796cfe8b629SGarrett Wollman break; 797cfe8b629SGarrett Wollman } 798cfe8b629SGarrett Wollman break; 799cfe8b629SGarrett Wollman } 800cfe8b629SGarrett Wollman 801cfe8b629SGarrett Wollman return (error); 802df8bae1dSRodney W. Grimes } 803df8bae1dSRodney W. Grimes 80439191c8eSGarrett Wollman /* 8050ae76120SRobert Watson * This function exists solely to receive the PRC_IFDOWN messages which are 8060ae76120SRobert Watson * sent by if_down(). It looks for an ifaddr whose ifa_addr is sa, and calls 8070ae76120SRobert Watson * in_ifadown() to remove all routes corresponding to that address. It also 8080ae76120SRobert Watson * receives the PRC_IFUP messages from if_up() and reinstalls the interface 8090ae76120SRobert Watson * routes. 81039191c8eSGarrett Wollman */ 81139191c8eSGarrett Wollman void 8123b6dd5a9SSam Leffler rip_ctlinput(int cmd, struct sockaddr *sa, void *vip) 81339191c8eSGarrett Wollman { 814cc0a3c8cSAndrey V. Elsukov struct rm_priotracker in_ifa_tracker; 81539191c8eSGarrett Wollman struct in_ifaddr *ia; 81639191c8eSGarrett Wollman struct ifnet *ifp; 81739191c8eSGarrett Wollman int err; 81839191c8eSGarrett Wollman int flags; 81939191c8eSGarrett Wollman 82039191c8eSGarrett Wollman switch (cmd) { 82139191c8eSGarrett Wollman case PRC_IFDOWN: 822cc0a3c8cSAndrey V. Elsukov IN_IFADDR_RLOCK(&in_ifa_tracker); 823d7c5a620SMatt Macy CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 82439191c8eSGarrett Wollman if (ia->ia_ifa.ifa_addr == sa 82539191c8eSGarrett Wollman && (ia->ia_flags & IFA_ROUTE)) { 8262d9cfabaSRobert Watson ifa_ref(&ia->ia_ifa); 827cc0a3c8cSAndrey V. Elsukov IN_IFADDR_RUNLOCK(&in_ifa_tracker); 82839191c8eSGarrett Wollman /* 829237bf7f7SGleb Smirnoff * in_scrubprefix() kills the interface route. 83039191c8eSGarrett Wollman */ 831237bf7f7SGleb Smirnoff in_scrubprefix(ia, 0); 83239191c8eSGarrett Wollman /* 8330ae76120SRobert Watson * in_ifadown gets rid of all the rest of the 8340ae76120SRobert Watson * routes. This is not quite the right thing 8350ae76120SRobert Watson * to do, but at least if we are running a 8360ae76120SRobert Watson * routing process they will come back. 83739191c8eSGarrett Wollman */ 83891854268SRuslan Ermilov in_ifadown(&ia->ia_ifa, 0); 8392d9cfabaSRobert Watson ifa_free(&ia->ia_ifa); 84039191c8eSGarrett Wollman break; 84139191c8eSGarrett Wollman } 84239191c8eSGarrett Wollman } 8432d9cfabaSRobert Watson if (ia == NULL) /* If ia matched, already unlocked. */ 844cc0a3c8cSAndrey V. Elsukov IN_IFADDR_RUNLOCK(&in_ifa_tracker); 84539191c8eSGarrett Wollman break; 84639191c8eSGarrett Wollman 84739191c8eSGarrett Wollman case PRC_IFUP: 848cc0a3c8cSAndrey V. Elsukov IN_IFADDR_RLOCK(&in_ifa_tracker); 849d7c5a620SMatt Macy CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 85039191c8eSGarrett Wollman if (ia->ia_ifa.ifa_addr == sa) 85139191c8eSGarrett Wollman break; 85239191c8eSGarrett Wollman } 8532d9cfabaSRobert Watson if (ia == NULL || (ia->ia_flags & IFA_ROUTE)) { 854cc0a3c8cSAndrey V. Elsukov IN_IFADDR_RUNLOCK(&in_ifa_tracker); 85539191c8eSGarrett Wollman return; 8562d9cfabaSRobert Watson } 8572d9cfabaSRobert Watson ifa_ref(&ia->ia_ifa); 858cc0a3c8cSAndrey V. Elsukov IN_IFADDR_RUNLOCK(&in_ifa_tracker); 85939191c8eSGarrett Wollman flags = RTF_UP; 86039191c8eSGarrett Wollman ifp = ia->ia_ifa.ifa_ifp; 86139191c8eSGarrett Wollman 86239191c8eSGarrett Wollman if ((ifp->if_flags & IFF_LOOPBACK) 86339191c8eSGarrett Wollman || (ifp->if_flags & IFF_POINTOPOINT)) 86439191c8eSGarrett Wollman flags |= RTF_HOST; 86539191c8eSGarrett Wollman 8665b84dc78SQing Li err = ifa_del_loopback_route((struct ifaddr *)ia, sa); 8675b84dc78SQing Li 868*81728a53SAlexander V. Chernikov rt_addrmsg(RTM_ADD, &ia->ia_ifa, ia->ia_ifp->if_fib); 869*81728a53SAlexander V. Chernikov err = in_handle_ifaddr_route(RTM_ADD, ia); 87039191c8eSGarrett Wollman if (err == 0) 87139191c8eSGarrett Wollman ia->ia_flags |= IFA_ROUTE; 8725b84dc78SQing Li 8739bb7d0f4SQing Li err = ifa_add_loopback_route((struct ifaddr *)ia, sa); 8745b84dc78SQing Li 8752d9cfabaSRobert Watson ifa_free(&ia->ia_ifa); 87639191c8eSGarrett Wollman break; 87739191c8eSGarrett Wollman } 87839191c8eSGarrett Wollman } 87939191c8eSGarrett Wollman 880117bcae7SGarrett Wollman static int 881b40ce416SJulian Elischer rip_attach(struct socket *so, int proto, struct thread *td) 882df8bae1dSRodney W. Grimes { 883117bcae7SGarrett Wollman struct inpcb *inp; 8843b6dd5a9SSam Leffler int error; 885c1f8a6ceSDavid Greenman 886117bcae7SGarrett Wollman inp = sotoinpcb(so); 88714ba8addSRobert Watson KASSERT(inp == NULL, ("rip_attach: inp != NULL")); 88832f9753cSRobert Watson 88932f9753cSRobert Watson error = priv_check(td, PRIV_NETINET_RAW); 890acd3428bSRobert Watson if (error) 8910ae76120SRobert Watson return (error); 89214ba8addSRobert Watson if (proto >= IPPROTO_MAX || proto < 0) 8934d3ffc98SBill Fenner return EPROTONOSUPPORT; 8946a800098SYoshinobu Inoue error = soreserve(so, rip_sendspace, rip_recvspace); 89514ba8addSRobert Watson if (error) 8960ae76120SRobert Watson return (error); 897603724d3SBjoern A. Zeeb INP_INFO_WLOCK(&V_ripcbinfo); 898603724d3SBjoern A. Zeeb error = in_pcballoc(so, &V_ripcbinfo); 8993b6dd5a9SSam Leffler if (error) { 900603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_ripcbinfo); 9010ae76120SRobert Watson return (error); 9023b6dd5a9SSam Leffler } 903df8bae1dSRodney W. Grimes inp = (struct inpcb *)so->so_pcb; 9046a800098SYoshinobu Inoue inp->inp_vflag |= INP_IPV4; 905ca98b82cSDavid Greenman inp->inp_ip_p = proto; 906603724d3SBjoern A. Zeeb inp->inp_ip_ttl = V_ip_defttl; 9079ed324c9SAlexander Motin rip_inshash(inp); 908603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_ripcbinfo); 9098501a69cSRobert Watson INP_WUNLOCK(inp); 9100ae76120SRobert Watson return (0); 911df8bae1dSRodney W. Grimes } 912117bcae7SGarrett Wollman 91350d7c061SSam Leffler static void 914a152f8a3SRobert Watson rip_detach(struct socket *so) 91550d7c061SSam Leffler { 916a152f8a3SRobert Watson struct inpcb *inp; 9173ca1570cSRobert Watson 918a152f8a3SRobert Watson inp = sotoinpcb(so); 919a152f8a3SRobert Watson KASSERT(inp != NULL, ("rip_detach: inp == NULL")); 920a152f8a3SRobert Watson KASSERT(inp->inp_faddr.s_addr == INADDR_ANY, 921a152f8a3SRobert Watson ("rip_detach: not closed")); 92250d7c061SSam Leffler 923603724d3SBjoern A. Zeeb INP_INFO_WLOCK(&V_ripcbinfo); 9248501a69cSRobert Watson INP_WLOCK(inp); 9259ed324c9SAlexander Motin rip_delhash(inp); 926603724d3SBjoern A. Zeeb if (so == V_ip_mrouter && ip_mrouter_done) 92750d7c061SSam Leffler ip_mrouter_done(); 92850d7c061SSam Leffler if (ip_rsvp_force_done) 92950d7c061SSam Leffler ip_rsvp_force_done(so); 930603724d3SBjoern A. Zeeb if (so == V_ip_rsvpd) 93150d7c061SSam Leffler ip_rsvp_done(); 93250d7c061SSam Leffler in_pcbdetach(inp); 93314ba8addSRobert Watson in_pcbfree(inp); 934603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_ripcbinfo); 93550d7c061SSam Leffler } 93650d7c061SSam Leffler 937bc725eafSRobert Watson static void 938a152f8a3SRobert Watson rip_dodisconnect(struct socket *so, struct inpcb *inp) 939117bcae7SGarrett Wollman { 940fa046d87SRobert Watson struct inpcbinfo *pcbinfo; 94118f401c6SAlexander Motin 942fa046d87SRobert Watson pcbinfo = inp->inp_pcbinfo; 943fa046d87SRobert Watson INP_INFO_WLOCK(pcbinfo); 944fa046d87SRobert Watson INP_WLOCK(inp); 9459ed324c9SAlexander Motin rip_delhash(inp); 946a152f8a3SRobert Watson inp->inp_faddr.s_addr = INADDR_ANY; 9479ed324c9SAlexander Motin rip_inshash(inp); 948a152f8a3SRobert Watson SOCK_LOCK(so); 949a152f8a3SRobert Watson so->so_state &= ~SS_ISCONNECTED; 950a152f8a3SRobert Watson SOCK_UNLOCK(so); 951fa046d87SRobert Watson INP_WUNLOCK(inp); 952fa046d87SRobert Watson INP_INFO_WUNLOCK(pcbinfo); 953117bcae7SGarrett Wollman } 954df8bae1dSRodney W. Grimes 955ac45e92fSRobert Watson static void 956117bcae7SGarrett Wollman rip_abort(struct socket *so) 957df8bae1dSRodney W. Grimes { 95850d7c061SSam Leffler struct inpcb *inp; 95950d7c061SSam Leffler 96050d7c061SSam Leffler inp = sotoinpcb(so); 96114ba8addSRobert Watson KASSERT(inp != NULL, ("rip_abort: inp == NULL")); 962a152f8a3SRobert Watson 963a152f8a3SRobert Watson rip_dodisconnect(so, inp); 964a152f8a3SRobert Watson } 965a152f8a3SRobert Watson 966a152f8a3SRobert Watson static void 967a152f8a3SRobert Watson rip_close(struct socket *so) 968a152f8a3SRobert Watson { 969a152f8a3SRobert Watson struct inpcb *inp; 970a152f8a3SRobert Watson 971a152f8a3SRobert Watson inp = sotoinpcb(so); 972a152f8a3SRobert Watson KASSERT(inp != NULL, ("rip_close: inp == NULL")); 973a152f8a3SRobert Watson 974a152f8a3SRobert Watson rip_dodisconnect(so, inp); 975117bcae7SGarrett Wollman } 976117bcae7SGarrett Wollman 977117bcae7SGarrett Wollman static int 978117bcae7SGarrett Wollman rip_disconnect(struct socket *so) 979117bcae7SGarrett Wollman { 980eb16472fSMaxim Konovalov struct inpcb *inp; 981eb16472fSMaxim Konovalov 9824cc20ab1SSeigo Tanimura if ((so->so_state & SS_ISCONNECTED) == 0) 9830ae76120SRobert Watson return (ENOTCONN); 984eb16472fSMaxim Konovalov 985eb16472fSMaxim Konovalov inp = sotoinpcb(so); 986eb16472fSMaxim Konovalov KASSERT(inp != NULL, ("rip_disconnect: inp == NULL")); 9870ae76120SRobert Watson 988a152f8a3SRobert Watson rip_dodisconnect(so, inp); 98914ba8addSRobert Watson return (0); 990117bcae7SGarrett Wollman } 991117bcae7SGarrett Wollman 992117bcae7SGarrett Wollman static int 993b40ce416SJulian Elischer rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 994117bcae7SGarrett Wollman { 99557bf258eSGarrett Wollman struct sockaddr_in *addr = (struct sockaddr_in *)nam; 99650d7c061SSam Leffler struct inpcb *inp; 997b89e82ddSJamie Gritton int error; 998df8bae1dSRodney W. Grimes 99957bf258eSGarrett Wollman if (nam->sa_len != sizeof(*addr)) 10000ae76120SRobert Watson return (EINVAL); 1001117bcae7SGarrett Wollman 1002b89e82ddSJamie Gritton error = prison_check_ip4(td->td_ucred, &addr->sin_addr); 1003b89e82ddSJamie Gritton if (error != 0) 1004b89e82ddSJamie Gritton return (error); 10055a59cefcSBosko Milekic 1006f44270e7SPawel Jakub Dawidek inp = sotoinpcb(so); 1007f44270e7SPawel Jakub Dawidek KASSERT(inp != NULL, ("rip_bind: inp == NULL")); 1008f44270e7SPawel Jakub Dawidek 10094f6c66ccSMatt Macy if (CK_STAILQ_EMPTY(&V_ifnet) || 101050d7c061SSam Leffler (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) || 1011032dcc76SLuigi Rizzo (addr->sin_addr.s_addr && 1012f44270e7SPawel Jakub Dawidek (inp->inp_flags & INP_BINDANY) == 0 && 10138896f83aSRobert Watson ifa_ifwithaddr_check((struct sockaddr *)addr) == 0)) 10140ae76120SRobert Watson return (EADDRNOTAVAIL); 101550d7c061SSam Leffler 1016603724d3SBjoern A. Zeeb INP_INFO_WLOCK(&V_ripcbinfo); 10178501a69cSRobert Watson INP_WLOCK(inp); 10189ed324c9SAlexander Motin rip_delhash(inp); 1019df8bae1dSRodney W. Grimes inp->inp_laddr = addr->sin_addr; 10209ed324c9SAlexander Motin rip_inshash(inp); 10218501a69cSRobert Watson INP_WUNLOCK(inp); 1022603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_ripcbinfo); 10230ae76120SRobert Watson return (0); 1024df8bae1dSRodney W. Grimes } 1025117bcae7SGarrett Wollman 1026117bcae7SGarrett Wollman static int 1027b40ce416SJulian Elischer rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 1028df8bae1dSRodney W. Grimes { 102957bf258eSGarrett Wollman struct sockaddr_in *addr = (struct sockaddr_in *)nam; 103050d7c061SSam Leffler struct inpcb *inp; 1031df8bae1dSRodney W. Grimes 103257bf258eSGarrett Wollman if (nam->sa_len != sizeof(*addr)) 10330ae76120SRobert Watson return (EINVAL); 10344f6c66ccSMatt Macy if (CK_STAILQ_EMPTY(&V_ifnet)) 10350ae76120SRobert Watson return (EADDRNOTAVAIL); 103650d7c061SSam Leffler if (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) 10370ae76120SRobert Watson return (EAFNOSUPPORT); 103850d7c061SSam Leffler 103950d7c061SSam Leffler inp = sotoinpcb(so); 104014ba8addSRobert Watson KASSERT(inp != NULL, ("rip_connect: inp == NULL")); 10410ae76120SRobert Watson 1042603724d3SBjoern A. Zeeb INP_INFO_WLOCK(&V_ripcbinfo); 10438501a69cSRobert Watson INP_WLOCK(inp); 10449ed324c9SAlexander Motin rip_delhash(inp); 1045df8bae1dSRodney W. Grimes inp->inp_faddr = addr->sin_addr; 10469ed324c9SAlexander Motin rip_inshash(inp); 1047df8bae1dSRodney W. Grimes soisconnected(so); 10488501a69cSRobert Watson INP_WUNLOCK(inp); 1049603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_ripcbinfo); 10500ae76120SRobert Watson return (0); 1051df8bae1dSRodney W. Grimes } 1052df8bae1dSRodney W. Grimes 1053117bcae7SGarrett Wollman static int 1054117bcae7SGarrett Wollman rip_shutdown(struct socket *so) 1055df8bae1dSRodney W. Grimes { 105650d7c061SSam Leffler struct inpcb *inp; 105750d7c061SSam Leffler 105850d7c061SSam Leffler inp = sotoinpcb(so); 105914ba8addSRobert Watson KASSERT(inp != NULL, ("rip_shutdown: inp == NULL")); 10600ae76120SRobert Watson 10618501a69cSRobert Watson INP_WLOCK(inp); 1062117bcae7SGarrett Wollman socantsendmore(so); 10638501a69cSRobert Watson INP_WUNLOCK(inp); 10640ae76120SRobert Watson return (0); 1065117bcae7SGarrett Wollman } 1066117bcae7SGarrett Wollman 1067117bcae7SGarrett Wollman static int 106857bf258eSGarrett Wollman rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 1069b40ce416SJulian Elischer struct mbuf *control, struct thread *td) 1070117bcae7SGarrett Wollman { 107150d7c061SSam Leffler struct inpcb *inp; 107250d7c061SSam Leffler u_long dst; 1073df8bae1dSRodney W. Grimes 107450d7c061SSam Leffler inp = sotoinpcb(so); 107514ba8addSRobert Watson KASSERT(inp != NULL, ("rip_send: inp == NULL")); 10760ae76120SRobert Watson 107714ba8addSRobert Watson /* 107814ba8addSRobert Watson * Note: 'dst' reads below are unlocked. 107914ba8addSRobert Watson */ 1080df8bae1dSRodney W. Grimes if (so->so_state & SS_ISCONNECTED) { 1081df8bae1dSRodney W. Grimes if (nam) { 1082117bcae7SGarrett Wollman m_freem(m); 10830ae76120SRobert Watson return (EISCONN); 1084df8bae1dSRodney W. Grimes } 108514ba8addSRobert Watson dst = inp->inp_faddr.s_addr; /* Unlocked read. */ 1086df8bae1dSRodney W. Grimes } else { 1087df8bae1dSRodney W. Grimes if (nam == NULL) { 1088117bcae7SGarrett Wollman m_freem(m); 10890ae76120SRobert Watson return (ENOTCONN); 1090df8bae1dSRodney W. Grimes } 109157bf258eSGarrett Wollman dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr; 1092df8bae1dSRodney W. Grimes } 10930ae76120SRobert Watson return (rip_output(m, so, dst)); 1094df8bae1dSRodney W. Grimes } 109500c081e9SBjoern A. Zeeb #endif /* INET */ 1096df8bae1dSRodney W. Grimes 109798271db4SGarrett Wollman static int 109882d9ae4eSPoul-Henning Kamp rip_pcblist(SYSCTL_HANDLER_ARGS) 109998271db4SGarrett Wollman { 110098271db4SGarrett Wollman struct xinpgen xig; 11016573d758SMatt Macy struct epoch_tracker et; 1102032677ceSGleb Smirnoff struct inpcb *inp; 1103032677ceSGleb Smirnoff int error; 110498271db4SGarrett Wollman 1105032677ceSGleb Smirnoff if (req->newptr != 0) 1106032677ceSGleb Smirnoff return (EPERM); 1107032677ceSGleb Smirnoff 110898271db4SGarrett Wollman if (req->oldptr == 0) { 1109032677ceSGleb Smirnoff int n; 1110032677ceSGleb Smirnoff 1111603724d3SBjoern A. Zeeb n = V_ripcbinfo.ipi_count; 1112c007b96aSJohn Baldwin n += imax(n / 8, 10); 1113c007b96aSJohn Baldwin req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xinpcb); 11140ae76120SRobert Watson return (0); 111598271db4SGarrett Wollman } 111698271db4SGarrett Wollman 1117032677ceSGleb Smirnoff if ((error = sysctl_wire_old_buffer(req, 0)) != 0) 1118032677ceSGleb Smirnoff return (error); 111998271db4SGarrett Wollman 112079db6fe7SMark Johnston bzero(&xig, sizeof(xig)); 112198271db4SGarrett Wollman xig.xig_len = sizeof xig; 1122032677ceSGleb Smirnoff xig.xig_count = V_ripcbinfo.ipi_count; 1123032677ceSGleb Smirnoff xig.xig_gen = V_ripcbinfo.ipi_gencnt; 112498271db4SGarrett Wollman xig.xig_sogen = so_gencnt; 112598271db4SGarrett Wollman error = SYSCTL_OUT(req, &xig, sizeof xig); 112698271db4SGarrett Wollman if (error) 11270ae76120SRobert Watson return (error); 112898271db4SGarrett Wollman 1129032677ceSGleb Smirnoff NET_EPOCH_ENTER(et); 1130032677ceSGleb Smirnoff for (inp = CK_LIST_FIRST(V_ripcbinfo.ipi_listhead); 1131032677ceSGleb Smirnoff inp != NULL; 1132b872626dSMatt Macy inp = CK_LIST_NEXT(inp, inp_list)) { 11339ad11dd8SRobert Watson INP_RLOCK(inp); 1134032677ceSGleb Smirnoff if (inp->inp_gencnt <= xig.xig_gen && 1135032677ceSGleb Smirnoff cr_canseeinpcb(req->td->td_ucred, inp) == 0) { 113698271db4SGarrett Wollman struct xinpcb xi; 11373bb87a6cSKip Macy 1138cc65eb4eSGleb Smirnoff in_pcbtoxinpcb(inp, &xi); 11399ad11dd8SRobert Watson INP_RUNLOCK(inp); 114098271db4SGarrett Wollman error = SYSCTL_OUT(req, &xi, sizeof xi); 1141032677ceSGleb Smirnoff if (error) 1142032677ceSGleb Smirnoff break; 1143d915b280SStephan Uphoff } else 11449ad11dd8SRobert Watson INP_RUNLOCK(inp); 114598271db4SGarrett Wollman } 1146032677ceSGleb Smirnoff NET_EPOCH_EXIT(et); 1147d0e157f6SBjoern A. Zeeb 114898271db4SGarrett Wollman if (!error) { 114998271db4SGarrett Wollman /* 11500ae76120SRobert Watson * Give the user an updated idea of our state. If the 11510ae76120SRobert Watson * generation differs from what we told her before, she knows 11520ae76120SRobert Watson * that something happened while we were processing this 11530ae76120SRobert Watson * request, and it might be necessary to retry. 115498271db4SGarrett Wollman */ 1155603724d3SBjoern A. Zeeb xig.xig_gen = V_ripcbinfo.ipi_gencnt; 115698271db4SGarrett Wollman xig.xig_sogen = so_gencnt; 1157603724d3SBjoern A. Zeeb xig.xig_count = V_ripcbinfo.ipi_count; 115898271db4SGarrett Wollman error = SYSCTL_OUT(req, &xig, sizeof xig); 115998271db4SGarrett Wollman } 1160032677ceSGleb Smirnoff 11610ae76120SRobert Watson return (error); 116298271db4SGarrett Wollman } 116398271db4SGarrett Wollman 116479c3d51bSMatthew D Fleming SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, 11657029da5cSPawel Biernacki CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 11667029da5cSPawel Biernacki rip_pcblist, "S,xinpcb", 11677029da5cSPawel Biernacki "List of active raw IP sockets"); 116898271db4SGarrett Wollman 116900c081e9SBjoern A. Zeeb #ifdef INET 1170117bcae7SGarrett Wollman struct pr_usrreqs rip_usrreqs = { 1171756d52a1SPoul-Henning Kamp .pru_abort = rip_abort, 1172756d52a1SPoul-Henning Kamp .pru_attach = rip_attach, 1173756d52a1SPoul-Henning Kamp .pru_bind = rip_bind, 1174756d52a1SPoul-Henning Kamp .pru_connect = rip_connect, 1175756d52a1SPoul-Henning Kamp .pru_control = in_control, 1176756d52a1SPoul-Henning Kamp .pru_detach = rip_detach, 1177756d52a1SPoul-Henning Kamp .pru_disconnect = rip_disconnect, 117854d642bbSRobert Watson .pru_peeraddr = in_getpeeraddr, 1179756d52a1SPoul-Henning Kamp .pru_send = rip_send, 1180756d52a1SPoul-Henning Kamp .pru_shutdown = rip_shutdown, 118154d642bbSRobert Watson .pru_sockaddr = in_getsockaddr, 1182a152f8a3SRobert Watson .pru_sosetlabel = in_pcbsosetlabel, 1183a152f8a3SRobert Watson .pru_close = rip_close, 1184117bcae7SGarrett Wollman }; 118500c081e9SBjoern A. Zeeb #endif /* INET */ 1186