hostapd: add ubus reload
Add ubus interface to hostapd and wpa_supplicant to allow dynamically reloading wiface configuration without having to restart the hostapd process. As a consequence, both hostapd and wpa_supplicant are now started persistently on boot for each wifi device in the system and then receive ubus calls adding, modifying or removing interface configuration. At a later stage it would be desirable to reduce the services to one single instance managing all radios. Signed-off-by: John Crispin <john@phrozen.org> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
		
							parent
							
								
									155ede4f1f
								
							
						
					
					
						commit
						60fb4c92b6
					
				| @ -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 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										14
									
								
								package/network/services/hostapd/files/hostapd.hotplug
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								package/network/services/hostapd/files/hostapd.hotplug
									
									
									
									
									
										Normal file
									
								
							| @ -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 & | ||||
| } | ||||
| @ -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 | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
							
								
								
									
										118
									
								
								package/network/services/hostapd/patches/700-wifi-reload.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								package/network/services/hostapd/patches/700-wifi-reload.patch
									
									
									
									
									
										Normal file
									
								
							| @ -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, | ||||
| @ -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; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
| { | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user