From 5730524bdca9d18adbb4c09f336fe56268d557d2 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Tue, 23 Jul 2019 12:27:18 +0530 Subject: [PATCH] qcacld-3.0: Register network interface for pktcapture mode For packet capture mode, register an interface through hdd_add_virtual_intf and delete using hdd_del_virtual_intf. During register, remove the P2P interface and add it back during deregister. Change-Id: I79d933c96591cd462e27eda73f5aed2cc7cad8af CRs-Fixed: 2528549 --- core/hdd/inc/wlan_hdd_main.h | 78 +++++++++ core/hdd/src/wlan_hdd_cfg80211.c | 3 + core/hdd/src/wlan_hdd_main.c | 273 ++++++++++++++++++++++++++++++- core/hdd/src/wlan_hdd_p2p.c | 18 +- 4 files changed, 366 insertions(+), 6 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 0eb9b82046f4..370ad25f4827 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -4097,4 +4097,82 @@ QDF_STATUS hdd_common_roam_callback(struct wlan_objmgr_psoc *psoc, uint32_t roam_id, eRoamCmdStatus roam_status, eCsrRoamResult roam_result); + +#ifdef WLAN_FEATURE_PKT_CAPTURE + +/** + * wlan_hdd_is_session_type_monitor() - check if session type is MONITOR + * @session_type: session type + * + * Return: True - if session type for adapter is monitor, else False + * + */ +bool wlan_hdd_is_session_type_monitor(uint8_t session_type); + +/** + * wlan_hdd_check_mon_concurrency() - check if MONITOR and STA concurrency + * is UP when packet capture mode is enabled. + * + * Return: True - if STA and monitor concurrency is there, else False + * + */ +bool wlan_hdd_check_mon_concurrency(void); + +/** + * wlan_hdd_add_monitor_check() - check for monitor intf and add if needed + * @hdd_ctx: pointer to hdd context + * @adapter: output pointer to hold created monitor adapter + * @type: type of the interface + * @name: name of the interface + * @rtnl_held: True if RTNL lock is held + * @name_assign_type: the name of assign type of the netdev + * + * Return: 0 - on success + * err code - on failure + */ +int wlan_hdd_add_monitor_check(struct hdd_context *hdd_ctx, + struct hdd_adapter **adapter, + enum nl80211_iftype type, const char *name, + bool rtnl_held, unsigned char name_assign_type); + +/** + * wlan_hdd_del_monitor() - delete monitor interface + * @hdd_ctx: pointer to hdd context + * @adapter: adapter to be deleted + * @rtnl_held: rtnl lock held + * + * This function is invoked to delete monitor interface. + * + * Return: None + */ +void wlan_hdd_del_monitor(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool rtnl_held); +#else +static inline +bool wlan_hdd_is_session_type_monitor(uint8_t session_type) +{ + return false; +} + +static inline +bool wlan_hdd_check_mon_concurrency(void) +{ + return false; +} + +static inline +int wlan_hdd_add_monitor_check(struct hdd_context *hdd_ctx, + struct hdd_adapter **adapter, + enum nl80211_iftype type, const char *name, + bool rtnl_held, unsigned char name_assign_type) +{ + return 0; +} + +static inline +void wlan_hdd_del_monitor(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool rtnl_held) +{ +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ #endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 79ac12c78b40..f4834d1f763f 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -16053,6 +16053,9 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, if (errno) return errno; + if (wlan_hdd_check_mon_concurrency()) + return -EINVAL; + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, TRACE_CODE_HDD_CFG80211_CHANGE_IFACE, adapter->vdev_id, type); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 83c68a73b4af..e3e4e5e2cf78 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -2541,6 +2541,61 @@ static int hdd_mon_open(struct net_device *net_dev) } #endif +#ifdef WLAN_FEATURE_PKT_CAPTURE +/** + * __hdd_pktcapture_open() - HDD Open function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_pktcapture_open(struct net_device *dev) +{ + int ret; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_mon_mode_ether_setup(dev); + + if (!ret) + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + + return ret; +} + +/** + * hdd_pktcapture_open() - Wrapper function for __hdd_mon_open to + * protect it from SSR + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int hdd_pktcapture_open(struct net_device *net_dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_pktcapture_open(net_dev); + + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} +#endif + static QDF_STATUS wlan_hdd_update_dbs_scan_and_fw_mode_config(void) { @@ -4294,11 +4349,30 @@ void hdd_set_station_ops(struct net_device *dev) #endif #endif +#ifdef WLAN_FEATURE_PKT_CAPTURE +/* Packet Capture mode net_device_ops, doesnot Tx and most of operations. */ +static const struct net_device_ops wlan_pktcapture_drv_ops = { + .ndo_open = hdd_pktcapture_open, + .ndo_stop = hdd_stop, + .ndo_get_stats = hdd_get_stats, +}; + +static void hdd_set_pktcapture_ops(struct net_device *dev) +{ + dev->netdev_ops = &wlan_pktcapture_drv_ops; +} +#else +static void hdd_set_pktcapture_ops(struct net_device *dev) +{ +} +#endif + /** * hdd_alloc_station_adapter() - allocate the station hdd adapter * @hdd_ctx: global hdd context * @mac_addr: mac address to assign to the interface * @name: User-visible name of the interface + * @session_type: interface type to be created * * hdd adapter pointer would point to the netdev->priv space, this function * would retrieve the pointer, and setup the hdd adapter configuration. @@ -4307,7 +4381,8 @@ void hdd_set_station_ops(struct net_device *dev) */ static struct hdd_adapter * hdd_alloc_station_adapter(struct hdd_context *hdd_ctx, tSirMacAddr mac_addr, - unsigned char name_assign_type, const char *name) + unsigned char name_assign_type, const char *name, + uint8_t session_type) { struct net_device *dev; struct hdd_adapter *adapter; @@ -4319,7 +4394,8 @@ hdd_alloc_station_adapter(struct hdd_context *hdd_ctx, tSirMacAddr mac_addr, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) name_assign_type, #endif - (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE ? + ((cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE || + wlan_hdd_is_session_type_monitor(session_type)) ? hdd_mon_mode_ether_setup : ether_setup), NUM_TX_QUEUES); @@ -4360,7 +4436,10 @@ hdd_alloc_station_adapter(struct hdd_context *hdd_ctx, tSirMacAddr mac_addr, qdf_mem_copy(adapter->mac_addr.bytes, mac_addr, sizeof(tSirMacAddr)); dev->watchdog_timeo = HDD_TX_TIMEOUT; - hdd_set_station_ops(adapter->dev); + if (wlan_hdd_is_session_type_monitor(session_type)) + hdd_set_pktcapture_ops(adapter->dev); + else + hdd_set_station_ops(adapter->dev); hdd_dev_setup_destructor(dev); dev->ieee80211_ptr = &adapter->wdev; @@ -5542,7 +5621,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio case QDF_NAN_DISC_MODE: adapter = hdd_alloc_station_adapter(hdd_ctx, mac_addr, name_assign_type, - iface_name); + iface_name, session_type); if (!adapter) { hdd_err("failed to allocate adapter for session %d", @@ -5650,7 +5729,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio case QDF_FTM_MODE: adapter = hdd_alloc_station_adapter(hdd_ctx, mac_addr, name_assign_type, - iface_name); + iface_name, session_type); if (!adapter) { hdd_err("Failed to allocate adapter for FTM mode"); return NULL; @@ -16160,6 +16239,190 @@ void hdd_hidden_ssid_enable_roaming(hdd_handle_t hdd_handle, uint8_t vdev_id) wlan_hdd_enable_roaming(adapter, RSO_START_BSS); } +#ifdef WLAN_FEATURE_PKT_CAPTURE + +/** + * wlan_hdd_is_session_type_monitor() - check if session type is MONITOR + * @session_type: session type + * + * Return: True - if session type for adapter is monitor, else False + * + */ +bool wlan_hdd_is_session_type_monitor(uint8_t session_type) +{ + if (cds_is_pktcapture_enabled() && + cds_get_conparam() != QDF_GLOBAL_MONITOR_MODE && + session_type == QDF_MONITOR_MODE) + return true; + else + return false; +} + +/** + * wlan_hdd_check_mon_concurrency() - check if MONITOR and STA concurrency + * is UP when packet capture mode is enabled. + * @void + * + * Return: True - if STA and monitor concurrency is there, else False + * + */ +bool wlan_hdd_check_mon_concurrency(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + if (cds_is_pktcapture_enabled()) { + if (policy_mgr_get_concurrency_mode(hdd_ctx->psoc) == + (QDF_STA_MASK | QDF_MONITOR_MASK)) { + hdd_err("STA + MON mode is UP"); + return true; + } + } + return false; +} + +/** + * wlan_hdd_del_monitor() - delete monitor interface + * @hdd_ctx: pointer to hdd context + * @adapter: adapter to be deleted + * @rtnl_held: rtnl lock held + * + * This function is invoked to delete monitor interface. + * + * Return: None + */ +void wlan_hdd_del_monitor(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool rtnl_held) +{ + wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); + hdd_stop_adapter(hdd_ctx, adapter); + hdd_close_adapter(hdd_ctx, adapter, true); + + hdd_open_p2p_interface(hdd_ctx); +} + +/** + * wlan_hdd_add_monitor_check() - check for monitor intf and add if needed + * @hdd_ctx: pointer to hdd context + * @adapter: output pointer to hold created monitor adapter + * @type: type of the interface + * @name: name of the interface + * @rtnl_held: True if RTNL lock is held + * @name_assign_type: the name of assign type of the netdev + * + * Return: 0 - on success + * err code - on failure + */ +int +wlan_hdd_add_monitor_check(struct hdd_context *hdd_ctx, + struct hdd_adapter **adapter, + enum nl80211_iftype type, const char *name, + bool rtnl_held, unsigned char name_assign_type) +{ + struct hdd_adapter *sta_adapter; + struct hdd_adapter *mon_adapter; + uint32_t mode; + uint8_t num_open_session = 0; + + if (!cds_is_pktcapture_enabled()) + return 0; + + /* + * If add interface request is for monitor mode, then it can run in + * parallel with only one station interface. + * If there is no existing station interface return error + */ + if (type != NL80211_IFTYPE_MONITOR) + return 0; + + if (QDF_STATUS_SUCCESS != policy_mgr_mode_specific_num_open_sessions( + hdd_ctx->psoc, + QDF_MONITOR_MODE, + &num_open_session)) + return -EINVAL; + + if (num_open_session) { + hdd_err("monitor mode already exists, only one is possible"); + return -EBUSY; + } + + /* Ensure there is only one station interface */ + if (QDF_STATUS_SUCCESS != policy_mgr_mode_specific_num_open_sessions( + hdd_ctx->psoc, + QDF_STA_MODE, + &num_open_session)) + return -EINVAL; + + if (num_open_session != 1) { + hdd_err("cannot add monitor mode, due to %u sta interfaces", + num_open_session); + return -EINVAL; + } + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (!sta_adapter) { + hdd_err("No station adapter"); + return -EINVAL; + } + + if (QDF_STATUS_SUCCESS != policy_mgr_mode_specific_num_open_sessions( + hdd_ctx->psoc, + QDF_SAP_MODE, + &num_open_session)) + return -EINVAL; + + if (num_open_session) { + hdd_err("cannot add monitor mode, due to SAP concurrency"); + return -EINVAL; + } + + /* delete p2p interface */ + for (mode = QDF_P2P_CLIENT_MODE; mode <= QDF_P2P_DEVICE_MODE; mode++) { + struct hdd_adapter *adapter; + + if (mode == QDF_FTM_MODE || + mode == QDF_MONITOR_MODE || + mode == QDF_IBSS_MODE) + continue; + + adapter = hdd_get_adapter(hdd_ctx, mode); + if (adapter) { + struct osif_vdev_sync *vdev_sync; + + vdev_sync = osif_vdev_sync_unregister(adapter->dev); + if (vdev_sync) + osif_vdev_sync_wait_for_ops(vdev_sync); + + wlan_hdd_release_intf_addr(hdd_ctx, + adapter->mac_addr.bytes); + hdd_stop_adapter(hdd_ctx, adapter); + hdd_deinit_adapter(hdd_ctx, adapter, true); + hdd_close_adapter(hdd_ctx, adapter, rtnl_held); + + if (vdev_sync) + osif_vdev_sync_destroy(vdev_sync); + } + } + + mon_adapter = hdd_open_adapter(hdd_ctx, QDF_MONITOR_MODE, name, + wlan_hdd_get_intf_addr( + hdd_ctx, + QDF_MONITOR_MODE), + name_assign_type, rtnl_held); + if (!mon_adapter) { + hdd_err("hdd_open_adapter failed"); + hdd_open_p2p_interface(hdd_ctx); + return -EINVAL; + } + + *adapter = mon_adapter; + return 0; +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ /* Register the module init/exit functions */ module_init(hdd_module_init); module_exit(hdd_module_exit); diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c index 2da9a2db8e42..b3a3984a52e1 100644 --- a/core/hdd/src/wlan_hdd_p2p.c +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020 The Linux Foundation. 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 @@ -689,6 +689,9 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, if (ret) return ERR_PTR(ret); + if (wlan_hdd_check_mon_concurrency()) + return ERR_PTR(-EINVAL); + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, TRACE_CODE_HDD_ADD_VIRTUAL_INTF, NO_SESSION, type); @@ -719,6 +722,16 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, } } + adapter = NULL; + ret = wlan_hdd_add_monitor_check(hdd_ctx, &adapter, type, name, + true, name_assign_type); + if (ret) + return ERR_PTR(-EINVAL); + if (adapter) { + hdd_exit(); + return adapter->dev->ieee80211_ptr; + } + if (mode == QDF_SAP_MODE) { struct wireless_dev *sap_dev; bool allow_add_sap = wlan_hdd_allow_sap_add(hdd_ctx, name, @@ -883,6 +896,9 @@ int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) if (adapter->device_mode == QDF_SAP_MODE && wlan_sap_is_pre_cac_active(hdd_ctx->mac_handle)) { hdd_clean_up_pre_cac_interface(hdd_ctx); + } else if (wlan_hdd_is_session_type_monitor( + adapter->device_mode)) { + wlan_hdd_del_monitor(hdd_ctx, adapter, TRUE); } else { wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes);