ether-addr-util: introduce hw_addr_is_valid()

Take this from udev, and adapt it to make it re-usable elsewhere.
This commit is contained in:
Nick Rosbrook
2026-03-30 10:48:54 -04:00
parent 566a4f3437
commit caeec0de6d
3 changed files with 27 additions and 22 deletions
+24
View File
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <stdio.h>
#include "ether-addr-util.h"
@@ -68,6 +69,29 @@ bool hw_addr_is_null(const struct hw_addr_data *addr) {
return addr->length == 0 || memeqzero(addr->bytes, addr->length);
}
bool hw_addr_is_valid(const struct hw_addr_data *addr, uint16_t iftype) {
assert(addr);
switch (iftype) {
case ARPHRD_ETHER:
/* Refuse all zero and all 0xFF. */
if (addr->length != ETH_ALEN)
return false;
return !ether_addr_is_null(&addr->ether) && !ether_addr_is_broadcast(&addr->ether);
case ARPHRD_INFINIBAND:
/* The last 8 bytes cannot be zero. */
if (addr->length != INFINIBAND_ALEN)
return false;
return !memeqzero(addr->bytes + INFINIBAND_ALEN - 8, 8);
default:
return false;
}
}
DEFINE_HASH_OPS(hw_addr_hash_ops, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare);
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(hw_addr_hash_ops_free, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare, free);
+1
View File
@@ -57,6 +57,7 @@ static inline bool hw_addr_equal(const struct hw_addr_data *a, const struct hw_a
return hw_addr_compare(a, b) == 0;
}
bool hw_addr_is_null(const struct hw_addr_data *addr) _pure_;
bool hw_addr_is_valid(const struct hw_addr_data *addr, uint16_t iftype);
extern const struct hash_ops hw_addr_hash_ops;
extern const struct hash_ops hw_addr_hash_ops_free;
+2 -22
View File
@@ -558,26 +558,6 @@ static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) {
return 0;
}
static bool hw_addr_is_valid(Link *link, const struct hw_addr_data *hw_addr) {
assert(link);
assert(hw_addr);
switch (link->iftype) {
case ARPHRD_ETHER:
/* Refuse all zero and all 0xFF. */
assert(hw_addr->length == ETH_ALEN);
return !ether_addr_is_null(&hw_addr->ether) && !ether_addr_is_broadcast(&hw_addr->ether);
case ARPHRD_INFINIBAND:
/* The last 8 bytes cannot be zero. */
assert(hw_addr->length == INFINIBAND_ALEN);
return !memeqzero(hw_addr->bytes + INFINIBAND_ALEN - 8, 8);
default:
assert_not_reached();
}
}
static int link_generate_new_hw_addr(Link *link, struct hw_addr_data *ret) {
struct hw_addr_data hw_addr = HW_ADDR_NULL;
bool is_static = false;
@@ -647,7 +627,7 @@ static int link_generate_new_hw_addr(Link *link, struct hw_addr_data *ret) {
* systems booting up at the very same time. */
for (;;) {
random_bytes(p, len);
if (hw_addr_is_valid(link, &hw_addr))
if (hw_addr_is_valid(&hw_addr, link->iftype))
break;
}
@@ -662,7 +642,7 @@ static int link_generate_new_hw_addr(Link *link, struct hw_addr_data *ret) {
assert(len <= sizeof(result));
memcpy(p, &result, len);
if (!hw_addr_is_valid(link, &hw_addr))
if (!hw_addr_is_valid(&hw_addr, link->iftype))
return log_link_warning_errno(link, SYNTHETIC_ERRNO(EINVAL),
"Could not generate valid persistent MAC address.");
}