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