[BACK]Return to raw_ip6.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/raw_ip6.c, Revision 1.49

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

CVSweb <webmaster@jp.NetBSD.org>