svn commit: r256509 - user/ae/inet6/sys/netinet6
Andrey V. Elsukov
ae at FreeBSD.org
Tue Oct 15 09:12:19 UTC 2013
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_ */
More information about the svn-src-user
mailing list