raw_ip.c revision 5089
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.9 1994/12/12 17:20:55 ugen 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_CLR:
235	case IP_ACCT_FLUSH:
236	case IP_ACCT_ZERO:
237
238		if (op = PRCO_SETOPT) {
239			error=ip_acct_ctl(optname, *m);
240			if (*m)
241				(void)m_free(*m);
242		}
243		else
244			error=EINVAL;
245		return(error);
246#endif
247
248	case IP_RSVP_ON:
249		error = ip_rsvp_init(so);
250		break;
251
252	case IP_RSVP_OFF:
253		error = ip_rsvp_done();
254		break;
255
256	case DVMRP_INIT:
257	case DVMRP_DONE:
258	case DVMRP_ADD_VIF:
259	case DVMRP_DEL_VIF:
260	case DVMRP_ADD_MFC:
261	case DVMRP_DEL_MFC:
262		if (op == PRCO_SETOPT) {
263			error = ip_mrouter_cmd(optname, so, *m);
264			if (*m)
265				(void)m_free(*m);
266		} else
267			error = EINVAL;
268		return (error);
269	}
270	return (ip_ctloutput(op, so, level, optname, m));
271}
272
273u_long	rip_sendspace = RIPSNDQ;
274u_long	rip_recvspace = RIPRCVQ;
275
276/*ARGSUSED*/
277int
278rip_usrreq(so, req, m, nam, control)
279	register struct socket *so;
280	int req;
281	struct mbuf *m, *nam, *control;
282{
283	register int error = 0;
284	register struct inpcb *inp = sotoinpcb(so);
285	switch (req) {
286
287	case PRU_ATTACH:
288		if (inp)
289			panic("rip_attach");
290		if ((so->so_state & SS_PRIV) == 0) {
291			error = EACCES;
292			break;
293		}
294		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
295		    (error = in_pcballoc(so, &rawinpcb)))
296			break;
297		inp = (struct inpcb *)so->so_pcb;
298		inp->inp_ip.ip_p = (int)nam;
299		break;
300
301	case PRU_DISCONNECT:
302		if ((so->so_state & SS_ISCONNECTED) == 0) {
303			error = ENOTCONN;
304			break;
305		}
306		/* FALLTHROUGH */
307	case PRU_ABORT:
308		soisdisconnected(so);
309		/* FALLTHROUGH */
310	case PRU_DETACH:
311		if (inp == 0)
312			panic("rip_detach");
313		if (so == ip_mrouter)
314			ip_mrouter_done();
315		in_pcbdetach(inp);
316		break;
317
318	case PRU_BIND:
319	    {
320		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
321
322		if (nam->m_len != sizeof(*addr)) {
323			error = EINVAL;
324			break;
325		}
326		if ((ifnet == 0) ||
327		    ((addr->sin_family != AF_INET) &&
328		     (addr->sin_family != AF_IMPLINK)) ||
329		    (addr->sin_addr.s_addr &&
330		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
331			error = EADDRNOTAVAIL;
332			break;
333		}
334		inp->inp_laddr = addr->sin_addr;
335		break;
336	    }
337	case PRU_CONNECT:
338	    {
339		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
340
341		if (nam->m_len != sizeof(*addr)) {
342			error = EINVAL;
343			break;
344		}
345		if (ifnet == 0) {
346			error = EADDRNOTAVAIL;
347			break;
348		}
349		if ((addr->sin_family != AF_INET) &&
350		     (addr->sin_family != AF_IMPLINK)) {
351			error = EAFNOSUPPORT;
352			break;
353		}
354		inp->inp_faddr = addr->sin_addr;
355		soisconnected(so);
356		break;
357	    }
358
359	case PRU_CONNECT2:
360		error = EOPNOTSUPP;
361		break;
362
363	/*
364	 * Mark the connection as being incapable of further input.
365	 */
366	case PRU_SHUTDOWN:
367		socantsendmore(so);
368		break;
369
370	/*
371	 * Ship a packet out.  The appropriate raw output
372	 * routine handles any massaging necessary.
373	 */
374	case PRU_SEND:
375	    {
376		register u_long dst;
377
378		if (so->so_state & SS_ISCONNECTED) {
379			if (nam) {
380				error = EISCONN;
381				break;
382			}
383			dst = inp->inp_faddr.s_addr;
384		} else {
385			if (nam == NULL) {
386				error = ENOTCONN;
387				break;
388			}
389			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
390		}
391		error = rip_output(m, so, dst);
392		m = NULL;
393		break;
394	    }
395
396	case PRU_SENSE:
397		/*
398		 * stat: don't bother with a blocksize.
399		 */
400		return (0);
401
402	/*
403	 * Not supported.
404	 */
405	case PRU_RCVOOB:
406	case PRU_RCVD:
407	case PRU_LISTEN:
408	case PRU_ACCEPT:
409	case PRU_SENDOOB:
410		error = EOPNOTSUPP;
411		break;
412
413	case PRU_SOCKADDR:
414		in_setsockaddr(inp, nam);
415		break;
416
417	case PRU_PEERADDR:
418		in_setpeeraddr(inp, nam);
419		break;
420
421	default:
422		panic("rip_usrreq");
423	}
424	if (m != NULL)
425		m_freem(m);
426	return (error);
427}
428