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

1.9     ! is          1: /*     $NetBSD: in6_ifattach.c,v 1.8 1999/09/19 21:31:34 is 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;
1.9     ! is        358:                if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8],
        !           359:                                laddr, 1) != 0) {
        !           360:                        break;
        !           361:                }
1.2       itojun    362:        }
                    363:
                    364:        ia->ia_ifa.ifa_metric = ifp->if_metric;
                    365:
                    366:        if (ifp->if_ioctl != NULL) {
                    367:                int s;
                    368:                int error;
                    369:
                    370:                /*
                    371:                 * give the interface a chance to initialize, in case this
                    372:                 * is the first address to be added.
                    373:                 */
                    374:                s = splimp();
                    375:                error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
                    376:                splx(s);
                    377:
                    378:                if (error) {
                    379:                        switch (error) {
                    380:                        case EAFNOSUPPORT:
1.4       thorpej   381:                                printf("%s: IPv6 not supported\n",
1.2       itojun    382:                                        ifp->if_xname);
                    383:                                break;
                    384:                        default:
1.4       thorpej   385:                                printf("%s: SIOCSIFADDR error %d\n",
1.2       itojun    386:                                        ifp->if_xname, error);
                    387:                                break;
                    388:                        }
                    389:
                    390:                        /* undo changes */
                    391:                        TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
                    392:                        if (oia)
                    393:                                oia->ia_next = ia->ia_next;
                    394:                        else
                    395:                                in6_ifaddr = ia->ia_next;
                    396:                        free(ia, M_IFADDR);
                    397:                        return;
                    398:                }
                    399:        }
                    400:
                    401:        /* add route to the interface. */
                    402:        rtrequest(RTM_ADD,
                    403:                  (struct sockaddr *)&ia->ia_addr,
                    404:                  (struct sockaddr *)&ia->ia_addr,
                    405:                  (struct sockaddr *)&ia->ia_prefixmask,
                    406:                  RTF_UP|rtflag,
                    407:                  (struct rtentry **)0);
                    408:        ia->ia_flags |= IFA_ROUTE;
                    409:
                    410:        if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
                    411:                /*
                    412:                 * route local address to loopback
                    413:                 */
                    414:                bzero(&gate, sizeof(gate));
                    415:                gate.sin6_len = sizeof(struct sockaddr_in6);
                    416:                gate.sin6_family = AF_INET6;
                    417:                gate.sin6_addr = in6addr_loopback;
                    418:                bzero(&mask, sizeof(mask));
                    419:                mask.sin6_len = sizeof(struct sockaddr_in6);
                    420:                mask.sin6_family = AF_INET6;
                    421:                mask.sin6_addr = in6mask64;
                    422:                rtrequest(RTM_ADD,
                    423:                          (struct sockaddr *)&ia->ia_addr,
                    424:                          (struct sockaddr *)&gate,
                    425:                          (struct sockaddr *)&mask,
                    426:                          RTF_UP|RTF_HOST,
                    427:                          (struct rtentry **)0);
                    428:        }
                    429:
                    430:        /*
                    431:         * loopback address
                    432:         */
                    433:        ib = (struct in6_ifaddr *)NULL;
                    434:        if (type == IN6_IFT_LOOP) {
                    435:                ib = (struct in6_ifaddr *)
                    436:                        malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
                    437:                bzero((caddr_t)ib, sizeof(*ib));
                    438:                ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
                    439:                ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
                    440:                ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
                    441:                ib->ia_ifp = ifp;
                    442:
                    443:                ia->ia_next = ib;
                    444:                TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
                    445:                        ifa_list);
                    446:
                    447:                ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
                    448:                ib->ia_prefixmask.sin6_family = AF_INET6;
                    449:                ib->ia_prefixmask.sin6_addr = in6mask128;
                    450:                ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
                    451:                ib->ia_addr.sin6_family = AF_INET6;
                    452:                ib->ia_addr.sin6_addr = in6addr_loopback;
                    453: #ifdef __bsdi__
                    454:                /*
                    455:                 * It is necessary to set the loopback address to the dstaddr
                    456:                 * field at least for BSDI. Without this setting, the BSDI
                    457:                 * version of ifa_ifwithroute() rejects to add a route
                    458:                 * to the loopback interface.
                    459:                 */
                    460:                ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
                    461:                ib->ia_dstaddr.sin6_family = AF_INET6;
                    462:                ib->ia_dstaddr.sin6_addr = in6addr_loopback;
                    463: #endif /* __bsdi__ */
                    464:
                    465:                ib->ia_ifa.ifa_metric = ifp->if_metric;
                    466:
                    467:                rtrequest(RTM_ADD,
                    468:                          (struct sockaddr *)&ib->ia_addr,
                    469:                          (struct sockaddr *)&ib->ia_addr,
                    470:                          (struct sockaddr *)&ib->ia_prefixmask,
                    471:                          RTF_UP|RTF_HOST,
                    472:                          (struct rtentry **)0);
                    473:
                    474:                ib->ia_flags |= IFA_ROUTE;
                    475:        }
                    476:
                    477:        /*
                    478:         * join multicast
                    479:         */
                    480:        if (ifp->if_flags & IFF_MULTICAST) {
                    481:                int error;      /* not used */
                    482:
1.7       itojun    483: #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
1.2       itojun    484:                /* Restore saved multicast addresses(if any). */
                    485:                in6_restoremkludge(ia, ifp);
                    486: #endif
                    487:
                    488:                bzero(&mltmask, sizeof(mltmask));
                    489:                mltmask.sin6_len = sizeof(struct sockaddr_in6);
                    490:                mltmask.sin6_family = AF_INET6;
                    491:                mltmask.sin6_addr = in6mask32;
                    492:
                    493:                /*
                    494:                 * join link-local all-nodes address
                    495:                 */
                    496:                bzero(&mltaddr, sizeof(mltaddr));
                    497:                mltaddr.sin6_len = sizeof(struct sockaddr_in6);
                    498:                mltaddr.sin6_family = AF_INET6;
                    499:                mltaddr.sin6_addr = in6addr_linklocal_allnodes;
                    500:                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
                    501:                rtrequest(RTM_ADD,
                    502:                          (struct sockaddr *)&mltaddr,
                    503:                          (struct sockaddr *)&ia->ia_addr,
                    504:                          (struct sockaddr *)&mltmask,
                    505:                          RTF_UP|RTF_CLONING,  /* xxx */
                    506:                          (struct rtentry **)0);
                    507:                (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
                    508:
                    509:                if (type == IN6_IFT_LOOP) {
                    510:                        /*
                    511:                         * join node-local all-nodes address
                    512:                         */
                    513:                        mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
                    514:                        rtrequest(RTM_ADD,
                    515:                                  (struct sockaddr *)&mltaddr,
                    516:                                  (struct sockaddr *)&ib->ia_addr,
                    517:                                  (struct sockaddr *)&mltmask,
                    518:                                  RTF_UP,
                    519:                                  (struct rtentry **)0);
                    520:                        (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
                    521:                } else {
                    522:                        /*
                    523:                         * join solicited multicast address
                    524:                         */
                    525:                        bzero(&llsol, sizeof(llsol));
                    526:                        llsol.s6_addr16[0] = htons(0xff02);
                    527:                        llsol.s6_addr16[1] = htons(ifp->if_index);
                    528:                        llsol.s6_addr32[1] = 0;
                    529:                        llsol.s6_addr32[2] = htonl(1);
                    530:                        llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
                    531:                        llsol.s6_addr8[12] = 0xff;
                    532:                        (void)in6_addmulti(&llsol, ifp, &error);
                    533:                }
                    534:        }
                    535:
                    536:        /* update dynamically. */
                    537:        in6_iflladdr[ifp->if_index] = &ia->ia_addr.sin6_addr;
                    538:        if (in6_maxmtu < ifp->if_mtu)
                    539:                in6_maxmtu = ifp->if_mtu;
                    540:
                    541:        /* initialize NDP variables */
                    542:        nd6_ifattach(ifp);
                    543:
                    544:        /* mark the address TENTATIVE, if needed. */
                    545:        switch (ifp->if_type) {
1.8       is        546:        case IFT_ARCNET:
1.2       itojun    547:        case IFT_ETHER:
                    548:        case IFT_FDDI:
                    549: #if 0
                    550:        case IFT_ATM:
                    551:        case IFT_SLIP:
                    552:        case IFT_PPP:
                    553: #endif
                    554:                ia->ia6_flags |= IN6_IFF_TENTATIVE;
                    555:                /* nd6_dad_start() will be called in in6_if_up */
                    556:                break;
                    557:        case IFT_GIF:
                    558:        case IFT_LOOP:
                    559:        case IFT_FAITH:
                    560:        default:
                    561:                break;
                    562:        }
                    563:
                    564:        return;
                    565: }
                    566:
                    567: void
                    568: in6_ifdetach(ifp)
                    569:        struct ifnet *ifp;
                    570: {
                    571:        struct in6_ifaddr *ia, *oia;
                    572:        struct ifaddr *ifa;
                    573:        struct rtentry *rt;
                    574:        short rtflags;
                    575:
                    576:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) {
                    577:                if (ifa->ifa_addr->sa_family != AF_INET6
                    578:                 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
                    579:                        continue;
                    580:                }
                    581:
                    582:                ia = (struct in6_ifaddr *)ifa;
                    583:
                    584:                /* remove from the routing table */
                    585:                if ((ia->ia_flags & IFA_ROUTE)
                    586:                 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
                    587:                        rtflags = rt->rt_flags;
                    588:                        rtfree(rt);
                    589:                        rtrequest(RTM_DELETE,
                    590:                                (struct sockaddr *)&ia->ia_addr,
                    591:                                (struct sockaddr *)&ia->ia_addr,
                    592:                                (struct sockaddr *)&ia->ia_prefixmask,
                    593:                                rtflags, (struct rtentry **)0);
                    594:                }
                    595:
                    596:                /* remove from the linked list */
                    597:                TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
                    598:
                    599:                /* also remove from the IPv6 address chain(itojun&jinmei) */
                    600:                oia = ia;
                    601:                if (oia == (ia = in6_ifaddr))
                    602:                        in6_ifaddr = ia->ia_next;
                    603:                else {
                    604:                        while (ia->ia_next && (ia->ia_next != oia))
                    605:                                ia = ia->ia_next;
                    606:                        if (ia->ia_next)
                    607:                                ia->ia_next = oia->ia_next;
1.4       thorpej   608: #ifdef DEBUG
1.2       itojun    609:                        else
1.4       thorpej   610:                                printf("%s: didn't unlink in6ifaddr from "
                    611:                                    "list\n", ifp->if_xname);
                    612: #endif
1.2       itojun    613:                }
                    614:
                    615:                free(ia, M_IFADDR);
                    616:        }
                    617: }

CVSweb <webmaster@jp.NetBSD.org>