X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=wireless.c;h=8bdfc4b10ec1b5b1b04afef78ca0eb8418c64a49;hp=daa4df74bdb8afc64de46084e18ad2940e81c73e;hb=258b79f7a912abc84a3066c90266d8835597362e;hpb=37769eb666aa614b76df9b537db35c2c70e3ac7a diff --git a/wireless.c b/wireless.c index daa4df7..8bdfc4b 100644 --- a/wireless.c +++ b/wireless.c @@ -40,7 +40,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_STRING }, + [VIF_ATTR_NETWORK] = { .name = "network", .type = BLOBMSG_TYPE_ARRAY }, }; static const struct uci_blob_param_list vif_param = { @@ -51,30 +51,43 @@ static const struct uci_blob_param_list vif_param = { static void put_container(struct blob_buf *buf, struct blob_attr *attr, const char *name) { - void *c = blobmsg_open_table(&b, name); - blob_put_raw(&b, blob_data(attr), blob_len(attr)); - blobmsg_close_table(&b, c); + void *c = blobmsg_open_table(buf, name); + blob_put_raw(buf, blob_data(attr), blob_len(attr)); + blobmsg_close_table(buf, c); } static void -vif_config_add_bridge(struct blob_buf *buf, const char *network, bool prepare) +vif_config_add_bridge(struct blob_buf *buf, struct blob_attr *networks, bool prepare) { struct interface *iface; - struct device *dev; + struct device *dev = NULL; + struct blob_attr *cur; + const char *network; + int rem; - if (!network) + if (!networks) return; - iface = vlist_find(&interfaces, network, iface, node); - if (!iface) - return; + blobmsg_for_each_attr(cur, networks, rem) { + network = blobmsg_data(cur); + + iface = vlist_find(&interfaces, network, iface, node); + if (!iface) + continue; + + dev = iface->main_dev.dev; + if (!dev) + return; + + if (dev->type != &bridge_device_type) + return; + } - dev = iface->main_dev.dev; if (!dev) return; - if (dev->type != &bridge_device_type) - return; + if (dev->hotplug_ops && dev->hotplug_ops->prepare) + dev->hotplug_ops->prepare(dev); blobmsg_add_string(buf, "bridge", dev->ifname); } @@ -122,6 +135,7 @@ wireless_complete_kill_request(struct wireless_device *wdev) static void wireless_process_free(struct wireless_device *wdev, struct wireless_process *proc) { + D(WIRELESS, "Wireless device '%s' free pid %d\n", wdev->name, proc->pid); list_del(&proc->list); free(proc); @@ -148,8 +162,10 @@ wireless_process_kill_all(struct wireless_device *wdev, int signal, bool free) list_for_each_entry_safe(proc, tmp, &wdev->script_proc, list) { bool check = wireless_process_check(proc); - if (check) + if (check) { + D(WIRELESS, "Wireless device '%s' kill pid %d\n", wdev->name, proc->pid); kill(proc->pid, signal); + } if (free || !check) wireless_process_free(wdev, proc); @@ -164,6 +180,8 @@ wireless_device_free_state(struct wireless_device *wdev) { struct wireless_interface *vif; + uloop_timeout_cancel(&wdev->script_check); + uloop_timeout_cancel(&wdev->timeout); wireless_complete_kill_request(wdev); free(wdev->data); wdev->data = NULL; @@ -177,15 +195,28 @@ wireless_device_free_state(struct wireless_device *wdev) static void wireless_interface_handle_link(struct wireless_interface *vif, bool up) { struct interface *iface; + struct blob_attr *cur; + const char *network; + int rem; if (!vif->network || !vif->ifname) return; - iface = vlist_find(&interfaces, vif->network, iface, node); - if (!iface) - return; + if (up) { + struct device *dev = device_get(vif->ifname, 2); + if (dev) + dev->wireless = true; + } + + blobmsg_for_each_attr(cur, vif->network, rem) { + network = blobmsg_data(cur); - interface_handle_link(iface, vif->ifname, up); + iface = vlist_find(&interfaces, network, iface, node); + if (!iface) + continue; + + interface_handle_link(iface, vif->ifname, up, true); + } } static void @@ -194,6 +225,7 @@ wireless_device_setup_cancel(struct wireless_device *wdev) if (wdev->cancel) return; + D(WIRELESS, "Cancel wireless device '%s' setup\n", wdev->name); wdev->cancel = true; uloop_timeout_set(&wdev->timeout, 10 * 1000); } @@ -207,6 +239,7 @@ wireless_device_run_handler(struct wireless_device *wdev, bool up) int i = 0; int fds[2] = { -1, -1 }; + D(WIRELESS, "Wireless device '%s' run %s handler\n", wdev->name, action); prepare_config(wdev, &b, up); config = blobmsg_format_json(b.head, true); @@ -234,6 +267,9 @@ wireless_device_run_handler(struct wireless_device *wdev, bool up) static void __wireless_device_set_up(struct wireless_device *wdev) { + if (wdev->disabled) + return; + if (wdev->state != IFS_DOWN || config_init) return; @@ -242,30 +278,48 @@ __wireless_device_set_up(struct wireless_device *wdev) } static void +wireless_device_free(struct wireless_device *wdev) +{ + vlist_flush_all(&wdev->interfaces); + avl_delete(&wireless_devices.avl, &wdev->node.avl); + free(wdev->config); + free(wdev); +} + +static void +wdev_handle_config_change(struct wireless_device *wdev) +{ + enum interface_config_state state = wdev->config_state; + + switch(state) { + case IFC_NORMAL: + case IFC_RELOAD: + wdev->config_state = IFC_NORMAL; + if (wdev->autostart) + __wireless_device_set_up(wdev); + break; + case IFC_REMOVE: + wireless_device_free(wdev); + break; + } +} + +static void wireless_device_mark_down(struct wireless_device *wdev) { struct wireless_interface *vif; + D(WIRELESS, "Wireless device '%s' is now down\n", wdev->name); + vlist_for_each_element(&wdev->interfaces, vif, node) wireless_interface_handle_link(vif, false); wireless_process_kill_all(wdev, SIGTERM, true); + wdev->cancel = false; wdev->state = IFS_DOWN; wireless_device_free_state(wdev); - - if (wdev->autostart) - __wireless_device_set_up(wdev); -} - -static void -wireless_device_mark_up(struct wireless_device *wdev) -{ - struct wireless_interface *vif; - - wdev->state = IFS_UP; - vlist_for_each_element(&wdev->interfaces, vif, node) - wireless_interface_handle_link(vif, true); + wdev_handle_config_change(wdev); } static void @@ -302,8 +356,28 @@ __wireless_device_set_down(struct wireless_device *wdev) } static void +wireless_device_mark_up(struct wireless_device *wdev) +{ + struct wireless_interface *vif; + + if (wdev->cancel) { + wdev->cancel = false; + __wireless_device_set_down(wdev); + return; + } + + D(WIRELESS, "Wireless device '%s' is now up\n", wdev->name); + wdev->state = IFS_UP; + vlist_for_each_element(&wdev->interfaces, vif, node) + wireless_interface_handle_link(vif, true); +} + +static void wireless_device_retry_setup(struct wireless_device *wdev) { + if (wdev->state == IFS_TEARDOWN || wdev->state == IFS_DOWN || wdev->cancel) + return; + if (--wdev->retry < 0) wdev->autostart = false; @@ -335,38 +409,12 @@ wireless_device_set_down(struct wireless_device *wdev) } static void -wireless_device_free(struct wireless_device *wdev) -{ - vlist_flush_all(&wdev->interfaces); - free(wdev->config); - free(wdev); -} - -static void -wdev_handle_config_change(struct wireless_device *wdev) -{ - switch(wdev->config_state) { - case IFC_NORMAL: - break; - case IFC_RELOAD: - if (wdev->autostart) - __wireless_device_set_up(wdev); - break; - case IFC_REMOVE: - wireless_device_free(wdev); - break; - } -} - -static void wdev_set_config_state(struct wireless_device *wdev, enum interface_config_state s) { - enum interface_config_state old_state = wdev->config_state; - - wdev->config_state = s; - if (old_state != IFC_NORMAL) + if (wdev->config_state != IFC_NORMAL) return; + wdev->config_state = s; if (wdev->state == IFS_DOWN) wdev_handle_config_change(wdev); else @@ -377,15 +425,17 @@ static void 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; free(wd_new); - if (blob_attr_equal(wdev->config, new_config)) + if (blob_attr_equal(wdev->config, new_config) && wdev->disabled == disabled) return; D(WIRELESS, "Update configuration of wireless device '%s'\n", wdev->name); free(wdev->config); wdev->config = blob_memdup(new_config); + wdev->disabled = disabled; wdev_set_config_state(wdev, IFC_RELOAD); } @@ -429,10 +479,10 @@ wireless_add_handler(const char *script, const char *name, json_object *obj) return; drv = calloc_a(sizeof(*drv), - &name_str, strlen(name) + 1, - &script_str, strlen(script) + 1, &dev_config, sizeof(*dev_config) + sizeof(void *), - &iface_config, sizeof(*iface_config) + sizeof(void *)); + &iface_config, sizeof(*iface_config) + sizeof(void *), + &name_str, strlen(name) + 1, + &script_str, strlen(script) + 1); drv->name = strcpy(name_str, name); drv->script = strcpy(script_str, script); @@ -453,8 +503,7 @@ wireless_add_handler(const char *script, const char *name, json_object *obj) D(WIRELESS, "Add handler for script %s: %s\n", script, name); } -static void __init -wireless_init_list(void) +void wireless_init(void) { vlist_init(&wireless_devices, avl_strcmp, wdev_update); wireless_devices.keep_old = true; @@ -478,7 +527,7 @@ wireless_interface_init_config(struct wireless_interface *vif) blobmsg_parse(vif_policy, __VIF_ATTR_MAX, tb, blob_data(vif->config), blob_len(vif->config)); if ((cur = tb[VIF_ATTR_NETWORK])) - vif->network = blobmsg_data(cur); + vif->network = cur; } static void @@ -495,7 +544,8 @@ vif_update(struct vlist_tree *tree, struct vlist_node *node_new, wdev = vif_new->wdev; if (vif_old && vif_new) { - vif_old->section = vif_new->section; + free((void *) vif_old->section); + vif_old->section = strdup(vif_new->section); if (blob_attr_equal(vif_old->config, vif_new->config)) { free(vif_new); return; @@ -508,10 +558,12 @@ vif_update(struct vlist_tree *tree, struct vlist_node *node_new, free(vif_new); } else if (vif_new) { D(WIRELESS, "Create new wireless interface %s on device %s\n", vif_new->name, wdev->name); + vif_new->section = strdup(vif_new->section); vif_new->config = blob_memdup(vif_new->config); wireless_interface_init_config(vif_new); } else if (vif_old) { D(WIRELESS, "Delete wireless interface %s on device %s\n", vif_old->name, wdev->name); + free((void *) vif_old->section); free(vif_old->config); free(vif_old); } @@ -557,6 +609,7 @@ wireless_device_check_script_tasks(struct uloop_timeout *timeout) if (wireless_process_check(proc)) continue; + D(WIRELESS, "Wireless device '%s' pid %d has terminated\n", wdev->name, proc->pid); if (proc->required) restart = true; @@ -577,10 +630,10 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo struct blob_attr *disabled; blobmsg_parse(&wdev_policy, 1, &disabled, blob_data(data), blob_len(data)); - if (disabled && blobmsg_get_bool(disabled)) - return; wdev = calloc_a(sizeof(*wdev), &name_buf, strlen(name) + 1); + if (disabled && blobmsg_get_bool(disabled)) + wdev->disabled = true; wdev->drv = drv; wdev->state = IFS_DOWN; wdev->config_state = IFC_NORMAL; @@ -591,8 +644,6 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo INIT_LIST_HEAD(&wdev->script_proc); vlist_init(&wdev->interfaces, avl_strcmp, vif_update); wdev->interfaces.keep_old = true; - wdev->interfaces.no_delete = true; - vlist_add(&wireless_devices, &wdev->node, wdev->name); wdev->timeout.cb = wireless_device_setup_timeout; wdev->script_task.cb = wireless_device_script_task_cb; @@ -603,6 +654,8 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo wdev->script_proc_fd.cb = wireless_proc_poll_fd; wdev->script_check.cb = wireless_device_check_script_tasks; + + vlist_add(&wireless_devices, &wdev->node, wdev->name); } void wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section) @@ -621,7 +674,8 @@ void wireless_interface_create(struct wireless_device *wdev, struct blob_attr *d sprintf(name, "%d", wdev->vif_idx++); - vif = calloc_a(sizeof(*vif), &name_buf, strlen(name) + 1); + vif = calloc_a(sizeof(*vif), + &name_buf, strlen(name) + 1); vif->name = strcpy(name_buf, name); vif->wdev = wdev; vif->config = data; @@ -634,13 +688,12 @@ wireless_interface_status(struct wireless_interface *iface, struct blob_buf *b) { void *i; - i = blobmsg_open_table(b, iface->name); + i = blobmsg_open_table(b, NULL); if (iface->section) blobmsg_add_string(b, "section", iface->section); if (iface->ifname) blobmsg_add_string(b, "ifname", iface->ifname); - if (iface->data) - blob_put_raw(b, blob_data(iface->data), blob_len(iface->data)); + put_container(b, iface->config, "config"); blobmsg_close_table(b, i); } @@ -654,10 +707,37 @@ wireless_device_status(struct wireless_device *wdev, struct blob_buf *b) blobmsg_add_u8(b, "up", wdev->state == IFS_UP); blobmsg_add_u8(b, "pending", wdev->state == IFS_SETUP || wdev->state == IFS_TEARDOWN); blobmsg_add_u8(b, "autostart", wdev->autostart); - i = blobmsg_open_table(b, "interfaces"); + blobmsg_add_u8(b, "disabled", wdev->disabled); + put_container(b, wdev->config, "config"); + + i = blobmsg_open_array(b, "interfaces"); vlist_for_each_element(&wdev->interfaces, iface, node) wireless_interface_status(iface, b); - blobmsg_close_table(b, i); + blobmsg_close_array(b, i); + blobmsg_close_table(b, c); +} + +void +wireless_device_get_validate(struct wireless_device *wdev, struct blob_buf *b) +{ + struct uci_blob_param_list *p; + void *c, *d; + int i; + + c = blobmsg_open_table(b, wdev->name); + + d = blobmsg_open_table(b, "device"); + p = wdev->drv->device.config; + for (i = 0; i < p->n_params; i++) + blobmsg_add_string(b, p->params[i].name, uci_get_validate_string(p, i)); + blobmsg_close_table(b, d); + + d = blobmsg_open_table(b, "interface"); + p = wdev->drv->interface.config; + for (i = 0; i < p->n_params; i++) + blobmsg_add_string(b, p->params[i].name, uci_get_validate_string(p, i)); + blobmsg_close_table(b, d); + blobmsg_close_table(b, c); } @@ -698,6 +778,7 @@ wireless_device_add_process(struct wireless_device *wdev, struct blob_attr *data struct blob_attr *tb[__PROC_ATTR_MAX]; struct wireless_process *proc; char *name; + int pid; if (!data) return UBUS_STATUS_INVALID_ARGUMENT; @@ -706,15 +787,20 @@ wireless_device_add_process(struct wireless_device *wdev, struct blob_attr *data if (!tb[PROC_ATTR_PID] || !tb[PROC_ATTR_EXE]) return UBUS_STATUS_INVALID_ARGUMENT; + pid = blobmsg_get_u32(tb[PROC_ATTR_PID]); + if (pid < 2) + return UBUS_STATUS_INVALID_ARGUMENT; + proc = calloc_a(sizeof(*proc), &name, strlen(blobmsg_data(tb[PROC_ATTR_EXE])) + 1); - proc->pid = blobmsg_get_u32(tb[PROC_ATTR_PID]); + proc->pid = pid; proc->exe = strcpy(name, blobmsg_data(tb[PROC_ATTR_EXE])); if (tb[PROC_ATTR_REQUIRED]) proc->required = blobmsg_get_bool(tb[PROC_ATTR_REQUIRED]); + D(WIRELESS, "Wireless device '%s' add pid %d\n", wdev->name, proc->pid); list_add(&proc->list, &wdev->script_proc); uloop_timeout_set(&wdev->script_check, 0); @@ -745,7 +831,7 @@ wireless_device_process_kill_all(struct wireless_device *wdev, struct blob_attr signal = blobmsg_get_u32(cur); if ((cur = tb[KILL_ATTR_IMMEDIATE])) - immediate = blobmsg_get_u32(cur); + immediate = blobmsg_get_bool(cur); if (wdev->state != IFS_TEARDOWN || wdev->kill_request) return UBUS_STATUS_PERMISSION_DENIED; @@ -827,9 +913,6 @@ wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data, if (wdev->state != IFS_SETUP) return UBUS_STATUS_PERMISSION_DENIED; - if (wdev->cancel) - return 0; - wireless_device_mark_up(wdev); break; case NOTIFY_CMD_SET_DATA: