diff --git a/core/hdd/inc/wlan_hdd_bcn_recv.h b/core/hdd/inc/wlan_hdd_bcn_recv.h index b169a30ae857..9ac79a3d2a89 100644 --- a/core/hdd/inc/wlan_hdd_bcn_recv.h +++ b/core/hdd/inc/wlan_hdd_bcn_recv.h @@ -50,7 +50,14 @@ int wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, WIPHY_VENDOR_CMD_NEED_RUNNING, \ .doit = wlan_hdd_cfg80211_bcn_rcv_start \ }, + +#define BCN_RECV_FEATURE_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING \ +}, #else #define BCN_RECV_FEATURE_VENDOR_COMMANDS +#define BCN_RECV_FEATURE_VENDOR_EVENTS #endif diff --git a/core/hdd/src/wlan_hdd_bcn_recv.c b/core/hdd/src/wlan_hdd_bcn_recv.c index dda46a014262..dc65934452bb 100644 --- a/core/hdd/src/wlan_hdd_bcn_recv.c +++ b/core/hdd/src/wlan_hdd_bcn_recv.c @@ -30,6 +30,8 @@ #include "osif_sync.h" #include "wlan_hdd_bcn_recv.h" +#define BOOTTIME QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED + static const struct nla_policy beacon_reporting_params[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE] = {.type = NLA_U8}, @@ -38,6 +40,101 @@ beacon_reporting_params[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD] = {.type = NLA_U8}, }; +/** + * get_beacon_report_data_len() - Calculate length for beacon + * report to allocate skb buffer + * @report: beacon report structure + * + * Return: skb buffer length + */ +static +int get_beacon_report_data_len(struct wlan_beacon_report *report) +{ + uint32_t data_len = NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE */ + data_len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID */ + data_len += nla_total_size(report->ssid.length); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID */ + data_len += nla_total_size(ETH_ALEN); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ */ + data_len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI */ + data_len += nla_total_size(sizeof(u16)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF */ + data_len += nla_total_size(sizeof(uint64_t)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED */ + data_len += nla_total_size(sizeof(uint64_t)); + + return data_len; +} + +/** + * hdd_send_bcn_recv_info() - Send beacon info to userspace for + * connected AP + * @hdd_handle: hdd_handle to get hdd_adapter + * @beacon_report: Required beacon report + * + * Send beacon info to userspace for connected AP through a vendor event: + * QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING. + */ +static void hdd_send_bcn_recv_info(hdd_handle_t hdd_handle, + struct wlan_beacon_report *beacon_report) +{ + struct sk_buff *vendor_event; + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + uint32_t data_len; + int flags = cds_get_gfp_flags(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + data_len = get_beacon_report_data_len(beacon_report); + + vendor_event = + cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, + data_len, + QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX, + flags); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE, + QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO) || + nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID, + beacon_report->ssid.length, beacon_report->ssid.ssid) || + nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID, + ETH_ALEN, beacon_report->bssid.bytes) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ, + beacon_report->frequency) || + nla_put_u16(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI, + beacon_report->beacon_interval) || + wlan_cfg80211_nla_put_u64(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF, + beacon_report->time_stamp) || + wlan_cfg80211_nla_put_u64(vendor_event, BOOTTIME, + beacon_report->boot_time)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, flags); +} + /** * __wlan_hdd_cfg80211_bcn_rcv_start() - enable/disable beacon reporting * indication @@ -62,6 +159,7 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, uint32_t bcn_report; int errno; QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + bool active_report; hdd_enter_dev(dev); @@ -74,6 +172,11 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, return -EINVAL; } + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("STA not in connected state"); + return -EINVAL; + } + errno = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX, @@ -88,13 +191,26 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, hdd_err("attr beacon report OP type failed"); return -EINVAL; } + active_report = + !!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING]; + hdd_debug("attr active_report %d", active_report); bcn_report = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE]); hdd_debug("Bcn Report: OP type:%d", bcn_report); if (bcn_report == QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START) { - /* Vendor event is intended for Start*/ + if (active_report) { + qdf_status = sme_register_bcn_report_pe_cb( + hdd_ctx->mac_handle, + hdd_send_bcn_recv_info); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("bcn recv info cb reg failed = %d", + qdf_status); + errno = qdf_status_to_os_return(qdf_status); + return errno; + } + } qdf_status = sme_handle_bcn_recv_start(hdd_ctx->mac_handle, adapter->vdev_id); diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 3c536884099b..eac7b6bbbb8a 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1507,6 +1507,9 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES, }, + + BCN_RECV_FEATURE_VENDOR_EVENTS + #ifdef WLAN_UMAC_CONVERGENCE COMMON_VENDOR_EVENTS #endif diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h index 821ffc4ee2b9..90d6d90c8242 100644 --- a/core/mac/inc/ani_global.h +++ b/core/mac/inc/ani_global.h @@ -673,6 +673,8 @@ typedef struct sAniSirLim { uint8_t retry_packet_cnt; uint8_t beacon_probe_rsp_cnt_per_scan; wlan_scan_requester req_id; + QDF_STATUS (*sme_bcn_rcv_callback)(hdd_handle_t hdd_handle, + struct wlan_beacon_report *beacon_report); } tAniSirLim, *tpAniSirLim; struct mgmt_frm_reg_info { diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 83c3c2b76825..680027526bc1 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -186,6 +186,25 @@ struct rsn_caps { uint16_t Reserved:8; }; +/** + * struct wlan_beacon_report - Beacon info to be send to userspace + * @ssid: ssid present in beacon + * @bssid: bssid present in beacon + * @frequency: channel frequency in MHz + * @beacon_interval: Interval between two consecutive beacons + * @time_stamp: time stamp at which beacon received from AP + * @boot_time: Boot time when beacon received + */ +struct wlan_beacon_report { + struct wlan_ssid ssid; + struct qdf_mac_addr bssid; + uint32_t frequency; + uint16_t beacon_interval; + qdf_time_t time_stamp; + qdf_time_t boot_time; +}; + + /* / Result codes Firmware return to Host SW */ typedef enum eSirResultCodes { eSIR_SME_SUCCESS, diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h index b0cbf1472666..a31ae81fc496 100644 --- a/core/mac/inc/wni_api.h +++ b/core/mac/inc/wni_api.h @@ -237,7 +237,8 @@ enum eWniMsgTypes { eWNI_SME_HIDDEN_SSID_RESTART_RSP = SIR_SME_MSG_TYPES_BEGIN + 151, eWNI_SME_FW_STATUS_IND = SIR_SME_MSG_TYPES_BEGIN + 152, eWNI_SME_STA_CSA_CONTINUE_REQ = SIR_SME_MSG_TYPES_BEGIN + 153, - eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 154 + WNI_SME_REGISTER_BCN_REPORT_SEND_CB = SIR_SME_MSG_TYPES_BEGIN + 154, + eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 155 }; typedef struct sAniCfgTxRateCtrs { diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c index 4dad389cf303..ad1277c9987b 100644 --- a/core/mac/src/pe/lim/lim_process_message_queue.c +++ b/core/mac/src/pe/lim/lim_process_message_queue.c @@ -1727,6 +1727,7 @@ static void lim_process_messages(struct mac_context *mac_ctx, case eWNI_SME_UPDATE_EDCA_PROFILE: case WNI_SME_UPDATE_MU_EDCA_PARAMS: case WNI_SME_CFG_ACTION_FRM_HE_TB_PPDU: + case WNI_SME_REGISTER_BCN_REPORT_SEND_CB: /* These messages are from HDD.No need to respond to HDD */ lim_process_normal_hdd_msg(mac_ctx, msg, false); break; diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index e69583596ea6..ba1537dfc1ff 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -390,6 +390,36 @@ static bool __lim_process_sme_sys_ready_ind(struct mac_context *mac, return false; } +#ifdef WLAN_BCN_RECV_FEATURE +/** + * lim_register_bcn_report_send_cb() - Register bcn receive start + * indication handler callback + * @mac: Pointer to Global MAC structure + * @msg: A pointer to the SME message buffer + * + * Once driver gets QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING vendor + * command with attribute for start only. LIM layer register a sme + * callback through this function. + * + * Return: None. + */ +static void lim_register_bcn_report_send_cb(struct mac_context *mac, + struct scheduler_msg *msg) +{ + if (!msg) { + pe_err("Invalid message"); + return; + } + + mac->lim.sme_bcn_rcv_callback = msg->callback; +} +#else +static inline +void lim_register_bcn_report_send_cb(struct mac_context *mac, + struct scheduler_msg *msg) +{ +} +#endif /** *lim_configure_ap_start_bss_session() - Configure the AP Start BSS in session. *@mac_ctx: Pointer to Global MAC structure @@ -4982,6 +5012,9 @@ bool lim_process_sme_req_messages(struct mac_context *mac, lim_process_sme_cfg_action_frm_in_tb_ppdu(mac, (struct sir_cfg_action_frm_tb_ppdu *)pMsgBuf); break; + case WNI_SME_REGISTER_BCN_REPORT_SEND_CB: + lim_register_bcn_report_send_cb(mac, pMsg); + break; default: qdf_mem_free((void *)pMsg->bodyptr); pMsg->bodyptr = NULL; diff --git a/core/mac/src/pe/sch/sch_beacon_process.c b/core/mac/src/pe/sch/sch_beacon_process.c index b791be3ef699..5c74f5b3c640 100644 --- a/core/mac/src/pe/sch/sch_beacon_process.c +++ b/core/mac/src/pe/sch/sch_beacon_process.c @@ -1083,6 +1083,69 @@ void sch_beacon_process_for_ap(struct mac_context *mac_ctx, } } +#ifdef WLAN_BCN_RECV_FEATURE +/* + * sch_send_beacon_report() - To Fill beacon report for + * each beacon coming from connected peer and sends it + * to upper layer + * @mac_ctx: Mac context + * @beacon_struct: Pointing to beacon structure + * @session: pointer to the PE session + * + * Return: None + */ +static +void sch_send_beacon_report(struct mac_context *mac_ctx, + struct sSirProbeRespBeacon *beacon_struct, + struct pe_session *session) +{ + struct wlan_beacon_report beacon_report; + + if (!mac_ctx->lim.sme_bcn_rcv_callback) { + pe_err("sme_bcn_rcv_callback is NULL"); + return; + } + + if (!LIM_IS_STA_ROLE(session)) { + pe_err("Session is not for STA"); + return; + } + + if (sir_compare_mac_addr(session->bssId, beacon_struct->bssid)) { + /* Prepare beacon report from incoming beacon */ + qdf_mem_copy(beacon_report.bssid.bytes, beacon_struct->bssid, + sizeof(tSirMacAddr)); + + qdf_mem_copy(&beacon_report.time_stamp, + &beacon_struct->timeStamp, sizeof(qdf_time_t)); + beacon_report.beacon_interval = beacon_struct->beaconInterval; + beacon_report.frequency = + cds_chan_to_freq(beacon_struct->channelNumber); + + beacon_report.ssid.length = beacon_struct->ssId.length; + qdf_mem_copy(&beacon_report.ssid.ssid, + &beacon_struct->ssId.ssId, + beacon_report.ssid.length); + + beacon_report.boot_time = + qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + + /* Send report to upper layer */ + mac_ctx->lim.sme_bcn_rcv_callback(mac_ctx->hdd_handle, + &beacon_report); + } +} + +#else +static inline +void sch_send_beacon_report(struct mac_context *mac_ctx, + struct sSirProbeRespBeacon *beacon_struct, + struct pe_session *session) +{ +} +#endif + /** * sch_beacon_process() - process the beacon frame * @mac_ctx: mac global context @@ -1108,11 +1171,13 @@ sch_beacon_process(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, * Now process the beacon in the context of the BSS which is * transmitting the beacons, if one is found */ - if (!session) + if (!session) { __sch_beacon_process_no_session(mac_ctx, &bcn, rx_pkt_info); - else + } else { + sch_send_beacon_report(mac_ctx, &bcn, session); __sch_beacon_process_for_session(mac_ctx, &bcn, rx_pkt_info, session); + } } /** diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index c5c7ab0287b7..d43becdff09f 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -411,6 +411,28 @@ QDF_STATUS sme_update_config(mac_handle_t mac_handle, QDF_STATUS sme_set11dinfo(mac_handle_t mac_handle, struct sme_config_params *pSmeConfigParams); QDF_STATUS sme_hdd_ready_ind(mac_handle_t mac_handle); + +#ifdef WLAN_BCN_RECV_FEATURE +/* + * sme_register_bcn_report_pe_cb() - Register SME callback + * @mac_handle: The handle returned by mac_open. + * @cb: cb of type beacon_report_cb + * + * This function Register SME callback in order to send + * beacon report to upper layer + * + * Return QDF_STATUS_SUCCESS - + */ +QDF_STATUS +sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb); +#else +static inline QDF_STATUS +sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif + /** * sme_ser_cmd_callback() - callback from serialization module * @cmd: serialization command diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index e6ca7224e26c..6d6802ccf17c 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -257,6 +257,14 @@ typedef void (*lost_link_info_cb)(hdd_handle_t hdd_handle, typedef void (*hidden_ssid_cb)(hdd_handle_t hdd_handle, uint8_t vdev_id); +/** + * typedef bcn_report_cb - recv bcn callback fun + * @hdd_handle: HDD handle registered with SME + * @beacon_report: Beacon report structure + */ +typedef void (*beacon_report_cb)(hdd_handle_t hdd_handle, + struct wlan_beacon_report *beacon_report); + #ifdef WLAN_FEATURE_MOTION_DETECTION typedef QDF_STATUS (*md_host_evt_cb)(void *hdd_ctx, struct sir_md_evt *event); #endif /* WLAN_FEATURE_MOTION_DETECTION */ @@ -364,6 +372,9 @@ struct sme_context { wmi_mws_coex_cmd_id cmd_id); #endif /* WLAN_MWS_INFO_DEBUGFS */ +#ifdef WLAN_BCN_RECV_FEATURE + beacon_report_cb beacon_report_cb; +#endif }; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 10fe9e5423ed..8ba26dfdf96a 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -1135,6 +1135,26 @@ QDF_STATUS sme_hdd_ready_ind(mac_handle_t mac_handle) return status; } +#ifdef WLAN_BCN_RECV_FEATURE +QDF_STATUS +sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + msg.type = WNI_SME_REGISTER_BCN_REPORT_SEND_CB; + msg.callback = cb; + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("Failed to post message to LIM"); + + return status; +} +#endif + QDF_STATUS sme_get_valid_channels(uint8_t *chan_list, uint32_t *list_len) { struct mac_context *mac_ctx = sme_get_mac_context();