Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/in6_ifattach.c
Show First 20 Lines • Show All 234 Lines • ▼ Show 20 Lines | |||||
* Get interface identifier for the specified interface. | * Get interface identifier for the specified interface. | ||||
* XXX assumes single sockaddr_dl (AF_LINK address) per an interface | * XXX assumes single sockaddr_dl (AF_LINK address) per an interface | ||||
* | * | ||||
* in6 - upper 64bits are preserved | * in6 - upper 64bits are preserved | ||||
*/ | */ | ||||
int | int | ||||
in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) | in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct sockaddr_dl *sdl; | struct sockaddr_dl *sdl; | ||||
u_int8_t *addr; | u_int8_t *addr; | ||||
size_t addrlen; | size_t addrlen; | ||||
static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | ||||
static u_int8_t allone[8] = | static u_int8_t allone[8] = | ||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ASSERT(); | ||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
if (ifa->ifa_addr->sa_family != AF_LINK) | if (ifa->ifa_addr->sa_family != AF_LINK) | ||||
continue; | continue; | ||||
sdl = (struct sockaddr_dl *)ifa->ifa_addr; | sdl = (struct sockaddr_dl *)ifa->ifa_addr; | ||||
if (sdl == NULL) | if (sdl == NULL) | ||||
continue; | continue; | ||||
if (sdl->sdl_alen == 0) | if (sdl->sdl_alen == 0) | ||||
continue; | continue; | ||||
goto found; | goto found; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return -1; | return -1; | ||||
found: | found: | ||||
IF_ADDR_LOCK_ASSERT(ifp); | |||||
addr = LLADDR(sdl); | addr = LLADDR(sdl); | ||||
addrlen = sdl->sdl_alen; | addrlen = sdl->sdl_alen; | ||||
/* get EUI64 */ | /* get EUI64 */ | ||||
switch (ifp->if_type) { | switch (ifp->if_type) { | ||||
case IFT_BRIDGE: | case IFT_BRIDGE: | ||||
case IFT_ETHER: | case IFT_ETHER: | ||||
case IFT_L2VLAN: | case IFT_L2VLAN: | ||||
case IFT_ATM: | case IFT_ATM: | ||||
case IFT_IEEE1394: | case IFT_IEEE1394: | ||||
/* IEEE802/EUI64 cases - what others? */ | /* IEEE802/EUI64 cases - what others? */ | ||||
/* IEEE1394 uses 16byte length address starting with EUI64 */ | /* IEEE1394 uses 16byte length address starting with EUI64 */ | ||||
if (addrlen > 8) | if (addrlen > 8) | ||||
addrlen = 8; | addrlen = 8; | ||||
/* look at IEEE802/EUI64 only */ | /* look at IEEE802/EUI64 only */ | ||||
if (addrlen != 8 && addrlen != 6) { | if (addrlen != 8 && addrlen != 6) | ||||
NET_EPOCH_EXIT(et); | |||||
return -1; | return -1; | ||||
} | |||||
/* | /* | ||||
* check for invalid MAC address - on bsdi, we see it a lot | * check for invalid MAC address - on bsdi, we see it a lot | ||||
* since wildboar configures all-zero MAC on pccard before | * since wildboar configures all-zero MAC on pccard before | ||||
* card insertion. | * card insertion. | ||||
*/ | */ | ||||
if (bcmp(addr, allzero, addrlen) == 0) { | if (bcmp(addr, allzero, addrlen) == 0) | ||||
NET_EPOCH_EXIT(et); | |||||
return -1; | return -1; | ||||
} | if (bcmp(addr, allone, addrlen) == 0) | ||||
if (bcmp(addr, allone, addrlen) == 0) { | |||||
NET_EPOCH_EXIT(et); | |||||
return -1; | return -1; | ||||
} | |||||
/* make EUI64 address */ | /* make EUI64 address */ | ||||
if (addrlen == 8) | if (addrlen == 8) | ||||
bcopy(addr, &in6->s6_addr[8], 8); | bcopy(addr, &in6->s6_addr[8], 8); | ||||
else if (addrlen == 6) { | else if (addrlen == 6) { | ||||
in6->s6_addr[8] = addr[0]; | in6->s6_addr[8] = addr[0]; | ||||
in6->s6_addr[9] = addr[1]; | in6->s6_addr[9] = addr[1]; | ||||
in6->s6_addr[10] = addr[2]; | in6->s6_addr[10] = addr[2]; | ||||
in6->s6_addr[11] = 0xff; | in6->s6_addr[11] = 0xff; | ||||
in6->s6_addr[12] = 0xfe; | in6->s6_addr[12] = 0xfe; | ||||
in6->s6_addr[13] = addr[3]; | in6->s6_addr[13] = addr[3]; | ||||
in6->s6_addr[14] = addr[4]; | in6->s6_addr[14] = addr[4]; | ||||
in6->s6_addr[15] = addr[5]; | in6->s6_addr[15] = addr[5]; | ||||
} | } | ||||
break; | break; | ||||
case IFT_GIF: | case IFT_GIF: | ||||
case IFT_STF: | case IFT_STF: | ||||
/* | /* | ||||
* RFC2893 says: "SHOULD use IPv4 address as ifid source". | * RFC2893 says: "SHOULD use IPv4 address as ifid source". | ||||
* however, IPv4 address is not very suitable as unique | * however, IPv4 address is not very suitable as unique | ||||
* identifier source (can be renumbered). | * identifier source (can be renumbered). | ||||
* we don't do this. | * we don't do this. | ||||
*/ | */ | ||||
NET_EPOCH_EXIT(et); | |||||
return -1; | return -1; | ||||
default: | default: | ||||
NET_EPOCH_EXIT(et); | |||||
return -1; | return -1; | ||||
} | } | ||||
/* sanity check: g bit must not indicate "group" */ | /* sanity check: g bit must not indicate "group" */ | ||||
if (EUI64_GROUP(in6)) { | if (EUI64_GROUP(in6)) | ||||
NET_EPOCH_EXIT(et); | |||||
return -1; | return -1; | ||||
} | |||||
/* convert EUI64 into IPv6 interface identifier */ | /* convert EUI64 into IPv6 interface identifier */ | ||||
EUI64_TO_IFID(in6); | EUI64_TO_IFID(in6); | ||||
/* | /* | ||||
* sanity check: ifid must not be all zero, avoid conflict with | * sanity check: ifid must not be all zero, avoid conflict with | ||||
* subnet router anycast | * subnet router anycast | ||||
*/ | */ | ||||
if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && | if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && | ||||
bcmp(&in6->s6_addr[9], allzero, 7) == 0) { | bcmp(&in6->s6_addr[9], allzero, 7) == 0) | ||||
NET_EPOCH_EXIT(et); | |||||
return -1; | return -1; | ||||
} | |||||
NET_EPOCH_EXIT(et); | |||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
* Get interface identifier for the specified interface. If it is not | * Get interface identifier for the specified interface. If it is not | ||||
* available on ifp0, borrow interface identifier from other information | * available on ifp0, borrow interface identifier from other information | ||||
* sources. | * sources. | ||||
* | * | ||||
* altifp - secondary EUI64 source | * altifp - secondary EUI64 source | ||||
*/ | */ | ||||
static int | static int | ||||
get_ifid(struct ifnet *ifp0, struct ifnet *altifp, | get_ifid(struct ifnet *ifp0, struct ifnet *altifp, | ||||
struct in6_addr *in6) | struct in6_addr *in6) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
NET_EPOCH_ASSERT(); | |||||
/* first, try to get it from the interface itself */ | /* first, try to get it from the interface itself */ | ||||
if (in6_get_hw_ifid(ifp0, in6) == 0) { | if (in6_get_hw_ifid(ifp0, in6) == 0) { | ||||
nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", | nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", | ||||
if_name(ifp0))); | if_name(ifp0))); | ||||
goto success; | goto success; | ||||
} | } | ||||
/* try secondary EUI64 source. this basically is for ATM PVC */ | /* try secondary EUI64 source. this basically is for ATM PVC */ | ||||
if (altifp && in6_get_hw_ifid(altifp, in6) == 0) { | if (altifp && in6_get_hw_ifid(altifp, in6) == 0) { | ||||
nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", | nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", | ||||
if_name(ifp0), if_name(altifp))); | if_name(ifp0), if_name(altifp))); | ||||
goto success; | goto success; | ||||
} | } | ||||
/* next, try to get it from some other hardware interface */ | /* next, try to get it from some other hardware interface */ | ||||
NET_EPOCH_ENTER(et); | |||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | ||||
if (ifp == ifp0) | if (ifp == ifp0) | ||||
continue; | continue; | ||||
if (in6_get_hw_ifid(ifp, in6) != 0) | if (in6_get_hw_ifid(ifp, in6) != 0) | ||||
continue; | continue; | ||||
/* | /* | ||||
* to borrow ifid from other interface, ifid needs to be | * to borrow ifid from other interface, ifid needs to be | ||||
* globally unique | * globally unique | ||||
*/ | */ | ||||
if (IFID_UNIVERSAL(in6)) { | if (IFID_UNIVERSAL(in6)) { | ||||
nd6log((LOG_DEBUG, | nd6log((LOG_DEBUG, | ||||
"%s: borrow interface identifier from %s\n", | "%s: borrow interface identifier from %s\n", | ||||
if_name(ifp0), if_name(ifp))); | if_name(ifp0), if_name(ifp))); | ||||
NET_EPOCH_EXIT(et); | |||||
goto success; | goto success; | ||||
} | } | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
/* last resort: get from random number source */ | /* last resort: get from random number source */ | ||||
if (get_rand_ifid(ifp, in6) == 0) { | if (get_rand_ifid(ifp, in6) == 0) { | ||||
nd6log((LOG_DEBUG, | nd6log((LOG_DEBUG, | ||||
"%s: interface identifier generated by random number\n", | "%s: interface identifier generated by random number\n", | ||||
if_name(ifp0))); | if_name(ifp0))); | ||||
goto success; | goto success; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 256 Lines • ▼ Show 20 Lines | |||||
* XXX multiple link-local address case | * XXX multiple link-local address case | ||||
* | * | ||||
* altifp - secondary EUI64 source | * altifp - secondary EUI64 source | ||||
*/ | */ | ||||
void | void | ||||
in6_ifattach(struct ifnet *ifp, struct ifnet *altifp) | in6_ifattach(struct ifnet *ifp, struct ifnet *altifp) | ||||
{ | { | ||||
struct in6_ifaddr *ia; | struct in6_ifaddr *ia; | ||||
NET_EPOCH_ASSERT(); | |||||
if (ifp->if_afdata[AF_INET6] == NULL) | if (ifp->if_afdata[AF_INET6] == NULL) | ||||
return; | return; | ||||
/* | /* | ||||
* quirks based on interface type | * quirks based on interface type | ||||
*/ | */ | ||||
switch (ifp->if_type) { | switch (ifp->if_type) { | ||||
case IFT_STF: | case IFT_STF: | ||||
▲ Show 20 Lines • Show All 212 Lines • Show Last 20 Lines |