From 516ab774cc16d4b04b3b17a067cbf2649f1adaeb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 7 Nov 2023 13:22:06 +0100 Subject: [PATCH] system-linux: fix race condition on bringing up wireless devices When wireless devices are added via hotplug before their state is set to up, adding routes to the device can fail in the kernel. Since the up state is managed externally, use it as input for netifd's device present state, so that they are only brought up when ready. Signed-off-by: Felix Fietkau --- system-linux.c | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/system-linux.c b/system-linux.c index e437377..bb23404 100644 --- a/system-linux.c +++ b/system-linux.c @@ -692,34 +692,44 @@ static int system_get_arp_accept(struct device *dev, char *buf, const size_t buf dev->ifname, buf, buf_sz); } +#ifndef IFF_LOWER_UP +#define IFF_LOWER_UP 0x10000 +#endif + +static void +system_device_update_state(struct device *dev, unsigned int flags, unsigned int ifindex) +{ + if (dev->type == &simple_device_type) { + bool present = ifindex > 0; + + if (dev->external) + present = present && (flags & IFF_UP); + + device_set_present(dev, present); + } + device_set_link(dev, flags & IFF_LOWER_UP ? true : false); +} + /* Evaluate netlink messages */ static int cb_rtnl_event(struct nl_msg *msg, void *arg) { struct nlmsghdr *nh = nlmsg_hdr(msg); + struct ifinfomsg *ifi = NLMSG_DATA(nh); struct nlattr *nla[__IFLA_MAX]; - int link_state = 0; - char buf[10]; + struct device *dev; if (nh->nlmsg_type != RTM_NEWLINK) - goto out; + return 0; nlmsg_parse(nh, sizeof(struct ifinfomsg), nla, __IFLA_MAX - 1, NULL); if (!nla[IFLA_IFNAME]) - goto out; + return 0; - struct device *dev = device_find(nla_data(nla[IFLA_IFNAME])); + dev = device_find(nla_data(nla[IFLA_IFNAME])); if (!dev) - goto out; - - if (!system_get_dev_sysfs("carrier", dev->ifname, buf, sizeof(buf))) - link_state = strtoul(buf, NULL, 0); - - if (dev->type == &simple_device_type) - device_set_present(dev, true); - - device_set_link(dev, link_state ? true : false); + return 0; -out: + system_device_update_state(dev, ifi->ifi_flags, ifi->ifi_index); return 0; } @@ -2092,10 +2102,6 @@ struct if_check_data { int ret; }; -#ifndef IFF_LOWER_UP -#define IFF_LOWER_UP 0x10000 -#endif - static int cb_if_check_valid(struct nl_msg *msg, void *arg) { struct nlmsghdr *nh = nlmsg_hdr(msg); @@ -2105,10 +2111,7 @@ static int cb_if_check_valid(struct nl_msg *msg, void *arg) if (nh->nlmsg_type != RTM_NEWLINK) return NL_SKIP; - if (chk->dev->type == &simple_device_type) - device_set_present(chk->dev, ifi->ifi_index > 0 ? true : false); - device_set_link(chk->dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false); - + system_device_update_state(chk->dev, ifi->ifi_flags, ifi->ifi_index); return NL_OK; } -- 2.30.2