[BACK]Return to in6_pcb.c CVS log [TXT][DIR] Up to [local] / sys / netinet6

Annotation of sys/netinet6/in6_pcb.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: in6_pcb.c,v 1.43 2005/06/24 07:57:24 markus Exp $     */
        !             2:
        !             3: /*
        !             4:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. Neither the name of the project nor the names of its contributors
        !            16:  *    may be used to endorse or promote products derived from this software
        !            17:  *    without specific prior written permission.
        !            18:  *
        !            19:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            29:  * SUCH DAMAGE.
        !            30:  */
        !            31:
        !            32: /*
        !            33:  *     @(#)COPYRIGHT   1.1 (NRL) 17 January 1995
        !            34:  *
        !            35:  * NRL grants permission for redistribution and use in source and binary
        !            36:  * forms, with or without modification, of the software and documentation
        !            37:  * created at NRL provided that the following conditions are met:
        !            38:  *
        !            39:  * 1. Redistributions of source code must retain the above copyright
        !            40:  *    notice, this list of conditions and the following disclaimer.
        !            41:  * 2. Redistributions in binary form must reproduce the above copyright
        !            42:  *    notice, this list of conditions and the following disclaimer in the
        !            43:  *    documentation and/or other materials provided with the distribution.
        !            44:  * 3. All advertising materials mentioning features or use of this software
        !            45:  *    must display the following acknowledgements:
        !            46:  *     This product includes software developed by the University of
        !            47:  *     California, Berkeley and its contributors.
        !            48:  *     This product includes software developed at the Information
        !            49:  *     Technology Division, US Naval Research Laboratory.
        !            50:  * 4. Neither the name of the NRL nor the names of its contributors
        !            51:  *    may be used to endorse or promote products derived from this software
        !            52:  *    without specific prior written permission.
        !            53:  *
        !            54:  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
        !            55:  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            56:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
        !            57:  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
        !            58:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
        !            59:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
        !            60:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
        !            61:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
        !            62:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
        !            63:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
        !            64:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            65:  *
        !            66:  * The views and conclusions contained in the software and documentation
        !            67:  * are those of the authors and should not be interpreted as representing
        !            68:  * official policies, either expressed or implied, of the US Naval
        !            69:  * Research Laboratory (NRL).
        !            70:  */
        !            71:
        !            72: /*
        !            73:  * Copyright (c) 1982, 1986, 1990, 1993, 1995
        !            74:  *     Regents of the University of California.  All rights reserved.
        !            75:  *
        !            76:  * Redistribution and use in source and binary forms, with or without
        !            77:  * modification, are permitted provided that the following conditions
        !            78:  * are met:
        !            79:  * 1. Redistributions of source code must retain the above copyright
        !            80:  *    notice, this list of conditions and the following disclaimer.
        !            81:  * 2. Redistributions in binary form must reproduce the above copyright
        !            82:  *    notice, this list of conditions and the following disclaimer in the
        !            83:  *    documentation and/or other materials provided with the distribution.
        !            84:  * 3. Neither the name of the University nor the names of its contributors
        !            85:  *    may be used to endorse or promote products derived from this software
        !            86:  *    without specific prior written permission.
        !            87:  *
        !            88:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            89:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            90:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            91:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            92:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            93:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            94:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            95:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            96:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            97:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            98:  * SUCH DAMAGE.
        !            99:  *
        !           100:  */
        !           101:
        !           102: #include <sys/param.h>
        !           103: #include <sys/systm.h>
        !           104: #include <sys/malloc.h>
        !           105: #include <sys/mbuf.h>
        !           106: #include <sys/domain.h>
        !           107: #include <sys/protosw.h>
        !           108: #include <sys/socket.h>
        !           109: #include <sys/socketvar.h>
        !           110: #include <sys/errno.h>
        !           111: #include <sys/time.h>
        !           112: #include <sys/proc.h>
        !           113:
        !           114: #include <net/if.h>
        !           115: #include <net/route.h>
        !           116:
        !           117: #include <netinet/in.h>
        !           118: #include <netinet/in_systm.h>
        !           119: #include <netinet/ip.h>
        !           120: #include <netinet/in_pcb.h>
        !           121:
        !           122: #include <netinet6/in6_var.h>
        !           123: #include <netinet/ip6.h>
        !           124: #include <netinet6/ip6_var.h>
        !           125:
        !           126: /*
        !           127:  * External globals
        !           128:  */
        !           129:
        !           130: #include <dev/rndvar.h>
        !           131:
        !           132: extern struct in6_ifaddr *in6_ifaddr;
        !           133:
        !           134: /*
        !           135:  * Globals
        !           136:  */
        !           137:
        !           138: struct in6_addr zeroin6_addr;
        !           139:
        !           140: extern int ipport_firstauto;
        !           141: extern int ipport_lastauto;
        !           142: extern int ipport_hifirstauto;
        !           143: extern int ipport_hilastauto;
        !           144:
        !           145: /*
        !           146:  * Keep separate inet6ctlerrmap, because I may remap some of these.
        !           147:  * I also put it here, because, quite frankly, it belongs here, not in
        !           148:  * ip{v6,}_input().
        !           149:  */
        !           150: #if 0
        !           151: u_char inet6ctlerrmap[PRC_NCMDS] = {
        !           152:        0,              0,              0,              0,
        !           153:        0,              EMSGSIZE,       EHOSTDOWN,      EHOSTUNREACH,
        !           154:        EHOSTUNREACH,   EHOSTUNREACH,   ECONNREFUSED,   ECONNREFUSED,
        !           155:        EMSGSIZE,       EHOSTUNREACH,   0,              0,
        !           156:        0,              0,              0,              0,
        !           157:        ENOPROTOOPT
        !           158: };
        !           159: #endif
        !           160:
        !           161: /*
        !           162:  * Bind an address (or at least a port) to an PF_INET6 socket.
        !           163:  */
        !           164: int
        !           165: in6_pcbbind(inp, nam)
        !           166:        struct inpcb *inp;
        !           167:        struct mbuf *nam;
        !           168: {
        !           169:        struct socket *so = inp->inp_socket;
        !           170:
        !           171:        struct inpcbtable *head = inp->inp_table;
        !           172:        struct sockaddr_in6 *sin6;
        !           173:        struct proc *p = curproc;               /* XXX */
        !           174:        u_short lport = 0;
        !           175:        int wild = INPLOOKUP_IPV6, reuseport = (so->so_options & SO_REUSEPORT);
        !           176:        int error;
        !           177:
        !           178:        /*
        !           179:         * REMINDER:  Once up to speed, flow label processing should go here,
        !           180:         * too.  (Same with in6_pcbconnect.)
        !           181:         */
        !           182:        if (in6_ifaddr == 0)
        !           183:                return EADDRNOTAVAIL;
        !           184:
        !           185:        if (inp->inp_lport != 0 || !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
        !           186:                return EINVAL;  /* If already bound, EINVAL! */
        !           187:
        !           188:        if ((so->so_options & (SO_REUSEADDR | SO_REUSEPORT)) == 0 &&
        !           189:            ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
        !           190:             (so->so_options & SO_ACCEPTCONN) == 0))
        !           191:                wild |= INPLOOKUP_WILDCARD;
        !           192:
        !           193:        /*
        !           194:         * If I did get a sockaddr passed in...
        !           195:         */
        !           196:        if (nam) {
        !           197:                sin6 = mtod(nam, struct sockaddr_in6 *);
        !           198:                if (nam->m_len != sizeof (*sin6))
        !           199:                        return EINVAL;
        !           200:
        !           201:                /*
        !           202:                 * Unlike v4, I have no qualms about EAFNOSUPPORT if the
        !           203:                 * wretched family is not filled in!
        !           204:                 */
        !           205:                if (sin6->sin6_family != AF_INET6)
        !           206:                        return EAFNOSUPPORT;
        !           207:
        !           208:                /* KAME hack: embed scopeid */
        !           209:                if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0)
        !           210:                        return EINVAL;
        !           211:                /* this must be cleared for ifa_ifwithaddr() */
        !           212:                sin6->sin6_scope_id = 0;
        !           213:
        !           214:                lport = sin6->sin6_port;
        !           215:
        !           216:                /* reject IPv4 mapped address, we have no support for it */
        !           217:                if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
        !           218:                        return EADDRNOTAVAIL;
        !           219:
        !           220:                if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
        !           221:                        /*
        !           222:                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
        !           223:                         * allow complete duplication of binding if
        !           224:                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
        !           225:                         * and a multicast address is bound on both
        !           226:                         * new and duplicated sockets.
        !           227:                         */
        !           228:                        if (so->so_options & SO_REUSEADDR)
        !           229:                                reuseport = SO_REUSEADDR | SO_REUSEPORT;
        !           230:                } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
        !           231:                        struct ifaddr *ia = NULL;
        !           232:
        !           233:                        sin6->sin6_port = 0;  /*
        !           234:                                               * Yechhhh, because of upcoming
        !           235:                                               * call to ifa_ifwithaddr(), which
        !           236:                                               * does bcmp's over the PORTS as
        !           237:                                               * well.  (What about flow?)
        !           238:                                               */
        !           239:                        sin6->sin6_flowinfo = 0;
        !           240:                        if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6))
        !           241:                            == NULL)
        !           242:                                return EADDRNOTAVAIL;
        !           243:
        !           244:                        /*
        !           245:                         * bind to an anycast address might accidentally
        !           246:                         * cause sending a packet with an anycast source
        !           247:                         * address, so we forbid it.
        !           248:                         *
        !           249:                         * We should allow to bind to a deprecated address,
        !           250:                         * since the application dare to use it.
        !           251:                         * But, can we assume that they are careful enough
        !           252:                         * to check if the address is deprecated or not?
        !           253:                         * Maybe, as a safeguard, we should have a setsockopt
        !           254:                         * flag to control the bind(2) behavior against
        !           255:                         * deprecated addresses (default: forbid bind(2)).
        !           256:                         */
        !           257:                        if (ia &&
        !           258:                            ((struct in6_ifaddr *)ia)->ia6_flags &
        !           259:                            (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED))
        !           260:                                return (EADDRNOTAVAIL);
        !           261:                }
        !           262:                if (lport) {
        !           263:                        struct inpcb *t;
        !           264:
        !           265:                        /*
        !           266:                         * Question:  Do we wish to continue the Berkeley
        !           267:                         * tradition of ports < IPPORT_RESERVED be only for
        !           268:                         * root?
        !           269:                         * Answer: For now yes, but IMHO, it should be REMOVED!
        !           270:                         * OUCH: One other thing, is there no better way of
        !           271:                         * finding a process for a socket instead of using
        !           272:                         * curproc?  (Marked with BSD's {in,}famous XXX ?
        !           273:                         */
        !           274:                        if (ntohs(lport) < IPPORT_RESERVED &&
        !           275:                            (error = suser(p, 0)))
        !           276:                                return error;
        !           277:
        !           278:                        t = in_pcblookup(head,
        !           279:                            (struct in_addr *)&zeroin6_addr, 0,
        !           280:                            (struct in_addr *)&sin6->sin6_addr, lport,
        !           281:                            wild);
        !           282:
        !           283:                        if (t && (reuseport & t->inp_socket->so_options) == 0)
        !           284:                                return EADDRINUSE;
        !           285:                }
        !           286:                inp->inp_laddr6 = sin6->sin6_addr;
        !           287:        }
        !           288:
        !           289:        if (lport == 0) {
        !           290:                error = in6_pcbsetport(&inp->inp_laddr6, inp, p);
        !           291:                if (error != 0)
        !           292:                        return error;
        !           293:        } else {
        !           294:                inp->inp_lport = lport;
        !           295:                in_pcbrehash(inp);
        !           296:        }
        !           297:
        !           298:        return 0;
        !           299: }
        !           300:
        !           301: int
        !           302: in6_pcbsetport(laddr, inp, p)
        !           303:        struct in6_addr *laddr;
        !           304:        struct inpcb *inp;
        !           305:        struct proc *p;
        !           306: {
        !           307:        struct socket *so = inp->inp_socket;
        !           308:        struct inpcbtable *table = inp->inp_table;
        !           309:        u_int16_t first, last;
        !           310:        u_int16_t *lastport = &inp->inp_table->inpt_lastport;
        !           311:        u_int16_t lport = 0;
        !           312:        int count;
        !           313:        int wild = INPLOOKUP_IPV6;
        !           314:        int error;
        !           315:
        !           316:        /* XXX we no longer support IPv4 mapped address, so no tweaks here */
        !           317:
        !           318:        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
        !           319:            ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
        !           320:             (so->so_options & SO_ACCEPTCONN) == 0))
        !           321:                wild |= INPLOOKUP_WILDCARD;
        !           322:
        !           323:        if (inp->inp_flags & INP_HIGHPORT) {
        !           324:                first = ipport_hifirstauto;     /* sysctl */
        !           325:                last = ipport_hilastauto;
        !           326:        } else if (inp->inp_flags & INP_LOWPORT) {
        !           327:                if ((error = suser(p, 0)))
        !           328:                        return (EACCES);
        !           329:                first = IPPORT_RESERVED-1; /* 1023 */
        !           330:                last = 600;                /* not IPPORT_RESERVED/2 */
        !           331:        } else {
        !           332:                first = ipport_firstauto;       /* sysctl */
        !           333:                last  = ipport_lastauto;
        !           334:        }
        !           335:
        !           336:        /*
        !           337:         * Simple check to ensure all ports are not used up causing
        !           338:         * a deadlock here.
        !           339:         *
        !           340:         * We split the two cases (up and down) so that the direction
        !           341:         * is not being tested on each round of the loop.
        !           342:         */
        !           343:
        !           344:        if (first > last) {
        !           345:                /*
        !           346:                 * counting down
        !           347:                 */
        !           348:                count = first - last;
        !           349:                if (count)
        !           350:                        *lastport = first - (arc4random() % count);
        !           351:
        !           352:                do {
        !           353:                        if (count-- < 0)        /* completely used? */
        !           354:                                return (EADDRNOTAVAIL);
        !           355:                        --*lastport;
        !           356:                        if (*lastport > first || *lastport < last)
        !           357:                                *lastport = first;
        !           358:                        lport = htons(*lastport);
        !           359:                } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
        !           360:                    in_pcblookup(table, &zeroin6_addr, 0,
        !           361:                    &inp->inp_laddr6, lport, wild));
        !           362:        } else {
        !           363:                /*
        !           364:                 * counting up
        !           365:                 */
        !           366:                count = last - first;
        !           367:                if (count)
        !           368:                        *lastport = first + (arc4random() % count);
        !           369:
        !           370:                do {
        !           371:                        if (count-- < 0)        /* completely used? */
        !           372:                                return (EADDRNOTAVAIL);
        !           373:                        ++*lastport;
        !           374:                        if (*lastport < first || *lastport > last)
        !           375:                                *lastport = first;
        !           376:                        lport = htons(*lastport);
        !           377:                } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
        !           378:                    in_pcblookup(table, &zeroin6_addr, 0,
        !           379:                    &inp->inp_laddr6, lport, wild));
        !           380:        }
        !           381:
        !           382:        inp->inp_lport = lport;
        !           383:        in_pcbrehash(inp);
        !           384:
        !           385: #if 0
        !           386:        inp->inp_flowinfo = 0;  /* XXX */
        !           387: #endif
        !           388:
        !           389:        return 0;
        !           390: }
        !           391:
        !           392: /*
        !           393:  * Connect from a socket to a specified address.
        !           394:  * Both address and port must be specified in argument sin6.
        !           395:  * Eventually, flow labels will have to be dealt with here, as well.
        !           396:  *
        !           397:  * If don't have a local address for this socket yet,
        !           398:  * then pick one.
        !           399:  *
        !           400:  * I believe this has to be called at splnet().
        !           401:  */
        !           402: int
        !           403: in6_pcbconnect(inp, nam)
        !           404:        struct inpcb *inp;
        !           405:        struct mbuf *nam;
        !           406: {
        !           407:        struct in6_addr *in6a = NULL;
        !           408:        struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
        !           409:        struct ifnet *ifp = NULL;       /* outgoing interface */
        !           410:        int error = 0;
        !           411:        struct sockaddr_in6 tmp;
        !           412:
        !           413:        (void)&in6a;                            /* XXX fool gcc */
        !           414:
        !           415:        if (nam->m_len != sizeof(*sin6))
        !           416:                return (EINVAL);
        !           417:        if (sin6->sin6_family != AF_INET6)
        !           418:                return (EAFNOSUPPORT);
        !           419:        if (sin6->sin6_port == 0)
        !           420:                return (EADDRNOTAVAIL);
        !           421:
        !           422:        /* reject IPv4 mapped address, we have no support for it */
        !           423:        if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
        !           424:                return EADDRNOTAVAIL;
        !           425:
        !           426:        /* sanity check for mapped address case */
        !           427:        if (IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6))
        !           428:                return EINVAL;
        !           429:
        !           430:        /* protect *sin6 from overwrites */
        !           431:        tmp = *sin6;
        !           432:        sin6 = &tmp;
        !           433:
        !           434:        /* KAME hack: embed scopeid */
        !           435:        if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0)
        !           436:                return EINVAL;
        !           437:        /* this must be cleared for ifa_ifwithaddr() */
        !           438:        sin6->sin6_scope_id = 0;
        !           439:
        !           440:        /* Source address selection. */
        !           441:        /*
        !           442:         * XXX: in6_selectsrc might replace the bound local address
        !           443:         * with the address specified by setsockopt(IPV6_PKTINFO).
        !           444:         * Is it the intended behavior?
        !           445:         */
        !           446:        in6a = in6_selectsrc(sin6, inp->inp_outputopts6,
        !           447:            inp->inp_moptions6, &inp->inp_route6, &inp->inp_laddr6,
        !           448:            &error);
        !           449:        if (in6a == 0) {
        !           450:                if (error == 0)
        !           451:                        error = EADDRNOTAVAIL;
        !           452:                return (error);
        !           453:        }
        !           454:
        !           455:        if (inp->inp_route6.ro_rt)
        !           456:                ifp = inp->inp_route6.ro_rt->rt_ifp;
        !           457:
        !           458:        inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp, ifp);
        !           459:
        !           460:        if (in_pcblookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port,
        !           461:            IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6,
        !           462:            inp->inp_lport, INPLOOKUP_IPV6)) {
        !           463:                return (EADDRINUSE);
        !           464:        }
        !           465:        if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
        !           466:                if (inp->inp_lport == 0)
        !           467:                        (void)in6_pcbbind(inp, (struct mbuf *)0);
        !           468:                inp->inp_laddr6 = *in6a;
        !           469:        }
        !           470:        inp->inp_faddr6 = sin6->sin6_addr;
        !           471:        inp->inp_fport = sin6->sin6_port;
        !           472:        inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK;
        !           473:        if (ip6_auto_flowlabel)
        !           474:                inp->inp_flowinfo |=
        !           475:                    (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
        !           476:        in_pcbrehash(inp);
        !           477:        return (0);
        !           478: }
        !           479:
        !           480: /*
        !           481:  * Pass some notification to all connections of a protocol
        !           482:  * associated with address dst.  The local address and/or port numbers
        !           483:  * may be specified to limit the search.  The "usual action" will be
        !           484:  * taken, depending on the ctlinput cmd.  The caller must filter any
        !           485:  * cmds that are uninteresting (e.g., no error in the map).
        !           486:  * Call the protocol specific routine (if any) to report
        !           487:  * any errors for each matching socket.
        !           488:  *
        !           489:  * Also perform input-side security policy check
        !           490:  *    once PCB to be notified has been located.
        !           491:  *
        !           492:  * Must be called at splnet.
        !           493:  */
        !           494: int
        !           495: in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)
        !           496:        struct inpcbtable *head;
        !           497:        struct sockaddr *dst, *src;
        !           498:        uint fport_arg;
        !           499:        uint lport_arg;
        !           500:        int cmd;
        !           501:        void *cmdarg;
        !           502:        void (*notify)(struct inpcb *, int);
        !           503: {
        !           504:        struct inpcb *inp, *ninp;
        !           505:        u_short fport = fport_arg, lport = lport_arg;
        !           506:        struct sockaddr_in6 sa6_src, *sa6_dst;
        !           507:        int errno, nmatch = 0;
        !           508:        u_int32_t flowinfo;
        !           509:
        !           510:        if ((unsigned)cmd >= PRC_NCMDS || dst->sa_family != AF_INET6)
        !           511:                return (0);
        !           512:
        !           513:        sa6_dst = (struct sockaddr_in6 *)dst;
        !           514:        if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
        !           515:                return (0);
        !           516:        if (IN6_IS_ADDR_V4MAPPED(&sa6_dst->sin6_addr)) {
        !           517: #ifdef DIAGNOSTIC
        !           518:                printf("Huh?  Thought in6_pcbnotify() never got "
        !           519:                       "called with mapped!\n");
        !           520: #endif
        !           521:                return (0);
        !           522:        }
        !           523:
        !           524:        /*
        !           525:         * note that src can be NULL when we get notify by local fragmentation.
        !           526:         */
        !           527:        sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;
        !           528:        flowinfo = sa6_src.sin6_flowinfo;
        !           529:
        !           530:        /*
        !           531:         * Redirects go to all references to the destination,
        !           532:         * and use in_rtchange to invalidate the route cache.
        !           533:         * Dead host indications: also use in_rtchange to invalidate
        !           534:         * the cache, and deliver the error to all the sockets.
        !           535:         * Otherwise, if we have knowledge of the local port and address,
        !           536:         * deliver only to that socket.
        !           537:         */
        !           538:        if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
        !           539:                fport = 0;
        !           540:                lport = 0;
        !           541:                sa6_src.sin6_addr = in6addr_any;
        !           542:
        !           543:                if (cmd != PRC_HOSTDEAD)
        !           544:                        notify = in_rtchange;
        !           545:        }
        !           546:        errno = inet6ctlerrmap[cmd];
        !           547:
        !           548:        for (inp = CIRCLEQ_FIRST(&head->inpt_queue);
        !           549:             inp != CIRCLEQ_END(&head->inpt_queue); inp = ninp) {
        !           550:                ninp = CIRCLEQ_NEXT(inp, inp_queue);
        !           551:
        !           552:                if ((inp->inp_flags & INP_IPV6) == 0)
        !           553:                        continue;
        !           554:
        !           555:                /*
        !           556:                 * Under the following condition, notify of redirects
        !           557:                 * to the pcb, without making address matches against inpcb.
        !           558:                 * - redirect notification is arrived.
        !           559:                 * - the inpcb is unconnected.
        !           560:                 * - the inpcb is caching !RTF_HOST routing entry.
        !           561:                 * - the ICMPv6 notification is from the gateway cached in the
        !           562:                 *   inpcb.  i.e. ICMPv6 notification is from nexthop gateway
        !           563:                 *   the inpcb used very recently.
        !           564:                 *
        !           565:                 * This is to improve interaction between netbsd/openbsd
        !           566:                 * redirect handling code, and inpcb route cache code.
        !           567:                 * without the clause, !RTF_HOST routing entry (which carries
        !           568:                 * gateway used by inpcb right before the ICMPv6 redirect)
        !           569:                 * will be cached forever in unconnected inpcb.
        !           570:                 *
        !           571:                 * There still is a question regarding to what is TRT:
        !           572:                 * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be
        !           573:                 *   generated on packet output.  inpcb will always cache
        !           574:                 *   RTF_HOST routing entry so there's no need for the clause
        !           575:                 *   (ICMPv6 redirect will update RTF_HOST routing entry,
        !           576:                 *   and inpcb is caching it already).
        !           577:                 *   However, bsdi/freebsd are vulnerable to local DoS attacks
        !           578:                 *   due to the cloned routing entries.
        !           579:                 * - Specwise, "destination cache" is mentioned in RFC2461.
        !           580:                 *   Jinmei says that it implies bsdi/freebsd behavior, itojun
        !           581:                 *   is not really convinced.
        !           582:                 * - Having hiwat/lowat on # of cloned host route (redirect/
        !           583:                 *   pmtud) may be a good idea.  netbsd/openbsd has it.  see
        !           584:                 *   icmp6_mtudisc_update().
        !           585:                 */
        !           586:                if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
        !           587:                    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
        !           588:                    inp->inp_route.ro_rt &&
        !           589:                    !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) {
        !           590:                        struct sockaddr_in6 *dst6;
        !           591:
        !           592:                        dst6 = (struct sockaddr_in6 *)&inp->inp_route.ro_dst;
        !           593:                        if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
        !           594:                            &sa6_dst->sin6_addr))
        !           595:                                goto do_notify;
        !           596:                }
        !           597:
        !           598:                /*
        !           599:                 * Detect if we should notify the error. If no source and
        !           600:                 * destination ports are specified, but non-zero flowinfo and
        !           601:                 * local address match, notify the error. This is the case
        !           602:                 * when the error is delivered with an encrypted buffer
        !           603:                 * by ESP. Otherwise, just compare addresses and ports
        !           604:                 * as usual.
        !           605:                 */
        !           606:                if (lport == 0 && fport == 0 && flowinfo &&
        !           607:                    inp->inp_socket != NULL &&
        !           608:                    flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) &&
        !           609:                    IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr))
        !           610:                        goto do_notify;
        !           611:                else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
        !           612:                                             &sa6_dst->sin6_addr) ||
        !           613:                         inp->inp_socket == 0 ||
        !           614:                         (lport && inp->inp_lport != lport) ||
        !           615:                         (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
        !           616:                          !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
        !           617:                                              &sa6_src.sin6_addr)) ||
        !           618:                         (fport && inp->inp_fport != fport)) {
        !           619:                        continue;
        !           620:                }
        !           621:          do_notify:
        !           622:                nmatch++;
        !           623:                if (notify)
        !           624:                        (*notify)(inp, errno);
        !           625:        }
        !           626:        return (nmatch);
        !           627: }
        !           628:
        !           629: /*
        !           630:  * Get the local address/port, and put it in a sockaddr_in6.
        !           631:  * This services the getsockname(2) call.
        !           632:  */
        !           633: int
        !           634: in6_setsockaddr(inp, nam)
        !           635:        struct inpcb *inp;
        !           636:        struct mbuf *nam;
        !           637: {
        !           638:        struct sockaddr_in6 *sin6;
        !           639:
        !           640:        nam->m_len = sizeof(struct sockaddr_in6);
        !           641:        sin6 = mtod(nam,struct sockaddr_in6 *);
        !           642:
        !           643:        bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
        !           644:        sin6->sin6_family = AF_INET6;
        !           645:        sin6->sin6_len = sizeof(struct sockaddr_in6);
        !           646:        sin6->sin6_port = inp->inp_lport;
        !           647:        sin6->sin6_addr = inp->inp_laddr6;
        !           648:        /* KAME hack: recover scopeid */
        !           649:        (void)in6_recoverscope(sin6, &inp->inp_laddr6, NULL);
        !           650:
        !           651:        return 0;
        !           652: }
        !           653:
        !           654: /*
        !           655:  * Get the foreign address/port, and put it in a sockaddr_in6.
        !           656:  * This services the getpeername(2) call.
        !           657:  */
        !           658: int
        !           659: in6_setpeeraddr(inp, nam)
        !           660:        struct inpcb *inp;
        !           661:        struct mbuf *nam;
        !           662: {
        !           663:        struct sockaddr_in6 *sin6;
        !           664:
        !           665:        nam->m_len = sizeof(struct sockaddr_in6);
        !           666:        sin6 = mtod(nam,struct sockaddr_in6 *);
        !           667:
        !           668:        bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
        !           669:        sin6->sin6_family = AF_INET6;
        !           670:        sin6->sin6_len = sizeof(struct sockaddr_in6);
        !           671:        sin6->sin6_port = inp->inp_fport;
        !           672:        sin6->sin6_addr = inp->inp_faddr6;
        !           673:        /* KAME hack: recover scopeid */
        !           674:        (void)in6_recoverscope(sin6, &inp->inp_faddr6, NULL);
        !           675:
        !           676:        return 0;
        !           677: }

CVSweb