xref: /freebsd/sys/netinet/raw_ip.c (revision ce69e37369aa44a96113387253aadc5e49246928)
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  */
32df8bae1dSRodney W. Grimes 
334b421e2dSMike Silbersack #include <sys/cdefs.h>
3400c081e9SBjoern A. Zeeb #include "opt_inet.h"
356a800098SYoshinobu Inoue #include "opt_inet6.h"
366a800098SYoshinobu Inoue #include "opt_ipsec.h"
370c325f53SAlexander V. Chernikov #include "opt_route.h"
386a800098SYoshinobu Inoue 
39df8bae1dSRodney W. Grimes #include <sys/param.h>
405a59cefcSBosko Milekic #include <sys/jail.h>
41117bcae7SGarrett Wollman #include <sys/kernel.h>
42ea8d1492SAlexander V. Chernikov #include <sys/eventhandler.h>
43960ed29cSSeigo Tanimura #include <sys/lock.h>
44df8bae1dSRodney W. Grimes #include <sys/malloc.h>
45df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
46acd3428bSRobert Watson #include <sys/priv.h>
474787fd37SPaul Saab #include <sys/proc.h>
48df8bae1dSRodney W. Grimes #include <sys/protosw.h>
49385195c0SMarko Zec #include <sys/rwlock.h>
50960ed29cSSeigo Tanimura #include <sys/signalvar.h>
51117bcae7SGarrett Wollman #include <sys/socket.h>
52df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
53960ed29cSSeigo Tanimura #include <sys/sx.h>
54117bcae7SGarrett Wollman #include <sys/sysctl.h>
55960ed29cSSeigo Tanimura #include <sys/systm.h>
568781d8e9SBruce Evans 
5769c2d429SJeff Roberson #include <vm/uma.h>
58df8bae1dSRodney W. Grimes 
59df8bae1dSRodney W. Grimes #include <net/if.h>
6076039bc8SGleb Smirnoff #include <net/if_var.h>
61df8bae1dSRodney W. Grimes #include <net/route.h>
6281728a53SAlexander V. Chernikov #include <net/route/route_ctl.h>
634b79449eSBjoern A. Zeeb #include <net/vnet.h>
64df8bae1dSRodney W. Grimes 
65df8bae1dSRodney W. Grimes #include <netinet/in.h>
66df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
670c325f53SAlexander V. Chernikov #include <netinet/in_fib.h>
68c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h>
69c1f8a6ceSDavid Greenman #include <netinet/in_var.h>
705b84dc78SQing Li #include <netinet/if_ether.h>
71960ed29cSSeigo Tanimura #include <netinet/ip.h>
72df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
73df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h>
746d7270a5SMichael Tuexen #include <netinet/ip_icmp.h>
75df8bae1dSRodney W. Grimes 
76fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h>
77b9234fafSSam Leffler 
7873d76e77SKevin Lo #include <machine/stdarg.h>
79aed55708SRobert Watson #include <security/mac/mac_framework.h>
80aed55708SRobert Watson 
8178b1fc05SGleb Smirnoff extern ipproto_input_t *ip_protox[];
8278b1fc05SGleb Smirnoff 
8374e9dcf7SBjoern A. Zeeb VNET_DEFINE(int, ip_defttl) = IPDEFTTL;
846df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_VNET | CTLFLAG_RW,
8574e9dcf7SBjoern A. Zeeb     &VNET_NAME(ip_defttl), 0,
8674e9dcf7SBjoern A. Zeeb     "Maximum TTL on IP packets");
8774e9dcf7SBjoern A. Zeeb 
88eddfbb76SRobert Watson VNET_DEFINE(struct inpcbinfo, ripcbinfo);
891e77c105SRobert Watson #define	V_ripcbinfo		VNET(ripcbinfo)
90df8bae1dSRodney W. Grimes 
91115a40c7SLuigi Rizzo /*
92b2019e17SLuigi Rizzo  * Control and data hooks for ipfw, dummynet, divert and so on.
93115a40c7SLuigi Rizzo  * The data hooks are not used here but it is convenient
94115a40c7SLuigi Rizzo  * to keep them all in one place.
95115a40c7SLuigi Rizzo  */
960b4b0b0fSJulian Elischer VNET_DEFINE(ip_fw_ctl_ptr_t, ip_fw_ctl_ptr) = NULL;
97b2019e17SLuigi Rizzo 
98b2019e17SLuigi Rizzo int	(*ip_dn_ctl_ptr)(struct sockopt *);
99dc0fa4f7SGleb Smirnoff int	(*ip_dn_io_ptr)(struct mbuf **, struct ip_fw_args *);
1001830dae3SGleb Smirnoff void	(*ip_divert_ptr)(struct mbuf *, bool);
101cef9f220SGleb Smirnoff int	(*ng_ipfw_input_p)(struct mbuf **, struct ip_fw_args *, bool);
102db69a05dSPaul Saab 
10300c081e9SBjoern A. Zeeb #ifdef INET
104df8bae1dSRodney W. Grimes /*
1050ae76120SRobert Watson  * Hooks for multicast routing. They all default to NULL, so leave them not
1060ae76120SRobert Watson  * initialized and rely on BSS being set to 0.
107bbb4330bSLuigi Rizzo  */
108bbb4330bSLuigi Rizzo 
1090ae76120SRobert Watson /*
1100ae76120SRobert Watson  * The socket used to communicate with the multicast routing daemon.
1110ae76120SRobert Watson  */
112eddfbb76SRobert Watson VNET_DEFINE(struct socket *, ip_mrouter);
113bbb4330bSLuigi Rizzo 
1140ae76120SRobert Watson /*
1150ae76120SRobert Watson  * The various mrouter and rsvp functions.
1160ae76120SRobert Watson  */
117bbb4330bSLuigi Rizzo int (*ip_mrouter_set)(struct socket *, struct sockopt *);
118bbb4330bSLuigi Rizzo int (*ip_mrouter_get)(struct socket *, struct sockopt *);
11977223d98SWojciech Macek int (*ip_mrouter_done)(void);
120bbb4330bSLuigi Rizzo int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
121bbb4330bSLuigi Rizzo 		   struct ip_moptions *);
122e40bae9aSRoman Divacky int (*mrt_ioctl)(u_long, caddr_t, int);
123bbb4330bSLuigi Rizzo int (*legal_vif_num)(int);
124bbb4330bSLuigi Rizzo u_long (*ip_mcast_src)(int);
125bbb4330bSLuigi Rizzo 
1268f5a8818SKevin Lo int (*rsvp_input_p)(struct mbuf **, int *, int);
127bbb4330bSLuigi Rizzo int (*ip_rsvp_vif)(struct socket *, struct sockopt *);
128bbb4330bSLuigi Rizzo void (*ip_rsvp_force_done)(struct socket *);
12900c081e9SBjoern A. Zeeb #endif /* INET */
13000c081e9SBjoern A. Zeeb 
13100c081e9SBjoern A. Zeeb u_long	rip_sendspace = 9216;
13200c081e9SBjoern A. Zeeb SYSCTL_ULONG(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
13300c081e9SBjoern A. Zeeb     &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
13400c081e9SBjoern A. Zeeb 
13500c081e9SBjoern A. Zeeb u_long	rip_recvspace = 9216;
13600c081e9SBjoern A. Zeeb SYSCTL_ULONG(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
13700c081e9SBjoern A. Zeeb     &rip_recvspace, 0, "Maximum space for incoming raw IP datagrams");
138bbb4330bSLuigi Rizzo 
139bbb4330bSLuigi Rizzo /*
1409ed324c9SAlexander Motin  * Hash functions
1419ed324c9SAlexander Motin  */
1429ed324c9SAlexander Motin 
1439ed324c9SAlexander Motin #define INP_PCBHASH_RAW_SIZE	256
1449ed324c9SAlexander Motin #define INP_PCBHASH_RAW(proto, laddr, faddr, mask) \
1459ed324c9SAlexander Motin         (((proto) + (laddr) + (faddr)) % (mask) + 1)
1469ed324c9SAlexander Motin 
14700c081e9SBjoern A. Zeeb #ifdef INET
1489ed324c9SAlexander Motin static void
rip_inshash(struct inpcb * inp)1499ed324c9SAlexander Motin rip_inshash(struct inpcb *inp)
1509ed324c9SAlexander Motin {
1519ed324c9SAlexander Motin 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
1529ed324c9SAlexander Motin 	struct inpcbhead *pcbhash;
1539ed324c9SAlexander Motin 	int hash;
1549ed324c9SAlexander Motin 
155db0ac6deSCy Schubert 	INP_HASH_WLOCK_ASSERT(pcbinfo);
1569ed324c9SAlexander Motin 	INP_WLOCK_ASSERT(inp);
1579ed324c9SAlexander Motin 
15818f401c6SAlexander Motin 	if (inp->inp_ip_p != 0 &&
15918f401c6SAlexander Motin 	    inp->inp_laddr.s_addr != INADDR_ANY &&
16018f401c6SAlexander Motin 	    inp->inp_faddr.s_addr != INADDR_ANY) {
1619ed324c9SAlexander Motin 		hash = INP_PCBHASH_RAW(inp->inp_ip_p, inp->inp_laddr.s_addr,
1629ed324c9SAlexander Motin 		    inp->inp_faddr.s_addr, pcbinfo->ipi_hashmask);
16318f401c6SAlexander Motin 	} else
1649ed324c9SAlexander Motin 		hash = 0;
165fdb987beSMark Johnston 	pcbhash = &pcbinfo->ipi_hash_exact[hash];
166fdb987beSMark Johnston 	CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash_exact);
1679ed324c9SAlexander Motin }
1689ed324c9SAlexander Motin 
1699ed324c9SAlexander Motin static void
rip_delhash(struct inpcb * inp)1709ed324c9SAlexander Motin rip_delhash(struct inpcb *inp)
1719ed324c9SAlexander Motin {
17218f401c6SAlexander Motin 
173db0ac6deSCy Schubert 	INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
1749ed324c9SAlexander Motin 	INP_WLOCK_ASSERT(inp);
17518f401c6SAlexander Motin 
176fdb987beSMark Johnston 	CK_LIST_REMOVE(inp, inp_hash_exact);
1779ed324c9SAlexander Motin }
17800c081e9SBjoern A. Zeeb #endif /* INET */
1799ed324c9SAlexander Motin 
1800aa120d5SGleb Smirnoff INPCBSTORAGE_DEFINE(ripcbstor, inpcb, "rawinp", "ripcb", "rip", "riphash");
181d915b280SStephan Uphoff 
18289128ff3SGleb Smirnoff static void
rip_init(void * arg __unused)18389128ff3SGleb Smirnoff rip_init(void *arg __unused)
184df8bae1dSRodney W. Grimes {
185f2565d68SRobert Watson 
186fec8a8c7SGleb Smirnoff 	in_pcbinfo_init(&V_ripcbinfo, &ripcbstor, INP_PCBHASH_RAW_SIZE, 1);
187df8bae1dSRodney W. Grimes }
18889128ff3SGleb Smirnoff VNET_SYSINIT(rip_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, rip_init, NULL);
189df8bae1dSRodney W. Grimes 
190bc29160dSMarko Zec #ifdef VIMAGE
1913f58662dSBjoern A. Zeeb static void
rip_destroy(void * unused __unused)1923f58662dSBjoern A. Zeeb rip_destroy(void *unused __unused)
193bc29160dSMarko Zec {
194bc29160dSMarko Zec 
1959bcd427bSRobert Watson 	in_pcbinfo_destroy(&V_ripcbinfo);
196bc29160dSMarko Zec }
1973f58662dSBjoern A. Zeeb VNET_SYSUNINIT(raw_ip, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, rip_destroy, NULL);
198bc29160dSMarko Zec #endif
199bc29160dSMarko Zec 
20000c081e9SBjoern A. Zeeb #ifdef INET
2013b6dd5a9SSam Leffler static int
rip_append(struct inpcb * inp,struct ip * ip,struct mbuf * m,struct sockaddr_in * ripsrc)202db0ac6deSCy Schubert rip_append(struct inpcb *inp, struct ip *ip, struct mbuf *m,
2033b19fa35SRobert Watson     struct sockaddr_in *ripsrc)
2043b6dd5a9SSam Leffler {
205db0ac6deSCy Schubert 	struct socket *so = inp->inp_socket;
206db0ac6deSCy Schubert 	struct mbuf *n, *opts = NULL;
20733841545SHajimu UMEMOTO 
208db0ac6deSCy Schubert 	INP_LOCK_ASSERT(inp);
209cbe42d48SRobert Watson 
210fcf59617SAndrey V. Elsukov #if defined(IPSEC) || defined(IPSEC_SUPPORT)
211da0f4099SHajimu UMEMOTO 	/* check AH/ESP integrity. */
212db0ac6deSCy Schubert 	if (IPSEC_ENABLED(ipv4) && IPSEC_CHECK_POLICY(ipv4, m, inp) != 0)
213db0ac6deSCy Schubert 		return (0);
214b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */
2154ea889c6SRobert Watson #ifdef MAC
216db0ac6deSCy Schubert 	if (mac_inpcb_check_deliver(inp, m) != 0)
217db0ac6deSCy Schubert 		return (0);
2184ea889c6SRobert Watson #endif
219936cd18dSAndre Oppermann 	/* Check the minimum TTL for socket. */
220db0ac6deSCy Schubert 	if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl)
221db0ac6deSCy Schubert 		return (0);
2223b6dd5a9SSam Leffler 
223db0ac6deSCy Schubert 	if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL)
224db0ac6deSCy Schubert 		return (0);
225db0ac6deSCy Schubert 
226db0ac6deSCy Schubert 	if ((inp->inp_flags & INP_CONTROLOPTS) ||
2271fd7af26SAndre Oppermann 	    (so->so_options & (SO_TIMESTAMP | SO_BINTIME)))
228db0ac6deSCy Schubert 		ip_savecontrol(inp, &opts, ip, n);
2291e4d7da7SRobert Watson 	SOCKBUF_LOCK(&so->so_rcv);
2301e4d7da7SRobert Watson 	if (sbappendaddr_locked(&so->so_rcv,
2313b19fa35SRobert Watson 	    (struct sockaddr *)ripsrc, n, opts) == 0) {
2327045b160SRoy Marples 		soroverflow_locked(so);
233df8bae1dSRodney W. Grimes 		m_freem(n);
23482c23ebaSBill Fenner 		if (opts)
23582c23ebaSBill Fenner 			m_freem(opts);
236db0ac6deSCy Schubert 		return (0);
237db0ac6deSCy Schubert 	}
2381e4d7da7SRobert Watson 	sorwakeup_locked(so);
239db0ac6deSCy Schubert 
240db0ac6deSCy Schubert 	return (1);
241db0ac6deSCy Schubert }
242db0ac6deSCy Schubert 
243db0ac6deSCy Schubert struct rip_inp_match_ctx {
244db0ac6deSCy Schubert 	struct ip *ip;
245db0ac6deSCy Schubert 	int proto;
246db0ac6deSCy Schubert };
247db0ac6deSCy Schubert 
248db0ac6deSCy Schubert static bool
rip_inp_match1(const struct inpcb * inp,void * v)249db0ac6deSCy Schubert rip_inp_match1(const struct inpcb *inp, void *v)
250db0ac6deSCy Schubert {
251db0ac6deSCy Schubert 	struct rip_inp_match_ctx *ctx = v;
252db0ac6deSCy Schubert 
253db0ac6deSCy Schubert 	if (inp->inp_ip_p != ctx->proto)
254db0ac6deSCy Schubert 		return (false);
255db0ac6deSCy Schubert #ifdef INET6
256db0ac6deSCy Schubert 	/* XXX inp locking */
257db0ac6deSCy Schubert 	if ((inp->inp_vflag & INP_IPV4) == 0)
258db0ac6deSCy Schubert 		return (false);
259db0ac6deSCy Schubert #endif
260db0ac6deSCy Schubert 	if (inp->inp_laddr.s_addr != ctx->ip->ip_dst.s_addr)
261db0ac6deSCy Schubert 		return (false);
262db0ac6deSCy Schubert 	if (inp->inp_faddr.s_addr != ctx->ip->ip_src.s_addr)
263db0ac6deSCy Schubert 		return (false);
264db0ac6deSCy Schubert 	return (true);
265db0ac6deSCy Schubert }
266db0ac6deSCy Schubert 
267db0ac6deSCy Schubert static bool
rip_inp_match2(const struct inpcb * inp,void * v)268db0ac6deSCy Schubert rip_inp_match2(const struct inpcb *inp, void *v)
269db0ac6deSCy Schubert {
270db0ac6deSCy Schubert 	struct rip_inp_match_ctx *ctx = v;
271db0ac6deSCy Schubert 
272db0ac6deSCy Schubert 	if (inp->inp_ip_p && inp->inp_ip_p != ctx->proto)
273db0ac6deSCy Schubert 		return (false);
274db0ac6deSCy Schubert #ifdef INET6
275db0ac6deSCy Schubert 	/* XXX inp locking */
276db0ac6deSCy Schubert 	if ((inp->inp_vflag & INP_IPV4) == 0)
277db0ac6deSCy Schubert 		return (false);
278db0ac6deSCy Schubert #endif
279db0ac6deSCy Schubert 	if (!in_nullhost(inp->inp_laddr) &&
280db0ac6deSCy Schubert 	    !in_hosteq(inp->inp_laddr, ctx->ip->ip_dst))
281db0ac6deSCy Schubert 		return (false);
282db0ac6deSCy Schubert 	if (!in_nullhost(inp->inp_faddr) &&
283db0ac6deSCy Schubert 	    !in_hosteq(inp->inp_faddr, ctx->ip->ip_src))
284db0ac6deSCy Schubert 		return (false);
285db0ac6deSCy Schubert 	return (true);
286df8bae1dSRodney W. Grimes }
2873b6dd5a9SSam Leffler 
2883b6dd5a9SSam Leffler /*
2890ae76120SRobert Watson  * Setup generic address and protocol structures for raw_input routine, then
2900ae76120SRobert Watson  * pass them along with mbuf chain.
2913b6dd5a9SSam Leffler  */
2928f5a8818SKevin Lo int
rip_input(struct mbuf ** mp,int * offp,int proto)2938f5a8818SKevin Lo rip_input(struct mbuf **mp, int *offp, int proto)
2943b6dd5a9SSam Leffler {
295db0ac6deSCy Schubert 	struct rip_inp_match_ctx ctx = {
296db0ac6deSCy Schubert 		.ip = mtod(*mp, struct ip *),
297db0ac6deSCy Schubert 		.proto = proto,
298db0ac6deSCy Schubert 	};
299db0ac6deSCy Schubert 	struct inpcb_iterator inpi = INP_ITERATOR(&V_ripcbinfo,
300db0ac6deSCy Schubert 	    INPLOOKUP_RLOCKPCB, rip_inp_match1, &ctx);
301d10910e6SBruce M Simpson 	struct ifnet *ifp;
3028f5a8818SKevin Lo 	struct mbuf *m = *mp;
303db0ac6deSCy Schubert 	struct inpcb *inp;
3043b19fa35SRobert Watson 	struct sockaddr_in ripsrc;
305db0ac6deSCy Schubert 	int appended;
306f42347c3SGleb Smirnoff 
3078f5a8818SKevin Lo 	*mp = NULL;
308db0ac6deSCy Schubert 	appended = 0;
3098f5a8818SKevin Lo 
3103b19fa35SRobert Watson 	bzero(&ripsrc, sizeof(ripsrc));
3113b19fa35SRobert Watson 	ripsrc.sin_len = sizeof(ripsrc);
3123b19fa35SRobert Watson 	ripsrc.sin_family = AF_INET;
313db0ac6deSCy Schubert 	ripsrc.sin_addr = ctx.ip->ip_src;
314d10910e6SBruce M Simpson 
315d10910e6SBruce M Simpson 	ifp = m->m_pkthdr.rcvif;
316d10910e6SBruce M Simpson 
317db0ac6deSCy Schubert 	inpi.hash = INP_PCBHASH_RAW(proto, ctx.ip->ip_src.s_addr,
318db0ac6deSCy Schubert 	    ctx.ip->ip_dst.s_addr, V_ripcbinfo.ipi_hashmask);
319db0ac6deSCy Schubert 	while ((inp = inp_next(&inpi)) != NULL) {
320db0ac6deSCy Schubert 		INP_RLOCK_ASSERT(inp);
321db0ac6deSCy Schubert 		if (jailed_without_vnet(inp->inp_cred) &&
322db0ac6deSCy Schubert 		    prison_check_ip4(inp->inp_cred, &ctx.ip->ip_dst) != 0) {
323e93fdbe2SMatt Macy 			/*
324e93fdbe2SMatt Macy 			 * XXX: If faddr was bound to multicast group,
325e93fdbe2SMatt Macy 			 * jailed raw socket will drop datagram.
326e93fdbe2SMatt Macy 			 */
327db0ac6deSCy Schubert 			continue;
328266f97b5SCy Schubert 		}
329db0ac6deSCy Schubert 		appended += rip_append(inp, ctx.ip, m, &ripsrc);
330e5c331cfSMatt Macy 	}
331e93fdbe2SMatt Macy 
332db0ac6deSCy Schubert 	inpi.hash = 0;
333db0ac6deSCy Schubert 	inpi.match = rip_inp_match2;
334db0ac6deSCy Schubert 	MPASS(inpi.inp == NULL);
335db0ac6deSCy Schubert 	while ((inp = inp_next(&inpi)) != NULL) {
336db0ac6deSCy Schubert 		INP_RLOCK_ASSERT(inp);
337db0ac6deSCy Schubert 		if (jailed_without_vnet(inp->inp_cred) &&
338db0ac6deSCy Schubert 		    !IN_MULTICAST(ntohl(ctx.ip->ip_dst.s_addr)) &&
339db0ac6deSCy Schubert 		    prison_check_ip4(inp->inp_cred, &ctx.ip->ip_dst) != 0)
340d10910e6SBruce M Simpson 			/*
341d10910e6SBruce M Simpson 			 * Allow raw socket in jail to receive multicast;
342d10910e6SBruce M Simpson 			 * assume process had PRIV_NETINET_RAW at attach,
343d10910e6SBruce M Simpson 			 * and fall through into normal filter path if so.
344d10910e6SBruce M Simpson 			 */
345db0ac6deSCy Schubert 			continue;
346d10910e6SBruce M Simpson 		/*
347d10910e6SBruce M Simpson 		 * If this raw socket has multicast state, and we
348d10910e6SBruce M Simpson 		 * have received a multicast, check if this socket
349d10910e6SBruce M Simpson 		 * should receive it, as multicast filtering is now
350d10910e6SBruce M Simpson 		 * the responsibility of the transport layer.
351d10910e6SBruce M Simpson 		 */
352d10910e6SBruce M Simpson 		if (inp->inp_moptions != NULL &&
353db0ac6deSCy Schubert 		    IN_MULTICAST(ntohl(ctx.ip->ip_dst.s_addr))) {
354793c7042SBruce M Simpson 			/*
355793c7042SBruce M Simpson 			 * If the incoming datagram is for IGMP, allow it
356793c7042SBruce M Simpson 			 * through unconditionally to the raw socket.
357793c7042SBruce M Simpson 			 *
358793c7042SBruce M Simpson 			 * In the case of IGMPv2, we may not have explicitly
359793c7042SBruce M Simpson 			 * joined the group, and may have set IFF_ALLMULTI
360793c7042SBruce M Simpson 			 * on the interface. imo_multi_filter() may discard
361793c7042SBruce M Simpson 			 * control traffic we actually need to see.
362793c7042SBruce M Simpson 			 *
363793c7042SBruce M Simpson 			 * Userland multicast routing daemons should continue
364793c7042SBruce M Simpson 			 * filter the control traffic appropriately.
365793c7042SBruce M Simpson 			 */
366d10910e6SBruce M Simpson 			int blocked;
367d10910e6SBruce M Simpson 
368793c7042SBruce M Simpson 			blocked = MCAST_PASS;
369793c7042SBruce M Simpson 			if (proto != IPPROTO_IGMP) {
370793c7042SBruce M Simpson 				struct sockaddr_in group;
371793c7042SBruce M Simpson 
372d10910e6SBruce M Simpson 				bzero(&group, sizeof(struct sockaddr_in));
373d10910e6SBruce M Simpson 				group.sin_len = sizeof(struct sockaddr_in);
374d10910e6SBruce M Simpson 				group.sin_family = AF_INET;
375db0ac6deSCy Schubert 				group.sin_addr = ctx.ip->ip_dst;
376d10910e6SBruce M Simpson 
377793c7042SBruce M Simpson 				blocked = imo_multi_filter(inp->inp_moptions,
378793c7042SBruce M Simpson 				    ifp,
379d10910e6SBruce M Simpson 				    (struct sockaddr *)&group,
380d10910e6SBruce M Simpson 				    (struct sockaddr *)&ripsrc);
381793c7042SBruce M Simpson 			}
382793c7042SBruce M Simpson 
383d10910e6SBruce M Simpson 			if (blocked != MCAST_PASS) {
38486425c62SRobert Watson 				IPSTAT_INC(ips_notmember);
385e93fdbe2SMatt Macy 				continue;
386df8bae1dSRodney W. Grimes 			}
387db0ac6deSCy Schubert 		}
388db0ac6deSCy Schubert 		appended += rip_append(inp, ctx.ip, m, &ripsrc);
389db0ac6deSCy Schubert 	}
39078b1fc05SGleb Smirnoff 	if (appended == 0 && ip_protox[ctx.ip->ip_p] == rip_input) {
39186425c62SRobert Watson 		IPSTAT_INC(ips_noproto);
39286425c62SRobert Watson 		IPSTAT_DEC(ips_delivered);
3936d7270a5SMichael Tuexen 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0);
394db0ac6deSCy Schubert 	} else
395ad2cbb09SMichael Tuexen 		m_freem(m);
3968f5a8818SKevin Lo 	return (IPPROTO_DONE);
397df8bae1dSRodney W. Grimes }
398df8bae1dSRodney W. Grimes 
399df8bae1dSRodney W. Grimes /*
4000ae76120SRobert Watson  * Generate IP header and pass packet to ip_output.  Tack on options user may
4010ae76120SRobert Watson  * have setup with control call.
402df8bae1dSRodney W. Grimes  */
4033d2041c0SGleb Smirnoff static int
rip_send(struct socket * so,int pruflags,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct thread * td)4043d2041c0SGleb Smirnoff rip_send(struct socket *so, int pruflags, struct mbuf *m, struct sockaddr *nam,
4053d2041c0SGleb Smirnoff     struct mbuf *control, struct thread *td)
406df8bae1dSRodney W. Grimes {
407b9555453SGleb Smirnoff 	struct epoch_tracker et;
4083b6dd5a9SSam Leffler 	struct ip *ip;
4093d2041c0SGleb Smirnoff 	struct inpcb *inp;
4103d2041c0SGleb Smirnoff 	in_addr_t *dst;
4113d2041c0SGleb Smirnoff 	int error, flags, cnt, hlen;
412aef06417SMichael Tuexen 	u_char opttype, optlen, *cp;
413df8bae1dSRodney W. Grimes 
4143d2041c0SGleb Smirnoff 	inp = sotoinpcb(so);
4153d2041c0SGleb Smirnoff 	KASSERT(inp != NULL, ("rip_send: inp == NULL"));
4163d2041c0SGleb Smirnoff 
4173d2041c0SGleb Smirnoff 	if (control != NULL) {
4183d2041c0SGleb Smirnoff 		m_freem(control);
4193d2041c0SGleb Smirnoff 		control = NULL;
4203d2041c0SGleb Smirnoff 	}
4213d2041c0SGleb Smirnoff 
4223d2041c0SGleb Smirnoff 	if (so->so_state & SS_ISCONNECTED) {
4233d2041c0SGleb Smirnoff 		if (nam) {
4243d2041c0SGleb Smirnoff 			error = EISCONN;
4253d2041c0SGleb Smirnoff 			m_freem(m);
4263d2041c0SGleb Smirnoff 			return (error);
4273d2041c0SGleb Smirnoff 		}
4283d2041c0SGleb Smirnoff 		dst = &inp->inp_faddr.s_addr;
4293d2041c0SGleb Smirnoff 	} else {
4303d2041c0SGleb Smirnoff 		if (nam == NULL)
4313d2041c0SGleb Smirnoff 			error = ENOTCONN;
4323d2041c0SGleb Smirnoff 		else if (nam->sa_family != AF_INET)
4333d2041c0SGleb Smirnoff 			error = EAFNOSUPPORT;
4343d2041c0SGleb Smirnoff 		else if (nam->sa_len != sizeof(struct sockaddr_in))
4353d2041c0SGleb Smirnoff 			error = EINVAL;
4363d2041c0SGleb Smirnoff 		else
4373d2041c0SGleb Smirnoff 			error = 0;
4383d2041c0SGleb Smirnoff 		if (error != 0) {
4393d2041c0SGleb Smirnoff 			m_freem(m);
4403d2041c0SGleb Smirnoff 			return (error);
4413d2041c0SGleb Smirnoff 		}
4423d2041c0SGleb Smirnoff 		dst = &((struct sockaddr_in *)nam)->sin_addr.s_addr;
4433d2041c0SGleb Smirnoff 	}
4443d2041c0SGleb Smirnoff 
4453d2041c0SGleb Smirnoff 	flags = ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) |
4463d2041c0SGleb Smirnoff 	    IP_ALLOWBROADCAST;
44773d76e77SKevin Lo 
448df8bae1dSRodney W. Grimes 	/*
4490ae76120SRobert Watson 	 * If the user handed us a complete IP packet, use it.  Otherwise,
4500ae76120SRobert Watson 	 * allocate an mbuf for a header and fill it in.
451df8bae1dSRodney W. Grimes 	 */
452df8bae1dSRodney W. Grimes 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
453430d30d8SBill Fenner 		if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
454430d30d8SBill Fenner 			m_freem(m);
455430d30d8SBill Fenner 			return(EMSGSIZE);
456430d30d8SBill Fenner 		}
457eb1b1807SGleb Smirnoff 		M_PREPEND(m, sizeof(struct ip), M_NOWAIT);
4586b48911bSRobert Watson 		if (m == NULL)
4596b48911bSRobert Watson 			return(ENOBUFS);
460ac830b58SBosko Milekic 
4619ad11dd8SRobert Watson 		INP_RLOCK(inp);
462df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
4638ce3f3ddSRuslan Ermilov 		ip->ip_tos = inp->inp_ip_tos;
464b2828ad2SAndre Oppermann 		if (inp->inp_flags & INP_DONTFRAG)
4658f134647SGleb Smirnoff 			ip->ip_off = htons(IP_DF);
466b2828ad2SAndre Oppermann 		else
4678f134647SGleb Smirnoff 			ip->ip_off = htons(0);
468ca98b82cSDavid Greenman 		ip->ip_p = inp->inp_ip_p;
4698f134647SGleb Smirnoff 		ip->ip_len = htons(m->m_pkthdr.len);
470b89e82ddSJamie Gritton 		ip->ip_src = inp->inp_laddr;
4713d2041c0SGleb Smirnoff 		ip->ip_dst.s_addr = *dst;
4720c325f53SAlexander V. Chernikov #ifdef ROUTE_MPATH
4730c325f53SAlexander V. Chernikov 		if (CALC_FLOWID_OUTBOUND) {
4740c325f53SAlexander V. Chernikov 			uint32_t hash_type, hash_val;
4750c325f53SAlexander V. Chernikov 
4760c325f53SAlexander V. Chernikov 			hash_val = fib4_calc_software_hash(ip->ip_src,
4770c325f53SAlexander V. Chernikov 			    ip->ip_dst, 0, 0, ip->ip_p, &hash_type);
4780c325f53SAlexander V. Chernikov 			m->m_pkthdr.flowid = hash_val;
4790c325f53SAlexander V. Chernikov 			M_HASHTYPE_SET(m, hash_type);
4800c325f53SAlexander V. Chernikov 			flags |= IP_NODEFAULTFLOWID;
4810c325f53SAlexander V. Chernikov 		}
4820c325f53SAlexander V. Chernikov #endif
4837a657e63SBjoern A. Zeeb 		if (jailed(inp->inp_cred)) {
4847a657e63SBjoern A. Zeeb 			/*
4857a657e63SBjoern A. Zeeb 			 * prison_local_ip4() would be good enough but would
4867a657e63SBjoern A. Zeeb 			 * let a source of INADDR_ANY pass, which we do not
487ae190832SSteven Hartland 			 * want to see from jails.
4887a657e63SBjoern A. Zeeb 			 */
489ae190832SSteven Hartland 			if (ip->ip_src.s_addr == INADDR_ANY) {
490c1604fe4SGleb Smirnoff 				NET_EPOCH_ENTER(et);
491c1604fe4SGleb Smirnoff 				error = in_pcbladdr(inp, &ip->ip_dst,
492c1604fe4SGleb Smirnoff 				    &ip->ip_src, inp->inp_cred);
493c1604fe4SGleb Smirnoff 				NET_EPOCH_EXIT(et);
494ae190832SSteven Hartland 			} else {
4957a657e63SBjoern A. Zeeb 				error = prison_local_ip4(inp->inp_cred,
4967a657e63SBjoern A. Zeeb 				    &ip->ip_src);
497ae190832SSteven Hartland 			}
498b89e82ddSJamie Gritton 			if (error != 0) {
499413628a7SBjoern A. Zeeb 				INP_RUNLOCK(inp);
500413628a7SBjoern A. Zeeb 				m_freem(m);
501b89e82ddSJamie Gritton 				return (error);
502413628a7SBjoern A. Zeeb 			}
5037a657e63SBjoern A. Zeeb 		}
5048ce3f3ddSRuslan Ermilov 		ip->ip_ttl = inp->inp_ip_ttl;
505df8bae1dSRodney W. Grimes 	} else {
506430d30d8SBill Fenner 		if (m->m_pkthdr.len > IP_MAXPACKET) {
507430d30d8SBill Fenner 			m_freem(m);
508430d30d8SBill Fenner 			return (EMSGSIZE);
509430d30d8SBill Fenner 		}
510ba218252SMark Johnston 		if (m->m_pkthdr.len < sizeof(*ip)) {
511ba218252SMark Johnston 			m_freem(m);
512ba218252SMark Johnston 			return (EINVAL);
513ba218252SMark Johnston 		}
514ba218252SMark Johnston 		m = m_pullup(m, sizeof(*ip));
515ba218252SMark Johnston 		if (m == NULL)
516ba218252SMark Johnston 			return (ENOMEM);
517df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
51820a6a3a7SMichael Tuexen 		hlen = ip->ip_hl << 2;
51920a6a3a7SMichael Tuexen 		if (m->m_len < hlen) {
52020a6a3a7SMichael Tuexen 			m = m_pullup(m, hlen);
52120a6a3a7SMichael Tuexen 			if (m == NULL)
52220a6a3a7SMichael Tuexen 				return (EINVAL);
52320a6a3a7SMichael Tuexen 			ip = mtod(m, struct ip *);
52420a6a3a7SMichael Tuexen 		}
5250c325f53SAlexander V. Chernikov #ifdef ROUTE_MPATH
5260c325f53SAlexander V. Chernikov 		if (CALC_FLOWID_OUTBOUND) {
5270c325f53SAlexander V. Chernikov 			uint32_t hash_type, hash_val;
52820a6a3a7SMichael Tuexen 
5290c325f53SAlexander V. Chernikov 			hash_val = fib4_calc_software_hash(ip->ip_dst,
5300c325f53SAlexander V. Chernikov 			    ip->ip_src, 0, 0, ip->ip_p, &hash_type);
5310c325f53SAlexander V. Chernikov 			m->m_pkthdr.flowid = hash_val;
5320c325f53SAlexander V. Chernikov 			M_HASHTYPE_SET(m, hash_type);
5330c325f53SAlexander V. Chernikov 			flags |= IP_NODEFAULTFLOWID;
5340c325f53SAlexander V. Chernikov 		}
5350c325f53SAlexander V. Chernikov #endif
53620a6a3a7SMichael Tuexen 		INP_RLOCK(inp);
53720a6a3a7SMichael Tuexen 		/*
53820a6a3a7SMichael Tuexen 		 * Don't allow both user specified and setsockopt options,
53920a6a3a7SMichael Tuexen 		 * and don't allow packet length sizes that will crash.
54020a6a3a7SMichael Tuexen 		 */
54120a6a3a7SMichael Tuexen 		if ((hlen < sizeof (*ip))
54220a6a3a7SMichael Tuexen 		    || ((hlen > sizeof (*ip)) && inp->inp_options)
54320a6a3a7SMichael Tuexen 		    || (ntohs(ip->ip_len) != m->m_pkthdr.len)) {
54420a6a3a7SMichael Tuexen 			INP_RUNLOCK(inp);
54520a6a3a7SMichael Tuexen 			m_freem(m);
54620a6a3a7SMichael Tuexen 			return (EINVAL);
54720a6a3a7SMichael Tuexen 		}
548b89e82ddSJamie Gritton 		error = prison_check_ip4(inp->inp_cred, &ip->ip_src);
549b89e82ddSJamie Gritton 		if (error != 0) {
5509ad11dd8SRobert Watson 			INP_RUNLOCK(inp);
5515a59cefcSBosko Milekic 			m_freem(m);
552b89e82ddSJamie Gritton 			return (error);
5535a59cefcSBosko Milekic 		}
5546d947416SGleb Smirnoff 		/*
555aef06417SMichael Tuexen 		 * Don't allow IP options which do not have the required
556aef06417SMichael Tuexen 		 * structure as specified in section 3.1 of RFC 791 on
557aef06417SMichael Tuexen 		 * pages 15-23.
558aef06417SMichael Tuexen 		 */
559aef06417SMichael Tuexen 		cp = (u_char *)(ip + 1);
56020a6a3a7SMichael Tuexen 		cnt = hlen - sizeof (struct ip);
561aef06417SMichael Tuexen 		for (; cnt > 0; cnt -= optlen, cp += optlen) {
562aef06417SMichael Tuexen 			opttype = cp[IPOPT_OPTVAL];
563aef06417SMichael Tuexen 			if (opttype == IPOPT_EOL)
564aef06417SMichael Tuexen 				break;
565aef06417SMichael Tuexen 			if (opttype == IPOPT_NOP) {
566aef06417SMichael Tuexen 				optlen = 1;
567aef06417SMichael Tuexen 				continue;
568aef06417SMichael Tuexen 			}
569aef06417SMichael Tuexen 			if (cnt < IPOPT_OLEN + sizeof(u_char)) {
570aef06417SMichael Tuexen 				INP_RUNLOCK(inp);
571aef06417SMichael Tuexen 				m_freem(m);
572aef06417SMichael Tuexen 				return (EINVAL);
573aef06417SMichael Tuexen 			}
574aef06417SMichael Tuexen 			optlen = cp[IPOPT_OLEN];
575aef06417SMichael Tuexen 			if (optlen < IPOPT_OLEN + sizeof(u_char) ||
576aef06417SMichael Tuexen 			    optlen > cnt) {
577aef06417SMichael Tuexen 				INP_RUNLOCK(inp);
578aef06417SMichael Tuexen 				m_freem(m);
579aef06417SMichael Tuexen 				return (EINVAL);
580aef06417SMichael Tuexen 			}
581aef06417SMichael Tuexen 		}
582aef06417SMichael Tuexen 		/*
5836d947416SGleb Smirnoff 		 * This doesn't allow application to specify ID of zero,
5846d947416SGleb Smirnoff 		 * but we got this limitation from the beginning of history.
5856d947416SGleb Smirnoff 		 */
586df8bae1dSRodney W. Grimes 		if (ip->ip_id == 0)
5876d947416SGleb Smirnoff 			ip_fillid(ip);
5880ae76120SRobert Watson 
5890ae76120SRobert Watson 		/*
5900ae76120SRobert Watson 		 * XXX prevent ip_output from overwriting header fields.
5910ae76120SRobert Watson 		 */
592df8bae1dSRodney W. Grimes 		flags |= IP_RAWOUTPUT;
59386425c62SRobert Watson 		IPSTAT_INC(ips_rawout);
594df8bae1dSRodney W. Grimes 	}
5956a800098SYoshinobu Inoue 
5966fbfd582SAndre Oppermann 	if (inp->inp_flags & INP_ONESBCAST)
5978afa2304SBruce M Simpson 		flags |= IP_SENDONES;
5988afa2304SBruce M Simpson 
599ac830b58SBosko Milekic #ifdef MAC
60030d239bcSRobert Watson 	mac_inpcb_create_mbuf(inp, m);
601ac830b58SBosko Milekic #endif
602ac830b58SBosko Milekic 
603b9555453SGleb Smirnoff 	NET_EPOCH_ENTER(et);
604ac830b58SBosko Milekic 	error = ip_output(m, inp->inp_options, NULL, flags,
605ac830b58SBosko Milekic 	    inp->inp_moptions, inp);
606b9555453SGleb Smirnoff 	NET_EPOCH_EXIT(et);
6079ad11dd8SRobert Watson 	INP_RUNLOCK(inp);
6080ae76120SRobert Watson 	return (error);
609df8bae1dSRodney W. Grimes }
610df8bae1dSRodney W. Grimes 
611df8bae1dSRodney W. Grimes /*
612df8bae1dSRodney W. Grimes  * Raw IP socket option processing.
61383503a92SRobert Watson  *
6146c67b8b6SRobert Watson  * IMPORTANT NOTE regarding access control: Traditionally, raw sockets could
6156c67b8b6SRobert Watson  * only be created by a privileged process, and as such, socket option
6166c67b8b6SRobert Watson  * operations to manage system properties on any raw socket were allowed to
6176c67b8b6SRobert Watson  * take place without explicit additional access control checks.  However,
6186c67b8b6SRobert Watson  * raw sockets can now also be created in jail(), and therefore explicit
6196c67b8b6SRobert Watson  * checks are now required.  Likewise, raw sockets can be used by a process
6206c67b8b6SRobert Watson  * after it gives up privilege, so some caution is required.  For options
6216c67b8b6SRobert Watson  * passed down to the IP layer via ip_ctloutput(), checks are assumed to be
6226c67b8b6SRobert Watson  * performed in ip_ctloutput() and therefore no check occurs here.
62302dd4b5cSRobert Watson  * Unilaterally checking priv_check() here breaks normal IP socket option
6246c67b8b6SRobert Watson  * operations on raw sockets.
6256c67b8b6SRobert Watson  *
6266c67b8b6SRobert Watson  * When adding new socket options here, make sure to add access control
6276c67b8b6SRobert Watson  * checks here as necessary.
628762ad1d6SBjoern A. Zeeb  *
629762ad1d6SBjoern A. Zeeb  * XXX-BZ inp locking?
630df8bae1dSRodney W. Grimes  */
631df8bae1dSRodney W. Grimes int
rip_ctloutput(struct socket * so,struct sockopt * sopt)6323b6dd5a9SSam Leffler rip_ctloutput(struct socket *so, struct sockopt *sopt)
633df8bae1dSRodney W. Grimes {
634cfe8b629SGarrett Wollman 	struct	inpcb *inp = sotoinpcb(so);
635cfe8b629SGarrett Wollman 	int	error, optval;
636df8bae1dSRodney W. Grimes 
637bc97ba51SJulian Elischer 	if (sopt->sopt_level != IPPROTO_IP) {
638bc97ba51SJulian Elischer 		if ((sopt->sopt_level == SOL_SOCKET) &&
639bc97ba51SJulian Elischer 		    (sopt->sopt_name == SO_SETFIB)) {
640bc97ba51SJulian Elischer 			inp->inp_inc.inc_fibnum = so->so_fibnum;
641bc97ba51SJulian Elischer 			return (0);
642bc97ba51SJulian Elischer 		}
643df8bae1dSRodney W. Grimes 		return (EINVAL);
644bc97ba51SJulian Elischer 	}
645df8bae1dSRodney W. Grimes 
64625f26ad8SGarrett Wollman 	error = 0;
647cfe8b629SGarrett Wollman 	switch (sopt->sopt_dir) {
648cfe8b629SGarrett Wollman 	case SOPT_GET:
649cfe8b629SGarrett Wollman 		switch (sopt->sopt_name) {
650cfe8b629SGarrett Wollman 		case IP_HDRINCL:
651cfe8b629SGarrett Wollman 			optval = inp->inp_flags & INP_HDRINCL;
652cfe8b629SGarrett Wollman 			error = sooptcopyout(sopt, &optval, sizeof optval);
653cfe8b629SGarrett Wollman 			break;
654df8bae1dSRodney W. Grimes 
6553429911dSLuigi Rizzo 		case IP_FW3:	/* generic ipfw v.3 functions */
6567b109fa4SLuigi Rizzo 		case IP_FW_ADD:	/* ADD actually returns the body... */
65709bb5f75SPoul-Henning Kamp 		case IP_FW_GET:
658cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_GETSIZE:
659cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_LIST:
660ff2f6fe8SPaolo Pisati 		case IP_FW_NAT_GET_CONFIG:
661ff2f6fe8SPaolo Pisati 		case IP_FW_NAT_GET_LOG:
6620b4b0b0fSJulian Elischer 			if (V_ip_fw_ctl_ptr != NULL)
6630b4b0b0fSJulian Elischer 				error = V_ip_fw_ctl_ptr(sopt);
6647b109fa4SLuigi Rizzo 			else
6657b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
666cfe8b629SGarrett Wollman 			break;
6674dd1662bSUgen J.S. Antsilevich 
6683429911dSLuigi Rizzo 		case IP_DUMMYNET3:	/* generic dummynet v.3 functions */
669b715f178SLuigi Rizzo 		case IP_DUMMYNET_GET:
6709b932e9eSAndre Oppermann 			if (ip_dn_ctl_ptr != NULL)
671b715f178SLuigi Rizzo 				error = ip_dn_ctl_ptr(sopt);
6727b109fa4SLuigi Rizzo 			else
6737b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
674b715f178SLuigi Rizzo 			break ;
6751c5de19aSGarrett Wollman 
6761c5de19aSGarrett Wollman 		case MRT_INIT:
6771c5de19aSGarrett Wollman 		case MRT_DONE:
6781c5de19aSGarrett Wollman 		case MRT_ADD_VIF:
6791c5de19aSGarrett Wollman 		case MRT_DEL_VIF:
6801c5de19aSGarrett Wollman 		case MRT_ADD_MFC:
6811c5de19aSGarrett Wollman 		case MRT_DEL_MFC:
6821c5de19aSGarrett Wollman 		case MRT_VERSION:
6831c5de19aSGarrett Wollman 		case MRT_ASSERT:
6841e78ac21SJeffrey Hsu 		case MRT_API_SUPPORT:
6851e78ac21SJeffrey Hsu 		case MRT_API_CONFIG:
6861e78ac21SJeffrey Hsu 		case MRT_ADD_BW_UPCALL:
6871e78ac21SJeffrey Hsu 		case MRT_DEL_BW_UPCALL:
688acd3428bSRobert Watson 			error = priv_check(curthread, PRIV_NETINET_MROUTE);
6896c67b8b6SRobert Watson 			if (error != 0)
6906c67b8b6SRobert Watson 				return (error);
69174ed2e8aSGleb Smirnoff 			if (inp->inp_ip_p != IPPROTO_IGMP)
69274ed2e8aSGleb Smirnoff 				return (EOPNOTSUPP);
693bbb4330bSLuigi Rizzo 			error = ip_mrouter_get ? ip_mrouter_get(so, sopt) :
694bbb4330bSLuigi Rizzo 				EOPNOTSUPP;
695cfe8b629SGarrett Wollman 			break;
696cfe8b629SGarrett Wollman 
697cfe8b629SGarrett Wollman 		default:
698cfe8b629SGarrett Wollman 			error = ip_ctloutput(so, sopt);
699cfe8b629SGarrett Wollman 			break;
700df8bae1dSRodney W. Grimes 		}
701cfe8b629SGarrett Wollman 		break;
702cfe8b629SGarrett Wollman 
703cfe8b629SGarrett Wollman 	case SOPT_SET:
704cfe8b629SGarrett Wollman 		switch (sopt->sopt_name) {
705cfe8b629SGarrett Wollman 		case IP_HDRINCL:
706cfe8b629SGarrett Wollman 			error = sooptcopyin(sopt, &optval, sizeof optval,
707cfe8b629SGarrett Wollman 					    sizeof optval);
708cfe8b629SGarrett Wollman 			if (error)
709cfe8b629SGarrett Wollman 				break;
710cfe8b629SGarrett Wollman 			if (optval)
711cfe8b629SGarrett Wollman 				inp->inp_flags |= INP_HDRINCL;
712cfe8b629SGarrett Wollman 			else
713cfe8b629SGarrett Wollman 				inp->inp_flags &= ~INP_HDRINCL;
714cfe8b629SGarrett Wollman 			break;
715cfe8b629SGarrett Wollman 
7163429911dSLuigi Rizzo 		case IP_FW3:	/* generic ipfw v.3 functions */
7178ba03966SRuslan Ermilov 		case IP_FW_ADD:
718cfe8b629SGarrett Wollman 		case IP_FW_DEL:
719cfe8b629SGarrett Wollman 		case IP_FW_FLUSH:
720cfe8b629SGarrett Wollman 		case IP_FW_ZERO:
7210b6c1a83SBrian Feldman 		case IP_FW_RESETLOG:
722cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_ADD:
723cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_DEL:
724cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_FLUSH:
725ff2f6fe8SPaolo Pisati 		case IP_FW_NAT_CFG:
726ff2f6fe8SPaolo Pisati 		case IP_FW_NAT_DEL:
7270b4b0b0fSJulian Elischer 			if (V_ip_fw_ctl_ptr != NULL)
7280b4b0b0fSJulian Elischer 				error = V_ip_fw_ctl_ptr(sopt);
7297b109fa4SLuigi Rizzo 			else
7307b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
731cfe8b629SGarrett Wollman 			break;
732cfe8b629SGarrett Wollman 
7333429911dSLuigi Rizzo 		case IP_DUMMYNET3:	/* generic dummynet v.3 functions */
734b715f178SLuigi Rizzo 		case IP_DUMMYNET_CONFIGURE:
735b715f178SLuigi Rizzo 		case IP_DUMMYNET_DEL:
736b715f178SLuigi Rizzo 		case IP_DUMMYNET_FLUSH:
7379b932e9eSAndre Oppermann 			if (ip_dn_ctl_ptr != NULL)
738b715f178SLuigi Rizzo 				error = ip_dn_ctl_ptr(sopt);
7397b109fa4SLuigi Rizzo 			else
7407b109fa4SLuigi Rizzo 				error = ENOPROTOOPT ;
741b715f178SLuigi Rizzo 			break ;
742cfe8b629SGarrett Wollman 
743cfe8b629SGarrett Wollman 		case IP_RSVP_ON:
744acd3428bSRobert Watson 			error = priv_check(curthread, PRIV_NETINET_MROUTE);
7456c67b8b6SRobert Watson 			if (error != 0)
7466c67b8b6SRobert Watson 				return (error);
74774ed2e8aSGleb Smirnoff 			if (inp->inp_ip_p != IPPROTO_RSVP)
74874ed2e8aSGleb Smirnoff 				return (EOPNOTSUPP);
749cfe8b629SGarrett Wollman 			error = ip_rsvp_init(so);
750cfe8b629SGarrett Wollman 			break;
751cfe8b629SGarrett Wollman 
752cfe8b629SGarrett Wollman 		case IP_RSVP_OFF:
753acd3428bSRobert Watson 			error = priv_check(curthread, PRIV_NETINET_MROUTE);
7546c67b8b6SRobert Watson 			if (error != 0)
7556c67b8b6SRobert Watson 				return (error);
756cfe8b629SGarrett Wollman 			error = ip_rsvp_done();
757cfe8b629SGarrett Wollman 			break;
758cfe8b629SGarrett Wollman 
759cfe8b629SGarrett Wollman 		case IP_RSVP_VIF_ON:
760cfe8b629SGarrett Wollman 		case IP_RSVP_VIF_OFF:
761acd3428bSRobert Watson 			error = priv_check(curthread, PRIV_NETINET_MROUTE);
7626c67b8b6SRobert Watson 			if (error != 0)
7636c67b8b6SRobert Watson 				return (error);
76474ed2e8aSGleb Smirnoff 			if (inp->inp_ip_p != IPPROTO_RSVP)
76574ed2e8aSGleb Smirnoff 				return (EOPNOTSUPP);
766bbb4330bSLuigi Rizzo 			error = ip_rsvp_vif ?
767bbb4330bSLuigi Rizzo 				ip_rsvp_vif(so, sopt) : EINVAL;
768cfe8b629SGarrett Wollman 			break;
769cfe8b629SGarrett Wollman 
770cfe8b629SGarrett Wollman 		case MRT_INIT:
771cfe8b629SGarrett Wollman 		case MRT_DONE:
772cfe8b629SGarrett Wollman 		case MRT_ADD_VIF:
773cfe8b629SGarrett Wollman 		case MRT_DEL_VIF:
774cfe8b629SGarrett Wollman 		case MRT_ADD_MFC:
775cfe8b629SGarrett Wollman 		case MRT_DEL_MFC:
776cfe8b629SGarrett Wollman 		case MRT_VERSION:
777cfe8b629SGarrett Wollman 		case MRT_ASSERT:
7781e78ac21SJeffrey Hsu 		case MRT_API_SUPPORT:
7791e78ac21SJeffrey Hsu 		case MRT_API_CONFIG:
7801e78ac21SJeffrey Hsu 		case MRT_ADD_BW_UPCALL:
7811e78ac21SJeffrey Hsu 		case MRT_DEL_BW_UPCALL:
782acd3428bSRobert Watson 			error = priv_check(curthread, PRIV_NETINET_MROUTE);
7836c67b8b6SRobert Watson 			if (error != 0)
7846c67b8b6SRobert Watson 				return (error);
78574ed2e8aSGleb Smirnoff 			if (inp->inp_ip_p != IPPROTO_IGMP)
78674ed2e8aSGleb Smirnoff 				return (EOPNOTSUPP);
787bbb4330bSLuigi Rizzo 			error = ip_mrouter_set ? ip_mrouter_set(so, sopt) :
788bbb4330bSLuigi Rizzo 					EOPNOTSUPP;
789cfe8b629SGarrett Wollman 			break;
790cfe8b629SGarrett Wollman 
791cfe8b629SGarrett Wollman 		default:
792cfe8b629SGarrett Wollman 			error = ip_ctloutput(so, sopt);
793cfe8b629SGarrett Wollman 			break;
794cfe8b629SGarrett Wollman 		}
795cfe8b629SGarrett Wollman 		break;
796cfe8b629SGarrett Wollman 	}
797cfe8b629SGarrett Wollman 
798cfe8b629SGarrett Wollman 	return (error);
799df8bae1dSRodney W. Grimes }
800df8bae1dSRodney W. Grimes 
80139191c8eSGarrett Wollman void
rip_ctlinput(struct icmp * icmp)802fcb3f813SGleb Smirnoff rip_ctlinput(struct icmp *icmp)
80339191c8eSGarrett Wollman {
804d9d59bb1SWojciech Macek #if defined(IPSEC) || defined(IPSEC_SUPPORT)
805d9d59bb1SWojciech Macek 	if (IPSEC_ENABLED(ipv4))
806fcb3f813SGleb Smirnoff 		IPSEC_CTLINPUT(ipv4, icmp);
807d9d59bb1SWojciech Macek #endif
80839191c8eSGarrett Wollman }
80939191c8eSGarrett Wollman 
810117bcae7SGarrett Wollman static int
rip_attach(struct socket * so,int proto,struct thread * td)811b40ce416SJulian Elischer rip_attach(struct socket *so, int proto, struct thread *td)
812df8bae1dSRodney W. Grimes {
813117bcae7SGarrett Wollman 	struct inpcb *inp;
8143b6dd5a9SSam Leffler 	int error;
815c1f8a6ceSDavid Greenman 
816117bcae7SGarrett Wollman 	inp = sotoinpcb(so);
81714ba8addSRobert Watson 	KASSERT(inp == NULL, ("rip_attach: inp != NULL"));
81832f9753cSRobert Watson 
81932f9753cSRobert Watson 	error = priv_check(td, PRIV_NETINET_RAW);
820acd3428bSRobert Watson 	if (error)
8210ae76120SRobert Watson 		return (error);
82214ba8addSRobert Watson 	if (proto >= IPPROTO_MAX || proto < 0)
8234d3ffc98SBill Fenner 		return EPROTONOSUPPORT;
8246a800098SYoshinobu Inoue 	error = soreserve(so, rip_sendspace, rip_recvspace);
82514ba8addSRobert Watson 	if (error)
8260ae76120SRobert Watson 		return (error);
827603724d3SBjoern A. Zeeb 	error = in_pcballoc(so, &V_ripcbinfo);
828db0ac6deSCy Schubert 	if (error)
8290ae76120SRobert Watson 		return (error);
830df8bae1dSRodney W. Grimes 	inp = (struct inpcb *)so->so_pcb;
831ca98b82cSDavid Greenman 	inp->inp_ip_p = proto;
832603724d3SBjoern A. Zeeb 	inp->inp_ip_ttl = V_ip_defttl;
833db0ac6deSCy Schubert 	INP_HASH_WLOCK(&V_ripcbinfo);
8349ed324c9SAlexander Motin 	rip_inshash(inp);
835db0ac6deSCy Schubert 	INP_HASH_WUNLOCK(&V_ripcbinfo);
8368501a69cSRobert Watson 	INP_WUNLOCK(inp);
8370ae76120SRobert Watson 	return (0);
838df8bae1dSRodney W. Grimes }
839117bcae7SGarrett Wollman 
84050d7c061SSam Leffler static void
rip_detach(struct socket * so)841a152f8a3SRobert Watson rip_detach(struct socket *so)
84250d7c061SSam Leffler {
843a152f8a3SRobert Watson 	struct inpcb *inp;
8443ca1570cSRobert Watson 
845a152f8a3SRobert Watson 	inp = sotoinpcb(so);
846a152f8a3SRobert Watson 	KASSERT(inp != NULL, ("rip_detach: inp == NULL"));
847a152f8a3SRobert Watson 	KASSERT(inp->inp_faddr.s_addr == INADDR_ANY,
848a152f8a3SRobert Watson 	    ("rip_detach: not closed"));
84950d7c061SSam Leffler 
85077223d98SWojciech Macek 	/* Disable mrouter first */
8519ce46cbcSWojciech Macek 	if (so == V_ip_mrouter && ip_mrouter_done)
85277223d98SWojciech Macek 		ip_mrouter_done();
8539ce46cbcSWojciech Macek 
8548501a69cSRobert Watson 	INP_WLOCK(inp);
855db0ac6deSCy Schubert 	INP_HASH_WLOCK(&V_ripcbinfo);
8569ed324c9SAlexander Motin 	rip_delhash(inp);
857db0ac6deSCy Schubert 	INP_HASH_WUNLOCK(&V_ripcbinfo);
8589ce46cbcSWojciech Macek 
85950d7c061SSam Leffler 	if (ip_rsvp_force_done)
86050d7c061SSam Leffler 		ip_rsvp_force_done(so);
861603724d3SBjoern A. Zeeb 	if (so == V_ip_rsvpd)
86250d7c061SSam Leffler 		ip_rsvp_done();
86314ba8addSRobert Watson 	in_pcbfree(inp);
86450d7c061SSam Leffler }
86550d7c061SSam Leffler 
866bc725eafSRobert Watson static void
rip_dodisconnect(struct socket * so,struct inpcb * inp)867a152f8a3SRobert Watson rip_dodisconnect(struct socket *so, struct inpcb *inp)
868117bcae7SGarrett Wollman {
869fa046d87SRobert Watson 	struct inpcbinfo *pcbinfo;
87018f401c6SAlexander Motin 
871fa046d87SRobert Watson 	pcbinfo = inp->inp_pcbinfo;
872fa046d87SRobert Watson 	INP_WLOCK(inp);
873db0ac6deSCy Schubert 	INP_HASH_WLOCK(pcbinfo);
8749ed324c9SAlexander Motin 	rip_delhash(inp);
875a152f8a3SRobert Watson 	inp->inp_faddr.s_addr = INADDR_ANY;
8769ed324c9SAlexander Motin 	rip_inshash(inp);
877db0ac6deSCy Schubert 	INP_HASH_WUNLOCK(pcbinfo);
878a152f8a3SRobert Watson 	SOCK_LOCK(so);
879a152f8a3SRobert Watson 	so->so_state &= ~SS_ISCONNECTED;
880a152f8a3SRobert Watson 	SOCK_UNLOCK(so);
881fa046d87SRobert Watson 	INP_WUNLOCK(inp);
882117bcae7SGarrett Wollman }
883df8bae1dSRodney W. Grimes 
884ac45e92fSRobert Watson static void
rip_abort(struct socket * so)885117bcae7SGarrett Wollman rip_abort(struct socket *so)
886df8bae1dSRodney W. Grimes {
88750d7c061SSam Leffler 	struct inpcb *inp;
88850d7c061SSam Leffler 
88950d7c061SSam Leffler 	inp = sotoinpcb(so);
89014ba8addSRobert Watson 	KASSERT(inp != NULL, ("rip_abort: inp == NULL"));
891a152f8a3SRobert Watson 
892a152f8a3SRobert Watson 	rip_dodisconnect(so, inp);
893a152f8a3SRobert Watson }
894a152f8a3SRobert Watson 
895a152f8a3SRobert Watson static void
rip_close(struct socket * so)896a152f8a3SRobert Watson rip_close(struct socket *so)
897a152f8a3SRobert Watson {
898a152f8a3SRobert Watson 	struct inpcb *inp;
899a152f8a3SRobert Watson 
900a152f8a3SRobert Watson 	inp = sotoinpcb(so);
901a152f8a3SRobert Watson 	KASSERT(inp != NULL, ("rip_close: inp == NULL"));
902a152f8a3SRobert Watson 
903a152f8a3SRobert Watson 	rip_dodisconnect(so, inp);
904117bcae7SGarrett Wollman }
905117bcae7SGarrett Wollman 
906117bcae7SGarrett Wollman static int
rip_disconnect(struct socket * so)907117bcae7SGarrett Wollman rip_disconnect(struct socket *so)
908117bcae7SGarrett Wollman {
909eb16472fSMaxim Konovalov 	struct inpcb *inp;
910eb16472fSMaxim Konovalov 
9114cc20ab1SSeigo Tanimura 	if ((so->so_state & SS_ISCONNECTED) == 0)
9120ae76120SRobert Watson 		return (ENOTCONN);
913eb16472fSMaxim Konovalov 
914eb16472fSMaxim Konovalov 	inp = sotoinpcb(so);
915eb16472fSMaxim Konovalov 	KASSERT(inp != NULL, ("rip_disconnect: inp == NULL"));
9160ae76120SRobert Watson 
917a152f8a3SRobert Watson 	rip_dodisconnect(so, inp);
91814ba8addSRobert Watson 	return (0);
919117bcae7SGarrett Wollman }
920117bcae7SGarrett Wollman 
921117bcae7SGarrett Wollman static int
rip_bind(struct socket * so,struct sockaddr * nam,struct thread * td)922b40ce416SJulian Elischer rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
923117bcae7SGarrett Wollman {
92457bf258eSGarrett Wollman 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
92550d7c061SSam Leffler 	struct inpcb *inp;
926b89e82ddSJamie Gritton 	int error;
927df8bae1dSRodney W. Grimes 
928f161d294SMark Johnston 	if (nam->sa_family != AF_INET)
929f161d294SMark Johnston 		return (EAFNOSUPPORT);
93057bf258eSGarrett Wollman 	if (nam->sa_len != sizeof(*addr))
9310ae76120SRobert Watson 		return (EINVAL);
932117bcae7SGarrett Wollman 
933b89e82ddSJamie Gritton 	error = prison_check_ip4(td->td_ucred, &addr->sin_addr);
934b89e82ddSJamie Gritton 	if (error != 0)
935b89e82ddSJamie Gritton 		return (error);
9365a59cefcSBosko Milekic 
937f44270e7SPawel Jakub Dawidek 	inp = sotoinpcb(so);
938f44270e7SPawel Jakub Dawidek 	KASSERT(inp != NULL, ("rip_bind: inp == NULL"));
939f44270e7SPawel Jakub Dawidek 
9404f6c66ccSMatt Macy 	if (CK_STAILQ_EMPTY(&V_ifnet) ||
94150d7c061SSam Leffler 	    (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) ||
942032dcc76SLuigi Rizzo 	    (addr->sin_addr.s_addr &&
943f44270e7SPawel Jakub Dawidek 	     (inp->inp_flags & INP_BINDANY) == 0 &&
9448896f83aSRobert Watson 	     ifa_ifwithaddr_check((struct sockaddr *)addr) == 0))
9450ae76120SRobert Watson 		return (EADDRNOTAVAIL);
94650d7c061SSam Leffler 
9478501a69cSRobert Watson 	INP_WLOCK(inp);
948db0ac6deSCy Schubert 	INP_HASH_WLOCK(&V_ripcbinfo);
9499ed324c9SAlexander Motin 	rip_delhash(inp);
950df8bae1dSRodney W. Grimes 	inp->inp_laddr = addr->sin_addr;
9519ed324c9SAlexander Motin 	rip_inshash(inp);
952db0ac6deSCy Schubert 	INP_HASH_WUNLOCK(&V_ripcbinfo);
9538501a69cSRobert Watson 	INP_WUNLOCK(inp);
9540ae76120SRobert Watson 	return (0);
955df8bae1dSRodney W. Grimes }
956117bcae7SGarrett Wollman 
957117bcae7SGarrett Wollman static int
rip_connect(struct socket * so,struct sockaddr * nam,struct thread * td)958b40ce416SJulian Elischer rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
959df8bae1dSRodney W. Grimes {
96057bf258eSGarrett Wollman 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
96150d7c061SSam Leffler 	struct inpcb *inp;
962df8bae1dSRodney W. Grimes 
96357bf258eSGarrett Wollman 	if (nam->sa_len != sizeof(*addr))
9640ae76120SRobert Watson 		return (EINVAL);
9654f6c66ccSMatt Macy 	if (CK_STAILQ_EMPTY(&V_ifnet))
9660ae76120SRobert Watson 		return (EADDRNOTAVAIL);
96750d7c061SSam Leffler 	if (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK)
9680ae76120SRobert Watson 		return (EAFNOSUPPORT);
96950d7c061SSam Leffler 
97050d7c061SSam Leffler 	inp = sotoinpcb(so);
97114ba8addSRobert Watson 	KASSERT(inp != NULL, ("rip_connect: inp == NULL"));
9720ae76120SRobert Watson 
9738501a69cSRobert Watson 	INP_WLOCK(inp);
974db0ac6deSCy Schubert 	INP_HASH_WLOCK(&V_ripcbinfo);
9759ed324c9SAlexander Motin 	rip_delhash(inp);
976df8bae1dSRodney W. Grimes 	inp->inp_faddr = addr->sin_addr;
9779ed324c9SAlexander Motin 	rip_inshash(inp);
978db0ac6deSCy Schubert 	INP_HASH_WUNLOCK(&V_ripcbinfo);
979df8bae1dSRodney W. Grimes 	soisconnected(so);
9808501a69cSRobert Watson 	INP_WUNLOCK(inp);
9810ae76120SRobert Watson 	return (0);
982df8bae1dSRodney W. Grimes }
983df8bae1dSRodney W. Grimes 
984117bcae7SGarrett Wollman static int
rip_shutdown(struct socket * so,enum shutdown_how how)9855bba2728SGleb Smirnoff rip_shutdown(struct socket *so, enum shutdown_how how)
986df8bae1dSRodney W. Grimes {
98750d7c061SSam Leffler 
9885bba2728SGleb Smirnoff 	SOCK_LOCK(so);
9895bba2728SGleb Smirnoff 	if (!(so->so_state & SS_ISCONNECTED)) {
9905bba2728SGleb Smirnoff 		SOCK_UNLOCK(so);
9915bba2728SGleb Smirnoff 		return (ENOTCONN);
9925bba2728SGleb Smirnoff 	}
9935bba2728SGleb Smirnoff 	SOCK_UNLOCK(so);
9940ae76120SRobert Watson 
9955bba2728SGleb Smirnoff 	switch (how) {
9965bba2728SGleb Smirnoff 	case SHUT_RD:
997*ce69e373SGleb Smirnoff 		sorflush(so);
9985bba2728SGleb Smirnoff 		break;
9995bba2728SGleb Smirnoff 	case SHUT_RDWR:
1000*ce69e373SGleb Smirnoff 		sorflush(so);
10015bba2728SGleb Smirnoff 		/* FALLTHROUGH */
10025bba2728SGleb Smirnoff 	case SHUT_WR:
1003117bcae7SGarrett Wollman 		socantsendmore(so);
10045bba2728SGleb Smirnoff 	}
10055bba2728SGleb Smirnoff 
10060ae76120SRobert Watson 	return (0);
1007117bcae7SGarrett Wollman }
100800c081e9SBjoern A. Zeeb #endif /* INET */
1009df8bae1dSRodney W. Grimes 
101098271db4SGarrett Wollman static int
rip_pcblist(SYSCTL_HANDLER_ARGS)101182d9ae4eSPoul-Henning Kamp rip_pcblist(SYSCTL_HANDLER_ARGS)
101298271db4SGarrett Wollman {
1013db0ac6deSCy Schubert 	struct inpcb_iterator inpi = INP_ALL_ITERATOR(&V_ripcbinfo,
1014db0ac6deSCy Schubert 	    INPLOOKUP_RLOCKPCB);
101598271db4SGarrett Wollman 	struct xinpgen xig;
1016032677ceSGleb Smirnoff 	struct inpcb *inp;
1017032677ceSGleb Smirnoff 	int error;
101898271db4SGarrett Wollman 
1019032677ceSGleb Smirnoff 	if (req->newptr != 0)
1020032677ceSGleb Smirnoff 		return (EPERM);
1021032677ceSGleb Smirnoff 
102298271db4SGarrett Wollman 	if (req->oldptr == 0) {
1023032677ceSGleb Smirnoff 		int n;
1024032677ceSGleb Smirnoff 
1025603724d3SBjoern A. Zeeb 		n = V_ripcbinfo.ipi_count;
1026c007b96aSJohn Baldwin 		n += imax(n / 8, 10);
1027c007b96aSJohn Baldwin 		req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xinpcb);
10280ae76120SRobert Watson 		return (0);
102998271db4SGarrett Wollman 	}
103098271db4SGarrett Wollman 
1031032677ceSGleb Smirnoff 	if ((error = sysctl_wire_old_buffer(req, 0)) != 0)
1032032677ceSGleb Smirnoff 		return (error);
103398271db4SGarrett Wollman 
103479db6fe7SMark Johnston 	bzero(&xig, sizeof(xig));
103598271db4SGarrett Wollman 	xig.xig_len = sizeof xig;
1036032677ceSGleb Smirnoff 	xig.xig_count = V_ripcbinfo.ipi_count;
1037032677ceSGleb Smirnoff 	xig.xig_gen = V_ripcbinfo.ipi_gencnt;
103898271db4SGarrett Wollman 	xig.xig_sogen = so_gencnt;
103998271db4SGarrett Wollman 	error = SYSCTL_OUT(req, &xig, sizeof xig);
104098271db4SGarrett Wollman 	if (error)
10410ae76120SRobert Watson 		return (error);
104298271db4SGarrett Wollman 
1043db0ac6deSCy Schubert 	while ((inp = inp_next(&inpi)) != NULL) {
1044032677ceSGleb Smirnoff 		if (inp->inp_gencnt <= xig.xig_gen &&
1045032677ceSGleb Smirnoff 		    cr_canseeinpcb(req->td->td_ucred, inp) == 0) {
104698271db4SGarrett Wollman 			struct xinpcb xi;
10473bb87a6cSKip Macy 
1048cc65eb4eSGleb Smirnoff 			in_pcbtoxinpcb(inp, &xi);
1049266f97b5SCy Schubert 			error = SYSCTL_OUT(req, &xi, sizeof xi);
1050db0ac6deSCy Schubert 			if (error) {
1051266f97b5SCy Schubert 				INP_RUNLOCK(inp);
1052db0ac6deSCy Schubert 				break;
105398271db4SGarrett Wollman 			}
1054db0ac6deSCy Schubert 		}
1055db0ac6deSCy Schubert 	}
1056d0e157f6SBjoern A. Zeeb 
105798271db4SGarrett Wollman 	if (!error) {
105898271db4SGarrett Wollman 		/*
10590ae76120SRobert Watson 		 * Give the user an updated idea of our state.  If the
10600ae76120SRobert Watson 		 * generation differs from what we told her before, she knows
10610ae76120SRobert Watson 		 * that something happened while we were processing this
10620ae76120SRobert Watson 		 * request, and it might be necessary to retry.
106398271db4SGarrett Wollman 		 */
1064603724d3SBjoern A. Zeeb 		xig.xig_gen = V_ripcbinfo.ipi_gencnt;
106598271db4SGarrett Wollman 		xig.xig_sogen = so_gencnt;
1066603724d3SBjoern A. Zeeb 		xig.xig_count = V_ripcbinfo.ipi_count;
106798271db4SGarrett Wollman 		error = SYSCTL_OUT(req, &xig, sizeof xig);
106898271db4SGarrett Wollman 	}
1069032677ceSGleb Smirnoff 
10700ae76120SRobert Watson 	return (error);
107198271db4SGarrett Wollman }
107298271db4SGarrett Wollman 
107379c3d51bSMatthew D Fleming SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist,
10747029da5cSPawel Biernacki     CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
10757029da5cSPawel Biernacki     rip_pcblist, "S,xinpcb",
10767029da5cSPawel Biernacki     "List of active raw IP sockets");
107798271db4SGarrett Wollman 
107800c081e9SBjoern A. Zeeb #ifdef INET
1079e7d02be1SGleb Smirnoff struct protosw rip_protosw = {
108061f7427fSGleb Smirnoff 	.pr_type =		SOCK_RAW,
108161f7427fSGleb Smirnoff 	.pr_flags =		PR_ATOMIC|PR_ADDR,
108261f7427fSGleb Smirnoff 	.pr_ctloutput =		rip_ctloutput,
108361f7427fSGleb Smirnoff 	.pr_abort =		rip_abort,
108461f7427fSGleb Smirnoff 	.pr_attach =		rip_attach,
108561f7427fSGleb Smirnoff 	.pr_bind =		rip_bind,
108661f7427fSGleb Smirnoff 	.pr_connect =		rip_connect,
108761f7427fSGleb Smirnoff 	.pr_control =		in_control,
108861f7427fSGleb Smirnoff 	.pr_detach =		rip_detach,
108961f7427fSGleb Smirnoff 	.pr_disconnect =	rip_disconnect,
109061f7427fSGleb Smirnoff 	.pr_peeraddr =		in_getpeeraddr,
109161f7427fSGleb Smirnoff 	.pr_send =		rip_send,
109261f7427fSGleb Smirnoff 	.pr_shutdown =		rip_shutdown,
109361f7427fSGleb Smirnoff 	.pr_sockaddr =		in_getsockaddr,
109461f7427fSGleb Smirnoff 	.pr_sosetlabel =	in_pcbsosetlabel,
109561f7427fSGleb Smirnoff 	.pr_close =		rip_close
1096117bcae7SGarrett Wollman };
109700c081e9SBjoern A. Zeeb #endif /* INET */
1098