📄 driver_wext.c
字号:
/* 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 - wb->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; int ap_num = 0, 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; memset(results, 0, max_size * sizeof(struct wpa_scan_result)); res_buf_len = IW_SCAN_MAX_DATA; for (;;) { res_buf = malloc(res_buf_len); if (res_buf == NULL) return -1; memset(&iwr, 0, sizeof(iwr)); 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) { 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]"); 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. */ 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; memcpy(dpos, pos + IW_EV_LCP_LEN, sizeof(struct iw_event) - dlen); } else { 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) { 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) { 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 > 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) >= sizeof(struct iw_param)) { /* Note: may be misaligned, make a local, * aligned copy */ 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 || memcmp(&gpos[2], "\x00\x50\xf2\x01", 4) != 0) break; memcpy(results[ap_num].wpa_ie, gpos, ielen); results[ap_num].wpa_ie_len = ielen; break; case RSN_INFO_ELEM: 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 && 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 && 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; } free(res_buf); res_buf = NULL; if (!first) ap_num++; if (ap_num > max_size) { wpa_printf(MSG_DEBUG, "Too small scan result buffer - %d BSSes" " but room only for %lu", 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 (%d BSSes)", (unsigned long) len, 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 = malloc(buflen); if (range == NULL) return -1; memset(range, 0, buflen); memset(&iwr, 0, sizeof(iwr)); 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]"); 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"); } free(range); return 0;}static int wpa_driver_wext_set_wpa(void *priv, int enabled){ struct wpa_driver_wext_data *drv = priv; wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); return wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, enabled);}static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len){ struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0; struct iw_encode_ext *ext; if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) { wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu", __FUNCTION__, (unsigned long) seq_len); return -1; } ext = malloc(sizeof(*ext) + key_len); if (ext == NULL) return -1; memset(ext, 0, sizeof(*ext) + key_len); memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); iwr.u.encoding.flags = key_idx + 1; if (alg == WPA_ALG_NONE) iwr.u.encoding.flags |= IW_ENCODE_DISABLED; iwr.u.encoding.pointer = (caddr_t) ext; iwr.u.encoding.length = sizeof(*ext) + key_len; if (addr == NULL || memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY; if (set_tx) ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY; ext->addr.sa_family = ARPHRD_ETHER; if (addr) memcpy(ext->addr.sa_data, addr, ETH_ALEN); else memset(ext->addr.sa_data, 0xff, ETH_ALEN); if (key && key_len) { memcpy(ext + 1, key, key_len); ext->key_len = key_len; } switch (alg) { case WPA_ALG_NONE: ext->alg = IW_ENCODE_ALG_NONE; break; case WPA_ALG_WEP: ext->alg = IW_ENCODE_ALG_WEP; break; case WPA_ALG_TKIP: ext->alg = IW_ENCODE_ALG_TKIP; break; case WPA_ALG_CCMP: ext->alg = IW_ENCODE_ALG_CCMP; break; default: wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d", __FUNCTION__, alg); free(ext); return -1; } if (seq && seq_len) { ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID; memcpy(ext->rx_seq, seq, seq_len); } if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) { ret = errno == EOPNOTSUPP ? -2 : -1; if (errno == ENODEV) { /* * ndiswrapper seems to be returning incorrect error * code.. */ ret = -2; } perror("ioctl[SIOCSIWENCODEEXT]"); } free(ext); return ret;}/** * wpa_driver_wext_set_key - Configure encryption key * @priv: Pointer to private wext data from wpa_driver_wext_init() * @priv: Private driver interface data * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key. * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for * broadcast/default keys * @key_idx: key index (0..3), usually 0 for unicast keys * @set_tx: Configure this key as the default Tx key (only used when * driver does not support separate unicast/individual key * @seq: Sequence number/packet number, seq_len octets, the next * packet number to be used for in replay protection; configured * for Rx keys (in most cases, this is only used with broadcast * keys and set to zero for unicast keys) * @seq_len: Length of the seq, depends on the algorithm: * TKIP: 6 octets, CCMP: 6 octets * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, * 8-byte Rx Mic Key * @key_len: Length of the key buffer in octets (WEP: 5 or 13, * TKIP: 32, CCMP: 16) * Returns: 0 on success, -1 on failure *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -