From owner-svn-src-user@FreeBSD.ORG Tue Oct 15 09:12:19 2013 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 92563606; Tue, 15 Oct 2013 09:12:19 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 8037E2F08; Tue, 15 Oct 2013 09:12:19 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r9F9CJw4057367; Tue, 15 Oct 2013 09:12:19 GMT (envelope-from ae@svn.freebsd.org) Received: (from ae@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r9F9CIKA057363; Tue, 15 Oct 2013 09:12:18 GMT (envelope-from ae@svn.freebsd.org) Message-Id: <201310150912.r9F9CIKA057363@svn.freebsd.org> From: "Andrey V. Elsukov" Date: Tue, 15 Oct 2013 09:12:18 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r256509 - user/ae/inet6/sys/netinet6 X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Oct 2013 09:12:19 -0000 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 +#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_ */