mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-11-15 11:35:35 +00:00
33d9f8e4f3
Add initial MxM (multi-chip-multi-interface) wifi driver. The driver target is to support 88w8987/88w8997/88w9098, currently it only supports 88w8987. The MxM wifi driver is merged from below repo and applied some patches for block and build issues. ssh://git@bitbucket.sw.nxp.com/wcswrel/ rel-nxp-wifi-fp92-bt-fp85-linux-android-mxm4x17169-gpl.git The sdk only includes application, the driver already is merged into linux kernel. Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
1167 lines
31 KiB
C
1167 lines
31 KiB
C
/** @file mlanmisc.c
|
|
*
|
|
* @brief Program to prepare command buffer
|
|
*
|
|
*
|
|
* Copyright 2014-2020 NXP
|
|
*
|
|
* NXP CONFIDENTIAL
|
|
* The source code contained or described herein and all documents related to
|
|
* the source code (Materials) are owned by NXP, its
|
|
* suppliers and/or its licensors. Title to the Materials remains with NXP,
|
|
* its suppliers and/or its licensors. The Materials contain
|
|
* trade secrets and proprietary and confidential information of NXP, its
|
|
* suppliers and/or its licensors. The Materials are protected by worldwide copyright
|
|
* and trade secret laws and treaty provisions. No part of the Materials may be
|
|
* used, copied, reproduced, modified, published, uploaded, posted,
|
|
* transmitted, distributed, or disclosed in any way without NXP's prior
|
|
* express written permission.
|
|
*
|
|
* No license under any patent, copyright, trade secret or other intellectual
|
|
* property right is granted to or conferred upon you by disclosure or delivery
|
|
* of the Materials, either expressly, by implication, inducement, estoppel or
|
|
* otherwise. Any license under such intellectual property rights must be
|
|
* express and approved by NXP in writing.
|
|
*
|
|
*/
|
|
|
|
/************************************************************************
|
|
Change log:
|
|
03/10/2009: initial version
|
|
************************************************************************/
|
|
|
|
#include "mlanconfig.h"
|
|
#include "mlanhostcmd.h"
|
|
#include "mlanmisc.h"
|
|
|
|
/********************************************************
|
|
Local Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Global Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Local Functions
|
|
********************************************************/
|
|
|
|
/**
|
|
* @brief Helper function for process_getscantable_idx
|
|
*
|
|
* @param pbuf A pointer to the buffer
|
|
* @param buf_len buffer length
|
|
*
|
|
* @return NA
|
|
*
|
|
*/
|
|
static void
|
|
dump_scan_elems(const t_u8 *pbuf, uint buf_len)
|
|
{
|
|
uint idx;
|
|
uint marker = 2 + pbuf[1];
|
|
|
|
for (idx = 0; idx < buf_len; idx++) {
|
|
if (idx % 0x10 == 0) {
|
|
printf("\n%04x: ", idx);
|
|
}
|
|
|
|
if (idx == marker) {
|
|
printf("|");
|
|
marker = idx + pbuf[idx + 1] + 2;
|
|
} else {
|
|
printf(" ");
|
|
}
|
|
|
|
printf("%02x ", pbuf[idx]);
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function for process_getscantable_idx
|
|
* Find next element
|
|
*
|
|
* @param pp_ie_out pointer of a IEEEtypes_Generic_t structure pointer
|
|
* @param p_buf_left integer pointer, which contains the number of left p_buf
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE
|
|
*/
|
|
static int
|
|
scantable_elem_next(IEEEtypes_Generic_t **pp_ie_out, int *p_buf_left)
|
|
{
|
|
IEEEtypes_Generic_t *pie_gen;
|
|
t_u8 *p_next;
|
|
|
|
if (*p_buf_left < 2) {
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
pie_gen = *pp_ie_out;
|
|
|
|
p_next = (t_u8 *)pie_gen + (pie_gen->ieee_hdr.len
|
|
+ sizeof(pie_gen->ieee_hdr));
|
|
*p_buf_left -= (p_next - (t_u8 *)pie_gen);
|
|
|
|
*pp_ie_out = (IEEEtypes_Generic_t *)p_next;
|
|
|
|
if (*p_buf_left <= 0) {
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function for process_getscantable_idx
|
|
* scantable find element
|
|
*
|
|
* @param ie_buf pointer of the IE buffer
|
|
* @param ie_buf_len IE buffer length
|
|
* @param ie_type IE type
|
|
* @param ppie_out pointer to the IEEEtypes_Generic_t structure pointer
|
|
* @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE
|
|
*/
|
|
static int
|
|
scantable_find_elem(t_u8 *ie_buf,
|
|
unsigned int ie_buf_len,
|
|
IEEEtypes_ElementId_e ie_type,
|
|
IEEEtypes_Generic_t **ppie_out)
|
|
{
|
|
int found;
|
|
unsigned int ie_buf_left;
|
|
|
|
ie_buf_left = ie_buf_len;
|
|
|
|
found = FALSE;
|
|
|
|
*ppie_out = (IEEEtypes_Generic_t *)ie_buf;
|
|
|
|
do {
|
|
found = ((*ppie_out)->ieee_hdr.element_id == ie_type);
|
|
|
|
} while (!found &&
|
|
(scantable_elem_next(ppie_out, (int *)&ie_buf_left) == 0));
|
|
|
|
if (!found) {
|
|
*ppie_out = NULL;
|
|
}
|
|
|
|
return (found ? MLAN_STATUS_SUCCESS : MLAN_STATUS_FAILURE);
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function for process_getscantable_idx
|
|
* It gets SSID from IE
|
|
*
|
|
* @param ie_buf IE buffer
|
|
* @param ie_buf_len IE buffer length
|
|
* @param pssid SSID
|
|
* @param ssid_buf_max size of SSID
|
|
* @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE
|
|
*/
|
|
static int
|
|
scantable_get_ssid_from_ie(t_u8 *ie_buf,
|
|
unsigned int ie_buf_len,
|
|
t_u8 *pssid, unsigned int ssid_buf_max)
|
|
{
|
|
int retval;
|
|
IEEEtypes_Generic_t *pie_gen;
|
|
|
|
retval = scantable_find_elem(ie_buf, ie_buf_len, SSID, &pie_gen);
|
|
if (retval == MLAN_STATUS_SUCCESS)
|
|
memcpy(pssid, pie_gen->data,
|
|
MIN(pie_gen->ieee_hdr.len, ssid_buf_max));
|
|
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* @brief Display detailed information for a specific scan table entry
|
|
*
|
|
* @param prsp_info_req Scan table entry request structure
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
int
|
|
process_getscantable_idx(wlan_ioctl_get_scan_table_info *prsp_info_req)
|
|
{
|
|
int ioctl_val, subioctl_val;
|
|
struct iwreq iwr;
|
|
t_u8 *pcurrent;
|
|
int ret = 0;
|
|
char ssid[33];
|
|
t_u16 tmp_cap;
|
|
t_u8 tsf[8];
|
|
t_u16 beacon_interval;
|
|
t_u8 *scan_rsp_buf = NULL;
|
|
t_u16 cap_info;
|
|
wlan_ioctl_get_scan_table_info *prsp_info;
|
|
|
|
wlan_get_scan_table_fixed fixed_fields;
|
|
t_u32 fixed_field_length;
|
|
t_u32 bss_info_length;
|
|
|
|
scan_rsp_buf = (t_u8 *)malloc(SCAN_RESP_BUF_SIZE);
|
|
if (scan_rsp_buf == NULL) {
|
|
printf("Error: allocate memory for scan_rsp_buf failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
memset(ssid, 0x00, sizeof(ssid));
|
|
|
|
prsp_info = (wlan_ioctl_get_scan_table_info *)scan_rsp_buf;
|
|
|
|
memcpy(prsp_info, prsp_info_req,
|
|
sizeof(wlan_ioctl_get_scan_table_info));
|
|
|
|
if (get_priv_ioctl("getscantable",
|
|
&ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
|
|
ret = -EOPNOTSUPP;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* Set up and execute the ioctl call
|
|
*/
|
|
strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1);
|
|
iwr.u.data.pointer = (caddr_t) prsp_info;
|
|
iwr.u.data.length = SCAN_RESP_BUF_SIZE;
|
|
iwr.u.data.flags = subioctl_val;
|
|
|
|
if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
|
|
perror("mlanconfig: getscantable ioctl");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
if (prsp_info->scan_number == 0) {
|
|
printf("mlanconfig: getscantable ioctl - index out of range\n");
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
pcurrent = prsp_info->scan_table_entry_buf;
|
|
|
|
memcpy((t_u8 *)&fixed_field_length,
|
|
(t_u8 *)pcurrent, sizeof(fixed_field_length));
|
|
pcurrent += sizeof(fixed_field_length);
|
|
|
|
memcpy((t_u8 *)&bss_info_length,
|
|
(t_u8 *)pcurrent, sizeof(bss_info_length));
|
|
pcurrent += sizeof(bss_info_length);
|
|
|
|
memcpy((t_u8 *)&fixed_fields, (t_u8 *)pcurrent, sizeof(fixed_fields));
|
|
pcurrent += fixed_field_length;
|
|
|
|
/* time stamp is 8 byte long */
|
|
memcpy(tsf, pcurrent, sizeof(tsf));
|
|
pcurrent += sizeof(tsf);
|
|
bss_info_length -= sizeof(tsf);
|
|
|
|
/* beacon interval is 2 byte long */
|
|
memcpy(&beacon_interval, pcurrent, sizeof(beacon_interval));
|
|
pcurrent += sizeof(beacon_interval);
|
|
bss_info_length -= sizeof(beacon_interval);
|
|
|
|
/* capability information is 2 byte long */
|
|
memcpy(&cap_info, pcurrent, sizeof(cap_info));
|
|
pcurrent += sizeof(cap_info);
|
|
bss_info_length -= sizeof(cap_info);
|
|
|
|
scantable_get_ssid_from_ie(pcurrent,
|
|
bss_info_length, (t_u8 *)ssid, sizeof(ssid));
|
|
|
|
printf("\n*** [%s], %02x:%02x:%02x:%02x:%02x:%2x\n",
|
|
ssid,
|
|
fixed_fields.bssid[0],
|
|
fixed_fields.bssid[1],
|
|
fixed_fields.bssid[2],
|
|
fixed_fields.bssid[3],
|
|
fixed_fields.bssid[4], fixed_fields.bssid[5]);
|
|
memcpy(&tmp_cap, &cap_info, sizeof(tmp_cap));
|
|
printf("Channel = %d, SS = %d, CapInfo = 0x%04x, BcnIntvl = %d\n",
|
|
fixed_fields.channel,
|
|
255 - fixed_fields.rssi, tmp_cap, beacon_interval);
|
|
|
|
printf("TSF Values: AP(0x%02x%02x%02x%02x%02x%02x%02x%02x), ",
|
|
tsf[7], tsf[6], tsf[5], tsf[4], tsf[3], tsf[2], tsf[1], tsf[0]);
|
|
|
|
printf("Network(0x%016llx)\n", fixed_fields.network_tsf);
|
|
printf("\n");
|
|
printf("Element Data (%d bytes)\n", (int)bss_info_length);
|
|
printf("------------");
|
|
dump_scan_elems(pcurrent, bss_info_length);
|
|
printf("\n");
|
|
|
|
done:
|
|
|
|
if (scan_rsp_buf)
|
|
free(scan_rsp_buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/********************************************************
|
|
Global Functions
|
|
********************************************************/
|
|
#ifdef SDIO
|
|
/** Maximum SDIO command-52 buffer length */
|
|
#define CMD52_BUF_LEN 3
|
|
|
|
/**
|
|
* @brief SD comand52 read/write
|
|
* @param argc number of arguments
|
|
* @param argv A pointer to arguments array
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
int
|
|
process_sdcmd52rw(int argc, char *argv[])
|
|
{
|
|
struct iwreq iwr;
|
|
int ioctl_val, subioctl_val, buf[CMD52_BUF_LEN];
|
|
|
|
if (get_priv_ioctl("sdcmd52rw",
|
|
&ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
if (argc == 5) {
|
|
/* CMD52 read */
|
|
iwr.u.data.length = CMD52_BUF_LEN - 1;
|
|
} else if (argc == 6) {
|
|
/* CMD52 write */
|
|
buf[2] = atoval(argv[5]); /* data */
|
|
iwr.u.data.length = CMD52_BUF_LEN;
|
|
} else {
|
|
fprintf(stderr, "Invalid number of parameters!\n");
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
buf[0] = atoval(argv[3]); /* func */
|
|
buf[1] = atoval(argv[4]); /* reg */
|
|
strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1);
|
|
iwr.u.data.flags = subioctl_val;
|
|
iwr.u.data.pointer = (caddr_t) buf;
|
|
|
|
if (ioctl(sockfd, ioctl_val, &iwr)) {
|
|
perror("mlanconfig");
|
|
fprintf(stderr,
|
|
"mlanconfig: CMD52 R/W not supported by "
|
|
"interface %s\n", dev_name);
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
printf("sdcmd52rw returns 0x%02X\n", buf[0]);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/** Maximum SDIO command-53 buffer length */
|
|
#define CMD53_BUF_LEN 2000
|
|
|
|
/**
|
|
* @brief SD comand53 read/write
|
|
*
|
|
* @param argc number of arguments
|
|
* @param argv A pointer to arguments array
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
int
|
|
process_sdcmd53rw(int argc, char *argv[])
|
|
{
|
|
struct iwreq iwr;
|
|
t_s8 *buf = NULL;
|
|
int addr, mode, blklen, blknum, i, rw;
|
|
int ioctl_val, subioctl_val;
|
|
|
|
if (get_priv_ioctl("sdcmd53rw",
|
|
&ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
if (argc < 8) {
|
|
fprintf(stderr, "Invalid number of parameters!\n");
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (!(buf = malloc(CMD53_BUF_LEN)))
|
|
return -ENOMEM;
|
|
memset(buf, 0, CMD53_BUF_LEN);
|
|
|
|
if (argc == 8) {
|
|
rw = buf[0] = 0; /* CMD53 read */
|
|
} else {
|
|
rw = buf[0] = 1; /* CMD53 write */
|
|
}
|
|
buf[1] = atoval(argv[3]); /* func */
|
|
addr = atoval(argv[4]); /* address */
|
|
buf[2] = addr & 0xff;
|
|
buf[3] = (addr >> 8) & 0xff;
|
|
buf[4] = (addr >> 16) & 0xff;
|
|
buf[5] = (addr >> 24) & 0xff;
|
|
mode = atoval(argv[5]); /* mode */
|
|
buf[6] = (t_u8)mode;
|
|
blklen = atoval(argv[6]); /* block size */
|
|
buf[7] = blklen & 0xff;
|
|
buf[8] = (blklen >> 8) & 0xff;
|
|
blknum = atoval(argv[7]); /* block number or byte number */
|
|
buf[9] = blknum & 0xff;
|
|
buf[10] = (blknum >> 8) & 0xff;
|
|
iwr.u.data.length = 11;
|
|
if (buf[0]) {
|
|
for (i = 0; i < (argc - 8); i++)
|
|
buf[11 + i] = atoval(argv[8 + i]);
|
|
iwr.u.data.length += (argc - 8);
|
|
}
|
|
strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1);
|
|
iwr.u.data.flags = subioctl_val;
|
|
iwr.u.data.pointer = (caddr_t) buf;
|
|
|
|
if (ioctl(sockfd, ioctl_val, &iwr)) {
|
|
perror("mlanconfig");
|
|
fprintf(stderr,
|
|
"mlanconfig: CMD53 R/W not supported by "
|
|
"interface %s\n", dev_name);
|
|
free(buf);
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (mode) {
|
|
fprintf(stderr, "CMD53rw blklen = %d, blknum = %d\n", blklen,
|
|
blknum);
|
|
} else {
|
|
blklen = 1;
|
|
fprintf(stderr, "CMD53rw bytelen = %d\n", blknum);
|
|
}
|
|
if (!rw)
|
|
hexdump("data", buf, blklen * blknum, ' ');
|
|
|
|
free(buf);
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief Retrieve and display the contents of the driver scan table.
|
|
*
|
|
* The ioctl to retrieve the scan table contents will be invoked, and portions
|
|
* of the scan data will be displayed on stdout. The entire beacon or
|
|
* probe response is also retrieved (if available in the driver). This
|
|
* data would be needed in case the application was explicitly controlling
|
|
* the association (inserting IEs, TLVs, etc).
|
|
*
|
|
* @param argc number of arguments
|
|
* @param argv A pointer to arguments array
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
int
|
|
process_getscantable(int argc, char *argv[])
|
|
{
|
|
int ioctl_val, subioctl_val;
|
|
struct iwreq iwr;
|
|
t_u8 *scan_rsp_buf = NULL;
|
|
|
|
struct wlan_ioctl_get_scan_list *scan_list_head = NULL;
|
|
struct wlan_ioctl_get_scan_list *scan_list_node = NULL;
|
|
struct wlan_ioctl_get_scan_list *curr = NULL, *prev = NULL, *next =
|
|
NULL;
|
|
|
|
t_u32 total_scan_res = 0;
|
|
|
|
unsigned int scan_start;
|
|
int idx, ret = 0;
|
|
|
|
t_u8 *pcurrent;
|
|
t_u8 *pnext;
|
|
IEEEtypes_ElementId_e *pelement_id;
|
|
t_u8 *pelement_len;
|
|
int ssid_idx;
|
|
t_u8 *pbyte;
|
|
t_u16 new_ss;
|
|
t_u16 curr_ss;
|
|
|
|
IEEEtypes_VendorSpecific_t *pwpa_ie;
|
|
const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
|
|
|
|
IEEEtypes_WmmParameter_t *pwmm_ie;
|
|
const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
|
|
IEEEtypes_VendorSpecific_t *pwps_ie;
|
|
const t_u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
|
|
|
|
int displayed_info;
|
|
|
|
wlan_ioctl_get_scan_table_info rspInfoReq;
|
|
wlan_ioctl_get_scan_table_info *prsp_info;
|
|
|
|
wlan_get_scan_table_fixed fixed_fields;
|
|
t_u32 fixed_field_length;
|
|
t_u32 bss_info_length;
|
|
wlan_ioctl_get_bss_info *bss_info;
|
|
|
|
scan_rsp_buf = (t_u8 *)malloc(SCAN_RESP_BUF_SIZE);
|
|
if (scan_rsp_buf == NULL) {
|
|
printf("Error: allocate memory for scan_rsp_buf failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
prsp_info = (wlan_ioctl_get_scan_table_info *)scan_rsp_buf;
|
|
|
|
if (get_priv_ioctl("getscantable",
|
|
&ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
|
|
ret = -EOPNOTSUPP;
|
|
goto done;
|
|
}
|
|
|
|
if (argc > 3 && (strcmp(argv[3], "tsf") != 0)
|
|
&& (strcmp(argv[3], "help") != 0)) {
|
|
|
|
idx = strtol(argv[3], NULL, 10);
|
|
|
|
if (idx >= 0) {
|
|
if (scan_rsp_buf) {
|
|
free(scan_rsp_buf);
|
|
}
|
|
rspInfoReq.scan_number = idx;
|
|
return process_getscantable_idx(&rspInfoReq);
|
|
}
|
|
}
|
|
|
|
displayed_info = FALSE;
|
|
scan_start = 1;
|
|
|
|
do {
|
|
prsp_info->scan_number = scan_start;
|
|
|
|
/*
|
|
* Set up and execute the ioctl call
|
|
*/
|
|
strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1);
|
|
iwr.u.data.pointer = (caddr_t) prsp_info;
|
|
iwr.u.data.length = SCAN_RESP_BUF_SIZE;
|
|
iwr.u.data.flags = subioctl_val;
|
|
|
|
if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
|
|
perror("mlanconfig: getscantable ioctl");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
total_scan_res += prsp_info->scan_number;
|
|
|
|
pcurrent = 0;
|
|
pnext = prsp_info->scan_table_entry_buf;
|
|
|
|
for (idx = 0; (unsigned int)idx < prsp_info->scan_number; idx++) {
|
|
|
|
/* Alloc memory for new node for next BSS */
|
|
scan_list_node = (struct wlan_ioctl_get_scan_list *)
|
|
malloc(sizeof(struct wlan_ioctl_get_scan_list));
|
|
if (scan_list_node == NULL) {
|
|
printf("Error: allocate memory for scan_list_head failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
memset(scan_list_node, 0,
|
|
sizeof(struct wlan_ioctl_get_scan_list));
|
|
|
|
/*
|
|
* Set pcurrent to pnext in case pad bytes are at the end
|
|
* of the last IE we processed.
|
|
*/
|
|
pcurrent = pnext;
|
|
|
|
/* Start extracting each BSS to prepare a linked list */
|
|
memcpy((t_u8 *)&fixed_field_length,
|
|
(t_u8 *)pcurrent, sizeof(fixed_field_length));
|
|
pcurrent += sizeof(fixed_field_length);
|
|
|
|
memcpy((t_u8 *)&bss_info_length,
|
|
(t_u8 *)pcurrent, sizeof(bss_info_length));
|
|
pcurrent += sizeof(bss_info_length);
|
|
|
|
memcpy((t_u8 *)&fixed_fields,
|
|
(t_u8 *)pcurrent, sizeof(fixed_fields));
|
|
pcurrent += fixed_field_length;
|
|
|
|
scan_list_node->fixed_buf.fixed_field_length =
|
|
fixed_field_length;
|
|
scan_list_node->fixed_buf.bss_info_length =
|
|
bss_info_length;
|
|
scan_list_node->fixed_buf.fixed_fields = fixed_fields;
|
|
|
|
bss_info = &scan_list_node->bss_info_buf;
|
|
|
|
/* Set next to be the start of the next scan entry */
|
|
pnext = pcurrent + bss_info_length;
|
|
|
|
if (bss_info_length >=
|
|
(sizeof(bss_info->tsf) +
|
|
sizeof(bss_info->beacon_interval) +
|
|
sizeof(bss_info->cap_info))) {
|
|
|
|
/* time stamp is 8 byte long */
|
|
memcpy(bss_info->tsf, pcurrent,
|
|
sizeof(bss_info->tsf));
|
|
pcurrent += sizeof(bss_info->tsf);
|
|
bss_info_length -= sizeof(bss_info->tsf);
|
|
|
|
/* beacon interval is 2 byte long */
|
|
memcpy(&bss_info->beacon_interval, pcurrent,
|
|
sizeof(bss_info->beacon_interval));
|
|
pcurrent += sizeof(bss_info->beacon_interval);
|
|
bss_info_length -=
|
|
sizeof(bss_info->beacon_interval);
|
|
|
|
/* capability information is 2 byte long */
|
|
memcpy(&bss_info->cap_info, pcurrent,
|
|
sizeof(bss_info->cap_info));
|
|
pcurrent += sizeof(bss_info->cap_info);
|
|
bss_info_length -= sizeof(bss_info->cap_info);
|
|
}
|
|
|
|
bss_info->wmm_cap = ' '; /* M (WMM), C (WMM-Call Admission Control) */
|
|
bss_info->wps_cap = ' '; /* "S" */
|
|
bss_info->dot11k_cap = ' '; /* "K" */
|
|
bss_info->dot11r_cap = ' '; /* "R" */
|
|
bss_info->ht_cap = ' '; /* "N" */
|
|
|
|
/* "P" for Privacy (WEP) since "W" is WPA, and "2" is RSN/WPA2 */
|
|
bss_info->priv_cap =
|
|
bss_info->cap_info.privacy ? 'P' : ' ';
|
|
|
|
memset(bss_info->ssid, 0, MRVDRV_MAX_SSID_LENGTH + 1);
|
|
bss_info->ssid_len = 0;
|
|
|
|
while (bss_info_length >= 2) {
|
|
pelement_id = (IEEEtypes_ElementId_e *)pcurrent;
|
|
pelement_len = pcurrent + 1;
|
|
pcurrent += 2;
|
|
|
|
switch (*pelement_id) {
|
|
|
|
case SSID:
|
|
if (*pelement_len &&
|
|
*pelement_len <=
|
|
MRVDRV_MAX_SSID_LENGTH) {
|
|
memcpy(bss_info->ssid, pcurrent,
|
|
*pelement_len);
|
|
bss_info->ssid_len =
|
|
*pelement_len;
|
|
}
|
|
break;
|
|
|
|
case WPA_IE:
|
|
pwpa_ie =
|
|
(IEEEtypes_VendorSpecific_t *)
|
|
pelement_id;
|
|
if ((memcmp
|
|
(pwpa_ie->vend_hdr.oui, wpa_oui,
|
|
sizeof(pwpa_ie->vend_hdr.oui)) ==
|
|
0)
|
|
&& (pwpa_ie->vend_hdr.oui_type ==
|
|
wpa_oui[3])) {
|
|
/* WPA IE found, 'W' for WPA */
|
|
bss_info->priv_cap = 'W';
|
|
} else {
|
|
pwmm_ie =
|
|
(IEEEtypes_WmmParameter_t
|
|
*)pelement_id;
|
|
if ((memcmp
|
|
(pwmm_ie->vend_hdr.oui,
|
|
wmm_oui,
|
|
sizeof(pwmm_ie->vend_hdr.
|
|
oui)) == 0)
|
|
&& (pwmm_ie->vend_hdr.
|
|
oui_type ==
|
|
wmm_oui[3])) {
|
|
/* Check the subtype: 1 == parameter, 0 == info */
|
|
if ((pwmm_ie->vend_hdr.
|
|
oui_subtype == 1)
|
|
&& pwmm_ie->
|
|
ac_params
|
|
[WMM_AC_VO].
|
|
aci_aifsn.acm) {
|
|
/* Call admission on VO; 'C' for CAC */
|
|
bss_info->
|
|
wmm_cap
|
|
= 'C';
|
|
} else {
|
|
/* No CAC; 'M' for uh, WMM */
|
|
bss_info->
|
|
wmm_cap
|
|
= 'M';
|
|
}
|
|
} else {
|
|
pwps_ie =
|
|
(IEEEtypes_VendorSpecific_t
|
|
*)pelement_id;
|
|
if ((memcmp
|
|
(pwps_ie->vend_hdr.
|
|
oui, wps_oui,
|
|
sizeof(pwps_ie->
|
|
vend_hdr.
|
|
oui)) == 0)
|
|
&& (pwps_ie->
|
|
vend_hdr.
|
|
oui_type ==
|
|
wps_oui[3])) {
|
|
bss_info->
|
|
wps_cap
|
|
= 'S';
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RSN_IE:
|
|
/* RSN IE found; '2' for WPA2 (RSN) */
|
|
bss_info->priv_cap = '2';
|
|
break;
|
|
case HT_CAPABILITY:
|
|
bss_info->ht_cap = 'N';
|
|
break;
|
|
case VHT_CAPABILITY:
|
|
bss_info->vht_cap[0] = 'A';
|
|
bss_info->vht_cap[1] = 'C';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
pcurrent += *pelement_len;
|
|
bss_info_length -= (2 + *pelement_len);
|
|
}
|
|
|
|
/* Create a sorted list of BSS using Insertion Sort.
|
|
Sort as per Signal Strength (descending order) */
|
|
new_ss = 255 - fixed_fields.rssi;
|
|
|
|
if (scan_list_head == NULL) {
|
|
// Node is the first element in the list.
|
|
scan_list_head = scan_list_node;
|
|
scan_list_node->next = NULL;
|
|
} else {
|
|
|
|
curr_ss =
|
|
255 -
|
|
scan_list_head->fixed_buf.fixed_fields.
|
|
rssi;
|
|
|
|
if (new_ss > curr_ss) {
|
|
// Insert the node to head of the list
|
|
scan_list_node->next = scan_list_head;
|
|
scan_list_head = scan_list_node;
|
|
} else {
|
|
for (curr = scan_list_head;
|
|
curr != NULL; curr = curr->next) {
|
|
curr_ss =
|
|
255 -
|
|
curr->fixed_buf.
|
|
fixed_fields.rssi;
|
|
if (prev && (new_ss > curr_ss)) {
|
|
// Insert the node to current position in list
|
|
scan_list_node->next =
|
|
curr;
|
|
prev->next =
|
|
scan_list_node;
|
|
break;
|
|
}
|
|
prev = curr;
|
|
}
|
|
if (prev && (curr == NULL)) {
|
|
// Insert the node to tail of the list
|
|
prev->next = scan_list_node;
|
|
scan_list_node->next = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
scan_start += prsp_info->scan_number;
|
|
} while (prsp_info->scan_number);
|
|
|
|
// Display scan results
|
|
printf("---------------------------------------");
|
|
printf("---------------------------------------\n");
|
|
printf("# | ch | ss | bssid | cap | SSID \n");
|
|
printf("---------------------------------------");
|
|
printf("---------------------------------------\n");
|
|
|
|
for (curr = scan_list_head, idx = 0;
|
|
(curr != NULL) && ((unsigned int)idx < total_scan_res);
|
|
curr = curr->next, idx++) {
|
|
|
|
fixed_fields = curr->fixed_buf.fixed_fields;
|
|
bss_info = &curr->bss_info_buf;
|
|
|
|
printf("%02u| %03d | %03d | %02x:%02x:%02x:%02x:%02x:%02x |",
|
|
idx,
|
|
fixed_fields.channel,
|
|
255 - fixed_fields.rssi,
|
|
fixed_fields.bssid[0],
|
|
fixed_fields.bssid[1],
|
|
fixed_fields.bssid[2],
|
|
fixed_fields.bssid[3],
|
|
fixed_fields.bssid[4], fixed_fields.bssid[5]);
|
|
|
|
displayed_info = TRUE;
|
|
|
|
/* "A" for Adhoc
|
|
* "I" for Infrastructure,
|
|
* "D" for DFS (Spectrum Mgmt)
|
|
*/
|
|
printf(" %c%c%c%c%c%c%c%c%c%c | ", bss_info->cap_info.ibss ? 'A' : 'I', bss_info->priv_cap, /* P (WEP), W (WPA), 2 (WPA2) */
|
|
bss_info->cap_info.spectrum_mgmt ? 'D' : ' ', bss_info->wmm_cap, /* M (WMM), C (WMM-Call Admission Control) */
|
|
bss_info->dot11k_cap, /* K */
|
|
bss_info->dot11r_cap, /* R */
|
|
bss_info->wps_cap, /* S */
|
|
bss_info->ht_cap, /* N */
|
|
bss_info->vht_cap[0], /* AC */
|
|
bss_info->vht_cap[1]);
|
|
|
|
/* Print out the ssid or the hex values if non-printable */
|
|
for (ssid_idx = 0; ssid_idx < bss_info->ssid_len; ssid_idx++) {
|
|
if (isprint(bss_info->ssid[ssid_idx])) {
|
|
printf("%c", bss_info->ssid[ssid_idx]);
|
|
} else {
|
|
printf("\\%02x", bss_info->ssid[ssid_idx]);
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
if (argc > 3 && strcmp(argv[3], "tsf") == 0) {
|
|
/* TSF is a u64, some formatted printing libs have trouble
|
|
printing long longs, so cast and dump as bytes */
|
|
pbyte = (t_u8 *)&fixed_fields.network_tsf;
|
|
printf(" TSF=%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
|
pbyte[7], pbyte[6], pbyte[5], pbyte[4],
|
|
pbyte[3], pbyte[2], pbyte[1], pbyte[0]);
|
|
}
|
|
}
|
|
|
|
if (displayed_info == TRUE) {
|
|
if (argc > 3 && strcmp(argv[3], "help") == 0) {
|
|
printf("\n\n"
|
|
"Capability Legend (Not all may be supported)\n"
|
|
"-----------------\n"
|
|
" I [ Infrastructure ]\n"
|
|
" A [ Ad-hoc ]\n"
|
|
" W [ WPA IE ]\n"
|
|
" 2 [ WPA2/RSN IE ]\n"
|
|
" M [ WMM IE ]\n"
|
|
" C [ Call Admission Control - WMM IE, VO ACM set ]\n"
|
|
" D [ Spectrum Management - DFS (11h) ]\n"
|
|
" K [ 11k ]\n"
|
|
" R [ 11r ]\n"
|
|
" S [ WPS ]\n"
|
|
" N [ HT (11n) ]\n"
|
|
" AC [VHT (11ac) ]\n" "\n\n");
|
|
}
|
|
} else {
|
|
printf("< No Scan Results >\n");
|
|
}
|
|
|
|
done:
|
|
if (scan_rsp_buf)
|
|
free(scan_rsp_buf);
|
|
for (curr = scan_list_head; curr != NULL; curr = next) {
|
|
next = curr->next;
|
|
free(curr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/** Maximum channel scratch */
|
|
#define MAX_CHAN_SCRATCH 100
|
|
|
|
/** Maximum channel number for b/g band */
|
|
#define MAX_CHAN_BG_BAND 14
|
|
|
|
/** Maximum number of probes to send on each channel */
|
|
#define MAX_PROBES 5
|
|
|
|
/** Scan all the channels in specified band */
|
|
#define BAND_SPECIFIED 0x80
|
|
/**
|
|
* @brief Request a scan from the driver and display the scan table afterwards
|
|
*
|
|
* Command line interface for performing a specific immediate scan based
|
|
* on the following keyword parsing:
|
|
*
|
|
* chan=[chan#][band][mode] where band is [a,b,g,n] and mode is
|
|
* blank for active or 'p' for passive
|
|
* bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
|
|
* ssid="[SSID]" specify a SSID filter for the scan
|
|
* keep=[0 or 1] keep the previous scan results (1), discard (0)
|
|
* dur=[scan time] time to scan for each channel in milliseconds
|
|
* probes=[#] number of probe requests to send on each chan
|
|
* type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
|
|
*
|
|
* Any combination of the above arguments can be supplied on the command line.
|
|
* If the chan token is absent, a full channel scan will be completed by
|
|
* the driver. If the dur or probes tokens are absent, the drivers default
|
|
* setting will be used. The bssid and ssid fields, if blank,
|
|
* will produce an unfiltered scan. The type field will default to 3 (Any)
|
|
* and the keep field will default to 0 (Discard).
|
|
*
|
|
* @param argc number of arguments
|
|
* @param argv A pointer to arguments array
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
int
|
|
process_setuserscan(int argc, char *argv[])
|
|
{
|
|
wlan_ioctl_user_scan_cfg scan_req;
|
|
int ioctl_val, subioctl_val;
|
|
struct iwreq iwr;
|
|
char *parg_tok;
|
|
char *pchan_tok;
|
|
char *parg_cookie;
|
|
char *pchan_cookie;
|
|
int arg_idx;
|
|
int chan_parse_idx;
|
|
int chan_cmd_idx;
|
|
char chan_scratch[MAX_CHAN_SCRATCH];
|
|
char *pscratch;
|
|
int tmp_idx;
|
|
int scan_time;
|
|
int num_ssid;
|
|
int is_radio_set;
|
|
unsigned int mac[ETH_ALEN];
|
|
|
|
memset(&scan_req, 0x00, sizeof(scan_req));
|
|
chan_cmd_idx = 0;
|
|
scan_time = 0;
|
|
num_ssid = 0;
|
|
|
|
if (get_priv_ioctl("setuserscan",
|
|
&ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
for (arg_idx = 0; arg_idx < argc; arg_idx++) {
|
|
|
|
if (strncmp(argv[arg_idx], "ssid=", strlen("ssid=")) == 0) {
|
|
/*
|
|
* "ssid" token string handler
|
|
*/
|
|
if (num_ssid < MRVDRV_MAX_SSID_LIST_LENGTH) {
|
|
strncpy(scan_req.ssid_list[num_ssid].ssid,
|
|
argv[arg_idx] + strlen("ssid="),
|
|
sizeof(scan_req.ssid_list[num_ssid].
|
|
ssid));
|
|
|
|
scan_req.ssid_list[num_ssid].max_len = 0;
|
|
|
|
num_ssid++;
|
|
}
|
|
} else if (strncmp(argv[arg_idx], "bssid=", strlen("bssid=")) ==
|
|
0) {
|
|
/*
|
|
* "bssid" token string handler
|
|
*/
|
|
sscanf(argv[arg_idx] + strlen("bssid="),
|
|
"%2x:%2x:%2x:%2x:%2x:%2x", mac + 0, mac + 1,
|
|
mac + 2, mac + 3, mac + 4, mac + 5);
|
|
|
|
for (tmp_idx = 0;
|
|
(unsigned int)tmp_idx < NELEMENTS(mac);
|
|
tmp_idx++) {
|
|
scan_req.specific_bssid[tmp_idx] =
|
|
(t_u8)mac[tmp_idx];
|
|
}
|
|
} else if (strncmp(argv[arg_idx], "chan=", strlen("chan=")) ==
|
|
0) {
|
|
/*
|
|
* "chan" token string handler
|
|
*/
|
|
parg_tok = argv[arg_idx] + strlen("chan=");
|
|
|
|
if (strlen(parg_tok) > MAX_CHAN_SCRATCH) {
|
|
printf("Error: Specified channels exceeds max limit\n");
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
is_radio_set = FALSE;
|
|
|
|
while ((parg_tok =
|
|
strtok_r(parg_tok, ",",
|
|
&parg_cookie)) != NULL) {
|
|
|
|
memset(chan_scratch, 0x00,
|
|
sizeof(chan_scratch));
|
|
pscratch = chan_scratch;
|
|
|
|
for (chan_parse_idx = 0;
|
|
(unsigned int)chan_parse_idx <
|
|
strlen(parg_tok); chan_parse_idx++) {
|
|
if (isalpha
|
|
(*(parg_tok + chan_parse_idx))) {
|
|
*pscratch++ = ' ';
|
|
}
|
|
|
|
*pscratch++ =
|
|
*(parg_tok + chan_parse_idx);
|
|
}
|
|
*pscratch = 0;
|
|
parg_tok = NULL;
|
|
|
|
pchan_tok = chan_scratch;
|
|
|
|
while ((pchan_tok = strtok_r(pchan_tok, " ",
|
|
&pchan_cookie)) !=
|
|
NULL) {
|
|
if (isdigit(*pchan_tok)) {
|
|
scan_req.
|
|
chan_list[chan_cmd_idx].
|
|
chan_number =
|
|
atoi(pchan_tok);
|
|
if (scan_req.
|
|
chan_list[chan_cmd_idx].
|
|
chan_number >
|
|
MAX_CHAN_BG_BAND)
|
|
scan_req.
|
|
chan_list
|
|
[chan_cmd_idx].
|
|
radio_type = 1;
|
|
} else {
|
|
switch (toupper(*pchan_tok)) {
|
|
case 'A':
|
|
scan_req.
|
|
chan_list
|
|
[chan_cmd_idx].
|
|
radio_type = 1;
|
|
is_radio_set = TRUE;
|
|
break;
|
|
case 'B':
|
|
case 'G':
|
|
scan_req.
|
|
chan_list
|
|
[chan_cmd_idx].
|
|
radio_type = 0;
|
|
is_radio_set = TRUE;
|
|
break;
|
|
case 'N':
|
|
break;
|
|
case 'P':
|
|
scan_req.
|
|
chan_list
|
|
[chan_cmd_idx].
|
|
scan_type =
|
|
MLAN_SCAN_TYPE_PASSIVE;
|
|
break;
|
|
default:
|
|
printf("Error: Band type not supported!\n");
|
|
return -EOPNOTSUPP;
|
|
}
|
|
if (!chan_cmd_idx &&
|
|
!scan_req.
|
|
chan_list[chan_cmd_idx].
|
|
chan_number && is_radio_set)
|
|
scan_req.
|
|
chan_list
|
|
[chan_cmd_idx].
|
|
radio_type |=
|
|
BAND_SPECIFIED;
|
|
}
|
|
pchan_tok = NULL;
|
|
}
|
|
chan_cmd_idx++;
|
|
}
|
|
} else if (strncmp(argv[arg_idx], "keep=", strlen("keep=")) ==
|
|
0) {
|
|
/*
|
|
* "keep" token string handler
|
|
*/
|
|
scan_req.keep_previous_scan =
|
|
atoi(argv[arg_idx] + strlen("keep="));
|
|
} else if (strncmp(argv[arg_idx], "dur=", strlen("dur=")) == 0) {
|
|
/*
|
|
* "dur" token string handler
|
|
*/
|
|
scan_time = atoi(argv[arg_idx] + strlen("dur="));
|
|
scan_req.chan_list[0].scan_time = scan_time;
|
|
|
|
} else if (strncmp(argv[arg_idx], "wc=", strlen("wc=")) == 0) {
|
|
|
|
if (num_ssid < MRVDRV_MAX_SSID_LIST_LENGTH) {
|
|
/*
|
|
* "wc" token string handler
|
|
*/
|
|
pscratch = strrchr(argv[arg_idx], ',');
|
|
|
|
if (pscratch) {
|
|
*pscratch = 0;
|
|
pscratch++;
|
|
|
|
if (isdigit(*pscratch)) {
|
|
scan_req.ssid_list[num_ssid].
|
|
max_len =
|
|
atoi(pscratch);
|
|
} else {
|
|
scan_req.ssid_list[num_ssid].
|
|
max_len = *pscratch;
|
|
}
|
|
} else {
|
|
/* Standard wildcard matching */
|
|
scan_req.ssid_list[num_ssid].max_len =
|
|
0xFF;
|
|
}
|
|
|
|
strncpy(scan_req.ssid_list[num_ssid].ssid,
|
|
argv[arg_idx] + strlen("wc="),
|
|
sizeof(scan_req.ssid_list[num_ssid].
|
|
ssid));
|
|
|
|
num_ssid++;
|
|
}
|
|
} else if (strncmp(argv[arg_idx], "probes=", strlen("probes="))
|
|
== 0) {
|
|
/*
|
|
* "probes" token string handler
|
|
*/
|
|
scan_req.num_probes =
|
|
atoi(argv[arg_idx] + strlen("probes="));
|
|
if (scan_req.num_probes > MAX_PROBES) {
|
|
fprintf(stderr, "Invalid probes (> %d)\n",
|
|
MAX_PROBES);
|
|
return -EOPNOTSUPP;
|
|
}
|
|
} else if (strncmp(argv[arg_idx], "type=", strlen("type=")) ==
|
|
0) {
|
|
/*
|
|
* "type" token string handler
|
|
*/
|
|
scan_req.bss_mode =
|
|
atoi(argv[arg_idx] + strlen("type="));
|
|
switch (scan_req.bss_mode) {
|
|
case MLAN_SCAN_MODE_BSS:
|
|
case MLAN_SCAN_MODE_IBSS:
|
|
break;
|
|
case MLAN_SCAN_MODE_ANY:
|
|
default:
|
|
/* Set any unknown types to ANY */
|
|
scan_req.bss_mode = MLAN_SCAN_MODE_ANY;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Update all the channels to have the same scan time
|
|
*/
|
|
for (tmp_idx = 1; tmp_idx < chan_cmd_idx; tmp_idx++) {
|
|
scan_req.chan_list[tmp_idx].scan_time = scan_time;
|
|
}
|
|
|
|
strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1);
|
|
iwr.u.data.pointer = (caddr_t) & scan_req;
|
|
iwr.u.data.length = sizeof(scan_req);
|
|
iwr.u.data.flags = subioctl_val;
|
|
|
|
if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
|
|
perror("mlanconfig: setuserscan ioctl");
|
|
return -EFAULT;
|
|
}
|
|
|
|
process_getscantable(0, 0);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|