Remove MBO dependency from Supported Operating Classes element
Supported Operating Classes element and its use is define in the IEEE 802.11 standard and can be sent even when MBO is disabled in the build. As such, move this functionality out from the CONFIG_MBO=y only mbo.c. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
62cd9d7926
commit
065c029a55
7 changed files with 325 additions and 331 deletions
|
@ -93,6 +93,7 @@ OBJS += src/utils/common.c
|
||||||
OBJS += src/utils/wpa_debug.c
|
OBJS += src/utils/wpa_debug.c
|
||||||
OBJS += src/utils/wpabuf.c
|
OBJS += src/utils/wpabuf.c
|
||||||
OBJS += wmm_ac.c
|
OBJS += wmm_ac.c
|
||||||
|
OBJS += op_classes.c
|
||||||
OBJS_p = wpa_passphrase.c
|
OBJS_p = wpa_passphrase.c
|
||||||
OBJS_p += src/utils/common.c
|
OBJS_p += src/utils/common.c
|
||||||
OBJS_p += src/utils/wpa_debug.c
|
OBJS_p += src/utils/wpa_debug.c
|
||||||
|
|
|
@ -103,6 +103,7 @@ OBJS += eap_register.o
|
||||||
OBJS += ../src/utils/common.o
|
OBJS += ../src/utils/common.o
|
||||||
OBJS += ../src/utils/wpa_debug.o
|
OBJS += ../src/utils/wpa_debug.o
|
||||||
OBJS += ../src/utils/wpabuf.o
|
OBJS += ../src/utils/wpabuf.o
|
||||||
|
OBJS += op_classes.o
|
||||||
OBJS_p = wpa_passphrase.o
|
OBJS_p = wpa_passphrase.o
|
||||||
OBJS_p += ../src/utils/common.o
|
OBJS_p += ../src/utils/common.o
|
||||||
OBJS_p += ../src/utils/wpa_debug.o
|
OBJS_p += ../src/utils/wpa_debug.o
|
||||||
|
|
|
@ -380,300 +380,6 @@ void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum chan_allowed {
|
|
||||||
NOT_ALLOWED, ALLOWED
|
|
||||||
};
|
|
||||||
|
|
||||||
static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
|
|
||||||
unsigned int *flags)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < mode->num_channels; i++) {
|
|
||||||
if (mode->channels[i].chan == chan)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == mode->num_channels ||
|
|
||||||
(mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
|
|
||||||
if (flags)
|
|
||||||
*flags = mode->channels[i].flag;
|
|
||||||
|
|
||||||
return ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
|
|
||||||
{
|
|
||||||
u8 center_channels[] = {42, 58, 106, 122, 138, 155};
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
|
|
||||||
/*
|
|
||||||
* In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
|
|
||||||
* so the center channel is 6 channels away from the start/end.
|
|
||||||
*/
|
|
||||||
if (channel >= center_channels[i] - 6 &&
|
|
||||||
channel <= center_channels[i] + 6)
|
|
||||||
return center_channels[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
|
|
||||||
{
|
|
||||||
u8 center_chan;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
center_chan = get_center_80mhz(mode, channel);
|
|
||||||
if (!center_chan)
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
|
|
||||||
/* check all the channels are available */
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
unsigned int flags;
|
|
||||||
u8 adj_chan = center_chan - 6 + i * 4;
|
|
||||||
|
|
||||||
if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
|
|
||||||
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
|
|
||||||
(i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
|
|
||||||
(i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
|
|
||||||
(i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
|
|
||||||
{
|
|
||||||
u8 center_channels[] = { 50, 114 };
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
|
|
||||||
/*
|
|
||||||
* In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
|
|
||||||
* so the center channel is 14 channels away from the start/end.
|
|
||||||
*/
|
|
||||||
if (channel >= center_channels[i] - 14 &&
|
|
||||||
channel <= center_channels[i] + 14)
|
|
||||||
return center_channels[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
|
|
||||||
u8 channel)
|
|
||||||
{
|
|
||||||
u8 center_chan;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
center_chan = get_center_160mhz(mode, channel);
|
|
||||||
if (!center_chan)
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
|
|
||||||
/* Check all the channels are available */
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
unsigned int flags;
|
|
||||||
u8 adj_chan = center_chan - 14 + i * 4;
|
|
||||||
|
|
||||||
if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
|
|
||||||
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
|
|
||||||
(i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
|
|
||||||
(i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
|
|
||||||
(i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
|
|
||||||
(i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
|
|
||||||
(i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
|
|
||||||
(i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
|
|
||||||
(i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode,
|
|
||||||
u8 channel, u8 bw)
|
|
||||||
{
|
|
||||||
unsigned int flag = 0;
|
|
||||||
enum chan_allowed res, res2;
|
|
||||||
|
|
||||||
res2 = res = allow_channel(mode, channel, &flag);
|
|
||||||
if (bw == BW40MINUS) {
|
|
||||||
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
res2 = allow_channel(mode, channel - 4, NULL);
|
|
||||||
} else if (bw == BW40PLUS) {
|
|
||||||
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
res2 = allow_channel(mode, channel + 4, NULL);
|
|
||||||
} else if (bw == BW80) {
|
|
||||||
/*
|
|
||||||
* channel is a center channel and as such, not necessarily a
|
|
||||||
* valid 20 MHz channels. Override earlier allow_channel()
|
|
||||||
* result and use only the 80 MHz specific version.
|
|
||||||
*/
|
|
||||||
res2 = res = verify_80mhz(mode, channel);
|
|
||||||
} else if (bw == BW160) {
|
|
||||||
/*
|
|
||||||
* channel is a center channel and as such, not necessarily a
|
|
||||||
* valid 20 MHz channels. Override earlier allow_channel()
|
|
||||||
* result and use only the 160 MHz specific version.
|
|
||||||
*/
|
|
||||||
res2 = res = verify_160mhz(mode, channel);
|
|
||||||
} else if (bw == BW80P80) {
|
|
||||||
/*
|
|
||||||
* channel is a center channel and as such, not necessarily a
|
|
||||||
* valid 20 MHz channels. Override earlier allow_channel()
|
|
||||||
* result and use only the 80 MHz specific version.
|
|
||||||
*/
|
|
||||||
res2 = res = verify_80mhz(mode, channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
|
|
||||||
return NOT_ALLOWED;
|
|
||||||
|
|
||||||
return ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
|
|
||||||
const struct oper_class_map *op_class)
|
|
||||||
{
|
|
||||||
int chan;
|
|
||||||
size_t i;
|
|
||||||
struct hostapd_hw_modes *mode;
|
|
||||||
int found;
|
|
||||||
|
|
||||||
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
|
|
||||||
if (!mode)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (op_class->op_class == 128) {
|
|
||||||
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(channels); i++) {
|
|
||||||
if (verify_channel(mode, channels[i], op_class->bw) ==
|
|
||||||
ALLOWED)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op_class->op_class == 129) {
|
|
||||||
/* Check if either 160 MHz channels is allowed */
|
|
||||||
return verify_channel(mode, 50, op_class->bw) == ALLOWED ||
|
|
||||||
verify_channel(mode, 114, op_class->bw) == ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op_class->op_class == 130) {
|
|
||||||
/* Need at least two non-contiguous 80 MHz segments */
|
|
||||||
found = 0;
|
|
||||||
|
|
||||||
if (verify_channel(mode, 42, op_class->bw) == ALLOWED ||
|
|
||||||
verify_channel(mode, 58, op_class->bw) == ALLOWED)
|
|
||||||
found++;
|
|
||||||
if (verify_channel(mode, 106, op_class->bw) == ALLOWED ||
|
|
||||||
verify_channel(mode, 122, op_class->bw) == ALLOWED ||
|
|
||||||
verify_channel(mode, 138, op_class->bw) == ALLOWED)
|
|
||||||
found++;
|
|
||||||
if (verify_channel(mode, 106, op_class->bw) == ALLOWED &&
|
|
||||||
verify_channel(mode, 138, op_class->bw) == ALLOWED)
|
|
||||||
found++;
|
|
||||||
if (verify_channel(mode, 155, op_class->bw) == ALLOWED)
|
|
||||||
found++;
|
|
||||||
|
|
||||||
if (found >= 2)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = 0;
|
|
||||||
for (chan = op_class->min_chan; chan <= op_class->max_chan;
|
|
||||||
chan += op_class->inc) {
|
|
||||||
if (verify_channel(mode, chan, op_class->bw) == ALLOWED) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
|
|
||||||
size_t len)
|
|
||||||
{
|
|
||||||
struct wpabuf *buf;
|
|
||||||
u8 op, current, chan;
|
|
||||||
u8 *ie_len;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assume 20 MHz channel for now.
|
|
||||||
* TODO: Use the secondary channel and VHT channel width that will be
|
|
||||||
* used after association.
|
|
||||||
*/
|
|
||||||
if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
|
|
||||||
¤t, &chan) == NUM_HOSTAPD_MODES)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Need 3 bytes for EID, length, and current operating class, plus
|
|
||||||
* 1 byte for every other supported operating class.
|
|
||||||
*/
|
|
||||||
buf = wpabuf_alloc(global_op_class_size + 3);
|
|
||||||
if (!buf)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
|
|
||||||
/* Will set the length later, putting a placeholder */
|
|
||||||
ie_len = wpabuf_put(buf, 1);
|
|
||||||
wpabuf_put_u8(buf, current);
|
|
||||||
|
|
||||||
for (op = 0; global_op_class[op].op_class; op++) {
|
|
||||||
if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
|
|
||||||
wpabuf_put_u8(buf, global_op_class[op].op_class);
|
|
||||||
}
|
|
||||||
|
|
||||||
*ie_len = wpabuf_len(buf) - 2;
|
|
||||||
if (*ie_len < 2 || wpabuf_len(buf) > len) {
|
|
||||||
wpa_printf(MSG_ERROR,
|
|
||||||
"Failed to add supported operating classes IE");
|
|
||||||
res = 0;
|
|
||||||
} else {
|
|
||||||
os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
|
|
||||||
res = wpabuf_len(buf);
|
|
||||||
wpa_hexdump_buf(MSG_DEBUG,
|
|
||||||
"MBO: Added supported operating classes IE",
|
|
||||||
buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
wpabuf_free(buf);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
|
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
|
|
309
wpa_supplicant/op_classes.c
Normal file
309
wpa_supplicant/op_classes.c
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
/*
|
||||||
|
* Operating classes
|
||||||
|
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||||
|
* Contact Information:
|
||||||
|
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||||
|
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utils/includes.h"
|
||||||
|
|
||||||
|
#include "utils/common.h"
|
||||||
|
#include "common/ieee802_11_common.h"
|
||||||
|
#include "wpa_supplicant_i.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum chan_allowed {
|
||||||
|
NOT_ALLOWED, ALLOWED
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
|
||||||
|
unsigned int *flags)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < mode->num_channels; i++) {
|
||||||
|
if (mode->channels[i].chan == chan)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == mode->num_channels ||
|
||||||
|
(mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
|
||||||
|
if (flags)
|
||||||
|
*flags = mode->channels[i].flag;
|
||||||
|
|
||||||
|
return ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
|
||||||
|
{
|
||||||
|
u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
|
||||||
|
/*
|
||||||
|
* In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
|
||||||
|
* so the center channel is 6 channels away from the start/end.
|
||||||
|
*/
|
||||||
|
if (channel >= center_channels[i] - 6 &&
|
||||||
|
channel <= center_channels[i] + 6)
|
||||||
|
return center_channels[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
|
||||||
|
{
|
||||||
|
u8 center_chan;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
center_chan = get_center_80mhz(mode, channel);
|
||||||
|
if (!center_chan)
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
|
||||||
|
/* check all the channels are available */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
unsigned int flags;
|
||||||
|
u8 adj_chan = center_chan - 6 + i * 4;
|
||||||
|
|
||||||
|
if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
|
||||||
|
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
|
||||||
|
(i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
|
||||||
|
(i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
|
||||||
|
(i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
|
||||||
|
{
|
||||||
|
u8 center_channels[] = { 50, 114 };
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
|
||||||
|
/*
|
||||||
|
* In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
|
||||||
|
* so the center channel is 14 channels away from the start/end.
|
||||||
|
*/
|
||||||
|
if (channel >= center_channels[i] - 14 &&
|
||||||
|
channel <= center_channels[i] + 14)
|
||||||
|
return center_channels[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
|
||||||
|
u8 channel)
|
||||||
|
{
|
||||||
|
u8 center_chan;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
center_chan = get_center_160mhz(mode, channel);
|
||||||
|
if (!center_chan)
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
|
||||||
|
/* Check all the channels are available */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
unsigned int flags;
|
||||||
|
u8 adj_chan = center_chan - 14 + i * 4;
|
||||||
|
|
||||||
|
if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
|
||||||
|
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
|
||||||
|
(i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
|
||||||
|
(i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
|
||||||
|
(i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
|
||||||
|
(i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
|
||||||
|
(i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
|
||||||
|
(i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
|
||||||
|
(i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode,
|
||||||
|
u8 channel, u8 bw)
|
||||||
|
{
|
||||||
|
unsigned int flag = 0;
|
||||||
|
enum chan_allowed res, res2;
|
||||||
|
|
||||||
|
res2 = res = allow_channel(mode, channel, &flag);
|
||||||
|
if (bw == BW40MINUS) {
|
||||||
|
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
res2 = allow_channel(mode, channel - 4, NULL);
|
||||||
|
} else if (bw == BW40PLUS) {
|
||||||
|
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
res2 = allow_channel(mode, channel + 4, NULL);
|
||||||
|
} else if (bw == BW80) {
|
||||||
|
/*
|
||||||
|
* channel is a center channel and as such, not necessarily a
|
||||||
|
* valid 20 MHz channels. Override earlier allow_channel()
|
||||||
|
* result and use only the 80 MHz specific version.
|
||||||
|
*/
|
||||||
|
res2 = res = verify_80mhz(mode, channel);
|
||||||
|
} else if (bw == BW160) {
|
||||||
|
/*
|
||||||
|
* channel is a center channel and as such, not necessarily a
|
||||||
|
* valid 20 MHz channels. Override earlier allow_channel()
|
||||||
|
* result and use only the 160 MHz specific version.
|
||||||
|
*/
|
||||||
|
res2 = res = verify_160mhz(mode, channel);
|
||||||
|
} else if (bw == BW80P80) {
|
||||||
|
/*
|
||||||
|
* channel is a center channel and as such, not necessarily a
|
||||||
|
* valid 20 MHz channels. Override earlier allow_channel()
|
||||||
|
* result and use only the 80 MHz specific version.
|
||||||
|
*/
|
||||||
|
res2 = res = verify_80mhz(mode, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
|
||||||
|
return NOT_ALLOWED;
|
||||||
|
|
||||||
|
return ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
|
||||||
|
const struct oper_class_map *op_class)
|
||||||
|
{
|
||||||
|
int chan;
|
||||||
|
size_t i;
|
||||||
|
struct hostapd_hw_modes *mode;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
|
||||||
|
if (!mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (op_class->op_class == 128) {
|
||||||
|
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(channels); i++) {
|
||||||
|
if (verify_channel(mode, channels[i], op_class->bw) ==
|
||||||
|
ALLOWED)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op_class->op_class == 129) {
|
||||||
|
/* Check if either 160 MHz channels is allowed */
|
||||||
|
return verify_channel(mode, 50, op_class->bw) == ALLOWED ||
|
||||||
|
verify_channel(mode, 114, op_class->bw) == ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op_class->op_class == 130) {
|
||||||
|
/* Need at least two non-contiguous 80 MHz segments */
|
||||||
|
found = 0;
|
||||||
|
|
||||||
|
if (verify_channel(mode, 42, op_class->bw) == ALLOWED ||
|
||||||
|
verify_channel(mode, 58, op_class->bw) == ALLOWED)
|
||||||
|
found++;
|
||||||
|
if (verify_channel(mode, 106, op_class->bw) == ALLOWED ||
|
||||||
|
verify_channel(mode, 122, op_class->bw) == ALLOWED ||
|
||||||
|
verify_channel(mode, 138, op_class->bw) == ALLOWED)
|
||||||
|
found++;
|
||||||
|
if (verify_channel(mode, 106, op_class->bw) == ALLOWED &&
|
||||||
|
verify_channel(mode, 138, op_class->bw) == ALLOWED)
|
||||||
|
found++;
|
||||||
|
if (verify_channel(mode, 155, op_class->bw) == ALLOWED)
|
||||||
|
found++;
|
||||||
|
|
||||||
|
if (found >= 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = 0;
|
||||||
|
for (chan = op_class->min_chan; chan <= op_class->max_chan;
|
||||||
|
chan += op_class->inc) {
|
||||||
|
if (verify_channel(mode, chan, op_class->bw) == ALLOWED) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct wpabuf *buf;
|
||||||
|
u8 op, current, chan;
|
||||||
|
u8 *ie_len;
|
||||||
|
size_t res;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assume 20 MHz channel for now.
|
||||||
|
* TODO: Use the secondary channel and VHT channel width that will be
|
||||||
|
* used after association.
|
||||||
|
*/
|
||||||
|
if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
|
||||||
|
¤t, &chan) == NUM_HOSTAPD_MODES)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need 3 bytes for EID, length, and current operating class, plus
|
||||||
|
* 1 byte for every other supported operating class.
|
||||||
|
*/
|
||||||
|
buf = wpabuf_alloc(global_op_class_size + 3);
|
||||||
|
if (!buf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
|
||||||
|
/* Will set the length later, putting a placeholder */
|
||||||
|
ie_len = wpabuf_put(buf, 1);
|
||||||
|
wpabuf_put_u8(buf, current);
|
||||||
|
|
||||||
|
for (op = 0; global_op_class[op].op_class; op++) {
|
||||||
|
if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
|
||||||
|
wpabuf_put_u8(buf, global_op_class[op].op_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
*ie_len = wpabuf_len(buf) - 2;
|
||||||
|
if (*ie_len < 2 || wpabuf_len(buf) > len) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"Failed to add supported operating classes IE");
|
||||||
|
res = 0;
|
||||||
|
} else {
|
||||||
|
os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
|
||||||
|
res = wpabuf_len(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG,
|
||||||
|
"Added supported operating classes IE", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpabuf_free(buf);
|
||||||
|
return res;
|
||||||
|
}
|
|
@ -212,9 +212,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
u8 ext_capab[18];
|
u8 ext_capab[18];
|
||||||
int ext_capab_len;
|
int ext_capab_len;
|
||||||
int skip_auth;
|
int skip_auth;
|
||||||
#ifdef CONFIG_MBO
|
|
||||||
const u8 *mbo;
|
|
||||||
#endif /* CONFIG_MBO */
|
|
||||||
|
|
||||||
if (bss == NULL) {
|
if (bss == NULL) {
|
||||||
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
|
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
|
||||||
|
@ -440,20 +437,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
|
|
||||||
sme_auth_handle_rrm(wpa_s, bss);
|
sme_auth_handle_rrm(wpa_s, bss);
|
||||||
|
|
||||||
#ifdef CONFIG_MBO
|
wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
|
||||||
mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
|
wpa_s, bss->freq,
|
||||||
if (mbo) {
|
wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
|
||||||
int len;
|
sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
|
||||||
|
|
||||||
len = wpas_mbo_supp_op_class_ie(
|
|
||||||
wpa_s, bss->freq,
|
|
||||||
wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
|
|
||||||
sizeof(wpa_s->sme.assoc_req_ie) -
|
|
||||||
wpa_s->sme.assoc_req_ie_len);
|
|
||||||
if (len > 0)
|
|
||||||
wpa_s->sme.assoc_req_ie_len += len;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_MBO */
|
|
||||||
|
|
||||||
if (params.p2p)
|
if (params.p2p)
|
||||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
|
wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
|
||||||
|
@ -511,7 +498,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MBO
|
#ifdef CONFIG_MBO
|
||||||
if (mbo) {
|
if (wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
|
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
|
||||||
|
|
|
@ -2147,9 +2147,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
|
||||||
struct ieee80211_vht_capabilities vhtcaps;
|
struct ieee80211_vht_capabilities vhtcaps;
|
||||||
struct ieee80211_vht_capabilities vhtcaps_mask;
|
struct ieee80211_vht_capabilities vhtcaps_mask;
|
||||||
#endif /* CONFIG_VHT_OVERRIDES */
|
#endif /* CONFIG_VHT_OVERRIDES */
|
||||||
#ifdef CONFIG_MBO
|
|
||||||
const u8 *mbo = NULL;
|
|
||||||
#endif /* CONFIG_MBO */
|
|
||||||
|
|
||||||
if (deinit) {
|
if (deinit) {
|
||||||
if (work->started) {
|
if (work->started) {
|
||||||
|
@ -2338,21 +2335,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
|
||||||
os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
|
os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
#ifdef CONFIG_MBO
|
|
||||||
if (bss) {
|
if (bss) {
|
||||||
mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
|
wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
|
||||||
if (mbo) {
|
wpa_ie + wpa_ie_len,
|
||||||
int len;
|
sizeof(wpa_ie) -
|
||||||
|
wpa_ie_len);
|
||||||
len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq,
|
|
||||||
wpa_ie + wpa_ie_len,
|
|
||||||
sizeof(wpa_ie) -
|
|
||||||
wpa_ie_len);
|
|
||||||
if (len > 0)
|
|
||||||
wpa_ie_len += len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_MBO */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Workaround: Add Extended Capabilities element only if the AP
|
* Workaround: Add Extended Capabilities element only if the AP
|
||||||
|
@ -2431,7 +2419,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
|
||||||
#endif /* CONFIG_FST */
|
#endif /* CONFIG_FST */
|
||||||
|
|
||||||
#ifdef CONFIG_MBO
|
#ifdef CONFIG_MBO
|
||||||
if (mbo) {
|
if (bss && wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
|
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
|
||||||
|
|
|
@ -1204,8 +1204,6 @@ const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
|
||||||
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
|
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
|
||||||
const char *non_pref_chan);
|
const char *non_pref_chan);
|
||||||
void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
|
void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
|
||||||
int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
|
|
||||||
size_t len);
|
|
||||||
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
|
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
|
||||||
size_t len);
|
size_t len);
|
||||||
size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
|
size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
|
||||||
|
@ -1215,6 +1213,10 @@ void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa);
|
||||||
struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
|
struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
|
||||||
struct wpa_bss *bss);
|
struct wpa_bss *bss);
|
||||||
|
|
||||||
|
/* op_classes.c */
|
||||||
|
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
|
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
|
||||||
* @wpa_s: Pointer to wpa_supplicant data
|
* @wpa_s: Pointer to wpa_supplicant data
|
||||||
|
|
Loading…
Reference in a new issue