blob: 4523a1ec112edf8e1527c1a661f5a92d7c7ef683 [file] [log] [blame]
/*
* wl keymgmt 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_keymgmt.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_wepstatus;
static cmd_func_t wl_addwep, wl_rmwep;
static cmd_func_t wl_primary_key;
static cmd_func_t wl_keys, wl_wsec_test;
static cmd_func_t wl_tsc;
static cmd_t wl_keymgmt_cmds[] = {
{ "wepstatus", wl_wepstatus, -1, -1, /* Deprecated. Use "wsec" */
"Set or Get WEP status\n"
"\twepstatus [on|off]" },
{ "primary_key", wl_primary_key, WLC_GET_KEY_PRIMARY, WLC_SET_KEY_PRIMARY,
"Set or get index of primary key" },
{ "addwep", wl_addwep, -1, WLC_SET_KEY,
"Set an encryption key. The key must be 5, 13 or 16 bytes long, or\n"
"\t10, 26, 32, or 64 hex digits long. The encryption algorithm is\n"
"\tautomatically selected based on the key size. keytype is accepted\n"
"\tonly when key length is 16 bytes/32 hex digits and specifies\n"
"\twhether AES-OCB or AES-CCM encryption is used. Default is ccm.\n"
"\tWAPI is selected if key len is 32 and arguments contain wapi.\n"
"\taddwep <keyindex> <keydata> [ocb | ccm | wapi] [notx] [xx:xx:xx:xx:xx:xx]" },
{ "rmwep", wl_rmwep, -1, WLC_SET_KEY,
"Remove the encryption key at the specified key index." },
{ "keys", wl_keys, WLC_GET_KEY, -1,
"Prints a list of the current WEP keys" },
{ "tsc", wl_tsc, WLC_GET_KEY_SEQ, -1,
"Print Tx Sequence Couter for key at specified key index." },
{ "wsec_test", wl_wsec_test, -1, WLC_SET_WSEC_TEST,
"Generate wsec errors\n"
"\twsec_test <test_type> <keyindex|xx:xx:xx:xx:xx:xx>\n"
"\ttype \'wl wsec_test ?\' for test_types" },
{ NULL, NULL, 0, 0, NULL }
};
static char *buf;
/* module initialization */
void
wluc_keymgmt_module_init(void)
{
/* get the global buf */
buf = wl_get_buf();
/* register keymgmt commands */
wl_module_cmds_register(wl_keymgmt_cmds);
}
static int
wl_wepstatus(void *wl, cmd_t *cmd, char **argv)
{
int val, error;
const char *name = "wsec";
int wsec;
UNUSED_PARAMETER(cmd);
if (!*++argv) {
if ((error = wlu_iovar_getint(wl, name, &val) < 0))
return error;
printf("%d\n", val);
return 0;
} else {
val = atoi(*argv);
if ((error = wlu_iovar_getint(wl, name, &wsec) < 0))
return error;
if (val)
wsec |= WEP_ENABLED;
else
wsec &= ~WEP_ENABLED;
return wlu_iovar_setint(wl, name, wsec);
}
}
static int
wl_primary_key(void *wl, cmd_t *cmd, char **argv)
{
int i, val, ret = 0;
if (!*++argv) {
i = 0;
do {
val = htod32(i);
if ((ret = wlu_get(wl, cmd->get, &val, sizeof(val))) < 0) {
return ret;
}
if (dtoh32(val)) {
printf("Key %d is primary\n", i);
return 0;
}
} while (++i < DOT11_MAX_DEFAULT_KEYS);
printf("No primary key set\n");
} else {
val = htod32(atoi(*argv));
ret = wlu_set(wl, cmd->set, &val, sizeof(val));
}
return ret;
}
static int
wl_addwep(void *wl, cmd_t *cmd, char **argv)
{
wl_wsec_key_t key;
int bsscfg_idx = 0;
int consumed;
int error;
memset(&key, 0, sizeof(key));
argv++;
/* parse a bsscfg_idx option if present */
if ((error = wl_cfg_option(argv, "addwep", &bsscfg_idx, &consumed)) != 0)
return error;
argv += consumed;
/* GET operation not allowed */
if (!*argv)
return BCME_USAGE_ERROR;
key.index = atoi(*argv++);
if (!*argv) {
fprintf(stderr, "No key specified\n");
return BCME_USAGE_ERROR;
}
if (parse_wep(argv, &key, TRUE))
return BCME_BADARG;
key.index = htod32(key.index);
key.len = htod32(key.len);
key.algo = htod32(key.algo);
key.flags = htod32(key.flags);
if (consumed == 0) {
error = wlu_set(wl, cmd->set, &key, sizeof(key));
} else {
error = wlu_bssiovar_setbuf(wl, "wsec_key", bsscfg_idx,
&key, sizeof(key), buf, WLC_IOCTL_MAXLEN);
}
return error;
}
static int
wl_rmwep(void *wl, cmd_t *cmd, char **argv)
{
wl_wsec_key_t key;
int bsscfg_idx = 0;
int consumed;
int error;
memset(&key, 0, sizeof(key));
argv++;
/* parse a bsscfg_idx option if present */
if ((error = wl_cfg_option(argv, "rmwep", &bsscfg_idx, &consumed)) != 0)
return error;
argv += consumed;
/* GET operation not allowed */
if (!*argv)
return BCME_USAGE_ERROR;
key.index = htod32(atoi(*argv++));
if (*argv) {
if (!(wl_ether_atoe(*argv, &key.ea)))
return BCME_USAGE_ERROR;
}
if (consumed == 0) {
error = wlu_set(wl, cmd->set, &key, sizeof(key));
} else {
error = wlu_var_setbuf(wl, "wsec_key", &key, sizeof(key));
}
return error;
}
static struct {
uint value;
const char *string;
} wsec_test[] = {
{WSEC_GEN_MIC_ERROR, "mic_error"},
{WSEC_GEN_REPLAY, "replay"},
{WSEC_GEN_ICV_ERROR, "icv_error"},
{WSEC_GEN_MFP_ACT_ERROR, "act_error"},
{WSEC_GEN_MFP_DISASSOC_ERROR, "disassoc_error"},
{WSEC_GEN_MFP_DEAUTH_ERROR, "deauth_error"},
{0, NULL}
};
static int
wl_wsec_test(void *wl, cmd_t *cmd, char **argv)
{
wl_wsec_key_t *key;
int i, len;
char *endptr = NULL, *wsec_buf = NULL;
uint32 val, last_val;
int err = 0;
if (!*++argv) {
err = BCME_USAGE_ERROR;
goto usage;
}
val = strtol(*argv, &endptr, 0);
if (endptr == *argv) {
/* the value string was not parsed by strtol */
for (i = 0; wsec_test[i].value; i++)
if (stricmp(wsec_test[i].string, *argv) == 0) {
val = wsec_test[i].value;
break;
}
if (wsec_test[i].value == 0) {
err = BCME_BADARG;
goto usage;
}
}
++argv;
switch (val) {
case WSEC_GEN_REPLAY:
case WSEC_GEN_MIC_ERROR:
case WSEC_GEN_ICV_ERROR:
case WSEC_GEN_MFP_ACT_ERROR:
case WSEC_GEN_MFP_DISASSOC_ERROR:
case WSEC_GEN_MFP_DEAUTH_ERROR:
if (!*argv) {
fprintf(stderr, "insufficient arguments\n");
return BCME_USAGE_ERROR;
}
len = sizeof(wl_wsec_key_t) + 4;
wsec_buf = malloc(len);
if (wsec_buf == NULL) {
fprintf(stderr, "Error allocating memory failed for wsec_buf");
return BCME_NOMEM;
}
*(uint32 *)wsec_buf = htod32(val);
key = (wl_wsec_key_t *)&wsec_buf[4];
memset(key, 0, sizeof(wl_wsec_key_t));
/* If it doesn't look like an ether addr, suppose it's a key index */
if (!(wl_ether_atoe(*argv, &key->ea))) {
memset(&key->ea, 0, ETHER_ADDR_LEN);
key->index = htod32(atoi(*argv));
}
break;
default:
goto usage;
}
err = wlu_set(wl, cmd->set, wsec_buf, len);
free(wsec_buf);
goto exit;
usage:
fprintf(stderr, "wsec test_type may be a number or name from the following set:");
last_val = 0xffffffff;
for (i = 0; (val = wsec_test[i].value); i++) {
if (val != last_val)
fprintf(stderr, "\n0x%04x %s", val, wsec_test[i].string);
else
fprintf(stderr, ", %s", wsec_test[i].string);
last_val = val;
}
fprintf(stderr, "\n");
exit:
return err;
}
static int
wl_keys(void *wl, cmd_t *cmd, char **argv)
{
uint i, j;
union {
int index;
wl_wsec_key_t key;
} u;
int wep_is_on = 0;
const char *addr;
int ret = BCME_OK;
UNUSED_PARAMETER(argv);
if (wlu_iovar_getint(wl, "wsec", &wep_is_on) < 0)
fprintf(stderr, "Could not query wsec status.\n");
for (i = 0; i < 256; i++) {
memset(&u, 0, sizeof(u));
u.index = htod32(i);
ret = wlu_get(wl, cmd->get, &u, sizeof(u));
if (ret == BCME_IOCTL_ERROR) {
int bcmerr;
if (wlu_iovar_getint(wl, "bcmerror", &bcmerr) >= 0 &&
(bcmerr == BCME_BADKEYIDX)) {
ret = BCME_OK;
}
}
if (ret != BCME_OK)
break;
/* ignore empty keys */
if (dtoh32(u.key.algo) == CRYPTO_ALGO_OFF || (u.key.len == 0))
continue;
if (ETHER_ISNULLADDR(&u.key.ea))
addr = "(default)";
else
addr = wl_ether_etoa(&u.key.ea);
printf("%3d: %-17s Key %d: %s ", i, addr, dtoh32(u.key.index),
bcm_crypto_algo_name(dtoh32(u.key.algo)));
if (wep_is_on && dtoh32(u.key.flags) & WL_PRIMARY_KEY)
printf("*");
printf("\t");
if (dtoh32(u.key.len) == 0)
printf("No key present");
else {
if (dtoh32(u.key.flags) & WL_SOFT_KEY)
printf("soft ");
printf("len %d, data 0x", dtoh32(u.key.len));
for (j = 0; j < dtoh32(u.key.len); j++)
printf("%02X", u.key.data[j]);
for (j = 0; j < dtoh32(u.key.len); j++)
if (!isprint(u.key.data[j]))
break;
if (j == dtoh32(u.key.len))
printf(" (%.*s)", (int)dtoh32(u.key.len), u.key.data);
}
printf("\n");
}
return ret;
}
static int
wl_tsc(void *wl, cmd_t *cmd, char **argv)
{
union {
int32 index;
uint8 tsc[DOT11_WPA_KEY_RSC_LEN];
} u;
uint32 hi, lo;
int idx, ret;
if (!*++argv)
return BCME_USAGE_ERROR;
idx = atoi(*argv);
if (idx < 0) {
fprintf(stderr, "Key index %d out of range. Should be positive.\n", idx);
return BCME_BADARG;
}
u.index = htod32(idx);
if ((ret = wlu_get(wl, cmd->get, &u, sizeof(u))) < 0)
return ret;
lo = u.tsc[0] | (u.tsc[1] << 8) | (u.tsc[2] << 16) | (u.tsc[3] << 24);
hi = u.tsc[4] | (u.tsc[5] << 8) | (u.tsc[6] << 16) | (u.tsc[7] << 24);
printf("Key %d TSC: 0x%04x:%08x\n", idx, hi, lo);
return 0;
}