📄 scan.c
字号:
struct ieeetypes_ibssparamset *pibss; DECLARE_MAC_BUF(mac); struct ieeetypes_countryinfoset *pcountryinfo; u8 *pos, *end, *p; u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; u16 beaconsize = 0; int ret; lbs_deb_enter(LBS_DEB_SCAN); if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo)); *bytesleft -= sizeof(beaconsize); *pbeaconinfo += sizeof(beaconsize); } if (beaconsize == 0 || beaconsize > *bytesleft) { *pbeaconinfo += *bytesleft; *bytesleft = 0; ret = -1; goto done; } /* Initialize the current working beacon pointer for this BSS iteration */ pos = *pbeaconinfo; end = pos + beaconsize; /* Advance the return beacon pointer past the current beacon */ *pbeaconinfo += beaconsize; *bytesleft -= beaconsize; memcpy(bss->bssid, pos, ETH_ALEN); lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid)); pos += ETH_ALEN; if ((end - pos) < 12) { lbs_deb_scan("process_bss: Not enough bytes left\n"); ret = -1; goto done; } /* * next 4 fields are RSSI, time stamp, beacon interval, * and capability information */ /* RSSI is 1 byte long */ bss->rssi = *pos; lbs_deb_scan("process_bss: RSSI=%02X\n", *pos); pos++; /* time stamp is 8 bytes long */ pos += 8; /* beacon interval is 2 bytes long */ bss->beaconperiod = le16_to_cpup((void *) pos); pos += 2; /* capability information is 2 bytes long */ bss->capability = le16_to_cpup((void *) pos); lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability); pos += 2; if (bss->capability & WLAN_CAPABILITY_PRIVACY) lbs_deb_scan("process_bss: AP WEP enabled\n"); if (bss->capability & WLAN_CAPABILITY_IBSS) bss->mode = IW_MODE_ADHOC; else bss->mode = IW_MODE_INFRA; /* rest of the current buffer are IE's */ lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos); /* process variable IE */ while (pos <= end - 2) { struct ieee80211_info_element * elem = (struct ieee80211_info_element *) pos; if (pos + elem->len > end) { lbs_deb_scan("process_bss: error in processing IE, " "bytes left < IE length\n"); break; } switch (elem->id) { case MFIE_TYPE_SSID: bss->ssid_len = elem->len; memcpy(bss->ssid, elem->data, elem->len); lbs_deb_scan("ssid '%s', ssid length %u\n", escape_essid(bss->ssid, bss->ssid_len), bss->ssid_len); break; case MFIE_TYPE_RATES: n_basic_rates = min_t(u8, MAX_RATES, elem->len); memcpy(bss->rates, elem->data, n_basic_rates); got_basic_rates = 1; break; case MFIE_TYPE_FH_SET: pFH = (struct ieeetypes_fhparamset *) pos; memmove(&bss->phyparamset.fhparamset, pFH, sizeof(struct ieeetypes_fhparamset));#if 0 /* I think we can store these LE */ bss->phyparamset.fhparamset.dwelltime = le16_to_cpu(bss->phyparamset.fhparamset.dwelltime);#endif break; case MFIE_TYPE_DS_SET: pDS = (struct ieeetypes_dsparamset *) pos; bss->channel = pDS->currentchan; memcpy(&bss->phyparamset.dsparamset, pDS, sizeof(struct ieeetypes_dsparamset)); break; case MFIE_TYPE_CF_SET: pCF = (struct ieeetypes_cfparamset *) pos; memcpy(&bss->ssparamset.cfparamset, pCF, sizeof(struct ieeetypes_cfparamset)); break; case MFIE_TYPE_IBSS_SET: pibss = (struct ieeetypes_ibssparamset *) pos; bss->atimwindow = le32_to_cpu(pibss->atimwindow); memmove(&bss->ssparamset.ibssparamset, pibss, sizeof(struct ieeetypes_ibssparamset));#if 0 bss->ssparamset.ibssparamset.atimwindow = le16_to_cpu(bss->ssparamset.ibssparamset.atimwindow);#endif break; case MFIE_TYPE_COUNTRY: pcountryinfo = (struct ieeetypes_countryinfoset *) pos; if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) || pcountryinfo->len > 254) { lbs_deb_scan("process_bss: 11D- Err " "CountryInfo len =%d min=%zd max=254\n", pcountryinfo->len, sizeof(pcountryinfo->countrycode)); ret = -1; goto done; } memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", (u8 *) pcountryinfo, (u32) (pcountryinfo->len + 2)); break; case MFIE_TYPE_RATES_EX: /* only process extended supported rate if data rate is * already found. Data rate IE should come before * extended supported rate IE */ if (!got_basic_rates) break; n_ex_rates = elem->len; if (n_basic_rates + n_ex_rates > MAX_RATES) n_ex_rates = MAX_RATES - n_basic_rates; p = bss->rates + n_basic_rates; memcpy(p, elem->data, n_ex_rates); break; case MFIE_TYPE_GENERIC: if (elem->len >= 4 && elem->data[0] == 0x00 && elem->data[1] == 0x50 && elem->data[2] == 0xf2 && elem->data[3] == 0x01) { bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie, elem->len); } else if (elem->len >= MARVELL_MESH_IE_LENGTH && elem->data[0] == 0x00 && elem->data[1] == 0x50 && elem->data[2] == 0x43 && elem->data[3] == 0x04) { bss->mesh = 1; } break; case MFIE_TYPE_RSN: bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len); break; default: break; } pos += elem->len + 2; } /* Timestamp */ bss->last_scanned = jiffies; libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); ret = 0;done: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret;}/** * @brief This function finds a specific compatible BSSID in the scan list * * Used in association code * * @param adapter A pointer to wlan_adapter * @param bssid BSSID to find in the scan list * @param mode Network mode: Infrastructure or IBSS * * @return index in BSSID list, or error return code (< 0) */struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, u8 * bssid, u8 mode){ struct bss_descriptor * iter_bss; struct bss_descriptor * found_bss = NULL; lbs_deb_enter(LBS_DEB_SCAN); if (!bssid) goto out; lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); /* Look through the scan table for a compatible match. The loop will * continue past a matched bssid that is not compatible in case there * is an AP with multiple SSIDs assigned to the same BSSID */ mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { if (compare_ether_addr(iter_bss->bssid, bssid)) continue; /* bssid doesn't match */ switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: if (!is_network_compatible(adapter, iter_bss, mode)) break; found_bss = iter_bss; break; default: found_bss = iter_bss; break; } } mutex_unlock(&adapter->lock);out: lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); return found_bss;}/** * @brief This function finds ssid in ssid list. * * Used in association code * * @param adapter A pointer to wlan_adapter * @param ssid SSID to find in the list * @param bssid BSSID to qualify the SSID selection (if provided) * @param mode Network mode: Infrastructure or IBSS * * @return index in BSSID list */struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode, int channel){ u8 bestrssi = 0; struct bss_descriptor * iter_bss = NULL; struct bss_descriptor * found_bss = NULL; struct bss_descriptor * tmp_oldest = NULL; lbs_deb_enter(LBS_DEB_SCAN); mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { if ( !tmp_oldest || (iter_bss->last_scanned < tmp_oldest->last_scanned)) tmp_oldest = iter_bss; if (libertas_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, ssid, ssid_len) != 0) continue; /* ssid doesn't match */ if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) continue; /* bssid doesn't match */ if ((channel > 0) && (iter_bss->channel != channel)) continue; /* channel doesn't match */ switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: if (!is_network_compatible(adapter, iter_bss, mode)) break; if (bssid) { /* Found requested BSSID */ found_bss = iter_bss; goto out; } if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { bestrssi = SCAN_RSSI(iter_bss->rssi); found_bss = iter_bss; } break; case IW_MODE_AUTO: default: if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { bestrssi = SCAN_RSSI(iter_bss->rssi); found_bss = iter_bss; } break; } }out: mutex_unlock(&adapter->lock); lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); return found_bss;}/** * @brief This function finds the best SSID in the Scan List * * Search the scan table for the best SSID that also matches the current * adapter network preference (infrastructure or adhoc) * * @param adapter A pointer to wlan_adapter * * @return index in BSSID list */static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, u8 mode){ u8 bestrssi = 0; struct bss_descriptor * iter_bss; struct bss_descriptor * best_bss = NULL; lbs_deb_enter(LBS_DEB_SCAN); mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: if (!is_network_compatible(adapter, iter_bss, mode)) break; if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) break; bestrssi = SCAN_RSSI(iter_bss->rssi); best_bss = iter_bss; break; case IW_MODE_AUTO: default: if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) break; bestrssi = SCAN_RSSI(iter_bss->rssi); best_bss = iter_bss; break; } } mutex_unlock(&adapter->lock); lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); return best_bss;}/** * @brief Find the AP with specific ssid in the scan list * * Used from association worker. * * @param priv A pointer to wlan_private structure * @param pSSID A pointer to AP's ssid * * @return 0--success, otherwise--fail */int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode){ wlan_adapter *adapter = priv->adapter; int ret = -1; struct bss_descriptor * found; lbs_deb_enter(LBS_DEB_SCAN); wlan_scan_networks(priv, NULL, 1); if (adapter->surpriseremoved) goto out; wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); found = libertas_find_best_ssid_in_list(adapter, preferred_mode); if (found && (found->ssid_len > 0)) { memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE); *out_ssid_len = found->ssid_len; *out_mode = found->mode; ret = 0; }out: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret;}/** * @brief Scan Network * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure * @param vwrq A pointer to iw_param structure * @param extra A pointer to extra data buf * * @return 0 --success, otherwise fail */int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra){ wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_SCAN); if (!delayed_work_pending(&priv->scan_work)) { queue_delayed_work(priv->work_thread, &priv->scan_work, msecs_to_jiffies(50)); } if (adapter->surpriseremoved) return -1; lbs_deb_leave(LBS_DEB_SCAN); return 0;}/** * @brief Send a scan command for all available channels filtered on a spec * * Used in association code and from debugfs * * @param priv A pointer to wlan_private structure * @param ssid A pointer to the SSID to scan for * @param ssid_len Length of the SSID * @param clear_ssid Should existing scan results with this SSID * be cleared? * @param prequestedssid A pointer to AP's ssid * @param keeppreviousscan Flag used to save/clear scan table before scan * * @return 0-success, otherwise fail */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -