qcacld-3.0: Send scan start indication to userspace

If firmware starts off-channel scan, driver does not
receive beacons. In this case driver should send a
pause event to userspace.

Change-Id: I90ba5c586656486df110778b73b236e5877f8684
CRs-Fixed: 2431359
This commit is contained in:
Abhinav Kumar 2019-04-11 22:11:47 +05:30 committed by nshrivas
parent 4d1f9f442d
commit 0ed614c1c9
4 changed files with 194 additions and 0 deletions

View File

@ -76,6 +76,92 @@ int get_beacon_report_data_len(struct wlan_beacon_report *report)
return data_len;
}
/**
* get_pause_ind_data_len() - Calculate skb buffer length
* @report: Required beacon report
*
* Calculate length for pause indication to allocate skb buffer
*
* Return: skb buffer length
*/
static int get_pause_ind_data_len(void)
{
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_PAUSE_REASON */
data_len += nla_total_size(sizeof(u32));
return data_len;
}
/**
* hdd_beacon_recv_pause_indication()- Send vendor event to user space
* to inform SCAN started indication
* @hdd_handle: hdd handler
* @vdev_id: vdev id
* @type: scan event type
*
* Return: None
*/
static void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle,
uint8_t vdev_id,
enum scan_event_type type)
{
struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
struct hdd_adapter *adapter;
struct sk_buff *vendor_event;
uint32_t data_len;
int flags;
uint32_t abort_reason;
if (wlan_hdd_validate_context(hdd_ctx))
return;
adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
if (hdd_validate_adapter(adapter))
return;
data_len = get_pause_ind_data_len();
flags = cds_get_gfp_flags();
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;
}
switch (type) {
case SCAN_EVENT_TYPE_STARTED:
abort_reason =
QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED;
break;
default:
abort_reason =
QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED;
}
/* Send vendor event to user space to inform ABORT */
if (nla_put_u32(vendor_event,
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE,
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE) ||
nla_put_u32(vendor_event,
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON,
abort_reason)) {
hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
kfree_skb(vendor_event);
return;
}
cfg80211_vendor_event(vendor_event, flags);
}
/**
* hdd_send_bcn_recv_info() - Send beacon info to userspace for
* connected AP
@ -211,6 +297,16 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy,
return errno;
}
}
qdf_status =
sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle,
hdd_beacon_recv_pause_indication);
if (QDF_IS_STATUS_ERROR(qdf_status)) {
hdd_err("bcn_recv_abort_ind 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);

View File

@ -3455,4 +3455,27 @@ sme_get_mws_coex_info(mac_handle_t mac_handle, uint32_t vdev_id,
void *context);
#endif /* WLAN_MWS_INFO_DEBUGFS */
#ifdef WLAN_BCN_RECV_FEATURE
/**
* sme_register_bcn_recv_pause_ind_cb() - Register pause ind cb
* mac_handle: man handler
* cb: callback function to HDD
*
* This function register HDD callback in order to indicate beacon
* receive pause indication to userspace.
*
* return QDF_STATUS of cb registration
*/
QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle,
beacon_pause_cb cb);
#else
static inline
QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle,
beacon_pause_cb cb)
{
return QDF_STATUS_SUCCESS;
}
#endif
#endif /* #if !defined( __SME_API_H ) */

View File

@ -265,6 +265,16 @@ typedef void (*hidden_ssid_cb)(hdd_handle_t hdd_handle,
typedef void (*beacon_report_cb)(hdd_handle_t hdd_handle,
struct wlan_beacon_report *beacon_report);
/**
* beacon_pause_cb : scan start callback fun
* @hdd_handler: HDD handler
* @vdev_id: vdev id
* @type: scan event type
*/
typedef void (*beacon_pause_cb)(hdd_handle_t hdd_handle,
uint8_t vdev_id,
enum scan_event_type type);
#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 */
@ -374,6 +384,7 @@ struct sme_context {
#ifdef WLAN_BCN_RECV_FEATURE
beacon_report_cb beacon_report_cb;
beacon_pause_cb beacon_pause_cb;
#endif
};

View File

@ -15526,3 +15526,67 @@ sme_get_mws_coex_info(mac_handle_t mac_handle, uint32_t vdev_id,
return status;
}
#endif /* WLAN_MWS_INFO_DEBUGFS */
#ifdef WLAN_BCN_RECV_FEATURE
/**
* sme_scan_event_handler() - Scan complete event handler
* @vdev: vdev obj manager
* @event: scan event
* @arg: arg of scan event
*
* This function is getting called after Host receive scan start
*
* Return: None
*/
static void sme_scan_event_handler(struct wlan_objmgr_vdev *vdev,
struct scan_event *event,
void *arg)
{
struct mac_context *mac = arg;
struct csr_roam_session *session;
if (!mac) {
sme_err("Invalid mac context");
return;
}
if (!CSR_IS_SESSION_VALID(mac, vdev->vdev_objmgr.vdev_id)) {
sme_err("Invalid vdev_id: %d", vdev->vdev_objmgr.vdev_id);
return;
}
session = CSR_GET_SESSION(mac, vdev->vdev_objmgr.vdev_id);
if (event->type == SCAN_EVENT_TYPE_STARTED) {
if (mac->sme.beacon_pause_cb)
mac->sme.beacon_pause_cb(mac->hdd_handle,
vdev->vdev_objmgr.vdev_id, event->type);
}
}
QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle,
beacon_pause_cb cb)
{
QDF_STATUS status;
struct mac_context *mac = MAC_CONTEXT(mac_handle);
if (!mac) {
sme_err("Invalid mac context");
return QDF_STATUS_E_NOMEM;
}
status = sme_acquire_global_lock(&mac->sme);
if (QDF_IS_STATUS_SUCCESS(status)) {
mac->sme.beacon_pause_cb = cb;
sme_release_global_lock(&mac->sme);
}
/* scan event registration */
status = ucfg_scan_register_event_handler(mac->pdev,
sme_scan_event_handler, mac);
if (QDF_IS_STATUS_ERROR(status))
sme_err("scan event register failed ");
return status;
}
#endif