blob: 96425c3119405710b2f0471ec59d10c0a6da77b7 [file] [log] [blame]
/*
* wl cac 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_cac.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 <proto/802.11e.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include "wlu_common.h"
#include "wlu.h"
static cmd_func_t wl_cac, wl_tslist, wl_tspec, wl_tslist_ea, wl_tspec_ea, wl_cac_delts_ea;
static void wl_cac_addts_usage(void);
static void wl_cac_delts_usage(void);
static void wl_print_tspec(tspec_arg_t *ts);
static cmd_t wl_cac_cmds[] = {
{ "cac_addts", wl_cac, -1, WLC_SET_VAR,
"add TSPEC, error if STA is not associated or WME is not enabled\n"
"\targ: TSPEC parameter input list"},
{ "cac_delts", wl_cac, -1, WLC_SET_VAR,
"delete TSPEC, error if STA is not associated or WME is not enabled\n"
"\targ: TSINFO for the target tspec"},
{ "cac_delts_ea", wl_cac_delts_ea, -1, WLC_SET_VAR,
"delete TSPEC, error if STA is not associated or WME is not enabled\n"
"\targ1: Desired TSINFO for the target tspec\n"
"\targ2: Desired MAC address"},
{ "cac_tslist", wl_tslist, WLC_GET_VAR, -1,
"Get the list of TSINFO in driver\n"
"\teg. 'wl cac_tslist' get a list of TSINFO"},
{ "cac_tslist_ea", wl_tslist_ea, WLC_GET_VAR, -1,
"Get the list of TSINFO for given STA in driver\n"
"\teg. 'wl cac_tslist_ea ea' get a list of TSINFO"},
{ "cac_tspec", wl_tspec, WLC_GET_VAR, -1,
"Get specific TSPEC with matching TSINFO\n"
"\teg. 'wl cac_tspec 0xaa 0xbb 0xcc' where 0xaa 0xbb & 0xcc are TSINFO octets"},
{ "cac_tspec_ea", wl_tspec_ea, WLC_GET_VAR, -1,
"Get specific TSPEC for given STA with matching TSINFO\n"
"\teg. 'wl cac_tspec 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx'\n"
"\t where 0xaa 0xbb & 0xcc are TSINFO octets and xx is mac address"},
{ NULL, NULL, 0, 0, NULL }
};
static char *buf;
/* module initialization */
void
wluc_cac_module_init(void)
{
/* get the global buf */
buf = wl_get_buf();
/* register cac commands */
wl_module_cmds_register(wl_cac_cmds);
}
#define NUM_TSLIST_ARG 3 /* minimum number of arguments required for TSLIST */
#define NUM_TSLIST_PER_EA_ARG 3 /* minimum number of arguments required for TSLIST */
#define MIN_NUM_DELTS_ARG 4 /* minimum number of arguments required for DELTS */
#define MIN_NUM_DELTS_EA_ARG 5 /* minimum number of arguments required for DELTS */
#define MIN_NUM_ADDTS_ARG 20 /* minimum number of arguments required for ADDTS */
#define PERIODIC_TRAFFIC 1 /* Periodic traffic type */
#define VO_TID (0 << 1) /* voice TID */
#define VI_TID (1 << 1) /* signal TID */
#define UPLINK_DIRECTION (0 << 5) /* uplink direction traffic stream */
#define DOWNLINK_DIRECTION (1 << 5) /* downlink direction traffic stream */
#define BI_DIRECTION (3 << 5) /* bi direction traffic stream */
#define EDCA_ACCESS (1 << 7) /* EDCA access policy */
#define UAPSD_PSB (1 << 2) /* U-APSD power saving behavior */
#define VO_USER_PRIO (6 << 3) /* voice user priority */
#define VI_USER_PRIO (4 << 3) /* signal user priority */
#define TID_SHIFT 1 /* TID Shift */
#define UP_SHIFT 3 /* UP Shift */
static void
wl_cac_format_tspec_htod(tspec_arg_t *tspec_arg)
{
tspec_arg->version = htod16(tspec_arg->version);
tspec_arg->length = htod16(tspec_arg->length);
tspec_arg->flag = htod32(tspec_arg->flag);
tspec_arg->nom_msdu_size = htod16(tspec_arg->nom_msdu_size);
tspec_arg->max_msdu_size = htod16(tspec_arg->max_msdu_size);
tspec_arg->min_srv_interval = htod32(tspec_arg->min_srv_interval);
tspec_arg->max_srv_interval = htod32(tspec_arg->max_srv_interval);
tspec_arg->inactivity_interval = htod32(tspec_arg->inactivity_interval);
tspec_arg->suspension_interval = htod32(tspec_arg->suspension_interval);
tspec_arg->srv_start_time = htod32(tspec_arg->srv_start_time);
tspec_arg->min_data_rate = htod32(tspec_arg->min_data_rate);
tspec_arg->mean_data_rate = htod32(tspec_arg->mean_data_rate);
tspec_arg->peak_data_rate = htod32(tspec_arg->peak_data_rate);
tspec_arg->max_burst_size = htod32(tspec_arg->max_burst_size);
tspec_arg->delay_bound = htod32(tspec_arg->delay_bound);
tspec_arg->min_phy_rate = htod32(tspec_arg->min_phy_rate);
tspec_arg->surplus_bw = htod16(tspec_arg->surplus_bw);
tspec_arg->medium_time = htod16(tspec_arg->medium_time);
}
static void
wl_cac_format_tspec_dtoh(tspec_arg_t *tspec_arg)
{
tspec_arg->version = dtoh16(tspec_arg->version);
tspec_arg->length = dtoh16(tspec_arg->length);
tspec_arg->flag = dtoh32(tspec_arg->flag);
tspec_arg->nom_msdu_size = dtoh16(tspec_arg->nom_msdu_size);
tspec_arg->max_msdu_size = dtoh16(tspec_arg->max_msdu_size);
tspec_arg->min_srv_interval = dtoh32(tspec_arg->min_srv_interval);
tspec_arg->max_srv_interval = dtoh32(tspec_arg->max_srv_interval);
tspec_arg->inactivity_interval = dtoh32(tspec_arg->inactivity_interval);
tspec_arg->suspension_interval = dtoh32(tspec_arg->suspension_interval);
tspec_arg->srv_start_time = dtoh32(tspec_arg->srv_start_time);
tspec_arg->min_data_rate = dtoh32(tspec_arg->min_data_rate);
tspec_arg->mean_data_rate = dtoh32(tspec_arg->mean_data_rate);
tspec_arg->peak_data_rate = dtoh32(tspec_arg->peak_data_rate);
tspec_arg->max_burst_size = dtoh32(tspec_arg->max_burst_size);
tspec_arg->delay_bound = dtoh32(tspec_arg->delay_bound);
tspec_arg->min_phy_rate = dtoh32(tspec_arg->min_phy_rate);
tspec_arg->surplus_bw = dtoh16(tspec_arg->surplus_bw);
tspec_arg->medium_time = dtoh16(tspec_arg->medium_time);
}
static void wl_cac_addts_usage(void)
{
fprintf(stderr, "Too few arguments\n");
fprintf(stderr, "wl cac_addts ver dtoken tid dir psb up a b c d e ...\n");
fprintf(stderr, "\twhere ver is the structure version\n");
fprintf(stderr, "\twhere dtoken is the dialog token [range 1-255]\n");
fprintf(stderr, "\twhere tid is the tspec identifier [range 0-7]\n");
fprintf(stderr, "\twhere dir is direction [uplink | downlink | bi-directional]\n");
fprintf(stderr, "\twhere psb is power save mode [legacy|U-APSD]\n");
fprintf(stderr, "\twhere up is user priority [range 0-7]\n");
fprintf(stderr, "\twhere a is the nominal MSDU size\n");
fprintf(stderr, "\twhere b is bool for fixed size msdu [ 0 and 1]\n");
fprintf(stderr, "\twhere c is the maximum MSDU size\n");
fprintf(stderr, "\twhere d is the minimum service interval\n");
fprintf(stderr, "\twhere e is the maximum service interval\n");
fprintf(stderr, "\twhere f is the inactivity interval\n");
fprintf(stderr, "\twhere g is the suspension interval\n");
fprintf(stderr, "\twhere h is the minimum data rate\n");
fprintf(stderr, "\twhere i is the mean data rate\n");
fprintf(stderr, "\twhere j is the peak data rate\n");
fprintf(stderr, "\twhere k is the max burst size\n");
fprintf(stderr, "\twhere l is the delay bound\n");
fprintf(stderr, "\twhere m is the surplus bandwidth [fixed point notation]\n");
fprintf(stderr, "\twhere n is the minimum PHY rate\n");
}
static void wl_cac_delts_usage(void)
{
fprintf(stderr, "Too few arguments\n");
fprintf(stderr, "wl cac_delts ver a b c \n");
fprintf(stderr, "\twhere ver is the tspec version\n");
fprintf(stderr, "\twhere a is byte[0] of tsinfo (bits 0-7)\n");
fprintf(stderr, "\twhere b is byte[1] of tsinfo (bits 8-15)\n");
fprintf(stderr, "\twhere c is byte[2] of tsinfo (bits 16-23)\n");
}
static int
wl_cac(void *wl, cmd_t *cmd, char **argv)
{
int err = -1;
int ap_mode = 0;
int apsta_mode = 0;
int cmd_type = 0;
tspec_arg_t tspec_arg;
char *endptr = NULL;
uint buflen;
char *arg1, *user_argv;
uint8 direction = BI_DIRECTION;
uint8 user_tid, user_prio, user_psb;
uint fixed;
if ((err = wlu_iovar_get(wl, "apsta", &apsta_mode, sizeof(apsta_mode))))
return err;
if (!apsta_mode) {
if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
return err;
else {
if (dtoh32(ap_mode)) {
fprintf(stderr,
"This command can ONLY be executed on a STA or APSTA\n");
return err;
}
}
}
if (!strcmp(*argv, "cac_addts"))
cmd_type = 1;
else if (!strcmp(*argv, "cac_delts"))
cmd_type = 2;
else {
fprintf(stderr, "unknown command\n");
return BCME_USAGE_ERROR;
}
/* eat command name */
if (!*++argv) {
(cmd_type == 1) ? wl_cac_addts_usage():wl_cac_delts_usage();
return BCME_BADARG;
}
buflen = sizeof(tspec_arg_t);
memset((uint8 *)&tspec_arg, 0, buflen);
/* get direction option */
arg1 = *argv;
/* Unidirectional DL/UL */
if (!strcmp(arg1, "UDL") || (!strcmp(arg1, "UUL")))
direction = DOWNLINK_DIRECTION;
if (cmd_type == 1) {
uint argc = 0;
/* arg count */
while (argv[argc])
argc++;
/* required argments */
if (argc < MIN_NUM_ADDTS_ARG) {
wl_cac_addts_usage();
return BCME_USAGE_ERROR;
}
tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.dialog_token = (uint8)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
user_tid = (uint8)strtol(*argv++, &endptr, 0);
user_tid <<= TID_SHIFT;
if (*endptr != '\0')
return BCME_USAGE_ERROR;
/* store the pointer for parsing */
user_argv = *argv++;
if (!strcmp(user_argv, "uplink"))
direction = UPLINK_DIRECTION;
else if (!strcmp(user_argv, "downlink"))
direction = DOWNLINK_DIRECTION;
else if (!strcmp(user_argv, "bi-directional"))
direction = BI_DIRECTION;
else
return BCME_USAGE_ERROR;
/* store the pointer for parsing */
user_argv = *argv++;
if (!strcmp(user_argv, "legacy"))
user_psb = 0;
else if (!strcmp(user_argv, "U-APSD"))
user_psb = UAPSD_PSB;
else
return BCME_USAGE_ERROR;
user_prio = (uint8)strtol(*argv++, &endptr, 0);
user_prio <<= UP_SHIFT;
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.tsinfo.octets[0] = (uint8)(user_tid |
direction | EDCA_ACCESS);
tspec_arg.tsinfo.octets[1] = (uint8)(user_prio | user_psb);
tspec_arg.tsinfo.octets[2] = 0x00;
tspec_arg.nom_msdu_size = (uint16)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
fixed = (uint)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
if (fixed == 1)
tspec_arg.nom_msdu_size |= 0x8000;
tspec_arg.max_msdu_size = (uint16)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.min_srv_interval = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.max_srv_interval = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.inactivity_interval = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.suspension_interval = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.min_data_rate = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.mean_data_rate = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.peak_data_rate = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.max_burst_size = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.delay_bound = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.surplus_bw = (uint16)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.min_phy_rate = strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
printf("Setting min_phy_rate to 0x%x\n", tspec_arg.min_phy_rate);
} else {
uint argc = 0;
/* arg count */
while (argv[argc])
argc++;
/* required argments */
if (argc < MIN_NUM_DELTS_ARG) {
wl_cac_delts_usage();
return BCME_USAGE_ERROR;
}
tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
}
wl_cac_format_tspec_htod(&tspec_arg);
err = wlu_var_setbuf(wl, cmd->name, &tspec_arg, buflen);
return err;
}
/* get a list of traffic stream (TSINFO) in driver */
static int
wl_tslist(void *wl, cmd_t *cmd, char **argv)
{
void *ptr;
int i;
int ap_mode, err = -1;
int apsta_mode = 0;
struct tslist *tslist;
UNUSED_PARAMETER(argv);
if ((err = wlu_iovar_get(wl, "apsta", &apsta_mode, sizeof(apsta_mode))))
return err;
if (!apsta_mode) {
if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
return err;
else {
if (dtoh32(ap_mode)) {
fprintf(stderr,
"This command can ONLY be executed on a STA or APSTA\n");
return err;
}
}
}
if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
return err;
tslist = (struct tslist *)ptr;
tslist->count = dtoh32(tslist->count);
for (i = 0; i < tslist->count; i++)
printf("tsinfo 0x%02X 0x%02X 0x%02X TID %d User Prio %d Direction %d\n",
tslist->tsinfo[i].octets[0],
tslist->tsinfo[i].octets[1],
tslist->tsinfo[i].octets[2],
WLC_CAC_GET_TID(tslist->tsinfo[i]),
WLC_CAC_GET_USER_PRIO(tslist->tsinfo[i]),
WLC_CAC_GET_DIR(tslist->tsinfo[i]));
return 0;
}
/* get specific TSPEC in driver */
static int
wl_tspec(void *wl, cmd_t *cmd, char **argv)
{
void *ptr;
int ap_mode, err = -1;
tspec_arg_t *ts, tspec_arg;
char *temp = NULL;
uint argc = 0;
if ((wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
return err;
ap_mode = dtoh32(ap_mode);
if (ap_mode) {
fprintf(stderr, "This command can only be executed on the STA\n");
return err;
}
/* eat command name */
argv++;
/* arg count */
while (argv[argc])
argc++;
/* required argments */
if (argc < NUM_TSLIST_ARG) {
fprintf(stderr, "Too few arguments\n");
fprintf(stderr, "wl cac_tspec 0xaa 0xbb 0xcc \n");
fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
return BCME_USAGE_ERROR;
}
memset((uint8 *)&tspec_arg, 0, sizeof(tspec_arg_t));
tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0);
if (*temp != '\0')
return BCME_USAGE_ERROR;
tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0);
if (*temp != '\0')
return BCME_USAGE_ERROR;
tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0);
if (*temp != '\0')
return BCME_USAGE_ERROR;
if ((err = wlu_var_getbuf(wl, cmd->name, &tspec_arg, sizeof(tspec_arg_t), &ptr)) < 0)
return err;
ts = (tspec_arg_t *)ptr;
wl_cac_format_tspec_dtoh(ts);
wl_print_tspec(ts);
return 0;
}
/* get the tspec list for the given station */
static int
wl_tslist_ea(void *wl, cmd_t *cmd, char **argv)
{
void *ptr;
int i;
int ap_mode, err = -1;
struct tslist *tslist;
scb_val_t scb_val;
if (!*++argv) {
printf("MAC address must be specified\n");
return BCME_USAGE_ERROR;
} else if (!wl_ether_atoe(*argv, &scb_val.ea)) {
printf("Malformed MAC address parameter\n");
return BCME_USAGE_ERROR;
}
if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
return err;
ap_mode = dtoh32(ap_mode);
if ((err = wlu_var_getbuf(wl, cmd->name, &scb_val.ea, ETHER_ADDR_LEN, &ptr)) < 0)
return err;
tslist = (struct tslist *)ptr;
for (i = 0; i < tslist->count; i++)
printf("tsinfo 0x%02X 0x%02X 0x%02X TID %d User Prio %d Direction %d\n",
tslist->tsinfo[i].octets[0],
tslist->tsinfo[i].octets[1],
tslist->tsinfo[i].octets[2],
WLC_CAC_GET_TID(tslist->tsinfo[i]),
WLC_CAC_GET_USER_PRIO(tslist->tsinfo[i]),
WLC_CAC_GET_DIR(tslist->tsinfo[i]));
return 0;
}
/* get specific TSPEC for a STA */
static int
wl_tspec_ea(void *wl, cmd_t *cmd, char **argv)
{
void *ptr;
int err = -1;
tspec_per_sta_arg_t tsea;
tspec_arg_t *ts;
char *temp;
uint argc = 0;
/* eat command name */
argv++;
while (argv[argc])
argc++;
/* required argments */
if (argc < (NUM_TSLIST_PER_EA_ARG + 1)) {
fprintf(stderr, "Too few arguments\n");
fprintf(stderr, "wl cac_tspec 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx\n");
fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
fprintf(stderr, "\twhere xx:xx:xx:xx:xx:xx is mac address )\n");
return BCME_USAGE_ERROR;
}
memset((uint8 *)&tsea, 0, sizeof(tspec_per_sta_arg_t));
ts = &tsea.ts;
ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0);
if (*temp != '\0')
return BCME_USAGE_ERROR;
ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0);
if (*temp != '\0')
return BCME_USAGE_ERROR;
ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0);
if (*temp != '\0')
return BCME_USAGE_ERROR;
/* add the ether address after tsinfo */
if (!*argv) {
printf("MAC address must be specified\n");
return BCME_USAGE_ERROR;
} else if (!wl_ether_atoe(*argv, &tsea.ea)) {
printf("Malformed MAC address parameter\n");
return BCME_USAGE_ERROR;
}
if ((err = wlu_var_getbuf(wl, cmd->name, &tsea, sizeof(tspec_per_sta_arg_t), &ptr)) < 0)
return err;
ts = (tspec_arg_t *)ptr;
wl_cac_format_tspec_dtoh(ts);
wl_print_tspec(ts);
return 0;
}
static const uint8 wlu_wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE,
AC_BE };
static const uint8 wlu_prio2fifo[NUMPRIO] = {
0, /* 0 BE AC_BE Best Effort */
1, /* 1 BK AC_BK Background */
2, /* 2 -- AC_BK Background */
3, /* 3 EE AC_BE Best Effort */
4, /* 4 CL AC_VI Video */
5, /* 5 VI AC_VI Video */
6, /* 6 VO AC_VO Voice */
7 /* 7 NC AC_VO Voice */
};
#define WME_PRIO2AC(prio) wlu_wme_fifo2ac[wlu_prio2fifo[(prio)]]
static void
wl_print_tspec(tspec_arg_t *ts)
{
const char *str;
if (ts->version != TSPEC_ARG_VERSION) {
printf("\tIncorrect version of TSPEC struct: expected %d; got %d\n",
TSPEC_ARG_VERSION, ts->version);
return;
}
if (ts->length < (sizeof(tspec_arg_t) - (2 * sizeof(uint16)))) {
printf("\tTSPEC arg length too short: expected %d; got %d\n",
(int)(sizeof(tspec_arg_t) - (2 * sizeof(uint16))), ts->length);
return;
}
switch (ts->flag & TSPEC_STATUS_MASK) {
case TSPEC_PENDING:
str = "PENDING";
break;
case TSPEC_ACCEPTED:
str = "ACCEPTED";
break;
case TSPEC_REJECTED:
str = "REJECTED";
break;
default:
str = "UNKNOWN";
break;
}
printf("version %d\n", ts->version);
printf("length %d\n", ts->length);
printf("TID %d %s\n", WLC_CAC_GET_TID(ts->tsinfo), str);
printf("tsinfo 0x%02x 0x%02x 0x%02x\n", ts->tsinfo.octets[0],
ts->tsinfo.octets[1], ts->tsinfo.octets[2]);
/* breakout bitfields for apsd */
if (WLC_CAC_GET_PSB(ts->tsinfo)) {
int ac = WME_PRIO2AC(WLC_CAC_GET_USER_PRIO(ts->tsinfo));
switch (WLC_CAC_GET_DIR(ts->tsinfo)) {
case (TS_INFO_UPLINK >> TS_INFO_DIRECTION_SHIFT):
printf("AC[%d] : Trigger enabled\n", ac);
break;
case (TS_INFO_DOWNLINK >> TS_INFO_DIRECTION_SHIFT):
printf("AC[%d] : Delivery enabled\n", ac);
break;
case (TS_INFO_BIDIRECTIONAL >>
TS_INFO_DIRECTION_SHIFT):
printf("AC[%d] : Trig & Delv enabled\n", ac);
break;
}
} else {
int ac;
ac = WME_PRIO2AC(WLC_CAC_GET_USER_PRIO(ts->tsinfo));
printf("AC [%d] : Legacy Power save\n", ac);
}
printf("nom_msdu_size %d %s\n", (ts->nom_msdu_size & 0x7fff),
((ts->nom_msdu_size & 0x8000) ? "fixed size" : ""));
printf("max_msdu_size %d\n", ts->max_msdu_size);
printf("min_srv_interval %d\n", ts->min_srv_interval);
printf("max_srv_interval %d\n", ts->max_srv_interval);
printf("inactivity_interval %d\n", ts->inactivity_interval);
printf("suspension_interval %d\n", ts->suspension_interval);
printf("srv_start_time %d\n", ts->srv_start_time);
printf("min_data_rate %d\n", ts->min_data_rate);
printf("mean_data_rate %d\n", ts->mean_data_rate);
printf("peak_data_rate %d\n", ts->peak_data_rate);
printf("max_burst_size %d\n", ts->max_burst_size);
printf("delay_bound %d\n", ts->delay_bound);
printf("min_phy_rate %d\n", ts->min_phy_rate);
printf("surplus_bw %d\n", ts->surplus_bw);
printf("medium_time %d\n", ts->medium_time);
}
/* send delts for a specific ea */
/* TODO : Club this with wl_tspec_ea */
static int
wl_cac_delts_ea(void *wl, cmd_t *cmd, char **argv)
{
void *ptr;
int err = -1;
char *endptr = NULL;
tspec_per_sta_arg_t tsea;
tspec_arg_t *ts;
uint argc = 0;
/* eat command name */
argv++;
while (argv[argc])
argc++;
/* required argments */
if (argc < (NUM_TSLIST_PER_EA_ARG + 1)) {
fprintf(stderr, "Too few arguments\n");
fprintf(stderr, "wl cac_delts_ea ver 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx\n");
fprintf(stderr, "\twhere ver is the tspec version\n");
fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
fprintf(stderr, "\twhere xx:xx:xx:xx:xx:xx is mac address )\n");
return BCME_USAGE_ERROR;
}
memset((uint8 *)&tsea, 0, sizeof(tspec_per_sta_arg_t));
ts = &tsea.ts;
ts->length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
ts->version = (uint16)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0);
if (*endptr != '\0')
return BCME_USAGE_ERROR;
/* add the ether address after tsinfo */
if (!*argv) {
printf("MAC address must be specified\n");
return BCME_USAGE_ERROR;
} else if (!wl_ether_atoe(*argv, &tsea.ea)) {
printf("Malformed MAC address parameter\n");
return BCME_USAGE_ERROR;
}
wl_cac_format_tspec_htod(ts);
if ((err = wlu_var_getbuf(wl, cmd->name, &tsea, sizeof(tspec_per_sta_arg_t), &ptr)) < 0)
return err;
return 0;
}