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