From: Timo Rothenpieler Date: Mon, 26 Oct 2020 15:22:13 +0000 (+0100) Subject: sd-netlink: introduce netlink_message_{read,append}_hw_addr X-Git-Tag: v247-rc2~40^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4fc8a29a7e06debb65f4e2651a03804beb41f781;p=thirdparty%2Fsystemd.git sd-netlink: introduce netlink_message_{read,append}_hw_addr Hardware addresses come in various shapes and sizes, these new functions and accomapying data structures account for that instead of hard-coding a hardware address to the 6 bytes of an ethernet MAC. --- diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index e875696a1a9..2af2ce02e5e 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include +#include #include #include #include @@ -9,6 +10,20 @@ #include "macro.h" #include "string-util.h" +char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) { + assert(addr); + assert(buffer); + assert(addr->length <= HW_ADDR_MAX_SIZE); + + for (size_t i = 0; i < addr->length; i++) { + sprintf(&buffer[3*i], "%02"PRIx8, addr->addr.bytes[i]); + if (i < addr->length - 1) + buffer[3*i + 2] = ':'; + } + + return buffer; +} + char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { assert(addr); assert(buffer); diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 4e44b30be98..462caded03c 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -1,11 +1,35 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#include #include #include #include "hash-funcs.h" +/* This is MAX_ADDR_LEN as defined in linux/netdevice.h, but net/if_arp.h + * defines a macro of the same name with a much lower size. */ +#define HW_ADDR_MAX_SIZE 32 + +union hw_addr_union { + struct ether_addr ether; + uint8_t infiniband[INFINIBAND_ALEN]; + uint8_t bytes[HW_ADDR_MAX_SIZE]; +}; + +typedef struct hw_addr_data { + union hw_addr_union addr; + size_t length; +} hw_addr_data; + +#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE) +char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]); + +/* Use only as function argument, never stand-alone! */ +#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){}) + +#define HW_ADDR_NULL ((const hw_addr_data){}) + #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X" #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index da4f5ba6888..2ffff861b25 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -495,6 +495,25 @@ int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short t return 0; } +int netlink_message_append_hw_addr(sd_netlink_message *m, unsigned short type, const hw_addr_data *data) { + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(data, -EINVAL); + assert_return(data->length > 0, -EINVAL); + + r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR); + if (r < 0) + return r; + + r = add_rtattr(m, type, data->addr.bytes, data->length); + if (r < 0) + return r; + + return 0; +} + int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) { int r; @@ -864,6 +883,30 @@ int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short typ return 0; } +int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, hw_addr_data *data) { + int r; + void *attr_data; + + assert_return(m, -EINVAL); + + r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR); + if (r < 0) + return r; + + r = netlink_message_read_internal(m, type, &attr_data, NULL); + if (r < 0) + return r; + else if ((size_t) r > sizeof(union hw_addr_union)) + return -EIO; + + if (data) { + memcpy(data->addr.bytes, attr_data, r); + data->length = r; + } + + return 0; +} + int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) { int r; void *attr_data; diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index 2768d5fdc4d..8f6c06af6e7 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -5,6 +5,7 @@ #include "sd-netlink.h" +#include "ether-addr-util.h" #include "in-addr-util.h" #include "ordered-set.h" #include "socket-util.h" @@ -100,9 +101,11 @@ int rtnl_log_create_error(int r); userdata, description); \ }) +int netlink_message_append_hw_addr(sd_netlink_message *m, unsigned short type, const hw_addr_data *data); int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data); int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data); +int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, hw_addr_data *data); int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short type, int family, union in_addr_union *data); void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length);