blob: dd30b514414ada3fa77839109d351f8bba02973f [file] [log] [blame]
/*
* wl natoe command module
*
* Broadcom Proprietary and Confidential. Copyright (C) 2017,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties, copied
* or duplicated in any form, in whole or in part, without the prior
* written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*
* $Id: wluc_natoe.c 625864 2016-03-18 00:12:54Z $
*/
#include <wlioctl.h>
#include <bcmendian.h>
#include "wlu_common.h"
#include "wlu.h"
static cmd_func_t wl_natoe_control;
typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
typedef int (natoe_cmd_handler_t)(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
struct wl_natoe_sub_cmd {
char *name;
uint8 version; /* cmd version */
uint16 id; /* id for the dongle f/w switch/case */
uint16 type; /* base type of argument */
natoe_cmd_handler_t *handler; /* cmd handler */
};
#define NATOE_PARAMS_USAGE \
"\tUsage: wl natoe [command] [cmd options] as follows:\n" \
"\t\twl natoe enable [1/0] - enable disable natoe functionality\n" \
"\t\twl natoe config_ips [sta ip][sta netmask][default router][sta dns]\n" \
"\t\t\t[ap ip][ap netmask]\n" \
"\t\twl natoe config_ports [starting port number][no of ports]\n" \
"\t\twl natoe stats [0] - 0 to clear stats\n" \
"\t\twl natoe tbl_cnt [no_tbl_entries]\n"
#define WL_NATOE_CMD "natoe"
#define WL_NATOE_MAX_PORT_NUM 65535
#define WL_NATOE_SUBCMD_ENABLE_ARGC 1
#define WL_NATOE_SUBCMD_CONFIG_IPS_ARGC 6
#define WL_NATOE_SUBCMD_CONFIG_PORTS_ARGC 2
#define WL_NATOE_SUBCMD_DBG_STATS_ARGC 1
#define WL_NATOE_SUBCMD_TBL_CNT_ARGC 1
#define WL_NATOE_FUNC(suffix) wl_natoe_subcmd_ ##suffix
static int wl_natoe_subcmd_enable(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
static int wl_natoe_subcmd_config_ips(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
static int wl_natoe_subcmd_config_ports(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
static int wl_natoe_subcmd_dbg_stats(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
static int wl_natoe_subcmd_tbl_cnt(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
static cmd_t wl_natoe_cmds[] = {
{ WL_NATOE_CMD, wl_natoe_control, WLC_GET_VAR, WLC_SET_VAR,
"superfunction for natoe commands \n\n"
NATOE_PARAMS_USAGE},
{ NULL, NULL, 0, 0, NULL }
};
static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
/* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
{"enable", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_ENABLE,
IOVT_BUFFER, WL_NATOE_FUNC(enable)
},
{"config_ips", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_CONFIG_IPS,
IOVT_BUFFER, WL_NATOE_FUNC(config_ips)
},
{"config_ports", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_CONFIG_PORTS,
IOVT_BUFFER, WL_NATOE_FUNC(config_ports)
},
{"stats", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_DBG_STATS,
IOVT_BUFFER, WL_NATOE_FUNC(dbg_stats)
},
{"tbl_cnt", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_TBL_CNT,
IOVT_BUFFER, WL_NATOE_FUNC(tbl_cnt)
},
{NULL, 0, 0, 0, NULL}
};
void
wluc_natoe_module_init(void)
{
/* register natoe commands */
wl_module_cmds_register(wl_natoe_cmds);
}
static int
wlu_natoe_set_vars_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
{
int res = BCME_OK;
UNUSED_PARAMETER(ctx);
UNUSED_PARAMETER(len);
switch (type) {
case WL_NATOE_XTLV_ENABLE:
{
printf("natoe: %s\n", *data?"enabled":"disabled");
break;
}
case WL_NATOE_XTLV_CONFIG_IPS:
{
wl_natoe_config_ips_t *config_ips;
config_ips = (wl_natoe_config_ips_t *)data;
printf("sta ip: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->sta_ip));
printf("sta netmask: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->sta_netmask));
printf("sta router ip: %s\n",
wl_iptoa((struct ipv4_addr *)&config_ips->sta_router_ip));
printf("sta dns ip: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->sta_dnsip));
printf("ap ip: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->ap_ip));
printf("ap netmask: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->ap_netmask));
break;
}
case WL_NATOE_XTLV_CONFIG_PORTS:
{
wl_natoe_ports_config_t *ports_config;
ports_config = (wl_natoe_ports_config_t *)data;
printf("starting port num: %d\n", dtoh16(ports_config->start_port_num));
printf("number of ports: %d\n", dtoh16(ports_config->no_of_ports));
break;
}
case WL_NATOE_XTLV_DBG_STATS:
{
char *stats_dump = ((char *)data);
printf("%s\n", stats_dump);
break;
}
case WL_NATOE_XTLV_TBL_CNT:
{
printf("natoe max table entries count: %d\n", dtoh32(*(uint32 *)data));
break;
}
default:
/* ignore */
break;
}
return res;
}
static int
wl_natoe_get_stats(void *wl, wl_natoe_ioc_t *natoe_ioc, uint16 iocsz)
{
/* for gets we only need to pass ioc header */
wl_natoe_ioc_t *iocresp = NULL;
int res;
int iocresp_sz = sizeof(*iocresp) + WL_NATOE_DBG_STATS_BUFSZ;
/* send getbuf natoe iovar */
iocresp = calloc(1, iocresp_sz);
if (iocresp == NULL) {
return BCME_NOMEM;
}
res = wlu_iovar_getbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz,
(void *)iocresp, iocresp_sz);
/* check the response buff */
if (res == BCME_OK) {
/* scans ioctl tlvbuf f& invokes the cbfn for processing */
res = bcm_unpack_xtlv_buf(natoe_ioc, iocresp->data, iocresp->len,
BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
}
free(iocresp);
return res;
}
/*
* --- common for all natoe get commands except for stats ----
*/
static int
wl_natoe_get_ioctl(void *wl, wl_natoe_ioc_t *natoe_ioc, uint16 iocsz)
{
/* for gets we only need to pass ioc header */
wl_natoe_ioc_t *iocresp = NULL;
int res;
/* send getbuf natoe iovar */
res = wlu_var_getbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz, (void *)&iocresp);
/* check the response buff */
if ((res == BCME_OK) && (iocresp != NULL)) {
/* scans ioctl tlvbuf f& invokes the cbfn for processing */
res = bcm_unpack_xtlv_buf(natoe_ioc, iocresp->data, iocresp->len,
BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
}
return res;
}
static int
wl_natoe_subcmd_enable(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
{
int res = BCME_OK;
wl_natoe_ioc_t *natoe_ioc;
uint16 buflen, buflen_at_start;
uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
bcm_xtlv_t *pxtlv = NULL;
/* alloc mem for ioctl headr + tlv data */
natoe_ioc = calloc(1, iocsz);
if (natoe_ioc == NULL) {
return BCME_NOMEM;
}
/* make up natoe cmd ioctl header */
natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
natoe_ioc->id = htod16(cmd->id);
natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
if(*argv == NULL) { /* get */
iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
res = wl_natoe_get_ioctl(wl, natoe_ioc, iocsz);
} else { /* set */
/* max tlv data we can write, it will be decremented as we pack */
uint8 val;
if (ARGCNT(argv) != WL_NATOE_SUBCMD_ENABLE_ARGC) {
res = BCME_USAGE_ERROR;
goto exit;
}
val = atoi(*argv);
buflen = WL_NATOE_IOC_BUFSZ;
/* save buflen at start */
buflen_at_start = buflen;
/* we'll adjust final ioc size at the end */
res = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
if (res != BCME_OK) {
goto exit;
}
/* adjust iocsz to the end of last data record */
natoe_ioc->len = (buflen_at_start - buflen);
iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
}
exit:
free(natoe_ioc);
return res;
}
static int
wl_natoe_subcmd_config_ips(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
{
int res = BCME_USAGE_ERROR;
wl_natoe_config_ips_t config_ips;
wl_natoe_ioc_t *natoe_ioc = NULL;
uint16 buflen, buflen_at_start;
uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
bcm_xtlv_t *pxtlv = NULL;
/* alloc mem for ioctl headr + tlv data */
natoe_ioc = calloc(1, iocsz);
if (natoe_ioc == NULL) {
return BCME_NOMEM;
}
/* make up natoe cmd ioctl header */
natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
natoe_ioc->id = htod16(cmd->id);
natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
if (*argv == NULL) {
iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
res = wl_natoe_get_ioctl(wl, natoe_ioc, iocsz);
} else {
memset(&config_ips, 0, sizeof(config_ips));
if (ARGCNT(argv) != WL_NATOE_SUBCMD_CONFIG_IPS_ARGC) {
res = BCME_USAGE_ERROR;
goto exit;
}
if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.sta_ip)) {
printf("%s: Invalid STA IP addr provided\n", __FUNCTION__);
res = BCME_USAGE_ERROR;
goto exit;
}
if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.sta_netmask)) {
printf("%s: Invalid STA netmask addr provided\n", __FUNCTION__);
res = BCME_USAGE_ERROR;
goto exit;
}
if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
printf("%s: Invalid STA router IP addr provided\n", __FUNCTION__);
res = BCME_USAGE_ERROR;
goto exit;
}
if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
printf("%s: Invalid STA DNS IP addr provided\n", __FUNCTION__);
res = BCME_USAGE_ERROR;
goto exit;
}
if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.ap_ip)) {
printf("%s: Invalid AP IP addr provided\n", __FUNCTION__);
res = BCME_USAGE_ERROR;
goto exit;
}
if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.ap_netmask)) {
printf("%s: Invalid AP netmask addr provided\n", __FUNCTION__);
res = BCME_USAGE_ERROR;
goto exit;
}
/* max data we can write, it will be decremented as we pack */
buflen = WL_NATOE_IOC_BUFSZ;
buflen_at_start = buflen;
res = bcm_pack_xtlv_entry((uint8 **)&pxtlv,
&buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
(uint8 *)&config_ips, BCM_XTLV_OPTION_ALIGN32);
if (res != BCME_OK) {
goto exit;
}
/* adjust iocsz to the end of last data record */
natoe_ioc->len = (buflen_at_start - buflen);
iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
}
exit:
free(natoe_ioc);
return res;
}
static int
wl_natoe_subcmd_config_ports(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
{
int res = BCME_USAGE_ERROR;
wl_natoe_ports_config_t ports_config;
wl_natoe_ioc_t *natoe_ioc = NULL;
uint16 buflen, buflen_at_start;
uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
bcm_xtlv_t *pxtlv = NULL;
/* alloc mem for ioctl headr + tlv data */
natoe_ioc = calloc(1, iocsz);
if (natoe_ioc == NULL) {
return BCME_NOMEM;
}
/* make up natoe cmd ioctl header */
natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
natoe_ioc->id = htod16(cmd->id);
natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
if (*argv == NULL) {
iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
res = wl_natoe_get_ioctl(wl, natoe_ioc, iocsz);
} else {
memset(&ports_config, 0, sizeof(ports_config));
if (ARGCNT(argv) != WL_NATOE_SUBCMD_CONFIG_PORTS_ARGC) {
res = BCME_USAGE_ERROR;
goto exit;
}
ports_config.start_port_num = htod16(strtoul(*argv++, NULL, 0));
ports_config.no_of_ports = htod16(strtoul(*argv++, NULL, 0));
if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
WL_NATOE_MAX_PORT_NUM) {
res = BCME_BADOPTION;
goto exit;
}
/* max data we can write, it will be decremented as we pack */
buflen = WL_NATOE_IOC_BUFSZ;
buflen_at_start = buflen;
res = bcm_pack_xtlv_entry((uint8 **)&pxtlv,
&buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
(uint8 *)&ports_config, BCM_XTLV_OPTION_ALIGN32);
if (res != BCME_OK) {
goto exit;
}
/* adjust iocsz to the end of last data record */
natoe_ioc->len = (buflen_at_start - buflen);
iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
}
exit:
free(natoe_ioc);
return res;
}
static int
wl_natoe_subcmd_dbg_stats(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
{
int res = BCME_USAGE_ERROR;
wl_natoe_ioc_t *natoe_ioc = NULL;
uint16 buflen, buflen_at_start;
uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
bcm_xtlv_t *pxtlv = NULL;
/* alloc mem for ioctl headr + tlv data */
natoe_ioc = calloc(1, iocsz);
if (natoe_ioc == NULL) {
return BCME_NOMEM;
}
/* make up natoe cmd ioctl header */
natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
natoe_ioc->id = htod16(cmd->id);
natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
if (*argv == NULL) {
iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
res = wl_natoe_get_stats(wl, natoe_ioc, iocsz);
} else {
uint8 val;
if (ARGCNT(argv) != WL_NATOE_SUBCMD_DBG_STATS_ARGC) {
res = BCME_USAGE_ERROR;
goto exit;
}
val = atoi(*argv);
buflen = WL_NATOE_DBG_STATS_BUFSZ;
/* save buflen at start */
buflen_at_start = buflen;
/* we'll adjust final ioc size at the end */
res = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_DBG_STATS,
sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
if (res != BCME_OK) {
goto exit;
}
/* adjust iocsz to the end of last data record */
natoe_ioc->len = (buflen_at_start - buflen);
iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
}
exit:
free(natoe_ioc);
return res;
}
static int
wl_natoe_subcmd_tbl_cnt(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
{
int res = BCME_OK;
wl_natoe_ioc_t *natoe_ioc;
uint16 buflen, buflen_at_start;
uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
bcm_xtlv_t *pxtlv = NULL;
/* alloc mem for ioctl headr + tlv data */
natoe_ioc = calloc(1, iocsz);
if (natoe_ioc == NULL) {
return BCME_NOMEM;
}
/* make up natoe cmd ioctl header */
natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
natoe_ioc->id = htod16(cmd->id);
natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
if(*argv == NULL) { /* get */
iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
res = wl_natoe_get_ioctl(wl, natoe_ioc, iocsz);
} else { /* set */
/* max tlv data we can write, it will be decremented as we pack */
uint32 val;
if (ARGCNT(argv) != WL_NATOE_SUBCMD_TBL_CNT_ARGC) {
res = BCME_USAGE_ERROR;
goto exit;
}
val = atoi(*argv);
buflen = WL_NATOE_IOC_BUFSZ;
/* save buflen at start */
buflen_at_start = buflen;
/* we'll adjust final ioc size at the end */
res = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
if (res != BCME_OK) {
goto exit;
}
/* adjust iocsz to the end of last data record */
natoe_ioc->len = (buflen_at_start - buflen);
iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
}
exit:
free(natoe_ioc);
return res;
}
static int
wl_natoe_control(void *wl, cmd_t *cmd, char **argv)
{
int ret = BCME_USAGE_ERROR;
char *natoe_query[2] = {"enable", NULL};
char *natoe_en[3] = {"enable", "1", NULL};
char *natoe_dis[3] = {"enable", "0", NULL};
const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
/* Skip the command name */
UNUSED_PARAMETER(cmd);
argv++;
/* skip to cmd name after "natoe" */
if (!*argv) {
/* query natoe "enable" state */
argv = natoe_query;
} else if (*argv[0] == '1') {
argv = natoe_en;
} else if (*argv[0] == '0') {
argv = natoe_dis;
} else if (!strcmp(*argv, "-h") || !strcmp(*argv, "help")) {
/* help , or -h* */
return ret;
}
while (natoe_cmd->name != NULL) {
if (strcmp(natoe_cmd->name, *argv) == 0) {
/* dispacth cmd to appropriate handler */
if (natoe_cmd->handler) {
ret = natoe_cmd->handler(wl, natoe_cmd, ++argv);
}
return ret;
}
natoe_cmd++;
}
return ret;
}