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

Annotation of src/sys/netinet6/in6_ifattach.c, Revision 1.8

1.8     ! is          1: /*     $NetBSD: in6_ifattach.c,v 1.7 1999/09/13 12:15:55 itojun Exp $  */
1.3       thorpej     2:
1.2       itojun      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: #include <sys/param.h>
                     33: #include <sys/systm.h>
                     34: #include <sys/malloc.h>
                     35: #include <sys/socket.h>
                     36: #include <sys/sockio.h>
                     37:
                     38: #include <net/if.h>
                     39: #include <net/if_dl.h>
                     40: #include <net/if_types.h>
                     41: #include <net/route.h>
                     42:
                     43: #include <netinet/in.h>
                     44: #include <netinet/in_var.h>
                     45: #ifndef __NetBSD__
                     46: #include <netinet/if_ether.h>
                     47: #endif
                     48:
                     49: #include <netinet6/in6.h>
                     50: #include <netinet6/ip6.h>
                     51: #include <netinet6/ip6_var.h>
                     52: #include <netinet6/in6_ifattach.h>
                     53: #include <netinet6/ip6.h>
                     54: #include <netinet6/ip6_var.h>
                     55: #include <netinet6/nd6.h>
                     56:
                     57: static struct in6_addr llsol;
                     58:
                     59: struct in6_addr **in6_iflladdr = NULL;
                     60: unsigned long in6_maxmtu = 0;
                     61:
                     62: int found_first_ifid = 0;
                     63: #define IFID_LEN 8
                     64: static char first_ifid[IFID_LEN];
                     65:
1.7       itojun     66: static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t));
1.2       itojun     67:
1.7       itojun     68: static int
                     69: laddr_to_eui64(dst, src, len)
1.2       itojun     70:        u_int8_t *dst;
                     71:        u_int8_t *src;
1.7       itojun     72:        size_t len;
1.2       itojun     73: {
1.7       itojun     74:        switch (len) {
1.8     ! is         75:        case 1:
        !            76:                bzero(dst, 7);
        !            77:                dst[7] = src[0];
        !            78:                break;
1.7       itojun     79:        case 6:
                     80:                dst[0] = src[0];
                     81:                dst[1] = src[1];
                     82:                dst[2] = src[2];
                     83:                dst[3] = 0xff;
                     84:                dst[4] = 0xfe;
                     85:                dst[5] = src[3];
                     86:                dst[6] = src[4];
                     87:                dst[7] = src[5];
                     88:                break;
                     89:        case 8:
                     90:                bcopy(src, dst, len);
                     91:                break;
                     92:        default:
                     93:                return EINVAL;
                     94:        }
                     95:
                     96:        return 0;
1.2       itojun     97: }
                     98:
                     99: /*
1.5       itojun    100:  * Find first ifid on list of interfaces.
                    101:  * This is assumed that ifp0's interface token (for example, IEEE802 MAC)
                    102:  * is globally unique.  We may need to have a flag parameter in the future.
1.2       itojun    103:  */
                    104: int
                    105: in6_ifattach_getifid(ifp0)
                    106:        struct ifnet *ifp0;
                    107: {
                    108:        struct ifnet *ifp;
                    109:        struct ifaddr *ifa;
                    110:        u_int8_t *addr = NULL;
                    111:        int addrlen = 0;
                    112:        struct sockaddr_dl *sdl;
                    113:
                    114:        if (found_first_ifid)
                    115:                return 0;
                    116:
                    117:        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
                    118:                if (ifp0 != NULL && ifp0 != ifp)
                    119:                        continue;
                    120:                for (ifa = ifp->if_addrlist.tqh_first;
                    121:                     ifa;
                    122:                     ifa = ifa->ifa_list.tqe_next) {
                    123:                        if (ifa->ifa_addr->sa_family != AF_LINK)
                    124:                                continue;
                    125:                        sdl = (struct sockaddr_dl *)ifa->ifa_addr;
                    126:                        if (sdl == NULL)
                    127:                                continue;
                    128:                        if (sdl->sdl_alen == 0)
                    129:                                continue;
                    130:                        switch (ifp->if_type) {
                    131:                        case IFT_ETHER:
                    132:                        case IFT_FDDI:
                    133:                        case IFT_ATM:
1.8     ! is        134:                        case IFT_ARCNET:
        !           135:                        /* what others? */
1.7       itojun    136:                                /* IEEE802/EUI64 cases - what others? */
1.2       itojun    137:                                addr = LLADDR(sdl);
                    138:                                addrlen = sdl->sdl_alen;
1.7       itojun    139:                                /*
                    140:                                 * to copy ifid from IEEE802/EUI64 interface,
                    141:                                 * u bit of the source needs to be 0.
                    142:                                 */
                    143:                                if ((addr[0] & 0x02) != 0)
                    144:                                        break;
1.2       itojun    145:                                goto found;
                    146:                        default:
                    147:                                break;
                    148:                        }
                    149:                }
                    150:        }
1.4       thorpej   151: #ifdef DEBUG
                    152:        printf("in6_ifattach_getifid: failed to get EUI64");
                    153: #endif
1.2       itojun    154:        return EADDRNOTAVAIL;
                    155:
                    156: found:
1.7       itojun    157:        if (laddr_to_eui64(first_ifid, addr, addrlen) == 0)
1.2       itojun    158:                found_first_ifid = 1;
                    159:
                    160:        if (found_first_ifid) {
1.4       thorpej   161:                printf("%s: supplying EUI64: "
                    162:                        "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
1.2       itojun    163:                        ifp->if_xname,
                    164:                        first_ifid[0] & 0xff, first_ifid[1] & 0xff,
                    165:                        first_ifid[2] & 0xff, first_ifid[3] & 0xff,
                    166:                        first_ifid[4] & 0xff, first_ifid[5] & 0xff,
                    167:                        first_ifid[6] & 0xff, first_ifid[7] & 0xff);
1.5       itojun    168:
                    169:                /* invert u bit to convert EUI64 to RFC2373 interface ID. */
                    170:                first_ifid[0] ^= 0x02;
                    171:
1.2       itojun    172:                return 0;
                    173:        } else {
1.4       thorpej   174: #ifdef DEBUG
                    175:                printf("in6_ifattach_getifid: failed to get EUI64");
                    176: #endif
1.2       itojun    177:                return EADDRNOTAVAIL;
                    178:        }
                    179: }
                    180:
                    181: /*
                    182:  * add link-local address to *pseudo* p2p interfaces.
                    183:  * get called when the first MAC address is made available in in6_ifattach().
1.5       itojun    184:  *
                    185:  * XXX I start feeling this as a bad idea. (itojun)
1.2       itojun    186:  */
                    187: void
                    188: in6_ifattach_p2p()
                    189: {
                    190:        struct ifnet *ifp;
                    191:
                    192:        /* prevent infinite loop. just in case. */
1.4       thorpej   193:        if (found_first_ifid == 0)
1.2       itojun    194:                return;
                    195:
                    196:        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
                    197:                switch (ifp->if_type) {
                    198:                case IFT_GIF:
                    199:                        /* pseudo interfaces - safe to initialize here */
                    200:                        in6_ifattach(ifp, IN6_IFT_P2P, 0, 0);
                    201:                        break;
1.5       itojun    202:                case IFT_FAITH:
                    203:                        /* this mistakingly becomes IFF_UP */
                    204:                        break;
1.2       itojun    205:                case IFT_SLIP:
                    206:                        /* IPv6 is not supported */
                    207:                        break;
                    208:                case IFT_PPP:
                    209:                        /* this is not a pseudo interface, skip it */
                    210:                        break;
                    211:                default:
                    212:                        break;
                    213:                }
                    214:        }
                    215: }
                    216:
                    217: void
                    218: in6_ifattach(ifp, type, laddr, noloop)
                    219:        struct ifnet *ifp;
                    220:        u_int type;
                    221:        caddr_t laddr;
1.7       itojun    222:        /* size_t laddrlen; */
1.2       itojun    223:        int noloop;
                    224: {
                    225:        static size_t if_indexlim = 8;
                    226:        struct sockaddr_in6 mltaddr;
                    227:        struct sockaddr_in6 mltmask;
                    228:        struct sockaddr_in6 gate;
                    229:        struct sockaddr_in6 mask;
                    230:
                    231:        struct in6_ifaddr *ia, *ib, *oia;
                    232:        struct ifaddr *ifa;
                    233:        int rtflag = 0;
                    234:
                    235:        if (type == IN6_IFT_P2P && found_first_ifid == 0) {
1.4       thorpej   236:                printf("%s: no ifid available for IPv6 link-local address\n",
1.2       itojun    237:                        ifp->if_xname);
                    238:                return;
                    239:        }
                    240:
                    241:        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
1.4       thorpej   242:                printf("%s: not multicast capable, IPv6 not enabled\n",
1.2       itojun    243:                        ifp->if_xname);
                    244:                return;
                    245:        }
                    246:
                    247:        /*
                    248:         * We have some arrays that should be indexed by if_index.
                    249:         * since if_index will grow dynamically, they should grow too.
                    250:         *      struct in6_addr **in6_iflladdr
                    251:         */
                    252:        if (in6_iflladdr == NULL || if_index >= if_indexlim) {
                    253:                size_t n;
                    254:                caddr_t q;
1.7       itojun    255:                size_t olim;
1.2       itojun    256:
1.7       itojun    257:                olim = if_indexlim;
                    258:                while (if_index >= if_indexlim)
1.2       itojun    259:                        if_indexlim <<= 1;
                    260:
                    261:                /* grow in6_iflladdr */
                    262:                n = if_indexlim * sizeof(struct in6_addr *);
                    263:                q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
                    264:                bzero(q, n);
                    265:                if (in6_iflladdr) {
1.7       itojun    266:                        bcopy((caddr_t)in6_iflladdr, q,
                    267:                                olim * sizeof(struct in6_addr *));
1.2       itojun    268:                        free((caddr_t)in6_iflladdr, M_IFADDR);
                    269:                }
                    270:                in6_iflladdr = (struct in6_addr **)q;
                    271:        }
                    272:
                    273:        /*
                    274:         * To prevent to assign link-local address to PnP network
                    275:         * cards multiple times.
                    276:         * This is lengthy for P2P and LOOP but works.
                    277:         */
                    278:        ifa = TAILQ_FIRST(&ifp->if_addrlist);
                    279:        if (ifa != NULL) {
                    280:                for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) {
                    281:                        if (ifa->ifa_addr->sa_family != AF_INET6)
                    282:                                continue;
                    283:                        if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
                    284:                                return;
                    285:                }
1.7       itojun    286:        } else {
1.2       itojun    287:                TAILQ_INIT(&ifp->if_addrlist);
1.7       itojun    288:        }
1.2       itojun    289:
                    290:        /*
                    291:         * link-local address
                    292:         */
                    293:        ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
                    294:        bzero((caddr_t)ia, sizeof(*ia));
                    295:        ia->ia_ifa.ifa_addr =    (struct sockaddr *)&ia->ia_addr;
                    296:        ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
                    297:        ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
                    298:        ia->ia_ifp = ifp;
                    299:        TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
                    300:        /*
                    301:         * Also link into the IPv6 address chain beginning with in6_ifaddr.
                    302:         * kazu opposed it, but itojun & jinmei wanted.
                    303:         */
                    304:        if ((oia = in6_ifaddr) != NULL) {
                    305:                for (; oia->ia_next; oia = oia->ia_next)
                    306:                        continue;
                    307:                oia->ia_next = ia;
                    308:        } else
                    309:                in6_ifaddr = ia;
                    310:
                    311:        ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
                    312:        ia->ia_prefixmask.sin6_family = AF_INET6;
                    313:        ia->ia_prefixmask.sin6_addr = in6mask64;
                    314:
                    315:        bzero(&ia->ia_addr, sizeof(struct sockaddr_in6));
                    316:        ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
                    317:        ia->ia_addr.sin6_family = AF_INET6;
                    318:        ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
                    319:        ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
                    320:        ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
                    321:
                    322:        switch (type) {
                    323:        case IN6_IFT_LOOP:
                    324:                ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
                    325:                ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
                    326:                break;
                    327:        case IN6_IFT_802:
                    328:                ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
                    329:                ia->ia_ifa.ifa_flags |= RTF_CLONING;
                    330:                rtflag = RTF_CLONING;
                    331:                /* fall through */
                    332:        case IN6_IFT_P2P802:
                    333:                if (laddr == NULL)
                    334:                        break;
1.7       itojun    335:                /* XXX use laddrlen */
                    336:                if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8],
                    337:                                laddr, 6) != 0) {
                    338:                        break;
                    339:                }
1.6       itojun    340:                /* invert u bit to convert EUI64 to RFC2373 interface ID. */
                    341:                ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02;
1.4       thorpej   342:                if (found_first_ifid == 0) {
1.2       itojun    343:                        if (in6_ifattach_getifid(ifp) == 0)
                    344:                                in6_ifattach_p2p();
                    345:                }
                    346:                break;
                    347:        case IN6_IFT_P2P:
                    348:                bcopy((caddr_t)first_ifid,
                    349:                      (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8],
                    350:                      IFID_LEN);
                    351:                break;
1.8     ! is        352:        case IN6_IFT_ARCNET:
        !           353:                ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
        !           354:                ia->ia_ifa.ifa_flags |= RTF_CLONING;
        !           355:                rtflag = RTF_CLONING;
        !           356:                if (laddr == NULL)
        !           357:                        break;
        !           358:                onebyte_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8], laddr);
        !           359:                break;
1.2       itojun    360:        }
                    361:
                    362:        ia->ia_ifa.ifa_metric = ifp->if_metric;
                    363:
                    364:        if (ifp->if_ioctl != NULL) {
                    365:                int s;
                    366:                int error;
                    367:
                    368:                /*
                    369:                 * give the interface a chance to initialize, in case this
                    370:                 * is the first address to be added.
                    371:                 */
                    372:                s = splimp();
                    373:                error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
                    374:                splx(s);
                    375:
                    376:                if (error) {
                    377:                        switch (error) {
                    378:                        case EAFNOSUPPORT:
1.4       thorpej   379:                                printf("%s: IPv6 not supported\n",
1.2       itojun    380:                                        ifp->if_xname);
                    381:                                break;
                    382:                        default:
1.4       thorpej   383:                                printf("%s: SIOCSIFADDR error %d\n",
1.2       itojun    384:                                        ifp->if_xname, error);
                    385:                                break;
                    386:                        }
                    387:
                    388:                        /* undo changes */
                    389:                        TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
                    390:                        if (oia)
                    391:                                oia->ia_next = ia->ia_next;
                    392:                        else
                    393:                                in6_ifaddr = ia->ia_next;
                    394:                        free(ia, M_IFADDR);
                    395:                        return;
                    396:                }
                    397:        }
                    398:
                    399:        /* add route to the interface. */
                    400:        rtrequest(RTM_ADD,
                    401:                  (struct sockaddr *)&ia->ia_addr,
                    402:                  (struct sockaddr *)&ia->ia_addr,
                    403:                  (struct sockaddr *)&ia->ia_prefixmask,
                    404:                  RTF_UP|rtflag,
                    405:                  (struct rtentry **)0);
                    406:        ia->ia_flags |= IFA_ROUTE;
                    407:
                    408:        if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
                    409:                /*
                    410:                 * route local address to loopback
                    411:                 */
                    412:                bzero(&gate, sizeof(gate));
                    413:                gate.sin6_len = sizeof(struct sockaddr_in6);
                    414:                gate.sin6_family = AF_INET6;
                    415:                gate.sin6_addr = in6addr_loopback;
                    416:                bzero(&mask, sizeof(mask));
                    417:                mask.sin6_len = sizeof(struct sockaddr_in6);
                    418:                mask.sin6_family = AF_INET6;
                    419:                mask.sin6_addr = in6mask64;
                    420:                rtrequest(RTM_ADD,
                    421:                          (struct sockaddr *)&ia->ia_addr,
                    422:                          (struct sockaddr *)&gate,
                    423:                          (struct sockaddr *)&mask,
                    424:                          RTF_UP|RTF_HOST,
                    425:                          (struct rtentry **)0);
                    426:        }
                    427:
                    428:        /*
                    429:         * loopback address
                    430:         */
                    431:        ib = (struct in6_ifaddr *)NULL;
                    432:        if (type == IN6_IFT_LOOP) {
                    433:                ib = (struct in6_ifaddr *)
                    434:                        malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
                    435:                bzero((caddr_t)ib, sizeof(*ib));
                    436:                ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
                    437:                ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
                    438:                ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
                    439:                ib->ia_ifp = ifp;
                    440:
                    441:                ia->ia_next = ib;
                    442:                TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
                    443:                        ifa_list);
                    444:
                    445:                ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
                    446:                ib->ia_prefixmask.sin6_family = AF_INET6;
                    447:                ib->ia_prefixmask.sin6_addr = in6mask128;
                    448:                ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
                    449:                ib->ia_addr.sin6_family = AF_INET6;
                    450:                ib->ia_addr.sin6_addr = in6addr_loopback;
                    451: #ifdef __bsdi__
                    452:                /*
                    453:                 * It is necessary to set the loopback address to the dstaddr
                    454:                 * field at least for BSDI. Without this setting, the BSDI
                    455:                 * version of ifa_ifwithroute() rejects to add a route
                    456:                 * to the loopback interface.
                    457:                 */
                    458:                ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
                    459:                ib->ia_dstaddr.sin6_family = AF_INET6;
                    460:                ib->ia_dstaddr.sin6_addr = in6addr_loopback;
                    461: #endif /* __bsdi__ */
                    462:
                    463:                ib->ia_ifa.ifa_metric = ifp->if_metric;
                    464:
                    465:                rtrequest(RTM_ADD,
                    466:                          (struct sockaddr *)&ib->ia_addr,
                    467:                          (struct sockaddr *)&ib->ia_addr,
                    468:                          (struct sockaddr *)&ib->ia_prefixmask,
                    469:                          RTF_UP|RTF_HOST,
                    470:                          (struct rtentry **)0);
                    471:
                    472:                ib->ia_flags |= IFA_ROUTE;
                    473:        }
                    474:
                    475:        /*
                    476:         * join multicast
                    477:         */
                    478:        if (ifp->if_flags & IFF_MULTICAST) {
                    479:                int error;      /* not used */
                    480:
1.7       itojun    481: #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
1.2       itojun    482:                /* Restore saved multicast addresses(if any). */
                    483:                in6_restoremkludge(ia, ifp);
                    484: #endif
                    485:
                    486:                bzero(&mltmask, sizeof(mltmask));
                    487:                mltmask.sin6_len = sizeof(struct sockaddr_in6);
                    488:                mltmask.sin6_family = AF_INET6;
                    489:                mltmask.sin6_addr = in6mask32;
                    490:
                    491:                /*
                    492:                 * join link-local all-nodes address
                    493:                 */
                    494:                bzero(&mltaddr, sizeof(mltaddr));
                    495:                mltaddr.sin6_len = sizeof(struct sockaddr_in6);
                    496:                mltaddr.sin6_family = AF_INET6;
                    497:                mltaddr.sin6_addr = in6addr_linklocal_allnodes;
                    498:                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
                    499:                rtrequest(RTM_ADD,
                    500:                          (struct sockaddr *)&mltaddr,
                    501:                          (struct sockaddr *)&ia->ia_addr,
                    502:                          (struct sockaddr *)&mltmask,
                    503:                          RTF_UP|RTF_CLONING,  /* xxx */
                    504:                          (struct rtentry **)0);
                    505:                (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
                    506:
                    507:                if (type == IN6_IFT_LOOP) {
                    508:                        /*
                    509:                         * join node-local all-nodes address
                    510:                         */
                    511:                        mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
                    512:                        rtrequest(RTM_ADD,
                    513:                                  (struct sockaddr *)&mltaddr,
                    514:                                  (struct sockaddr *)&ib->ia_addr,
                    515:                                  (struct sockaddr *)&mltmask,
                    516:                                  RTF_UP,
                    517:                                  (struct rtentry **)0);
                    518:                        (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
                    519:                } else {
                    520:                        /*
                    521:                         * join solicited multicast address
                    522:                         */
                    523:                        bzero(&llsol, sizeof(llsol));
                    524:                        llsol.s6_addr16[0] = htons(0xff02);
                    525:                        llsol.s6_addr16[1] = htons(ifp->if_index);
                    526:                        llsol.s6_addr32[1] = 0;
                    527:                        llsol.s6_addr32[2] = htonl(1);
                    528:                        llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
                    529:                        llsol.s6_addr8[12] = 0xff;
                    530:                        (void)in6_addmulti(&llsol, ifp, &error);
                    531:                }
                    532:        }
                    533:
                    534:        /* update dynamically. */
                    535:        in6_iflladdr[ifp->if_index] = &ia->ia_addr.sin6_addr;
                    536:        if (in6_maxmtu < ifp->if_mtu)
                    537:                in6_maxmtu = ifp->if_mtu;
                    538:
                    539:        /* initialize NDP variables */
                    540:        nd6_ifattach(ifp);
                    541:
                    542:        /* mark the address TENTATIVE, if needed. */
                    543:        switch (ifp->if_type) {
1.8     ! is        544:        case IFT_ARCNET:
1.2       itojun    545:        case IFT_ETHER:
                    546:        case IFT_FDDI:
                    547: #if 0
                    548:        case IFT_ATM:
                    549:        case IFT_SLIP:
                    550:        case IFT_PPP:
                    551: #endif
                    552:                ia->ia6_flags |= IN6_IFF_TENTATIVE;
                    553:                /* nd6_dad_start() will be called in in6_if_up */
                    554:                break;
                    555:        case IFT_GIF:
                    556:        case IFT_LOOP:
                    557:        case IFT_FAITH:
                    558:        default:
                    559:                break;
                    560:        }
                    561:
                    562:        return;
                    563: }
                    564:
                    565: void
                    566: in6_ifdetach(ifp)
                    567:        struct ifnet *ifp;
                    568: {
                    569:        struct in6_ifaddr *ia, *oia;
                    570:        struct ifaddr *ifa;
                    571:        struct rtentry *rt;
                    572:        short rtflags;
                    573:
                    574:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) {
                    575:                if (ifa->ifa_addr->sa_family != AF_INET6
                    576:                 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
                    577:                        continue;
                    578:                }
                    579:
                    580:                ia = (struct in6_ifaddr *)ifa;
                    581:
                    582:                /* remove from the routing table */
                    583:                if ((ia->ia_flags & IFA_ROUTE)
                    584:                 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
                    585:                        rtflags = rt->rt_flags;
                    586:                        rtfree(rt);
                    587:                        rtrequest(RTM_DELETE,
                    588:                                (struct sockaddr *)&ia->ia_addr,
                    589:                                (struct sockaddr *)&ia->ia_addr,
                    590:                                (struct sockaddr *)&ia->ia_prefixmask,
                    591:                                rtflags, (struct rtentry **)0);
                    592:                }
                    593:
                    594:                /* remove from the linked list */
                    595:                TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
                    596:
                    597:                /* also remove from the IPv6 address chain(itojun&jinmei) */
                    598:                oia = ia;
                    599:                if (oia == (ia = in6_ifaddr))
                    600:                        in6_ifaddr = ia->ia_next;
                    601:                else {
                    602:                        while (ia->ia_next && (ia->ia_next != oia))
                    603:                                ia = ia->ia_next;
                    604:                        if (ia->ia_next)
                    605:                                ia->ia_next = oia->ia_next;
1.4       thorpej   606: #ifdef DEBUG
1.2       itojun    607:                        else
1.4       thorpej   608:                                printf("%s: didn't unlink in6ifaddr from "
                    609:                                    "list\n", ifp->if_xname);
                    610: #endif
1.2       itojun    611:                }
                    612:
                    613:                free(ia, M_IFADDR);
                    614:        }
                    615: }

CVSweb <webmaster@jp.NetBSD.org>