📄 in6.c
字号:
} else {
log(LOG_WARNING, "in6_update_ifa: "
"addmulti failed for %s on %s "
"(errno=%d)\n",
ip6_sprintf(&mltaddr.sin6_addr),
if_name(ifp), error);
goto cleanup;
}
}
#ifdef MEASURE_PERFORMANCE
{
int s = splnet();
if (new_ifa)
in6h_addifa(ia);
else
in6h_rebuild(0);
splx(s);
}
#endif
/*
* make sure to initialize ND6 information. this is to workaround
* issues with interfaces with IPv6 addresses, which have never brought
* up. We are assuming that it is safe to nd6_ifattach multiple times.
*/
nd6_ifattach(ifp);
/*
* Perform DAD, if needed.
* XXX It may be of use, if we can administratively
* disable DAD.
*/
#ifdef MIP6
if (hostIsNew && in6if_do_dad(ifp) && mip6_ifa_need_dad(ia) &&
(ifra->ifra_flags & IN6_IFF_NODAD) == 0)
#else /* MIP6 */
if (hostIsNew && in6if_do_dad(ifp) &&
(ifra->ifra_flags & IN6_IFF_NODAD) == 0)
#endif /* MIP6 */
{
nd6_dad_start((struct ifaddr *)ia, NULL);
}
return(error);
unlink:
/*
* XXX: if a change of an existing address failed, keep the entry
* anyway.
*/
if (hostIsNew)
in6_unlink_ifa(ia, ifp);
return(error);
cleanup:
in6_purgeaddr(&ia->ia_ifa);
return error;
}
void
in6_purgeaddr(ifa)
struct ifaddr *ifa;
{
struct ifnet *ifp = ifa->ifa_ifp;
struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
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);
}
int
in6_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 void
in6_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);
}
void
in6_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;
#else
in6_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -