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