nd6_nbr.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,526 行 · 第 1/3 页
C
1,526 行
nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; nd_opt->nd_opt_len = optlen >> 3; bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen); } else flags &= ~ND_NA_FLAG_OVERRIDE; ip6->ip6_plen = htons((u_short)icmp6len); nd_na->nd_na_flags_reserved = flags; nd_na->nd_na_cksum = 0; nd_na->nd_na_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);#ifdef IPSEC /* Don't lookup socket */ (void)ipsec_setsocket(m, NULL);#endif ip6_output(m, NULL, NULL, 0, &im6o, NULL); icmp6_ifstat_inc(ifp, ifs6_out_msg); icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;}caddr_tnd6_ifptomac(ifp) struct ifnet *ifp;{ switch (ifp->if_type) { case IFT_ARCNET: case IFT_ETHER: case IFT_FDDI: case IFT_IEEE1394:#ifdef IFT_PROPVIRTUAL case IFT_PROPVIRTUAL:#endif#ifdef IFT_L2VLAN case IFT_L2VLAN:#endif#ifdef IFT_IEEE80211 case IFT_IEEE80211:#endif#ifdef __NetBSD__ return LLADDR(ifp->if_sadl);#else return ((caddr_t)(ifp + 1));#endif break; default: return NULL; }}TAILQ_HEAD(dadq_head, dadq);struct dadq { TAILQ_ENTRY(dadq) dad_list; struct ifaddr *dad_ifa; int dad_count; /* max NS to send */ int dad_ns_tcount; /* # of trials to send NS */ int dad_ns_ocount; /* NS sent so far */ int dad_ns_icount; int dad_na_icount;#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) struct callout dad_timer_ch;#elif defined(__OpenBSD__) struct timeout dad_timer_ch;#endif};static struct dadq_head dadq;static int dad_init = 0;static struct dadq *nd6_dad_find(ifa) struct ifaddr *ifa;{ struct dadq *dp; for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) { if (dp->dad_ifa == ifa) return dp; } return NULL;}static voidnd6_dad_starttimer(dp, _ticks) struct dadq *dp; int _ticks;{#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) callout_reset(&dp->dad_timer_ch, _ticks, (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);#elif defined(__OpenBSD__) timeout_set(&dp->dad_timer_ch, (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa); timeout_add(&dp->dad_timer_ch, _ticks);#else timeout((void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa, _ticks);#endif}static voidnd6_dad_stoptimer(dp) struct dadq *dp;{#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) callout_stop(&dp->dad_timer_ch);#elif defined(__OpenBSD__) timeout_del(&dp->dad_timer_ch);#else untimeout((void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);#endif}/* * Start Duplicated Address Detection (DAD) for specified interface address. */voidnd6_dad_start(ifa, tick) struct ifaddr *ifa; int *tick; /* minimum delay ticks for IFF_UP event */{ struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; struct dadq *dp; int ntick; if (!dad_init) { TAILQ_INIT(&dadq); dad_init++; } /* * If we don't need DAD, don't do it. * There are several cases: * - DAD is disabled (ip6_dad_count == 0) * - the interface address is anycast */ if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) { log(LOG_DEBUG, "nd6_dad_start: called with non-tentative address " "%s(%s)\n", ip6_sprintf(&ia->ia_addr.sin6_addr), ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); return; } if (ia->ia6_flags & IN6_IFF_ANYCAST) { ia->ia6_flags &= ~IN6_IFF_TENTATIVE; return; } if (!ip6_dad_count) { ia->ia6_flags &= ~IN6_IFF_TENTATIVE; return; } if (!ifa->ifa_ifp) panic("nd6_dad_start: ifa->ifa_ifp == NULL"); if (!(ifa->ifa_ifp->if_flags & IFF_UP)) return; if (nd6_dad_find(ifa) != NULL) { /* DAD already in progress */ return; } dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT); if (dp == NULL) { log(LOG_ERR, "nd6_dad_start: memory allocation failed for " "%s(%s)\n", ip6_sprintf(&ia->ia_addr.sin6_addr), ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); return; } bzero(dp, sizeof(*dp));#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) callout_init(&dp->dad_timer_ch);#elif defined(__OpenBSD__) bzero(&dp->dad_timer_ch, sizeof(dp->dad_timer_ch));#endif TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list); nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr))); /* * Send NS packet for DAD, ip6_dad_count times. * Note that we must delay the first transmission, if this is the * first packet to be sent from the interface after interface * (re)initialization. */ dp->dad_ifa = ifa; IFAREF(ifa); /* just for safety */ dp->dad_count = ip6_dad_count; dp->dad_ns_icount = dp->dad_na_icount = 0; dp->dad_ns_ocount = dp->dad_ns_tcount = 0; if (tick == NULL) { nd6_dad_ns_output(dp, ifa); ntick = nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000; } else {#ifdef __OpenBSD__#define random arc4random#endif if (*tick == 0) ntick = random() % (MAX_RTR_SOLICITATION_DELAY * hz); else ntick = *tick + random() % (hz / 2);#ifdef __OpenBSD__#undef random#endif *tick = ntick; } if (ntick <= 0) ntick = 1; // Defensive nd6_dad_starttimer(dp, ntick);}/* * terminate DAD unconditionally. used for address removals. */voidnd6_dad_stop(ifa) struct ifaddr *ifa;{ struct dadq *dp; if (!dad_init) return; dp = nd6_dad_find(ifa); if (!dp) { /* DAD wasn't started yet */ return; } nd6_dad_stoptimer(dp); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); free(dp, M_IP6NDP); dp = NULL; IFAFREE(ifa);}static voidnd6_dad_timer(ifa) struct ifaddr *ifa;{ int s; struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; struct dadq *dp;#ifdef __NetBSD__ s = splsoftnet(); /* XXX */#else s = splnet(); /* XXX */#endif /* Sanity check */ if (ia == NULL) { log(LOG_ERR, "nd6_dad_timer: called with null parameter\n"); goto done; } dp = nd6_dad_find(ifa); if (dp == NULL) { log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n"); goto done; } if (ia->ia6_flags & IN6_IFF_DUPLICATED) { log(LOG_ERR, "nd6_dad_timer: called with duplicated address " "%s(%s)\n", ip6_sprintf(&ia->ia_addr.sin6_addr), ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); goto done; } if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) { log(LOG_ERR, "nd6_dad_timer: called with non-tentative address " "%s(%s)\n", ip6_sprintf(&ia->ia_addr.sin6_addr), ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); goto done; } /* timeouted with IFF_{RUNNING,UP} check */ if (dp->dad_ns_tcount > dad_maxtry) { nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n", if_name(ifa->ifa_ifp))); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); free(dp, M_IP6NDP); dp = NULL; IFAFREE(ifa); goto done; } /* Need more checks? */ if (dp->dad_ns_ocount < dp->dad_count) { /* * We have more NS to go. Send NS packet for DAD. */ nd6_dad_ns_output(dp, ifa); nd6_dad_starttimer(dp, nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000); } else { /* * We have transmitted sufficient number of DAD packets. * See what we've got. */ int duplicate; duplicate = 0; if (dp->dad_na_icount) { /* * the check is in nd6_dad_na_input(), * but just in case */ duplicate++; } if (dp->dad_ns_icount) {#if 0 /* heuristics */ /* * if * - we have sent many(?) DAD NS, and * - the number of NS we sent equals to the * number of NS we've got, and * - we've got no NA * we may have a faulty network card/driver which * loops back multicasts to myself. */ if (3 < dp->dad_count && dp->dad_ns_icount == dp->dad_count && dp->dad_na_icount == 0) { log(LOG_INFO, "DAD questionable for %s(%s): " "network card loops back multicast?\n", ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifa->ifa_ifp)); /* XXX consider it a duplicate or not? */ /* duplicate++; */ } else { /* We've seen NS, means DAD has failed. */ duplicate++; }#else /* We've seen NS, means DAD has failed. */ duplicate++;#endif } if (duplicate) { /* (*dp) will be freed in nd6_dad_duplicated() */ dp = NULL; nd6_dad_duplicated(ifa); } else { /* * We are done with DAD. No NA came, no NS came. * duplicated address found. */ ia->ia6_flags &= ~IN6_IFF_TENTATIVE; nd6log((LOG_DEBUG, "%s: DAD complete for %s - no duplicates found\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr))); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); free(dp, M_IP6NDP); dp = NULL;#ifdef MIP6 if (mip6_dad_success(ifa) == ENOENT)#endif IFAFREE(ifa); } }done: splx(s);}voidnd6_dad_duplicated(ifa) struct ifaddr *ifa;{ struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; struct dadq *dp; dp = nd6_dad_find(ifa); if (dp == NULL) { log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n"); return; } log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: " "NS in/out=%d/%d, NA in=%d\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr), dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount); ia->ia6_flags &= ~IN6_IFF_TENTATIVE; ia->ia6_flags |= IN6_IFF_DUPLICATED; /* We are done with DAD, with duplicated address found. (failure) */ nd6_dad_stoptimer(dp); log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr)); log(LOG_ERR, "%s: manual intervention required\n", if_name(ifa->ifa_ifp)); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); free(dp, M_IP6NDP); dp = NULL;#ifdef MIP6 if (mip6_dad_duplicated(ifa) == ENOENT)#endif IFAFREE(ifa);}static voidnd6_dad_ns_output(dp, ifa) struct dadq *dp; struct ifaddr *ifa;{ struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; struct ifnet *ifp = ifa->ifa_ifp; dp->dad_ns_tcount++; if ((ifp->if_flags & IFF_UP) == 0) {#if 0 printf("%s: interface down?\n", if_name(ifp));#endif return; } if ((ifp->if_flags & IFF_RUNNING) == 0) {#if 0 printf("%s: interface not running?\n", if_name(ifp));#endif return; } dp->dad_ns_ocount++; nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);}static voidnd6_dad_ns_input(ifa) struct ifaddr *ifa;{ struct in6_ifaddr *ia; struct ifnet *ifp; const struct in6_addr *taddr6; struct dadq *dp; int duplicate; if (!ifa) panic("ifa == NULL in nd6_dad_ns_input"); ia = (struct in6_ifaddr *)ifa; ifp = ifa->ifa_ifp; taddr6 = &ia->ia_addr.sin6_addr; duplicate = 0; dp = nd6_dad_find(ifa); /* Quickhack - completely ignore DAD NS packets */ if (dad_ignore_ns) { nd6log((LOG_INFO, "nd6_dad_ns_input: ignoring DAD NS packet for " "address %s(%s)\n", ip6_sprintf(taddr6), if_name(ifa->ifa_ifp))); return; } /* * if I'm yet to start DAD, someone else started using this address * first. I have a duplicate and you win. */ if (!dp || dp->dad_ns_ocount == 0) duplicate++; /* XXX more checks for loopback situation - see nd6_dad_timer too */ if (duplicate) { dp = NULL; /* will be freed in nd6_dad_duplicated() */ nd6_dad_duplicated(ifa); } else { /* * not sure if I got a duplicate. * increment ns count and see what happens. */ if (dp) dp->dad_ns_icount++; }}static voidnd6_dad_na_input(ifa) struct ifaddr *ifa;{ struct dadq *dp; if (!ifa) panic("ifa == NULL in nd6_dad_na_input"); dp = nd6_dad_find(ifa); if (dp) dp->dad_na_icount++; /* remove the address. */ nd6_dad_duplicated(ifa);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?