summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau2023-11-07 12:22:06 +0000
committerFelix Fietkau2023-11-07 12:22:09 +0000
commit516ab774cc16d4b04b3b17a067cbf2649f1adaeb (patch)
tree2d4758a633d8d342362b41af0229bdfe0768cf0f
parent40ed7363caf2b22b6e29ed9d9948189c2bc4c8f3 (diff)
downloadnetifd-516ab774cc16d4b04b3b17a067cbf2649f1adaeb.tar.gz
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 <nbd@nbd.name>
-rw-r--r--system-linux.c49
1 files 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;
}