raw_ip6.c revision 1.29 1 /* $NetBSD: raw_ip6.c,v 1.29 2001/02/11 06:49:52 itojun Exp $ */
2 /* $KAME: raw_ip6.c,v 1.65 2001/02/08 18:36:17 itojun 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. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
66 */
67
68 #include "opt_ipsec.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 #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 #ifdef ENABLE_DEFAULT_SCOPE
94 #include <netinet6/scope6_var.h>
95 #endif
96
97 #ifdef IPSEC
98 #include <netinet6/ipsec.h>
99 #endif /*IPSEC*/
100
101 #include <machine/stdarg.h>
102
103 #include "faith.h"
104
105 struct in6pcb rawin6pcb;
106 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
107
108 /*
109 * Raw interface to IP6 protocol.
110 */
111
112 /*
113 * Initialize raw connection block queue.
114 */
115 void
116 rip6_init()
117 {
118 rawin6pcb.in6p_next = rawin6pcb.in6p_prev = &rawin6pcb;
119 }
120
121 /*
122 * Setup generic address and protocol structures
123 * for raw_input routine, then pass them along with
124 * mbuf chain.
125 */
126 int
127 rip6_input(mp, offp, proto)
128 struct mbuf **mp;
129 int *offp, proto;
130 {
131 struct mbuf *m = *mp;
132 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
133 struct in6pcb *in6p;
134 struct in6pcb *last = NULL;
135 struct sockaddr_in6 rip6src;
136 struct mbuf *opts = NULL;
137
138 #if defined(NFAITH) && 0 < NFAITH
139 if (m->m_pkthdr.rcvif) {
140 if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
141 /* send icmp6 host unreach? */
142 m_freem(m);
143 return IPPROTO_DONE;
144 }
145 }
146 #endif
147
148 /* Be proactive about malicious use of IPv4 mapped address */
149 if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
150 IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
151 /* XXX stat */
152 m_freem(m);
153 return IPPROTO_DONE;
154 }
155
156 bzero(&rip6src, sizeof(rip6src));
157 rip6src.sin6_len = sizeof(struct sockaddr_in6);
158 rip6src.sin6_family = AF_INET6;
159 #if 0 /*XXX inbound flowlabel */
160 rip6src.sin6_flowinfo = ip6->ip6_flow & IPV6_FLOWINFO_MASK;
161 #endif
162 /* KAME hack: recover scopeid */
163 (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
164
165 for (in6p = rawin6pcb.in6p_next;
166 in6p != &rawin6pcb; in6p = in6p->in6p_next)
167 {
168 if (in6p->in6p_ip6.ip6_nxt &&
169 in6p->in6p_ip6.ip6_nxt != proto)
170 continue;
171 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
172 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
173 continue;
174 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
175 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
176 continue;
177 if (in6p->in6p_cksum != -1
178 && in6_cksum(m, ip6->ip6_nxt, *offp, m->m_pkthdr.len - *offp))
179 {
180 /* XXX bark something */
181 continue;
182 }
183 if (last) {
184 struct mbuf *n;
185 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
186 if (last->in6p_flags & IN6P_CONTROLOPTS)
187 ip6_savecontrol(last, &opts, ip6, n);
188 /* strip intermediate headers */
189 m_adj(n, *offp);
190 if (sbappendaddr(&last->in6p_socket->so_rcv,
191 (struct sockaddr *)&rip6src,
192 n, opts) == 0) {
193 /* should notify about lost packet */
194 m_freem(n);
195 if (opts)
196 m_freem(opts);
197 } else
198 sorwakeup(last->in6p_socket);
199 opts = NULL;
200 }
201 }
202 last = in6p;
203 }
204 if (last) {
205 if (last->in6p_flags & IN6P_CONTROLOPTS)
206 ip6_savecontrol(last, &opts, ip6, m);
207 /* strip intermediate headers */
208 m_adj(m, *offp);
209 if (sbappendaddr(&last->in6p_socket->so_rcv,
210 (struct sockaddr *)&rip6src, m, opts) == 0) {
211 m_freem(m);
212 if (opts)
213 m_freem(opts);
214 } else
215 sorwakeup(last->in6p_socket);
216 } else {
217 if (proto == IPPROTO_NONE)
218 m_freem(m);
219 else {
220 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
221 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown);
222 icmp6_error(m, ICMP6_PARAM_PROB,
223 ICMP6_PARAMPROB_NEXTHEADER,
224 prvnxtp - mtod(m, char *));
225 }
226 ip6stat.ip6s_delivered--;
227 }
228 return IPPROTO_DONE;
229 }
230
231 void
232 rip6_ctlinput(cmd, sa, d)
233 int cmd;
234 struct sockaddr *sa;
235 void *d;
236 {
237 struct ip6_hdr *ip6;
238 struct mbuf *m;
239 int off;
240 struct ip6ctlparam *ip6cp = NULL;
241 const struct sockaddr_in6 *sa6_src = NULL;
242 void *cmdarg;
243 void (*notify) __P((struct in6pcb *, int)) = in6_rtchange;
244 int nxt;
245
246 if (sa->sa_family != AF_INET6 ||
247 sa->sa_len != sizeof(struct sockaddr_in6))
248 return;
249
250 if ((unsigned)cmd >= PRC_NCMDS)
251 return;
252 if (PRC_IS_REDIRECT(cmd))
253 notify = in6_rtchange, d = NULL;
254 else if (cmd == PRC_HOSTDEAD)
255 d = NULL;
256 else if (cmd == PRC_MSGSIZE)
257 ; /* special code is present, see below */
258 else if (inet6ctlerrmap[cmd] == 0)
259 return;
260
261 /* if the parameter is from icmp6, decode it. */
262 if (d != NULL) {
263 ip6cp = (struct ip6ctlparam *)d;
264 m = ip6cp->ip6c_m;
265 ip6 = ip6cp->ip6c_ip6;
266 off = ip6cp->ip6c_off;
267 cmdarg = ip6cp->ip6c_cmdarg;
268 sa6_src = ip6cp->ip6c_src;
269 nxt = ip6cp->ip6c_nxt;
270 } else {
271 m = NULL;
272 ip6 = NULL;
273 cmdarg = NULL;
274 sa6_src = &sa6_any;
275 nxt = -1;
276 }
277
278 if (ip6 && cmd == PRC_MSGSIZE) {
279 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
280 int valid = 0;
281 struct in6pcb *in6p;
282
283 /*
284 * Check to see if we have a valid raw IPv6 socket
285 * corresponding to the address in the ICMPv6 message
286 * payload, and the protocol (ip6_nxt) meets the socket.
287 * XXX chase extension headers, or pass final nxt value
288 * from icmp6_notify_error()
289 */
290 in6p = NULL;
291 in6p = in6_pcblookup_connect(&rawin6pcb,
292 &sa6->sin6_addr, 0,
293 (struct in6_addr *)&sa6_src->sin6_addr, 0, 0);
294 #if 0
295 if (!in6p) {
296 /*
297 * As the use of sendto(2) is fairly popular,
298 * we may want to allow non-connected pcb too.
299 * But it could be too weak against attacks...
300 * We should at least check if the local
301 * address (= s) is really ours.
302 */
303 in6p = in6_pcblookup_bind(&rawin6pcb,
304 &sa6->sin6_addr, 0, 0))
305 }
306 #endif
307
308 if (in6p && in6p->in6p_ip6.ip6_nxt &&
309 in6p->in6p_ip6.ip6_nxt == nxt)
310 valid++;
311
312 /*
313 * Depending on the value of "valid" and routing table
314 * size (mtudisc_{hi,lo}wat), we will:
315 * - recalcurate the new MTU and create the
316 * corresponding routing entry, or
317 * - ignore the MTU change notification.
318 */
319 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
320
321 /*
322 * regardless of if we called icmp6_mtudisc_update(),
323 * we need to call in6_pcbnotify(), to notify path
324 * MTU change to the userland (2292bis-02), because
325 * some unconnected sockets may share the same
326 * destination and want to know the path MTU.
327 */
328 }
329
330 (void) in6_pcbnotify(&rawin6pcb, sa, 0,
331 (struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
332 }
333
334 /*
335 * Generate IPv6 header and pass packet to ip6_output.
336 * Tack on options user may have setup with control call.
337 */
338 int
339 #if __STDC__
340 rip6_output(struct mbuf *m, ...)
341 #else
342 rip6_output(m, va_alist)
343 struct mbuf *m;
344 va_dcl
345 #endif
346 {
347 struct socket *so;
348 struct sockaddr_in6 *dstsock;
349 struct mbuf *control;
350 struct in6_addr *dst;
351 struct ip6_hdr *ip6;
352 struct in6pcb *in6p;
353 u_int plen = m->m_pkthdr.len;
354 int error = 0;
355 struct ip6_pktopts opt, *optp = NULL, *origoptp;
356 struct ifnet *oifp = NULL;
357 int type, code; /* for ICMPv6 output statistics only */
358 int priv = 0;
359 va_list ap;
360 int flags;
361
362 va_start(ap, m);
363 so = va_arg(ap, struct socket *);
364 dstsock = va_arg(ap, struct sockaddr_in6 *);
365 control = va_arg(ap, struct mbuf *);
366 va_end(ap);
367
368 in6p = sotoin6pcb(so);
369
370 priv = 0;
371 {
372 struct proc *p = curproc; /* XXX */
373
374 if (p && !suser(p->p_ucred, &p->p_acflag))
375 priv = 1;
376 }
377 dst = &dstsock->sin6_addr;
378 if (control) {
379 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
380 goto bad;
381 optp = &opt;
382 } else
383 optp = in6p->in6p_outputopts;
384
385 /*
386 * For an ICMPv6 packet, we should know its type and code
387 * to update statistics.
388 */
389 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
390 struct icmp6_hdr *icmp6;
391 if (m->m_len < sizeof(struct icmp6_hdr) &&
392 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
393 error = ENOBUFS;
394 goto bad;
395 }
396 icmp6 = mtod(m, struct icmp6_hdr *);
397 type = icmp6->icmp6_type;
398 code = icmp6->icmp6_code;
399 }
400
401 M_PREPEND(m, sizeof(*ip6), M_WAIT);
402 ip6 = mtod(m, struct ip6_hdr *);
403
404 /*
405 * Next header might not be ICMP6 but use its pseudo header anyway.
406 */
407 ip6->ip6_dst = *dst;
408
409 /* KAME hack: embed scopeid */
410 origoptp = in6p->in6p_outputopts;
411 in6p->in6p_outputopts = optp;
412 if (in6_embedscope(&ip6->ip6_dst, dstsock, in6p, &oifp) != 0) {
413 error = EINVAL;
414 goto bad;
415 }
416 in6p->in6p_outputopts = origoptp;
417
418 /*
419 * Source address selection.
420 */
421 {
422 struct in6_addr *in6a;
423
424 if ((in6a = in6_selectsrc(dstsock, optp,
425 in6p->in6p_moptions,
426 &in6p->in6p_route,
427 &in6p->in6p_laddr,
428 &error)) == 0) {
429 if (error == 0)
430 error = EADDRNOTAVAIL;
431 goto bad;
432 }
433 ip6->ip6_src = *in6a;
434 if (in6p->in6p_route.ro_rt) {
435 /* what if oifp contradicts ? */
436 oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
437 }
438 }
439
440 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
441 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
442 ip6->ip6_vfc |= IPV6_VERSION;
443 #if 0 /* ip6_plen will be filled in ip6_output. */
444 ip6->ip6_plen = htons((u_short)plen);
445 #endif
446 ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt;
447 ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
448
449 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
450 in6p->in6p_cksum != -1) {
451 struct mbuf *n;
452 int off;
453 u_int16_t *p;
454
455 #define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */
456
457 /* compute checksum */
458 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
459 off = offsetof(struct icmp6_hdr, icmp6_cksum);
460 else
461 off = in6p->in6p_cksum;
462 if (plen < off + 1) {
463 error = EINVAL;
464 goto bad;
465 }
466 off += sizeof(struct ip6_hdr);
467
468 n = m;
469 while (n && n->m_len <= off) {
470 off -= n->m_len;
471 n = n->m_next;
472 }
473 if (!n)
474 goto bad;
475 p = (u_int16_t *)(mtod(n, caddr_t) + off);
476 *p = 0;
477 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
478 }
479
480 #ifdef IPSEC
481 if (ipsec_setsocket(m, so) != 0) {
482 error = ENOBUFS;
483 goto bad;
484 }
485 #endif /*IPSEC*/
486
487 flags = 0;
488 #ifdef IPV6_MINMTU
489 if (in6p->in6p_flags & IN6P_MINMTU)
490 flags |= IPV6_MINMTU;
491 #endif
492
493 error = ip6_output(m, optp, &in6p->in6p_route, flags,
494 in6p->in6p_moptions, &oifp);
495 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
496 if (oifp)
497 icmp6_ifoutstat_inc(oifp, type, code);
498 icmp6stat.icp6s_outhist[type]++;
499 }
500
501 goto freectl;
502
503 bad:
504 if (m)
505 m_freem(m);
506
507 freectl:
508 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
509 RTFREE(optp->ip6po_route.ro_rt);
510 if (control)
511 m_freem(control);
512 return(error);
513 }
514
515 /*
516 * Raw IPv6 socket option processing.
517 */
518 int
519 rip6_ctloutput(op, so, level, optname, m)
520 int op;
521 struct socket *so;
522 int level, optname;
523 struct mbuf **m;
524 {
525 int error = 0;
526
527 switch (level) {
528 case IPPROTO_IPV6:
529 switch (optname) {
530 case MRT6_INIT:
531 case MRT6_DONE:
532 case MRT6_ADD_MIF:
533 case MRT6_DEL_MIF:
534 case MRT6_ADD_MFC:
535 case MRT6_DEL_MFC:
536 case MRT6_PIM:
537 if (op == PRCO_SETOPT) {
538 error = ip6_mrouter_set(optname, so, *m);
539 if (*m)
540 (void)m_free(*m);
541 } else if (op == PRCO_GETOPT) {
542 error = ip6_mrouter_get(optname, so, m);
543 } else
544 error = EINVAL;
545 return (error);
546 }
547 return (ip6_ctloutput(op, so, level, optname, m));
548 /* NOTREACHED */
549
550 case IPPROTO_ICMPV6:
551 /*
552 * XXX: is it better to call icmp6_ctloutput() directly
553 * from protosw?
554 */
555 return(icmp6_ctloutput(op, so, level, optname, m));
556
557 default:
558 if (op == PRCO_SETOPT && *m)
559 (void)m_free(*m);
560 return(EINVAL);
561 }
562 }
563
564 extern u_long rip6_sendspace;
565 extern u_long rip6_recvspace;
566
567 int
568 rip6_usrreq(so, req, m, nam, control, p)
569 struct socket *so;
570 int req;
571 struct mbuf *m, *nam, *control;
572 struct proc *p;
573 {
574 struct in6pcb *in6p = sotoin6pcb(so);
575 int s;
576 int error = 0;
577 /* extern struct socket *ip6_mrouter; */ /* xxx */
578 int priv;
579
580 priv = 0;
581 if (p && !suser(p->p_ucred, &p->p_acflag))
582 priv++;
583
584 if (req == PRU_CONTROL)
585 return (in6_control(so, (u_long)m, (caddr_t)nam,
586 (struct ifnet *)control, p));
587
588 if (req == PRU_PURGEIF) {
589 in6_purgeif((struct ifnet *)control);
590 in6_pcbpurgeif(&rawin6pcb, (struct ifnet *)control);
591 return (0);
592 }
593
594 switch (req) {
595 case PRU_ATTACH:
596 if (in6p)
597 panic("rip6_attach");
598 if (!priv) {
599 error = EACCES;
600 break;
601 }
602 s = splsoftnet();
603 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) != 0) {
604 splx(s);
605 break;
606 }
607 if ((error = in6_pcballoc(so, &rawin6pcb)) != 0)
608 {
609 splx(s);
610 break;
611 }
612 splx(s);
613 in6p = sotoin6pcb(so);
614 in6p->in6p_ip6.ip6_nxt = (long)nam;
615 in6p->in6p_cksum = -1;
616 #ifdef IPSEC
617 error = ipsec_init_policy(so, &in6p->in6p_sp);
618 if (error != 0) {
619 in6_pcbdetach(in6p);
620 break;
621 }
622 #endif /*IPSEC*/
623
624 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
625 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
626 if (in6p->in6p_icmp6filt == NULL) {
627 in6_pcbdetach(in6p);
628 error = ENOMEM;
629 break;
630 }
631 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
632 break;
633
634 case PRU_DISCONNECT:
635 if ((so->so_state & SS_ISCONNECTED) == 0) {
636 error = ENOTCONN;
637 break;
638 }
639 in6p->in6p_faddr = in6addr_any;
640 so->so_state &= ~SS_ISCONNECTED; /* XXX */
641 break;
642
643 case PRU_ABORT:
644 soisdisconnected(so);
645 /* Fallthrough */
646 case PRU_DETACH:
647 if (in6p == 0)
648 panic("rip6_detach");
649 if (so == ip6_mrouter)
650 ip6_mrouter_done();
651 /* xxx: RSVP */
652 if (in6p->in6p_icmp6filt) {
653 FREE(in6p->in6p_icmp6filt, M_PCB);
654 in6p->in6p_icmp6filt = NULL;
655 }
656 in6_pcbdetach(in6p);
657 break;
658
659 case PRU_BIND:
660 {
661 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
662 struct ifaddr *ia = NULL;
663
664 if (nam->m_len != sizeof(*addr)) {
665 error = EINVAL;
666 break;
667 }
668 if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6)) {
669 error = EADDRNOTAVAIL;
670 break;
671 }
672 #ifdef ENABLE_DEFAULT_SCOPE
673 if (addr->sin6_scope_id == 0) /* not change if specified */
674 addr->sin6_scope_id =
675 scope6_addr2default(&addr->sin6_addr);
676 #endif
677 /*
678 * we don't support mapped address here, it would confuse
679 * users so reject it
680 */
681 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
682 error = EADDRNOTAVAIL;
683 break;
684 }
685 /*
686 * Currently, ifa_ifwithaddr tends to fail for a link-local
687 * address, since it implicitly expects that the link ID
688 * for the address is embedded in the sin6_addr part.
689 * For now, we'd rather keep this "as is". We'll eventually fix
690 * this in a more natural way.
691 */
692 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
693 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) {
694 error = EADDRNOTAVAIL;
695 break;
696 }
697 if (ia &&
698 ((struct in6_ifaddr *)ia)->ia6_flags &
699 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
700 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
701 error = EADDRNOTAVAIL;
702 break;
703 }
704 in6p->in6p_laddr = addr->sin6_addr;
705 break;
706 }
707
708 case PRU_CONNECT:
709 {
710 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
711 struct in6_addr *in6a = NULL;
712 #ifdef ENABLE_DEFAULT_SCOPE
713 struct sockaddr_in6 sin6;
714 #endif
715
716 if (nam->m_len != sizeof(*addr)) {
717 error = EINVAL;
718 break;
719 }
720 if (ifnet.tqh_first == 0)
721 {
722 error = EADDRNOTAVAIL;
723 break;
724 }
725 if (addr->sin6_family != AF_INET6) {
726 error = EAFNOSUPPORT;
727 break;
728 }
729
730 #ifdef ENABLE_DEFAULT_SCOPE
731 if (addr->sin6_scope_id == 0) {
732 /* protect *addr */
733 sin6 = *addr;
734 addr = &sin6;
735 addr->sin6_scope_id =
736 scope6_addr2default(&addr->sin6_addr);
737 }
738 #endif
739
740 /* Source address selection. XXX: need pcblookup? */
741 in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
742 in6p->in6p_moptions,
743 &in6p->in6p_route,
744 &in6p->in6p_laddr,
745 &error);
746 if (in6a == NULL) {
747 if (error == 0)
748 error = EADDRNOTAVAIL;
749 break;
750 }
751 in6p->in6p_laddr = *in6a;
752 in6p->in6p_faddr = addr->sin6_addr;
753 soisconnected(so);
754 break;
755 }
756
757 case PRU_CONNECT2:
758 error = EOPNOTSUPP;
759 break;
760
761 /*
762 * Mark the connection as being incapable of futther input.
763 */
764 case PRU_SHUTDOWN:
765 socantsendmore(so);
766 break;
767 /*
768 * Ship a packet out. The appropriate raw output
769 * routine handles any messaging necessary.
770 */
771 case PRU_SEND:
772 {
773 struct sockaddr_in6 tmp;
774 struct sockaddr_in6 *dst;
775
776 /* always copy sockaddr to avoid overwrites */
777 if (so->so_state & SS_ISCONNECTED) {
778 if (nam) {
779 error = EISCONN;
780 break;
781 }
782 /* XXX */
783 bzero(&tmp, sizeof(tmp));
784 tmp.sin6_family = AF_INET6;
785 tmp.sin6_len = sizeof(struct sockaddr_in6);
786 bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
787 sizeof(struct in6_addr));
788 dst = &tmp;
789 } else {
790 if (nam == NULL) {
791 error = ENOTCONN;
792 break;
793 }
794 tmp = *mtod(nam, struct sockaddr_in6 *);
795 dst = &tmp;
796 }
797 #ifdef ENABLE_DEFAULT_SCOPE
798 if (dst->sin6_scope_id == 0) {
799 dst->sin6_scope_id =
800 scope6_addr2default(&dst->sin6_addr);
801 }
802 #endif
803 error = rip6_output(m, so, dst, control);
804 m = NULL;
805 break;
806 }
807
808 case PRU_SENSE:
809 /*
810 * stat: don't bother with a blocksize
811 */
812 return(0);
813 /*
814 * Not supported.
815 */
816 case PRU_RCVOOB:
817 case PRU_RCVD:
818 case PRU_LISTEN:
819 case PRU_ACCEPT:
820 case PRU_SENDOOB:
821 error = EOPNOTSUPP;
822 break;
823
824 case PRU_SOCKADDR:
825 in6_setsockaddr(in6p, nam);
826 break;
827
828 case PRU_PEERADDR:
829 in6_setpeeraddr(in6p, nam);
830 break;
831
832 default:
833 panic("rip6_usrreq");
834 }
835 if (m != NULL)
836 m_freem(m);
837 return(error);
838 }
839