📄 scan.c
字号:
numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0; /* * Set the BSSID filter to the incoming configuration, * if non-zero. If not set, it will remain disabled (all zeros). */ memcpy(pscancfgout->bssid, puserscanin->bssid, sizeof(pscancfgout->bssid)); if (puserscanin->ssid_len) { pssidtlv = (struct mrvlietypes_ssidparamset *) pscancfgout-> tlvbuffer; pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID); pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len); memcpy(pssidtlv->ssid, puserscanin->ssid, puserscanin->ssid_len); ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len; } /* * The default number of channels sent in the command is low to * ensure the response buffer from the firmware does not truncate * scan results. That is not an issue with an SSID or BSSID * filter applied to the scan results in the firmware. */ if ( puserscanin->ssid_len || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) { *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN; *pfilteredscan = 1; } } else { pscancfgout->bsstype = CMD_BSS_TYPE_ANY; numprobes = 0; } /* If the input config or adapter has the number of Probes set, add tlv */ if (numprobes) { pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos; pnumprobestlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); pnumprobestlv->header.len = cpu_to_le16(2); pnumprobestlv->numprobes = cpu_to_le16(numprobes); ptlvpos += sizeof(*pnumprobestlv); } /* * Set the output for the channel TLV to the address in the tlv buffer * past any TLVs that were added in this fuction (SSID, numprobes). * channel TLVs will be added past this for each scan command, preserving * the TLVs that were previously added. */ *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; if (!puserscanin || !puserscanin->chanlist[0].channumber) { /* Create a default channel scan list */ lbs_deb_scan("creating full region channel list\n"); wlan_scan_create_channel_list(priv, pscanchanlist, *pfilteredscan); goto out; } for (chanidx = 0; chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX && puserscanin->chanlist[chanidx].channumber; chanidx++) { channel = puserscanin->chanlist[chanidx].channumber; (pscanchanlist + chanidx)->channumber = channel; radiotype = puserscanin->chanlist[chanidx].radiotype; (pscanchanlist + chanidx)->radiotype = radiotype; scantype = puserscanin->chanlist[chanidx].scantype; if (scantype == CMD_SCAN_TYPE_PASSIVE) { (pscanchanlist + chanidx)->chanscanmode.passivescan = 1; } else { (pscanchanlist + chanidx)->chanscanmode.passivescan = 0; } if (puserscanin->chanlist[chanidx].scantime) { scandur = puserscanin->chanlist[chanidx].scantime; } else { if (scantype == CMD_SCAN_TYPE_PASSIVE) { scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; } else { scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; } } (pscanchanlist + chanidx)->minscantime = cpu_to_le16(scandur); (pscanchanlist + chanidx)->maxscantime = cpu_to_le16(scandur); } /* Check if we are only scanning the current channel */ if ((chanidx == 1) && (puserscanin->chanlist[0].channumber == priv->adapter->curbssparams.channel)) { *pscancurrentonly = 1; lbs_deb_scan("scanning current channel only"); }out: return pscancfgout;}/** * @brief Construct and send multiple scan config commands to the firmware * * Only used from wlan_scan_networks() * * Previous routines have created a wlan_scan_cmd_config with any requested * TLVs. This function splits the channel TLV into maxchanperscan lists * and sends the portion of the channel TLV along with the other TLVs * to the wlan_cmd routines for execution in the firmware. * * @param priv A pointer to wlan_private structure * @param maxchanperscan Maximum number channels to be included in each * scan command sent to firmware * @param filteredscan Flag indicating whether or not a BSSID or SSID * filter is being used for the firmware command * scan command sent to firmware * @param pscancfgout Scan configuration used for this scan. * @param pchantlvout Pointer in the pscancfgout where the channel TLV * should start. This is past any other TLVs that * must be sent down in each firmware command. * @param pscanchanlist List of channels to scan in maxchanperscan segments * * @return 0 or error return otherwise */static int wlan_scan_channel_list(wlan_private * priv, int maxchanperscan, u8 filteredscan, struct wlan_scan_cmd_config * pscancfgout, struct mrvlietypes_chanlistparamset * pchantlvout, struct chanscanparamset * pscanchanlist, const struct wlan_ioctl_user_scan_cfg * puserscanin, int full_scan){ struct chanscanparamset *ptmpchan; struct chanscanparamset *pstartchan; u8 scanband; int doneearly; int tlvidx; int ret = 0; int scanned = 0; union iwreq_data wrqu; lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, " "full_scan %d", maxchanperscan, filteredscan, full_scan); if (!pscancfgout || !pchantlvout || !pscanchanlist) { lbs_deb_scan("pscancfgout, pchantlvout or " "pscanchanlist is NULL\n"); ret = -1; goto out; } pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); /* Set the temp channel struct pointer to the start of the desired list */ ptmpchan = pscanchanlist; if (priv->adapter->last_scanned_channel && !puserscanin) ptmpchan += priv->adapter->last_scanned_channel; /* Loop through the desired channel list, sending a new firmware scan * commands for each maxchanperscan channels (or for 1,6,11 individually * if configured accordingly) */ while (ptmpchan->channumber) { tlvidx = 0; pchantlvout->header.len = 0; scanband = ptmpchan->radiotype; pstartchan = ptmpchan; doneearly = 0; /* Construct the channel TLV for the scan command. Continue to * insert channel TLVs until: * - the tlvidx hits the maximum configured per scan command * - the next channel to insert is 0 (end of desired channel list) * - doneearly is set (controlling individual scanning of 1,6,11) */ while (tlvidx < maxchanperscan && ptmpchan->channumber && !doneearly && scanned < 2) { lbs_deb_scan("channel %d, radio %d, passive %d, " "dischanflt %d, maxscantime %d\n", ptmpchan->channumber, ptmpchan->radiotype, ptmpchan->chanscanmode.passivescan, ptmpchan->chanscanmode.disablechanfilt, ptmpchan->maxscantime); /* Copy the current channel TLV to the command being prepared */ memcpy(pchantlvout->chanscanparam + tlvidx, ptmpchan, sizeof(pchantlvout->chanscanparam)); /* Increment the TLV header length by the size appended */ /* Ew, it would be _so_ nice if we could just declare the variable little-endian and let GCC handle it for us */ pchantlvout->header.len = cpu_to_le16(le16_to_cpu(pchantlvout->header.len) + sizeof(pchantlvout->chanscanparam)); /* * The tlv buffer length is set to the number of bytes of the * between the channel tlv pointer and the start of the * tlv buffer. This compensates for any TLVs that were appended * before the channel list. */ pscancfgout->tlvbufferlen = ((u8 *) pchantlvout - pscancfgout->tlvbuffer); /* Add the size of the channel tlv header and the data length */ pscancfgout->tlvbufferlen += (sizeof(pchantlvout->header) + le16_to_cpu(pchantlvout->header.len)); /* Increment the index to the channel tlv we are constructing */ tlvidx++; doneearly = 0; /* Stop the loop if the *current* channel is in the 1,6,11 set * and we are not filtering on a BSSID or SSID. */ if (!filteredscan && (ptmpchan->channumber == 1 || ptmpchan->channumber == 6 || ptmpchan->channumber == 11)) { doneearly = 1; } /* Increment the tmp pointer to the next channel to be scanned */ ptmpchan++; scanned++; /* Stop the loop if the *next* channel is in the 1,6,11 set. * This will cause it to be the only channel scanned on the next * interation */ if (!filteredscan && (ptmpchan->channumber == 1 || ptmpchan->channumber == 6 || ptmpchan->channumber == 11)) { doneearly = 1; } } /* Send the scan command to the firmware with the specified cfg */ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SCAN, 0, 0, 0, pscancfgout); if (scanned >= 2 && !full_scan) { ret = 0; goto done; } scanned = 0; }done: priv->adapter->last_scanned_channel = ptmpchan->channumber; if (priv->adapter->last_scanned_channel) { /* Schedule the next part of the partial scan */ if (!full_scan && !priv->adapter->surpriseremoved) { cancel_delayed_work(&priv->scan_work); queue_delayed_work(priv->work_thread, &priv->scan_work, msecs_to_jiffies(300)); } } else { /* All done, tell userspace the scan table has been updated */ memset(&wrqu, 0, sizeof(union iwreq_data)); wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); }out: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret;}/* * Only used from wlan_scan_networks()*/static void clear_selected_scan_list_entries(wlan_adapter *adapter, const struct wlan_ioctl_user_scan_cfg *scan_cfg){ struct bss_descriptor *bss; struct bss_descriptor *safe; u32 clear_ssid_flag = 0, clear_bssid_flag = 0; lbs_deb_enter(LBS_DEB_SCAN); if (!scan_cfg) goto out; if (scan_cfg->clear_ssid && scan_cfg->ssid_len) clear_ssid_flag = 1; if (scan_cfg->clear_bssid && (compare_ether_addr(scan_cfg->bssid, &zeromac[0]) != 0) && (compare_ether_addr(scan_cfg->bssid, &bcastmac[0]) != 0)) { clear_bssid_flag = 1; } if (!clear_ssid_flag && !clear_bssid_flag) goto out; mutex_lock(&adapter->lock); list_for_each_entry_safe (bss, safe, &adapter->network_list, list) { u32 clear = 0; /* Check for an SSID match */ if ( clear_ssid_flag && (bss->ssid_len == scan_cfg->ssid_len) && !memcmp(bss->ssid, scan_cfg->ssid, bss->ssid_len)) clear = 1; /* Check for a BSSID match */ if ( clear_bssid_flag && !compare_ether_addr(bss->bssid, scan_cfg->bssid)) clear = 1; if (clear) { list_move_tail (&bss->list, &adapter->network_free_list); clear_bss_descriptor(bss); } } mutex_unlock(&adapter->lock);out: lbs_deb_leave(LBS_DEB_SCAN);}/** * @brief Internal function used to start a scan based on an input config * * Also used from debugfs * * Use the input user scan configuration information when provided in * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table * * @param priv A pointer to wlan_private structure * @param puserscanin Pointer to the input configuration for the requested * scan. * @param full_scan ??? * * @return 0 or < 0 if error */int wlan_scan_networks(wlan_private * priv, const struct wlan_ioctl_user_scan_cfg * puserscanin, int full_scan){ wlan_adapter * adapter = priv->adapter; struct mrvlietypes_chanlistparamset *pchantlvout; struct chanscanparamset * scan_chan_list = NULL; struct wlan_scan_cmd_config * scan_cfg = NULL; u8 filteredscan; u8 scancurrentchanonly; int maxchanperscan; int ret;#ifdef CONFIG_LIBERTAS_DEBUG struct bss_descriptor * iter_bss; int i = 0; DECLARE_MAC_BUF(mac);#endif lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); /* Cancel any partial outstanding partial scans if this scan * is a full scan. */ if (full_scan && delayed_work_pending(&priv->scan_work)) cancel_delayed_work(&priv->scan_work); scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); if (scan_chan_list == NULL) { ret = -ENOMEM; goto out; } scan_cfg = wlan_scan_setup_scan_config(priv, puserscanin, &pchantlvout, scan_chan_list, &maxchanperscan, &filteredscan, &scancurrentchanonly); if (scan_cfg == NULL) { ret = -ENOMEM; goto out; } clear_selected_scan_list_entries(adapter, puserscanin); /* Keep the data path active if we are only scanning our current channel */ if (!scancurrentchanonly) { netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); if (priv->mesh_dev) { netif_stop_queue(priv->mesh_dev); netif_carrier_off(priv->mesh_dev); } } ret = wlan_scan_channel_list(priv, maxchanperscan, filteredscan, scan_cfg, pchantlvout, scan_chan_list, puserscanin, full_scan);#ifdef CONFIG_LIBERTAS_DEBUG /* Dump the scan table */ mutex_lock(&adapter->lock); lbs_deb_scan("The scan table contains:\n"); list_for_each_entry (iter_bss, &adapter->network_list, list) { lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n", i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi, escape_essid(iter_bss->ssid, iter_bss->ssid_len)); } mutex_unlock(&adapter->lock);#endif if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); if (priv->mesh_dev) { netif_carrier_on(priv->mesh_dev); netif_wake_queue(priv->mesh_dev); } }out: if (scan_cfg) kfree(scan_cfg); if (scan_chan_list) kfree(scan_chan_list); lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret;}/** * @brief Interpret a BSS scan response returned from the firmware * * Parse the various fixed fields and IEs passed back for a a BSS probe * response or beacon from the scan command. Record information as needed * in the scan table struct bss_descriptor for that entry. * * @param bss Output parameter: Pointer to the BSS Entry * * @return 0 or -1 */static int libertas_process_bss(struct bss_descriptor * bss, u8 ** pbeaconinfo, int *bytesleft){ struct ieeetypes_fhparamset *pFH; struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -