mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			203 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- a/hostapd/config_file.c
 | |
| +++ b/hostapd/config_file.c
 | |
| @@ -1957,6 +1957,10 @@ static int hostapd_config_fill(struct ho
 | |
|  					   "ht_capab", line);
 | |
|  				errors++;
 | |
|  			}
 | |
| +		} else if (os_strcmp(buf, "dynamic_ht40") == 0) {
 | |
| +			conf->dynamic_ht40 = atoi(pos);
 | |
| +			if (conf->dynamic_ht40 == 1)
 | |
| +				conf->dynamic_ht40 = 1500;
 | |
|  		} else if (os_strcmp(buf, "require_ht") == 0) {
 | |
|  			conf->require_ht = atoi(pos);
 | |
|  #endif /* CONFIG_IEEE80211N */
 | |
| --- a/src/ap/ap_config.h
 | |
| +++ b/src/ap/ap_config.h
 | |
| @@ -434,6 +434,7 @@ struct hostapd_config {
 | |
|  	int ieee80211n;
 | |
|  	int secondary_channel;
 | |
|  	int require_ht;
 | |
| +	int dynamic_ht40;
 | |
|  };
 | |
|  
 | |
|  
 | |
| --- a/src/ap/hostapd.c
 | |
| +++ b/src/ap/hostapd.c
 | |
| @@ -21,6 +21,7 @@
 | |
|  #include "beacon.h"
 | |
|  #include "iapp.h"
 | |
|  #include "ieee802_1x.h"
 | |
| +#include "ieee802_11.h"
 | |
|  #include "ieee802_11_auth.h"
 | |
|  #include "vlan_init.h"
 | |
|  #include "wpa_auth.h"
 | |
| @@ -307,6 +308,7 @@ static void hostapd_cleanup_iface_pre(st
 | |
|  
 | |
|  static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
 | |
|  {
 | |
| +	hostapd_deinit_ht(iface);
 | |
|  	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
 | |
|  	iface->hw_features = NULL;
 | |
|  	os_free(iface->current_rates);
 | |
| --- a/src/ap/hostapd.h
 | |
| +++ b/src/ap/hostapd.h
 | |
| @@ -238,6 +238,9 @@ struct hostapd_iface {
 | |
|  	/* Overlapping BSS information */
 | |
|  	int olbc_ht;
 | |
|  
 | |
| +	int force_20mhz;
 | |
| +	struct os_time last_20mhz_trigger;
 | |
| +
 | |
|  	u16 ht_op_mode;
 | |
|  	void (*scan_cb)(struct hostapd_iface *iface);
 | |
|  
 | |
| --- a/src/ap/ieee802_11.c
 | |
| +++ b/src/ap/ieee802_11.c
 | |
| @@ -1205,6 +1205,9 @@ static void handle_beacon(struct hostapd
 | |
|  					     sizeof(mgmt->u.beacon)), &elems,
 | |
|  				      0);
 | |
|  
 | |
| +	if (!elems.ht_capabilities)
 | |
| +		hostapd_trigger_20mhz(hapd->iface);
 | |
| +
 | |
|  	ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
 | |
|  }
 | |
|  
 | |
| --- a/src/ap/ieee802_11.h
 | |
| +++ b/src/ap/ieee802_11.h
 | |
| @@ -73,4 +73,17 @@ u8 * hostapd_eid_time_zone(struct hostap
 | |
|  int hostapd_update_time_adv(struct hostapd_data *hapd);
 | |
|  void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
 | |
|  
 | |
| +#ifdef CONFIG_IEEE80211N
 | |
| +void hostapd_trigger_20mhz(struct hostapd_iface *iface);
 | |
| +void hostapd_deinit_ht(struct hostapd_iface *iface);
 | |
| +
 | |
| +#else
 | |
| +static inline void hostapd_deinit_ht(struct hostapd_iface *iface)
 | |
| +{
 | |
| +}
 | |
| +static inline void hostapd_trigger_20mhz(struct hostapd_iface *iface)
 | |
| +{
 | |
| +}
 | |
| +#endif /* CONFIG_IEEE80211N */
 | |
| +
 | |
|  #endif /* IEEE802_11_H */
 | |
| --- a/src/ap/ieee802_11_ht.c
 | |
| +++ b/src/ap/ieee802_11_ht.c
 | |
| @@ -20,9 +20,11 @@
 | |
|  #include "drivers/driver.h"
 | |
|  #include "hostapd.h"
 | |
|  #include "ap_config.h"
 | |
| +#include "ap_drv_ops.h"
 | |
|  #include "sta_info.h"
 | |
|  #include "beacon.h"
 | |
|  #include "ieee802_11.h"
 | |
| +#include "utils/eloop.h"
 | |
|  
 | |
|  
 | |
|  u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
 | |
| @@ -70,12 +72,15 @@ u8 * hostapd_eid_ht_operation(struct hos
 | |
|  
 | |
|  	oper->control_chan = hapd->iconf->channel;
 | |
|  	oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
 | |
| -	if (hapd->iconf->secondary_channel == 1)
 | |
| -		oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
 | |
| -			HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
 | |
| -	if (hapd->iconf->secondary_channel == -1)
 | |
| -		oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
 | |
| -			HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
 | |
| +
 | |
| +	if (!hapd->iface->force_20mhz) {
 | |
| +		if (hapd->iconf->secondary_channel == 1)
 | |
| +			oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
 | |
| +				HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
 | |
| +		if (hapd->iconf->secondary_channel == -1)
 | |
| +			oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
 | |
| +				HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
 | |
| +	}
 | |
|  
 | |
|  	pos += sizeof(*oper);
 | |
|  
 | |
| @@ -271,3 +276,80 @@ void hostapd_get_ht_capab(struct hostapd
 | |
|  
 | |
|  	neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
 | |
|  }
 | |
| +
 | |
| +static void hostapd_set_force_20mhz(struct hostapd_iface *iface);
 | |
| +
 | |
| +static void hostapd_restore_40mhz(void *eloop_data, void *user_ctx)
 | |
| +{
 | |
| +	struct hostapd_iface *iface = eloop_data;
 | |
| +	struct os_time time;
 | |
| +	int timeout;
 | |
| +
 | |
| +	if (!iface->last_20mhz_trigger.sec)
 | |
| +	    return;
 | |
| +
 | |
| +	os_get_time(&time);
 | |
| +	timeout = iface->last_20mhz_trigger.sec + iface->conf->dynamic_ht40 -
 | |
| +		  time.sec;
 | |
| +
 | |
| +	if (timeout > 0) {
 | |
| +		eloop_register_timeout(timeout, 0, hostapd_restore_40mhz,
 | |
| +				       iface, NULL);
 | |
| +		return;
 | |
| +	}
 | |
| +
 | |
| +	iface->last_20mhz_trigger.sec = 0;
 | |
| +	iface->last_20mhz_trigger.usec = 0;
 | |
| +
 | |
| +	iface->force_20mhz = 0;
 | |
| +	hostapd_set_force_20mhz(iface);
 | |
| +}
 | |
| +
 | |
| +static void hostapd_set_force_20mhz(struct hostapd_iface *iface)
 | |
| +{
 | |
| +	int secondary_channel;
 | |
| +	int i;
 | |
| +
 | |
| +	ieee802_11_set_beacons(iface);
 | |
| +
 | |
| +	for (i = 0; i < iface->num_bss; i++) {
 | |
| +		struct hostapd_data *hapd = iface->bss[i];
 | |
| +
 | |
| +		if (iface->force_20mhz)
 | |
| +			secondary_channel = 0;
 | |
| +		else
 | |
| +			secondary_channel = hapd->iconf->secondary_channel;
 | |
| +
 | |
| +		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
 | |
| +					 hapd->iconf->channel,
 | |
| +					 hapd->iconf->ieee80211n,
 | |
| +					 secondary_channel)) {
 | |
| +			wpa_printf(MSG_ERROR, "Could not set channel for "
 | |
| +				   "kernel driver");
 | |
| +		}
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +void hostapd_deinit_ht(struct hostapd_iface *iface)
 | |
| +{
 | |
| +	eloop_cancel_timeout(hostapd_restore_40mhz, iface, NULL);
 | |
| +}
 | |
| +
 | |
| +void hostapd_trigger_20mhz(struct hostapd_iface *iface)
 | |
| +{
 | |
| +	if (!iface->conf->dynamic_ht40)
 | |
| +		return;
 | |
| +
 | |
| +	if (!iface->force_20mhz) {
 | |
| +		iface->force_20mhz = 1;
 | |
| +		hostapd_set_force_20mhz(iface);
 | |
| +	}
 | |
| +
 | |
| +	if (!iface->last_20mhz_trigger.sec) {
 | |
| +		eloop_cancel_timeout(hostapd_restore_40mhz, iface, NULL);
 | |
| +		eloop_register_timeout(iface->conf->dynamic_ht40, 0,
 | |
| +				       hostapd_restore_40mhz, iface, NULL);
 | |
| +	}
 | |
| +
 | |
| +	os_get_time(&iface->last_20mhz_trigger);
 | |
| +}
 |