P2P: Apply unsafe frequency rules to available channels
This adds a QCA vendor specific nl80211 event to allow the driver to indicate a list of frequency ranges that should be avoided due to interference or possible known co-existance constraints. Such frequencies are marked as not allowed for P2P use to force groups to be formed on different channels. If a P2P GO is operating on a channel that the driver recommended not to use, a notification about this is sent on the control interface and upper layer code may decide to tear down the group and optionally restart it on another channel. As a TODO item, this could also be changed to use CSA to avoid removing the group. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
1682c62360
commit
253f2e3795
9 changed files with 148 additions and 1 deletions
|
@ -24,10 +24,28 @@
|
||||||
* @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0
|
* @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0
|
||||||
*
|
*
|
||||||
* @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event
|
* @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event
|
||||||
|
*
|
||||||
|
* @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency
|
||||||
|
* ranges to avoid to reduce issues due to interference or internal
|
||||||
|
* co-existence information in the driver. The event data structure is
|
||||||
|
* defined in struct qca_avoid_freq_list.
|
||||||
*/
|
*/
|
||||||
enum qca_nl80211_vendor_subcmds {
|
enum qca_nl80211_vendor_subcmds {
|
||||||
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
|
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
|
||||||
QCA_NL80211_VENDOR_SUBCMD_TEST = 1,
|
QCA_NL80211_VENDOR_SUBCMD_TEST = 1,
|
||||||
|
/* subcmds 2..9 not yet allocated */
|
||||||
|
QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct qca_avoid_freq_range {
|
||||||
|
u32 start_freq;
|
||||||
|
u32 end_freq;
|
||||||
|
} STRUCT_PACKED;
|
||||||
|
|
||||||
|
struct qca_avoid_freq_list {
|
||||||
|
u32 count;
|
||||||
|
struct qca_avoid_freq_range range[0];
|
||||||
|
} STRUCT_PACKED;
|
||||||
|
|
||||||
#endif /* QCA_VENDOR_H */
|
#endif /* QCA_VENDOR_H */
|
||||||
|
|
|
@ -74,6 +74,8 @@ extern "C" {
|
||||||
* be used again.
|
* be used again.
|
||||||
*/
|
*/
|
||||||
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
|
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
|
||||||
|
/** Frequency ranges that the driver recommends to avoid */
|
||||||
|
#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
|
||||||
/** WPS overlap detected in PBC mode */
|
/** WPS overlap detected in PBC mode */
|
||||||
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
|
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
|
||||||
/** Available WPS AP with active PBC found in scan results */
|
/** Available WPS AP with active PBC found in scan results */
|
||||||
|
@ -151,6 +153,7 @@ extern "C" {
|
||||||
|
|
||||||
/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
|
/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
|
||||||
#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
|
#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
|
||||||
|
#define P2P_EVENT_REMOVE_AND_REFORM_GROUP "P2P-REMOVE-AND-REFORM-GROUP "
|
||||||
|
|
||||||
#define INTERWORKING_AP "INTERWORKING-AP "
|
#define INTERWORKING_AP "INTERWORKING-AP "
|
||||||
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
|
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
|
||||||
|
|
|
@ -3147,7 +3147,16 @@ enum wpa_event_type {
|
||||||
* EVENT_SCAN_RESULTS is used to indicate when the scan has been
|
* EVENT_SCAN_RESULTS is used to indicate when the scan has been
|
||||||
* completed (either successfully or by getting cancelled).
|
* completed (either successfully or by getting cancelled).
|
||||||
*/
|
*/
|
||||||
EVENT_SCAN_STARTED
|
EVENT_SCAN_STARTED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EVENT_AVOID_FREQUENCIES - Received avoid frequency range
|
||||||
|
*
|
||||||
|
* This event indicates a set of frequency ranges that should be avoided
|
||||||
|
* to reduce issues due to interference or internal co-existence
|
||||||
|
* information in the driver.
|
||||||
|
*/
|
||||||
|
EVENT_AVOID_FREQUENCIES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -3766,6 +3775,13 @@ union wpa_event_data {
|
||||||
struct channel_list_changed {
|
struct channel_list_changed {
|
||||||
enum reg_change_initiator initiator;
|
enum reg_change_initiator initiator;
|
||||||
} channel_list_changed;
|
} channel_list_changed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* freq_range - List of frequency ranges
|
||||||
|
*
|
||||||
|
* This is used as the data with EVENT_AVOID_FREQUENCIES.
|
||||||
|
*/
|
||||||
|
struct wpa_freq_range_list freq_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -78,6 +78,7 @@ const char * event_to_string(enum wpa_event_type event)
|
||||||
E2S(DFS_NOP_FINISHED);
|
E2S(DFS_NOP_FINISHED);
|
||||||
E2S(SURVEY);
|
E2S(SURVEY);
|
||||||
E2S(SCAN_STARTED);
|
E2S(SCAN_STARTED);
|
||||||
|
E2S(AVOID_FREQUENCIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
|
|
|
@ -2717,10 +2717,60 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
|
||||||
|
const u8 *data, size_t len)
|
||||||
|
{
|
||||||
|
u32 i, count;
|
||||||
|
union wpa_event_data event;
|
||||||
|
struct wpa_freq_range *range = NULL;
|
||||||
|
const struct qca_avoid_freq_list *freq_range;
|
||||||
|
|
||||||
|
freq_range = (const struct qca_avoid_freq_list *) data;
|
||||||
|
if (len < sizeof(freq_range->count))
|
||||||
|
return;
|
||||||
|
|
||||||
|
count = freq_range->count;
|
||||||
|
if (len < sizeof(freq_range->count) +
|
||||||
|
count * sizeof(struct qca_avoid_freq_range)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
|
||||||
|
(unsigned int) len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
range = os_calloc(count, sizeof(struct wpa_freq_range));
|
||||||
|
if (range == NULL)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&event, 0, sizeof(event));
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
unsigned int idx = event.freq_range.num;
|
||||||
|
range[idx].min = freq_range->range[i].start_freq;
|
||||||
|
range[idx].max = freq_range->range[i].end_freq;
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
|
||||||
|
range[idx].min, range[idx].max);
|
||||||
|
if (range[idx].min > range[idx].max) {
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
event.freq_range.num++;
|
||||||
|
}
|
||||||
|
event.freq_range.range = range;
|
||||||
|
|
||||||
|
wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
|
||||||
|
|
||||||
|
os_free(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
|
static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
|
||||||
u32 subcmd, u8 *data, size_t len)
|
u32 subcmd, u8 *data, size_t len)
|
||||||
{
|
{
|
||||||
switch (subcmd) {
|
switch (subcmd) {
|
||||||
|
case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
|
||||||
|
qca_nl80211_avoid_freq(drv, data, len);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"nl80211: Ignore unsupported QCA vendor event %u",
|
"nl80211: Ignore unsupported QCA vendor event %u",
|
||||||
|
|
|
@ -2775,6 +2775,58 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s,
|
||||||
|
union wpa_event_data *event)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
|
struct wpa_supplicant *ifs;
|
||||||
|
#endif /* CONFIG_P2P */
|
||||||
|
struct wpa_freq_range_list *list;
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
|
list = &event->freq_range;
|
||||||
|
|
||||||
|
if (list->num)
|
||||||
|
str = freq_range_list_str(list);
|
||||||
|
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AVOID_FREQ "ranges=%s",
|
||||||
|
str ? str : "");
|
||||||
|
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
|
if (freq_range_list_parse(&wpa_s->global->p2p_go_avoid_freq, str)) {
|
||||||
|
wpa_dbg(wpa_s, MSG_ERROR, "%s: Failed to parse freq range",
|
||||||
|
__func__);
|
||||||
|
} else {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Update channel list based on frequency avoid event");
|
||||||
|
wpas_p2p_update_channel_list(wpa_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
|
||||||
|
int freq;
|
||||||
|
if (!ifs->current_ssid ||
|
||||||
|
!ifs->current_ssid->p2p_group ||
|
||||||
|
(ifs->current_ssid->mode != WPAS_MODE_P2P_GO &&
|
||||||
|
ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
freq = ifs->current_ssid->frequency;
|
||||||
|
if (!freq_range_list_includes(list, freq)) {
|
||||||
|
wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating frequency %d MHz in safe range",
|
||||||
|
freq);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating in unsafe frequency %d MHz",
|
||||||
|
freq);
|
||||||
|
/* TODO: Consider using CSA or removing the group within
|
||||||
|
* wpa_supplicant */
|
||||||
|
wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
|
os_free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
union wpa_event_data *data)
|
union wpa_event_data *data)
|
||||||
{
|
{
|
||||||
|
@ -3266,6 +3318,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
wpas_wps_start_pbc(wpa_s, NULL, 0);
|
wpas_wps_start_pbc(wpa_s, NULL, 0);
|
||||||
#endif /* CONFIG_WPS */
|
#endif /* CONFIG_WPS */
|
||||||
break;
|
break;
|
||||||
|
case EVENT_AVOID_FREQUENCIES:
|
||||||
|
wpa_supplicant_notify_avoid_freq(wpa_s, data);
|
||||||
|
break;
|
||||||
case EVENT_CONNECT_FAILED_REASON:
|
case EVENT_CONNECT_FAILED_REASON:
|
||||||
#ifdef CONFIG_AP
|
#ifdef CONFIG_AP
|
||||||
if (!wpa_s->ap_iface || !data)
|
if (!wpa_s->ap_iface || !data)
|
||||||
|
|
|
@ -3190,6 +3190,8 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
|
||||||
static int wpas_p2p_disallowed_freq(struct wpa_global *global,
|
static int wpas_p2p_disallowed_freq(struct wpa_global *global,
|
||||||
unsigned int freq)
|
unsigned int freq)
|
||||||
{
|
{
|
||||||
|
if (freq_range_list_includes(&global->p2p_go_avoid_freq, freq))
|
||||||
|
return 1;
|
||||||
return freq_range_list_includes(&global->p2p_disallow_freq, freq);
|
return freq_range_list_includes(&global->p2p_disallow_freq, freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3927,6 +3927,7 @@ void wpa_supplicant_deinit(struct wpa_global *global)
|
||||||
os_free(global->params.override_ctrl_interface);
|
os_free(global->params.override_ctrl_interface);
|
||||||
|
|
||||||
os_free(global->p2p_disallow_freq.range);
|
os_free(global->p2p_disallow_freq.range);
|
||||||
|
os_free(global->p2p_go_avoid_freq.range);
|
||||||
os_free(global->add_psk);
|
os_free(global->add_psk);
|
||||||
|
|
||||||
os_free(global);
|
os_free(global);
|
||||||
|
|
|
@ -252,6 +252,7 @@ struct wpa_global {
|
||||||
int p2p_disabled;
|
int p2p_disabled;
|
||||||
int cross_connection;
|
int cross_connection;
|
||||||
struct wpa_freq_range_list p2p_disallow_freq;
|
struct wpa_freq_range_list p2p_disallow_freq;
|
||||||
|
struct wpa_freq_range_list p2p_go_avoid_freq;
|
||||||
enum wpa_conc_pref {
|
enum wpa_conc_pref {
|
||||||
WPA_CONC_PREF_NOT_SET,
|
WPA_CONC_PREF_NOT_SET,
|
||||||
WPA_CONC_PREF_STA,
|
WPA_CONC_PREF_STA,
|
||||||
|
|
Loading…
Reference in a new issue