wlan: add support for vendor specific event
Add support for vendor specific event and use it to provide
interfering frequency information to userspace. Userspace should
stop P2P-GO, in case P2P-GO is operating on interfering frequency
and restart P2P-GO by avoiding interfering frequency range(s). User
space may decide to continue operation on interfering frequency,
but in such case, there might be impact on performance.
CRs-Fixed: 531882
Change-Id: Ife3650d6ccb3c55aea38b5d9ba1e0b8b6c7fbca3
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 979a797..1d78e19 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -123,6 +123,33 @@
}__attribute__((packed)) qcom_ie_age ;
#endif
+/* Vendor id to be used in vendor specific command and events
+ * to user space. Use QCA OUI 00:13:74 to match with define in
+ * supplicant code.
+ */
+#define QCOM_NL80211_VENDOR_ID 0x001374
+
+/* Vendor speicific sub-command id and their index */
+#ifdef FEATURE_WLAN_CH_AVOID
+#define QCOM_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY 10
+#define QCOM_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX 0
+#endif /* FEATURE_WLAN_CH_AVOID */
+
+#ifdef FEATURE_WLAN_CH_AVOID
+#define HDD_MAX_AVOID_FREQ_RANGES 4
+typedef struct sHddAvoidFreqRange
+{
+ u32 startFreq;
+ u32 endFreq;
+} tHddAvoidFreqRange;
+
+typedef struct sHddAvoidFreqList
+{
+ u32 avoidFreqRangeCount;
+ tHddAvoidFreqRange avoidFreqRange[HDD_MAX_AVOID_FREQ_RANGES];
+} tHddAvoidFreqList;
+#endif /* FEATURE_WLAN_CH_AVOID */
+
struct cfg80211_bss* wlan_hdd_cfg80211_update_bss_db( hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo
);
@@ -195,4 +222,7 @@
void hdd_select_cbmode( hdd_adapter_t *pAdapter,v_U8_t operationChannel);
+int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx,
+ tHddAvoidFreqList *pAvoidFreqList);
+
#endif
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 6371351..9f6905a 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -75,6 +75,8 @@
#ifdef FEATURE_WLAN_TDLS
#include "wlan_hdd_tdls.h"
#endif
+#include "wlan_hdd_cfg80211.h"
+
/*---------------------------------------------------------------------------
Preprocessor definitions and constants
-------------------------------------------------------------------------*/
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 131ab42..0666ba1 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -535,6 +535,65 @@
};
#endif /* WLAN_NL80211_TESTMODE */
+#ifdef FEATURE_WLAN_CH_AVOID
+/*
+ * FUNCTION: wlan_hdd_send_avoid_freq_event
+ * This is called when wlan driver needs to send vendor specific
+ * avoid frequency range event to userspace
+ */
+int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx,
+ tHddAvoidFreqList *pAvoidFreqList)
+{
+ struct sk_buff *vendor_event;
+
+ ENTER();
+
+ if (!pHddCtx)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: HDD context is null", __func__);
+ return -1;
+ }
+
+ if (!pAvoidFreqList)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: pAvoidFreqList is null", __func__);
+ return -1;
+ }
+
+ vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
+ sizeof(tHddAvoidFreqList),
+ QCOM_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX,
+ GFP_KERNEL);
+ if (!vendor_event)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: cfg80211_vendor_event_alloc failed", __func__);
+ return -1;
+ }
+
+ memcpy(skb_put(vendor_event, sizeof(tHddAvoidFreqList)),
+ (void *)pAvoidFreqList, sizeof(tHddAvoidFreqList));
+
+ cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+
+ EXIT();
+ return 0;
+}
+#endif /* FEATURE_WLAN_CH_AVOID */
+
+/* vendor specific events */
+static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
+{
+#ifdef FEATURE_WLAN_CH_AVOID
+ {
+ .vendor_id = QCOM_NL80211_VENDOR_ID,
+ .subcmd = QCOM_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY
+ },
+#endif /* FEATURE_WLAN_CH_AVOID */
+};
+
/*
* FUNCTION: wlan_hdd_cfg80211_wiphy_alloc
* This function is called by hdd_wlan_startup()
@@ -792,6 +851,10 @@
wiphy->max_remain_on_channel_duration = 1000;
#endif
+ wiphy->n_vendor_commands = 0;
+ wiphy->vendor_events = wlan_hdd_cfg80211_vendor_events;
+ wiphy->n_vendor_events = ARRAY_SIZE(wlan_hdd_cfg80211_vendor_events);
+
EXIT();
return 0;
}
diff --git a/CORE/HDD/src/wlan_hdd_hostapd.c b/CORE/HDD/src/wlan_hdd_hostapd.c
index a04f6e8..1786856 100644
--- a/CORE/HDD/src/wlan_hdd_hostapd.c
+++ b/CORE/HDD/src/wlan_hdd_hostapd.c
@@ -1216,6 +1216,8 @@
v_U16_t unsafeChannelCount = 0;
v_U16_t unsafeChannelList[NUM_20MHZ_RF_CHANNELS];
v_CONTEXT_t pVosContext;
+ tHddAvoidFreqList hddAvoidFreqList;
+ tANI_U32 i;
/* Basic sanity */
if ((NULL == pAdapter) || (NULL == indParam))
@@ -1294,6 +1296,19 @@
unsafeChannelList,
unsafeChannelCount);
+ /* generate vendor specific event */
+ vos_mem_zero((void *)&hddAvoidFreqList, sizeof(tHddAvoidFreqList));
+ for (i = 0; i < chAvoidInd->avoidRangeCount; i++)
+ {
+ hddAvoidFreqList.avoidFreqRange[i].startFreq =
+ chAvoidInd->avoidFreqRange[i].startFreq;
+ hddAvoidFreqList.avoidFreqRange[i].endFreq =
+ chAvoidInd->avoidFreqRange[i].endFreq;
+ }
+ hddAvoidFreqList.avoidFreqRangeCount = chAvoidInd->avoidRangeCount;
+
+ wlan_hdd_send_avoid_freq_event(hddCtxt, &hddAvoidFreqList);
+
/* Get SAP context first
* SAP and P2PGO would not concurrent */
pHostapdAdapter = hdd_get_adapter(hddCtxt, WLAN_HDD_SOFTAP);