[BACK]Return to in6_pcb.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/in6_pcb.c, Revision 1.26.2.1

1.26.2.1! itojun      1: /*     $NetBSD: in6_pcb.c,v 1.26 2000/06/08 13:51:33 itojun Exp $      */
        !             2: /*     $KAME: in6_pcb.c,v 1.55 2000/07/02 07:50:30 itojun Exp $        */
1.5       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.23      itojun      7:  *
1.2       itojun      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the project nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
1.23      itojun     19:  *
1.2       itojun     20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * Copyright (c) 1982, 1986, 1991, 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:  *     @(#)in_pcb.c    8.2 (Berkeley) 1/4/94
                     66:  */
1.7       thorpej    67:
                     68: #include "opt_ipsec.h"
1.2       itojun     69:
                     70: #include <sys/param.h>
                     71: #include <sys/systm.h>
                     72: #include <sys/malloc.h>
                     73: #include <sys/mbuf.h>
                     74: #include <sys/protosw.h>
                     75: #include <sys/socket.h>
                     76: #include <sys/socketvar.h>
                     77: #include <sys/ioctl.h>
                     78: #include <sys/errno.h>
                     79: #include <sys/time.h>
                     80: #include <sys/proc.h>
                     81:
                     82: #include <net/if.h>
                     83: #include <net/route.h>
                     84:
                     85: #include <netinet/in.h>
                     86: #include <netinet/in_var.h>
                     87: #include <netinet/in_systm.h>
                     88: #include <netinet/ip.h>
                     89: #include <netinet/in_pcb.h>
1.19      itojun     90: #include <netinet/ip6.h>
1.11      itojun     91: #include <netinet6/ip6_var.h>
1.2       itojun     92: #include <netinet6/in6_pcb.h>
                     93: #include <netinet6/nd6.h>
                     94:
                     95: #include "loop.h"
                     96: extern struct ifnet loif[NLOOP];
1.8       itojun     97: #include "faith.h"
1.2       itojun     98:
                     99: #ifdef IPSEC
                    100: #include <netinet6/ipsec.h>
                    101: #include <netkey/key.h>
                    102: #include <netkey/key_debug.h>
                    103: #endif /* IPSEC */
                    104:
                    105: struct in6_addr zeroin6_addr;
                    106:
                    107: int
                    108: in6_pcballoc(so, head)
                    109:        struct socket *so;
                    110:        struct in6pcb *head;
                    111: {
                    112:        struct in6pcb *in6p;
                    113:
                    114:        MALLOC(in6p, struct in6pcb *, sizeof(*in6p), M_PCB, M_NOWAIT);
                    115:        if (in6p == NULL)
                    116:                return(ENOBUFS);
                    117:        bzero((caddr_t)in6p, sizeof(*in6p));
                    118:        in6p->in6p_head = head;
                    119:        in6p->in6p_socket = so;
                    120:        in6p->in6p_hops = -1;   /* use kernel default */
                    121:        in6p->in6p_icmp6filt = NULL;
1.3       itojun    122:        in6p->in6p_next = head->in6p_next;
                    123:        head->in6p_next = in6p;
                    124:        in6p->in6p_prev = head;
                    125:        in6p->in6p_next->in6p_prev = in6p;
1.12      itojun    126: #ifndef INET6_BINDV6ONLY
1.11      itojun    127:        if (ip6_bindv6only)
                    128:                in6p->in6p_flags |= IN6P_BINDV6ONLY;
                    129: #else
                    130:        in6p->in6p_flags |= IN6P_BINDV6ONLY;    /*just for safety*/
                    131: #endif
1.2       itojun    132:        so->so_pcb = (caddr_t)in6p;
                    133:        return(0);
                    134: }
                    135:
                    136: int
1.24      itojun    137: in6_pcbbind(in6p, nam, p)
1.2       itojun    138:        register struct in6pcb *in6p;
                    139:        struct mbuf *nam;
1.24      itojun    140:        struct proc *p;
1.2       itojun    141: {
                    142:        struct socket *so = in6p->in6p_socket;
                    143:        struct in6pcb *head = in6p->in6p_head;
                    144:        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
1.18      itojun    145:        u_int16_t lport = 0;
1.2       itojun    146:        int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
                    147:        int error;
                    148:
1.10      itojun    149:        if (in6p->in6p_lport || !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
1.2       itojun    150:                return(EINVAL);
                    151:        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
                    152:           ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
                    153:            (so->so_options & SO_ACCEPTCONN) == 0))
                    154:                wild = IN6PLOOKUP_WILDCARD;
                    155:        if (nam) {
                    156:                sin6 = mtod(nam, struct sockaddr_in6 *);
                    157:                if (nam->m_len != sizeof(*sin6))
                    158:                        return(EINVAL);
                    159:                /*
                    160:                 * We should check the family, but old programs
                    161:                 * incorrectly fail to intialize it.
                    162:                 */
                    163:                if (sin6->sin6_family != AF_INET6)
                    164:                        return(EAFNOSUPPORT);
1.22      itojun    165:
                    166:                /*
                    167:                 * since we do not check port number duplicate with IPv4 space,
                    168:                 * we reject it at this moment.  If we leave it, we make normal
                    169:                 * user to hijack port number from other users.
                    170:                 */
                    171:                if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
                    172:                        return(EADDRNOTAVAIL);
1.2       itojun    173:
                    174:                /*
                    175:                 * If the scope of the destination is link-local, embed the
                    176:                 * interface index in the address.
                    177:                 */
                    178:                if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
                    179:                        /* XXX boundary check is assumed to be already done. */
                    180:                        /* XXX sin6_scope_id is weaker than advanced-api. */
                    181:                        struct in6_pktinfo *pi;
                    182:                        if (in6p->in6p_outputopts &&
                    183:                            (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
                    184:                            pi->ipi6_ifindex) {
                    185:                                sin6->sin6_addr.s6_addr16[1]
                    186:                                        = htons(pi->ipi6_ifindex);
                    187:                        } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)
                    188:                                && in6p->in6p_moptions
                    189:                                && in6p->in6p_moptions->im6o_multicast_ifp) {
                    190:                                sin6->sin6_addr.s6_addr16[1] =
                    191:                                        htons(in6p->in6p_moptions->im6o_multicast_ifp->if_index);
                    192:                        } else if (sin6->sin6_scope_id) {
                    193:                                /* boundary check */
1.23      itojun    194:                                if (sin6->sin6_scope_id < 0
1.2       itojun    195:                                 || if_index < sin6->sin6_scope_id) {
                    196:                                        return ENXIO;  /* XXX EINVAL? */
                    197:                                }
                    198:                                sin6->sin6_addr.s6_addr16[1]
                    199:                                        = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/
                    200:                                /* this must be cleared for ifa_ifwithaddr() */
                    201:                                sin6->sin6_scope_id = 0;
                    202:                        }
                    203:                }
                    204:
                    205:                lport = sin6->sin6_port;
                    206:                if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
                    207:                        /*
                    208:                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
                    209:                         * allow compepte duplication of binding if
                    210:                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
                    211:                         * and a multicast address is bound on both
                    212:                         * new and duplicated sockets.
                    213:                         */
                    214:                        if (so->so_options & SO_REUSEADDR)
                    215:                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
                    216:                } else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
                    217:                        struct sockaddr_in sin;
                    218:
                    219:                        bzero(&sin, sizeof(sin));
                    220:                        sin.sin_len = sizeof(sin);
                    221:                        sin.sin_family = AF_INET;
                    222:                        bcopy(&sin6->sin6_addr.s6_addr32[3], &sin.sin_addr,
                    223:                                sizeof(sin.sin_addr));
                    224:                        if (ifa_ifwithaddr((struct sockaddr *)&sin) == 0)
                    225:                                return EADDRNOTAVAIL;
1.10      itojun    226:                } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1.2       itojun    227:                        struct ifaddr *ia = NULL;
                    228:
                    229:                        sin6->sin6_port = 0;            /* yech... */
1.10      itojun    230: #if defined(NFAITH) && NFAITH > 0
                    231:                        if ((in6p->in6p_flags & IN6P_FAITH) == 0
                    232:                         && (ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0)
                    233: #else
1.2       itojun    234:                        if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0)
1.10      itojun    235: #endif
1.2       itojun    236:                                return(EADDRNOTAVAIL);
                    237:
                    238:                        /*
                    239:                         * XXX: bind to an anycast address might accidentally
                    240:                         * cause sending a packet with anycast source address.
                    241:                         */
1.20      itojun    242:                        if (ia &&
                    243:                            ((struct in6_ifaddr *)ia)->ia6_flags &
                    244:                            (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
                    245:                             IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
                    246:                                return(EADDRNOTAVAIL);
1.2       itojun    247:                        }
                    248:                }
                    249:                if (lport) {
1.13      itojun    250: #ifndef IPNOPRIVPORTS
1.2       itojun    251:                        /* GROSS */
                    252:                        if (ntohs(lport) < IPV6PORT_RESERVED &&
1.13      itojun    253:                            (p == 0 ||
                    254:                             (error = suser(p->p_ucred, &p->p_acflag))))
1.2       itojun    255:                                return(EACCES);
1.13      itojun    256: #endif
1.2       itojun    257:
                    258:                        if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
                    259:                                /* should check this but we can't ... */
                    260: #if 0
                    261:                                struct inpcb *t;
                    262:
                    263:                                t = in_pcblookup_bind(&tcbtable,
                    264:                                        (struct in_addr *)&sin6->sin6_addr.s6_addr32[3],
                    265:                                        lport);
                    266:                                if (t && (reuseport & t->inp_socket->so_options) == 0)
                    267:                                        return EADDRINUSE;
                    268: #endif
                    269:                        } else {
                    270:                                struct in6pcb *t;
                    271:
                    272:                                t = in6_pcblookup(head, &zeroin6_addr, 0,
                    273:                                                  &sin6->sin6_addr, lport, wild);
                    274:                                if (t && (reuseport & t->in6p_socket->so_options) == 0)
                    275:                                        return(EADDRINUSE);
                    276:                        }
                    277:                }
                    278:                in6p->in6p_laddr = sin6->sin6_addr;
                    279:        }
1.10      itojun    280:
1.2       itojun    281:        if (lport == 0) {
1.10      itojun    282:                int e;
                    283:                if ((e = in6_pcbsetport(&in6p->in6p_laddr, in6p)) != 0)
                    284:                        return(e);
                    285:        }
                    286:        else
                    287:                in6p->in6p_lport = lport;
                    288:
                    289:        in6p->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0;   /*XXX*/
                    290:        return(0);
                    291: }
                    292:
                    293: /*
1.2       itojun    294:  * Connect from a socket to a specified address.
                    295:  * Both address and port must be specified in argument sin6.
                    296:  * If don't have a local address for this socket yet,
                    297:  * then pick one.
                    298:  */
                    299: int
                    300: in6_pcbconnect(in6p, nam)
                    301:        struct in6pcb *in6p;
                    302:        struct mbuf *nam;
                    303: {
                    304:        struct in6_addr *in6a = NULL;
                    305:        struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
                    306:        struct in6_pktinfo *pi;
                    307:        struct ifnet *ifp = NULL;       /* outgoing interface */
                    308:        int error = 0;
                    309:        struct in6_addr mapped;
1.26      itojun    310:        struct sockaddr_in6 tmp;
1.2       itojun    311:
                    312:        (void)&in6a;                            /* XXX fool gcc */
                    313:
                    314:        if (nam->m_len != sizeof(*sin6))
                    315:                return(EINVAL);
                    316:        if (sin6->sin6_family != AF_INET6)
                    317:                return(EAFNOSUPPORT);
                    318:        if (sin6->sin6_port == 0)
                    319:                return(EADDRNOTAVAIL);
                    320:
                    321:        /* sanity check for mapped address case */
                    322:        if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
                    323:                if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
                    324:                        in6p->in6p_laddr.s6_addr16[5] = htons(0xffff);
                    325:                if (!IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
                    326:                        return EINVAL;
                    327:        } else {
                    328:                if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
                    329:                        return EINVAL;
                    330:        }
1.26      itojun    331:
                    332:        /* protect *sin6 from overwrites */
                    333:        tmp = *sin6;
                    334:        sin6 = &tmp;
1.2       itojun    335:
                    336:        /*
                    337:         * If the scope of the destination is link-local, embed the interface
                    338:         * index in the address.
                    339:         */
                    340:        if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
                    341:                /* XXX boundary check is assumed to be already done. */
                    342:                /* XXX sin6_scope_id is weaker than advanced-api. */
                    343:                if (in6p->in6p_outputopts &&
                    344:                    (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
                    345:                    pi->ipi6_ifindex) {
                    346:                        sin6->sin6_addr.s6_addr16[1] = htons(pi->ipi6_ifindex);
                    347:                        ifp = ifindex2ifnet[pi->ipi6_ifindex];
                    348:                }
                    349:                else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) &&
                    350:                         in6p->in6p_moptions &&
                    351:                         in6p->in6p_moptions->im6o_multicast_ifp) {
                    352:                        sin6->sin6_addr.s6_addr16[1] =
                    353:                                htons(in6p->in6p_moptions->im6o_multicast_ifp->if_index);
                    354:                        ifp = ifindex2ifnet[in6p->in6p_moptions->im6o_multicast_ifp->if_index];
                    355:                } else if (sin6->sin6_scope_id) {
                    356:                        /* boundary check */
1.23      itojun    357:                        if (sin6->sin6_scope_id < 0
1.2       itojun    358:                         || if_index < sin6->sin6_scope_id) {
                    359:                                return ENXIO;  /* XXX EINVAL? */
                    360:                        }
                    361:                        sin6->sin6_addr.s6_addr16[1]
                    362:                                = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/
                    363:                        ifp = ifindex2ifnet[sin6->sin6_scope_id];
                    364:                }
                    365:        }
                    366:
                    367:        /* Source address selection. */
                    368:        if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
                    369:         && in6p->in6p_laddr.s6_addr32[3] == 0) {
                    370:                struct sockaddr_in sin, *sinp;
                    371:
                    372:                bzero(&sin, sizeof(sin));
                    373:                sin.sin_len = sizeof(sin);
                    374:                sin.sin_family = AF_INET;
                    375:                bcopy(&sin6->sin6_addr.s6_addr32[3], &sin.sin_addr,
                    376:                        sizeof(sin.sin_addr));
                    377:                sinp = in_selectsrc(&sin, (struct route *)&in6p->in6p_route,
                    378:                        in6p->in6p_socket->so_options, NULL, &error);
                    379:                if (sinp == 0) {
                    380:                        if (error == 0)
                    381:                                error = EADDRNOTAVAIL;
                    382:                        return(error);
                    383:                }
                    384:                bzero(&mapped, sizeof(mapped));
                    385:                mapped.s6_addr16[5] = htons(0xffff);
                    386:                bcopy(&sinp->sin_addr, &mapped.s6_addr32[3], sizeof(sinp->sin_addr));
                    387:                in6a = &mapped;
1.10      itojun    388:        } else {
                    389:                /*
                    390:                 * XXX: in6_selectsrc might replace the bound local address
                    391:                 * with the address specified by setsockopt(IPV6_PKTINFO).
                    392:                 * Is it the intended behavior?
                    393:                 */
1.2       itojun    394:                in6a = in6_selectsrc(sin6, in6p->in6p_outputopts,
1.10      itojun    395:                                     in6p->in6p_moptions,
                    396:                                     &in6p->in6p_route,
                    397:                                     &in6p->in6p_laddr, &error);
1.2       itojun    398:                if (in6a == 0) {
                    399:                        if (error == 0)
                    400:                                error = EADDRNOTAVAIL;
                    401:                        return(error);
                    402:                }
                    403:        }
                    404:        if (in6p->in6p_route.ro_rt)
                    405:                ifp = in6p->in6p_route.ro_rt->rt_ifp;
                    406:
