From 59f861d11d0daf043e33b23f2e3a050453ca6cb0 Mon Sep 17 00:00:00 2001 From: Manjunathappa Prakash Date: Thu, 21 Apr 2016 10:33:31 -0700 Subject: [PATCH] qcacld-3.0: Add monitor mode support Add monitor mode support. Configure target to deliver 802.11 packets in raw mode. Below is the procedure to start the monitor mode. insmod /system/lib/modules/wlan.ko con_mode=4 ifconfig wlan0 up "iwpriv wlan0 setMonChan 36 2" or "iw dev mon0 set channel 36 HT40+" tcpdump -i wlan0 -w In this mode concurrency is not supported and module doesnot support Tx. Change-Id: I211ece0a66e2d43bc111e523714942e1557e36f4 CRs-Fixed: 963060 --- core/hdd/inc/wlan_hdd_main.h | 16 +++ core/hdd/inc/wlan_hdd_tx_rx.h | 4 +- core/hdd/src/wlan_hdd_cfg.c | 63 ++++++++++++ core/hdd/src/wlan_hdd_cfg80211.c | 163 +++++++++++++++++++++++++++---- core/hdd/src/wlan_hdd_main.c | 100 ++++++++++++++++++- core/hdd/src/wlan_hdd_tx_rx.c | 121 +++++++++++++++++++++++ core/hdd/src/wlan_hdd_wext.c | 55 +++++++++++ core/mac/inc/sir_api.h | 13 +++ core/mac/inc/wni_api.h | 1 + core/sme/inc/sme_api.h | 1 + core/sme/src/common/sme_api.c | 24 ++++- 11 files changed, 537 insertions(+), 24 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index be49ab0c6d7f..0262528886b8 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -631,6 +631,20 @@ typedef struct hdd_cfg80211_state_s { eP2PActionFrameState actionFrmState; } hdd_cfg80211_state_t; +/** + * struct hdd_mon_set_ch_info - Holds monitor mode channel switch params + * @channel: Channel number. + * @cb_mode: Channel bonding + * @channel_width: Channel width 0/1/2 for 20/40/80MHz respectively. + * @phy_mode: PHY mode + */ +struct hdd_mon_set_ch_info { + uint8_t channel; + uint8_t cb_mode; + uint32_t channel_width; + eCsrPhyMode phy_mode; +}; + struct hdd_station_ctx { /** Handle to the Wireless Extension State */ hdd_wext_state_t WextState; @@ -665,6 +679,8 @@ struct hdd_station_ctx { int staDebugState; uint8_t broadcast_ibss_staid; + + struct hdd_mon_set_ch_info ch_info; }; #define BSS_STOP 0 diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h index df570cd83e48..526d8d098536 100644 --- a/core/hdd/inc/wlan_hdd_tx_rx.h +++ b/core/hdd/inc/wlan_hdd_tx_rx.h @@ -128,11 +128,9 @@ static inline void wlan_hdd_log_eapol(struct sk_buff *skb, } #endif /* FEATURE_WLAN_DIAG_SUPPORT */ - const char *hdd_reason_type_to_string(enum netif_reason_type reason); const char *hdd_action_type_to_string(enum netif_action_type action); void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, enum netif_action_type action, enum netif_reason_type reason); - - +int hdd_set_mon_rx_cb(struct net_device *dev); #endif /* end #if !defined(WLAN_HDD_TX_RX_H) */ diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index 23513f5677c5..6cf3949a18dc 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -44,6 +44,7 @@ #include #include #include +#include static void cb_notify_set_roam_prefer5_g_hz(hdd_context_t *pHddCtx, unsigned long notifyId) @@ -5474,6 +5475,66 @@ config_exit: return qdf_status; } +/** + * hdd_disable_runtime_pm() - Override to disable runtime_pm. + * @cfg_ini: Handle to struct hdd_config + * + * Return: None + */ +#ifdef FEATURE_RUNTIME_PM +static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini) +{ + cfg_ini->runtime_pm = 0; +} +#else +static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini) +{ +} +#endif + +/** + * hdd_disable_auto_shutdown() - Override to disable auto_shutdown. + * @cfg_ini: Handle to struct hdd_config + * + * Return: None + */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini) +{ + cfg_ini->WlanAutoShutdown = 0; +} +#else +static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini) +{ +} +#endif + +/** + * hdd_override_all_ps() - overrides to disables all the powersave features. + * @hdd_ctx: Pointer to HDD context. + * Overrides below powersave ini configurations. + * gEnableImps=0 + * gEnableBmps=0 + * gRuntimePM=0 + * gWlanAutoShutdown = 0 + * gEnableSuspend=0 + * gEnablePowerSaveOffload=0 + * gEnableWoW=0 + * + * Return: None + */ +static void hdd_override_all_ps(hdd_context_t *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + + cfg_ini->fIsImpsEnabled = 0; + cfg_ini->is_ps_enabled = 0; + hdd_disable_runtime_pm(cfg_ini); + hdd_disable_auto_shutdown(cfg_ini); + cfg_ini->enablePowersaveOffload = 0; + cfg_ini->wowEnable = 0; +} + /** * hdd_parse_config_ini() - parse the ini configuration file * @pHddCtx: the pointer to hdd context @@ -5577,6 +5638,8 @@ QDF_STATUS hdd_parse_config_ini(hdd_context_t *pHddCtx) hdd_napi_event(NAPI_EVT_INI_FILE, (void *)pHddCtx->config->napi_enable); #endif /* FEATURE_NAPI */ + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + hdd_override_all_ps(pHddCtx); config_exit: release_firmware(fw); diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 4019b623ad87..104aa9396064 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -505,6 +505,24 @@ wlan_hdd_p2p_p2p_iface_limit[] = { }, }; +static const struct ieee80211_iface_limit + wlan_hdd_mon_iface_limit[] = { + { + .max = 3, /* Monitor interface */ + .types = BIT(NL80211_IFTYPE_MONITOR), + }, +}; + +static struct ieee80211_iface_combination + wlan_hdd_mon_iface[] = { + { + .limits = wlan_hdd_mon_iface_limit, + .max_interfaces = 3, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_mon_iface_limit), + }, +}; + static struct ieee80211_iface_combination wlan_hdd_iface_combination[] = { /* STA */ @@ -5908,26 +5926,35 @@ int wlan_hdd_cfg80211_init(struct device *dev, wiphy->max_acl_mac_addrs = MAX_ACL_MAC_ADDRESS; - /* Supports STATION & AD-HOC modes right now */ - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) - | BIT(NL80211_IFTYPE_ADHOC) - | BIT(NL80211_IFTYPE_P2P_CLIENT) - | BIT(NL80211_IFTYPE_P2P_GO) - | BIT(NL80211_IFTYPE_AP); + if (cds_get_conparam() != QDF_GLOBAL_MONITOR_MODE) { + /* Supports STATION & AD-HOC modes right now */ + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) + | BIT(NL80211_IFTYPE_AP); - if (pCfg->advertiseConcurrentOperation) { - if (pCfg->enableMCC) { - int i; - for (i = 0; i < ARRAY_SIZE(wlan_hdd_iface_combination); - i++) { - if (!pCfg->allowMCCGODiffBI) - wlan_hdd_iface_combination[i]. - beacon_int_infra_match = true; + if (pCfg->advertiseConcurrentOperation) { + if (pCfg->enableMCC) { + int i; + + for (i = 0; + i < ARRAY_SIZE(wlan_hdd_iface_combination); + i++) { + if (!pCfg->allowMCCGODiffBI) + wlan_hdd_iface_combination[i]. + beacon_int_infra_match = true; + } } + wiphy->n_iface_combinations = + ARRAY_SIZE(wlan_hdd_iface_combination); + wiphy->iface_combinations = wlan_hdd_iface_combination; } + } else { + wiphy->interface_modes = BIT(NL80211_IFTYPE_MONITOR); wiphy->n_iface_combinations = - ARRAY_SIZE(wlan_hdd_iface_combination); - wiphy->iface_combinations = wlan_hdd_iface_combination; + ARRAY_SIZE(wlan_hdd_mon_iface); + wiphy->iface_combinations = wlan_hdd_mon_iface; } /* Before registering we need to update the ht capabilitied based @@ -8242,6 +8269,10 @@ void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel) uint8_t iniDot11Mode = (WLAN_HDD_GET_CTX(pAdapter))->config->dot11Mode; eHddDot11Mode hddDot11Mode = iniDot11Mode; struct ch_params_s ch_params; + hdd_station_ctx_t *station_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + uint32_t cb_mode; + struct hdd_mon_set_ch_info *ch_info = &station_ctx->ch_info; + ch_params.ch_width = (WLAN_HDD_GET_CTX(pAdapter))->config->vhtChannelWidth; @@ -8264,10 +8295,20 @@ void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel) break; } /* This call decides required channel bonding mode */ - sme_set_ch_params((WLAN_HDD_GET_CTX(pAdapter)->hHal), + cb_mode = sme_set_ch_params((WLAN_HDD_GET_CTX(pAdapter)->hHal), hdd_cfg_xlate_to_csr_phy_mode(hddDot11Mode), operationChannel, 0, &ch_params); + + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) { + ch_info->channel_width = ch_params.ch_width; + ch_info->phy_mode = hdd_cfg_xlate_to_csr_phy_mode(hddDot11Mode); + ch_info->channel = operationChannel; + ch_info->cb_mode = cb_mode; + hdd_info("ch_info width %d, phymode %d channel %d", + ch_info->channel_width, ch_info->phy_mode, + ch_info->channel); + } } /** @@ -11841,6 +11882,93 @@ enum cds_con_mode wlan_hdd_convert_nl_iftype_to_hdd_type( return mode; } +/** + * wlan_hdd_cfg80211_set_mon_ch() - Set monitor mode capture channel + * @wiphy: Handle to struct wiphy to get handle to module context. + * @chandef: Contains information about the capture channel to be set. + * + * This interface is called if and only if monitor mode interface alone is + * active. + * + * Return: 0 success or error code on failure. + */ +static int __wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + hdd_adapter_t *adapter; + hdd_station_ctx_t *sta_ctx; + struct hdd_mon_set_ch_info *ch_info; + QDF_STATUS status; + tHalHandle hal_hdl; + struct qdf_mac_addr bssid; + tCsrRoamProfile roam_profile; + struct ch_params_s ch_params; + int ret; + uint16_t chan_num = cds_freq_to_chan(chandef->chan->center_freq); + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hal_hdl = hdd_ctx->hHal; + + adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + if (!adapter) + return -EIO; + + hdd_info("%s: set monitor mode Channel %d and freq %d", + adapter->dev->name, chan_num, chandef->chan->center_freq); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + ch_info = &sta_ctx->ch_info; + hdd_select_cbmode(adapter, chan_num); + roam_profile.ChannelInfo.ChannelList = &ch_info->channel; + roam_profile.ChannelInfo.numOfChannels = 1; + roam_profile.phyMode = ch_info->phy_mode; + roam_profile.ch_params.ch_width = chandef->width; + + qdf_mem_copy(bssid.bytes, adapter->macAddressCurrent.bytes, + QDF_MAC_ADDR_SIZE); + + ch_params.ch_width = chandef->width; + sme_set_ch_params(hal_hdl, ch_info->phy_mode, chan_num, 0, + &ch_params); + status = sme_roam_channel_change_req(hal_hdl, bssid, &ch_params, + &roam_profile); + if (status) { + hdd_err("Status: %d Failed to set sme_RoamChannel for monitor mode", + status); + ret = qdf_status_to_os_return(status); + return ret; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_mon_ch() - Set monitor mode capture channel + * @wiphy: Handle to struct wiphy to get handle to module context. + * @chandef: Contains information about the capture channel to be set. + * + * This interface is called if and only if monitor mode interface alone is + * active. + * + * Return: 0 success or error code on failure. + */ +static int wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_mon_ch(wiphy, chandef); + cds_ssr_unprotect(__func__); + return ret; +} + /** * struct cfg80211_ops - cfg80211_ops * @@ -11956,4 +12084,5 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = { #ifdef CHANNEL_SWITCH_SUPPORTED .channel_switch = wlan_hdd_cfg80211_channel_switch, #endif + .set_monitor_channel = wlan_hdd_cfg80211_set_mon_ch, }; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index c616f48260de..cf03f2014d06 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -1435,6 +1435,42 @@ bool hdd_is_valid_mac_address(const uint8_t *pMacAddr) return xdigit == 12 && (separator == 5 || separator == 0); } +/** + * __hdd__mon_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_mon_open(struct net_device *dev) +{ + int ret; + + ENTER_DEV(dev); + ret = hdd_set_mon_rx_cb(dev); + return ret; +} + +/** + * hdd_mon_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 + */ +int hdd_mon_open(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_mon_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + /** * __hdd_open() - HDD Open function * @dev: Pointer to net_device structure @@ -1892,9 +1928,44 @@ static struct net_device_ops wlan_drv_ops = { #endif }; +/* Monitor mode net_device_ops, doesnot Tx and most of operations. */ +static struct net_device_ops wlan_mon_drv_ops = { + .ndo_open = hdd_mon_open, + .ndo_stop = hdd_stop, + .ndo_get_stats = hdd_get_stats, +}; + +/** + * hdd_set_station_ops() - update net_device ops for monitor mode + * @pWlanDev: Handle to struct net_device to be updated. + * Return: None + */ void hdd_set_station_ops(struct net_device *pWlanDev) { - pWlanDev->netdev_ops = &wlan_drv_ops; + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + pWlanDev->netdev_ops = &wlan_mon_drv_ops; + else + pWlanDev->netdev_ops = &wlan_drv_ops; +} + +/** + * hdd_mon_mode_ether_setup() - Update monitor mode struct net_device. + * @dev: Handle to struct net_device to be updated. + * + * Return: None + */ +static void hdd_mon_mode_ether_setup(struct net_device *dev) +{ + dev->header_ops = NULL; + dev->type = ARPHRD_IEEE80211_RADIOTAP; + dev->hard_header_len = ETH_HLEN; + dev->mtu = ETH_DATA_LEN; + dev->addr_len = ETH_ALEN; + dev->tx_queue_len = 1000; /* Ethernet wants good queues */ + dev->flags = IFF_BROADCAST|IFF_MULTICAST; + dev->priv_flags |= IFF_TX_SKB_SHARING; + + memset(dev->broadcast, 0xFF, ETH_ALEN); } /** @@ -1922,7 +1993,9 @@ static hdd_adapter_t *hdd_alloc_station_adapter(hdd_context_t *hdd_ctx, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) name_assign_type, #endif - ether_setup, NUM_TX_QUEUES); + (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam() ? + hdd_mon_mode_ether_setup : ether_setup), + NUM_TX_QUEUES); if (pWlanDev != NULL) { @@ -2434,6 +2507,7 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type, case QDF_P2P_CLIENT_MODE: case QDF_P2P_DEVICE_MODE: case QDF_OCB_MODE: + case QDF_MONITOR_MODE: { adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr, name_assign_type, @@ -2450,6 +2524,8 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type, adapter->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; else if (QDF_P2P_DEVICE_MODE == session_type) adapter->wdev.iftype = NL80211_IFTYPE_P2P_DEVICE; + else if (QDF_MONITOR_MODE == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_MONITOR; else adapter->wdev.iftype = NL80211_IFTYPE_STATION; @@ -5635,6 +5711,21 @@ static inline int hdd_open_p2p_interface(struct hdd_context_t *hdd_ctx, } #endif +/** + * hdd_open_monitor_interface() - Open monitor mode interface + * @hdd_ctx: HDD context + * @rtnl_held: True if RTNL lock is held + * + * Return: Primary adapter on success and PTR_ERR on failure + */ +static hdd_adapter_t *hdd_open_monitor_interface(hdd_context_t *hdd_ctx, + bool rtnl_held) +{ + return hdd_open_adapter(hdd_ctx, QDF_MONITOR_MODE, "wlan%d", + wlan_hdd_get_intf_addr(hdd_ctx), + NET_NAME_UNKNOWN, rtnl_held); +} + /** * hdd_open_interfaces - Open all required interfaces * hdd_ctx: HDD context @@ -6059,7 +6150,10 @@ int hdd_wlan_startup(struct device *dev, void *hif_sc) rtnl_held = hdd_hold_rtnl_lock(); - adapter = hdd_open_interfaces(hdd_ctx, rtnl_held); + if (QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) + adapter = hdd_open_monitor_interface(hdd_ctx, rtnl_held); + else + adapter = hdd_open_interfaces(hdd_ctx, rtnl_held); if (IS_ERR(adapter)) { ret = PTR_ERR(adapter); diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 60d3162afaed..2e390476d5ef 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -55,6 +55,7 @@ #include "wlan_hdd_lro.h" #include "cdp_txrx_peer_ops.h" +#include "ol_txrx.h" #ifdef FEATURE_WLAN_DIAG_SUPPORT #define HDD_EAPOL_ETHER_TYPE (0x888E) @@ -669,6 +670,84 @@ QDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter) return status; } +/** + * hdd_mon_rx_packet_cbk() - Receive callback registered with OL layer. + * @context: [in] pointer to qdf context + * @rxBuf: [in] pointer to rx qdf_nbuf + * + * TL will call this to notify the HDD when one or more packets were + * received for a registered STA. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, QDF_STATUS_SUCCESS + * otherwise + */ +static QDF_STATUS hdd_mon_rx_packet_cbk(void *context, qdf_nbuf_t rxbuf) +{ + hdd_adapter_t *adapter; + int rxstat; + struct sk_buff *skb; + struct sk_buff *skb_next; + unsigned int cpu_index; + + /* Sanity check on inputs */ + if ((NULL == context) || (NULL == rxbuf)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + adapter = (hdd_adapter_t *)context; + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "invalid adapter %p", adapter); + return QDF_STATUS_E_FAILURE; + } + + cpu_index = wlan_hdd_get_cpu(); + + /* walk the chain until all are processed */ + skb = (struct sk_buff *) rxbuf; + while (NULL != skb) { + skb_next = skb->next; + skb->dev = adapter->dev; + + ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; + ++adapter->stats.rx_packets; + adapter->stats.rx_bytes += skb->len; + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(skb); + + /* + * If this is not a last packet on the chain + * Just put packet into backlog queue, not scheduling RX sirq + */ + if (skb->next) { + rxstat = netif_rx(skb); + } else { + /* + * This is the last packet on the chain + * Scheduling rx sirq + */ + rxstat = netif_rx_ni(skb); + } + + if (NET_RX_SUCCESS == rxstat) + ++adapter-> + hdd_stats.hddTxRxStats.rxDelivered[cpu_index]; + else + ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index]; + + skb = skb_next; + } + + adapter->dev->last_rx = jiffies; + + return QDF_STATUS_SUCCESS; +} + /** * hdd_rx_packet_cbk() - Receive packet handler * @context: pointer to HDD context @@ -1108,3 +1187,45 @@ void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, return; } +/** + * hdd_set_mon_rx_cb() - Set Monitor mode Rx callback + * @dev: Pointer to net_device structure + * + * Return: 0 for success; non-zero for failure + */ +int hdd_set_mon_rx_cb(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + QDF_STATUS qdf_status; + struct ol_txrx_desc_type sta_desc = {0}; + struct ol_txrx_ops txrx_ops; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_mon_rx_packet_cbk; + ol_txrx_vdev_register( + ol_txrx_get_vdev_from_vdev_id(adapter->sessionId), + adapter, &txrx_ops); + /* peer is created wma_vdev_attach->wma_create_peer */ + qdf_status = ol_txrx_register_peer(&sta_desc); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("WLANTL_RegisterSTAClient() failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + goto exit; + } + + qdf_status = sme_create_mon_session(hdd_ctx->hHal, + adapter->macAddressCurrent.bytes); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("sme_create_mon_session() failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + } +exit: + ret = qdf_status_to_os_return(qdf_status); + return ret; +} diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index e741530bce03..28a9522582cc 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -367,6 +367,7 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { #define WE_SET_DUAL_MAC_SCAN_CONFIG 21 #define WE_SET_DUAL_MAC_FW_MODE_CONFIG 22 +#define WE_SET_MON_MODE_CHAN 23 #ifdef FEATURE_WLAN_TDLS #undef MAX_VAR_ARGS @@ -9728,6 +9729,53 @@ static int iw_set_band_config(struct net_device *dev, return ret; } +/** + * wlan_hdd_set_mon_chan() - Set capture channel on the monitor mode interface. + * @adapter: Handle to adapter + * @chan: Monitor mode channel + * @bandwidth: Capture channel bandwidth + * + * Return: 0 on success else error code. + */ +static int wlan_hdd_set_mon_chan(hdd_adapter_t *adapter, uint32_t chan, + uint32_t bandwidth) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_mon_set_ch_info *ch_info = &sta_ctx->ch_info; + QDF_STATUS status; + tHalHandle hal_hdl = hdd_ctx->hHal; + struct qdf_mac_addr bssid; + tCsrRoamProfile roam_profile; + struct ch_params_s ch_params; + + if (QDF_GLOBAL_MONITOR_MODE != hdd_get_conparam()) { + hdd_err("Not supported, device is not in monitor mode"); + return -EINVAL; + } + + hdd_info("Set monitor mode Channel %d", chan); + hdd_select_cbmode(adapter, chan); + roam_profile.ChannelInfo.ChannelList = &ch_info->channel; + roam_profile.ChannelInfo.numOfChannels = 1; + roam_profile.phyMode = ch_info->phy_mode; + roam_profile.ch_params.ch_width = bandwidth; + + qdf_mem_copy(bssid.bytes, adapter->macAddressCurrent.bytes, + QDF_MAC_ADDR_SIZE); + + ch_params.ch_width = bandwidth; + sme_set_ch_params(hal_hdl, ch_info->phy_mode, chan, 0, &ch_params); + status = sme_roam_channel_change_req(hal_hdl, bssid, &ch_params, + &roam_profile); + if (status) { + hdd_err("Status: %d Failed to set sme_roam Channel for monitor mode", + status); + } + + return qdf_status_to_os_return(status); +} + static int __iw_set_two_ints_getnone(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -9793,6 +9841,9 @@ static int __iw_set_two_ints_getnone(struct net_device *dev, if (value[1] == DUMP_DP_TRACE) qdf_dp_trace_dump_all(value[2]); break; + case WE_SET_MON_MODE_CHAN: + ret = wlan_hdd_set_mon_chan(pAdapter, value[1], value[2]); + break; default: hddLog(LOGE, "%s: Invalid IOCTL command %d", __func__, sub_cmd); break; @@ -11014,6 +11065,10 @@ static const struct iw_priv_args we_private_args[] = { IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "dump_dp_trace"} , + {WE_SET_MON_MODE_CHAN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "setMonChan"} + , }; const struct iw_handler_def we_handler_def = { diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 0f6854fa15d6..0a58715270b2 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -494,6 +494,7 @@ typedef enum eSirBssType { eSIR_INFRA_AP_MODE, /* Added for softAP support */ eSIR_IBSS_MODE, eSIR_AUTO_MODE, + eSIR_MONITOR_MODE, eSIR_DONOT_USE_BSS_TYPE = SIR_MAX_ENUM_SIZE } tSirBssType; @@ -2429,6 +2430,18 @@ typedef struct sSirUpdateParams { uint8_t ssidHidden; /* Hide SSID */ } tSirUpdateParams, *tpSirUpdateParams; +/** + * struct sir_create_session - Used for creating session in monitor mode + * @type: SME host message type. + * @msg_len: Length of the message. + * @bss_id: bss_id for creating the session. + */ +struct sir_create_session { + uint16_t type; + uint16_t msg_len; + struct qdf_mac_addr bss_id; +}; + /* Beacon Interval */ typedef struct sSirChangeBIParams { uint16_t messageType; diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h index 93aae032223e..e6dfb2dda66a 100644 --- a/core/mac/inc/wni_api.h +++ b/core/mac/inc/wni_api.h @@ -249,6 +249,7 @@ enum eWniMsgTypes { eWNI_SME_SET_ANTENNA_MODE_REQ, eWNI_SME_SET_ANTENNA_MODE_RESP, eWNI_SME_TSF_EVENT, + eWNI_SME_MON_INIT_SESSION, eWNI_SME_MSG_TYPES_END }; diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 64ef4362a757..7b74226e7fde 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1125,4 +1125,5 @@ QDF_STATUS sme_get_bpf_offload_capabilities(tHalHandle hal); QDF_STATUS sme_set_bpf_instructions(tHalHandle hal, struct sir_bpf_set_offload *); +QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, uint8_t *bssid); #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 120f306b8dc7..03a9ee6bcad4 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -15630,7 +15630,6 @@ QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id) return qdf_status; } - /** * sme_get_bpf_offload_capabilities() - Get length for BPF offload * @hal: Global HAL handle @@ -15754,3 +15753,26 @@ QDF_STATUS sme_bpf_offload_register_callback(tHalHandle hal, } return status; } + +/** + * sme_create_mon_session() - post message to create PE session for monitormode + * operation + * @hal_handle: Handle to the HAL + * @bssid: pointer to bssid + * + * Return: QDF_STATUS_SUCCESS on success, non-zero error code on failure. + */ +QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, tSirMacAddr bss_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sir_create_session *msg; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL != msg) { + msg->type = eWNI_SME_MON_INIT_SESSION; + msg->msg_len = sizeof(*msg); + qdf_mem_copy(msg->bss_id.bytes, bss_id, QDF_MAC_ADDR_SIZE); + status = cds_send_mb_message_to_mac(msg); + } + return status; +}