net: yaip: IPv6 address utility funcs for network interface

Added more functions to get proper IPv6 address from
a given network interface.

Change-Id: I5aecdb35eb549a0781949134ab4821dcb8ce9e7b
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2016-05-18 11:15:41 +03:00
commit d85fa3fe2d
3 changed files with 224 additions and 0 deletions

View file

@ -268,6 +268,48 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
enum net_addr_type addr_type,
uint32_t vlifetime);
/**
* @brief Get IPv6 hop limit specified for a given interface
* @param iface Network interface
* @return Hop limit
*/
static inline uint8_t net_if_ipv6_get_hop_limit(struct net_if *iface)
{
#if defined(CONFIG_NET_IPV6)
return iface->hop_limit;
#else
return 0;
#endif
}
/**
* @brief Get a IPv6 source address that should be used when sending
* network data to destination.
* @param iface Interface that was used when packet was received.
* If the interface is not known, then NULL can be given.
* @param dst IPv6 destination address
* @return Pointer to IPv6 address to use, NULL if no IPv6 address
* could be found.
*/
struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *iface,
struct in6_addr *dst);
/**
* @brief Return IPv6 any address (all zeros, ::)
* @return IPv6 any address with all bits set to zero.
*/
struct in6_addr *net_if_ipv6_unspecified_addr(void);
/**
* @brief Get a IPv6 link local address in a given state.
* @param iface Interface to use. Must be a valid pointer to an interface.
* @param addr_state IPv6 address state (preferred, tentative, deprecated)
* @return Pointer to link local IPv6 address, NULL if no proper IPv6 address
* could be found.
*/
struct in6_addr *net_if_ipv6_get_ll(struct net_if *iface,
enum net_addr_state addr_state);
struct net_if_api {
void (*init)(struct net_if *iface);
int (*send)(struct net_if *iface, struct net_buf *buf);

View file

@ -151,6 +151,7 @@ static inline char *net_addr_type2str(enum net_addr_type type)
/** What is the current state of the network address */
enum net_addr_state {
NET_ADDR_ANY_STATE = -1,
NET_ADDR_TENTATIVE = 0,
NET_ADDR_PREFERRED,
NET_ADDR_DEPRECATED,
@ -235,6 +236,37 @@ static inline bool net_is_my_ipv4_addr(struct in_addr *addr)
return net_if_ipv4_addr_lookup(addr) != NULL;
}
/** @def net_ipaddr_copy
* @brief Copy an IPv4 or IPv6 address
*
* @param dest Destination IP address.
* @param src Source IP address.
*
* @return Destination address.
*/
#define net_ipaddr_copy(dest, src) ((*dest) = (*src))
/** @brief Check if the given IPv6 address is a link local address.
*
* @return True if it is, false otherwise.
*/
static inline bool net_is_ipv6_ll_addr(struct in6_addr *addr)
{
return ((addr->s6_addr[0]) == 0xFE) &&
((addr->s6_addr[1]) == 0x80);
}
struct in6_addr *net_if_ipv6_unspecified_addr(void);
/** @brief Return pointer to any (all bits zeros) IPv6 address.
*
* @return Any IPv6 address.
*/
static inline struct in6_addr *net_ipv6_unspecified_address(void)
{
return net_if_ipv6_unspecified_addr();
}
#ifdef __cplusplus
}
#endif

View file

@ -189,6 +189,156 @@ struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(struct in6_addr *maddr)
return NULL;
}
struct in6_addr *net_if_ipv6_unspecified_addr(void)
{
#if defined(CONFIG_NET_IPV6)
static struct in6_addr addr = IN6ADDR_ANY_INIT;
return &addr;
#else
return NULL;
#endif
}
struct in6_addr *net_if_ipv6_get_ll(struct net_if *iface,
enum net_addr_state addr_state)
{
int i;
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
if (!iface->ipv6.unicast[i].is_used ||
(addr_state != NET_ADDR_ANY_STATE &&
iface->ipv6.unicast[i].addr_state != addr_state) ||
iface->ipv6.unicast[i].address.family != AF_INET6) {
continue;
}
if (net_is_ipv6_ll_addr(&iface->ipv6.unicast[i].address.in6_addr)) {
return &iface->ipv6.unicast[i].address.in6_addr;
}
}
return NULL;
}
static inline uint8_t get_length(struct in6_addr *src, struct in6_addr *dst)
{
uint8_t j, k, xor;
uint8_t len = 0;
for (j = 0; j < 16; j++) {
if (src->s6_addr[j] == dst->s6_addr[j]) {
len += 8;
} else {
xor = src->s6_addr[j] ^ dst->s6_addr[j];
for (k = 0; k < 8; k++) {
if (!(xor & 0x80)) {
len++;
xor <<= 1;
} else {
break;
}
}
break;
}
}
return len;
}
static inline bool is_proper_ipv6_address(struct net_if_addr *addr)
{
if (addr->is_used && addr->addr_state == NET_ADDR_PREFERRED &&
addr->address.family == AF_INET6 &&
!net_is_ipv6_ll_addr(&addr->address.in6_addr)) {
return true;
}
return false;
}
static inline struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface,
struct in6_addr *dst,
uint8_t *best_so_far)
{
#if defined(CONFIG_NET_IPV6)
struct in6_addr *src = NULL;
uint8_t i, len;
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
if (!is_proper_ipv6_address(&iface->ipv6.unicast[i])) {
continue;
}
len = get_length(dst,
&iface->ipv6.unicast[i].address.in6_addr);
if (len >= *best_so_far) {
*best_so_far = len;
src = &iface->ipv6.unicast[i].address.in6_addr;
}
}
return src;
#else
return NULL;
#endif
}
struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface,
struct in6_addr *dst)
{
#if defined(CONFIG_NET_IPV6)
struct in6_addr *src = NULL;
uint8_t best_match = 0;
struct net_if *iface;
if (!net_is_ipv6_ll_addr(dst) && !net_is_ipv6_addr_mcast(dst)) {
for (iface = __net_if_start;
!dst_iface && iface != __net_if_end;
iface++) {
struct in6_addr *addr;
addr = net_if_ipv6_get_best_match(iface, dst,
&best_match);
if (addr) {
src = addr;
}
}
/* If caller has supplied interface, then use that */
if (dst_iface) {
src = net_if_ipv6_get_best_match(dst_iface, dst,
&best_match);
}
} else {
for (iface = __net_if_start;
!dst_iface && iface != __net_if_end;
iface++) {
struct in6_addr *addr;
addr = net_if_ipv6_get_ll(iface, NET_ADDR_PREFERRED);
if (addr) {
src = addr;
break;
}
}
if (dst_iface) {
src = net_if_ipv6_get_ll(dst_iface, NET_ADDR_PREFERRED);
}
}
if (!src) {
return net_if_ipv6_unspecified_addr();
}
return src;
#else
return NULL;
#endif
}
struct net_if_addr *net_if_ipv4_addr_lookup(struct in_addr *addr)
{
struct net_if *iface;