diff options
| author | Felix Fietkau | 2023-11-07 12:22:06 +0000 |
|---|---|---|
| committer | Felix Fietkau | 2023-11-07 12:22:09 +0000 |
| commit | 516ab774cc16d4b04b3b17a067cbf2649f1adaeb (patch) | |
| tree | 2d4758a633d8d342362b41af0229bdfe0768cf0f | |
| parent | 40ed7363caf2b22b6e29ed9d9948189c2bc4c8f3 (diff) | |
| download | netifd-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.c | 49 |
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; } |