xref: /freebsd/sys/netinet/raw_ip.c (revision fed1c7e9e49e3145f0fdca9bc6ac91be93ab1898)
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
34fed1c7e9SSøren Schmidt  *	$Id: raw_ip.c,v 1.33 1996/07/24 18:46:18 wollman Exp $
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
37df8bae1dSRodney W. Grimes #include <sys/param.h>
382ee45d7dSDavid Greenman #include <sys/queue.h>
39df8bae1dSRodney W. Grimes #include <sys/malloc.h>
40df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
41df8bae1dSRodney W. Grimes #include <sys/socket.h>
42df8bae1dSRodney W. Grimes #include <sys/protosw.h>
43df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
44df8bae1dSRodney W. Grimes #include <sys/errno.h>
45df8bae1dSRodney W. Grimes #include <sys/systm.h>
46df8bae1dSRodney W. Grimes 
47df8bae1dSRodney W. Grimes #include <net/if.h>
48df8bae1dSRodney W. Grimes #include <net/route.h>
49df8bae1dSRodney W. Grimes 
505e2d0696SGarrett Wollman #define _IP_VHL
51df8bae1dSRodney W. Grimes #include <netinet/in.h>
52df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
53df8bae1dSRodney W. Grimes #include <netinet/ip.h>
54c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h>
55c1f8a6ceSDavid Greenman #include <netinet/in_var.h>
56df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
57df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h>
58df8bae1dSRodney W. Grimes 
59100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h>
60100ba1a6SJordan K. Hubbard 
61f9493383SGarrett Wollman #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
62f9493383SGarrett Wollman #undef COMPAT_IPFW
63f9493383SGarrett Wollman #define COMPAT_IPFW 1
64f9493383SGarrett Wollman #else
65f9493383SGarrett Wollman #undef COMPAT_IPFW
66f9493383SGarrett Wollman #endif
67f9493383SGarrett Wollman 
68f6d24a78SPoul-Henning Kamp static struct inpcbhead ripcb;
69f6d24a78SPoul-Henning Kamp static struct inpcbinfo ripcbinfo;
70df8bae1dSRodney W. Grimes 
71df8bae1dSRodney W. Grimes /*
72df8bae1dSRodney W. Grimes  * Nominal space allocated to a raw ip socket.
73df8bae1dSRodney W. Grimes  */
74df8bae1dSRodney W. Grimes #define	RIPSNDQ		8192
75df8bae1dSRodney W. Grimes #define	RIPRCVQ		8192
76df8bae1dSRodney W. Grimes 
77df8bae1dSRodney W. Grimes /*
78df8bae1dSRodney W. Grimes  * Raw interface to IP protocol.
79df8bae1dSRodney W. Grimes  */
80df8bae1dSRodney W. Grimes 
81df8bae1dSRodney W. Grimes /*
82df8bae1dSRodney W. Grimes  * Initialize raw connection block q.
83df8bae1dSRodney W. Grimes  */
84df8bae1dSRodney W. Grimes void
85df8bae1dSRodney W. Grimes rip_init()
86df8bae1dSRodney W. Grimes {
8715bd2b43SDavid Greenman 	LIST_INIT(&ripcb);
8815bd2b43SDavid Greenman 	ripcbinfo.listhead = &ripcb;
8915bd2b43SDavid Greenman 	/*
9015bd2b43SDavid Greenman 	 * XXX We don't use the hash list for raw IP, but it's easier
9115bd2b43SDavid Greenman 	 * to allocate a one entry hash list than it is to check all
9215bd2b43SDavid Greenman 	 * over the place for hashbase == NULL.
9315bd2b43SDavid Greenman 	 */
9415bd2b43SDavid Greenman 	ripcbinfo.hashbase = phashinit(1, M_PCB, &ripcbinfo.hashsize);
95df8bae1dSRodney W. Grimes }
96df8bae1dSRodney W. Grimes 
97f6d24a78SPoul-Henning Kamp static struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
98df8bae1dSRodney W. Grimes /*
99df8bae1dSRodney W. Grimes  * Setup generic address and protocol structures
100df8bae1dSRodney W. Grimes  * for raw_input routine, then pass them along with
101df8bae1dSRodney W. Grimes  * mbuf chain.
102df8bae1dSRodney W. Grimes  */
103df8bae1dSRodney W. Grimes void
104e62b8c49SBill Fenner rip_input(m, iphlen)
105df8bae1dSRodney W. Grimes 	struct mbuf *m;
106e62b8c49SBill Fenner 	int iphlen;
107df8bae1dSRodney W. Grimes {
108df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
109df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
110df8bae1dSRodney W. Grimes 	struct socket *last = 0;
111df8bae1dSRodney W. Grimes 
112df8bae1dSRodney W. Grimes 	ripsrc.sin_addr = ip->ip_src;
11315bd2b43SDavid Greenman 	for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
114df8bae1dSRodney W. Grimes 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
115df8bae1dSRodney W. Grimes 			continue;
116df8bae1dSRodney W. Grimes 		if (inp->inp_laddr.s_addr &&
117d99c7a23SGarrett Wollman                   inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
118df8bae1dSRodney W. Grimes 			continue;
119df8bae1dSRodney W. Grimes 		if (inp->inp_faddr.s_addr &&
120d99c7a23SGarrett Wollman                   inp->inp_faddr.s_addr != ip->ip_src.s_addr)
121df8bae1dSRodney W. Grimes 			continue;
122df8bae1dSRodney W. Grimes 		if (last) {
123623ae52eSPoul-Henning Kamp 			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
124623ae52eSPoul-Henning Kamp 			if (n) {
125623ae52eSPoul-Henning Kamp 				if (sbappendaddr(&last->so_rcv,
126623ae52eSPoul-Henning Kamp 				    (struct sockaddr *)&ripsrc, n,
127623ae52eSPoul-Henning Kamp 				    (struct mbuf *)0) == 0)
128df8bae1dSRodney W. Grimes 					/* should notify about lost packet */
129df8bae1dSRodney W. Grimes 					m_freem(n);
130df8bae1dSRodney W. Grimes 				else
131df8bae1dSRodney W. Grimes 					sorwakeup(last);
132df8bae1dSRodney W. Grimes 			}
133df8bae1dSRodney W. Grimes 		}
134df8bae1dSRodney W. Grimes 		last = inp->inp_socket;
135df8bae1dSRodney W. Grimes 	}
136df8bae1dSRodney W. Grimes 	if (last) {
137623ae52eSPoul-Henning Kamp 		if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc,
138df8bae1dSRodney W. Grimes 		    m, (struct mbuf *)0) == 0)
139df8bae1dSRodney W. Grimes 			m_freem(m);
140df8bae1dSRodney W. Grimes 		else
141df8bae1dSRodney W. Grimes 			sorwakeup(last);
142df8bae1dSRodney W. Grimes 	} else {
143df8bae1dSRodney W. Grimes 		m_freem(m);
144df8bae1dSRodney W. Grimes               ipstat.ips_noproto++;
145df8bae1dSRodney W. Grimes               ipstat.ips_delivered--;
146df8bae1dSRodney W. Grimes       }
147df8bae1dSRodney W. Grimes }
148df8bae1dSRodney W. Grimes 
149df8bae1dSRodney W. Grimes /*
150df8bae1dSRodney W. Grimes  * Generate IP header and pass packet to ip_output.
151df8bae1dSRodney W. Grimes  * Tack on options user may have setup with control call.
152df8bae1dSRodney W. Grimes  */
153df8bae1dSRodney W. Grimes int
154df8bae1dSRodney W. Grimes rip_output(m, so, dst)
155df8bae1dSRodney W. Grimes 	register struct mbuf *m;
156df8bae1dSRodney W. Grimes 	struct socket *so;
157df8bae1dSRodney W. Grimes 	u_long dst;
158df8bae1dSRodney W. Grimes {
159df8bae1dSRodney W. Grimes 	register struct ip *ip;
160df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
161df8bae1dSRodney W. Grimes 	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
162df8bae1dSRodney W. Grimes 
163df8bae1dSRodney W. Grimes 	/*
164df8bae1dSRodney W. Grimes 	 * If the user handed us a complete IP packet, use it.
165df8bae1dSRodney W. Grimes 	 * Otherwise, allocate an mbuf for a header and fill it in.
166df8bae1dSRodney W. Grimes 	 */
167df8bae1dSRodney W. Grimes 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
168df8bae1dSRodney W. Grimes 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
169df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
170df8bae1dSRodney W. Grimes 		ip->ip_tos = 0;
171df8bae1dSRodney W. Grimes 		ip->ip_off = 0;
172df8bae1dSRodney W. Grimes 		ip->ip_p = inp->inp_ip.ip_p;
173df8bae1dSRodney W. Grimes 		ip->ip_len = m->m_pkthdr.len;
174df8bae1dSRodney W. Grimes 		ip->ip_src = inp->inp_laddr;
175df8bae1dSRodney W. Grimes 		ip->ip_dst.s_addr = dst;
176df8bae1dSRodney W. Grimes 		ip->ip_ttl = MAXTTL;
177df8bae1dSRodney W. Grimes 	} else {
178df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
179072b9b24SPaul Traina 		/* don't allow both user specified and setsockopt options,
180072b9b24SPaul Traina 		   and don't allow packet length sizes that will crash */
1815e2d0696SGarrett Wollman 		if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
1825e2d0696SGarrett Wollman 		     && inp->inp_options)
1835e2d0696SGarrett Wollman 		    || (ip->ip_len > m->m_pkthdr.len)) {
184072b9b24SPaul Traina 			m_freem(m);
185072b9b24SPaul Traina 			return EINVAL;
186072b9b24SPaul Traina 		}
187df8bae1dSRodney W. Grimes 		if (ip->ip_id == 0)
188df8bae1dSRodney W. Grimes 			ip->ip_id = htons(ip_id++);
189df8bae1dSRodney W. Grimes 		/* XXX prevent ip_output from overwriting header fields */
190df8bae1dSRodney W. Grimes 		flags |= IP_RAWOUTPUT;
191df8bae1dSRodney W. Grimes 		ipstat.ips_rawout++;
192df8bae1dSRodney W. Grimes 	}
193072b9b24SPaul Traina 	return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
194072b9b24SPaul Traina 			  inp->inp_moptions));
195df8bae1dSRodney W. Grimes }
196df8bae1dSRodney W. Grimes 
197df8bae1dSRodney W. Grimes /*
198df8bae1dSRodney W. Grimes  * Raw IP socket option processing.
199df8bae1dSRodney W. Grimes  */
200df8bae1dSRodney W. Grimes int
201df8bae1dSRodney W. Grimes rip_ctloutput(op, so, level, optname, m)
202df8bae1dSRodney W. Grimes 	int op;
203df8bae1dSRodney W. Grimes 	struct socket *so;
204df8bae1dSRodney W. Grimes 	int level, optname;
205df8bae1dSRodney W. Grimes 	struct mbuf **m;
206df8bae1dSRodney W. Grimes {
207df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
208df8bae1dSRodney W. Grimes 	register int error;
209df8bae1dSRodney W. Grimes 
210aedcdea1SDavid Greenman 	if (level != IPPROTO_IP) {
211aedcdea1SDavid Greenman 		if (op == PRCO_SETOPT && *m)
212aedcdea1SDavid Greenman 			(void)m_free(*m);
213df8bae1dSRodney W. Grimes 		return (EINVAL);
214aedcdea1SDavid Greenman 	}
215df8bae1dSRodney W. Grimes 
216df8bae1dSRodney W. Grimes 	switch (optname) {
217df8bae1dSRodney W. Grimes 
218df8bae1dSRodney W. Grimes 	case IP_HDRINCL:
21925f26ad8SGarrett Wollman 		error = 0;
220df8bae1dSRodney W. Grimes 		if (op == PRCO_SETOPT) {
22125f26ad8SGarrett Wollman 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
22225f26ad8SGarrett Wollman 				error = EINVAL;
22325f26ad8SGarrett Wollman 			else if (*mtod(*m, int *))
224df8bae1dSRodney W. Grimes 				inp->inp_flags |= INP_HDRINCL;
225df8bae1dSRodney W. Grimes 			else
226df8bae1dSRodney W. Grimes 				inp->inp_flags &= ~INP_HDRINCL;
22725f26ad8SGarrett Wollman 			if (*m)
228df8bae1dSRodney W. Grimes 				(void)m_free(*m);
229df8bae1dSRodney W. Grimes 		} else {
23025f26ad8SGarrett Wollman 			*m = m_get(M_WAIT, MT_SOOPTS);
231df8bae1dSRodney W. Grimes 			(*m)->m_len = sizeof (int);
232df8bae1dSRodney W. Grimes 			*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
233df8bae1dSRodney W. Grimes 		}
23425f26ad8SGarrett Wollman 		return (error);
235df8bae1dSRodney W. Grimes 
236f9493383SGarrett Wollman #ifdef COMPAT_IPFW
23709bb5f75SPoul-Henning Kamp 	case IP_FW_GET:
23809bb5f75SPoul-Henning Kamp 		if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) {
23909bb5f75SPoul-Henning Kamp 			if (*m) (void)m_free(*m);
24009bb5f75SPoul-Henning Kamp 			return(EINVAL);
24109bb5f75SPoul-Henning Kamp 		}
24209bb5f75SPoul-Henning Kamp 		return (*ip_fw_ctl_ptr)(optname, m);
243fed1c7e9SSøren Schmidt 
2444dd1662bSUgen J.S. Antsilevich 	case IP_FW_ADD:
2454dd1662bSUgen J.S. Antsilevich 	case IP_FW_DEL:
246100ba1a6SJordan K. Hubbard 	case IP_FW_FLUSH:
247e7319babSPoul-Henning Kamp 	case IP_FW_ZERO:
24809bb5f75SPoul-Henning Kamp 		if (ip_fw_ctl_ptr == NULL || op != PRCO_SETOPT) {
24909bb5f75SPoul-Henning Kamp 			if (*m) (void)m_free(*m);
2504dd1662bSUgen J.S. Antsilevich 			return(EINVAL);
2514dd1662bSUgen J.S. Antsilevich 		}
25209bb5f75SPoul-Henning Kamp 		return (*ip_fw_ctl_ptr)(optname, m);
253f9493383SGarrett Wollman #endif
2544dd1662bSUgen J.S. Antsilevich 
255fed1c7e9SSøren Schmidt 	case IP_NAT:
256fed1c7e9SSøren Schmidt 		if (ip_nat_ctl_ptr == NULL) {
257fed1c7e9SSøren Schmidt 			if (*m) (void)m_free(*m);
258fed1c7e9SSøren Schmidt 			return(EINVAL);
259fed1c7e9SSøren Schmidt 		}
260fed1c7e9SSøren Schmidt 		return (*ip_nat_ctl_ptr)(optname, m);
261fed1c7e9SSøren Schmidt 
262f0068c4aSGarrett Wollman 	case IP_RSVP_ON:
263479bb8daSGarrett Wollman 		return ip_rsvp_init(so);
264f0068c4aSGarrett Wollman 		break;
265f0068c4aSGarrett Wollman 
266f0068c4aSGarrett Wollman 	case IP_RSVP_OFF:
267479bb8daSGarrett Wollman 		return ip_rsvp_done();
268f0068c4aSGarrett Wollman 		break;
269f0068c4aSGarrett Wollman 
2701c5de19aSGarrett Wollman 	case IP_RSVP_VIF_ON:
2711c5de19aSGarrett Wollman 		return ip_rsvp_vif_init(so, *m);
2721c5de19aSGarrett Wollman 
2731c5de19aSGarrett Wollman 	case IP_RSVP_VIF_OFF:
2741c5de19aSGarrett Wollman 		return ip_rsvp_vif_done(so, *m);
2751c5de19aSGarrett Wollman 
2761c5de19aSGarrett Wollman 	case MRT_INIT:
2771c5de19aSGarrett Wollman 	case MRT_DONE:
2781c5de19aSGarrett Wollman 	case MRT_ADD_VIF:
2791c5de19aSGarrett Wollman 	case MRT_DEL_VIF:
2801c5de19aSGarrett Wollman 	case MRT_ADD_MFC:
2811c5de19aSGarrett Wollman 	case MRT_DEL_MFC:
2821c5de19aSGarrett Wollman 	case MRT_VERSION:
2831c5de19aSGarrett Wollman 	case MRT_ASSERT:
284df8bae1dSRodney W. Grimes 		if (op == PRCO_SETOPT) {
2851c5de19aSGarrett Wollman 			error = ip_mrouter_set(optname, so, *m);
286df8bae1dSRodney W. Grimes 			if (*m)
287df8bae1dSRodney W. Grimes 				(void)m_free(*m);
2881c5de19aSGarrett Wollman 		} else if (op == PRCO_GETOPT) {
2891c5de19aSGarrett Wollman 			error = ip_mrouter_get(optname, so, m);
290df8bae1dSRodney W. Grimes 		} else
291df8bae1dSRodney W. Grimes 			error = EINVAL;
292df8bae1dSRodney W. Grimes 		return (error);
293df8bae1dSRodney W. Grimes 	}
294df8bae1dSRodney W. Grimes 	return (ip_ctloutput(op, so, level, optname, m));
295df8bae1dSRodney W. Grimes }
296df8bae1dSRodney W. Grimes 
2970312fbe9SPoul-Henning Kamp static u_long	rip_sendspace = RIPSNDQ; /* XXX sysctl ? */
2980312fbe9SPoul-Henning Kamp static u_long	rip_recvspace = RIPRCVQ; /* XXX sysctl ? */
299df8bae1dSRodney W. Grimes 
300df8bae1dSRodney W. Grimes /*ARGSUSED*/
301df8bae1dSRodney W. Grimes int
302df8bae1dSRodney W. Grimes rip_usrreq(so, req, m, nam, control)
303df8bae1dSRodney W. Grimes 	register struct socket *so;
304df8bae1dSRodney W. Grimes 	int req;
305df8bae1dSRodney W. Grimes 	struct mbuf *m, *nam, *control;
306df8bae1dSRodney W. Grimes {
307df8bae1dSRodney W. Grimes 	register int error = 0;
308df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
309c1f8a6ceSDavid Greenman 
310c1f8a6ceSDavid Greenman 	if (req == PRU_CONTROL)
311c1f8a6ceSDavid Greenman 		return (in_control(so, (u_long)m, (caddr_t)nam,
312c1f8a6ceSDavid Greenman 			(struct ifnet *)control));
313c1f8a6ceSDavid Greenman 
314df8bae1dSRodney W. Grimes 	switch (req) {
315df8bae1dSRodney W. Grimes 
316df8bae1dSRodney W. Grimes 	case PRU_ATTACH:
317df8bae1dSRodney W. Grimes 		if (inp)
318df8bae1dSRodney W. Grimes 			panic("rip_attach");
319df8bae1dSRodney W. Grimes 		if ((so->so_state & SS_PRIV) == 0) {
320df8bae1dSRodney W. Grimes 			error = EACCES;
321df8bae1dSRodney W. Grimes 			break;
322df8bae1dSRodney W. Grimes 		}
323df8bae1dSRodney W. Grimes 		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
32415bd2b43SDavid Greenman 		    (error = in_pcballoc(so, &ripcbinfo)))
325df8bae1dSRodney W. Grimes 			break;
326df8bae1dSRodney W. Grimes 		inp = (struct inpcb *)so->so_pcb;
327df8bae1dSRodney W. Grimes 		inp->inp_ip.ip_p = (int)nam;
328df8bae1dSRodney W. Grimes 		break;
329df8bae1dSRodney W. Grimes 
330df8bae1dSRodney W. Grimes 	case PRU_DISCONNECT:
331df8bae1dSRodney W. Grimes 		if ((so->so_state & SS_ISCONNECTED) == 0) {
332df8bae1dSRodney W. Grimes 			error = ENOTCONN;
333df8bae1dSRodney W. Grimes 			break;
334df8bae1dSRodney W. Grimes 		}
335df8bae1dSRodney W. Grimes 		/* FALLTHROUGH */
336df8bae1dSRodney W. Grimes 	case PRU_ABORT:
337df8bae1dSRodney W. Grimes 		soisdisconnected(so);
338df8bae1dSRodney W. Grimes 		/* FALLTHROUGH */
339df8bae1dSRodney W. Grimes 	case PRU_DETACH:
340df8bae1dSRodney W. Grimes 		if (inp == 0)
341df8bae1dSRodney W. Grimes 			panic("rip_detach");
342df8bae1dSRodney W. Grimes 		if (so == ip_mrouter)
343df8bae1dSRodney W. Grimes 			ip_mrouter_done();
344b4489dc3SGarrett Wollman 		ip_rsvp_force_done(so);
345838ecf42SGarrett Wollman 		if (so == ip_rsvpd)
346838ecf42SGarrett Wollman 			ip_rsvp_done();
347df8bae1dSRodney W. Grimes 		in_pcbdetach(inp);
348df8bae1dSRodney W. Grimes 		break;
349df8bae1dSRodney W. Grimes 
350df8bae1dSRodney W. Grimes 	case PRU_BIND:
351df8bae1dSRodney W. Grimes 	    {
352df8bae1dSRodney W. Grimes 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
353df8bae1dSRodney W. Grimes 
354df8bae1dSRodney W. Grimes 		if (nam->m_len != sizeof(*addr)) {
355df8bae1dSRodney W. Grimes 			error = EINVAL;
356df8bae1dSRodney W. Grimes 			break;
357df8bae1dSRodney W. Grimes 		}
358df8bae1dSRodney W. Grimes 		if ((ifnet == 0) ||
359df8bae1dSRodney W. Grimes 		    ((addr->sin_family != AF_INET) &&
360df8bae1dSRodney W. Grimes 		     (addr->sin_family != AF_IMPLINK)) ||
361df8bae1dSRodney W. Grimes 		    (addr->sin_addr.s_addr &&
362df8bae1dSRodney W. Grimes 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
363df8bae1dSRodney W. Grimes 			error = EADDRNOTAVAIL;
364df8bae1dSRodney W. Grimes 			break;
365df8bae1dSRodney W. Grimes 		}
366df8bae1dSRodney W. Grimes 		inp->inp_laddr = addr->sin_addr;
367df8bae1dSRodney W. Grimes 		break;
368df8bae1dSRodney W. Grimes 	    }
369df8bae1dSRodney W. Grimes 	case PRU_CONNECT:
370df8bae1dSRodney W. Grimes 	    {
371df8bae1dSRodney W. Grimes 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
372df8bae1dSRodney W. Grimes 
373df8bae1dSRodney W. Grimes 		if (nam->m_len != sizeof(*addr)) {
374df8bae1dSRodney W. Grimes 			error = EINVAL;
375df8bae1dSRodney W. Grimes 			break;
376df8bae1dSRodney W. Grimes 		}
377df8bae1dSRodney W. Grimes 		if (ifnet == 0) {
378df8bae1dSRodney W. Grimes 			error = EADDRNOTAVAIL;
379df8bae1dSRodney W. Grimes 			break;
380df8bae1dSRodney W. Grimes 		}
381df8bae1dSRodney W. Grimes 		if ((addr->sin_family != AF_INET) &&
382df8bae1dSRodney W. Grimes 		     (addr->sin_family != AF_IMPLINK)) {
383df8bae1dSRodney W. Grimes 			error = EAFNOSUPPORT;
384df8bae1dSRodney W. Grimes 			break;
385df8bae1dSRodney W. Grimes 		}
386df8bae1dSRodney W. Grimes 		inp->inp_faddr = addr->sin_addr;
387df8bae1dSRodney W. Grimes 		soisconnected(so);
388df8bae1dSRodney W. Grimes 		break;
389df8bae1dSRodney W. Grimes 	    }
390df8bae1dSRodney W. Grimes 
391df8bae1dSRodney W. Grimes 	case PRU_CONNECT2:
392df8bae1dSRodney W. Grimes 		error = EOPNOTSUPP;
393df8bae1dSRodney W. Grimes 		break;
394df8bae1dSRodney W. Grimes 
395df8bae1dSRodney W. Grimes 	/*
396df8bae1dSRodney W. Grimes 	 * Mark the connection as being incapable of further input.
397df8bae1dSRodney W. Grimes 	 */
398df8bae1dSRodney W. Grimes 	case PRU_SHUTDOWN:
399df8bae1dSRodney W. Grimes 		socantsendmore(so);
400df8bae1dSRodney W. Grimes 		break;
401df8bae1dSRodney W. Grimes 
402df8bae1dSRodney W. Grimes 	/*
403df8bae1dSRodney W. Grimes 	 * Ship a packet out.  The appropriate raw output
404df8bae1dSRodney W. Grimes 	 * routine handles any massaging necessary.
405df8bae1dSRodney W. Grimes 	 */
406df8bae1dSRodney W. Grimes 	case PRU_SEND:
407df8bae1dSRodney W. Grimes 	    {
408df8bae1dSRodney W. Grimes 		register u_long dst;
409df8bae1dSRodney W. Grimes 
410df8bae1dSRodney W. Grimes 		if (so->so_state & SS_ISCONNECTED) {
411df8bae1dSRodney W. Grimes 			if (nam) {
412df8bae1dSRodney W. Grimes 				error = EISCONN;
413df8bae1dSRodney W. Grimes 				break;
414df8bae1dSRodney W. Grimes 			}
415df8bae1dSRodney W. Grimes 			dst = inp->inp_faddr.s_addr;
416df8bae1dSRodney W. Grimes 		} else {
417df8bae1dSRodney W. Grimes 			if (nam == NULL) {
418df8bae1dSRodney W. Grimes 				error = ENOTCONN;
419df8bae1dSRodney W. Grimes 				break;
420df8bae1dSRodney W. Grimes 			}
421df8bae1dSRodney W. Grimes 			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
422df8bae1dSRodney W. Grimes 		}
423df8bae1dSRodney W. Grimes 		error = rip_output(m, so, dst);
424df8bae1dSRodney W. Grimes 		m = NULL;
425df8bae1dSRodney W. Grimes 		break;
426df8bae1dSRodney W. Grimes 	    }
427df8bae1dSRodney W. Grimes 
428df8bae1dSRodney W. Grimes 	case PRU_SENSE:
429df8bae1dSRodney W. Grimes 		/*
430df8bae1dSRodney W. Grimes 		 * stat: don't bother with a blocksize.
431df8bae1dSRodney W. Grimes 		 */
432df8bae1dSRodney W. Grimes 		return (0);
433df8bae1dSRodney W. Grimes 
434df8bae1dSRodney W. Grimes 	/*
435df8bae1dSRodney W. Grimes 	 * Not supported.
436df8bae1dSRodney W. Grimes 	 */
437df8bae1dSRodney W. Grimes 	case PRU_RCVOOB:
438df8bae1dSRodney W. Grimes 	case PRU_RCVD:
439df8bae1dSRodney W. Grimes 	case PRU_LISTEN:
440df8bae1dSRodney W. Grimes 	case PRU_ACCEPT:
441df8bae1dSRodney W. Grimes 	case PRU_SENDOOB:
442df8bae1dSRodney W. Grimes 		error = EOPNOTSUPP;
443df8bae1dSRodney W. Grimes 		break;
444df8bae1dSRodney W. Grimes 
445df8bae1dSRodney W. Grimes 	case PRU_SOCKADDR:
446df8bae1dSRodney W. Grimes 		in_setsockaddr(inp, nam);
447df8bae1dSRodney W. Grimes 		break;
448df8bae1dSRodney W. Grimes 
449df8bae1dSRodney W. Grimes 	case PRU_PEERADDR:
450df8bae1dSRodney W. Grimes 		in_setpeeraddr(inp, nam);
451df8bae1dSRodney W. Grimes 		break;
452df8bae1dSRodney W. Grimes 
453df8bae1dSRodney W. Grimes 	default:
454df8bae1dSRodney W. Grimes 		panic("rip_usrreq");
455df8bae1dSRodney W. Grimes 	}
456df8bae1dSRodney W. Grimes 	if (m != NULL)
457df8bae1dSRodney W. Grimes 		m_freem(m);
458df8bae1dSRodney W. Grimes 	return (error);
459df8bae1dSRodney W. Grimes }
460