raw_ip6.c revision 1.17 1 /* $NetBSD: raw_ip6.c,v 1.17 2000/02/01 22:52:12 thorpej 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. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
65 */
66
67 #include "opt_ipsec.h"
68
69 #include <sys/param.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
79 #include <net/if.h>
80 #include <net/route.h>
81 #include <net/if_types.h>
82
83 #include <netinet/in.h>
84 #include <netinet/in_var.h>
85 #include <netinet6/ip6.h>
86 #include <netinet6/ip6_var.h>
87 #include <netinet6/ip6_mroute.h>
88 #include <netinet6/icmp6.h>
89 #include <netinet6/in6_pcb.h>
90 #include <netinet6/nd6.h>
91
92 #ifdef IPSEC
93 #include <netinet6/ipsec.h>
94 #endif /*IPSEC*/
95
96 #include <machine/stdarg.h>
97
98 #include "faith.h"
99
100 struct in6pcb rawin6pcb;
101 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
102
103 /*
104 * Raw interface to IP6 protocol.
105 */
106
107 /*
108 * Initialize raw connection block queue.
109 */
110 void
111 rip6_init()
112 {
113 rawin6pcb.in6p_next = rawin6pcb.in6p_prev = &rawin6pcb;
114 }
115
116 /*
117 * Setup generic address and protocol structures
118 * for raw_input routine, then pass them along with
119 * mbuf chain.
120 */
121 int
122 rip6_input(mp, offp, proto)
123 struct mbuf **mp;
124 int *offp, proto;
125 {
126 struct mbuf *m = *mp;
127 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
128 register struct in6pcb *in6p;
129 struct in6pcb *last = NULL;
130 struct sockaddr_in6 rip6src;
131 struct mbuf *opts = NULL;
132
133 #if defined(NFAITH) && 0 < NFAITH
134 if (m->m_pkthdr.rcvif) {
135 if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
136 /* send icmp6 host unreach? */
137 m_freem(m);
138 return IPPROTO_DONE;
139 }
140 }
141 #endif
142
143 /* Be proactive about malicious use of IPv4 mapped address */
144 if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
145 IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
146 /* XXX stat */
147 m_freem(m);
148 return IPPROTO_DONE;
149 }
150
151 bzero(&rip6src, sizeof(rip6src));
152 rip6src.sin6_len = sizeof(struct sockaddr_in6);
153 rip6src.sin6_family = AF_INET6;
154 rip6src.sin6_addr = ip6->ip6_src;
155 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
156 rip6src.sin6_addr.s6_addr16[1] = 0;
157 if (m->m_pkthdr.rcvif) {
158 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
159 rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
160 else
161 rip6src.sin6_scope_id = 0;
162 } else
163 rip6src.sin6_scope_id = 0;
164
165 for (in6p = rawin6pcb.in6p_next;
166 in6p != &rawin6pcb; in6p = in6p->in6p_next) {
167 if (in6p->in6p_ip6.ip6_nxt &&
168 in6p->in6p_ip6.ip6_nxt != proto)
169 continue;
170 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
171 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
172 continue;
173 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
174 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
175 continue;
176 if (in6p->in6p_cksum != -1
177 && in6_cksum(m, ip6->ip6_nxt, *offp, m->m_pkthdr.len - *offp))
178 {
179 /* XXX bark something */
180 continue;
181 }
182 if (last) {
183 struct mbuf *n;
184 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
185 if (last->in6p_flags & IN6P_CONTROLOPTS)
186 ip6_savecontrol(last, &opts, ip6, n);
187 /* strip intermediate headers */
188 m_adj(n, *offp);
189 if (sbappendaddr(&last->in6p_socket->so_rcv,
190 (struct sockaddr *)&rip6src,
191 n, opts) == 0) {
192 /* should notify about lost packet */
193 m_freem(n);
194 if (opts)
195 m_freem(opts);
196 } else
197 sorwakeup(last->in6p_socket);
198 opts = NULL;
199 }
200 }
201 last = in6p;
202 }
203 if (last) {
204 if (last->in6p_flags & IN6P_CONTROLOPTS)
205 ip6_savecontrol(last, &opts, ip6, m);
206 /* strip intermediate headers */
207 m_adj(m, *offp);
208 if (sbappendaddr(&last->in6p_socket->so_rcv,
209 (struct sockaddr *)&rip6src, m, opts) == 0) {
210 m_freem(m);
211 if (opts)
212 m_freem(opts);
213 } else
214 sorwakeup(last->in6p_socket);
215 } else {
216 if (proto == IPPROTO_NONE)
217 m_freem(m);
218 else {
219 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
220 icmp6_error(m, ICMP6_PARAM_PROB,
221 ICMP6_PARAMPROB_NEXTHEADER,
222 prvnxtp - mtod(m, char *));
223 }
224 ip6stat.ip6s_delivered--;
225 }
226 return IPPROTO_DONE;
227 }
228
229 /*
230 * Generate IPv6 header and pass packet to ip6_output.
231 * Tack on options user may have setup with control call.
232 */
233 int
234 #if __STDC__
235 rip6_output(struct mbuf *m, ...)
236 #else
237 rip6_output(m, va_alist)
238 struct mbuf *m;
239 va_dcl
240 #endif
241 {
242 struct socket *so;
243 struct sockaddr_in6 *dstsock;
244 struct mbuf *control;
245 struct in6_addr *dst;
246 struct ip6_hdr *ip6;
247 struct in6pcb *in6p;
248 u_int plen = m->m_pkthdr.len;
249 int error = 0;
250 struct ip6_pktopts opt, *optp = NULL;
251 struct ifnet *oifp = NULL;
252 int type, code; /* for ICMPv6 output statistics only */
253 int priv;
254 va_list ap;
255
256 va_start(ap, m);
257 so = va_arg(ap, struct socket *);
258 dstsock = va_arg(ap, struct sockaddr_in6 *);
259 control = va_arg(ap, struct mbuf *);
260 va_end(ap);
261
262 in6p = sotoin6pcb(so);
263
264 priv = 0;
265 {
266 struct proc *p = curproc; /* XXX */
267
268 if (p && !suser(p->p_ucred, &p->p_acflag))
269 priv = 1;
270 }
271 dst = &dstsock->sin6_addr;
272 if (control) {
273 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
274 goto bad;
275 optp = &opt;
276 } else
277 optp = in6p->in6p_outputopts;
278
279 /*
280 * For an ICMPv6 packet, we should know its type and code
281 * to update statistics.
282 */
283 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
284 struct icmp6_hdr *icmp6;
285 if (m->m_len < sizeof(struct icmp6_hdr) &&
286 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
287 error = ENOBUFS;
288 goto bad;
289 }
290 icmp6 = mtod(m, struct icmp6_hdr *);
291 type = icmp6->icmp6_type;
292 code = icmp6->icmp6_code;
293 }
294
295 M_PREPEND(m, sizeof(*ip6), M_WAIT);
296 ip6 = mtod(m, struct ip6_hdr *);
297
298 /*
299 * Next header might not be ICMP6 but use its pseudo header anyway.
300 */
301 ip6->ip6_dst = *dst;
302
303 /*
304 * If the scope of the destination is link-local, embed the interface
305 * index in the address.
306 *
307 * XXX advanced-api value overrides sin6_scope_id
308 */
309 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) ||
310 IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) {
311 struct in6_pktinfo *pi;
312
313 /*
314 * XXX Boundary check is assumed to be already done in
315 * ip6_setpktoptions().
316 */
317 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) {
318 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex);
319 oifp = ifindex2ifnet[pi->ipi6_ifindex];
320 }
321 else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
322 in6p->in6p_moptions &&
323 in6p->in6p_moptions->im6o_multicast_ifp) {
324 oifp = in6p->in6p_moptions->im6o_multicast_ifp;
325 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
326 } else if (dstsock->sin6_scope_id) {
327 /* boundary check */
328 if (dstsock->sin6_scope_id < 0
329 || if_index < dstsock->sin6_scope_id) {
330 error = ENXIO; /* XXX EINVAL? */
331 goto bad;
332 }
333 ip6->ip6_dst.s6_addr16[1]
334 = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
335 }
336 }
337
338 /*
339 * Source address selection.
340 */
341 {
342 struct in6_addr *in6a;
343
344 if ((in6a = in6_selectsrc(dstsock, optp,
345 in6p->in6p_moptions,
346 &in6p->in6p_route,
347 &in6p->in6p_laddr,
348 &error)) == 0) {
349 if (error == 0)
350 error = EADDRNOTAVAIL;
351 goto bad;
352 }
353 ip6->ip6_src = *in6a;
354 if (in6p->in6p_route.ro_rt)
355 oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
356 }
357
358 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
359 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
360 ip6->ip6_vfc |= IPV6_VERSION;
361 #if 0 /* ip6_plen will be filled in ip6_output. */
362 ip6->ip6_plen = htons((u_short)plen);
363 #endif
364 ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt;
365 ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
366
367 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
368 in6p->in6p_cksum != -1) {
369 struct mbuf *n;
370 int off;
371 u_int16_t *p;
372
373 #define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */
374
375 /* compute checksum */
376 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
377 off = offsetof(struct icmp6_hdr, icmp6_cksum);
378 else
379 off = in6p->in6p_cksum;
380 if (plen < off + 1) {
381 error = EINVAL;
382 goto bad;
383 }
384 off += sizeof(struct ip6_hdr);
385
386 n = m;
387 while (n && n->m_len <= off) {
388 off -= n->m_len;
389 n = n->m_next;
390 }
391 if (!n)
392 goto bad;
393 p = (u_int16_t *)(mtod(n, caddr_t) + off);
394 *p = 0;
395 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
396 }
397
398 #ifdef IPSEC
399 m->m_pkthdr.rcvif = (struct ifnet *)so;
400 #endif /*IPSEC*/
401
402 error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions,
403 &oifp);
404 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
405 if (oifp)
406 icmp6_ifoutstat_inc(oifp, type, code);
407 icmp6stat.icp6s_outhist[type]++;
408 }
409
410 goto freectl;
411
412 bad:
413 if (m)
414 m_freem(m);
415
416 freectl:
417 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
418 RTFREE(optp->ip6po_route.ro_rt);
419 if (control)
420 m_freem(control);
421 return(error);
422 }
423
424 /*
425 * Raw IPv6 socket option processing.
426 */
427 int
428 rip6_ctloutput(op, so, level, optname, m)
429 int op;
430 struct socket *so;
431 int level, optname;
432 struct mbuf **m;
433 {
434 int error = 0;
435
436 switch(level) {
437 case IPPROTO_IPV6:
438 switch(optname) {
439 case MRT6_INIT:
440 case MRT6_DONE:
441 case MRT6_ADD_MIF:
442 case MRT6_DEL_MIF:
443 case MRT6_ADD_MFC:
444 case MRT6_DEL_MFC:
445 case MRT6_PIM:
446 if (op == PRCO_SETOPT) {
447 error = ip6_mrouter_set(optname, so, *m);
448 if (*m)
449 (void)m_free(*m);
450 } else if (op == PRCO_GETOPT) {
451 error = ip6_mrouter_get(optname, so, m);
452 } else
453 error = EINVAL;
454 return (error);
455 }
456 return (ip6_ctloutput(op, so, level, optname, m));
457 /* NOTREACHED */
458
459 case IPPROTO_ICMPV6:
460 /*
461 * XXX: is it better to call icmp6_ctloutput() directly
462 * from protosw?
463 */
464 return(icmp6_ctloutput(op, so, level, optname, m));
465
466 default:
467 if (op == PRCO_SETOPT && *m)
468 (void)m_free(*m);
469 return(EINVAL);
470 }
471 }
472
473 extern u_long rip6_sendspace;
474 extern u_long rip6_recvspace;
475
476 int
477 rip6_usrreq(so, req, m, nam, control, p)
478 register struct socket *so;
479 int req;
480 struct mbuf *m, *nam, *control;
481 struct proc *p;
482 {
483 register struct in6pcb *in6p = sotoin6pcb(so);
484 int s;
485 int error = 0;
486 /* extern struct socket *ip6_mrouter; */ /* xxx */
487 int priv;
488
489 priv = 0;
490 if (p && !suser(p->p_ucred, &p->p_acflag))
491 priv++;
492
493 if (req == PRU_CONTROL)
494 return (in6_control(so, (u_long)m, (caddr_t)nam,
495 (struct ifnet *)control, p));
496
497 if (req == PRU_PURGEADDR) {
498 in6_purgeaddr((struct ifaddr *)nam, (struct ifnet *)control);
499 return (0);
500 }
501
502 switch (req) {
503 case PRU_ATTACH:
504 if (in6p)
505 panic("rip6_attach");
506 if (!priv) {
507 error = EACCES;
508 break;
509 }
510 s = splsoftnet();
511 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) ||
512 (error = in6_pcballoc(so, &rawin6pcb))) {
513 splx(s);
514 break;
515 }
516 splx(s);
517 in6p = sotoin6pcb(so);
518 in6p->in6p_ip6.ip6_nxt = (long)nam;
519 in6p->in6p_cksum = -1;
520 #ifdef IPSEC
521 error = ipsec_init_policy(so, &in6p->in6p_sp);
522 if (error != 0) {
523 in6_pcbdetach(in6p);
524 break;
525 }
526 #endif /*IPSEC*/
527
528 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
529 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
530 if (in6p->in6p_icmp6filt == NULL) {
531 in6_pcbdetach(in6p);
532 error = ENOMEM;
533 break;
534 }
535 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
536 break;
537
538 case PRU_DISCONNECT:
539 if ((so->so_state & SS_ISCONNECTED) == 0) {
540 error = ENOTCONN;
541 break;
542 }
543 in6p->in6p_faddr = in6addr_any;
544 so->so_state &= ~SS_ISCONNECTED; /* XXX */
545 break;
546
547 case PRU_ABORT:
548 soisdisconnected(so);
549 /* Fallthrough */
550 case PRU_DETACH:
551 if (in6p == 0)
552 panic("rip6_detach");
553 if (so == ip6_mrouter)
554 ip6_mrouter_done();
555 /* xxx: RSVP */
556 if (in6p->in6p_icmp6filt) {
557 FREE(in6p->in6p_icmp6filt, M_PCB);
558 in6p->in6p_icmp6filt = NULL;
559 }
560 in6_pcbdetach(in6p);
561 break;
562
563 case PRU_BIND:
564 {
565 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
566 struct ifaddr *ia = NULL;
567
568 if (nam->m_len != sizeof(*addr)) {
569 error = EINVAL;
570 break;
571 }
572 if ((ifnet.tqh_first == 0) ||
573 (addr->sin6_family != AF_INET6) ||
574 (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
575 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) {
576 error = EADDRNOTAVAIL;
577 break;
578 }
579 if (ia &&
580 ((struct in6_ifaddr *)ia)->ia6_flags &
581 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
582 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
583 error = EADDRNOTAVAIL;
584 break;
585 }
586 in6p->in6p_laddr = addr->sin6_addr;
587 break;
588 }
589
590 case PRU_CONNECT:
591 {
592 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
593 struct in6_addr *in6a = NULL;
594
595 if (nam->m_len != sizeof(*addr)) {
596 error = EINVAL;
597 break;
598 }
599 if (ifnet.tqh_first == 0) {
600 error = EADDRNOTAVAIL;
601 break;
602 }
603 if (addr->sin6_family != AF_INET6) {
604 error = EAFNOSUPPORT;
605 break;
606 }
607
608 /* Source address selection. XXX: need pcblookup? */
609 in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
610 in6p->in6p_moptions,
611 &in6p->in6p_route,
612 &in6p->in6p_laddr,
613 &error);
614 if (in6a == NULL) {
615 if (error == 0)
616 error = EADDRNOTAVAIL;
617 break;
618 }
619 in6p->in6p_laddr = *in6a;
620 in6p->in6p_faddr = addr->sin6_addr;
621 soisconnected(so);
622 break;
623 }
624
625 case PRU_CONNECT2:
626 error = EOPNOTSUPP;
627 break;
628
629 /*
630 * Mark the connection as being incapable of futther input.
631 */
632 case PRU_SHUTDOWN:
633 socantsendmore(so);
634 break;
635 /*
636 * Ship a packet out. The appropriate raw output
637 * routine handles any messaging necessary.
638 */
639 case PRU_SEND:
640 {
641 struct sockaddr_in6 tmp;
642 struct sockaddr_in6 *dst;
643
644 if (so->so_state & SS_ISCONNECTED) {
645 if (nam) {
646 error = EISCONN;
647 break;
648 }
649 /* XXX */
650 bzero(&tmp, sizeof(tmp));
651 tmp.sin6_family = AF_INET6;
652 tmp.sin6_len = sizeof(struct sockaddr_in6);
653 bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
654 sizeof(struct in6_addr));
655 dst = &tmp;
656 } else {
657 if (nam == NULL) {
658 error = ENOTCONN;
659 break;
660 }
661 dst = mtod(nam, struct sockaddr_in6 *);
662 }
663 error = rip6_output(m, so, dst, control);
664 m = NULL;
665 break;
666 }
667
668 case PRU_SENSE:
669 /*
670 * stat: don't bother with a blocksize
671 */
672 return(0);
673 /*
674 * Not supported.
675 */
676 case PRU_RCVOOB:
677 case PRU_RCVD:
678 case PRU_LISTEN:
679 case PRU_ACCEPT:
680 case PRU_SENDOOB:
681 error = EOPNOTSUPP;
682 break;
683
684 case PRU_SOCKADDR:
685 in6_setsockaddr(in6p, nam);
686 break;
687
688 case PRU_PEERADDR:
689 in6_setpeeraddr(in6p, nam);
690 break;
691
692 default:
693 panic("rip6_usrreq");
694 }
695 if (m != NULL)
696 m_freem(m);
697 return(error);
698 }
699