]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: introduce netlink_message_{read,append}_hw_addr
authorTimo Rothenpieler <timo@rothenpieler.org>
Mon, 26 Oct 2020 15:22:13 +0000 (16:22 +0100)
committerTimo Rothenpieler <timo@rothenpieler.org>
Wed, 28 Oct 2020 13:44:43 +0000 (14:44 +0100)
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.

src/basic/ether-addr-util.c
src/basic/ether-addr-util.h
src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/netlink-util.h

index e875696a1a9ea26e066ecf724949460d4b0f8a8c..2af2ce02e5ec4fe8aecbf503273ac66213a08785 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <inttypes.h>
 #include <net/ethernet.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -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);
index 4e44b30be98e6fbb7f097e03002baa47d01077e6..462caded03cbdf977d0054eff46d00700dc0a7ab 100644 (file)
@@ -1,11 +1,35 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <linux/if_infiniband.h>
 #include <net/ethernet.h>
 #include <stdbool.h>
 
 #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]
 
index da4f5ba6888f79595f3bddd81064026d25ec6ba2..2ffff861b253f10c6f6e934038d3fccffcc38a2d 100644 (file)
@@ -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;
index 2768d5fdc4db6302a7e34ebeb9f37aa60bcec588..8f6c06af6e76aefc93cbee32b51a2adf02c1c5e8 100644 (file)
@@ -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);