📄 driver_wext.c
字号:
/* * WPA Supplicant - driver interaction with generic Linux Wireless Extensions * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file implements a driver interface for the Linux Wireless Extensions. * When used with WE-18 or newer, this interface can be used as-is with number * of drivers. In addition to this, some of the common functions in this file * can be used by other driver interface implementations that use generic WE * ioctls, but require private ioctls for some of the functionality. */#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/ioctl.h>#include <errno.h>#include <net/if_arp.h>#include "wireless_copy.h"#include "common.h"#include "driver.h"#include "l2_packet.h"#include "eloop.h"#include "wpa_supplicant.h"#include "priv_netlink.h"#include "driver_wext.h"#include "wpa.h"struct wpa_driver_wext_data { void *ctx; int event_sock; int ioctl_sock; char ifname[IFNAMSIZ + 1]; int ifindex; int ifindex2; u8 *assoc_req_ies; size_t assoc_req_ies_len; u8 *assoc_resp_ies; size_t assoc_resp_ies_len; struct wpa_driver_capa capa; int has_capability; int we_version_compiled; /* for set_auth_alg fallback */ int use_crypt; int auth_alg_fallback;};static int wpa_driver_wext_flush_pmkid(void *priv);static int wpa_driver_wext_get_range(void *priv);static int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, int idx, u32 value){ struct iwreq iwr; int ret = 0; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); iwr.u.param.flags = idx & IW_AUTH_INDEX; iwr.u.param.value = value; if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) { perror("ioctl[SIOCSIWAUTH]"); fprintf(stderr, "WEXT auth param %d value 0x%x - ", idx, value); ret = errno == EOPNOTSUPP ? -2 : -1; } return ret;}/** * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP * @priv: Pointer to private wext data from wpa_driver_wext_init() * @bssid: Buffer for BSSID * Returns: 0 on success, -1 on failure */int wpa_driver_wext_get_bssid(void *priv, u8 *bssid){ struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { perror("ioctl[SIOCGIWAP]"); ret = -1; } memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); return ret;}/** * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP * @priv: Pointer to private wext data from wpa_driver_wext_init() * @bssid: BSSID * Returns: 0 on success, -1 on failure */int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid){ struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); iwr.u.ap_addr.sa_family = ARPHRD_ETHER; if (bssid) memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); else memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN); if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) { perror("ioctl[SIOCSIWAP]"); ret = -1; } return ret;}/** * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID * @priv: Pointer to private wext data from wpa_driver_wext_init() * @ssid: Buffer for the SSID; must be at least 32 bytes long * Returns: SSID length on success, -1 on failure */int wpa_driver_wext_get_ssid(void *priv, u8 *ssid){ struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); iwr.u.essid.pointer = (caddr_t) ssid; iwr.u.essid.length = 32; if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { perror("ioctl[SIOCGIWESSID]"); ret = -1; } else { ret = iwr.u.essid.length; if (ret > 32) ret = 32; /* Some drivers include nul termination in the SSID, so let's * remove it here before further processing. WE-21 changes this * to explicitly require the length _not_ to include nul * termination. */ if (ret > 0 && ssid[ret - 1] == '\0' && drv->we_version_compiled < 21) ret--; } return ret;}/** * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID * @priv: Pointer to private wext data from wpa_driver_wext_init() * @ssid: SSID * @ssid_len: Length of SSID (0..32) * Returns: 0 on success, -1 on failure */int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len){ struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0; char buf[33]; if (ssid_len > 32) return -1; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ iwr.u.essid.flags = (ssid_len != 0); memset(buf, 0, sizeof(buf)); memcpy(buf, ssid, ssid_len); iwr.u.essid.pointer = (caddr_t) buf; if (drv->we_version_compiled < 21) { /* For historic reasons, set SSID length to include one extra * character, C string nul termination, even though SSID is * really an octet string that should not be presented as a C * string. Some Linux drivers decrement the length by one and * can thus end up missing the last octet of the SSID if the * length is not incremented here. WE-21 changes this to * explicitly require the length _not_ to include nul * termination. */ if (ssid_len) ssid_len++; } iwr.u.essid.length = ssid_len; if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { perror("ioctl[SIOCSIWESSID]"); ret = -1; } return ret;}/** * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ * @priv: Pointer to private wext data from wpa_driver_wext_init() * @freq: Frequency in MHz * Returns: 0 on success, -1 on failure */int wpa_driver_wext_set_freq(void *priv, int freq){ struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); iwr.u.freq.m = freq * 100000; iwr.u.freq.e = 1; if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { perror("ioctl[SIOCSIWFREQ]"); ret = -1; } return ret;}static voidwpa_driver_wext_event_wireless_custom(struct wpa_driver_wext_data *drv, void *ctx, char *custom){ union wpa_event_data data; wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); memset(&data, 0, sizeof(data)); /* Host AP driver */ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { data.michael_mic_failure.unicast = strstr(custom, " unicast ") != NULL; /* TODO: parse parameters(?) */ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); } else if (strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) { char *spos; int bytes; spos = custom + 17; bytes = strspn(spos, "0123456789abcdefABCDEF"); if (!bytes || (bytes & 1)) return; bytes /= 2; data.assoc_info.req_ies = malloc(bytes); if (data.assoc_info.req_ies == NULL) return; data.assoc_info.req_ies_len = bytes; hexstr2bin(spos, data.assoc_info.req_ies, bytes); spos += bytes * 2; data.assoc_info.resp_ies = NULL; data.assoc_info.resp_ies_len = 0; if (strncmp(spos, " RespIEs=", 9) == 0) { spos += 9; bytes = strspn(spos, "0123456789abcdefABCDEF"); if (!bytes || (bytes & 1)) goto done; bytes /= 2; data.assoc_info.resp_ies = malloc(bytes); if (data.assoc_info.resp_ies == NULL) goto done; data.assoc_info.resp_ies_len = bytes; hexstr2bin(spos, data.assoc_info.resp_ies, bytes); } wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); done: free(data.assoc_info.resp_ies); free(data.assoc_info.req_ies); }}static int wpa_driver_wext_event_wireless_michaelmicfailure( struct wpa_driver_wext_data *drv, void *ctx, const char *ev, int len){ const struct iw_michaelmicfailure *mic; union wpa_event_data data; if (len < sizeof(*mic)) return -1; mic = (const struct iw_michaelmicfailure *) ev; wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: " "flags=0x%x src_addr=" MACSTR, mic->flags, MAC2STR(mic->src_addr.sa_data)); memset(&data, 0, sizeof(data)); data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP); wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); return 0;}static int wpa_driver_wext_event_wireless_pmkidcand( struct wpa_driver_wext_data *drv, void *ctx, const char *ev, int len){ const struct iw_pmkid_cand *cand; union wpa_event_data data; const u8 *addr; if (len < sizeof(*cand)) return -1; cand = (const struct iw_pmkid_cand *) ev; addr = (const u8 *) cand->bssid.sa_data; wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: " "flags=0x%x index=%d bssid=" MACSTR, cand->flags, cand->index, MAC2STR(addr)); memset(&data, 0, sizeof(data)); memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN); data.pmkid_candidate.index = cand->index; data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH; wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); return 0;}static int wpa_driver_wext_event_wireless_assocreqie( struct wpa_driver_wext_data *drv, void *ctx, const char *ev, int len){ if (len < 0) return -1; wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, len); free(drv->assoc_req_ies); drv->assoc_req_ies = malloc(len); if (drv->assoc_req_ies == NULL) { drv->assoc_req_ies_len = 0; return -1; } memcpy(drv->assoc_req_ies, ev, len); drv->assoc_req_ies_len = len; return 0;}static int wpa_driver_wext_event_wireless_assocrespie( struct wpa_driver_wext_data *drv, void *ctx, const char *ev, int len){ if (len < 0) return -1; wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev, len); free(drv->assoc_resp_ies); drv->assoc_resp_ies = malloc(len); if (drv->assoc_resp_ies == NULL) { drv->assoc_resp_ies_len = 0; return -1; } memcpy(drv->assoc_resp_ies, ev, len); drv->assoc_resp_ies_len = len; return 0;}static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv){ union wpa_event_data data; if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL) return; memset(&data, 0, sizeof(data)); if (drv->assoc_req_ies) { data.assoc_info.req_ies = drv->assoc_req_ies; drv->assoc_req_ies = NULL; data.assoc_info.req_ies_len = drv->assoc_req_ies_len; } if (drv->assoc_resp_ies) { data.assoc_info.resp_ies = drv->assoc_resp_ies; drv->assoc_resp_ies = NULL; data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; } wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); free(data.assoc_info.req_ies); free(data.assoc_info.resp_ies);}static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, void *ctx, char *data, int len){ struct iw_event iwe_buf, *iwe = &iwe_buf; char *pos, *end, *custom, *buf; pos = data; end = data + len; while (pos + IW_EV_LCP_LEN <= end) { /* Event data may be unaligned, so make a local, aligned copy * before processing. */ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", iwe->cmd, iwe->len); if (iwe->len <= IW_EV_LCP_LEN) return; custom = pos + IW_EV_POINT_LEN; if (drv->we_version_compiled > 18 && (iwe->cmd == IWEVMICHAELMICFAILURE || iwe->cmd == IWEVCUSTOM || iwe->cmd == IWEVASSOCREQIE || iwe->cmd == IWEVASSOCRESPIE || iwe->cmd == IWEVPMKIDCAND)) { /* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -