raw_ip6.c revision 1.19 1 /* $NetBSD: raw_ip6.c,v 1.19 2000/02/06 12:49:49 itojun 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 <netinet/ip6.h>
86 #include <netinet6/ip6_var.h>
87 #include <netinet6/ip6_mroute.h>
88 #include <netinet/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_PURGEIF) {
498 in6_purgeif((struct ifnet *)control);
499 in6_pcbpurgeif(&rawin6pcb, (struct ifnet *)control);
500 return (0);
501 }
502
503 switch (req) {
504 case PRU_ATTACH:
505 if (in6p)
506 panic("rip6_attach");
507 if (!priv) {
508 error = EACCES;
509 break;
510 }
511 s = splsoftnet();
512 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) ||
513 (error = in6_pcballoc(so, &rawin6pcb))) {
514 splx(s);
515 break;
516 }
517 splx(s);
518 in6p = sotoin6pcb(so);
519 in6p->in6p_ip6.ip6_nxt = (long)nam;
520 in6p->in6p_cksum = -1;
521 #ifdef IPSEC
522 error = ipsec_init_policy(so, &in6p->in6p_sp);
523 if (error != 0) {
524 in6_pcbdetach(in6p);
525 break;
526 }
527 #endif /*IPSEC*/
528
529 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
530 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
531 if (in6p->in6p_icmp6filt == NULL) {
532 in6_pcbdetach(in6p);
533 error = ENOMEM;
534 break;
535 }
536 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
537 break;
538
539 case PRU_DISCONNECT:
540 if ((so->so_state & SS_ISCONNECTED) == 0) {
541 error = ENOTCONN;
542 break;
543 }
544 in6p->in6p_faddr = in6addr_any;
545 so->so_state &= ~SS_ISCONNECTED; /* XXX */
546 break;
547
548 case PRU_ABORT:
549 soisdisconnected(so);
550 /* Fallthrough */
551 case PRU_DETACH:
552 if (in6p == 0)
553 panic("rip6_detach");
554 if (so == ip6_mrouter)
555 ip6_mrouter_done();
556 /* xxx: RSVP */
557 if (in6p->in6p_icmp6filt) {
558 FREE(in6p->in6p_icmp6filt, M_PCB);
559 in6p->in6p_icmp6filt = NULL;
560 }
561 in6_pcbdetach(in6p);
562 break;
563
564 case PRU_BIND:
565 {
566 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
567 struct ifaddr *ia = NULL;
568
569 if (nam->m_len != sizeof(*addr)) {
570 error = EINVAL;
571 break;
572 }
573 if ((ifnet.tqh_first == 0) ||
574 (addr->sin6_family != AF_INET6) ||
575 (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
576 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) {
577 error = EADDRNOTAVAIL;
578 break;
579 }
580 if (ia &&
581 ((struct in6_ifaddr *)ia)->ia6_flags &
582 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
583 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
584 error = EADDRNOTAVAIL;
585 break;
586 }
587 in6p->in6p_laddr = addr->sin6_addr;
588 break;
589 }
590
591 case PRU_CONNECT:
592 {
593 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
594 struct in6_addr *in6a = NULL;
595
596 if (nam->m_len != sizeof(*addr)) {
597 error = EINVAL;
598 break;
599 }
600 if (ifnet.tqh_first == 0) {
601 error = EADDRNOTAVAIL;
602 break;
603 }
604 if (addr->sin6_family != AF_INET6) {
605 error = EAFNOSUPPORT;
606 break;
607 }
608
609 /* Source address selection. XXX: need pcblookup? */
610 in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
611 in6p->in6p_moptions,
612 &in6p->in6p_route,
613 &in6p->in6p_laddr,
614 &error);
615 if (in6a == NULL) {
616 if (error == 0)
617 error = EADDRNOTAVAIL;
618 break;
619 }
620 in6p->in6p_laddr = *in6a;
621 in6p->in6p_faddr = addr->sin6_addr;
622 soisconnected(so);
623 break;
624 }
625
626 case PRU_CONNECT2:
627 error = EOPNOTSUPP;
628 break;
629
630 /*
631 * Mark the connection as being incapable of futther input.
632 */
633 case PRU_SHUTDOWN:
634 socantsendmore(so);
635 break;
636 /*
637 * Ship a packet out. The appropriate raw output
638 * routine handles any messaging necessary.
639 */
640 case PRU_SEND:
641 {
642 struct sockaddr_in6 tmp;
643 struct sockaddr_in6 *dst;
644
645 if (so->so_state & SS_ISCONNECTED) {
646 if (nam) {
647 error = EISCONN;
648 break;
649 }
650 /* XXX */
651 bzero(&tmp, sizeof(tmp));
652 tmp.sin6_family = AF_INET6;
653 tmp.sin6_len = sizeof(struct sockaddr_in6);
654 bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
655 sizeof(struct in6_addr));
656 dst = &tmp;
657 } else {
658 if (nam == NULL) {
659 error = ENOTCONN;
660 break;
661 }
662 dst = mtod(nam, struct sockaddr_in6 *);
663 }
664 error = rip6_output(m, so, dst, control);
665 m = NULL;
666 break;
667 }
668
669 case PRU_SENSE:
670 /*
671 * stat: don't bother with a blocksize
672 */
673 return(0);
674 /*
675 * Not supported.
676 */
677 case PRU_RCVOOB:
678 case PRU_RCVD:
679 case PRU_LISTEN:
680 case PRU_ACCEPT:
681 case PRU_SENDOOB:
682 error = EOPNOTSUPP;
683 break;
684
685 case PRU_SOCKADDR:
686 in6_setsockaddr(in6p, nam);
687 break;
688
689 case PRU_PEERADDR:
690 in6_setpeeraddr(in6p, nam);
691 break;
692
693 default:
694 panic("rip6_usrreq");
695 }
696 if (m != NULL)
697 m_freem(m);
698 return(error);
699 }
700