1.10      itojun    407:        in6p->in6p_ip6.ip6_hlim = (u_int8_t)in6_selecthlim(in6p, ifp);
1.2       itojun    408:
                    409:        if (in6_pcblookup(in6p->in6p_head,
                    410:                         &sin6->sin6_addr,
                    411:                         sin6->sin6_port,
1.10      itojun    412:                         IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) ?
1.2       itojun    413:                          in6a : &in6p->in6p_laddr,
                    414:                         in6p->in6p_lport,
                    415:                         0))
                    416:                return(EADDRINUSE);
1.10      itojun    417:        if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)
1.2       itojun    418:         || (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
                    419:          && in6p->in6p_laddr.s6_addr32[3] == 0)) {
                    420:                if (in6p->in6p_lport == 0)
1.24      itojun    421:                        (void)in6_pcbbind(in6p, (struct mbuf *)0,
                    422:                            (struct proc *)0);
1.2       itojun    423:                in6p->in6p_laddr = *in6a;
                    424:        }
                    425:        in6p->in6p_faddr = sin6->sin6_addr;
                    426:        in6p->in6p_fport = sin6->sin6_port;
                    427:        /*
                    428:         * xxx kazu flowlabel is necessary for connect?
                    429:         * but if this line is missing, the garbage value remains.
                    430:         */
                    431:        in6p->in6p_flowinfo = sin6->sin6_flowinfo;
                    432:        return(0);
                    433: }
                    434:
                    435: void
                    436: in6_pcbdisconnect(in6p)
                    437:        struct in6pcb *in6p;
                    438: {
                    439:        bzero((caddr_t)&in6p->in6p_faddr, sizeof(in6p->in6p_faddr));
                    440:        in6p->in6p_fport = 0;
                    441:        if (in6p->in6p_socket->so_state & SS_NOFDREF)
                    442:                in6_pcbdetach(in6p);
                    443: }
                    444:
                    445: void
                    446: in6_pcbdetach(in6p)
                    447:        struct in6pcb *in6p;
                    448: {
                    449:        struct socket *so = in6p->in6p_socket;
                    450:
                    451: #ifdef IPSEC
                    452:        ipsec6_delete_pcbpolicy(in6p);
                    453: #endif /* IPSEC */
                    454:        sotoin6pcb(so) = 0;
                    455:        sofree(so);
                    456:        if (in6p->in6p_options)
                    457:                m_freem(in6p->in6p_options);
                    458:        if (in6p->in6p_outputopts) {
                    459:                if (in6p->in6p_outputopts->ip6po_rthdr &&
                    460:                    in6p->in6p_outputopts->ip6po_route.ro_rt)
                    461:                        RTFREE(in6p->in6p_outputopts->ip6po_route.ro_rt);
                    462:                if (in6p->in6p_outputopts->ip6po_m)
                    463:                        (void)m_free(in6p->in6p_outputopts->ip6po_m);
                    464:                free(in6p->in6p_outputopts, M_IP6OPT);
                    465:        }
                    466:        if (in6p->in6p_route.ro_rt)
                    467:                rtfree(in6p->in6p_route.ro_rt);
                    468:        ip6_freemoptions(in6p->in6p_moptions);
1.3       itojun    469:        in6p->in6p_next->in6p_prev = in6p->in6p_prev;
                    470:        in6p->in6p_prev->in6p_next = in6p->in6p_next;
                    471:        in6p->in6p_prev = NULL;
1.2       itojun    472:        FREE(in6p, M_PCB);
                    473: }
                    474:
                    475: void
                    476: in6_setsockaddr(in6p, nam)
                    477:        struct in6pcb *in6p;
                    478:        struct mbuf *nam;
                    479: {
                    480:        struct sockaddr_in6 *sin6;
                    481:
                    482:        nam->m_len = sizeof(*sin6);
                    483:        sin6 = mtod(nam, struct sockaddr_in6 *);
                    484:        bzero((caddr_t)sin6, sizeof(*sin6));
                    485:        sin6->sin6_family = AF_INET6;
                    486:        sin6->sin6_len = sizeof(struct sockaddr_in6);
                    487:        sin6->sin6_port = in6p->in6p_lport;
                    488:        sin6->sin6_addr = in6p->in6p_laddr;
                    489:        if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
                    490:                sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
                    491:        else
                    492:                sin6->sin6_scope_id = 0;        /*XXX*/
                    493:        if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
                    494:                sin6->sin6_addr.s6_addr16[1] = 0;
                    495: }
                    496:
                    497: void
                    498: in6_setpeeraddr(in6p, nam)
                    499:        struct in6pcb *in6p;
                    500:        struct mbuf *nam;
                    501: {
                    502:        struct sockaddr_in6 *sin6;
                    503:
                    504:        nam->m_len = sizeof(*sin6);
                    505:        sin6 = mtod(nam, struct sockaddr_in6 *);
                    506:        bzero((caddr_t)sin6, sizeof(*sin6));
                    507:        sin6->sin6_family = AF_INET6;
                    508:        sin6->sin6_len = sizeof(struct sockaddr_in6);
                    509:        sin6->sin6_port = in6p->in6p_fport;
                    510:        sin6->sin6_addr = in6p->in6p_faddr;
                    511:        if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
                    512:                sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
                    513:        else
                    514:                sin6->sin6_scope_id = 0;        /*XXX*/
                    515:        if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
                    516:                sin6->sin6_addr.s6_addr16[1] = 0;
                    517: }
                    518:
                    519: /*
                    520:  * Pass some notification to all connections of a protocol
                    521:  * associated with address dst.  The local address and/or port numbers
                    522:  * may be specified to limit the search.  The "usual action" will be
                    523:  * taken, depending on the ctlinput cmd.  The caller must filter any
                    524:  * cmds that are uninteresting (e.g., no error in the map).
                    525:  * Call the protocol specific routine (if any) to report
                    526:  * any errors for each matching socket.
                    527:  *
1.6       itojun    528:  * Must be called at splsoftnet.
1.2       itojun    529:  */
                    530: int
                    531: in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
                    532:        struct in6pcb *head;
                    533:        struct sockaddr *dst;
                    534:        u_int fport_arg, lport_arg;
                    535:        struct in6_addr *laddr6;
                    536:        int cmd;
                    537:        void (*notify) __P((struct in6pcb *, int));
                    538: {
1.20      itojun    539:        struct in6pcb *in6p, *nin6p;
1.2       itojun    540:        struct in6_addr faddr6;
1.18      itojun    541:        u_int16_t fport = fport_arg, lport = lport_arg;
1.2       itojun    542:        int errno;
                    543:        int nmatch = 0;
1.25      itojun    544:        void (*notify2) __P((struct in6pcb *, int));
                    545:
                    546:        notify2 = NULL;
1.2       itojun    547:
                    548:        if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
                    549:                return 0;
                    550:        faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
1.10      itojun    551:        if (IN6_IS_ADDR_UNSPECIFIED(&faddr6))
1.2       itojun    552:                return 0;
                    553:
                    554:        /*
                    555:         * Redirects go to all references to the destination,
1.20      itojun    556:         * and use in6_rtchange to invalidate the route cache.
                    557:         * Dead host indications: also use in6_rtchange to invalidate
                    558:         * the cache, and deliver the error to all the sockets.
1.2       itojun    559:         * Otherwise, if we have knowledge of the local port and address,
                    560:         * deliver only to that socket.
                    561:         */
                    562:        if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
                    563:                fport = 0;
                    564:                lport = 0;
                    565:                bzero((caddr_t)laddr6, sizeof(*laddr6));
1.20      itojun    566:
1.25      itojun    567:                /*
                    568:                 * Keep the old notify function to store a soft error
                    569:                 * in each PCB.
                    570:                 */
                    571:                if (cmd == PRC_HOSTDEAD && notify != in6_rtchange)
                    572:                        notify2 = notify;
                    573:
                    574:                notify = in6_rtchange;
1.2       itojun    575:        }
1.20      itojun    576:
1.2       itojun    577:        if (notify == NULL)
                    578:                return 0;
