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

1.108   ! dyoung      1: /*     $NetBSD: raw_ip6.c,v 1.107 2010/07/08 01:22:28 dyoung 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.108   ! dyoung     65: __KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.107 2010/07/08 01:22:28 dyoung Exp $");
1.6       thorpej    66:
                     67: #include "opt_ipsec.h"
1.2       itojun     68:
                     69: #include <sys/param.h>
1.69      atatat     70: #include <sys/sysctl.h>
1.2       itojun     71: #include <sys/malloc.h>
                     72: #include <sys/mbuf.h>
                     73: #include <sys/socket.h>
                     74: #include <sys/protosw.h>
                     75: #include <sys/socketvar.h>
                     76: #include <sys/errno.h>
                     77: #include <sys/systm.h>
                     78: #include <sys/proc.h>
1.77      elad       79: #include <sys/kauth.h>
1.2       itojun     80:
                     81: #include <net/if.h>
                     82: #include <net/route.h>
                     83: #include <net/if_types.h>
1.97      thorpej    84: #include <net/net_stats.h>
1.2       itojun     85:
                     86: #include <netinet/in.h>
                     87: #include <netinet/in_var.h>
1.19      itojun     88: #include <netinet/ip6.h>
1.2       itojun     89: #include <netinet6/ip6_var.h>
1.94      thorpej    90: #include <netinet6/ip6_private.h>
1.2       itojun     91: #include <netinet6/ip6_mroute.h>
1.19      itojun     92: #include <netinet/icmp6.h>
1.94      thorpej    93: #include <netinet6/icmp6_private.h>
1.2       itojun     94: #include <netinet6/in6_pcb.h>
                     95: #include <netinet6/nd6.h>
1.20      itojun     96: #include <netinet6/ip6protosw.h>
1.24      itojun     97: #include <netinet6/scope6_var.h>
1.37      itojun     98: #include <netinet6/raw_ip6.h>
1.2       itojun     99:
                    100: #ifdef IPSEC
                    101: #include <netinet6/ipsec.h>
1.97      thorpej   102: #include <netinet6/ipsec_private.h>
1.38      itojun    103: #endif /* IPSEC */
1.2       itojun    104:
1.81      degroote  105: #ifdef FAST_IPSEC
                    106: #include <netipsec/ipsec.h>
1.97      thorpej   107: #include <netipsec/ipsec_var.h>
                    108: #include <netipsec/ipsec_private.h>
1.81      degroote  109: #include <netipsec/ipsec6.h>
                    110: #endif
                    111:
1.2       itojun    112: #include "faith.h"
1.32      itojun    113: #if defined(NFAITH) && 0 < NFAITH
                    114: #include <net/if_faith.h>
                    115: #endif
1.2       itojun    116:
1.59      itojun    117: extern struct inpcbtable rawcbtable;
                    118: struct inpcbtable raw6cbtable;
1.2       itojun    119: #define ifatoia6(ifa)  ((struct in6_ifaddr *)(ifa))
                    120:
                    121: /*
                    122:  * Raw interface to IP6 protocol.
                    123:  */
                    124:
1.95      thorpej   125: static percpu_t *rip6stat_percpu;
                    126:
1.97      thorpej   127: #define        RIP6_STATINC(x)         _NET_STATINC(rip6stat_percpu, x)
1.37      itojun    128:
1.105     pooka     129: static void sysctl_net_inet6_raw6_setup(struct sysctllog **);
                    130:
1.2       itojun    131: /*
                    132:  * Initialize raw connection block queue.
                    133:  */
                    134: void
1.103     cegger    135: rip6_init(void)
1.2       itojun    136: {
1.47      itojun    137:
1.105     pooka     138:        sysctl_net_inet6_raw6_setup(NULL);
1.59      itojun    139:        in6_pcbinit(&raw6cbtable, 1, 1);
1.95      thorpej   140:
                    141:        rip6stat_percpu = percpu_alloc(sizeof(uint64_t) * RIP6_NSTATS);
1.2       itojun    142: }
                    143:
                    144: /*
                    145:  * Setup generic address and protocol structures
                    146:  * for raw_input routine, then pass them along with
                    147:  * mbuf chain.
                    148:  */
                    149: int
1.85      christos  150: rip6_input(struct mbuf **mp, int *offp, int proto)
1.2       itojun    151: {
                    152:        struct mbuf *m = *mp;
1.27      itojun    153:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.59      itojun    154:        struct inpcb_hdr *inph;
1.27      itojun    155:        struct in6pcb *in6p;
1.2       itojun    156:        struct in6pcb *last = NULL;
                    157:        struct sockaddr_in6 rip6src;
                    158:        struct mbuf *opts = NULL;
                    159:
1.95      thorpej   160:        RIP6_STATINC(RIP6_STAT_IPACKETS);
1.37      itojun    161:
1.2       itojun    162: #if defined(NFAITH) && 0 < NFAITH
1.32      itojun    163:        if (faithprefix(&ip6->ip6_dst)) {
                    164:                /* send icmp6 host unreach? */
                    165:                m_freem(m);
                    166:                return IPPROTO_DONE;
1.2       itojun    167:        }
                    168: #endif
1.14      itojun    169:
                    170:        /* Be proactive about malicious use of IPv4 mapped address */
                    171:        if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
                    172:            IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
                    173:                /* XXX stat */
                    174:                m_freem(m);
                    175:                return IPPROTO_DONE;
                    176:        }
                    177:
1.89      dyoung    178:        sockaddr_in6_init(&rip6src, &ip6->ip6_src, 0, 0, 0);
1.75      rpaulo    179:        if (sa6_recoverscope(&rip6src) != 0) {
                    180:                /* XXX: should be impossible. */
                    181:                m_freem(m);
                    182:                return IPPROTO_DONE;
                    183:        }
1.2       itojun    184:
1.59      itojun    185:        CIRCLEQ_FOREACH(inph, &raw6cbtable.inpt_queue, inph_queue) {
                    186:                in6p = (struct in6pcb *)inph;
                    187:                if (in6p->in6p_af != AF_INET6)
                    188:                        continue;
1.2       itojun    189:                if (in6p->in6p_ip6.ip6_nxt &&
                    190:                    in6p->in6p_ip6.ip6_nxt != proto)
                    191:                        continue;
1.12      itojun    192:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
1.37      itojun    193:                    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
1.2       itojun    194:                        continue;
1.12      itojun    195:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
1.37      itojun    196:                    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
1.2       itojun    197:                        continue;
1.37      itojun    198:                if (in6p->in6p_cksum != -1) {
1.95      thorpej   199:                        RIP6_STATINC(RIP6_STAT_ISUM);
1.64      itojun    200:                        if (in6_cksum(m, proto, *offp,
1.37      itojun    201:                            m->m_pkthdr.len - *offp)) {
1.95      thorpej   202:                                RIP6_STATINC(RIP6_STAT_BADSUM);
1.37      itojun    203:                                continue;
                    204:                        }
1.2       itojun    205:                }
                    206:                if (last) {
                    207:                        struct  mbuf *n;
1.30      itojun    208:
                    209: #ifdef IPSEC
                    210:                        /*
                    211:                         * Check AH/ESP integrity.
                    212:                         */
                    213:                        if (ipsec6_in_reject(m, last)) {
1.97      thorpej   214:                                IPSEC6_STATINC(IPSEC_STAT_IN_INVAL);
1.30      itojun    215:                                /* do not inject data into pcb */
                    216:                        } else
1.38      itojun    217: #endif /* IPSEC */
1.81      degroote  218: #ifdef FAST_IPSEC
                    219:                        /*
                    220:                         * Check AH/ESP integrity
                    221:                         */
                    222:                        if (!ipsec6_in_reject(m,last))
                    223: #endif /* FAST_IPSEC */
1.2       itojun    224:                        if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
                    225:                                if (last->in6p_flags & IN6P_CONTROLOPTS)
                    226:                                        ip6_savecontrol(last, &opts, ip6, n);
                    227:                                /* strip intermediate headers */
                    228:                                m_adj(n, *offp);
                    229:                                if (sbappendaddr(&last->in6p_socket->so_rcv,
1.43      itojun    230:                                    (struct sockaddr *)&rip6src, n, opts) == 0) {
1.2       itojun    231:                                        /* should notify about lost packet */
                    232:                                        m_freem(n);
                    233:                                        if (opts)
                    234:                                                m_freem(opts);
1.95      thorpej   235:                                        RIP6_STATINC(RIP6_STAT_FULLSOCK);
1.2       itojun    236:                                } else
                    237:                                        sorwakeup(last->in6p_socket);
                    238:                                opts = NULL;
                    239:                        }
                    240:                }
                    241:                last = in6p;
                    242:        }
1.30      itojun    243: #ifdef IPSEC
                    244:        /*
                    245:         * Check AH/ESP integrity.
                    246:         */
                    247:        if (last && ipsec6_in_reject(m, last)) {
                    248:                m_freem(m);
1.97      thorpej   249:                IPSEC6_STATINC(IPSEC_STAT_IN_INVAL);
1.94      thorpej   250:                IP6_STATDEC(IP6_STAT_DELIVERED);
1.30      itojun    251:                /* do not inject data into pcb */
                    252:        } else
1.38      itojun    253: #endif /* IPSEC */
1.81      degroote  254: #ifdef FAST_IPSEC
                    255:        if (last && ipsec6_in_reject(m, last)) {
                    256:                m_freem(m);
                    257:                /*
                    258:                 * XXX ipsec6_in_reject update stat if there is an error
                    259:                 * so we just need to update stats by hand in the case of last is
                    260:                 * NULL
                    261:                 */
                    262:                if (!last)
1.97      thorpej   263:                        IPSEC6_STATINC(IPSEC_STAT_IN_POLVIO);
1.94      thorpej   264:                        IP6_STATDEC(IP6_STAT_DELIVERED);
1.81      degroote  265:                        /* do not inject data into pcb */
                    266:                } else
                    267: #endif /* FAST_IPSEC */
1.2       itojun    268:        if (last) {
                    269:                if (last->in6p_flags & IN6P_CONTROLOPTS)
                    270:                        ip6_savecontrol(last, &opts, ip6, m);
                    271:                /* strip intermediate headers */
                    272:                m_adj(m, *offp);
                    273:                if (sbappendaddr(&last->in6p_socket->so_rcv,
1.43      itojun    274:                    (struct sockaddr *)&rip6src, m, opts) == 0) {
1.2       itojun    275:                        m_freem(m);
                    276:                        if (opts)
                    277:                                m_freem(opts);
1.95      thorpej   278:                        RIP6_STATINC(RIP6_STAT_FULLSOCK);
1.2       itojun    279:                } else
                    280:                        sorwakeup(last->in6p_socket);
                    281:        } else {
1.95      thorpej   282:                RIP6_STATINC(RIP6_STAT_NOSOCK);
1.37      itojun    283:                if (m->m_flags & M_MCAST)
1.95      thorpej   284:                        RIP6_STATINC(RIP6_STAT_NOSOCKMCAST);
1.2       itojun    285:                if (proto == IPPROTO_NONE)
                    286:                        m_freem(m);
                    287:                else {
1.50      itojun    288:                        u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
1.27      itojun    289:                        in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown);
1.2       itojun    290:                        icmp6_error(m, ICMP6_PARAM_PROB,
1.43      itojun    291:                            ICMP6_PARAMPROB_NEXTHEADER,
1.50      itojun    292:                            prvnxtp - mtod(m, u_int8_t *));
1.2       itojun    293:                }
1.94      thorpej   294:                IP6_STATDEC(IP6_STAT_DELIVERED);
1.2       itojun    295:        }
                    296:        return IPPROTO_DONE;
                    297: }
                    298:
1.98      ad        299: void *
1.82      dyoung    300: rip6_ctlinput(int cmd, const struct sockaddr *sa, void *d)
1.20      itojun    301: {
1.27      itojun    302:        struct ip6_hdr *ip6;
1.29      itojun    303:        struct ip6ctlparam *ip6cp = NULL;
                    304:        const struct sockaddr_in6 *sa6_src = NULL;
                    305:        void *cmdarg;
1.88      dyoung    306:        void (*notify)(struct in6pcb *, int) = in6_rtchange;
1.29      itojun    307:        int nxt;
1.20      itojun    308:
                    309:        if (sa->sa_family != AF_INET6 ||
                    310:            sa->sa_len != sizeof(struct sockaddr_in6))
1.102     yamt      311:                return NULL;
1.20      itojun    312:
1.21      itojun    313:        if ((unsigned)cmd >= PRC_NCMDS)
1.102     yamt      314:                return NULL;
1.21      itojun    315:        if (PRC_IS_REDIRECT(cmd))
                    316:                notify = in6_rtchange, d = NULL;
                    317:        else if (cmd == PRC_HOSTDEAD)
                    318:                d = NULL;
1.29      itojun    319:        else if (cmd == PRC_MSGSIZE)
                    320:                ; /* special code is present, see below */
1.21      itojun    321:        else if (inet6ctlerrmap[cmd] == 0)
1.102     yamt      322:                return NULL;
1.20      itojun    323:
                    324:        /* if the parameter is from icmp6, decode it. */
                    325:        if (d != NULL) {
1.29      itojun    326:                ip6cp = (struct ip6ctlparam *)d;
1.20      itojun    327:                ip6 = ip6cp->ip6c_ip6;
1.29      itojun    328:                cmdarg = ip6cp->ip6c_cmdarg;
                    329:                sa6_src = ip6cp->ip6c_src;
                    330:                nxt = ip6cp->ip6c_nxt;
1.20      itojun    331:        } else {
                    332:                ip6 = NULL;
1.29      itojun    333:                cmdarg = NULL;
                    334:                sa6_src = &sa6_any;
                    335:                nxt = -1;
1.20      itojun    336:        }
                    337:
1.29      itojun    338:        if (ip6 && cmd == PRC_MSGSIZE) {
1.82      dyoung    339:                const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *)sa;
1.29      itojun    340:                int valid = 0;
                    341:                struct in6pcb *in6p;
1.20      itojun    342:
                    343:                /*
1.29      itojun    344:                 * Check to see if we have a valid raw IPv6 socket
                    345:                 * corresponding to the address in the ICMPv6 message
                    346:                 * payload, and the protocol (ip6_nxt) meets the socket.
                    347:                 * XXX chase extension headers, or pass final nxt value
                    348:                 * from icmp6_notify_error()
1.20      itojun    349:                 */
1.29      itojun    350:                in6p = NULL;
1.59      itojun    351:                in6p = in6_pcblookup_connect(&raw6cbtable, &sa6->sin6_addr, 0,
1.108   ! dyoung    352:                                             (const struct in6_addr *)&sa6_src->sin6_addr, 0, 0, 0);
1.29      itojun    353: #if 0
                    354:                if (!in6p) {
                    355:                        /*
                    356:                         * As the use of sendto(2) is fairly popular,
                    357:                         * we may want to allow non-connected pcb too.
                    358:                         * But it could be too weak against attacks...
                    359:                         * We should at least check if the local
                    360:                         * address (= s) is really ours.
                    361:                         */
1.59      itojun    362:                        in6p = in6_pcblookup_bind(&raw6cbtable,
1.75      rpaulo    363:                            &sa6->sin6_addr, 0, 0);
1.29      itojun    364:                }
                    365: #endif
                    366:
                    367:                if (in6p && in6p->in6p_ip6.ip6_nxt &&
                    368:                    in6p->in6p_ip6.ip6_nxt == nxt)
                    369:                        valid++;
1.20      itojun    370:
1.29      itojun    371:                /*
                    372:                 * Depending on the value of "valid" and routing table
                    373:                 * size (mtudisc_{hi,lo}wat), we will:
1.44      itojun    374:                 * - recalculate the new MTU and create the
1.29      itojun    375:                 *   corresponding routing entry, or
                    376:                 * - ignore the MTU change notification.
                    377:                 */
                    378:                icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1.20      itojun    379:
1.29      itojun    380:                /*
                    381:                 * regardless of if we called icmp6_mtudisc_update(),
1.76      rpaulo    382:                 * we need to call in6_pcbnotify(), to notify path MTU
                    383:                 * change to the userland (RFC3542), because some
                    384:                 * unconnected sockets may share the same destination
                    385:                 * and want to know the path MTU.
1.29      itojun    386:                 */
1.20      itojun    387:        }
1.29      itojun    388:
1.59      itojun    389:        (void) in6_pcbnotify(&raw6cbtable, sa, 0,
1.72      christos  390:            (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
1.98      ad        391:        return NULL;
1.20      itojun    392: }
                    393:
1.2       itojun    394: /*
                    395:  * Generate IPv6 header and pass packet to ip6_output.
                    396:  * Tack on options user may have setup with control call.
                    397:  */
                    398: int
1.106     dyoung    399: rip6_output(struct mbuf *m, struct socket * const so,
                    400:     struct sockaddr_in6 * const dstsock, struct mbuf * const control)
1.2       itojun    401: {
                    402:        struct in6_addr *dst;
                    403:        struct ip6_hdr *ip6;
                    404:        struct in6pcb *in6p;
                    405:        u_int   plen = m->m_pkthdr.len;
                    406:        int error = 0;
1.75      rpaulo    407:        struct ip6_pktopts opt, *optp = NULL;
1.2       itojun    408:        struct ifnet *oifp = NULL;
1.12      itojun    409:        int type, code;         /* for ICMPv6 output statistics only */
1.75      rpaulo    410:        int scope_ambiguous = 0;
                    411:        struct in6_addr *in6a;
1.2       itojun    412:
                    413:        in6p = sotoin6pcb(so);
                    414:
                    415:        dst = &dstsock->sin6_addr;
                    416:        if (control) {
1.76      rpaulo    417:                if ((error = ip6_setpktopts(control, &opt,
                    418:                    in6p->in6p_outputopts,
1.104     elad      419:                    kauth_cred_get(), so->so_proto->pr_protocol)) != 0) {
1.2       itojun    420:                        goto bad;
1.76      rpaulo    421:                }
1.2       itojun    422:                optp = &opt;
                    423:        } else
                    424:                optp = in6p->in6p_outputopts;
                    425:
1.12      itojun    426:        /*
1.75      rpaulo    427:         * Check and convert scope zone ID into internal form.
                    428:         * XXX: we may still need to determine the zone later.
                    429:         */
                    430:        if (!(so->so_state & SS_ISCONNECTED)) {
                    431:                if (dstsock->sin6_scope_id == 0 && !ip6_use_defzone)
                    432:                        scope_ambiguous = 1;
                    433:                if ((error = sa6_embedscope(dstsock, ip6_use_defzone)) != 0)
                    434:                        goto bad;
                    435:        }
                    436:
                    437:        /*
1.12      itojun    438:         * For an ICMPv6 packet, we should know its type and code
                    439:         * to update statistics.
                    440:         */
                    441:        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
                    442:                struct icmp6_hdr *icmp6;
                    443:                if (m->m_len < sizeof(struct icmp6_hdr) &&
                    444:                    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
                    445:                        error = ENOBUFS;
                    446:                        goto bad;
                    447:                }
                    448:                icmp6 = mtod(m, struct icmp6_hdr *);
                    449:                type = icmp6->icmp6_type;
                    450:                code = icmp6->icmp6_code;
1.62      christos  451:        } else {
                    452:                type = 0;
                    453:                code = 0;
1.12      itojun    454:        }
                    455:
1.52      itojun    456:        M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
                    457:        if (!m) {
                    458:                error = ENOBUFS;
                    459:                goto bad;
                    460:        }
1.2       itojun    461:        ip6 = mtod(m, struct ip6_hdr *);
                    462:
                    463:        /*
                    464:         * Next header might not be ICMP6 but use its pseudo header anyway.
                    465:         */
                    466:        ip6->ip6_dst = *dst;
                    467:
1.12      itojun    468:        /*
                    469:         * Source address selection.
                    470:         */
1.75      rpaulo    471:        if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
1.107     dyoung    472:            &in6p->in6p_route, &in6p->in6p_laddr, &oifp,
1.82      dyoung    473:            &error)) == 0) {
1.75      rpaulo    474:                if (error == 0)
                    475:                        error = EADDRNOTAVAIL;
                    476:                goto bad;
                    477:        }
                    478:        ip6->ip6_src = *in6a;
1.2       itojun    479:
1.75      rpaulo    480:        if (oifp && scope_ambiguous) {
                    481:                /*
                    482:                 * Application should provide a proper zone ID or the use of
                    483:                 * default zone IDs should be enabled.  Unfortunately, some
                    484:                 * applications do not behave as it should, so we need a
                    485:                 * workaround.  Even if an appropriate ID is not determined
                    486:                 * (when it's required), if we can determine the outgoing
                    487:                 * interface. determine the zone ID based on the interface.
                    488:                 */
                    489:                error = in6_setscope(&dstsock->sin6_addr, oifp, NULL);
                    490:                if (error != 0)
1.2       itojun    491:                        goto bad;
1.12      itojun    492:        }
1.75      rpaulo    493:        ip6->ip6_dst = dstsock->sin6_addr;
1.2       itojun    494:
1.75      rpaulo    495:        /* fill in the rest of the IPv6 header fields */
1.2       itojun    496:        ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
1.20      itojun    497:        ip6->ip6_vfc  &= ~IPV6_VERSION_MASK;
                    498:        ip6->ip6_vfc  |= IPV6_VERSION;
1.75      rpaulo    499:        /* ip6_plen will be filled in ip6_output, so not fill it here. */
1.2       itojun    500:        ip6->ip6_nxt   = in6p->in6p_ip6.ip6_nxt;
1.12      itojun    501:        ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
1.2       itojun    502:
                    503:        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
                    504:            in6p->in6p_cksum != -1) {
                    505:                int off;
1.67      yamt      506:                u_int16_t sum;
1.2       itojun    507:
                    508:                /* compute checksum */
                    509:                if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
                    510:                        off = offsetof(struct icmp6_hdr, icmp6_cksum);
                    511:                else
                    512:                        off = in6p->in6p_cksum;
                    513:                if (plen < off + 1) {
                    514:                        error = EINVAL;
                    515:                        goto bad;
                    516:                }
                    517:                off += sizeof(struct ip6_hdr);
                    518:
1.68      yamt      519:                sum = 0;
1.84      christos  520:                m = m_copyback_cow(m, off, sizeof(sum), (void *)&sum,
1.68      yamt      521:                    M_DONTWAIT);
                    522:                if (m == NULL) {
1.66      yamt      523:                        error = ENOBUFS;
                    524:                        goto bad;
                    525:                }
1.67      yamt      526:                sum = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
1.84      christos  527:                m = m_copyback_cow(m, off, sizeof(sum), (void *)&sum,
1.68      yamt      528:                    M_DONTWAIT);
                    529:                if (m == NULL) {
                    530:                        error = ENOBUFS;
                    531:                        goto bad;
                    532:                }
1.2       itojun    533:        }
1.27      itojun    534:
1.76      rpaulo    535:        error = ip6_output(m, optp, &in6p->in6p_route, 0,
1.57      itojun    536:            in6p->in6p_moptions, so, &oifp);
1.12      itojun    537:        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
                    538:                if (oifp)
                    539:                        icmp6_ifoutstat_inc(oifp, type, code);
1.94      thorpej   540:                ICMP6_STATINC(ICMP6_STAT_OUTHIST + type);
1.37      itojun    541:        } else
1.95      thorpej   542:                RIP6_STATINC(RIP6_STAT_OPACKETS);
1.2       itojun    543:
                    544:        goto freectl;
                    545:
                    546:  bad:
                    547:        if (m)
                    548:                m_freem(m);
                    549:
                    550:  freectl:
1.76      rpaulo    551:        if (control) {
                    552:                ip6_clearpktopts(&opt, -1);
1.2       itojun    553:                m_freem(control);
1.76      rpaulo    554:        }
1.83      dyoung    555:        return error;
1.2       itojun    556: }
                    557:
1.40      itojun    558: /*
1.2       itojun    559:  * Raw IPv6 socket option processing.
1.40      itojun    560:  */
1.2       itojun    561: int
1.100     plunky    562: rip6_ctloutput(int op, struct socket *so, struct sockopt *sopt)
1.2       itojun    563: {
                    564:        int error = 0;
                    565:
1.100     plunky    566:        if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) {
                    567:                int optval;
                    568:
1.87      dyoung    569:                /* need to fiddle w/ opt(IPPROTO_IPV6, IPV6_CHECKSUM)? */
1.90      dyoung    570:                if (op == PRCO_GETOPT) {
1.100     plunky    571:                        optval = 1;
                    572:                        error = sockopt_set(sopt, &optval, sizeof(optval));
                    573:                } else if (op == PRCO_SETOPT) {
                    574:                        error = sockopt_getint(sopt, &optval);
                    575:                        if (error)
                    576:                                goto out;
                    577:                        if (optval == 0)
                    578:                                error = EINVAL;
                    579:                }
                    580:
                    581:                goto out;
                    582:        } else if (sopt->sopt_level != IPPROTO_IPV6)
                    583:                return ip6_ctloutput(op, so, sopt);
1.87      dyoung    584:
1.100     plunky    585:        switch (sopt->sopt_name) {
1.87      dyoung    586:        case MRT6_INIT:
                    587:        case MRT6_DONE:
                    588:        case MRT6_ADD_MIF:
                    589:        case MRT6_DEL_MIF:
                    590:        case MRT6_ADD_MFC:
                    591:        case MRT6_DEL_MFC:
                    592:        case MRT6_PIM:
                    593:                if (op == PRCO_SETOPT)
1.100     plunky    594:                        error = ip6_mrouter_set(so, sopt);
1.87      dyoung    595:                else if (op == PRCO_GETOPT)
1.100     plunky    596:                        error = ip6_mrouter_get(so, sopt);
1.87      dyoung    597:                else
                    598:                        error = EINVAL;
                    599:                break;
                    600:        case IPV6_CHECKSUM:
1.100     plunky    601:                return ip6_raw_ctloutput(op, so, sopt);
1.27      itojun    602:        default:
1.100     plunky    603:                return ip6_ctloutput(op, so, sopt);
1.2       itojun    604:        }
1.100     plunky    605:  out:
1.87      dyoung    606:        return error;
1.2       itojun    607: }
                    608:
                    609: extern u_long rip6_sendspace;
                    610: extern u_long rip6_recvspace;
                    611:
                    612: int
1.85      christos  613: rip6_usrreq(struct socket *so, int req, struct mbuf *m,
                    614:        struct mbuf *nam, struct mbuf *control, struct lwp *l)
1.2       itojun    615: {
1.27      itojun    616:        struct in6pcb *in6p = sotoin6pcb(so);
1.2       itojun    617:        int s;
                    618:        int error = 0;
                    619:
                    620:        if (req == PRU_CONTROL)
1.84      christos  621:                return in6_control(so, (u_long)m, (void *)nam,
1.83      dyoung    622:                    (struct ifnet *)control, l);
1.17      thorpej   623:
1.18      thorpej   624:        if (req == PRU_PURGEIF) {
1.98      ad        625:                mutex_enter(softnet_lock);
1.59      itojun    626:                in6_pcbpurgeif0(&raw6cbtable, (struct ifnet *)control);
1.18      thorpej   627:                in6_purgeif((struct ifnet *)control);
1.59      itojun    628:                in6_pcbpurgeif(&raw6cbtable, (struct ifnet *)control);
1.98      ad        629:                mutex_exit(softnet_lock);
1.83      dyoung    630:                return 0;
1.17      thorpej   631:        }
1.2       itojun    632:
                    633:        switch (req) {
                    634:        case PRU_ATTACH:
1.104     elad      635:                error = kauth_authorize_network(l->l_cred,
                    636:                    KAUTH_NETWORK_SOCKET, KAUTH_REQ_NETWORK_SOCKET_RAWSOCK,
1.108   ! dyoung    637:                    KAUTH_ARG(AF_INET6),
        !           638:                    KAUTH_ARG(SOCK_RAW),
        !           639:                    KAUTH_ARG(so->so_proto->pr_protocol));
1.98      ad        640:                sosetlock(so);
1.83      dyoung    641:                if (in6p != NULL)
1.2       itojun    642:                        panic("rip6_attach");
1.104     elad      643:                if (error) {
1.2       itojun    644:                        break;
                    645:                }
1.4       itojun    646:                s = splsoftnet();
1.83      dyoung    647:                error = soreserve(so, rip6_sendspace, rip6_recvspace);
                    648:                if (error != 0) {
1.27      itojun    649:                        splx(s);
                    650:                        break;
                    651:                }
1.83      dyoung    652:                if ((error = in6_pcballoc(so, &raw6cbtable)) != 0) {
1.2       itojun    653:                        splx(s);
                    654:                        break;
                    655:                }
                    656:                splx(s);
                    657:                in6p = sotoin6pcb(so);
1.5       itojun    658:                in6p->in6p_ip6.ip6_nxt = (long)nam;
1.2       itojun    659:                in6p->in6p_cksum = -1;
1.48      itojun    660:
1.101     cegger    661:                in6p->in6p_icmp6filt = malloc(sizeof(struct icmp6_filter),
                    662:                        M_PCB, M_NOWAIT);
1.12      itojun    663:                if (in6p->in6p_icmp6filt == NULL) {
                    664:                        in6_pcbdetach(in6p);
                    665:                        error = ENOMEM;
                    666:                        break;
                    667:                }
1.2       itojun    668:                ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
                    669:                break;
                    670:
                    671:        case PRU_DISCONNECT:
                    672:                if ((so->so_state & SS_ISCONNECTED) == 0) {
                    673:                        error = ENOTCONN;
                    674:                        break;
                    675:                }
                    676:                in6p->in6p_faddr = in6addr_any;
                    677:                so->so_state &= ~SS_ISCONNECTED;        /* XXX */
                    678:                break;
                    679:
                    680:        case PRU_ABORT:
                    681:                soisdisconnected(so);
                    682:                /* Fallthrough */
                    683:        case PRU_DETACH:
1.83      dyoung    684:                if (in6p == NULL)
1.2       itojun    685:                        panic("rip6_detach");
                    686:                if (so == ip6_mrouter)
                    687:                        ip6_mrouter_done();
                    688:                /* xxx: RSVP */
1.83      dyoung    689:                if (in6p->in6p_icmp6filt != NULL) {
1.101     cegger    690:                        free(in6p->in6p_icmp6filt, M_PCB);
1.2       itojun    691:                        in6p->in6p_icmp6filt = NULL;
                    692:                }
                    693:                in6_pcbdetach(in6p);
                    694:                break;
                    695:
                    696:        case PRU_BIND:
                    697:            {
                    698:                struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
                    699:                struct ifaddr *ia = NULL;
                    700:
                    701:                if (nam->m_len != sizeof(*addr)) {
                    702:                        error = EINVAL;
                    703:                        break;
                    704:                }
1.79      dyoung    705:                if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) {
1.24      itojun    706:                        error = EADDRNOTAVAIL;
                    707:                        break;
                    708:                }
1.75      rpaulo    709:                if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0)
                    710:                        break;
1.34      itojun    711:
1.23      itojun    712:                /*
                    713:                 * we don't support mapped address here, it would confuse
                    714:                 * users so reject it
                    715:                 */
                    716:                if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
                    717:                        error = EADDRNOTAVAIL;
                    718:                        break;
                    719:                }
