xref: /freebsd/sys/netinet/raw_ip.c (revision 1e78ac216edcdcb63645d59c37b2df81b907260a)
1df8bae1dSRodney W. Grimes /*
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  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
3325f26ad8SGarrett Wollman  *	@(#)raw_ip.c	8.7 (Berkeley) 5/15/95
34c3aac50fSPeter Wemm  * $FreeBSD$
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
376a800098SYoshinobu Inoue #include "opt_inet6.h"
386a800098SYoshinobu Inoue #include "opt_ipsec.h"
394ea889c6SRobert Watson #include "opt_mac.h"
4064dddc18SKris Kennaway #include "opt_random_ip_id.h"
416a800098SYoshinobu Inoue 
42df8bae1dSRodney W. Grimes #include <sys/param.h>
43117bcae7SGarrett Wollman #include <sys/kernel.h>
44960ed29cSSeigo Tanimura #include <sys/lock.h>
453b6aad64SRobert Watson #include <sys/mac.h>
46df8bae1dSRodney W. Grimes #include <sys/malloc.h>
47df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
484787fd37SPaul Saab #include <sys/proc.h>
49df8bae1dSRodney W. Grimes #include <sys/protosw.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>
60df8bae1dSRodney W. Grimes #include <net/route.h>
61df8bae1dSRodney W. Grimes 
62df8bae1dSRodney W. Grimes #include <netinet/in.h>
63df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
64c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h>
65c1f8a6ceSDavid Greenman #include <netinet/in_var.h>
66960ed29cSSeigo Tanimura #include <netinet/ip.h>
67df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
68df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h>
69df8bae1dSRodney W. Grimes 
70100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h>
71db69a05dSPaul Saab #include <netinet/ip_dummynet.h>
72100ba1a6SJordan K. Hubbard 
73b9234fafSSam Leffler #ifdef FAST_IPSEC
74b9234fafSSam Leffler #include <netipsec/ipsec.h>
75b9234fafSSam Leffler #endif /*FAST_IPSEC*/
76b9234fafSSam Leffler 
776a800098SYoshinobu Inoue #ifdef IPSEC
786a800098SYoshinobu Inoue #include <netinet6/ipsec.h>
796a800098SYoshinobu Inoue #endif /*IPSEC*/
806a800098SYoshinobu Inoue 
8182cd038dSYoshinobu Inoue struct	inpcbhead ripcb;
8282cd038dSYoshinobu Inoue struct	inpcbinfo ripcbinfo;
83df8bae1dSRodney W. Grimes 
84db69a05dSPaul Saab /* control hooks for ipfw and dummynet */
85db69a05dSPaul Saab ip_fw_ctl_t *ip_fw_ctl_ptr;
86db69a05dSPaul Saab ip_dn_ctl_t *ip_dn_ctl_ptr;
87db69a05dSPaul Saab 
88df8bae1dSRodney W. Grimes /*
89bbb4330bSLuigi Rizzo  * hooks for multicast routing. They all default to NULL,
90bbb4330bSLuigi Rizzo  * so leave them not initialized and rely on BSS being set to 0.
91bbb4330bSLuigi Rizzo  */
92bbb4330bSLuigi Rizzo 
93bbb4330bSLuigi Rizzo /* The socket used to communicate with the multicast routing daemon.  */
94bbb4330bSLuigi Rizzo struct socket  *ip_mrouter;
95bbb4330bSLuigi Rizzo 
96bbb4330bSLuigi Rizzo /* The various mrouter and rsvp functions */
97bbb4330bSLuigi Rizzo int (*ip_mrouter_set)(struct socket *, struct sockopt *);
98bbb4330bSLuigi Rizzo int (*ip_mrouter_get)(struct socket *, struct sockopt *);
99bbb4330bSLuigi Rizzo int (*ip_mrouter_done)(void);
100bbb4330bSLuigi Rizzo int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
101bbb4330bSLuigi Rizzo                    struct ip_moptions *);
102bbb4330bSLuigi Rizzo int (*mrt_ioctl)(int, caddr_t);
103bbb4330bSLuigi Rizzo int (*legal_vif_num)(int);
104bbb4330bSLuigi Rizzo u_long (*ip_mcast_src)(int);
105bbb4330bSLuigi Rizzo 
106bbb4330bSLuigi Rizzo void (*rsvp_input_p)(struct mbuf *m, int off);
107bbb4330bSLuigi Rizzo int (*ip_rsvp_vif)(struct socket *, struct sockopt *);
108bbb4330bSLuigi Rizzo void (*ip_rsvp_force_done)(struct socket *);
109bbb4330bSLuigi Rizzo 
110bbb4330bSLuigi Rizzo /*
111df8bae1dSRodney W. Grimes  * Nominal space allocated to a raw ip socket.
112df8bae1dSRodney W. Grimes  */
113df8bae1dSRodney W. Grimes #define	RIPSNDQ		8192
114df8bae1dSRodney W. Grimes #define	RIPRCVQ		8192
115df8bae1dSRodney W. Grimes 
116df8bae1dSRodney W. Grimes /*
117df8bae1dSRodney W. Grimes  * Raw interface to IP protocol.
118df8bae1dSRodney W. Grimes  */
119df8bae1dSRodney W. Grimes 
120df8bae1dSRodney W. Grimes /*
121032dcc76SLuigi Rizzo  * Initialize raw connection block q.
122df8bae1dSRodney W. Grimes  */
123df8bae1dSRodney W. Grimes void
124032dcc76SLuigi Rizzo rip_init()
125df8bae1dSRodney W. Grimes {
1267a9378e7SJeffrey Hsu 	INP_INFO_LOCK_INIT(&ripcbinfo, "rip");
12715bd2b43SDavid Greenman 	LIST_INIT(&ripcb);
12815bd2b43SDavid Greenman 	ripcbinfo.listhead = &ripcb;
12915bd2b43SDavid Greenman 	/*
13015bd2b43SDavid Greenman 	 * XXX We don't use the hash list for raw IP, but it's easier
13115bd2b43SDavid Greenman 	 * to allocate a one entry hash list than it is to check all
13215bd2b43SDavid Greenman 	 * over the place for hashbase == NULL.
13315bd2b43SDavid Greenman 	 */
134ddd79a97SDavid Greenman 	ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
135c3229e05SDavid Greenman 	ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
13669c2d429SJeff Roberson 	ripcbinfo.ipi_zone = uma_zcreate("ripcb", sizeof(struct inpcb),
13769c2d429SJeff Roberson 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
13869c2d429SJeff Roberson 	uma_zone_set_max(ripcbinfo.ipi_zone, maxsockets);
139df8bae1dSRodney W. Grimes }
140df8bae1dSRodney W. Grimes 
141f6d24a78SPoul-Henning Kamp static struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
142df8bae1dSRodney W. Grimes /*
143df8bae1dSRodney W. Grimes  * Setup generic address and protocol structures
144df8bae1dSRodney W. Grimes  * for raw_input routine, then pass them along with
145df8bae1dSRodney W. Grimes  * mbuf chain.
146df8bae1dSRodney W. Grimes  */
147df8bae1dSRodney W. Grimes void
148032dcc76SLuigi Rizzo rip_input(m, off)
149032dcc76SLuigi Rizzo 	struct mbuf *m;
150032dcc76SLuigi Rizzo 	int off;
151df8bae1dSRodney W. Grimes {
152032dcc76SLuigi Rizzo 	register struct ip *ip = mtod(m, struct ip *);
153032dcc76SLuigi Rizzo 	register struct inpcb *inp;
15482c23ebaSBill Fenner 	struct inpcb *last = 0;
15582c23ebaSBill Fenner 	struct mbuf *opts = 0;
156f0ffb944SJulian Elischer 	int proto = ip->ip_p;
157df8bae1dSRodney W. Grimes 
158df8bae1dSRodney W. Grimes 	ripsrc.sin_addr = ip->ip_src;
1596a800098SYoshinobu Inoue 	LIST_FOREACH(inp, &ripcb, inp_list) {
1606a800098SYoshinobu Inoue #ifdef INET6
1616a800098SYoshinobu Inoue 		if ((inp->inp_vflag & INP_IPV4) == 0)
1626a800098SYoshinobu Inoue 			continue;
1636a800098SYoshinobu Inoue #endif
1646a800098SYoshinobu Inoue 		if (inp->inp_ip_p && inp->inp_ip_p != proto)
165df8bae1dSRodney W. Grimes 			continue;
166032dcc76SLuigi Rizzo 		if (inp->inp_laddr.s_addr &&
167d99c7a23SGarrett Wollman                   inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
168df8bae1dSRodney W. Grimes 			continue;
169032dcc76SLuigi Rizzo 		if (inp->inp_faddr.s_addr &&
170d99c7a23SGarrett Wollman                   inp->inp_faddr.s_addr != ip->ip_src.s_addr)
171df8bae1dSRodney W. Grimes 			continue;
172df8bae1dSRodney W. Grimes 		if (last) {
173032dcc76SLuigi Rizzo 			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
1744ea889c6SRobert Watson 			int policyfail = 0;
17533841545SHajimu UMEMOTO 
1764ea889c6SRobert Watson 			if (n != NULL) {
177cd6c2a88SSeigo Tanimura #ifdef IPSEC
17833841545SHajimu UMEMOTO 				/* check AH/ESP integrity. */
1794ea889c6SRobert Watson 				if (ipsec4_in_reject_so(n, last->inp_socket)) {
1804ea889c6SRobert Watson 					policyfail = 1;
18133841545SHajimu UMEMOTO 					ipsecstat.in_polvio++;
18233841545SHajimu UMEMOTO 					/* do not inject data to pcb */
1834ea889c6SRobert Watson 				}
18433841545SHajimu UMEMOTO #endif /*IPSEC*/
185b9234fafSSam Leffler #ifdef FAST_IPSEC
186b9234fafSSam Leffler 				/* check AH/ESP integrity. */
187b9234fafSSam Leffler 				if (ipsec4_in_reject(n, last)) {
188b9234fafSSam Leffler 					policyfail = 1;
189b9234fafSSam Leffler 					/* do not inject data to pcb */
190b9234fafSSam Leffler 				}
191b9234fafSSam Leffler #endif /*FAST_IPSEC*/
1924ea889c6SRobert Watson #ifdef MAC
1934ea889c6SRobert Watson 				if (policyfail == 0 &&
194fb95b5d3SRobert Watson 				    mac_check_socket_deliver(last->inp_socket,
1954ea889c6SRobert Watson 				    n) != 0)
1964ea889c6SRobert Watson 					policyfail = 1;
1974ea889c6SRobert Watson #endif
1984ea889c6SRobert Watson 			}
1994ea889c6SRobert Watson 			if (policyfail)
2004ea889c6SRobert Watson 				m_freem(n);
2014ea889c6SRobert Watson 			else if (n) {
2024cc20ab1SSeigo Tanimura 				if (last->inp_flags & INP_CONTROLOPTS ||
2034cc20ab1SSeigo Tanimura 				    last->inp_socket->so_options & SO_TIMESTAMP)
20482c23ebaSBill Fenner 				    ip_savecontrol(last, &opts, ip, n);
20582c23ebaSBill Fenner 				if (sbappendaddr(&last->inp_socket->so_rcv,
206623ae52eSPoul-Henning Kamp 				    (struct sockaddr *)&ripsrc, n,
20782c23ebaSBill Fenner 				    opts) == 0) {
208df8bae1dSRodney W. Grimes 					/* should notify about lost packet */
209df8bae1dSRodney W. Grimes 					m_freem(n);
21082c23ebaSBill Fenner 					if (opts)
21182c23ebaSBill Fenner 					    m_freem(opts);
2124cc20ab1SSeigo Tanimura 				} else
21382c23ebaSBill Fenner 					sorwakeup(last->inp_socket);
21482c23ebaSBill Fenner 				opts = 0;
215df8bae1dSRodney W. Grimes 			}
216df8bae1dSRodney W. Grimes 		}
21782c23ebaSBill Fenner 		last = inp;
218df8bae1dSRodney W. Grimes 	}
2194ea889c6SRobert Watson 	if (last) {
22033841545SHajimu UMEMOTO #ifdef IPSEC
22133841545SHajimu UMEMOTO 		/* check AH/ESP integrity. */
2224ea889c6SRobert Watson 		if (ipsec4_in_reject_so(m, last->inp_socket)) {
22333841545SHajimu UMEMOTO 			m_freem(m);
22433841545SHajimu UMEMOTO 			ipsecstat.in_polvio++;
22533841545SHajimu UMEMOTO 			ipstat.ips_delivered--;
22633841545SHajimu UMEMOTO 			/* do not inject data to pcb */
2274ea889c6SRobert Watson 			return;
2284ea889c6SRobert Watson 		}
22933841545SHajimu UMEMOTO #endif /*IPSEC*/
230b9234fafSSam Leffler #ifdef FAST_IPSEC
231b9234fafSSam Leffler 		/* check AH/ESP integrity. */
232b9234fafSSam Leffler 		if (ipsec4_in_reject(m, last)) {
233b9234fafSSam Leffler 			m_freem(m);
234b9234fafSSam Leffler 			ipstat.ips_delivered--;
235b9234fafSSam Leffler 			/* do not inject data to pcb */
236b9234fafSSam Leffler 			return;
237b9234fafSSam Leffler 		}
238b9234fafSSam Leffler #endif /*FAST_IPSEC*/
2394ea889c6SRobert Watson #ifdef MAC
240fb95b5d3SRobert Watson 		if (mac_check_socket_deliver(last->inp_socket, m) != 0) {
2414ea889c6SRobert Watson 			m_freem(m);
2424ea889c6SRobert Watson 			ipstat.ips_delivered--;
2434ea889c6SRobert Watson 			return;
2444ea889c6SRobert Watson 		}
2454ea889c6SRobert Watson #endif
2464cc20ab1SSeigo Tanimura 		if (last->inp_flags & INP_CONTROLOPTS ||
2474cc20ab1SSeigo Tanimura 		    last->inp_socket->so_options & SO_TIMESTAMP)
24882c23ebaSBill Fenner 			ip_savecontrol(last, &opts, ip, m);
24982c23ebaSBill Fenner 		if (sbappendaddr(&last->inp_socket->so_rcv,
25082c23ebaSBill Fenner 		    (struct sockaddr *)&ripsrc, m, opts) == 0) {
251df8bae1dSRodney W. Grimes 			m_freem(m);
25282c23ebaSBill Fenner 			if (opts)
25382c23ebaSBill Fenner 			    m_freem(opts);
2544cc20ab1SSeigo Tanimura 		} else
25582c23ebaSBill Fenner 			sorwakeup(last->inp_socket);
256df8bae1dSRodney W. Grimes 	} else {
257df8bae1dSRodney W. Grimes 		m_freem(m);
258df8bae1dSRodney W. Grimes 		ipstat.ips_noproto++;
259df8bae1dSRodney W. Grimes 		ipstat.ips_delivered--;
260df8bae1dSRodney W. Grimes 	}
261df8bae1dSRodney W. Grimes }
262df8bae1dSRodney W. Grimes 
263df8bae1dSRodney W. Grimes /*
264df8bae1dSRodney W. Grimes  * Generate IP header and pass packet to ip_output.
265df8bae1dSRodney W. Grimes  * Tack on options user may have setup with control call.
266df8bae1dSRodney W. Grimes  */
267df8bae1dSRodney W. Grimes int
268032dcc76SLuigi Rizzo rip_output(m, so, dst)
269032dcc76SLuigi Rizzo 	struct mbuf *m;
270032dcc76SLuigi Rizzo 	struct socket *so;
271032dcc76SLuigi Rizzo 	u_long dst;
272df8bae1dSRodney W. Grimes {
273032dcc76SLuigi Rizzo 	register struct ip *ip;
274032dcc76SLuigi Rizzo 	register struct inpcb *inp = sotoinpcb(so);
2754cc20ab1SSeigo Tanimura 	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
276df8bae1dSRodney W. Grimes 
2774ea889c6SRobert Watson #ifdef MAC
2784ea889c6SRobert Watson 	mac_create_mbuf_from_socket(so, m);
2794ea889c6SRobert Watson #endif
2804ea889c6SRobert Watson 
281df8bae1dSRodney W. Grimes 	/*
282df8bae1dSRodney W. Grimes 	 * If the user handed us a complete IP packet, use it.
283df8bae1dSRodney W. Grimes 	 * Otherwise, allocate an mbuf for a header and fill it in.
284df8bae1dSRodney W. Grimes 	 */
285df8bae1dSRodney W. Grimes 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
286430d30d8SBill Fenner 		if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
287430d30d8SBill Fenner 			m_freem(m);
288430d30d8SBill Fenner 			return(EMSGSIZE);
289430d30d8SBill Fenner 		}
290a163d034SWarner Losh 		M_PREPEND(m, sizeof(struct ip), M_TRYWAIT);
291df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
2928ce3f3ddSRuslan Ermilov 		ip->ip_tos = inp->inp_ip_tos;
293df8bae1dSRodney W. Grimes 		ip->ip_off = 0;
294ca98b82cSDavid Greenman 		ip->ip_p = inp->inp_ip_p;
295df8bae1dSRodney W. Grimes 		ip->ip_len = m->m_pkthdr.len;
296df8bae1dSRodney W. Grimes 		ip->ip_src = inp->inp_laddr;
297df8bae1dSRodney W. Grimes 		ip->ip_dst.s_addr = dst;
2988ce3f3ddSRuslan Ermilov 		ip->ip_ttl = inp->inp_ip_ttl;
299df8bae1dSRodney W. Grimes 	} else {
300430d30d8SBill Fenner 		if (m->m_pkthdr.len > IP_MAXPACKET) {
301430d30d8SBill Fenner 			m_freem(m);
302430d30d8SBill Fenner 			return(EMSGSIZE);
303430d30d8SBill Fenner 		}
304df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
305072b9b24SPaul Traina 		/* don't allow both user specified and setsockopt options,
306072b9b24SPaul Traina 		   and don't allow packet length sizes that will crash */
30753be11f6SPoul-Henning Kamp 		if (((ip->ip_hl != (sizeof (*ip) >> 2))
3085e2d0696SGarrett Wollman 		     && inp->inp_options)
30991108995SBill Fenner 		    || (ip->ip_len > m->m_pkthdr.len)
31053be11f6SPoul-Henning Kamp 		    || (ip->ip_len < (ip->ip_hl << 2))) {
311072b9b24SPaul Traina 			m_freem(m);
312072b9b24SPaul Traina 			return EINVAL;
313072b9b24SPaul Traina 		}
314df8bae1dSRodney W. Grimes 		if (ip->ip_id == 0)
31564dddc18SKris Kennaway #ifdef RANDOM_IP_ID
31664dddc18SKris Kennaway 			ip->ip_id = ip_randomid();
31764dddc18SKris Kennaway #else
318e30177e0SRuslan Ermilov 			ip->ip_id = htons(ip_id++);
31964dddc18SKris Kennaway #endif
320df8bae1dSRodney W. Grimes 		/* XXX prevent ip_output from overwriting header fields */
321df8bae1dSRodney W. Grimes 		flags |= IP_RAWOUTPUT;
322df8bae1dSRodney W. Grimes 		ipstat.ips_rawout++;
323df8bae1dSRodney W. Grimes 	}
3246a800098SYoshinobu Inoue 
325686cdd19SJun-ichiro itojun Hagino 	return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
3265d846453SSam Leffler 			  inp->inp_moptions, inp));
327df8bae1dSRodney W. Grimes }
328df8bae1dSRodney W. Grimes 
329df8bae1dSRodney W. Grimes /*
330df8bae1dSRodney W. Grimes  * Raw IP socket option processing.
33183503a92SRobert Watson  *
33283503a92SRobert Watson  * Note that access to all of the IP administrative functions here is
33383503a92SRobert Watson  * implicitly protected by suser() as gaining access to a raw socket
33483503a92SRobert Watson  * requires either that the thread pass a suser() check, or that it be
33583503a92SRobert Watson  * passed a raw socket by another thread that has passed a suser() check.
33683503a92SRobert Watson  * If FreeBSD moves to a more fine-grained access control mechanism,
33783503a92SRobert Watson  * additional checks will need to be placed here if the raw IP attachment
33883503a92SRobert Watson  * check is not equivilent the the check required for these
33983503a92SRobert Watson  * administrative operations; in some cases, these checks are already
34083503a92SRobert Watson  * present.
341df8bae1dSRodney W. Grimes  */
342df8bae1dSRodney W. Grimes int
343032dcc76SLuigi Rizzo rip_ctloutput(so, sopt)
344032dcc76SLuigi Rizzo 	struct socket *so;
345032dcc76SLuigi Rizzo 	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 
355cfe8b629SGarrett Wollman 	switch (sopt->sopt_dir) {
356cfe8b629SGarrett Wollman 	case SOPT_GET:
357cfe8b629SGarrett Wollman 		switch (sopt->sopt_name) {
358cfe8b629SGarrett Wollman 		case IP_HDRINCL:
359cfe8b629SGarrett Wollman 			optval = inp->inp_flags & INP_HDRINCL;
360cfe8b629SGarrett Wollman 			error = sooptcopyout(sopt, &optval, sizeof optval);
361cfe8b629SGarrett Wollman 			break;
362df8bae1dSRodney W. Grimes 
3637b109fa4SLuigi Rizzo 		case IP_FW_ADD:	/* ADD actually returns the body... */
36409bb5f75SPoul-Henning Kamp 		case IP_FW_GET:
3657b109fa4SLuigi Rizzo 			if (IPFW_LOADED)
366cfe8b629SGarrett Wollman 				error = ip_fw_ctl_ptr(sopt);
3677b109fa4SLuigi Rizzo 			else
3687b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
369cfe8b629SGarrett Wollman 			break;
3704dd1662bSUgen J.S. Antsilevich 
371b715f178SLuigi Rizzo 		case IP_DUMMYNET_GET:
3727b109fa4SLuigi Rizzo 			if (DUMMYNET_LOADED)
373b715f178SLuigi Rizzo 				error = ip_dn_ctl_ptr(sopt);
3747b109fa4SLuigi Rizzo 			else
3757b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
376b715f178SLuigi Rizzo 			break ;
3771c5de19aSGarrett Wollman 
3781c5de19aSGarrett Wollman 		case MRT_INIT:
3791c5de19aSGarrett Wollman 		case MRT_DONE:
3801c5de19aSGarrett Wollman 		case MRT_ADD_VIF:
3811c5de19aSGarrett Wollman 		case MRT_DEL_VIF:
3821c5de19aSGarrett Wollman 		case MRT_ADD_MFC:
3831c5de19aSGarrett Wollman 		case MRT_DEL_MFC:
3841c5de19aSGarrett Wollman 		case MRT_VERSION:
3851c5de19aSGarrett Wollman 		case MRT_ASSERT:
3861e78ac21SJeffrey Hsu 		case MRT_API_SUPPORT:
3871e78ac21SJeffrey Hsu 		case MRT_API_CONFIG:
3881e78ac21SJeffrey Hsu 		case MRT_ADD_BW_UPCALL:
3891e78ac21SJeffrey Hsu 		case MRT_DEL_BW_UPCALL:
390bbb4330bSLuigi Rizzo 			error = ip_mrouter_get ? ip_mrouter_get(so, sopt) :
391bbb4330bSLuigi Rizzo 				EOPNOTSUPP;
392cfe8b629SGarrett Wollman 			break;
393cfe8b629SGarrett Wollman 
394cfe8b629SGarrett Wollman 		default:
395cfe8b629SGarrett Wollman 			error = ip_ctloutput(so, sopt);
396cfe8b629SGarrett Wollman 			break;
397df8bae1dSRodney W. Grimes 		}
398cfe8b629SGarrett Wollman 		break;
399cfe8b629SGarrett Wollman 
400cfe8b629SGarrett Wollman 	case SOPT_SET:
401cfe8b629SGarrett Wollman 		switch (sopt->sopt_name) {
402cfe8b629SGarrett Wollman 		case IP_HDRINCL:
403cfe8b629SGarrett Wollman 			error = sooptcopyin(sopt, &optval, sizeof optval,
404cfe8b629SGarrett Wollman 					    sizeof optval);
405cfe8b629SGarrett Wollman 			if (error)
406cfe8b629SGarrett Wollman 				break;
407cfe8b629SGarrett Wollman 			if (optval)
408cfe8b629SGarrett Wollman 				inp->inp_flags |= INP_HDRINCL;
409cfe8b629SGarrett Wollman 			else
410cfe8b629SGarrett Wollman 				inp->inp_flags &= ~INP_HDRINCL;
411cfe8b629SGarrett Wollman 			break;
412cfe8b629SGarrett Wollman 
4138ba03966SRuslan Ermilov 		case IP_FW_ADD:
414cfe8b629SGarrett Wollman 		case IP_FW_DEL:
415cfe8b629SGarrett Wollman 		case IP_FW_FLUSH:
416cfe8b629SGarrett Wollman 		case IP_FW_ZERO:
4170b6c1a83SBrian Feldman 		case IP_FW_RESETLOG:
4187b109fa4SLuigi Rizzo 			if (IPFW_LOADED)
419cfe8b629SGarrett Wollman 				error = ip_fw_ctl_ptr(sopt);
4207b109fa4SLuigi Rizzo 			else
4217b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
422cfe8b629SGarrett Wollman 			break;
423cfe8b629SGarrett Wollman 
424b715f178SLuigi Rizzo 		case IP_DUMMYNET_CONFIGURE:
425b715f178SLuigi Rizzo 		case IP_DUMMYNET_DEL:
426b715f178SLuigi Rizzo 		case IP_DUMMYNET_FLUSH:
4277b109fa4SLuigi Rizzo 			if (DUMMYNET_LOADED)
428b715f178SLuigi Rizzo 				error = ip_dn_ctl_ptr(sopt);
4297b109fa4SLuigi Rizzo 			else
4307b109fa4SLuigi Rizzo 				error = ENOPROTOOPT ;
431b715f178SLuigi Rizzo 			break ;
432cfe8b629SGarrett Wollman 
433cfe8b629SGarrett Wollman 		case IP_RSVP_ON:
434cfe8b629SGarrett Wollman 			error = ip_rsvp_init(so);
435cfe8b629SGarrett Wollman 			break;
436cfe8b629SGarrett Wollman 
437cfe8b629SGarrett Wollman 		case IP_RSVP_OFF:
438cfe8b629SGarrett Wollman 			error = ip_rsvp_done();
439cfe8b629SGarrett Wollman 			break;
440cfe8b629SGarrett Wollman 
441cfe8b629SGarrett Wollman 		case IP_RSVP_VIF_ON:
442cfe8b629SGarrett Wollman 		case IP_RSVP_VIF_OFF:
443bbb4330bSLuigi Rizzo 			error = ip_rsvp_vif ?
444bbb4330bSLuigi Rizzo 				ip_rsvp_vif(so, sopt) : EINVAL;
445cfe8b629SGarrett Wollman 			break;
446cfe8b629SGarrett Wollman 
447cfe8b629SGarrett Wollman 		case MRT_INIT:
448cfe8b629SGarrett Wollman 		case MRT_DONE:
449cfe8b629SGarrett Wollman 		case MRT_ADD_VIF:
450cfe8b629SGarrett Wollman 		case MRT_DEL_VIF:
451cfe8b629SGarrett Wollman 		case MRT_ADD_MFC:
452cfe8b629SGarrett Wollman 		case MRT_DEL_MFC:
453cfe8b629SGarrett Wollman 		case MRT_VERSION:
454cfe8b629SGarrett Wollman 		case MRT_ASSERT:
4551e78ac21SJeffrey Hsu 		case MRT_API_SUPPORT:
4561e78ac21SJeffrey Hsu 		case MRT_API_CONFIG:
4571e78ac21SJeffrey Hsu 		case MRT_ADD_BW_UPCALL:
4581e78ac21SJeffrey Hsu 		case MRT_DEL_BW_UPCALL:
459bbb4330bSLuigi Rizzo 			error = ip_mrouter_set ? ip_mrouter_set(so, sopt) :
460bbb4330bSLuigi Rizzo 					EOPNOTSUPP;
461cfe8b629SGarrett Wollman 			break;
462cfe8b629SGarrett Wollman 
463cfe8b629SGarrett Wollman 		default:
464cfe8b629SGarrett Wollman 			error = ip_ctloutput(so, sopt);
465cfe8b629SGarrett Wollman 			break;
466cfe8b629SGarrett Wollman 		}
467cfe8b629SGarrett Wollman 		break;
468cfe8b629SGarrett Wollman 	}
469cfe8b629SGarrett Wollman 
470cfe8b629SGarrett Wollman 	return (error);
471df8bae1dSRodney W. Grimes }
472df8bae1dSRodney W. Grimes 
47339191c8eSGarrett Wollman /*
47439191c8eSGarrett Wollman  * This function exists solely to receive the PRC_IFDOWN messages which
47539191c8eSGarrett Wollman  * are sent by if_down().  It looks for an ifaddr whose ifa_addr is sa,
47639191c8eSGarrett Wollman  * and calls in_ifadown() to remove all routes corresponding to that address.
47739191c8eSGarrett Wollman  * It also receives the PRC_IFUP messages from if_up() and reinstalls the
47839191c8eSGarrett Wollman  * interface routes.
47939191c8eSGarrett Wollman  */
48039191c8eSGarrett Wollman void
481032dcc76SLuigi Rizzo rip_ctlinput(cmd, sa, vip)
482032dcc76SLuigi Rizzo 	int cmd;
483032dcc76SLuigi Rizzo 	struct sockaddr *sa;
484032dcc76SLuigi Rizzo 	void *vip;
48539191c8eSGarrett Wollman {
48639191c8eSGarrett Wollman 	struct in_ifaddr *ia;
48739191c8eSGarrett Wollman 	struct ifnet *ifp;
48839191c8eSGarrett Wollman 	int err;
48939191c8eSGarrett Wollman 	int flags;
49039191c8eSGarrett Wollman 
49139191c8eSGarrett Wollman 	switch (cmd) {
49239191c8eSGarrett Wollman 	case PRC_IFDOWN:
493462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
49439191c8eSGarrett Wollman 			if (ia->ia_ifa.ifa_addr == sa
49539191c8eSGarrett Wollman 			    && (ia->ia_flags & IFA_ROUTE)) {
49639191c8eSGarrett Wollman 				/*
49739191c8eSGarrett Wollman 				 * in_ifscrub kills the interface route.
49839191c8eSGarrett Wollman 				 */
49939191c8eSGarrett Wollman 				in_ifscrub(ia->ia_ifp, ia);
50039191c8eSGarrett Wollman 				/*
50139191c8eSGarrett Wollman 				 * in_ifadown gets rid of all the rest of
50239191c8eSGarrett Wollman 				 * the routes.  This is not quite the right
50339191c8eSGarrett Wollman 				 * thing to do, but at least if we are running
50439191c8eSGarrett Wollman 				 * a routing process they will come back.
50539191c8eSGarrett Wollman 				 */
50691854268SRuslan Ermilov 				in_ifadown(&ia->ia_ifa, 0);
50739191c8eSGarrett Wollman 				break;
50839191c8eSGarrett Wollman 			}
50939191c8eSGarrett Wollman 		}
51039191c8eSGarrett Wollman 		break;
51139191c8eSGarrett Wollman 
51239191c8eSGarrett Wollman 	case PRC_IFUP:
513462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
51439191c8eSGarrett Wollman 			if (ia->ia_ifa.ifa_addr == sa)
51539191c8eSGarrett Wollman 				break;
51639191c8eSGarrett Wollman 		}
51739191c8eSGarrett Wollman 		if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
51839191c8eSGarrett Wollman 			return;
51939191c8eSGarrett Wollman 		flags = RTF_UP;
52039191c8eSGarrett Wollman 		ifp = ia->ia_ifa.ifa_ifp;
52139191c8eSGarrett Wollman 
52239191c8eSGarrett Wollman 		if ((ifp->if_flags & IFF_LOOPBACK)
52339191c8eSGarrett Wollman 		    || (ifp->if_flags & IFF_POINTOPOINT))
52439191c8eSGarrett Wollman 			flags |= RTF_HOST;
52539191c8eSGarrett Wollman 
52639191c8eSGarrett Wollman 		err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
52739191c8eSGarrett Wollman 		if (err == 0)
52839191c8eSGarrett Wollman 			ia->ia_flags |= IFA_ROUTE;
52939191c8eSGarrett Wollman 		break;
53039191c8eSGarrett Wollman 	}
53139191c8eSGarrett Wollman }
53239191c8eSGarrett Wollman 
53382cd038dSYoshinobu Inoue u_long	rip_sendspace = RIPSNDQ;
53482cd038dSYoshinobu Inoue u_long	rip_recvspace = RIPRCVQ;
5354d3ffc98SBill Fenner int	rip_olddiverterror = 1;
536df8bae1dSRodney W. Grimes 
5373d177f46SBill Fumerola SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
5383d177f46SBill Fumerola     &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
5393d177f46SBill Fumerola SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
5403d177f46SBill Fumerola     &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
5414d3ffc98SBill Fenner SYSCTL_INT(_net_inet_raw, OID_AUTO, olddiverterror, CTLFLAG_RW,
542032dcc76SLuigi Rizzo     &rip_olddiverterror, 0, "Return an error when creating an 'old' DIVERT socket");
543117bcae7SGarrett Wollman 
544117bcae7SGarrett Wollman static int
545b40ce416SJulian Elischer rip_attach(struct socket *so, int proto, struct thread *td)
546df8bae1dSRodney W. Grimes {
547117bcae7SGarrett Wollman 	struct inpcb *inp;
54886b3ebceSDavid Greenman 	int error, s;
549c1f8a6ceSDavid Greenman 
550117bcae7SGarrett Wollman 	inp = sotoinpcb(so);
551df8bae1dSRodney W. Grimes 	if (inp)
552df8bae1dSRodney W. Grimes 		panic("rip_attach");
55344731cabSJohn Baldwin 	if (td && (error = suser(td)) != 0)
554a29f300eSGarrett Wollman 		return error;
555117bcae7SGarrett Wollman 
5564d3ffc98SBill Fenner 	if (proto >= IPPROTO_MAX || proto < 0)
5574d3ffc98SBill Fenner 		return EPROTONOSUPPORT;
5584d3ffc98SBill Fenner 
5594d3ffc98SBill Fenner 	/* To be removed before 5.2 */
5604d3ffc98SBill Fenner 	if (rip_olddiverterror && proto == IPPROTO_OLD_DIVERT) {
561032dcc76SLuigi Rizzo 		printf("Old IPDIVERT program needs to be recompiled, or new IP proto 254 user needs sysctl net.inet.raw.olddiverterror=0\n");
5624d3ffc98SBill Fenner 		return EPROTONOSUPPORT;
5634d3ffc98SBill Fenner 	}
5644d3ffc98SBill Fenner 
5656a800098SYoshinobu Inoue 	error = soreserve(so, rip_sendspace, rip_recvspace);
5666a800098SYoshinobu Inoue 	if (error)
5676a800098SYoshinobu Inoue 		return error;
56886b3ebceSDavid Greenman 	s = splnet();
569b40ce416SJulian Elischer 	error = in_pcballoc(so, &ripcbinfo, td);
57086b3ebceSDavid Greenman 	splx(s);
57186b3ebceSDavid Greenman 	if (error)
57286b3ebceSDavid Greenman 		return error;
573df8bae1dSRodney W. Grimes 	inp = (struct inpcb *)so->so_pcb;
5746a800098SYoshinobu Inoue 	inp->inp_vflag |= INP_IPV4;
575ca98b82cSDavid Greenman 	inp->inp_ip_p = proto;
5768ce3f3ddSRuslan Ermilov 	inp->inp_ip_ttl = ip_defttl;
577117bcae7SGarrett Wollman 	return 0;
578df8bae1dSRodney W. Grimes }
579117bcae7SGarrett Wollman 
580117bcae7SGarrett Wollman static int
581117bcae7SGarrett Wollman rip_detach(struct socket *so)
582117bcae7SGarrett Wollman {
583117bcae7SGarrett Wollman 	struct inpcb *inp;
584117bcae7SGarrett Wollman 
585117bcae7SGarrett Wollman 	inp = sotoinpcb(so);
586df8bae1dSRodney W. Grimes 	if (inp == 0)
587df8bae1dSRodney W. Grimes 		panic("rip_detach");
588bbb4330bSLuigi Rizzo 	if (so == ip_mrouter && ip_mrouter_done)
589df8bae1dSRodney W. Grimes 		ip_mrouter_done();
590bbb4330bSLuigi Rizzo 	if (ip_rsvp_force_done)
591b4489dc3SGarrett Wollman 		ip_rsvp_force_done(so);
592838ecf42SGarrett Wollman 	if (so == ip_rsvpd)
593838ecf42SGarrett Wollman 		ip_rsvp_done();
594df8bae1dSRodney W. Grimes 	in_pcbdetach(inp);
595117bcae7SGarrett Wollman 	return 0;
596117bcae7SGarrett Wollman }
597df8bae1dSRodney W. Grimes 
598117bcae7SGarrett Wollman static int
599117bcae7SGarrett Wollman rip_abort(struct socket *so)
600df8bae1dSRodney W. Grimes {
601117bcae7SGarrett Wollman 	soisdisconnected(so);
602f5c57460SJeffrey Hsu 	if (so->so_state & SS_NOFDREF)
603117bcae7SGarrett Wollman 		return rip_detach(so);
604f5c57460SJeffrey Hsu 	return 0;
605117bcae7SGarrett Wollman }
606117bcae7SGarrett Wollman 
607117bcae7SGarrett Wollman static int
608117bcae7SGarrett Wollman rip_disconnect(struct socket *so)
609117bcae7SGarrett Wollman {
6104cc20ab1SSeigo Tanimura 	if ((so->so_state & SS_ISCONNECTED) == 0)
611117bcae7SGarrett Wollman 		return ENOTCONN;
612117bcae7SGarrett Wollman 	return rip_abort(so);
613117bcae7SGarrett Wollman }
614117bcae7SGarrett Wollman 
615117bcae7SGarrett Wollman static int
616b40ce416SJulian Elischer rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
617117bcae7SGarrett Wollman {
618117bcae7SGarrett Wollman 	struct inpcb *inp = sotoinpcb(so);
61957bf258eSGarrett Wollman 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
620df8bae1dSRodney W. Grimes 
62157bf258eSGarrett Wollman 	if (nam->sa_len != sizeof(*addr))
622117bcae7SGarrett Wollman 		return EINVAL;
623117bcae7SGarrett Wollman 
624117bcae7SGarrett Wollman 	if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
625df8bae1dSRodney W. Grimes 				    (addr->sin_family != AF_IMPLINK)) ||
626032dcc76SLuigi Rizzo 	    (addr->sin_addr.s_addr &&
627117bcae7SGarrett Wollman 	     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
628117bcae7SGarrett Wollman 		return EADDRNOTAVAIL;
629df8bae1dSRodney W. Grimes 	inp->inp_laddr = addr->sin_addr;
630117bcae7SGarrett Wollman 	return 0;
631df8bae1dSRodney W. Grimes }
632117bcae7SGarrett Wollman 
633117bcae7SGarrett Wollman static int
634b40ce416SJulian Elischer rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
635df8bae1dSRodney W. Grimes {
636117bcae7SGarrett Wollman 	struct inpcb *inp = sotoinpcb(so);
63757bf258eSGarrett Wollman 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
638df8bae1dSRodney W. Grimes 
63957bf258eSGarrett Wollman 	if (nam->sa_len != sizeof(*addr))
640117bcae7SGarrett Wollman 		return EINVAL;
641117bcae7SGarrett Wollman 	if (TAILQ_EMPTY(&ifnet))
642117bcae7SGarrett Wollman 		return EADDRNOTAVAIL;
643df8bae1dSRodney W. Grimes 	if ((addr->sin_family != AF_INET) &&
644117bcae7SGarrett Wollman 	    (addr->sin_family != AF_IMPLINK))
645117bcae7SGarrett Wollman 		return EAFNOSUPPORT;
646df8bae1dSRodney W. Grimes 	inp->inp_faddr = addr->sin_addr;
647df8bae1dSRodney W. Grimes 	soisconnected(so);
648117bcae7SGarrett Wollman 	return 0;
649df8bae1dSRodney W. Grimes }
650df8bae1dSRodney W. Grimes 
651117bcae7SGarrett Wollman static int
652117bcae7SGarrett Wollman rip_shutdown(struct socket *so)
653df8bae1dSRodney W. Grimes {
654117bcae7SGarrett Wollman 	socantsendmore(so);
655117bcae7SGarrett Wollman 	return 0;
656117bcae7SGarrett Wollman }
657117bcae7SGarrett Wollman 
658117bcae7SGarrett Wollman static int
65957bf258eSGarrett Wollman rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
660b40ce416SJulian Elischer 	 struct mbuf *control, struct thread *td)
661117bcae7SGarrett Wollman {
662117bcae7SGarrett Wollman 	struct inpcb *inp = sotoinpcb(so);
663032dcc76SLuigi Rizzo 	register u_long dst;
664df8bae1dSRodney W. Grimes 
665df8bae1dSRodney W. Grimes 	if (so->so_state & SS_ISCONNECTED) {
666df8bae1dSRodney W. Grimes 		if (nam) {
667117bcae7SGarrett Wollman 			m_freem(m);
668117bcae7SGarrett Wollman 			return EISCONN;
669df8bae1dSRodney W. Grimes 		}
670df8bae1dSRodney W. Grimes 		dst = inp->inp_faddr.s_addr;
671df8bae1dSRodney W. Grimes 	} else {
672df8bae1dSRodney W. Grimes 		if (nam == NULL) {
673117bcae7SGarrett Wollman 			m_freem(m);
674117bcae7SGarrett Wollman 			return ENOTCONN;
675df8bae1dSRodney W. Grimes 		}
67657bf258eSGarrett Wollman 		dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
677df8bae1dSRodney W. Grimes 	}
678117bcae7SGarrett Wollman 	return rip_output(m, so, dst);
679df8bae1dSRodney W. Grimes }
680df8bae1dSRodney W. Grimes 
68198271db4SGarrett Wollman static int
68282d9ae4eSPoul-Henning Kamp rip_pcblist(SYSCTL_HANDLER_ARGS)
68398271db4SGarrett Wollman {
68498271db4SGarrett Wollman 	int error, i, n, s;
68598271db4SGarrett Wollman 	struct inpcb *inp, **inp_list;
68698271db4SGarrett Wollman 	inp_gen_t gencnt;
68798271db4SGarrett Wollman 	struct xinpgen xig;
68898271db4SGarrett Wollman 
68998271db4SGarrett Wollman 	/*
69098271db4SGarrett Wollman 	 * The process of preparing the TCB list is too time-consuming and
69198271db4SGarrett Wollman 	 * resource-intensive to repeat twice on every request.
69298271db4SGarrett Wollman 	 */
69398271db4SGarrett Wollman 	if (req->oldptr == 0) {
69498271db4SGarrett Wollman 		n = ripcbinfo.ipi_count;
69598271db4SGarrett Wollman 		req->oldidx = 2 * (sizeof xig)
69698271db4SGarrett Wollman 			+ (n + n/8) * sizeof(struct xinpcb);
69798271db4SGarrett Wollman 		return 0;
69898271db4SGarrett Wollman 	}
69998271db4SGarrett Wollman 
70098271db4SGarrett Wollman 	if (req->newptr != 0)
70198271db4SGarrett Wollman 		return EPERM;
70298271db4SGarrett Wollman 
70398271db4SGarrett Wollman 	/*
70498271db4SGarrett Wollman 	 * OK, now we're committed to doing something.
70598271db4SGarrett Wollman 	 */
70698271db4SGarrett Wollman 	s = splnet();
70798271db4SGarrett Wollman 	gencnt = ripcbinfo.ipi_gencnt;
70898271db4SGarrett Wollman 	n = ripcbinfo.ipi_count;
70998271db4SGarrett Wollman 	splx(s);
71098271db4SGarrett Wollman 
71198271db4SGarrett Wollman 	xig.xig_len = sizeof xig;
71298271db4SGarrett Wollman 	xig.xig_count = n;
71398271db4SGarrett Wollman 	xig.xig_gen = gencnt;
71498271db4SGarrett Wollman 	xig.xig_sogen = so_gencnt;
71598271db4SGarrett Wollman 	error = SYSCTL_OUT(req, &xig, sizeof xig);
71698271db4SGarrett Wollman 	if (error)
71798271db4SGarrett Wollman 		return error;
71898271db4SGarrett Wollman 
719a163d034SWarner Losh 	inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
72098271db4SGarrett Wollman 	if (inp_list == 0)
72198271db4SGarrett Wollman 		return ENOMEM;
72298271db4SGarrett Wollman 
72398271db4SGarrett Wollman 	s = splnet();
724fc2ffbe6SPoul-Henning Kamp 	for (inp = LIST_FIRST(ripcbinfo.listhead), i = 0; inp && i < n;
725fc2ffbe6SPoul-Henning Kamp 	     inp = LIST_NEXT(inp, inp_list)) {
7264787fd37SPaul Saab 		if (inp->inp_gencnt <= gencnt) {
72729dc1288SRobert Watson 			if (cr_canseesocket(req->td->td_ucred,
72829dc1288SRobert Watson 			    inp->inp_socket))
7294787fd37SPaul Saab 				continue;
73098271db4SGarrett Wollman 			inp_list[i++] = inp;
73198271db4SGarrett Wollman 		}
7324787fd37SPaul Saab 	}
73398271db4SGarrett Wollman 	splx(s);
73498271db4SGarrett Wollman 	n = i;
73598271db4SGarrett Wollman 
73698271db4SGarrett Wollman 	error = 0;
73798271db4SGarrett Wollman 	for (i = 0; i < n; i++) {
73898271db4SGarrett Wollman 		inp = inp_list[i];
73998271db4SGarrett Wollman 		if (inp->inp_gencnt <= gencnt) {
74098271db4SGarrett Wollman 			struct xinpcb xi;
74198271db4SGarrett Wollman 			xi.xi_len = sizeof xi;
74298271db4SGarrett Wollman 			/* XXX should avoid extra copy */
74398271db4SGarrett Wollman 			bcopy(inp, &xi.xi_inp, sizeof *inp);
74498271db4SGarrett Wollman 			if (inp->inp_socket)
74598271db4SGarrett Wollman 				sotoxsocket(inp->inp_socket, &xi.xi_socket);
74698271db4SGarrett Wollman 			error = SYSCTL_OUT(req, &xi, sizeof xi);
74798271db4SGarrett Wollman 		}
74898271db4SGarrett Wollman 	}
74998271db4SGarrett Wollman 	if (!error) {
75098271db4SGarrett Wollman 		/*
75198271db4SGarrett Wollman 		 * Give the user an updated idea of our state.
75298271db4SGarrett Wollman 		 * If the generation differs from what we told
75398271db4SGarrett Wollman 		 * her before, she knows that something happened
75498271db4SGarrett Wollman 		 * while we were processing this request, and it
75598271db4SGarrett Wollman 		 * might be necessary to retry.
75698271db4SGarrett Wollman 		 */
75798271db4SGarrett Wollman 		s = splnet();
75898271db4SGarrett Wollman 		xig.xig_gen = ripcbinfo.ipi_gencnt;
75998271db4SGarrett Wollman 		xig.xig_sogen = so_gencnt;
76098271db4SGarrett Wollman 		xig.xig_count = ripcbinfo.ipi_count;
76198271db4SGarrett Wollman 		splx(s);
76298271db4SGarrett Wollman 		error = SYSCTL_OUT(req, &xig, sizeof xig);
76398271db4SGarrett Wollman 	}
76498271db4SGarrett Wollman 	free(inp_list, M_TEMP);
76598271db4SGarrett Wollman 	return error;
76698271db4SGarrett Wollman }
76798271db4SGarrett Wollman 
768f76fcf6dSJeffrey Hsu /*
769f76fcf6dSJeffrey Hsu  * This is the wrapper function for in_setsockaddr.  We just pass down
770f76fcf6dSJeffrey Hsu  * the pcbinfo for in_setpeeraddr to lock.
771f76fcf6dSJeffrey Hsu  */
772f76fcf6dSJeffrey Hsu static int
773f76fcf6dSJeffrey Hsu rip_sockaddr(struct socket *so, struct sockaddr **nam)
774f76fcf6dSJeffrey Hsu {
775f76fcf6dSJeffrey Hsu 	return (in_setsockaddr(so, nam, &ripcbinfo));
776f76fcf6dSJeffrey Hsu }
777f76fcf6dSJeffrey Hsu 
778f76fcf6dSJeffrey Hsu /*
779f76fcf6dSJeffrey Hsu  * This is the wrapper function for in_setpeeraddr.  We just pass down
780f76fcf6dSJeffrey Hsu  * the pcbinfo for in_setpeeraddr to lock.
781f76fcf6dSJeffrey Hsu  */
782f76fcf6dSJeffrey Hsu static int
783f76fcf6dSJeffrey Hsu rip_peeraddr(struct socket *so, struct sockaddr **nam)
784f76fcf6dSJeffrey Hsu {
785f76fcf6dSJeffrey Hsu 	return (in_setpeeraddr(so, nam, &ripcbinfo));
786f76fcf6dSJeffrey Hsu }
787f76fcf6dSJeffrey Hsu 
788f76fcf6dSJeffrey Hsu 
78998271db4SGarrett Wollman SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
79098271db4SGarrett Wollman 	    rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
79198271db4SGarrett Wollman 
792117bcae7SGarrett Wollman struct pr_usrreqs rip_usrreqs = {
793117bcae7SGarrett Wollman 	rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
794117bcae7SGarrett Wollman 	pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
795f76fcf6dSJeffrey Hsu 	pru_listen_notsupp, rip_peeraddr, pru_rcvd_notsupp,
796117bcae7SGarrett Wollman 	pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
797f76fcf6dSJeffrey Hsu 	rip_sockaddr, sosend, soreceive, sopoll
798117bcae7SGarrett Wollman };
799