aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArif Hussain <c_arifh@qca.qualcomm.com>2014-01-24 14:14:29 (GMT)
committerJouni Malinen <j@w1.fi>2014-01-27 09:49:05 (GMT)
commit253f2e37957e726677d545f5598aad56d7d33bf5 (patch)
tree08b770d19c906a85220aefd1cf224804e2f537b1
parent1682c6236017f28b8fdb3b791565c835e988a559 (diff)
downloadhostap-253f2e37957e726677d545f5598aad56d7d33bf5.zip
hostap-253f2e37957e726677d545f5598aad56d7d33bf5.tar.gz
hostap-253f2e37957e726677d545f5598aad56d7d33bf5.tar.bz2
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>
-rw-r--r--src/common/qca-vendor.h18
-rw-r--r--src/common/wpa_ctrl.h3
-rw-r--r--src/drivers/driver.h18
-rw-r--r--src/drivers/driver_common.c1
-rw-r--r--src/drivers/driver_nl80211.c50
-rw-r--r--wpa_supplicant/events.c55
-rw-r--r--wpa_supplicant/p2p_supplicant.c2
-rw-r--r--wpa_supplicant/wpa_supplicant.c1
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h1
9 files changed, 148 insertions, 1 deletions
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 6e2f0c0..0d83920 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -24,10 +24,28 @@
* @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0
*
* @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 {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
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 */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 9bd59a9..57c3878 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -74,6 +74,8 @@ extern "C" {
* be used again.
*/
#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 */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** 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> */
#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_NO_MATCH "INTERWORKING-NO-MATCH "
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 4fd16ed..2f4536e 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3147,7 +3147,16 @@ enum wpa_event_type {
* EVENT_SCAN_RESULTS is used to indicate when the scan has been
* 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 {
enum reg_change_initiator initiator;
} 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;
};
/**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 64bdddb..3058cd5 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -78,6 +78,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(DFS_NOP_FINISHED);
E2S(SURVEY);
E2S(SCAN_STARTED);
+ E2S(AVOID_FREQUENCIES);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 008b031..646d3f8 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -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,
u32 subcmd, u8 *data, size_t len)
{
switch (subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
+ qca_nl80211_avoid_freq(drv, data, len);
+ break;
default:
wpa_printf(MSG_DEBUG,
"nl80211: Ignore unsupported QCA vendor event %u",
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index d9449fd..d5ac6bf 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -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,
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);
#endif /* CONFIG_WPS */
break;
+ case EVENT_AVOID_FREQUENCIES:
+ wpa_supplicant_notify_avoid_freq(wpa_s, data);
+ break;
case EVENT_CONNECT_FAILED_REASON:
#ifdef CONFIG_AP
if (!wpa_s->ap_iface || !data)
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 889a949..a7eb9aa 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -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,
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);
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index aa9c32d..1bb1a2c 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3927,6 +3927,7 @@ void wpa_supplicant_deinit(struct wpa_global *global)
os_free(global->params.override_ctrl_interface);
os_free(global->p2p_disallow_freq.range);
+ os_free(global->p2p_go_avoid_freq.range);
os_free(global->add_psk);
os_free(global);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 078856e..68995fc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -252,6 +252,7 @@ struct wpa_global {
int p2p_disabled;
int cross_connection;
struct wpa_freq_range_list p2p_disallow_freq;
+ struct wpa_freq_range_list p2p_go_avoid_freq;
enum wpa_conc_pref {
WPA_CONC_PREF_NOT_SET,
WPA_CONC_PREF_STA,