blob: 6085c4998f8b86220a600cd9081c899e40f63686 [file] [log] [blame]
/*
* wl pkt_filter 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_pkt_filter.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_pkt_filter_add;
static cmd_func_t wl_pkt_filter_enable;
static cmd_func_t wl_pkt_filter_list;
static cmd_func_t wl_pkt_filter_stats;
static cmd_func_t wl_pkt_filter_ports;
static cmd_t wl_pkt_filter_cmds[] = {
{ "pkt_filter_add", wl_pkt_filter_add, -1, -1,
"Install a packet filter.\n"
"\tUsage: wl pkt_filter_add <id> <polarity> <type> <offset> <bitmask> <pattern>\n"
"\tid: Integer. User specified id.\n"
"\ttype: 0 (Pattern matching filter)\n"
"\t 1 (Magic pattern match (variable offset)\n"
"\t 2 (Extended pattern list)\n"
"\t 4 (Android Packet Filter)\n"
"\t 5 (Pattern matching filter with timeout event)\n"
"\t 6 (Immediate Packet filter)\n"
"\toffset: (type 0): Integer offset in received packet to start matching.\n"
"\t (type 1): Integer offset, match here are anywhere later.\n"
"\t (type 2): [<base>:]<offset>. Symbolic packet loc plus relative\n"
"\t offset, use wl_pkt_filter_add -l for a <base> list.\n"
"\t (type 5): Integer offset in received packet to start matching.\n"
"\t (type 6): [<base>:]<offset>. Symbolic packet loc plus relative\n"
"\t offset, use wl_pkt_filter_add -l for a <base> list.\n"
"\tpolarity: Set to 1 to negate match result. 0 is default.\n"
"\tbitmask: Hex bitmask that indicates which bits of 'pattern' to match.\n"
"\t Must be same size as 'pattern'. Bit 0 of bitmask corresponds\n"
"\t to bit 0 of pattern, etc. If bit N of bitmask is 0, then do\n"
"\t *not* match bit N of the pattern with the received payload. If\n"
"\t bit N of bitmask is 1, then perform match.\n"
"\tpattern: Hex pattern to match. Must be same size as <bitmask>.\n"
"\t Syntax: same as bitmask, but for type 2 (pattern list), a '!'\n"
"\t may be used to negate that pattern match (e.g. !0xff03).\n"
"\tFor type 2 & 6: [<base>:]<offset> <bitmask> [!]<pattern> triple may be\n"
"\trepeated; all sub-patterns must match for the filter to match.\n"
"\tFor type 4: <id> <polarity> <type> <apf program> \n"
"\ttimeout: (type 5): Number of seconds to wait before sending a timeout event when\n"
"\t a matching pattern packet is not received.\n"},
{ "pkt_filter_clear_stats", wl_varint, -1, WLC_SET_VAR,
"Clear packet filter statistic counter values.\n"
"\tUsage: wl pkt_filter_clear_stats <id>" },
{ "pkt_filter_enable", wl_pkt_filter_enable, -1, -1,
"Enable/disable a packet filter.\n"
"\tUsage: wl pkt_filter_enable <id> <0|1>"},
{ "pkt_filter_list", wl_pkt_filter_list, -1, -1,
"List installed packet filters.\n"
"\tUsage: wl pkt_filter_list [val]\n"
"\tval: 0 (disabled filters) 1 (enabled filters)"},
{ "pkt_filter_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
"Set packet filter match action.\n"
"\tUsage: wl pkt_filter_mode <value>\n"
"\tvalue: 1 - Forward packet on match, discard on non-match (default).\n"
"\t 0 - Discard packet on match, forward on non-match." },
{ "pkt_filter_delete", wl_varint, -1, WLC_SET_VAR,
"Uninstall a packet filter.\n"
"\tUsage: wl pkt_filter_delete <id>"},
{ "pkt_filter_stats", wl_pkt_filter_stats, -1, -1,
"Retrieve packet filter statistic counter values.\n"
"\tUsage: wl pkt_filter_stats <id>"},
{ "pkt_filter_ports", wl_pkt_filter_ports, WLC_GET_VAR, WLC_SET_VAR,
"Set up additional port filters for TCP and UDP packets.\n"
"\tUsage: wl pkt_filter_ports [<port-number>] ...\n"
"\t wl pkt_filter_ports none (to clear/disable)"},
{ NULL, NULL, 0, 0, NULL }
};
static char *buf;
/* module initialization */
void
wluc_pkt_filter_module_init(void)
{
/* get the global buf */
buf = wl_get_buf();
/* register pkt_filter commands */
wl_module_cmds_register(wl_pkt_filter_cmds);
}
/* Packet filter section: extended filters have named offsets, add table here */
typedef struct {
char *name;
uint16 base;
} wl_pfbase_t;
static wl_pfbase_t basenames[] = { WL_PKT_FILTER_BASE_NAMES };
static void
wl_pkt_filter_base_list(void)
{
uint i;
printf("Names accepted for base offsets:\n");
for (i = 0; i < ARRAYSIZE(basenames); i++)
{
printf("\t%s\n", basenames[i].name);
}
}
static int
wl_pkt_filter_base_parse(char *name)
{
uint i;
char *bname, *uname;
for (i = 0; i < ARRAYSIZE(basenames); i++) {
bname = basenames[i].name;
for (uname = name; *uname; bname++, uname++) {
if (*bname != toupper(*uname))
break;
}
if (!*uname && !*bname)
break;
}
if (i < ARRAYSIZE(basenames)) {
return basenames[i].base;
} else {
return -1;
}
}
static char *
wl_pkt_filter_base_show(uint16 base)
{
uint i;
static char numeric[6];
for (i = 0; i < ARRAYSIZE(basenames); i++) {
if (basenames[i].base == base)
return basenames[i].name;
}
sprintf(numeric, "%d", base);
return numeric;
}
/* Enable/disable installed packet filter. */
static int
wl_pkt_filter_enable(void *wl, cmd_t *cmd, char **argv)
{
wl_pkt_filter_enable_t enable_parm;
int rc;
if (*++argv == NULL) {
printf("No args provided\n");
return BCME_USAGE_ERROR;
}
/* Parse packet filter id. */
enable_parm.id = htod32(strtoul(*argv, NULL, 0));
if (*++argv == NULL) {
printf("Enable/disable value not provided\n");
return BCME_USAGE_ERROR;
}
/* Parse enable/disable value. */
enable_parm.enable = htod32(strtoul(*argv, NULL, 0));
/* Enable/disable the specified filter. */
rc = wlu_var_setbuf(wl,
cmd->name,
&enable_parm,
sizeof(wl_pkt_filter_enable_t));
return (rc);
}
/* Install a new packet filter. */
static int
wl_pkt_filter_add(void *wl, cmd_t *cmd, char **argv)
{
const char *str;
wl_pkt_filter_t pkt_filter;
wl_pkt_filter_t *pkt_filterp;
int buf_len;
int str_len;
int rc;
uint32 mask_size;
uint32 pattern_size;
uint ftype;
char *endptr;
UNUSED_PARAMETER(cmd);
str = "pkt_filter_add";
str_len = strlen(str);
strncpy(buf, str, str_len);
buf[ str_len ] = '\0';
buf_len = str_len + 1;
pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
if (argv[1] && strcmp(argv[1], "-l") == 0) {
wl_pkt_filter_base_list();
return BCME_OK;
}
/* Parse packet filter id. */
if (*++argv == NULL) {
printf("No args provided\n");
return BCME_USAGE_ERROR;
}
pkt_filter.id = htod32(strtoul(*argv, &endptr, 0));
if (*endptr) {
printf("Invalid number for id: %s\n", *argv);
return BCME_USAGE_ERROR;
}
/* Parse filter polarity. */
if (*++argv == NULL) {
printf("Polarity not provided\n");
return BCME_USAGE_ERROR;
}
pkt_filter.negate_match = htod32(strtoul(*argv, &endptr, 0));
if (*endptr) {
printf("Invalid number for polarity: %s\n", *argv);
return BCME_USAGE_ERROR;
}
/* Parse filter type. */
if (*++argv == NULL) {
printf("Filter type not provided\n");
return BCME_USAGE_ERROR;
}
pkt_filter.type = htod32(strtoul(*argv, &endptr, 0));
ftype = htod32(strtoul(*argv, &endptr, 0));
if (*endptr) {
printf("Invalid number for filter type: %s\n", *argv);
return BCME_USAGE_ERROR;
}
if ((ftype != WL_PKT_FILTER_TYPE_PATTERN_MATCH) &&
(ftype != WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH) &&
(ftype != WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH) &&
(ftype != WL_PKT_FILTER_TYPE_APF_MATCH) &&
(ftype != WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT) &&
(ftype != WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH)) {
printf("Invalid filter type %d\n", ftype);
return BCME_USAGE_ERROR;
}
pkt_filter.type = htod32(ftype);
/* Handle basic (or magic) pattern filter */
if ((ftype == WL_PKT_FILTER_TYPE_PATTERN_MATCH) ||
(ftype == WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH)) {
wl_pkt_filter_pattern_t *pfilter = &pkt_filterp->u.pattern;
/* Parse pattern filter offset. */
if (*++argv == NULL) {
printf("Offset not provided\n");
return BCME_USAGE_ERROR;
}
pkt_filter.u.pattern.offset = htod32(strtoul(*argv, &endptr, 0));
if (*endptr) {
printf("Invalid number for offset: %s\n", *argv);
return BCME_USAGE_ERROR;
}
/* Parse pattern filter mask. */
if (*++argv == NULL) {
printf("Bitmask not provided\n");
return BCME_USAGE_ERROR;
}
rc = wl_pattern_atoh(*argv, (char *)pfilter->mask_and_pattern);
if (rc == -1) {
printf("Rejecting: %s\n", *argv);
return BCME_USAGE_ERROR;
}
mask_size = htod32(rc);
/* Parse pattern filter pattern. */
if (*++argv == NULL) {
printf("Pattern not provided\n");
return BCME_USAGE_ERROR;
}
rc = wl_pattern_atoh(*argv, (char *)&pfilter->mask_and_pattern[rc]);
if (rc == -1) {
printf("Rejecting: %s\n", *argv);
return BCME_USAGE_ERROR;
}
pattern_size = htod32(rc);
if (mask_size != pattern_size) {
printf("Mask and pattern not the same size\n");
return BCME_USAGE_ERROR;
}
pkt_filter.u.pattern.size_bytes = mask_size;
buf_len += WL_PKT_FILTER_FIXED_LEN;
buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * rc);
/* The fields that were put in a local for alignment purposes now
* get copied to the right place in the ioctl buffer.
*/
memcpy((char *)pkt_filterp, &pkt_filter,
WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
}
/* Handle pattern list */
if ((ftype == WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH) ||
(ftype == WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH)) {
int list_cnt = 0;
wl_pkt_filter_pattern_listel_t *pf_el = &pkt_filterp->u.patlist.patterns[0];
while (*++argv != NULL) {
/* Parse pattern filter base and offset. */
if (isdigit(**argv)) {
/* Numeric base */
rc = strtoul(*argv, &endptr, 0);
} else {
endptr = strchr(*argv, ':');
if (endptr) {
*endptr = '\0';
rc = wl_pkt_filter_base_parse(*argv);
if (rc == -1) {
printf("Invalid base %s\n", *argv);
wl_pkt_filter_base_list();
return BCME_USAGE_ERROR;
}
*endptr = ':';
} else {
printf("Invalid [base:]offset format: %s\n", *argv);
return BCME_USAGE_ERROR;
}
}
if (*endptr == ':') {
pkt_filter.u.patlist.patterns[0].base_offs = htod16(rc);
rc = strtoul(endptr + 1, &endptr, 0);
} else {
/* Must have had a numeric offset only */
pkt_filter.u.patlist.patterns[0].base_offs = htod16(0);
}
if (*endptr) {
printf("Invalid [base:]offset format: %s\n", *argv);
return BCME_USAGE_ERROR;
}
if (rc > 0x0000FFFF) {
printf("Offset too large\n");
return BCME_USAGE_ERROR;
}
pkt_filter.u.patlist.patterns[0].rel_offs = htod16(rc);
/* Clear match_flag (may be set in parsing which follows) */
pkt_filter.u.patlist.patterns[0].match_flags = htod16(0);
/* Parse pattern filter mask and pattern directly into ioctl buffer */
if (*++argv == NULL) {
printf("Bitmask not provided\n");
return BCME_USAGE_ERROR;
}
rc = wl_pattern_atoh(*argv, (char*)pf_el->mask_and_data);
if (rc == -1) {
printf("Rejecting: %s\n", *argv);
return BCME_USAGE_ERROR;
}
mask_size = htod16(rc);
if (*++argv == NULL) {
printf("Pattern not provided\n");
return BCME_USAGE_ERROR;
}
if (**argv == '!') {
pkt_filter.u.patlist.patterns[0].match_flags =
htod16(WL_PKT_FILTER_MFLAG_NEG);
(*argv)++;
}
if (*argv == '\0') {
printf("Pattern not provided\n");
return BCME_USAGE_ERROR;
}
rc = wl_pattern_atoh(*argv, (char*)&pf_el->mask_and_data[rc]);
if (rc == -1) {
printf("Rejecting: %s\n", *argv);
return BCME_USAGE_ERROR;
}
pattern_size = htod16(rc);
if (mask_size != pattern_size) {
printf("Mask and pattern not the same size\n");
return BCME_USAGE_ERROR;
}
pkt_filter.u.patlist.patterns[0].size_bytes = mask_size;
/* Account for the size of this pattern element */
buf_len += WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc;
/* And the pattern element fields that were put in a local for
* alignment purposes now get copied to the ioctl buffer.
*/
memcpy((char*)pf_el, &pkt_filter.u.patlist.patterns[0],
WL_PKT_FILTER_PATTERN_FIXED_LEN);
/* Move to next element location in ioctl buffer */
pf_el = (wl_pkt_filter_pattern_listel_t*)
((uint8*)pf_el + WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc);
/* Count list element */
list_cnt++;
}
/* Account for initial fixed size, and copy initial fixed fields */
buf_len += WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN;
/* Update list count and total size */
pkt_filter.u.patlist.list_cnt = list_cnt;
pkt_filter.u.patlist.PAD1[0] = 0;
pkt_filter.u.patlist.totsize = buf + buf_len - (char*)pkt_filterp;
pkt_filter.u.patlist.totsize -= WL_PKT_FILTER_FIXED_LEN;
memcpy((char *)pkt_filterp, &pkt_filter,
WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN);
}
/* Android Packet Filter */
if (ftype == WL_PKT_FILTER_TYPE_APF_MATCH) {
wl_apf_program_t *apf_program = &pkt_filterp->u.apf_program;
char *token = *++argv;
int count;
char num[3];
if (strlen(token) % 2) {
printf("Invalid APF program length: %s\n", *argv);
return BCME_USAGE_ERROR;
}
for (count = 0; *token != '\0'; count++, token += 2) {
strncpy(num, token, 2);
num[2] = '\0';
apf_program->instrs[count] = (uint8)strtoul(num, NULL, 16);
}
apf_program->instr_len = htod16(count);
apf_program->version = htod16(WL_APF_INTERNAL_VERSION);
buf_len += WL_PKT_FILTER_FIXED_LEN;
buf_len += WL_APF_PROGRAM_TOTAL_LEN(apf_program);
memcpy((char *)pkt_filterp, &pkt_filter, WL_PKT_FILTER_FIXED_LEN);
}
/* Handle pattern filter with timeout event */
if (ftype == WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT) {
wl_pkt_filter_pattern_timeout_t *pfilter = &pkt_filterp->u.pattern_timeout;
/* Parse pattern filter offset. */
if (*++argv == NULL) {
printf("Offset not provided\n");
return BCME_USAGE_ERROR;
}
pkt_filter.u.pattern.offset = htod32(strtoul(*argv, &endptr, 0));
if (*endptr) {
printf("Invalid number for offset: %s\n", *argv);
return BCME_USAGE_ERROR;
}
/* Parse pattern filter mask. */
if (*++argv == NULL) {
printf("Bitmask not provided\n");
return BCME_USAGE_ERROR;
}
rc = wl_pattern_atoh(*argv, (char *)pfilter->mask_and_pattern);
if (rc == -1) {
printf("Rejecting: %s\n", *argv);
return BCME_USAGE_ERROR;
}
mask_size = htod32(rc);
/* Parse pattern filter pattern. */
if (*++argv == NULL) {
printf("Pattern not provided\n");
return BCME_USAGE_ERROR;
}
rc = wl_pattern_atoh(*argv, (char *)&pfilter->mask_and_pattern[rc]);
if (rc == -1) {
printf("Rejecting: %s\n", *argv);
return BCME_USAGE_ERROR;
}
pattern_size = htod32(rc);
if (mask_size != pattern_size) {
printf("Mask and pattern not the same size\n");
return BCME_USAGE_ERROR;
}
if (*++argv == NULL) {
printf("timeout not specified\n");
return BCME_USAGE_ERROR;
}
pkt_filter.u.pattern_timeout.timeout = htod32(strtoul(*argv, &endptr, 0));
pkt_filter.u.pattern.size_bytes = mask_size;
buf_len += WL_PKT_FILTER_FIXED_LEN;
buf_len += (WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN + 2 * rc);
/* The fields that were put in a local for alignment purposes now
* get copied to the right place in the ioctl buffer.
*/
memcpy((char *)pkt_filterp, &pkt_filter,
WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN);
}
rc = wlu_set(wl, WLC_SET_VAR, buf, buf_len);
return (rc);
}
/* List installed packet filters. */
static void
wl_pkt_filter_list_mask_pat(uint8 *bytes, uint size, char *indent)
{
uint j;
printf("%sMask :0x", indent);
for (j = 0; j < size; j++)
printf("%02x", bytes[j]);
printf("\n%sPattern :0x", indent);
for (; j < 2 * size; j++)
printf("%02x", bytes[j]);
printf("\n\n");
}
/* List installed packet filters. */
static int
wl_pkt_filter_list(void *wl, cmd_t *cmd, char **argv)
{
wl_pkt_filter_list_t *list;
wl_pkt_filter_t *filterp;
void *ptr = NULL;
unsigned int i;
unsigned int j;
int rc;
unsigned int filter_len;
uint32 enable;
if (*++argv == NULL) {
printf("No args provided\n");
return (BCME_USAGE_ERROR);
}
/* Parse filter list to retrieve (enabled/disabled). */
enable = htod32(strtoul(*argv, NULL, 0));
/*
** Get list of installed packet filters.
*/
if ((rc = wlu_var_getbuf(wl, cmd->name, &enable, sizeof(enable), &ptr)) < 0)
return rc;
list = (wl_pkt_filter_list_t *) ptr;
printf("Num filters: %d\n\n", list->num);
filterp = list->filter;
for (i = 0; i < list->num; i++)
{
uint type = dtoh32(filterp->type);
if (type == WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT) {
printf("Id :%d\n"
"Negate :%d\n"
"Type :%d\n"
"Offset :%d\n"
"Pattern len :%d\n"
"Timeout :%d seconds\n",
dtoh32(filterp->id),
dtoh32(filterp->negate_match),
dtoh32(filterp->type),
dtoh32(filterp->u.pattern_timeout.offset),
dtoh32(filterp->u.pattern_timeout.size_bytes),
dtoh32(filterp->u.pattern_timeout.timeout));
wl_pkt_filter_list_mask_pat(filterp->u.pattern_timeout.mask_and_pattern,
dtoh32(filterp->u.pattern_timeout.size_bytes), "");
filter_len = WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN +
2 * dtoh32(filterp->u.pattern_timeout.size_bytes);
} else if (type == WL_PKT_FILTER_TYPE_APF_MATCH) {
wl_apf_program_t *apf_program;
uint8 *pc;
uint16 len;
apf_program = &filterp->u.apf_program;
pc = apf_program->instrs;
len = dtoh16(apf_program->instr_len);
if (dtoh16(apf_program->version) != WL_APF_INTERNAL_VERSION) {
printf("%s: APF: incorrect version, version=%d, "
"expected version=%d\n", __FUNCTION__,
dtoh16(apf_program->version), WL_APF_INTERNAL_VERSION);
rc = BCME_BADARG;
break;
}
printf("Id :%d\n"
"Negate :%d\n"
"Type :%d\n"
"Program len :%d\n",
dtoh32(filterp->id),
dtoh32(filterp->negate_match),
dtoh32(filterp->type),
len);
printf("Program :");
for (j = 0; pc && (j < len); pc++, j++) {
printf("%02X", *pc);
}
printf("\n\n");
filter_len = WL_APF_PROGRAM_TOTAL_LEN(apf_program);
} else if ((type == WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH) ||
(type == WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH)) {
char *indent = " ";
uint cnt = filterp->u.patlist.list_cnt;
wl_pkt_filter_pattern_listel_t *listel = filterp->u.patlist.patterns;
printf("Id :%d\n"
"Negate :%d\n"
"Type :%d\n"
"List count :%d\n",
dtoh32(filterp->id),
dtoh32(filterp->negate_match),
dtoh32(filterp->type),
cnt);
for (j = 1; j <= cnt; j++) {
printf("%sPattern %d\n", indent, j);
printf("%sOffset :%s:%d\n"
"%sMatch flags :%04x\n"
"%sPattern len :%d\n",
indent, wl_pkt_filter_base_show(dtoh16(listel->base_offs)),
dtoh16(listel->rel_offs),
indent, dtoh16(listel->match_flags),
indent, dtoh16(listel->size_bytes));
wl_pkt_filter_list_mask_pat(listel->mask_and_data,
dtoh16(listel->size_bytes), indent);
listel = (wl_pkt_filter_pattern_listel_t*)
((uintptr)listel +
WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN +
2 * dtoh16(listel->size_bytes));
}
filter_len = (uint8*)listel - (uint8*)&filterp->u.patlist;
} else {
printf("Id :%d\n"
"Negate :%d\n"
"Type :%d\n"
"Offset :%d\n"
"Pattern len :%d\n",
dtoh32(filterp->id),
dtoh32(filterp->negate_match),
dtoh32(filterp->type),
dtoh32(filterp->u.pattern.offset),
dtoh32(filterp->u.pattern.size_bytes));
wl_pkt_filter_list_mask_pat(filterp->u.pattern.mask_and_pattern,
dtoh32(filterp->u.pattern.size_bytes), "");
filter_len = WL_PKT_FILTER_PATTERN_FIXED_LEN +
2 * dtoh32(filterp->u.pattern.size_bytes);
}
filter_len += WL_PKT_FILTER_FIXED_LEN;
filterp = (wl_pkt_filter_t *) ((uint8 *)filterp + filter_len);
filterp = ALIGN_ADDR(filterp, sizeof(uint32));
}
return (rc);
}
/* Get packet filter debug statistics. */
static int
wl_pkt_filter_stats(void *wl, cmd_t *cmd, char **argv)
{
wl_pkt_filter_stats_t *stats;
uint32 id;
int rc;
void *ptr = NULL;
if (*++argv == NULL) {
printf("No args provided\n");
return BCME_USAGE_ERROR;
}
/* Parse filter id to retrieve. */
id = htod32(strtoul(*argv, NULL, 0));
/* Get debug stats. */
if ((rc = wlu_var_getbuf(wl, cmd->name, &id, sizeof(id), &ptr)) < 0)
return rc;
stats = (wl_pkt_filter_stats_t *) ptr;
printf("Packets matched for filter '%d': %d\n"
"Total packets discarded : %d\n"
"Total packet forwarded : %d\n",
id,
dtoh32(stats->num_pkts_matched),
dtoh32(stats->num_pkts_discarded),
dtoh32(stats->num_pkts_forwarded));
return (rc);
}
/* Get/set packet filter port list */
static int
wl_pkt_filter_ports(void *wl, cmd_t *cmd, char **argv)
{
int rc, i;
void *ptr;
uint16 count;
uint16 *ports;
wl_pkt_filter_ports_t *portlist;
uint len;
char *endptr = NULL;
unsigned long portnum;
if ((strlen("pkt_filter_ports") + 1 +
WL_PKT_FILTER_PORTS_FIXED_LEN +
sizeof(uint16) * WL_PKT_FILTER_PORTS_MAX) > WLC_IOCTL_MEDLEN) {
fprintf(stderr, "Ioctl sizing error.\n");
return -1;
}
if (*++argv == NULL) {
/* Get iovar */
if ((rc = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)))
return rc;
portlist = (wl_pkt_filter_ports_t*)ptr;
count = dtoh16(portlist->count);
ports = &portlist->ports[0];
/* Bail if anything in the headeer is unexpected */
if (portlist->version != WL_PKT_FILTER_PORTS_VERSION) {
printf("Unsupported version %d, only support %d\n",
portlist->version, WL_PKT_FILTER_PORTS_VERSION);
return BCME_USAGE_ERROR;
}
if (portlist->reserved != 0) {
printf("Format error: nonzero reserved element 0x%02x\n",
portlist->reserved);
return BCME_USAGE_ERROR;
}
if (count > WL_PKT_FILTER_PORTS_MAX) {
printf("Invalid count %d\n", count);
return BCME_USAGE_ERROR;
}
printf("Port count %d:\n", count);
for (i = 0; i < count; i++) {
printf("%d\n", dtoh16(ports[i]));
}
return 0;
} else {
/* Set iovar - build the structure in the global buffer */
portlist = (wl_pkt_filter_ports_t*)buf;
portlist->version = WL_PKT_FILTER_PORTS_VERSION;
portlist->reserved = 0;
ports = &portlist->ports[0];
for (count = 0; *argv && (count < WL_PKT_FILTER_PORTS_MAX); count++, argv++) {
portnum = strtoul(*argv, &endptr, 0);
if ((*endptr != '\0') || (portnum > 0xffff)) {
if (!strcmp(*argv, "none")) {
argv += 1;
break;
} else {
printf("Bad port number %s\n", *argv);
return BCME_USAGE_ERROR;
}
}
ports[count] = htod16((uint16)portnum);
}
if (*argv) {
printf("Too many port numbers!\n");
return BCME_USAGE_ERROR;
}
portlist->count = htod16(count);
len = WL_PKT_FILTER_PORTS_FIXED_LEN + (count * sizeof(uint16));
memmove((buf + strlen("pkt_filter_ports") + 1), buf, len);
strcpy(buf, "pkt_filter_ports");
len += strlen("pkt_filter_ports") + 1;
return wlu_set(wl, WLC_SET_VAR, buf, len);
}
}