[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.60

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

CVSweb <webmaster@jp.NetBSD.org>