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

1.23    ! itojun      1: /*     $NetBSD: raw_ip6.c,v 1.22 2000/03/01 12:49:50 itojun Exp $      */
        !             2: /*     $KAME: raw_ip6.c,v 1.28 2000/05/28 23:25:07 itojun Exp $        */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
                      7:  *
                      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.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * Copyright (c) 1982, 1986, 1988, 1993
                     35:  *     The Regents of the University of California.  All rights reserved.
                     36:  *
                     37:  * Redistribution and use in source and binary forms, with or without
                     38:  * modification, are permitted provided that the following conditions
                     39:  * are met:
                     40:  * 1. Redistributions of source code must retain the above copyright
                     41:  *    notice, this list of conditions and the following disclaimer.
                     42:  * 2. Redistributions in binary form must reproduce the above copyright
                     43:  *    notice, this list of conditions and the following disclaimer in the
                     44:  *    documentation and/or other materials provided with the distribution.
                     45:  * 3. All advertising materials mentioning features or use of this software
                     46:  *    must display the following acknowledgement:
                     47:  *     This product includes software developed by the University of
                     48:  *     California, Berkeley and its contributors.
                     49:  * 4. Neither the name of the University nor the names of its contributors
                     50:  *    may be used to endorse or promote products derived from this software
                     51:  *    without specific prior written permission.
                     52:  *
                     53:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     54:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     55:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     56:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     57:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     58:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     59:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     60:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     61:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     62:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     63:  * SUCH DAMAGE.
                     64:  *
                     65:  *     @(#)raw_ip.c    8.2 (Berkeley) 1/4/94
                     66:  */
1.6       thorpej    67:
                     68: #include "opt_ipsec.h"
1.2       itojun     69:
                     70: #include <sys/param.h>
                     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>
                     79:
                     80: #include <net/if.h>
                     81: #include <net/route.h>
                     82: #include <net/if_types.h>
                     83:
                     84: #include <netinet/in.h>
                     85: #include <netinet/in_var.h>
1.19      itojun     86: #include <netinet/ip6.h>
1.2       itojun     87: #include <netinet6/ip6_var.h>
                     88: #include <netinet6/ip6_mroute.h>
1.19      itojun     89: #include <netinet/icmp6.h>
1.2       itojun     90: #include <netinet6/in6_pcb.h>
                     91: #include <netinet6/nd6.h>
1.20      itojun     92: #include <netinet6/ip6protosw.h>
1.2       itojun     93:
                     94: #ifdef IPSEC
                     95: #include <netinet6/ipsec.h>
                     96: #endif /*IPSEC*/
                     97:
                     98: #include <machine/stdarg.h>
                     99:
                    100: #include "faith.h"
                    101:
                    102: struct in6pcb rawin6pcb;
                    103: #define ifatoia6(ifa)  ((struct in6_ifaddr *)(ifa))
                    104:
                    105: /*
                    106:  * Raw interface to IP6 protocol.
                    107:  */
                    108:
                    109: /*
                    110:  * Initialize raw connection block queue.
                    111:  */
                    112: void
                    113: rip6_init()
                    114: {
                    115:        rawin6pcb.in6p_next = rawin6pcb.in6p_prev = &rawin6pcb;
                    116: }
                    117:
                    118: /*
                    119:  * Setup generic address and protocol structures
                    120:  * for raw_input routine, then pass them along with
                    121:  * mbuf chain.
                    122:  */
                    123: int
                    124: rip6_input(mp, offp, proto)
                    125:        struct  mbuf **mp;
                    126:        int     *offp, proto;
                    127: {
                    128:        struct mbuf *m = *mp;
                    129:        register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
                    130:        register struct in6pcb *in6p;
                    131:        struct in6pcb *last = NULL;
                    132:        struct sockaddr_in6 rip6src;
                    133:        struct mbuf *opts = NULL;
                    134:
                    135: #if defined(NFAITH) && 0 < NFAITH
                    136:        if (m->m_pkthdr.rcvif) {
                    137:                if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
                    138:                        /* send icmp6 host unreach? */
                    139:                        m_freem(m);
                    140:                        return IPPROTO_DONE;
                    141:                }
                    142:        }
                    143: #endif
1.14      itojun    144:
                    145:        /* Be proactive about malicious use of IPv4 mapped address */
                    146:        if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
                    147:            IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
                    148:                /* XXX stat */
                    149:                m_freem(m);
                    150:                return IPPROTO_DONE;
                    151:        }
                    152:
1.2       itojun    153:        bzero(&rip6src, sizeof(rip6src));
                    154:        rip6src.sin6_len = sizeof(struct sockaddr_in6);
                    155:        rip6src.sin6_family = AF_INET6;
                    156:        rip6src.sin6_addr = ip6->ip6_src;
                    157:        if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
                    158:                rip6src.sin6_addr.s6_addr16[1] = 0;
                    159:        if (m->m_pkthdr.rcvif) {
                    160:                if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
                    161:                        rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
                    162:                else
                    163:                        rip6src.sin6_scope_id = 0;
                    164:        } else
                    165:                rip6src.sin6_scope_id = 0;
                    166:
                    167:        for (in6p = rawin6pcb.in6p_next;
                    168:             in6p != &rawin6pcb; in6p = in6p->in6p_next) {
                    169:                if (in6p->in6p_ip6.ip6_nxt &&
                    170:                    in6p->in6p_ip6.ip6_nxt != proto)
                    171:                        continue;
1.12      itojun    172:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
1.2       itojun    173:                   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
                    174:                        continue;
1.12      itojun    175:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
1.2       itojun    176:                   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
                    177:                        continue;
                    178:                if (in6p->in6p_cksum != -1
1.7       itojun    179:                 && in6_cksum(m, ip6->ip6_nxt, *offp, m->m_pkthdr.len - *offp))
                    180:                {
1.2       itojun    181:                        /* XXX bark something */
                    182:                        continue;
                    183:                }
                    184:                if (last) {
                    185:                        struct  mbuf *n;
                    186:                        if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
                    187:                                if (last->in6p_flags & IN6P_CONTROLOPTS)
                    188:                                        ip6_savecontrol(last, &opts, ip6, n);
                    189:                                /* strip intermediate headers */
                    190:                                m_adj(n, *offp);
                    191:                                if (sbappendaddr(&last->in6p_socket->so_rcv,
                    192:                                                (struct sockaddr *)&rip6src,
                    193:                                                 n, opts) == 0) {
                    194:                                        /* should notify about lost packet */
                    195:                                        m_freem(n);
                    196:                                        if (opts)
                    197:                                                m_freem(opts);
                    198:                                } else
                    199:                                        sorwakeup(last->in6p_socket);
                    200:                                opts = NULL;
                    201:                        }
                    202:                }
                    203:                last = in6p;
                    204:        }
                    205:        if (last) {
                    206:                if (last->in6p_flags & IN6P_CONTROLOPTS)
                    207:                        ip6_savecontrol(last, &opts, ip6, m);
                    208:                /* strip intermediate headers */
                    209:                m_adj(m, *offp);
                    210:                if (sbappendaddr(&last->in6p_socket->so_rcv,
                    211:                                (struct sockaddr *)&rip6src, m, opts) == 0) {
                    212:                        m_freem(m);
                    213:                        if (opts)
                    214:                                m_freem(opts);
                    215:                } else
                    216:                        sorwakeup(last->in6p_socket);
                    217:        } else {
                    218:                if (proto == IPPROTO_NONE)
                    219:                        m_freem(m);
                    220:                else {
                    221:                        char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
                    222:                        icmp6_error(m, ICMP6_PARAM_PROB,
                    223:                                    ICMP6_PARAMPROB_NEXTHEADER,
                    224:                                    prvnxtp - mtod(m, char *));
                    225:                }
                    226:                ip6stat.ip6s_delivered--;
                    227:        }
                    228:        return IPPROTO_DONE;
                    229: }
                    230:
