[BACK]Return to raw_ip6.c CVS log [TXT][DIR] Up to [local] / sys / netinet6

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