📄 driver_nl80211.c
字号:
ret = -1; } /* Not all drivers generate "scan completed" wireless event, so try to * read results after a timeout. */ timeout = 5; if (drv->scan_complete_events) { /* * The driver seems to deliver SIOCGIWSCAN events to notify * when scan is complete, so use longer timeout to avoid race * conditions with scanning and following association request. */ timeout = 30; } wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " "seconds", ret, timeout); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, drv, drv->ctx); return ret;}static u8 * wpa_driver_nl80211_giwscan(struct wpa_driver_nl80211_data *drv, size_t *len){ struct iwreq iwr; u8 *res_buf; size_t res_buf_len; res_buf_len = IW_SCAN_MAX_DATA; for (;;) { res_buf = os_malloc(res_buf_len); if (res_buf == NULL) return NULL; os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); iwr.u.data.pointer = res_buf; iwr.u.data.length = res_buf_len; if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0) break; if (errno == E2BIG && res_buf_len < 100000) { os_free(res_buf); res_buf = NULL; res_buf_len *= 2; wpa_printf(MSG_DEBUG, "Scan results did not fit - " "trying larger buffer (%lu bytes)", (unsigned long) res_buf_len); } else { perror("ioctl[SIOCGIWSCAN]"); os_free(res_buf); return NULL; } } if (iwr.u.data.length > res_buf_len) { os_free(res_buf); return NULL; } *len = iwr.u.data.length; return res_buf;}/* * Data structure for collecting WEXT scan results. This is needed to allow * the various methods of reporting IEs to be combined into a single IE buffer. */struct wext_scan_data { struct wpa_scan_res res; u8 *ie; size_t ie_len; u8 ssid[32]; size_t ssid_len; int maxrate;};static void wext_get_scan_mode(struct iw_event *iwe, struct wext_scan_data *res){ if (iwe->u.mode == IW_MODE_ADHOC) res->res.caps |= IEEE80211_CAP_IBSS; else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA) res->res.caps |= IEEE80211_CAP_ESS;}static void wext_get_scan_ssid(struct iw_event *iwe, struct wext_scan_data *res, char *custom, char *end){ int ssid_len = iwe->u.essid.length; if (custom + ssid_len > end) return; if (iwe->u.essid.flags && ssid_len > 0 && ssid_len <= IW_ESSID_MAX_SIZE) { os_memcpy(res->ssid, custom, ssid_len); res->ssid_len = ssid_len; }}static void wext_get_scan_freq(struct iw_event *iwe, struct wext_scan_data *res){ int divi = 1000000, i; if (iwe->u.freq.e == 0) { /* * Some drivers do not report frequency, but a channel. * Try to map this to frequency by assuming they are using * IEEE 802.11b/g. But don't overwrite a previously parsed * frequency if the driver sends both frequency and channel, * since the driver may be sending an A-band channel that we * don't handle here. */ if (res->res.freq) return; if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) { res->res.freq = 2407 + 5 * iwe->u.freq.m; return; } else if (iwe->u.freq.m == 14) { res->res.freq = 2484; return; } } if (iwe->u.freq.e > 6) { wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID=" MACSTR " m=%d e=%d)", MAC2STR(res->res.bssid), iwe->u.freq.m, iwe->u.freq.e); return; } for (i = 0; i < iwe->u.freq.e; i++) divi /= 10; res->res.freq = iwe->u.freq.m / divi;}static void wext_get_scan_qual(struct iw_event *iwe, struct wext_scan_data *res){ res->res.qual = iwe->u.qual.qual; res->res.noise = iwe->u.qual.noise; res->res.level = iwe->u.qual.level;}static void wext_get_scan_encode(struct iw_event *iwe, struct wext_scan_data *res){ if (!(iwe->u.data.flags & IW_ENCODE_DISABLED)) res->res.caps |= IEEE80211_CAP_PRIVACY;}static void wext_get_scan_rate(struct iw_event *iwe, struct wext_scan_data *res, char *pos, char *end){ int maxrate; char *custom = pos + IW_EV_LCP_LEN; struct iw_param p; size_t clen; clen = iwe->len; if (custom + clen > end) return; maxrate = 0; while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) { /* Note: may be misaligned, make a local, aligned copy */ os_memcpy(&p, custom, sizeof(struct iw_param)); if (p.value > maxrate) maxrate = p.value; clen -= sizeof(struct iw_param); custom += sizeof(struct iw_param); } /* Convert the maxrate from WE-style (b/s units) to * 802.11 rates (500000 b/s units). */ res->maxrate = maxrate / 500000;}static void wext_get_scan_iwevgenie(struct iw_event *iwe, struct wext_scan_data *res, char *custom, char *end){ char *genie, *gpos, *gend; u8 *tmp; gpos = genie = custom; gend = genie + iwe->u.data.length; if (gend > end) { wpa_printf(MSG_INFO, "IWEVGENIE overflow"); return; } tmp = os_realloc(res->ie, res->ie_len + gend - gpos); if (tmp == NULL) return; os_memcpy(tmp + res->ie_len, gpos, gend - gpos); res->ie = tmp; res->ie_len += gend - gpos;}static void wext_get_scan_custom(struct iw_event *iwe, struct wext_scan_data *res, char *custom, char *end){ size_t clen; u8 *tmp; clen = iwe->u.data.length; if (custom + clen > end) return; if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) { char *spos; int bytes; spos = custom + 7; bytes = custom + clen - spos; if (bytes & 1) return; bytes /= 2; tmp = os_realloc(res->ie, res->ie_len + bytes); if (tmp == NULL) return; hexstr2bin(spos, tmp + res->ie_len, bytes); res->ie = tmp; res->ie_len += bytes; } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) { char *spos; int bytes; spos = custom + 7; bytes = custom + clen - spos; if (bytes & 1) return; bytes /= 2; tmp = os_realloc(res->ie, res->ie_len + bytes); if (tmp == NULL) return; hexstr2bin(spos, tmp + res->ie_len, bytes); res->ie = tmp; res->ie_len += bytes; } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) { char *spos; int bytes; u8 bin[8]; spos = custom + 4; bytes = custom + clen - spos; if (bytes != 16) { wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes); return; } bytes /= 2; hexstr2bin(spos, bin, bytes); res->res.tsf += WPA_GET_BE64(bin); }}static int wext_19_iw_point(struct wpa_driver_nl80211_data *drv, u16 cmd){ return drv->we_version_compiled > 18 && (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE || cmd == IWEVGENIE || cmd == IWEVCUSTOM);}static void wpa_driver_nl80211_add_scan_entry(struct wpa_scan_results *res, struct wext_scan_data *data){ struct wpa_scan_res **tmp; struct wpa_scan_res *r; size_t extra_len; u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL; /* Figure out whether we need to fake any IEs */ pos = data->ie; end = pos + data->ie_len; while (pos && pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_SSID) ssid_ie = pos; else if (pos[0] == WLAN_EID_SUPP_RATES) rate_ie = pos; else if (pos[0] == WLAN_EID_EXT_SUPP_RATES) rate_ie = pos; pos += 2 + pos[1]; } extra_len = 0; if (ssid_ie == NULL) extra_len += 2 + data->ssid_len; if (rate_ie == NULL && data->maxrate) extra_len += 3; r = os_zalloc(sizeof(*r) + extra_len + data->ie_len); if (r == NULL) return; os_memcpy(r, &data->res, sizeof(*r)); r->ie_len = extra_len + data->ie_len; pos = (u8 *) (r + 1); if (ssid_ie == NULL) { /* * Generate a fake SSID IE since the driver did not report * a full IE list. */ *pos++ = WLAN_EID_SSID; *pos++ = data->ssid_len; os_memcpy(pos, data->ssid, data->ssid_len); pos += data->ssid_len; } if (rate_ie == NULL && data->maxrate) { /* * Generate a fake Supported Rates IE since the driver did not * report a full IE list. */ *pos++ = WLAN_EID_SUPP_RATES; *pos++ = 1; *pos++ = data->maxrate; } if (data->ie) os_memcpy(pos, data->ie, data->ie_len); tmp = os_realloc(res->res, (res->num + 1) * sizeof(struct wpa_scan_res *)); if (tmp == NULL) { os_free(r); return; } tmp[res->num++] = r; res->res = tmp;} /** * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results * @priv: Pointer to private wext data from wpa_driver_nl80211_init() * Returns: Scan results on success, -1 on failure */struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv){ struct wpa_driver_nl80211_data *drv = priv; size_t ap_num = 0, len; int first; u8 *res_buf; struct iw_event iwe_buf, *iwe = &iwe_buf; char *pos, *end, *custom; struct wpa_scan_results *res; struct wext_scan_data data; res_buf = wpa_driver_nl80211_giwscan(drv, &len); if (res_buf == NULL) return NULL; ap_num = 0; first = 1; res = os_zalloc(sizeof(*res)); if (res == NULL) { os_free(res_buf); return NULL; } pos = (char *) res_buf; end = (char *) res_buf + len; os_memset(&data, 0, sizeof(data)); while (pos + IW_EV_LCP_LEN <= end) { /* Event data may be unaligned, so make a local, aligned copy * before processing. */ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); if (iwe->len <= IW_EV_LCP_LEN) break; custom = pos + IW_EV_POINT_LEN; if (wext_19_iw_point(drv, iwe->cmd)) { /* WE-19 removed the pointer from struct iw_point */ char *dpos = (char *) &iwe_buf.u.data.length; int dlen = dpos - (char *) &iwe_buf; os_memcpy(dpos, pos + IW_EV_LCP_LEN, sizeof(struct iw_event) - dlen); } else { os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); custom += IW_EV_POINT_OFF; } switch (iwe->cmd) { case SIOCGIWAP: if (!first) wpa_driver_nl80211_add_scan_entry(res, &data); first = 0; os_free(data.ie); os_memset(&data, 0, sizeof(data)); os_memcpy(data.res.bssid, iwe->u.ap_addr.sa_data, ETH_ALEN); break; case SIOCGIWMODE: wext_get_scan_mode(iwe, &data); break; case SIOCGIWESSID: wext_get_scan_ssid(iwe, &data, custom, end); break; case SIOCGIWFREQ: wext_get_scan_freq(iwe, &data); break; case IWEVQUAL: wext_get_scan_qual(iwe, &data); break; case SIOCGIWENCODE: wext_get_scan_encode(iwe, &data); break; case SIOCGIWRATE: wext_get_scan_rate(iwe, &data, pos, end); break; case IWEVGENIE: wext_get_scan_iwevgenie(iwe, &data, custom, end); break; case IWEVCUSTOM: wext_get_scan_custom(iwe, &data, custom, end); break; } pos += iwe->len; } os_free(res_buf); res_buf = NULL; if (!first) wpa_driver_nl80211_add_scan_entry(res, &data); os_free(data.ie); wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)", (unsigned long) len, (unsigned long) res->num); return res;}static int wpa_driver_nl80211_get_range(void *priv){ struct wpa_driver_nl80211_data *drv = priv; struct iw_range *range; struct iwreq iwr; int minlen; size_t buflen; /* * Use larger buffer than struct iw_range in order to allow the * structure to grow in the future. */ buflen = sizeof(struct iw_range) + 500; range = os_zalloc(buflen); if (range == NULL) return -1; os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); iwr.u.data.pointer = (caddr_t) range; iwr.u.data.length = buflen; minlen = ((char *) &range->enc_capa) - (char *) range + sizeof(range->enc_capa); if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { perror("ioctl[SIOCGIWRANGE]"); os_free(range); return -1; } else if (iwr.u.data.length >= minlen && range->we_version_compiled >= 18) { wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " "WE(source)=%d enc_capa=0x%x", range->we_version_compiled, range->we_version_source, range->enc_capa); drv->has_capability = 1; drv->we_version_compiled = range->we_version_compiled; if (range->enc_capa & IW_ENC_CAPA_WPA) { drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; } if (range->enc_capa & IW_ENC_CAPA_WPA2) { drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; } drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104; if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x", drv->capa.key_mgmt, drv->capa.enc); } else { wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " "assuming WPA is not supported"); } os_free(range); return 0;}static int wpa_driver_nl80211_set_wpa(void *priv, int enabled){ struct wpa_driver_nl80211_data *drv = priv; wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_WPA_ENABLED, enabled);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -