raw_ip.c revision 5085
1/*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	@(#)raw_ip.c	8.2 (Berkeley) 1/4/94
34 * $Id: raw_ip.c,v 1.8 1994/11/16 10:17:11 jkh Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/malloc.h>
39#include <sys/mbuf.h>
40#include <sys/socket.h>
41#include <sys/protosw.h>
42#include <sys/socketvar.h>
43#include <sys/errno.h>
44#include <sys/systm.h>
45
46#include <net/if.h>
47#include <net/route.h>
48
49#include <netinet/in.h>
50#include <netinet/in_systm.h>
51#include <netinet/ip.h>
52#include <netinet/ip_var.h>
53#include <netinet/ip_mroute.h>
54#include <netinet/in_pcb.h>
55
56#ifdef IPFIREWALL
57#include <netinet/ip_fw.h>
58#endif
59#ifdef IPACCT
60#include <netinet/ip_fw.h>
61#endif
62
63struct inpcb rawinpcb;
64
65/*
66 * Nominal space allocated to a raw ip socket.
67 */
68#define	RIPSNDQ		8192
69#define	RIPRCVQ		8192
70
71/*
72 * Raw interface to IP protocol.
73 */
74
75/*
76 * Initialize raw connection block q.
77 */
78void
79rip_init()
80{
81
82	rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb;
83}
84
85struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
86/*
87 * Setup generic address and protocol structures
88 * for raw_input routine, then pass them along with
89 * mbuf chain.
90 */
91void
92rip_input(m)
93	struct mbuf *m;
94{
95	register struct ip *ip = mtod(m, struct ip *);
96	register struct inpcb *inp;
97	struct socket *last = 0;
98
99	ripsrc.sin_addr = ip->ip_src;
100	for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) {
101		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
102			continue;
103		if (inp->inp_laddr.s_addr &&
104		    inp->inp_laddr.s_addr == ip->ip_dst.s_addr)
105			continue;
106		if (inp->inp_faddr.s_addr &&
107		    inp->inp_faddr.s_addr == ip->ip_src.s_addr)
108			continue;
109		if (last) {
110			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
111			if (n) {
112				if (sbappendaddr(&last->so_rcv,
113				    (struct sockaddr *)&ripsrc, n,
114				    (struct mbuf *)0) == 0)
115					/* should notify about lost packet */
116					m_freem(n);
117				else
118					sorwakeup(last);
119			}
120		}
121		last = inp->inp_socket;
122	}
123	if (last) {
124		if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc,
125		    m, (struct mbuf *)0) == 0)
126			m_freem(m);
127		else
128			sorwakeup(last);
129	} else {
130		m_freem(m);
131		ipstat.ips_noproto++;
132		ipstat.ips_delivered--;
133	}
134}
135
136/*
137 * Generate IP header and pass packet to ip_output.
138 * Tack on options user may have setup with control call.
139 */
140int
141rip_output(m, so, dst)
142	register struct mbuf *m;
143	struct socket *so;
144	u_long dst;
145{
146	register struct ip *ip;
147	register struct inpcb *inp = sotoinpcb(so);
148	struct mbuf *opts;
149	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
150
151	/*
152	 * If the user handed us a complete IP packet, use it.
153	 * Otherwise, allocate an mbuf for a header and fill it in.
154	 */
155	if ((inp->inp_flags & INP_HDRINCL) == 0) {
156		M_PREPEND(m, sizeof(struct ip), M_WAIT);
157		ip = mtod(m, struct ip *);
158		ip->ip_tos = 0;
159		ip->ip_off = 0;
160		ip->ip_p = inp->inp_ip.ip_p;
161		ip->ip_len = m->m_pkthdr.len;
162		ip->ip_src = inp->inp_laddr;
163		ip->ip_dst.s_addr = dst;
164		ip->ip_ttl = MAXTTL;
165		opts = inp->inp_options;
166	} else {
167		ip = mtod(m, struct ip *);
168		if (ip->ip_id == 0)
169			ip->ip_id = htons(ip_id++);
170		opts = NULL;
171		/* XXX prevent ip_output from overwriting header fields */
172		flags |= IP_RAWOUTPUT;
173		ipstat.ips_rawout++;
174	}
175	return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
176}
177
178/*
179 * Raw IP socket option processing.
180 */
181int
182rip_ctloutput(op, so, level, optname, m)
183	int op;
184	struct socket *so;
185	int level, optname;
186	struct mbuf **m;
187{
188	register struct inpcb *inp = sotoinpcb(so);
189	register int error;
190
191	if (level != IPPROTO_IP)
192		return (EINVAL);
193
194	switch (optname) {
195
196	case IP_HDRINCL:
197		if (op == PRCO_SETOPT || op == PRCO_GETOPT) {
198			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
199				return (EINVAL);
200			if (op == PRCO_SETOPT) {
201				if (*mtod(*m, int *))
202					inp->inp_flags |= INP_HDRINCL;
203				else
204					inp->inp_flags &= ~INP_HDRINCL;
205				(void)m_free(*m);
206			} else {
207				(*m)->m_len = sizeof (int);
208				*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
209			}
210			return (0);
211		}
212		break;
213
214#ifdef IPFIREWALL
215	case IP_FW_ADD_BLK:
216	case IP_FW_ADD_FWD:
217	case IP_FW_DEL_BLK:
218	case IP_FW_DEL_FWD:
219	case IP_FW_FLUSH:
220	case IP_FW_POLICY:
221
222		if (op == PRCO_SETOPT) {
223			error=ip_fw_ctl(optname, *m);
224			if (*m)
225				(void)m_free(*m);
226		}
227		else
228			error=EINVAL;
229		return(error);
230#endif
231#ifdef IPACCT
232	case IP_ACCT_DEL:
233	case IP_ACCT_ADD:
234	case IP_ACCT_FLUSH:
235	case IP_ACCT_ZERO:
236
237		if (op = PRCO_SETOPT) {
238			error=ip_acct_ctl(optname, *m);
239			if (*m)
240				(void)m_free(*m);
241		}
242		else
243			error=EINVAL;
244		return(error);
245#endif
246
247	case IP_RSVP_ON:
248		error = ip_rsvp_init(so);
249		break;
250
251	case IP_RSVP_OFF:
252		error = ip_rsvp_done();
253		break;
254
255	case DVMRP_INIT:
256	case DVMRP_DONE:
257	case DVMRP_ADD_VIF:
258	case DVMRP_DEL_VIF:
259	case DVMRP_ADD_MFC:
260	case DVMRP_DEL_MFC:
261		if (op == PRCO_SETOPT) {
262			error = ip_mrouter_cmd(optname, so, *m);
263			if (*m)
264				(void)m_free(*m);
265		} else
266			error = EINVAL;
267		return (error);
268	}
269	return (ip_ctloutput(op, so, level, optname, m));
270}
271
272u_long	rip_sendspace = RIPSNDQ;
273u_long	rip_recvspace = RIPRCVQ;
274
275/*ARGSUSED*/
276int
277rip_usrreq(so, req, m, nam, control)
278	register struct socket *so;
279	int req;
280	struct mbuf *m, *nam, *control;
281{
282	register int error = 0;
283	register struct inpcb *inp = sotoinpcb(so);
284	switch (req) {
285
286	case PRU_ATTACH:
287		if (inp)
288			panic("rip_attach");
289		if ((so->so_state & SS_PRIV) == 0) {
290			error = EACCES;
291			break;
292		}
293		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
294		    (error = in_pcballoc(so, &rawinpcb)))
295			break;
296		inp = (struct inpcb *)so->so_pcb;
297		inp->inp_ip.ip_p = (int)nam;
298		break;
299
300	case PRU_DISCONNECT:
301		if ((so->so_state & SS_ISCONNECTED) == 0) {
302			error = ENOTCONN;
303			break;
304		}
305		/* FALLTHROUGH */
306	case PRU_ABORT:
307		soisdisconnected(so);
308		/* FALLTHROUGH */
309	case PRU_DETACH:
310		if (inp == 0)
311			panic("rip_detach");
312		if (so == ip_mrouter)
313			ip_mrouter_done();
314		in_pcbdetach(inp);
315		break;
316
317	case PRU_BIND:
318	    {
319		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
320
321		if (nam->m_len != sizeof(*addr)) {
322			error = EINVAL;
323			break;
324		}
325		if ((ifnet == 0) ||
326		    ((addr->sin_family != AF_INET) &&
327		     (addr->sin_family != AF_IMPLINK)) ||
328		    (addr->sin_addr.s_addr &&
329		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
330			error = EADDRNOTAVAIL;
331			break;
332		}
333		inp->inp_laddr = addr->sin_addr;
334		break;
335	    }
336	case PRU_CONNECT:
337	    {
338		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
339
340		if (nam->m_len != sizeof(*addr)) {
341			error = EINVAL;
342			break;
343		}
344		if (ifnet == 0) {
345			error = EADDRNOTAVAIL;
346			break;
347		}
348		if ((addr->sin_family != AF_INET) &&
349		     (addr->sin_family != AF_IMPLINK)) {
350			error = EAFNOSUPPORT;
351			break;
352		}
353		inp->inp_faddr = addr->sin_addr;
354		soisconnected(so);
355		break;
356	    }
357
358	case PRU_CONNECT2:
359		error = EOPNOTSUPP;
360		break;
361
362	/*
363	 * Mark the connection as being incapable of further input.
364	 */
365	case PRU_SHUTDOWN:
366		socantsendmore(so);
367		break;
368
369	/*
370	 * Ship a packet out.  The appropriate raw output
371	 * routine handles any massaging necessary.
372	 */
373	case PRU_SEND:
374	    {
375		register u_long dst;
376
377		if (so->so_state & SS_ISCONNECTED) {
378			if (nam) {
379				error = EISCONN;
380				break;
381			}
382			dst = inp->inp_faddr.s_addr;
383		} else {
384			if (nam == NULL) {
385				error = ENOTCONN;
386				break;
387			}
388			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
389		}
390		error = rip_output(m, so, dst);
391		m = NULL;
392		break;
393	    }
394
395	case PRU_SENSE:
396		/*
397		 * stat: don't bother with a blocksize.
398		 */
399		return (0);
400
401	/*
402	 * Not supported.
403	 */
404	case PRU_RCVOOB:
405	case PRU_RCVD:
406	case PRU_LISTEN:
407	case PRU_ACCEPT:
408	case PRU_SENDOOB:
409		error = EOPNOTSUPP;
410		break;
411
412	case PRU_SOCKADDR:
413		in_setsockaddr(inp, nam);
414		break;
415
416	case PRU_PEERADDR:
417		in_setpeeraddr(inp, nam);
418		break;
419
420	default:
421		panic("rip_usrreq");
422	}
423	if (m != NULL)
424		m_freem(m);
425	return (error);
426}
427