raw_ip6.c revision 1.23.2.2 1 /* $NetBSD: raw_ip6.c,v 1.23.2.2 2001/04/06 00:29:21 he Exp $ */
2 /* $KAME: raw_ip6.c,v 1.28 2000/05/28 23:25:07 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
94 #ifdef IPSEC
95 #include <netinet6/ipsec.h>
96 #endif /*IPSEC*/
97
98 #include <machine/stdarg.h>
99
100 #include "faith.h"
101
102 struct in6pcb rawin6pcb;
103 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
104
105 /*
106 * Raw interface to IP6 protocol.
107 */
108
109 /*
110 * Initialize raw connection block queue.
111 */
112 void
113 rip6_init()
114 {
115 rawin6pcb.in6p_next = rawin6pcb.in6p_prev = &rawin6pcb;
116 }
117
118 /*
119 * Setup generic address and protocol structures
120 * for raw_input routine, then pass them along with
121 * mbuf chain.
122 */
123 int
124 rip6_input(mp, offp, proto)
125 struct mbuf **mp;
126 int *offp, proto;
127 {
128 struct mbuf *m = *mp;
129 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
130 register struct in6pcb *in6p;
131 struct in6pcb *last = NULL;
132 struct sockaddr_in6 rip6src;
133 struct mbuf *opts = NULL;
134
135 #if defined(NFAITH) && 0 < NFAITH
136 if (m->m_pkthdr.rcvif) {
137 if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
138 /* send icmp6 host unreach? */
139 m_freem(m);
140 return IPPROTO_DONE;
141 }
142 }
143 #endif
144
145 /* Be proactive about malicious use of IPv4 mapped address */
146 if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
147 IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
148 /* XXX stat */
149 m_freem(m);
150 return IPPROTO_DONE;
151 }
152
153 bzero(&rip6src, sizeof(rip6src));
154 rip6src.sin6_len = sizeof(struct sockaddr_in6);
155 rip6src.sin6_family = AF_INET6;
156 rip6src.sin6_addr = ip6->ip6_src;
157 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
158 rip6src.sin6_addr.s6_addr16[1] = 0;
159 if (m->m_pkthdr.rcvif) {
160 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
161 rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
162 else
163 rip6src.sin6_scope_id = 0;
164 } else
165 rip6src.sin6_scope_id = 0;
166
167 for (in6p = rawin6pcb.in6p_next;
168 in6p != &rawin6pcb; in6p = in6p->in6p_next) {
169 if (in6p->in6p_ip6.ip6_nxt &&
170 in6p->in6p_ip6.ip6_nxt != proto)
171 continue;
172 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
173 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
174 continue;
175 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
176 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
177 continue;
178 if (in6p->in6p_cksum != -1
179 && in6_cksum(m, ip6->ip6_nxt, *offp, m->m_pkthdr.len - *offp))
180 {
181 /* XXX bark something */
182 continue;
183 }
184 if (last) {
185 struct mbuf *n;
186
187 #ifdef IPSEC
188 /*
189 * Check AH/ESP integrity.
190 */
191 if (ipsec6_in_reject(m, last)) {
192 ipsec6stat.in_polvio++;
193 /* do not inject data into pcb */
194 } else
195 #endif /*IPSEC*/
196 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
197 if (last->in6p_flags & IN6P_CONTROLOPTS)
198 ip6_savecontrol(last, &opts, ip6, n);
199 /* strip intermediate headers */
200 m_adj(n, *offp);
201 if (sbappendaddr(&last->in6p_socket->so_rcv,
202 (struct sockaddr *)&rip6src,
203 n, opts) == 0) {
204 /* should notify about lost packet */
205 m_freem(n);
206 if (opts)
207 m_freem(opts);
208 } else
209 sorwakeup(last->in6p_socket);
210 opts = NULL;
211 }
212 }
213 last = in6p;
214 }
215 #ifdef IPSEC
216 /*
217 * Check AH/ESP integrity.
218 */
219 if (last && ipsec6_in_reject(m, last)) {
220 m_freem(m);
221 ipsec6stat.in_polvio++;
222 ip6stat.ip6s_delivered--;
223 /* do not inject data into pcb */
224 } else
225 #endif /*IPSEC*/
226 if (last) {
227 if (last->in6p_flags & IN6P_CONTROLOPTS)
228 ip6_savecontrol(last, &opts, ip6, m);
229 /* strip intermediate headers */
230 m_adj(m, *offp);
231 if (sbappendaddr(&last->in6p_socket->so_rcv,
232 (struct sockaddr *)&rip6src, m, opts) == 0) {
233 m_freem(m);
234 if (opts)
235 m_freem(opts);
236 } else
237 sorwakeup(last->in6p_socket);
238 } else {
239 if (proto == IPPROTO_NONE)
240 m_freem(m);
241 else {
242 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
243 icmp6_error(m, ICMP6_PARAM_PROB,
244 ICMP6_PARAMPROB_NEXTHEADER,
245 prvnxtp - mtod(m, char *));
246 }
247 ip6stat.ip6s_delivered--;
248 }
249 return IPPROTO_DONE;
250 }
251
252 void
253 rip6_ctlinput(cmd, sa, d)
254 int cmd;
255 struct sockaddr *sa;
256 void *d;
257 {
258 struct sockaddr_in6 sa6;
259 register struct ip6_hdr *ip6;
260 struct mbuf *m;
261 int off;
262 void (*notify) __P((struct in6pcb *, int)) = in6_rtchange;
263
264 if (sa->sa_family != AF_INET6 ||
265 sa->sa_len != sizeof(struct sockaddr_in6))
266 return;
267
268 if ((unsigned)cmd >= PRC_NCMDS)
269 return;
270 if (PRC_IS_REDIRECT(cmd))
271 notify = in6_rtchange, d = NULL;
272 else if (cmd == PRC_HOSTDEAD)
273 d = NULL;
274 else if (inet6ctlerrmap[cmd] == 0)
275 return;
276
277 /* if the parameter is from icmp6, decode it. */
278 if (d != NULL) {
279 struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
280 m = ip6cp->ip6c_m;
281 ip6 = ip6cp->ip6c_ip6;
282 off = ip6cp->ip6c_off;
283 } else {
284 m = NULL;
285 ip6 = NULL;
286 }
287
288 /* translate addresses into internal form */
289 sa6 = *(struct sockaddr_in6 *)sa;
290 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
291 sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
292
293 if (ip6) {
294 /*
295 * XXX: We assume that when IPV6 is non NULL,
296 * M and OFF are valid.
297 */
298 struct in6_addr s;
299
300 /* translate addresses into internal form */
301 memcpy(&s, &ip6->ip6_src, sizeof(s));
302 if (IN6_IS_ADDR_LINKLOCAL(&s))
303 s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
304
305 (void) in6_pcbnotify(&rawin6pcb, (struct sockaddr *)&sa6,
306 0, &s, 0, cmd, notify);
307 } else {
308 (void) in6_pcbnotify(&rawin6pcb, (struct sockaddr *)&sa6, 0,
309 &zeroin6_addr, 0, cmd, notify);
310 }
311 }
312
313 /*
314 * Generate IPv6 header and pass packet to ip6_output.
315 * Tack on options user may have setup with control call.
316 */
317 int
318 #if __STDC__
319 rip6_output(struct mbuf *m, ...)
320 #else
321 rip6_output(m, va_alist)
322 struct mbuf *m;
323 va_dcl
324 #endif
325 {
326 struct socket *so;
327 struct sockaddr_in6 *dstsock;
328 struct mbuf *control;
329 struct in6_addr *dst;
330 struct ip6_hdr *ip6;
331 struct in6pcb *in6p;
332 u_int plen = m->m_pkthdr.len;
333 int error = 0;
334 struct ip6_pktopts opt, *optp = NULL;
335 struct ifnet *oifp = NULL;
336 int type, code; /* for ICMPv6 output statistics only */
337 int priv = 0;
338 va_list ap;
339
340 va_start(ap, m);
341 so = va_arg(ap, struct socket *);
342 dstsock = va_arg(ap, struct sockaddr_in6 *);
343 control = va_arg(ap, struct mbuf *);
344 va_end(ap);
345
346 in6p = sotoin6pcb(so);
347
348 priv = 0;
349 {
350 struct proc *p = curproc; /* XXX */
351
352 if (p && !suser(p->p_ucred, &p->p_acflag))
353 priv = 1;
354 }
355 dst = &dstsock->sin6_addr;
356 if (control) {
357 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
358 goto bad;
359 optp = &opt;
360 } else
361 optp = in6p->in6p_outputopts;
362
363 /*
364 * For an ICMPv6 packet, we should know its type and code
365 * to update statistics.
366 */
367 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
368 struct icmp6_hdr *icmp6;
369 if (m->m_len < sizeof(struct icmp6_hdr) &&
370 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
371 error = ENOBUFS;
372 goto bad;
373 }
374 icmp6 = mtod(m, struct icmp6_hdr *);
375 type = icmp6->icmp6_type;
376 code = icmp6->icmp6_code;
377 }
378
379 M_PREPEND(m, sizeof(*ip6), M_WAIT);
380 ip6 = mtod(m, struct ip6_hdr *);
381
382 /*
383 * Next header might not be ICMP6 but use its pseudo header anyway.
384 */
385 ip6->ip6_dst = *dst;
386
387 /*
388 * If the scope of the destination is link-local, embed the interface
389 * index in the address.
390 *
391 * XXX advanced-api value overrides sin6_scope_id
392 */
393 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) ||
394 IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) {
395 struct in6_pktinfo *pi;
396
397 /*
398 * XXX Boundary check is assumed to be already done in
399 * ip6_setpktoptions().
400 */
401 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) {
402 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex);
403 oifp = ifindex2ifnet[pi->ipi6_ifindex];
404 }
405 else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
406 in6p->in6p_moptions &&
407 in6p->in6p_moptions->im6o_multicast_ifp) {
408 oifp = in6p->in6p_moptions->im6o_multicast_ifp;
409 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
410 } else if (dstsock->sin6_scope_id) {
411 /* boundary check */
412 if (dstsock->sin6_scope_id < 0
413 || if_index < dstsock->sin6_scope_id) {
414 error = ENXIO; /* XXX EINVAL? */
415 goto bad;
416 }
417 ip6->ip6_dst.s6_addr16[1]
418 = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
419 }
420 }
421
422 /*
423 * Source address selection.
424 */
425 {
426 struct in6_addr *in6a;
427
428 if ((in6a = in6_selectsrc(dstsock, optp,
429 in6p->in6p_moptions,
430 &in6p->in6p_route,
431 &in6p->in6p_laddr,
432 &error)) == 0) {
433 if (error == 0)
434 error = EADDRNOTAVAIL;
435 goto bad;
436 }
437 ip6->ip6_src = *in6a;
438 if (in6p->in6p_route.ro_rt)
439 oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
440 }
441
442 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
443 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
444 ip6->ip6_vfc |= IPV6_VERSION;
445 #if 0 /* ip6_plen will be filled in ip6_output. */
446 ip6->ip6_plen = htons((u_short)plen);
447 #endif
448 ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt;
449 ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
450
451 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
452 in6p->in6p_cksum != -1) {
453 struct mbuf *n;
454 int off;
455 u_int16_t *p;
456
457 #define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */
458
459 /* compute checksum */
460 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
461 off = offsetof(struct icmp6_hdr, icmp6_cksum);
462 else
463 off = in6p->in6p_cksum;
464 if (plen < off + 1) {
465 error = EINVAL;
466 goto bad;
467 }
468 off += sizeof(struct ip6_hdr);
469
470 n = m;
471 while (n && n->m_len <= off) {
472 off -= n->m_len;
473 n = n->m_next;
474 }
475 if (!n)
476 goto bad;
477 p = (u_int16_t *)(mtod(n, caddr_t) + off);
478 *p = 0;
479 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
480 }
481
482 #ifdef IPSEC
483 if (ipsec_setsocket(m, so) != 0) {
484 error = ENOBUFS;
485 goto bad;
486 }
487 #endif /*IPSEC*/
488
489 error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions,
490 &oifp);
491 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
492 if (oifp)
493 icmp6_ifoutstat_inc(oifp, type, code);
494 icmp6stat.icp6s_outhist[type]++;
495 }
496
497 goto freectl;
498
499 bad:
500 if (m)
501 m_freem(m);
502
503 freectl:
504 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
505 RTFREE(optp->ip6po_route.ro_rt);
506 if (control)
507 m_freem(control);
508 return(error);
509 }
510
511 /*
512 * Raw IPv6 socket option processing.
513 */
514 int
515 rip6_ctloutput(op, so, level, optname, m)
516 int op;
517 struct socket *so;
518 int level, optname;
519 struct mbuf **m;
520 {
521 int error = 0;
522
523 switch(level) {
524 case IPPROTO_IPV6:
525 switch(optname) {
526 case MRT6_INIT:
527 case MRT6_DONE:
528 case MRT6_ADD_MIF:
529 case MRT6_DEL_MIF:
530 case MRT6_ADD_MFC:
531 case MRT6_DEL_MFC:
532 case MRT6_PIM:
533 if (op == PRCO_SETOPT) {
534 error = ip6_mrouter_set(optname, so, *m);
535 if (*m)
536 (void)m_free(*m);
537 } else if (op == PRCO_GETOPT) {
538 error = ip6_mrouter_get(optname, so, m);
539 } else
540 error = EINVAL;
541 return (error);
542 }
543 return (ip6_ctloutput(op, so, level, optname, m));
544 /* NOTREACHED */
545
546 case IPPROTO_ICMPV6:
547 /*
548 * XXX: is it better to call icmp6_ctloutput() directly
549 * from protosw?
550 */
551 return(icmp6_ctloutput(op, so, level, optname, m));
552
553 default:
554 if (op == PRCO_SETOPT && *m)
555 (void)m_free(*m);
556 return(EINVAL);
557 }
558 }
559
560 extern u_long rip6_sendspace;
561 extern u_long rip6_recvspace;
562
563 int
564 rip6_usrreq(so, req, m, nam, control, p)
565 register struct socket *so;
566 int req;
567 struct mbuf *m, *nam, *control;
568 struct proc *p;
569 {
570 register struct in6pcb *in6p = sotoin6pcb(so);
571 int s;
572 int error = 0;
573 /* extern struct socket *ip6_mrouter; */ /* xxx */
574 int priv;
575
576 priv = 0;
577 if (p && !suser(p->p_ucred, &p->p_acflag))
578 priv++;
579
580 if (req == PRU_CONTROL)
581 return (in6_control(so, (u_long)m, (caddr_t)nam,
582 (struct ifnet *)control, p));
583
584 if (req == PRU_PURGEIF) {
585 in6_purgeif((struct ifnet *)control);
586 in6_pcbpurgeif(&rawin6pcb, (struct ifnet *)control);
587 return (0);
588 }
589
590 switch (req) {
591 case PRU_ATTACH:
592 if (in6p)
593 panic("rip6_attach");
594 if (!priv) {
595 error = EACCES;
596 break;
597 }
598 s = splsoftnet();
599 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) ||
600 (error = in6_pcballoc(so, &rawin6pcb))) {
601 splx(s);
602 break;
603 }
604 splx(s);
605 in6p = sotoin6pcb(so);
606 in6p->in6p_ip6.ip6_nxt = (long)nam;
607 in6p->in6p_cksum = -1;
608 #ifdef IPSEC
609 error = ipsec_init_policy(so, &in6p->in6p_sp);
610 if (error != 0) {
611 in6_pcbdetach(in6p);
612 break;
613 }
614 #endif /*IPSEC*/
615
616 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
617 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
618 if (in6p->in6p_icmp6filt == NULL) {
619 in6_pcbdetach(in6p);
620 error = ENOMEM;
621 break;
622 }
623 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
624 break;
625
626 case PRU_DISCONNECT:
627 if ((so->so_state & SS_ISCONNECTED) == 0) {
628 error = ENOTCONN;
629 break;
630 }
631 in6p->in6p_faddr = in6addr_any;
632 so->so_state &= ~SS_ISCONNECTED; /* XXX */
633 break;
634
635 case PRU_ABORT:
636 soisdisconnected(so);
637 /* Fallthrough */
638 case PRU_DETACH:
639 if (in6p == 0)
640 panic("rip6_detach");
641 if (so == ip6_mrouter)
642 ip6_mrouter_done();
643 /* xxx: RSVP */
644 if (in6p->in6p_icmp6filt) {
645 FREE(in6p->in6p_icmp6filt, M_PCB);
646 in6p->in6p_icmp6filt = NULL;
647 }
648 in6_pcbdetach(in6p);
649 break;
650
651 case PRU_BIND:
652 {
653 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
654 struct ifaddr *ia = NULL;
655
656 if (nam->m_len != sizeof(*addr)) {
657 error = EINVAL;
658 break;
659 }
660
661 /*
662 * we don't support mapped address here, it would confuse
663 * users so reject it
664 */
665 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
666 error = EADDRNOTAVAIL;
667 break;
668 }
669
670 if ((ifnet.tqh_first == 0) ||
671 (addr->sin6_family != AF_INET6) ||
672 (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
673 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) {
674 error = EADDRNOTAVAIL;
675 break;
676 }
677 if (ia &&
678 ((struct in6_ifaddr *)ia)->ia6_flags &
679 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
680 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
681 error = EADDRNOTAVAIL;
682 break;
683 }
684 in6p->in6p_laddr = addr->sin6_addr;
685 break;
686 }
687
688 case PRU_CONNECT:
689 {
690 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
691 struct in6_addr *in6a = NULL;
692
693 if (nam->m_len != sizeof(*addr)) {
694 error = EINVAL;
695 break;
696 }
697 if (ifnet.tqh_first == 0) {
698 error = EADDRNOTAVAIL;
699 break;
700 }
701 if (addr->sin6_family != AF_INET6) {
702 error = EAFNOSUPPORT;
703 break;
704 }
705
706 /* Source address selection. XXX: need pcblookup? */
707 in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
708 in6p->in6p_moptions,
709 &in6p->in6p_route,
710 &in6p->in6p_laddr,
711 &error);
712 if (in6a == NULL) {
713 if (error == 0)
714 error = EADDRNOTAVAIL;
715 break;
716 }
717 in6p->in6p_laddr = *in6a;
718 in6p->in6p_faddr = addr->sin6_addr;
719 soisconnected(so);
720 break;
721 }
722
723 case PRU_CONNECT2:
724 error = EOPNOTSUPP;
725 break;
726
727 /*
728 * Mark the connection as being incapable of futther input.
729 */
730 case PRU_SHUTDOWN:
731 socantsendmore(so);
732 break;
733 /*
734 * Ship a packet out. The appropriate raw output
735 * routine handles any messaging necessary.
736 */
737 case PRU_SEND:
738 {
739 struct sockaddr_in6 tmp;
740 struct sockaddr_in6 *dst;
741
742 if (so->so_state & SS_ISCONNECTED) {
743 if (nam) {
744 error = EISCONN;
745 break;
746 }
747 /* XXX */
748 bzero(&tmp, sizeof(tmp));
749 tmp.sin6_family = AF_INET6;
750 tmp.sin6_len = sizeof(struct sockaddr_in6);
751 bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
752 sizeof(struct in6_addr));
753 dst = &tmp;
754 } else {
755 if (nam == NULL) {
756 error = ENOTCONN;
757 break;
758 }
759 dst = mtod(nam, struct sockaddr_in6 *);
760 }
761 error = rip6_output(m, so, dst, control);
762 m = NULL;
763 break;
764 }
765
766 case PRU_SENSE:
767 /*
768 * stat: don't bother with a blocksize
769 */
770 return(0);
771 /*
772 * Not supported.
773 */
774 case PRU_RCVOOB:
775 case PRU_RCVD:
776 case PRU_LISTEN:
777 case PRU_ACCEPT:
778 case PRU_SENDOOB:
779 error = EOPNOTSUPP;
780 break;
781
782 case PRU_SOCKADDR:
783 in6_setsockaddr(in6p, nam);
784 break;
785
786 case PRU_PEERADDR:
787 in6_setpeeraddr(in6p, nam);
788 break;
789
790 default:
791 panic("rip6_usrreq");
792 }
793 if (m != NULL)
794 m_freem(m);
795 return(error);
796 }
797