1.24      itojun    720:                if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
                    721:                    (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) {
1.2       itojun    722:                        error = EADDRNOTAVAIL;
                    723:                        break;
                    724:                }
1.46      itojun    725:                if (ia && ((struct in6_ifaddr *)ia)->ia6_flags &
1.2       itojun    726:                    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
                    727:                     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
                    728:                        error = EADDRNOTAVAIL;
                    729:                        break;
                    730:                }
                    731:                in6p->in6p_laddr = addr->sin6_addr;
                    732:                break;
                    733:            }
1.36      itojun    734:
1.2       itojun    735:        case PRU_CONNECT:
1.40      itojun    736:        {
1.2       itojun    737:                struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
                    738:                struct in6_addr *in6a = NULL;
1.75      rpaulo    739:                struct ifnet *ifp = NULL;
                    740:                int scope_ambiguous = 0;
1.2       itojun    741:
                    742:                if (nam->m_len != sizeof(*addr)) {
                    743:                        error = EINVAL;
                    744:                        break;
                    745:                }
1.79      dyoung    746:                if (TAILQ_EMPTY(&ifnet)) {
1.2       itojun    747:                        error = EADDRNOTAVAIL;
                    748:                        break;
                    749:                }
                    750:                if (addr->sin6_family != AF_INET6) {
                    751:                        error = EAFNOSUPPORT;
                    752:                        break;
                    753:                }
                    754:
1.75      rpaulo    755:                /*
                    756:                 * Application should provide a proper zone ID or the use of
                    757:                 * default zone IDs should be enabled.  Unfortunately, some
                    758:                 * applications do not behave as it should, so we need a
                    759:                 * workaround.  Even if an appropriate ID is not determined,
                    760:                 * we'll see if we can determine the outgoing interface.  If we
                    761:                 * can, determine the zone ID based on the interface below.
                    762:                 */
                    763:                if (addr->sin6_scope_id == 0 && !ip6_use_defzone)
                    764:                        scope_ambiguous = 1;
                    765:                if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0)
1.83      dyoung    766:                        return error;
1.24      itojun    767:
1.2       itojun    768:                /* Source address selection. XXX: need pcblookup? */
1.12      itojun    769:                in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
1.107     dyoung    770:                    in6p->in6p_moptions, &in6p->in6p_route,
1.75      rpaulo    771:                    &in6p->in6p_laddr, &ifp, &error);
1.12      itojun    772:                if (in6a == NULL) {
1.2       itojun    773:                        if (error == 0)
                    774:                                error = EADDRNOTAVAIL;
                    775:                        break;
                    776:                }
1.75      rpaulo    777:                /* XXX: see above */
                    778:                if (ifp && scope_ambiguous &&
                    779:                    (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
                    780:                        break;
                    781:                }
1.2       itojun    782:                in6p->in6p_laddr = *in6a;
                    783:                in6p->in6p_faddr = addr->sin6_addr;
                    784:                soisconnected(so);
                    785:                break;
1.40      itojun    786:        }
1.2       itojun    787:
                    788:        case PRU_CONNECT2:
                    789:                error = EOPNOTSUPP;
                    790:                break;
                    791:
                    792:        /*
                    793:         * Mark the connection as being incapable of futther input.
                    794:         */
                    795:        case PRU_SHUTDOWN:
                    796:                socantsendmore(so);
                    797:                break;
                    798:        /*
                    799:         * Ship a packet out. The appropriate raw output
                    800:         * routine handles any messaging necessary.
                    801:         */
                    802:        case PRU_SEND:
1.40      itojun    803:        {
1.2       itojun    804:                struct sockaddr_in6 tmp;
                    805:                struct sockaddr_in6 *dst;
                    806:
1.24      itojun    807:                /* always copy sockaddr to avoid overwrites */
1.2       itojun    808:                if (so->so_state & SS_ISCONNECTED) {
                    809:                        if (nam) {
                    810:                                error = EISCONN;
                    811:                                break;
                    812:                        }
                    813:                        /* XXX */
1.89      dyoung    814:                        sockaddr_in6_init(&tmp, &in6p->in6p_faddr, 0, 0, 0);
1.2       itojun    815:                        dst = &tmp;
                    816:                } else {
                    817:                        if (nam == NULL) {
                    818:                                error = ENOTCONN;
                    819:                                break;
                    820:                        }
1.42      itojun    821:                        if (nam->m_len != sizeof(tmp)) {
                    822:                                error = EINVAL;
                    823:                                break;
                    824:                        }
                    825:
1.24      itojun    826:                        tmp = *mtod(nam, struct sockaddr_in6 *);
                    827:                        dst = &tmp;
1.42      itojun    828:
                    829:                        if (dst->sin6_family != AF_INET6) {
                    830:                                error = EAFNOSUPPORT;
                    831:                                break;
                    832:                        }
1.2       itojun    833:                }
                    834:                error = rip6_output(m, so, dst, control);
                    835:                m = NULL;
                    836:                break;
1.40      itojun    837:        }
1.2       itojun    838:
                    839:        case PRU_SENSE:
                    840:                /*
                    841:                 * stat: don't bother with a blocksize
                    842:                 */
1.83      dyoung    843:                return 0;
1.2       itojun    844:        /*
                    845:         * Not supported.
                    846:         */
                    847:        case PRU_RCVOOB:
                    848:        case PRU_RCVD:
                    849:        case PRU_LISTEN:
                    850:        case PRU_ACCEPT:
                    851:        case PRU_SENDOOB:
                    852:                error = EOPNOTSUPP;
                    853:                break;
                    854:
                    855:        case PRU_SOCKADDR:
                    856:                in6_setsockaddr(in6p, nam);
                    857:                break;
                    858:
                    859:        case PRU_PEERADDR:
                    860:                in6_setpeeraddr(in6p, nam);
                    861:                break;
                    862:
                    863:        default:
                    864:                panic("rip6_usrreq");
                    865:        }
                    866:        if (m != NULL)
                    867:                m_freem(m);
1.83      dyoung    868:        return error;
1.2       itojun    869: }
1.69      atatat    870:
1.95      thorpej   871: static int
                    872: sysctl_net_inet6_raw6_stats(SYSCTLFN_ARGS)
                    873: {
                    874:
1.99      thorpej   875:        return (NETSTAT_SYSCTL(rip6stat_percpu, RIP6_NSTATS));
1.95      thorpej   876: }
                    877:
1.105     pooka     878: static void
                    879: sysctl_net_inet6_raw6_setup(struct sysctllog **clog)
1.69      atatat    880: {
                    881:
                    882:        sysctl_createv(clog, 0, NULL, NULL,
                    883:                       CTLFLAG_PERMANENT,
                    884:                       CTLTYPE_NODE, "net", NULL,
                    885:                       NULL, 0, NULL, 0,
                    886:                       CTL_NET, CTL_EOL);
                    887:        sysctl_createv(clog, 0, NULL, NULL,
                    888:                       CTLFLAG_PERMANENT,
                    889:                       CTLTYPE_NODE, "inet6", NULL,
                    890:                       NULL, 0, NULL, 0,
                    891:                       CTL_NET, PF_INET6, CTL_EOL);
                    892:        sysctl_createv(clog, 0, NULL, NULL,
                    893:                       CTLFLAG_PERMANENT,
                    894:                       CTLTYPE_NODE, "raw6",
                    895:                       SYSCTL_DESCR("Raw IPv6 settings"),
                    896:                       NULL, 0, NULL, 0,
                    897:                       CTL_NET, PF_INET6, IPPROTO_RAW, CTL_EOL);
                    898:
                    899:        sysctl_createv(clog, 0, NULL, NULL,
                    900:                       CTLFLAG_PERMANENT,
1.71      atatat    901:                       CTLTYPE_STRUCT, "pcblist",
1.69      atatat    902:                       SYSCTL_DESCR("Raw IPv6 control block list"),
                    903:                       sysctl_inpcblist, 0, &raw6cbtable, 0,
                    904:                       CTL_NET, PF_INET6, IPPROTO_RAW,
                    905:                       CTL_CREATE, CTL_EOL);
1.73      rpaulo    906:        sysctl_createv(clog, 0, NULL, NULL,
                    907:                       CTLFLAG_PERMANENT,
                    908:                       CTLTYPE_STRUCT, "stats",
                    909:                       SYSCTL_DESCR("Raw IPv6 statistics"),
1.95      thorpej   910:                       sysctl_net_inet6_raw6_stats, 0, NULL, 0,
1.73      rpaulo    911:                       CTL_NET, PF_INET6, IPPROTO_RAW, RAW6CTL_STATS,
                    912:                       CTL_EOL);
1.69      atatat    913: }

CVSweb <webmaster@jp.NetBSD.org>