Files
wlan-ap/patches/0078-netifd-add-various-backports.patch
John Crispin 8ecd0c36dd netifd: various backports from HEAD branch
Signed-off-by: John Crispin <john@phrozen.org>
2024-11-07 17:43:44 +01:00

503 lines
15 KiB
Diff

From d5484e69a2476ff3bea5d402d06ed3c68d2ef24d Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Wed, 6 Nov 2024 12:28:41 +0100
Subject: [PATCH] netifd: add various backports
Signed-off-by: John Crispin <john@phrozen.org>
---
.../netifd/patches/100-backport_fixes.patch | 482 ++++++++++++++++++
1 file changed, 482 insertions(+)
create mode 100644 package/network/config/netifd/patches/100-backport_fixes.patch
diff --git a/package/network/config/netifd/patches/100-backport_fixes.patch b/package/network/config/netifd/patches/100-backport_fixes.patch
new file mode 100644
index 0000000000..0442beb053
--- /dev/null
+++ b/package/network/config/netifd/patches/100-backport_fixes.patch
@@ -0,0 +1,482 @@
+--- a/device.c
++++ b/device.c
+@@ -166,12 +166,19 @@ static int set_device_state(struct devic
+ dev->orig_settings.flags &= dev->settings.flags;
+ system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
+
+- system_if_up(dev);
++ if (!dev->external)
++ system_if_up(dev);
+
+ system_if_apply_settings_after_up(dev, &dev->settings);
+ } else {
+- system_if_down(dev);
++ if (!dev->external)
++ system_if_down(dev);
+ system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags);
++
++ /* Restore any settings present in UCI which may have
++ * failed to apply so that they will be re-attempted
++ * the next time the device is brought up */
++ dev->settings.flags |= dev->settings.valid_flags;
+ }
+
+ return 0;
+@@ -571,6 +578,9 @@ device_init_settings(struct device *dev,
+ s->flags |= DEV_OPT_EEE;
+ }
+
++ /* Remember the settings present in UCI */
++ s->valid_flags = s->flags;
++
+ cur = tb[DEV_ATTR_AUTH_VLAN];
+ free(dev->config_auth_vlans);
+ dev->config_auth_vlans = cur ? blob_memdup(cur) : NULL;
+@@ -609,11 +619,15 @@ static int device_broadcast_cb(void *ctx
+ return 0;
+ }
+
+-void device_broadcast_event(struct device *dev, enum device_event ev)
++static const char *device_event_name(enum device_event ev)
+ {
+ static const char * const event_names[] = {
+ [DEV_EVENT_ADD] = "add",
+ [DEV_EVENT_REMOVE] = "remove",
++ [DEV_EVENT_UPDATE_IFNAME] = "update_ifname",
++ [DEV_EVENT_UPDATE_IFINDEX] = "update_ifindex",
++ [DEV_EVENT_SETUP] = "setup",
++ [DEV_EVENT_TEARDOWN] = "teardown",
+ [DEV_EVENT_UP] = "up",
+ [DEV_EVENT_DOWN] = "down",
+ [DEV_EVENT_AUTH_UP] = "auth_up",
+@@ -621,12 +635,37 @@ void device_broadcast_event(struct devic
+ [DEV_EVENT_LINK_DOWN] = "link_down",
+ [DEV_EVENT_TOPO_CHANGE] = "topo_change",
+ };
++
++ if (ev >= ARRAY_SIZE(event_names) || !event_names[ev])
++ return "unknown";
++
++ return event_names[ev];
++}
++
++void device_broadcast_event(struct device *dev, enum device_event ev)
++{
++ const char *ev_name;
+ int dev_ev = ev;
+
+ safe_list_for_each(&dev->aliases, device_broadcast_cb, &dev_ev);
+ safe_list_for_each(&dev->users, device_broadcast_cb, &dev_ev);
+
+- if (ev >= ARRAY_SIZE(event_names) || !event_names[ev] || !dev->ifname[0])
++ switch (ev) {
++ case DEV_EVENT_ADD:
++ case DEV_EVENT_REMOVE:
++ case DEV_EVENT_UP:
++ case DEV_EVENT_DOWN:
++ case DEV_EVENT_AUTH_UP:
++ case DEV_EVENT_LINK_UP:
++ case DEV_EVENT_LINK_DOWN:
++ case DEV_EVENT_TOPO_CHANGE:
++ break;
++ default:
++ return;
++ }
++
++ ev_name = device_event_name(ev);
++ if (!dev->ifname[0])
+ return;
+
+ blob_buf_init(&b, 0);
+@@ -635,7 +674,7 @@ void device_broadcast_event(struct devic
+ blobmsg_add_u8(&b, "present", dev->present);
+ blobmsg_add_u8(&b, "active", dev->active);
+ blobmsg_add_u8(&b, "link_active", dev->link_active);
+- netifd_ubus_device_notify(event_names[ev], b.head, -1);
++ netifd_ubus_device_notify(ev_name, b.head, -1);
+ }
+
+ static void
+@@ -689,17 +728,7 @@ int device_claim(struct device_user *dep
+
+ device_broadcast_event(dev, DEV_EVENT_SETUP);
+ device_fill_default_settings(dev);
+- if (dev->external) {
+- /* Get ifindex for external claimed devices so a valid */
+- /* ifindex is in place avoiding possible race conditions */
+- device_set_ifindex(dev, system_if_resolve(dev));
+- if (!dev->ifindex)
+- ret = -1;
+-
+- system_if_get_settings(dev, &dev->orig_settings);
+- } else
+- ret = dev->set_state(dev, true);
+-
++ ret = dev->set_state(dev, true);
+ if (ret == 0)
+ device_broadcast_event(dev, DEV_EVENT_UP);
+ else {
+@@ -727,8 +756,7 @@ void device_release(struct device_user *
+ return;
+
+ device_broadcast_event(dev, DEV_EVENT_TEARDOWN);
+- if (!dev->external)
+- dev->set_state(dev, false);
++ dev->set_state(dev, false);
+
+ if (dev->active)
+ return;
+@@ -810,9 +838,6 @@ device_create_default(const char *name,
+ }
+
+ dev->default_config = true;
+- if (external)
+- system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
+-
+ device_check_state(dev);
+
+ return dev;
+@@ -841,7 +866,6 @@ __device_get(const char *name, int creat
+
+ if (dev) {
+ if (create > 1 && !dev->external) {
+- system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
+ dev->external = true;
+ device_set_present(dev, true);
+ }
+@@ -1164,11 +1188,6 @@ device_apply_config(struct device *dev,
+ enum dev_change_type change;
+
+ change = device_set_config(dev, type, config);
+- if (dev->external) {
+- system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
+- change = DEV_CONFIG_APPLIED;
+- }
+-
+ switch (change) {
+ case DEV_CONFIG_RESTART:
+ case DEV_CONFIG_APPLIED:
+@@ -1180,7 +1199,7 @@ device_apply_config(struct device *dev,
+ int ret = 0;
+
+ device_set_present(dev, false);
+- if (dev->active && !dev->external) {
++ if (dev->active) {
+ ret = dev->set_state(dev, false);
+ if (!ret)
+ ret = dev->set_state(dev, true);
+--- a/interface.c
++++ b/interface.c
+@@ -1078,11 +1078,17 @@ interface_add_link(struct interface *ifa
+ {
+ struct device *mdev = iface->main_dev.dev;
+
+- if (mdev == dev)
++ if (mdev == dev) {
++ if (iface->state != IFS_UP) {
++ interface_set_available(iface, false);
++ if (dev->present)
++ interface_set_available(iface, true);
++ }
+ return 0;
++ }
+
+ if (iface->main_dev.hotplug)
+- device_remove_user(&iface->main_dev);
++ interface_set_main_dev(iface, NULL);
+
+ if (mdev) {
+ if (mdev->hotplug_ops)
+--- a/wireless.c
++++ b/wireless.c
+@@ -138,7 +138,7 @@ static void
+ put_container(struct blob_buf *buf, struct blob_attr *attr, const char *name)
+ {
+ void *c = blobmsg_open_table(buf, name);
+- blob_put_raw(buf, blob_data(attr), blob_len(attr));
++ blob_put_raw(buf, blobmsg_data(attr), blobmsg_len(attr));
+ blobmsg_close_table(buf, c);
+ }
+
+@@ -337,12 +337,39 @@ static void wireless_device_set_mcast_to
+ dev->settings.flags |= DEV_OPT_MULTICAST_TO_UNICAST;
+ }
+
++static void wireless_check_interface(struct blob_attr *list, int *enabled, int *ifindex)
++{
++ struct interface *iface;
++ struct blob_attr *cur;
++ size_t rem;
++
++ blobmsg_for_each_attr(cur, list, rem) {
++ struct device *mdev;
++
++ iface = vlist_find(&interfaces, blobmsg_get_string(cur), iface, node);
++ if (!iface)
++ continue;
++
++ if (iface->autostart)
++ *enabled = 1;
++ else if (*enabled != 1)
++ *enabled = 0;
++
++ mdev = iface->main_dev.dev;
++ if (!mdev || !mdev->hotplug_ops)
++ continue;
++
++ *ifindex = mdev->ifindex;
++ }
++}
++
+ static void wireless_interface_handle_link(struct wireless_interface *vif, const char *ifname, bool up)
+ {
+ struct interface *iface;
+ struct blob_attr *cur;
+ const char *network;
+ struct device *dev;
++ int enabled = -1;
+ size_t rem;
+
+ if (!vif->network || !vif->ifname)
+@@ -372,6 +399,7 @@ static void wireless_interface_handle_li
+ dev->bpdu_filter = dev->wireless_ap;
+
+ out:
++ wireless_check_interface(vif->network, &enabled, &vif->network_ifindex);
+ blobmsg_for_each_attr(cur, vif->network, rem) {
+ network = blobmsg_data(cur);
+
+@@ -388,6 +416,7 @@ static void wireless_vlan_handle_link(st
+ struct interface *iface;
+ struct blob_attr *cur;
+ const char *network;
++ int enabled = -1;
+ size_t rem;
+
+ if (!vlan->network || !vlan->ifname)
+@@ -406,6 +435,7 @@ static void wireless_vlan_handle_link(st
+ }
+ }
+
++ wireless_check_interface(vlan->network, &enabled, &vlan->network_ifindex);
+ blobmsg_for_each_attr(cur, vlan->network, rem) {
+ network = blobmsg_data(cur);
+
+@@ -838,7 +868,7 @@ wireless_interface_init_config(struct wi
+ struct blob_attr *cur;
+
+ vif->network = NULL;
+- blobmsg_parse(vif_policy, __VIF_ATTR_MAX, tb, blob_data(vif->config), blob_len(vif->config));
++ blobmsg_parse_attr(vif_policy, __VIF_ATTR_MAX, tb, vif->config);
+
+ if ((cur = tb[VIF_ATTR_NETWORK]))
+ vif->network = cur;
+@@ -922,7 +952,7 @@ wireless_vlan_init_config(struct wireles
+ struct blob_attr *cur;
+
+ vlan->network = NULL;
+- blobmsg_parse(vlan_policy, __VLAN_ATTR_MAX, tb, blob_data(vlan->config), blob_len(vlan->config));
++ blobmsg_parse_attr(vlan_policy, __VLAN_ATTR_MAX, tb, vlan->config);
+
+ if ((cur = tb[VLAN_ATTR_NETWORK]))
+ vlan->network = cur;
+@@ -1079,7 +1109,7 @@ wireless_device_create(struct wireless_d
+ struct blob_attr *tb[__WDEV_ATTR_MAX];
+ struct blob_attr *cur;
+
+- blobmsg_parse(wdev_policy, __WDEV_ATTR_MAX, tb, blob_data(data), blob_len(data));
++ blobmsg_parse_attr(wdev_policy, __WDEV_ATTR_MAX, tb, data);
+
+ wdev = calloc_a(sizeof(*wdev), &name_buf, strlen(name) + 1);
+
+@@ -1128,7 +1158,7 @@ wireless_station_create(struct wireless_
+ char *name_buf;
+ char name[8];
+
+- blobmsg_parse(sta_policy, __STA_ATTR_MAX, tb, blob_data(data), blob_len(data));
++ blobmsg_parse_attr(sta_policy, __STA_ATTR_MAX, tb, data);
+
+ cur = tb[STA_ATTR_DISABLED];
+ if (cur && blobmsg_get_bool(cur))
+@@ -1168,7 +1198,7 @@ wireless_vlan_create(struct wireless_int
+ char *name_buf;
+ char name[8];
+
+- blobmsg_parse(vlan_policy, __VLAN_ATTR_MAX, tb, blob_data(data), blob_len(data));
++ blobmsg_parse_attr(vlan_policy, __VLAN_ATTR_MAX, tb, data);
+
+ cur = tb[VLAN_ATTR_DISABLED];
+ if (cur && blobmsg_get_bool(cur))
+@@ -1208,7 +1238,7 @@ struct wireless_interface* wireless_inte
+ char *name_buf;
+ char name[8];
+
+- blobmsg_parse(vif_policy, __VIF_ATTR_MAX, tb, blob_data(data), blob_len(data));
++ blobmsg_parse_attr(vif_policy, __VIF_ATTR_MAX, tb, data);
+
+ cur = tb[VIF_ATTR_DISABLED];
+ if (cur && blobmsg_get_bool(cur))
+@@ -1232,7 +1262,15 @@ struct wireless_interface* wireless_inte
+
+ vlist_add(&wdev->interfaces, &vif->node, vif->name);
+
+- return vlist_find(&wdev->interfaces, name, vif, node);
++ vif = vlist_find(&wdev->interfaces, name, vif, node);
++ if (!vif)
++ return NULL;
++
++ vif->vlan_idx = vif->sta_idx = 0;
++ vlist_update(&vif->vlans);
++ vlist_update(&vif->stations);
++
++ return vif;
+ }
+
+ /* ubus callback network.wireless.status, runs for every interface */
+@@ -1321,8 +1359,7 @@ wireless_interface_set_data(struct wirel
+ struct blob_attr *tb[__VIF_DATA_MAX];
+ struct blob_attr *cur;
+
+- blobmsg_parse(data_policy, __VIF_DATA_MAX, tb,
+- blobmsg_data(vif->data), blobmsg_data_len(vif->data));
++ blobmsg_parse_attr(data_policy, __VIF_DATA_MAX, tb, vif->data);
+
+ if ((cur = tb[VIF_DATA_IFNAME]))
+ vif->ifname = blobmsg_data(cur);
+@@ -1342,8 +1379,7 @@ wireless_vlan_set_data(struct wireless_v
+ struct blob_attr *tb[__VLAN_DATA_MAX];
+ struct blob_attr *cur;
+
+- blobmsg_parse(data_policy, __VLAN_DATA_MAX, tb,
+- blobmsg_data(vlan->data), blobmsg_data_len(vlan->data));
++ blobmsg_parse_attr(data_policy, __VLAN_DATA_MAX, tb, vlan->data);
+
+ if ((cur = tb[VLAN_DATA_IFNAME]))
+ vlan->ifname = blobmsg_data(cur);
+@@ -1374,7 +1410,7 @@ wireless_device_add_process(struct wirel
+ if (!data)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+- blobmsg_parse(proc_policy, __PROC_ATTR_MAX, tb, blobmsg_data(data), blobmsg_data_len(data));
++ blobmsg_parse_attr(proc_policy, __PROC_ATTR_MAX, tb, data);
+ if (!tb[PROC_ATTR_PID] || !tb[PROC_ATTR_EXE])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+@@ -1420,7 +1456,7 @@ wireless_device_process_kill_all(struct
+ bool immediate = false;
+ int signal = SIGTERM;
+
+- blobmsg_parse(kill_policy, __KILL_ATTR_MAX, tb, blobmsg_data(data), blobmsg_data_len(data));
++ blobmsg_parse_attr(kill_policy, __KILL_ATTR_MAX, tb, data);
+
+ if ((cur = tb[KILL_ATTR_SIGNAL]))
+ signal = blobmsg_get_u32(cur);
+@@ -1451,7 +1487,7 @@ wireless_device_set_retry(struct wireles
+ };
+ struct blob_attr *val;
+
+- blobmsg_parse(&retry_policy, 1, &val, blobmsg_data(data), blobmsg_data_len(data));
++ blobmsg_parse_attr(&retry_policy, 1, &val, data);
+ if (val)
+ wdev->retry = blobmsg_get_u32(val);
+ else
+@@ -1492,7 +1528,7 @@ wireless_device_notify(struct wireless_d
+ struct blob_attr *tb[__NOTIFY_MAX];
+ struct blob_attr *cur, **pdata;
+
+- blobmsg_parse(notify_policy, __NOTIFY_MAX, tb, blob_data(data), blob_len(data));
++ blobmsg_parse_attr(notify_policy, __NOTIFY_MAX, tb, data);
+
+ if (!tb[NOTIFY_ATTR_COMMAND])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+@@ -1555,33 +1591,41 @@ wireless_device_notify(struct wireless_d
+ }
+
+ static void
++wdev_vlan_check_network_enabled(struct wireless_device *wdev,
++ struct wireless_interface *vif)
++{
++ struct wireless_vlan *vlan;
++
++ vlist_for_each_element(&vif->vlans, vlan, node) {
++ int enabled = -1, ifindex = -1;
++
++ wireless_check_interface(vlan->network, &enabled, &ifindex);
++
++ if (wdev->state != IFS_UP || vlan->network_ifindex == ifindex)
++ continue;
++
++ vlan->network_ifindex = ifindex;
++ wdev->config_update = true;
++ }
++}
++
++static void
+ wdev_check_network_enabled(struct wireless_device *wdev)
+ {
+ struct wireless_interface *vif;
+- struct interface *iface;
+- struct blob_attr *cur;
+- size_t rem;
+
+ vlist_for_each_element(&wdev->interfaces, vif, node) {
+- int enabled = -1;
++ int enabled = -1, ifindex = -1;
+
+- blobmsg_for_each_attr(cur, vif->network, rem) {
+- iface = vlist_find(&interfaces, blobmsg_get_string(cur), iface, node);
+- if (!iface)
+- continue;
++ wireless_check_interface(vif->network, &enabled, &ifindex);
++ wdev_vlan_check_network_enabled(wdev, vif);
+
+- if (iface->autostart) {
+- enabled = 1;
+- break;
+- }
+- if (enabled != 1)
+- enabled = 0;
+- }
+-
+- if (vif->disabled == !enabled)
++ if (vif->disabled == !enabled &&
++ (wdev->state != IFS_UP || vif->network_ifindex == ifindex))
+ continue;
+
+ vif->disabled = !enabled;
++ vif->network_ifindex = ifindex;
+ wdev->config_update = true;
+ }
+ }
+@@ -1639,10 +1683,8 @@ void wireless_device_hotplug_event(const
+ return;
+
+ len = s - name;
+- } else if (!device_find(name)) {
+- len = strlen(name);
+ } else {
+- return;
++ len = strlen(name);
+ }
+
+ vlist_for_each_element(&wireless_devices, wdev, node) {
+--- a/wireless.h
++++ b/wireless.h
+@@ -96,6 +96,8 @@ struct wireless_interface {
+ int vlan_idx;
+ int sta_idx;
+ bool disabled;
++
++ int network_ifindex;
+ };
+
+ struct wireless_vlan {
+@@ -112,6 +114,8 @@ struct wireless_vlan {
+ int multicast_to_unicast;
+ bool isolate;
+ bool bridge_isolate;
++
++ int network_ifindex;
+ };
+
+ struct wireless_station {
--
2.34.1