xref: /freebsd/sys/netinet/raw_ip.c (revision 3ca1570c8223eb9b1891246cb61a3f87de9fd21a)
1c398230bSWarner Losh /*-
2df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1988, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
14df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
15df8bae1dSRodney W. Grimes  *    without specific prior written permission.
16df8bae1dSRodney W. Grimes  *
17df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
28df8bae1dSRodney W. Grimes  *
2925f26ad8SGarrett Wollman  *	@(#)raw_ip.c	8.7 (Berkeley) 5/15/95
30c3aac50fSPeter Wemm  * $FreeBSD$
31df8bae1dSRodney W. Grimes  */
32df8bae1dSRodney W. Grimes 
336a800098SYoshinobu Inoue #include "opt_inet6.h"
346a800098SYoshinobu Inoue #include "opt_ipsec.h"
354ea889c6SRobert Watson #include "opt_mac.h"
366a800098SYoshinobu Inoue 
37df8bae1dSRodney W. Grimes #include <sys/param.h>
385a59cefcSBosko Milekic #include <sys/jail.h>
39117bcae7SGarrett Wollman #include <sys/kernel.h>
40960ed29cSSeigo Tanimura #include <sys/lock.h>
413b6aad64SRobert Watson #include <sys/mac.h>
42df8bae1dSRodney W. Grimes #include <sys/malloc.h>
43df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
444787fd37SPaul Saab #include <sys/proc.h>
45df8bae1dSRodney W. Grimes #include <sys/protosw.h>
46960ed29cSSeigo Tanimura #include <sys/signalvar.h>
47117bcae7SGarrett Wollman #include <sys/socket.h>
48df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
49960ed29cSSeigo Tanimura #include <sys/sx.h>
50117bcae7SGarrett Wollman #include <sys/sysctl.h>
51960ed29cSSeigo Tanimura #include <sys/systm.h>
528781d8e9SBruce Evans 
5369c2d429SJeff Roberson #include <vm/uma.h>
54df8bae1dSRodney W. Grimes 
55df8bae1dSRodney W. Grimes #include <net/if.h>
56df8bae1dSRodney W. Grimes #include <net/route.h>
57df8bae1dSRodney W. Grimes 
58df8bae1dSRodney W. Grimes #include <netinet/in.h>
59df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
60c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h>
61c1f8a6ceSDavid Greenman #include <netinet/in_var.h>
62960ed29cSSeigo Tanimura #include <netinet/ip.h>
63df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
64df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h>
65df8bae1dSRodney W. Grimes 
66100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h>
67db69a05dSPaul Saab #include <netinet/ip_dummynet.h>
68100ba1a6SJordan K. Hubbard 
69b9234fafSSam Leffler #ifdef FAST_IPSEC
70b9234fafSSam Leffler #include <netipsec/ipsec.h>
71b9234fafSSam Leffler #endif /*FAST_IPSEC*/
72b9234fafSSam Leffler 
736a800098SYoshinobu Inoue #ifdef IPSEC
746a800098SYoshinobu Inoue #include <netinet6/ipsec.h>
756a800098SYoshinobu Inoue #endif /*IPSEC*/
766a800098SYoshinobu Inoue 
7782cd038dSYoshinobu Inoue struct	inpcbhead ripcb;
7882cd038dSYoshinobu Inoue struct	inpcbinfo ripcbinfo;
79df8bae1dSRodney W. Grimes 
80db69a05dSPaul Saab /* control hooks for ipfw and dummynet */
819b932e9eSAndre Oppermann ip_fw_ctl_t *ip_fw_ctl_ptr = NULL;
829b932e9eSAndre Oppermann ip_dn_ctl_t *ip_dn_ctl_ptr = NULL;
83db69a05dSPaul Saab 
84df8bae1dSRodney W. Grimes /*
85bbb4330bSLuigi Rizzo  * hooks for multicast routing. They all default to NULL,
86bbb4330bSLuigi Rizzo  * so leave them not initialized and rely on BSS being set to 0.
87bbb4330bSLuigi Rizzo  */
88bbb4330bSLuigi Rizzo 
89bbb4330bSLuigi Rizzo /* The socket used to communicate with the multicast routing daemon.  */
90bbb4330bSLuigi Rizzo struct socket  *ip_mrouter;
91bbb4330bSLuigi Rizzo 
92bbb4330bSLuigi Rizzo /* The various mrouter and rsvp functions */
93bbb4330bSLuigi Rizzo int (*ip_mrouter_set)(struct socket *, struct sockopt *);
94bbb4330bSLuigi Rizzo int (*ip_mrouter_get)(struct socket *, struct sockopt *);
95bbb4330bSLuigi Rizzo int (*ip_mrouter_done)(void);
96bbb4330bSLuigi Rizzo int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
97bbb4330bSLuigi Rizzo 		   struct ip_moptions *);
98bbb4330bSLuigi Rizzo int (*mrt_ioctl)(int, caddr_t);
99bbb4330bSLuigi Rizzo int (*legal_vif_num)(int);
100bbb4330bSLuigi Rizzo u_long (*ip_mcast_src)(int);
101bbb4330bSLuigi Rizzo 
102bbb4330bSLuigi Rizzo void (*rsvp_input_p)(struct mbuf *m, int off);
103bbb4330bSLuigi Rizzo int (*ip_rsvp_vif)(struct socket *, struct sockopt *);
104bbb4330bSLuigi Rizzo void (*ip_rsvp_force_done)(struct socket *);
105bbb4330bSLuigi Rizzo 
106bbb4330bSLuigi Rizzo /*
107df8bae1dSRodney W. Grimes  * Nominal space allocated to a raw ip socket.
108df8bae1dSRodney W. Grimes  */
109df8bae1dSRodney W. Grimes #define	RIPSNDQ		8192
110df8bae1dSRodney W. Grimes #define	RIPRCVQ		8192
111df8bae1dSRodney W. Grimes 
112df8bae1dSRodney W. Grimes /*
113df8bae1dSRodney W. Grimes  * Raw interface to IP protocol.
114df8bae1dSRodney W. Grimes  */
115df8bae1dSRodney W. Grimes 
116df8bae1dSRodney W. Grimes /*
117032dcc76SLuigi Rizzo  * Initialize raw connection block q.
118df8bae1dSRodney W. Grimes  */
119df8bae1dSRodney W. Grimes void
120032dcc76SLuigi Rizzo rip_init()
121df8bae1dSRodney W. Grimes {
1227a9378e7SJeffrey Hsu 	INP_INFO_LOCK_INIT(&ripcbinfo, "rip");
12315bd2b43SDavid Greenman 	LIST_INIT(&ripcb);
12415bd2b43SDavid Greenman 	ripcbinfo.listhead = &ripcb;
12515bd2b43SDavid Greenman 	/*
12615bd2b43SDavid Greenman 	 * XXX We don't use the hash list for raw IP, but it's easier
12715bd2b43SDavid Greenman 	 * to allocate a one entry hash list than it is to check all
12815bd2b43SDavid Greenman 	 * over the place for hashbase == NULL.
12915bd2b43SDavid Greenman 	 */
130ddd79a97SDavid Greenman 	ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
131c3229e05SDavid Greenman 	ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
13269c2d429SJeff Roberson 	ripcbinfo.ipi_zone = uma_zcreate("ripcb", sizeof(struct inpcb),
133420a2811SAndre Oppermann 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
13469c2d429SJeff Roberson 	uma_zone_set_max(ripcbinfo.ipi_zone, maxsockets);
135df8bae1dSRodney W. Grimes }
136df8bae1dSRodney W. Grimes 
137f6d24a78SPoul-Henning Kamp static struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
138df8bae1dSRodney W. Grimes 
1393b6dd5a9SSam Leffler static int
1403b6dd5a9SSam Leffler raw_append(struct inpcb *last, struct ip *ip, struct mbuf *n)
1413b6dd5a9SSam Leffler {
1424ea889c6SRobert Watson 	int policyfail = 0;
14333841545SHajimu UMEMOTO 
144cbe42d48SRobert Watson 	INP_LOCK_ASSERT(last);
145cbe42d48SRobert Watson 
146da0f4099SHajimu UMEMOTO #if defined(IPSEC) || defined(FAST_IPSEC)
147da0f4099SHajimu UMEMOTO 	/* check AH/ESP integrity. */
148da0f4099SHajimu UMEMOTO 	if (ipsec4_in_reject(n, last)) {
149da0f4099SHajimu UMEMOTO 		policyfail = 1;
150cd6c2a88SSeigo Tanimura #ifdef IPSEC
15133841545SHajimu UMEMOTO 		ipsecstat.in_polvio++;
15233841545SHajimu UMEMOTO #endif /*IPSEC*/
153b9234fafSSam Leffler 		/* do not inject data to pcb */
154b9234fafSSam Leffler 	}
155da0f4099SHajimu UMEMOTO #endif /*IPSEC || FAST_IPSEC*/
1564ea889c6SRobert Watson #ifdef MAC
157a557af22SRobert Watson 	if (!policyfail && mac_check_inpcb_deliver(last, n) != 0)
1584ea889c6SRobert Watson 		policyfail = 1;
1594ea889c6SRobert Watson #endif
1603b6dd5a9SSam Leffler 	if (!policyfail) {
1613b6dd5a9SSam Leffler 		struct mbuf *opts = NULL;
1621e4d7da7SRobert Watson 		struct socket *so;
1633b6dd5a9SSam Leffler 
1641e4d7da7SRobert Watson 		so = last->inp_socket;
1653b6dd5a9SSam Leffler 		if ((last->inp_flags & INP_CONTROLOPTS) ||
1661e4d7da7SRobert Watson 		    (so->so_options & SO_TIMESTAMP))
16782c23ebaSBill Fenner 			ip_savecontrol(last, &opts, ip, n);
1681e4d7da7SRobert Watson 		SOCKBUF_LOCK(&so->so_rcv);
1691e4d7da7SRobert Watson 		if (sbappendaddr_locked(&so->so_rcv,
1703b6dd5a9SSam Leffler 		    (struct sockaddr *)&ripsrc, n, opts) == 0) {
171df8bae1dSRodney W. Grimes 			/* should notify about lost packet */
172df8bae1dSRodney W. Grimes 			m_freem(n);
17382c23ebaSBill Fenner 			if (opts)
17482c23ebaSBill Fenner 				m_freem(opts);
1751e4d7da7SRobert Watson 			SOCKBUF_UNLOCK(&so->so_rcv);
1764cc20ab1SSeigo Tanimura 		} else
1771e4d7da7SRobert Watson 			sorwakeup_locked(so);
1783b6dd5a9SSam Leffler 	} else
1793b6dd5a9SSam Leffler 		m_freem(n);
1803b6dd5a9SSam Leffler 	return policyfail;
181df8bae1dSRodney W. Grimes }
1823b6dd5a9SSam Leffler 
1833b6dd5a9SSam Leffler /*
1843b6dd5a9SSam Leffler  * Setup generic address and protocol structures
1853b6dd5a9SSam Leffler  * for raw_input routine, then pass them along with
1863b6dd5a9SSam Leffler  * mbuf chain.
1873b6dd5a9SSam Leffler  */
1883b6dd5a9SSam Leffler void
1893b6dd5a9SSam Leffler rip_input(struct mbuf *m, int off)
1903b6dd5a9SSam Leffler {
1913b6dd5a9SSam Leffler 	struct ip *ip = mtod(m, struct ip *);
1923b6dd5a9SSam Leffler 	int proto = ip->ip_p;
1933b6dd5a9SSam Leffler 	struct inpcb *inp, *last;
1943b6dd5a9SSam Leffler 
1953b6dd5a9SSam Leffler 	INP_INFO_RLOCK(&ripcbinfo);
1963b6dd5a9SSam Leffler 	ripsrc.sin_addr = ip->ip_src;
1973b6dd5a9SSam Leffler 	last = NULL;
1983b6dd5a9SSam Leffler 	LIST_FOREACH(inp, &ripcb, inp_list) {
1993b6dd5a9SSam Leffler 		INP_LOCK(inp);
2003b6dd5a9SSam Leffler 		if (inp->inp_ip_p && inp->inp_ip_p != proto) {
2013b6dd5a9SSam Leffler 	docontinue:
2023b6dd5a9SSam Leffler 			INP_UNLOCK(inp);
2033b6dd5a9SSam Leffler 			continue;
2043b6dd5a9SSam Leffler 		}
2053b6dd5a9SSam Leffler #ifdef INET6
2063b6dd5a9SSam Leffler 		if ((inp->inp_vflag & INP_IPV4) == 0)
2073b6dd5a9SSam Leffler 			goto docontinue;
2083b6dd5a9SSam Leffler #endif
2093b6dd5a9SSam Leffler 		if (inp->inp_laddr.s_addr &&
2103b6dd5a9SSam Leffler 		    inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
2113b6dd5a9SSam Leffler 			goto docontinue;
2123b6dd5a9SSam Leffler 		if (inp->inp_faddr.s_addr &&
2133b6dd5a9SSam Leffler 		    inp->inp_faddr.s_addr != ip->ip_src.s_addr)
2143b6dd5a9SSam Leffler 			goto docontinue;
2155a59cefcSBosko Milekic 		if (jailed(inp->inp_socket->so_cred))
2161a0c4873SMaxim Konovalov 			if (htonl(prison_getip(inp->inp_socket->so_cred)) !=
2171a0c4873SMaxim Konovalov 			    ip->ip_dst.s_addr)
2185a59cefcSBosko Milekic 				goto docontinue;
2193b6dd5a9SSam Leffler 		if (last) {
2203b6dd5a9SSam Leffler 			struct mbuf *n;
2213b6dd5a9SSam Leffler 
2223b6dd5a9SSam Leffler 			n = m_copy(m, 0, (int)M_COPYALL);
2233b6dd5a9SSam Leffler 			if (n != NULL)
2243b6dd5a9SSam Leffler 				(void) raw_append(last, ip, n);
2253b6dd5a9SSam Leffler 			/* XXX count dropped packet */
2263b6dd5a9SSam Leffler 			INP_UNLOCK(last);
227df8bae1dSRodney W. Grimes 		}
22882c23ebaSBill Fenner 		last = inp;
229df8bae1dSRodney W. Grimes 	}
2303b6dd5a9SSam Leffler 	if (last != NULL) {
2313b6dd5a9SSam Leffler 		if (raw_append(last, ip, m) != 0)
23233841545SHajimu UMEMOTO 			ipstat.ips_delivered--;
2333b6dd5a9SSam Leffler 		INP_UNLOCK(last);
234df8bae1dSRodney W. Grimes 	} else {
235df8bae1dSRodney W. Grimes 		m_freem(m);
236df8bae1dSRodney W. Grimes 		ipstat.ips_noproto++;
237df8bae1dSRodney W. Grimes 		ipstat.ips_delivered--;
238df8bae1dSRodney W. Grimes 	}
2393b6dd5a9SSam Leffler 	INP_INFO_RUNLOCK(&ripcbinfo);
240df8bae1dSRodney W. Grimes }
241df8bae1dSRodney W. Grimes 
242df8bae1dSRodney W. Grimes /*
243df8bae1dSRodney W. Grimes  * Generate IP header and pass packet to ip_output.
244df8bae1dSRodney W. Grimes  * Tack on options user may have setup with control call.
245df8bae1dSRodney W. Grimes  */
246df8bae1dSRodney W. Grimes int
2473b6dd5a9SSam Leffler rip_output(struct mbuf *m, struct socket *so, u_long dst)
248df8bae1dSRodney W. Grimes {
2493b6dd5a9SSam Leffler 	struct ip *ip;
250ac830b58SBosko Milekic 	int error;
2513b6dd5a9SSam Leffler 	struct inpcb *inp = sotoinpcb(so);
252b5d47ff5SJohn-Mark Gurney 	int flags = ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) |
253b5d47ff5SJohn-Mark Gurney 	    IP_ALLOWBROADCAST;
254df8bae1dSRodney W. Grimes 
255df8bae1dSRodney W. Grimes 	/*
256df8bae1dSRodney W. Grimes 	 * If the user handed us a complete IP packet, use it.
257df8bae1dSRodney W. Grimes 	 * Otherwise, allocate an mbuf for a header and fill it in.
258df8bae1dSRodney W. Grimes 	 */
259df8bae1dSRodney W. Grimes 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
260430d30d8SBill Fenner 		if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
261430d30d8SBill Fenner 			m_freem(m);
262430d30d8SBill Fenner 			return(EMSGSIZE);
263430d30d8SBill Fenner 		}
2642d01d331SRobert Watson 		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
2656b48911bSRobert Watson 		if (m == NULL)
2666b48911bSRobert Watson 			return(ENOBUFS);
267ac830b58SBosko Milekic 
268ac830b58SBosko Milekic 		INP_LOCK(inp);
269df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
2708ce3f3ddSRuslan Ermilov 		ip->ip_tos = inp->inp_ip_tos;
271df8bae1dSRodney W. Grimes 		ip->ip_off = 0;
272ca98b82cSDavid Greenman 		ip->ip_p = inp->inp_ip_p;
273df8bae1dSRodney W. Grimes 		ip->ip_len = m->m_pkthdr.len;
2745a59cefcSBosko Milekic 		if (jailed(inp->inp_socket->so_cred))
2755a59cefcSBosko Milekic 			ip->ip_src.s_addr =
2765a59cefcSBosko Milekic 			    htonl(prison_getip(inp->inp_socket->so_cred));
2775a59cefcSBosko Milekic 		else
278df8bae1dSRodney W. Grimes 			ip->ip_src = inp->inp_laddr;
279df8bae1dSRodney W. Grimes 		ip->ip_dst.s_addr = dst;
2808ce3f3ddSRuslan Ermilov 		ip->ip_ttl = inp->inp_ip_ttl;
281df8bae1dSRodney W. Grimes 	} else {
282430d30d8SBill Fenner 		if (m->m_pkthdr.len > IP_MAXPACKET) {
283430d30d8SBill Fenner 			m_freem(m);
284430d30d8SBill Fenner 			return(EMSGSIZE);
285430d30d8SBill Fenner 		}
286ac830b58SBosko Milekic 		INP_LOCK(inp);
287df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
2885a59cefcSBosko Milekic 		if (jailed(inp->inp_socket->so_cred)) {
2895a59cefcSBosko Milekic 			if (ip->ip_src.s_addr !=
2905a59cefcSBosko Milekic 			    htonl(prison_getip(inp->inp_socket->so_cred))) {
291ac830b58SBosko Milekic 				INP_UNLOCK(inp);
2925a59cefcSBosko Milekic 				m_freem(m);
2935a59cefcSBosko Milekic 				return (EPERM);
2945a59cefcSBosko Milekic 			}
2955a59cefcSBosko Milekic 		}
296072b9b24SPaul Traina 		/* don't allow both user specified and setsockopt options,
297072b9b24SPaul Traina 		   and don't allow packet length sizes that will crash */
29853be11f6SPoul-Henning Kamp 		if (((ip->ip_hl != (sizeof (*ip) >> 2))
2995e2d0696SGarrett Wollman 		     && inp->inp_options)
30091108995SBill Fenner 		    || (ip->ip_len > m->m_pkthdr.len)
30153be11f6SPoul-Henning Kamp 		    || (ip->ip_len < (ip->ip_hl << 2))) {
302ac830b58SBosko Milekic 			INP_UNLOCK(inp);
303072b9b24SPaul Traina 			m_freem(m);
304072b9b24SPaul Traina 			return EINVAL;
305072b9b24SPaul Traina 		}
306df8bae1dSRodney W. Grimes 		if (ip->ip_id == 0)
3071f44b0a1SDavid Malone 			ip->ip_id = ip_newid();
308df8bae1dSRodney W. Grimes 		/* XXX prevent ip_output from overwriting header fields */
309df8bae1dSRodney W. Grimes 		flags |= IP_RAWOUTPUT;
310df8bae1dSRodney W. Grimes 		ipstat.ips_rawout++;
311df8bae1dSRodney W. Grimes 	}
3126a800098SYoshinobu Inoue 
3138afa2304SBruce M Simpson 	if (inp->inp_flags & INP_ONESBCAST)
3148afa2304SBruce M Simpson 		flags |= IP_SENDONES;
3158afa2304SBruce M Simpson 
316ac830b58SBosko Milekic #ifdef MAC
317ac830b58SBosko Milekic 	mac_create_mbuf_from_inpcb(inp, m);
318ac830b58SBosko Milekic #endif
319ac830b58SBosko Milekic 
320ac830b58SBosko Milekic 	error = ip_output(m, inp->inp_options, NULL, flags,
321ac830b58SBosko Milekic 	    inp->inp_moptions, inp);
322ac830b58SBosko Milekic 	INP_UNLOCK(inp);
323ac830b58SBosko Milekic 	return error;
324df8bae1dSRodney W. Grimes }
325df8bae1dSRodney W. Grimes 
326df8bae1dSRodney W. Grimes /*
327df8bae1dSRodney W. Grimes  * Raw IP socket option processing.
32883503a92SRobert Watson  *
3296c67b8b6SRobert Watson  * IMPORTANT NOTE regarding access control: Traditionally, raw sockets could
3306c67b8b6SRobert Watson  * only be created by a privileged process, and as such, socket option
3316c67b8b6SRobert Watson  * operations to manage system properties on any raw socket were allowed to
3326c67b8b6SRobert Watson  * take place without explicit additional access control checks.  However,
3336c67b8b6SRobert Watson  * raw sockets can now also be created in jail(), and therefore explicit
3346c67b8b6SRobert Watson  * checks are now required.  Likewise, raw sockets can be used by a process
3356c67b8b6SRobert Watson  * after it gives up privilege, so some caution is required.  For options
3366c67b8b6SRobert Watson  * passed down to the IP layer via ip_ctloutput(), checks are assumed to be
3376c67b8b6SRobert Watson  * performed in ip_ctloutput() and therefore no check occurs here.
3386c67b8b6SRobert Watson  * Unilaterally checking suser() here breaks normal IP socket option
3396c67b8b6SRobert Watson  * operations on raw sockets.
3406c67b8b6SRobert Watson  *
3416c67b8b6SRobert Watson  * When adding new socket options here, make sure to add access control
3426c67b8b6SRobert Watson  * checks here as necessary.
343df8bae1dSRodney W. Grimes  */
344df8bae1dSRodney W. Grimes int
3453b6dd5a9SSam Leffler rip_ctloutput(struct socket *so, struct sockopt *sopt)
346df8bae1dSRodney W. Grimes {
347cfe8b629SGarrett Wollman 	struct	inpcb *inp = sotoinpcb(so);
348cfe8b629SGarrett Wollman 	int	error, optval;
349df8bae1dSRodney W. Grimes 
350cfe8b629SGarrett Wollman 	if (sopt->sopt_level != IPPROTO_IP)
351df8bae1dSRodney W. Grimes 		return (EINVAL);
352df8bae1dSRodney W. Grimes 
35325f26ad8SGarrett Wollman 	error = 0;
354cfe8b629SGarrett Wollman 	switch (sopt->sopt_dir) {
355cfe8b629SGarrett Wollman 	case SOPT_GET:
356cfe8b629SGarrett Wollman 		switch (sopt->sopt_name) {
357cfe8b629SGarrett Wollman 		case IP_HDRINCL:
358cfe8b629SGarrett Wollman 			optval = inp->inp_flags & INP_HDRINCL;
359cfe8b629SGarrett Wollman 			error = sooptcopyout(sopt, &optval, sizeof optval);
360cfe8b629SGarrett Wollman 			break;
361df8bae1dSRodney W. Grimes 
3627b109fa4SLuigi Rizzo 		case IP_FW_ADD:	/* ADD actually returns the body... */
36309bb5f75SPoul-Henning Kamp 		case IP_FW_GET:
364cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_GETSIZE:
365cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_LIST:
3666c67b8b6SRobert Watson 			error = suser(curthread);
3676c67b8b6SRobert Watson 			if (error != 0)
3686c67b8b6SRobert Watson 				return (error);
3699b932e9eSAndre Oppermann 			if (ip_fw_ctl_ptr != NULL)
370cfe8b629SGarrett Wollman 				error = ip_fw_ctl_ptr(sopt);
3717b109fa4SLuigi Rizzo 			else
3727b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
373cfe8b629SGarrett Wollman 			break;
3744dd1662bSUgen J.S. Antsilevich 
375b715f178SLuigi Rizzo 		case IP_DUMMYNET_GET:
3766c67b8b6SRobert Watson 			error = suser(curthread);
3776c67b8b6SRobert Watson 			if (error != 0)
3786c67b8b6SRobert Watson 				return (error);
3799b932e9eSAndre Oppermann 			if (ip_dn_ctl_ptr != NULL)
380b715f178SLuigi Rizzo 				error = ip_dn_ctl_ptr(sopt);
3817b109fa4SLuigi Rizzo 			else
3827b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
383b715f178SLuigi Rizzo 			break ;
3841c5de19aSGarrett Wollman 
3851c5de19aSGarrett Wollman 		case MRT_INIT:
3861c5de19aSGarrett Wollman 		case MRT_DONE:
3871c5de19aSGarrett Wollman 		case MRT_ADD_VIF:
3881c5de19aSGarrett Wollman 		case MRT_DEL_VIF:
3891c5de19aSGarrett Wollman 		case MRT_ADD_MFC:
3901c5de19aSGarrett Wollman 		case MRT_DEL_MFC:
3911c5de19aSGarrett Wollman 		case MRT_VERSION:
3921c5de19aSGarrett Wollman 		case MRT_ASSERT:
3931e78ac21SJeffrey Hsu 		case MRT_API_SUPPORT:
3941e78ac21SJeffrey Hsu 		case MRT_API_CONFIG:
3951e78ac21SJeffrey Hsu 		case MRT_ADD_BW_UPCALL:
3961e78ac21SJeffrey Hsu 		case MRT_DEL_BW_UPCALL:
3976c67b8b6SRobert Watson 			error = suser(curthread);
3986c67b8b6SRobert Watson 			if (error != 0)
3996c67b8b6SRobert Watson 				return (error);
400bbb4330bSLuigi Rizzo 			error = ip_mrouter_get ? ip_mrouter_get(so, sopt) :
401bbb4330bSLuigi Rizzo 				EOPNOTSUPP;
402cfe8b629SGarrett Wollman 			break;
403cfe8b629SGarrett Wollman 
404cfe8b629SGarrett Wollman 		default:
405cfe8b629SGarrett Wollman 			error = ip_ctloutput(so, sopt);
406cfe8b629SGarrett Wollman 			break;
407df8bae1dSRodney W. Grimes 		}
408cfe8b629SGarrett Wollman 		break;
409cfe8b629SGarrett Wollman 
410cfe8b629SGarrett Wollman 	case SOPT_SET:
411cfe8b629SGarrett Wollman 		switch (sopt->sopt_name) {
412cfe8b629SGarrett Wollman 		case IP_HDRINCL:
413cfe8b629SGarrett Wollman 			error = sooptcopyin(sopt, &optval, sizeof optval,
414cfe8b629SGarrett Wollman 					    sizeof optval);
415cfe8b629SGarrett Wollman 			if (error)
416cfe8b629SGarrett Wollman 				break;
417cfe8b629SGarrett Wollman 			if (optval)
418cfe8b629SGarrett Wollman 				inp->inp_flags |= INP_HDRINCL;
419cfe8b629SGarrett Wollman 			else
420cfe8b629SGarrett Wollman 				inp->inp_flags &= ~INP_HDRINCL;
421cfe8b629SGarrett Wollman 			break;
422cfe8b629SGarrett Wollman 
4238ba03966SRuslan Ermilov 		case IP_FW_ADD:
424cfe8b629SGarrett Wollman 		case IP_FW_DEL:
425cfe8b629SGarrett Wollman 		case IP_FW_FLUSH:
426cfe8b629SGarrett Wollman 		case IP_FW_ZERO:
4270b6c1a83SBrian Feldman 		case IP_FW_RESETLOG:
428cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_ADD:
429cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_DEL:
430cd8b5ae0SRuslan Ermilov 		case IP_FW_TABLE_FLUSH:
4316c67b8b6SRobert Watson 			error = suser(curthread);
4326c67b8b6SRobert Watson 			if (error != 0)
4336c67b8b6SRobert Watson 				return (error);
4349b932e9eSAndre Oppermann 			if (ip_fw_ctl_ptr != NULL)
435cfe8b629SGarrett Wollman 				error = ip_fw_ctl_ptr(sopt);
4367b109fa4SLuigi Rizzo 			else
4377b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
438cfe8b629SGarrett Wollman 			break;
439cfe8b629SGarrett Wollman 
440b715f178SLuigi Rizzo 		case IP_DUMMYNET_CONFIGURE:
441b715f178SLuigi Rizzo 		case IP_DUMMYNET_DEL:
442b715f178SLuigi Rizzo 		case IP_DUMMYNET_FLUSH:
4436c67b8b6SRobert Watson 			error = suser(curthread);
4446c67b8b6SRobert Watson 			if (error != 0)
4456c67b8b6SRobert Watson 				return (error);
4469b932e9eSAndre Oppermann 			if (ip_dn_ctl_ptr != NULL)
447b715f178SLuigi Rizzo 				error = ip_dn_ctl_ptr(sopt);
4487b109fa4SLuigi Rizzo 			else
4497b109fa4SLuigi Rizzo 				error = ENOPROTOOPT ;
450b715f178SLuigi Rizzo 			break ;
451cfe8b629SGarrett Wollman 
452cfe8b629SGarrett Wollman 		case IP_RSVP_ON:
4536c67b8b6SRobert Watson 			error = suser(curthread);
4546c67b8b6SRobert Watson 			if (error != 0)
4556c67b8b6SRobert Watson 				return (error);
456cfe8b629SGarrett Wollman 			error = ip_rsvp_init(so);
457cfe8b629SGarrett Wollman 			break;
458cfe8b629SGarrett Wollman 
459cfe8b629SGarrett Wollman 		case IP_RSVP_OFF:
4606c67b8b6SRobert Watson 			error = suser(curthread);
4616c67b8b6SRobert Watson 			if (error != 0)
4626c67b8b6SRobert Watson 				return (error);
463cfe8b629SGarrett Wollman 			error = ip_rsvp_done();
464cfe8b629SGarrett Wollman 			break;
465cfe8b629SGarrett Wollman 
466cfe8b629SGarrett Wollman 		case IP_RSVP_VIF_ON:
467cfe8b629SGarrett Wollman 		case IP_RSVP_VIF_OFF:
4686c67b8b6SRobert Watson 			error = suser(curthread);
4696c67b8b6SRobert Watson 			if (error != 0)
4706c67b8b6SRobert Watson 				return (error);
471bbb4330bSLuigi Rizzo 			error = ip_rsvp_vif ?
472bbb4330bSLuigi Rizzo 				ip_rsvp_vif(so, sopt) : EINVAL;
473cfe8b629SGarrett Wollman 			break;
474cfe8b629SGarrett Wollman 
475cfe8b629SGarrett Wollman 		case MRT_INIT:
476cfe8b629SGarrett Wollman 		case MRT_DONE:
477cfe8b629SGarrett Wollman 		case MRT_ADD_VIF:
478cfe8b629SGarrett Wollman 		case MRT_DEL_VIF:
479cfe8b629SGarrett Wollman 		case MRT_ADD_MFC:
480cfe8b629SGarrett Wollman 		case MRT_DEL_MFC:
481cfe8b629SGarrett Wollman 		case MRT_VERSION:
482cfe8b629SGarrett Wollman 		case MRT_ASSERT:
4831e78ac21SJeffrey Hsu 		case MRT_API_SUPPORT:
4841e78ac21SJeffrey Hsu 		case MRT_API_CONFIG:
4851e78ac21SJeffrey Hsu 		case MRT_ADD_BW_UPCALL:
4861e78ac21SJeffrey Hsu 		case MRT_DEL_BW_UPCALL:
4876c67b8b6SRobert Watson 			error = suser(curthread);
4886c67b8b6SRobert Watson 			if (error != 0)
4896c67b8b6SRobert Watson 				return (error);
490bbb4330bSLuigi Rizzo 			error = ip_mrouter_set ? ip_mrouter_set(so, sopt) :
491bbb4330bSLuigi Rizzo 					EOPNOTSUPP;
492cfe8b629SGarrett Wollman 			break;
493cfe8b629SGarrett Wollman 
494cfe8b629SGarrett Wollman 		default:
495cfe8b629SGarrett Wollman 			error = ip_ctloutput(so, sopt);
496cfe8b629SGarrett Wollman 			break;
497cfe8b629SGarrett Wollman 		}
498cfe8b629SGarrett Wollman 		break;
499cfe8b629SGarrett Wollman 	}
500cfe8b629SGarrett Wollman 
501cfe8b629SGarrett Wollman 	return (error);
502df8bae1dSRodney W. Grimes }
503df8bae1dSRodney W. Grimes 
50439191c8eSGarrett Wollman /*
50539191c8eSGarrett Wollman  * This function exists solely to receive the PRC_IFDOWN messages which
50639191c8eSGarrett Wollman  * are sent by if_down().  It looks for an ifaddr whose ifa_addr is sa,
50739191c8eSGarrett Wollman  * and calls in_ifadown() to remove all routes corresponding to that address.
50839191c8eSGarrett Wollman  * It also receives the PRC_IFUP messages from if_up() and reinstalls the
50939191c8eSGarrett Wollman  * interface routes.
51039191c8eSGarrett Wollman  */
51139191c8eSGarrett Wollman void
5123b6dd5a9SSam Leffler rip_ctlinput(int cmd, struct sockaddr *sa, void *vip)
51339191c8eSGarrett Wollman {
51439191c8eSGarrett Wollman 	struct in_ifaddr *ia;
51539191c8eSGarrett Wollman 	struct ifnet *ifp;
51639191c8eSGarrett Wollman 	int err;
51739191c8eSGarrett Wollman 	int flags;
51839191c8eSGarrett Wollman 
51939191c8eSGarrett Wollman 	switch (cmd) {
52039191c8eSGarrett Wollman 	case PRC_IFDOWN:
521462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
52239191c8eSGarrett Wollman 			if (ia->ia_ifa.ifa_addr == sa
52339191c8eSGarrett Wollman 			    && (ia->ia_flags & IFA_ROUTE)) {
52439191c8eSGarrett Wollman 				/*
52539191c8eSGarrett Wollman 				 * in_ifscrub kills the interface route.
52639191c8eSGarrett Wollman 				 */
52739191c8eSGarrett Wollman 				in_ifscrub(ia->ia_ifp, ia);
52839191c8eSGarrett Wollman 				/*
52939191c8eSGarrett Wollman 				 * in_ifadown gets rid of all the rest of
53039191c8eSGarrett Wollman 				 * the routes.  This is not quite the right
53139191c8eSGarrett Wollman 				 * thing to do, but at least if we are running
53239191c8eSGarrett Wollman 				 * a routing process they will come back.
53339191c8eSGarrett Wollman 				 */
53491854268SRuslan Ermilov 				in_ifadown(&ia->ia_ifa, 0);
53539191c8eSGarrett Wollman 				break;
53639191c8eSGarrett Wollman 			}
53739191c8eSGarrett Wollman 		}
53839191c8eSGarrett Wollman 		break;
53939191c8eSGarrett Wollman 
54039191c8eSGarrett Wollman 	case PRC_IFUP:
541462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
54239191c8eSGarrett Wollman 			if (ia->ia_ifa.ifa_addr == sa)
54339191c8eSGarrett Wollman 				break;
54439191c8eSGarrett Wollman 		}
54539191c8eSGarrett Wollman 		if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
54639191c8eSGarrett Wollman 			return;
54739191c8eSGarrett Wollman 		flags = RTF_UP;
54839191c8eSGarrett Wollman 		ifp = ia->ia_ifa.ifa_ifp;
54939191c8eSGarrett Wollman 
55039191c8eSGarrett Wollman 		if ((ifp->if_flags & IFF_LOOPBACK)
55139191c8eSGarrett Wollman 		    || (ifp->if_flags & IFF_POINTOPOINT))
55239191c8eSGarrett Wollman 			flags |= RTF_HOST;
55339191c8eSGarrett Wollman 
55439191c8eSGarrett Wollman 		err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
55539191c8eSGarrett Wollman 		if (err == 0)
55639191c8eSGarrett Wollman 			ia->ia_flags |= IFA_ROUTE;
55739191c8eSGarrett Wollman 		break;
55839191c8eSGarrett Wollman 	}
55939191c8eSGarrett Wollman }
56039191c8eSGarrett Wollman 
56182cd038dSYoshinobu Inoue u_long	rip_sendspace = RIPSNDQ;
56282cd038dSYoshinobu Inoue u_long	rip_recvspace = RIPRCVQ;
563df8bae1dSRodney W. Grimes 
5643d177f46SBill Fumerola SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
5653d177f46SBill Fumerola     &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
5663d177f46SBill Fumerola SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
5670ca2861fSRuslan Ermilov     &rip_recvspace, 0, "Maximum space for incoming raw IP datagrams");
568117bcae7SGarrett Wollman 
569117bcae7SGarrett Wollman static int
570b40ce416SJulian Elischer rip_attach(struct socket *so, int proto, struct thread *td)
571df8bae1dSRodney W. Grimes {
572117bcae7SGarrett Wollman 	struct inpcb *inp;
5733b6dd5a9SSam Leffler 	int error;
574c1f8a6ceSDavid Greenman 
5753b6dd5a9SSam Leffler 	/* XXX why not lower? */
5763b6dd5a9SSam Leffler 	INP_INFO_WLOCK(&ripcbinfo);
577117bcae7SGarrett Wollman 	inp = sotoinpcb(so);
5783b6dd5a9SSam Leffler 	if (inp) {
5793b6dd5a9SSam Leffler 		/* XXX counter, printf */
5803b6dd5a9SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
5813b6dd5a9SSam Leffler 		return EINVAL;
5823b6dd5a9SSam Leffler 	}
583812d8653SSam Leffler 	if (jailed(td->td_ucred) && !jail_allow_raw_sockets) {
5845a59cefcSBosko Milekic 		INP_INFO_WUNLOCK(&ripcbinfo);
5855a59cefcSBosko Milekic 		return (EPERM);
5865a59cefcSBosko Milekic 	}
587812d8653SSam Leffler 	if ((error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) != 0) {
5883b6dd5a9SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
589a29f300eSGarrett Wollman 		return error;
5903b6dd5a9SSam Leffler 	}
5913b6dd5a9SSam Leffler 	if (proto >= IPPROTO_MAX || proto < 0) {
5923b6dd5a9SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
5934d3ffc98SBill Fenner 		return EPROTONOSUPPORT;
5943b6dd5a9SSam Leffler 	}
5954d3ffc98SBill Fenner 
5966a800098SYoshinobu Inoue 	error = soreserve(so, rip_sendspace, rip_recvspace);
5973b6dd5a9SSam Leffler 	if (error) {
5983b6dd5a9SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
5996a800098SYoshinobu Inoue 		return error;
6003b6dd5a9SSam Leffler 	}
6016823b823SPawel Jakub Dawidek 	error = in_pcballoc(so, &ripcbinfo, "rawinp");
6023b6dd5a9SSam Leffler 	if (error) {
6033b6dd5a9SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
60486b3ebceSDavid Greenman 		return error;
6053b6dd5a9SSam Leffler 	}
606df8bae1dSRodney W. Grimes 	inp = (struct inpcb *)so->so_pcb;
6073b6dd5a9SSam Leffler 	INP_LOCK(inp);
6083b6dd5a9SSam Leffler 	INP_INFO_WUNLOCK(&ripcbinfo);
6096a800098SYoshinobu Inoue 	inp->inp_vflag |= INP_IPV4;
610ca98b82cSDavid Greenman 	inp->inp_ip_p = proto;
6118ce3f3ddSRuslan Ermilov 	inp->inp_ip_ttl = ip_defttl;
6123b6dd5a9SSam Leffler 	INP_UNLOCK(inp);
613117bcae7SGarrett Wollman 	return 0;
614df8bae1dSRodney W. Grimes }
615117bcae7SGarrett Wollman 
61650d7c061SSam Leffler static void
61750d7c061SSam Leffler rip_pcbdetach(struct socket *so, struct inpcb *inp)
61850d7c061SSam Leffler {
6193ca1570cSRobert Watson 
62050d7c061SSam Leffler 	INP_INFO_WLOCK_ASSERT(&ripcbinfo);
62150d7c061SSam Leffler 	INP_LOCK_ASSERT(inp);
62250d7c061SSam Leffler 
62350d7c061SSam Leffler 	if (so == ip_mrouter && ip_mrouter_done)
62450d7c061SSam Leffler 		ip_mrouter_done();
62550d7c061SSam Leffler 	if (ip_rsvp_force_done)
62650d7c061SSam Leffler 		ip_rsvp_force_done(so);
62750d7c061SSam Leffler 	if (so == ip_rsvpd)
62850d7c061SSam Leffler 		ip_rsvp_done();
62950d7c061SSam Leffler 	in_pcbdetach(inp);
63050d7c061SSam Leffler }
63150d7c061SSam Leffler 
632117bcae7SGarrett Wollman static int
633117bcae7SGarrett Wollman rip_detach(struct socket *so)
634117bcae7SGarrett Wollman {
635117bcae7SGarrett Wollman 	struct inpcb *inp;
636117bcae7SGarrett Wollman 
6373b6dd5a9SSam Leffler 	INP_INFO_WLOCK(&ripcbinfo);
638117bcae7SGarrett Wollman 	inp = sotoinpcb(so);
6393b6dd5a9SSam Leffler 	if (inp == 0) {
6403b6dd5a9SSam Leffler 		/* XXX counter, printf */
6413b6dd5a9SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
6423b6dd5a9SSam Leffler 		return EINVAL;
6433b6dd5a9SSam Leffler 	}
6443b6dd5a9SSam Leffler 	INP_LOCK(inp);
64550d7c061SSam Leffler 	rip_pcbdetach(so, inp);
6463b6dd5a9SSam Leffler 	INP_INFO_WUNLOCK(&ripcbinfo);
647117bcae7SGarrett Wollman 	return 0;
648117bcae7SGarrett Wollman }
649df8bae1dSRodney W. Grimes 
650117bcae7SGarrett Wollman static int
651117bcae7SGarrett Wollman rip_abort(struct socket *so)
652df8bae1dSRodney W. Grimes {
65350d7c061SSam Leffler 	struct inpcb *inp;
65450d7c061SSam Leffler 
65550d7c061SSam Leffler 	INP_INFO_WLOCK(&ripcbinfo);
65650d7c061SSam Leffler 	inp = sotoinpcb(so);
65750d7c061SSam Leffler 	if (inp == 0) {
65850d7c061SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
65950d7c061SSam Leffler 		return EINVAL;	/* ??? possible? panic instead? */
66050d7c061SSam Leffler 	}
66150d7c061SSam Leffler 	INP_LOCK(inp);
662117bcae7SGarrett Wollman 	soisdisconnected(so);
663f5c57460SJeffrey Hsu 	if (so->so_state & SS_NOFDREF)
66450d7c061SSam Leffler 		rip_pcbdetach(so, inp);
6658c8268cbSOlivier Houchard 	else
6668c8268cbSOlivier Houchard 		INP_UNLOCK(inp);
66750d7c061SSam Leffler 	INP_INFO_WUNLOCK(&ripcbinfo);
668f5c57460SJeffrey Hsu 	return 0;
669117bcae7SGarrett Wollman }
670117bcae7SGarrett Wollman 
671117bcae7SGarrett Wollman static int
672117bcae7SGarrett Wollman rip_disconnect(struct socket *so)
673117bcae7SGarrett Wollman {
6744cc20ab1SSeigo Tanimura 	if ((so->so_state & SS_ISCONNECTED) == 0)
675117bcae7SGarrett Wollman 		return ENOTCONN;
676117bcae7SGarrett Wollman 	return rip_abort(so);
677117bcae7SGarrett Wollman }
678117bcae7SGarrett Wollman 
679117bcae7SGarrett Wollman static int
680b40ce416SJulian Elischer rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
681117bcae7SGarrett Wollman {
68257bf258eSGarrett Wollman 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
68350d7c061SSam Leffler 	struct inpcb *inp;
684df8bae1dSRodney W. Grimes 
68557bf258eSGarrett Wollman 	if (nam->sa_len != sizeof(*addr))
686117bcae7SGarrett Wollman 		return EINVAL;
687117bcae7SGarrett Wollman 
6885a59cefcSBosko Milekic 	if (jailed(td->td_ucred)) {
6895a59cefcSBosko Milekic 		if (addr->sin_addr.s_addr == INADDR_ANY)
6905a59cefcSBosko Milekic 			addr->sin_addr.s_addr =
6915a59cefcSBosko Milekic 			    htonl(prison_getip(td->td_ucred));
6921a0c4873SMaxim Konovalov 		if (htonl(prison_getip(td->td_ucred)) != addr->sin_addr.s_addr)
6935a59cefcSBosko Milekic 			return (EADDRNOTAVAIL);
6945a59cefcSBosko Milekic 	}
6955a59cefcSBosko Milekic 
69650d7c061SSam Leffler 	if (TAILQ_EMPTY(&ifnet) ||
69750d7c061SSam Leffler 	    (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) ||
698032dcc76SLuigi Rizzo 	    (addr->sin_addr.s_addr &&
699117bcae7SGarrett Wollman 	     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
700117bcae7SGarrett Wollman 		return EADDRNOTAVAIL;
70150d7c061SSam Leffler 
70250d7c061SSam Leffler 	INP_INFO_WLOCK(&ripcbinfo);
70350d7c061SSam Leffler 	inp = sotoinpcb(so);
70450d7c061SSam Leffler 	if (inp == 0) {
70550d7c061SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
70650d7c061SSam Leffler 		return EINVAL;
70750d7c061SSam Leffler 	}
70850d7c061SSam Leffler 	INP_LOCK(inp);
709df8bae1dSRodney W. Grimes 	inp->inp_laddr = addr->sin_addr;
71050d7c061SSam Leffler 	INP_UNLOCK(inp);
71150d7c061SSam Leffler 	INP_INFO_WUNLOCK(&ripcbinfo);
712117bcae7SGarrett Wollman 	return 0;
713df8bae1dSRodney W. Grimes }
714117bcae7SGarrett Wollman 
715117bcae7SGarrett Wollman static int
716b40ce416SJulian Elischer rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
717df8bae1dSRodney W. Grimes {
71857bf258eSGarrett Wollman 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
71950d7c061SSam Leffler 	struct inpcb *inp;
720df8bae1dSRodney W. Grimes 
72157bf258eSGarrett Wollman 	if (nam->sa_len != sizeof(*addr))
722117bcae7SGarrett Wollman 		return EINVAL;
723117bcae7SGarrett Wollman 	if (TAILQ_EMPTY(&ifnet))
724117bcae7SGarrett Wollman 		return EADDRNOTAVAIL;
72550d7c061SSam Leffler 	if (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK)
726117bcae7SGarrett Wollman 		return EAFNOSUPPORT;
72750d7c061SSam Leffler 
72850d7c061SSam Leffler 	INP_INFO_WLOCK(&ripcbinfo);
72950d7c061SSam Leffler 	inp = sotoinpcb(so);
73050d7c061SSam Leffler 	if (inp == 0) {
73150d7c061SSam Leffler 		INP_INFO_WUNLOCK(&ripcbinfo);
73250d7c061SSam Leffler 		return EINVAL;
73350d7c061SSam Leffler 	}
73450d7c061SSam Leffler 	INP_LOCK(inp);
735df8bae1dSRodney W. Grimes 	inp->inp_faddr = addr->sin_addr;
736df8bae1dSRodney W. Grimes 	soisconnected(so);
73750d7c061SSam Leffler 	INP_UNLOCK(inp);
73850d7c061SSam Leffler 	INP_INFO_WUNLOCK(&ripcbinfo);
739117bcae7SGarrett Wollman 	return 0;
740df8bae1dSRodney W. Grimes }
741df8bae1dSRodney W. Grimes 
742117bcae7SGarrett Wollman static int
743117bcae7SGarrett Wollman rip_shutdown(struct socket *so)
744df8bae1dSRodney W. Grimes {
74550d7c061SSam Leffler 	struct inpcb *inp;
74650d7c061SSam Leffler 
74750d7c061SSam Leffler 	INP_INFO_RLOCK(&ripcbinfo);
74850d7c061SSam Leffler 	inp = sotoinpcb(so);
74950d7c061SSam Leffler 	if (inp == 0) {
75050d7c061SSam Leffler 		INP_INFO_RUNLOCK(&ripcbinfo);
75150d7c061SSam Leffler 		return EINVAL;
75250d7c061SSam Leffler 	}
75350d7c061SSam Leffler 	INP_LOCK(inp);
75450d7c061SSam Leffler 	INP_INFO_RUNLOCK(&ripcbinfo);
755117bcae7SGarrett Wollman 	socantsendmore(so);
75650d7c061SSam Leffler 	INP_UNLOCK(inp);
757117bcae7SGarrett Wollman 	return 0;
758117bcae7SGarrett Wollman }
759117bcae7SGarrett Wollman 
760117bcae7SGarrett Wollman static int
76157bf258eSGarrett Wollman rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
762b40ce416SJulian Elischer 	 struct mbuf *control, struct thread *td)
763117bcae7SGarrett Wollman {
76450d7c061SSam Leffler 	struct inpcb *inp;
76550d7c061SSam Leffler 	u_long dst;
76650d7c061SSam Leffler 	int ret;
767df8bae1dSRodney W. Grimes 
76850d7c061SSam Leffler 	INP_INFO_WLOCK(&ripcbinfo);
76950d7c061SSam Leffler 	inp = sotoinpcb(so);
770df8bae1dSRodney W. Grimes 	if (so->so_state & SS_ISCONNECTED) {
771df8bae1dSRodney W. Grimes 		if (nam) {
77250d7c061SSam Leffler 			INP_INFO_WUNLOCK(&ripcbinfo);
773117bcae7SGarrett Wollman 			m_freem(m);
774117bcae7SGarrett Wollman 			return EISCONN;
775df8bae1dSRodney W. Grimes 		}
776df8bae1dSRodney W. Grimes 		dst = inp->inp_faddr.s_addr;
777df8bae1dSRodney W. Grimes 	} else {
778df8bae1dSRodney W. Grimes 		if (nam == NULL) {
77950d7c061SSam Leffler 			INP_INFO_WUNLOCK(&ripcbinfo);
780117bcae7SGarrett Wollman 			m_freem(m);
781117bcae7SGarrett Wollman 			return ENOTCONN;
782df8bae1dSRodney W. Grimes 		}
78357bf258eSGarrett Wollman 		dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
784df8bae1dSRodney W. Grimes 	}
78550d7c061SSam Leffler 	ret = rip_output(m, so, dst);
78650d7c061SSam Leffler 	INP_INFO_WUNLOCK(&ripcbinfo);
78750d7c061SSam Leffler 	return ret;
788df8bae1dSRodney W. Grimes }
789df8bae1dSRodney W. Grimes 
79098271db4SGarrett Wollman static int
79182d9ae4eSPoul-Henning Kamp rip_pcblist(SYSCTL_HANDLER_ARGS)
79298271db4SGarrett Wollman {
7933b6dd5a9SSam Leffler 	int error, i, n;
79498271db4SGarrett Wollman 	struct inpcb *inp, **inp_list;
79598271db4SGarrett Wollman 	inp_gen_t gencnt;
79698271db4SGarrett Wollman 	struct xinpgen xig;
79798271db4SGarrett Wollman 
79898271db4SGarrett Wollman 	/*
79998271db4SGarrett Wollman 	 * The process of preparing the TCB list is too time-consuming and
80098271db4SGarrett Wollman 	 * resource-intensive to repeat twice on every request.
80198271db4SGarrett Wollman 	 */
80298271db4SGarrett Wollman 	if (req->oldptr == 0) {
80398271db4SGarrett Wollman 		n = ripcbinfo.ipi_count;
80498271db4SGarrett Wollman 		req->oldidx = 2 * (sizeof xig)
80598271db4SGarrett Wollman 			+ (n + n/8) * sizeof(struct xinpcb);
80698271db4SGarrett Wollman 		return 0;
80798271db4SGarrett Wollman 	}
80898271db4SGarrett Wollman 
80998271db4SGarrett Wollman 	if (req->newptr != 0)
81098271db4SGarrett Wollman 		return EPERM;
81198271db4SGarrett Wollman 
81298271db4SGarrett Wollman 	/*
81398271db4SGarrett Wollman 	 * OK, now we're committed to doing something.
81498271db4SGarrett Wollman 	 */
8153b6dd5a9SSam Leffler 	INP_INFO_RLOCK(&ripcbinfo);
81698271db4SGarrett Wollman 	gencnt = ripcbinfo.ipi_gencnt;
81798271db4SGarrett Wollman 	n = ripcbinfo.ipi_count;
8183b6dd5a9SSam Leffler 	INP_INFO_RUNLOCK(&ripcbinfo);
81998271db4SGarrett Wollman 
82098271db4SGarrett Wollman 	xig.xig_len = sizeof xig;
82198271db4SGarrett Wollman 	xig.xig_count = n;
82298271db4SGarrett Wollman 	xig.xig_gen = gencnt;
82398271db4SGarrett Wollman 	xig.xig_sogen = so_gencnt;
82498271db4SGarrett Wollman 	error = SYSCTL_OUT(req, &xig, sizeof xig);
82598271db4SGarrett Wollman 	if (error)
82698271db4SGarrett Wollman 		return error;
82798271db4SGarrett Wollman 
828a163d034SWarner Losh 	inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
82998271db4SGarrett Wollman 	if (inp_list == 0)
83098271db4SGarrett Wollman 		return ENOMEM;
83198271db4SGarrett Wollman 
8323b6dd5a9SSam Leffler 	INP_INFO_RLOCK(&ripcbinfo);
833fc2ffbe6SPoul-Henning Kamp 	for (inp = LIST_FIRST(ripcbinfo.listhead), i = 0; inp && i < n;
834fc2ffbe6SPoul-Henning Kamp 	     inp = LIST_NEXT(inp, inp_list)) {
8353b6dd5a9SSam Leffler 		INP_LOCK(inp);
836f34f3a70SSam Leffler 		if (inp->inp_gencnt <= gencnt &&
837f34f3a70SSam Leffler 		    cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0) {
8383b6dd5a9SSam Leffler 			/* XXX held references? */
83998271db4SGarrett Wollman 			inp_list[i++] = inp;
84098271db4SGarrett Wollman 		}
8413b6dd5a9SSam Leffler 		INP_UNLOCK(inp);
8424787fd37SPaul Saab 	}
8433b6dd5a9SSam Leffler 	INP_INFO_RUNLOCK(&ripcbinfo);
84498271db4SGarrett Wollman 	n = i;
84598271db4SGarrett Wollman 
84698271db4SGarrett Wollman 	error = 0;
84798271db4SGarrett Wollman 	for (i = 0; i < n; i++) {
84898271db4SGarrett Wollman 		inp = inp_list[i];
84998271db4SGarrett Wollman 		if (inp->inp_gencnt <= gencnt) {
85098271db4SGarrett Wollman 			struct xinpcb xi;
851fd94099eSColin Percival 			bzero(&xi, sizeof(xi));
85298271db4SGarrett Wollman 			xi.xi_len = sizeof xi;
85398271db4SGarrett Wollman 			/* XXX should avoid extra copy */
85498271db4SGarrett Wollman 			bcopy(inp, &xi.xi_inp, sizeof *inp);
85598271db4SGarrett Wollman 			if (inp->inp_socket)
85698271db4SGarrett Wollman 				sotoxsocket(inp->inp_socket, &xi.xi_socket);
85798271db4SGarrett Wollman 			error = SYSCTL_OUT(req, &xi, sizeof xi);
85898271db4SGarrett Wollman 		}
85998271db4SGarrett Wollman 	}
86098271db4SGarrett Wollman 	if (!error) {
86198271db4SGarrett Wollman 		/*
86298271db4SGarrett Wollman 		 * Give the user an updated idea of our state.
86398271db4SGarrett Wollman 		 * If the generation differs from what we told
86498271db4SGarrett Wollman 		 * her before, she knows that something happened
86598271db4SGarrett Wollman 		 * while we were processing this request, and it
86698271db4SGarrett Wollman 		 * might be necessary to retry.
86798271db4SGarrett Wollman 		 */
8683b6dd5a9SSam Leffler 		INP_INFO_RLOCK(&ripcbinfo);
86998271db4SGarrett Wollman 		xig.xig_gen = ripcbinfo.ipi_gencnt;
87098271db4SGarrett Wollman 		xig.xig_sogen = so_gencnt;
87198271db4SGarrett Wollman 		xig.xig_count = ripcbinfo.ipi_count;
8723b6dd5a9SSam Leffler 		INP_INFO_RUNLOCK(&ripcbinfo);
87398271db4SGarrett Wollman 		error = SYSCTL_OUT(req, &xig, sizeof xig);
87498271db4SGarrett Wollman 	}
87598271db4SGarrett Wollman 	free(inp_list, M_TEMP);
87698271db4SGarrett Wollman 	return error;
87798271db4SGarrett Wollman }
87898271db4SGarrett Wollman 
879f76fcf6dSJeffrey Hsu /*
880f76fcf6dSJeffrey Hsu  * This is the wrapper function for in_setsockaddr.  We just pass down
881f76fcf6dSJeffrey Hsu  * the pcbinfo for in_setpeeraddr to lock.
882f76fcf6dSJeffrey Hsu  */
883f76fcf6dSJeffrey Hsu static int
884f76fcf6dSJeffrey Hsu rip_sockaddr(struct socket *so, struct sockaddr **nam)
885f76fcf6dSJeffrey Hsu {
886f76fcf6dSJeffrey Hsu 	return (in_setsockaddr(so, nam, &ripcbinfo));
887f76fcf6dSJeffrey Hsu }
888f76fcf6dSJeffrey Hsu 
889f76fcf6dSJeffrey Hsu /*
890f76fcf6dSJeffrey Hsu  * This is the wrapper function for in_setpeeraddr.  We just pass down
891f76fcf6dSJeffrey Hsu  * the pcbinfo for in_setpeeraddr to lock.
892f76fcf6dSJeffrey Hsu  */
893f76fcf6dSJeffrey Hsu static int
894f76fcf6dSJeffrey Hsu rip_peeraddr(struct socket *so, struct sockaddr **nam)
895f76fcf6dSJeffrey Hsu {
896f76fcf6dSJeffrey Hsu 	return (in_setpeeraddr(so, nam, &ripcbinfo));
897f76fcf6dSJeffrey Hsu }
898f76fcf6dSJeffrey Hsu 
899f76fcf6dSJeffrey Hsu 
90098271db4SGarrett Wollman SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
90198271db4SGarrett Wollman 	    rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
90298271db4SGarrett Wollman 
903117bcae7SGarrett Wollman struct pr_usrreqs rip_usrreqs = {
904756d52a1SPoul-Henning Kamp 	.pru_abort =		rip_abort,
905756d52a1SPoul-Henning Kamp 	.pru_attach =		rip_attach,
906756d52a1SPoul-Henning Kamp 	.pru_bind =		rip_bind,
907756d52a1SPoul-Henning Kamp 	.pru_connect =		rip_connect,
908756d52a1SPoul-Henning Kamp 	.pru_control =		in_control,
909756d52a1SPoul-Henning Kamp 	.pru_detach =		rip_detach,
910756d52a1SPoul-Henning Kamp 	.pru_disconnect =	rip_disconnect,
911756d52a1SPoul-Henning Kamp 	.pru_peeraddr =		rip_peeraddr,
912756d52a1SPoul-Henning Kamp 	.pru_send =		rip_send,
913756d52a1SPoul-Henning Kamp 	.pru_shutdown =		rip_shutdown,
914756d52a1SPoul-Henning Kamp 	.pru_sockaddr =		rip_sockaddr,
915756d52a1SPoul-Henning Kamp 	.pru_sosetlabel =	in_pcbsosetlabel
916117bcae7SGarrett Wollman };
917