1.20      itojun    579:
1.2       itojun    580:        errno = inet6ctlerrmap[cmd];
1.20      itojun    581:        for (in6p = head->in6p_next; in6p != head; in6p = nin6p) {
                    582:                nin6p = in6p->in6p_next;
                    583:
1.25      itojun    584:                if (notify == in6_rtchange) {
1.20      itojun    585:                        /*
                    586:                         * Since a non-connected PCB might have a cached route,
                    587:                         * we always call in6_rtchange without matching
                    588:                         * the PCB to the src/dst pair.
                    589:                         *
                    590:                         * XXX: we assume in6_rtchange does not free the PCB.
                    591:                         */
                    592:                        if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_route.ro_dst.sin6_addr,
                    593:                                               &faddr6))
                    594:                                in6_rtchange(in6p, errno);
                    595:
1.25      itojun    596:                        if (notify2 == NULL)
                    597:                                continue;
                    598:
                    599:                        notify = notify2;
1.20      itojun    600:                }
                    601:
                    602:                /* at this point, we can assume that NOTIFY is not NULL. */
                    603:
                    604:                if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &faddr6) ||
                    605:                    in6p->in6p_socket == 0 ||
                    606:                    (lport && in6p->in6p_lport != lport) ||
                    607:                    (!IN6_IS_ADDR_UNSPECIFIED(laddr6) &&
                    608:                     !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6)) ||
                    609:                    (fport && in6p->in6p_fport != fport))
