Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/in6.c
Show First 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | |||||
#include <sys/rmlock.h> | #include <sys/rmlock.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_types.h> | #include <net/if_types.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route/route_ctl.h> | |||||
#include <net/route/nhop.h> | #include <net/route/nhop.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_var.h> | #include <netinet/in_var.h> | ||||
#include <net/if_llatbl.h> | #include <net/if_llatbl.h> | ||||
#include <netinet/if_ether.h> | #include <netinet/if_ether.h> | ||||
▲ Show 20 Lines • Show All 1,165 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); | ||||
} | } | ||||
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_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); | |||||
} | |||||
void | void | ||||
in6_purgeaddr(struct ifaddr *ifa) | in6_purgeaddr(struct ifaddr *ifa) | ||||
{ | { | ||||
struct ifnet *ifp = ifa->ifa_ifp; | struct ifnet *ifp = ifa->ifa_ifp; | ||||
struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; | struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; | ||||
struct in6_multi_mship *imm; | struct in6_multi_mship *imm; | ||||
int plen, error; | int plen, error; | ||||
Show All 17 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 */ | |||||
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ | plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ | ||||
if (ia->ia_dstaddr.sin6_family != AF_INET6) | |||||
plen = 0; | |||||
if ((ia->ia_flags & IFA_ROUTE) && plen == 128) { | if ((ia->ia_flags & IFA_ROUTE) && plen == 128) { | ||||
error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags | | error = in6_handle_dstaddr_rtrequest(RTM_DELETE, ia); | ||||
(ia->ia_dstaddr.sin6_family == AF_INET6 ? RTF_HOST : 0)); | |||||
if (error != 0) | if (error != 0) | ||||
log(LOG_INFO, "%s: err=%d, destination address delete " | log(LOG_INFO, "%s: err=%d, destination address delete " | ||||
"failed\n", __func__, error); | "failed\n", __func__, error); | ||||
ia->ia_flags &= ~IFA_ROUTE; | ia->ia_flags &= ~IFA_ROUTE; | ||||
} | } | ||||
in6_newaddrmsg(ia, RTM_DELETE); | in6_newaddrmsg(ia, RTM_DELETE); | ||||
in6_unlink_ifa(ia, ifp); | in6_unlink_ifa(ia, ifp); | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 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 && | if ((ia->ia_flags & IFA_ROUTE) != 0 && | ||||
(rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST) != 0)) { | (in6_handle_dstaddr_rtrequest(RTM_DELETE, ia) != 0)) { | ||||
nd6log((LOG_ERR, "in6_update_ifa_internal: failed to " | nd6log((LOG_ERR, "in6_update_ifa_internal: failed to " | ||||
"remove a route to the old destination: %s\n", | "remove a route to the old destination: %s\n", | ||||
ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); | ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); | ||||
/* proceed anyway... */ | /* proceed anyway... */ | ||||
} else | } else | ||||
ia->ia_flags &= ~IFA_ROUTE; | 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. | ||||
*/ | */ | ||||
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ | plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ | ||||
if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && | if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && | ||||
ia->ia_dstaddr.sin6_family == AF_INET6) { | ia->ia_dstaddr.sin6_family == AF_INET6) { | ||||
int rtflags = RTF_UP | RTF_HOST; | |||||
/* | /* | ||||
* Handle the case for ::1 . | * Handle the case for ::1 . | ||||
*/ | */ | ||||
if (ifp->if_flags & IFF_LOOPBACK) | if (ifp->if_flags & IFF_LOOPBACK) | ||||
ia->ia_flags |= IFA_RTSELF; | ia->ia_flags |= IFA_RTSELF; | ||||
error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags); | error = in6_handle_dstaddr_rtrequest(RTM_ADD, ia); | ||||
if (error) | if (error) | ||||
goto done; | goto done; | ||||
ia->ia_flags |= IFA_ROUTE; | ia->ia_flags |= IFA_ROUTE; | ||||
} | } | ||||
/* | /* | ||||
* add a loopback route to self if not exists | * add a loopback route to self if not exists | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 1,094 Lines • Show Last 20 Lines |