blob: df23873d756f896c500d9c56802dfbe1db393993 [file] [log] [blame]
/*
* wl obss 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_obss.c 458728 2014-02-27 18:15:25Z $
*/
#ifdef WIN32
#include <windows.h>
#endif
#include <wlioctl.h>
#if defined(DONGLEBUILD)
#include <typedefs.h>
#include <osl.h>
#endif
/* Because IL_BIGENDIAN was removed there are few warnings that need
* to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
* Hence these warnings were not seen earlier.
* For now ignore the following warnings
*/
#ifdef WIN32
#pragma warning(push)
#pragma warning(disable : 4244)
#pragma warning(disable : 4761)
#endif
#include <bcmutils.h>
#include <bcmendian.h>
#include "wlu_common.h"
#include "wlu.h"
static cmd_func_t wl_obss_scan, wl_obss_coex_action;
static cmd_t wl_obss_cmds[] = {
{ "obss_scan_params", wl_obss_scan, WLC_GET_VAR, WLC_SET_VAR,
"set/get Overlapping BSS scan parameters\n"
"Usage: wl obss_scan a b c d e ...; where\n"
"\ta-Passive Dwell, {5-1000TU}, default = 100\n"
"\tb-Active Dwell, {10-1000TU}, default = 20\n"
"\tc-Width Trigger Scan Interval, {10-900sec}, default = 300\n"
"\td-Passive Total per Channel, {200-10000TU}, default = 200\n"
"\te-Active Total per Channel, {20-1000TU}, default = 20\n"
"\tf-Channel Transition Delay Factor, {5-100}, default = 5\n"
"\tg-Activity Threshold, {0-100%}, default = 25"},
{ "obss_coex_action", wl_obss_coex_action, -1, WLC_SET_VAR,
"send OBSS 20/40 Coexistence Mangement Action Frame\n"
"\tUsage: wl obss_coex_action -i <1/0> -w <1/0> -c <channel list>\n"
"\t -i: 40MHz intolerate bit; -w: 20MHz width Req bit;\n"
"\t -c: channel list, 1 - 14\n"
"\t At least one option must be provided"
},
{ NULL, NULL, 0, 0, NULL }
};
static char *buf;
/* module initialization */
void
wluc_obss_module_init(void)
{
/* get the global buf */
buf = wl_get_buf();
/* register obss commands */
wl_module_cmds_register(wl_obss_cmds);
}
static int
wl_obss_scan_params_range_chk(wl_obss_scan_arg_t *obss_scan_arg)
{
if (obss_scan_arg->passive_dwell < 0)
obss_scan_arg->passive_dwell = WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT;
else if (obss_scan_arg->passive_dwell < WLC_OBSS_SCAN_PASSIVE_DWELL_MIN ||
obss_scan_arg->passive_dwell > WLC_OBSS_SCAN_PASSIVE_DWELL_MAX) {
printf("passive dwell not in range %d\n", obss_scan_arg->passive_dwell);
return -1;
}
if (obss_scan_arg->active_dwell < 0)
obss_scan_arg->active_dwell = WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT;
else if (obss_scan_arg->active_dwell < WLC_OBSS_SCAN_ACTIVE_DWELL_MIN ||
obss_scan_arg->active_dwell > WLC_OBSS_SCAN_ACTIVE_DWELL_MAX) {
printf("active dwell not in range %d\n", obss_scan_arg->active_dwell);
return -1;
}
if (obss_scan_arg->bss_widthscan_interval < 0)
obss_scan_arg->bss_widthscan_interval =
WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT;
else if (obss_scan_arg->bss_widthscan_interval < WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN ||
obss_scan_arg->bss_widthscan_interval > WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX) {
printf("Width Trigger Scan Interval not in range %d\n",
obss_scan_arg->bss_widthscan_interval);
return -1;
}
if (obss_scan_arg->chanwidth_transition_delay < 0)
obss_scan_arg->chanwidth_transition_delay =
WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT;
else if ((obss_scan_arg->chanwidth_transition_delay <
WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN) ||
(obss_scan_arg->chanwidth_transition_delay >
WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX)) {
printf("Width Channel Transition Delay Factor not in range %d\n",
obss_scan_arg->chanwidth_transition_delay);
return -1;
}
if (obss_scan_arg->passive_total < 0)
obss_scan_arg->passive_total = WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT;
else if (obss_scan_arg->passive_total < WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN ||
obss_scan_arg->passive_total > WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX) {
printf("Passive Total per Channel not in range %d\n", obss_scan_arg->passive_total);
return -1;
}
if (obss_scan_arg->active_total < 0)
obss_scan_arg->active_total = WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT;
if (obss_scan_arg->active_total < WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN ||
obss_scan_arg->active_total > WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX) {
printf("Active Total per Channel not in range %d\n", obss_scan_arg->active_total);
return -1;
}
if (obss_scan_arg->activity_threshold < 0)
obss_scan_arg->activity_threshold = WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT;
else if (obss_scan_arg->activity_threshold < WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN ||
obss_scan_arg->activity_threshold > WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX) {
printf("Activity Threshold not in range %d\n", obss_scan_arg->activity_threshold);
return -1;
}
return 0;
}
static int
wl_obss_scan(void *wl, cmd_t *cmd, char **argv)
{
int err = -1;
wl_obss_scan_arg_t obss_scan_arg;
char *endptr = NULL;
uint buflen;
uint argc = 0;
if (!*++argv) {
void *ptr = NULL;
wl_obss_scan_arg_t *obss_scan_param;
err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr);
if (err < 0)
return err;
obss_scan_param = (wl_obss_scan_arg_t *)ptr;
printf("%d %d %d %d %d %d %d\n",
dtoh16(obss_scan_param->passive_dwell),
dtoh16(obss_scan_param->active_dwell),
dtoh16(obss_scan_param->bss_widthscan_interval),
dtoh16(obss_scan_param->passive_total),
dtoh16(obss_scan_param->active_total),
dtoh16(obss_scan_param->chanwidth_transition_delay),
dtoh16(obss_scan_param->activity_threshold));
return 0;
}
/* arg count */
while (argv[argc])
argc++;
buflen = WL_OBSS_SCAN_PARAM_LEN;
memset((uint8 *)&obss_scan_arg, 0, buflen);
/* required argments */
if (argc < WL_MIN_NUM_OBSS_SCAN_ARG) {
fprintf(stderr, "Too few/many arguments (require %d, got %d)\n",
WL_MIN_NUM_OBSS_SCAN_ARG, argc);
return BCME_USAGE_ERROR;
}
obss_scan_arg.passive_dwell = htod16((int16)strtol(*argv++, &endptr, 0));
if (*endptr != '\0')
return BCME_USAGE_ERROR;
obss_scan_arg.active_dwell = htod16((int16)strtol(*argv++, &endptr, 0));
if (*endptr != '\0')
return BCME_USAGE_ERROR;
obss_scan_arg.bss_widthscan_interval = htod16((int16)strtol(*argv++, &endptr, 0));
if (*endptr != '\0')
return BCME_USAGE_ERROR;
obss_scan_arg.passive_total = htod16((int16)strtol(*argv++, &endptr, 0));
if (*endptr != '\0')
return BCME_USAGE_ERROR;
obss_scan_arg.active_total = htod16((int16)strtol(*argv++, &endptr, 0));
if (*endptr != '\0')
return BCME_USAGE_ERROR;
obss_scan_arg.chanwidth_transition_delay = htod16((int16)strtol(*argv++, &endptr, 0));
if (*endptr != '\0')
return BCME_USAGE_ERROR;
obss_scan_arg.activity_threshold = htod16((int16)strtol(*argv++, &endptr, 0));
if (*endptr != '\0')
return BCME_USAGE_ERROR;
if (wl_obss_scan_params_range_chk(&obss_scan_arg))
return BCME_RANGE;
err = wlu_var_setbuf(wl, cmd->name, &obss_scan_arg, buflen);
return err;
}
static int
wl_obss_coex_action(void *wl, cmd_t *cmd, char **argv)
{
int err;
char var[256];
wl_action_obss_coex_req_t *req = (wl_action_obss_coex_req_t *)var;
int val;
int num = 0;
uint8 options = 0;
argv++;
memset(&var, 0, sizeof(wl_action_obss_coex_req_t));
while (*argv) {
if (!strncmp(*argv, "-i", 2) && ((options & 0x1) != 0x1)) {
argv++;
if (!*argv)
return BCME_USAGE_ERROR;
val = atoi(*argv);
if ((val != 0) && (val != 1))
return BCME_BADARG;
req->info |= val ? WL_COEX_40MHZ_INTOLERANT : 0;
options |= 0x1;
}
else if (!strncmp(*argv, "-w", 2) && ((options & 0x2) != 0x2)) {
argv++;
if (!*argv)
return BCME_USAGE_ERROR;
val = atoi(*argv);
if ((val != 0) && (val != 1))
return BCME_BADARG;
req->info |= val ? WL_COEX_WIDTH20 : 0;
options |= 0x2;
}
else if (!strncmp(*argv, "-c", 2) && ((options & 0x4) != 0x4)) {
argv++;
while (*argv) {
if (isdigit((unsigned char)(**argv))) {
val = htod32(strtoul(*argv, NULL, 0));
if ((val == 0) || (val > 14)) {
printf("Invalid channel %d\n", val);
return BCME_BADARG;
}
req->ch_list[num] = (uint8)val;
num++;
argv++;
if (num > 14) {
printf("Too many channels (max 14)\n");
return BCME_BADARG;
}
} else
break;
}
if (!num) {
printf("With option '-c' specified, a channel list is required\n");
return BCME_BADARG;
}
req->num = num;
options |= 0x4;
continue;
}
else
return BCME_USAGE_ERROR;
argv++;
}
if (!options)
return BCME_BADARG;
err = wlu_var_setbuf(wl, cmd->name, &var, (sizeof(wl_action_obss_coex_req_t) +
(req->num ? (req->num - 1) * sizeof(uint8) : 0)));
return err;
}