📄 driver_devicescape.c
字号:
/* * hostapd / Kernel driver communication with Devicescape IEEE 802.11 stack * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> * Copyright (c) 2003-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * * 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. */#include "includes.h"#include <sys/ioctl.h>#ifdef USE_KERNEL_HEADERS#include <asm/types.h>#include <linux/if_packet.h>#include <linux/if_ether.h> /* The L2 protocols */#include <linux/if_arp.h>#include <linux/wireless.h>#else /* USE_KERNEL_HEADERS */#include <net/if_arp.h>#include <netpacket/packet.h>#include "wireless_copy.h"#endif /* USE_KERNEL_HEADERS */#include "hostapd.h"#include "driver.h"#include "ieee802_1x.h"#include "eloop.h"#include "priv_netlink.h"#include "ieee802_11.h"#include "sta_info.h"#include "hw_features.h"#include <hostapd_ioctl.h>#include <net/d80211_common.h>#include <net/d80211_shared.h>/* from net/d80211.h */#define WLAN_FC_PVER 0x0003#define WLAN_FC_TODS 0x0100#define WLAN_FC_FROMDS 0x0200#define WLAN_FC_ISWEP 0x4000#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)#define WLAN_FC_TYPE_MGMT 0#define WLAN_FC_TYPE_CTRL 1#define WLAN_FC_TYPE_DATA 2#define WLAN_FC_STYPE_PROBE_REQ 4#define WLAN_FC_STYPE_BEACON 8#define WLAN_FC_STYPE_DISASSOC 10#define WLAN_FC_STYPE_DEAUTH 12#define WLAN_FC_STYPE_DATA 0#define WLAN_FC_STYPE_QOS_DATA 8/* from net/d80211_mgmt.h */#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7struct i802_driver_data { struct driver_ops ops; struct hostapd_data *hapd; char iface[IFNAMSIZ + 1]; int sock; /* raw packet socket for driver access */ int ioctl_sock; /* socket for ioctl() use */ int wext_sock; /* socket for wireless events */ int we_version;};static const struct driver_ops devicescape_driver_ops;#define HAPD_DECL struct hostapd_data *hapd = iface->bss[0]static int i802_sta_set_flags(void *priv, const u8 *addr, int flags_or, int flags_and);static int hostapd_set_iface_flags(struct i802_driver_data *drv, int dev_up){ struct ifreq ifr; if (drv->ioctl_sock < 0) return -1; memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface); if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { perror("ioctl[SIOCGIFFLAGS]"); return -1; } if (dev_up) ifr.ifr_flags |= IFF_UP; else ifr.ifr_flags &= ~IFF_UP; if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { perror("ioctl[SIOCSIFFLAGS]"); return -1; } if (dev_up) { memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface); ifr.ifr_mtu = HOSTAPD_MTU; if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { perror("ioctl[SIOCSIFMTU]"); printf("Setting MTU failed - trying to survive with " "current value\n"); } } memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, IFNAMSIZ, "%s.11", drv->iface); if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { perror("ioctl[SIOCGIFFLAGS]"); return -1; } if (dev_up) ifr.ifr_flags |= IFF_UP; else ifr.ifr_flags &= ~IFF_UP; if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { perror("ioctl[SIOCSIFFLAGS]"); return -1; } return 0;}static int hostapd_ioctl_iface(const char *iface, struct i802_driver_data *drv, struct prism2_hostapd_param *param, int len){ struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, iface, IFNAMSIZ); iwr.u.data.pointer = (caddr_t) param; iwr.u.data.length = len; if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { /* perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); */ return -1; } return 0;}static int hostapd_ioctl(struct i802_driver_data *drv, struct prism2_hostapd_param *param, int len){ return hostapd_ioctl_iface(drv->iface, drv, param, len);}static int i802_set_encryption(const char *iface, void *priv, const char *alg, const u8 *addr, int idx, const u8 *key, size_t key_len, int txkey){ struct i802_driver_data *drv = priv; struct prism2_hostapd_param *param; u8 *buf; size_t blen; int ret = 0; blen = sizeof(*param) + key_len; buf = wpa_zalloc(blen); if (buf == NULL) return -1; param = (struct prism2_hostapd_param *) buf; param->cmd = PRISM2_SET_ENCRYPTION; if (addr == NULL) memset(param->sta_addr, 0xff, ETH_ALEN); else memcpy(param->sta_addr, addr, ETH_ALEN); strncpy((char *) param->u.crypt.alg, alg, HOSTAP_CRYPT_ALG_NAME_LEN); param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; param->u.crypt.idx = idx; param->u.crypt.key_len = key_len; memcpy(param->u.crypt.key, key, key_len); if (hostapd_ioctl_iface(iface, drv, param, blen) && errno != ENOENT) { printf("%s: Failed to set encryption to alg '%s' addr " MACSTR " errno=%d\n", iface, alg, MAC2STR(param->sta_addr), errno); ret = -1; } free(buf); return ret;}static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, int idx, u8 *seq){ struct i802_driver_data *drv = priv; struct prism2_hostapd_param *param; size_t param_len; int ret; param_len = sizeof(struct prism2_hostapd_param) + 32; param = wpa_zalloc(param_len); if (param == NULL) return -1; param->cmd = PRISM2_GET_ENCRYPTION; if (addr == NULL) memset(param->sta_addr, 0xff, ETH_ALEN); else memcpy(param->sta_addr, addr, ETH_ALEN); param->u.crypt.idx = idx; ret = hostapd_ioctl_iface(iface, drv, param, param_len); if (ret == 0) { memcpy(seq, param->u.crypt.seq_counter, HOSTAP_SEQ_COUNTER_SIZE); } free(param); return ret;}static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, int mode){ struct i802_driver_data *drv = priv; struct prism2_hostapd_param *param; u8 *buf; u16 *pos; size_t blen; int ret = 0; int i, num_supp = 0, num_basic = 0; if (supp_rates) for (i = 0; supp_rates[i] >= 0; i++) num_supp++; if (basic_rates) for (i = 0; basic_rates[i] >= 0; i++) num_basic++; blen = sizeof(*param) + (num_supp + num_basic) * 2; buf = wpa_zalloc(blen); if (buf == NULL) return -1; param = (struct prism2_hostapd_param *) buf; param->cmd = PRISM2_HOSTAPD_SET_RATE_SETS; param->u.set_rate_sets.mode = mode; param->u.set_rate_sets.num_supported_rates = num_supp; param->u.set_rate_sets.num_basic_rates = num_basic; pos = (u16 *) param->u.set_rate_sets.data; for (i = 0; i < num_supp; i++) *pos++ = supp_rates[i]; for (i = 0; i < num_basic; i++) *pos++ = basic_rates[i]; if (hostapd_ioctl(drv, param, blen)) { printf("Failed to set rate sets.\n"); ret = -1; } free(buf); return ret;}static int hostap_ioctl_prism2param_iface(const char *iface, struct i802_driver_data *drv, int param, int value){ struct iwreq iwr; int *i; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, iface, IFNAMSIZ); i = (int *) iwr.u.name; *i++ = param; *i++ = value; if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { char buf[128]; snprintf(buf, sizeof(buf), "%s: ioctl[PRISM2_IOCTL_PRISM2_PARAM]", iface); perror(buf); return -1; } return 0;}static int hostap_ioctl_prism2param(struct i802_driver_data *drv, int param, int value){ return hostap_ioctl_prism2param_iface(drv->iface, drv, param, value);} static int i802_set_ssid(void *priv, const u8 *buf, int len){ struct i802_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.essid.flags = 1; /* SSID active */ iwr.u.essid.pointer = (caddr_t) buf; iwr.u.essid.length = len; if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { perror("ioctl[SIOCSIWESSID]"); printf("len=%d\n", len); return -1; } return 0;}static int i802_send_mgmt_frame(void *priv, const void *msg, size_t len, int flags){ struct i802_driver_data *drv = priv; return send(drv->sock, msg, len, flags);}/* Set kernel driver on given frequency (MHz) */static int i802_set_freq(void *priv, int mode, int freq){ struct i802_driver_data *drv = priv; struct iwreq iwr; hostap_ioctl_prism2param(drv, PRISM2_PARAM_NEXT_MODE, mode); memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); iwr.u.freq.m = freq; iwr.u.freq.e = 6; if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { perror("ioctl[SIOCSIWFREQ]"); return -1; } return 0;}static int i802_set_rts(void *priv, int rts){ struct i802_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); iwr.u.rts.value = rts; iwr.u.rts.fixed = 1; if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &iwr) < 0) { perror("ioctl[SIOCSIWRTS]"); return -1; } return 0;}static int i802_get_rts(void *priv, int *rts){ struct i802_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &iwr) < 0) { perror("ioctl[SIOCGIWRTS]"); return -1; } *rts = iwr.u.rts.value; return 0;}static int i802_set_frag(void *priv, int frag){ struct i802_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); iwr.u.frag.value = frag; iwr.u.frag.fixed = 1; if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { perror("ioctl[SIOCSIWFRAG]"); return -1; } return 0;}static int i802_get_frag(void *priv, int *frag){ struct i802_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIWFRAG, &iwr) < 0) { perror("ioctl[SIOCGIWFRAG]"); return -1; } *frag = iwr.u.frag.value; return 0;}static int i802_set_retry(void *priv, int short_retry, int long_retry){ struct i802_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); iwr.u.retry.value = short_retry; iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { perror("ioctl[SIOCSIWRETRY(short)]"); return -1; } iwr.u.retry.value = long_retry; iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { perror("ioctl[SIOCSIWRETRY(long)]"); return -1; } return 0;}static int i802_get_retry(void *priv, int *short_retry, int *long_retry){ struct i802_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { perror("ioctl[SIOCGIWFRAG(short)]"); return -1; } *short_retry = iwr.u.retry.value; iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { perror("ioctl[SIOCGIWFRAG(long)]"); return -1; } *long_retry = iwr.u.retry.value; return 0;}static int i802_flush(void *priv){ struct i802_driver_data *drv = priv; struct prism2_hostapd_param param; memset(¶m, 0, sizeof(param)); param.cmd = PRISM2_HOSTAPD_FLUSH; return hostapd_ioctl(drv, ¶m, sizeof(param));}static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, const u8 *addr){ struct i802_driver_data *drv = priv; struct prism2_hostapd_param param; memset(data, 0, sizeof(*data)); memset(¶m, 0, sizeof(param)); param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; memcpy(param.sta_addr, addr, ETH_ALEN); if (hostapd_ioctl(drv, ¶m, sizeof(param))) { printf(" Could not get station info from kernel driver.\n"); return -1; } data->inactive_msec = param.u.get_info_sta.inactive_msec; data->rx_packets = param.u.get_info_sta.rx_packets; data->tx_packets = param.u.get_info_sta.tx_packets; data->rx_bytes = param.u.get_info_sta.rx_bytes; data->tx_bytes = param.u.get_info_sta.tx_bytes; data->current_tx_rate = param.u.get_info_sta.current_tx_rate; data->flags = param.u.get_info_sta.flags; data->num_ps_buf_frames = param.u.get_info_sta.num_ps_buf_frames; data->tx_retry_failed = param.u.get_info_sta.tx_retry_failed; data->tx_retry_count = param.u.get_info_sta.tx_retry_count; data->last_rssi = param.u.get_info_sta.last_rssi; data->last_ack_rssi = param.u.get_info_sta.last_ack_rssi; return 0;}static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt){ struct i802_driver_data *drv = priv; struct ieee80211_hdr *hdr; size_t len; u8 *pos; int res;#if 0 /* FIX */ int qos = sta->flags & WLAN_STA_WME;#else int qos = 0;#endif len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + data_len; hdr = wpa_zalloc(len); if (hdr == NULL) { printf("malloc() failed for i802_send_data(len=%lu)\n", (unsigned long) len); return -1; } hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); /* Request TX callback */ hdr->frame_control |= host_to_le16(BIT(1)); if (encrypt) hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); if (qos) { hdr->frame_control |= host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); } memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); memcpy(hdr->IEEE80211_BSSID_FROMDS, drv->hapd->own_addr, ETH_ALEN); memcpy(hdr->IEEE80211_SA_FROMDS, drv->hapd->own_addr, ETH_ALEN); pos = (u8 *) (hdr + 1); if (qos) { /* add an empty QoS header if needed */ pos[0] = 0; pos[1] = 0; pos += 2; } memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); pos += sizeof(rfc1042_header); /* Network order, i.e. big endian, or MSB first */ pos[0] = (ETH_P_PAE >> 8) & 0xff; pos[1] = ETH_P_PAE & 0xff; pos += 2; memcpy(pos, data, data_len); res = i802_send_mgmt_frame(drv, (u8 *) hdr, len, 0); free(hdr); if (res < 0) { perror("i802_send_eapol: send"); printf("i802_send_eapol - packet len: %lu - failed\n", (unsigned long) len); } return res;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -