Annotation of sys/netinet6/raw_ip6.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: raw_ip6.c,v 1.33 2007/06/01 00:52:39 henning Exp $ */
2: /* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 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. Neither the name of the University nor the names of its contributors
46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: *
61: * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
62: */
63:
64: #include <sys/param.h>
65: #include <sys/malloc.h>
66: #include <sys/mbuf.h>
67: #include <sys/socket.h>
68: #include <sys/protosw.h>
69: #include <sys/socketvar.h>
70: #include <sys/errno.h>
71: #include <sys/systm.h>
72:
73: #include <net/if.h>
74: #include <net/route.h>
75: #include <net/if_types.h>
76:
77: #include <netinet/in.h>
78: #include <netinet/in_var.h>
79: #include <netinet/ip6.h>
80: #include <netinet6/ip6_var.h>
81: #ifdef MROUTING
82: #include <netinet6/ip6_mroute.h>
83: #endif
84: #include <netinet/icmp6.h>
85: #include <netinet/in_systm.h>
86: #include <netinet/ip.h>
87: #include <netinet/in_pcb.h>
88: #include <netinet6/nd6.h>
89: #include <netinet6/ip6protosw.h>
90: #ifdef ENABLE_DEFAULT_SCOPE
91: #include <netinet6/scope6_var.h>
92: #endif
93: #include <netinet6/raw_ip6.h>
94:
95: #include <sys/stdarg.h>
96:
97: #include "faith.h"
98:
99: /*
100: * Raw interface to IP6 protocol.
101: */
102: /* inpcb members */
103: #define in6pcb inpcb
104: #define in6p_laddr inp_laddr6
105: #define in6p_faddr inp_faddr6
106: #define in6p_icmp6filt inp_icmp6filt
107: #define in6p_route inp_route6
108: #define in6p_socket inp_socket
109: #define in6p_flags inp_flags
110: #define in6p_moptions inp_moptions6
111: #define in6p_outputopts inp_outputopts6
112: #define in6p_ip6 inp_ipv6
113: #define in6p_flowinfo inp_flowinfo
114: #define in6p_sp inp_sp
115: #define in6p_next inp_next
116: #define in6p_prev inp_prev
117: /* macro names */
118: #define sotoin6pcb sotoinpcb
119: /* function names */
120: #define in6_pcbdetach in_pcbdetach
121: #define in6_rtchange in_rtchange
122:
123: struct inpcbtable rawin6pcbtable;
124: #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
125:
126: struct rip6stat rip6stat;
127:
128: /*
129: * Initialize raw connection block queue.
130: */
131: void
132: rip6_init()
133: {
134:
135: in_pcbinit(&rawin6pcbtable, 1);
136: }
137:
138: /*
139: * Setup generic address and protocol structures
140: * for raw_input routine, then pass them along with
141: * mbuf chain.
142: */
143: int
144: rip6_input(mp, offp, proto)
145: struct mbuf **mp;
146: int *offp, proto;
147: {
148: struct mbuf *m = *mp;
149: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
150: struct in6pcb *in6p;
151: struct in6pcb *last = NULL;
152: struct sockaddr_in6 rip6src;
153: struct mbuf *opts = NULL;
154:
155: rip6stat.rip6s_ipackets++;
156:
157: #if defined(NFAITH) && 0 < NFAITH
158: if (m->m_pkthdr.rcvif) {
159: if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
160: /* send icmp6 host unreach? */
161: m_freem(m);
162: return IPPROTO_DONE;
163: }
164: }
165: #endif
166:
167: /* Be proactive about malicious use of IPv4 mapped address */
168: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
169: IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
170: /* XXX stat */
171: m_freem(m);
172: return IPPROTO_DONE;
173: }
174:
175: bzero(&rip6src, sizeof(rip6src));
176: rip6src.sin6_len = sizeof(struct sockaddr_in6);
177: rip6src.sin6_family = AF_INET6;
178: /* KAME hack: recover scopeid */
179: (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
180:
181: CIRCLEQ_FOREACH(in6p, &rawin6pcbtable.inpt_queue, inp_queue) {
182: if (!(in6p->in6p_flags & INP_IPV6))
183: continue;
184: if (in6p->in6p_ip6.ip6_nxt &&
185: in6p->in6p_ip6.ip6_nxt != proto)
186: continue;
187: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
188: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
189: continue;
190: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
191: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
192: continue;
193: if (in6p->in6p_cksum != -1) {
194: rip6stat.rip6s_isum++;
195: if (in6_cksum(m, proto, *offp,
196: m->m_pkthdr.len - *offp)) {
197: rip6stat.rip6s_badsum++;
198: continue;
199: }
200: }
201: if (last) {
202: struct mbuf *n;
203: if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
204: if (last->in6p_flags & IN6P_CONTROLOPTS)
205: ip6_savecontrol(last, n, &opts);
206: /* strip intermediate headers */
207: m_adj(n, *offp);
208: if (sbappendaddr(&last->in6p_socket->so_rcv,
209: (struct sockaddr *)&rip6src, n, opts) == 0) {
210: /* should notify about lost packet */
211: m_freem(n);
212: if (opts)
213: m_freem(opts);
214: rip6stat.rip6s_fullsock++;
215: } else
216: sorwakeup(last->in6p_socket);
217: opts = NULL;
218: }
219: }
220: last = in6p;
221: }
222: if (last) {
223: if (last->in6p_flags & IN6P_CONTROLOPTS)
224: ip6_savecontrol(last, m, &opts);
225: /* strip intermediate headers */
226: m_adj(m, *offp);
227: if (sbappendaddr(&last->in6p_socket->so_rcv,
228: (struct sockaddr *)&rip6src, m, opts) == 0) {
229: m_freem(m);
230: if (opts)
231: m_freem(opts);
232: rip6stat.rip6s_fullsock++;
233: } else
234: sorwakeup(last->in6p_socket);
235: } else {
236: rip6stat.rip6s_nosock++;
237: if (m->m_flags & M_MCAST)
238: rip6stat.rip6s_nosockmcast++;
239: if (proto == IPPROTO_NONE)
240: m_freem(m);
241: else {
242: u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
243: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown);
244: icmp6_error(m, ICMP6_PARAM_PROB,
245: ICMP6_PARAMPROB_NEXTHEADER,
246: prvnxtp - mtod(m, u_int8_t *));
247: }
248: ip6stat.ip6s_delivered--;
249: }
250: return IPPROTO_DONE;
251: }
252:
253: void
254: rip6_ctlinput(cmd, sa, d)
255: int cmd;
256: struct sockaddr *sa;
257: void *d;
258: {
259: struct ip6_hdr *ip6;
260: struct mbuf *m;
261: int off;
262: struct ip6ctlparam *ip6cp = NULL;
263: const struct sockaddr_in6 *sa6_src = NULL;
264: void *cmdarg;
265: void (*notify)(struct in6pcb *, int) = in6_rtchange;
266: int nxt;
267:
268: if (sa->sa_family != AF_INET6 ||
269: sa->sa_len != sizeof(struct sockaddr_in6))
270: return;
271:
272: if ((unsigned)cmd >= PRC_NCMDS)
273: return;
274: if (PRC_IS_REDIRECT(cmd))
275: notify = in6_rtchange, d = NULL;
276: else if (cmd == PRC_HOSTDEAD)
277: d = NULL;
278: else if (cmd == PRC_MSGSIZE)
279: ; /* special code is present, see below */
280: else if (inet6ctlerrmap[cmd] == 0)
281: return;
282:
283: /* if the parameter is from icmp6, decode it. */
284: if (d != NULL) {
285: ip6cp = (struct ip6ctlparam *)d;
286: m = ip6cp->ip6c_m;
287: ip6 = ip6cp->ip6c_ip6;
288: off = ip6cp->ip6c_off;
289: cmdarg = ip6cp->ip6c_cmdarg;
290: sa6_src = ip6cp->ip6c_src;
291: nxt = ip6cp->ip6c_nxt;
292: } else {
293: m = NULL;
294: ip6 = NULL;
295: cmdarg = NULL;
296: sa6_src = &sa6_any;
297: nxt = -1;
298: }
299:
300: if (ip6 && cmd == PRC_MSGSIZE) {
301: struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
302: int valid = 0;
303: struct in6pcb *in6p;
304:
305: /*
306: * Check to see if we have a valid raw IPv6 socket
307: * corresponding to the address in the ICMPv6 message
308: * payload, and the protocol (ip6_nxt) meets the socket.
309: * XXX chase extension headers, or pass final nxt value
310: * from icmp6_notify_error()
311: */
312: in6p = NULL;
313: in6p = in6_pcbhashlookup(&rawin6pcbtable, &sa6->sin6_addr, 0,
314: (struct in6_addr *)&sa6_src->sin6_addr, 0);
315: #if 0
316: if (!in6p) {
317: /*
318: * As the use of sendto(2) is fairly popular,
319: * we may want to allow non-connected pcb too.
320: * But it could be too weak against attacks...
321: * We should at least check if the local
322: * address (= s) is really ours.
323: */
324: in6p = in_pcblookup(&rawin6pcbtable, &sa6->sin6_addr, 0,
325: (struct in6_addr *)&sa6_src->sin6_addr, 0,
326: INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
327: }
328: #endif
329:
330: if (in6p && in6p->in6p_ip6.ip6_nxt &&
331: in6p->in6p_ip6.ip6_nxt == nxt)
332: valid++;
333:
334: /*
335: * Depending on the value of "valid" and routing table
336: * size (mtudisc_{hi,lo}wat), we will:
337: * - recalculate the new MTU and create the
338: * corresponding routing entry, or
339: * - ignore the MTU change notification.
340: */
341: icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
342:
343: /*
344: * regardless of if we called icmp6_mtudisc_update(),
345: * we need to call in6_pcbnotify(), to notify path
346: * MTU change to the userland (2292bis-02), because
347: * some unconnected sockets may share the same
348: * destination and want to know the path MTU.
349: */
350: }
351:
352: (void) in6_pcbnotify(&rawin6pcbtable, sa, 0,
353: (struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
354: }
355:
356: /*
357: * Generate IPv6 header and pass packet to ip6_output.
358: * Tack on options user may have setup with control call.
359: */
360: int
361: rip6_output(struct mbuf *m, ...)
362: {
363: struct socket *so;
364: struct sockaddr_in6 *dstsock;
365: struct mbuf *control;
366: struct in6_addr *dst;
367: struct ip6_hdr *ip6;
368: struct in6pcb *in6p;
369: u_int plen = m->m_pkthdr.len;
370: int error = 0;
371: struct ip6_pktopts opt, *optp = NULL, *origoptp;
372: struct ifnet *oifp = NULL;
373: int type, code; /* for ICMPv6 output statistics only */
374: int priv = 0;
375: va_list ap;
376: int flags;
377:
378: va_start(ap, m);
379: so = va_arg(ap, struct socket *);
380: dstsock = va_arg(ap, struct sockaddr_in6 *);
381: control = va_arg(ap, struct mbuf *);
382: va_end(ap);
383:
384: in6p = sotoin6pcb(so);
385:
386: priv = 0;
387: if ((so->so_state & SS_PRIV) != 0)
388: priv = 1;
389: dst = &dstsock->sin6_addr;
390: if (control) {
391: if ((error = ip6_setpktopts(control, &opt,
392: in6p->in6p_outputopts,
393: priv, so->so_proto->pr_protocol)) != 0)
394: goto bad;
395: optp = &opt;
396: } else
397: optp = in6p->in6p_outputopts;
398:
399: /*
400: * For an ICMPv6 packet, we should know its type and code
401: * to update statistics.
402: */
403: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
404: struct icmp6_hdr *icmp6;
405: if (m->m_len < sizeof(struct icmp6_hdr) &&
406: (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
407: error = ENOBUFS;
408: goto bad;
409: }
410: icmp6 = mtod(m, struct icmp6_hdr *);
411: type = icmp6->icmp6_type;
412: code = icmp6->icmp6_code;
413: }
414:
415: M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
416: if (!m) {
417: error = ENOBUFS;
418: goto bad;
419: }
420: ip6 = mtod(m, struct ip6_hdr *);
421:
422: /*
423: * Next header might not be ICMP6 but use its pseudo header anyway.
424: */
425: ip6->ip6_dst = *dst;
426:
427: /* KAME hack: embed scopeid */
428: origoptp = in6p->in6p_outputopts;
429: in6p->in6p_outputopts = optp;
430: if (in6_embedscope(&ip6->ip6_dst, dstsock, in6p, &oifp) != 0) {
431: error = EINVAL;
432: goto bad;
433: }
434: in6p->in6p_outputopts = origoptp;
435:
436: /*
437: * Source address selection.
438: */
439: {
440: struct in6_addr *in6a;
441:
442: if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
443: &in6p->in6p_route, &in6p->in6p_laddr, &error)) == 0) {
444: if (error == 0)
445: error = EADDRNOTAVAIL;
446: goto bad;
447: }
448: ip6->ip6_src = *in6a;
449: if (in6p->in6p_route.ro_rt) {
450: /* what if oifp contradicts ? */
451: oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
452: }
453: }
454:
455: ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
456: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
457: ip6->ip6_vfc |= IPV6_VERSION;
458: #if 0 /* ip6_plen will be filled in ip6_output. */
459: ip6->ip6_plen = htons((u_short)plen);
460: #endif
461: ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt;
462: ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
463:
464: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
465: in6p->in6p_cksum != -1) {
466: struct mbuf *n;
467: int off;
468: u_int16_t *sump;
469: int sumoff;
470:
471: /* compute checksum */
472: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
473: off = offsetof(struct icmp6_hdr, icmp6_cksum);
474: else
475: off = in6p->in6p_cksum;
476: if (plen < off + 1) {
477: error = EINVAL;
478: goto bad;
479: }
480: off += sizeof(struct ip6_hdr);
481:
482: n = m_pulldown(m, off, sizeof(*sump), &sumoff);
483: if (n == NULL) {
484: m = NULL;
485: error = ENOBUFS;
486: goto bad;
487: }
488: sump = (u_int16_t *)(mtod(n, caddr_t) + sumoff);
489: *sump = 0;
490: *sump = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
491: }
492:
493: flags = 0;
494: if (in6p->in6p_flags & IN6P_MINMTU)
495: flags |= IPV6_MINMTU;
496:
497: error = ip6_output(m, optp, &in6p->in6p_route, flags,
498: in6p->in6p_moptions, &oifp, in6p);
499: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
500: if (oifp)
501: icmp6_ifoutstat_inc(oifp, type, code);
502: icmp6stat.icp6s_outhist[type]++;
503: } else
504: rip6stat.rip6s_opackets++;
505:
506: goto freectl;
507:
508: bad:
509: if (m)
510: m_freem(m);
511:
512: freectl:
513: if (control) {
514: ip6_clearpktopts(&opt, -1);
515: m_freem(control);
516: }
517: return (error);
518: }
519:
520: /*
521: * Raw IPv6 socket option processing.
522: */
523: int
524: rip6_ctloutput(op, so, level, optname, mp)
525: int op;
526: struct socket *so;
527: int level, optname;
528: struct mbuf **mp;
529: {
530: #ifdef MROUTING
531: int error = 0;
532: #endif
533:
534: switch (level) {
535: case IPPROTO_IPV6:
536: switch (optname) {
537: #ifdef MROUTING
538: case MRT6_INIT:
539: case MRT6_DONE:
540: case MRT6_ADD_MIF:
541: case MRT6_DEL_MIF:
542: case MRT6_ADD_MFC:
543: case MRT6_DEL_MFC:
544: case MRT6_PIM:
545: if (op == PRCO_SETOPT) {
546: error = ip6_mrouter_set(optname, so, *mp);
547: if (*mp)
548: (void)m_free(*mp);
549: } else if (op == PRCO_GETOPT)
550: error = ip6_mrouter_get(optname, so, mp);
551: else
552: error = EINVAL;
553: return (error);
554: #endif
555: case IPV6_CHECKSUM:
556: return (ip6_raw_ctloutput(op, so, level, optname, mp));
557: default:
558: return (ip6_ctloutput(op, so, level, optname, mp));
559: }
560:
561: case IPPROTO_ICMPV6:
562: /*
563: * XXX: is it better to call icmp6_ctloutput() directly
564: * from protosw?
565: */
566: return (icmp6_ctloutput(op, so, level, optname, mp));
567:
568: default:
569: if (op == PRCO_SETOPT && *mp)
570: m_free(*mp);
571: return EINVAL;
572: }
573: }
574:
575: extern u_long rip6_sendspace;
576: extern u_long rip6_recvspace;
577:
578: int
579: rip6_usrreq(so, req, m, nam, control, p)
580: struct socket *so;
581: int req;
582: struct mbuf *m, *nam, *control;
583: struct proc *p;
584: {
585: struct in6pcb *in6p = sotoin6pcb(so);
586: int s;
587: int error = 0;
588: int priv;
589:
590: priv = 0;
591: if ((so->so_state & SS_PRIV) != 0)
592: priv++;
593:
594: if (req == PRU_CONTROL)
595: return (in6_control(so, (u_long)m, (caddr_t)nam,
596: (struct ifnet *)control, p));
597:
598: switch (req) {
599: case PRU_ATTACH:
600: if (in6p)
601: panic("rip6_attach");
602: if (!priv) {
603: error = EACCES;
604: break;
605: }
606: s = splsoftnet();
607: if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) != 0) {
608: splx(s);
609: break;
610: }
611: if ((error = in_pcballoc(so, &rawin6pcbtable)) != 0)
612: {
613: splx(s);
614: break;
615: }
616: splx(s);
617: in6p = sotoin6pcb(so);
618: in6p->in6p_ip6.ip6_nxt = (long)nam;
619: in6p->in6p_cksum = -1;
620:
621: MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
622: sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
623: if (in6p->in6p_icmp6filt == NULL) {
624: in6_pcbdetach(in6p);
625: error = ENOMEM;
626: break;
627: }
628: ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
629: break;
630:
631: case PRU_DISCONNECT:
632: if ((so->so_state & SS_ISCONNECTED) == 0) {
633: error = ENOTCONN;
634: break;
635: }
636: in6p->in6p_faddr = in6addr_any;
637: so->so_state &= ~SS_ISCONNECTED; /* XXX */
638: break;
639:
640: case PRU_ABORT:
641: soisdisconnected(so);
642: /* FALLTHROUGH */
643: case PRU_DETACH:
644: if (in6p == 0)
645: panic("rip6_detach");
646: #ifdef MROUTING
647: if (so == ip6_mrouter)
648: ip6_mrouter_done();
649: #endif
650: /* xxx: RSVP */
651: if (in6p->in6p_icmp6filt) {
652: FREE(in6p->in6p_icmp6filt, M_PCB);
653: in6p->in6p_icmp6filt = NULL;
654: }
655: in6_pcbdetach(in6p);
656: break;
657:
658: case PRU_BIND:
659: {
660: struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
661: struct ifaddr *ia = NULL;
662:
663: if (nam->m_len != sizeof(*addr)) {
664: error = EINVAL;
665: break;
666: }
667: if (TAILQ_EMPTY(&ifnet) || (addr->sin6_family != AF_INET6)) {
668: error = EADDRNOTAVAIL;
669: break;
670: }
671: #ifdef ENABLE_DEFAULT_SCOPE
672: if (addr->sin6_scope_id == 0) /* not change if specified */
673: addr->sin6_scope_id =
674: scope6_addr2default(&addr->sin6_addr);
675: #endif
676: /*
677: * we don't support mapped address here, it would confuse
678: * users so reject it
679: */
680: if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
681: error = EADDRNOTAVAIL;
682: break;
683: }
684: /*
685: * Currently, ifa_ifwithaddr tends to fail for a link-local
686: * address, since it implicitly expects that the link ID
687: * for the address is embedded in the sin6_addr part.
688: * For now, we'd rather keep this "as is". We'll eventually fix
689: * this in a more natural way.
690: */
691: if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
692: (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) {
693: error = EADDRNOTAVAIL;
694: break;
695: }
696: if (ia && ((struct in6_ifaddr *)ia)->ia6_flags &
697: (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
698: IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
699: error = EADDRNOTAVAIL;
700: break;
701: }
702: in6p->in6p_laddr = addr->sin6_addr;
703: break;
704: }
705:
706: case PRU_CONNECT:
707: {
708: struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
709: struct in6_addr *in6a = NULL;
710: #ifdef ENABLE_DEFAULT_SCOPE
711: struct sockaddr_in6 sin6;
712: #endif
713:
714: if (nam->m_len != sizeof(*addr)) {
715: error = EINVAL;
716: break;
717: }
718: if (TAILQ_EMPTY(&ifnet)) {
719: error = EADDRNOTAVAIL;
720: break;
721: }
722: if (addr->sin6_family != AF_INET6) {
723: error = EAFNOSUPPORT;
724: break;
725: }
726:
727: #ifdef ENABLE_DEFAULT_SCOPE
728: if (addr->sin6_scope_id == 0) {
729: /* protect *addr */
730: sin6 = *addr;
731: addr = &sin6;
732: addr->sin6_scope_id =
733: scope6_addr2default(&addr->sin6_addr);
734: }
735: #endif
736:
737: /* Source address selection. XXX: need pcblookup? */
738: in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
739: in6p->in6p_moptions, &in6p->in6p_route,
740: &in6p->in6p_laddr, &error);
741: if (in6a == NULL) {
742: if (error == 0)
743: error = EADDRNOTAVAIL;
744: break;
745: }
746: in6p->in6p_laddr = *in6a;
747: in6p->in6p_faddr = addr->sin6_addr;
748: soisconnected(so);
749: break;
750: }
751:
752: case PRU_CONNECT2:
753: error = EOPNOTSUPP;
754: break;
755:
756: /*
757: * Mark the connection as being incapable of futther input.
758: */
759: case PRU_SHUTDOWN:
760: socantsendmore(so);
761: break;
762: /*
763: * Ship a packet out. The appropriate raw output
764: * routine handles any messaging necessary.
765: */
766: case PRU_SEND:
767: {
768: struct sockaddr_in6 tmp;
769: struct sockaddr_in6 *dst;
770:
771: /* always copy sockaddr to avoid overwrites */
772: if (so->so_state & SS_ISCONNECTED) {
773: if (nam) {
774: error = EISCONN;
775: break;
776: }
777: /* XXX */
778: bzero(&tmp, sizeof(tmp));
779: tmp.sin6_family = AF_INET6;
780: tmp.sin6_len = sizeof(struct sockaddr_in6);
781: bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
782: sizeof(struct in6_addr));
783: dst = &tmp;
784: } else {
785: if (nam == NULL) {
786: error = ENOTCONN;
787: break;
788: }
789: if (nam->m_len != sizeof(tmp)) {
790: error = EINVAL;
791: break;
792: }
793:
794: tmp = *mtod(nam, struct sockaddr_in6 *);
795: dst = &tmp;
796:
797: if (dst->sin6_family != AF_INET6) {
798: error = EAFNOSUPPORT;
799: break;
800: }
801: }
802: #ifdef ENABLE_DEFAULT_SCOPE
803: if (dst->sin6_scope_id == 0) {
804: dst->sin6_scope_id =
805: scope6_addr2default(&dst->sin6_addr);
806: }
807: #endif
808: error = rip6_output(m, so, dst, control);
809: m = NULL;
810: break;
811: }
812:
813: case PRU_SENSE:
814: /*
815: * stat: don't bother with a blocksize
816: */
817: return (0);
818: /*
819: * Not supported.
820: */
821: case PRU_RCVOOB:
822: case PRU_RCVD:
823: case PRU_LISTEN:
824: case PRU_ACCEPT:
825: case PRU_SENDOOB:
826: error = EOPNOTSUPP;
827: break;
828:
829: case PRU_SOCKADDR:
830: in6_setsockaddr(in6p, nam);
831: break;
832:
833: case PRU_PEERADDR:
834: in6_setpeeraddr(in6p, nam);
835: break;
836:
837: default:
838: panic("rip6_usrreq");
839: }
840: if (m != NULL)
841: m_freem(m);
842: return (error);
843: }
CVSweb