[IPV6]: Make ipv6_addr_type() more generic so that we can use it for source address selection.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
971f359ddc
commit
b1cacb6820
3 changed files with 62 additions and 45 deletions
|
@ -252,12 +252,25 @@ typedef int (*inet_getfrag_t) (const void *data,
|
|||
char *,
|
||||
unsigned int, unsigned int);
|
||||
|
||||
|
||||
extern int ipv6_addr_type(const struct in6_addr *addr);
|
||||
extern int __ipv6_addr_type(const struct in6_addr *addr);
|
||||
static inline int ipv6_addr_type(const struct in6_addr *addr)
|
||||
{
|
||||
return __ipv6_addr_type(addr) & 0xffff;
|
||||
}
|
||||
|
||||
static inline int ipv6_addr_scope(const struct in6_addr *addr)
|
||||
{
|
||||
return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
|
||||
return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
|
||||
}
|
||||
|
||||
static inline int __ipv6_addr_src_scope(int type)
|
||||
{
|
||||
return (type == IPV6_ADDR_ANY ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16));
|
||||
}
|
||||
|
||||
static inline int ipv6_addr_src_scope(const struct in6_addr *addr)
|
||||
{
|
||||
return __ipv6_addr_src_scope(__ipv6_addr_type(addr));
|
||||
}
|
||||
|
||||
static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
* YOSHIFUJI Hideaki @USAGI : ARCnet support
|
||||
* YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to
|
||||
* seq_file.
|
||||
* YOSHIFUJI Hideaki @USAGI : improved source address
|
||||
* selection; consider scope,
|
||||
* status etc.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
|
@ -193,46 +196,51 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
|
|||
#endif
|
||||
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
|
||||
|
||||
int ipv6_addr_type(const struct in6_addr *addr)
|
||||
#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
|
||||
|
||||
static inline unsigned ipv6_addr_scope2type(unsigned scope)
|
||||
{
|
||||
switch(scope) {
|
||||
case IPV6_ADDR_SCOPE_NODELOCAL:
|
||||
return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
|
||||
IPV6_ADDR_LOOPBACK);
|
||||
case IPV6_ADDR_SCOPE_LINKLOCAL:
|
||||
return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
|
||||
IPV6_ADDR_LINKLOCAL);
|
||||
case IPV6_ADDR_SCOPE_SITELOCAL:
|
||||
return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
|
||||
IPV6_ADDR_SITELOCAL);
|
||||
}
|
||||
return IPV6_ADDR_SCOPE_TYPE(scope);
|
||||
}
|
||||
|
||||
int __ipv6_addr_type(const struct in6_addr *addr)
|
||||
{
|
||||
int type;
|
||||
u32 st;
|
||||
|
||||
st = addr->s6_addr32[0];
|
||||
|
||||
if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
|
||||
type = IPV6_ADDR_MULTICAST;
|
||||
|
||||
switch((st & htonl(0x00FF0000))) {
|
||||
case __constant_htonl(0x00010000):
|
||||
type |= IPV6_ADDR_LOOPBACK;
|
||||
break;
|
||||
|
||||
case __constant_htonl(0x00020000):
|
||||
type |= IPV6_ADDR_LINKLOCAL;
|
||||
break;
|
||||
|
||||
case __constant_htonl(0x00050000):
|
||||
type |= IPV6_ADDR_SITELOCAL;
|
||||
break;
|
||||
};
|
||||
return type;
|
||||
}
|
||||
|
||||
type = IPV6_ADDR_UNICAST;
|
||||
|
||||
/* Consider all addresses with the first three bits different of
|
||||
000 and 111 as finished.
|
||||
000 and 111 as unicasts.
|
||||
*/
|
||||
if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
|
||||
(st & htonl(0xE0000000)) != htonl(0xE0000000))
|
||||
return type;
|
||||
|
||||
if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
|
||||
return (IPV6_ADDR_LINKLOCAL | type);
|
||||
return (IPV6_ADDR_UNICAST |
|
||||
IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
|
||||
|
||||
if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
|
||||
/* multicast */
|
||||
/* addr-select 3.1 */
|
||||
return (IPV6_ADDR_MULTICAST |
|
||||
ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
|
||||
}
|
||||
|
||||
if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
|
||||
return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
|
||||
IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */
|
||||
if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
|
||||
return (IPV6_ADDR_SITELOCAL | type);
|
||||
return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
|
||||
IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */
|
||||
|
||||
if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
|
||||
if (addr->s6_addr32[2] == 0) {
|
||||
|
@ -240,24 +248,20 @@ int ipv6_addr_type(const struct in6_addr *addr)
|
|||
return IPV6_ADDR_ANY;
|
||||
|
||||
if (addr->s6_addr32[3] == htonl(0x00000001))
|
||||
return (IPV6_ADDR_LOOPBACK | type);
|
||||
return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
|
||||
IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */
|
||||
|
||||
return (IPV6_ADDR_COMPATv4 | type);
|
||||
return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
|
||||
IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */
|
||||
}
|
||||
|
||||
if (addr->s6_addr32[2] == htonl(0x0000ffff))
|
||||
return IPV6_ADDR_MAPPED;
|
||||
return (IPV6_ADDR_MAPPED |
|
||||
IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */
|
||||
}
|
||||
|
||||
st &= htonl(0xFF000000);
|
||||
if (st == 0)
|
||||
return IPV6_ADDR_RESERVED;
|
||||
st &= htonl(0xFE000000);
|
||||
if (st == htonl(0x02000000))
|
||||
return IPV6_ADDR_RESERVED; /* for NSAP */
|
||||
if (st == htonl(0x04000000))
|
||||
return IPV6_ADDR_RESERVED; /* for IPX */
|
||||
return type;
|
||||
return (IPV6_ADDR_RESERVED |
|
||||
IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */
|
||||
}
|
||||
|
||||
static void addrconf_del_timer(struct inet6_ifaddr *ifp)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <net/ip6_route.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
EXPORT_SYMBOL(ipv6_addr_type);
|
||||
EXPORT_SYMBOL(__ipv6_addr_type);
|
||||
EXPORT_SYMBOL(icmpv6_send);
|
||||
EXPORT_SYMBOL(icmpv6_statistics);
|
||||
EXPORT_SYMBOL(icmpv6_err_convert);
|
||||
|
|
Loading…
Reference in a new issue