|
@@ -1,5 +1,6 @@
|
|
|
/*
|
|
|
* Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
|
|
|
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
|
*
|
|
|
* Permission to use, copy, modify, and/or distribute this software for
|
|
|
* any purpose with or without fee is hereby granted, provided that the
|
|
@@ -546,3 +547,109 @@ err:
|
|
|
}
|
|
|
return status;
|
|
|
}
|
|
|
+
|
|
|
+QDF_STATUS
|
|
|
+cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct roam_scan_candidate_frame *candidate)
|
|
|
+{
|
|
|
+ struct wlan_objmgr_vdev *vdev;
|
|
|
+ struct wlan_objmgr_pdev *pdev;
|
|
|
+ struct cnx_mgr *cm_ctx;
|
|
|
+ uint32_t ie_offset, ie_len;
|
|
|
+ uint8_t *ie_ptr = NULL;
|
|
|
+ uint8_t *extracted_ie = NULL;
|
|
|
+ uint8_t primary_channel, band;
|
|
|
+ qdf_freq_t op_freq;
|
|
|
+
|
|
|
+ vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, candidate->vdev_id,
|
|
|
+ WLAN_MLME_CM_ID);
|
|
|
+ if (!vdev) {
|
|
|
+ mlme_err("vdev object is NULL");
|
|
|
+ return QDF_STATUS_E_NULL_VALUE;
|
|
|
+ }
|
|
|
+
|
|
|
+ pdev = wlan_vdev_get_pdev(vdev);
|
|
|
+ if (!pdev) {
|
|
|
+ mlme_err("pdev object is NULL");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ cm_ctx = cm_get_cm_ctx(vdev);
|
|
|
+ if (!cm_ctx) {
|
|
|
+ mlme_err("cm ctx is NULL");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG,
|
|
|
+ candidate->frame, candidate->frame_length);
|
|
|
+ /* Fixed parameters offset */
|
|
|
+ ie_offset = sizeof(struct wlan_frame_hdr) + MAC_B_PR_SSID_OFFSET;
|
|
|
+
|
|
|
+ if (candidate->frame_length <= ie_offset) {
|
|
|
+ mlme_err("Invalid frame length");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ ie_ptr = candidate->frame + ie_offset;
|
|
|
+ ie_len = candidate->frame_length - ie_offset;
|
|
|
+
|
|
|
+ /* For 2.4GHz,5GHz get channel from DS IE */
|
|
|
+ extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_DSPARMS,
|
|
|
+ ie_ptr, ie_len);
|
|
|
+ if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_DSPARMS &&
|
|
|
+ extracted_ie[1] == WLAN_DS_PARAM_IE_MAX_LEN) {
|
|
|
+ band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
|
|
|
+ primary_channel = *(extracted_ie + 2);
|
|
|
+ mlme_debug("Extracted primary channel from DS : %d",
|
|
|
+ primary_channel);
|
|
|
+ goto update_beacon;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* For HT, VHT and non-6GHz HE, get channel from HTINFO IE */
|
|
|
+ extracted_ie = (uint8_t *)
|
|
|
+ wlan_get_ie_ptr_from_eid(WLAN_ELEMID_HTINFO_ANA,
|
|
|
+ ie_ptr, ie_len);
|
|
|
+ if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_HTINFO_ANA &&
|
|
|
+ extracted_ie[1] == sizeof(struct wlan_ie_htinfo_cmn)) {
|
|
|
+ band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
|
|
|
+ primary_channel =
|
|
|
+ ((struct wlan_ie_htinfo *)extracted_ie)->
|
|
|
+ hi_ie.hi_ctrlchannel;
|
|
|
+ mlme_debug("Extracted primary channel from HT INFO : %d",
|
|
|
+ primary_channel);
|
|
|
+ goto update_beacon;
|
|
|
+ }
|
|
|
+ /* For 6GHz, get channel from HE OP IE */
|
|
|
+ extracted_ie = (uint8_t *)
|
|
|
+ wlan_get_ext_ie_ptr_from_ext_id(WLAN_HEOP_OUI_TYPE,
|
|
|
+ (uint8_t)
|
|
|
+ WLAN_HEOP_OUI_SIZE,
|
|
|
+ ie_ptr, ie_len);
|
|
|
+ if (extracted_ie && !qdf_mem_cmp(&extracted_ie[2], WLAN_HEOP_OUI_TYPE,
|
|
|
+ WLAN_HEOP_OUI_SIZE) &&
|
|
|
+ extracted_ie[1] <= WLAN_MAX_HEOP_IE_LEN) {
|
|
|
+ band = BIT(REG_BAND_6G);
|
|
|
+ primary_channel = util_scan_get_6g_oper_channel(extracted_ie);
|
|
|
+ mlme_debug("Extracted primary channel from HE OP : %d",
|
|
|
+ primary_channel);
|
|
|
+ if (primary_channel)
|
|
|
+ goto update_beacon;
|
|
|
+ }
|
|
|
+
|
|
|
+ mlme_err("Primary channel was not found in the candidate scan entry");
|
|
|
+ goto err;
|
|
|
+
|
|
|
+update_beacon:
|
|
|
+ op_freq = wlan_reg_chan_band_to_freq(pdev, primary_channel, band);
|
|
|
+ mlme_debug("Roaming candidate frequency : %d", op_freq);
|
|
|
+ cm_inform_bcn_probe(cm_ctx, candidate->frame, candidate->frame_length,
|
|
|
+ op_freq,
|
|
|
+ 0, /* Real RSSI will be updated by Roam synch ind */
|
|
|
+ cm_ctx->active_cm_id);
|
|
|
+
|
|
|
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+err:
|
|
|
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
|
|
|
+ return QDF_STATUS_E_FAILURE;
|
|
|
+}
|