summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/in6.c
diff options
context:
space:
mode:
authorsuz <suz@FreeBSD.org>2005-10-21 16:23:01 +0000
committersuz <suz@FreeBSD.org>2005-10-21 16:23:01 +0000
commitc2b19f24a4ba01108e047a35a4a060cbfdf28a17 (patch)
treeb24292a814b8011ab44cabf6cac263a8a214a60a /sys/netinet6/in6.c
parent6ee4447c50d54cfee8b2556c2cdcc45dc05bca37 (diff)
downloadFreeBSD-src-c2b19f24a4ba01108e047a35a4a060cbfdf28a17.zip
FreeBSD-src-c2b19f24a4ba01108e047a35a4a060cbfdf28a17.tar.gz
sync with KAME regarding NDP
- introduced fine-grain-timer to manage ND-caches and IPv6 Multicast-Listeners - supports Router-Preference <draft-ietf-ipv6-router-selection-07.txt> - better prefix lifetime management - more spec-comformant DAD advertisement - updated RFC/internet-draft revisions Obtained from: KAME Reviewed by: ume, gnn MFC after: 2 month
Diffstat (limited to 'sys/netinet6/in6.c')
-rw-r--r--sys/netinet6/in6.c402
1 files changed, 322 insertions, 80 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 53d2c2d..d5a8e15 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -328,6 +328,7 @@ in6_control(so, cmd, data, ifp, td)
struct in6_ifaddr *ia = NULL;
struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
int error, privileged;
+ struct sockaddr_in6 *sa6;
privileged = 0;
if (td == NULL || !suser(td))
@@ -408,19 +409,56 @@ in6_control(so, cmd, data, ifp, td)
/*
* Find address for this interface, if it exists.
+ *
+ * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation
+ * only, and used the first interface address as the target of other
+ * operations (without checking ifra_addr). This was because netinet
+ * code/API assumed at most 1 interface address per interface.
+ * Since IPv6 allows a node to assign multiple addresses
+ * on a single interface, we almost always look and check the
+ * presence of ifra_addr, and reject invalid ones here.
+ * It also decreases duplicated code among SIOC*_IN6 operations.
*/
- if (ifra->ifra_addr.sin6_family == AF_INET6) { /* XXX */
+ switch (cmd) {
+ case SIOCAIFADDR_IN6:
+ case SIOCSIFPHYADDR_IN6:
+ sa6 = &ifra->ifra_addr;
+ break;
+ case SIOCSIFADDR_IN6:
+ case SIOCGIFADDR_IN6:
+ case SIOCSIFDSTADDR_IN6:
+ case SIOCSIFNETMASK_IN6:
+ case SIOCGIFDSTADDR_IN6:
+ case SIOCGIFNETMASK_IN6:
+ case SIOCDIFADDR_IN6:
+ case SIOCGIFPSRCADDR_IN6:
+ case SIOCGIFPDSTADDR_IN6:
+ case SIOCGIFAFLAG_IN6:
+ case SIOCSNDFLUSH_IN6:
+ case SIOCSPFXFLUSH_IN6:
+ case SIOCSRTRFLUSH_IN6:
+ case SIOCGIFALIFETIME_IN6:
+ case SIOCSIFALIFETIME_IN6:
+ case SIOCGIFSTAT_IN6:
+ case SIOCGIFSTAT_ICMP6:
+ sa6 = &ifr->ifr_addr;
+ break;
+ default:
+ sa6 = NULL;
+ break;
+ }
+ if (sa6 && sa6->sin6_family == AF_INET6) {
int error = 0;
- if (ifra->ifra_addr.sin6_scope_id != 0)
- error = sa6_embedscope(&ifra->ifra_addr, 0);
+ if (sa6->sin6_scope_id != 0)
+ error = sa6_embedscope(sa6, 0);
else
- error = in6_setscope(&ifra->ifra_addr.sin6_addr,
- ifp, NULL);
+ error = in6_setscope(&sa6->sin6_addr, ifp, NULL);
if (error != 0)
return (error);
- ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
- }
+ ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
+ } else
+ ia = NULL;
switch (cmd) {
case SIOCSIFADDR_IN6:
@@ -538,6 +576,42 @@ in6_control(so, cmd, data, ifp, td)
case SIOCGIFALIFETIME_IN6:
ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
+ if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
+ time_t maxexpire;
+ struct in6_addrlifetime *retlt =
+ &ifr->ifr_ifru.ifru_lifetime;
+
+ /*
+ * XXX: adjust expiration time assuming time_t is
+ * signed.
+ */
+ maxexpire = (-1) &
+ ~(1 << ((sizeof(maxexpire) * 8) - 1));
+ if (ia->ia6_lifetime.ia6t_vltime <
+ maxexpire - ia->ia6_updatetime) {
+ retlt->ia6t_expire = ia->ia6_updatetime +
+ ia->ia6_lifetime.ia6t_vltime;
+ } else
+ retlt->ia6t_expire = maxexpire;
+ }
+ if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
+ time_t maxexpire;
+ struct in6_addrlifetime *retlt =
+ &ifr->ifr_ifru.ifru_lifetime;
+
+ /*
+ * XXX: adjust expiration time assuming time_t is
+ * signed.
+ */
+ maxexpire = (-1) &
+ ~(1 << ((sizeof(maxexpire) * 8) - 1));
+ if (ia->ia6_lifetime.ia6t_pltime <
+ maxexpire - ia->ia6_updatetime) {
+ retlt->ia6t_preferred = ia->ia6_updatetime +
+ ia->ia6_lifetime.ia6t_pltime;
+ } else
+ retlt->ia6t_preferred = maxexpire;
+ }
break;
case SIOCSIFALIFETIME_IN6:
@@ -558,13 +632,14 @@ in6_control(so, cmd, data, ifp, td)
case SIOCAIFADDR_IN6:
{
int i, error = 0;
- struct nd_prefix pr0, *pr;
+ struct nd_prefixctl pr0;
+ struct nd_prefix *pr;
/*
* first, make or update the interface address structure,
* and link it to the list.
*/
- if ((error = in6_update_ifa(ifp, ifra, ia)) != 0)
+ if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
return (error);
/*
@@ -586,7 +661,6 @@ in6_control(so, cmd, data, ifp, td)
break; /* we don't need to install a host route. */
}
pr0.ndpr_prefix = ifra->ifra_addr;
- pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr;
/* apply the mask for safety. */
for (i = 0; i < 4; i++) {
pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
@@ -638,7 +712,7 @@ in6_control(so, cmd, data, ifp, td)
if (ip6_use_tempaddr &&
pr->ndpr_refcnt == 1) {
int e;
- if ((e = in6_tmpifadd(ia, 1)) != 0) {
+ if ((e = in6_tmpifadd(ia, 1, 0)) != 0) {
log(LOG_NOTICE, "in6_control: "
"failed to create a "
"temporary address, "
@@ -662,7 +736,8 @@ in6_control(so, cmd, data, ifp, td)
case SIOCDIFADDR_IN6:
{
int i = 0;
- struct nd_prefix pr0, *pr;
+ struct nd_prefixctl pr0;
+ struct nd_prefix *pr;
/*
* If the address being deleted is the only one that owns
@@ -680,10 +755,10 @@ in6_control(so, cmd, data, ifp, td)
if (pr0.ndpr_plen == 128)
goto purgeaddr;
pr0.ndpr_prefix = ia->ia_addr;
- pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr;
+ /* apply the mask for safety. */
for (i = 0; i < 4; i++) {
pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
- ia->ia_prefixmask.sin6_addr.s6_addr32[i];
+ ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];
}
/*
* The logic of the following condition is a bit complicated.
@@ -723,16 +798,20 @@ in6_control(so, cmd, data, ifp, td)
* XXX: should this be performed under splnet()?
*/
int
-in6_update_ifa(ifp, ifra, ia)
+in6_update_ifa(ifp, ifra, ia, flags)
struct ifnet *ifp;
struct in6_aliasreq *ifra;
struct in6_ifaddr *ia;
+ int flags;
{
int error = 0, hostIsNew = 0, plen = -1;
struct in6_ifaddr *oia;
struct sockaddr_in6 dst6;
struct in6_addrlifetime *lt;
+ struct in6_multi_mship *imm;
+ struct in6_multi *in6m_sol;
struct rtentry *rt;
+ int delay;
/* Validate parameters */
if (ifp == NULL || ifra == NULL) /* this maybe redundant */
@@ -818,10 +897,8 @@ in6_update_ifa(ifp, ifra, ia)
}
/* lifetime consistency check */
lt = &ifra->ifra_lifetime;
- if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
- && lt->ia6t_vltime + time_second < time_second) {
- return EINVAL;
- }
+ if (lt->ia6t_pltime > lt->ia6t_vltime)
+ return (EINVAL);
if (lt->ia6t_vltime == 0) {
/*
* the following log might be noisy, but this is a typical
@@ -830,10 +907,9 @@ in6_update_ifa(ifp, ifra, ia)
nd6log((LOG_INFO,
"in6_update_ifa: valid lifetime is 0 for %s\n",
ip6_sprintf(&ifra->ifra_addr.sin6_addr)));
- }
- if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
- && lt->ia6t_pltime + time_second < time_second) {
- return EINVAL;
+
+ if (ia == NULL)
+ return (0); /* there's nothing to do */
}
/*
@@ -852,11 +928,12 @@ in6_update_ifa(ifp, ifra, ia)
if (ia == NULL)
return (ENOBUFS);
bzero((caddr_t)ia, sizeof(*ia));
- /* Initialize the address and masks */
+ /* Initialize the address and masks, and put time stamp */
IFA_LOCK_INIT(&ia->ia_ifa);
ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
ia->ia_addr.sin6_family = AF_INET6;
ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
+ ia->ia6_createtime = time_second;
if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
/*
* XXX: some functions expect that ifa_dstaddr is not
@@ -881,6 +958,9 @@ in6_update_ifa(ifp, ifra, ia)
TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
}
+ /* update timestamp */
+ ia->ia6_updatetime = time_second;
+
/* set prefix mask */
if (ifra->ifra_prefixmask.sin6_len) {
/*
@@ -945,8 +1025,6 @@ in6_update_ifa(ifp, ifra, ia)
* configure address flags.
*/
ia->ia6_flags = ifra->ifra_flags;
- ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */
- ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */
/*
* backward compatibility - if IN6_IFF_DEPRECATED is set from the
* userland, make it deprecated.
@@ -955,17 +1033,14 @@ in6_update_ifa(ifp, ifra, ia)
ia->ia6_lifetime.ia6t_pltime = 0;
ia->ia6_lifetime.ia6t_preferred = time_second;
}
-
/*
- * Perform DAD, if needed.
- * XXX It may be of use, if we can administratively
- * disable DAD.
+ * Make the address tentative before joining multicast addresses,
+ * so that corresponding MLD responses would not have a tentative
+ * source address.
*/
- if (in6if_do_dad(ifp) && hostIsNew &&
- (ifra->ifra_flags & IN6_IFF_NODAD) == 0) {
+ ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */
+ if (hostIsNew && in6if_do_dad(ifp))
ia->ia6_flags |= IN6_IFF_TENTATIVE;
- nd6_dad_start((struct ifaddr *)ia, NULL);
- }
/*
* We are done if we have simply modified an existing address.
@@ -979,9 +1054,9 @@ in6_update_ifa(ifp, ifra, ia)
*/
/* Join necessary multicast groups */
+ in6m_sol = NULL;
if ((ifp->if_flags & IFF_MULTICAST) != 0) {
struct sockaddr_in6 mltaddr, mltmask;
- struct in6_multi *in6m;
struct in6_addr llsol;
/* join solicited multicast addr for new host id */
@@ -997,15 +1072,29 @@ in6_update_ifa(ifp, ifra, ia)
"in6_setscope failed\n");
goto cleanup;
}
- (void)in6_addmulti(&llsol, ifp, &error);
+ delay = 0;
+ if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+ /*
+ * We need a random delay for DAD on the address
+ * being configured. It also means delaying
+ * transmission of the corresponding MLD report to
+ * avoid report collision.
+ * [draft-ietf-ipv6-rfc2462bis-02.txt]
+ */
+ delay = arc4random() %
+ (MAX_RTR_SOLICITATION_DELAY * hz);
+ }
+ imm = in6_joingroup(ifp, &llsol, &error, delay);
if (error != 0) {
nd6log((LOG_WARNING,
"in6_update_ifa: addmulti failed for "
"%s on %s (errno=%d)\n",
ip6_sprintf(&llsol), if_name(ifp),
error));
- goto cleanup;
+ in6_purgeaddr((struct ifaddr *)ia);
+ return (error);
}
+ in6m_sol = imm->i6mm_maddr;
bzero(&mltmask, sizeof(mltmask));
mltmask.sin6_len = sizeof(struct sockaddr_in6);
@@ -1050,37 +1139,67 @@ in6_update_ifa(ifp, ifra, ia)
} else
RTFREE_LOCKED(rt);
- IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
- if (in6m == NULL) {
- (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
- if (error != 0) {
- nd6log((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;
+ /*
+ * XXX: do we really need this automatic routes?
+ * We should probably reconsider this stuff. Most applications
+ * actually do not need the routes, since they usually specify
+ * the outgoing interface.
+ */
+ rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+ if (rt) {
+ /* XXX: only works in !SCOPEDROUTING case. */
+ if (memcmp(&mltaddr.sin6_addr,
+ &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+ MLTMASK_LEN)) {
+ RTFREE_LOCKED(rt);
+ rt = NULL;
}
}
+ if (!rt) {
+ error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+ (struct sockaddr *)&ia->ia_addr,
+ (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING,
+ (struct rtentry **)0);
+ if (error)
+ goto cleanup;
+ } else {
+ RTFREE_LOCKED(rt);
+ }
+
+ imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+ if (!imm) {
+ nd6log((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;
+ }
/*
* join node information group address
*/
#define hostnamelen strlen(hostname)
+ delay = 0;
+ if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+ /*
+ * The spec doesn't say anything about delay for this
+ * group, but the same logic should apply.
+ */
+ delay = arc4random() %
+ (MAX_RTR_SOLICITATION_DELAY * hz);
+ }
if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr)
== 0) {
- IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
- if (in6m == NULL) {
- (void)in6_addmulti(&mltaddr.sin6_addr,
- ifp, &error);
- if (error != 0) {
- nd6log((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;
- }
+ imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error,
+ delay); /* XXX jinmei */
+ if (!imm) {
+ nd6log((LOG_WARNING, "in6_update_ifa: "
+ "addmulti failed for %s on %s "
+ "(errno=%d)\n",
+ ip6_sprintf(&mltaddr.sin6_addr),
+ if_name(ifp), error));
+ /* XXX not very fatal, go on... */
}
}
#undef hostnamelen
@@ -1113,21 +1232,77 @@ in6_update_ifa(ifp, ifra, ia)
} else
RTFREE_LOCKED(rt);
- IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
- if (in6m == NULL) {
- (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
- if (error != 0) {
- nd6log((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;
+ /* XXX: again, do we really need the route? */
+ rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+ if (rt) {
+ if (memcmp(&mltaddr.sin6_addr,
+ &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+ MLTMASK_LEN)) {
+ RTFREE_LOCKED(rt);
+ rt = NULL;
}
}
+ if (!rt) {
+ error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+ (struct sockaddr *)&ia->ia_addr,
+ (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING,
+ (struct rtentry **)0);
+ if (error)
+ goto cleanup;
+ } else {
+ RTFREE_LOCKED(rt);
+ }
+
+ imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+ if (!imm) {
+ nd6log((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;
+ }
#undef MLTMASK_LEN
}
+ /*
+ * Perform DAD, if needed.
+ * XXX It may be of use, if we can administratively
+ * disable DAD.
+ */
+ if (hostIsNew && in6if_do_dad(ifp) &&
+ ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
+ (ia->ia6_flags & IN6_IFF_TENTATIVE))
+ {
+ int mindelay, maxdelay;
+
+ delay = 0;
+ if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+ /*
+ * We need to impose a delay before sending an NS
+ * for DAD. Check if we also needed a delay for the
+ * corresponding MLD message. If we did, the delay
+ * should be larger than the MLD delay (this could be
+ * relaxed a bit, but this simple logic is at least
+ * safe).
+ */
+ mindelay = 0;
+ if (in6m_sol != NULL &&
+ in6m_sol->in6m_state == MLD_REPORTPENDING) {
+ mindelay = in6m_sol->in6m_timer;
+ }
+ maxdelay = MAX_RTR_SOLICITATION_DELAY * hz;
+ if (maxdelay - mindelay == 0)
+ delay = 0;
+ else {
+ delay =
+ (arc4random() % (maxdelay - mindelay)) +
+ mindelay;
+ }
+ }
+ nd6_dad_start((struct ifaddr *)ia, delay);
+ }
+
return (error);
unlink:
@@ -1603,10 +1778,11 @@ in6_ifinit(ifp, ia, sin6, newhost)
}
struct in6_multi_mship *
-in6_joingroup(ifp, addr, errorp)
+in6_joingroup(ifp, addr, errorp, delay)
struct ifnet *ifp;
struct in6_addr *addr;
int *errorp;
+ int delay;
{
struct in6_multi_mship *imm;
@@ -1615,7 +1791,7 @@ in6_joingroup(ifp, addr, errorp)
*errorp = ENOBUFS;
return NULL;
}
- imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp);
+ imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp, delay);
if (!imm->i6mm_maddr) {
/* *errorp is alrady set */
free(imm, M_IP6MADDR);
@@ -1943,21 +2119,27 @@ in6_if_up(ifp)
{
struct ifaddr *ifa;
struct in6_ifaddr *ia;
- int dad_delay; /* delay ticks before DAD output */
-
- /*
- * special cases, like 6to4, are handled in in6_ifattach
- */
- in6_ifattach(ifp, NULL);
- dad_delay = 0;
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
- if (ia->ia6_flags & IN6_IFF_TENTATIVE)
- nd6_dad_start(ifa, &dad_delay);
+ if (ia->ia6_flags & IN6_IFF_TENTATIVE) {
+ /*
+ * The TENTATIVE flag was likely set by hand
+ * beforehand, implicitly indicating the need for DAD.
+ * We may be able to skip the random delay in this
+ * case, but we impose delays just in case.
+ */
+ nd6_dad_start(ifa,
+ arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz));
+ }
}
+
+ /*
+ * special cases, like 6to4, are handled in in6_ifattach
+ */
+ in6_ifattach(ifp, NULL);
}
int
@@ -2021,6 +2203,66 @@ in6_setmaxmtu()
in6_maxmtu = maxmtu;
}
+/*
+ * Provide the length of interface identifiers to be used for the link attached
+ * to the given interface. The length should be defined in "IPv6 over
+ * xxx-link" document. Note that address architecture might also define
+ * the length for a particular set of address prefixes, regardless of the
+ * link type. As clarified in rfc2462bis, those two definitions should be
+ * consistent, and those really are as of August 2004.
+ */
+int
+in6_if2idlen(ifp)
+ struct ifnet *ifp;
+{
+ switch (ifp->if_type) {
+ case IFT_ETHER: /* RFC2464 */
+#ifdef IFT_PROPVIRTUAL
+ case IFT_PROPVIRTUAL: /* XXX: no RFC. treat it as ether */
+#endif
+#ifdef IFT_L2VLAN
+ case IFT_L2VLAN: /* ditto */
+#endif
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211: /* ditto */
+#endif
+#ifdef IFT_MIP
+ case IFT_MIP: /* ditto */
+#endif
+ return (64);
+ case IFT_FDDI: /* RFC2467 */
+ return (64);
+ case IFT_ISO88025: /* RFC2470 (IPv6 over Token Ring) */
+ return (64);
+ case IFT_PPP: /* RFC2472 */
+ return (64);
+ case IFT_ARCNET: /* RFC2497 */
+ return (64);
+ case IFT_FRELAY: /* RFC2590 */
+ return (64);
+ case IFT_IEEE1394: /* RFC3146 */
+ return (64);
+ case IFT_GIF:
+ return (64); /* draft-ietf-v6ops-mech-v2-07 */
+ case IFT_LOOP:
+ return (64); /* XXX: is this really correct? */
+ default:
+ /*
+ * Unknown link type:
+ * It might be controversial to use the today's common constant
+ * of 64 for these cases unconditionally. For full compliance,
+ * we should return an error in this case. On the other hand,
+ * if we simply miss the standard for the link type or a new
+ * standard is defined for a new link type, the IFID length
+ * is very likely to be the common constant. As a compromise,
+ * we always use the constant, but make an explicit notice
+ * indicating the "unknown" case.
+ */
+ printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type);
+ return (64);
+ }
+}
+
void *
in6_domifattach(ifp)
struct ifnet *ifp;
OpenPOWER on IntegriCloud