Annotation of sys/netinet6/raw_ip6.c, Revision 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