xref: /freebsd/sys/netinet/raw_ip.c (revision 8afa23047014b6c73e856501c7dc4deb6caf899f)
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 
3258afa2304SBruce M Simpson 	if (inp->inp_flags & INP_ONESBCAST)
3268afa2304SBruce M Simpson 		flags |= IP_SENDONES;
3278afa2304SBruce M Simpson 
328686cdd19SJun-ichiro itojun Hagino 	return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
3295d846453SSam Leffler 			  inp->inp_moptions, inp));
330df8bae1dSRodney W. Grimes }
331df8bae1dSRodney W. Grimes 
332df8bae1dSRodney W. Grimes /*
333df8bae1dSRodney W. Grimes  * Raw IP socket option processing.
33483503a92SRobert Watson  *
33583503a92SRobert Watson  * Note that access to all of the IP administrative functions here is
33683503a92SRobert Watson  * implicitly protected by suser() as gaining access to a raw socket
33783503a92SRobert Watson  * requires either that the thread pass a suser() check, or that it be
33883503a92SRobert Watson  * passed a raw socket by another thread that has passed a suser() check.
33983503a92SRobert Watson  * If FreeBSD moves to a more fine-grained access control mechanism,
34083503a92SRobert Watson  * additional checks will need to be placed here if the raw IP attachment
34183503a92SRobert Watson  * check is not equivilent the the check required for these
34283503a92SRobert Watson  * administrative operations; in some cases, these checks are already
34383503a92SRobert Watson  * present.
344df8bae1dSRodney W. Grimes  */
345df8bae1dSRodney W. Grimes int
346032dcc76SLuigi Rizzo rip_ctloutput(so, sopt)
347032dcc76SLuigi Rizzo 	struct socket *so;
348032dcc76SLuigi Rizzo 	struct sockopt *sopt;
349df8bae1dSRodney W. Grimes {
350cfe8b629SGarrett Wollman 	struct	inpcb *inp = sotoinpcb(so);
351cfe8b629SGarrett Wollman 	int	error, optval;
352df8bae1dSRodney W. Grimes 
353cfe8b629SGarrett Wollman 	if (sopt->sopt_level != IPPROTO_IP)
354df8bae1dSRodney W. Grimes 		return (EINVAL);
355df8bae1dSRodney W. Grimes 
35625f26ad8SGarrett Wollman 	error = 0;
357cfe8b629SGarrett Wollman 
358cfe8b629SGarrett Wollman 	switch (sopt->sopt_dir) {
359cfe8b629SGarrett Wollman 	case SOPT_GET:
360cfe8b629SGarrett Wollman 		switch (sopt->sopt_name) {
361cfe8b629SGarrett Wollman 		case IP_HDRINCL:
362cfe8b629SGarrett Wollman 			optval = inp->inp_flags & INP_HDRINCL;
363cfe8b629SGarrett Wollman 			error = sooptcopyout(sopt, &optval, sizeof optval);
364cfe8b629SGarrett Wollman 			break;
365df8bae1dSRodney W. Grimes 
3667b109fa4SLuigi Rizzo 		case IP_FW_ADD:	/* ADD actually returns the body... */
36709bb5f75SPoul-Henning Kamp 		case IP_FW_GET:
3687b109fa4SLuigi Rizzo 			if (IPFW_LOADED)
369cfe8b629SGarrett Wollman 				error = ip_fw_ctl_ptr(sopt);
3707b109fa4SLuigi Rizzo 			else
3717b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
372cfe8b629SGarrett Wollman 			break;
3734dd1662bSUgen J.S. Antsilevich 
374b715f178SLuigi Rizzo 		case IP_DUMMYNET_GET:
3757b109fa4SLuigi Rizzo 			if (DUMMYNET_LOADED)
376b715f178SLuigi Rizzo 				error = ip_dn_ctl_ptr(sopt);
3777b109fa4SLuigi Rizzo 			else
3787b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
379b715f178SLuigi Rizzo 			break ;
3801c5de19aSGarrett Wollman 
3811c5de19aSGarrett Wollman 		case MRT_INIT:
3821c5de19aSGarrett Wollman 		case MRT_DONE:
3831c5de19aSGarrett Wollman 		case MRT_ADD_VIF:
3841c5de19aSGarrett Wollman 		case MRT_DEL_VIF:
3851c5de19aSGarrett Wollman 		case MRT_ADD_MFC:
3861c5de19aSGarrett Wollman 		case MRT_DEL_MFC:
3871c5de19aSGarrett Wollman 		case MRT_VERSION:
3881c5de19aSGarrett Wollman 		case MRT_ASSERT:
3891e78ac21SJeffrey Hsu 		case MRT_API_SUPPORT:
3901e78ac21SJeffrey Hsu 		case MRT_API_CONFIG:
3911e78ac21SJeffrey Hsu 		case MRT_ADD_BW_UPCALL:
3921e78ac21SJeffrey Hsu 		case MRT_DEL_BW_UPCALL:
393bbb4330bSLuigi Rizzo 			error = ip_mrouter_get ? ip_mrouter_get(so, sopt) :
394bbb4330bSLuigi Rizzo 				EOPNOTSUPP;
395cfe8b629SGarrett Wollman 			break;
396cfe8b629SGarrett Wollman 
397cfe8b629SGarrett Wollman 		default:
398cfe8b629SGarrett Wollman 			error = ip_ctloutput(so, sopt);
399cfe8b629SGarrett Wollman 			break;
400df8bae1dSRodney W. Grimes 		}
401cfe8b629SGarrett Wollman 		break;
402cfe8b629SGarrett Wollman 
403cfe8b629SGarrett Wollman 	case SOPT_SET:
404cfe8b629SGarrett Wollman 		switch (sopt->sopt_name) {
405cfe8b629SGarrett Wollman 		case IP_HDRINCL:
406cfe8b629SGarrett Wollman 			error = sooptcopyin(sopt, &optval, sizeof optval,
407cfe8b629SGarrett Wollman 					    sizeof optval);
408cfe8b629SGarrett Wollman 			if (error)
409cfe8b629SGarrett Wollman 				break;
410cfe8b629SGarrett Wollman 			if (optval)
411cfe8b629SGarrett Wollman 				inp->inp_flags |= INP_HDRINCL;
412cfe8b629SGarrett Wollman 			else
413cfe8b629SGarrett Wollman 				inp->inp_flags &= ~INP_HDRINCL;
414cfe8b629SGarrett Wollman 			break;
415cfe8b629SGarrett Wollman 
4168ba03966SRuslan Ermilov 		case IP_FW_ADD:
417cfe8b629SGarrett Wollman 		case IP_FW_DEL:
418cfe8b629SGarrett Wollman 		case IP_FW_FLUSH:
419cfe8b629SGarrett Wollman 		case IP_FW_ZERO:
4200b6c1a83SBrian Feldman 		case IP_FW_RESETLOG:
4217b109fa4SLuigi Rizzo 			if (IPFW_LOADED)
422cfe8b629SGarrett Wollman 				error = ip_fw_ctl_ptr(sopt);
4237b109fa4SLuigi Rizzo 			else
4247b109fa4SLuigi Rizzo 				error = ENOPROTOOPT;
425cfe8b629SGarrett Wollman 			break;
426cfe8b629SGarrett Wollman 
427b715f178SLuigi Rizzo 		case IP_DUMMYNET_CONFIGURE:
428b715f178SLuigi Rizzo 		case IP_DUMMYNET_DEL:
429b715f178SLuigi Rizzo 		case IP_DUMMYNET_FLUSH:
4307b109fa4SLuigi Rizzo 			if (DUMMYNET_LOADED)
431b715f178SLuigi Rizzo 				error = ip_dn_ctl_ptr(sopt);
4327b109fa4SLuigi Rizzo 			else
4337b109fa4SLuigi Rizzo 				error = ENOPROTOOPT ;
434b715f178SLuigi Rizzo 			break ;
435cfe8b629SGarrett Wollman 
436cfe8b629SGarrett Wollman 		case IP_RSVP_ON:
437cfe8b629SGarrett Wollman 			error = ip_rsvp_init(so);
438cfe8b629SGarrett Wollman 			break;
439cfe8b629SGarrett Wollman 
440cfe8b629SGarrett Wollman 		case IP_RSVP_OFF:
441cfe8b629SGarrett Wollman 			error = ip_rsvp_done();
442cfe8b629SGarrett Wollman 			break;
443cfe8b629SGarrett Wollman 
444cfe8b629SGarrett Wollman 		case IP_RSVP_VIF_ON:
445cfe8b629SGarrett Wollman 		case IP_RSVP_VIF_OFF:
446bbb4330bSLuigi Rizzo 			error = ip_rsvp_vif ?
447bbb4330bSLuigi Rizzo 				ip_rsvp_vif(so, sopt) : EINVAL;
448cfe8b629SGarrett Wollman 			break;
449cfe8b629SGarrett Wollman 
450cfe8b629SGarrett Wollman 		case MRT_INIT:
451cfe8b629SGarrett Wollman 		case MRT_DONE:
452cfe8b629SGarrett Wollman 		case MRT_ADD_VIF:
453cfe8b629SGarrett Wollman 		case MRT_DEL_VIF:
454cfe8b629SGarrett Wollman 		case MRT_ADD_MFC:
455cfe8b629SGarrett Wollman 		case MRT_DEL_MFC:
456cfe8b629SGarrett Wollman 		case MRT_VERSION:
457cfe8b629SGarrett Wollman 		case MRT_ASSERT:
4581e78ac21SJeffrey Hsu 		case MRT_API_SUPPORT:
4591e78ac21SJeffrey Hsu 		case MRT_API_CONFIG:
4601e78ac21SJeffrey Hsu 		case MRT_ADD_BW_UPCALL:
4611e78ac21SJeffrey Hsu 		case MRT_DEL_BW_UPCALL:
462bbb4330bSLuigi Rizzo 			error = ip_mrouter_set ? ip_mrouter_set(so, sopt) :
463bbb4330bSLuigi Rizzo 					EOPNOTSUPP;
464cfe8b629SGarrett Wollman 			break;
465cfe8b629SGarrett Wollman 
466cfe8b629SGarrett Wollman 		default:
467cfe8b629SGarrett Wollman 			error = ip_ctloutput(so, sopt);
468cfe8b629SGarrett Wollman 			break;
469cfe8b629SGarrett Wollman 		}
470cfe8b629SGarrett Wollman 		break;
471cfe8b629SGarrett Wollman 	}
472cfe8b629SGarrett Wollman 
473cfe8b629SGarrett Wollman 	return (error);
474df8bae1dSRodney W. Grimes }
475df8bae1dSRodney W. Grimes 
47639191c8eSGarrett Wollman /*
47739191c8eSGarrett Wollman  * This function exists solely to receive the PRC_IFDOWN messages which
47839191c8eSGarrett Wollman  * are sent by if_down().  It looks for an ifaddr whose ifa_addr is sa,
47939191c8eSGarrett Wollman  * and calls in_ifadown() to remove all routes corresponding to that address.
48039191c8eSGarrett Wollman  * It also receives the PRC_IFUP messages from if_up() and reinstalls the
48139191c8eSGarrett Wollman  * interface routes.
48239191c8eSGarrett Wollman  */
48339191c8eSGarrett Wollman void
484032dcc76SLuigi Rizzo rip_ctlinput(cmd, sa, vip)
485032dcc76SLuigi Rizzo 	int cmd;
486032dcc76SLuigi Rizzo 	struct sockaddr *sa;
487032dcc76SLuigi Rizzo 	void *vip;
48839191c8eSGarrett Wollman {
48939191c8eSGarrett Wollman 	struct in_ifaddr *ia;
49039191c8eSGarrett Wollman 	struct ifnet *ifp;
49139191c8eSGarrett Wollman 	int err;
49239191c8eSGarrett Wollman 	int flags;
49339191c8eSGarrett Wollman 
49439191c8eSGarrett Wollman 	switch (cmd) {
49539191c8eSGarrett Wollman 	case PRC_IFDOWN:
496462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
49739191c8eSGarrett Wollman 			if (ia->ia_ifa.ifa_addr == sa
49839191c8eSGarrett Wollman 			    && (ia->ia_flags & IFA_ROUTE)) {
49939191c8eSGarrett Wollman 				/*
50039191c8eSGarrett Wollman 				 * in_ifscrub kills the interface route.
50139191c8eSGarrett Wollman 				 */
50239191c8eSGarrett Wollman 				in_ifscrub(ia->ia_ifp, ia);
50339191c8eSGarrett Wollman 				/*
50439191c8eSGarrett Wollman 				 * in_ifadown gets rid of all the rest of
50539191c8eSGarrett Wollman 				 * the routes.  This is not quite the right
50639191c8eSGarrett Wollman 				 * thing to do, but at least if we are running
50739191c8eSGarrett Wollman 				 * a routing process they will come back.
50839191c8eSGarrett Wollman 				 */
50991854268SRuslan Ermilov 				in_ifadown(&ia->ia_ifa, 0);
51039191c8eSGarrett Wollman 				break;
51139191c8eSGarrett Wollman 			}
51239191c8eSGarrett Wollman 		}
51339191c8eSGarrett Wollman 		break;
51439191c8eSGarrett Wollman 
51539191c8eSGarrett Wollman 	case PRC_IFUP:
516462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
51739191c8eSGarrett Wollman 			if (ia->ia_ifa.ifa_addr == sa)
51839191c8eSGarrett Wollman 				break;
51939191c8eSGarrett Wollman 		}
52039191c8eSGarrett Wollman 		if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
52139191c8eSGarrett Wollman 			return;
52239191c8eSGarrett Wollman 		flags = RTF_UP;
52339191c8eSGarrett Wollman 		ifp = ia->ia_ifa.ifa_ifp;
52439191c8eSGarrett Wollman 
52539191c8eSGarrett Wollman 		if ((ifp->if_flags & IFF_LOOPBACK)
52639191c8eSGarrett Wollman 		    || (ifp->if_flags & IFF_POINTOPOINT))
52739191c8eSGarrett Wollman 			flags |= RTF_HOST;
52839191c8eSGarrett Wollman 
52939191c8eSGarrett Wollman 		err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
53039191c8eSGarrett Wollman 		if (err == 0)
53139191c8eSGarrett Wollman 			ia->ia_flags |= IFA_ROUTE;
53239191c8eSGarrett Wollman 		break;
53339191c8eSGarrett Wollman 	}
53439191c8eSGarrett Wollman }
53539191c8eSGarrett Wollman 
53682cd038dSYoshinobu Inoue u_long	rip_sendspace = RIPSNDQ;
53782cd038dSYoshinobu Inoue u_long	rip_recvspace = RIPRCVQ;
5384d3ffc98SBill Fenner int	rip_olddiverterror = 1;
539df8bae1dSRodney W. Grimes 
5403d177f46SBill Fumerola SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
5413d177f46SBill Fumerola     &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
5423d177f46SBill Fumerola SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
5433d177f46SBill Fumerola     &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
5444d3ffc98SBill Fenner SYSCTL_INT(_net_inet_raw, OID_AUTO, olddiverterror, CTLFLAG_RW,
545032dcc76SLuigi Rizzo     &rip_olddiverterror, 0, "Return an error when creating an 'old' DIVERT socket");
546117bcae7SGarrett Wollman 
547117bcae7SGarrett Wollman static int
548b40ce416SJulian Elischer rip_attach(struct socket *so, int proto, struct thread *td)
549df8bae1dSRodney W. Grimes {
550117bcae7SGarrett Wollman 	struct inpcb *inp;
55186b3ebceSDavid Greenman 	int error, s;
552c1f8a6ceSDavid Greenman 
553117bcae7SGarrett Wollman 	inp = sotoinpcb(so);
554df8bae1dSRodney W. Grimes 	if (inp)
555df8bae1dSRodney W. Grimes 		panic("rip_attach");
55644731cabSJohn Baldwin 	if (td && (error = suser(td)) != 0)
557a29f300eSGarrett Wollman 		return error;
558117bcae7SGarrett Wollman 
5594d3ffc98SBill Fenner 	if (proto >= IPPROTO_MAX || proto < 0)
5604d3ffc98SBill Fenner 		return EPROTONOSUPPORT;
5614d3ffc98SBill Fenner 
5624d3ffc98SBill Fenner 	/* To be removed before 5.2 */
5634d3ffc98SBill Fenner 	if (rip_olddiverterror && proto == IPPROTO_OLD_DIVERT) {
564032dcc76SLuigi Rizzo 		printf("Old IPDIVERT program needs to be recompiled, or new IP proto 254 user needs sysctl net.inet.raw.olddiverterror=0\n");
5654d3ffc98SBill Fenner 		return EPROTONOSUPPORT;
5664d3ffc98SBill Fenner 	}
5674d3ffc98SBill Fenner 
5686a800098SYoshinobu Inoue 	error = soreserve(so, rip_sendspace, rip_recvspace);
5696a800098SYoshinobu Inoue 	if (error)
5706a800098SYoshinobu Inoue 		return error;
57186b3ebceSDavid Greenman 	s = splnet();
572b40ce416SJulian Elischer 	error = in_pcballoc(so, &ripcbinfo, td);
57386b3ebceSDavid Greenman 	splx(s);
57486b3ebceSDavid Greenman 	if (error)
57586b3ebceSDavid Greenman 		return error;
576df8bae1dSRodney W. Grimes 	inp = (struct inpcb *)so->so_pcb;
5776a800098SYoshinobu Inoue 	inp->inp_vflag |= INP_IPV4;
578ca98b82cSDavid Greenman 	inp->inp_ip_p = proto;
5798ce3f3ddSRuslan Ermilov 	inp->inp_ip_ttl = ip_defttl;
580117bcae7SGarrett Wollman 	return 0;
581df8bae1dSRodney W. Grimes }
582117bcae7SGarrett Wollman 
583117bcae7SGarrett Wollman static int
584117bcae7SGarrett Wollman rip_detach(struct socket *so)
585117bcae7SGarrett Wollman {
586117bcae7SGarrett Wollman 	struct inpcb *inp;
587117bcae7SGarrett Wollman 
588117bcae7SGarrett Wollman 	inp = sotoinpcb(so);
589df8bae1dSRodney W. Grimes 	if (inp == 0)
590df8bae1dSRodney W. Grimes 		panic("rip_detach");
591bbb4330bSLuigi Rizzo 	if (so == ip_mrouter && ip_mrouter_done)
592df8bae1dSRodney W. Grimes 		ip_mrouter_done();
593bbb4330bSLuigi Rizzo 	if (ip_rsvp_force_done)
594b4489dc3SGarrett Wollman 		ip_rsvp_force_done(so);
595838ecf42SGarrett Wollman 	if (so == ip_rsvpd)
596838ecf42SGarrett Wollman 		ip_rsvp_done();
597df8bae1dSRodney W. Grimes 	in_pcbdetach(inp);
598117bcae7SGarrett Wollman 	return 0;
599117bcae7SGarrett Wollman }
600df8bae1dSRodney W. Grimes 
601117bcae7SGarrett Wollman static int
602117bcae7SGarrett Wollman rip_abort(struct socket *so)
603df8bae1dSRodney W. Grimes {
604117bcae7SGarrett Wollman 	soisdisconnected(so);
605f5c57460SJeffrey Hsu 	if (so->so_state & SS_NOFDREF)
606117bcae7SGarrett Wollman 		return rip_detach(so);
607f5c57460SJeffrey Hsu 	return 0;
608117bcae7SGarrett Wollman }
609117bcae7SGarrett Wollman 
610117bcae7SGarrett Wollman static int
611117bcae7SGarrett Wollman rip_disconnect(struct socket *so)
612117bcae7SGarrett Wollman {
6134cc20ab1SSeigo Tanimura 	if ((so->so_state & SS_ISCONNECTED) == 0)
614117bcae7SGarrett Wollman 		return ENOTCONN;
615117bcae7SGarrett Wollman 	return rip_abort(so);
616117bcae7SGarrett Wollman }
617117bcae7SGarrett Wollman 
618117bcae7SGarrett Wollman static int
619b40ce416SJulian Elischer rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
620117bcae7SGarrett Wollman {
621117bcae7SGarrett Wollman 	struct inpcb *inp = sotoinpcb(so);
62257bf258eSGarrett Wollman 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
623df8bae1dSRodney W. Grimes 
62457bf258eSGarrett Wollman 	if (nam->sa_len != sizeof(*addr))
625117bcae7SGarrett Wollman 		return EINVAL;
626117bcae7SGarrett Wollman 
627117bcae7SGarrett Wollman 	if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
628df8bae1dSRodney W. Grimes 				    (addr->sin_family != AF_IMPLINK)) ||
629032dcc76SLuigi Rizzo 	    (addr->sin_addr.s_addr &&
630117bcae7SGarrett Wollman 	     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
631117bcae7SGarrett Wollman 		return EADDRNOTAVAIL;
632df8bae1dSRodney W. Grimes 	inp->inp_laddr = addr->sin_addr;
633117bcae7SGarrett Wollman 	return 0;
634df8bae1dSRodney W. Grimes }
635117bcae7SGarrett Wollman 
636117bcae7SGarrett Wollman static int
637b40ce416SJulian Elischer rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
638df8bae1dSRodney W. Grimes {
639117bcae7SGarrett Wollman 	struct inpcb *inp = sotoinpcb(so);
64057bf258eSGarrett Wollman 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
641df8bae1dSRodney W. Grimes 
64257bf258eSGarrett Wollman 	if (nam->sa_len != sizeof(*addr))
643117bcae7SGarrett Wollman 		return EINVAL;
644117bcae7SGarrett Wollman 	if (TAILQ_EMPTY(&ifnet))
645117bcae7SGarrett Wollman 		return EADDRNOTAVAIL;
646df8bae1dSRodney W. Grimes 	if ((addr->sin_family != AF_INET) &&
647117bcae7SGarrett Wollman 	    (addr->sin_family != AF_IMPLINK))
648117bcae7SGarrett Wollman 		return EAFNOSUPPORT;
649df8bae1dSRodney W. Grimes 	inp->inp_faddr = addr->sin_addr;
650df8bae1dSRodney W. Grimes 	soisconnected(so);
651117bcae7SGarrett Wollman 	return 0;
652df8bae1dSRodney W. Grimes }
653df8bae1dSRodney W. Grimes 
654117bcae7SGarrett Wollman static int
655117bcae7SGarrett Wollman rip_shutdown(struct socket *so)
656df8bae1dSRodney W. Grimes {
657117bcae7SGarrett Wollman 	socantsendmore(so);
658117bcae7SGarrett Wollman 	return 0;
659117bcae7SGarrett Wollman }
660117bcae7SGarrett Wollman 
661117bcae7SGarrett Wollman static int
66257bf258eSGarrett Wollman rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
663b40ce416SJulian Elischer 	 struct mbuf *control, struct thread *td)
664117bcae7SGarrett Wollman {
665117bcae7SGarrett Wollman 	struct inpcb *inp = sotoinpcb(so);
666032dcc76SLuigi Rizzo 	register u_long dst;
667df8bae1dSRodney W. Grimes 
668df8bae1dSRodney W. Grimes 	if (so->so_state & SS_ISCONNECTED) {
669df8bae1dSRodney W. Grimes 		if (nam) {
670117bcae7SGarrett Wollman 			m_freem(m);
671117bcae7SGarrett Wollman 			return EISCONN;
672df8bae1dSRodney W. Grimes 		}
673df8bae1dSRodney W. Grimes 		dst = inp->inp_faddr.s_addr;
674df8bae1dSRodney W. Grimes 	} else {
675df8bae1dSRodney W. Grimes 		if (nam == NULL) {
676117bcae7SGarrett Wollman 			m_freem(m);
677117bcae7SGarrett Wollman 			return ENOTCONN;
678df8bae1dSRodney W. Grimes 		}
67957bf258eSGarrett Wollman 		dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
680df8bae1dSRodney W. Grimes 	}
681117bcae7SGarrett Wollman 	return rip_output(m, so, dst);
682df8bae1dSRodney W. Grimes }
683df8bae1dSRodney W. Grimes 
68498271db4SGarrett Wollman static int
68582d9ae4eSPoul-Henning Kamp rip_pcblist(SYSCTL_HANDLER_ARGS)
68698271db4SGarrett Wollman {
68798271db4SGarrett Wollman 	int error, i, n, s;
68898271db4SGarrett Wollman 	struct inpcb *inp, **inp_list;
68998271db4SGarrett Wollman 	inp_gen_t gencnt;
69098271db4SGarrett Wollman 	struct xinpgen xig;
69198271db4SGarrett Wollman 
69298271db4SGarrett Wollman 	/*
69398271db4SGarrett Wollman 	 * The process of preparing the TCB list is too time-consuming and
69498271db4SGarrett Wollman 	 * resource-intensive to repeat twice on every request.
69598271db4SGarrett Wollman 	 */
69698271db4SGarrett Wollman 	if (req->oldptr == 0) {
69798271db4SGarrett Wollman 		n = ripcbinfo.ipi_count;
69898271db4SGarrett Wollman 		req->oldidx = 2 * (sizeof xig)
69998271db4SGarrett Wollman 			+ (n + n/8) * sizeof(struct xinpcb);
70098271db4SGarrett Wollman 		return 0;
70198271db4SGarrett Wollman 	}
70298271db4SGarrett Wollman 
70398271db4SGarrett Wollman 	if (req->newptr != 0)
70498271db4SGarrett Wollman 		return EPERM;
70598271db4SGarrett Wollman 
70698271db4SGarrett Wollman 	/*
70798271db4SGarrett Wollman 	 * OK, now we're committed to doing something.
70898271db4SGarrett Wollman 	 */
70998271db4SGarrett Wollman 	s = splnet();
71098271db4SGarrett Wollman 	gencnt = ripcbinfo.ipi_gencnt;
71198271db4SGarrett Wollman 	n = ripcbinfo.ipi_count;
71298271db4SGarrett Wollman 	splx(s);
71398271db4SGarrett Wollman 
71498271db4SGarrett Wollman 	xig.xig_len = sizeof xig;
71598271db4SGarrett Wollman 	xig.xig_count = n;
71698271db4SGarrett Wollman 	xig.xig_gen = gencnt;
71798271db4SGarrett Wollman 	xig.xig_sogen = so_gencnt;
71898271db4SGarrett Wollman 	error = SYSCTL_OUT(req, &xig, sizeof xig);
71998271db4SGarrett Wollman 	if (error)
72098271db4SGarrett Wollman 		return error;
72198271db4SGarrett Wollman 
722a163d034SWarner Losh 	inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
72398271db4SGarrett Wollman 	if (inp_list == 0)
72498271db4SGarrett Wollman 		return ENOMEM;
72598271db4SGarrett Wollman 
72698271db4SGarrett Wollman 	s = splnet();
727fc2ffbe6SPoul-Henning Kamp 	for (inp = LIST_FIRST(ripcbinfo.listhead), i = 0; inp && i < n;
728fc2ffbe6SPoul-Henning Kamp 	     inp = LIST_NEXT(inp, inp_list)) {
7294787fd37SPaul Saab 		if (inp->inp_gencnt <= gencnt) {
73029dc1288SRobert Watson 			if (cr_canseesocket(req->td->td_ucred,
73129dc1288SRobert Watson 			    inp->inp_socket))
7324787fd37SPaul Saab 				continue;
73398271db4SGarrett Wollman 			inp_list[i++] = inp;
73498271db4SGarrett Wollman 		}
7354787fd37SPaul Saab 	}
73698271db4SGarrett Wollman 	splx(s);
73798271db4SGarrett Wollman 	n = i;
73898271db4SGarrett Wollman 
73998271db4SGarrett Wollman 	error = 0;
74098271db4SGarrett Wollman 	for (i = 0; i < n; i++) {
74198271db4SGarrett Wollman 		inp = inp_list[i];
74298271db4SGarrett Wollman 		if (inp->inp_gencnt <= gencnt) {
74398271db4SGarrett Wollman 			struct xinpcb xi;
74498271db4SGarrett Wollman 			xi.xi_len = sizeof xi;
74598271db4SGarrett Wollman 			/* XXX should avoid extra copy */
74698271db4SGarrett Wollman 			bcopy(inp, &xi.xi_inp, sizeof *inp);
74798271db4SGarrett Wollman 			if (inp->inp_socket)
74898271db4SGarrett Wollman 				sotoxsocket(inp->inp_socket, &xi.xi_socket);
74998271db4SGarrett Wollman 			error = SYSCTL_OUT(req, &xi, sizeof xi);
75098271db4SGarrett Wollman 		}
75198271db4SGarrett Wollman 	}
75298271db4SGarrett Wollman 	if (!error) {
75398271db4SGarrett Wollman 		/*
75498271db4SGarrett Wollman 		 * Give the user an updated idea of our state.
75598271db4SGarrett Wollman 		 * If the generation differs from what we told
75698271db4SGarrett Wollman 		 * her before, she knows that something happened
75798271db4SGarrett Wollman 		 * while we were processing this request, and it
75898271db4SGarrett Wollman 		 * might be necessary to retry.
75998271db4SGarrett Wollman 		 */
76098271db4SGarrett Wollman 		s = splnet();
76198271db4SGarrett Wollman 		xig.xig_gen = ripcbinfo.ipi_gencnt;
76298271db4SGarrett Wollman 		xig.xig_sogen = so_gencnt;
76398271db4SGarrett Wollman 		xig.xig_count = ripcbinfo.ipi_count;
76498271db4SGarrett Wollman 		splx(s);
76598271db4SGarrett Wollman 		error = SYSCTL_OUT(req, &xig, sizeof xig);
76698271db4SGarrett Wollman 	}
76798271db4SGarrett Wollman 	free(inp_list, M_TEMP);
76898271db4SGarrett Wollman 	return error;
76998271db4SGarrett Wollman }
77098271db4SGarrett Wollman 
771f76fcf6dSJeffrey Hsu /*
772f76fcf6dSJeffrey Hsu  * This is the wrapper function for in_setsockaddr.  We just pass down
773f76fcf6dSJeffrey Hsu  * the pcbinfo for in_setpeeraddr to lock.
774f76fcf6dSJeffrey Hsu  */
775f76fcf6dSJeffrey Hsu static int
776f76fcf6dSJeffrey Hsu rip_sockaddr(struct socket *so, struct sockaddr **nam)
777f76fcf6dSJeffrey Hsu {
778f76fcf6dSJeffrey Hsu 	return (in_setsockaddr(so, nam, &ripcbinfo));
779f76fcf6dSJeffrey Hsu }
780f76fcf6dSJeffrey Hsu 
781f76fcf6dSJeffrey Hsu /*
782f76fcf6dSJeffrey Hsu  * This is the wrapper function for in_setpeeraddr.  We just pass down
783f76fcf6dSJeffrey Hsu  * the pcbinfo for in_setpeeraddr to lock.
784f76fcf6dSJeffrey Hsu  */
785f76fcf6dSJeffrey Hsu static int
786f76fcf6dSJeffrey Hsu rip_peeraddr(struct socket *so, struct sockaddr **nam)
787f76fcf6dSJeffrey Hsu {
788f76fcf6dSJeffrey Hsu 	return (in_setpeeraddr(so, nam, &ripcbinfo));
789f76fcf6dSJeffrey Hsu }
790f76fcf6dSJeffrey Hsu 
791f76fcf6dSJeffrey Hsu 
79298271db4SGarrett Wollman SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
79398271db4SGarrett Wollman 	    rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
79498271db4SGarrett Wollman 
795117bcae7SGarrett Wollman struct pr_usrreqs rip_usrreqs = {
796117bcae7SGarrett Wollman 	rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
797117bcae7SGarrett Wollman 	pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
798f76fcf6dSJeffrey Hsu 	pru_listen_notsupp, rip_peeraddr, pru_rcvd_notsupp,
799117bcae7SGarrett Wollman 	pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
800f76fcf6dSJeffrey Hsu 	rip_sockaddr, sosend, soreceive, sopoll
801117bcae7SGarrett Wollman };
802