diff options
| -rw-r--r-- | src/common/qca-vendor.h | 18 | ||||
| -rw-r--r-- | src/common/wpa_ctrl.h | 3 | ||||
| -rw-r--r-- | src/drivers/driver.h | 18 | ||||
| -rw-r--r-- | src/drivers/driver_common.c | 1 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 50 | ||||
| -rw-r--r-- | wpa_supplicant/events.c | 55 | ||||
| -rw-r--r-- | wpa_supplicant/p2p_supplicant.c | 2 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 1 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant_i.h | 1 |
9 files changed, 148 insertions, 1 deletions
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index 6e2f0c00..0d83920a 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 815dce91..efe8c487 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -68,6 +68,8 @@ extern "C" { /** Notify the Userspace about the freq conflict */ #define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT " #endif +/** Frequency ranges that the driver recommends to avoid */ +#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ " /** RSN IBSS 4-way handshakes completed with specified peer */ #define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED " @@ -148,6 +150,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 4449db2f..23883f05 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -3307,7 +3307,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 }; @@ -4006,6 +4015,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 8a6b438a..043895f3 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -86,6 +86,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 0881868e..899b47a8 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2613,10 +2613,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 de891b52..5a0c6445 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2656,6 +2656,58 @@ static void wpas_event_deauth(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) { @@ -3216,6 +3268,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 2a851f31..653af4f3 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2962,6 +2962,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 c7db8510..2e9cbfb9 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -3508,6 +3508,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 97fe3d1f..7252c4a3 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, |
