[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

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