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

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

CVSweb <webmaster@jp.NetBSD.org>