+ uci_foreach_element(&uci_network->sections, e) {
+ struct uci_section *s = uci_to_section(e);
+
+ if (!strcmp(s->type, "interface"))
+ config_parse_interface(s, false);
+ }
+
+ uci_foreach_element(&uci_network->sections, e) {
+ struct uci_section *s = uci_to_section(e);
+
+ if (!strcmp(s->type, "alias"))
+ config_parse_interface(s, true);
+ }
+}
+
+static void
+config_init_ip(void)
+{
+ struct interface *iface;
+ struct uci_element *e;
+
+ vlist_for_each_element(&interfaces, iface, node)
+ interface_ip_update_start(&iface->config_ip);
+
+ uci_foreach_element(&uci_network->sections, e) {
+ struct uci_section *s = uci_to_section(e);
+
+ if (!strcmp(s->type, "route"))
+ config_parse_route(s, false);
+ else if (!strcmp(s->type, "route6"))
+ config_parse_route(s, true);
+ if (!strcmp(s->type, "neighbor"))
+ config_parse_neighbor(s, false);
+ else if (!strcmp(s->type, "neighbor6"))
+ config_parse_neighbor(s, true);
+ }
+
+ vlist_for_each_element(&interfaces, iface, node)
+ interface_ip_update_complete(&iface->config_ip);
+}
+
+static void
+config_init_rules(void)
+{
+ struct uci_element *e;
+
+ iprule_update_start();
+
+ uci_foreach_element(&uci_network->sections, e) {
+ struct uci_section *s = uci_to_section(e);
+
+ if (!strcmp(s->type, "rule"))
+ config_parse_rule(s, false);
+ else if (!strcmp(s->type, "rule6"))
+ config_parse_rule(s, true);
+ }
+
+ iprule_update_complete();
+}
+
+static void
+config_init_globals(void)
+{
+ struct uci_section *globals = uci_lookup_section(
+ uci_ctx, uci_network, "globals");
+ if (!globals)
+ return;
+
+ const char *ula_prefix = uci_lookup_option_string(
+ uci_ctx, globals, "ula_prefix");
+ interface_ip_set_ula_prefix(ula_prefix);
+}
+
+static void
+config_parse_wireless_device(struct uci_section *s)
+{
+ struct wireless_driver *drv;
+ const char *driver_name;
+
+ driver_name = uci_lookup_option_string(uci_ctx, s, "type");
+ if (!driver_name)
+ return;
+
+ drv = avl_find_element(&wireless_drivers, driver_name, drv, node);
+ if (!drv)
+ return;
+
+ blob_buf_init(&b, 0);
+ uci_to_blob(&b, s, drv->device.config);
+ wireless_device_create(drv, s->e.name, b.head);
+}
+
+static void
+config_parse_wireless_vlan(struct wireless_interface *vif, struct uci_section *s)
+{
+ char *name;
+
+ name = alloca(strlen(s->type) + 16);
+ sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
+
+ blob_buf_init(&b, 0);
+ uci_to_blob(&b, s, vif->wdev->drv->vlan.config);
+ wireless_vlan_create(vif, b.head, s->anonymous ? name : s->e.name);
+}
+
+static void
+config_parse_wireless_station(struct wireless_interface *vif, struct uci_section *s)
+{
+ char *name;
+
+ name = alloca(strlen(s->type) + 16);
+ sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
+
+ blob_buf_init(&b, 0);
+ uci_to_blob(&b, s, vif->wdev->drv->station.config);
+ wireless_station_create(vif, b.head, s->anonymous ? name : s->e.name);
+}
+
+static void
+config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s)
+{
+ struct wireless_interface *vif;
+ struct uci_element *f;
+ char *name;
+
+ name = alloca(strlen(s->type) + 16);
+ sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
+
+ blob_buf_init(&b, 0);
+ uci_to_blob(&b, s, wdev->drv->interface.config);
+ vif = wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name);
+ if (!vif)
+ return;
+
+ if (s->anonymous)
+ goto out;
+
+ uci_foreach_element(&uci_wireless->sections, f) {
+ struct uci_section *cur = uci_to_section(f);
+ const char *vif_name;
+
+ if (strcmp(cur->type, "wifi-vlan") != 0)
+ continue;
+
+ vif_name = uci_lookup_option_string(uci_ctx, cur, "iface");
+ if (vif_name && strcmp(s->e.name, vif_name))
+ continue;
+ config_parse_wireless_vlan(vif, cur);
+ }
+
+ uci_foreach_element(&uci_wireless->sections, f) {
+ struct uci_section *cur = uci_to_section(f);
+ const char *vif_name;
+
+ if (strcmp(cur->type, "wifi-station") != 0)
+ continue;
+
+ vif_name = uci_lookup_option_string(uci_ctx, cur, "iface");
+ if (vif_name && strcmp(s->e.name, vif_name))
+ continue;
+ config_parse_wireless_station(vif, cur);
+ }
+
+out:
+ vlist_flush(&vif->vlans);
+ vlist_flush(&vif->stations);
+}
+
+static void
+config_init_procd_wireless_interface(const char *wdev_name, const char *vif_name,
+ struct blob_attr *config,
+ struct blob_attr *vlans,
+ struct blob_attr *stations)
+{
+ struct wireless_interface *vif;
+ struct wireless_device *wdev;
+ struct blob_attr *cur;
+ char name[16];
+ int idx = 0;
+ int rem;
+
+ wdev = vlist_find(&wireless_devices, wdev_name, wdev, node);
+ if (!wdev) {
+ D(WIRELESS, "device %s not found!", wdev_name);
+ return;
+ }
+
+ vif = wireless_interface_create(wdev, config, vif_name);
+ if (!vif)
+ return;
+
+ blobmsg_for_each_attr(cur, vlans, rem) {
+ snprintf(name, sizeof(name), "%d", ++idx);
+ wireless_vlan_create(vif, cur, name);
+ }
+
+ blobmsg_for_each_attr(cur, stations, rem) {
+ snprintf(name, sizeof(name), "%d", ++idx);
+ wireless_station_create(vif, cur, name);
+ }
+
+ vlist_flush(&vif->vlans);
+ vlist_flush(&vif->stations);
+}
+
+static void
+config_procd_wireless_interface_cb(struct blob_attr *data)
+{
+ enum {
+ UDATA_ATTR_DEVICE,
+ UDATA_ATTR_CONFIG,
+ UDATA_ATTR_STATIONS,
+ UDATA_ATTR_VLANS,
+ __UDATA_ATTR_MAX,
+ };
+ static const struct blobmsg_policy policy[__UDATA_ATTR_MAX] = {
+ [UDATA_ATTR_DEVICE] = { "device", BLOBMSG_TYPE_STRING },
+ [UDATA_ATTR_CONFIG] = { "config", BLOBMSG_TYPE_TABLE },
+ [UDATA_ATTR_STATIONS] = { "stations", BLOBMSG_TYPE_ARRAY },
+ [UDATA_ATTR_VLANS] = { "vlans", BLOBMSG_TYPE_ARRAY },
+ };
+ struct blob_attr *tb[__UDATA_ATTR_MAX];
+ const char *dev;
+
+ blobmsg_parse_attr(policy, __UDATA_ATTR_MAX, tb, data);
+ if (!tb[UDATA_ATTR_DEVICE] || !tb[UDATA_ATTR_CONFIG])
+ return;
+
+ dev = blobmsg_get_string(tb[UDATA_ATTR_DEVICE]);
+ config_init_procd_wireless_interface(dev, blobmsg_name(data),
+ tb[UDATA_ATTR_CONFIG],
+ tb[UDATA_ATTR_VLANS],
+ tb[UDATA_ATTR_STATIONS]);
+}
+
+static void
+config_init_wireless(void)
+{
+ struct wireless_device *wdev;
+ struct uci_element *e;
+ const char *dev_name;
+
+ if (!uci_wireless) {
+ D(WIRELESS, "No wireless configuration found");