@@ -229,9 +229,6 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
int pri_chan, sec_chan;
- if (!iface->conf->secondary_channel)
- return 1; /* HT40 not used */
-
pri_chan = iface->conf->channel;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
@@ -692,31 +689,30 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
}
-
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int channel, int primary)
{
- int i;
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if (chan->chan != channel)
- continue;
+ chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+ if (!chan)
+ return 0;
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
- return 1;
+ if (primary && chan_pri_allowed(chan))
+ return 1;
- wpa_printf(MSG_DEBUG,
- "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
- primary ? "" : "Configured HT40 secondary ",
- i, chan->chan, chan->flag,
- chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
- chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
- }
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
+ return 1;
+
+ wpa_printf(MSG_DEBUG,
+ "%schannel (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
+ primary ? "" : "Configured HT40 secondary ",
+ chan->chan, chan->flag,
+ chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
+ chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
channel, primary ? "primary" : "secondary");
@@ -727,6 +723,13 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
int secondary_chan;
+ struct hostapd_channel_data *pri_chan;
+
+ pri_chan = hw_get_channel_chan(iface->current_mode,
+ iface->conf->channel, NULL);
+
+ if (!pri_chan)
+ return 0;
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
return 0;
@@ -741,13 +744,15 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
secondary_chan = iface->conf->channel + 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
+ if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
iface->conf->secondary_channel = 1;
return 1;
}
secondary_chan = iface->conf->channel - 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
+ if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
}
@@ -84,35 +84,45 @@ int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
}
-int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
- int sec_chan)
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan_num,
+ int sec_chan_num)
{
- int ok, j, first;
+ int ok, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
149, 157, 165, 184, 192 };
size_t k;
+ struct hostapd_channel_data *pri_chan, *sec_chan;
+ const int ht_plus = pri_chan_num < sec_chan_num ? 1 : 0;
- if (pri_chan == sec_chan || !sec_chan)
- return 1; /* HT40 not used */
+ pri_chan = hw_get_channel_chan(mode, pri_chan_num, NULL);
+ if (!pri_chan)
+ return 0;
+
+ if (pri_chan_num == sec_chan_num || !sec_chan_num) {
+ if (chan_pri_allowed(pri_chan)) {
+ return 1; /* HT40 not used */
+ } else {
+ wpa_printf(MSG_ERROR, "Channel %d is not allowed as primary",
+ pri_chan_num);
+ return 0;
+ }
+ }
+
+ sec_chan = hw_get_channel_chan(mode, sec_chan_num, NULL);
+ if (!sec_chan)
+ return 0;
wpa_printf(MSG_DEBUG,
"HT40: control channel: %d secondary channel: %d",
- pri_chan, sec_chan);
+ pri_chan_num, sec_chan_num);
/* Verify that HT40 secondary channel is an allowed 20 MHz
* channel */
- ok = 0;
- for (j = 0; j < mode->num_channels; j++) {
- struct hostapd_channel_data *chan = &mode->channels[j];
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
- chan->chan == sec_chan) {
- ok = 1;
- break;
- }
- }
- if (!ok) {
+ if ((sec_chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ (ht_plus && !(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) ||
+ (!ht_plus && !(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))) {
wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
- sec_chan);
+ sec_chan_num);
return 0;
}
@@ -125,7 +135,7 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 1;
- first = pri_chan < sec_chan ? pri_chan : sec_chan;
+ first = pri_chan_num < sec_chan_num ? pri_chan_num : sec_chan_num;
ok = 0;
for (k = 0; k < ARRAY_SIZE(allowed); k++) {
@@ -136,7 +146,7 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
}
if (!ok) {
wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
- pri_chan, sec_chan);
+ pri_chan_num, sec_chan_num);
return 0;
}
@@ -553,3 +563,54 @@ int ieee80211ac_cap_check(u32 hw, u32 conf)
}
#endif /* CONFIG_IEEE80211AC */
+
+u32 num_chan_to_bw(int num_chans)
+{
+ switch (num_chans) {
+ case 2:
+ case 4:
+ case 8:
+ return num_chans * 20;
+ default:
+ return 20;
+ }
+}
+
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+ int ht40_plus, int pri)
+{
+ u32 bw_mask;
+
+ switch (bw) {
+ case 20:
+ bw_mask = HOSTAPD_CHAN_WIDTH_20;
+ break;
+ case 40:
+ /* HT 40 MHz support declared only for primary channel,
+ * just skip 40 MHz secondary checking */
+ if (pri && ht40_plus)
+ bw_mask = HOSTAPD_CHAN_WIDTH_40P;
+ else if (pri && !ht40_plus)
+ bw_mask = HOSTAPD_CHAN_WIDTH_40M;
+ else
+ bw_mask = 0;
+ break;
+ case 80:
+ bw_mask = HOSTAPD_CHAN_WIDTH_80;
+ break;
+ case 160:
+ bw_mask = HOSTAPD_CHAN_WIDTH_160;
+ break;
+ default:
+ bw_mask = 0;
+ break;
+ }
+
+ return (chan->allowed_bw & bw_mask) == bw_mask;
+}
+
+int chan_pri_allowed(const struct hostapd_channel_data *chan)
+{
+ return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
+}
@@ -20,8 +20,8 @@ struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
int hw_get_chan(struct hostapd_hw_modes *mode, int freq);
-int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
- int sec_chan);
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan_num,
+ int sec_chan_num);
void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
int check_40mhz_5g(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
@@ -39,4 +39,11 @@ void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
int disabled);
int ieee80211ac_cap_check(u32 hw, u32 conf);
+u32 num_chan_to_bw(int num_chans);
+/* check if BW is applicable for channel */
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+ int ht40_plus, int pri);
+/* check if channel is allowed to be used as primary */
+int chan_pri_allowed(const struct hostapd_channel_data *chan);
+
#endif /* HW_FEATURES_COMMON_H */