Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/in6.c
Show First 20 Lines • Show All 230 Lines • ▼ Show 20 Lines | if (p < lim) { | ||||
for (p = p + 1; p < lim; p++) | for (p = p + 1; p < lim; p++) | ||||
if (*p != 0) | if (*p != 0) | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return x * 8 + y; | return x * 8 + y; | ||||
} | } | ||||
int | |||||
in6_prefix_rtrequest(int cmd, struct in6_ifaddr *ia) | |||||
{ | |||||
struct ifnet *ifp = ia->ia_ifp; | |||||
uint32_t fibnum = ifp->if_fib; | |||||
struct epoch_tracker et; | |||||
int error; | |||||
struct sockaddr_in6 dst6 = { | |||||
.sin6_family = AF_INET6, | |||||
.sin6_len = sizeof(struct sockaddr_in6), | |||||
.sin6_addr = ia->ia_addr.sin6_addr, | |||||
}; | |||||
struct sockaddr_in6 netmask6 = { | |||||
.sin6_family = AF_INET6, | |||||
.sin6_len = sizeof(struct sockaddr_in6), | |||||
.sin6_addr = ia->ia_prefixmask.sin6_addr, | |||||
}; | |||||
struct sockaddr_dl_short sdl = { | |||||
.sdl_family = AF_LINK, | |||||
.sdl_len = sizeof(struct sockaddr_dl_short), | |||||
.sdl_type = ifp->if_type, | |||||
.sdl_index = ifp->if_index, | |||||
}; | |||||
struct rt_addrinfo info = { | |||||
.rti_ifa = &ia->ia_ifa, | |||||
.rti_ifp = ifp, | |||||
.rti_flags = RTF_PINNED, | |||||
.rti_info = { | |||||
[RTAX_DST] = (struct sockaddr *)&dst6, | |||||
[RTAX_GATEWAY] = (struct sockaddr *)&sdl, | |||||
}, | |||||
}; | |||||
if (ia->ia_dstaddr.sin6_len != 0) | |||||
dst6.sin6_addr = ia->ia_dstaddr.sin6_addr; | |||||
else | |||||
dst6.sin6_addr = ia->ia_addr.sin6_addr; | |||||
IN6_MASK_ADDR(&dst6.sin6_addr, &netmask6.sin6_addr); | |||||
if (in6_mask2len(&netmask6.sin6_addr, NULL) == 128) { | |||||
if (ia->ia_dstaddr.sin6_family != AF_INET6) | |||||
/* We don't need to install a host route */ | |||||
return 0; | |||||
info.rti_flags |= RTF_HOST; | |||||
} else | |||||
info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&netmask6; | |||||
NET_EPOCH_ENTER(et); | |||||
error = rib_handle_ifaddr_info(fibnum, cmd, &info); | |||||
NET_EPOCH_EXIT(et); | |||||
return error; | |||||
} | |||||
/* Delete network prefix route if present. | |||||
* Re-add it to another address if the prefix matches. */ | |||||
static int | |||||
in6_ifremprefix(struct in6_ifaddr *target) | |||||
{ | |||||
struct rm_priotracker in6_ifa_tracker; | |||||
struct in6_ifaddr *ia; | |||||
int error = 0; | |||||
if ((target->ia_flags & IFA_ROUTE) == 0) | |||||
return 0; | |||||
IN6_IFADDR_RLOCK(&in6_ifa_tracker); | |||||
CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { | |||||
if (target->ia_dstaddr.sin6_len) { | |||||
if (ia->ia_dstaddr.sin6_len == 0 || | |||||
!IN6_ARE_ADDR_EQUAL(&ia->ia_dstaddr.sin6_addr, | |||||
&target->ia_dstaddr.sin6_addr)) | |||||
continue; | |||||
} else { | |||||
if (!IN6_ARE_MASKED_ADDR_EQUAL(&ia->ia_addr.sin6_addr, | |||||
&target->ia_addr.sin6_addr, | |||||
&target->ia_prefixmask.sin6_addr)) | |||||
continue; | |||||
} | |||||
/* If we got a matching prefix route, move IFA_ROUTE to it. */ | |||||
if ((ia->ia_flags & IFA_ROUTE) == 0) { | |||||
in6_prefix_rtrequest(RTM_DELETE, target); | |||||
target->ia_flags &= ~IFA_ROUTE; | |||||
nd6_rem_ifa_lle(target, 1); | |||||
error = in6_prefix_rtrequest(RTM_ADD, ia); | |||||
if (error == 0) | |||||
ia->ia_flags |= IFA_ROUTE; | |||||
return error; | |||||
} | |||||
} | |||||
IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); | |||||
/* No-one has the prefix, so remove it. */ | |||||
in6_prefix_rtrequest(RTM_DELETE, target); | |||||
target->ia_flags &= ~IFA_ROUTE; | |||||
nd6_rem_ifa_lle(target, 1); | |||||
return error; | |||||
} | |||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
struct in6_ndifreq32 { | struct in6_ndifreq32 { | ||||
char ifname[IFNAMSIZ]; | char ifname[IFNAMSIZ]; | ||||
uint32_t ifindex; | uint32_t ifindex; | ||||
}; | }; | ||||
#define SIOCGDEFIFACE32_IN6 _IOWR('i', 86, struct in6_ndifreq32) | #define SIOCGDEFIFACE32_IN6 _IOWR('i', 86, struct in6_ndifreq32) | ||||
#endif | #endif | ||||
int | int | ||||
in6_control(struct socket *so, u_long cmd, void *data, | in6_control(struct socket *so, u_long cmd, void *data, | ||||
struct ifnet *ifp, struct thread *td) | struct ifnet *ifp, struct thread *td) | ||||
{ | { | ||||
struct in6_ifreq *ifr = (struct in6_ifreq *)data; | struct in6_ifreq *ifr = (struct in6_ifreq *)data; | ||||
struct in6_ifaddr *ia = NULL; | struct in6_ifaddr *ia = NULL; | ||||
struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; | struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; | ||||
struct sockaddr_in6 *sa6; | struct sockaddr_in6 *sa6; | ||||
int carp_attached = 0; | |||||
int error; | int error; | ||||
u_long ocmd = cmd; | u_long ocmd = cmd; | ||||
/* | /* | ||||
* Compat to make pre-10.x ifconfig(8) operable. | * Compat to make pre-10.x ifconfig(8) operable. | ||||
*/ | */ | ||||
if (cmd == OSIOCAIFADDR_IN6) | if (cmd == OSIOCAIFADDR_IN6) | ||||
cmd = SIOCAIFADDR_IN6; | cmd = SIOCAIFADDR_IN6; | ||||
▲ Show 20 Lines • Show All 291 Lines • ▼ Show 20 Lines | if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { | ||||
retlt->ia6t_preferred = ia->ia6_updatetime + | retlt->ia6t_preferred = ia->ia6_updatetime + | ||||
ia->ia6_lifetime.ia6t_pltime; | ia->ia6_lifetime.ia6t_pltime; | ||||
} else | } else | ||||
retlt->ia6t_preferred = maxexpire; | retlt->ia6t_preferred = maxexpire; | ||||
} | } | ||||
break; | break; | ||||
case SIOCAIFADDR_IN6: | case SIOCAIFADDR_IN6: | ||||
{ | |||||
struct nd_prefixctl pr0; | |||||
struct nd_prefix *pr; | |||||
/* | /* | ||||
* first, make or update the interface address structure, | * first, make or update the interface address structure, | ||||
* and link it to the list. | * and link it to the list. | ||||
*/ | */ | ||||
if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0) | if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0) | ||||
goto out; | goto out; | ||||
if (ia != NULL) { | if (ia != NULL) { | ||||
if (ia->ia_ifa.ifa_carp) | if (ia->ia_ifa.ifa_carp) | ||||
Show All 12 Lines | case SIOCAIFADDR_IN6: | ||||
if (cmd == ocmd && ifra->ifra_vhid > 0) { | if (cmd == ocmd && ifra->ifra_vhid > 0) { | ||||
if (carp_attach_p != NULL) | if (carp_attach_p != NULL) | ||||
error = (*carp_attach_p)(&ia->ia_ifa, | error = (*carp_attach_p)(&ia->ia_ifa, | ||||
ifra->ifra_vhid); | ifra->ifra_vhid); | ||||
else | else | ||||
error = EPROTONOSUPPORT; | error = EPROTONOSUPPORT; | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
else | |||||
carp_attached = 1; | |||||
} | } | ||||
/* | /* | ||||
* then, make the prefix on-link on the interface. | |||||
* XXX: we'd rather create the prefix before the address, but | |||||
* we need at least one address to install the corresponding | |||||
* interface route, so we configure the address first. | |||||
*/ | |||||
/* | |||||
* convert mask to prefix length (prefixmask has already | |||||
* been validated in in6_update_ifa(). | |||||
*/ | |||||
bzero(&pr0, sizeof(pr0)); | |||||
pr0.ndpr_ifp = ifp; | |||||
pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, | |||||
NULL); | |||||
if (pr0.ndpr_plen == 128) { | |||||
/* we don't need to install a host route. */ | |||||
goto aifaddr_out; | |||||
} | |||||
pr0.ndpr_prefix = ifra->ifra_addr; | |||||
/* apply the mask for safety. */ | |||||
IN6_MASK_ADDR(&pr0.ndpr_prefix.sin6_addr, | |||||
&ifra->ifra_prefixmask.sin6_addr); | |||||
/* | |||||
* XXX: since we don't have an API to set prefix (not address) | |||||
* lifetimes, we just use the same lifetimes as addresses. | |||||
* The (temporarily) installed lifetimes can be overridden by | |||||
* later advertised RAs (when accept_rtadv is non 0), which is | |||||
* an intended behavior. | |||||
*/ | |||||
pr0.ndpr_raf_onlink = 1; /* should be configurable? */ | |||||
pr0.ndpr_raf_auto = | |||||
((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); | |||||
pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; | |||||
pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; | |||||
/* add the prefix if not yet. */ | |||||
if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { | |||||
/* | |||||
* nd6_prelist_add will install the corresponding | |||||
* interface route. | |||||
*/ | |||||
if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) { | |||||
if (carp_attached) | |||||
(*carp_detach_p)(&ia->ia_ifa, false); | |||||
goto out; | |||||
} | |||||
} | |||||
/* relate the address to the prefix */ | |||||
if (ia->ia6_ndpr == NULL) { | |||||
ia->ia6_ndpr = pr; | |||||
pr->ndpr_addrcnt++; | |||||
/* | |||||
* If this is the first autoconf address from the | |||||
* prefix, create a temporary address as well | |||||
* (when required). | |||||
*/ | |||||
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) && | |||||
V_ip6_use_tempaddr && pr->ndpr_addrcnt == 1) { | |||||
int e; | |||||
if ((e = in6_tmpifadd(ia, 1, 0)) != 0) { | |||||
log(LOG_NOTICE, "in6_control: failed " | |||||
"to create a temporary address, " | |||||
"errno=%d\n", e); | |||||
} | |||||
} | |||||
} | |||||
nd6_prefix_rele(pr); | |||||
/* | |||||
* this might affect the status of autoconfigured addresses, | |||||
* that is, this address might make other addresses detached. | |||||
*/ | |||||
pfxlist_onlink_check(); | |||||
aifaddr_out: | |||||
/* | |||||
* Try to clear the flag when a new IPv6 address is added | * Try to clear the flag when a new IPv6 address is added | ||||
* onto an IFDISABLED interface and it succeeds. | * onto an IFDISABLED interface and it succeeds. | ||||
*/ | */ | ||||
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { | if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { | ||||
struct in6_ndireq nd; | struct in6_ndireq nd; | ||||
memset(&nd, 0, sizeof(nd)); | memset(&nd, 0, sizeof(nd)); | ||||
nd.ndi.flags = ND_IFINFO(ifp)->flags; | nd.ndi.flags = ND_IFINFO(ifp)->flags; | ||||
nd.ndi.flags &= ~ND6_IFF_IFDISABLED; | nd.ndi.flags &= ~ND6_IFF_IFDISABLED; | ||||
if (nd6_ioctl(SIOCSIFINFO_FLAGS, (caddr_t)&nd, ifp) < 0) | if (nd6_ioctl(SIOCSIFINFO_FLAGS, (caddr_t)&nd, ifp) < 0) | ||||
log(LOG_NOTICE, "SIOCAIFADDR_IN6: " | log(LOG_NOTICE, "SIOCAIFADDR_IN6: " | ||||
"SIOCSIFINFO_FLAGS for -ifdisabled " | "SIOCSIFINFO_FLAGS for -ifdisabled " | ||||
"failed."); | "failed."); | ||||
/* | /* | ||||
* Ignore failure of clearing the flag intentionally. | * Ignore failure of clearing the flag intentionally. | ||||
* The failure means address duplication was detected. | * The failure means address duplication was detected. | ||||
*/ | */ | ||||
} | } | ||||
break; | break; | ||||
} | |||||
case SIOCDIFADDR_IN6: | case SIOCDIFADDR_IN6: | ||||
in6_purgeifaddr(ia); | in6_purgeifaddr(ia); | ||||
EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, &ia->ia_ifa, | EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, &ia->ia_ifa, | ||||
IFADDR_EVENT_DEL); | IFADDR_EVENT_DEL); | ||||
break; | break; | ||||
default: | default: | ||||
▲ Show 20 Lines • Show All 395 Lines • ▼ Show 20 Lines | if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { | ||||
*/ | */ | ||||
ia->ia_ifa.ifa_dstaddr = | ia->ia_ifa.ifa_dstaddr = | ||||
(struct sockaddr *)&ia->ia_dstaddr; | (struct sockaddr *)&ia->ia_dstaddr; | ||||
} else { | } else { | ||||
ia->ia_ifa.ifa_dstaddr = NULL; | ia->ia_ifa.ifa_dstaddr = NULL; | ||||
} | } | ||||
/* set prefix mask if any */ | /* set prefix mask if any */ | ||||
ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; | |||||
if (ifra->ifra_prefixmask.sin6_len != 0) { | if (ifra->ifra_prefixmask.sin6_len != 0) { | ||||
if (!!IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, | |||||
&ifra->ifra_prefixmask.sin6_addr)) | |||||
in6_ifremprefix(ia); | |||||
ia->ia_prefixmask.sin6_family = AF_INET6; | ia->ia_prefixmask.sin6_family = AF_INET6; | ||||
ia->ia_prefixmask.sin6_len = ifra->ifra_prefixmask.sin6_len; | ia->ia_prefixmask.sin6_len = ifra->ifra_prefixmask.sin6_len; | ||||
ia->ia_prefixmask.sin6_addr = ifra->ifra_prefixmask.sin6_addr; | ia->ia_prefixmask.sin6_addr = ifra->ifra_prefixmask.sin6_addr; | ||||
} | } | ||||
ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; | |||||
ia->ia_ifp = ifp; | ia->ia_ifp = ifp; | ||||
ifa_ref(&ia->ia_ifa); /* if_addrhead */ | ifa_ref(&ia->ia_ifa); /* if_addrhead */ | ||||
IF_ADDR_WLOCK(ifp); | IF_ADDR_WLOCK(ifp); | ||||
CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); | CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); | ||||
IF_ADDR_WUNLOCK(ifp); | IF_ADDR_WUNLOCK(ifp); | ||||
ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ | ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | if ((ia->ia6_flags & IN6_IFF_TENTATIVE)) { | ||||
nd6_dad_start((struct ifaddr *)ia, delay); | nd6_dad_start((struct ifaddr *)ia, delay); | ||||
} | } | ||||
in6_newaddrmsg(ia, RTM_ADD); | in6_newaddrmsg(ia, RTM_ADD); | ||||
ifa_free(&ia->ia_ifa); | ifa_free(&ia->ia_ifa); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* Adds or deletes interface route for p2p ifa. | |||||
* Returns 0 on success or errno. | |||||
*/ | |||||
static int | |||||
in6_handle_dstaddr_rtrequest(int cmd, struct in6_ifaddr *ia) | |||||
{ | |||||
struct epoch_tracker et; | |||||
struct ifaddr *ifa = &ia->ia_ifa; | |||||
int error; | |||||
/* Prepare gateway */ | |||||
struct sockaddr_dl_short sdl = { | |||||
.sdl_family = AF_LINK, | |||||
.sdl_len = sizeof(struct sockaddr_dl_short), | |||||
.sdl_type = ifa->ifa_ifp->if_type, | |||||
.sdl_index = ifa->ifa_ifp->if_index, | |||||
}; | |||||
struct sockaddr_in6 dst = { | |||||
.sin6_family = AF_INET6, | |||||
.sin6_len = sizeof(struct sockaddr_in6), | |||||
.sin6_addr = ia->ia_dstaddr.sin6_addr, | |||||
}; | |||||
struct rt_addrinfo info = { | |||||
.rti_ifa = ifa, | |||||
.rti_ifp = ifa->ifa_ifp, | |||||
.rti_flags = RTF_PINNED | RTF_HOST, | |||||
.rti_info = { | |||||
[RTAX_DST] = (struct sockaddr *)&dst, | |||||
[RTAX_GATEWAY] = (struct sockaddr *)&sdl, | |||||
}, | |||||
}; | |||||
/* Don't set additional per-gw filters on removal */ | |||||
NET_EPOCH_ENTER(et); | |||||
error = rib_handle_ifaddr_info(ifa->ifa_ifp->if_fib, cmd, &info); | |||||
NET_EPOCH_EXIT(et); | |||||
return (error); | |||||
} | |||||
static bool | static bool | ||||
ifa_is_p2p(struct in6_ifaddr *ia) | ifa_is_p2p(struct in6_ifaddr *ia) | ||||
{ | { | ||||
int plen; | int plen; | ||||
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ | plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ | ||||
if ((plen == 128) && (ia->ia_dstaddr.sin6_family == AF_INET6) && | if ((plen == 128) && (ia->ia_dstaddr.sin6_family == AF_INET6) && | ||||
Show All 31 Lines | in6_purgeaddr(struct ifaddr *ifa) | ||||
/* Leave multicast groups. */ | /* Leave multicast groups. */ | ||||
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { | while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { | ||||
LIST_REMOVE(imm, i6mm_chain); | LIST_REMOVE(imm, i6mm_chain); | ||||
if (imm->i6mm_maddr != NULL) | if (imm->i6mm_maddr != NULL) | ||||
in6_leavegroup(imm->i6mm_maddr, NULL); | in6_leavegroup(imm->i6mm_maddr, NULL); | ||||
free(imm, M_IP6MADDR); | free(imm, M_IP6MADDR); | ||||
} | } | ||||
/* Check if we need to remove p2p route */ | |||||
if ((ia->ia_flags & IFA_ROUTE) && ifa_is_p2p(ia)) { | |||||
error = in6_handle_dstaddr_rtrequest(RTM_DELETE, ia); | |||||
if (error != 0) | |||||
log(LOG_INFO, "%s: err=%d, destination address delete " | |||||
"failed\n", __func__, error); | |||||
ia->ia_flags &= ~IFA_ROUTE; | |||||
} | |||||
/* Remove any prefix route */ | |||||
in6_ifremprefix(ia); | |||||
in6_newaddrmsg(ia, RTM_DELETE); | in6_newaddrmsg(ia, RTM_DELETE); | ||||
in6_unlink_ifa(ia, ifp); | in6_unlink_ifa(ia, ifp); | ||||
} | } | ||||
/* | /* | ||||
* Removes @ia from the corresponding interfaces and unlinks corresponding | * Removes @ia from the corresponding interfaces and unlinks corresponding | ||||
* prefix if no addresses are using it anymore. | * prefix if no addresses are using it anymore. | ||||
*/ | */ | ||||
Show All 21 Lines | if (pr != NULL && pr->ndpr_addrcnt == 0) { | ||||
nd6_prefix_del(pr); | nd6_prefix_del(pr); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) | in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) | ||||
{ | { | ||||
char ip6buf[INET6_ADDRSTRLEN]; | |||||
int remove_lle; | int remove_lle; | ||||
IF_ADDR_WLOCK(ifp); | IF_ADDR_WLOCK(ifp); | ||||
CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); | CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); | ||||
IF_ADDR_WUNLOCK(ifp); | IF_ADDR_WUNLOCK(ifp); | ||||
ifa_free(&ia->ia_ifa); /* if_addrhead */ | ifa_free(&ia->ia_ifa); /* if_addrhead */ | ||||
/* | /* | ||||
* Defer the release of what might be the last reference to the | * Defer the release of what might be the last reference to the | ||||
* in6_ifaddr so that it can't be freed before the remainder of the | * in6_ifaddr so that it can't be freed before the remainder of the | ||||
* cleanup. | * cleanup. | ||||
*/ | */ | ||||
IN6_IFADDR_WLOCK(); | IN6_IFADDR_WLOCK(); | ||||
CK_STAILQ_REMOVE(&V_in6_ifaddrhead, ia, in6_ifaddr, ia_link); | CK_STAILQ_REMOVE(&V_in6_ifaddrhead, ia, in6_ifaddr, ia_link); | ||||
CK_LIST_REMOVE(ia, ia6_hash); | CK_LIST_REMOVE(ia, ia6_hash); | ||||
IN6_IFADDR_WUNLOCK(); | IN6_IFADDR_WUNLOCK(); | ||||
/* | /* | ||||
* Release the reference to the base prefix. There should be a | * Release the reference to the base prefix. | ||||
* positive reference. | |||||
*/ | */ | ||||
remove_lle = 0; | remove_lle = 0; | ||||
if (ia->ia6_ndpr == NULL) { | if (ia->ia6_ndpr != NULL) { | ||||
nd6log((LOG_NOTICE, | |||||
"in6_unlink_ifa: autoconf'ed address " | |||||
"%s has no prefix\n", ip6_sprintf(ip6buf, IA6_IN6(ia)))); | |||||
} else { | |||||
ia->ia6_ndpr->ndpr_addrcnt--; | ia->ia6_ndpr->ndpr_addrcnt--; | ||||
/* Do not delete lles within prefix if refcont != 0 */ | /* Do not delete lles within prefix if refcont != 0 */ | ||||
if (ia->ia6_ndpr->ndpr_addrcnt == 0) | if (ia->ia6_ndpr->ndpr_addrcnt == 0) | ||||
remove_lle = 1; | remove_lle = 1; | ||||
ia->ia6_ndpr = NULL; | ia->ia6_ndpr = NULL; | ||||
} | } | ||||
nd6_rem_ifa_lle(ia, remove_lle); | nd6_rem_ifa_lle(ia, remove_lle); | ||||
Show All 17 Lines | |||||
*/ | */ | ||||
static int | static int | ||||
in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia, | in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia, | ||||
struct in6_aliasreq *ifra, int hostIsNew) | struct in6_aliasreq *ifra, int hostIsNew) | ||||
{ | { | ||||
int error = 0, ifacount = 0; | int error = 0, ifacount = 0; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct sockaddr_in6 *pdst; | struct sockaddr_in6 *pdst; | ||||
char ip6buf[INET6_ADDRSTRLEN]; | |||||
/* | /* | ||||
* Give the interface a chance to initialize | * Give the interface a chance to initialize | ||||
* if this is its first address, | * if this is its first address, | ||||
*/ | */ | ||||
if (hostIsNew != 0) { | if (hostIsNew != 0) { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
Show All 15 Lines | in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia, | ||||
/* | /* | ||||
* If a new destination address is specified, scrub the old one and | * If a new destination address is specified, scrub the old one and | ||||
* install the new destination. Note that the interface must be | * install the new destination. Note that the interface must be | ||||
* p2p or loopback. | * p2p or loopback. | ||||
*/ | */ | ||||
pdst = &ifra->ifra_dstaddr; | pdst = &ifra->ifra_dstaddr; | ||||
if (pdst->sin6_family == AF_INET6 && | if (pdst->sin6_family == AF_INET6 && | ||||
!IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr, &ia->ia_dstaddr.sin6_addr)) { | !IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr, &ia->ia_dstaddr.sin6_addr)) { | ||||
if ((ia->ia_flags & IFA_ROUTE) != 0 && | in6_ifremprefix(ia); | ||||
(in6_handle_dstaddr_rtrequest(RTM_DELETE, ia) != 0)) { | |||||
nd6log((LOG_ERR, "in6_update_ifa_internal: failed to " | |||||
"remove a route to the old destination: %s\n", | |||||
ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); | |||||
/* proceed anyway... */ | |||||
} else | |||||
ia->ia_flags &= ~IFA_ROUTE; | |||||
ia->ia_dstaddr = *pdst; | ia->ia_dstaddr = *pdst; | ||||
} | } | ||||
/* | /* | ||||
* If a new destination address is specified for a point-to-point | * If a new destination address is specified for a point-to-point | ||||
* interface, install a route to the destination as an interface | * interface, install a route to the destination as an interface | ||||
* direct route. | * direct route. | ||||
* XXX: the logic below rejects assigning multiple addresses on a p2p | * XXX: the logic below rejects assigning multiple addresses on a p2p | ||||
* interface that share the same destination. | * interface that share the same destination. | ||||
*/ | */ | ||||
if (!(ia->ia_flags & IFA_ROUTE) && ifa_is_p2p(ia)) { | if (!(ia->ia_flags & IFA_ROUTE)) { | ||||
error = in6_handle_dstaddr_rtrequest(RTM_ADD, ia); | error = in6_prefix_rtrequest(RTM_ADD, ia); | ||||
if (error) | if (error == 0) { | ||||
goto done; | |||||
ia->ia_flags |= IFA_ROUTE; | ia->ia_flags |= IFA_ROUTE; | ||||
/* | |||||
* If this is the first autoconf address from the | |||||
* prefix, create a temporary address as well | |||||
* (when required). | |||||
*/ | |||||
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) && | |||||
V_ip6_use_tempaddr) { | |||||
int e; | |||||
if ((e = in6_tmpifadd(ia, 1, 0)) != 0) { | |||||
log(LOG_NOTICE, "in6_control: failed " | |||||
"to create a temporary address, " | |||||
"errno=%d\n", e); | |||||
} | |||||
} | |||||
} else if (error == EEXIST) | |||||
error = 0; | |||||
else | |||||
goto done; | |||||
} | } | ||||
/* | /* | ||||
* add a loopback route to self if not exists | * add a loopback route to self if not exists | ||||
*/ | */ | ||||
if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) { | if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) { | ||||
error = ifa_add_loopback_route((struct ifaddr *)ia, | error = ifa_add_loopback_route((struct ifaddr *)ia, | ||||
(struct sockaddr *)&ia->ia_addr); | (struct sockaddr *)&ia->ia_addr); | ||||
▲ Show 20 Lines • Show All 1,188 Lines • Show Last 20 Lines |