raw_ip6.c revision 1.23.2.1 1 /* $NetBSD: raw_ip6.c,v 1.23.2.1 2001/02/26 22:44:34 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 error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions,
483 &oifp);
484 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
485 if (oifp)
486 icmp6_ifoutstat_inc(oifp, type, code);
487 icmp6stat.icp6s_outhist[type]++;
488 }
489
490 goto freectl;
491
492 bad:
493 if (m)
494 m_freem(m);
495
496 freectl:
497 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
498 RTFREE(optp->ip6po_route.ro_rt);
499 if (control)
500 m_freem(control);
501 return(error);
502 }
503
504 /*
505 * Raw IPv6 socket option processing.
506 */
507 int
508 rip6_ctloutput(op, so, level, optname, m)
509 int op;
510 struct socket *so;
511 int level, optname;
512 struct mbuf **m;
513 {
514 int error = 0;
515
516 switch(level) {
517 case IPPROTO_IPV6:
518 switch(optname) {
519 case MRT6_INIT:
520 case MRT6_DONE:
521 case MRT6_ADD_MIF:
522 case MRT6_DEL_MIF:
523 case MRT6_ADD_MFC:
524 case MRT6_DEL_MFC:
525 case MRT6_PIM:
526 if (op == PRCO_SETOPT) {
527 error = ip6_mrouter_set(optname, so, *m);
528 if (*m)
529 (void)m_free(*m);
530 } else if (op == PRCO_GETOPT) {
531 error = ip6_mrouter_get(optname, so, m);
532 } else
533 error = EINVAL;
534 return (error);
535 }
536 return (ip6_ctloutput(op, so, level, optname, m));
537 /* NOTREACHED */
538
539 case IPPROTO_ICMPV6:
540 /*
541 * XXX: is it better to call icmp6_ctloutput() directly
542 * from protosw?
543 */
544 return(icmp6_ctloutput(op, so, level, optname, m));
545
546 default:
547 if (op == PRCO_SETOPT && *m)
548 (void)m_free(*m);
549 return(EINVAL);
550 }
551 }
552
553 extern u_long rip6_sendspace;
554 extern u_long rip6_recvspace;
555
556 int
557 rip6_usrreq(so, req, m, nam, control, p)
558 register struct socket *so;
559 int req;
560 struct mbuf *m, *nam, *control;
561 struct proc *p;
562 {
563 register struct in6pcb *in6p = sotoin6pcb(so);
564 int s;
565 int error = 0;
566 /* extern struct socket *ip6_mrouter; */ /* xxx */
567 int priv;
568
569 priv = 0;
570 if (p && !suser(p->p_ucred, &p->p_acflag))
571 priv++;
572
573 if (req == PRU_CONTROL)
574 return (in6_control(so, (u_long)m, (caddr_t)nam,
575 (struct ifnet *)control, p));
576
577 if (req == PRU_PURGEIF) {
578 in6_purgeif((struct ifnet *)control);
579 in6_pcbpurgeif(&rawin6pcb, (struct ifnet *)control);
580 return (0);
581 }
582
583 switch (req) {
584 case PRU_ATTACH:
585 if (in6p)
586 panic("rip6_attach");
587 if (!priv) {
588 error = EACCES;
589 break;
590 }
591 s = splsoftnet();
592 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) ||
593 (error = in6_pcballoc(so, &rawin6pcb))) {
594 splx(s);
595 break;
596 }
597 splx(s);
598 in6p = sotoin6pcb(so);
599 in6p->in6p_ip6.ip6_nxt = (long)nam;
600 in6p->in6p_cksum = -1;
601 #ifdef IPSEC
602 error = ipsec_init_policy(so, &in6p->in6p_sp);
603 if (error != 0) {
604 in6_pcbdetach(in6p);
605 break;
606 }
607 #endif /*IPSEC*/
608
609 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
610 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
611 if (in6p->in6p_icmp6filt == NULL) {
612 in6_pcbdetach(in6p);
613 error = ENOMEM;
614 break;
615 }
616 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
617 break;
618
619 case PRU_DISCONNECT:
620 if ((so->so_state & SS_ISCONNECTED) == 0) {
621 error = ENOTCONN;
622 break;
623 }
624 in6p->in6p_faddr = in6addr_any;
625 so->so_state &= ~SS_ISCONNECTED; /* XXX */
626 break;
627
628 case PRU_ABORT:
629 soisdisconnected(so);
630 /* Fallthrough */
631 case PRU_DETACH:
632 if (in6p == 0)
633 panic("rip6_detach");
634 if (so == ip6_mrouter)
635 ip6_mrouter_done();
636 /* xxx: RSVP */
637 if (in6p->in6p_icmp6filt) {
638 FREE(in6p->in6p_icmp6filt, M_PCB);
639 in6p->in6p_icmp6filt = NULL;
640 }
641 in6_pcbdetach(in6p);
642 break;
643
644 case PRU_BIND:
645 {
646 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
647 struct ifaddr *ia = NULL;
648
649 if (nam->m_len != sizeof(*addr)) {
650 error = EINVAL;
651 break;
652 }
653
654 /*
655 * we don't support mapped address here, it would confuse
656 * users so reject it
657 */
658 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
659 error = EADDRNOTAVAIL;
660 break;
661 }
662
663 if ((ifnet.tqh_first == 0) ||
664 (addr->sin6_family != AF_INET6) ||
665 (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
666 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) {
667 error = EADDRNOTAVAIL;
668 break;
669 }
670 if (ia &&
671 ((struct in6_ifaddr *)ia)->ia6_flags &
672 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
673 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
674 error = EADDRNOTAVAIL;
675 break;
676 }
677 in6p->in6p_laddr = addr->sin6_addr;
678 break;
679 }
680
681 case PRU_CONNECT:
682 {
683 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
684 struct in6_addr *in6a = NULL;
685
686 if (nam->m_len != sizeof(*addr)) {
687 error = EINVAL;
688 break;
689 }
690 if (ifnet.tqh_first == 0) {
691 error = EADDRNOTAVAIL;
692 break;
693 }
694 if (addr->sin6_family != AF_INET6) {
695 error = EAFNOSUPPORT;
696 break;
697 }
698
699 /* Source address selection. XXX: need pcblookup? */
700 in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
701 in6p->in6p_moptions,
702 &in6p->in6p_route,
703 &in6p->in6p_laddr,
704 &error);
705 if (in6a == NULL) {
706 if (error == 0)
707 error = EADDRNOTAVAIL;
708 break;
709 }
710 in6p->in6p_laddr = *in6a;
711 in6p->in6p_faddr = addr->sin6_addr;
712 soisconnected(so);
713 break;
714 }
715
716 case PRU_CONNECT2:
717 error = EOPNOTSUPP;
718 break;
719
720 /*
721 * Mark the connection as being incapable of futther input.
722 */
723 case PRU_SHUTDOWN:
724 socantsendmore(so);
725 break;
726 /*
727 * Ship a packet out. The appropriate raw output
728 * routine handles any messaging necessary.
729 */
730 case PRU_SEND:
731 {
732 struct sockaddr_in6 tmp;
733 struct sockaddr_in6 *dst;
734
735 if (so->so_state & SS_ISCONNECTED) {
736 if (nam) {
737 error = EISCONN;
738 break;
739 }
740 /* XXX */
741 bzero(&tmp, sizeof(tmp));
742 tmp.sin6_family = AF_INET6;
743 tmp.sin6_len = sizeof(struct sockaddr_in6);
744 bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
745 sizeof(struct in6_addr));
746 dst = &tmp;
747 } else {
748 if (nam == NULL) {
749 error = ENOTCONN;
750 break;
751 }
752 dst = mtod(nam, struct sockaddr_in6 *);
753 }
754 error = rip6_output(m, so, dst, control);
755 m = NULL;
756 break;
757 }
758
759 case PRU_SENSE:
760 /*
761 * stat: don't bother with a blocksize
762 */
763 return(0);
764 /*
765 * Not supported.
766 */
767 case PRU_RCVOOB:
768 case PRU_RCVD:
769 case PRU_LISTEN:
770 case PRU_ACCEPT:
771 case PRU_SENDOOB:
772 error = EOPNOTSUPP;
773 break;
774
775 case PRU_SOCKADDR:
776 in6_setsockaddr(in6p, nam);
777 break;
778
779 case PRU_PEERADDR:
780 in6_setpeeraddr(in6p, nam);
781 break;
782
783 default:
784 panic("rip6_usrreq");
785 }
786 if (m != NULL)
787 m_freem(m);
788 return(error);
789 }
790