net: 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:
parent
7851aecc1c
commit
93f129060d
3 changed files with 224 additions and 0 deletions
|
@ -268,6 +268,48 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
|
||||||
enum net_addr_type addr_type,
|
enum net_addr_type addr_type,
|
||||||
uint32_t vlifetime);
|
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 {
|
struct net_if_api {
|
||||||
void (*init)(struct net_if *iface);
|
void (*init)(struct net_if *iface);
|
||||||
int (*send)(struct net_if *iface, struct net_buf *buf);
|
int (*send)(struct net_if *iface, struct net_buf *buf);
|
||||||
|
|
|
@ -151,6 +151,7 @@ static inline char *net_addr_type2str(enum net_addr_type type)
|
||||||
|
|
||||||
/** What is the current state of the network address */
|
/** What is the current state of the network address */
|
||||||
enum net_addr_state {
|
enum net_addr_state {
|
||||||
|
NET_ADDR_ANY_STATE = -1,
|
||||||
NET_ADDR_TENTATIVE = 0,
|
NET_ADDR_TENTATIVE = 0,
|
||||||
NET_ADDR_PREFERRED,
|
NET_ADDR_PREFERRED,
|
||||||
NET_ADDR_DEPRECATED,
|
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;
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -189,6 +189,156 @@ struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(struct in6_addr *maddr)
|
||||||
return NULL;
|
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_addr *net_if_ipv4_addr_lookup(struct in_addr *addr)
|
||||||
{
|
{
|
||||||
struct net_if *iface;
|
struct net_if *iface;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue