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