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