📄 driver_wext.c
字号:
/* * WPA Supplicant - driver interaction with generic Linux Wireless Extensions * Copyright (c) 2003-2007, Jouni Malinen <j@w1.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 "includes.h"#include <sys/ioctl.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"#ifdef CONFIG_CLIENT_MLME#include <netpacket/packet.h>#include <hostapd_ioctl.h>#include <ieee80211_common.h>/* from net/mac80211.h */enum { MODE_IEEE80211A = 0 /* IEEE 802.11a */, MODE_IEEE80211B = 1 /* IEEE 802.11b only */, MODE_ATHEROS_TURBO = 2 /* Atheros Turbo mode (2x.11a at 5 GHz) */, MODE_IEEE80211G = 3 /* IEEE 802.11g (and 802.11b compatibility) */, MODE_ATHEROS_TURBOG = 4 /* Atheros Turbo mode (2x.11g at 2.4 GHz) */, NUM_IEEE80211_MODES = 5};#include "mlme.h"#ifndef ETH_P_ALL#define ETH_P_ALL 0x0003#endif#endif /* CONFIG_CLIENT_MLME */struct wpa_driver_wext_data { void *ctx; int event_sock; int ioctl_sock; int mlme_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; int operstate; char mlmedev[IFNAMSIZ + 1]; int scan_complete_events;};static int wpa_driver_wext_flush_pmkid(void *priv);static int wpa_driver_wext_get_range(void *priv);static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv, int linkmode, int operstate){ struct { struct nlmsghdr hdr; struct ifinfomsg ifinfo; char opts[16]; } req; struct rtattr *rta; static int nl_seq; ssize_t ret; req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.hdr.nlmsg_type = RTM_SETLINK; req.hdr.nlmsg_flags = NLM_F_REQUEST; req.hdr.nlmsg_seq = ++nl_seq; req.hdr.nlmsg_pid = 0; req.ifinfo.ifi_family = AF_UNSPEC; req.ifinfo.ifi_type = 0; req.ifinfo.ifi_index = drv->ifindex; req.ifinfo.ifi_flags = 0; req.ifinfo.ifi_change = 0; if (linkmode != -1) { rta = (struct rtattr *) ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)); rta->rta_type = IFLA_LINKMODE; rta->rta_len = RTA_LENGTH(sizeof(char)); *((char *) RTA_DATA(rta)) = linkmode; req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char)); } if (operstate != -1) { rta = (struct rtattr *) ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)); rta->rta_type = IFLA_OPERSTATE; rta->rta_len = RTA_LENGTH(sizeof(char)); *((char *) RTA_DATA(rta)) = operstate; req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char)); } wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d", linkmode, operstate); ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0); if (ret < 0) { wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: " "%s (assume operstate is not supported)", strerror(errno)); } return ret < 0 ? -1 : 0;}static int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, int idx, u32 value){ struct iwreq iwr; int ret = 0; os_memset(&iwr, 0, sizeof(iwr)); os_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; os_memset(&iwr, 0, sizeof(iwr)); os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { perror("ioctl[SIOCGIWAP]"); ret = -1; } os_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; os_memset(&iwr, 0, sizeof(iwr)); os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); iwr.u.ap_addr.sa_family = ARPHRD_ETHER; if (bssid) os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); else os_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; os_memset(&iwr, 0, sizeof(iwr)); os_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; os_memset(&iwr, 0, sizeof(iwr)); os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ iwr.u.essid.flags = (ssid_len != 0); os_memset(buf, 0, sizeof(buf)); os_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; os_memset(&iwr, 0, sizeof(iwr)); os_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(void *ctx, char *custom){ union wpa_event_data data; wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'", custom); os_memset(&data, 0, sizeof(data)); /* Host AP driver */ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { data.michael_mic_failure.unicast = os_strstr(custom, " unicast ") != NULL; /* TODO: parse parameters(?) */ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); } else if (os_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 = os_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 (os_strncmp(spos, " RespIEs=", 9) == 0) { spos += 9; bytes = strspn(spos, "0123456789abcdefABCDEF"); if (!bytes || (bytes & 1)) goto done; bytes /= 2; data.assoc_info.resp_ies = os_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: os_free(data.assoc_info.resp_ies); os_free(data.assoc_info.req_ies);#ifdef CONFIG_PEERKEY } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) { if (hwaddr_aton(custom + 17, data.stkstart.peer)) { wpa_printf(MSG_DEBUG, "WEXT: unrecognized " "STKSTART.request '%s'", custom + 17); return; } wpa_supplicant_event(ctx, EVENT_STKSTART, &data);#endif /* CONFIG_PEERKEY */ }}static int wpa_driver_wext_event_wireless_michaelmicfailure( void *ctx, const char *ev, size_t 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)); os_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, const char *ev, size_t 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)); os_memset(&data, 0, sizeof(data)); os_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, const char *ev, int len){ if (len < 0) return -1; wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, len); os_free(drv->assoc_req_ies); drv->assoc_req_ies = os_malloc(len); if (drv->assoc_req_ies == NULL) { drv->assoc_req_ies_len = 0; return -1; } os_memcpy(drv->assoc_req_ies, ev, len); drv->assoc_req_ies_len = len; return 0;}static int wpa_driver_wext_event_wireless_assocrespie(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -