Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,119 @@
# ----------------------------------------------------------------------------
# FILE: Makefile
#
# PURPOSE:
# Build instructions for SCSC Wlan driver.
#
#
# Copyright (C) 2016 by Samsung Electronics Co., Ltd
# ----------------------------------------------------------------------------
CONFIG_SCSC_WLAN_MODULE=scsc_wlan_unittest
# ----------------------------------------------------------------------------
# Common Driver Files
# ----------------------------------------------------------------------------
$(CONFIG_SCSC_WLAN_MODULE)-y += ../mib.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../mib_text_convert.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../debug.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../debug_frame.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../procfs.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../mgt.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../udi.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../log_clients.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../src_sink.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../fw_test.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../cac.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../ioctl.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../wakelock.o
# enable Oxygen
ifeq ($(CONFIG_SCSC_WLAN_OXYGEN_ENABLE),y)
$(CONFIG_SCSC_WLAN_MODULE)-y += ../oxygen_ioctl.o
endif
# enable GSCAN
ifeq ($(CONFIG_SCSC_WLAN_GSCAN_ENABLE),y)
$(CONFIG_SCSC_WLAN_MODULE)-y += ../nl80211_vendor.o
ccflags-y += -DCONFIG_SCSC_WLAN_GSCAN_ENABLE
endif
# enable roam offload
ifeq ($(CONFIG_SCSC_WLAN_KEY_MGMT_OFFLOAD),y)
ccflags-y += -DCONFIG_SCSC_WLAN_KEY_MGMT_OFFLOAD
endif
# ----------------------------------------------------------------------------
# Building for cfg802.11
# ----------------------------------------------------------------------------
$(CONFIG_SCSC_WLAN_MODULE)-y += ../cfg80211_ops.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../mlme.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../netif.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../rx.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../tx.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../ba.o
# ----------------------------------------------------------------------------
# Building for SAP
# ----------------------------------------------------------------------------
$(CONFIG_SCSC_WLAN_MODULE)-y += ../sap_ma.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../sap_mlme.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../sap_dbg.o
$(CONFIG_SCSC_WLAN_MODULE)-y += ../sap_test.o
# ----------------------------------------------------------------------------
# unittest Driver
# ----------------------------------------------------------------------------
$(CONFIG_SCSC_WLAN_MODULE)-y += ../dev.o
$(CONFIG_SCSC_WLAN_MODULE)-y += dev_test.o
$(CONFIG_SCSC_WLAN_MODULE)-y += hip_test.o
$(CONFIG_SCSC_WLAN_MODULE)-y += hydra_test.o
$(CONFIG_SCSC_WLAN_MODULE)-y += udi_test.o
# Suppress -Wempty-body when not built with Debug enabled.
ifneq ($(CONFIG_SCSC_WLAN_DEBUG),y)
ccflags-y += -Wno-empty-body
else
ccflags-y += -g -ggdb
endif
ccflags-y += -Wno-unused-parameter
ccflags-y += -Wno-sign-compare
# ----------------------------------------------------------------------------
# wlan configuration
# ----------------------------------------------------------------------------
ccflags-$(CONFIG_SCSC_WLAN_DEBUG) += -DCONFIG_SCSC_WLAN_DEBUG
ccflags-$(CONFIG_SCSC_WLAN_SKB_TRACKING) += -DCONFIG_SCSC_WLAN_SKB_TRACKING
ccflags-$(CONFIG_SCSC_WLAN_OFFLINE_TRACE) += -DCONFIG_SCSC_WLAN_OFFLINE_TRACE
ccflags-$(CONFIG_SCSC_WLAN_OFFLINE_SDIO_TRACE) += -DCONFIG_SCSC_WLAN_OFFLINE_SDIO_TRACE
ccflags-$(CONFIG_SCSC_WLAN_OFFLINE_DATA_PLANE_PROFILE_TRACE) += -DCONFIG_SCSC_WLAN_OFFLINE_DATA_PLANE_PROFILE_TRACE
ccflags-$(CONFIG_SCSC_WLAN_OFFLINE_TX_TRACE) += -DCONFIG_SCSC_WLAN_OFFLINE_TX_TRACE
ccflags-$(CONFIG_SCSC_WLAN_HIP_CLEAR_TH_SLOT_SUPPORT) += -DCONFIG_SCSC_WLAN_HIP_CLEAR_TH_SLOT_SUPPORT
ccflags-$(CONFIG_SCSC_WLAN_HIP_DEFER_SLOT_SUPPORT) += -DCONFIG_SCSC_WLAN_HIP_DEFER_SLOT_SUPPORT
ccflags-$(CONFIG_SCSC_WLAN_RX_NAPI) += -DCONFIG_SCSC_WLAN_RX_NAPI
ccflags-$(CONFIG_SCSC_WLAN_RX_NAPI_GRO) += -DCONFIG_SCSC_WLAN_RX_NAPI_GRO
ccflags-$(CONFIG_SCSC_WLAN_WES_NCHO) += -DCONFIG_SCSC_WLAN_WES_NCHO
ccflags-$(CONFIG_SCSC_WLAN_MUTEX_DEBUG) += -DCONFIG_SCSC_WLAN_MUTEX_DEBUG
ccflags-y += -DCONFIG_SCSC_WLAN_MAX_INTERFACES=$(CONFIG_SCSC_WLAN_MAX_INTERFACES)
# Android specific build options
ccflags-$(CONFIG_SCSC_WLAN_ANDROID) += -DCONFIG_SCSC_WLAN_ANDROID
# enable Oxygen
ifeq ($(CONFIG_SCSC_WLAN_OXYGEN_ENABLE),y)
ccflags-y += -DCONFIG_SCSC_WLAN_OXYGEN_ENABLE
ccflags-y += -DCONFIG_SCSC_WLAN_OXYGEN_UT_EXCEPTION
endif
ccflags-y += -I$(src) -I$(src)/..
ccflags-y += -I$(src)/../../../../../include -I$(src)/../../../../../include/scsc
ccflags-y += -DSLSI_TEST_DEV
ccflags-y += $(CONFIG_SCSC_WLAN_EXTRA)
# ----------------------------------------------------------------------------
# module
# ----------------------------------------------------------------------------
obj-$(CONFIG_SCSC_WLAN_UNITTEST) := $(CONFIG_SCSC_WLAN_MODULE).o

View file

@ -0,0 +1,511 @@
/****************************************************************************
*
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd
*
****************************************************************************/
#include <net/ip.h>
#include "debug.h"
#include "utils.h"
#include "udi.h"
#include "unittest.h"
#include "mgt.h"
#include "scsc/scsc_mx.h"
#define SLSI_TESTDRV_NAME "s5n2560_test"
static int radios = 11;
module_param(radios, int, 0444);
MODULE_PARM_DESC(radios, "Number of simulated radios");
/* spinlock for retaining the (struct slsi_dev) information */
static struct slsi_spinlock slsi_test_devices_lock;
static struct slsi_test_dev *slsi_test_devices[SLSI_UDI_MINOR_NODES];
static struct class *test_dev_class;
/* Major number of device created by system. */
static dev_t major_number;
static struct device_driver slsi_test_driver = {
.name = SLSI_TESTDRV_NAME
};
static void slsi_test_dev_attach_work(struct work_struct *work);
static void slsi_test_dev_detach_work(struct work_struct *work);
static void slsi_test_dev_free(void)
{
int i;
for (i = 0; i < SLSI_UDI_MINOR_NODES; i++) {
struct slsi_test_dev *uftestdev;
slsi_spinlock_lock(&slsi_test_devices_lock);
uftestdev = slsi_test_devices[i];
slsi_test_devices[i] = NULL;
slsi_spinlock_unlock(&slsi_test_devices_lock);
if (uftestdev != NULL) {
SLSI_INFO_NODEV("Free Test Device: %02X:%02X:%02X:%02X:%02X:%02X\n",
uftestdev->hw_addr[0],
uftestdev->hw_addr[1],
uftestdev->hw_addr[2],
uftestdev->hw_addr[3],
uftestdev->hw_addr[4],
uftestdev->hw_addr[5]);
if (WARN_ON(uftestdev->attached)) {
slsi_test_bh_deinit(uftestdev);
flush_workqueue(uftestdev->attach_detach_work_queue);
}
destroy_workqueue(uftestdev->attach_detach_work_queue);
slsi_test_udi_node_deinit(uftestdev);
device_unregister(uftestdev->dev);
device_destroy(test_dev_class, uftestdev->dev->devt);
}
}
slsi_test_udi_deinit();
if (test_dev_class != NULL)
class_destroy(test_dev_class);
unregister_chrdev_region(major_number, SLSI_UDI_MINOR_NODES);
}
int slsi_sdio_func_drv_register(void)
{
int i = 0, err = 0, ret = 0;
struct slsi_test_dev *uftestdev;
dev_t devno;
SLSI_INFO_NODEV("Loading SLSI " SLSI_TESTDRV_NAME " Test Driver for mac80211\n");
if (radios > SLSI_UDI_MINOR_NODES) {
SLSI_ERR_NODEV("Loading failed, configure SLSI_UDI_MINOR_NODES to match no. of simulated radios\n");
return -ENOMEM;
}
slsi_spinlock_create(&slsi_test_devices_lock);
memset(slsi_test_devices, 0x00, sizeof(slsi_test_devices));
/* Allocate two device numbers for each device. */
ret = alloc_chrdev_region(&major_number, 0, SLSI_UDI_MINOR_NODES, SLSI_TESTDRV_NAME);
if (ret) {
SLSI_ERR_NODEV("Failed to add alloc dev numbers: %d\n", ret);
unregister_chrdev_region(major_number, SLSI_UDI_MINOR_NODES);
major_number = 0;
return -ENOMEM;
}
test_dev_class = class_create(THIS_MODULE, SLSI_TESTDRV_NAME);
if (IS_ERR(test_dev_class))
return -EAGAIN;
slsi_test_udi_init();
for (i = 0; i < radios; i++) {
uftestdev = kmalloc(sizeof(*uftestdev), GFP_KERNEL);
memset(uftestdev, 0, sizeof(*uftestdev));
uftestdev->attach_detach_work_queue = alloc_ordered_workqueue("Test Work", 0);
INIT_WORK(&uftestdev->attach_work, slsi_test_dev_attach_work);
INIT_WORK(&uftestdev->detach_work, slsi_test_dev_detach_work);
devno = MKDEV(MAJOR(major_number), i);
uftestdev->dev = device_create(test_dev_class, NULL, devno, uftestdev, SLSI_TESTDRV_NAME "_dev%d", i);
if (IS_ERR(uftestdev->dev)) {
SLSI_ERR_NODEV("device_create FAILED, returned - (%ld)\n", PTR_ERR(uftestdev->dev));
err = -ENOMEM;
goto failed_free_all;
}
uftestdev->dev->driver = &slsi_test_driver;
mutex_init(&uftestdev->attach_detach_mutex);
slsi_test_bh_init(uftestdev);
spin_lock_init(&uftestdev->route_spinlock);
if (slsi_test_udi_node_init(uftestdev, uftestdev->dev) != 0) {
SLSI_ERR_NODEV("udi <node> init FAILED\n");
goto failed_dev_unregister;
}
/* Using a fixed MAC address instead of slsi_get_hw_mac_address(),
* MAC Address format 00:12:FB:00:00:<xx> where xx increments for every PHY
* (00:12:FB OUI Samsung Electronics)
*/
memset(uftestdev->hw_addr, 0, sizeof(uftestdev->hw_addr));
uftestdev->hw_addr[1] = 0x12;
uftestdev->hw_addr[2] = 0xFB;
/*To randomize the mac address*/
uftestdev->hw_addr[ETH_ALEN - 1] += (i & (0xff));
SLSI_INFO_NODEV("Create Test Device: %02X:%02X:%02X:%02X:%02X:%02X\n",
uftestdev->hw_addr[0],
uftestdev->hw_addr[1],
uftestdev->hw_addr[2],
uftestdev->hw_addr[3],
uftestdev->hw_addr[4],
uftestdev->hw_addr[5]);
slsi_test_devices[uftestdev->device_minor_number] = uftestdev;
}
return 0;
failed_dev_unregister:
device_unregister(uftestdev->dev);
device_destroy(test_dev_class, uftestdev->dev->devt);
failed_free_all:
slsi_test_dev_free();
return -EPERM;
}
void slsi_sdio_func_drv_unregister(void)
{
SLSI_INFO_NODEV("Unloading UF6K Test Driver for mac80211\n");
slsi_test_dev_free();
}
void slsi_test_dev_attach(struct slsi_test_dev *uftestdev)
{
struct slsi_dev *sdev;
struct scsc_service_client service_client;
mutex_lock(&uftestdev->attach_detach_mutex);
SLSI_INFO_NODEV("UnitTest UDI Attached : %02X:%02X:%02X:%02X:%02X:%02X\n",
uftestdev->hw_addr[0],
uftestdev->hw_addr[1],
uftestdev->hw_addr[2],
uftestdev->hw_addr[3],
uftestdev->hw_addr[4],
uftestdev->hw_addr[5]);
if (uftestdev->attached) {
SLSI_ERR_NODEV("attached == true\n");
goto exit;
}
uftestdev->attached = true;
sdev = slsi_dev_attach(uftestdev->dev, (struct scsc_mx *)uftestdev, &service_client);
slsi_spinlock_lock(&slsi_test_devices_lock);
uftestdev->sdev = sdev;
if (!sdev) {
SLSI_ERR_NODEV("slsi_dev_attach() Failed\n");
uftestdev->attached = false;
} else {
slsi_test_bh_start(uftestdev);
}
slsi_spinlock_unlock(&slsi_test_devices_lock);
exit:
mutex_unlock(&uftestdev->attach_detach_mutex);
}
void slsi_test_dev_detach(struct slsi_test_dev *uftestdev)
{
mutex_lock(&uftestdev->attach_detach_mutex);
SLSI_INFO(uftestdev->sdev, "UnitTest UDI Detached : %02X:%02X:%02X:%02X:%02X:%02X\n",
uftestdev->hw_addr[0],
uftestdev->hw_addr[1],
uftestdev->hw_addr[2],
uftestdev->hw_addr[3],
uftestdev->hw_addr[4],
uftestdev->hw_addr[5]);
if (!uftestdev->attached) {
SLSI_ERR(uftestdev->sdev, "attached != true\n");
goto exit;
}
uftestdev->attached = false;
if (uftestdev->sdev) {
struct slsi_dev *sdev = uftestdev->sdev;
slsi_test_bh_stop(uftestdev);
slsi_dev_detach(sdev);
slsi_spinlock_lock(&slsi_test_devices_lock);
uftestdev->sdev = NULL;
slsi_spinlock_unlock(&slsi_test_devices_lock);
}
exit:
mutex_unlock(&uftestdev->attach_detach_mutex);
}
void slsi_init_netdev_mac_addr(struct slsi_dev *sdev)
{
/* Get mac address from file system. */
slsi_get_hw_mac_address(sdev, sdev->hw_addr);
SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_WLAN], sdev->hw_addr);
SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_P2P], sdev->hw_addr);
sdev->netdev_addresses[SLSI_NET_INDEX_P2P][0] |= 0x02; /* Set the local bit */
SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_P2PX], sdev->hw_addr);
sdev->netdev_addresses[SLSI_NET_INDEX_P2PX][0] |= 0x02; /* Set the local bit */
sdev->netdev_addresses[SLSI_NET_INDEX_P2PX][4] ^= 0x80; /* EXOR 5th byte with 0x80 */
SLSI_ETHER_COPY(sdev->netdev[SLSI_NET_INDEX_WLAN]->dev_addr, sdev->netdev_addresses[SLSI_NET_INDEX_WLAN]);
SLSI_ETHER_COPY(sdev->netdev[SLSI_NET_INDEX_P2P]->dev_addr, sdev->netdev_addresses[SLSI_NET_INDEX_P2P]);
}
bool slsi_test_process_signal_ip_remap(struct slsi_test_dev *uftestdev, struct sk_buff *skb, struct slsi_test_data_route *route)
{
int proto = ntohs(skb->protocol);
u8 *frame = fapi_get_data(skb) + 14;
switch (proto) {
case 0x0806:
{
/* Arp */
u8 *sha = &frame[8];
u8 *spa = &frame[14];
u8 *tha = &frame[18];
u8 *tpa = &frame[24];
SLSI_UNUSED_PARAMETER(sha);
SLSI_UNUSED_PARAMETER(spa);
SLSI_UNUSED_PARAMETER(tha);
SLSI_UNUSED_PARAMETER(tpa);
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "ARP: sha:%pM, spa:%d.%d.%d.%d, tha:%pM, tpa:%d.%d.%d.%d\n",
sha, spa[0], spa[1], spa[2], spa[3],
tha, tpa[0], tpa[1], tpa[2], tpa[3]);
spa[2] = route->ipsubnet;
tpa[2] = route->ipsubnet;
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "ARP: sha:%pM, spa:%d.%d.%d.%d, tha:%pM, tpa:%d.%d.%d.%d\n",
sha, spa[0], spa[1], spa[2], spa[3],
tha, tpa[0], tpa[1], tpa[2], tpa[3]);
return true;
}
case 0x0800:
{
/* IPv4 */
struct iphdr *iph = (struct iphdr *)frame;
u8 *src = (u8 *)&iph->saddr;
u8 *dst = (u8 *)&iph->daddr;
SLSI_UNUSED_PARAMETER(src);
SLSI_UNUSED_PARAMETER(dst);
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "PING: src:%d.%d.%d.%d, dst:%d.%d.%d.%d, check:0x%.4X\n",
src[0], src[1], src[2], src[3],
dst[0], dst[1], dst[2], dst[3],
iph->check);
src[2] = route->ipsubnet;
dst[2] = route->ipsubnet;
/* Calculation of IP header checksum */
iph->check = 0;
ip_send_check(iph);
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "PING: src:%d.%d.%d.%d, dst:%d.%d.%d.%d, check:0x%.4X\n",
src[0], src[1], src[2], src[3],
dst[0], dst[1], dst[2], dst[3],
iph->check);
return true;
}
default:
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "Proto:0x%.4X\n", proto);
break;
}
return false;
}
static struct slsi_test_data_route *slsi_test_process_signal_get_route(struct slsi_test_dev *uftestdev, const u8 *mac)
{
struct slsi_test_data_route *route;
int i;
if (WARN_ON(!spin_is_locked(&uftestdev->route_spinlock)))
return NULL;
for (i = 0; i < SLSI_AP_PEER_CONNECTIONS_MAX; i++) {
route = &uftestdev->route[i];
if (route->configured && ether_addr_equal(route->mac, mac))
return route;
}
return NULL;
}
static struct slsi_test_data_route *slsi_test_process_signal_get_free_route(struct slsi_test_dev *uftestdev)
{
struct slsi_test_data_route *route;
int i;
if (WARN_ON(!spin_is_locked(&uftestdev->route_spinlock)))
return NULL;
for (i = 0; i < SLSI_AP_PEER_CONNECTIONS_MAX; i++) {
route = &uftestdev->route[i];
if (!route->configured)
return route;
}
return NULL;
}
void slsi_test_process_signal_set_route(struct slsi_test_dev *uftestdev, struct sk_buff *skb)
{
struct slsi_test_data_route *route;
u8 mac[ETH_ALEN];
u16 dest_device_minor_number = 0xFFFF;
int i;
mac[0] = fapi_get_buff(skb, u.debug_generic_req.debug_words[2]) >> 8;
mac[1] = fapi_get_buff(skb, u.debug_generic_req.debug_words[2]) & 0xFF;
mac[2] = fapi_get_buff(skb, u.debug_generic_req.debug_words[3]) >> 8;
mac[3] = fapi_get_buff(skb, u.debug_generic_req.debug_words[3]) & 0xFF;
mac[4] = fapi_get_buff(skb, u.debug_generic_req.debug_words[4]) >> 8;
mac[5] = fapi_get_buff(skb, u.debug_generic_req.debug_words[4]) & 0xFF;
slsi_spinlock_lock(&slsi_test_devices_lock);
for (i = 0; i < SLSI_UDI_MINOR_NODES; i++) {
struct slsi_test_dev *destdev = slsi_test_devices[i];
if (destdev != NULL && ether_addr_equal(destdev->hw_addr, mac))
dest_device_minor_number = destdev->device_minor_number;
}
slsi_spinlock_unlock(&slsi_test_devices_lock);
if (dest_device_minor_number == 0xFFFF) {
SLSI_ERR(uftestdev->sdev, "Setting Route for %pM FAILED. No match found\n", mac);
return;
}
spin_lock(&uftestdev->route_spinlock);
route = slsi_test_process_signal_get_route(uftestdev, mac);
if (!route)
route = slsi_test_process_signal_get_free_route(uftestdev);
if (route) {
SLSI_DBG1(uftestdev->sdev, SLSI_TEST, "Setting Route for %pM -> %pM\n", uftestdev->hw_addr, mac);
route->configured = true;
route->test_device_minor_number = dest_device_minor_number;
SLSI_ETHER_COPY(route->mac, mac);
route->vif = fapi_get_u16(skb, u.debug_generic_req.debug_words[5]);
route->ipsubnet = fapi_get_u16(skb, u.debug_generic_req.debug_words[6]) & 0xFF;
route->sequence_number = 1;
} else {
SLSI_ERR(uftestdev->sdev, "Setting Route for %pM FAILED. No Free Route Entry\n", mac);
}
spin_unlock(&uftestdev->route_spinlock);
}
void slsi_test_process_signal_clear_route(struct slsi_test_dev *uftestdev, struct sk_buff *skb)
{
struct slsi_test_data_route *route;
u8 mac[ETH_ALEN];
mac[0] = fapi_get_buff(skb, u.debug_generic_req.debug_words[2]) >> 8;
mac[1] = fapi_get_buff(skb, u.debug_generic_req.debug_words[2]) & 0xFF;
mac[2] = fapi_get_buff(skb, u.debug_generic_req.debug_words[3]) >> 8;
mac[3] = fapi_get_buff(skb, u.debug_generic_req.debug_words[3]) & 0xFF;
mac[4] = fapi_get_buff(skb, u.debug_generic_req.debug_words[4]) >> 8;
mac[5] = fapi_get_buff(skb, u.debug_generic_req.debug_words[4]) & 0xFF;
spin_lock(&uftestdev->route_spinlock);
SLSI_DBG1(uftestdev->sdev, SLSI_TEST, "Clearing Route for %pM\n", mac);
route = slsi_test_process_signal_get_route(uftestdev, mac);
if (route)
route->configured = false;
else
SLSI_ERR(uftestdev->sdev, "Clearing Route for %pM FAILED. No Route Entry Found\n", mac);
spin_unlock(&uftestdev->route_spinlock);
}
bool slsi_test_process_signal(struct slsi_test_dev *uftestdev, struct sk_buff *skb)
{
if (fapi_get_sigid(skb) == DEBUG_GENERIC_REQ) {
SLSI_DBG1(uftestdev->sdev, SLSI_TEST, "fapi_get_u16(skb, u.debug_generic_req.debug_words[0]) = %d\n", fapi_get_u16(skb, u.debug_generic_req.debug_words[0]));
SLSI_DBG1(uftestdev->sdev, SLSI_TEST, "fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) = %d\n", fapi_get_u16(skb, u.debug_generic_req.debug_words[1]));
if (fapi_get_u16(skb, u.debug_generic_req.debug_words[0]) == 0x1357) {
if (fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) == 0)
queue_work(uftestdev->attach_detach_work_queue, &uftestdev->detach_work);
else if (fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) == 1)
queue_work(uftestdev->attach_detach_work_queue, &uftestdev->attach_work);
else if (fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) == 2)
slsi_test_process_signal_set_route(uftestdev, skb);
else if (fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) == 3)
slsi_test_process_signal_clear_route(uftestdev, skb);
}
slsi_kfree_skb(skb);
return true;
}
/* Automatically route the packet to the other test device and bypass the */
if (fapi_get_sigid(skb) == MA_UNITDATA_REQ) {
struct slsi_test_data_route *route;
struct ethhdr *ehdr = (struct ethhdr *)skb->data;
spin_lock(&uftestdev->route_spinlock);
route = slsi_test_process_signal_get_route(uftestdev, ehdr->h_dest);
if (route && slsi_test_process_signal_ip_remap(uftestdev, skb, route)) {
struct slsi_skb_cb *cb;
struct fapi_signal req = *((struct fapi_signal *)skb->data);
struct fapi_signal *ind;
/* Convert the MA_UNITDATA_REQ to a MA_UNITDATA_IND */
WARN_ON(!skb_pull(skb, fapi_sig_size(ma_unitdata_req)));
ind = (struct fapi_signal *)skb_push(skb, fapi_sig_size(ma_unitdata_ind));
if (WARN_ON(!ind)) {
slsi_kfree_skb(skb);
spin_unlock(&uftestdev->route_spinlock);
return true;
}
ind->id = cpu_to_le16(MA_UNITDATA_IND);
ind->receiver_pid = 0;
ind->sender_pid = 0;
fapi_set_u16(skb, u.ma_unitdata_ind.vif, cpu_to_le16(route->vif));
fapi_set_u16(skb, u.ma_unitdata_ind.sequence_number, route->sequence_number++);
cb = slsi_skb_cb_init(skb);
cb->sig_length = fapi_get_expected_size(skb);
cb->data_length = skb->len;
slsi_spinlock_lock(&slsi_test_devices_lock);
if (slsi_test_devices[route->test_device_minor_number] &&
slsi_test_devices[route->test_device_minor_number]->sdev) {
if (slsi_hip_rx(slsi_test_devices[route->test_device_minor_number]->sdev, skb) != 0)
slsi_kfree_skb(skb);
} else {
route->configured = false;
slsi_kfree_skb(skb);
}
slsi_spinlock_unlock(&slsi_test_devices_lock);
spin_unlock(&uftestdev->route_spinlock);
return true;
}
spin_unlock(&uftestdev->route_spinlock);
}
return false;
}
static void slsi_test_dev_attach_work(struct work_struct *work)
{
struct slsi_test_dev *uftestdev = container_of(work, struct slsi_test_dev, attach_work);
SLSI_INFO_NODEV("UnitTest TEST Attach\n");
slsi_test_dev_attach(uftestdev);
slsi_test_udi_node_reregister(uftestdev);
}
static void slsi_test_dev_detach_work(struct work_struct *work)
{
struct slsi_test_dev *uftestdev = container_of(work, struct slsi_test_dev, detach_work);
SLSI_INFO(uftestdev->sdev, "UnitTest TEST Detach\n");
slsi_test_dev_detach(uftestdev);
}

View file

@ -0,0 +1,272 @@
/******************************************************************************
*
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
*
*****************************************************************************/
#include <linux/kthread.h>
#include "unittest.h"
#include "hip.h"
#include "sap.h"
#include "debug.h"
#include "procfs.h"
#include "hydra.h"
#include "hip4.h"
#define SLSI_TEST_DEV_SDIO_BLOCK_SIZE 500
bool hip4_sampler_sample_start_stop_q = true;
struct hip4_hip_control test_hip_control;
/* SAP implementations container. Local and static to hip */
static struct hip_sap {
struct sap_api *sap[SAP_TOTAL];
} hip_sap_cont;
/* Register SAP with HIP layer */
int slsi_hip_sap_register(struct sap_api *sap_api)
{
u8 class = sap_api->sap_class;
if (class >= SAP_TOTAL)
return -ENODEV;
hip_sap_cont.sap[class] = sap_api;
return 0;
}
/* UNregister SAP with HIP layer */
int slsi_hip_sap_unregister(struct sap_api *sap_api)
{
u8 class = sap_api->sap_class;
if (class >= SAP_TOTAL)
return -ENODEV;
hip_sap_cont.sap[class] = NULL;
return 0;
}
int slsi_hip_sap_setup(struct slsi_dev *sdev)
{
/* Execute callbacks to intorm Supported version */
u16 version = 0;
if (hip_sap_cont.sap[SAP_MLME]->sap_version_supported) {
version = scsc_wifi_get_hip_config_version_4_u16(&sdev->hip4_inst.hip_control->config_v4, sap_mlme_ver);
if (hip_sap_cont.sap[SAP_MLME]->sap_version_supported(version))
return -ENODEV;
} else {
return -ENODEV;
}
if (hip_sap_cont.sap[SAP_MA]->sap_version_supported) {
version = scsc_wifi_get_hip_config_version_4_u16(&sdev->hip4_inst.hip_control->config_v4, sap_ma_ver);
if (hip_sap_cont.sap[SAP_MA]->sap_version_supported(version))
return -ENODEV;
} else {
return -ENODEV;
}
if (hip_sap_cont.sap[SAP_DBG]->sap_version_supported) {
version = scsc_wifi_get_hip_config_version_4_u16(&sdev->hip4_inst.hip_control->config_v4, sap_debug_ver);
if (hip_sap_cont.sap[SAP_DBG]->sap_version_supported(version))
return -ENODEV;
} else {
return -ENODEV;
}
if (hip_sap_cont.sap[SAP_TST]->sap_version_supported) {
version = scsc_wifi_get_hip_config_version_4_u16(&sdev->hip4_inst.hip_control->config_v4, sap_test_ver);
if (hip_sap_cont.sap[SAP_TST]->sap_version_supported(version))
return -ENODEV;
} else {
return -ENODEV;
}
/* Success */
return 0;
}
/* SAP rx proxy */
int slsi_hip_rx(struct slsi_dev *sdev, struct sk_buff *skb)
{
u16 pid;
/* Udi test : If pid in UDI range then pass to UDI and ignore */
slsi_log_clients_log_signal_fast(sdev, &sdev->log_clients, skb, SLSI_LOG_DIRECTION_TO_HOST);
pid = fapi_get_u16(skb, receiver_pid);
if (pid >= SLSI_TX_PROCESS_ID_UDI_MIN && pid <= SLSI_TX_PROCESS_ID_UDI_MAX) {
slsi_kfree_skb(skb);
return 0;
}
if (fapi_is_ma(skb))
return hip_sap_cont.sap[SAP_MA]->sap_handler(sdev, skb);
if (fapi_is_mlme(skb))
return hip_sap_cont.sap[SAP_MLME]->sap_handler(sdev, skb);
if (fapi_is_debug(skb))
return hip_sap_cont.sap[SAP_DBG]->sap_handler(sdev, skb);
if (fapi_is_test(skb))
return hip_sap_cont.sap[SAP_TST]->sap_handler(sdev, skb);
return -EIO;
}
/* value used at all levels in the driver */
int slsi_hip_init(struct slsi_dev *sdev, struct device *dev)
{
SLSI_UNUSED_PARAMETER(dev);
memset(&sdev->hip, 0, sizeof(sdev->hip));
sdev->hip.sdev = sdev;
mutex_init(&sdev->hip.hip_mutex);
sdev->hip4_inst.hip_control = &test_hip_control;
return 0;
}
void slsi_hip_deinit(struct slsi_dev *sdev)
{
mutex_destroy(&sdev->hip.hip_mutex);
}
int slsi_hip_stop(struct slsi_dev *sdev)
{
return 0;
}
int scsc_wifi_transmit_frame(struct slsi_hip4 *hip, bool ctrl_packet, struct sk_buff *skb)
{
struct slsi_dev *sdev = container_of(hip, struct slsi_dev, hip4_inst);
slsi_log_clients_log_signal_fast(sdev, &sdev->log_clients, skb, SLSI_LOG_DIRECTION_FROM_HOST);
slsi_kfree_skb(skb);
return 0;
}
void slsi_test_bh_work_f(struct work_struct *work)
{
}
/* ALL Dummies to get UT build through goes below */
bool hip4_sampler_sample_q;
bool hip4_sampler_sample_qref;
bool hip4_sampler_sample_int;
bool hip4_sampler_sample_fapi;
bool hip4_sampler_sample_through;
bool hip4_sampler_sample_start_stop_q;
bool hip4_sampler_sample_mbulk;
bool hip4_sampler_sample_qfull;
bool hip4_sampler_sample_mfull;
bool hip4_sampler_vif;
bool hip4_sampler_bot;
bool hip4_sampler_pkt_tx;
void hip4_sampler_update_record(u32 minor, u8 param1, u8 param2, u8 param3, u8 param4)
{
}
void hip4_sampler_create(struct scsc_mx *mx)
{
}
void hip4_sampler_destroy(struct scsc_mx *mx)
{
}
int hip4_sampler_register_hip(struct scsc_mx *mx)
{
return 0;
}
int scsc_wifi_fcq_ctrl_q_init(struct scsc_wifi_fcq_ctrl_q *queue)
{
return 0;
}
void scsc_wifi_fcq_ctrl_q_deinit(struct scsc_wifi_fcq_ctrl_q *queue)
{
}
int scsc_wifi_fcq_unicast_qset_init(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, u8 qs_num, struct slsi_dev *sdev, u8 vif, struct slsi_peer *peer)
{
return 0;
}
int scsc_wifi_fcq_multicast_qset_init(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, struct slsi_dev *sdev, u8 vif)
{
return 0;
}
void scsc_wifi_fcq_qset_deinit(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, struct slsi_dev *sdev, u8 vif, struct slsi_peer *peer)
{
}
int scsc_wifi_fcq_transmit_data(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, u16 priority, struct slsi_dev *sdev, u8 vif, u8 peer_index)
{
return 0;
}
int scsc_wifi_fcq_receive_data(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, u16 priority, struct slsi_dev *sdev, u8 vif, u8 peer_index)
{
return 0;
}
int scsc_wifi_fcq_receive_data_no_peer(struct net_device *dev, u16 priority, struct slsi_dev *sdev, u8 vif, u8 peer_index)
{
return 0;
}
void scsc_wifi_fcq_pause_queues(struct slsi_dev *sdev)
{
}
void scsc_wifi_fcq_unpause_queues(struct slsi_dev *sdev)
{
}
int scsc_wifi_fcq_transmit_ctrl(struct net_device *dev, struct scsc_wifi_fcq_ctrl_q *queue)
{
return 0;
}
int scsc_wifi_fcq_receive_ctrl(struct net_device *dev, struct scsc_wifi_fcq_ctrl_q *queue)
{
return 0;
}
int scsc_wifi_fcq_update_smod(struct scsc_wifi_fcq_data_qset *qs, enum scsc_wifi_fcq_ps_state peer_ps_state,
enum scsc_wifi_fcq_queue_set_type type)
{
return 0;
}
int scsc_wifi_fcq_8021x_port_state(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, enum scsc_wifi_fcq_8021x_state state)
{
return 0;
}
int scsc_wifi_fcq_stat_queue(struct scsc_wifi_fcq_q_header *queue,
struct scsc_wifi_fcq_q_stat *queue_stat,
int *qmod, int *qcod)
{
return 0;
}
int scsc_wifi_fcq_stat_queueset(struct scsc_wifi_fcq_data_qset *queue_set,
struct scsc_wifi_fcq_q_stat *queue_stat,
int *smod, int *scod, enum scsc_wifi_fcq_8021x_state *cp_state,
u32 *peer_ps_state_transitions)
{
return 0;
}

View file

@ -0,0 +1,84 @@
/*****************************************************************************
*
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
*
****************************************************************************/
#include "dev.h"
#include "hydra.h"
#include "unittest.h"
#include "debug.h"
#include "hip_bh.h"
int slsi_sm_service_driver_register(void)
{
int csr_result;
csr_result = slsi_sdio_func_drv_register();
if (csr_result != 0) {
SLSI_ERR_NODEV("Failed to register the pretend SDIO function driver: csrResult=%d\n", csr_result);
return -EIO;
}
return 0;
}
void slsi_sm_service_driver_unregister(void)
{
slsi_sdio_func_drv_unregister();
}
void slsi_sm_service_failed(struct slsi_dev *sdev, const char *reason)
{
}
bool slsi_is_test_mode_enabled(void)
{
return false;
}
bool slsi_is_232338_test_mode_enabled(void)
{
return false;
}
int check_mcd_232338_rf_mode(void)
{
return 0;
}
int slsi_sm_wlan_service_start(struct slsi_dev *sdev)
{
return 0;
}
void slsi_sm_wlan_service_stop(struct slsi_dev *sdev)
{
}
void slsi_hydra_get_chip_info(struct hydra_service_info *chip_info)
{
strcpy(chip_info->ver_str, "java - unittest");
chip_info->hw_ver = 0xFFFF;
chip_info->fw_rom_ver = 0xFFFFFFFF;
chip_info->fw_patch_ver = 0xFFFFFFFF;
chip_info->populated = true;
}
int slsi_sm_wlan_service_open(struct slsi_dev *sdev)
{
return 0;
}
int mx140_file_request_conf(struct scsc_mx *mx, const struct firmware **conf, const char *config_rel_path)
{
return 0;
}
void mx140_file_release_conf(struct scsc_mx *mx, const struct firmware *conf)
{
}
void slsi_sm_wlan_service_close(struct slsi_dev *sdev)
{
}

View file

@ -0,0 +1,632 @@
/****************************************************************************
*
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
*
****************************************************************************/
#include <linux/sysfs.h>
#include <linux/poll.h>
#include <linux/cdev.h>
#include "dev.h"
#include "hip.h"
#include "log_clients.h"
#include "debug.h"
#include "unittest.h"
#include "udi.h"
#include "unifiio.h"
#define UDI_CHAR_DEVICE_NAME "s5e7570unittesthip"
#define UDI_CLASS_NAME "s5e7570unittesthip"
/**
* Control character device for debug
* ==================================
*/
#define NUM_CHAR_CLIENTS 1 /* Number of client programmes on one node. */
#define MAX_MINOR (SLSI_UDI_MINOR_NODES - 1) /* Maximum node number. */
static dev_t major_number; /* Major number of device created by system. */
static struct class *class; /* Device class. */
struct slsi_test_cdev_client;
struct slsi_cdev {
int minor;
struct cdev cdev;
struct slsi_test_cdev_client *client[NUM_CHAR_CLIENTS];
struct slsi_test_dev *uftestdev;
struct device *parent;
};
struct slsi_test_cdev_client {
struct slsi_cdev *ufcdev;
int log_enabled;
/* Flags set for special filtering of ma_packet data */
u16 ma_packet_filter_config;
struct sk_buff_head log_list;
wait_queue_head_t log_wq;
};
/**
* One minor node per phy. In normal driver mode, this may be one.
* In unit test mode, this may be several.
*/
static struct slsi_cdev *uf_cdevs[SLSI_UDI_MINOR_NODES];
static int udi_log_event(struct slsi_log_client *log_client, struct sk_buff *skb, int dir);
static int send_signal_to_log_filter(struct slsi_log_client *log_client, struct sk_buff *skb, int dir);
static int send_signal_to_inverse_log_filter(struct slsi_log_client *log_client, struct sk_buff *skb, int dir);
static int slsi_test_cdev_open(struct inode *inode, struct file *file)
{
struct slsi_cdev *uf_cdev;
struct slsi_test_cdev_client *client;
int indx;
int minor;
minor = iminor(inode);
if (minor > MAX_MINOR) {
SLSI_ERR_NODEV("minor %d exceeds range\n", minor);
return -EINVAL;
}
uf_cdev = uf_cdevs[minor];
if (!uf_cdev) {
SLSI_ERR_NODEV("no cdev instance for minor %d\n", minor);
return -EINVAL;
}
if (!uf_cdev->uftestdev) {
SLSI_ERR_NODEV("uftestdev not set\n");
return -EINVAL;
}
for (indx = 0; indx < NUM_CHAR_CLIENTS; indx++)
if (uf_cdev->client[indx] == NULL)
break;
if (indx >= NUM_CHAR_CLIENTS) {
SLSI_ERR_NODEV("already opened\n");
return -ENOTSUPP;
}
client = kmalloc(sizeof(*client), GFP_KERNEL);
if (client == NULL)
return -ENOMEM;
memset(client, 0, sizeof(struct slsi_test_cdev_client));
/* init other resource */
skb_queue_head_init(&client->log_list);
init_waitqueue_head(&client->log_wq);
client->ufcdev = uf_cdev;
uf_cdev->client[indx] = client;
file->private_data = client;
slsi_test_dev_attach(client->ufcdev->uftestdev);
return 0;
}
static int slsi_test_cdev_release(struct inode *inode, struct file *filp)
{
struct slsi_test_cdev_client *client = (void *)filp->private_data;
struct slsi_cdev *uf_cdev;
int indx;
int minor;
minor = iminor(inode);
if (minor > MAX_MINOR) {
SLSI_ERR_NODEV("minor %d exceeds range\n", minor);
return -EINVAL;
}
uf_cdev = uf_cdevs[minor];
if (!uf_cdev) {
SLSI_ERR_NODEV("no cdev instance for minor %d\n", minor);
return -EINVAL;
}
if (client == NULL)
return -EINVAL;
if (!client->ufcdev) {
SLSI_ERR_NODEV("ufcdev not set\n");
return -EINVAL;
}
if (!client->ufcdev->uftestdev) {
SLSI_ERR_NODEV("uftestdev not set\n");
return -EINVAL;
}
for (indx = 0; indx < NUM_CHAR_CLIENTS; indx++)
if (uf_cdev->client[indx] == client)
break;
if (indx >= NUM_CHAR_CLIENTS) {
SLSI_ERR_NODEV("client not found in list\n");
return -EINVAL;
}
if (waitqueue_active(&client->log_wq))
wake_up_interruptible(&client->log_wq);
if (client->log_enabled && client->ufcdev->uftestdev->sdev)
slsi_log_client_unregister(client->ufcdev->uftestdev->sdev, client);
slsi_test_dev_detach(client->ufcdev->uftestdev);
slsi_skb_queue_purge(&client->log_list);
/* free other resource */
kfree(client);
uf_cdev->client[indx] = NULL;
return 0;
}
static ssize_t slsi_test_cdev_read(struct file *filp, char *p, size_t len, loff_t *poff)
{
struct slsi_test_cdev_client *client = (void *)filp->private_data;
int msglen;
struct sk_buff *skb;
SLSI_UNUSED_PARAMETER(poff);
if (client == NULL)
return -EINVAL;
if (!skb_queue_len(&client->log_list)) {
if (filp->f_flags & O_NONBLOCK)
return 0;
/* wait until getting a signal */
if (wait_event_interruptible(client->log_wq, skb_queue_len(&client->log_list)))
return -ERESTARTSYS;
}
skb = slsi_skb_dequeue(&client->log_list);
msglen = skb->len;
if (msglen > (s32)len) {
SLSI_WARN_NODEV("truncated read to %d actual msg len is %lu\n", msglen, (unsigned long int)len);
msglen = len;
}
SLSI_DBG_HEX_NODEV(SLSI_TEST, skb->data, skb->len, "cdev read skb:%p skb->data:%p\n", skb, skb->data);
if (copy_to_user(p, skb->data, msglen)) {
SLSI_ERR_NODEV("Failed to copy UDI log to user\n");
slsi_kfree_skb(skb);
return -EFAULT;
}
slsi_kfree_skb(skb);
return msglen;
}
static ssize_t slsi_test_cdev_write(struct file *filp, const char *p, size_t len, loff_t *poff)
{
struct slsi_test_cdev_client *client;
struct slsi_test_dev *uftestdev;
struct sk_buff *skb;
struct slsi_skb_cb *cb;
u8 *data;
SLSI_UNUSED_PARAMETER(poff);
client = (void *)filp->private_data;
if (client == NULL) {
SLSI_ERR_NODEV("filep private data not set\n");
return -EINVAL;
}
if (!client->ufcdev) {
SLSI_ERR_NODEV("ufcdev not set\n");
return -EINVAL;
}
uftestdev = client->ufcdev->uftestdev;
if (!uftestdev) {
SLSI_ERR_NODEV("uftestdev not set\n");
return -EINVAL;
}
skb = slsi_alloc_skb(len, GFP_KERNEL);
data = skb_put(skb, len);
if (copy_from_user(data, p, len)) {
SLSI_ERR_NODEV("copy from user failed\n");
slsi_kfree_skb(skb);
return -EFAULT;
}
if (skb->len < sizeof(struct fapi_signal_header)) {
SLSI_ERR_NODEV("Data(%d) too short for a signal\n", skb->len);
slsi_kfree_skb(skb);
return -EINVAL;
}
SLSI_DBG_HEX_NODEV(SLSI_TEST, skb->data, skb->len, "cdev write skb:%p skb->data:%p\n", skb, skb->data);
/* Intercept some requests */
if (slsi_test_process_signal(uftestdev, skb))
return len;
{
struct slsi_dev *sdev;
sdev = uftestdev->sdev;
if (!sdev) {
SLSI_ERR_NODEV("sdev not set\n");
slsi_kfree_skb(skb);
return -EINVAL;
}
cb = slsi_skb_cb_init(skb);
cb->sig_length = fapi_get_expected_size(skb);
cb->data_length = skb->len;
if (WARN_ON(slsi_hip_rx(sdev, skb))) {
slsi_kfree_skb(skb);
return -EINVAL;
}
}
return len;
}
static long slsi_test_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct slsi_test_cdev_client *client = (void *)filp->private_data;
struct slsi_test_dev *uftestdev;
struct slsi_dev *sdev;
long r = 0;
int int_param;
if (client == NULL || client->ufcdev == NULL)
return -EINVAL;
uftestdev = client->ufcdev->uftestdev;
if (!uftestdev) {
SLSI_ERR_NODEV("uftestdev not set\n");
return -EINVAL;
}
sdev = uftestdev->sdev;
if (!sdev) {
SLSI_ERR_NODEV("sdev not set\n");
return -EINVAL;
}
FUNC_ENTER_NODEV();
slsi_wakelock(&sdev->wlan_wl);
switch (cmd) {
case UNIFI_GET_UDI_ENABLE:
int_param = client->log_enabled;
put_user(int_param, (int *)arg);
break;
case UNIFI_SET_UDI_ENABLE:
if (get_user(int_param, (int *)arg)) {
r = -EFAULT;
break;
}
if (int_param) {
slsi_log_client_register(sdev, client, udi_log_event, NULL, 0, 0);
client->log_enabled = 1;
} else {
slsi_log_client_unregister(sdev, client);
client->log_enabled = 0;
}
break;
case UNIFI_SET_UDI_LOG_MASK:
{
struct unifiio_filter_t filter;
int i;
/* to minimise load on data path, list is converted here to array indexed by signal number */
if (copy_from_user(&filter, (void *)arg, sizeof(filter))) {
SLSI_ERR(sdev, "UNIFI_SET_UDI_LOG_MASK: Failed to copy from userspace\n");
r = -EFAULT;
break;
}
if (filter.signal_ids_n) {
char *signal_filter_index;
int max;
int min;
int size = filter.signal_ids_n * sizeof(filter.signal_ids[0]);
u16 *signal_ids = kmalloc(size, GFP_KERNEL);
if (!signal_ids) {
r = -ENOMEM;
break;
}
max = signal_ids[0];
min = signal_ids[0];
if (copy_from_user(signal_ids, filter.signal_ids, size)) {
SLSI_ERR(sdev, "UNIFI_SET_UDI_LOG_MASK: Failed to copy filter from userspace\n");
kfree(signal_ids);
r = -EFAULT;
break;
}
/* find maximum and minimum signal id in filter */
for (i = 0; i < filter.signal_ids_n; i++) {
if (signal_ids[i] & UDI_MA_UNITDATA_FILTER_ALLOW_MASK) {
client->ma_packet_filter_config |= signal_ids[i];
continue;
}
if (signal_ids[i] > max)
max = signal_ids[i];
else if (signal_ids[i] < min)
min = signal_ids[i];
}
/* and create array only big enough to index the range of signal id specified */
signal_filter_index = kmalloc(max - min + 1, GFP_KERNEL);
if (signal_filter_index) {
memset(signal_filter_index, 0, max - min + 1);
for (i = 0; i < filter.signal_ids_n; i++) {
if (signal_ids[i] & UDI_MA_UNITDATA_FILTER_ALLOW_MASK)
continue;
signal_filter_index[signal_ids[i] - min] = 1;
}
slsi_log_client_unregister(sdev, client);
slsi_log_client_register(sdev, client,
filter.log_listed_flag ? send_signal_to_inverse_log_filter :
send_signal_to_log_filter, signal_filter_index, min, max);
} else {
r = -ENOMEM;
}
kfree(signal_ids);
}
break;
}
default:
SLSI_WARN(sdev, "Operation (%d) not supported\n", cmd);
r = -EINVAL;
}
slsi_wakeunlock(&sdev->wlan_wl);
return r;
}
static unsigned int slsi_test_cdev_poll(struct file *filp, poll_table *wait)
{
struct slsi_test_cdev_client *client = (void *)filp->private_data;
unsigned int mask = 0;
int ready;
ready = skb_queue_len(&client->log_list);
poll_wait(filp, &client->log_wq, wait);
if (ready)
mask |= POLLIN | POLLRDNORM; /* readable */
return mask;
}
/* we know for sure that there is a filter present in log_client->signal_filter if this function is called.
* we know this because it is called only through a function pointer that is assigned
* only when a filter is also set up in the log_client
*/
static int send_signal_to_log_filter(struct slsi_log_client *log_client, struct sk_buff *skb, int dir)
{
int ret = 0;
u16 signal_id = fapi_get_u16(skb, id);
if (signal_id > log_client->max_signal_id || signal_id < log_client->min_signal_id || !log_client->signal_filter[signal_id - log_client->min_signal_id])
ret = udi_log_event(log_client, skb, dir);
return ret;
}
static int send_signal_to_inverse_log_filter(struct slsi_log_client *log_client, struct sk_buff *skb, int dir)
{
int ret = 0;
u16 signal_id = fapi_get_u16(skb, id);
if (signal_id <= log_client->max_signal_id && signal_id >= log_client->min_signal_id && log_client->signal_filter[signal_id - log_client->min_signal_id])
ret = udi_log_event(log_client, skb, dir);
return ret;
}
static int udi_log_event(struct slsi_log_client *log_client, struct sk_buff *skb, int dir)
{
struct slsi_test_cdev_client *client = log_client->log_client_ctx;
struct udi_msg_t msg;
struct udi_msg_t *msg_skb;
if (WARN_ON(client == NULL))
return -EINVAL;
if (WARN_ON(skb == NULL))
return -EINVAL;
if (WARN_ON(skb->len == 0))
return -EINVAL;
skb = slsi_skb_copy_expand(skb, sizeof(msg), 0, GFP_ATOMIC);
if (WARN_ON(!skb))
return -ENOMEM;
/* Intercept some requests */
if (slsi_test_process_signal(client->ufcdev->uftestdev, skb))
return -ECANCELED;
if (WARN_ON(skb_headroom(skb) < sizeof(msg)))
return -ENOMEM;
msg.length = sizeof(msg) + skb->len;
msg.timestamp = jiffies_to_msecs(jiffies);
msg.direction = dir;
msg.signal_length = fapi_get_siglen(skb);
msg_skb = (struct udi_msg_t *)skb_push(skb, sizeof(msg));
*msg_skb = msg;
slsi_skb_queue_tail(&client->log_list, skb);
/* Wake any waiting user process */
wake_up_interruptible(&client->log_wq);
return 0;
}
#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \
device_create(_class, _parent, _devno, _priv, _fmt, _args)
static const struct file_operations slsi_test_cdev_fops = {
.owner = THIS_MODULE,
.open = slsi_test_cdev_open,
.release = slsi_test_cdev_release,
.read = slsi_test_cdev_read,
.write = slsi_test_cdev_write,
.unlocked_ioctl = slsi_test_cdev_ioctl,
.compat_ioctl = slsi_test_cdev_ioctl,
.poll = slsi_test_cdev_poll,
};
#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \
device_create(_class, _parent, _devno, _priv, _fmt, _args)
static int slsi_get_minor(void)
{
int minor;
for (minor = 0; minor < SLSI_UDI_MINOR_NODES; minor++)
if (uf_cdevs[minor] == 0)
return minor;
return -1;
}
static int slsi_test_cdev_create(struct slsi_test_dev *uftestdev, struct device *parent)
{
dev_t devno;
int ret;
struct slsi_cdev *pdev;
int minor;
FUNC_ENTER_NODEV();
minor = slsi_get_minor();
if (minor < 0) {
SLSI_ERR_NODEV("no minor numbers available\n");
return -ENOMEM;
}
pdev = kmalloc(sizeof(*pdev), GFP_KERNEL);
if (pdev == NULL)
return -ENOMEM;
memset(pdev, 0, sizeof(*pdev));
cdev_init(&pdev->cdev, &slsi_test_cdev_fops);
pdev->cdev.owner = THIS_MODULE;
pdev->minor = minor;
devno = MKDEV(MAJOR(major_number), minor);
ret = cdev_add(&pdev->cdev, devno, 1);
if (ret) {
SLSI_ERR_NODEV("cdev_add failed with %d for minor %d\n", ret, minor);
kfree(pdev);
return ret;
}
pdev->uftestdev = uftestdev;
pdev->parent = parent;
if (!UF_DEVICE_CREATE(class, pdev->parent, devno, pdev, UDI_CHAR_DEVICE_NAME "%d", minor)) {
cdev_del(&pdev->cdev);
kfree(pdev);
return -EINVAL;
}
uftestdev->uf_cdev = (void *)pdev;
uftestdev->device_minor_number = minor;
uf_cdevs[minor] = pdev;
return 0;
}
static void slsi_test_cdev_destroy(struct slsi_test_dev *uftestdev)
{
struct slsi_cdev *pdev = (struct slsi_cdev *)uftestdev->uf_cdev;
FUNC_ENTER_NODEV();
if (!pdev)
return;
device_destroy(class, pdev->cdev.dev);
cdev_del(&pdev->cdev);
uftestdev->uf_cdev = 0;
uf_cdevs[pdev->minor] = 0;
kfree(pdev);
}
static int udi_initialised;
int slsi_test_udi_init(void)
{
int ret;
memset(uf_cdevs, 0, sizeof(uf_cdevs));
/* Allocate two device numbers for each device. */
ret = alloc_chrdev_region(&major_number, 0, SLSI_UDI_MINOR_NODES, UDI_CLASS_NAME);
if (ret) {
SLSI_ERR_NODEV("Failed to add alloc dev numbers: %d\n", ret);
return ret;
}
/* Create a UniFi class */
class = class_create(THIS_MODULE, UDI_CLASS_NAME);
if (IS_ERR(class)) {
SLSI_ERR_NODEV("Failed to create UniFi class\n");
unregister_chrdev_region(major_number, SLSI_UDI_MINOR_NODES);
major_number = 0;
return -EINVAL;
}
udi_initialised = 1;
return 0;
}
int slsi_test_udi_deinit(void)
{
if (!udi_initialised)
return -1;
class_destroy(class);
unregister_chrdev_region(major_number, SLSI_UDI_MINOR_NODES);
udi_initialised = 0;
return 0;
}
int slsi_test_udi_node_init(struct slsi_test_dev *uftestdev, struct device *parent)
{
FUNC_ENTER_NODEV();
if (!udi_initialised)
return -1;
return slsi_test_cdev_create(uftestdev, parent);
}
int slsi_test_udi_node_reregister(struct slsi_test_dev *uftestdev)
{
struct slsi_cdev *pdev = uftestdev->uf_cdev;
int indx;
if (uftestdev->sdev)
for (indx = 0; indx < NUM_CHAR_CLIENTS; indx++)
if (pdev->client[indx] != NULL && pdev->client[indx]->log_enabled)
slsi_log_client_register(uftestdev->sdev, pdev->client[indx], udi_log_event, NULL, 0, 0);
return 0;
}
int slsi_test_udi_node_deinit(struct slsi_test_dev *uftestdev)
{
FUNC_ENTER_NODEV();
if (!udi_initialised)
return -1;
slsi_test_cdev_destroy(uftestdev);
return 0;
}

View file

@ -0,0 +1,129 @@
/****************************************************************************
*
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
*
****************************************************************************/
#ifndef __SLSI_UNITTEST_H__
#define __SLSI_UNITTEST_H__
#include "dev.h"
struct slsi_test_dev;
struct slsi_test_bh_work {
bool available;
struct slsi_test_dev *uftestdev;
struct workqueue_struct *workqueue;
struct work_struct work;
struct slsi_spinlock spinlock;
};
struct slsi_test_data_route {
bool configured;
u16 test_device_minor_number; /* index into slsi_test_devices[] */
u8 mac[ETH_ALEN];
u16 vif;
u8 ipsubnet;
u16 sequence_number;
};
struct slsi_test_dev {
/* This is used for:
* 1) The uf6kunittesthip<n> chardevice number
* 2) The uf6kunittest<n> chardevice number
* 3) The /procf/devices/unifi<n> number
*/
int device_minor_number;
void *uf_cdev;
struct device *dev;
struct slsi_dev *sdev;
struct workqueue_struct *attach_detach_work_queue;
/* a std mutex */
struct mutex attach_detach_mutex;
struct work_struct attach_work;
struct work_struct detach_work;
bool attached;
u8 hw_addr[ETH_ALEN];
struct slsi_test_bh_work bh_work;
/* a std spinlock */
spinlock_t route_spinlock;
struct slsi_test_data_route route[SLSI_AP_PEER_CONNECTIONS_MAX];
};
void slsi_test_dev_attach(struct slsi_test_dev *uftestdev);
void slsi_test_dev_detach(struct slsi_test_dev *uftestdev);
bool slsi_test_process_signal(struct slsi_test_dev *uftestdev, struct sk_buff *skb);
int slsi_test_udi_node_init(struct slsi_test_dev *uftestdev, struct device *parent);
int slsi_test_udi_node_reregister(struct slsi_test_dev *uftestdev);
int slsi_test_udi_node_deinit(struct slsi_test_dev *uftestdev);
int slsi_test_udi_init(void);
int slsi_test_udi_deinit(void);
void slsi_test_bh_work_f(struct work_struct *work);
static inline int slsi_test_bh_init(struct slsi_test_dev *uftestdev)
{
uftestdev->bh_work.available = false;
uftestdev->bh_work.uftestdev = uftestdev;
slsi_spinlock_create(&uftestdev->bh_work.spinlock);
INIT_WORK(&uftestdev->bh_work.work, slsi_test_bh_work_f);
uftestdev->bh_work.workqueue = alloc_ordered_workqueue("slsi_wlan_unittest_bh", 0);
if (!uftestdev->bh_work.workqueue)
return -ENOMEM;
uftestdev->bh_work.available = true;
return 0;
}
static inline void slsi_test_bh_start(struct slsi_test_dev *uftestdev)
{
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
uftestdev->bh_work.available = true;
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
}
static inline void slsi_test_bh_run(struct slsi_test_dev *uftestdev)
{
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
if (!uftestdev->bh_work.available)
goto exit;
queue_work(uftestdev->bh_work.workqueue, &uftestdev->bh_work.work);
exit:
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
}
static inline void slsi_test_bh_stop(struct slsi_test_dev *uftestdev)
{
struct workqueue_struct *workqueue = NULL;
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
uftestdev->bh_work.available = false;
workqueue = uftestdev->bh_work.workqueue;
uftestdev->bh_work.workqueue = NULL;
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
if (workqueue)
flush_workqueue(workqueue);
}
static inline void slsi_test_bh_deinit(struct slsi_test_dev *uftestdev)
{
struct workqueue_struct *workqueue = NULL;
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
WARN_ON(uftestdev->bh_work.available);
uftestdev->bh_work.available = false;
workqueue = uftestdev->bh_work.workqueue;
uftestdev->bh_work.workqueue = NULL;
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
if (workqueue) {
flush_workqueue(workqueue);
destroy_workqueue(workqueue);
}
}
#endif