xref: /freebsd/sys/netinet/raw_ip.c (revision e7319bab6bd0bb7f1f719c5cbb670d5ed21b3296)
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
34e7319babSPoul-Henning Kamp  *	$Id: raw_ip.c,v 1.25 1995/12/09 20:43:53 phk 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>
53c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h>
54c1f8a6ceSDavid Greenman #include <netinet/in_var.h>
55df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
56df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h>
57df8bae1dSRodney W. Grimes 
58100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h>
59100ba1a6SJordan K. Hubbard 
60f6d24a78SPoul-Henning Kamp static struct inpcbhead ripcb;
61f6d24a78SPoul-Henning Kamp static struct inpcbinfo ripcbinfo;
62df8bae1dSRodney W. Grimes 
63df8bae1dSRodney W. Grimes /*
64df8bae1dSRodney W. Grimes  * Nominal space allocated to a raw ip socket.
65df8bae1dSRodney W. Grimes  */
66df8bae1dSRodney W. Grimes #define	RIPSNDQ		8192
67df8bae1dSRodney W. Grimes #define	RIPRCVQ		8192
68df8bae1dSRodney W. Grimes 
69df8bae1dSRodney W. Grimes /*
70df8bae1dSRodney W. Grimes  * Raw interface to IP protocol.
71df8bae1dSRodney W. Grimes  */
72df8bae1dSRodney W. Grimes 
73df8bae1dSRodney W. Grimes /*
74df8bae1dSRodney W. Grimes  * Initialize raw connection block q.
75df8bae1dSRodney W. Grimes  */
76df8bae1dSRodney W. Grimes void
77df8bae1dSRodney W. Grimes rip_init()
78df8bae1dSRodney W. Grimes {
7915bd2b43SDavid Greenman 	LIST_INIT(&ripcb);
8015bd2b43SDavid Greenman 	ripcbinfo.listhead = &ripcb;
8115bd2b43SDavid Greenman 	/*
8215bd2b43SDavid Greenman 	 * XXX We don't use the hash list for raw IP, but it's easier
8315bd2b43SDavid Greenman 	 * to allocate a one entry hash list than it is to check all
8415bd2b43SDavid Greenman 	 * over the place for hashbase == NULL.
8515bd2b43SDavid Greenman 	 */
8615bd2b43SDavid Greenman 	ripcbinfo.hashbase = phashinit(1, M_PCB, &ripcbinfo.hashsize);
87df8bae1dSRodney W. Grimes }
88df8bae1dSRodney W. Grimes 
89f6d24a78SPoul-Henning Kamp static struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
90df8bae1dSRodney W. Grimes /*
91df8bae1dSRodney W. Grimes  * Setup generic address and protocol structures
92df8bae1dSRodney W. Grimes  * for raw_input routine, then pass them along with
93df8bae1dSRodney W. Grimes  * mbuf chain.
94df8bae1dSRodney W. Grimes  */
95df8bae1dSRodney W. Grimes void
96df8bae1dSRodney W. Grimes rip_input(m)
97df8bae1dSRodney W. Grimes 	struct mbuf *m;
98df8bae1dSRodney W. Grimes {
99df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
100df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
101df8bae1dSRodney W. Grimes 	struct socket *last = 0;
102df8bae1dSRodney W. Grimes 
103df8bae1dSRodney W. Grimes 	ripsrc.sin_addr = ip->ip_src;
10415bd2b43SDavid Greenman 	for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
105df8bae1dSRodney W. Grimes 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
106df8bae1dSRodney W. Grimes 			continue;
107df8bae1dSRodney W. Grimes 		if (inp->inp_laddr.s_addr &&
108d99c7a23SGarrett Wollman                   inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
109df8bae1dSRodney W. Grimes 			continue;
110df8bae1dSRodney W. Grimes 		if (inp->inp_faddr.s_addr &&
111d99c7a23SGarrett Wollman                   inp->inp_faddr.s_addr != ip->ip_src.s_addr)
112df8bae1dSRodney W. Grimes 			continue;
113df8bae1dSRodney W. Grimes 		if (last) {
114623ae52eSPoul-Henning Kamp 			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
115623ae52eSPoul-Henning Kamp 			if (n) {
116623ae52eSPoul-Henning Kamp 				if (sbappendaddr(&last->so_rcv,
117623ae52eSPoul-Henning Kamp 				    (struct sockaddr *)&ripsrc, n,
118623ae52eSPoul-Henning Kamp 				    (struct mbuf *)0) == 0)
119df8bae1dSRodney W. Grimes 					/* should notify about lost packet */
120df8bae1dSRodney W. Grimes 					m_freem(n);
121df8bae1dSRodney W. Grimes 				else
122df8bae1dSRodney W. Grimes 					sorwakeup(last);
123df8bae1dSRodney W. Grimes 			}
124df8bae1dSRodney W. Grimes 		}
125df8bae1dSRodney W. Grimes 		last = inp->inp_socket;
126df8bae1dSRodney W. Grimes 	}
127df8bae1dSRodney W. Grimes 	if (last) {
128623ae52eSPoul-Henning Kamp 		if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc,
129df8bae1dSRodney W. Grimes 		    m, (struct mbuf *)0) == 0)
130df8bae1dSRodney W. Grimes 			m_freem(m);
131df8bae1dSRodney W. Grimes 		else
132df8bae1dSRodney W. Grimes 			sorwakeup(last);
133df8bae1dSRodney W. Grimes 	} else {
134df8bae1dSRodney W. Grimes 		m_freem(m);
135df8bae1dSRodney W. Grimes               ipstat.ips_noproto++;
136df8bae1dSRodney W. Grimes               ipstat.ips_delivered--;
137df8bae1dSRodney W. Grimes       }
138df8bae1dSRodney W. Grimes }
139df8bae1dSRodney W. Grimes 
140df8bae1dSRodney W. Grimes /*
141df8bae1dSRodney W. Grimes  * Generate IP header and pass packet to ip_output.
142df8bae1dSRodney W. Grimes  * Tack on options user may have setup with control call.
143df8bae1dSRodney W. Grimes  */
144df8bae1dSRodney W. Grimes int
145df8bae1dSRodney W. Grimes rip_output(m, so, dst)
146df8bae1dSRodney W. Grimes 	register struct mbuf *m;
147df8bae1dSRodney W. Grimes 	struct socket *so;
148df8bae1dSRodney W. Grimes 	u_long dst;
149df8bae1dSRodney W. Grimes {
150df8bae1dSRodney W. Grimes 	register struct ip *ip;
151df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
152df8bae1dSRodney W. Grimes 	struct mbuf *opts;
153df8bae1dSRodney W. Grimes 	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
154df8bae1dSRodney W. Grimes 
155df8bae1dSRodney W. Grimes 	/*
156df8bae1dSRodney W. Grimes 	 * If the user handed us a complete IP packet, use it.
157df8bae1dSRodney W. Grimes 	 * Otherwise, allocate an mbuf for a header and fill it in.
158df8bae1dSRodney W. Grimes 	 */
159df8bae1dSRodney W. Grimes 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
160df8bae1dSRodney W. Grimes 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
161df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
162df8bae1dSRodney W. Grimes 		ip->ip_tos = 0;
163df8bae1dSRodney W. Grimes 		ip->ip_off = 0;
164df8bae1dSRodney W. Grimes 		ip->ip_p = inp->inp_ip.ip_p;
165df8bae1dSRodney W. Grimes 		ip->ip_len = m->m_pkthdr.len;
166df8bae1dSRodney W. Grimes 		ip->ip_src = inp->inp_laddr;
167df8bae1dSRodney W. Grimes 		ip->ip_dst.s_addr = dst;
168df8bae1dSRodney W. Grimes 		ip->ip_ttl = MAXTTL;
169df8bae1dSRodney W. Grimes 		opts = inp->inp_options;
170df8bae1dSRodney W. Grimes 	} else {
171df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
172df8bae1dSRodney W. Grimes 		if (ip->ip_id == 0)
173df8bae1dSRodney W. Grimes 			ip->ip_id = htons(ip_id++);
174df8bae1dSRodney W. Grimes 		opts = NULL;
175df8bae1dSRodney W. Grimes 		/* XXX prevent ip_output from overwriting header fields */
176df8bae1dSRodney W. Grimes 		flags |= IP_RAWOUTPUT;
177df8bae1dSRodney W. Grimes 		ipstat.ips_rawout++;
178df8bae1dSRodney W. Grimes 	}
179df8bae1dSRodney W. Grimes 	return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
180df8bae1dSRodney W. Grimes }
181df8bae1dSRodney W. Grimes 
182df8bae1dSRodney W. Grimes /*
183df8bae1dSRodney W. Grimes  * Raw IP socket option processing.
184df8bae1dSRodney W. Grimes  */
185df8bae1dSRodney W. Grimes int
186df8bae1dSRodney W. Grimes rip_ctloutput(op, so, level, optname, m)
187df8bae1dSRodney W. Grimes 	int op;
188df8bae1dSRodney W. Grimes 	struct socket *so;
189df8bae1dSRodney W. Grimes 	int level, optname;
190df8bae1dSRodney W. Grimes 	struct mbuf **m;
191df8bae1dSRodney W. Grimes {
192df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
193df8bae1dSRodney W. Grimes 	register int error;
194df8bae1dSRodney W. Grimes 
195aedcdea1SDavid Greenman 	if (level != IPPROTO_IP) {
196aedcdea1SDavid Greenman 		if (op == PRCO_SETOPT && *m)
197aedcdea1SDavid Greenman 			(void)m_free(*m);
198df8bae1dSRodney W. Grimes 		return (EINVAL);
199aedcdea1SDavid Greenman 	}
200df8bae1dSRodney W. Grimes 
201df8bae1dSRodney W. Grimes 	switch (optname) {
202df8bae1dSRodney W. Grimes 
203df8bae1dSRodney W. Grimes 	case IP_HDRINCL:
20425f26ad8SGarrett Wollman 		error = 0;
205df8bae1dSRodney W. Grimes 		if (op == PRCO_SETOPT) {
20625f26ad8SGarrett Wollman 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
20725f26ad8SGarrett Wollman 				error = EINVAL;
20825f26ad8SGarrett Wollman 			else if (*mtod(*m, int *))
209df8bae1dSRodney W. Grimes 				inp->inp_flags |= INP_HDRINCL;
210df8bae1dSRodney W. Grimes 			else
211df8bae1dSRodney W. Grimes 				inp->inp_flags &= ~INP_HDRINCL;
21225f26ad8SGarrett Wollman 			if (*m)
213df8bae1dSRodney W. Grimes 				(void)m_free(*m);
214df8bae1dSRodney W. Grimes 		} else {
21525f26ad8SGarrett Wollman 			*m = m_get(M_WAIT, MT_SOOPTS);
216df8bae1dSRodney W. Grimes 			(*m)->m_len = sizeof (int);
217df8bae1dSRodney W. Grimes 			*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
218df8bae1dSRodney W. Grimes 		}
21925f26ad8SGarrett Wollman 		return (error);
220df8bae1dSRodney W. Grimes 
2214dd1662bSUgen J.S. Antsilevich 	case IP_FW_ADD:
2224dd1662bSUgen J.S. Antsilevich 	case IP_FW_DEL:
223100ba1a6SJordan K. Hubbard 	case IP_FW_FLUSH:
224e7319babSPoul-Henning Kamp 	case IP_FW_ZERO:
2254dd1662bSUgen J.S. Antsilevich 		if (ip_fw_ctl_ptr==NULL) {
2264dd1662bSUgen J.S. Antsilevich 			if (*m)
2274dd1662bSUgen J.S. Antsilevich 				(void)m_free(*m);
2284dd1662bSUgen J.S. Antsilevich 			return(EINVAL);
2294dd1662bSUgen J.S. Antsilevich 		}
230100ba1a6SJordan K. Hubbard 
231ad63b513SJordan K. Hubbard 		if (op == PRCO_SETOPT) {
2324dd1662bSUgen J.S. Antsilevich 			error=(*ip_fw_ctl_ptr)(optname, *m);
233ad63b513SJordan K. Hubbard 			if (*m)
234ad63b513SJordan K. Hubbard 				(void)m_free(*m);
235ad63b513SJordan K. Hubbard 		}
236100ba1a6SJordan K. Hubbard 		else
237100ba1a6SJordan K. Hubbard 			error=EINVAL;
238100ba1a6SJordan K. Hubbard 		return(error);
2394dd1662bSUgen J.S. Antsilevich 
240f0068c4aSGarrett Wollman 	case IP_RSVP_ON:
241479bb8daSGarrett Wollman 		return ip_rsvp_init(so);
242f0068c4aSGarrett Wollman 		break;
243f0068c4aSGarrett Wollman 
244f0068c4aSGarrett Wollman 	case IP_RSVP_OFF:
245479bb8daSGarrett Wollman 		return ip_rsvp_done();
246f0068c4aSGarrett Wollman 		break;
247f0068c4aSGarrett Wollman 
2481c5de19aSGarrett Wollman 	case IP_RSVP_VIF_ON:
2491c5de19aSGarrett Wollman 		return ip_rsvp_vif_init(so, *m);
2501c5de19aSGarrett Wollman 
2511c5de19aSGarrett Wollman 	case IP_RSVP_VIF_OFF:
2521c5de19aSGarrett Wollman 		return ip_rsvp_vif_done(so, *m);
2531c5de19aSGarrett Wollman 
2541c5de19aSGarrett Wollman 	case MRT_INIT:
2551c5de19aSGarrett Wollman 	case MRT_DONE:
2561c5de19aSGarrett Wollman 	case MRT_ADD_VIF:
2571c5de19aSGarrett Wollman 	case MRT_DEL_VIF:
2581c5de19aSGarrett Wollman 	case MRT_ADD_MFC:
2591c5de19aSGarrett Wollman 	case MRT_DEL_MFC:
2601c5de19aSGarrett Wollman 	case MRT_VERSION:
2611c5de19aSGarrett Wollman 	case MRT_ASSERT:
262df8bae1dSRodney W. Grimes 		if (op == PRCO_SETOPT) {
2631c5de19aSGarrett Wollman 			error = ip_mrouter_set(optname, so, *m);
264df8bae1dSRodney W. Grimes 			if (*m)
265df8bae1dSRodney W. Grimes 				(void)m_free(*m);
2661c5de19aSGarrett Wollman 		} else if (op == PRCO_GETOPT) {
2671c5de19aSGarrett Wollman 			error = ip_mrouter_get(optname, so, m);
268df8bae1dSRodney W. Grimes 		} else
269df8bae1dSRodney W. Grimes 			error = EINVAL;
270df8bae1dSRodney W. Grimes 		return (error);
271df8bae1dSRodney W. Grimes 	}
272df8bae1dSRodney W. Grimes 	return (ip_ctloutput(op, so, level, optname, m));
273df8bae1dSRodney W. Grimes }
274df8bae1dSRodney W. Grimes 
2750312fbe9SPoul-Henning Kamp static u_long	rip_sendspace = RIPSNDQ; /* XXX sysctl ? */
2760312fbe9SPoul-Henning Kamp static u_long	rip_recvspace = RIPRCVQ; /* XXX sysctl ? */
277df8bae1dSRodney W. Grimes 
278df8bae1dSRodney W. Grimes /*ARGSUSED*/
279df8bae1dSRodney W. Grimes int
280df8bae1dSRodney W. Grimes rip_usrreq(so, req, m, nam, control)
281df8bae1dSRodney W. Grimes 	register struct socket *so;
282df8bae1dSRodney W. Grimes 	int req;
283df8bae1dSRodney W. Grimes 	struct mbuf *m, *nam, *control;
284df8bae1dSRodney W. Grimes {
285df8bae1dSRodney W. Grimes 	register int error = 0;
286df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
287c1f8a6ceSDavid Greenman 
288c1f8a6ceSDavid Greenman 	if (req == PRU_CONTROL)
289c1f8a6ceSDavid Greenman 		return (in_control(so, (u_long)m, (caddr_t)nam,
290c1f8a6ceSDavid Greenman 			(struct ifnet *)control));
291c1f8a6ceSDavid Greenman 
292df8bae1dSRodney W. Grimes 	switch (req) {
293df8bae1dSRodney W. Grimes 
294df8bae1dSRodney W. Grimes 	case PRU_ATTACH:
295df8bae1dSRodney W. Grimes 		if (inp)
296df8bae1dSRodney W. Grimes 			panic("rip_attach");
297df8bae1dSRodney W. Grimes 		if ((so->so_state & SS_PRIV) == 0) {
298df8bae1dSRodney W. Grimes 			error = EACCES;
299df8bae1dSRodney W. Grimes 			break;
300df8bae1dSRodney W. Grimes 		}
301df8bae1dSRodney W. Grimes 		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
30215bd2b43SDavid Greenman 		    (error = in_pcballoc(so, &ripcbinfo)))
303df8bae1dSRodney W. Grimes 			break;
304df8bae1dSRodney W. Grimes 		inp = (struct inpcb *)so->so_pcb;
305df8bae1dSRodney W. Grimes 		inp->inp_ip.ip_p = (int)nam;
306df8bae1dSRodney W. Grimes 		break;
307df8bae1dSRodney W. Grimes 
308df8bae1dSRodney W. Grimes 	case PRU_DISCONNECT:
309df8bae1dSRodney W. Grimes 		if ((so->so_state & SS_ISCONNECTED) == 0) {
310df8bae1dSRodney W. Grimes 			error = ENOTCONN;
311df8bae1dSRodney W. Grimes 			break;
312df8bae1dSRodney W. Grimes 		}
313df8bae1dSRodney W. Grimes 		/* FALLTHROUGH */
314df8bae1dSRodney W. Grimes 	case PRU_ABORT:
315df8bae1dSRodney W. Grimes 		soisdisconnected(so);
316df8bae1dSRodney W. Grimes 		/* FALLTHROUGH */
317df8bae1dSRodney W. Grimes 	case PRU_DETACH:
318df8bae1dSRodney W. Grimes 		if (inp == 0)
319df8bae1dSRodney W. Grimes 			panic("rip_detach");
320df8bae1dSRodney W. Grimes 		if (so == ip_mrouter)
321df8bae1dSRodney W. Grimes 			ip_mrouter_done();
322b4489dc3SGarrett Wollman 		ip_rsvp_force_done(so);
323838ecf42SGarrett Wollman 		if (so == ip_rsvpd)
324838ecf42SGarrett Wollman 			ip_rsvp_done();
325df8bae1dSRodney W. Grimes 		in_pcbdetach(inp);
326df8bae1dSRodney W. Grimes 		break;
327df8bae1dSRodney W. Grimes 
328df8bae1dSRodney W. Grimes 	case PRU_BIND:
329df8bae1dSRodney W. Grimes 	    {
330df8bae1dSRodney W. Grimes 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
331df8bae1dSRodney W. Grimes 
332df8bae1dSRodney W. Grimes 		if (nam->m_len != sizeof(*addr)) {
333df8bae1dSRodney W. Grimes 			error = EINVAL;
334df8bae1dSRodney W. Grimes 			break;
335df8bae1dSRodney W. Grimes 		}
336df8bae1dSRodney W. Grimes 		if ((ifnet == 0) ||
337df8bae1dSRodney W. Grimes 		    ((addr->sin_family != AF_INET) &&
338df8bae1dSRodney W. Grimes 		     (addr->sin_family != AF_IMPLINK)) ||
339df8bae1dSRodney W. Grimes 		    (addr->sin_addr.s_addr &&
340df8bae1dSRodney W. Grimes 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
341df8bae1dSRodney W. Grimes 			error = EADDRNOTAVAIL;
342df8bae1dSRodney W. Grimes 			break;
343df8bae1dSRodney W. Grimes 		}
344df8bae1dSRodney W. Grimes 		inp->inp_laddr = addr->sin_addr;
345df8bae1dSRodney W. Grimes 		break;
346df8bae1dSRodney W. Grimes 	    }
347df8bae1dSRodney W. Grimes 	case PRU_CONNECT:
348df8bae1dSRodney W. Grimes 	    {
349df8bae1dSRodney W. Grimes 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
350df8bae1dSRodney W. Grimes 
351df8bae1dSRodney W. Grimes 		if (nam->m_len != sizeof(*addr)) {
352df8bae1dSRodney W. Grimes 			error = EINVAL;
353df8bae1dSRodney W. Grimes 			break;
354df8bae1dSRodney W. Grimes 		}
355df8bae1dSRodney W. Grimes 		if (ifnet == 0) {
356df8bae1dSRodney W. Grimes 			error = EADDRNOTAVAIL;
357df8bae1dSRodney W. Grimes 			break;
358df8bae1dSRodney W. Grimes 		}
359df8bae1dSRodney W. Grimes 		if ((addr->sin_family != AF_INET) &&
360df8bae1dSRodney W. Grimes 		     (addr->sin_family != AF_IMPLINK)) {
361df8bae1dSRodney W. Grimes 			error = EAFNOSUPPORT;
362df8bae1dSRodney W. Grimes 			break;
363df8bae1dSRodney W. Grimes 		}
364df8bae1dSRodney W. Grimes 		inp->inp_faddr = addr->sin_addr;
365df8bae1dSRodney W. Grimes 		soisconnected(so);
366df8bae1dSRodney W. Grimes 		break;
367df8bae1dSRodney W. Grimes 	    }
368df8bae1dSRodney W. Grimes 
369df8bae1dSRodney W. Grimes 	case PRU_CONNECT2:
370df8bae1dSRodney W. Grimes 		error = EOPNOTSUPP;
371df8bae1dSRodney W. Grimes 		break;
372df8bae1dSRodney W. Grimes 
373df8bae1dSRodney W. Grimes 	/*
374df8bae1dSRodney W. Grimes 	 * Mark the connection as being incapable of further input.
375df8bae1dSRodney W. Grimes 	 */
376df8bae1dSRodney W. Grimes 	case PRU_SHUTDOWN:
377df8bae1dSRodney W. Grimes 		socantsendmore(so);
378df8bae1dSRodney W. Grimes 		break;
379df8bae1dSRodney W. Grimes 
380df8bae1dSRodney W. Grimes 	/*
381df8bae1dSRodney W. Grimes 	 * Ship a packet out.  The appropriate raw output
382df8bae1dSRodney W. Grimes 	 * routine handles any massaging necessary.
383df8bae1dSRodney W. Grimes 	 */
384df8bae1dSRodney W. Grimes 	case PRU_SEND:
385df8bae1dSRodney W. Grimes 	    {
386df8bae1dSRodney W. Grimes 		register u_long dst;
387df8bae1dSRodney W. Grimes 
388df8bae1dSRodney W. Grimes 		if (so->so_state & SS_ISCONNECTED) {
389df8bae1dSRodney W. Grimes 			if (nam) {
390df8bae1dSRodney W. Grimes 				error = EISCONN;
391df8bae1dSRodney W. Grimes 				break;
392df8bae1dSRodney W. Grimes 			}
393df8bae1dSRodney W. Grimes 			dst = inp->inp_faddr.s_addr;
394df8bae1dSRodney W. Grimes 		} else {
395df8bae1dSRodney W. Grimes 			if (nam == NULL) {
396df8bae1dSRodney W. Grimes 				error = ENOTCONN;
397df8bae1dSRodney W. Grimes 				break;
398df8bae1dSRodney W. Grimes 			}
399df8bae1dSRodney W. Grimes 			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
400df8bae1dSRodney W. Grimes 		}
401df8bae1dSRodney W. Grimes 		error = rip_output(m, so, dst);
402df8bae1dSRodney W. Grimes 		m = NULL;
403df8bae1dSRodney W. Grimes 		break;
404df8bae1dSRodney W. Grimes 	    }
405df8bae1dSRodney W. Grimes 
406df8bae1dSRodney W. Grimes 	case PRU_SENSE:
407df8bae1dSRodney W. Grimes 		/*
408df8bae1dSRodney W. Grimes 		 * stat: don't bother with a blocksize.
409df8bae1dSRodney W. Grimes 		 */
410df8bae1dSRodney W. Grimes 		return (0);
411df8bae1dSRodney W. Grimes 
412df8bae1dSRodney W. Grimes 	/*
413df8bae1dSRodney W. Grimes 	 * Not supported.
414df8bae1dSRodney W. Grimes 	 */
415df8bae1dSRodney W. Grimes 	case PRU_RCVOOB:
416df8bae1dSRodney W. Grimes 	case PRU_RCVD:
417df8bae1dSRodney W. Grimes 	case PRU_LISTEN:
418df8bae1dSRodney W. Grimes 	case PRU_ACCEPT:
419df8bae1dSRodney W. Grimes 	case PRU_SENDOOB:
420df8bae1dSRodney W. Grimes 		error = EOPNOTSUPP;
421df8bae1dSRodney W. Grimes 		break;
422df8bae1dSRodney W. Grimes 
423df8bae1dSRodney W. Grimes 	case PRU_SOCKADDR:
424df8bae1dSRodney W. Grimes 		in_setsockaddr(inp, nam);
425df8bae1dSRodney W. Grimes 		break;
426df8bae1dSRodney W. Grimes 
427df8bae1dSRodney W. Grimes 	case PRU_PEERADDR:
428df8bae1dSRodney W. Grimes 		in_setpeeraddr(inp, nam);
429df8bae1dSRodney W. Grimes 		break;
430df8bae1dSRodney W. Grimes 
431df8bae1dSRodney W. Grimes 	default:
432df8bae1dSRodney W. Grimes 		panic("rip_usrreq");
433df8bae1dSRodney W. Grimes 	}
434df8bae1dSRodney W. Grimes 	if (m != NULL)
435df8bae1dSRodney W. Grimes 		m_freem(m);
436df8bae1dSRodney W. Grimes 	return (error);
437df8bae1dSRodney W. Grimes }
438