blob: fec5661401b0673c29ee56460d6a136ba157fbb0 [file] [log] [blame]
/*
* Copyright (c) 2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#include "wlan_hdd_includes.h"
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <cds_sched.h>
#include <cds_utils.h>
#include "wlan_hdd_rx_monitor.h"
/**
* hdd_rx_monitor_callback(): Callback function for receive monitor mode
* @vdev: Handle to vdev object
* @mpdu: pointer to mpdu to be delivered to os
* @rx_status: receive status
*
* Returns: None
*/
void hdd_rx_monitor_callback(ol_osif_vdev_handle context,
qdf_nbuf_t rxbuf,
void *rx_status)
{
struct hdd_adapter *adapter;
int rxstat;
struct sk_buff *skb;
struct sk_buff *skb_next;
unsigned int cpu_index;
qdf_assert(context);
qdf_assert(rxbuf);
adapter = (struct hdd_adapter *)context;
if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) {
QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
"invalid adapter %p", adapter);
return;
}
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;
}
return;
}
/**
* hdd_monitor_set_rx_monitor_cb(): Set rx monitor mode callback function
* @txrx: pointer to txrx ops
* @rx_monitor_cb: pointer to callback function
*
* Returns: None
*/
void hdd_monitor_set_rx_monitor_cb(struct ol_txrx_ops *txrx,
ol_txrx_rx_mon_fp rx_monitor_cb)
{
txrx->rx.mon = rx_monitor_cb;
}
/**
* hdd_enable_monitor_mode() - Enable monitor mode
* @dev: Pointer to the net_device structure
*
* This function invokes cdp interface API to enable
* monitor mode configuration on the hardware. In this
* case sends HTT messages to FW to setup hardware rings
*
* Return: 0 for success; non-zero for failure
*/
int hdd_enable_monitor_mode(struct net_device *dev)
{
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
ENTER_DEV(dev);
return cdp_set_monitor_mode(soc,
(struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc,
(struct cdp_pdev *)pdev, adapter->sessionId), false);
}