1.20      itojun    231: void
                    232: rip6_ctlinput(cmd, sa, d)
                    233:        int cmd;
                    234:        struct sockaddr *sa;
                    235:        void *d;
                    236: {
                    237:        struct sockaddr_in6 sa6;
                    238:        register struct ip6_hdr *ip6;
                    239:        struct mbuf *m;
                    240:        int off;
1.21      itojun    241:        void (*notify) __P((struct in6pcb *, int)) = in6_rtchange;
1.20      itojun    242:
                    243:        if (sa->sa_family != AF_INET6 ||
                    244:            sa->sa_len != sizeof(struct sockaddr_in6))
                    245:                return;
                    246:
1.21      itojun    247:        if ((unsigned)cmd >= PRC_NCMDS)
                    248:                return;
                    249:        if (PRC_IS_REDIRECT(cmd))
                    250:                notify = in6_rtchange, d = NULL;
                    251:        else if (cmd == PRC_HOSTDEAD)
                    252:                d = NULL;
                    253:        else if (inet6ctlerrmap[cmd] == 0)
1.20      itojun    254:                return;
                    255:
                    256:        /* if the parameter is from icmp6, decode it. */
                    257:        if (d != NULL) {
                    258:                struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
                    259:                m = ip6cp->ip6c_m;
                    260:                ip6 = ip6cp->ip6c_ip6;
                    261:                off = ip6cp->ip6c_off;
                    262:        } else {
                    263:                m = NULL;
                    264:                ip6 = NULL;
                    265:        }
                    266:
                    267:        /* translate addresses into internal form */
                    268:        sa6 = *(struct sockaddr_in6 *)sa;
                    269:        if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
                    270:                sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
                    271:
                    272:        if (ip6) {
                    273:                /*
                    274:                 * XXX: We assume that when IPV6 is non NULL,
                    275:                 * M and OFF are valid.
                    276:                 */
                    277:                struct in6_addr s;
                    278:
                    279:                /* translate addresses into internal form */
                    280:                memcpy(&s, &ip6->ip6_src, sizeof(s));
                    281:                if (IN6_IS_ADDR_LINKLOCAL(&s))
                    282:                        s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
                    283:
                    284:                (void) in6_pcbnotify(&rawin6pcb, (struct sockaddr *)&sa6,
1.21      itojun    285:                                        0, &s, 0, cmd, notify);
1.20      itojun    286:        } else {
                    287:                (void) in6_pcbnotify(&rawin6pcb, (struct sockaddr *)&sa6, 0,
1.21      itojun    288:                                        &zeroin6_addr, 0, cmd, notify);
1.20      itojun    289:        }
                    290: }
                    291:
1.2       itojun    292: /*
                    293:  * Generate IPv6 header and pass packet to ip6_output.
                    294:  * Tack on options user may have setup with control call.
                    295:  */
                    296: int
                    297: #if __STDC__
                    298: rip6_output(struct mbuf *m, ...)
                    299: #else
                    300: rip6_output(m, va_alist)
                    301:        struct mbuf *m;
                    302:        va_dcl
                    303: #endif
                    304: {
                    305:        struct socket *so;
                    306:        struct sockaddr_in6 *dstsock;
                    307:        struct mbuf *control;
                    308:        struct in6_addr *dst;
                    309:        struct ip6_hdr *ip6;
                    310:        struct in6pcb *in6p;
                    311:        u_int   plen = m->m_pkthdr.len;
                    312:        int error = 0;
                    313:        struct ip6_pktopts opt, *optp = NULL;
                    314:        struct ifnet *oifp = NULL;
1.12      itojun    315:        int type, code;         /* for ICMPv6 output statistics only */
1.20      itojun    316:        int priv = 0;
1.2       itojun    317:        va_list ap;
                    318:
                    319:        va_start(ap, m);
                    320:        so = va_arg(ap, struct socket *);
                    321:        dstsock = va_arg(ap, struct sockaddr_in6 *);
                    322:        control = va_arg(ap, struct mbuf *);
                    323:        va_end(ap);
                    324:
                    325:        in6p = sotoin6pcb(so);
                    326:
1.12      itojun    327:        priv = 0;
                    328:     {
                    329:        struct proc *p = curproc;       /* XXX */
                    330:
                    331:        if (p && !suser(p->p_ucred, &p->p_acflag))
                    332:                priv = 1;
                    333:     }
1.2       itojun    334:        dst = &dstsock->sin6_addr;
                    335:        if (control) {
                    336:                if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
                    337:                        goto bad;
                    338:                optp = &opt;
                    339:        } else
                    340:                optp = in6p->in6p_outputopts;
                    341:
1.12      itojun    342:        /*
                    343:         * For an ICMPv6 packet, we should know its type and code
                    344:         * to update statistics.
                    345:         */
                    346:        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
                    347:                struct icmp6_hdr *icmp6;
                    348:                if (m->m_len < sizeof(struct icmp6_hdr) &&
                    349:                    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
                    350:                        error = ENOBUFS;
                    351:                        goto bad;
                    352:                }
                    353:                icmp6 = mtod(m, struct icmp6_hdr *);
                    354:                type = icmp6->icmp6_type;
                    355:                code = icmp6->icmp6_code;
                    356:        }
                    357:
1.2       itojun    358:        M_PREPEND(m, sizeof(*ip6), M_WAIT);
                    359:        ip6 = mtod(m, struct ip6_hdr *);
                    360:
                    361:        /*
                    362:         * Next header might not be ICMP6 but use its pseudo header anyway.
                    363:         */
                    364:        ip6->ip6_dst = *dst;
                    365:
                    366:        /*
                    367:         * If the scope of the destination is link-local, embed the interface
                    368:         * index in the address.
                    369:         *
                    370:         * XXX advanced-api value overrides sin6_scope_id
                    371:         */
1.12      itojun    372:        if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) ||
                    373:            IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) {
1.2       itojun    374:                struct in6_pktinfo *pi;
                    375:
                    376:                /*
                    377:                 * XXX Boundary check is assumed to be already done in
1.12      itojun    378:                 * ip6_setpktoptions().
1.2       itojun    379:                 */
                    380:                if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) {
                    381:                        ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex);
                    382:                        oifp = ifindex2ifnet[pi->ipi6_ifindex];
                    383:                }
                    384:                else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
                    385:                         in6p->in6p_moptions &&
                    386:                         in6p->in6p_moptions->im6o_multicast_ifp) {
1.12      itojun    387:                        oifp = in6p->in6p_moptions->im6o_multicast_ifp;
                    388:                        ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
1.2       itojun    389:                } else if (dstsock->sin6_scope_id) {
                    390:                        /* boundary check */
                    391:                        if (dstsock->sin6_scope_id < 0
                    392:                         || if_index < dstsock->sin6_scope_id) {
                    393:                                error = ENXIO;  /* XXX EINVAL? */
                    394:                                goto bad;
                    395:                        }
                    396:                        ip6->ip6_dst.s6_addr16[1]
                    397:                                = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
                    398:                }
                    399:        }
                    400:
1.12      itojun    401:        /*
                    402:         * Source address selection.
                    403:         */
                    404:        {
1.2       itojun    405:                struct in6_addr *in6a;
                    406:
                    407:                if ((in6a = in6_selectsrc(dstsock, optp,
                    408:                                          in6p->in6p_moptions,
                    409:                                          &in6p->in6p_route,
1.12      itojun    410:                                          &in6p->in6p_laddr,
1.2       itojun    411:                                          &error)) == 0) {
                    412:                        if (error == 0)
                    413:                                error = EADDRNOTAVAIL;
                    414:                        goto bad;
                    415:                }
                    416:                ip6->ip6_src = *in6a;
                    417:                if (in6p->in6p_route.ro_rt)
                    418:                        oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
1.12      itojun    419:        }
1.2       itojun    420:
                    421:        ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
1.20      itojun    422:        ip6->ip6_vfc  &= ~IPV6_VERSION_MASK;
                    423:        ip6->ip6_vfc  |= IPV6_VERSION;
1.2       itojun    424: #if 0                          /* ip6_plen will be filled in ip6_output. */
                    425:        ip6->ip6_plen  = htons((u_short)plen);
                    426: #endif
                    427:        ip6->ip6_nxt   = in6p->in6p_ip6.ip6_nxt;
1.12      itojun    428:        ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
1.2       itojun    429:
                    430:        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
                    431:            in6p->in6p_cksum != -1) {
                    432:                struct mbuf *n;
                    433:                int off;
                    434:                u_int16_t *p;
                    435:
                    436: #define        offsetof(type, member)  ((size_t)(&((type *)0)->member)) /* XXX */
                    437:
                    438:                /* compute checksum */
                    439:                if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
                    440:                        off = offsetof(struct icmp6_hdr, icmp6_cksum);
                    441:                else
                    442:                        off = in6p->in6p_cksum;
                    443:                if (plen < off + 1) {
                    444:                        error = EINVAL;
                    445:                        goto bad;
                    446:                }
                    447:                off += sizeof(struct ip6_hdr);
                    448:
                    449:                n = m;
                    450:                while (n && n->m_len <= off) {
                    451:                        off -= n->m_len;
                    452:                        n = n->m_next;
                    453:                }
                    454:                if (!n)
                    455:                        goto bad;
                    456:                p = (u_int16_t *)(mtod(n, caddr_t) + off);
                    457:                *p = 0;
                    458:                *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
                    459:        }
                    460:
1.12      itojun    461:        error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions,
                    462:                           &oifp);
                    463:        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
                    464:                if (oifp)
                    465:                        icmp6_ifoutstat_inc(oifp, type, code);
                    466:                icmp6stat.icp6s_outhist[type]++;
                    467:        }
1.2       itojun    468:
                    469:        goto freectl;
                    470:
                    471:  bad:
                    472:        if (m)
                    473:                m_freem(m);
                    474:
                    475:  freectl:
                    476:        if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
                    477:                RTFREE(optp->ip6po_route.ro_rt);
                    478:        if (control)
                    479:                m_freem(control);
                    480:        return(error);
                    481: }
                    482:
                    483: /*
                    484:  * Raw IPv6 socket option processing.
                    485:  */
                    486: int
                    487: rip6_ctloutput(op, so, level, optname, m)
                    488:        int op;
                    489:        struct socket *so;
                    490:        int level, optname;
                    491:        struct mbuf **m;
                    492: {
                    493:        int error = 0;
                    494:
                    495:        switch(level) {
                    496:         case IPPROTO_IPV6:
                    497:                 switch(optname) {
                    498:                  case MRT6_INIT:
                    499:                  case MRT6_DONE:
                    500:                  case MRT6_ADD_MIF:
                    501:                  case MRT6_DEL_MIF:
                    502:                  case MRT6_ADD_MFC:
                    503:                  case MRT6_DEL_MFC:
                    504:                  case MRT6_PIM:
                    505:                          if (op == PRCO_SETOPT) {
                    506:                                  error = ip6_mrouter_set(optname, so, *m);
                    507:                                  if (*m)
                    508:                                          (void)m_free(*m);
                    509:                          } else if (op == PRCO_GETOPT) {
                    510:                                  error = ip6_mrouter_get(optname, so, m);
                    511:                          } else
                    512:                                  error = EINVAL;
                    513:                          return (error);
                    514:                 }
                    515:                 return (ip6_ctloutput(op, so, level, optname, m));
                    516:                 /* NOTREACHED */
                    517:
                    518:         case IPPROTO_ICMPV6:
                    519:                 /*
                    520:                  * XXX: is it better to call icmp6_ctloutput() directly
                    521:                  * from protosw?
                    522:                  */
                    523:                 return(icmp6_ctloutput(op, so, level, optname, m));
                    524:
                    525:         default:
                    526:                 if (op == PRCO_SETOPT && *m)
                    527:                         (void)m_free(*m);
                    528:                 return(EINVAL);
                    529:        }
                    530: }
                    531:
                    532: extern u_long rip6_sendspace;
                    533: extern u_long rip6_recvspace;
                    534:
                    535: int
                    536: rip6_usrreq(so, req, m, nam, control, p)
                    537:        register struct socket *so;
                    538:        int req;
                    539:        struct mbuf *m, *nam, *control;
                    540:        struct proc *p;
                    541: {
                    542:        register struct in6pcb *in6p = sotoin6pcb(so);
                    543:        int s;
                    544:        int error = 0;
                    545: /*     extern  struct socket *ip6_mrouter; */ /* xxx */
1.12      itojun    546:        int priv;
                    547:
                    548:        priv = 0;
                    549:        if (p && !suser(p->p_ucred, &p->p_acflag))
                    550:                priv++;
1.2       itojun    551:
                    552:        if (req == PRU_CONTROL)
                    553:                return (in6_control(so, (u_long)m, (caddr_t)nam,
                    554:                                    (struct ifnet *)control, p));
1.17      thorpej   555:
1.18      thorpej   556:        if (req == PRU_PURGEIF) {
                    557:                in6_purgeif((struct ifnet *)control);
                    558:                in6_pcbpurgeif(&rawin6pcb, (struct ifnet *)control);
1.17      thorpej   559:                return (0);
                    560:        }
1.2       itojun    561:
                    562:        switch (req) {
                    563:        case PRU_ATTACH:
                    564:                if (in6p)
                    565:                        panic("rip6_attach");
1.12      itojun    566:                if (!priv) {
1.2       itojun    567:                        error = EACCES;
                    568:                        break;
                    569:                }
1.4       itojun    570:                s = splsoftnet();
1.2       itojun    571:                if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) ||
                    572:                    (error = in6_pcballoc(so, &rawin6pcb))) {
                    573:                        splx(s);
                    574:                        break;
                    575:                }
                    576:                splx(s);
                    577:                in6p = sotoin6pcb(so);
1.5       itojun    578:                in6p->in6p_ip6.ip6_nxt = (long)nam;
1.2       itojun    579:                in6p->in6p_cksum = -1;
                    580: #ifdef IPSEC
1.16      itojun    581:                error = ipsec_init_policy(so, &in6p->in6p_sp);
1.12      itojun    582:                if (error != 0) {
1.11      itojun    583:                        in6_pcbdetach(in6p);
1.2       itojun    584:                        break;
1.11      itojun    585:                }
1.2       itojun    586: #endif /*IPSEC*/
                    587:
                    588:                MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
                    589:                        sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
1.12      itojun    590:                if (in6p->in6p_icmp6filt == NULL) {
                    591:                        in6_pcbdetach(in6p);
                    592:                        error = ENOMEM;
                    593:                        break;
                    594:                }
1.2       itojun    595:                ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
                    596:                break;
                    597:
                    598:        case PRU_DISCONNECT:
                    599:                if ((so->so_state & SS_ISCONNECTED) == 0) {
                    600:                        error = ENOTCONN;
                    601:                        break;
                    602:                }
                    603:                in6p->in6p_faddr = in6addr_any;
                    604:                so->so_state &= ~SS_ISCONNECTED;        /* XXX */
                    605:                break;
                    606:
                    607:        case PRU_ABORT:
                    608:                soisdisconnected(so);
                    609:                /* Fallthrough */
                    610:        case PRU_DETACH:
                    611:                if (in6p == 0)
                    612:                        panic("rip6_detach");
                    613:                if (so == ip6_mrouter)
                    614:                        ip6_mrouter_done();
                    615:                /* xxx: RSVP */
                    616:                if (in6p->in6p_icmp6filt) {
                    617:                        FREE(in6p->in6p_icmp6filt, M_PCB);
                    618:                        in6p->in6p_icmp6filt = NULL;
                    619:                }
                    620:                in6_pcbdetach(in6p);
                    621:                break;
                    622:
                    623:        case PRU_BIND:
                    624:            {
                    625:                struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
                    626:                struct ifaddr *ia = NULL;
                    627:
                    628:                if (nam->m_len != sizeof(*addr)) {
                    629:                        error = EINVAL;
                    630:                        break;
                    631:                }
1.23    ! itojun    632:
        !           633:                /*
        !           634:                 * we don't support mapped address here, it would confuse
        !           635:                 * users so reject it
        !           636:                 */
        !           637:                if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
        !           638:                        error = EADDRNOTAVAIL;
        !           639:                        break;
        !           640:                }
        !           641:
1.2       itojun    642:                if ((ifnet.tqh_first == 0) ||
                    643:                   (addr->sin6_family != AF_INET6) ||
1.12      itojun    644:                   (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
1.2       itojun    645:                    (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) {
                    646:                        error = EADDRNOTAVAIL;
                    647:                        break;
                    648:                }
                    649:                if (ia &&
                    650:                    ((struct in6_ifaddr *)ia)->ia6_flags &
                    651:                    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
                    652:                     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
                    653:                        error = EADDRNOTAVAIL;
                    654:                        break;
                    655:                }
                    656:                in6p->in6p_laddr = addr->sin6_addr;
                    657:                break;
                    658:            }
                    659:
                    660:        case PRU_CONNECT:
                    661:            {
                    662:                struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
                    663:                struct in6_addr *in6a = NULL;
                    664:
                    665:                if (nam->m_len != sizeof(*addr)) {
                    666:                        error = EINVAL;
                    667:                        break;
                    668:                }
                    669:                if (ifnet.tqh_first == 0) {
                    670:                        error = EADDRNOTAVAIL;
                    671:                        break;
                    672:                }
                    673:                if (addr->sin6_family != AF_INET6) {
                    674:                        error = EAFNOSUPPORT;
                    675:                        break;
                    676:                }
                    677:
                    678:                /* Source address selection. XXX: need pcblookup? */
1.12      itojun    679:                in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
                    680:                                     in6p->in6p_moptions,
                    681:                                     &in6p->in6p_route,
                    682:                                     &in6p->in6p_laddr,
                    683:                                     &error);
                    684:                if (in6a == NULL) {
1.2       itojun    685:                        if (error == 0)
                    686:                                error = EADDRNOTAVAIL;
                    687:                        break;
                    688:                }
                    689:                in6p->in6p_laddr = *in6a;
                    690:                in6p->in6p_faddr = addr->sin6_addr;
                    691:                soisconnected(so);
                    692:                break;
                    693:            }
                    694:
                    695:        case PRU_CONNECT2:
                    696:                error = EOPNOTSUPP;
                    697:                break;
                    698:
                    699:        /*
                    700:         * Mark the connection as being incapable of futther input.
                    701:         */
                    702:        case PRU_SHUTDOWN:
                    703:                socantsendmore(so);
                    704:                break;
                    705:        /*
                    706:         * Ship a packet out. The appropriate raw output
                    707:         * routine handles any messaging necessary.
                    708:         */
                    709:        case PRU_SEND:
                    710:            {
                    711:                struct sockaddr_in6 tmp;
                    712:                struct sockaddr_in6 *dst;
                    713:
                    714:                if (so->so_state & SS_ISCONNECTED) {
                    715:                        if (nam) {
                    716:                                error = EISCONN;
                    717:                                break;
                    718:                        }
                    719:                        /* XXX */
                    720:                        bzero(&tmp, sizeof(tmp));
                    721:                        tmp.sin6_family = AF_INET6;
                    722:                        tmp.sin6_len = sizeof(struct sockaddr_in6);
                    723:                        bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
                    724:                                sizeof(struct in6_addr));
                    725:                        dst = &tmp;
                    726:                } else {
                    727:                        if (nam == NULL) {
                    728:                                error = ENOTCONN;
                    729:                                break;
                    730:                        }
                    731:                        dst = mtod(nam, struct sockaddr_in6 *);
                    732:                }
                    733:                error = rip6_output(m, so, dst, control);
                    734:                m = NULL;
                    735:                break;
                    736:            }
                    737:
                    738:        case PRU_SENSE:
                    739:                /*
                    740:                 * stat: don't bother with a blocksize
                    741:                 */
                    742:                return(0);
                    743:        /*
                    744:         * Not supported.
                    745:         */
                    746:        case PRU_RCVOOB:
                    747:        case PRU_RCVD:
                    748:        case PRU_LISTEN:
                    749:        case PRU_ACCEPT:
                    750:        case PRU_SENDOOB:
                    751:                error = EOPNOTSUPP;
                    752:                break;
                    753:
                    754:        case PRU_SOCKADDR:
                    755:                in6_setsockaddr(in6p, nam);
                    756:                break;
                    757:
                    758:        case PRU_PEERADDR:
                    759:                in6_setpeeraddr(in6p, nam);
                    760:                break;
                    761:
                    762:        default:
                    763:                panic("rip6_usrreq");
                    764:        }
                    765:        if (m != NULL)
                    766:                m_freem(m);
                    767:        return(error);
                    768: }

CVSweb <webmaster@jp.NetBSD.org>