blob: c8f25e46b461bdcbc3949845837f572f0a7eda7c [file]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*******************************************************************************
* C O M P I L E R F L A G S
********************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <net/genetlink.h>
#include "precomp.h"
#if CFG_SUPPORT_CUSTOM_NETLINK
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
#define MAX_BIND_PROCESS (1)
#define GL_CUSTOM_FAMILY_NAME "WIFI_NL_CUSTOM"
#define MAX_CUSTOM_PKT_LENGTH (2048)
enum {
__GL_CUSTOM_ATTR_INVALID,
GL_CUSTOM_ATTR_MSG, /* message */
__GL_CUSTOM_ATTR_MAX,
};
#define GL_CUSTOM_ATTR_MAX (__GL_CUSTOM_ATTR_MAX - 1)
enum {
__GL_CUSTOM_COMMAND_INVALID,
GL_CUSTOM_COMMAND_BIND, /* bind */
GL_CUSTOM_COMMAND_SEND, /* user -> kernel */
GL_CUSTOM_COMMAND_RECV, /* kernel -> user */
__GL_CUSTOM_COMMAND_MAX,
};
#define GL_CUSTOM_COMMAND_MAX (__GL_CUSTOM_COMMAND_MAX - 1)
#if CFG_SUPPORT_TX_BEACON_STA_MODE
#define CUSTOM_BEACON_TYPE (0x80)
#endif
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
static int32_t glCustomGenlBind(
struct sk_buff *skb, struct genl_info *info);
static int32_t glCustomRecvFromUplayer(
struct sk_buff *skb, struct genl_info *info);
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
static struct genl_family glCustomGenlFamily = {
.id = GENL_ID_GENERATE,
.hdrsize = 0,
.name = GL_CUSTOM_FAMILY_NAME,
.version = 1,
.maxattr = GL_CUSTOM_ATTR_MAX,
};
/* attribute policy */
static struct nla_policy glCustomGenlPolicy[GL_CUSTOM_ATTR_MAX + 1] = {
[GL_CUSTOM_ATTR_MSG] = {.type = NLA_NUL_STRING},
};
/* operation definition */
static struct genl_ops glCustomGenlOpsArray[] = {
{
.cmd = GL_CUSTOM_COMMAND_BIND,
.flags = 0,
.policy = glCustomGenlPolicy,
.doit = glCustomGenlBind,
.dumpit = NULL,
},
{
.cmd = GL_CUSTOM_COMMAND_SEND,
.flags = 0,
.policy = glCustomGenlPolicy,
.doit = glCustomRecvFromUplayer,
.dumpit = NULL,
},
};
int32_t gBindProcessNum;
pid_t gBindPid;
uint8_t gScanIEBuf[MAX_IE_LENGTH];
uint32_t gScanIELen;
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
void glCustomGenlInit(void)
{
if (genl_register_family_with_ops(&glCustomGenlFamily,
glCustomGenlOpsArray) != 0)
DBGLOG(INIT, ERROR,
"%s(): GE_NELINK family registration fail\n",
__func__);
}
void glCustomGenlDeinit(void)
{
genl_unregister_family(&glCustomGenlFamily);
}
static int32_t glCustomGenlBind(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *na;
int8_t *pData = NULL;
DBGLOG(INIT, ERROR, "%s(): ->\n", __func__);
if (info == NULL)
return -1;
na = info->attrs[GL_CUSTOM_ATTR_MSG];
if (na)
pData = (int8_t *) nla_data(na);
if (strcmp(pData, "BIND") == 0) {
if (gBindProcessNum < MAX_BIND_PROCESS) {
gBindPid = info->snd_portid;
gBindProcessNum++;
DBGLOG(INIT, ERROR,
"%s():-> pid = %d\n",
__func__, info->snd_portid);
} else {
gBindPid = info->snd_portid;
DBGLOG(INIT, ERROR,
"%s(): exceeding binding limit %d\n",
__func__, MAX_BIND_PROCESS);
}
} else if (strcmp(pData, "UNBIND") == 0) {
if (gBindProcessNum == 1) {
gBindPid = 0;
gBindProcessNum--;
DBGLOG(INIT, ERROR,
"%s():-> pid = %d unbind\n",
__func__, info->snd_portid);
} else {
DBGLOG(INIT, ERROR,
"%s(): unbinding error %d\n",
__func__, gBindProcessNum);
}
} else {
DBGLOG(INIT, ERROR,
"%s(): Unknown cmd %s\n",
__func__, pData);
}
return 0;
}
#if CFG_SUPPORT_TX_BEACON_STA_MODE
static uint32_t glCustomBeaconTxDone(IN struct ADAPTER *prAdapter,
IN struct MSDU_INFO *prMsduInfo,
IN enum ENUM_TX_RESULT_CODE rTxDoneStatus)
{
do {
ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL));
DBGLOG(TX, WARN,
"glCustomBeaconTxDone: Status: %d, seq NO. %d\n",
rTxDoneStatus, prMsduInfo->ucTxSeqNum);
} while (FALSE);
return WLAN_STATUS_SUCCESS;
}
static uint32_t glCustomSendBeacon(void *probe_resp, uint32_t resp_len)
{
struct ADAPTER *prAdapter;
struct MSDU_INFO *prMsduInfo;
struct GLUE_INFO *prGlueInfo = NULL;
prGlueInfo = wlanGetGlueInfo();
if (!prGlueInfo) {
DBGLOG(INIT, ERROR, "No glue info\n");
return WLAN_STATUS_FAILURE;
}
prAdapter = prGlueInfo->prAdapter;
/* 4 <1> Allocate a PKT_INFO_T for Probe Response Frame */
/* Allocate a MSDU_INFO_T */
prMsduInfo = cnmMgtPktAlloc(prAdapter, resp_len);
if (prMsduInfo == NULL) {
DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Custom Frame\n");
return WLAN_STATUS_RESOURCES;
}
/* 4 <2> Compose Probe Response frame header */
/* and fixed fields in MSDU_INfO_T. */
/* Compose Header and Fixed Field */
memcpy((int8_t *)prMsduInfo->prPacket, (int8_t *)probe_resp, resp_len);
/* 4 <3> Update information of MSDU_INFO_T */
nicTxSetMngPacket(prAdapter, prMsduInfo, 0,
0xFF, WLAN_MAC_MGMT_HEADER_LEN,
resp_len, glCustomBeaconTxDone,
MSDU_RATE_MODE_LOWEST_RATE);
nicTxConfigPktControlFlag(prMsduInfo,
MSDU_CONTROL_FLAG_FORCE_TX, TRUE);
DBGLOG(TX, WARN, "glCustomSendBeacon seq NO %d\n",
prMsduInfo->ucTxSeqNum);
/* 4 <6> Inform TXM to send this Beacon /Probe Response frame. */
nicTxEnqueueMsdu(prAdapter, prMsduInfo);
return WLAN_STATUS_SUCCESS;
}
#endif
static int32_t glCustomRecvFromUplayer(
struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *na;
int8_t *pData = NULL;
int32_t u4DataLen = 0;
if (info == NULL)
goto out;
na = info->attrs[GL_CUSTOM_ATTR_MSG];
if (na) {
pData = (int8_t *) nla_data(na);
u4DataLen = nla_len(na);
}
DBGLOG(INIT, TRACE, "glCustomRecvFromUplayer len=%d, data[0]=0x%2x\n",
u4DataLen, (uint8_t)pData[0]);
#if CFG_SUPPORT_TX_BEACON_STA_MODE
if ((uint8_t)pData[0] == CUSTOM_BEACON_TYPE)
glCustomSendBeacon(pData, u4DataLen);
#endif
out:
return 0;
}
#endif /* CFG_CUSTOM_NETLINK_SUPPORT */