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

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

CVSweb <webmaster@jp.NetBSD.org>