|
@@ -28,6 +28,10 @@
|
|
|
#include <osif_cm_util.h>
|
|
|
#include <wlan_cfg80211.h>
|
|
|
#include <wlan_cfg80211_scan.h>
|
|
|
+#ifdef CONN_MGR_ADV_FEATURE
|
|
|
+#include "wlan_mlme_ucfg_api.h"
|
|
|
+#endif
|
|
|
+#include "wlan_crypto_global_api.h"
|
|
|
|
|
|
#ifdef CONN_MGR_ADV_FEATURE
|
|
|
#ifdef WLAN_FEATURE_FILS_SK
|
|
@@ -85,6 +89,291 @@ static inline void osif_roamed_ind(struct net_device *dev,
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
|
|
|
+#ifdef WLAN_FEATURE_FILS_SK
|
|
|
+/**
|
|
|
+ * wlan_hdd_add_fils_params_roam_auth_event() - Adds FILS params in roam auth
|
|
|
+ * @skb: SK buffer
|
|
|
+ * @roam_info: Roam info
|
|
|
+ *
|
|
|
+ * API adds fils params[pmk, pmkid, next sequence number] to roam auth event
|
|
|
+ *
|
|
|
+ * Return: zero on success, error code on failure
|
|
|
+ */
|
|
|
+static int
|
|
|
+osif_add_fils_params_roam_auth_event(struct sk_buff *skb,
|
|
|
+ struct wlan_roam_sync_info *roam_info)
|
|
|
+{
|
|
|
+ if (roam_info->pmk_len &&
|
|
|
+ nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK,
|
|
|
+ roam_info->pmk_len, roam_info->pmk)) {
|
|
|
+ osif_err("pmk send fail");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID,
|
|
|
+ PMKID_LEN, roam_info->pmkid)) {
|
|
|
+ osif_err("pmkid send fail");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ osif_debug("Update ERP Seq Num %d, Next ERP Seq Num %d",
|
|
|
+ roam_info->update_erp_next_seq_num,
|
|
|
+ roam_info->next_erp_seq_num);
|
|
|
+ if (roam_info->update_erp_next_seq_num &&
|
|
|
+ nla_put_u16(skb,
|
|
|
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM,
|
|
|
+ roam_info->next_erp_seq_num)) {
|
|
|
+ osif_err("ERP seq num send fail");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#else
|
|
|
+static inline int
|
|
|
+osif_add_fils_params_roam_auth_event(struct sk_buff *skb,
|
|
|
+ struct wlan_roam_sync_info *roam_info)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/**
|
|
|
+ * osif_get_roam_reason() - convert wmi roam reason to
|
|
|
+ * enum qca_roam_reason
|
|
|
+ * @roam_scan_trigger: wmi roam scan trigger ID
|
|
|
+ *
|
|
|
+ * Return: Meaningful qca_roam_reason from enum WMI_ROAM_TRIGGER_REASON_ID
|
|
|
+ */
|
|
|
+static enum qca_roam_reason osif_get_roam_reason(uint16_t roam_scan_trigger)
|
|
|
+{
|
|
|
+ switch (roam_scan_trigger) {
|
|
|
+ case ROAM_TRIGGER_REASON_PER:
|
|
|
+ return QCA_ROAM_REASON_PER;
|
|
|
+ case ROAM_TRIGGER_REASON_BMISS:
|
|
|
+ return QCA_ROAM_REASON_BEACON_MISS;
|
|
|
+ case ROAM_TRIGGER_REASON_LOW_RSSI:
|
|
|
+ case ROAM_TRIGGER_REASON_BACKGROUND:
|
|
|
+ return QCA_ROAM_REASON_POOR_RSSI;
|
|
|
+ case ROAM_TRIGGER_REASON_HIGH_RSSI:
|
|
|
+ return QCA_ROAM_REASON_BETTER_RSSI;
|
|
|
+ case ROAM_TRIGGER_REASON_DENSE:
|
|
|
+ return QCA_ROAM_REASON_CONGESTION;
|
|
|
+ case ROAM_TRIGGER_REASON_FORCED:
|
|
|
+ return QCA_ROAM_REASON_USER_TRIGGER;
|
|
|
+ case ROAM_TRIGGER_REASON_BTM:
|
|
|
+ return QCA_ROAM_REASON_BTM;
|
|
|
+ case ROAM_TRIGGER_REASON_BSS_LOAD:
|
|
|
+ return QCA_ROAM_REASON_BSS_LOAD;
|
|
|
+ default:
|
|
|
+ return QCA_ROAM_REASON_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ return QCA_ROAM_REASON_UNKNOWN;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * osif_send_roam_auth_event() - API to send roam auth event response to kernel
|
|
|
+ * @vdev: vdev pointer
|
|
|
+ * @osif_priv: OS private structure of vdev
|
|
|
+ * @rsp: Connection manager response
|
|
|
+ *
|
|
|
+ * This is called when wlan driver needs to send the roaming and
|
|
|
+ * authorization information after roaming.
|
|
|
+ *
|
|
|
+ * The information that would be sent is the request RSN IE, response
|
|
|
+ * RSN IE and BSSID of the newly roamed AP.
|
|
|
+ *
|
|
|
+ * If the Authorized status is authenticated, then additional parameters
|
|
|
+ * like PTK's KCK and KEK and Replay Counter would also be passed to the
|
|
|
+ * supplicant.
|
|
|
+ *
|
|
|
+ * The supplicant upon receiving this event would ignore the legacy
|
|
|
+ * cfg80211_roamed call and use the entire information from this event.
|
|
|
+ * The cfg80211_roamed should still co-exist since the kernel will
|
|
|
+ * make use of the parameters even if the supplicant ignores it.
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * Context: Any context.
|
|
|
+ * Return: int
|
|
|
+ */
|
|
|
+static int osif_send_roam_auth_event(struct wlan_objmgr_vdev *vdev,
|
|
|
+ struct vdev_osif_priv *osif_priv,
|
|
|
+ struct wlan_cm_connect_resp *rsp,
|
|
|
+ const uint8_t *req_ie,
|
|
|
+ size_t req_ie_len, const uint8_t *resp_ie,
|
|
|
+ size_t resp_ie_len)
|
|
|
+{
|
|
|
+ struct wlan_objmgr_psoc *psoc;
|
|
|
+ uint32_t fils_params_len;
|
|
|
+ struct sk_buff *skb = NULL;
|
|
|
+ struct wlan_roam_sync_info *roaming_info;
|
|
|
+ int status;
|
|
|
+ int32_t akm;
|
|
|
+ bool roam_offload_enable;
|
|
|
+
|
|
|
+ psoc = wlan_vdev_get_psoc(vdev);
|
|
|
+ ucfg_mlme_get_roaming_offload(psoc, &roam_offload_enable);
|
|
|
+
|
|
|
+ if (!roam_offload_enable)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ roaming_info = rsp->roaming_info;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * PMK is sent from FW in Roam Synch Event for FILS Roaming.
|
|
|
+ * In that case, add three more NL attributes.ie. PMK, PMKID
|
|
|
+ * and ERP next sequence number. Add corresponding lengths
|
|
|
+ * with 3 extra NL message headers for each of the
|
|
|
+ * aforementioned params.
|
|
|
+ */
|
|
|
+ fils_params_len = roaming_info->pmk_len + PMKID_LEN +
|
|
|
+ sizeof(uint16_t) + (3 * NLMSG_HDRLEN);
|
|
|
+
|
|
|
+ skb = cfg80211_vendor_event_alloc(osif_priv->wdev->wiphy,
|
|
|
+ osif_priv->wdev,
|
|
|
+ ETH_ALEN + req_ie_len +
|
|
|
+ resp_ie_len +
|
|
|
+ sizeof(uint8_t) + REPLAY_CTR_LEN +
|
|
|
+ KCK_KEY_LEN + roaming_info->kek_len +
|
|
|
+ sizeof(uint16_t) + sizeof(uint8_t) +
|
|
|
+ (9 * NLMSG_HDRLEN) + fils_params_len,
|
|
|
+ QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX,
|
|
|
+ GFP_KERNEL);
|
|
|
+
|
|
|
+ if (!skb) {
|
|
|
+ osif_err("cfg80211_vendor_event_alloc failed");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
|
|
|
+ ETH_ALEN, rsp->bssid.bytes) ||
|
|
|
+ nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE,
|
|
|
+ req_ie_len, req_ie) ||
|
|
|
+ nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE,
|
|
|
+ resp_ie_len, resp_ie)) {
|
|
|
+ osif_err("nla put fail");
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (roaming_info->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED) {
|
|
|
+ osif_debug("Include Auth Params TLV's");
|
|
|
+ if (nla_put_u8(skb,
|
|
|
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED,
|
|
|
+ true)) {
|
|
|
+ osif_err("nla put fail");
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+ akm = wlan_crypto_get_param(vdev,
|
|
|
+ WLAN_CRYPTO_PARAM_KEY_MGMT);
|
|
|
+ /* if FT or CCKM connection: dont send replay counter */
|
|
|
+ if (!QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X) &&
|
|
|
+ !QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK) &&
|
|
|
+ !QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE) &&
|
|
|
+ !QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384) &&
|
|
|
+ !QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM) &&
|
|
|
+ nla_put(skb,
|
|
|
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR,
|
|
|
+ REPLAY_CTR_LEN,
|
|
|
+ roaming_info->replay_ctr)) {
|
|
|
+ osif_err("non FT/non CCKM connection");
|
|
|
+ osif_err("failed to send replay counter");
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+ if (roaming_info->kek_len > MAX_KEK_LENGTH ||
|
|
|
+ nla_put(skb,
|
|
|
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK,
|
|
|
+ roaming_info->kck_len, roaming_info->kck) ||
|
|
|
+ nla_put(skb,
|
|
|
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK,
|
|
|
+ roaming_info->kek_len, roaming_info->kek)) {
|
|
|
+ osif_err("nla put fail, kek_len %d",
|
|
|
+ roaming_info->kek_len);
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nla_put_u16(skb,
|
|
|
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON,
|
|
|
+ osif_get_roam_reason(roaming_info->roam_reason))) {
|
|
|
+ osif_err("roam reason send failure");
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ status = osif_add_fils_params_roam_auth_event(skb,
|
|
|
+ roaming_info);
|
|
|
+ if (status)
|
|
|
+ goto nla_put_failure;
|
|
|
+ /*
|
|
|
+ * Save the gtk rekey parameters in HDD STA context. They will
|
|
|
+ * be used next time when host enables GTK offload and goes
|
|
|
+ * into power save state.
|
|
|
+ */
|
|
|
+ osif_cm_save_gtk(vdev, rsp);
|
|
|
+ osif_debug("roam_info_ptr->replay_ctr 0x%llx",
|
|
|
+ *((uint64_t *)roaming_info->replay_ctr));
|
|
|
+
|
|
|
+ } else {
|
|
|
+ osif_debug("No Auth Params TLV's");
|
|
|
+ if (nla_put_u8(skb,
|
|
|
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED,
|
|
|
+ false)) {
|
|
|
+ osif_err("nla put fail");
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ osif_debug("Auth Status = %d Subnet Change Status = %d",
|
|
|
+ roaming_info->auth_status,
|
|
|
+ roaming_info->subnet_change_status);
|
|
|
+ /*
|
|
|
+ * Add subnet change status if subnet has changed
|
|
|
+ * 0 = unchanged
|
|
|
+ * 1 = changed
|
|
|
+ * 2 = unknown
|
|
|
+ */
|
|
|
+ if (roaming_info->subnet_change_status) {
|
|
|
+ if (nla_put_u8(skb,
|
|
|
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS,
|
|
|
+ roaming_info->subnet_change_status)) {
|
|
|
+ osif_err("nla put fail");
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ cfg80211_vendor_event(skb, GFP_KERNEL);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+nla_put_failure:
|
|
|
+ kfree_skb(skb);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+#else
|
|
|
+static inline int
|
|
|
+osif_send_roam_auth_event(struct wlan_objmgr_vdev *vdev,
|
|
|
+ struct vdev_osif_priv *osif_priv,
|
|
|
+ struct wlan_cm_connect_resp *rsp,
|
|
|
+ const uint8_t *req_ie,
|
|
|
+ size_t req_ie_len, const uint8_t *resp_ie,
|
|
|
+ size_t resp_ie_len)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static void osif_cm_get_reassoc_req_ie_data(struct element_info *assoc_req,
|
|
|
+ size_t *ie_data_len,
|
|
|
+ const uint8_t **ie_data_ptr)
|
|
|
+{
|
|
|
+ /* Validate IE and length */
|
|
|
+ if (!assoc_req->len || !assoc_req->ptr ||
|
|
|
+ assoc_req->len <= WLAN_REASSOC_REQ_IES_OFFSET)
|
|
|
+ return;
|
|
|
+
|
|
|
+ *ie_data_len = assoc_req->len - WLAN_REASSOC_REQ_IES_OFFSET;
|
|
|
+ *ie_data_ptr = assoc_req->ptr + WLAN_REASSOC_REQ_IES_OFFSET;
|
|
|
+}
|
|
|
+
|
|
|
void osif_indicate_reassoc_results(struct wlan_objmgr_vdev *vdev,
|
|
|
struct vdev_osif_priv *osif_priv,
|
|
|
struct wlan_cm_connect_resp *rsp)
|
|
@@ -96,10 +385,18 @@ void osif_indicate_reassoc_results(struct wlan_objmgr_vdev *vdev,
|
|
|
const uint8_t *rsp_ie = NULL;
|
|
|
struct cfg80211_bss *bss;
|
|
|
struct ieee80211_channel *chan;
|
|
|
+ struct wlan_objmgr_psoc *psoc;
|
|
|
+ bool roam_offload = false;
|
|
|
|
|
|
if (QDF_IS_STATUS_ERROR(rsp->connect_status))
|
|
|
return;
|
|
|
|
|
|
+ psoc = wlan_vdev_get_psoc(vdev);
|
|
|
+ if (!psoc)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ucfg_mlme_is_roam_scan_offload_enabled(psoc, &roam_offload);
|
|
|
+
|
|
|
chan = ieee80211_get_channel(osif_priv->wdev->wiphy,
|
|
|
rsp->freq);
|
|
|
bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan,
|
|
@@ -107,15 +404,17 @@ void osif_indicate_reassoc_results(struct wlan_objmgr_vdev *vdev,
|
|
|
rsp->ssid.length);
|
|
|
if (!bss)
|
|
|
osif_warn("not able to find bss");
|
|
|
- osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req,
|
|
|
- &req_len, &req_ie);
|
|
|
+ if (!roam_offload || rsp->is_ft)
|
|
|
+ osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req,
|
|
|
+ &req_len, &req_ie);
|
|
|
+ else
|
|
|
+ osif_cm_get_reassoc_req_ie_data(&rsp->connect_ies.assoc_req,
|
|
|
+ &req_len, &req_ie);
|
|
|
osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp,
|
|
|
&rsp_len, &rsp_ie);
|
|
|
osif_roamed_ind(dev, bss, req_ie, req_len, rsp_ie, rsp_len);
|
|
|
-
|
|
|
- osif_cm_save_gtk(vdev, rsp);
|
|
|
-
|
|
|
- /* Add osif_send_roam_auth_event (wlan_hdd_send_roam_auth_event) */
|
|
|
+ osif_send_roam_auth_event(vdev, osif_priv, rsp, req_ie, req_len, rsp_ie,
|
|
|
+ rsp_len);
|
|
|
|
|
|
osif_update_fils_hlp_data(dev, vdev, rsp);
|
|
|
}
|