netifd: fix disabling radio via config if reconf is being used
[project/netifd.git] / wireless.c
index 1b203b6b33f8df3bca257c97c5464ea01d80e631..898a01220011e41932180c8b0a4e79de50aa2002 100644 (file)
@@ -62,6 +62,7 @@ static const struct uci_blob_param_list wdev_param = {
 enum {
        VIF_ATTR_DISABLED,
        VIF_ATTR_NETWORK,
+       VIF_ATTR_NETWORK_VLAN,
        VIF_ATTR_ISOLATE,
        VIF_ATTR_MODE,
        VIF_ATTR_PROXYARP,
@@ -72,6 +73,7 @@ enum {
 static const struct blobmsg_policy vif_policy[__VIF_ATTR_MAX] = {
        [VIF_ATTR_DISABLED] = { .name = "disabled", .type = BLOBMSG_TYPE_BOOL },
        [VIF_ATTR_NETWORK] = { .name = "network", .type = BLOBMSG_TYPE_ARRAY },
+       [VIF_ATTR_NETWORK_VLAN] = { .name = "network_vlan", .type = BLOBMSG_TYPE_ARRAY },
        [VIF_ATTR_ISOLATE] = { .name = "isolate", .type = BLOBMSG_TYPE_BOOL },
        [VIF_ATTR_MODE] = { .name = "mode", .type = BLOBMSG_TYPE_STRING },
        [VIF_ATTR_PROXYARP] = { .name = "proxy_arp", .type = BLOBMSG_TYPE_BOOL },
@@ -86,6 +88,7 @@ static const struct uci_blob_param_list vif_param = {
 enum {
        VLAN_ATTR_DISABLED,
        VLAN_ATTR_NETWORK,
+       VLAN_ATTR_NETWORK_VLAN,
        VLAN_ATTR_ISOLATE,
        VLAN_ATTR_MCAST_TO_UCAST,
        __VLAN_ATTR_MAX,
@@ -94,6 +97,7 @@ enum {
 static const struct blobmsg_policy vlan_policy[__VLAN_ATTR_MAX] = {
        [VLAN_ATTR_DISABLED] = { .name = "disabled", .type = BLOBMSG_TYPE_BOOL },
        [VLAN_ATTR_NETWORK] = { .name = "network", .type = BLOBMSG_TYPE_ARRAY },
+       [VLAN_ATTR_NETWORK_VLAN] = { .name = "network_vlan", .type = BLOBMSG_TYPE_ARRAY },
        [VLAN_ATTR_ISOLATE] = { .name = "isolate", .type = BLOBMSG_TYPE_BOOL },
        [VLAN_ATTR_MCAST_TO_UCAST] = { .name = "multicast_to_unicast", .type = BLOBMSG_TYPE_BOOL },
 };
@@ -363,7 +367,7 @@ static void wireless_interface_handle_link(struct wireless_interface *vif, const
                if (!iface)
                        continue;
 
-               interface_handle_link(iface, ifname, NULL, up, true);
+               interface_handle_link(iface, ifname, vif->network_vlan, up, true);
        }
 }
 
@@ -395,7 +399,7 @@ static void wireless_vlan_handle_link(struct wireless_vlan *vlan, bool up)
                if (!iface)
                        continue;
 
-               interface_handle_link(iface, vlan->ifname, NULL, up, true);
+               interface_handle_link(iface, vlan->ifname, vlan->network_vlan, up, true);
        }
 }
 
@@ -492,7 +496,7 @@ __wireless_device_set_up(struct wireless_device *wdev, int force)
        if (!wdev->autostart)
                return;
 
-       if (!force && (wdev->state != IFS_DOWN || config_init))
+       if ((!force && wdev->state != IFS_DOWN) || config_init)
                return;
 
        free(wdev->prev_config);
@@ -676,10 +680,16 @@ wdev_set_config_state(struct wireless_device *wdev, enum interface_config_state
        if (wdev->config_state != IFC_NORMAL)
                return;
 
+       wdev->config_update = false;
+       if (!wdev->disabled && s == IFC_RELOAD && wdev->reconf && wdev->state == IFS_UP) {
+               wireless_device_reconf(wdev);
+               return;
+       }
+
        wdev->config_state = s;
        if (wdev->state == IFS_DOWN)
                wdev_handle_config_change(wdev);
-       else if (!wdev->reconf || wdev->state != IFS_UP)
+       else
                __wireless_device_set_down(wdev);
 }
 
@@ -699,6 +709,8 @@ wdev_change_config(struct wireless_device *wdev, struct wireless_device *wd_new)
        struct blob_attr *new_config = wd_new->config;
        bool disabled = wd_new->disabled;
 
+       wdev->reconf = wd_new->reconf;
+       wdev->serialize = wd_new->serialize;
        free(wd_new);
 
        wdev_prepare_prev_config(wdev);
@@ -709,7 +721,7 @@ wdev_change_config(struct wireless_device *wdev, struct wireless_device *wd_new)
        free(wdev->config);
        wdev->config = blob_memdup(new_config);
        wdev->disabled = disabled;
-       wdev_set_config_state(wdev, IFC_RELOAD);
+       wdev->config_update = true;
 }
 
 static void
@@ -820,6 +832,9 @@ wireless_interface_init_config(struct wireless_interface *vif)
        if ((cur = tb[VIF_ATTR_NETWORK]))
                vif->network = cur;
 
+       if ((cur = tb[VIF_ATTR_NETWORK_VLAN]))
+               vif->network_vlan = cur;
+
        cur = tb[VIF_ATTR_MODE];
        vif->ap_mode = cur && !strcmp(blobmsg_get_string(cur), "ap");
 
@@ -874,7 +889,7 @@ vif_update(struct vlist_tree *tree, struct vlist_node *node_new,
                free(vif_old);
        }
 
-       wdev_set_config_state(wdev, IFC_RELOAD);
+       wdev->config_update = true;
 }
 
 /* parse blob config into the vlan object */
@@ -890,6 +905,9 @@ wireless_vlan_init_config(struct wireless_vlan *vlan)
        if ((cur = tb[VLAN_ATTR_NETWORK]))
                vlan->network = cur;
 
+       if ((cur = tb[VLAN_ATTR_NETWORK_VLAN]))
+               vlan->network_vlan = cur;
+
        cur = tb[VLAN_ATTR_ISOLATE];
        if (cur)
                vlan->isolate = blobmsg_get_bool(cur);
@@ -940,7 +958,7 @@ vlan_update(struct vlist_tree *tree, struct vlist_node *node_new,
                free(vlan_old);
        }
 
-       wdev_set_config_state(wdev, IFC_RELOAD);
+       wdev->config_update = true;
 }
 
 /* vlist update call for station list */
@@ -980,7 +998,7 @@ station_update(struct vlist_tree *tree, struct vlist_node *node_new,
                free(sta_old);
        }
 
-       wdev_set_config_state(wdev, IFC_RELOAD);
+       wdev->config_update = true;
 }
 
 static void
@@ -1063,7 +1081,7 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo
        wdev->serialize = cur && blobmsg_get_bool(cur);
 
        cur = tb[WDEV_ATTR_RECONF];
-       wdev->reconf = cur && blobmsg_get_bool(cur);
+       wdev->reconf = !cur || blobmsg_get_bool(cur);
 
        wdev->retry_setup_failed = false;
        wdev->autostart = true;
@@ -1505,9 +1523,7 @@ wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data,
                else
                        pdata = &wdev->data;
 
-               if (*pdata)
-                       return UBUS_STATUS_INVALID_ARGUMENT;
-
+               free(*pdata);
                *pdata = blob_memdup(cur);
                if (vif)
                        wireless_interface_set_data(vif);
@@ -1533,8 +1549,11 @@ wireless_start_pending(void)
 {
        struct wireless_device *wdev;
 
-       vlist_for_each_element(&wireless_devices, wdev, node)
+       vlist_for_each_element(&wireless_devices, wdev, node) {
+               if (wdev->config_update)
+                       wdev_set_config_state(wdev, IFC_RELOAD);
                __wireless_device_set_up(wdev, 0);
+       }
 }
 
 void wireless_device_hotplug_event(const char *name, bool add)