|
@@ -3276,6 +3276,412 @@ int wma_roam_auth_offload_event_handler(WMA_HANDLE handle, uint8_t *event,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
|
|
|
+static void
|
|
|
+wma_get_trigger_detail_str(struct wmi_roam_trigger_info roam_info, char *buf)
|
|
|
+{
|
|
|
+ uint16_t buf_cons, buf_left = MAX_ROAM_DEBUG_BUF_SIZE;
|
|
|
+ char *temp = buf;
|
|
|
+
|
|
|
+ buf_cons = qdf_snprint(temp, buf_left, "Reason: \"%s\" ",
|
|
|
+ mlme_get_roam_trigger_str(roam_info.trigger_reason));
|
|
|
+ temp += buf_cons;
|
|
|
+ buf_left -= buf_cons;
|
|
|
+
|
|
|
+ if (roam_info.trigger_sub_reason) {
|
|
|
+ buf_cons = qdf_snprint(
|
|
|
+ temp, buf_left, "Sub-Reason: %s",
|
|
|
+ mlme_get_sub_reason_str(roam_info.trigger_sub_reason));
|
|
|
+ temp += buf_cons;
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (roam_info.trigger_reason) {
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_PER:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_BMISS:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_HIGH_RSSI:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_PERIODIC:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_MAWC:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_DENSE:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_BACKGROUND:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_IDLE:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_FORCED:
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_UNIT_TEST:
|
|
|
+ return;
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_BTM:
|
|
|
+ buf_cons = qdf_snprint(temp, buf_left,
|
|
|
+ "Req_mode: %d Disassoc_timer: %d",
|
|
|
+ roam_info.btm_trig_data.btm_request_mode,
|
|
|
+ roam_info.btm_trig_data.disassoc_timer);
|
|
|
+ temp += buf_cons;
|
|
|
+ buf_left -= buf_cons;
|
|
|
+
|
|
|
+ buf_cons = qdf_snprint(temp, buf_left,
|
|
|
+ "validity_interval: %d candidate_list_cnt: %d resp_status: %d",
|
|
|
+ roam_info.btm_trig_data.validity_interval,
|
|
|
+ roam_info.btm_trig_data.candidate_list_count,
|
|
|
+ roam_info.btm_trig_data.btm_resp_status);
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ temp += buf_cons;
|
|
|
+ return;
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_BSS_LOAD:
|
|
|
+ buf_cons = qdf_snprint(temp, buf_left, "CU: %d %% ",
|
|
|
+ roam_info.cu_trig_data.cu_load);
|
|
|
+ temp += buf_cons;
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ return;
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_DEAUTH:
|
|
|
+ buf_cons = qdf_snprint(temp, buf_left, "Type: %d Reason: %d ",
|
|
|
+ roam_info.deauth_trig_data.type,
|
|
|
+ roam_info.deauth_trig_data.reason);
|
|
|
+ temp += buf_cons;
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ return;
|
|
|
+ case WMI_ROAM_TRIGGER_REASON_LOW_RSSI:
|
|
|
+ buf_cons = qdf_snprint(temp, buf_left, "Low_rssi_threshold: %d",
|
|
|
+ roam_info.rssi_trig_data.threshold);
|
|
|
+ temp += buf_cons;
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ return;
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+wma_rso_print_trigger_info(struct wmi_roam_trigger_info data, uint8_t vdev_id)
|
|
|
+{
|
|
|
+ char *buf;
|
|
|
+ char time[TIME_STRING_LEN];
|
|
|
+
|
|
|
+ buf = qdf_mem_malloc(MAX_ROAM_DEBUG_BUF_SIZE);
|
|
|
+ if (!buf)
|
|
|
+ return;
|
|
|
+
|
|
|
+ wma_get_trigger_detail_str(data, buf);
|
|
|
+ mlme_get_converted_timestamp(data.timestamp, time);
|
|
|
+ WMA_LOGI("[ROAM_DEBUG] %s [ROAM_TRIGGER]: VDEV[%d] Current_rssi: %d dBm %s",
|
|
|
+ time, vdev_id, data.current_rssi, buf);
|
|
|
+
|
|
|
+ qdf_mem_free(buf);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+wma_log_roam_scan_candidates(struct wmi_roam_candidate_info *ap,
|
|
|
+ uint8_t num_entries)
|
|
|
+{
|
|
|
+ uint16_t i;
|
|
|
+ char time[TIME_STRING_LEN];
|
|
|
+
|
|
|
+ WMA_LOGI("%40s%40s%40s", LINE_STR, LINE_STR, LINE_STR);
|
|
|
+ WMA_LOGI("%13s %20s %11s %6s %12s %8s %12s %8s %10s %13s",
|
|
|
+ "AP BSSID", "TIMESTAMP", "CHANNEL", "TYPE", "ETP", "RSSI",
|
|
|
+ "RSSI_SCORE", "CU_LOAD", "CU_SCORE", "TOTAL_SCORE");
|
|
|
+ WMA_LOGI("%40s%40s%40s", LINE_STR, LINE_STR, LINE_STR);
|
|
|
+
|
|
|
+ if (num_entries > MAX_ROAM_CANDIDATE_AP)
|
|
|
+ num_entries = MAX_ROAM_CANDIDATE_AP;
|
|
|
+
|
|
|
+ for (i = 0; i < num_entries; i++) {
|
|
|
+ mlme_get_converted_timestamp(ap->timestamp, time);
|
|
|
+ WMA_LOGI(QDF_MAC_ADDR_STR " %20s %5d %-12s %4d(Mbps) %3d(dBm) %6d %7d %% %10d %12d",
|
|
|
+ QDF_MAC_ADDR_ARRAY(ap->bssid.bytes), time, ap->freq,
|
|
|
+ ((ap->type == 0) ? "CANDIDATE_AP" :
|
|
|
+ ((ap->type == 2) ? "ROAMED_AP" : "PREVIOUS_AP")),
|
|
|
+ ap->etp, ap->rssi, ap->rssi_score, ap->cu_load,
|
|
|
+ ap->cu_score, ap->total_score);
|
|
|
+ ap++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+wma_rso_print_scan_info(struct wmi_roam_scan_data scan, uint8_t vdev_id,
|
|
|
+ uint32_t trigger, uint32_t timestamp)
|
|
|
+{
|
|
|
+ uint16_t num_ch = scan.num_chan;
|
|
|
+ uint16_t buf_cons = 0, buf_left = ROAM_CHANNEL_BUF_SIZE;
|
|
|
+ uint8_t i;
|
|
|
+ char *buf, *buf1, *tmp;
|
|
|
+ char time[TIME_STRING_LEN];
|
|
|
+
|
|
|
+ buf = qdf_mem_malloc(ROAM_CHANNEL_BUF_SIZE);
|
|
|
+ if (!buf)
|
|
|
+ return;
|
|
|
+
|
|
|
+ tmp = buf;
|
|
|
+ /* For partial scans, print the channel info */
|
|
|
+ if (!scan.type) {
|
|
|
+ buf_cons = qdf_snprint(tmp, buf_left, "{");
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ tmp += buf_cons;
|
|
|
+
|
|
|
+ for (i = 0; i < num_ch; i++) {
|
|
|
+ buf_cons = qdf_snprint(tmp, buf_left, "%d ",
|
|
|
+ scan.chan_freq[i]);
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ tmp += buf_cons;
|
|
|
+ }
|
|
|
+ buf_cons = qdf_snprint(tmp, buf_left, "}");
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ tmp += buf_cons;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf1 = qdf_mem_malloc(ROAM_FAILURE_BUF_SIZE);
|
|
|
+ if (!buf1) {
|
|
|
+ qdf_mem_free(buf);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (WMI_ROAM_TRIGGER_REASON_LOW_RSSI == trigger) {
|
|
|
+ qdf_snprint(buf1, ROAM_FAILURE_BUF_SIZE,
|
|
|
+ "next_rssi_threshold: %d dBm",
|
|
|
+ scan.next_rssi_threshold);
|
|
|
+ }
|
|
|
+
|
|
|
+ mlme_get_converted_timestamp(timestamp, time);
|
|
|
+ WMA_LOGI("[ROAM_DEBUG] %s [ROAM_SCAN]: VDEV[%d] Scan_type: %s %s %s",
|
|
|
+ time, vdev_id, (scan.type ? "FULL" : "PARTIAL"),
|
|
|
+ buf1, buf);
|
|
|
+ wma_log_roam_scan_candidates(scan.ap, scan.num_ap);
|
|
|
+
|
|
|
+ qdf_mem_free(buf);
|
|
|
+ qdf_mem_free(buf1);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+wma_rso_print_roam_result(struct wmi_roam_result res,
|
|
|
+ uint8_t vdev_id)
|
|
|
+{
|
|
|
+ char *buf;
|
|
|
+ char time[TIME_STRING_LEN];
|
|
|
+
|
|
|
+ buf = qdf_mem_malloc(ROAM_FAILURE_BUF_SIZE);
|
|
|
+ if (!buf)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!res.status)
|
|
|
+ qdf_snprint(buf, ROAM_FAILURE_BUF_SIZE, "Fail-Reason: %s",
|
|
|
+ mlme_get_roam_fail_reason_str(res.fail_reason));
|
|
|
+
|
|
|
+ mlme_get_converted_timestamp(res.timestamp, time);
|
|
|
+ WMA_LOGI("[ROAM_DEBUG] %s [ROAM_RESULT]: VDEV[%d] status:%s %s",
|
|
|
+ time, vdev_id, (res.status) ? "SUCCESS" : "FAILED", buf);
|
|
|
+
|
|
|
+ qdf_mem_free(buf);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+wma_rso_print_11kv_info(struct wmi_neighbor_report_data neigh_rpt,
|
|
|
+ uint8_t vdev_id, bool is_roam_success)
|
|
|
+{
|
|
|
+ char time[TIME_STRING_LEN], time1[TIME_STRING_LEN];
|
|
|
+ char *buf, *tmp;
|
|
|
+ uint8_t type = neigh_rpt.req_type, i;
|
|
|
+ uint16_t buf_left = ROAM_CHANNEL_BUF_SIZE, buf_cons;
|
|
|
+ uint8_t num_ch = neigh_rpt.num_freq;
|
|
|
+
|
|
|
+ if (!is_roam_success)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!type) {
|
|
|
+ WMA_LOGI("[ROAM_DEBUG] AP doesn't support neighbor rpt/BTM");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf = qdf_mem_malloc(ROAM_CHANNEL_BUF_SIZE);
|
|
|
+ if (!buf)
|
|
|
+ return;
|
|
|
+
|
|
|
+ tmp = buf;
|
|
|
+ for (i = 0; i < num_ch; i++) {
|
|
|
+ buf_cons = qdf_snprint(tmp, buf_left, "{ ");
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ tmp += buf_cons;
|
|
|
+
|
|
|
+ buf_cons = qdf_snprint(tmp, buf_left, "%d ",
|
|
|
+ neigh_rpt.freq[i]);
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ tmp += buf_cons;
|
|
|
+
|
|
|
+ buf_cons = qdf_snprint(tmp, buf_left, "}");
|
|
|
+ buf_left -= buf_cons;
|
|
|
+ tmp += buf_cons;
|
|
|
+ }
|
|
|
+ mlme_get_converted_timestamp(neigh_rpt.req_time, time);
|
|
|
+ WMA_LOGI("[ROAM_DEBUG] %s [%s] RX: VDEV[%d] %s", time,
|
|
|
+ (type == 1) ? "BTM" : "NEIGH_RPT", vdev_id, buf);
|
|
|
+
|
|
|
+ mlme_get_converted_timestamp(neigh_rpt.resp_time, time1);
|
|
|
+ WMA_LOGI("[ROAM_DEBUG] %s [%s] TX: VDEV[%d]", time1,
|
|
|
+ (type == 1) ? "BTM" : "NEIGH_RPT", vdev_id);
|
|
|
+ qdf_mem_free(buf);
|
|
|
+}
|
|
|
+
|
|
|
+int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
|
|
|
+ uint32_t len)
|
|
|
+{
|
|
|
+ tp_wma_handle wma = (tp_wma_handle) handle;
|
|
|
+ WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf;
|
|
|
+ wmi_roam_stats_event_fixed_param *fixed_param;
|
|
|
+ struct mlme_roam_debug_info *roam_info = NULL;
|
|
|
+ uint8_t vdev_id, i;
|
|
|
+ uint8_t num_tlv = 0, num_chan = 0, num_ap = 0, num_rpt = 0;
|
|
|
+ uint32_t rem_len;
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)event;
|
|
|
+ if (!param_buf) {
|
|
|
+ wma_err_rl("NULL event received from target");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ fixed_param = param_buf->fixed_param;
|
|
|
+ if (!fixed_param) {
|
|
|
+ wma_err_rl(" NULL fixed param");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ vdev_id = fixed_param->vdev_id;
|
|
|
+ if (vdev_id >= wma->max_bssid) {
|
|
|
+ wma_err_rl("Invalid vdev_id %d", vdev_id);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ num_tlv = fixed_param->roam_scan_trigger_count;
|
|
|
+ if (num_tlv != param_buf->num_roam_scan_info ||
|
|
|
+ num_tlv != param_buf->num_roam_trigger_reason ||
|
|
|
+ num_tlv != param_buf->num_roam_result ||
|
|
|
+ num_tlv != param_buf->num_roam_neighbor_report_info) {
|
|
|
+ wma_err_rl("Invalid roam stats num_tlv:%d num_scan:%d num_res:%d num_rept:%d",
|
|
|
+ num_tlv, param_buf->num_roam_scan_info,
|
|
|
+ param_buf->num_roam_result,
|
|
|
+ param_buf->num_roam_neighbor_report_info);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ rem_len = WMI_SVC_MSG_MAX_SIZE - sizeof(*fixed_param);
|
|
|
+ if (rem_len < num_tlv * sizeof(wmi_roam_trigger_reason)) {
|
|
|
+ wma_err_rl("Invalid roam trigger data");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ rem_len -= num_tlv * sizeof(wmi_roam_trigger_reason);
|
|
|
+ if (rem_len < num_tlv * sizeof(wmi_roam_scan_info)) {
|
|
|
+ wma_err_rl("Invalid roam scan data");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ rem_len -= num_tlv * sizeof(wmi_roam_scan_info);
|
|
|
+ if (rem_len < num_tlv * sizeof(wmi_roam_result)) {
|
|
|
+ wma_err_rl("Invalid roam result data");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ rem_len -= num_tlv * sizeof(wmi_roam_result);
|
|
|
+ if (rem_len < (num_tlv * sizeof(wmi_roam_neighbor_report_info))) {
|
|
|
+ wma_err_rl("Invalid roam neighbor report data");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ rem_len -= num_tlv * sizeof(wmi_roam_neighbor_report_info);
|
|
|
+ if (rem_len < (param_buf->num_roam_scan_chan_info *
|
|
|
+ sizeof(wmi_roam_scan_channel_info))) {
|
|
|
+ wma_err_rl("Invalid roam chan data num_tlv:%d",
|
|
|
+ param_buf->num_roam_scan_chan_info);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ rem_len -= param_buf->num_roam_scan_chan_info *
|
|
|
+ sizeof(wmi_roam_scan_channel_info);
|
|
|
+
|
|
|
+ if (rem_len < (param_buf->num_roam_ap_info *
|
|
|
+ sizeof(wmi_roam_ap_info))) {
|
|
|
+ wma_err_rl("Invalid roam ap data num_tlv:%d",
|
|
|
+ param_buf->num_roam_ap_info);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ rem_len -= param_buf->num_roam_ap_info * sizeof(wmi_roam_ap_info);
|
|
|
+ if (rem_len < (param_buf->num_roam_neighbor_report_chan_info *
|
|
|
+ sizeof(wmi_roam_neighbor_report_channel_info))) {
|
|
|
+ wma_err_rl("Invalid roam neigb rpt chan data num_tlv:%d",
|
|
|
+ param_buf->num_roam_neighbor_report_chan_info);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < num_tlv; i++) {
|
|
|
+ roam_info = qdf_mem_malloc(sizeof(*roam_info));
|
|
|
+ if (!roam_info)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Roam Trigger id and that specific roam trigger related
|
|
|
+ * details.
|
|
|
+ */
|
|
|
+ status = wmi_unified_extract_roam_trigger_stats(
|
|
|
+ wma->wmi_handle, event,
|
|
|
+ &roam_info->trigger, i);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ WMA_LOGE("%s: Extract roam trigger stats failed vdev%d",
|
|
|
+ __func__, vdev_id);
|
|
|
+ qdf_mem_free(roam_info);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Roam scan related details - Scan channel, scan type .. */
|
|
|
+ status = wmi_unified_extract_roam_scan_stats(
|
|
|
+ wma->wmi_handle, event, &roam_info->scan, i,
|
|
|
+ num_chan, num_ap);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ WMA_LOGE("%s: Roam scan stats extract failed vdev %d",
|
|
|
+ __func__, vdev_id);
|
|
|
+ qdf_mem_free(roam_info);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ num_chan += roam_info->scan.num_chan;
|
|
|
+ num_ap += roam_info->scan.num_ap;
|
|
|
+
|
|
|
+ /* Roam result - Success/Failure status, failure reason */
|
|
|
+ status = wmi_unified_extract_roam_result_stats(
|
|
|
+ wma->wmi_handle, event,
|
|
|
+ &roam_info->result, i);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ WMA_LOGE("%s: Roam result stats extract failed vdev %d",
|
|
|
+ __func__, vdev_id);
|
|
|
+ qdf_mem_free(roam_info);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* BTM req/resp or Neighbor report/response info */
|
|
|
+ status = wmi_unified_extract_roam_11kv_stats(
|
|
|
+ wma->wmi_handle, event,
|
|
|
+ &roam_info->data_11kv, i, num_rpt);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ WMA_LOGE("%s: Roam 11kv stats extract failed vdev %d",
|
|
|
+ __func__, vdev_id);
|
|
|
+ qdf_mem_free(roam_info);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ num_rpt += roam_info->data_11kv.num_freq;
|
|
|
+
|
|
|
+ wma_rso_print_trigger_info(roam_info->trigger, vdev_id);
|
|
|
+ wma_rso_print_scan_info(roam_info->scan, vdev_id,
|
|
|
+ roam_info->trigger.trigger_reason,
|
|
|
+ roam_info->trigger.timestamp);
|
|
|
+ wma_rso_print_roam_result(roam_info->result, vdev_id);
|
|
|
+ wma_rso_print_11kv_info(roam_info->data_11kv, vdev_id,
|
|
|
+ roam_info->result.status);
|
|
|
+
|
|
|
+ qdf_mem_free(roam_info);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err:
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
#define RSN_CAPS_SHIFT 16
|
|
|
/**
|
|
|
* wma_roam_scan_fill_self_caps() - fill capabilities
|