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

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

1.1     ! nbrk        1: /*     $OpenBSD: nd6_nbr.c,v 1.45 2007/06/08 09:31:38 henning Exp $    */
        !             2: /*     $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $        */
        !             3:
        !             4: /*
        !             5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
        !             6:  * All rights reserved.
        !             7:  *
        !             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.
        !            19:  *
        !            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: #include <sys/param.h>
        !            34: #include <sys/systm.h>
        !            35: #include <sys/malloc.h>
        !            36: #include <sys/mbuf.h>
        !            37: #include <sys/socket.h>
        !            38: #include <sys/sockio.h>
        !            39: #include <sys/time.h>
        !            40: #include <sys/kernel.h>
        !            41: #include <sys/errno.h>
        !            42: #include <sys/ioctl.h>
        !            43: #include <sys/syslog.h>
        !            44: #include <sys/queue.h>
        !            45: #include <sys/timeout.h>
        !            46:
        !            47: #include <net/if.h>
        !            48: #include <net/if_types.h>
        !            49: #include <net/if_dl.h>
        !            50: #include <net/route.h>
        !            51:
        !            52: #include <netinet/in.h>
        !            53: #include <netinet/in_var.h>
        !            54: #include <netinet6/in6_var.h>
        !            55: #include <netinet/ip6.h>
        !            56: #include <netinet6/ip6_var.h>
        !            57: #include <netinet6/nd6.h>
        !            58: #include <netinet/icmp6.h>
        !            59:
        !            60: #include <dev/rndvar.h>
        !            61:
        !            62: #include "carp.h"
        !            63: #if NCARP > 0
        !            64: #include <netinet/ip_carp.h>
        !            65: #endif
        !            66:
        !            67: #define SDL(s) ((struct sockaddr_dl *)s)
        !            68:
        !            69: struct dadq;
        !            70: static struct dadq *nd6_dad_find(struct ifaddr *);
        !            71: static void nd6_dad_starttimer(struct dadq *, int);
        !            72: static void nd6_dad_stoptimer(struct dadq *);
        !            73: static void nd6_dad_timer(struct ifaddr *);
        !            74: static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
        !            75: static void nd6_dad_ns_input(struct ifaddr *);
        !            76: static void nd6_dad_na_input(struct ifaddr *);
        !            77:
        !            78: static int dad_ignore_ns = 0;  /* ignore NS in DAD - specwise incorrect*/
        !            79: static int dad_maxtry = 15;    /* max # of *tries* to transmit DAD packet */
        !            80:
        !            81: /*
        !            82:  * Input an Neighbor Solicitation Message.
        !            83:  *
        !            84:  * Based on RFC 2461
        !            85:  * Based on RFC 2462 (duplicated address detection)
        !            86:  */
        !            87: void
        !            88: nd6_ns_input(m, off, icmp6len)
        !            89:        struct mbuf *m;
        !            90:        int off, icmp6len;
        !            91: {
        !            92:        struct ifnet *ifp = m->m_pkthdr.rcvif;
        !            93:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        !            94:        struct nd_neighbor_solicit *nd_ns;
        !            95:        struct in6_addr saddr6 = ip6->ip6_src;
        !            96:        struct in6_addr daddr6 = ip6->ip6_dst;
        !            97:        struct in6_addr taddr6;
        !            98:        struct in6_addr myaddr6;
        !            99:        char *lladdr = NULL;
        !           100:        struct ifaddr *ifa = NULL;
        !           101:        int lladdrlen = 0;
        !           102:        int anycast = 0, proxy = 0, tentative = 0;
        !           103:        int router = ip6_forwarding;
        !           104:        int tlladdr;
        !           105:        union nd_opts ndopts;
        !           106:        struct sockaddr_dl *proxydl = NULL;
        !           107:
        !           108:        IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
        !           109:        if (nd_ns == NULL) {
        !           110:                icmp6stat.icp6s_tooshort++;
        !           111:                return;
        !           112:        }
        !           113:        ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
        !           114:        taddr6 = nd_ns->nd_ns_target;
        !           115:
        !           116:        if (ip6->ip6_hlim != 255) {
        !           117:                nd6log((LOG_ERR,
        !           118:                    "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
        !           119:                    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
        !           120:                    ip6_sprintf(&ip6->ip6_dst), ifp->if_xname));
        !           121:                goto bad;
        !           122:        }
        !           123:
        !           124:        if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
        !           125:                /* dst has to be solicited node multicast address. */
        !           126:                /* don't check ifindex portion */
        !           127:                if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL &&
        !           128:                    daddr6.s6_addr32[1] == 0 &&
        !           129:                    daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE &&
        !           130:                    daddr6.s6_addr8[12] == 0xff) {
        !           131:                        ; /*good*/
        !           132:                } else {
        !           133:                        nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
        !           134:                            "(wrong ip6 dst)\n"));
        !           135:                        goto bad;
        !           136:                }
        !           137:        }
        !           138:
        !           139:        if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
        !           140:                nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
        !           141:                goto bad;
        !           142:        }
        !           143:
        !           144:        if (IN6_IS_SCOPE_EMBED(&taddr6))
        !           145:                taddr6.s6_addr16[1] = htons(ifp->if_index);
        !           146:
        !           147:        icmp6len -= sizeof(*nd_ns);
        !           148:        nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
        !           149:        if (nd6_options(&ndopts) < 0) {
        !           150:                nd6log((LOG_INFO,
        !           151:                    "nd6_ns_input: invalid ND option, ignored\n"));
        !           152:                /* nd6_options have incremented stats */
        !           153:                goto freeit;
        !           154:        }
        !           155:
        !           156:        if (ndopts.nd_opts_src_lladdr) {
        !           157:                lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
        !           158:                lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
        !           159:        }
        !           160:
        !           161:        if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
        !           162:                nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
        !           163:                    "(link-layer address option)\n"));
        !           164:                goto bad;
        !           165:        }
        !           166:
        !           167:        /*
        !           168:         * Attaching target link-layer address to the NA?
        !           169:         * (RFC 2461 7.2.4)
        !           170:         *
        !           171:         * NS IP dst is unicast/anycast                 MUST NOT add
        !           172:         * NS IP dst is solicited-node multicast        MUST add
        !           173:         *
        !           174:         * In implementation, we add target link-layer address by default.
        !           175:         * We do not add one in MUST NOT cases.
        !           176:         */
        !           177: #if 0 /* too much! */
        !           178:        ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6);
        !           179:        if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST))
        !           180:                tlladdr = 0;
        !           181:        else
        !           182: #endif
        !           183:        if (!IN6_IS_ADDR_MULTICAST(&daddr6))
        !           184:                tlladdr = 0;
        !           185:        else
        !           186:                tlladdr = 1;
        !           187:
        !           188:        /*
        !           189:         * Target address (taddr6) must be either:
        !           190:         * (1) Valid unicast/anycast address for my receiving interface,
        !           191:         * (2) Unicast address for which I'm offering proxy service, or
        !           192:         * (3) "tentative" address on which DAD is being performed.
        !           193:         */
        !           194:        /* (1) and (3) check. */
        !           195: #if NCARP > 0
        !           196:        if (ifp->if_type == IFT_CARP) {
        !           197:                ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
        !           198:                if (ifa && !carp_iamatch6(ifp, ifa))
        !           199:                        ifa = NULL;
        !           200:        } else {
        !           201:                ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
        !           202:        }
        !           203: #else
        !           204:        ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
        !           205: #endif
        !           206:
        !           207:        /* (2) check. */
        !           208:        if (!ifa) {
        !           209:                struct rtentry *rt;
        !           210:                struct sockaddr_in6 tsin6;
        !           211:
        !           212:                bzero(&tsin6, sizeof tsin6);
        !           213:                tsin6.sin6_len = sizeof(struct sockaddr_in6);
        !           214:                tsin6.sin6_family = AF_INET6;
        !           215:                tsin6.sin6_addr = taddr6;
        !           216:
        !           217:                rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
        !           218:                if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
        !           219:                    rt->rt_gateway->sa_family == AF_LINK) {
        !           220:                        /*
        !           221:                         * proxy NDP for single entry
        !           222:                         */
        !           223:                        ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
        !           224:                                IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
        !           225:                        if (ifa) {
        !           226:                                proxy = 1;
        !           227:                                proxydl = SDL(rt->rt_gateway);
        !           228:                                router = 0;     /* XXX */
        !           229:                        }
        !           230:                }
        !           231:                if (rt)
        !           232:                        rtfree(rt);
        !           233:        }
        !           234:        if (!ifa) {
        !           235:                /*
        !           236:                 * We've got an NS packet, and we don't have that address
        !           237:                 * assigned for us.  We MUST silently ignore it.
        !           238:                 * See RFC2461 7.2.3.
        !           239:                 */
        !           240:                goto freeit;
        !           241:        }
        !           242:        myaddr6 = *IFA_IN6(ifa);
        !           243:        anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
        !           244:        tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
        !           245:        if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
        !           246:                goto freeit;
        !           247:
        !           248:        if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
        !           249:                nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s "
        !           250:                    "(if %d, NS packet %d)\n",
        !           251:                    ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
        !           252:                goto bad;
        !           253:        }
        !           254:
        !           255:        if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
        !           256:                log(LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
        !           257:                    ip6_sprintf(&saddr6));
        !           258:                goto freeit;
        !           259:        }
        !           260:
        !           261:        /*
        !           262:         * We have neighbor solicitation packet, with target address equals to
        !           263:         * one of my tentative address.
        !           264:         *
        !           265:         * src addr     how to process?
        !           266:         * ---          ---
        !           267:         * multicast    of course, invalid (rejected in ip6_input)
        !           268:         * unicast      somebody is doing address resolution -> ignore
        !           269:         * unspec       dup address detection
        !           270:         *
        !           271:         * The processing is defined in RFC 2462.
        !           272:         */
        !           273:        if (tentative) {
        !           274:                /*
        !           275:                 * If source address is unspecified address, it is for
        !           276:                 * duplicated address detection.
        !           277:                 *
        !           278:                 * If not, the packet is for address resolution;
        !           279:                 * silently ignore it.
        !           280:                 */
        !           281:                if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
        !           282:                        nd6_dad_ns_input(ifa);
        !           283:
        !           284:                goto freeit;
        !           285:        }
        !           286:
        !           287:        /*
        !           288:         * If the source address is unspecified address, entries must not
        !           289:         * be created or updated.
        !           290:         * It looks that sender is performing DAD.  Output NA toward
        !           291:         * all-node multicast address, to tell the sender that I'm using
        !           292:         * the address.
        !           293:         * S bit ("solicited") must be zero.
        !           294:         */
        !           295:        if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
        !           296:                saddr6 = in6addr_linklocal_allnodes;
        !           297:                saddr6.s6_addr16[1] = htons(ifp->if_index);
        !           298:                nd6_na_output(ifp, &saddr6, &taddr6,
        !           299:                    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
        !           300:                    (router ? ND_NA_FLAG_ROUTER : 0),
        !           301:                    tlladdr, (struct sockaddr *)proxydl);
        !           302:                goto freeit;
        !           303:        }
        !           304:
        !           305:        nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);
        !           306:
        !           307:        nd6_na_output(ifp, &saddr6, &taddr6,
        !           308:            ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
        !           309:            (router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
        !           310:            tlladdr, (struct sockaddr *)proxydl);
        !           311:  freeit:
        !           312:        m_freem(m);
        !           313:        return;
        !           314:
        !           315:  bad:
        !           316:        nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)));
        !           317:        nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)));
        !           318:        nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)));
        !           319:        icmp6stat.icp6s_badns++;
        !           320:        m_freem(m);
        !           321: }
        !           322:
        !           323: /*
        !           324:  * Output an Neighbor Solicitation Message. Caller specifies:
        !           325:  *     - ICMP6 header source IP6 address
        !           326:  *     - ND6 header target IP6 address
        !           327:  *     - ND6 header source datalink address
        !           328:  *
        !           329:  * Based on RFC 2461
        !           330:  * Based on RFC 2462 (duplicated address detection)
        !           331:  */
        !           332: void
        !           333: nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
        !           334:        struct ifnet *ifp;
        !           335:        struct in6_addr *daddr6, *taddr6;
        !           336:        struct llinfo_nd6 *ln;  /* for source address determination */
        !           337:        int dad;        /* duplicated address detection */
        !           338: {
        !           339:        struct mbuf *m;
        !           340:        struct ip6_hdr *ip6;
        !           341:        struct nd_neighbor_solicit *nd_ns;
        !           342:        struct sockaddr_in6 src_sa, dst_sa;
        !           343:        struct ip6_moptions im6o;
        !           344:        int icmp6len;
        !           345:        int maxlen;
        !           346:        caddr_t mac;
        !           347:        struct route_in6 ro;
        !           348:
        !           349:        bzero(&ro, sizeof(ro));
        !           350:
        !           351:        if (IN6_IS_ADDR_MULTICAST(taddr6))
        !           352:                return;
        !           353:
        !           354:        /* estimate the size of message */
        !           355:        maxlen = sizeof(*ip6) + sizeof(*nd_ns);
        !           356:        maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
        !           357: #ifdef DIAGNOSTIC
        !           358:        if (max_linkhdr + maxlen >= MCLBYTES) {
        !           359:                printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
        !           360:                    "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
        !           361:                panic("nd6_ns_output: insufficient MCLBYTES");
        !           362:                /* NOTREACHED */
        !           363:        }
        !           364: #endif
        !           365:
        !           366:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           367:        if (m && max_linkhdr + maxlen >= MHLEN) {
        !           368:                MCLGET(m, M_DONTWAIT);
        !           369:                if ((m->m_flags & M_EXT) == 0) {
        !           370:                        m_free(m);
        !           371:                        m = NULL;
        !           372:                }
        !           373:        }
        !           374:        if (m == NULL)
        !           375:                return;
        !           376:        m->m_pkthdr.rcvif = NULL;
        !           377:
        !           378:        if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
        !           379:                m->m_flags |= M_MCAST;
        !           380:                im6o.im6o_multicast_ifp = ifp;
        !           381:                im6o.im6o_multicast_hlim = 255;
        !           382:                im6o.im6o_multicast_loop = 0;
        !           383:        }
        !           384:
        !           385:        icmp6len = sizeof(*nd_ns);
        !           386:        m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
        !           387:        m->m_data += max_linkhdr;       /* or MH_ALIGN() equivalent? */
        !           388:
        !           389:        /* fill neighbor solicitation packet */
        !           390:        ip6 = mtod(m, struct ip6_hdr *);
        !           391:        ip6->ip6_flow = 0;
        !           392:        ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
        !           393:        ip6->ip6_vfc |= IPV6_VERSION;
        !           394:        /* ip6->ip6_plen will be set later */
        !           395:        ip6->ip6_nxt = IPPROTO_ICMPV6;
        !           396:        ip6->ip6_hlim = 255;
        !           397:        /* determine the source and destination addresses */
        !           398:        bzero(&src_sa, sizeof(src_sa));
        !           399:        bzero(&dst_sa, sizeof(dst_sa));
        !           400:        src_sa.sin6_family = dst_sa.sin6_family = AF_INET6;
        !           401:        src_sa.sin6_len = dst_sa.sin6_len = sizeof(struct sockaddr_in6);
        !           402:        if (daddr6)
        !           403:                dst_sa.sin6_addr = *daddr6;
        !           404:        else {
        !           405:                dst_sa.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
        !           406:                dst_sa.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !           407:                dst_sa.sin6_addr.s6_addr32[1] = 0;
        !           408:                dst_sa.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
        !           409:                dst_sa.sin6_addr.s6_addr32[3] = taddr6->s6_addr32[3];
        !           410:                dst_sa.sin6_addr.s6_addr8[12] = 0xff;
        !           411:        }
        !           412:        ip6->ip6_dst = dst_sa.sin6_addr;
        !           413:        if (!dad) {
        !           414:                /*
        !           415:                 * RFC2461 7.2.2:
        !           416:                 * "If the source address of the packet prompting the
        !           417:                 * solicitation is the same as one of the addresses assigned
        !           418:                 * to the outgoing interface, that address SHOULD be placed
        !           419:                 * in the IP Source Address of the outgoing solicitation.
        !           420:                 * Otherwise, any one of the addresses assigned to the
        !           421:                 * interface should be used."
        !           422:                 *
        !           423:                 * We use the source address for the prompting packet
        !           424:                 * (saddr6), if:
        !           425:                 * - saddr6 is given from the caller (by giving "ln"), and
        !           426:                 * - saddr6 belongs to the outgoing interface.
        !           427:                 * Otherwise, we perform the source address selection as usual.
        !           428:                 */
        !           429:                struct ip6_hdr *hip6;           /* hold ip6 */
        !           430:                struct in6_addr *saddr6;
        !           431:
        !           432:                if (ln && ln->ln_hold) {
        !           433:                        hip6 = mtod(ln->ln_hold, struct ip6_hdr *);
        !           434:                        /* XXX pullup? */
        !           435:                        if (sizeof(*hip6) < ln->ln_hold->m_len)
        !           436:                                saddr6 = &hip6->ip6_src;
        !           437:                        else
        !           438:                                saddr6 = NULL;
        !           439:                } else
        !           440:                        saddr6 = NULL;
        !           441:                if (saddr6 && in6ifa_ifpwithaddr(ifp, saddr6))
        !           442:                        src_sa.sin6_addr = *saddr6;
        !           443:                else {
        !           444:                        struct in6_addr *src0;
        !           445:                        int error;
        !           446:
        !           447:                        bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
        !           448:                        src0 = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL,
        !           449:                            &error);
        !           450:                        if (src0 == NULL) {
        !           451:                                nd6log((LOG_DEBUG,
        !           452:                                    "nd6_ns_output: source can't be "
        !           453:                                    "determined: dst=%s, error=%d\n",
        !           454:                                    ip6_sprintf(&dst_sa.sin6_addr), error));
        !           455:                                goto bad;
        !           456:                        }
        !           457:                        src_sa.sin6_addr = *src0;
        !           458:                }
        !           459:        } else {
        !           460:                /*
        !           461:                 * Source address for DAD packet must always be IPv6
        !           462:                 * unspecified address. (0::0)
        !           463:                 * We actually don't have to 0-clear the address (we did it
        !           464:                 * above), but we do so here explicitly to make the intention
        !           465:                 * clearer.
        !           466:                 */
        !           467:                bzero(&src_sa.sin6_addr, sizeof(src_sa.sin6_addr));
        !           468:        }
        !           469:        ip6->ip6_src = src_sa.sin6_addr;
        !           470:        nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);
        !           471:        nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
        !           472:        nd_ns->nd_ns_code = 0;
        !           473:        nd_ns->nd_ns_reserved = 0;
        !           474:        nd_ns->nd_ns_target = *taddr6;
        !           475:
        !           476:        if (IN6_IS_SCOPE_EMBED(&nd_ns->nd_ns_target))
        !           477:                nd_ns->nd_ns_target.s6_addr16[1] = 0;
        !           478:
        !           479:        /*
        !           480:         * Add source link-layer address option.
        !           481:         *
        !           482:         *                              spec            implementation
        !           483:         *                              ---             ---
        !           484:         * DAD packet                   MUST NOT        do not add the option
        !           485:         * there's no link layer address:
        !           486:         *                              impossible      do not add the option
        !           487:         * there's link layer address:
        !           488:         *      Multicast NS            MUST add one    add the option
        !           489:         *      Unicast NS              SHOULD add one  add the option
        !           490:         */
        !           491:        if (!dad && (mac = nd6_ifptomac(ifp))) {
        !           492:                int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
        !           493:                struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
        !           494:                /* 8 byte alignments... */
        !           495:                optlen = (optlen + 7) & ~7;
        !           496:
        !           497:                m->m_pkthdr.len += optlen;
        !           498:                m->m_len += optlen;
        !           499:                icmp6len += optlen;
        !           500:                bzero((caddr_t)nd_opt, optlen);
        !           501:                nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
        !           502:                nd_opt->nd_opt_len = optlen >> 3;
        !           503:                bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
        !           504:        }
        !           505:
        !           506:        ip6->ip6_plen = htons((u_short)icmp6len);
        !           507:        nd_ns->nd_ns_cksum = 0;
        !           508:        nd_ns->nd_ns_cksum =
        !           509:            in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
        !           510:
        !           511:        ip6_output(m, NULL, &ro, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL, NULL);
        !           512:        icmp6_ifstat_inc(ifp, ifs6_out_msg);
        !           513:        icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
        !           514:        icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
        !           515:
        !           516:        if (ro.ro_rt) {         /* we don't cache this route. */
        !           517:                RTFREE(ro.ro_rt);
        !           518:        }
        !           519:        return;
        !           520:
        !           521:   bad:
        !           522:        if (ro.ro_rt) {
        !           523:                RTFREE(ro.ro_rt);
        !           524:        }
        !           525:        m_freem(m);
        !           526:        return;
        !           527: }
        !           528:
        !           529: /*
        !           530:  * Neighbor advertisement input handling.
        !           531:  *
        !           532:  * Based on RFC 2461
        !           533:  * Based on RFC 2462 (duplicated address detection)
        !           534:  *
        !           535:  * the following items are not implemented yet:
        !           536:  * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
        !           537:  * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
        !           538:  */
        !           539: void
        !           540: nd6_na_input(m, off, icmp6len)
        !           541:        struct mbuf *m;
        !           542:        int off, icmp6len;
        !           543: {
        !           544:        struct ifnet *ifp = m->m_pkthdr.rcvif;
        !           545:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        !           546:        struct nd_neighbor_advert *nd_na;
        !           547: #if 0
        !           548:        struct in6_addr saddr6 = ip6->ip6_src;
        !           549: #endif
        !           550:        struct in6_addr daddr6 = ip6->ip6_dst;
        !           551:        struct in6_addr taddr6;
        !           552:        int flags;
        !           553:        int is_router;
        !           554:        int is_solicited;
        !           555:        int is_override;
        !           556:        char *lladdr = NULL;
        !           557:        int lladdrlen = 0;
        !           558:        struct ifaddr *ifa;
        !           559:        struct llinfo_nd6 *ln;
        !           560:        struct rtentry *rt;
        !           561:        struct sockaddr_dl *sdl;
        !           562:        union nd_opts ndopts;
        !           563:
        !           564:        if (ip6->ip6_hlim != 255) {
        !           565:                nd6log((LOG_ERR,
        !           566:                    "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n",
        !           567:                    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
        !           568:                    ip6_sprintf(&ip6->ip6_dst), ifp->if_xname));
        !           569:                goto bad;
        !           570:        }
        !           571:
        !           572:        IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
        !           573:        if (nd_na == NULL) {
        !           574:                icmp6stat.icp6s_tooshort++;
        !           575:                return;
        !           576:        }
        !           577:        taddr6 = nd_na->nd_na_target;
        !           578:        flags = nd_na->nd_na_flags_reserved;
        !           579:        is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
        !           580:        is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
        !           581:        is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
        !           582:
        !           583:        if (IN6_IS_SCOPE_EMBED(&taddr6))
        !           584:                taddr6.s6_addr16[1] = htons(ifp->if_index);
        !           585:
        !           586:        if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
        !           587:                nd6log((LOG_ERR,
        !           588:                    "nd6_na_input: invalid target address %s\n",
        !           589:                    ip6_sprintf(&taddr6)));
        !           590:                goto bad;
        !           591:        }
        !           592:        if (is_solicited && IN6_IS_ADDR_MULTICAST(&daddr6)) {
        !           593:                nd6log((LOG_ERR,
        !           594:                    "nd6_na_input: a solicited adv is multicasted\n"));
        !           595:                goto bad;
        !           596:        }
        !           597:
        !           598:        icmp6len -= sizeof(*nd_na);
        !           599:        nd6_option_init(nd_na + 1, icmp6len, &ndopts);
        !           600:        if (nd6_options(&ndopts) < 0) {
        !           601:                nd6log((LOG_INFO,
        !           602:                    "nd6_na_input: invalid ND option, ignored\n"));
        !           603:                /* nd6_options have incremented stats */
        !           604:                goto freeit;
        !           605:        }
        !           606:
        !           607:        if (ndopts.nd_opts_tgt_lladdr) {
        !           608:                lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
        !           609:                lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
        !           610:        }
        !           611:
        !           612:        ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
        !           613:
        !           614:        /*
        !           615:         * Target address matches one of my interface address.
        !           616:         *
        !           617:         * If my address is tentative, this means that there's somebody
        !           618:         * already using the same address as mine.  This indicates DAD failure.
        !           619:         * This is defined in RFC 2462.
        !           620:         *
        !           621:         * Otherwise, process as defined in RFC 2461.
        !           622:         */
        !           623:        if (ifa
        !           624:         && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
        !           625:                nd6_dad_na_input(ifa);
        !           626:                goto freeit;
        !           627:        }
        !           628:
        !           629:        /* Just for safety, maybe unnecessary. */
        !           630:        if (ifa) {
        !           631:                log(LOG_ERR,
        !           632:                    "nd6_na_input: duplicate IP6 address %s\n",
        !           633:                    ip6_sprintf(&taddr6));
        !           634:                goto freeit;
        !           635:        }
        !           636:
        !           637:        if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
        !           638:                nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s "
        !           639:                    "(if %d, NA packet %d)\n", ip6_sprintf(&taddr6),
        !           640:                    ifp->if_addrlen, lladdrlen - 2));
        !           641:                goto bad;
        !           642:        }
        !           643:
        !           644:        /*
        !           645:         * If no neighbor cache entry is found, NA SHOULD silently be
        !           646:         * discarded.
        !           647:         */
        !           648:        rt = nd6_lookup(&taddr6, 0, ifp);
        !           649:        if ((rt == NULL) ||
        !           650:           ((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
        !           651:           ((sdl = SDL(rt->rt_gateway)) == NULL))
        !           652:                goto freeit;
        !           653:
        !           654:        if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
        !           655:                /*
        !           656:                 * If the link-layer has address, and no lladdr option came,
        !           657:                 * discard the packet.
        !           658:                 */
        !           659:                if (ifp->if_addrlen && !lladdr)
        !           660:                        goto freeit;
        !           661:
        !           662:                /*
        !           663:                 * Record link-layer address, and update the state.
        !           664:                 */
        !           665:                sdl->sdl_alen = ifp->if_addrlen;
        !           666:                bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
        !           667:                if (is_solicited) {
        !           668:                        ln->ln_state = ND6_LLINFO_REACHABLE;
        !           669:                        ln->ln_byhint = 0;
        !           670:                        if (!ND6_LLINFO_PERMANENT(ln)) {
        !           671:                                nd6_llinfo_settimer(ln,
        !           672:                                    (long)ND_IFINFO(rt->rt_ifp)->reachable * hz);
        !           673:                        }
        !           674:                } else {
        !           675:                        ln->ln_state = ND6_LLINFO_STALE;
        !           676:                        nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
        !           677:                }
        !           678:                if ((ln->ln_router = is_router) != 0) {
        !           679:                        /*
        !           680:                         * This means a router's state has changed from
        !           681:                         * non-reachable to probably reachable, and might
        !           682:                         * affect the status of associated prefixes..
        !           683:                         */
        !           684:                        pfxlist_onlink_check();
        !           685:                }
        !           686:        } else {
        !           687:                int llchange;
        !           688:
        !           689:                /*
        !           690:                 * Check if the link-layer address has changed or not.
        !           691:                 */
        !           692:                if (!lladdr)
        !           693:                        llchange = 0;
        !           694:                else {
        !           695:                        if (sdl->sdl_alen) {
        !           696:                                if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen))
        !           697:                                        llchange = 1;
        !           698:                                else
        !           699:                                        llchange = 0;
        !           700:                        } else
        !           701:                                llchange = 1;
        !           702:                }
        !           703:
        !           704:                /*
        !           705:                 * This is VERY complex.  Look at it with care.
        !           706:                 *
        !           707:                 * override solicit lladdr llchange     action
        !           708:                 *                                      (L: record lladdr)
        !           709:                 *
        !           710:                 *      0       0       n       --      (2c)
        !           711:                 *      0       0       y       n       (2b) L
        !           712:                 *      0       0       y       y       (1)    REACHABLE->STALE
        !           713:                 *      0       1       n       --      (2c)   *->REACHABLE
        !           714:                 *      0       1       y       n       (2b) L *->REACHABLE
        !           715:                 *      0       1       y       y       (1)    REACHABLE->STALE
        !           716:                 *      1       0       n       --      (2a)
        !           717:                 *      1       0       y       n       (2a) L
        !           718:                 *      1       0       y       y       (2a) L *->STALE
        !           719:                 *      1       1       n       --      (2a)   *->REACHABLE
        !           720:                 *      1       1       y       n       (2a) L *->REACHABLE
        !           721:                 *      1       1       y       y       (2a) L *->REACHABLE
        !           722:                 */
        !           723:                if (!is_override && (lladdr && llchange)) {        /* (1) */
        !           724:                        /*
        !           725:                         * If state is REACHABLE, make it STALE.
        !           726:                         * no other updates should be done.
        !           727:                         */
        !           728:                        if (ln->ln_state == ND6_LLINFO_REACHABLE) {
        !           729:                                ln->ln_state = ND6_LLINFO_STALE;
        !           730:                                nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
        !           731:                        }
        !           732:                        goto freeit;
        !           733:                } else if (is_override                             /* (2a) */
        !           734:                        || (!is_override && (lladdr && !llchange)) /* (2b) */
        !           735:                        || !lladdr) {                              /* (2c) */
        !           736:                        /*
        !           737:                         * Update link-local address, if any.
        !           738:                         */
        !           739:                        if (lladdr) {
        !           740:                                sdl->sdl_alen = ifp->if_addrlen;
        !           741:                                bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
        !           742:                        }
        !           743:
        !           744:                        /*
        !           745:                         * If solicited, make the state REACHABLE.
        !           746:                         * If not solicited and the link-layer address was
        !           747:                         * changed, make it STALE.
        !           748:                         */
        !           749:                        if (is_solicited) {
        !           750:                                ln->ln_state = ND6_LLINFO_REACHABLE;
        !           751:                                ln->ln_byhint = 0;
        !           752:                                if (!ND6_LLINFO_PERMANENT(ln)) {
        !           753:                                        nd6_llinfo_settimer(ln,
        !           754:                                            (long)ND_IFINFO(ifp)->reachable * hz);
        !           755:                                }
        !           756:                        } else {
        !           757:                                if (lladdr && llchange) {
        !           758:                                        ln->ln_state = ND6_LLINFO_STALE;
        !           759:                                        nd6_llinfo_settimer(ln,
        !           760:                                            (long)nd6_gctimer * hz);
        !           761:                                }
        !           762:                        }
        !           763:                }
        !           764:
        !           765:                if (ln->ln_router && !is_router) {
        !           766:                        /*
        !           767:                         * The peer dropped the router flag.
        !           768:                         * Remove the sender from the Default Router List and
        !           769:                         * update the Destination Cache entries.
        !           770:                         */
        !           771:                        struct nd_defrouter *dr;
        !           772:                        struct in6_addr *in6;
        !           773:                        int s;
        !           774:
        !           775:                        in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
        !           776:
        !           777:                        /*
        !           778:                         * Lock to protect the default router list.
        !           779:                         * XXX: this might be unnecessary, since this function
        !           780:                         * is only called under the network software interrupt
        !           781:                         * context.  However, we keep it just for safety.
        !           782:                         */
        !           783:                        s = splsoftnet();
        !           784:                        dr = defrouter_lookup(in6, rt->rt_ifp);
        !           785:                        if (dr)
        !           786:                                defrtrlist_del(dr);
        !           787:                        else if (!ip6_forwarding) {
        !           788:                                /*
        !           789:                                 * Even if the neighbor is not in the default
        !           790:                                 * router list, the neighbor may be used
        !           791:                                 * as a next hop for some destinations
        !           792:                                 * (e.g. redirect case). So we must
        !           793:                                 * call rt6_flush explicitly.
        !           794:                                 */
        !           795:                                rt6_flush(&ip6->ip6_src, rt->rt_ifp);
        !           796:                        }
        !           797:                        splx(s);
        !           798:                }
        !           799:                ln->ln_router = is_router;
        !           800:        }
        !           801:        rt->rt_flags &= ~RTF_REJECT;
        !           802:        ln->ln_asked = 0;
        !           803:        if (ln->ln_hold) {
        !           804:                /*
        !           805:                 * we assume ifp is not a loopback here, so just set the 2nd
        !           806:                 * argument as the 1st one.
        !           807:                 */
        !           808:                nd6_output(ifp, ifp, ln->ln_hold,
        !           809:                           (struct sockaddr_in6 *)rt_key(rt), rt);
        !           810:                ln->ln_hold = NULL;
        !           811:        }
        !           812:
        !           813:  freeit:
        !           814:        m_freem(m);
        !           815:        return;
        !           816:
        !           817:  bad:
        !           818:        icmp6stat.icp6s_badna++;
        !           819:        m_freem(m);
        !           820: }
        !           821:
        !           822: /*
        !           823:  * Neighbor advertisement output handling.
        !           824:  *
        !           825:  * Based on RFC 2461
        !           826:  *
        !           827:  * the following items are not implemented yet:
        !           828:  * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
        !           829:  * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
        !           830:  */
        !           831: void
        !           832: nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
        !           833:        struct ifnet *ifp;
        !           834:        struct in6_addr *daddr6, *taddr6;
        !           835:        u_long flags;
        !           836:        int tlladdr;            /* 1 if include target link-layer address */
        !           837:        struct sockaddr *sdl0;  /* sockaddr_dl (= proxy NA) or NULL */
        !           838: {
        !           839:        struct mbuf *m;
        !           840:        struct ip6_hdr *ip6;
        !           841:        struct nd_neighbor_advert *nd_na;
        !           842:        struct ip6_moptions im6o;
        !           843:        struct sockaddr_in6 src_sa, dst_sa;
        !           844:        struct in6_addr *src0;
        !           845:        int icmp6len, maxlen, error;
        !           846:        caddr_t mac;
        !           847:        struct route_in6 ro;
        !           848:
        !           849:        mac = NULL;
        !           850:        bzero(&ro, sizeof(ro));
        !           851:
        !           852:        /* estimate the size of message */
        !           853:        maxlen = sizeof(*ip6) + sizeof(*nd_na);
        !           854:        maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
        !           855: #ifdef DIAGNOSTIC
        !           856:        if (max_linkhdr + maxlen >= MCLBYTES) {
        !           857:                printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
        !           858:                    "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
        !           859:                panic("nd6_na_output: insufficient MCLBYTES");
        !           860:                /* NOTREACHED */
        !           861:        }
        !           862: #endif
        !           863:
        !           864:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           865:        if (m && max_linkhdr + maxlen >= MHLEN) {
        !           866:                MCLGET(m, M_DONTWAIT);
        !           867:                if ((m->m_flags & M_EXT) == 0) {
        !           868:                        m_free(m);
        !           869:                        m = NULL;
        !           870:                }
        !           871:        }
        !           872:        if (m == NULL)
        !           873:                return;
        !           874:        m->m_pkthdr.rcvif = NULL;
        !           875:
        !           876:        if (IN6_IS_ADDR_MULTICAST(daddr6)) {
        !           877:                m->m_flags |= M_MCAST;
        !           878:                im6o.im6o_multicast_ifp = ifp;
        !           879:                im6o.im6o_multicast_hlim = 255;
        !           880:                im6o.im6o_multicast_loop = 0;
        !           881:        }
        !           882:
        !           883:        icmp6len = sizeof(*nd_na);
        !           884:        m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
        !           885:        m->m_data += max_linkhdr;       /* or MH_ALIGN() equivalent? */
        !           886:
        !           887:        /* fill neighbor advertisement packet */
        !           888:        ip6 = mtod(m, struct ip6_hdr *);
        !           889:        ip6->ip6_flow = 0;
        !           890:        ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
        !           891:        ip6->ip6_vfc |= IPV6_VERSION;
        !           892:        ip6->ip6_nxt = IPPROTO_ICMPV6;
        !           893:        ip6->ip6_hlim = 255;
        !           894:        bzero(&src_sa, sizeof(src_sa));
        !           895:        bzero(&dst_sa, sizeof(dst_sa));
        !           896:        src_sa.sin6_len = dst_sa.sin6_len = sizeof(struct sockaddr_in6);
        !           897:        src_sa.sin6_family = dst_sa.sin6_family = AF_INET6;
        !           898:        dst_sa.sin6_addr = *daddr6;
        !           899:        if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
        !           900:                /* reply to DAD */
        !           901:                dst_sa.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
        !           902:                dst_sa.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !           903:                dst_sa.sin6_addr.s6_addr32[1] = 0;
        !           904:                dst_sa.sin6_addr.s6_addr32[2] = 0;
        !           905:                dst_sa.sin6_addr.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
        !           906:
        !           907:                flags &= ~ND_NA_FLAG_SOLICITED;
        !           908:        }
        !           909:        ip6->ip6_dst = dst_sa.sin6_addr;
        !           910:
        !           911:        /*
        !           912:         * Select a source whose scope is the same as that of the dest.
        !           913:         */
        !           914:        bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
        !           915:        src0 = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, &error);
        !           916:        if (src0 == NULL) {
        !           917:                nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
        !           918:                    "determined: dst=%s, error=%d\n",
        !           919:                    ip6_sprintf(&dst_sa.sin6_addr), error));
        !           920:                goto bad;
        !           921:        }
        !           922:        src_sa.sin6_addr = *src0;
        !           923:        ip6->ip6_src = src_sa.sin6_addr;
        !           924:        nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
        !           925:        nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
        !           926:        nd_na->nd_na_code = 0;
        !           927:        nd_na->nd_na_target = *taddr6;
        !           928:        if (IN6_IS_SCOPE_EMBED(&nd_na->nd_na_target))
        !           929:                nd_na->nd_na_target.s6_addr16[1] = 0;
        !           930:
        !           931:        /*
        !           932:         * "tlladdr" indicates NS's condition for adding tlladdr or not.
        !           933:         * see nd6_ns_input() for details.
        !           934:         * Basically, if NS packet is sent to unicast/anycast addr,
        !           935:         * target lladdr option SHOULD NOT be included.
        !           936:         */
        !           937:        if (tlladdr) {
        !           938:                /*
        !           939:                 * sdl0 != NULL indicates proxy NA.  If we do proxy, use
        !           940:                 * lladdr in sdl0.  If we are not proxying (sending NA for
        !           941:                 * my address) use lladdr configured for the interface.
        !           942:                 */
        !           943:                if (sdl0 == NULL) {
        !           944:                        mac = nd6_ifptomac(ifp);
        !           945:                } else if (sdl0->sa_family == AF_LINK) {
        !           946:                        struct sockaddr_dl *sdl;
        !           947:                        sdl = (struct sockaddr_dl *)sdl0;
        !           948:                        if (sdl->sdl_alen == ifp->if_addrlen)
        !           949:                                mac = LLADDR(sdl);
        !           950:                }
        !           951:        }
        !           952:        if (tlladdr && mac) {
        !           953:                int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
        !           954:                struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
        !           955:
        !           956:                /* roundup to 8 bytes alignment! */
        !           957:                optlen = (optlen + 7) & ~7;
        !           958:
        !           959:                m->m_pkthdr.len += optlen;
        !           960:                m->m_len += optlen;
        !           961:                icmp6len += optlen;
        !           962:                bzero((caddr_t)nd_opt, optlen);
        !           963:                nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
        !           964:                nd_opt->nd_opt_len = optlen >> 3;
        !           965:                bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
        !           966:        } else
        !           967:                flags &= ~ND_NA_FLAG_OVERRIDE;
        !           968:
        !           969:        ip6->ip6_plen = htons((u_short)icmp6len);
        !           970:        nd_na->nd_na_flags_reserved = flags;
        !           971:        nd_na->nd_na_cksum = 0;
        !           972:        nd_na->nd_na_cksum =
        !           973:            in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
        !           974:
        !           975:        ip6_output(m, NULL, &ro, 0, &im6o, NULL, NULL);
        !           976:
        !           977:        icmp6_ifstat_inc(ifp, ifs6_out_msg);
        !           978:        icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert);
        !           979:        icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
        !           980:
        !           981:        if (ro.ro_rt) {         /* we don't cache this route. */
        !           982:                RTFREE(ro.ro_rt);
        !           983:        }
        !           984:        return;
        !           985:
        !           986:   bad:
        !           987:        if (ro.ro_rt) {
        !           988:                RTFREE(ro.ro_rt);
        !           989:        }
        !           990:        m_freem(m);
        !           991:        return;
        !           992: }
        !           993:
        !           994: caddr_t
        !           995: nd6_ifptomac(ifp)
        !           996:        struct ifnet *ifp;
        !           997: {
        !           998:        switch (ifp->if_type) {
        !           999:        case IFT_ETHER:
        !          1000:        case IFT_FDDI:
        !          1001:        case IFT_IEEE1394:
        !          1002:        case IFT_PROPVIRTUAL:
        !          1003:        case IFT_CARP:
        !          1004:        case IFT_L2VLAN:
        !          1005:        case IFT_IEEE80211:
        !          1006:                return ((caddr_t)(ifp + 1));
        !          1007:        default:
        !          1008:                return NULL;
        !          1009:        }
        !          1010: }
        !          1011:
        !          1012: TAILQ_HEAD(dadq_head, dadq);
        !          1013: struct dadq {
        !          1014:        TAILQ_ENTRY(dadq) dad_list;
        !          1015:        struct ifaddr *dad_ifa;
        !          1016:        int dad_count;          /* max NS to send */
        !          1017:        int dad_ns_tcount;      /* # of trials to send NS */
        !          1018:        int dad_ns_ocount;      /* NS sent so far */
        !          1019:        int dad_ns_icount;
        !          1020:        int dad_na_icount;
        !          1021:        struct timeout dad_timer_ch;
        !          1022: };
        !          1023:
        !          1024: static struct dadq_head dadq;
        !          1025: static int dad_init = 0;
        !          1026:
        !          1027: static struct dadq *
        !          1028: nd6_dad_find(ifa)
        !          1029:        struct ifaddr *ifa;
        !          1030: {
        !          1031:        struct dadq *dp;
        !          1032:
        !          1033:        TAILQ_FOREACH(dp, &dadq, dad_list) {
        !          1034:                if (dp->dad_ifa == ifa)
        !          1035:                        return dp;
        !          1036:        }
        !          1037:        return NULL;
        !          1038: }
        !          1039:
        !          1040: static void
        !          1041: nd6_dad_starttimer(dp, ticks)
        !          1042:        struct dadq *dp;
        !          1043:        int ticks;
        !          1044: {
        !          1045:
        !          1046:        timeout_set(&dp->dad_timer_ch, (void (*)(void *))nd6_dad_timer,
        !          1047:            (void *)dp->dad_ifa);
        !          1048:        timeout_add(&dp->dad_timer_ch, ticks);
        !          1049: }
        !          1050:
        !          1051: static void
        !          1052: nd6_dad_stoptimer(dp)
        !          1053:        struct dadq *dp;
        !          1054: {
        !          1055:
        !          1056:        timeout_del(&dp->dad_timer_ch);
        !          1057: }
        !          1058:
        !          1059: /*
        !          1060:  * Start Duplicated Address Detection (DAD) for specified interface address.
        !          1061:  */
        !          1062: void
        !          1063: nd6_dad_start(ifa, tick)
        !          1064:        struct ifaddr *ifa;
        !          1065:        int *tick;      /* minimum delay ticks for IFF_UP event */
        !          1066: {
        !          1067:        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
        !          1068:        struct dadq *dp;
        !          1069:
        !          1070:        if (!dad_init) {
        !          1071:                TAILQ_INIT(&dadq);
        !          1072:                dad_init++;
        !          1073:        }
        !          1074:
        !          1075:        /*
        !          1076:         * If we don't need DAD, don't do it.
        !          1077:         * There are several cases:
        !          1078:         * - DAD is disabled (ip6_dad_count == 0)
        !          1079:         * - the interface address is anycast
        !          1080:         */
        !          1081:        if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
        !          1082:                log(LOG_DEBUG,
        !          1083:                        "nd6_dad_start: called with non-tentative address "
        !          1084:                        "%s(%s)\n",
        !          1085:                        ip6_sprintf(&ia->ia_addr.sin6_addr),
        !          1086:                        ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???");
        !          1087:                return;
        !          1088:        }
        !          1089:        if (ia->ia6_flags & IN6_IFF_ANYCAST) {
        !          1090:                ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
        !          1091:                return;
        !          1092:        }
        !          1093:        if (!ip6_dad_count) {
        !          1094:                ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
        !          1095:                return;
        !          1096:        }
        !          1097:        if (!ifa->ifa_ifp)
        !          1098:                panic("nd6_dad_start: ifa->ifa_ifp == NULL");
        !          1099:        if (!(ifa->ifa_ifp->if_flags & IFF_UP))
        !          1100:                return;
        !          1101:        if (nd6_dad_find(ifa) != NULL) {
        !          1102:                /* DAD already in progress */
        !          1103:                return;
        !          1104:        }
        !          1105:
        !          1106:        dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
        !          1107:        if (dp == NULL) {
        !          1108:                log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
        !          1109:                        "%s(%s)\n",
        !          1110:                        ip6_sprintf(&ia->ia_addr.sin6_addr),
        !          1111:                        ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???");
        !          1112:                return;
        !          1113:        }
        !          1114:        bzero(dp, sizeof(*dp));
        !          1115:        bzero(&dp->dad_timer_ch, sizeof(dp->dad_timer_ch));
        !          1116:        TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
        !          1117:
        !          1118:        nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", ifa->ifa_ifp->if_xname,
        !          1119:            ip6_sprintf(&ia->ia_addr.sin6_addr)));
        !          1120:
        !          1121:        /*
        !          1122:         * Send NS packet for DAD, ip6_dad_count times.
        !          1123:         * Note that we must delay the first transmission, if this is the
        !          1124:         * first packet to be sent from the interface after interface
        !          1125:         * (re)initialization.
        !          1126:         */
        !          1127:        dp->dad_ifa = ifa;
        !          1128:        ifa->ifa_refcnt++;      /* just for safety */
        !          1129:        dp->dad_count = ip6_dad_count;
        !          1130:        dp->dad_ns_icount = dp->dad_na_icount = 0;
        !          1131:        dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
        !          1132:        if (tick == NULL) {
        !          1133:                nd6_dad_ns_output(dp, ifa);
        !          1134:                nd6_dad_starttimer(dp,
        !          1135:                    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
        !          1136:        } else {
        !          1137:                int ntick;
        !          1138:
        !          1139:                if (*tick == 0)
        !          1140:                        ntick = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
        !          1141:                else
        !          1142:                        ntick = *tick + arc4random() % (hz / 2);
        !          1143:                *tick = ntick;
        !          1144:                nd6_dad_starttimer(dp, ntick);
        !          1145:        }
        !          1146: }
        !          1147:
        !          1148: /*
        !          1149:  * terminate DAD unconditionally.  used for address removals.
        !          1150:  */
        !          1151: void
        !          1152: nd6_dad_stop(ifa)
        !          1153:        struct ifaddr *ifa;
        !          1154: {
        !          1155:        struct dadq *dp;
        !          1156:
        !          1157:        if (!dad_init)
        !          1158:                return;
        !          1159:        dp = nd6_dad_find(ifa);
        !          1160:        if (!dp) {
        !          1161:                /* DAD wasn't started yet */
        !          1162:                return;
        !          1163:        }
        !          1164:
        !          1165:        nd6_dad_stoptimer(dp);
        !          1166:
        !          1167:        TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
        !          1168:        free(dp, M_IP6NDP);
        !          1169:        dp = NULL;
        !          1170:        IFAFREE(ifa);
        !          1171: }
        !          1172:
        !          1173: static void
        !          1174: nd6_dad_timer(ifa)
        !          1175:        struct ifaddr *ifa;
        !          1176: {
        !          1177:        int s;
        !          1178:        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
        !          1179:        struct dadq *dp;
        !          1180:
        !          1181:        s = splsoftnet();               /* XXX */
        !          1182:
        !          1183:        /* Sanity check */
        !          1184:        if (ia == NULL) {
        !          1185:                log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
        !          1186:                goto done;
        !          1187:        }
        !          1188:        dp = nd6_dad_find(ifa);
        !          1189:        if (dp == NULL) {
        !          1190:                log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
        !          1191:                goto done;
        !          1192:        }
        !          1193:        if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
        !          1194:                log(LOG_ERR, "nd6_dad_timer: called with duplicated address "
        !          1195:                        "%s(%s)\n",
        !          1196:                        ip6_sprintf(&ia->ia_addr.sin6_addr),
        !          1197:                        ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???");
        !          1198:                goto done;
        !          1199:        }
        !          1200:        if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
        !          1201:                log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
        !          1202:                        "%s(%s)\n",
        !          1203:                        ip6_sprintf(&ia->ia_addr.sin6_addr),
        !          1204:                        ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???");
        !          1205:                goto done;
        !          1206:        }
        !          1207:
        !          1208:        /* timeouted with IFF_{RUNNING,UP} check */
        !          1209:        if (dp->dad_ns_tcount > dad_maxtry) {
        !          1210:                nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
        !          1211:                        ifa->ifa_ifp->if_xname));
        !          1212:
        !          1213:                TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
        !          1214:                free(dp, M_IP6NDP);
        !          1215:                dp = NULL;
        !          1216:                IFAFREE(ifa);
        !          1217:                goto done;
        !          1218:        }
        !          1219:
        !          1220:        /* Need more checks? */
        !          1221:        if (dp->dad_ns_ocount < dp->dad_count) {
        !          1222:                /*
        !          1223:                 * We have more NS to go.  Send NS packet for DAD.
        !          1224:                 */
        !          1225:                nd6_dad_ns_output(dp, ifa);
        !          1226:                nd6_dad_starttimer(dp,
        !          1227:                    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
        !          1228:        } else {
        !          1229:                /*
        !          1230:                 * We have transmitted sufficient number of DAD packets.
        !          1231:                 * See what we've got.
        !          1232:                 */
        !          1233:                int duplicate;
        !          1234:
        !          1235:                duplicate = 0;
        !          1236:
        !          1237:                if (dp->dad_na_icount) {
        !          1238:                        /*
        !          1239:                         * the check is in nd6_dad_na_input(),
        !          1240:                         * but just in case
        !          1241:                         */
        !          1242:                        duplicate++;
        !          1243:                }
        !          1244:
        !          1245:                if (dp->dad_ns_icount) {
        !          1246:                        /* We've seen NS, means DAD has failed. */
        !          1247:                        duplicate++;
        !          1248:                }
        !          1249:
        !          1250:                if (duplicate) {
        !          1251:                        /* (*dp) will be freed in nd6_dad_duplicated() */
        !          1252:                        dp = NULL;
        !          1253:                        nd6_dad_duplicated(ifa);
        !          1254:                } else {
        !          1255:                        /*
        !          1256:                         * We are done with DAD.  No NA came, no NS came.
        !          1257:                         * duplicated address found.
        !          1258:                         */
        !          1259:                        ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
        !          1260:
        !          1261:                        nd6log((LOG_DEBUG,
        !          1262:                            "%s: DAD complete for %s - no duplicates found\n",
        !          1263:                            ifa->ifa_ifp->if_xname,
        !          1264:                            ip6_sprintf(&ia->ia_addr.sin6_addr)));
        !          1265:
        !          1266:                        TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
        !          1267:                        free(dp, M_IP6NDP);
        !          1268:                        dp = NULL;
        !          1269:                        IFAFREE(ifa);
        !          1270:                }
        !          1271:        }
        !          1272:
        !          1273: done:
        !          1274:        splx(s);
        !          1275: }
        !          1276:
        !          1277: void
        !          1278: nd6_dad_duplicated(ifa)
        !          1279:        struct ifaddr *ifa;
        !          1280: {
        !          1281:        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
        !          1282:        struct dadq *dp;
        !          1283:
        !          1284:        dp = nd6_dad_find(ifa);
        !          1285:        if (dp == NULL) {
        !          1286:                log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
        !          1287:                return;
        !          1288:        }
        !          1289:
        !          1290:        log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
        !          1291:            "NS in/out=%d/%d, NA in=%d\n",
        !          1292:            ifa->ifa_ifp->if_xname, ip6_sprintf(&ia->ia_addr.sin6_addr),
        !          1293:            dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
        !          1294:
        !          1295:        ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
        !          1296:        ia->ia6_flags |= IN6_IFF_DUPLICATED;
        !          1297:
        !          1298:        /* We are done with DAD, with duplicated address found. (failure) */
        !          1299:        nd6_dad_stoptimer(dp);
        !          1300:
        !          1301:        log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
        !          1302:            ifa->ifa_ifp->if_xname, ip6_sprintf(&ia->ia_addr.sin6_addr));
        !          1303:        log(LOG_ERR, "%s: manual intervention required\n",
        !          1304:            ifa->ifa_ifp->if_xname);
        !          1305:
        !          1306:        TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
        !          1307:        free(dp, M_IP6NDP);
        !          1308:        dp = NULL;
        !          1309:        IFAFREE(ifa);
        !          1310: }
        !          1311:
        !          1312: static void
        !          1313: nd6_dad_ns_output(dp, ifa)
        !          1314:        struct dadq *dp;
        !          1315:        struct ifaddr *ifa;
        !          1316: {
        !          1317:        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
        !          1318:        struct ifnet *ifp = ifa->ifa_ifp;
        !          1319:
        !          1320:        dp->dad_ns_tcount++;
        !          1321:        if ((ifp->if_flags & IFF_UP) == 0) {
        !          1322: #if 0
        !          1323:                printf("%s: interface down?\n", ifp->if_xname);
        !          1324: #endif
        !          1325:                return;
        !          1326:        }
        !          1327:        if ((ifp->if_flags & IFF_RUNNING) == 0) {
        !          1328: #if 0
        !          1329:                printf("%s: interface not running?\n", ifp->if_xname);
        !          1330: #endif
        !          1331:                return;
        !          1332:        }
        !          1333:
        !          1334:        dp->dad_ns_ocount++;
        !          1335:        nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
        !          1336: }
        !          1337:
        !          1338: static void
        !          1339: nd6_dad_ns_input(ifa)
        !          1340:        struct ifaddr *ifa;
        !          1341: {
        !          1342:        struct in6_ifaddr *ia;
        !          1343:        struct ifnet *ifp;
        !          1344:        struct in6_addr *taddr6;
        !          1345:        struct dadq *dp;
        !          1346:        int duplicate;
        !          1347:
        !          1348:        if (!ifa)
        !          1349:                panic("ifa == NULL in nd6_dad_ns_input");
        !          1350:
        !          1351:        ia = (struct in6_ifaddr *)ifa;
        !          1352:        ifp = ifa->ifa_ifp;
        !          1353:        taddr6 = &ia->ia_addr.sin6_addr;
        !          1354:        duplicate = 0;
        !          1355:        dp = nd6_dad_find(ifa);
        !          1356:
        !          1357:        /* Quickhack - completely ignore DAD NS packets */
        !          1358:        if (dad_ignore_ns) {
        !          1359:                nd6log((LOG_INFO,
        !          1360:                    "nd6_dad_ns_input: ignoring DAD NS packet for "
        !          1361:                    "address %s(%s)\n", ip6_sprintf(taddr6),
        !          1362:                    ifa->ifa_ifp->if_xname));
        !          1363:                return;
        !          1364:        }
        !          1365:
        !          1366:        /*
        !          1367:         * if I'm yet to start DAD, someone else started using this address
        !          1368:         * first.  I have a duplicate and you win.
        !          1369:         */
        !          1370:        if (!dp || dp->dad_ns_ocount == 0)
        !          1371:                duplicate++;
        !          1372:
        !          1373:        /* XXX more checks for loopback situation - see nd6_dad_timer too */
        !          1374:
        !          1375:        if (duplicate) {
        !          1376:                dp = NULL;      /* will be freed in nd6_dad_duplicated() */
        !          1377:                nd6_dad_duplicated(ifa);
        !          1378:        } else {
        !          1379:                /*
        !          1380:                 * not sure if I got a duplicate.
        !          1381:                 * increment ns count and see what happens.
        !          1382:                 */
        !          1383:                if (dp)
        !          1384:                        dp->dad_ns_icount++;
        !          1385:        }
        !          1386: }
        !          1387:
        !          1388: static void
        !          1389: nd6_dad_na_input(ifa)
        !          1390:        struct ifaddr *ifa;
        !          1391: {
        !          1392:        struct dadq *dp;
        !          1393:
        !          1394:        if (!ifa)
        !          1395:                panic("ifa == NULL in nd6_dad_na_input");
        !          1396:
        !          1397:        dp = nd6_dad_find(ifa);
        !          1398:        if (dp)
        !          1399:                dp->dad_na_icount++;
        !          1400:
        !          1401:        /* remove the address. */
        !          1402:        nd6_dad_duplicated(ifa);
        !          1403: }

CVSweb