📄 driver_wext.c
字号:
* @priv: Pointer to private wext data from wpa_driver_wext_init() * * Shut down driver interface and processing of driver events. Free * private data buffer if one was allocated in wpa_driver_wext_init(). */void wpa_driver_wext_deinit(void *priv){ struct wpa_driver_wext_data *drv = priv; int flags; eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); /* * Clear possibly configured driver parameters in order to make it * easier to use the driver after wpa_supplicant has been terminated. */ wpa_driver_wext_set_bssid(drv, (u8 *) "\x00\x00\x00\x00\x00\x00"); wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP); eloop_unregister_read_sock(drv->event_sock); if (drv->mlme_sock >= 0) eloop_unregister_read_sock(drv->mlme_sock); if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);#ifdef CONFIG_CLIENT_MLME if (drv->mlmedev[0] && wpa_driver_wext_get_ifflags_ifname(drv, drv->mlmedev, &flags) == 0) (void) wpa_driver_wext_set_ifflags_ifname(drv, drv->mlmedev, flags & ~IFF_UP);#endif /* CONFIG_CLIENT_MLME */ close(drv->event_sock); close(drv->ioctl_sock); if (drv->mlme_sock >= 0) close(drv->mlme_sock); os_free(drv->assoc_req_ies); os_free(drv->assoc_resp_ies); os_free(drv);}/** * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion * @eloop_ctx: Unused * @timeout_ctx: ctx argument given to wpa_driver_wext_init() * * This function can be used as registered timeout when starting a scan to * generate a scan completed event if the driver does not report this. */void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx){ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);}/** * wpa_driver_wext_scan - Request the driver to initiate scan * @priv: Pointer to private wext data from wpa_driver_wext_init() * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for * all SSIDs (either active scan with broadcast SSID or passive * scan * @ssid_len: Length of the SSID * Returns: 0 on success, -1 on failure */int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len){ struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0, timeout; struct iw_scan_req req; if (ssid_len > IW_ESSID_MAX_SIZE) { wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", __FUNCTION__, (unsigned long) ssid_len); return -1; } os_memset(&iwr, 0, sizeof(iwr)); os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); if (ssid && ssid_len) { os_memset(&req, 0, sizeof(req)); req.essid_len = ssid_len; req.bssid.sa_family = ARPHRD_ETHER; os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); os_memcpy(req.essid, ssid, ssid_len); iwr.u.data.pointer = (caddr_t) &req; iwr.u.data.length = sizeof(req); iwr.u.data.flags = IW_SCAN_THIS_ESSID; } if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { perror("ioctl[SIOCSIWSCAN]"); 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_wext_scan_timeout, drv, drv->ctx); eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv, drv->ctx); return ret;}/* Compare function for sorting scan results. Return >0 if @b is considered * better. */static int wpa_scan_result_compar(const void *a, const void *b){ const struct wpa_scan_result *wa = a; const struct wpa_scan_result *wb = b; /* WPA/WPA2 support preferred */ if ((wb->wpa_ie_len || wb->rsn_ie_len) && !(wa->wpa_ie_len || wa->rsn_ie_len)) return 1; if (!(wb->wpa_ie_len || wb->rsn_ie_len) && (wa->wpa_ie_len || wa->rsn_ie_len)) return -1; /* privacy support preferred */ if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && (wb->caps & IEEE80211_CAP_PRIVACY)) return 1; if ((wa->caps & IEEE80211_CAP_PRIVACY) && (wb->caps & IEEE80211_CAP_PRIVACY) == 0) return -1; /* best/max rate preferred if signal level close enough XXX */ if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5) return wb->maxrate - wa->maxrate; /* use freq for channel preference */ /* all things being equal, use signal level; if signal levels are * identical, use quality values since some drivers may only report * that value and leave the signal level zero */ if (wb->level == wa->level) return wb->qual - wa->qual; return wb->level - wa->level;}/** * wpa_driver_wext_get_scan_results - Fetch the latest scan results * @priv: Pointer to private wext data from wpa_driver_wext_init() * @results: Pointer to buffer for scan results * @max_size: Maximum number of entries (buffer size) * Returns: Number of scan result entries used on success, -1 on * failure * * If scan results include more than max_size BSSes, max_size will be * returned and the remaining entries will not be included in the * buffer. */int wpa_driver_wext_get_scan_results(void *priv, struct wpa_scan_result *results, size_t max_size){ struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; size_t ap_num = 0; int first, maxrate; u8 *res_buf; struct iw_event iwe_buf, *iwe = &iwe_buf; char *pos, *end, *custom, *genie, *gpos, *gend; struct iw_param p; size_t len, clen, res_buf_len; os_memset(results, 0, max_size * sizeof(struct wpa_scan_result)); res_buf_len = IW_SCAN_MAX_DATA; for (;;) { res_buf = os_malloc(res_buf_len); if (res_buf == NULL) return -1; os_memset(&iwr, 0, sizeof(iwr)); os_strncpy(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 -1; } } len = iwr.u.data.length; ap_num = 0; first = 1; pos = (char *) res_buf; end = (char *) res_buf + len; while (pos + IW_EV_LCP_LEN <= end) { int ssid_len; /* 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 (drv->we_version_compiled > 18 && (iwe->cmd == SIOCGIWESSID || iwe->cmd == SIOCGIWENCODE || iwe->cmd == IWEVGENIE || iwe->cmd == IWEVCUSTOM)) { /* 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) ap_num++; first = 0; if (ap_num < max_size) { os_memcpy(results[ap_num].bssid, iwe->u.ap_addr.sa_data, ETH_ALEN); } break; case SIOCGIWMODE: if (ap_num >= max_size) break; if (iwe->u.mode == IW_MODE_ADHOC) results[ap_num].caps |= IEEE80211_CAP_IBSS; else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA) results[ap_num].caps |= IEEE80211_CAP_ESS; break; case SIOCGIWESSID: ssid_len = iwe->u.essid.length; if (custom + ssid_len > end) break; if (iwe->u.essid.flags && ssid_len > 0 && ssid_len <= IW_ESSID_MAX_SIZE) { if (ap_num < max_size) { os_memcpy(results[ap_num].ssid, custom, ssid_len); results[ap_num].ssid_len = ssid_len; } } break; case SIOCGIWFREQ: if (ap_num < max_size) { 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. */ if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) { results[ap_num].freq = 2407 + 5 * iwe->u.freq.m; break; } else if (iwe->u.freq.m == 14) { results[ap_num].freq = 2484; break; } } if (iwe->u.freq.e > 6) { wpa_printf( MSG_DEBUG, "Invalid freq " "in scan results (BSSID=" MACSTR ": m=%d e=%d\n", MAC2STR(results[ap_num].bssid), iwe->u.freq.m, iwe->u.freq.e); break; } for (i = 0; i < iwe->u.freq.e; i++) divi /= 10; results[ap_num].freq = iwe->u.freq.m / divi; } break; case IWEVQUAL: if (ap_num < max_size) { results[ap_num].qual = iwe->u.qual.qual; results[ap_num].noise = iwe->u.qual.noise; results[ap_num].level = iwe->u.qual.level; } break; case SIOCGIWENCODE: if (ap_num < max_size && !(iwe->u.data.flags & IW_ENCODE_DISABLED)) results[ap_num].caps |= IEEE80211_CAP_PRIVACY; break; case SIOCGIWRATE: custom = pos + IW_EV_LCP_LEN; clen = iwe->len; if (custom + clen > end) break; 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); } if (ap_num < max_size) results[ap_num].maxrate = maxrate; break; case IWEVGENIE: if (ap_num >= max_size) break; gpos = genie = custom; gend = genie + iwe->u.data.length; if (gend > end) { wpa_printf(MSG_INFO, "IWEVGENIE overflow"); break; } while (gpos + 1 < gend && gpos + 2 + (u8) gpos[1] <= gend) { u8 ie = gpos[0], ielen = gpos[1] + 2; if (ielen > SSID_MAX_WPA_IE_LEN) { gpos += ielen; continue; } switch (ie) { case GENERIC_INFO_ELEM: if (ielen < 2 + 4 || os_memcmp(&gpos[2], "\x00\x50\xf2\x01", 4) != 0) break; os_memcpy(results[ap_num].wpa_ie, gpos, ielen); results[ap_num].wpa_ie_len = ielen; break; case RSN_INFO_ELEM: os_memcpy(results[ap_num].rsn_ie, gpos, ielen); results[ap_num].rsn_ie_len = ielen; break; } gpos += ielen; } break; case IWEVCUSTOM: clen = iwe->u.data.length; if (custom + clen > end) break; if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0 && ap_num < max_size) { char *spos; int bytes; spos = custom + 7; bytes = custom + clen - spos; if (bytes & 1) break; bytes /= 2; if (bytes > SSID_MAX_WPA_IE_LEN) { wpa_printf(MSG_INFO, "Too long WPA IE " "(%d)", bytes); break; } hexstr2bin(spos, results[ap_num].wpa_ie, bytes); results[ap_num].wpa_ie_len = bytes; } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0 && ap_num < max_size) { char *spos; int bytes; spos = custom + 7; bytes = custom + clen - spos; if (bytes & 1) break; bytes /= 2; if (bytes > SSID_MAX_WPA_IE_LEN) { wpa_printf(MSG_INFO, "Too long RSN IE " "(%d)", bytes); break; } hexstr2bin(spos, results[ap_num].rsn_ie, bytes); results[ap_num].rsn_ie_len = bytes; } break; } pos += iwe->len; } os_free(res_buf); res_buf = NULL; if (!first) ap_num++; if (ap_num > max_size) { wpa_printf(MSG_DEBUG, "Too small scan result buffer - " "%lu BSSes but room only for %lu", (unsigned long) ap_num, (unsigned long) max_size); ap_num = max_size; } qsort(results, ap_num, sizeof(struct wpa_scan_result), wpa_scan_result_compar); wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)", (unsigned long) len, (unsigned long) ap_num); return ap_num;}static int wpa_driver_wext_get_range(void *priv){ struct wpa_driver_wext_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_strncpy(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]");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -