xref: /netbsd-src/sys/netinet/raw_ip.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: raw_ip.c,v 1.36 1997/01/11 05:21:13 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 inpcb *last = 0;
104 	struct mbuf *opts = 0;
105 	struct sockaddr_in ripsrc;
106 
107 	ripsrc.sin_family = AF_INET;
108 	ripsrc.sin_len = sizeof(struct sockaddr_in);
109 	ripsrc.sin_addr = ip->ip_src;
110 	ripsrc.sin_port = 0;
111 	bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero));
112 
113 	for (inp = rawcbtable.inpt_queue.cqh_first;
114 	    inp != (struct inpcb *)&rawcbtable.inpt_queue;
115 	    inp = inp->inp_queue.cqe_next) {
116 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
117 			continue;
118 		if (!in_nullhost(inp->inp_laddr) &&
119 		    !in_hosteq(inp->inp_laddr, ip->ip_dst))
120 			continue;
121 		if (!in_nullhost(inp->inp_faddr) &&
122 		    !in_hosteq(inp->inp_faddr, ip->ip_src))
123 			continue;
124 		if (last) {
125 			struct mbuf *n;
126 			if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
127 				if (last->inp_flags & INP_CONTROLOPTS ||
128 				    last->inp_socket->so_options & SO_TIMESTAMP)
129 					ip_savecontrol(last, &opts, ip, n);
130 				if (sbappendaddr(&last->inp_socket->so_rcv,
131 				    sintosa(&ripsrc), n, opts) == 0) {
132 					/* should notify about lost packet */
133 					m_freem(n);
134 					if (opts)
135 						m_freem(opts);
136 				} else
137 					sorwakeup(last->inp_socket);
138 			}
139 		}
140 		last = inp;
141 	}
142 	if (last) {
143 		if (last->inp_flags & INP_CONTROLOPTS ||
144 		    last->inp_socket->so_options & SO_TIMESTAMP)
145 			ip_savecontrol(last, &opts, ip, m);
146 		if (sbappendaddr(&last->inp_socket->so_rcv,
147 		    sintosa(&ripsrc), m, opts) == 0) {
148 			m_freem(m);
149 			if (opts)
150 				m_freem(opts);
151 		} else
152 			sorwakeup(last->inp_socket);
153 	} else {
154 		m_freem(m);
155 		ipstat.ips_noproto++;
156 		ipstat.ips_delivered--;
157 	}
158 }
159 
160 /*
161  * Generate IP header and pass packet to ip_output.
162  * Tack on options user may have setup with control call.
163  */
164 int
165 #if __STDC__
166 rip_output(struct mbuf *m, ...)
167 #else
168 rip_output(m, va_alist)
169 	struct mbuf *m;
170 	va_dcl
171 #endif
172 {
173 	register struct inpcb *inp;
174 	register struct ip *ip;
175 	struct mbuf *opts;
176 	int flags;
177 	va_list ap;
178 
179 	va_start(ap, m);
180 	inp = va_arg(ap, struct inpcb *);
181 	va_end(ap);
182 
183 	flags =
184 	    (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
185 
186 	/*
187 	 * If the user handed us a complete IP packet, use it.
188 	 * Otherwise, allocate an mbuf for a header and fill it in.
189 	 */
190 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
191 		if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
192 			m_freem(m);
193 			return (EMSGSIZE);
194 		}
195 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
196 		ip = mtod(m, struct ip *);
197 		ip->ip_tos = 0;
198 		ip->ip_off = 0;
199 		ip->ip_p = inp->inp_ip.ip_p;
200 		ip->ip_len = m->m_pkthdr.len;
201 		ip->ip_src = inp->inp_laddr;
202 		ip->ip_dst = inp->inp_faddr;
203 		ip->ip_ttl = MAXTTL;
204 		opts = inp->inp_options;
205 	} else {
206 		if (m->m_pkthdr.len > IP_MAXPACKET) {
207 			m_freem(m);
208 			return (EMSGSIZE);
209 		}
210 		ip = mtod(m, struct ip *);
211 		if (ip->ip_id == 0)
212 			ip->ip_id = htons(ip_id++);
213 		opts = NULL;
214 		/* XXX prevent ip_output from overwriting header fields */
215 		flags |= IP_RAWOUTPUT;
216 		ipstat.ips_rawout++;
217 	}
218 	return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
219 }
220 
221 /*
222  * Raw IP socket option processing.
223  */
224 int
225 rip_ctloutput(op, so, level, optname, m)
226 	int op;
227 	struct socket *so;
228 	int level, optname;
229 	struct mbuf **m;
230 {
231 	register struct inpcb *inp = sotoinpcb(so);
232 	int error = 0;
233 
234 	if (level != IPPROTO_IP) {
235 		error = ENOPROTOOPT;
236 		if (op == PRCO_SETOPT && *m != 0)
237 			(void) m_free(*m);
238 	} else switch (op) {
239 
240 	case PRCO_SETOPT:
241 		switch (optname) {
242 		case IP_HDRINCL:
243 			if (*m == 0 || (*m)->m_len < sizeof (int))
244 				error = EINVAL;
245 			else {
246 				if (*mtod(*m, int *))
247 					inp->inp_flags |= INP_HDRINCL;
248 				else
249 					inp->inp_flags &= ~INP_HDRINCL;
250 			}
251 			if (*m != 0)
252 				(void) m_free(*m);
253 			break;
254 
255 #ifdef MROUTING
256 		case MRT_INIT:
257 		case MRT_DONE:
258 		case MRT_ADD_VIF:
259 		case MRT_DEL_VIF:
260 		case MRT_ADD_MFC:
261 		case MRT_DEL_MFC:
262 		case MRT_ASSERT:
263 			error = ip_mrouter_set(so, optname, m);
264 			break;
265 #endif
266 
267 		default:
268 			error = ip_ctloutput(op, so, level, optname, m);
269 			break;
270 		}
271 		break;
272 
273 	case PRCO_GETOPT:
274 		switch (optname) {
275 		case IP_HDRINCL:
276 			*m = m_get(M_WAIT, M_SOOPTS);
277 			(*m)->m_len = sizeof (int);
278 			*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0;
279 			break;
280 
281 #ifdef MROUTING
282 		case MRT_VERSION:
283 		case MRT_ASSERT:
284 			error = ip_mrouter_get(so, optname, m);
285 			break;
286 #endif
287 
288 		default:
289 			error = ip_ctloutput(op, so, level, optname, m);
290 			break;
291 		}
292 		break;
293 	}
294 	return (error);
295 }
296 
297 int
298 rip_bind(inp, nam)
299 	struct inpcb *inp;
300 	struct mbuf *nam;
301 {
302 	struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
303 
304 	if (nam->m_len != sizeof(*addr))
305 		return (EINVAL);
306 	if (ifnet.tqh_first == 0)
307 		return (EADDRNOTAVAIL);
308 	if (addr->sin_family != AF_INET &&
309 	    addr->sin_family != AF_IMPLINK)
310 		return (EAFNOSUPPORT);
311 	if (!in_nullhost(addr->sin_addr) &&
312 	    ifa_ifwithaddr(sintosa(addr)) == 0)
313 		return (EADDRNOTAVAIL);
314 	inp->inp_laddr = addr->sin_addr;
315 	return (0);
316 }
317 
318 int
319 rip_connect(inp, nam)
320 	struct inpcb *inp;
321 	struct mbuf *nam;
322 {
323 	struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
324 
325 	if (nam->m_len != sizeof(*addr))
326 		return (EINVAL);
327 	if (ifnet.tqh_first == 0)
328 		return (EADDRNOTAVAIL);
329 	if (addr->sin_family != AF_INET &&
330 	    addr->sin_family != AF_IMPLINK)
331 		return (EAFNOSUPPORT);
332 	inp->inp_faddr = addr->sin_addr;
333 	return (0);
334 }
335 
336 void
337 rip_disconnect(inp)
338 	struct inpcb *inp;
339 {
340 
341 	inp->inp_faddr = zeroin_addr;
342 }
343 
344 u_long	rip_sendspace = RIPSNDQ;
345 u_long	rip_recvspace = RIPRCVQ;
346 
347 /*ARGSUSED*/
348 int
349 rip_usrreq(so, req, m, nam, control, p)
350 	register struct socket *so;
351 	int req;
352 	struct mbuf *m, *nam, *control;
353 	struct proc *p;
354 {
355 	register struct inpcb *inp;
356 	int s;
357 	register int error = 0;
358 #ifdef MROUTING
359 	extern struct socket *ip_mrouter;
360 #endif
361 
362 	if (req == PRU_CONTROL)
363 		return (in_control(so, (long)m, (caddr_t)nam,
364 		    (struct ifnet *)control, p));
365 
366 	s = splsoftnet();
367 	inp = sotoinpcb(so);
368 #ifdef DIAGNOSTIC
369 	if (req != PRU_SEND && req != PRU_SENDOOB && control)
370 		panic("rip_usrreq: unexpected control mbuf");
371 #endif
372 	if (inp == 0 && req != PRU_ATTACH) {
373 		error = EINVAL;
374 		goto release;
375 	}
376 
377 	switch (req) {
378 
379 	case PRU_ATTACH:
380 		if (inp != 0) {
381 			error = EISCONN;
382 			break;
383 		}
384 		if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) {
385 			error = EACCES;
386 			break;
387 		}
388 		if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
389 			error = soreserve(so, rip_sendspace, rip_recvspace);
390 			if (error)
391 				break;
392 		}
393 		error = in_pcballoc(so, &rawcbtable);
394 		if (error)
395 			break;
396 		inp = sotoinpcb(so);
397 		inp->inp_ip.ip_p = (long)nam;
398 		break;
399 
400 	case PRU_DETACH:
401 #ifdef MROUTING
402 		if (so == ip_mrouter)
403 			ip_mrouter_done();
404 #endif
405 		in_pcbdetach(inp);
406 		break;
407 
408 	case PRU_BIND:
409 		error = rip_bind(inp, nam);
410 		break;
411 
412 	case PRU_LISTEN:
413 		error = EOPNOTSUPP;
414 		break;
415 
416 	case PRU_CONNECT:
417 		error = rip_connect(inp, nam);
418 		if (error)
419 			break;
420 		soisconnected(so);
421 		break;
422 
423 	case PRU_CONNECT2:
424 		error = EOPNOTSUPP;
425 		break;
426 
427 	case PRU_DISCONNECT:
428 		soisdisconnected(so);
429 		rip_disconnect(inp);
430 		break;
431 
432 	/*
433 	 * Mark the connection as being incapable of further input.
434 	 */
435 	case PRU_SHUTDOWN:
436 		socantsendmore(so);
437 		break;
438 
439 	case PRU_RCVD:
440 		error = EOPNOTSUPP;
441 		break;
442 
443 	/*
444 	 * Ship a packet out.  The appropriate raw output
445 	 * routine handles any massaging necessary.
446 	 */
447 	case PRU_SEND:
448 		if (control && control->m_len) {
449 			m_freem(control);
450 			m_freem(m);
451 			error = EINVAL;
452 			break;
453 		}
454 	{
455 		if (nam) {
456 			if ((so->so_state & SS_ISCONNECTED) != 0) {
457 				error = EISCONN;
458 				goto die;
459 			}
460 			error = rip_connect(inp, nam);
461 			if (error) {
462 			die:
463 				m_freem(m);
464 				break;
465 			}
466 		} else {
467 			if ((so->so_state & SS_ISCONNECTED) == 0) {
468 				error = ENOTCONN;
469 				goto die;
470 			}
471 		}
472 		error = rip_output(m, inp);
473 		if (nam)
474 			rip_disconnect(inp);
475 	}
476 		break;
477 
478 	case PRU_SENSE:
479 		/*
480 		 * stat: don't bother with a blocksize.
481 		 */
482 		splx(s);
483 		return (0);
484 
485 	case PRU_RCVOOB:
486 		error = EOPNOTSUPP;
487 		break;
488 
489 	case PRU_SENDOOB:
490 		m_freem(control);
491 		m_freem(m);
492 		error = EOPNOTSUPP;
493 		break;
494 
495 	case PRU_SOCKADDR:
496 		in_setsockaddr(inp, nam);
497 		break;
498 
499 	case PRU_PEERADDR:
500 		in_setpeeraddr(inp, nam);
501 		break;
502 
503 	default:
504 		panic("rip_usrreq");
505 	}
506 
507 release:
508 	splx(s);
509 	return (error);
510 }
511