diff --git a/os_if/linux/scan/inc/wlan_cfg80211_scan.h b/os_if/linux/scan/inc/wlan_cfg80211_scan.h index d35e3c6a1e8e..174cb58a4a87 100644 --- a/os_if/linux/scan/inc/wlan_cfg80211_scan.h +++ b/os_if/linux/scan/inc/wlan_cfg80211_scan.h @@ -32,7 +32,7 @@ #include #include #include - +#include /* Max number of scans allowed from userspace */ #define WLAN_MAX_SCAN_COUNT 8 @@ -126,6 +126,25 @@ struct scan_params { struct element_info default_ie; }; +/** + * struct wlan_cfg80211_inform_bss - BSS inform data + * @chan: channel the frame was received on + * @mgmt: beacon/probe resp frame + * @frame_len: frame length + * @rssi: signal strength in mBm (100*dBm) + * @boottime_ns: timestamp (CLOCK_BOOTTIME) when the information was received. + * @per_chain_snr: per chain snr received + */ +struct wlan_cfg80211_inform_bss { + struct ieee80211_channel *chan; + struct ieee80211_mgmt *mgmt; + size_t frame_len; + int rssi; + uint64_t boottime_ns; + uint8_t per_chain_snr[WLAN_MGMT_TXRX_HOST_MAX_ANTENNA]; +}; + + #ifdef FEATURE_WLAN_SCAN_PNO /** * wlan_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start @@ -211,6 +230,19 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev, struct cfg80211_scan_request *request, struct scan_params *params); +/** + * wlan_cfg80211_inform_bss_frame_data() - API to inform beacon to cfg80211 + * @wiphy: wiphy + * @bss_data: bss data + * + * API to inform beacon to cfg80211 + * + * Return: pointer to bss entry + */ +struct cfg80211_bss * +wlan_cfg80211_inform_bss_frame_data(struct wiphy *wiphy, + struct wlan_cfg80211_inform_bss *bss); + /** * wlan_cfg80211_inform_bss_frame() - API to inform beacon to cfg80211 * @pdev: Pointer to pdev diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c index f1b5f7fb4616..fee58cb63d4f 100644 --- a/os_if/linux/scan/src/wlan_cfg80211_scan.c +++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c @@ -1574,16 +1574,82 @@ static inline void wlan_add_age_ie(uint8_t *mgmt_frame, } #endif /* WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || \ + defined(CFG80211_INFORM_BSS_FRAME_DATA) +/** + * wlan_fill_per_chain_rssi() - fill per chain RSSI in inform bss + * @data: bss data + * @per_chain_snr: per chain RSSI + * + * Return: void + */ +#if defined(CFG80211_SCAN_PER_CHAIN_RSSI_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) +static void wlan_fill_per_chain_rssi(struct cfg80211_inform_bss *data, + struct wlan_cfg80211_inform_bss *bss) +{ + + uint32_t i; + + if (!bss || !data) { + cfg80211_err("Received bss is NULL"); + return; + } + for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) { + if (!bss->per_chain_snr[i] || + (bss->per_chain_snr[i] == WLAN_INVALID_PER_CHAIN_RSSI)) + continue; + /* Add noise margin to SNR to convert it to RSSI */ + data->chain_signal[i] = bss->per_chain_snr[i] + + WLAN_NOISE_FLOOR_DBM_DEFAULT; + data->chains |= BIT(i); + } +} +#else +static inline void +wlan_fill_per_chain_rssi(struct cfg80211_inform_bss *data, + struct wlan_cfg80211_inform_bss *bss) +{ +} +#endif + +struct cfg80211_bss * +wlan_cfg80211_inform_bss_frame_data(struct wiphy *wiphy, + struct wlan_cfg80211_inform_bss *bss) +{ + struct cfg80211_inform_bss data = {0}; + + if (!bss) { + cfg80211_err("bss is null"); + return NULL; + } + wlan_fill_per_chain_rssi(&data, bss); + + data.chan = bss->chan; + data.boottime_ns = bss->boottime_ns; + data.signal = bss->rssi; + return cfg80211_inform_bss_frame_data(wiphy, &data, bss->mgmt, + bss->frame_len, GFP_KERNEL); +} +#else +struct cfg80211_bss * +wlan_cfg80211_inform_bss_frame_data(struct wiphy *wiphy, + struct wlan_cfg80211_inform_bss *bss) + +{ + return cfg80211_inform_bss_frame(wiphy, bss->chan, bss->mgmt, + bss->frame_len, + bss->rssi, GFP_KERNEL); +} +#endif + void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params) { struct pdev_osif_priv *pdev_ospriv = wlan_pdev_get_ospriv(pdev); struct wiphy *wiphy; - int frame_len; - struct ieee80211_mgmt *mgmt = NULL; - struct ieee80211_channel *chan; - int rssi = 0; struct cfg80211_bss *bss_status = NULL; + struct wlan_cfg80211_inform_bss bss_data = {0}; if (!pdev_ospriv) { cfg80211_err("os_priv is NULL"); @@ -1592,31 +1658,31 @@ void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev, wiphy = pdev_ospriv->wiphy; - frame_len = wlan_get_frame_len(scan_params); - mgmt = qdf_mem_malloc(frame_len); - if (!mgmt) { + bss_data.frame_len = wlan_get_frame_len(scan_params); + bss_data.mgmt = qdf_mem_malloc(bss_data.frame_len); + if (!bss_data.mgmt) { cfg80211_err("mem alloc failed"); return; } - qdf_mem_copy(mgmt, + qdf_mem_copy(bss_data.mgmt, util_scan_entry_frame_ptr(scan_params), util_scan_entry_frame_len(scan_params)); /* * Android does not want the timestamp from the frame. * Instead it wants a monotonic increasing value */ - mgmt->u.probe_resp.timestamp = qdf_get_monotonic_boottime(); - wlan_add_age_ie((uint8_t *)mgmt, scan_params); + bss_data.mgmt->u.probe_resp.timestamp = qdf_get_monotonic_boottime(); + wlan_add_age_ie((uint8_t *)bss_data.mgmt, scan_params); /* * Based on .ini configuration, raw rssi can be reported for bss. * Raw rssi is typically used for estimating power. */ - rssi = scan_params->rssi_raw; + bss_data.rssi = scan_params->rssi_raw; - chan = wlan_get_ieee80211_channel(wiphy, + bss_data.chan = wlan_get_ieee80211_channel(wiphy, scan_params->channel.chan_idx); - if (!chan) { - qdf_mem_free(mgmt); + if (!bss_data.chan) { + qdf_mem_free(bss_data.mgmt); return; } @@ -1624,13 +1690,20 @@ void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev, * Supplicant takes the signal strength in terms of * mBm (1 dBm = 100 mBm). */ - rssi = QDF_MIN(rssi, 0) * 100; + bss_data.rssi = QDF_MIN(bss_data.rssi, 0) * 100; + + bss_data.boottime_ns = scan_params->boottime_ns; + + qdf_mem_copy(bss_data.per_chain_snr, scan_params->per_chain_snr, + WLAN_MGMT_TXRX_HOST_MAX_ANTENNA); cfg80211_info("BSSID: %pM Channel:%d RSSI:%d", - mgmt->bssid, chan->center_freq, (int)(rssi / 100)); + bss_data.mgmt->bssid, bss_data.chan->center_freq, + (int)(bss_data.rssi / 100)); - bss_status = - cfg80211_inform_bss_frame(wiphy, chan, mgmt, - frame_len, rssi, GFP_KERNEL); - qdf_mem_free(mgmt); + bss_status = wlan_cfg80211_inform_bss_frame_data(wiphy, &bss_data); + if (!bss_status) + cfg80211_err("failed to inform bss"); + + qdf_mem_free(bss_data.mgmt); } diff --git a/umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h b/umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h index b85056829e3e..57cfb35e3adc 100644 --- a/umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h +++ b/umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h @@ -644,8 +644,9 @@ enum mgmt_frame_type { MGMT_MAX_FRAME_TYPE, }; -#define WLAN_MGMT_TXRX_HOST_MAX_ANTENNA 4 - +#define WLAN_MGMT_TXRX_HOST_MAX_ANTENNA 4 +#define WLAN_INVALID_PER_CHAIN_RSSI 0x80 +#define WLAN_NOISE_FLOOR_DBM_DEFAULT -96 /** * struct mgmt_rx_event_params - host mgmt header params * @channel: channel on which this frame is received diff --git a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h index 50325d7e58e1..9eead5aba51d 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h +++ b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h @@ -27,6 +27,7 @@ #include #include #include +#include typedef uint16_t wlan_scan_requester; typedef uint32_t wlan_scan_id; @@ -278,6 +279,8 @@ struct security_info { * @tsf_delta: TSF delta * @bss_score: bss score calculated on basis of RSSI/caps etc. * @neg_sec_info: negotiated security info + * @per_chain_snr: per chain SNR value received. + * boottime_ns: boottime in ns. * @rrm_parent_tsf: RRM parent tsf * @mlme_info: Mlme info, this will be updated by MLME for the scan entry * @alt_wcn_ie: alternate WCN IE @@ -314,6 +317,8 @@ struct scan_cache_entry { uint32_t tsf_delta; uint32_t bss_score; struct security_info neg_sec_info; + uint8_t per_chain_snr[WLAN_MGMT_TXRX_HOST_MAX_ANTENNA]; + uint64_t boottime_ns; uint32_t rrm_parent_tsf; struct element_info alt_wcn_ie; struct ie_list ie_list; diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c index fa8ecfafd40b..9a4b4c6d7222 100644 --- a/umac/scan/dispatcher/src/wlan_scan_utils_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_utils_api.c @@ -853,6 +853,9 @@ util_scan_unpack_beacon_frame(uint8_t *frame, (frame + sizeof(*hdr)); hdr = (struct wlan_frame_hdr *)frame; + /* update timestamp in nanoseconds needed by kernel layers */ + scan_entry->boottime_ns = qdf_get_monotonic_boottime_ns(); + scan_entry->frm_subtype = frm_subtype; qdf_mem_copy(scan_entry->bssid.bytes, hdr->i_addr3, QDF_MAC_ADDR_SIZE); @@ -866,6 +869,10 @@ util_scan_unpack_beacon_frame(uint8_t *frame, scan_entry->avg_rssi = WLAN_RSSI_IN(scan_entry->rssi_raw); scan_entry->tsf_delta = rx_param->tsf_delta; + /* Copy per chain rssi to scan entry */ + qdf_mem_copy(scan_entry->per_chain_snr, rx_param->rssi_ctl, + WLAN_MGMT_TXRX_HOST_MAX_ANTENNA); + /* store jiffies */ scan_entry->rrm_parent_tsf = (u_int32_t) qdf_system_ticks(); diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 344165e54a8b..a65df736e6fd 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -18416,6 +18416,7 @@ static QDF_STATUS extract_mgmt_rx_params_tlv(wmi_unified_t wmi_handle, { WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs = NULL; wmi_mgmt_rx_hdr *ev_hdr = NULL; + int i; param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *) evt_buf; if (!param_tlvs) { @@ -18441,7 +18442,8 @@ static QDF_STATUS extract_mgmt_rx_params_tlv(wmi_unified_t wmi_handle, hdr->flags = ev_hdr->flags; hdr->rssi = ev_hdr->rssi; hdr->tsf_delta = ev_hdr->tsf_delta; - qdf_mem_copy(hdr->rssi_ctl, ev_hdr->rssi_ctl, sizeof(hdr->rssi_ctl)); + for (i = 0; i < ATH_MAX_ANTENNA; i++) + hdr->rssi_ctl[i] = ev_hdr->rssi_ctl[i]; *bufp = param_tlvs->bufp;