xref: /freebsd/sys/netinet/raw_ip.c (revision 838ecf42258d76662a9d494e1f561750b84c865e)
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  *
33df8bae1dSRodney W. Grimes  *	@(#)raw_ip.c	8.2 (Berkeley) 1/4/94
34838ecf42SGarrett Wollman  * $Id: raw_ip.c,v 1.13 1995/01/26 18:59:02 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>
45df8bae1dSRodney W. Grimes 
46df8bae1dSRodney W. Grimes #include <net/if.h>
47df8bae1dSRodney W. Grimes #include <net/route.h>
48df8bae1dSRodney W. Grimes 
49df8bae1dSRodney W. Grimes #include <netinet/in.h>
50df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
51df8bae1dSRodney W. Grimes #include <netinet/ip.h>
52df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
53df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h>
54df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h>
55df8bae1dSRodney W. Grimes 
56100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h>
57100ba1a6SJordan K. Hubbard 
58df8bae1dSRodney W. Grimes struct inpcb rawinpcb;
59df8bae1dSRodney W. Grimes 
60df8bae1dSRodney W. Grimes /*
61df8bae1dSRodney W. Grimes  * Nominal space allocated to a raw ip socket.
62df8bae1dSRodney W. Grimes  */
63df8bae1dSRodney W. Grimes #define	RIPSNDQ		8192
64df8bae1dSRodney W. Grimes #define	RIPRCVQ		8192
65df8bae1dSRodney W. Grimes 
66df8bae1dSRodney W. Grimes /*
67df8bae1dSRodney W. Grimes  * Raw interface to IP protocol.
68df8bae1dSRodney W. Grimes  */
69df8bae1dSRodney W. Grimes 
70df8bae1dSRodney W. Grimes /*
71df8bae1dSRodney W. Grimes  * Initialize raw connection block q.
72df8bae1dSRodney W. Grimes  */
73df8bae1dSRodney W. Grimes void
74df8bae1dSRodney W. Grimes rip_init()
75df8bae1dSRodney W. Grimes {
76df8bae1dSRodney W. Grimes 
77df8bae1dSRodney W. Grimes 	rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb;
78df8bae1dSRodney W. Grimes }
79df8bae1dSRodney W. Grimes 
80df8bae1dSRodney W. Grimes struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
81df8bae1dSRodney W. Grimes /*
82df8bae1dSRodney W. Grimes  * Setup generic address and protocol structures
83df8bae1dSRodney W. Grimes  * for raw_input routine, then pass them along with
84df8bae1dSRodney W. Grimes  * mbuf chain.
85df8bae1dSRodney W. Grimes  */
86df8bae1dSRodney W. Grimes void
87df8bae1dSRodney W. Grimes rip_input(m)
88df8bae1dSRodney W. Grimes 	struct mbuf *m;
89df8bae1dSRodney W. Grimes {
90df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
91df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
92df8bae1dSRodney W. Grimes 	struct socket *last = 0;
93df8bae1dSRodney W. Grimes 
94df8bae1dSRodney W. Grimes 	ripsrc.sin_addr = ip->ip_src;
95df8bae1dSRodney W. Grimes 	for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) {
96df8bae1dSRodney W. Grimes 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
97df8bae1dSRodney W. Grimes 			continue;
98df8bae1dSRodney W. Grimes 		if (inp->inp_laddr.s_addr &&
99df8bae1dSRodney W. Grimes 		    inp->inp_laddr.s_addr == ip->ip_dst.s_addr)
100df8bae1dSRodney W. Grimes 			continue;
101df8bae1dSRodney W. Grimes 		if (inp->inp_faddr.s_addr &&
102df8bae1dSRodney W. Grimes 		    inp->inp_faddr.s_addr == ip->ip_src.s_addr)
103df8bae1dSRodney W. Grimes 			continue;
104df8bae1dSRodney W. Grimes 		if (last) {
105623ae52eSPoul-Henning Kamp 			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
106623ae52eSPoul-Henning Kamp 			if (n) {
107623ae52eSPoul-Henning Kamp 				if (sbappendaddr(&last->so_rcv,
108623ae52eSPoul-Henning Kamp 				    (struct sockaddr *)&ripsrc, n,
109623ae52eSPoul-Henning Kamp 				    (struct mbuf *)0) == 0)
110df8bae1dSRodney W. Grimes 					/* should notify about lost packet */
111df8bae1dSRodney W. Grimes 					m_freem(n);
112df8bae1dSRodney W. Grimes 				else
113df8bae1dSRodney W. Grimes 					sorwakeup(last);
114df8bae1dSRodney W. Grimes 			}
115df8bae1dSRodney W. Grimes 		}
116df8bae1dSRodney W. Grimes 		last = inp->inp_socket;
117df8bae1dSRodney W. Grimes 	}
118df8bae1dSRodney W. Grimes 	if (last) {
119623ae52eSPoul-Henning Kamp 		if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc,
120df8bae1dSRodney W. Grimes 		    m, (struct mbuf *)0) == 0)
121df8bae1dSRodney W. Grimes 			m_freem(m);
122df8bae1dSRodney W. Grimes 		else
123df8bae1dSRodney W. Grimes 			sorwakeup(last);
124df8bae1dSRodney W. Grimes 	} else {
125df8bae1dSRodney W. Grimes 		m_freem(m);
126df8bae1dSRodney W. Grimes 		ipstat.ips_noproto++;
127df8bae1dSRodney W. Grimes 		ipstat.ips_delivered--;
128df8bae1dSRodney W. Grimes 	}
129df8bae1dSRodney W. Grimes }
130df8bae1dSRodney W. Grimes 
131df8bae1dSRodney W. Grimes /*
132df8bae1dSRodney W. Grimes  * Generate IP header and pass packet to ip_output.
133df8bae1dSRodney W. Grimes  * Tack on options user may have setup with control call.
134df8bae1dSRodney W. Grimes  */
135df8bae1dSRodney W. Grimes int
136df8bae1dSRodney W. Grimes rip_output(m, so, dst)
137df8bae1dSRodney W. Grimes 	register struct mbuf *m;
138df8bae1dSRodney W. Grimes 	struct socket *so;
139df8bae1dSRodney W. Grimes 	u_long dst;
140df8bae1dSRodney W. Grimes {
141df8bae1dSRodney W. Grimes 	register struct ip *ip;
142df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
143df8bae1dSRodney W. Grimes 	struct mbuf *opts;
144df8bae1dSRodney W. Grimes 	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
145df8bae1dSRodney W. Grimes 
146df8bae1dSRodney W. Grimes 	/*
147df8bae1dSRodney W. Grimes 	 * If the user handed us a complete IP packet, use it.
148df8bae1dSRodney W. Grimes 	 * Otherwise, allocate an mbuf for a header and fill it in.
149df8bae1dSRodney W. Grimes 	 */
150df8bae1dSRodney W. Grimes 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
151df8bae1dSRodney W. Grimes 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
152df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
153df8bae1dSRodney W. Grimes 		ip->ip_tos = 0;
154df8bae1dSRodney W. Grimes 		ip->ip_off = 0;
155df8bae1dSRodney W. Grimes 		ip->ip_p = inp->inp_ip.ip_p;
156df8bae1dSRodney W. Grimes 		ip->ip_len = m->m_pkthdr.len;
157df8bae1dSRodney W. Grimes 		ip->ip_src = inp->inp_laddr;
158df8bae1dSRodney W. Grimes 		ip->ip_dst.s_addr = dst;
159df8bae1dSRodney W. Grimes 		ip->ip_ttl = MAXTTL;
160df8bae1dSRodney W. Grimes 		opts = inp->inp_options;
161df8bae1dSRodney W. Grimes 	} else {
162df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
163df8bae1dSRodney W. Grimes 		if (ip->ip_id == 0)
164df8bae1dSRodney W. Grimes 			ip->ip_id = htons(ip_id++);
165df8bae1dSRodney W. Grimes 		opts = NULL;
166df8bae1dSRodney W. Grimes 		/* XXX prevent ip_output from overwriting header fields */
167df8bae1dSRodney W. Grimes 		flags |= IP_RAWOUTPUT;
168df8bae1dSRodney W. Grimes 		ipstat.ips_rawout++;
169df8bae1dSRodney W. Grimes 	}
170df8bae1dSRodney W. Grimes 	return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
171df8bae1dSRodney W. Grimes }
172df8bae1dSRodney W. Grimes 
173df8bae1dSRodney W. Grimes /*
174df8bae1dSRodney W. Grimes  * Raw IP socket option processing.
175df8bae1dSRodney W. Grimes  */
176df8bae1dSRodney W. Grimes int
177df8bae1dSRodney W. Grimes rip_ctloutput(op, so, level, optname, m)
178df8bae1dSRodney W. Grimes 	int op;
179df8bae1dSRodney W. Grimes 	struct socket *so;
180df8bae1dSRodney W. Grimes 	int level, optname;
181df8bae1dSRodney W. Grimes 	struct mbuf **m;
182df8bae1dSRodney W. Grimes {
183df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
184df8bae1dSRodney W. Grimes 	register int error;
185df8bae1dSRodney W. Grimes 
186aedcdea1SDavid Greenman 	if (level != IPPROTO_IP) {
187aedcdea1SDavid Greenman 		if (op == PRCO_SETOPT && *m)
188aedcdea1SDavid Greenman 			(void)m_free(*m);
189df8bae1dSRodney W. Grimes 		return (EINVAL);
190aedcdea1SDavid Greenman 	}
191df8bae1dSRodney W. Grimes 
192df8bae1dSRodney W. Grimes 	switch (optname) {
193df8bae1dSRodney W. Grimes 
194df8bae1dSRodney W. Grimes 	case IP_HDRINCL:
195df8bae1dSRodney W. Grimes 		if (op == PRCO_SETOPT || op == PRCO_GETOPT) {
196df8bae1dSRodney W. Grimes 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
197df8bae1dSRodney W. Grimes 				return (EINVAL);
198df8bae1dSRodney W. Grimes 			if (op == PRCO_SETOPT) {
199df8bae1dSRodney W. Grimes 				if (*mtod(*m, int *))
200df8bae1dSRodney W. Grimes 					inp->inp_flags |= INP_HDRINCL;
201df8bae1dSRodney W. Grimes 				else
202df8bae1dSRodney W. Grimes 					inp->inp_flags &= ~INP_HDRINCL;
203df8bae1dSRodney W. Grimes 				(void)m_free(*m);
204df8bae1dSRodney W. Grimes 			} else {
205df8bae1dSRodney W. Grimes 				(*m)->m_len = sizeof (int);
206df8bae1dSRodney W. Grimes 				*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
207df8bae1dSRodney W. Grimes 			}
208df8bae1dSRodney W. Grimes 			return (0);
209df8bae1dSRodney W. Grimes 		}
210df8bae1dSRodney W. Grimes 		break;
211df8bae1dSRodney W. Grimes 
2124dd1662bSUgen J.S. Antsilevich 	case IP_FW_ADD:
2134dd1662bSUgen J.S. Antsilevich 	case IP_FW_DEL:
214100ba1a6SJordan K. Hubbard 	case IP_FW_FLUSH:
215100ba1a6SJordan K. Hubbard 	case IP_FW_POLICY:
2164dd1662bSUgen J.S. Antsilevich 		if (ip_fw_ctl_ptr==NULL) {
2174dd1662bSUgen J.S. Antsilevich 			if (*m)
2184dd1662bSUgen J.S. Antsilevich 				(void)m_free(*m);
2194dd1662bSUgen J.S. Antsilevich 			return(EINVAL);
2204dd1662bSUgen J.S. Antsilevich 		}
221100ba1a6SJordan K. Hubbard 
222ad63b513SJordan K. Hubbard 		if (op == PRCO_SETOPT) {
2234dd1662bSUgen J.S. Antsilevich 			error=(*ip_fw_ctl_ptr)(optname, *m);
224ad63b513SJordan K. Hubbard 			if (*m)
225ad63b513SJordan K. Hubbard 				(void)m_free(*m);
226ad63b513SJordan K. Hubbard 		}
227100ba1a6SJordan K. Hubbard 		else
228100ba1a6SJordan K. Hubbard 			error=EINVAL;
229100ba1a6SJordan K. Hubbard 		return(error);
2304dd1662bSUgen J.S. Antsilevich 
23163f8d699SJordan K. Hubbard 	case IP_ACCT_DEL:
23263f8d699SJordan K. Hubbard 	case IP_ACCT_ADD:
2333107b31bSUgen J.S. Antsilevich 	case IP_ACCT_CLR:
23463f8d699SJordan K. Hubbard 	case IP_ACCT_FLUSH:
23563f8d699SJordan K. Hubbard 	case IP_ACCT_ZERO:
2364dd1662bSUgen J.S. Antsilevich 		if (ip_acct_ctl_ptr==NULL) {
2374dd1662bSUgen J.S. Antsilevich 			if (*m)
2384dd1662bSUgen J.S. Antsilevich 				(void)m_free(*m);
2394dd1662bSUgen J.S. Antsilevich 			return(EINVAL);
2404dd1662bSUgen J.S. Antsilevich 		}
241100ba1a6SJordan K. Hubbard 
24263f8d699SJordan K. Hubbard 		if (op = PRCO_SETOPT) {
2434dd1662bSUgen J.S. Antsilevich 			error=(*ip_acct_ctl_ptr)(optname, *m);
24463f8d699SJordan K. Hubbard 			if (*m)
24563f8d699SJordan K. Hubbard 				(void)m_free(*m);
24663f8d699SJordan K. Hubbard 		}
24763f8d699SJordan K. Hubbard 		else
24863f8d699SJordan K. Hubbard 			error=EINVAL;
24963f8d699SJordan K. Hubbard 		return(error);
250100ba1a6SJordan K. Hubbard 
251f0068c4aSGarrett Wollman 	case IP_RSVP_ON:
252479bb8daSGarrett Wollman 		return ip_rsvp_init(so);
253f0068c4aSGarrett Wollman 		break;
254f0068c4aSGarrett Wollman 
255f0068c4aSGarrett Wollman 	case IP_RSVP_OFF:
256479bb8daSGarrett Wollman 		return ip_rsvp_done();
257f0068c4aSGarrett Wollman 		break;
258f0068c4aSGarrett Wollman 
259df8bae1dSRodney W. Grimes 	case DVMRP_INIT:
260df8bae1dSRodney W. Grimes 	case DVMRP_DONE:
261df8bae1dSRodney W. Grimes 	case DVMRP_ADD_VIF:
262df8bae1dSRodney W. Grimes 	case DVMRP_DEL_VIF:
263f0068c4aSGarrett Wollman 	case DVMRP_ADD_MFC:
264f0068c4aSGarrett Wollman 	case DVMRP_DEL_MFC:
265df8bae1dSRodney W. Grimes 		if (op == PRCO_SETOPT) {
266df8bae1dSRodney W. Grimes 			error = ip_mrouter_cmd(optname, so, *m);
267df8bae1dSRodney W. Grimes 			if (*m)
268df8bae1dSRodney W. Grimes 				(void)m_free(*m);
269df8bae1dSRodney W. Grimes 		} else
270df8bae1dSRodney W. Grimes 			error = EINVAL;
271df8bae1dSRodney W. Grimes 		return (error);
272df8bae1dSRodney W. Grimes 	}
273df8bae1dSRodney W. Grimes 	return (ip_ctloutput(op, so, level, optname, m));
274df8bae1dSRodney W. Grimes }
275df8bae1dSRodney W. Grimes 
276df8bae1dSRodney W. Grimes u_long	rip_sendspace = RIPSNDQ;
277df8bae1dSRodney W. Grimes u_long	rip_recvspace = RIPRCVQ;
278df8bae1dSRodney W. Grimes 
279df8bae1dSRodney W. Grimes /*ARGSUSED*/
280df8bae1dSRodney W. Grimes int
281df8bae1dSRodney W. Grimes rip_usrreq(so, req, m, nam, control)
282df8bae1dSRodney W. Grimes 	register struct socket *so;
283df8bae1dSRodney W. Grimes 	int req;
284df8bae1dSRodney W. Grimes 	struct mbuf *m, *nam, *control;
285df8bae1dSRodney W. Grimes {
286df8bae1dSRodney W. Grimes 	register int error = 0;
287df8bae1dSRodney W. Grimes 	register struct inpcb *inp = sotoinpcb(so);
288df8bae1dSRodney W. Grimes 	switch (req) {
289df8bae1dSRodney W. Grimes 
290df8bae1dSRodney W. Grimes 	case PRU_ATTACH:
291df8bae1dSRodney W. Grimes 		if (inp)
292df8bae1dSRodney W. Grimes 			panic("rip_attach");
293df8bae1dSRodney W. Grimes 		if ((so->so_state & SS_PRIV) == 0) {
294df8bae1dSRodney W. Grimes 			error = EACCES;
295df8bae1dSRodney W. Grimes 			break;
296df8bae1dSRodney W. Grimes 		}
297df8bae1dSRodney W. Grimes 		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
298df8bae1dSRodney W. Grimes 		    (error = in_pcballoc(so, &rawinpcb)))
299df8bae1dSRodney W. Grimes 			break;
300df8bae1dSRodney W. Grimes 		inp = (struct inpcb *)so->so_pcb;
301df8bae1dSRodney W. Grimes 		inp->inp_ip.ip_p = (int)nam;
302df8bae1dSRodney W. Grimes 		break;
303df8bae1dSRodney W. Grimes 
304df8bae1dSRodney W. Grimes 	case PRU_DISCONNECT:
305df8bae1dSRodney W. Grimes 		if ((so->so_state & SS_ISCONNECTED) == 0) {
306df8bae1dSRodney W. Grimes 			error = ENOTCONN;
307df8bae1dSRodney W. Grimes 			break;
308df8bae1dSRodney W. Grimes 		}
309df8bae1dSRodney W. Grimes 		/* FALLTHROUGH */
310df8bae1dSRodney W. Grimes 	case PRU_ABORT:
311df8bae1dSRodney W. Grimes 		soisdisconnected(so);
312df8bae1dSRodney W. Grimes 		/* FALLTHROUGH */
313df8bae1dSRodney W. Grimes 	case PRU_DETACH:
314df8bae1dSRodney W. Grimes 		if (inp == 0)
315df8bae1dSRodney W. Grimes 			panic("rip_detach");
316df8bae1dSRodney W. Grimes 		if (so == ip_mrouter)
317df8bae1dSRodney W. Grimes 			ip_mrouter_done();
318838ecf42SGarrett Wollman 		if (so == ip_rsvpd)
319838ecf42SGarrett Wollman 			ip_rsvp_done();
320df8bae1dSRodney W. Grimes 		in_pcbdetach(inp);
321df8bae1dSRodney W. Grimes 		break;
322df8bae1dSRodney W. Grimes 
323df8bae1dSRodney W. Grimes 	case PRU_BIND:
324df8bae1dSRodney W. Grimes 	    {
325df8bae1dSRodney W. Grimes 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
326df8bae1dSRodney W. Grimes 
327df8bae1dSRodney W. Grimes 		if (nam->m_len != sizeof(*addr)) {
328df8bae1dSRodney W. Grimes 			error = EINVAL;
329df8bae1dSRodney W. Grimes 			break;
330df8bae1dSRodney W. Grimes 		}
331df8bae1dSRodney W. Grimes 		if ((ifnet == 0) ||
332df8bae1dSRodney W. Grimes 		    ((addr->sin_family != AF_INET) &&
333df8bae1dSRodney W. Grimes 		     (addr->sin_family != AF_IMPLINK)) ||
334df8bae1dSRodney W. Grimes 		    (addr->sin_addr.s_addr &&
335df8bae1dSRodney W. Grimes 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
336df8bae1dSRodney W. Grimes 			error = EADDRNOTAVAIL;
337df8bae1dSRodney W. Grimes 			break;
338df8bae1dSRodney W. Grimes 		}
339df8bae1dSRodney W. Grimes 		inp->inp_laddr = addr->sin_addr;
340df8bae1dSRodney W. Grimes 		break;
341df8bae1dSRodney W. Grimes 	    }
342df8bae1dSRodney W. Grimes 	case PRU_CONNECT:
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 			error = EADDRNOTAVAIL;
352df8bae1dSRodney W. Grimes 			break;
353df8bae1dSRodney W. Grimes 		}
354df8bae1dSRodney W. Grimes 		if ((addr->sin_family != AF_INET) &&
355df8bae1dSRodney W. Grimes 		     (addr->sin_family != AF_IMPLINK)) {
356df8bae1dSRodney W. Grimes 			error = EAFNOSUPPORT;
357df8bae1dSRodney W. Grimes 			break;
358df8bae1dSRodney W. Grimes 		}
359df8bae1dSRodney W. Grimes 		inp->inp_faddr = addr->sin_addr;
360df8bae1dSRodney W. Grimes 		soisconnected(so);
361df8bae1dSRodney W. Grimes 		break;
362df8bae1dSRodney W. Grimes 	    }
363df8bae1dSRodney W. Grimes 
364df8bae1dSRodney W. Grimes 	case PRU_CONNECT2:
365df8bae1dSRodney W. Grimes 		error = EOPNOTSUPP;
366df8bae1dSRodney W. Grimes 		break;
367df8bae1dSRodney W. Grimes 
368df8bae1dSRodney W. Grimes 	/*
369df8bae1dSRodney W. Grimes 	 * Mark the connection as being incapable of further input.
370df8bae1dSRodney W. Grimes 	 */
371df8bae1dSRodney W. Grimes 	case PRU_SHUTDOWN:
372df8bae1dSRodney W. Grimes 		socantsendmore(so);
373df8bae1dSRodney W. Grimes 		break;
374df8bae1dSRodney W. Grimes 
375df8bae1dSRodney W. Grimes 	/*
376df8bae1dSRodney W. Grimes 	 * Ship a packet out.  The appropriate raw output
377df8bae1dSRodney W. Grimes 	 * routine handles any massaging necessary.
378df8bae1dSRodney W. Grimes 	 */
379df8bae1dSRodney W. Grimes 	case PRU_SEND:
380df8bae1dSRodney W. Grimes 	    {
381df8bae1dSRodney W. Grimes 		register u_long dst;
382df8bae1dSRodney W. Grimes 
383df8bae1dSRodney W. Grimes 		if (so->so_state & SS_ISCONNECTED) {
384df8bae1dSRodney W. Grimes 			if (nam) {
385df8bae1dSRodney W. Grimes 				error = EISCONN;
386df8bae1dSRodney W. Grimes 				break;
387df8bae1dSRodney W. Grimes 			}
388df8bae1dSRodney W. Grimes 			dst = inp->inp_faddr.s_addr;
389df8bae1dSRodney W. Grimes 		} else {
390df8bae1dSRodney W. Grimes 			if (nam == NULL) {
391df8bae1dSRodney W. Grimes 				error = ENOTCONN;
392df8bae1dSRodney W. Grimes 				break;
393df8bae1dSRodney W. Grimes 			}
394df8bae1dSRodney W. Grimes 			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
395df8bae1dSRodney W. Grimes 		}
396df8bae1dSRodney W. Grimes 		error = rip_output(m, so, dst);
397df8bae1dSRodney W. Grimes 		m = NULL;
398df8bae1dSRodney W. Grimes 		break;
399df8bae1dSRodney W. Grimes 	    }
400df8bae1dSRodney W. Grimes 
401df8bae1dSRodney W. Grimes 	case PRU_SENSE:
402df8bae1dSRodney W. Grimes 		/*
403df8bae1dSRodney W. Grimes 		 * stat: don't bother with a blocksize.
404df8bae1dSRodney W. Grimes 		 */
405df8bae1dSRodney W. Grimes 		return (0);
406df8bae1dSRodney W. Grimes 
407df8bae1dSRodney W. Grimes 	/*
408df8bae1dSRodney W. Grimes 	 * Not supported.
409df8bae1dSRodney W. Grimes 	 */
410df8bae1dSRodney W. Grimes 	case PRU_RCVOOB:
411df8bae1dSRodney W. Grimes 	case PRU_RCVD:
412df8bae1dSRodney W. Grimes 	case PRU_LISTEN:
413df8bae1dSRodney W. Grimes 	case PRU_ACCEPT:
414df8bae1dSRodney W. Grimes 	case PRU_SENDOOB:
415df8bae1dSRodney W. Grimes 		error = EOPNOTSUPP;
416df8bae1dSRodney W. Grimes 		break;
417df8bae1dSRodney W. Grimes 
418df8bae1dSRodney W. Grimes 	case PRU_SOCKADDR:
419df8bae1dSRodney W. Grimes 		in_setsockaddr(inp, nam);
420df8bae1dSRodney W. Grimes 		break;
421df8bae1dSRodney W. Grimes 
422df8bae1dSRodney W. Grimes 	case PRU_PEERADDR:
423df8bae1dSRodney W. Grimes 		in_setpeeraddr(inp, nam);
424df8bae1dSRodney W. Grimes 		break;
425df8bae1dSRodney W. Grimes 
426df8bae1dSRodney W. Grimes 	default:
427df8bae1dSRodney W. Grimes 		panic("rip_usrreq");
428df8bae1dSRodney W. Grimes 	}
429df8bae1dSRodney W. Grimes 	if (m != NULL)
430df8bae1dSRodney W. Grimes 		m_freem(m);
431df8bae1dSRodney W. Grimes 	return (error);
432df8bae1dSRodney W. Grimes }
433