Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 15 Oct 2013 09:12:18 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r256509 - user/ae/inet6/sys/netinet6
Message-ID:  <201310150912.r9F9CIKA057363@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Tue Oct 15 09:12:18 2013
New Revision: 256509
URL: http://svnweb.freebsd.org/changeset/base/256509

Log:
  * Replace hardcoded number of scopes count with macro.
  * Simplify in6_addrscope() function.
  * Add several new scope related functions:
   in6_getlinkifnet() returns pointer to struct ifnet, corresponding
    to given link-local scope zone id.
   in6_getscopezone() returns zone id for given scope.
   sa6_checkzone() checks given sockaddr_in6 structure for correctness
    of sin6_scope_id field.

Modified:
  user/ae/inet6/sys/netinet6/in6.h
  user/ae/inet6/sys/netinet6/scope6.c
  user/ae/inet6/sys/netinet6/scope6_var.h

Modified: user/ae/inet6/sys/netinet6/in6.h
==============================================================================
--- user/ae/inet6/sys/netinet6/in6.h	Tue Oct 15 08:20:20 2013	(r256508)
+++ user/ae/inet6/sys/netinet6/in6.h	Tue Oct 15 09:12:18 2013	(r256509)
@@ -638,7 +638,7 @@ int	in6_cksum_pseudo(struct ip6_hdr *, u
 int	in6_cksum(struct mbuf *, u_int8_t, u_int32_t, u_int32_t);
 int	in6_localaddr(struct in6_addr *);
 int	in6_localip(struct in6_addr *);
-int	in6_addrscope(struct in6_addr *);
+int	in6_addrscope(const struct in6_addr *);
 struct	in6_ifaddr *in6_ifawithifp(struct ifnet *, struct in6_addr *);
 extern void in6_if_up(struct ifnet *);
 struct sockaddr;

Modified: user/ae/inet6/sys/netinet6/scope6.c
==============================================================================
--- user/ae/inet6/sys/netinet6/scope6.c	Tue Oct 15 08:20:20 2013	(r256508)
+++ user/ae/inet6/sys/netinet6/scope6.c	Tue Oct 15 09:12:18 2013	(r256509)
@@ -207,62 +207,15 @@ scope6_get(struct ifnet *ifp, struct sco
  * Get a scope of the address. Node-local, link-local, site-local or global.
  */
 int
-in6_addrscope(struct in6_addr *addr)
+in6_addrscope(const struct in6_addr *addr)
 {
-	int scope;
-
-	if (addr->s6_addr[0] == 0xfe) {
-		scope = addr->s6_addr[1] & 0xc0;
-
-		switch (scope) {
-		case 0x80:
-			return IPV6_ADDR_SCOPE_LINKLOCAL;
-			break;
-		case 0xc0:
-			return IPV6_ADDR_SCOPE_SITELOCAL;
-			break;
-		default:
-			return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
-			break;
-		}
-	}
-
-
-	if (addr->s6_addr[0] == 0xff) {
-		scope = addr->s6_addr[1] & 0x0f;
-
-		/*
-		 * due to other scope such as reserved,
-		 * return scope doesn't work.
-		 */
-		switch (scope) {
-		case IPV6_ADDR_SCOPE_INTFACELOCAL:
-			return IPV6_ADDR_SCOPE_INTFACELOCAL;
-			break;
-		case IPV6_ADDR_SCOPE_LINKLOCAL:
-			return IPV6_ADDR_SCOPE_LINKLOCAL;
-			break;
-		case IPV6_ADDR_SCOPE_SITELOCAL:
-			return IPV6_ADDR_SCOPE_SITELOCAL;
-			break;
-		default:
-			return IPV6_ADDR_SCOPE_GLOBAL;
-			break;
-		}
-	}
-
-	/*
-	 * Regard loopback and unspecified addresses as global, since
-	 * they have no ambiguity.
-	 */
-	if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
-		if (addr->s6_addr[15] == 1) /* loopback */
-			return IPV6_ADDR_SCOPE_LINKLOCAL;
-		if (addr->s6_addr[15] == 0) /* unspecified */
-			return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */
-	}
 
-	return IPV6_ADDR_SCOPE_GLOBAL;
+	if (IN6_IS_ADDR_MULTICAST(addr))
+		return (IPV6_ADDR_MC_SCOPE(addr));
+	if (IN6_IS_ADDR_LINKLOCAL(addr) ||
+	    IN6_IS_ADDR_LOOPBACK(addr))
+		return (IPV6_ADDR_SCOPE_LINKLOCAL);
+	return (IPV6_ADDR_SCOPE_GLOBAL);
 }
 
 /*
@@ -477,3 +430,72 @@ in6_getscope(struct in6_addr *in6)
 
 	return (0);
 }
+
+/*
+ * Return pointer to ifnet structure, corresponding to the
+ * link-local scope zone id.
+ */
+struct ifnet*
+in6_getlinkifnet(uint32_t zoneid)
+{
+
+	return (ifnet_byindex((u_short)zoneid));
+}
+
+/*
+ * Return zone id for the specified scope.
+ * XXX: currently we don't take any locks.
+ */
+uint32_t
+in6_getscopezone(const struct ifnet *ifp, int scope)
+{
+
+	if (scope == IPV6_ADDR_SCOPE_INTFACELOCAL ||
+	    scope == IPV6_ADDR_SCOPE_LINKLOCAL)
+		return (ifp->if_index);
+	if (scope >= 0 && scope < IPV6_ADDR_SCOPES_COUNT)
+		return (SID(ifp)->s6id_list[scope]);
+	return (0);
+}
+
+/*
+ * This function is for checking sockaddr_in6 structure passed
+ * from the application level (usually).
+ *
+ * sin6_scope_id should be set for link-local unicast addresses and for
+ * any multicast addresses.
+ * If it is zero, then look into default zone ids. If default zone id is
+ * not set or disabled, then return error.
+ */
+int
+sa6_checkzone(struct sockaddr_in6 *sa6)
+{
+	int scope;
+
+	scope = in6_addrscope(&sa6->sin6_addr);
+	if (!IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
+		if (scope == IPV6_ADDR_SCOPE_GLOBAL)
+			return (sa6->sin6_scope_id ? EINVAL: 0);
+		/*
+		 * Since ::1 address always configured on the lo0, we can
+		 * automatically set its zone id, when it is not specified.
+		 * Return error, when specified zone id doesn't match with
+		 * actual value.
+		 */
+		if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) {
+			if (sa6->sin6_scope_id == 0)
+				sa6->sin6_scope_id = in6_getscopezone(
+				    V_loif, IPV6_ADDR_SCOPE_LINKLOCAL);
+			else if (sa6->sin6_scope_id != in6_getscopezone(
+			    V_loif, IPV6_ADDR_SCOPE_LINKLOCAL))
+				return (EADDRNOTAVAIL);
+		}
+	}
+	/* Any multicast and link-local addresses. */
+	if (sa6->sin6_scope_id != 0)
+		return (0);
+	if (V_ip6_use_defzone != 0)
+		sa6->sin6_scope_id = V_sid_default.s6id_list[scope];
+	/* Return error if we can't determine zone id */
+	return (sa6->sin6_scope_id ? 0: EADDRNOTAVAIL);
+}

Modified: user/ae/inet6/sys/netinet6/scope6_var.h
==============================================================================
--- user/ae/inet6/sys/netinet6/scope6_var.h	Tue Oct 15 08:20:20 2013	(r256508)
+++ user/ae/inet6/sys/netinet6/scope6_var.h	Tue Oct 15 09:12:18 2013	(r256509)
@@ -35,13 +35,14 @@
 
 #ifdef _KERNEL
 #include <net/vnet.h>
+#define	IPV6_ADDR_SCOPES_COUNT	16
 
 struct scope6_id {
 	/*
 	 * 16 is correspondent to 4bit multicast scope field.
 	 * i.e. from node-local to global with some reserved/unassigned types.
 	 */
-	u_int32_t s6id_list[16];
+	uint32_t s6id_list[IPV6_ADDR_SCOPES_COUNT];
 };
 
 VNET_DECLARE(int, deembed_scopeid);
@@ -57,9 +58,12 @@ int	scope6_get_default(struct scope6_id 
 u_int32_t scope6_addr2default(struct in6_addr *);
 int	sa6_embedscope(struct sockaddr_in6 *, int);
 int	sa6_recoverscope(struct sockaddr_in6 *);
+int	sa6_checkzone(struct sockaddr_in6 *);
 int	in6_setscope(struct in6_addr *, struct ifnet *, u_int32_t *);
 int	in6_clearscope(struct in6_addr *);
 uint16_t in6_getscope(struct in6_addr *);
+uint32_t in6_getscopezone(const struct ifnet *, int);
+struct ifnet* in6_getlinkifnet(uint32_t);
 #endif /* _KERNEL */
 
 #endif /* _NETINET6_SCOPE6_VAR_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310150912.r9F9CIKA057363>