You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openwrt/package/network/services/hostapd/patches/440-dynamic_20_40_mhz.patch

207 lines
5.7 KiB
Diff

--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2422,6 +2422,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);
} else if (os_strcmp(buf, "obss_interval") == 0) {
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -531,6 +531,7 @@ struct hostapd_config {
int ieee80211n;
int secondary_channel;
int require_ht;
+ int dynamic_ht40;
int obss_interval;
u32 vht_capab;
int ieee80211ac;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -23,6 +23,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"
@@ -329,6 +330,7 @@ static void hostapd_cleanup(struct hosta
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, 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
@@ -326,6 +326,9 @@ struct hostapd_iface {
/* Overlapping BSS information */
int olbc_ht;
+ int force_20mhz;
+ struct os_time last_20mhz_trigger;
+
u16 ht_op_mode;
/* surveying helpers */
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1538,6 +1538,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
@@ -82,4 +82,17 @@ int hostapd_update_time_adv(struct hosta
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
+#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)
@@ -86,12 +88,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);
@@ -286,3 +291,84 @@ 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,
+ hapd->iconf->ieee80211ac,
+ secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ hapd->iconf->vht_oper_centr_freq_seg0_idx,
+ hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
+ 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);
+}