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