1 /* $NetBSD: raw_ip6.c,v 1.78.8.1 2007/05/24 19:13:15 pavel Exp $ */
2 /* $KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * Copyright (c) 1982, 1986, 1988, 1993
35 * The Regents of the University of California. All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
62 */
63
64 #include <sys/cdefs.h>
65 __KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.78.8.1 2007/05/24 19:13:15 pavel Exp $");
66
67 #include "opt_ipsec.h"
68
69 #include <sys/param.h>
70 #include <sys/sysctl.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 #include <sys/kauth.h>
80
81 #include <net/if.h>
82 #include <net/route.h>
83 #include <net/if_types.h>
84
85 #include <netinet/in.h>
86 #include <netinet/in_var.h>
87 #include <netinet/ip6.h>
88 #include <netinet6/ip6_var.h>
89 #include <netinet6/ip6_mroute.h>
90 #include <netinet/icmp6.h>
91 #include <netinet6/in6_pcb.h>
92 #include <netinet6/nd6.h>
93 #include <netinet6/ip6protosw.h>
94 #include <netinet6/scope6_var.h>
95 #include <netinet6/raw_ip6.h>
96
97 #ifdef IPSEC
98 #include <netinet6/ipsec.h>
99 #endif /* IPSEC */
100
101 #ifdef FAST_IPSEC
102 #include <netipsec/ipsec.h>
103 #include <netipsec/ipsec_var.h> /* XXX ipsecstat namespace */
104 #include <netipsec/ipsec6.h>
105 #endif
106
107 #include <machine/stdarg.h>
108
109 #include "faith.h"
110 #if defined(NFAITH) && 0 < NFAITH
111 #include <net/if_faith.h>
112 #endif
113
114 extern struct inpcbtable rawcbtable;
115 struct inpcbtable raw6cbtable;
116 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
117
118 /*
119 * Raw interface to IP6 protocol.
120 */
121
122 struct rip6stat rip6stat;
123
124 /*
125 * Initialize raw connection block queue.
126 */
127 void
128 rip6_init()
129 {
130
131 in6_pcbinit(&raw6cbtable, 1, 1);
132 }
133
134 /*
135 * Setup generic address and protocol structures
136 * for raw_input routine, then pass them along with
137 * mbuf chain.
138 */
139 int
140 rip6_input(mp, offp, proto)
141 struct mbuf **mp;
142 int *offp, proto;
143 {
144 struct mbuf *m = *mp;
145 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
146 struct inpcb_hdr *inph;
147 struct in6pcb *in6p;
148 struct in6pcb *last = NULL;
149 struct sockaddr_in6 rip6src;
150 struct mbuf *opts = NULL;
151
152 rip6stat.rip6s_ipackets++;
153
154 #if defined(NFAITH) && 0 < NFAITH
155 if (faithprefix(&ip6->ip6_dst)) {
156 /* send icmp6 host unreach? */
157 m_freem(m);
158 return IPPROTO_DONE;
159 }
160 #endif
161
162 /* Be proactive about malicious use of IPv4 mapped address */
163 if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
164 IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
165 /* XXX stat */
166 m_freem(m);
167 return IPPROTO_DONE;
168 }
169
170 bzero(&rip6src, sizeof(rip6src));
171 rip6src.sin6_len = sizeof(struct sockaddr_in6);
172 rip6src.sin6_family = AF_INET6;
173 rip6src.sin6_addr = ip6->ip6_src;
174 if (sa6_recoverscope(&rip6src) != 0) {
175 /* XXX: should be impossible. */
176 m_freem(m);
177 return IPPROTO_DONE;
178 }
179
180 CIRCLEQ_FOREACH(inph, &raw6cbtable.inpt_queue, inph_queue) {
181 in6p = (struct in6pcb *)inph;
182 if (in6p->in6p_af != AF_INET6)
183 continue;
184 if (in6p->in6p_ip6.ip6_nxt &&
185 in6p->in6p_ip6.ip6_nxt != proto)
186 continue;
187 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
188 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
189 continue;
190 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
191 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
192 continue;
193 if (in6p->in6p_cksum != -1) {
194 rip6stat.rip6s_isum++;
195 if (in6_cksum(m, proto, *offp,
196 m->m_pkthdr.len - *offp)) {
197 rip6stat.rip6s_badsum++;
198 continue;
199 }
200 }
201 if (last) {
202 struct mbuf *n;
203
204 #ifdef IPSEC
205 /*
206 * Check AH/ESP integrity.
207 */
208 if (ipsec6_in_reject(m, last)) {
209 ipsec6stat.in_polvio++;
210 /* do not inject data into pcb */
211 } else
212 #endif /* IPSEC */
213 #ifdef FAST_IPSEC
214 /*
215 * Check AH/ESP integrity
216 */
217 if (!ipsec6_in_reject(m,last))
218 #endif /* FAST_IPSEC */
219 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
220 if (last->in6p_flags & IN6P_CONTROLOPTS)
221 ip6_savecontrol(last, &opts, ip6, n);
222 /* strip intermediate headers */
223 m_adj(n, *offp);
224 if (sbappendaddr(&last->in6p_socket->so_rcv,
225 (struct sockaddr *)&rip6src, n, opts) == 0) {
226 /* should notify about lost packet */
227 m_freem(n);
228 if (opts)
229 m_freem(opts);
230 rip6stat.rip6s_fullsock++;
231 } else
232 sorwakeup(last->in6p_socket);
233 opts = NULL;
234 }
235 }
236 last = in6p;
237 }
238 #ifdef IPSEC
239 /*
240 * Check AH/ESP integrity.
241 */
242 if (last && ipsec6_in_reject(m, last)) {
243 m_freem(m);
244 ipsec6stat.in_polvio++;
245 ip6stat.ip6s_delivered--;
246 /* do not inject data into pcb */
247 } else
248 #endif /* IPSEC */
249 #ifdef FAST_IPSEC
250 if (last && ipsec6_in_reject(m, last)) {
251 m_freem(m);
252 /*
253 * XXX ipsec6_in_reject update stat if there is an error
254 * so we just need to update stats by hand in the case of last is
255 * NULL
256 */
257 if (!last)
258 ipsec6stat.in_polvio++;
259 ip6stat.ip6s_delivered--;
260 /* do not inject data into pcb */
261 } else
262 #endif /* FAST_IPSEC */
263 if (last) {
264 if (last->in6p_flags & IN6P_CONTROLOPTS)
265 ip6_savecontrol(last, &opts, ip6, m);
266 /* strip intermediate headers */
267 m_adj(m, *offp);
268 if (sbappendaddr(&last->in6p_socket->so_rcv,
269 (struct sockaddr *)&rip6src, m, opts) == 0) {
270 m_freem(m);
271 if (opts)
272 m_freem(opts);
273 rip6stat.rip6s_fullsock++;
274 } else
275 sorwakeup(last->in6p_socket);
276 } else {
277 rip6stat.rip6s_nosock++;
278 if (m->m_flags & M_MCAST)
279 rip6stat.rip6s_nosockmcast++;
280 if (proto == IPPROTO_NONE)
281 m_freem(m);
282 else {
283 u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
284 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown);
285 icmp6_error(m, ICMP6_PARAM_PROB,
286 ICMP6_PARAMPROB_NEXTHEADER,
287 prvnxtp - mtod(m, u_int8_t *));
288 }
289 ip6stat.ip6s_delivered--;
290 }
291 return IPPROTO_DONE;
292 }
293
294 void
295 rip6_ctlinput(cmd, sa, d)
296 int cmd;
297 struct sockaddr *sa;
298 void *d;
299 {
300 struct ip6_hdr *ip6;
301 struct ip6ctlparam *ip6cp = NULL;
302 const struct sockaddr_in6 *sa6_src = NULL;
303 void *cmdarg;
304 void (*notify) __P((struct in6pcb *, int)) = in6_rtchange;
305 int nxt;
306
307 if (sa->sa_family != AF_INET6 ||
308 sa->sa_len != sizeof(struct sockaddr_in6))
309 return;
310
311 if ((unsigned)cmd >= PRC_NCMDS)
312 return;
313 if (PRC_IS_REDIRECT(cmd))
314 notify = in6_rtchange, d = NULL;
315 else if (cmd == PRC_HOSTDEAD)
316 d = NULL;
317 else if (cmd == PRC_MSGSIZE)
318 ; /* special code is present, see below */
319 else if (inet6ctlerrmap[cmd] == 0)
320 return;
321
322 /* if the parameter is from icmp6, decode it. */
323 if (d != NULL) {
324 ip6cp = (struct ip6ctlparam *)d;
325 ip6 = ip6cp->ip6c_ip6;
326 cmdarg = ip6cp->ip6c_cmdarg;
327 sa6_src = ip6cp->ip6c_src;
328 nxt = ip6cp->ip6c_nxt;
329 } else {
330 ip6 = NULL;
331 cmdarg = NULL;
332 sa6_src = &sa6_any;
333 nxt = -1;
334 }
335
336 if (ip6 && cmd == PRC_MSGSIZE) {
337 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
338 int valid = 0;
339 struct in6pcb *in6p;
340
341 /*
342 * Check to see if we have a valid raw IPv6 socket
343 * corresponding to the address in the ICMPv6 message
344 * payload, and the protocol (ip6_nxt) meets the socket.
345 * XXX chase extension headers, or pass final nxt value
346 * from icmp6_notify_error()
347 */
348 in6p = NULL;
349 in6p = in6_pcblookup_connect(&raw6cbtable, &sa6->sin6_addr, 0,
350 (const struct in6_addr *)&sa6_src->sin6_addr, 0, 0);
351 #if 0
352 if (!in6p) {
353 /*
354 * As the use of sendto(2) is fairly popular,
355 * we may want to allow non-connected pcb too.
356 * But it could be too weak against attacks...
357 * We should at least check if the local
358 * address (= s) is really ours.
359 */
360 in6p = in6_pcblookup_bind(&raw6cbtable,
361 &sa6->sin6_addr, 0, 0);
362 }
363 #endif
364
365 if (in6p && in6p->in6p_ip6.ip6_nxt &&
366 in6p->in6p_ip6.ip6_nxt == nxt)
367 valid++;
368
369 /*
370 * Depending on the value of "valid" and routing table
371 * size (mtudisc_{hi,lo}wat), we will:
372 * - recalculate the new MTU and create the
373 * corresponding routing entry, or
374 * - ignore the MTU change notification.
375 */
376 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
377
378 /*
379 * regardless of if we called icmp6_mtudisc_update(),
380 * we need to call in6_pcbnotify(), to notify path MTU
381 * change to the userland (RFC3542), because some
382 * unconnected sockets may share the same destination
383 * and want to know the path MTU.
384 */
385 }
386
387 (void) in6_pcbnotify(&raw6cbtable, sa, 0,
388 (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
389 }
390
391 /*
392 * Generate IPv6 header and pass packet to ip6_output.
393 * Tack on options user may have setup with control call.
394 */
395 int
396 #if __STDC__
397 rip6_output(struct mbuf *m, ...)
398 #else
399 rip6_output(m, va_alist)
400 struct mbuf *m;
401 va_dcl
402 #endif
403 {
404 struct socket *so;
405 struct sockaddr_in6 *dstsock;
406 struct mbuf *control;
407 struct in6_addr *dst;
408 struct ip6_hdr *ip6;
409 struct in6pcb *in6p;
410 u_int plen = m->m_pkthdr.len;
411 int error = 0;
412 struct ip6_pktopts opt, *optp = NULL;
413 struct ifnet *oifp = NULL;
414 int type, code; /* for ICMPv6 output statistics only */
415 int priv = 0;
416 int scope_ambiguous = 0;
417 struct in6_addr *in6a;
418 va_list ap;
419
420 va_start(ap, m);
421 so = va_arg(ap, struct socket *);
422 dstsock = va_arg(ap, struct sockaddr_in6 *);
423 control = va_arg(ap, struct mbuf *);
424 va_end(ap);
425
426 in6p = sotoin6pcb(so);
427
428 priv = 0;
429 if (curlwp && !kauth_authorize_generic(curlwp->l_cred,
430 KAUTH_GENERIC_ISSUSER, &curlwp->l_acflag))
431 priv = 1;
432
433 dst = &dstsock->sin6_addr;
434 if (control) {
435 if ((error = ip6_setpktopts(control, &opt,
436 in6p->in6p_outputopts,
437 priv, so->so_proto->pr_protocol)) != 0) {
438 goto bad;
439 }
440 optp = &opt;
441 } else
442 optp = in6p->in6p_outputopts;
443
444 /*
445 * Check and convert scope zone ID into internal form.
446 * XXX: we may still need to determine the zone later.
447 */
448 if (!(so->so_state & SS_ISCONNECTED)) {
449 if (dstsock->sin6_scope_id == 0 && !ip6_use_defzone)
450 scope_ambiguous = 1;
451 if ((error = sa6_embedscope(dstsock, ip6_use_defzone)) != 0)
452 goto bad;
453 }
454
455 /*
456 * For an ICMPv6 packet, we should know its type and code
457 * to update statistics.
458 */
459 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
460 struct icmp6_hdr *icmp6;
461 if (m->m_len < sizeof(struct icmp6_hdr) &&
462 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
463 error = ENOBUFS;
464 goto bad;
465 }
466 icmp6 = mtod(m, struct icmp6_hdr *);
467 type = icmp6->icmp6_type;
468 code = icmp6->icmp6_code;
469 } else {
470 type = 0;
471 code = 0;
472 }
473
474 M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
475 if (!m) {
476 error = ENOBUFS;
477 goto bad;
478 }
479 ip6 = mtod(m, struct ip6_hdr *);
480
481 /*
482 * Next header might not be ICMP6 but use its pseudo header anyway.
483 */
484 ip6->ip6_dst = *dst;
485
486 /*
487 * Source address selection.
488 */
489 if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
490 &in6p->in6p_route, &in6p->in6p_laddr, &oifp, &error)) == 0) {
491 if (error == 0)
492 error = EADDRNOTAVAIL;
493 goto bad;
494 }
495 ip6->ip6_src = *in6a;
496
497 if (oifp && scope_ambiguous) {
498 /*
499 * Application should provide a proper zone ID or the use of
500 * default zone IDs should be enabled. Unfortunately, some
501 * applications do not behave as it should, so we need a
502 * workaround. Even if an appropriate ID is not determined
503 * (when it's required), if we can determine the outgoing
504 * interface. determine the zone ID based on the interface.
505 */
506 error = in6_setscope(&dstsock->sin6_addr, oifp, NULL);
507 if (error != 0)
508 goto bad;
509 }
510 ip6->ip6_dst = dstsock->sin6_addr;
511
512 /* fill in the rest of the IPv6 header fields */
513 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
514 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
515 ip6->ip6_vfc |= IPV6_VERSION;
516 /* ip6_plen will be filled in ip6_output, so not fill it here. */
517 ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt;
518 ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
519
520 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
521 in6p->in6p_cksum != -1) {
522 int off;
523 u_int16_t sum;
524
525 /* compute checksum */
526 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
527 off = offsetof(struct icmp6_hdr, icmp6_cksum);
528 else
529 off = in6p->in6p_cksum;
530 if (plen < off + 1) {
531 error = EINVAL;
532 goto bad;
533 }
534 off += sizeof(struct ip6_hdr);
535
536 sum = 0;
537 m = m_copyback_cow(m, off, sizeof(sum), (caddr_t)&sum,
538 M_DONTWAIT);
539 if (m == NULL) {
540 error = ENOBUFS;
541 goto bad;
542 }
543 sum = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
544 m = m_copyback_cow(m, off, sizeof(sum), (caddr_t)&sum,
545 M_DONTWAIT);
546 if (m == NULL) {
547 error = ENOBUFS;
548 goto bad;
549 }
550 }
551
552 error = ip6_output(m, optp, &in6p->in6p_route, 0,
553 in6p->in6p_moptions, so, &oifp);
554 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
555 if (oifp)
556 icmp6_ifoutstat_inc(oifp, type, code);
557 icmp6stat.icp6s_outhist[type]++;
558 } else
559 rip6stat.rip6s_opackets++;
560
561 goto freectl;
562
563 bad:
564 if (m)
565 m_freem(m);
566
567 freectl:
568 if (control) {
569 ip6_clearpktopts(&opt, -1);
570 m_freem(control);
571 }
572 return (error);
573 }
574
575 /*
576 * Raw IPv6 socket option processing.
577 */
578 int
579 rip6_ctloutput(op, so, level, optname, mp)
580 int op;
581 struct socket *so;
582 int level, optname;
583 struct mbuf **mp;
584 {
585 int error = 0;
586
587 switch (level) {
588 case IPPROTO_IPV6:
589 switch (optname) {
590 case MRT6_INIT:
591 case MRT6_DONE:
592 case MRT6_ADD_MIF:
593 case MRT6_DEL_MIF:
594 case MRT6_ADD_MFC:
595 case MRT6_DEL_MFC:
596 case MRT6_PIM:
597 if (op == PRCO_SETOPT) {
598 error = ip6_mrouter_set(optname, so, *mp);
599 if (*mp)
600 (void)m_free(*mp);
601 } else if (op == PRCO_GETOPT)
602 error = ip6_mrouter_get(optname, so, mp);
603 else
604 error = EINVAL;
605 return (error);
606 case IPV6_CHECKSUM:
607 return (ip6_raw_ctloutput(op, so, level, optname, mp));
608 default:
609 return (ip6_ctloutput(op, so, level, optname, mp));
610 }
611
612 case IPPROTO_ICMPV6:
613 /*
614 * XXX: is it better to call icmp6_ctloutput() directly
615 * from protosw?
616 */
617 return (icmp6_ctloutput(op, so, level, optname, mp));
618
619 default:
620 if (op == PRCO_SETOPT && *mp)
621 m_free(*mp);
622 return EINVAL;
623 }
624 }
625
626 extern u_long rip6_sendspace;
627 extern u_long rip6_recvspace;
628
629 int
630 rip6_usrreq(so, req, m, nam, control, l)
631 struct socket *so;
632 int req;
633 struct mbuf *m, *nam, *control;
634 struct lwp *l;
635 {
636 struct in6pcb *in6p = sotoin6pcb(so);
637 int s;
638 int error = 0;
639 int priv;
640
641 priv = 0;
642 if (l && !kauth_authorize_generic(l->l_cred,
643 KAUTH_GENERIC_ISSUSER, &l->l_acflag))
644 priv++;
645
646 if (req == PRU_CONTROL)
647 return (in6_control(so, (u_long)m, (caddr_t)nam,
648 (struct ifnet *)control, l));
649
650 if (req == PRU_PURGEIF) {
651 in6_pcbpurgeif0(&raw6cbtable, (struct ifnet *)control);
652 in6_purgeif((struct ifnet *)control);
653 in6_pcbpurgeif(&raw6cbtable, (struct ifnet *)control);
654 return (0);
655 }
656
657 switch (req) {
658 case PRU_ATTACH:
659 if (in6p)
660 panic("rip6_attach");
661 if (!priv) {
662 error = EACCES;
663 break;
664 }
665 s = splsoftnet();
666 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) != 0) {
667 splx(s);
668 break;
669 }
670 if ((error = in6_pcballoc(so, &raw6cbtable)) != 0)
671 {
672 splx(s);
673 break;
674 }
675 splx(s);
676 in6p = sotoin6pcb(so);
677 in6p->in6p_ip6.ip6_nxt = (long)nam;
678 in6p->in6p_cksum = -1;
679
680 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
681 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
682 if (in6p->in6p_icmp6filt == NULL) {
683 in6_pcbdetach(in6p);
684 error = ENOMEM;
685 break;
686 }
687 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
688 break;
689
690 case PRU_DISCONNECT:
691 if ((so->so_state & SS_ISCONNECTED) == 0) {
692 error = ENOTCONN;
693 break;
694 }
695 in6p->in6p_faddr = in6addr_any;
696 so->so_state &= ~SS_ISCONNECTED; /* XXX */
697 break;
698
699 case PRU_ABORT:
700 soisdisconnected(so);
701 /* Fallthrough */
702 case PRU_DETACH:
703 if (in6p == 0)
704 panic("rip6_detach");
705 if (so == ip6_mrouter)
706 ip6_mrouter_done();
707 /* xxx: RSVP */
708 if (in6p->in6p_icmp6filt) {
709 FREE(in6p->in6p_icmp6filt, M_PCB);
710 in6p->in6p_icmp6filt = NULL;
711 }
712 in6_pcbdetach(in6p);
713 break;
714
715 case PRU_BIND:
716 {
717 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
718 struct ifaddr *ia = NULL;
719
720 if (nam->m_len != sizeof(*addr)) {
721 error = EINVAL;
722 break;
723 }
724 if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6)) {
725 error = EADDRNOTAVAIL;
726 break;
727 }
728 if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0)
729 break;
730
731 /*
732 * we don't support mapped address here, it would confuse
733 * users so reject it
734 */
735 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
736 error = EADDRNOTAVAIL;
737 break;
738 }
739 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
740 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) {
741 error = EADDRNOTAVAIL;
742 break;
743 }
744 if (ia && ((struct in6_ifaddr *)ia)->ia6_flags &
745 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
746 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
747 error = EADDRNOTAVAIL;
748 break;
749 }
750 in6p->in6p_laddr = addr->sin6_addr;
751 break;
752 }
753
754 case PRU_CONNECT:
755 {
756 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
757 struct in6_addr *in6a = NULL;
758 struct ifnet *ifp = NULL;
759 int scope_ambiguous = 0;
760
761 if (nam->m_len != sizeof(*addr)) {
762 error = EINVAL;
763 break;
764 }
765 if (ifnet.tqh_first == 0)
766 {
767 error = EADDRNOTAVAIL;
768 break;
769 }
770 if (addr->sin6_family != AF_INET6) {
771 error = EAFNOSUPPORT;
772 break;
773 }
774
775 /*
776 * Application should provide a proper zone ID or the use of
777 * default zone IDs should be enabled. Unfortunately, some
778 * applications do not behave as it should, so we need a
779 * workaround. Even if an appropriate ID is not determined,
780 * we'll see if we can determine the outgoing interface. If we
781 * can, determine the zone ID based on the interface below.
782 */
783 if (addr->sin6_scope_id == 0 && !ip6_use_defzone)
784 scope_ambiguous = 1;
785 if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0)
786 return(error);
787
788 /* Source address selection. XXX: need pcblookup? */
789 in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
790 in6p->in6p_moptions, &in6p->in6p_route,
791 &in6p->in6p_laddr, &ifp, &error);
792 if (in6a == NULL) {
793 if (error == 0)
794 error = EADDRNOTAVAIL;
795 break;
796 }
797 /* XXX: see above */
798 if (ifp && scope_ambiguous &&
799 (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
800 break;
801 }
802 in6p->in6p_laddr = *in6a;
803 in6p->in6p_faddr = addr->sin6_addr;
804 soisconnected(so);
805 break;
806 }
807
808 case PRU_CONNECT2:
809 error = EOPNOTSUPP;
810 break;
811
812 /*
813 * Mark the connection as being incapable of futther input.
814 */
815 case PRU_SHUTDOWN:
816 socantsendmore(so);
817 break;
818 /*
819 * Ship a packet out. The appropriate raw output
820 * routine handles any messaging necessary.
821 */
822 case PRU_SEND:
823 {
824 struct sockaddr_in6 tmp;
825 struct sockaddr_in6 *dst;
826
827 /* always copy sockaddr to avoid overwrites */
828 if (so->so_state & SS_ISCONNECTED) {
829 if (nam) {
830 error = EISCONN;
831 break;
832 }
833 /* XXX */
834 bzero(&tmp, sizeof(tmp));
835 tmp.sin6_family = AF_INET6;
836 tmp.sin6_len = sizeof(struct sockaddr_in6);
837 bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
838 sizeof(struct in6_addr));
839 dst = &tmp;
840 } else {
841 if (nam == NULL) {
842 error = ENOTCONN;
843 break;
844 }
845 if (nam->m_len != sizeof(tmp)) {
846 error = EINVAL;
847 break;
848 }
849
850 tmp = *mtod(nam, struct sockaddr_in6 *);
851 dst = &tmp;
852
853 if (dst->sin6_family != AF_INET6) {
854 error = EAFNOSUPPORT;
855 break;
856 }
857 }
858 error = rip6_output(m, so, dst, control);
859 m = NULL;
860 break;
861 }
862
863 case PRU_SENSE:
864 /*
865 * stat: don't bother with a blocksize
866 */
867 return (0);
868 /*
869 * Not supported.
870 */
871 case PRU_RCVOOB:
872 case PRU_RCVD:
873 case PRU_LISTEN:
874 case PRU_ACCEPT:
875 case PRU_SENDOOB:
876 error = EOPNOTSUPP;
877 break;
878
879 case PRU_SOCKADDR:
880 in6_setsockaddr(in6p, nam);
881 break;
882
883 case PRU_PEERADDR:
884 in6_setpeeraddr(in6p, nam);
885 break;
886
887 default:
888 panic("rip6_usrreq");
889 }
890 if (m != NULL)
891 m_freem(m);
892 return (error);
893 }
894
895 SYSCTL_SETUP(sysctl_net_inet6_raw6_setup, "sysctl net.inet6.raw6 subtree setup")
896 {
897
898 sysctl_createv(clog, 0, NULL, NULL,
899 CTLFLAG_PERMANENT,
900 CTLTYPE_NODE, "net", NULL,
901 NULL, 0, NULL, 0,
902 CTL_NET, CTL_EOL);
903 sysctl_createv(clog, 0, NULL, NULL,
904 CTLFLAG_PERMANENT,
905 CTLTYPE_NODE, "inet6", NULL,
906 NULL, 0, NULL, 0,
907 CTL_NET, PF_INET6, CTL_EOL);
908 sysctl_createv(clog, 0, NULL, NULL,
909 CTLFLAG_PERMANENT,
910 CTLTYPE_NODE, "raw6",
911 SYSCTL_DESCR("Raw IPv6 settings"),
912 NULL, 0, NULL, 0,
913 CTL_NET, PF_INET6, IPPROTO_RAW, CTL_EOL);
914
915 sysctl_createv(clog, 0, NULL, NULL,
916 CTLFLAG_PERMANENT,
917 CTLTYPE_STRUCT, "pcblist",
918 SYSCTL_DESCR("Raw IPv6 control block list"),
919 sysctl_inpcblist, 0, &raw6cbtable, 0,
920 CTL_NET, PF_INET6, IPPROTO_RAW,
921 CTL_CREATE, CTL_EOL);
922 sysctl_createv(clog, 0, NULL, NULL,
923 CTLFLAG_PERMANENT,
924 CTLTYPE_STRUCT, "stats",
925 SYSCTL_DESCR("Raw IPv6 statistics"),
926 NULL, 0, &rip6stat, sizeof(rip6stat),
927 CTL_NET, PF_INET6, IPPROTO_RAW, RAW6CTL_STATS,
928 CTL_EOL);
929 }
Cache object: 47f890b0737b6c1f268e0232f3269153
|