diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile index 4f6420f503..408c15390e 100644 --- a/package/network/services/hostapd/Makefile +++ b/package/network/services/hostapd/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=hostapd -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_URL:=http://w1.fi/hostap.git PKG_SOURCE_PROTO:=git @@ -519,8 +519,9 @@ define Install/supplicant endef define Package/hostapd-common/install - $(INSTALL_DIR) $(1)/lib/netifd $(1)/etc/rc.button + $(INSTALL_DIR) $(1)/lib/netifd $(1)/etc/rc.button $(1)/etc/hotplug.d/ieee80211 $(INSTALL_DATA) ./files/hostapd.sh $(1)/lib/netifd/hostapd.sh + $(INSTALL_BIN) ./files/hostapd.hotplug $(1)/etc/hotplug.d/ieee80211/20-hostapd $(INSTALL_BIN) ./files/wps-hotplug.sh $(1)/etc/rc.button/wps endef diff --git a/package/network/services/hostapd/files/hostapd.hotplug b/package/network/services/hostapd/files/hostapd.hotplug new file mode 100644 index 0000000000..d568b3c85a --- /dev/null +++ b/package/network/services/hostapd/files/hostapd.hotplug @@ -0,0 +1,14 @@ +#!/bin/sh + +[ ${ACTION} = "remove" -a -n "${DEVICENAME}" ] && { + kill $(cat /var/run/hostapd-${DEVICENAME}.pid) + rm -rf /var/run/hostapd-${DEVICENAME}.pid /var/run/hostapd-${DEVICENAME}/ + kill $(cat /var/run/wpa_supplicant-${DEVICENAME}.pid) + rm -rf /var/run/wpa_supplicant-${DEVICENAME}.pid /var/run/wpa_supplicant-${DEVICENAME}/ +} + +[ ${ACTION} = "add" -a -n "${DEVICENAME}" ] && { + /usr/sbin/hostapd -s -n ${DEVICENAME} -P /var/run/hostapd-${DEVICENAME}.pid -g /var/run/hostapd-${DEVICENAME}/global -B & + mkdir -p /var/run/wpa_supplicant-${DEVICENAME} + /usr/sbin/wpa_supplicant -s -n ${DEVICENAME} -P /var/run/wpa_supplicant-${DEVICENAME}.pid -g /var/run/wpa_supplicant-${DEVICENAME}/global -B & +} diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index 3c1504ca60..f03b98ff85 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -254,7 +254,7 @@ hostapd_set_bss_options() { wireless_vif_parse_encryption - local bss_conf + local bss_conf bss_md5sum local wep_rekey wpa_group_rekey wpa_pair_rekey wpa_master_rekey wpa_key_mgmt json_get_vars \ @@ -627,6 +627,9 @@ hostapd_set_bss_options() { } } + bss_md5sum=$(echo $bss_conf | md5sum | cut -d" " -f1) + append bss_conf "config_id=$bss_md5sum" "$N" + append "$var" "$bss_conf" "$N" return 0 } @@ -950,21 +953,19 @@ EOF } wpa_supplicant_run() { - local ifname="$1"; shift + local ifname="$1" + local hostapd_ctrl="$2" _wpa_supplicant_common "$ifname" - /usr/sbin/wpa_supplicant -B -s \ - ${network_bridge:+-b $network_bridge} \ - -P "/var/run/wpa_supplicant-${ifname}.pid" \ - -D ${_w_driver:-wext} \ - -i "$ifname" \ - -c "$_config" \ - -C "$_rpath" \ - "$@" + ubus call wpa_supplicant.$phy config_add "{ \ + \"driver\": \"${_w_driver:-wext}\", \"ctrl\": \"$_rpath\", \ + \"iface\": \"$ifname\", \"config\": \"$_config\" \ + ${network_bridge:+, \"bridge\": \"$network_bridge\"} \ + ${hostapd_ctrl:+, \"hostapd_ctrl\": \"$hostapd_ctrl\"} \ + }" ret="$?" - wireless_add_process "$(cat "/var/run/wpa_supplicant-${ifname}.pid")" /usr/sbin/wpa_supplicant 1 [ "$ret" != 0 ] && wireless_setup_vif_failed WPA_SUPPLICANT_FAILED @@ -972,5 +973,5 @@ wpa_supplicant_run() { } hostapd_common_cleanup() { - killall hostapd wpa_supplicant meshd-nl80211 + killall meshd-nl80211 } diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index 0eb0a4a3ba..6842c0e63e 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -22,7 +22,16 @@ #define OCE_STA_CFON_ENABLED(hapd) \ ((hapd->conf->oce & OCE_STA_CFON) && \ -@@ -145,6 +146,7 @@ struct hostapd_data { +@@ -72,6 +73,8 @@ struct hapd_interfaces { + #ifdef CONFIG_DPP + struct dpp_global *dpp; + #endif /* CONFIG_DPP */ ++ struct ubus_object ubus; ++ char *name; + }; + + enum hostapd_chan_status { +@@ -145,6 +148,7 @@ struct hostapd_data { struct hostapd_iface *iface; struct hostapd_config *iconf; struct hostapd_bss_config *conf; @@ -30,6 +39,14 @@ int interface_added; /* virtual interface added for this BSS */ unsigned int started:1; unsigned int disabled:1; +@@ -580,6 +584,7 @@ hostapd_alloc_bss_data(struct hostapd_if + struct hostapd_bss_config *bss); + int hostapd_setup_interface(struct hostapd_iface *iface); + int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); ++void hostapd_set_own_neighbor_report(struct hostapd_data *hapd); + void hostapd_interface_deinit(struct hostapd_iface *iface); + void hostapd_interface_free(struct hostapd_iface *iface); + struct hostapd_iface * hostapd_alloc_iface(void); --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -380,6 +380,7 @@ static void hostapd_free_hapd_data(struc @@ -298,6 +315,36 @@ /* Remove interface from the global list of interfaces */ prev = global->ifaces; if (prev == wpa_s) { +@@ -6520,6 +6524,8 @@ struct wpa_global * wpa_supplicant_init( + if (params->override_ctrl_interface) + global->params.override_ctrl_interface = + os_strdup(params->override_ctrl_interface); ++ if (params->name) ++ global->params.name = os_strdup(params->name); + #ifdef CONFIG_MATCH_IFACE + global->params.match_iface_count = params->match_iface_count; + if (params->match_iface_count) { +@@ -6626,8 +6632,12 @@ int wpa_supplicant_run(struct wpa_global + eloop_register_signal_terminate(wpa_supplicant_terminate, global); + eloop_register_signal_reconfig(wpa_supplicant_reconfig, global); + ++ wpas_ubus_add(global); ++ + eloop_run(); + ++ wpas_ubus_free(global); ++ + return 0; + } + +@@ -6687,6 +6697,7 @@ void wpa_supplicant_deinit(struct wpa_gl + #ifdef CONFIG_MATCH_IFACE + os_free(global->params.match_ifaces); + #endif /* CONFIG_MATCH_IFACE */ ++ os_free(global->params.name); + #ifdef CONFIG_P2P + os_free(global->params.conf_p2p_dev); + #endif /* CONFIG_P2P */ --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -17,6 +17,7 @@ @@ -308,7 +355,25 @@ extern const char *const wpa_supplicant_version; extern const char *const wpa_supplicant_license; -@@ -506,6 +507,7 @@ struct wpa_supplicant { +@@ -246,6 +247,8 @@ struct wpa_params { + */ + int match_iface_count; + #endif /* CONFIG_MATCH_IFACE */ ++ ++ char *name; + }; + + struct p2p_srv_bonjour { +@@ -306,6 +309,8 @@ struct wpa_global { + #endif /* CONFIG_WIFI_DISPLAY */ + + struct psk_list_entry *add_psk; /* From group formation */ ++ ++ struct ubus_object ubus_global; + }; + + +@@ -506,6 +511,7 @@ struct wpa_supplicant { unsigned char own_addr[ETH_ALEN]; unsigned char perm_addr[ETH_ALEN]; char ifname[100]; @@ -335,3 +400,61 @@ if (wpa_s->conf->wps_cred_processing == 1) return 0; +--- a/hostapd/main.c ++++ b/hostapd/main.c +@@ -688,7 +688,7 @@ int main(int argc, char *argv[]) + wpa_supplicant_event = hostapd_wpa_event; + wpa_supplicant_event_global = hostapd_wpa_event_global; + for (;;) { +- c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:g:G:v::"); ++ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:g:G:n:v::"); + if (c < 0) + break; + switch (c) { +@@ -763,6 +763,8 @@ int main(int argc, char *argv[]) + if (hostapd_get_interface_names(&if_names, + &if_names_size, optarg)) + goto out; ++ case 'n': ++ interfaces.name = optarg; + break; + default: + usage(); +@@ -894,6 +896,7 @@ int main(int argc, char *argv[]) + } + + hostapd_global_ctrl_iface_init(&interfaces); ++ hostapd_ubus_add(&interfaces); + + if (hostapd_global_run(&interfaces, daemonize, pid_file)) { + wpa_printf(MSG_ERROR, "Failed to start eloop"); +@@ -903,6 +906,7 @@ int main(int argc, char *argv[]) + ret = 0; + + out: ++ hostapd_ubus_free(&interfaces); + hostapd_global_ctrl_iface_deinit(&interfaces); + /* Deinitialize all interfaces */ + for (i = 0; i < interfaces.count; i++) { +--- a/wpa_supplicant/main.c ++++ b/wpa_supplicant/main.c +@@ -203,7 +203,7 @@ int main(int argc, char *argv[]) + + for (;;) { + c = getopt(argc, argv, +- "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuv::W"); ++ "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:n:No:O:p:P:qsTtuv::W"); + if (c < 0) + break; + switch (c) { +@@ -271,6 +271,10 @@ int main(int argc, char *argv[]) + params.conf_p2p_dev = optarg; + break; + #endif /* CONFIG_P2P */ ++ case 'n': ++ params.name = optarg; ++ iface_count = 0; ++ break; + case 'o': + params.override_driver = optarg; + break; diff --git a/package/network/services/hostapd/patches/700-wifi-reload.patch b/package/network/services/hostapd/patches/700-wifi-reload.patch new file mode 100644 index 0000000000..c5ba631a0f --- /dev/null +++ b/package/network/services/hostapd/patches/700-wifi-reload.patch @@ -0,0 +1,118 @@ +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -2470,6 +2470,8 @@ static int hostapd_config_fill(struct ho + bss->isolate = atoi(pos); + } else if (os_strcmp(buf, "ap_max_inactivity") == 0) { + bss->ap_max_inactivity = atoi(pos); ++ } else if (os_strcmp(buf, "config_id") == 0) { ++ bss->config_id = os_strdup(pos); + } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { + bss->skip_inactivity_poll = atoi(pos); + } else if (os_strcmp(buf, "country_code") == 0) { +--- a/src/ap/ap_config.c ++++ b/src/ap/ap_config.c +@@ -698,6 +698,7 @@ void hostapd_config_free_bss(struct host + os_free(conf->radius_req_attr_sqlite); + os_free(conf->rsn_preauth_interfaces); + os_free(conf->ctrl_interface); ++ os_free(conf->config_id); + os_free(conf->ca_cert); + os_free(conf->server_cert); + os_free(conf->server_cert2); +--- a/src/ap/ap_config.h ++++ b/src/ap/ap_config.h +@@ -829,6 +829,7 @@ struct hostapd_bss_config { + */ + u8 mka_psk_set; + #endif /* CONFIG_MACSEC */ ++ char *config_id; + }; + + /** +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -242,13 +242,13 @@ int hostapd_reload_config(struct hostapd + if (newconf == NULL) + return -1; + +- hostapd_clear_old(iface); +- + oldconf = hapd->iconf; + if (hostapd_iface_conf_changed(newconf, oldconf)) { + char *fname; + int res; + ++ hostapd_clear_old(iface); ++ + wpa_printf(MSG_DEBUG, + "Configuration changes include interface/BSS modification - force full disable+enable sequence"); + fname = os_strdup(iface->config_fname); +@@ -273,6 +273,22 @@ int hostapd_reload_config(struct hostapd + wpa_printf(MSG_ERROR, + "Failed to enable interface on config reload"); + return res; ++ } else { ++ for (j = 0; j < iface->num_bss; j++) { ++ hapd = iface->bss[j]; ++ if (!hapd->config_id || strcmp(hapd->config_id, newconf->bss[j]->config_id)) { ++ hostapd_flush_old_stations(iface->bss[j], ++ WLAN_REASON_PREV_AUTH_NOT_VALID); ++ hostapd_broadcast_wep_clear(iface->bss[j]); ++ ++#ifndef CONFIG_NO_RADIUS ++ /* TODO: update dynamic data based on changed configuration ++ * items (e.g., open/close sockets, etc.) */ ++ radius_client_flush(iface->bss[j]->radius, 0); ++#endif /* CONFIG_NO_RADIUS */ ++ wpa_printf(MSG_INFO, "bss %d changed", j); ++ } ++ } + } + iface->conf = newconf; + +@@ -289,6 +305,12 @@ int hostapd_reload_config(struct hostapd + + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; ++ if (hapd->config_id) { ++ os_free(hapd->config_id); ++ hapd->config_id = NULL; ++ } ++ if (newconf->bss[j]->config_id) ++ hapd->config_id = strdup(newconf->bss[j]->config_id); + hapd->iconf = newconf; + hapd->conf = newconf->bss[j]; + hostapd_reload_bss(hapd); +@@ -2257,6 +2279,10 @@ hostapd_alloc_bss_data(struct hostapd_if + hapd->iconf = conf; + hapd->conf = bss; + hapd->iface = hapd_iface; ++ if (bss->config_id) ++ hapd->config_id = strdup(bss->config_id); ++ else ++ hapd->config_id = NULL; + if (conf) + hapd->driver = conf->driver; + hapd->ctrl_sock = -1; +--- a/src/ap/hostapd.h ++++ b/src/ap/hostapd.h +@@ -149,6 +149,7 @@ struct hostapd_data { + struct hostapd_config *iconf; + struct hostapd_bss_config *conf; + struct hostapd_ubus_bss ubus; ++ char *config_id; + int interface_added; /* virtual interface added for this BSS */ + unsigned int started:1; + unsigned int disabled:1; +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -4295,6 +4295,9 @@ static int wpa_driver_nl80211_set_ap(voi + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", + ret, strerror(-ret)); ++ if (!bss->beacon_set) ++ ret = 0; ++ bss->beacon_set = 0; + } else { + bss->beacon_set = 1; + nl80211_set_bss(bss, params->cts_protect, params->preamble, diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c index 3b768d0e8c..e25c3294ee 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.c +++ b/package/network/services/hostapd/src/src/ap/ubus.c @@ -26,12 +26,16 @@ static struct ubus_context *ctx; static struct blob_buf b; static int ctx_ref; +static inline struct hapd_interfaces *get_hapd_interfaces_from_object(struct ubus_object *obj) +{ + return container_of(obj, struct hapd_interfaces, ubus); +} + static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj) { return container_of(obj, struct hostapd_data, ubus.obj); } - struct ubus_banned_client { struct avl_node avl; u8 addr[ETH_ALEN]; @@ -142,6 +146,16 @@ hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time) eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd); } +static int +hostapd_bss_reload(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); + hostapd_reload_config(hapd->iface); + hostapd_reload_iface(hapd->iface); +} + static int hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, @@ -379,6 +393,70 @@ hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj, return 0; } +enum { + CONFIG_IFACE, + CONFIG_FILE, + __CONFIG_MAX +}; + +static const struct blobmsg_policy config_add_policy[__CONFIG_MAX] = { + [CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING }, + [CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING }, +}; + +static int +hostapd_config_add(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__CONFIG_MAX]; + struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj); + char buf[128]; + + blobmsg_parse(config_add_policy, __CONFIG_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[CONFIG_FILE] || !tb[CONFIG_IFACE]) + return UBUS_STATUS_INVALID_ARGUMENT; + + snprintf(buf, sizeof(buf), "bss_config=%s:%s", + blobmsg_get_string(tb[CONFIG_IFACE]), + blobmsg_get_string(tb[CONFIG_FILE])); + + if (hostapd_add_iface(interfaces, buf)) + return UBUS_STATUS_INVALID_ARGUMENT; + + return UBUS_STATUS_OK; +} + +enum { + CONFIG_REM_IFACE, + __CONFIG_REM_MAX +}; + +static const struct blobmsg_policy config_remove_policy[__CONFIG_REM_MAX] = { + [CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING }, +}; + +static int +hostapd_config_remove(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__CONFIG_REM_MAX]; + struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj); + char buf[128]; + + blobmsg_parse(config_remove_policy, __CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[CONFIG_REM_IFACE]) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (hostapd_remove_iface(interfaces, blobmsg_get_string(tb[CONFIG_REM_IFACE]))) + return UBUS_STATUS_INVALID_ARGUMENT; + + return UBUS_STATUS_OK; +} + enum { CSA_FREQ, CSA_BCN_COUNT, @@ -949,6 +1027,7 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj, #endif static const struct ubus_method bss_methods[] = { + UBUS_METHOD_NOARG("reload", hostapd_bss_reload), UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients), UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy), UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans), @@ -1021,6 +1100,56 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd) free(name); } +static const struct ubus_method daemon_methods[] = { + UBUS_METHOD("config_add", hostapd_config_add, config_add_policy), + UBUS_METHOD("config_remove", hostapd_config_remove, config_remove_policy), +}; + +static struct ubus_object_type daemon_object_type = + UBUS_OBJECT_TYPE("hostapd", daemon_methods); + +void hostapd_ubus_add(struct hapd_interfaces *interfaces) +{ + struct ubus_object *obj = &interfaces->ubus; + int name_len; + int ret; + + if (!hostapd_ubus_init()) + return; + + name_len = strlen("hostapd") + 1; + if (interfaces->name) + name_len += strlen(interfaces->name) + 1; + obj->name = malloc(name_len); + strcpy(obj->name, "hostapd"); + if (interfaces->name) { + strcat(obj->name, "."); + strcat(obj->name, interfaces->name); + } + + obj->type = &daemon_object_type; + obj->methods = daemon_object_type.methods; + obj->n_methods = daemon_object_type.n_methods; + ret = ubus_add_object(ctx, obj); + hostapd_ubus_ref_inc(); +} + +void hostapd_ubus_free(struct hapd_interfaces *interfaces) +{ + struct ubus_object *obj = &interfaces->ubus; + char *name = (char *) obj->name; + + if (!ctx) + return; + + if (obj->id) { + ubus_remove_object(ctx, obj); + hostapd_ubus_ref_dec(); + } + + free(name); +} + struct ubus_event_req { struct ubus_notify_request nreq; int resp; diff --git a/package/network/services/hostapd/src/src/ap/ubus.h b/package/network/services/hostapd/src/src/ap/ubus.h index 58ebe0e65b..27acd32659 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.h +++ b/package/network/services/hostapd/src/src/ap/ubus.h @@ -25,6 +25,7 @@ struct hostapd_ubus_request { struct hostapd_iface; struct hostapd_data; +struct hapd_interfaces; #ifdef UBUS_SUPPORT @@ -45,6 +46,9 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd); int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req); void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac); +void hostapd_ubus_add(struct hapd_interfaces *interfaces); +void hostapd_ubus_free(struct hapd_interfaces *interfaces); + #else struct hostapd_ubus_bss {}; @@ -73,6 +77,14 @@ static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct ho static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac) { } + +static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces) +{ +} + +static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces) +{ +} #endif #endif diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.c b/package/network/services/hostapd/src/wpa_supplicant/ubus.c index 5fdb57be7a..9a98979e9a 100644 --- a/package/network/services/hostapd/src/wpa_supplicant/ubus.c +++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.c @@ -20,6 +20,11 @@ static struct ubus_context *ctx; static struct blob_buf b; static int ctx_ref; +static inline struct wpa_global *get_wpa_global_from_object(struct ubus_object *obj) +{ + return container_of(obj, struct wpa_global, ubus_global); +} + static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *obj) { return container_of(obj, struct wpa_supplicant, ubus.obj); @@ -95,6 +100,19 @@ wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj, return 0; } +static int +wpas_bss_reload(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct wpa_supplicant *wpa_s = get_wpas_from_object(obj); + + if (wpa_supplicant_reload_configuration(wpa_s)) + return UBUS_STATUS_UNKNOWN_ERROR; + else + return 0; +} + #ifdef CONFIG_WPS enum { WPS_START_MULTI_AP, @@ -146,11 +164,12 @@ wpas_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj, #endif static const struct ubus_method bss_methods[] = { + UBUS_METHOD_NOARG("reload", wpas_bss_reload), + UBUS_METHOD_NOARG("get_features", wpas_bss_get_features), #ifdef CONFIG_WPS UBUS_METHOD_NOARG("wps_start", wpas_bss_wps_start), UBUS_METHOD_NOARG("wps_cancel", wpas_bss_wps_cancel), #endif - UBUS_METHOD_NOARG("get_features", wpas_bss_get_features), }; static struct ubus_object_type bss_object_type = @@ -162,8 +181,6 @@ void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s) char *name; int ret; - if (!wpas_ubus_init()) - return; if (asprintf(&name, "wpa_supplicant.%s", wpa_s->ifname) < 0) return; @@ -192,6 +209,159 @@ void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s) free(name); } +enum { + WPAS_CONFIG_DRIVER, + WPAS_CONFIG_IFACE, + WPAS_CONFIG_BRIDGE, + WPAS_CONFIG_HOSTAPD_CTRL, + WPAS_CONFIG_CTRL, + WPAS_CONFIG_FILE, + __WPAS_CONFIG_MAX +}; + +static const struct blobmsg_policy wpas_config_add_policy[__WPAS_CONFIG_MAX] = { + [WPAS_CONFIG_DRIVER] = { "driver", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_BRIDGE] = { "bridge", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_HOSTAPD_CTRL] = { "hostapd_ctrl", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_CTRL] = { "ctrl", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING }, +}; + +static int +wpas_config_add(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__WPAS_CONFIG_MAX]; + struct wpa_global *global = get_wpa_global_from_object(obj); + struct wpa_interface *iface; + + blobmsg_parse(wpas_config_add_policy, __WPAS_CONFIG_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[WPAS_CONFIG_FILE] || !tb[WPAS_CONFIG_IFACE] || !tb[WPAS_CONFIG_DRIVER]) + return UBUS_STATUS_INVALID_ARGUMENT; + + iface = os_zalloc(sizeof(struct wpa_interface)); + if (iface == NULL) + return UBUS_STATUS_UNKNOWN_ERROR; + + iface->driver = blobmsg_get_string(tb[WPAS_CONFIG_DRIVER]); + iface->ifname = blobmsg_get_string(tb[WPAS_CONFIG_IFACE]); + iface->confname = blobmsg_get_string(tb[WPAS_CONFIG_FILE]); + + if (tb[WPAS_CONFIG_BRIDGE]) + iface->bridge_ifname = blobmsg_get_string(tb[WPAS_CONFIG_BRIDGE]); + + if (tb[WPAS_CONFIG_CTRL]) + iface->ctrl_interface = blobmsg_get_string(tb[WPAS_CONFIG_CTRL]); + + if (tb[WPAS_CONFIG_HOSTAPD_CTRL]) + iface->hostapd_ctrl = blobmsg_get_string(tb[WPAS_CONFIG_HOSTAPD_CTRL]); + + if (!wpa_supplicant_add_iface(global, iface, NULL)) + return UBUS_STATUS_INVALID_ARGUMENT; + + return UBUS_STATUS_OK; +} + +enum { + WPAS_CONFIG_REM_IFACE, + __WPAS_CONFIG_REM_MAX +}; + +static const struct blobmsg_policy wpas_config_remove_policy[__WPAS_CONFIG_REM_MAX] = { + [WPAS_CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING }, +}; + +static int +wpas_config_remove(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__WPAS_CONFIG_REM_MAX]; + struct wpa_global *global = get_wpa_global_from_object(obj); + struct wpa_supplicant *wpa_s = NULL; + unsigned int found = 0; + + blobmsg_parse(wpas_config_remove_policy, __WPAS_CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[WPAS_CONFIG_REM_IFACE]) + return UBUS_STATUS_INVALID_ARGUMENT; + + /* find wpa_s object for to-be-removed interface */ + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (!strncmp(wpa_s->ifname, + blobmsg_get_string(tb[WPAS_CONFIG_REM_IFACE]), + sizeof(wpa_s->ifname))) + { + found = 1; + break; + } + } + + if (!found) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (wpa_supplicant_remove_iface(global, wpa_s, 0)) + return UBUS_STATUS_INVALID_ARGUMENT; + + return UBUS_STATUS_OK; +} + +static const struct ubus_method wpas_daemon_methods[] = { + UBUS_METHOD("config_add", wpas_config_add, wpas_config_add_policy), + UBUS_METHOD("config_remove", wpas_config_remove, wpas_config_remove_policy), +}; + +static struct ubus_object_type wpas_daemon_object_type = + UBUS_OBJECT_TYPE("wpa_supplicant", wpas_daemon_methods); + +void wpas_ubus_add(struct wpa_global *global) +{ + struct ubus_object *obj = &global->ubus_global; + int name_len; + int ret; + + if (!wpas_ubus_init()) + return; + + name_len = strlen("wpa_supplicant") + 1; + if (global->params.name) + name_len += strlen(global->params.name) + 1; + obj->name = malloc(name_len); + strcpy(obj->name, "wpa_supplicant"); + + if (global->params.name) + { + strcat(obj->name, "."); + strcat(obj->name, global->params.name); + } + + obj->type = &wpas_daemon_object_type; + obj->methods = wpas_daemon_object_type.methods; + obj->n_methods = wpas_daemon_object_type.n_methods; + ret = ubus_add_object(ctx, obj); + wpas_ubus_ref_inc(); +} + +void wpas_ubus_free(struct wpa_global *global) +{ + struct ubus_object *obj = &global->ubus_global; + char *name = (char *) obj->name; + + if (!ctx) + return; + + if (obj->id) { + ubus_remove_object(ctx, obj); + wpas_ubus_ref_dec(); + } + + free(name); +} + + #ifdef CONFIG_WPS void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.h b/package/network/services/hostapd/src/wpa_supplicant/ubus.h index c37e743e73..bf92b98c01 100644 --- a/package/network/services/hostapd/src/wpa_supplicant/ubus.h +++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.h @@ -10,6 +10,8 @@ #define __WPAS_UBUS_H struct wpa_supplicant; +struct wpa_global; + #include "wps_supplicant.h" #ifdef UBUS_SUPPORT @@ -22,6 +24,9 @@ struct wpas_ubus_bss { void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s); void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s); +void wpas_ubus_add(struct wpa_global *global); +void wpas_ubus_free(struct wpa_global *global); + #ifdef CONFIG_WPS void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); #endif @@ -48,6 +53,14 @@ static inline void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s) static inline void wpas_ubus_notify(struct wpa_supplicant *wpa_s, struct wps_credential *cred) { } + +static inline void wpas_ubus_add(struct wpa_global *global) +{ +} + +static inline void wpas_ubus_free(struct wpa_global *global) +{ +} #endif #endif