diff options
| author | Cy Schubert <cy@FreeBSD.org> | 2017-10-18 03:44:27 +0000 | 
|---|---|---|
| committer | Cy Schubert <cy@FreeBSD.org> | 2017-10-18 03:44:27 +0000 | 
| commit | 256810032c472505440606bd9c1c4f7dbf06b0a2 (patch) | |
| tree | d019f4f1ae29b86cbd3e9e74f832689976a267cf /src/ap/hostapd.c | |
| parent | b834757ea3bcd1bba3381ff7cab216458d8f7efb (diff) | |
Diffstat (limited to 'src/ap/hostapd.c')
| -rw-r--r-- | src/ap/hostapd.c | 424 | 
1 files changed, 373 insertions, 51 deletions
| diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index c09c17a446963..9fafc7f457bb0 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -12,6 +12,7 @@  #include "utils/eloop.h"  #include "common/ieee802_11_defs.h"  #include "common/wpa_ctrl.h" +#include "common/hw_features_common.h"  #include "radius/radius_client.h"  #include "radius/radius_das.h"  #include "eap_server/tncs.h" @@ -42,6 +43,8 @@  #include "x_snoop.h"  #include "dhcp_snoop.h"  #include "ndisc_snoop.h" +#include "neighbor_db.h" +#include "rrm.h"  static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); @@ -203,10 +206,12 @@ int hostapd_reload_config(struct hostapd_iface *iface)  static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, -					      char *ifname) +					      const char *ifname)  {  	int i; +	if (!ifname) +		return;  	for (i = 0; i < NUM_WEP_KEYS; i++) {  		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,  					0, NULL, 0, NULL, 0)) { @@ -334,6 +339,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)  	wpabuf_free(hapd->mesh_pending_auth);  	hapd->mesh_pending_auth = NULL;  #endif /* CONFIG_MESH */ + +	hostapd_clean_rrm(hapd);  } @@ -367,7 +374,7 @@ static void sta_track_deinit(struct hostapd_iface *iface)  				     list))) {  		dl_list_del(&info->list);  		iface->num_sta_seen--; -		os_free(info); +		sta_track_del(info);  	}  } @@ -511,6 +518,9 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)  	if (hostapd_drv_none(hapd))  		return 0; +	if (iface->conf->use_driver_iface_addr) +		return 0; +  	/* Generate BSSID mask that is large enough to cover the BSSIDs. */  	/* Determine the bits necessary to cover the number of BSSIDs. */ @@ -520,7 +530,7 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)  	/* Determine the bits necessary to any configured BSSIDs,  	   if they are higher than the number of BSSIDs. */  	for (j = 0; j < iface->conf->num_bss; j++) { -		if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) { +		if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) {  			if (j)  				auto_addr++;  			continue; @@ -672,7 +682,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,  	if (attr->acct_session_id) {  		num_attr++; -		if (attr->acct_session_id_len != 17) { +		if (attr->acct_session_id_len != 16) {  			wpa_printf(MSG_DEBUG,  				   "RADIUS DAS: Acct-Session-Id cannot match");  			return NULL; @@ -682,10 +692,9 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,  		for (sta = hapd->sta_list; sta; sta = sta->next) {  			if (!sta->radius_das_match)  				continue; -			os_snprintf(buf, sizeof(buf), "%08X-%08X", -				    sta->acct_session_id_hi, -				    sta->acct_session_id_lo); -			if (os_memcmp(attr->acct_session_id, buf, 17) != 0) +			os_snprintf(buf, sizeof(buf), "%016llX", +				    (unsigned long long) sta->acct_session_id); +			if (os_memcmp(attr->acct_session_id, buf, 16) != 0)  				sta->radius_das_match = 0;  			else  				count++; @@ -701,7 +710,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,  	if (attr->acct_multi_session_id) {  		num_attr++; -		if (attr->acct_multi_session_id_len != 17) { +		if (attr->acct_multi_session_id_len != 16) {  			wpa_printf(MSG_DEBUG,  				   "RADIUS DAS: Acct-Multi-Session-Id cannot match");  			return NULL; @@ -712,14 +721,14 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,  			if (!sta->radius_das_match)  				continue;  			if (!sta->eapol_sm || -			    !sta->eapol_sm->acct_multi_session_id_hi) { +			    !sta->eapol_sm->acct_multi_session_id) {  				sta->radius_das_match = 0;  				continue;  			} -			os_snprintf(buf, sizeof(buf), "%08X+%08X", -				    sta->eapol_sm->acct_multi_session_id_hi, -				    sta->eapol_sm->acct_multi_session_id_lo); -			if (os_memcmp(attr->acct_multi_session_id, buf, 17) != +			os_snprintf(buf, sizeof(buf), "%016llX", +				    (unsigned long long) +				    sta->eapol_sm->acct_multi_session_id); +			if (os_memcmp(attr->acct_multi_session_id, buf, 16) !=  			    0)  				sta->radius_das_match = 0;  			else @@ -905,12 +914,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)  	hapd->started = 1;  	if (!first || first == -1) { -		if (hostapd_mac_comp_empty(conf->bssid) == 0) { -			/* Allocate the next available BSSID. */ -			do { -				inc_byte_array(hapd->own_addr, ETH_ALEN); -			} while (mac_in_conf(hapd->iconf, hapd->own_addr)); -		} else { +		u8 *addr = hapd->own_addr; + +		if (!is_zero_ether_addr(conf->bssid)) {  			/* Allocate the configured BSSID. */  			os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN); @@ -922,11 +928,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)  					   "the radio", conf->iface);  				return -1;  			} +		} else if (hapd->iconf->use_driver_iface_addr) { +			addr = NULL; +		} else { +			/* Allocate the next available BSSID. */ +			do { +				inc_byte_array(hapd->own_addr, ETH_ALEN); +			} while (mac_in_conf(hapd->iconf, hapd->own_addr));  		}  		hapd->interface_added = 1;  		if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, -				   conf->iface, hapd->own_addr, hapd, +				   conf->iface, addr, hapd,  				   &hapd->drv_priv, force_ifname, if_addr,  				   conf->bridge[0] ? conf->bridge : NULL,  				   first == -1)) { @@ -935,11 +948,19 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)  			hapd->interface_added = 0;  			return -1;  		} + +		if (!addr) +			os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);  	}  	if (conf->wmm_enabled < 0)  		conf->wmm_enabled = hapd->iconf->ieee80211n; +#ifdef CONFIG_IEEE80211R +	if (is_zero_ether_addr(conf->r1_key_holder)) +		os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN); +#endif /* CONFIG_IEEE80211R */ +  #ifdef CONFIG_MESH  	if (hapd->iface->mconf == NULL)  		flush_old_stations = 0; @@ -1022,6 +1043,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)  		das_conf.time_window = conf->radius_das_time_window;  		das_conf.require_event_timestamp =  			conf->radius_das_require_event_timestamp; +		das_conf.require_message_authenticator = +			conf->radius_das_require_message_authenticator;  		das_conf.ctx = hapd;  		das_conf.disconnect = hostapd_das_disconnect;  		hapd->radius_das = radius_das_init(&das_conf); @@ -1509,15 +1532,128 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,  #endif /* CONFIG_FST */ -/** - * hostapd_setup_interface_complete - Complete interface setup - * - * This function is called when previous steps in the interface setup has been - * completed. This can also start operations, e.g., DFS, that will require - * additional processing before interface is ready to be enabled. Such - * operations will call this function from eloop callbacks when finished. - */ -int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) +#ifdef NEED_AP_MLME +static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd, +						    int ht, int vht) +{ +	if (!ht && !vht) +		return NR_CHAN_WIDTH_20; +	if (!hapd->iconf->secondary_channel) +		return NR_CHAN_WIDTH_20; +	if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT) +		return NR_CHAN_WIDTH_40; +	if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ) +		return NR_CHAN_WIDTH_80; +	if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ) +		return NR_CHAN_WIDTH_160; +	if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) +		return NR_CHAN_WIDTH_80P80; +	return NR_CHAN_WIDTH_20; +} +#endif /* NEED_AP_MLME */ + + +static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd) +{ +#ifdef NEED_AP_MLME +	u16 capab = hostapd_own_capab_info(hapd); +	int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n; +	int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac; +	struct wpa_ssid_value ssid; +	u8 channel, op_class; +	int center_freq1 = 0, center_freq2 = 0; +	enum nr_chan_width width; +	u32 bssid_info; +	struct wpabuf *nr; + +	if (!(hapd->conf->radio_measurements[0] & +	      WLAN_RRM_CAPS_NEIGHBOR_REPORT)) +		return; + +	bssid_info = 3; /* AP is reachable */ +	bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */ +	bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */ + +	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) +		bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; + +	bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */ + +	if (hapd->conf->wmm_enabled) { +		bssid_info |= NEI_REP_BSSID_INFO_QOS; + +		if (hapd->conf->wmm_uapsd && +		    (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) +			bssid_info |= NEI_REP_BSSID_INFO_APSD; +	} + +	if (ht) { +		bssid_info |= NEI_REP_BSSID_INFO_HT | +			NEI_REP_BSSID_INFO_DELAYED_BA; + +		/* VHT bit added in IEEE P802.11-REVmc/D4.3 */ +		if (vht) +			bssid_info |= NEI_REP_BSSID_INFO_VHT; +	} + +	/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */ + +	ieee80211_freq_to_channel_ext(hapd->iface->freq, +				      hapd->iconf->secondary_channel, +				      hapd->iconf->vht_oper_chwidth, +				      &op_class, &channel); +	width = hostapd_get_nr_chan_width(hapd, ht, vht); +	if (vht) { +		center_freq1 = ieee80211_chan_to_freq( +			NULL, op_class, +			hapd->iconf->vht_oper_centr_freq_seg0_idx); +		if (width == NR_CHAN_WIDTH_80P80) +			center_freq2 = ieee80211_chan_to_freq( +				NULL, op_class, +				hapd->iconf->vht_oper_centr_freq_seg1_idx); +	} else if (ht) { +		center_freq1 = hapd->iface->freq + +			10 * hapd->iconf->secondary_channel; +	} + +	ssid.ssid_len = hapd->conf->ssid.ssid_len; +	os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len); + +	/* +	 * Neighbor Report element size = BSSID + BSSID info + op_class + chan + +	 * phy type + wide bandwidth channel subelement. +	 */ +	nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5); +	if (!nr) +		return; + +	wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN); +	wpabuf_put_le32(nr, bssid_info); +	wpabuf_put_u8(nr, op_class); +	wpabuf_put_u8(nr, channel); +	wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht)); + +	/* +	 * Wide Bandwidth Channel subelement may be needed to allow the +	 * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0 +	 * Figure 9-301. +	 */ +	wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN); +	wpabuf_put_u8(nr, 3); +	wpabuf_put_u8(nr, width); +	wpabuf_put_u8(nr, center_freq1); +	wpabuf_put_u8(nr, center_freq2); + +	hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci, +			     hapd->iconf->civic); + +	wpabuf_free(nr); +#endif /* NEED_AP_MLME */ +} + + +static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, +						 int err)  {  	struct hostapd_data *hapd = iface->bss[0];  	size_t j; @@ -1633,7 +1769,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)  			} while (j-- > 0);  			goto fail;  		} -		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) +		if (is_zero_ether_addr(hapd->conf->bssid))  			prev_addr = hapd->own_addr;  	}  	hapd = iface->bss[0]; @@ -1641,7 +1777,6 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)  	hostapd_tx_queue_params(iface);  	ap_list_init(iface); -	dl_list_init(&iface->sta_seen);  	hostapd_set_acl(hapd); @@ -1701,6 +1836,9 @@ dfs_offload:  	if (iface->interfaces && iface->interfaces->terminate_on_error > 0)  		iface->interfaces->terminate_on_error--; +	for (j = 0; j < iface->num_bss; j++) +		hostapd_set_own_neighbor_report(iface->bss[j]); +  	return 0;  fail: @@ -1720,6 +1858,89 @@ fail:  /** + * hostapd_setup_interface_complete - Complete interface setup + * + * This function is called when previous steps in the interface setup has been + * completed. This can also start operations, e.g., DFS, that will require + * additional processing before interface is ready to be enabled. Such + * operations will call this function from eloop callbacks when finished. + */ +int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) +{ +	struct hapd_interfaces *interfaces = iface->interfaces; +	struct hostapd_data *hapd = iface->bss[0]; +	unsigned int i; +	int not_ready_in_sync_ifaces = 0; + +	if (!iface->need_to_start_in_sync) +		return hostapd_setup_interface_complete_sync(iface, err); + +	if (err) { +		wpa_printf(MSG_ERROR, "Interface initialization failed"); +		hostapd_set_state(iface, HAPD_IFACE_DISABLED); +		iface->need_to_start_in_sync = 0; +		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); +		if (interfaces && interfaces->terminate_on_error) +			eloop_terminate(); +		return -1; +	} + +	if (iface->ready_to_start_in_sync) { +		/* Already in ready and waiting. should never happpen */ +		return 0; +	} + +	for (i = 0; i < interfaces->count; i++) { +		if (interfaces->iface[i]->need_to_start_in_sync && +		    !interfaces->iface[i]->ready_to_start_in_sync) +			not_ready_in_sync_ifaces++; +	} + +	/* +	 * Check if this is the last interface, if yes then start all the other +	 * waiting interfaces. If not, add this interface to the waiting list. +	 */ +	if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) { +		/* +		 * If this interface went through CAC, do not synchronize, just +		 * start immediately. +		 */ +		iface->need_to_start_in_sync = 0; +		wpa_printf(MSG_INFO, +			   "%s: Finished CAC - bypass sync and start interface", +			   iface->bss[0]->conf->iface); +		return hostapd_setup_interface_complete_sync(iface, err); +	} + +	if (not_ready_in_sync_ifaces > 1) { +		/* need to wait as there are other interfaces still coming up */ +		iface->ready_to_start_in_sync = 1; +		wpa_printf(MSG_INFO, +			   "%s: Interface waiting to sync with other interfaces", +			   iface->bss[0]->conf->iface); +		return 0; +	} + +	wpa_printf(MSG_INFO, +		   "%s: Last interface to sync - starting all interfaces", +		   iface->bss[0]->conf->iface); +	iface->need_to_start_in_sync = 0; +	hostapd_setup_interface_complete_sync(iface, err); +	for (i = 0; i < interfaces->count; i++) { +		if (interfaces->iface[i]->need_to_start_in_sync && +		    interfaces->iface[i]->ready_to_start_in_sync) { +			hostapd_setup_interface_complete_sync( +				interfaces->iface[i], 0); +			/* Only once the interfaces are sync started */ +			interfaces->iface[i]->need_to_start_in_sync = 0; +		} +	} + +	return 0; +} + + +/**   * hostapd_setup_interface - Setup of an interface   * @iface: Pointer to interface data.   * Returns: 0 on success, -1 on failure @@ -1778,6 +1999,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,  	hapd->iface = hapd_iface;  	hapd->driver = hapd->iconf->driver;  	hapd->ctrl_sock = -1; +	dl_list_init(&hapd->ctrl_dst); +	dl_list_init(&hapd->nr_db);  	return hapd;  } @@ -1785,6 +2008,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,  static void hostapd_bss_deinit(struct hostapd_data *hapd)  { +	if (!hapd) +		return;  	wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,  		   hapd->conf->iface);  	hostapd_bss_deinit_no_free(hapd); @@ -1819,8 +2044,11 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)  	}  #endif /* CONFIG_FST */ -	for (j = iface->num_bss - 1; j >= 0; j--) +	for (j = iface->num_bss - 1; j >= 0; j--) { +		if (!iface->bss) +			break;  		hostapd_bss_deinit(iface->bss[j]); +	}  } @@ -1829,6 +2057,8 @@ void hostapd_interface_free(struct hostapd_iface *iface)  	size_t j;  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);  	for (j = 0; j < iface->num_bss; j++) { +		if (!iface->bss) +			break;  		wpa_printf(MSG_DEBUG, "%s: free hapd %p",  			   __func__, iface->bss[j]);  		os_free(iface->bss[j]); @@ -1837,6 +2067,20 @@ void hostapd_interface_free(struct hostapd_iface *iface)  } +struct hostapd_iface * hostapd_alloc_iface(void) +{ +	struct hostapd_iface *hapd_iface; + +	hapd_iface = os_zalloc(sizeof(*hapd_iface)); +	if (!hapd_iface) +		return NULL; + +	dl_list_init(&hapd_iface->sta_seen); + +	return hapd_iface; +} + +  /**   * hostapd_init - Allocate and initialize per-interface data   * @config_file: Path to the configuration file @@ -1854,7 +2098,7 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,  	struct hostapd_data *hapd;  	size_t i; -	hapd_iface = os_zalloc(sizeof(*hapd_iface)); +	hapd_iface = hostapd_alloc_iface();  	if (hapd_iface == NULL)  		goto fail; @@ -2190,7 +2434,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces)  		return NULL;  	interfaces->iface = iface;  	hapd_iface = interfaces->iface[interfaces->count] = -		os_zalloc(sizeof(*hapd_iface)); +		hostapd_alloc_iface();  	if (hapd_iface == NULL) {  		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "  			   "the interface", __func__); @@ -2557,6 +2801,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,  	}  	hostapd_prune_associations(hapd, sta->addr); +	ap_sta_clear_disconnect_timeouts(hapd, sta);  	/* IEEE 802.11F (IAPP) */  	if (hapd->conf->ieee802_11f) @@ -2590,9 +2835,10 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,  		wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);  	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { -		wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " -			   "for " MACSTR " (%d seconds - ap_max_inactivity)", -			   __func__, MAC2STR(sta->addr), +		wpa_printf(MSG_DEBUG, +			   "%s: %s: reschedule ap_handle_timer timeout for " +			   MACSTR " (%d seconds - ap_max_inactivity)", +			   hapd->conf->iface, __func__, MAC2STR(sta->addr),  			   hapd->conf->ap_max_inactivity);  		eloop_cancel_timeout(ap_handle_timer, hapd, sta);  		eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, @@ -2627,12 +2873,23 @@ const char * hostapd_state_text(enum hostapd_iface_state s)  void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)  {  	wpa_printf(MSG_INFO, "%s: interface state %s->%s", -		   iface->conf->bss[0]->iface, hostapd_state_text(iface->state), -		   hostapd_state_text(s)); +		   iface->conf ? iface->conf->bss[0]->iface : "N/A", +		   hostapd_state_text(iface->state), hostapd_state_text(s));  	iface->state = s;  } +int hostapd_csa_in_progress(struct hostapd_iface *iface) +{ +	unsigned int i; + +	for (i = 0; i < iface->num_bss; i++) +		if (iface->bss[i]->csa_in_progress) +			return 1; +	return 0; +} + +  #ifdef NEED_AP_MLME  static void free_beacon_data(struct beacon_data *beacon) @@ -2744,9 +3001,9 @@ free_ap_params:  /* - * TODO: This flow currently supports only changing frequency within the - * same hw_mode. Any other changes to MAC parameters or provided settings (even - * width) are not supported. + * TODO: This flow currently supports only changing channel and width within + * the same hw_mode. Any other changes to MAC parameters or provided settings + * are not supported.   */  static int hostapd_change_config_freq(struct hostapd_data *hapd,  				      struct hostapd_config *conf, @@ -2765,15 +3022,44 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,  		return -1;  	/* if a pointer to old_params is provided we save previous state */ -	if (old_params) { -		old_params->channel = conf->channel; -		old_params->ht_enabled = conf->ieee80211n; -		old_params->sec_channel_offset = conf->secondary_channel; +	if (old_params && +	    hostapd_set_freq_params(old_params, conf->hw_mode, +				    hostapd_hw_get_freq(hapd, conf->channel), +				    conf->channel, conf->ieee80211n, +				    conf->ieee80211ac, +				    conf->secondary_channel, +				    conf->vht_oper_chwidth, +				    conf->vht_oper_centr_freq_seg0_idx, +				    conf->vht_oper_centr_freq_seg1_idx, +				    conf->vht_capab)) +		return -1; + +	switch (params->bandwidth) { +	case 0: +	case 20: +	case 40: +		conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT; +		break; +	case 80: +		if (params->center_freq2) +			conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ; +		else +			conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ; +		break; +	case 160: +		conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ; +		break; +	default: +		return -1;  	}  	conf->channel = channel;  	conf->ieee80211n = params->ht_enabled;  	conf->secondary_channel = params->sec_channel_offset; +	ieee80211_freq_to_chan(params->center_freq1, +			       &conf->vht_oper_centr_freq_seg0_idx); +	ieee80211_freq_to_chan(params->center_freq2, +			       &conf->vht_oper_centr_freq_seg1_idx);  	/* TODO: maybe call here hostapd_config_check here? */ @@ -2787,11 +3073,43 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,  	struct hostapd_iface *iface = hapd->iface;  	struct hostapd_freq_params old_freq;  	int ret; +	u8 chan, vht_bandwidth;  	os_memset(&old_freq, 0, sizeof(old_freq));  	if (!iface || !iface->freq || hapd->csa_in_progress)  		return -1; +	switch (settings->freq_params.bandwidth) { +	case 80: +		if (settings->freq_params.center_freq2) +			vht_bandwidth = VHT_CHANWIDTH_80P80MHZ; +		else +			vht_bandwidth = VHT_CHANWIDTH_80MHZ; +		break; +	case 160: +		vht_bandwidth = VHT_CHANWIDTH_160MHZ; +		break; +	default: +		vht_bandwidth = VHT_CHANWIDTH_USE_HT; +		break; +	} + +	if (ieee80211_freq_to_channel_ext( +		    settings->freq_params.freq, +		    settings->freq_params.sec_channel_offset, +		    vht_bandwidth, +		    &hapd->iface->cs_oper_class, +		    &chan) == NUM_HOSTAPD_MODES) { +		wpa_printf(MSG_DEBUG, +			   "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)", +			   settings->freq_params.freq, +			   settings->freq_params.sec_channel_offset, +			   settings->freq_params.vht_enabled); +		return -1; +	} + +	settings->freq_params.channel = chan; +  	ret = hostapd_change_config_freq(iface->bss[0], iface->conf,  					 &settings->freq_params,  					 &old_freq); @@ -2818,8 +3136,10 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,  		return ret;  	} -	settings->counter_offset_beacon = hapd->cs_c_off_beacon; -	settings->counter_offset_presp = hapd->cs_c_off_proberesp; +	settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon; +	settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp; +	settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon; +	settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;  	return 0;  } @@ -2833,6 +3153,8 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)  	hapd->cs_c_off_beacon = 0;  	hapd->cs_c_off_proberesp = 0;  	hapd->csa_in_progress = 0; +	hapd->cs_c_off_ecsa_beacon = 0; +	hapd->cs_c_off_ecsa_proberesp = 0;  } @@ -2920,6 +3242,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,  	hostapd_enable_iface(iface);  } +#endif /* NEED_AP_MLME */ +  struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,  					const char *ifname) @@ -2940,8 +3264,6 @@ struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,  	return NULL;  } -#endif /* NEED_AP_MLME */ -  void hostapd_periodic_iface(struct hostapd_iface *iface)  { | 
