driver_madwifi.c

来自「hostapd无线AP工具」· C语言 代码 · 共 1,184 行 · 第 1/2 页

C
1,184
字号
/* * Host AP - driver interaction with MADWIFI 802.11 driver * Copyright (c) 2004, Sam Leffler <sam@errno.com> * Copyright (c) 2004, Video54 Technologies * * 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 <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/ioctl.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <include/compat.h>#include <net80211/ieee80211.h>#ifdef WME_NUM_AC/* Assume this is built against BSD branch of madwifi driver. */#define MADWIFI_BSD#include <net80211/_ieee80211.h>#endif /* WME_NUM_AC */#include <net80211/ieee80211_crypto.h>#include <net80211/ieee80211_ioctl.h>#include <net/if_arp.h>#include <linux/wireless.h>#include <netinet/in.h>#include <netpacket/packet.h>#include "hostapd.h"#include "driver.h"#include "ieee802_1x.h"#include "eloop.h"#include "priv_netlink.h"#include "sta_info.h"#include "l2_packet.h"#include "eapol_sm.h"#include "wpa.h"#include "radius.h"#include "ieee802_11.h"#include "accounting.h"#include "common.h"struct madwifi_driver_data {	struct driver_ops ops;			/* base class */	struct hostapd_data *hapd;		/* back pointer */	char	iface[IFNAMSIZ + 1];	int     ifindex;	struct l2_packet_data *sock_xmit;	/* raw packet xmit socket */	struct l2_packet_data *sock_recv;	/* raw packet recv socket */	int	ioctl_sock;			/* socket for ioctl() use */	int	wext_sock;			/* socket for wireless events */	u8	acct_mac[ETH_ALEN];	struct hostap_sta_driver_data acct_data;};static const struct driver_ops madwifi_driver_ops;static int madwifi_sta_deauth(void *priv, u8 *addr, int reason_code);static intset80211priv(struct madwifi_driver_data *drv, int op, void *data, int len){#define	N(a)	(sizeof(a)/sizeof(a[0]))	struct iwreq iwr;	memset(&iwr, 0, sizeof(iwr));	strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);	if (len < IFNAMSIZ) {		/*		 * Argument data fits inline; put it there.		 */		memcpy(iwr.u.name, data, len);	} else {		/*		 * Argument data too big for inline transfer; setup a		 * parameter block instead; the kernel will transfer		 * the data for the driver.		 */		iwr.u.data.pointer = data;		iwr.u.data.length = len;	}	if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {		static const char *opnames[] = {			"ioctl[IEEE80211_IOCTL_SETPARAM]",			"ioctl[IEEE80211_IOCTL_GETPARAM]",			"ioctl[IEEE80211_IOCTL_SETKEY]",			"ioctl[SIOCIWFIRSTPRIV+3]",			"ioctl[IEEE80211_IOCTL_DELKEY]",			"ioctl[SIOCIWFIRSTPRIV+5]",			"ioctl[IEEE80211_IOCTL_SETMLME]",			"ioctl[SIOCIWFIRSTPRIV+7]",			"ioctl[IEEE80211_IOCTL_SETOPTIE]",			"ioctl[IEEE80211_IOCTL_GETOPTIE]",			"ioctl[IEEE80211_IOCTL_ADDMAC]",			"ioctl[SIOCIWFIRSTPRIV+11]",			"ioctl[IEEE80211_IOCTL_DELMAC]",			"ioctl[SIOCIWFIRSTPRIV+13]",			"ioctl[IEEE80211_IOCTL_CHANLIST]",			"ioctl[SIOCIWFIRSTPRIV+15]",			"ioctl[IEEE80211_IOCTL_GETRSN]",			"ioctl[SIOCIWFIRSTPRIV+17]",			"ioctl[IEEE80211_IOCTL_GETKEY]",		};		op -= SIOCIWFIRSTPRIV;		if (0 <= op && op < N(opnames))			perror(opnames[op]);		else			perror("ioctl[unknown???]");		return -1;	}	return 0;#undef N}static intset80211param(struct madwifi_driver_data *drv, int op, int arg){	struct iwreq iwr;	memset(&iwr, 0, sizeof(iwr));	strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);	iwr.u.mode = op;	memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {		perror("ioctl[IEEE80211_IOCTL_SETPARAM]");		return -1;	}	return 0;}static const char *ether_sprintf(const u8 *addr){	static char buf[sizeof(MACSTR)];	if (addr != NULL)		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));	else		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);	return buf;}/* * Configure WPA parameters. */static intmadwifi_configure_wpa(struct madwifi_driver_data *drv){	hostapd *hapd = drv->hapd;	struct hostapd_config *conf = hapd->conf;	int v;	switch (conf->wpa_group) {	case WPA_CIPHER_CCMP:		v = IEEE80211_CIPHER_AES_CCM;		break;	case WPA_CIPHER_TKIP:		v = IEEE80211_CIPHER_TKIP;		break;	case WPA_CIPHER_WEP104:		v = IEEE80211_CIPHER_WEP;		break;	case WPA_CIPHER_WEP40:		v = IEEE80211_CIPHER_WEP;		break;	case WPA_CIPHER_NONE:		v = IEEE80211_CIPHER_NONE;		break;	default:		printf("Unknown group key cipher %u\n",			conf->wpa_group);		return -1;	}	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: group key cipher=%d\n", __func__, v);	if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {		printf("Unable to set group key cipher to %u\n", v);		return -1;	}	if (v == IEEE80211_CIPHER_WEP) {		/* key length is done only for specific ciphers */		v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);		if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {			printf("Unable to set group key length to %u\n", v);			return -1;		}	}	v = 0;	if (conf->wpa_pairwise & WPA_CIPHER_CCMP)		v |= 1<<IEEE80211_CIPHER_AES_CCM;	if (conf->wpa_pairwise & WPA_CIPHER_TKIP)		v |= 1<<IEEE80211_CIPHER_TKIP;	if (conf->wpa_pairwise & WPA_CIPHER_NONE)		v |= 1<<IEEE80211_CIPHER_NONE;	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: pairwise key ciphers=0x%x\n", __func__, v);	if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {		printf("Unable to set pairwise key ciphers to 0x%x\n", v);		return -1;	}	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: key management algorithms=0x%x\n",		__func__, conf->wpa_key_mgmt);	if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, conf->wpa_key_mgmt)) {		printf("Unable to set key management algorithms to 0x%x\n",			conf->wpa_key_mgmt);		return -1;	}	v = 0;	if (conf->rsn_preauth)		v |= BIT(0);	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: rsn capabilities=0x%x\n", __func__, conf->rsn_preauth);	if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {		printf("Unable to set RSN capabilities to 0x%x\n", v);		return -1;	}	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: enable WPA= 0x%x\n", __func__, conf->wpa);	if (set80211param(drv, IEEE80211_PARAM_WPA, conf->wpa)) {		printf("Unable to set WPA to %u\n", conf->wpa);		return -1;	}	return 0;}static intmadwifi_set_iface_flags(void *priv, int dev_up){	struct madwifi_driver_data *drv = priv;	hostapd *hapd = drv->hapd;	struct ifreq ifr;	HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE,		"%s: dev_up=%d\n", __func__, dev_up);	if (drv->ioctl_sock < 0)		return -1;	memset(&ifr, 0, sizeof(ifr));	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", 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, "%s", 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");		}	}	return 0;}static intmadwifi_set_ieee8021x(void *priv, int enabled){	struct madwifi_driver_data *drv = priv;	hostapd *hapd = drv->hapd;	struct hostapd_config *conf = hapd->conf;	HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE,		"%s: enabled=%d\n", __func__, enabled);	if (!enabled) {		/* XXX restore state */		return set80211param(priv, IEEE80211_PARAM_AUTHMODE,			IEEE80211_AUTH_AUTO);	}	if (!conf->wpa && !conf->ieee802_1x) {		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");		return -1;	}	if (conf->wpa && madwifi_configure_wpa(drv) != 0) {		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");		return -1;	}	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,		(conf->wpa ?  IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");		return -1;	}	return madwifi_set_iface_flags(priv, 1);}static intmadwifi_set_privacy(void *priv, int enabled){	struct madwifi_driver_data *drv = priv;	hostapd *hapd = drv->hapd;	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: enabled=%d\n", __func__, enabled);	return set80211param(priv, IEEE80211_PARAM_PRIVACY, enabled);}static intmadwifi_set_sta_authorized(void *priv, u8 *addr, int authorized){	struct madwifi_driver_data *drv = priv;	hostapd *hapd = drv->hapd;	struct ieee80211req_mlme mlme;	HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE,		"%s: addr=%s authorized=%d\n",		__func__, ether_sprintf(addr), authorized);	if (authorized)		mlme.im_op = IEEE80211_MLME_AUTHORIZE;	else		mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;	mlme.im_reason = 0;	memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);	return set80211priv(priv, IEEE80211_IOCTL_SETMLME, &mlme,			    sizeof(mlme));}static intmadwifi_del_key(void *priv, unsigned char *addr, int key_idx){	struct madwifi_driver_data *drv = priv;	hostapd *hapd = drv->hapd;	struct ieee80211req_del_key wk;	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: addr=%s key_idx=%d\n",		__func__, ether_sprintf(addr), key_idx);	memset(&wk, 0, sizeof(wk));	if (addr != NULL) {		memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);		wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;	} else {		wk.idk_keyix = key_idx;	}	return set80211priv(priv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));}static intmadwifi_set_key(void *priv, const char *alg,	     unsigned char *addr, int key_idx,	     u8 *key, size_t key_len){	struct madwifi_driver_data *drv = priv;	hostapd *hapd = drv->hapd;	struct ieee80211req_key wk;	u_int8_t cipher;	if (strcmp(alg, "none") == 0)		return madwifi_del_key(priv, addr, key_idx);	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: alg=%s addr=%s key_idx=%d\n",		__func__, alg, ether_sprintf(addr), key_idx);	if (strcmp(alg, "WEP") == 0)		cipher = IEEE80211_CIPHER_WEP;	else if (strcmp(alg, "TKIP") == 0)		cipher = IEEE80211_CIPHER_TKIP;	else if (strcmp(alg, "CCMP") == 0)		cipher = IEEE80211_CIPHER_AES_CCM;	else {		printf("%s: unknown/unsupported algorithm %s\n",			__func__, alg);		return -1;	}	if (key_len > sizeof(wk.ik_keydata)) {		printf("%s: key length %lu too big\n", __func__,		       (unsigned long) key_len);		return -3;	}	memset(&wk, 0, sizeof(wk));	wk.ik_type = cipher;	wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;	if (addr == NULL) {		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);		wk.ik_keyix = key_idx;		wk.ik_flags |= IEEE80211_KEY_DEFAULT;	} else {		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);		wk.ik_keyix = IEEE80211_KEYIX_NONE;	}	wk.ik_keylen = key_len;	memcpy(wk.ik_keydata, key, key_len);	return set80211priv(priv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));}static intmadwifi_get_seqnum(void *priv, u8 *addr, int idx, u8 *seq){	struct madwifi_driver_data *drv = priv;	hostapd *hapd = drv->hapd;	struct ieee80211req_key wk;	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,		"%s: addr=%s idx=%d\n", __func__, ether_sprintf(addr), idx);	memset(&wk, 0, sizeof(wk));	if (addr == NULL)		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);	else		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);	wk.ik_keyix = idx;	if (set80211priv(priv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {		printf("Failed to get encryption.\n");		return -1;	}#ifdef WORDS_BIGENDIAN	{		/*		 * wk.ik_keytsc is in host byte order (big endian), need to		 * swap it to match with the byte order used in WPA.		 */		int i;		u8 tmp[WPA_KEY_RSC_LEN];		memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));		for (i = 0; i < WPA_KEY_RSC_LEN; i++) {			seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];		}	}#else /* WORDS_BIGENDIAN */	memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));#endif /* WORDS_BIGENDIAN */	return 0;}static int madwifi_flush(void *priv){#ifdef MADWIFI_BSD	u8 allsta[IEEE80211_ADDR_LEN];	memset(allsta, 0xff, IEEE80211_ADDR_LEN);	return madwifi_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE);#else /* MADWIFI_BSD */	return 0;		/* XXX */#endif /* MADWIFI_BSD */}static intmadwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,					u8 *addr){	struct madwifi_driver_data *drv = priv;#ifdef MADWIFI_BSD	struct ieee80211req_sta_stats stats;	memset(data, 0, sizeof(*data));	/*	 * Fetch statistics for station from the system.	 */	memset(&stats, 0, sizeof(stats));	memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);	if (set80211priv(drv, IEEE80211_IOCTL_GETSTASTATS, &stats,			 sizeof(stats))) {		if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {			memcpy(data, &drv->acct_data, sizeof(*data));			return 0;		}		printf("Failed to get station stats information element.\n");		return -1;	}	data->rx_packets = stats.is_stats.ns_rx_data;	data->rx_bytes = stats.is_stats.ns_rx_bytes;	data->tx_packets = stats.is_stats.ns_tx_data;	data->tx_bytes = stats.is_stats.ns_tx_bytes;	return 0;#else /* MADWIFI_BSD */	char buf[1024], line[128], *pos;	FILE *f;	unsigned long val;	memset(data, 0, sizeof(*data));	snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR,		 drv->iface, MAC2STR(addr));	f = fopen(buf, "r");	if (!f) {		if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0)			return -1;		memcpy(data, &drv->acct_data, sizeof(*data));		return 0;	}	/* Need to read proc file with in one piece, so use large enough	 * buffer. */	setbuffer(f, buf, sizeof(buf));	while (fgets(line, sizeof(line), f)) {		pos = strchr(line, '=');		if (!pos)			continue;		*pos++ = '\0';		val = strtoul(pos, NULL, 10);		if (strcmp(line, "rx_packets") == 0)			data->rx_packets = val;		else if (strcmp(line, "tx_packets") == 0)			data->tx_packets = val;		else if (strcmp(line, "rx_bytes") == 0)			data->rx_bytes = val;		else if (strcmp(line, "tx_bytes") == 0)			data->tx_bytes = val;	}	fclose(f);	return 0;#endif /* MADWIFI_BSD */}static intmadwifi_sta_clear_stats(void *priv, u8 *addr){#ifdef MADWIFI_BSD	struct madwifi_driver_data *drv = priv;	struct hostapd_data *hapd = drv->hapd;	struct ieee80211req_mlme mlme;		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: addr=%s\n",		      __func__, ether_sprintf(addr));	mlme.im_op = IEEE80211_MLME_CLEAR_STATS;	memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);	return set80211priv(priv, IEEE80211_IOCTL_SETMLME, &mlme,			    sizeof(mlme));#else /* MADWIFI_BSD */	return 0; /* FIX */#endif /* MADWIFI_BSD */}static intmadwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len){	/*	 * Do nothing; we setup parameters at startup that define the

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?