net: ipv4: Rework source address matching for LL addresses
Currently we blindly return the LL address found on the default interface or else on the first interface that has a valid LL address configured. This doesn't work well, if different interfaces have LL addresses configured with a different subnet mask. Therefore, instead of blindly selecting the address based on the first LL address encountered, use net_if_ipv4_get_best_match() function for LL addresses to find the best match for the given interface. The rework takes into account current behavior, i. e. default interface still gets the preference if there is no better candidate. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
parent
9db7f8d0a0
commit
a909b538dc
1 changed files with 23 additions and 15 deletions
|
@ -3561,8 +3561,7 @@ static uint8_t get_diff_ipv4(const struct in_addr *src,
|
|||
static inline bool is_proper_ipv4_address(struct net_if_addr *addr)
|
||||
{
|
||||
if (addr->is_used && addr->addr_state == NET_ADDR_PREFERRED &&
|
||||
addr->address.family == AF_INET &&
|
||||
!net_ipv4_is_ll_addr(&addr->address.in_addr)) {
|
||||
addr->address.family == AF_INET) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3571,7 +3570,7 @@ static inline bool is_proper_ipv4_address(struct net_if_addr *addr)
|
|||
|
||||
static struct in_addr *net_if_ipv4_get_best_match(struct net_if *iface,
|
||||
const struct in_addr *dst,
|
||||
uint8_t *best_so_far)
|
||||
uint8_t *best_so_far, bool ll)
|
||||
{
|
||||
struct net_if_ipv4 *ipv4;
|
||||
struct in_addr *src = NULL;
|
||||
|
@ -3589,6 +3588,10 @@ static struct in_addr *net_if_ipv4_get_best_match(struct net_if *iface,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (net_ipv4_is_ll_addr(&ipv4->unicast[i].ipv4.address.in_addr) != ll) {
|
||||
continue;
|
||||
}
|
||||
|
||||
len = get_diff_ipv4(dst, &ipv4->unicast[i].ipv4.address.in_addr);
|
||||
if (len >= *best_so_far) {
|
||||
*best_so_far = len;
|
||||
|
@ -3672,13 +3675,14 @@ const struct in_addr *net_if_ipv4_select_src_addr(struct net_if *dst_iface,
|
|||
/* If caller has supplied interface, then use that */
|
||||
if (dst_iface) {
|
||||
src = net_if_ipv4_get_best_match(dst_iface, dst,
|
||||
&best_match);
|
||||
&best_match, false);
|
||||
} else {
|
||||
STRUCT_SECTION_FOREACH(net_if, iface) {
|
||||
struct in_addr *addr;
|
||||
|
||||
addr = net_if_ipv4_get_best_match(iface, dst,
|
||||
&best_match);
|
||||
&best_match,
|
||||
false);
|
||||
if (addr) {
|
||||
src = addr;
|
||||
}
|
||||
|
@ -3691,20 +3695,25 @@ const struct in_addr *net_if_ipv4_select_src_addr(struct net_if *dst_iface,
|
|||
} else {
|
||||
struct in_addr *addr;
|
||||
|
||||
addr = net_if_ipv4_get_ll(net_if_get_default(), NET_ADDR_PREFERRED);
|
||||
if (addr) {
|
||||
src = addr;
|
||||
goto out;
|
||||
}
|
||||
|
||||
STRUCT_SECTION_FOREACH(net_if, iface) {
|
||||
addr = net_if_ipv4_get_ll(iface,
|
||||
NET_ADDR_PREFERRED);
|
||||
addr = net_if_ipv4_get_best_match(iface, dst,
|
||||
&best_match,
|
||||
true);
|
||||
if (addr) {
|
||||
src = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the default interface again. It will only
|
||||
* be used if it has a valid LL address, and there was
|
||||
* no better match on any other interface.
|
||||
*/
|
||||
addr = net_if_ipv4_get_best_match(net_if_get_default(),
|
||||
dst, &best_match,
|
||||
true);
|
||||
if (addr) {
|
||||
src = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3724,7 +3733,6 @@ const struct in_addr *net_if_ipv4_select_src_addr(struct net_if *dst_iface,
|
|||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return src;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue