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 <tcpdump.pcap>

In this mode concurrency is not supported and module doesnot support Tx.

Change-Id: I211ece0a66e2d43bc111e523714942e1557e36f4
CRs-Fixed: 963060
This commit is contained in:
Manjunathappa Prakash
2016-04-21 10:33:31 -07:00
committed by Akash Patel
parent 2476ef58f4
commit 59f861d11d
11 changed files with 537 additions and 24 deletions

View File

@@ -631,6 +631,20 @@ typedef struct hdd_cfg80211_state_s {
eP2PActionFrameState actionFrmState; eP2PActionFrameState actionFrmState;
} hdd_cfg80211_state_t; } 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 { struct hdd_station_ctx {
/** Handle to the Wireless Extension State */ /** Handle to the Wireless Extension State */
hdd_wext_state_t WextState; hdd_wext_state_t WextState;
@@ -665,6 +679,8 @@ struct hdd_station_ctx {
int staDebugState; int staDebugState;
uint8_t broadcast_ibss_staid; uint8_t broadcast_ibss_staid;
struct hdd_mon_set_ch_info ch_info;
}; };
#define BSS_STOP 0 #define BSS_STOP 0

View File

@@ -128,11 +128,9 @@ static inline void wlan_hdd_log_eapol(struct sk_buff *skb,
} }
#endif /* FEATURE_WLAN_DIAG_SUPPORT */ #endif /* FEATURE_WLAN_DIAG_SUPPORT */
const char *hdd_reason_type_to_string(enum netif_reason_type reason); const char *hdd_reason_type_to_string(enum netif_reason_type reason);
const char *hdd_action_type_to_string(enum netif_action_type action); const char *hdd_action_type_to_string(enum netif_action_type action);
void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter,
enum netif_action_type action, enum netif_reason_type reason); 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) */ #endif /* end #if !defined(WLAN_HDD_TX_RX_H) */

View File

@@ -44,6 +44,7 @@
#include <csr_api.h> #include <csr_api.h>
#include <wlan_hdd_misc.h> #include <wlan_hdd_misc.h>
#include <wlan_hdd_napi.h> #include <wlan_hdd_napi.h>
#include <cds_concurrency.h>
static void static void
cb_notify_set_roam_prefer5_g_hz(hdd_context_t *pHddCtx, unsigned long notifyId) cb_notify_set_roam_prefer5_g_hz(hdd_context_t *pHddCtx, unsigned long notifyId)
@@ -5474,6 +5475,66 @@ config_exit:
return qdf_status; 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 * hdd_parse_config_ini() - parse the ini configuration file
* @pHddCtx: the pointer to hdd context * @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, hdd_napi_event(NAPI_EVT_INI_FILE,
(void *)pHddCtx->config->napi_enable); (void *)pHddCtx->config->napi_enable);
#endif /* FEATURE_NAPI */ #endif /* FEATURE_NAPI */
if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam())
hdd_override_all_ps(pHddCtx);
config_exit: config_exit:
release_firmware(fw); release_firmware(fw);

View File

@@ -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 static struct ieee80211_iface_combination
wlan_hdd_iface_combination[] = { wlan_hdd_iface_combination[] = {
/* STA */ /* STA */
@@ -5908,26 +5926,35 @@ int wlan_hdd_cfg80211_init(struct device *dev,
wiphy->max_acl_mac_addrs = MAX_ACL_MAC_ADDRESS; wiphy->max_acl_mac_addrs = MAX_ACL_MAC_ADDRESS;
/* Supports STATION & AD-HOC modes right now */ if (cds_get_conparam() != QDF_GLOBAL_MONITOR_MODE) {
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) /* Supports STATION & AD-HOC modes right now */
| BIT(NL80211_IFTYPE_ADHOC) wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
| BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_ADHOC)
| BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT)
| BIT(NL80211_IFTYPE_AP); | BIT(NL80211_IFTYPE_P2P_GO)
| BIT(NL80211_IFTYPE_AP);
if (pCfg->advertiseConcurrentOperation) { if (pCfg->advertiseConcurrentOperation) {
if (pCfg->enableMCC) { if (pCfg->enableMCC) {
int i; int i;
for (i = 0; i < ARRAY_SIZE(wlan_hdd_iface_combination);
i++) { for (i = 0;
if (!pCfg->allowMCCGODiffBI) i < ARRAY_SIZE(wlan_hdd_iface_combination);
wlan_hdd_iface_combination[i]. i++) {
beacon_int_infra_match = true; 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 = wiphy->n_iface_combinations =
ARRAY_SIZE(wlan_hdd_iface_combination); ARRAY_SIZE(wlan_hdd_mon_iface);
wiphy->iface_combinations = wlan_hdd_iface_combination; wiphy->iface_combinations = wlan_hdd_mon_iface;
} }
/* Before registering we need to update the ht capabilitied based /* 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; uint8_t iniDot11Mode = (WLAN_HDD_GET_CTX(pAdapter))->config->dot11Mode;
eHddDot11Mode hddDot11Mode = iniDot11Mode; eHddDot11Mode hddDot11Mode = iniDot11Mode;
struct ch_params_s ch_params; 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 = ch_params.ch_width =
(WLAN_HDD_GET_CTX(pAdapter))->config->vhtChannelWidth; (WLAN_HDD_GET_CTX(pAdapter))->config->vhtChannelWidth;
@@ -8264,10 +8295,20 @@ void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel)
break; break;
} }
/* This call decides required channel bonding mode */ /* 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), hdd_cfg_xlate_to_csr_phy_mode(hddDot11Mode),
operationChannel, 0, operationChannel, 0,
&ch_params); &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; 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 * struct cfg80211_ops - cfg80211_ops
* *
@@ -11956,4 +12084,5 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = {
#ifdef CHANNEL_SWITCH_SUPPORTED #ifdef CHANNEL_SWITCH_SUPPORTED
.channel_switch = wlan_hdd_cfg80211_channel_switch, .channel_switch = wlan_hdd_cfg80211_channel_switch,
#endif #endif
.set_monitor_channel = wlan_hdd_cfg80211_set_mon_ch,
}; };

View File

@@ -1435,6 +1435,42 @@ bool hdd_is_valid_mac_address(const uint8_t *pMacAddr)
return xdigit == 12 && (separator == 5 || separator == 0); 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 * __hdd_open() - HDD Open function
* @dev: Pointer to net_device structure * @dev: Pointer to net_device structure
@@ -1892,9 +1928,44 @@ static struct net_device_ops wlan_drv_ops = {
#endif #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) 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) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS)
name_assign_type, name_assign_type,
#endif #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) { 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_CLIENT_MODE:
case QDF_P2P_DEVICE_MODE: case QDF_P2P_DEVICE_MODE:
case QDF_OCB_MODE: case QDF_OCB_MODE:
case QDF_MONITOR_MODE:
{ {
adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr, adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr,
name_assign_type, 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; adapter->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT;
else if (QDF_P2P_DEVICE_MODE == session_type) else if (QDF_P2P_DEVICE_MODE == session_type)
adapter->wdev.iftype = NL80211_IFTYPE_P2P_DEVICE; adapter->wdev.iftype = NL80211_IFTYPE_P2P_DEVICE;
else if (QDF_MONITOR_MODE == session_type)
adapter->wdev.iftype = NL80211_IFTYPE_MONITOR;
else else
adapter->wdev.iftype = NL80211_IFTYPE_STATION; adapter->wdev.iftype = NL80211_IFTYPE_STATION;
@@ -5635,6 +5711,21 @@ static inline int hdd_open_p2p_interface(struct hdd_context_t *hdd_ctx,
} }
#endif #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_open_interfaces - Open all required interfaces
* hdd_ctx: HDD context * hdd_ctx: HDD context
@@ -6059,7 +6150,10 @@ int hdd_wlan_startup(struct device *dev, void *hif_sc)
rtnl_held = hdd_hold_rtnl_lock(); 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)) { if (IS_ERR(adapter)) {
ret = PTR_ERR(adapter); ret = PTR_ERR(adapter);

View File

@@ -55,6 +55,7 @@
#include "wlan_hdd_lro.h" #include "wlan_hdd_lro.h"
#include "cdp_txrx_peer_ops.h" #include "cdp_txrx_peer_ops.h"
#include "ol_txrx.h"
#ifdef FEATURE_WLAN_DIAG_SUPPORT #ifdef FEATURE_WLAN_DIAG_SUPPORT
#define HDD_EAPOL_ETHER_TYPE (0x888E) #define HDD_EAPOL_ETHER_TYPE (0x888E)
@@ -669,6 +670,84 @@ QDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter)
return status; 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 * hdd_rx_packet_cbk() - Receive packet handler
* @context: pointer to HDD context * @context: pointer to HDD context
@@ -1108,3 +1187,45 @@ void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter,
return; 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;
}

View File

@@ -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_SCAN_CONFIG 21
#define WE_SET_DUAL_MAC_FW_MODE_CONFIG 22 #define WE_SET_DUAL_MAC_FW_MODE_CONFIG 22
#define WE_SET_MON_MODE_CHAN 23
#ifdef FEATURE_WLAN_TDLS #ifdef FEATURE_WLAN_TDLS
#undef MAX_VAR_ARGS #undef MAX_VAR_ARGS
@@ -9728,6 +9729,53 @@ static int iw_set_band_config(struct net_device *dev,
return ret; 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, static int __iw_set_two_ints_getnone(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra) 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) if (value[1] == DUMP_DP_TRACE)
qdf_dp_trace_dump_all(value[2]); qdf_dp_trace_dump_all(value[2]);
break; break;
case WE_SET_MON_MODE_CHAN:
ret = wlan_hdd_set_mon_chan(pAdapter, value[1], value[2]);
break;
default: default:
hddLog(LOGE, "%s: Invalid IOCTL command %d", __func__, sub_cmd); hddLog(LOGE, "%s: Invalid IOCTL command %d", __func__, sub_cmd);
break; break;
@@ -11014,6 +11065,10 @@ static const struct iw_priv_args we_private_args[] = {
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
0, "dump_dp_trace"} 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 = { const struct iw_handler_def we_handler_def = {

View File

@@ -494,6 +494,7 @@ typedef enum eSirBssType {
eSIR_INFRA_AP_MODE, /* Added for softAP support */ eSIR_INFRA_AP_MODE, /* Added for softAP support */
eSIR_IBSS_MODE, eSIR_IBSS_MODE,
eSIR_AUTO_MODE, eSIR_AUTO_MODE,
eSIR_MONITOR_MODE,
eSIR_DONOT_USE_BSS_TYPE = SIR_MAX_ENUM_SIZE eSIR_DONOT_USE_BSS_TYPE = SIR_MAX_ENUM_SIZE
} tSirBssType; } tSirBssType;
@@ -2429,6 +2430,18 @@ typedef struct sSirUpdateParams {
uint8_t ssidHidden; /* Hide SSID */ uint8_t ssidHidden; /* Hide SSID */
} tSirUpdateParams, *tpSirUpdateParams; } 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 */ /* Beacon Interval */
typedef struct sSirChangeBIParams { typedef struct sSirChangeBIParams {
uint16_t messageType; uint16_t messageType;

View File

@@ -249,6 +249,7 @@ enum eWniMsgTypes {
eWNI_SME_SET_ANTENNA_MODE_REQ, eWNI_SME_SET_ANTENNA_MODE_REQ,
eWNI_SME_SET_ANTENNA_MODE_RESP, eWNI_SME_SET_ANTENNA_MODE_RESP,
eWNI_SME_TSF_EVENT, eWNI_SME_TSF_EVENT,
eWNI_SME_MON_INIT_SESSION,
eWNI_SME_MSG_TYPES_END eWNI_SME_MSG_TYPES_END
}; };

View File

@@ -1125,4 +1125,5 @@ QDF_STATUS sme_get_bpf_offload_capabilities(tHalHandle hal);
QDF_STATUS sme_set_bpf_instructions(tHalHandle hal, QDF_STATUS sme_set_bpf_instructions(tHalHandle hal,
struct sir_bpf_set_offload *); struct sir_bpf_set_offload *);
QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, uint8_t *bssid);
#endif /* #if !defined( __SME_API_H ) */ #endif /* #if !defined( __SME_API_H ) */

View File

@@ -15630,7 +15630,6 @@ QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id)
return qdf_status; return qdf_status;
} }
/** /**
* sme_get_bpf_offload_capabilities() - Get length for BPF offload * sme_get_bpf_offload_capabilities() - Get length for BPF offload
* @hal: Global HAL handle * @hal: Global HAL handle
@@ -15754,3 +15753,26 @@ QDF_STATUS sme_bpf_offload_register_callback(tHalHandle hal,
} }
return status; 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;
}