xref: /freebsd/sys/netinet/raw_ip.c (revision 81728a538d24f483d0986850fa3f51d5d84d8f26)
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