1.2       itojun    610:                        continue;
1.20      itojun    611:
                    612:                (*notify)(in6p, errno);
1.2       itojun    613:                nmatch++;
                    614:        }
                    615:        return nmatch;
1.16      thorpej   616: }
                    617:
                    618: void
                    619: in6_pcbpurgeif(head, ifp)
                    620:        struct in6pcb *head;
                    621:        struct ifnet *ifp;
                    622: {
                    623:        struct in6pcb *in6p, *nin6p;
                    624:
                    625:        for (in6p = head->in6p_next; in6p != head; in6p = nin6p) {
                    626:                nin6p = in6p->in6p_next;
                    627:                if (in6p->in6p_route.ro_rt != NULL &&
                    628:                    in6p->in6p_route.ro_rt->rt_ifp == ifp)
                    629:                        in6_rtchange(in6p, 0);
                    630:        }
1.2       itojun    631: }
                    632:
                    633: /*
                    634:  * Check for alternatives when higher level complains
                    635:  * about service problems.  For now, invalidate cached
                    636:  * routing information.  If the route was created dynamically
                    637:  * (by a redirect), time to try a default gateway again.
                    638:  */
                    639: void
                    640: in6_losing(in6p)
                    641:        struct in6pcb *in6p;
                    642: {
                    643:        struct rtentry *rt;
                    644:        struct rt_addrinfo info;
                    645:
                    646:        if ((rt = in6p->in6p_route.ro_rt) != NULL) {
                    647:                in6p->in6p_route.ro_rt = 0;
                    648:                bzero((caddr_t)&info, sizeof(info));
                    649:                info.rti_info[RTAX_DST] =
                    650:                        (struct sockaddr *)&in6p->in6p_route.ro_dst;
                    651:                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                    652:                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                    653:                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
                    654:                if (rt->rt_flags & RTF_DYNAMIC)
                    655:                        (void)rtrequest(RTM_DELETE, rt_key(rt),
                    656:                                        rt->rt_gateway, rt_mask(rt), rt->rt_flags,
                    657:                                        (struct rtentry **)0);
                    658:                else
                    659:                /*
                    660:                 * A new route can be allocated
                    661:                 * the next time output is attempted.
                    662:                 */
                    663:                        rtfree(rt);
                    664:        }
                    665: }
                    666:
                    667: /*
                    668:  * After a routing change, flush old routing
                    669:  * and allocate a (hopefully) better one.
                    670:  */
                    671: void
                    672: in6_rtchange(in6p, errno)
                    673:        struct in6pcb *in6p;
                    674:        int errno;
                    675: {
                    676:        if (in6p->in6p_route.ro_rt) {
                    677:                rtfree(in6p->in6p_route.ro_rt);
                    678:                in6p->in6p_route.ro_rt = 0;
                    679:                /*
                    680:                 * A new route can be allocated the next time
                    681:                 * output is attempted.
                    682:                 */
                    683:        }
                    684: }
                    685:
                    686: struct in6pcb *
                    687: in6_pcblookup(head, faddr6, fport_arg, laddr6, lport_arg, flags)
                    688:        struct in6pcb *head;
                    689:        struct in6_addr *faddr6, *laddr6;
                    690:        u_int fport_arg, lport_arg;
                    691:        int flags;
                    692: {
                    693:        struct in6pcb *in6p, *match = 0;
                    694:        int matchwild = 3, wildcard;
1.18      itojun    695:        u_int16_t fport = fport_arg, lport = lport_arg;
1.2       itojun    696:
                    697:        for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
                    698:                if (in6p->in6p_lport != lport)
                    699:                        continue;
                    700:                wildcard = 0;
1.10      itojun    701:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
                    702:                        if (IN6_IS_ADDR_UNSPECIFIED(laddr6))
1.2       itojun    703:                                wildcard++;
                    704:                        else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
                    705:                                continue;
1.11      itojun    706:                }
                    707: #ifndef TCP6
                    708:                else if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
                    709:                        && in6p->in6p_laddr.s6_addr32[3] == 0) {
                    710:                        if (!IN6_IS_ADDR_V4MAPPED(laddr6))
                    711:                                continue;
                    712:                        if (laddr6->s6_addr32[3] == 0)
                    713:                                ;
                    714:                        else
                    715:                                wildcard++;
                    716:                }
                    717: #endif
                    718:                else {
                    719:                        if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
                    720: #if !defined(TCP6) && !defined(INET6_BINDV6ONLY)
                    721:                                if (in6p->in6p_flags & IN6P_BINDV6ONLY)
                    722:                                        continue;
                    723:                                else
                    724:                                        wildcard++;
                    725: #else
                    726:                                continue;
                    727: #endif
                    728:                        } else if (!IN6_IS_ADDR_UNSPECIFIED(laddr6))
1.2       itojun    729:                                wildcard++;
                    730:                }
1.10      itojun    731:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
                    732:                        if (IN6_IS_ADDR_UNSPECIFIED(faddr6))
1.2       itojun    733:                                wildcard++;
                    734:                        else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, faddr6)
                    735:                              || in6p->in6p_fport != fport)
                    736:                                continue;
1.11      itojun    737:                }
                    738: #ifndef TCP6
                    739:                else if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)
                    740:                        && in6p->in6p_faddr.s6_addr32[3] == 0) {
                    741:                        if (!IN6_IS_ADDR_V4MAPPED(faddr6))
                    742:                                continue;
                    743:                        if (faddr6->s6_addr32[3] == 0)
                    744:                                ;
                    745:                        else
                    746:                                wildcard++;
                    747:                }
                    748: #endif
                    749:                else {
                    750:                        if (IN6_IS_ADDR_V4MAPPED(faddr6)) {
                    751: #if !defined(TCP6) && !defined(INET6_BINDV6ONLY)
                    752:                                if (in6p->in6p_flags & IN6P_BINDV6ONLY)
                    753:                                        continue;
                    754:                                else
                    755:                                        wildcard++;
                    756: #else
                    757:                                continue;
                    758: #endif
                    759:                        } else if (!IN6_IS_ADDR_UNSPECIFIED(faddr6))
1.2       itojun    760:                                wildcard++;
                    761:                }
1.11      itojun    762:
1.2       itojun    763:                if (wildcard && (flags & IN6PLOOKUP_WILDCARD) == 0)
                    764:                        continue;
                    765:                if (wildcard < matchwild) {
                    766:                        match = in6p;
                    767:                        matchwild = wildcard;
                    768:                        if (matchwild == 0)
                    769:                                break;
                    770:                }
                    771:        }
                    772:        return(match);
                    773: }
                    774:
                    775: #ifndef TCP6
                    776: struct rtentry *
                    777: in6_pcbrtentry(in6p)
                    778:        struct in6pcb *in6p;
                    779: {
                    780:        struct route_in6 *ro;
                    781:
                    782:        ro = &in6p->in6p_route;
                    783:
                    784:        if (ro->ro_rt == NULL) {
                    785:                /*
                    786:                 * No route yet, so try to acquire one.
                    787:                 */
                    788:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
                    789:                        bzero(&ro->ro_dst, sizeof(ro->ro_dst));
                    790:                        ro->ro_dst.sin6_family = AF_INET6;
                    791:                        ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
                    792:                        satosin6(&ro->ro_dst)->sin6_addr = in6p->in6p_faddr;
                    793:                        rtalloc((struct route *)ro);
                    794:                }
                    795:        }
                    796:        return (ro->ro_rt);
                    797: }
                    798:
                    799: struct in6pcb *
1.8       itojun    800: in6_pcblookup_connect(head, faddr6, fport_arg, laddr6, lport_arg, faith)
1.2       itojun    801:        struct in6pcb *head;
                    802:        struct in6_addr *faddr6, *laddr6;
                    803:        u_int fport_arg, lport_arg;
1.8       itojun    804:        int faith;
1.2       itojun    805: {
                    806:        struct in6pcb *in6p;
1.18      itojun    807:        u_int16_t fport = fport_arg, lport = lport_arg;
1.2       itojun    808:
                    809:        for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
                    810:                /* find exact match on both source and dest */
                    811:                if (in6p->in6p_fport != fport)
                    812:                        continue;
                    813:                if (in6p->in6p_lport != lport)
                    814:                        continue;
                    815:                if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr))
                    816:                        continue;
                    817:                if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, faddr6))
                    818:                        continue;
                    819:                if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
                    820:                        continue;
                    821:                if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
                    822:                        continue;
                    823:                return in6p;
                    824:        }
                    825:        return NULL;
                    826: }
                    827:
                    828: struct in6pcb *
1.8       itojun    829: in6_pcblookup_bind(head, laddr6, lport_arg, faith)
1.2       itojun    830:        struct in6pcb *head;
                    831:        struct in6_addr *laddr6;
                    832:        u_int lport_arg;
1.8       itojun    833:        int faith;
1.2       itojun    834: {
                    835:        struct in6pcb *in6p, *match;
1.18      itojun    836:        u_int16_t lport = lport_arg;
1.2       itojun    837:
                    838:        match = NULL;
                    839:        for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
                    840:                /*
                    841:                 * find destination match.  exact match is preferred
                    842:                 * against wildcard match.
                    843:                 */
1.8       itojun    844: #if defined(NFAITH) && NFAITH > 0
                    845:                if (faith && (in6p->in6p_flags & IN6P_FAITH) == 0)
                    846:                        continue;
                    847: #endif
1.2       itojun    848:                if (in6p->in6p_fport != 0)
                    849:                        continue;
                    850:                if (in6p->in6p_lport != lport)
                    851:                        continue;
1.11      itojun    852:                if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
                    853:                        if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
                    854: #ifndef INET6_BINDV6ONLY
                    855:                                if (in6p->in6p_flags & IN6P_BINDV6ONLY)
                    856:                                        continue;
                    857:                                else
                    858:                                        match = in6p;
                    859: #else
                    860:                                continue;
                    861: #endif
                    862:                        } else
                    863:                                match = in6p;
                    864:                }
1.20      itojun    865:                else if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) &&
1.11      itojun    866:                         in6p->in6p_laddr.s6_addr32[3] == 0) {
1.20      itojun    867:                        if (IN6_IS_ADDR_V4MAPPED(laddr6) &&
                    868:                            laddr6->s6_addr32[3] != 0)
1.11      itojun    869:                                match = in6p;
                    870:                }
1.2       itojun    871:                else if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
                    872:                        return in6p;
                    873:        }
                    874:        return match;
                    875: }
                    876: #endif

CVSweb <webmaster@jp.NetBSD.org>