| /** @file mlanmisc.c |
| * |
| * @brief Program to prepare command buffer |
| * |
| * Copyright (C) 2008-2017, Marvell International Ltd. |
| * |
| * This software file (the "File") is distributed by Marvell International |
| * Ltd. under the terms of the GNU General Public License Version 2, June 1991 |
| * (the "License"). You may use, redistribute and/or modify this File in |
| * accordance with the terms and conditions of the License, a copy of which |
| * is available by writing to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the |
| * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. |
| * |
| * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE |
| * ARE EXPRESSLY DISCLAIMED. The License provides additional details about |
| * this warranty disclaimer. |
| * |
| */ |
| |
| /************************************************************************ |
| 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); |
| |
| 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 |
| ********************************************************/ |
| /** 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; |
| } |
| |
| /** |
| * @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 (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 (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 4 |
| |
| /** 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; |
| } |