summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2013-01-09 00:36:06 +0000
committerae <ae@FreeBSD.org>2013-01-09 00:36:06 +0000
commit5f7fde904cfb8fa7627b565f2c1a79201a9832fb (patch)
tree364e6e385e9f309ecbb2c2fba361a94d3deda69a /sys/netinet6
parent8d1a456222c0ec267a60f2acee69d14b2c53a9a1 (diff)
downloadFreeBSD-src-5f7fde904cfb8fa7627b565f2c1a79201a9832fb.zip
FreeBSD-src-5f7fde904cfb8fa7627b565f2c1a79201a9832fb.tar.gz
The in6_setscope() function determines the scope zone id of an address
and embeds it into address. Inside the kernel we keep addresses with embedded zone id only for two scopes: link-local and interface-local. For other scopes this function is nop in most cases. To reduce an overhead of locking, first check that address is capable for embedding. Also, handle the loopback address before acquire the lock. Sponsored by: Yandex LLC MFC after: 1 week
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/scope6.c29
1 files changed, 15 insertions, 14 deletions
diff --git a/sys/netinet6/scope6.c b/sys/netinet6/scope6.c
index 060fe59..74d034e 100644
--- a/sys/netinet6/scope6.c
+++ b/sys/netinet6/scope6.c
@@ -420,33 +420,34 @@ in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
u_int32_t zoneid = 0;
struct scope6_id *sid;
- IF_AFDATA_RLOCK(ifp);
-
- sid = SID(ifp);
-
-#ifdef DIAGNOSTIC
- if (sid == NULL) { /* should not happen */
- panic("in6_setscope: scope array is NULL");
- /* NOTREACHED */
- }
-#endif
-
/*
* special case: the loopback address can only belong to a loopback
* interface.
*/
if (IN6_IS_ADDR_LOOPBACK(in6)) {
if (!(ifp->if_flags & IFF_LOOPBACK)) {
- IF_AFDATA_RUNLOCK(ifp);
return (EINVAL);
} else {
if (ret_id != NULL)
*ret_id = 0; /* there's no ambiguity */
- IF_AFDATA_RUNLOCK(ifp);
return (0);
}
}
+ if (ret_id == NULL && !IN6_IS_SCOPE_EMBED(in6))
+ return (0);
+
+ IF_AFDATA_RLOCK(ifp);
+
+ sid = SID(ifp);
+
+#ifdef DIAGNOSTIC
+ if (sid == NULL) { /* should not happen */
+ panic("in6_setscope: scope array is NULL");
+ /* NOTREACHED */
+ }
+#endif
+
scope = in6_addrscope(in6);
switch (scope) {
case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */
@@ -474,7 +475,7 @@ in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
if (ret_id != NULL)
*ret_id = zoneid;
- if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))
+ if (IN6_IS_SCOPE_EMBED(in6))
in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
return (0);
OpenPOWER on IntegriCloud