📄 in6.c
字号:
struct in6_multi_mship *imm; /* stop DAD processing */ nd6_dad_stop(ifa); /* * delete route to the destination of the address being purged. * The interface must be p2p or loopback in this case. */ if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) { int e; if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { log(LOG_ERR, "in6_purgeaddr: failed to remove " "a route to the p2p destination: %s on %s, " "errno=%d\n", ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifp), e); /* proceed anyway... */ } else ia->ia_flags &= ~IFA_ROUTE; } /* Remove ownaddr's loopback rtentry, if it exists. */ in6_ifremloop(&(ia->ia_ifa)); /* * leave from multicast groups we have joined for the interface */ while ((imm = ia->ia6_memberships.lh_first) != NULL) { LIST_REMOVE(imm, i6mm_chain); in6_leavegroup(imm); } in6_unlink_ifa(ia, ifp);}intin6_update_ifa(ifp, ifra, ia) struct ifnet *ifp; struct in6_aliasreq *ifra; struct in6_ifaddr *ia;{ int res; int s = splnet();// extern int irq_level;// if (irq_level) {// diag_printf("%s - called from IRQ!\n", __FUNCTION__);// } res = _in6_update_ifa(ifp, ifra, ia); splx(s); return res;}static voidin6_unlink_ifa(ia, ifp) struct in6_ifaddr *ia; struct ifnet *ifp;{ struct in6_ifaddr *oia;#ifdef __NetBSD__ int s = splsoftnet();#else int s = splnet();#endif#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) struct ifaddr *ifa;#endif#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) if ((ifa = ifp->if_addrlist) == ia62ifa(ia)) ifp->if_addrlist = ifa->ifa_next; else { while (ifa->ifa_next && (ifa->ifa_next != ia62ifa(ia))) ifa = ifa->ifa_next; if (ifa->ifa_next) ifa->ifa_next = ia62ifa(ia)->ifa_next; else { /* search failed */ printf("Couldn't unlink in6_ifaddr from ifp\n"); } }#else TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); log_(LOG_ADDR) { diag_printf("%s.%d - After removing %p into list %p\n", __FUNCTION__, __LINE__, &ia->ia_ifa, &ifp->if_addrlist); _show_ifp(ifp); }#endif#ifdef __NetBSD__ /* release a refcnt for the link from if_addrlist */ IFAFREE(&ia->ia_ifa);#endif oia = ia; if (oia == (ia = in6_ifaddr)) in6_ifaddr = ia->ia_next; else { while (ia->ia_next && (ia->ia_next != oia)) ia = ia->ia_next; if (ia->ia_next) ia->ia_next = oia->ia_next; else { /* search failed */ printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n"); } }#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) if (oia->ia6_multiaddrs.lh_first != NULL) {#ifdef __NetBSD__ /* * XXX thorpej@netbsd.org -- if the interface is going * XXX away, don't save the multicast entries, delete them! */ if (oia->ia_ifa.ifa_ifp->if_output == if_nulloutput) { struct in6_multi *in6m; while ((in6m = LIST_FIRST(&oia->ia6_multiaddrs)) != NULL) in6_delmulti(in6m); } else in6_savemkludge(oia);#else in6_savemkludge(oia);#endif }#endif#ifdef MEASURE_PERFORMANCE in6h_delifa(oia);#endif /* * When an autoconfigured address is being removed, release the * reference to the base prefix. Also, since the release might * affect the status of other (detached) addresses, call * pfxlist_onlink_check(). */ if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { if (oia->ia6_ndpr == NULL) { log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address " "%p has no prefix\n", oia); } else { oia->ia6_ndpr->ndpr_refcnt--; oia->ia6_flags &= ~IN6_IFF_AUTOCONF; oia->ia6_ndpr = NULL; } pfxlist_onlink_check(); } /* * release another refcnt for the link from in6_ifaddr. * Note that we should decrement the refcnt at least once for all *BSD. */ IFAFREE(&oia->ia_ifa); splx(s);}voidin6_purgeif(ifp) struct ifnet *ifp;{ struct ifaddr *ifa, *nifa;#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (ifa = ifp->if_addrlist; ifa; ifa = nifa)#else for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa)#endif {#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) nifa = ifa->ifa_next;#else nifa = TAILQ_NEXT(ifa, ifa_list);#endif if (ifa->ifa_addr->sa_family != AF_INET6) continue; in6_purgeaddr(ifa); }#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) in6_ifdetach(ifp);#endif}/* * SIOC[GAD]LIFADDR. * SIOCGLIFADDR: get first address. (?) * SIOCGLIFADDR with IFLR_PREFIX: * get first address that matches the specified prefix. * SIOCALIFADDR: add the specified address. * SIOCALIFADDR with IFLR_PREFIX: * add the specified prefix, filling hostid part from * the first link-local address. prefixlen must be <= 64. * SIOCDLIFADDR: delete the specified address. * SIOCDLIFADDR with IFLR_PREFIX: * delete the first address that matches the specified prefix. * return values: * EINVAL on invalid parameters * EADDRNOTAVAIL on prefix match failed/specified address not found * other values may be returned from in6_ioctl() * * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. * this is to accomodate address naming scheme other than RFC2374, * in the future. * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 * address encoding scheme. (see figure on page 8) */static int#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)in6_lifaddr_ioctl(so, cmd, data, ifp, p) struct socket *so; u_long cmd; caddr_t data; struct ifnet *ifp; struct proc *p;#elsein6_lifaddr_ioctl(so, cmd, data, ifp) struct socket *so; u_long cmd; caddr_t data; struct ifnet *ifp;#endif{ struct if_laddrreq *iflr = (struct if_laddrreq *)data; struct ifaddr *ifa; struct sockaddr *sa; int64_t zoneid; /* sanity checks */ if (!data || !ifp) { panic("invalid argument to in6_lifaddr_ioctl"); /* NOTREACHED */ } switch (cmd) { case SIOCGLIFADDR: /* address must be specified on GET with IFLR_PREFIX */ if ((iflr->flags & IFLR_PREFIX) == 0) break; /* FALLTHROUGH */ case SIOCALIFADDR: case SIOCDLIFADDR: /* address must be specified on ADD and DELETE */ sa = (struct sockaddr *)&iflr->addr; if (sa->sa_family != AF_INET6) return EINVAL; if (sa->sa_len != sizeof(struct sockaddr_in6)) return EINVAL; /* XXX need improvement */ sa = (struct sockaddr *)&iflr->dstaddr; if (sa->sa_family && sa->sa_family != AF_INET6) return EINVAL; if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) return EINVAL; break; default: /* shouldn't happen */#if 0 panic("invalid cmd to in6_lifaddr_ioctl"); /* NOTREACHED */#else return EOPNOTSUPP;#endif } if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) return EINVAL; switch (cmd) { case SIOCALIFADDR: { struct in6_aliasreq ifra; struct in6_addr *hostid = NULL; int prefixlen; if ((iflr->flags & IFLR_PREFIX) != 0) { struct sockaddr_in6 *sin6; /* * hostid is to fill in the hostid part of the * address. hostid points to the first link-local * address attached to the interface. */ ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); if (!ifa) return EADDRNOTAVAIL; hostid = IFA_IN6(ifa); /* prefixlen must be <= 64. */ if (64 < iflr->prefixlen) return EINVAL; prefixlen = iflr->prefixlen; /* hostid part must be zero. */ sin6 = (struct sockaddr_in6 *)&iflr->addr; if (sin6->sin6_addr.s6_addr32[2] != 0 || sin6->sin6_addr.s6_addr32[3] != 0) { return EINVAL; } } else prefixlen = iflr->prefixlen; /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ bzero(&ifra, sizeof(ifra)); bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); bcopy(&iflr->addr, &ifra.ifra_addr, ((struct sockaddr *)&iflr->addr)->sa_len); if (hostid) { /* fill in hostid part */ ifra.ifra_addr.sin6_addr.s6_addr32[2] = hostid->s6_addr32[2]; ifra.ifra_addr.sin6_addr.s6_addr32[3] = hostid->s6_addr32[3]; } if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, ((struct sockaddr *)&iflr->dstaddr)->sa_len); if (hostid) { ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = hostid->s6_addr32[2]; ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = hostid->s6_addr32[3]; } } ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p);#else return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp);#endif } case SIOCGLIFADDR: case SIOCDLIFADDR: { struct in6_ifaddr *ia; struct in6_addr mask, candidate, match; struct sockaddr_in6 *sin6; int cmp; bzero(&mask, sizeof(mask)); if (iflr->flags & IFLR_PREFIX) { /* lookup a prefix rather than address. */ in6_prefixlen2mask(&mask, iflr->prefixlen); sin6 = (struct sockaddr_in6 *)&iflr->addr; bcopy(&sin6->sin6_addr, &match, sizeof(match)); match.s6_addr32[0] &= mask.s6_addr32[0]; match.s6_addr32[1] &= mask.s6_addr32[1]; match.s6_addr32[2] &= mask.s6_addr32[2]; match.s6_addr32[3] &= mask.s6_addr32[3]; /* if you set extra bits, that's wrong */ if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) return EINVAL; cmp = 1; } else { if (cmd == SIOCGLIFADDR) { /* on getting an address, take the 1st match */ cmp = 0; /* XXX */ } else { /* on deleting an address, do exact match */ in6_prefixlen2mask(&mask, 128); sin6 = (struct sockaddr_in6 *)&iflr->addr; bcopy(&sin6->sin6_addr, &match, sizeof(match)); cmp = 1; } }#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)#elif defined(__FreeBSD__) && __FreeBSD__ >= 4 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)#else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)#endif { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (!cmp) break; bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));#ifndef SCOPEDROUTING /* * XXX: this is adhoc, but is necessary to allow * a user to specify fe80::/64 (not /10) for a * link-local address. */ if (IN6_IS_ADDR_LINKLOCAL(&candidate)) candidate.s6_addr16[1] = 0;#endif candidate.s6_addr32[0] &= mask.s6_addr32[0]; candidate.s6_addr32[1] &= mask.s6_addr32[1]; candidate.s6_addr32[2] &= mask.s6_addr32[2]; candidate.s6_addr32[3] &= mask.s6_addr32[3]; if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) break; } if (!ifa) return EADDRNOTAVAIL; ia = ifa2ia6(ifa); if (cmd == SIOCGLIFADDR) {#ifndef SCOPEDROUTING struct sockaddr_in6 *s6;#endif /* fill in the if_laddrreq structure */ bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);#ifndef SCOPEDROUTING /* XXX see above */ s6 = (struct sockaddr_in6 *)&iflr->addr; if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { s6->sin6_addr.s6_addr16[1] = 0; zoneid = in6_addr2zoneid(ifp, &s6->sin6_addr); if (zoneid < 0) /* XXX: should not happen */ return(EINVAL); s6->sin6_scope_id = zoneid; }#endif if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { bcopy(&ia->ia_dstaddr, &iflr->dstaddr, ia->ia_dstaddr.sin6_len);#ifndef SCOPEDROUTING /* XXX see above */ s6 = (struct sockaddr_in6 *)&iflr->dstaddr; if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { s6->sin6_addr.s6_addr16[1] = 0; zoneid = in6_addr2zoneid(ifp, &s6->sin6_addr); if (zoneid < 0) /* XXX */ return(EINVAL); s6->sin6_scope_id = zoneid; }#endif } else bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); iflr->prefixlen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); iflr->flags = ia->ia6_flags; /* XXX */ return 0; } else { struct in6_aliasreq ifra; /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ bzero(&ifra, sizeof(ifra)); bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); bcopy(&ia->ia_addr, &ifra.ifra_addr, ia->ia_addr.sin6_len); if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, ia->ia_dstaddr.sin6_len); } else { bzero(&ifra.ifra_dstaddr, sizeof(ifra.ifra_dstaddr)); } bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, ia->ia_prefixmask.sin6_len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -