xref: /freebsd/sys/netinet/raw_ip.c (revision 25f26ad85a04bd6f42218e38501f9db2c870a6af)
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
3425f26ad8SGarrett Wollman  *	$Id: raw_ip.c,v 1.21 1995/07/24 16:33:51 wollman Exp $
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
37df8bae1dSRodney W. Grimes #include <sys/param.h>
38df8bae1dSRodney W. Grimes #include <sys/malloc.h>
39df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
40df8bae1dSRodney W. Grimes #include <sys/socket.h>
41df8bae1dSRodney W. Grimes #include <sys/protosw.h>
42df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
43df8bae1dSRodney W. Grimes #include <sys/errno.h>
44df8bae1dSRodney W. Grimes #include <sys/systm.h>
4515bd2b43SDavid Greenman #include <sys/queue.h>
46df8bae1dSRodney W. Grimes 
47df8bae1dSRodney W. Grimes #include <net/if.h>
48df8bae1dSRodney W. Grimes #include <net/route.h>
49df8bae1dSRodney W. Grimes 
50df8bae1dSRodney W. Grimes #include <netinet/in.h>
51df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
52df8bae1dSRodney W. Grimes #include <netinet/ip.h>
53df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
54df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h>
55df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h>
56df8bae1dSRodney W. Grimes 
57100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h>
58100ba1a6SJordan K. Hubbard 
5915bd2b43SDavid Greenman struct inpcbhead ripcb;
6015bd2b43SDavid Greenman struct inpcbinfo ripcbinfo;
61df8bae1dSRodney W. Grimes 
62df8bae1dSRodney W. Grimes /*
63df8bae1dSRodney W. Grimes  * Nominal space allocated to a raw ip socket.
64df8bae1dSRodney W. Grimes  */
65df8bae1dSRodney W. Grimes #define	RIPSNDQ		8192
66df8bae1dSRodney W. Grimes #define	RIPRCVQ		8192
67df8bae1dSRodney W. Grimes 
68df8bae1dSRodney W. Grimes /*
69df8bae1dSRodney W. Grimes  * Raw interface to IP protocol.
70df8bae1dSRodney W. Grimes  */
71df8bae1dSRodney W. Grimes 
72df8bae1dSRodney W. Grimes /*
73df8bae1dSRodney W. Grimes  * Initialize raw connection block q.
74df8bae1dSRodney W. Grimes  */
75df8bae1dSRodney W. Grimes void
76df8bae1dSRodney W. Grimes rip_init()
77df8bae1dSRodney W. Grimes {
7815bd2b43SDavid Greenman 	LIST_INIT(&ripcb);
7915bd2b43SDavid Greenman 	ripcbinfo.listhead = &ripcb;
8015bd2b43SDavid Greenman 	/*
8115bd2b43SDavid Greenman 	 * XXX We don't use the hash list for raw IP, but it's easier
8215bd2b43SDavid Greenman 	 * to allocate a one entry hash list than it is to check all
8315bd2b43SDavid Greenman 	 * over the place for hashbase == NULL.
8415bd2b43SDavid Greenman 	 */
8515bd2b43SDavid Greenman 	ripcbinfo.hashbase = phashinit(1, M_PCB, &ripcbinfo.hashsize);
86df8bae1dSRodney W. Grimes }
87df8bae1dSRodney W. Grimes 
88df8bae1dSRodney W. Grimes struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
89df8bae1dSRodney W. Grimes /*
90df8bae1dSRodney W. Grimes  * Setup generic address and protocol structures
91df8bae1dSRodney W. Grimes  * for raw_input routine, then pass them along with
92df8bae1dSRodney W. Grimes  * mbuf chain.
93df8bae1dSRodney W. Grimes  */
94df8bae1dSRodney W. Grimes void
95df8bae1dSRodney W. Grimes rip_input(m)
96df8bae1dSRodney W. Grimes 	struct mbuf *m;
97df8bae1dSRodney W. Grimes {
98df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
99df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
100df8bae1dSRodney W. Grimes 	struct socket *last = 0;
101df8bae1dSRodney W. Grimes 
102df8bae1dSRodney W. Grimes 	ripsrc.sin_addr = ip->ip_src;
10315bd2b43SDavid Greenman 	for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
104df8bae1dSRodney W. Grimes 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
105df8bae1dSRodney W. Grimes 			continue;
106df8bae1dSRodney W. Grimes 		if (inp->inp_laddr.s_addr &&
107d99c7a23SGarrett Wollman                   inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
108df8bae1dSRodney W. Grimes 			continue;
109df8bae1dSRodney W. Grimes 		if (inp->inp_faddr.s_addr &&
110d99c7a23SGarrett Wollman                   inp->inp_faddr.s_addr != ip->ip_src.s_addr)
111df8bae1dSRodney W. Grimes 			continue;
112df8bae1dSRodney W. Grimes 		if (last) {
113623ae52eSPoul-Henning Kamp 			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
114623ae52eSPoul-Henning Kamp 			if (n) {
115623ae52eSPoul-Henning Kamp 				if (sbappendaddr(&last->so_rcv,
116623ae52eSPoul-Henning Kamp 				    (struct sockaddr *)&ripsrc, n,
117623ae52eSPoul-Henning Kamp 				    (struct mbuf *)0) == 0)
118df8bae1dSRodney W. Grimes 					/* should notify about lost packet */
119df8bae1dSRodney W. Grimes 					m_freem(n);
120df8bae1dSRodney W. Grimes 				else
121df8bae1dSRodney W. Grimes 					sorwakeup(last);
122df8bae1dSRodney W. Grimes 			}
123df8bae1dSRodney W. Grimes 		}
124df8bae1dSRodney W. Grimes 		last = inp->inp_socket;
125df8bae1dSRodney W. Grimes 	}
126df8bae1dSRodney W. Grimes 	if (last) {
127623ae52eSPoul-Henning Kamp 		if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc,
128df8bae1dSRodney W. Grimes 		    m, (struct mbuf *)0) == 0)
129df8bae1dSRodney W. Grimes 			m_freem(m);
130df8bae1dSRodney W. Grimes 		else
131df8bae1dSRodney W. Grimes 			sorwakeup(last);
132df8bae1dSRodney W. Grimes 	} else {
133df8bae1dSRodney W. Grimes 		m_freem(m);
134df8bae1dSRodney W. Grimes               ipstat.ips_noproto++;
135df8bae1dSRodney W. Grimes               ipstat.ips_delivered--;
136df8bae1dSRodney W. Grimes       }
137df8bae1dSRodney W. Grimes }
138df8bae1dSRodney W. Grimes 
139df8bae1dSRodney W. Grimes /*
140df8bae1dSRodney W. Grimes  * Generate IP header and pass packet to ip_output.
141df8bae1dSRodney W. Grimes  * Tack on options user may have setup with control call.
142df8bae1dSRodney W. Grimes  */
143df8bae1dSRodney W. Grimes int
144df8bae1dSRodney W. Grimes rip_output(m, so, dst)
145df8bae1dSRodney W. Grimes 	register struct mbuf *m;
146df8bae1dSRodney W. Grimes 	struct socket *so;
147df8bae1dSRodney W. Grimes 	u_long dst;
148df8bae1dSRodney W. Grimes {
149df8bae1dSRodney W. Grimes 	register struct ip *ip;
150df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
151df8bae1dSRodney W. Grimes 	struct mbuf *opts;
152df8bae1dSRodney W. Grimes 	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
153df8bae1dSRodney W. Grimes 
154df8bae1dSRodney W. Grimes 	/*
155df8bae1dSRodney W. Grimes 	 * If the user handed us a complete IP packet, use it.
156df8bae1dSRodney W. Grimes 	 * Otherwise, allocate an mbuf for a header and fill it in.
157df8bae1dSRodney W. Grimes 	 */
158df8bae1dSRodney W. Grimes 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
159df8bae1dSRodney W. Grimes 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
160df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
161df8bae1dSRodney W. Grimes 		ip->ip_tos = 0;
162df8bae1dSRodney W. Grimes 		ip->ip_off = 0;
163df8bae1dSRodney W. Grimes 		ip->ip_p = inp->inp_ip.ip_p;
164df8bae1dSRodney W. Grimes 		ip->ip_len = m->m_pkthdr.len;
165df8bae1dSRodney W. Grimes 		ip->ip_src = inp->inp_laddr;
166df8bae1dSRodney W. Grimes 		ip->ip_dst.s_addr = dst;
167df8bae1dSRodney W. Grimes 		ip->ip_ttl = MAXTTL;
168df8bae1dSRodney W. Grimes 		opts = inp->inp_options;
169df8bae1dSRodney W. Grimes 	} else {
170df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
171df8bae1dSRodney W. Grimes 		if (ip->ip_id == 0)
172df8bae1dSRodney W. Grimes 			ip->ip_id = htons(ip_id++);
173df8bae1dSRodney W. Grimes 		opts = NULL;
174df8bae1dSRodney W. Grimes 		/* XXX prevent ip_output from overwriting header fields */
175df8bae1dSRodney W. Grimes 		flags |= IP_RAWOUTPUT;
176df8bae1dSRodney W. Grimes 		ipstat.ips_rawout++;
177df8bae1dSRodney W. Grimes 	}
178df8bae1dSRodney W. Grimes 	return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
179df8bae1dSRodney W. Grimes }
180df8bae1dSRodney W. Grimes 
181df8bae1dSRodney W. Grimes /*
182df8bae1dSRodney W. Grimes  * Raw IP socket option processing.
183df8bae1dSRodney W. Grimes  */
184df8bae1dSRodney W. Grimes int
185df8bae1dSRodney W. Grimes rip_ctloutput(op, so, level, optname, m)
186df8bae1dSRodney W. Grimes 	int op;
187df8bae1dSRodney W. Grimes 	struct socket *so;
188df8bae1dSRodney W. Grimes 	int level, optname;
189df8bae1dSRodney W. Grimes 	struct mbuf **m;
190df8bae1dSRodney W. Grimes {
191df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
192df8bae1dSRodney W. Grimes 	register int error;
193df8bae1dSRodney W. Grimes 
194aedcdea1SDavid Greenman 	if (level != IPPROTO_IP) {
195aedcdea1SDavid Greenman 		if (op == PRCO_SETOPT && *m)
196aedcdea1SDavid Greenman 			(void)m_free(*m);
197df8bae1dSRodney W. Grimes 		return (EINVAL);
198aedcdea1SDavid Greenman 	}
199df8bae1dSRodney W. Grimes 
200df8bae1dSRodney W. Grimes 	switch (optname) {
201df8bae1dSRodney W. Grimes 
202df8bae1dSRodney W. Grimes 	case IP_HDRINCL:
20325f26ad8SGarrett Wollman 		error = 0;
204df8bae1dSRodney W. Grimes 		if (op == PRCO_SETOPT) {
20525f26ad8SGarrett Wollman 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
20625f26ad8SGarrett Wollman 				error = EINVAL;
20725f26ad8SGarrett Wollman 			else if (*mtod(*m, int *))
208df8bae1dSRodney W. Grimes 				inp->inp_flags |= INP_HDRINCL;
209df8bae1dSRodney W. Grimes 			else
210df8bae1dSRodney W. Grimes 				inp->inp_flags &= ~INP_HDRINCL;
21125f26ad8SGarrett Wollman 			if (*m)
212df8bae1dSRodney W. Grimes 				(void)m_free(*m);
213df8bae1dSRodney W. Grimes 		} else {
21425f26ad8SGarrett Wollman 			*m = m_get(M_WAIT, MT_SOOPTS);
215df8bae1dSRodney W. Grimes 			(*m)->m_len = sizeof (int);
216df8bae1dSRodney W. Grimes 			*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
217df8bae1dSRodney W. Grimes 		}
21825f26ad8SGarrett Wollman 		return (error);
219df8bae1dSRodney W. Grimes 
2204dd1662bSUgen J.S. Antsilevich 	case IP_FW_ADD:
2214dd1662bSUgen J.S. Antsilevich 	case IP_FW_DEL:
222100ba1a6SJordan K. Hubbard 	case IP_FW_FLUSH:
223100ba1a6SJordan K. Hubbard 	case IP_FW_POLICY:
2244dd1662bSUgen J.S. Antsilevich 		if (ip_fw_ctl_ptr==NULL) {
2254dd1662bSUgen J.S. Antsilevich 			if (*m)
2264dd1662bSUgen J.S. Antsilevich 				(void)m_free(*m);
2274dd1662bSUgen J.S. Antsilevich 			return(EINVAL);
2284dd1662bSUgen J.S. Antsilevich 		}
229100ba1a6SJordan K. Hubbard 
230ad63b513SJordan K. Hubbard 		if (op == PRCO_SETOPT) {
2314dd1662bSUgen J.S. Antsilevich 			error=(*ip_fw_ctl_ptr)(optname, *m);
232ad63b513SJordan K. Hubbard 			if (*m)
233ad63b513SJordan K. Hubbard 				(void)m_free(*m);
234ad63b513SJordan K. Hubbard 		}
235100ba1a6SJordan K. Hubbard 		else
236100ba1a6SJordan K. Hubbard 			error=EINVAL;
237100ba1a6SJordan K. Hubbard 		return(error);
2384dd1662bSUgen J.S. Antsilevich 
23963f8d699SJordan K. Hubbard 	case IP_ACCT_DEL:
24063f8d699SJordan K. Hubbard 	case IP_ACCT_ADD:
2413107b31bSUgen J.S. Antsilevich 	case IP_ACCT_CLR:
24263f8d699SJordan K. Hubbard 	case IP_ACCT_FLUSH:
24363f8d699SJordan K. Hubbard 	case IP_ACCT_ZERO:
2444dd1662bSUgen J.S. Antsilevich 		if (ip_acct_ctl_ptr==NULL) {
2454dd1662bSUgen J.S. Antsilevich 			if (*m)
2464dd1662bSUgen J.S. Antsilevich 				(void)m_free(*m);
2474dd1662bSUgen J.S. Antsilevich 			return(EINVAL);
2484dd1662bSUgen J.S. Antsilevich 		}
249100ba1a6SJordan K. Hubbard 
2502f632e8fSAndrey A. Chernov 		if (op == PRCO_SETOPT) {
2514dd1662bSUgen J.S. Antsilevich 			error=(*ip_acct_ctl_ptr)(optname, *m);
25263f8d699SJordan K. Hubbard 			if (*m)
25363f8d699SJordan K. Hubbard 				(void)m_free(*m);
25463f8d699SJordan K. Hubbard 		}
25563f8d699SJordan K. Hubbard 		else
25663f8d699SJordan K. Hubbard 			error=EINVAL;
25763f8d699SJordan K. Hubbard 		return(error);
258100ba1a6SJordan K. Hubbard 
259f0068c4aSGarrett Wollman 	case IP_RSVP_ON:
260479bb8daSGarrett Wollman 		return ip_rsvp_init(so);
261f0068c4aSGarrett Wollman 		break;
262f0068c4aSGarrett Wollman 
263f0068c4aSGarrett Wollman 	case IP_RSVP_OFF:
264479bb8daSGarrett Wollman 		return ip_rsvp_done();
265f0068c4aSGarrett Wollman 		break;
266f0068c4aSGarrett Wollman 
2671c5de19aSGarrett Wollman 	case IP_RSVP_VIF_ON:
2681c5de19aSGarrett Wollman 		return ip_rsvp_vif_init(so, *m);
2691c5de19aSGarrett Wollman 
2701c5de19aSGarrett Wollman 	case IP_RSVP_VIF_OFF:
2711c5de19aSGarrett Wollman 		return ip_rsvp_vif_done(so, *m);
2721c5de19aSGarrett Wollman 
2731c5de19aSGarrett Wollman 	case MRT_INIT:
2741c5de19aSGarrett Wollman 	case MRT_DONE:
2751c5de19aSGarrett Wollman 	case MRT_ADD_VIF:
2761c5de19aSGarrett Wollman 	case MRT_DEL_VIF:
2771c5de19aSGarrett Wollman 	case MRT_ADD_MFC:
2781c5de19aSGarrett Wollman 	case MRT_DEL_MFC:
2791c5de19aSGarrett Wollman 	case MRT_VERSION:
2801c5de19aSGarrett Wollman 	case MRT_ASSERT:
281df8bae1dSRodney W. Grimes 		if (op == PRCO_SETOPT) {
2821c5de19aSGarrett Wollman 			error = ip_mrouter_set(optname, so, *m);
283df8bae1dSRodney W. Grimes 			if (*m)
284df8bae1dSRodney W. Grimes 				(void)m_free(*m);
2851c5de19aSGarrett Wollman 		} else if (op == PRCO_GETOPT) {
2861c5de19aSGarrett Wollman 			error = ip_mrouter_get(optname, so, m);
287df8bae1dSRodney W. Grimes 		} else
288df8bae1dSRodney W. Grimes 			error = EINVAL;
289df8bae1dSRodney W. Grimes 		return (error);
290df8bae1dSRodney W. Grimes 	}
291df8bae1dSRodney W. Grimes 	return (ip_ctloutput(op, so, level, optname, m));
292df8bae1dSRodney W. Grimes }
293df8bae1dSRodney W. Grimes 
294df8bae1dSRodney W. Grimes u_long	rip_sendspace = RIPSNDQ;
295df8bae1dSRodney W. Grimes u_long	rip_recvspace = RIPRCVQ;
296df8bae1dSRodney W. Grimes 
297df8bae1dSRodney W. Grimes /*ARGSUSED*/
298df8bae1dSRodney W. Grimes int
299df8bae1dSRodney W. Grimes rip_usrreq(so, req, m, nam, control)
300df8bae1dSRodney W. Grimes 	register struct socket *so;
301df8bae1dSRodney W. Grimes 	int req;
302df8bae1dSRodney W. Grimes 	struct mbuf *m, *nam, *control;
303df8bae1dSRodney W. Grimes {
304df8bae1dSRodney W. Grimes 	register int error = 0;
305df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
306df8bae1dSRodney W. Grimes 	switch (req) {
307df8bae1dSRodney W. Grimes 
308df8bae1dSRodney W. Grimes 	case PRU_ATTACH:
309df8bae1dSRodney W. Grimes 		if (inp)
310df8bae1dSRodney W. Grimes 			panic("rip_attach");
311df8bae1dSRodney W. Grimes 		if ((so->so_state & SS_PRIV) == 0) {
312df8bae1dSRodney W. Grimes 			error = EACCES;
313df8bae1dSRodney W. Grimes 			break;
314df8bae1dSRodney W. Grimes 		}
315df8bae1dSRodney W. Grimes 		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
31615bd2b43SDavid Greenman 		    (error = in_pcballoc(so, &ripcbinfo)))
317df8bae1dSRodney W. Grimes 			break;
318df8bae1dSRodney W. Grimes 		inp = (struct inpcb *)so->so_pcb;
319df8bae1dSRodney W. Grimes 		inp->inp_ip.ip_p = (int)nam;
320df8bae1dSRodney W. Grimes 		break;
321df8bae1dSRodney W. Grimes 
322df8bae1dSRodney W. Grimes 	case PRU_DISCONNECT:
323df8bae1dSRodney W. Grimes 		if ((so->so_state & SS_ISCONNECTED) == 0) {
324df8bae1dSRodney W. Grimes 			error = ENOTCONN;
325df8bae1dSRodney W. Grimes 			break;
326df8bae1dSRodney W. Grimes 		}
327df8bae1dSRodney W. Grimes 		/* FALLTHROUGH */
328df8bae1dSRodney W. Grimes 	case PRU_ABORT:
329df8bae1dSRodney W. Grimes 		soisdisconnected(so);
330df8bae1dSRodney W. Grimes 		/* FALLTHROUGH */
331df8bae1dSRodney W. Grimes 	case PRU_DETACH:
332df8bae1dSRodney W. Grimes 		if (inp == 0)
333df8bae1dSRodney W. Grimes 			panic("rip_detach");
334df8bae1dSRodney W. Grimes 		if (so == ip_mrouter)
335df8bae1dSRodney W. Grimes 			ip_mrouter_done();
336b4489dc3SGarrett Wollman 		ip_rsvp_force_done(so);
337838ecf42SGarrett Wollman 		if (so == ip_rsvpd)
338838ecf42SGarrett Wollman 			ip_rsvp_done();
339df8bae1dSRodney W. Grimes 		in_pcbdetach(inp);
340df8bae1dSRodney W. Grimes 		break;
341df8bae1dSRodney W. Grimes 
342df8bae1dSRodney W. Grimes 	case PRU_BIND:
343df8bae1dSRodney W. Grimes 	    {
344df8bae1dSRodney W. Grimes 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
345df8bae1dSRodney W. Grimes 
346df8bae1dSRodney W. Grimes 		if (nam->m_len != sizeof(*addr)) {
347df8bae1dSRodney W. Grimes 			error = EINVAL;
348df8bae1dSRodney W. Grimes 			break;
349df8bae1dSRodney W. Grimes 		}
350df8bae1dSRodney W. Grimes 		if ((ifnet == 0) ||
351df8bae1dSRodney W. Grimes 		    ((addr->sin_family != AF_INET) &&
352df8bae1dSRodney W. Grimes 		     (addr->sin_family != AF_IMPLINK)) ||
353df8bae1dSRodney W. Grimes 		    (addr->sin_addr.s_addr &&
354df8bae1dSRodney W. Grimes 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
355df8bae1dSRodney W. Grimes 			error = EADDRNOTAVAIL;
356df8bae1dSRodney W. Grimes 			break;
357df8bae1dSRodney W. Grimes 		}
358df8bae1dSRodney W. Grimes 		inp->inp_laddr = addr->sin_addr;
359df8bae1dSRodney W. Grimes 		break;
360df8bae1dSRodney W. Grimes 	    }
361df8bae1dSRodney W. Grimes 	case PRU_CONNECT:
362df8bae1dSRodney W. Grimes 	    {
363df8bae1dSRodney W. Grimes 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
364df8bae1dSRodney W. Grimes 
365df8bae1dSRodney W. Grimes 		if (nam->m_len != sizeof(*addr)) {
366df8bae1dSRodney W. Grimes 			error = EINVAL;
367df8bae1dSRodney W. Grimes 			break;
368df8bae1dSRodney W. Grimes 		}
369df8bae1dSRodney W. Grimes 		if (ifnet == 0) {
370df8bae1dSRodney W. Grimes 			error = EADDRNOTAVAIL;
371df8bae1dSRodney W. Grimes 			break;
372df8bae1dSRodney W. Grimes 		}
373df8bae1dSRodney W. Grimes 		if ((addr->sin_family != AF_INET) &&
374df8bae1dSRodney W. Grimes 		     (addr->sin_family != AF_IMPLINK)) {
375df8bae1dSRodney W. Grimes 			error = EAFNOSUPPORT;
376df8bae1dSRodney W. Grimes 			break;
377df8bae1dSRodney W. Grimes 		}
378df8bae1dSRodney W. Grimes 		inp->inp_faddr = addr->sin_addr;
379df8bae1dSRodney W. Grimes 		soisconnected(so);
380df8bae1dSRodney W. Grimes 		break;
381df8bae1dSRodney W. Grimes 	    }
382df8bae1dSRodney W. Grimes 
383df8bae1dSRodney W. Grimes 	case PRU_CONNECT2:
384df8bae1dSRodney W. Grimes 		error = EOPNOTSUPP;
385df8bae1dSRodney W. Grimes 		break;
386df8bae1dSRodney W. Grimes 
387df8bae1dSRodney W. Grimes 	/*
388df8bae1dSRodney W. Grimes 	 * Mark the connection as being incapable of further input.
389df8bae1dSRodney W. Grimes 	 */
390df8bae1dSRodney W. Grimes 	case PRU_SHUTDOWN:
391df8bae1dSRodney W. Grimes 		socantsendmore(so);
392df8bae1dSRodney W. Grimes 		break;
393df8bae1dSRodney W. Grimes 
394df8bae1dSRodney W. Grimes 	/*
395df8bae1dSRodney W. Grimes 	 * Ship a packet out.  The appropriate raw output
396df8bae1dSRodney W. Grimes 	 * routine handles any massaging necessary.
397df8bae1dSRodney W. Grimes 	 */
398df8bae1dSRodney W. Grimes 	case PRU_SEND:
399df8bae1dSRodney W. Grimes 	    {
400df8bae1dSRodney W. Grimes 		register u_long dst;
401df8bae1dSRodney W. Grimes 
402df8bae1dSRodney W. Grimes 		if (so->so_state & SS_ISCONNECTED) {
403df8bae1dSRodney W. Grimes 			if (nam) {
404df8bae1dSRodney W. Grimes 				error = EISCONN;
405df8bae1dSRodney W. Grimes 				break;
406df8bae1dSRodney W. Grimes 			}
407df8bae1dSRodney W. Grimes 			dst = inp->inp_faddr.s_addr;
408df8bae1dSRodney W. Grimes 		} else {
409df8bae1dSRodney W. Grimes 			if (nam == NULL) {
410df8bae1dSRodney W. Grimes 				error = ENOTCONN;
411df8bae1dSRodney W. Grimes 				break;
412df8bae1dSRodney W. Grimes 			}
413df8bae1dSRodney W. Grimes 			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
414df8bae1dSRodney W. Grimes 		}
415df8bae1dSRodney W. Grimes 		error = rip_output(m, so, dst);
416df8bae1dSRodney W. Grimes 		m = NULL;
417df8bae1dSRodney W. Grimes 		break;
418df8bae1dSRodney W. Grimes 	    }
419df8bae1dSRodney W. Grimes 
420df8bae1dSRodney W. Grimes 	case PRU_SENSE:
421df8bae1dSRodney W. Grimes 		/*
422df8bae1dSRodney W. Grimes 		 * stat: don't bother with a blocksize.
423df8bae1dSRodney W. Grimes 		 */
424df8bae1dSRodney W. Grimes 		return (0);
425df8bae1dSRodney W. Grimes 
426df8bae1dSRodney W. Grimes 	/*
427df8bae1dSRodney W. Grimes 	 * Not supported.
428df8bae1dSRodney W. Grimes 	 */
429df8bae1dSRodney W. Grimes 	case PRU_RCVOOB:
430df8bae1dSRodney W. Grimes 	case PRU_RCVD:
431df8bae1dSRodney W. Grimes 	case PRU_LISTEN:
432df8bae1dSRodney W. Grimes 	case PRU_ACCEPT:
433df8bae1dSRodney W. Grimes 	case PRU_SENDOOB:
434df8bae1dSRodney W. Grimes 		error = EOPNOTSUPP;
435df8bae1dSRodney W. Grimes 		break;
436df8bae1dSRodney W. Grimes 
437df8bae1dSRodney W. Grimes 	case PRU_SOCKADDR:
438df8bae1dSRodney W. Grimes 		in_setsockaddr(inp, nam);
439df8bae1dSRodney W. Grimes 		break;
440df8bae1dSRodney W. Grimes 
441df8bae1dSRodney W. Grimes 	case PRU_PEERADDR:
442df8bae1dSRodney W. Grimes 		in_setpeeraddr(inp, nam);
443df8bae1dSRodney W. Grimes 		break;
444df8bae1dSRodney W. Grimes 
445df8bae1dSRodney W. Grimes 	default:
446df8bae1dSRodney W. Grimes 		panic("rip_usrreq");
447df8bae1dSRodney W. Grimes 	}
448df8bae1dSRodney W. Grimes 	if (m != NULL)
449df8bae1dSRodney W. Grimes 		m_freem(m);
450df8bae1dSRodney W. Grimes 	return (error);
451df8bae1dSRodney W. Grimes }
452