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