diff mbox series

[RFC] udev: Add module for checking interface renaming actions

Message ID 20240126231339.10388-1-marcel@holtmann.org (mailing list archive)
State New
Headers show
Series [RFC] udev: Add module for checking interface renaming actions | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
prestwoj/iwd-alpine-ci-fetch success Fetch PR
prestwoj/iwd-ci-gitlint success GitLint
prestwoj/iwd-ci-fetch success Fetch PR
prestwoj/iwd-ci-incremental_build success Incremental build not run PASS
prestwoj/iwd-alpine-ci-makedistcheck success Make Distcheck
prestwoj/iwd-alpine-ci-incremental_build success Incremental build not run PASS
prestwoj/iwd-ci-build success Build - Configure
prestwoj/iwd-alpine-ci-build success Build - Configure
prestwoj/iwd-alpine-ci-makecheckvalgrind success Make Check w/Valgrind
prestwoj/iwd-alpine-ci-makecheck success Make Check
prestwoj/iwd-ci-makecheckvalgrind success Make Check w/Valgrind
prestwoj/iwd-ci-clang success clang PASS
prestwoj/iwd-ci-makecheck success Make Check
prestwoj/iwd-ci-makedistcheck success Make Distcheck
prestwoj/iwd-ci-testrunner success test-runner PASS

Commit Message

Marcel Holtmann Jan. 26, 2024, 11:13 p.m. UTC
---
 Makefile.am |   1 +
 src/udev.c  | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 286 insertions(+)
 create mode 100644 src/udev.c

Comments

James Prestwood Jan. 30, 2024, 12:38 p.m. UTC | #1
Hi Marcel,

On 1/26/24 3:13 PM, Marcel Holtmann wrote:
> ---
>   Makefile.am |   1 +
>   src/udev.c  | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 286 insertions(+)
>   create mode 100644 src/udev.c
>
Just curious what this is for. Are we trying to avoid needing to install 
the link file to disable udev renaming? And instead allow renaming but 
pick up the changes internally?

Thanks,

James
Marcel Holtmann Jan. 30, 2024, 2:54 p.m. UTC | #2
Hi James,

>> ---
>>  Makefile.am |   1 +
>>  src/udev.c  | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 286 insertions(+)
>>  create mode 100644 src/udev.c
>> 
> Just curious what this is for. Are we trying to avoid needing to install the link file to disable udev renaming? And instead allow renaming but pick up the changes internally?

this is meant as sample what it takes to wait for udev renaming. When you receive that event above, then you know for sure that udev is done with renaming and we can IFF_UP the hardware.

I do need to check this on big endian and if we have to adjust the hash value for “net”.

Regards

Marcel
diff mbox series

Patch

diff --git a/Makefile.am b/Makefile.am
index 5ed6ab37164b..0a875dcef1a7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -265,6 +265,7 @@  src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
 					src/dpp-util.h src/dpp-util.c \
 					src/json.h src/json.c \
 					src/dpp.c \
+					src/udev.c \
 					$(eap_sources) \
 					$(builtin_sources)
 
diff --git a/src/udev.c b/src/udev.c
new file mode 100644
index 000000000000..8baf47246be7
--- /dev/null
+++ b/src/udev.c
@@ -0,0 +1,285 @@ 
+/*
+ *
+ *  Wireless daemon for Linux
+ *
+ *  Copyright (C) 2024  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/filter.h>
+#include <ell/ell.h>
+
+#include "src/module.h"
+
+static void receive_props(const void *buf, uint32_t len)
+{
+	const char *action = NULL;
+	const char *interface = NULL;
+	const char *ifindex = NULL;
+
+	while (len > 0) {
+		const char *s = buf;
+		size_t l = strlen(s);
+		const char *t;
+
+		if (l < 2)
+			break;
+
+		t = strchr(s, '=');
+		if (t) {
+			size_t p = t - s;
+
+			if (!strncmp(s, "ACTION", p))
+				action = t + 1;
+			else if (!strncmp(s, "INTERFACE", p))
+				interface = t + 1;
+			else if (!strncmp(s, "IFINDEX", p))
+				ifindex = t + 1;
+		}
+
+		buf += l + 1;
+		len -= l + 1;
+	}
+
+	if (action && !strcmp(action, "add"))
+		l_info("udev interface=%s ifindex=%s", interface, ifindex);
+}
+
+static struct l_io *udev_io;
+
+static int create_socket(uint32_t *pid)
+{
+	struct sockaddr_nl addr;
+	socklen_t addrlen = sizeof(addr);
+	int fd, pktinfo = 1;
+
+	fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
+						NETLINK_KOBJECT_UEVENT);
+	if (fd < 0)
+		return -1;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.nl_family = AF_NETLINK;
+
+	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		close(fd);
+		return -1;
+	}
+
+	if (getsockname(fd, (struct sockaddr *) &addr, &addrlen) < 0) {
+		close(fd);
+		return -1;
+	}
+
+	if (setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO,
+					&pktinfo, sizeof(pktinfo)) < 0) {
+		close(fd);
+		return -1;
+	}
+
+	if (pid)
+		*pid = addr.nl_pid;
+
+	return fd;
+}
+
+static struct sock_filter subsys_filter[] = {
+	{ 0x20,  0,  0, 0x00000008 },	/* ldw #magic	*/
+	{ 0x15,  0,  3, 0xfeedcafe },	/* jne #feedcafe, drop	*/
+	{ 0x20,  0,  0, 0x00000018 },	/* ldw #subsys_hash	*/
+	{ 0x15,  0,  1, 0xa74d3cc8 },	/* jne #net, drop	*/
+	{ 0x06,  0,  0, 0xffffffff },	/* keep: ret #-1	*/
+	{ 0x06,  0,  0, 0000000000 },	/* drop: ret #0		*/
+};
+
+static const struct sock_fprog subsys_fprog = { .len = 6,
+						.filter = subsys_filter };
+
+static bool attach_filter(struct l_io *io)
+{
+	int fd;
+
+	fd = l_io_get_fd(io);
+	if (fd < 0)
+		return false;
+
+	if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER,
+				&subsys_fprog, sizeof(subsys_fprog)) < 0)
+		return false;
+
+	return true;
+}
+
+static bool add_membership(struct l_io *io, uint32_t group)
+{
+	int fd, value = group;
+
+	fd = l_io_get_fd(io);
+	if (fd < 0)
+		return false;
+
+	if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+						&value, sizeof(value)) < 0)
+		return false;
+
+	return true;
+}
+
+static bool drop_membership(struct l_io *io, uint32_t group)
+{
+	int fd, value = group;
+
+	fd = l_io_get_fd(io);
+	if (fd < 0)
+		return false;
+
+	if (setsockopt(fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
+						&value, sizeof(value)) < 0)
+		return false;
+
+	return true;
+}
+
+static const uint8_t LIBUDEV_PREFIX[8] = { "libudev" };
+static uint32_t LIBUDEV_MAGIC = 0xfeedcafe;
+
+struct udev_hdr {
+	char prefix[8];
+	uint32_t magic;
+	uint32_t hdr_size;
+	uint32_t props_off;
+	uint32_t props_len;
+	uint32_t flt_subsys_hash;
+	uint32_t flt_devtype_hash;
+	uint32_t flt_tag_bloom_hi;
+	uint32_t flt_tag_bloom_lo;
+};
+
+static void receive_msg(const void *buf, uint32_t len)
+{
+	const struct udev_hdr *hdr = buf;
+
+	if (len < sizeof(struct udev_hdr))
+		return;
+
+	if (memcmp(hdr->prefix, LIBUDEV_PREFIX, 8))
+		return;
+
+	if (L_BE32_TO_CPU(hdr->magic) != LIBUDEV_MAGIC)
+		return;
+
+	if (hdr->hdr_size > len)
+		return;
+
+	if (hdr->props_off + hdr->props_len != len)
+		return;
+
+	receive_props(buf + hdr->props_off, hdr->props_len);
+}
+
+enum {
+	GROUP_NONE,
+	GROUP_KERNEL,
+	GROUP_UDEV,
+};
+
+static bool can_read_data(struct l_io *io, void *user_data)
+{
+	struct cmsghdr *cmsg;
+	struct msghdr msg;
+	struct iovec iov;
+	unsigned char buffer[4096];
+	unsigned char control[32];
+	uint32_t group = GROUP_NONE;
+	ssize_t len;
+	int fd;
+
+	memset(buffer, 0, sizeof(buffer));
+	memset(control, 0, sizeof(control));
+
+	fd = l_io_get_fd(io);
+
+	iov.iov_base = buffer;
+	iov.iov_len = sizeof(buffer);
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = control;
+	msg.msg_controllen = sizeof(control);
+
+	len = recvmsg(fd, &msg, 0);
+	if (len < 0)
+		return false;
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+					cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		struct nl_pktinfo *pktinfo;
+
+		if (cmsg->cmsg_level != SOL_NETLINK)
+			continue;
+
+		if (cmsg->cmsg_type != NETLINK_PKTINFO)
+			continue;
+
+		pktinfo = (void *) CMSG_DATA(cmsg);
+		group = pktinfo->group;
+	}
+
+	if (group == GROUP_UDEV)
+		receive_msg(buffer, len);
+
+	return true;
+}
+
+static int udev_init(void)
+{
+	int fd;
+
+	l_debug("");
+
+	fd = create_socket(NULL);
+	if (fd < 0)
+		return -EIO;
+
+	udev_io = l_io_new(fd);
+	l_io_set_close_on_destroy(udev_io, true);
+	l_io_set_read_handler(udev_io, can_read_data, NULL, NULL);
+	attach_filter(udev_io);
+	add_membership(udev_io, GROUP_UDEV);
+
+	return 0;
+}
+
+static void udev_exit(void)
+{
+	l_debug("");
+
+	drop_membership(udev_io, GROUP_UDEV);
+	l_io_destroy(udev_io);
+}
+
+IWD_MODULE(udev, udev_init, udev_exit);
+IWD_MODULE_DEPENDS(udev, netdev);