📄 scan.c
字号:
int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid, u8 ssid_len, u8 clear_ssid){ wlan_adapter *adapter = priv->adapter; struct wlan_ioctl_user_scan_cfg scancfg; int ret = 0; lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", escape_essid(ssid, ssid_len), clear_ssid); if (!ssid_len) goto out; memset(&scancfg, 0x00, sizeof(scancfg)); memcpy(scancfg.ssid, ssid, ssid_len); scancfg.ssid_len = ssid_len; scancfg.clear_ssid = clear_ssid; wlan_scan_networks(priv, &scancfg, 1); if (adapter->surpriseremoved) { ret = -1; goto out; } wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);out: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret;}/*********************************************************************//* *//* Support for Wireless Extensions *//* *//*********************************************************************/#define MAX_CUSTOM_LEN 64static inline char *libertas_translate_scan(wlan_private *priv, char *start, char *stop, struct bss_descriptor *bss){ wlan_adapter *adapter = priv->adapter; struct chan_freq_power *cfp; char *current_val; /* For rates */ struct iw_event iwe; /* Temporary buffer */ int j;#define PERFECT_RSSI ((u8)50)#define WORST_RSSI ((u8)0)#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) u8 rssi; lbs_deb_enter(LBS_DEB_SCAN); cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel); if (!cfp) { lbs_deb_scan("Invalid channel number %d\n", bss->channel); start = NULL; goto out; } /* First entry *MUST* be the AP BSSID */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN); start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); /* SSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; iwe.u.data.length = min((u32) bss->ssid_len, (u32) IW_ESSID_MAX_SIZE); start = iwe_stream_add_point(start, stop, &iwe, bss->ssid); /* Mode */ iwe.cmd = SIOCGIWMODE; iwe.u.mode = bss->mode; start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); /* Frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = (long)cfp->freq * 100000; iwe.u.freq.e = 1; start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); /* Add quality statistics */ iwe.cmd = IWEVQUAL; iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; iwe.u.qual.level = SCAN_RSSI(bss->rssi); rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; iwe.u.qual.qual = (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / (RSSI_DIFF * RSSI_DIFF); if (iwe.u.qual.qual > 100) iwe.u.qual.qual = 100; if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; } else { iwe.u.qual.noise = CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); } /* Locally created ad-hoc BSSs won't have beacons if this is the * only station in the adhoc network; so get signal strength * from receive statistics. */ if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate && !libertas_ssid_cmp(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len, bss->ssid, bss->ssid_len)) { int snr, nf; snr = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; nf = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; iwe.u.qual.level = CAL_RSSI(snr, nf); } start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; if (bss->capability & WLAN_CAPABILITY_PRIVACY) { iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; } else { iwe.u.data.flags = IW_ENCODE_DISABLED; } iwe.u.data.length = 0; start = iwe_stream_add_point(start, stop, &iwe, bss->ssid); current_val = start + IW_EV_LCP_LEN; iwe.cmd = SIOCGIWRATE; iwe.u.bitrate.fixed = 0; iwe.u.bitrate.disabled = 0; iwe.u.bitrate.value = 0; for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) { /* Bit rate given in 500 kb/s units */ iwe.u.bitrate.value = bss->rates[j] * 500000; current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); } if ((bss->mode == IW_MODE_ADHOC) && !libertas_ssid_cmp(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len, bss->ssid, bss->ssid_len) && adapter->adhoccreate) { iwe.u.bitrate.value = 22 * 500000; current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ if((current_val - start) > IW_EV_LCP_LEN) start = current_val; memset(&iwe, 0, sizeof(iwe)); if (bss->wpa_ie_len) { char buf[MAX_WPA_IE_LEN]; memcpy(buf, bss->wpa_ie, bss->wpa_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->wpa_ie_len; start = iwe_stream_add_point(start, stop, &iwe, buf); } memset(&iwe, 0, sizeof(iwe)); if (bss->rsn_ie_len) { char buf[MAX_WPA_IE_LEN]; memcpy(buf, bss->rsn_ie, bss->rsn_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->rsn_ie_len; start = iwe_stream_add_point(start, stop, &iwe, buf); } if (bss->mesh) { char custom[MAX_CUSTOM_LEN]; char *p = custom; iwe.cmd = IWEVCUSTOM; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "mesh-type: olpc"); iwe.u.data.length = p - custom; if (iwe.u.data.length) start = iwe_stream_add_point(start, stop, &iwe, custom); }out: lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start); return start;}/** * @brief Handle Retrieve scan table ioctl * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure * @param dwrq A pointer to iw_point structure * @param extra A pointer to extra data buf * * @return 0 --success, otherwise fail */int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){#define SCAN_ITEM_SIZE 128 wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; int err = 0; char *ev = extra; char *stop = ev + dwrq->length; struct bss_descriptor * iter_bss; struct bss_descriptor * safe; lbs_deb_enter(LBS_DEB_SCAN); /* Update RSSI if current BSS is a locally created ad-hoc BSS */ if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); } mutex_lock(&adapter->lock); list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { char * next_ev; unsigned long stale_time; if (stop - ev < SCAN_ITEM_SIZE) { err = -E2BIG; break; } /* For mesh device, list only mesh networks */ if (dev == priv->mesh_dev && !iter_bss->mesh) continue; /* Prune old an old scan result */ stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_after(jiffies, stale_time)) { list_move_tail (&iter_bss->list, &adapter->network_free_list); clear_bss_descriptor(iter_bss); continue; } /* Translate to WE format this entry */ next_ev = libertas_translate_scan(priv, ev, stop, iter_bss); if (next_ev == NULL) continue; ev = next_ev; } mutex_unlock(&adapter->lock); dwrq->length = (ev - extra); dwrq->flags = 0; lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err); return err;}/*********************************************************************//* *//* Command execution *//* *//*********************************************************************//** * @brief Prepare a scan command to be sent to the firmware * * Called from libertas_prepare_and_send_command() in cmd.c * * Sends a fixed lenght data part (specifying the BSS type and BSSID filters) * as well as a variable number/length of TLVs to the firmware. * * @param priv A pointer to wlan_private structure * @param cmd A pointer to cmd_ds_command structure to be sent to * firmware with the cmd_DS_801_11_SCAN structure * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used * to set the fields/TLVs for the command sent to firmware * * @return 0 or -1 */int libertas_cmd_80211_scan(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf){ struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; struct wlan_scan_cmd_config *pscancfg = pdata_buf; lbs_deb_enter(LBS_DEB_SCAN); /* Set fixed field variables in scan command */ pscan->bsstype = pscancfg->bsstype; memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN); memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); cmd->command = cpu_to_le16(CMD_802_11_SCAN); /* size is equal to the sizeof(fixed portions) + the TLV len + header */ cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN + pscancfg->tlvbufferlen + S_DS_GEN); lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n", le16_to_cpu(cmd->command), le16_to_cpu(cmd->size), le16_to_cpu(cmd->seqnum)); lbs_deb_leave(LBS_DEB_SCAN); return 0;}static inline int is_same_network(struct bss_descriptor *src, struct bss_descriptor *dst){ /* A network is only a duplicate if the channel, BSSID, and ESSID * all match. We treat all <hidden> with the same BSSID and channel * as one network */ return ((src->ssid_len == dst->ssid_len) && (src->channel == dst->channel) && !compare_ether_addr(src->bssid, dst->bssid) && !memcmp(src->ssid, dst->ssid, src->ssid_len));}/** * @brief This function handles the command response of scan * * Called from handle_cmd_response() in cmdrespc. * * The response buffer for the scan command has the following * memory layout: * * .-----------------------------------------------------------. * | header (4 * sizeof(u16)): Standard command response hdr | * .-----------------------------------------------------------. * | bufsize (u16) : sizeof the BSS Description data | * .-----------------------------------------------------------. * | NumOfSet (u8) : Number of BSS Descs returned | * .-----------------------------------------------------------. * | BSSDescription data (variable, size given in bufsize) | * .-----------------------------------------------------------. * | TLV data (variable, size calculated using header->size, | * | bufsize and sizeof the fixed fields above) | * .-----------------------------------------------------------. * * @param priv A pointer to wlan_private structure * @param resp A pointer to cmd_ds_command * * @return 0 or -1 */int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp){ wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_scan_rsp *pscan; struct bss_descriptor * iter_bss; struct bss_descriptor * safe; u8 *pbssinfo; u16 scanrespsize; int bytesleft; int idx; int tlvbufsize; int ret; lbs_deb_enter(LBS_DEB_SCAN); /* Prune old entries from scan table */ list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_before(jiffies, stale_time)) continue; list_move_tail (&iter_bss->list, &adapter->network_free_list); clear_bss_descriptor(iter_bss); } pscan = &resp->params.scanresp; if (pscan->nr_sets > MAX_NETWORK_COUNT) { lbs_deb_scan( "SCAN_RESP: too many scan results (%d, max %d)!!\n", pscan->nr_sets, MAX_NETWORK_COUNT); ret = -1; goto done; } bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize)); lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size)); lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n", pscan->nr_sets); pbssinfo = pscan->bssdesc_and_tlvbuffer; /* The size of the TLV buffer is equal to the entire command response * size (scanrespsize) minus the fixed fields (sizeof()'s), the * BSS Descriptions (bssdescriptsize as bytesLef) and the command * response header (S_DS_GEN) */ tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize) + sizeof(pscan->nr_sets) + S_DS_GEN); /* * Process each scan response returned (pscan->nr_sets). Save * the information in the newbssentry and then insert into the * driver scan table either as an update to an existing entry * or as an addition at the end of the table */ for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) { struct bss_descriptor new; struct bss_descriptor * found = NULL; struct bss_descriptor * oldest = NULL; DECLARE_MAC_BUF(mac); /* Process the data fields and IEs returned for this BSS */ memset(&new, 0, sizeof (struct bss_descriptor)); if (libertas_process_bss(&new, &pbssinfo, &bytesleft) != 0) { /* error parsing the scan response, skipped */ lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); continue; } /* Try to find this bss in the scan table */ list_for_each_entry (iter_bss, &adapter->network_list, list) { if (is_same_network(iter_bss, &new)) { found = iter_bss; break; } if ((oldest == NULL) || (iter_bss->last_scanned < oldest->last_scanned)) oldest = iter_bss; } if (found) { /* found, clear it */ clear_bss_descriptor(found); } else if (!list_empty(&adapter->network_free_list)) { /* Pull one from the free list */ found = list_entry(adapter->network_free_list.next, struct bss_descriptor, list); list_move_tail(&found->list, &adapter->network_list); } else if (oldest) { /* If there are no more slots, expire the oldest */ found = oldest; clear_bss_descriptor(found); list_move_tail(&found->list, &adapter->network_list); } else { continue; } lbs_deb_scan("SCAN_RESP: BSSID = %s\n", print_mac(mac, new.bssid)); /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); } ret = 0;done: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -