⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 driver_nl80211.c

📁 最新的Host AP 新添加了许多pcmcia 的驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * hostapd / Kernel driver communication via nl80211 * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> * Copyright (c) 2003-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> * * 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>#include <netlink/genl/genl.h>#include <netlink/genl/family.h>#include <netlink/genl/ctrl.h>#include <netlink/msg.h>#include <netlink/attr.h>#include "nl80211_copy.h"#include <net/if.h>#include <netpacket/packet.h>#include "wireless_copy.h"#include <linux/filter.h>#include <net/if_arp.h>#include "hostapd.h"#include "driver.h"#include "ieee802_1x.h"#include "eloop.h"#include "ieee802_11.h"#include "sta_info.h"#include "hw_features.h"#include "mlme.h"#include "radiotap.h"#include "radiotap_iter.h"#ifdef CONFIG_LIBNL20/* libnl 2.0 compatibility code */#define nl_handle_alloc_cb nl_socket_alloc_cb#define nl_handle_destroy nl_socket_free#endif /* CONFIG_LIBNL20 */enum ieee80211_msg_type {	ieee80211_msg_normal = 0,	ieee80211_msg_tx_callback_ack = 1,	ieee80211_msg_tx_callback_fail = 2,};struct i802_driver_data {	struct hostapd_data *hapd;	char iface[IFNAMSIZ + 1];	int bridge;	int ioctl_sock; /* socket for ioctl() use */	int wext_sock; /* socket for wireless events */	int eapol_sock; /* socket for EAPOL frames */	int monitor_sock; /* socket for monitor */	int monitor_ifidx;	int default_if_indices[16];	int *if_indices;	int num_if_indices;	int we_version;	struct nl_handle *nl_handle;	struct nl_cache *nl_cache;	struct nl_cb *nl_cb;	struct genl_family *nl80211;	int dtim_period, beacon_int;	unsigned int beacon_set:1;	unsigned int ieee802_1x_active:1;	int last_freq;	int last_freq_ht;};static void add_ifidx(struct i802_driver_data *drv, int ifidx){	int i;	int *old;	for (i = 0; i < drv->num_if_indices; i++) {		if (drv->if_indices[i] == 0) {			drv->if_indices[i] = ifidx;			return;		}	}	if (drv->if_indices != drv->default_if_indices)		old = drv->if_indices;	else		old = NULL;	drv->if_indices = realloc(old,				  sizeof(int) * (drv->num_if_indices + 1));	if (!drv->if_indices) {		if (!old)			drv->if_indices = drv->default_if_indices;		else			drv->if_indices = old;		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "			   "interfaces");		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);		return;	}	drv->if_indices[drv->num_if_indices] = ifidx;	drv->num_if_indices++;}static void del_ifidx(struct i802_driver_data *drv, int ifidx){	int i;	for (i = 0; i < drv->num_if_indices; i++) {		if (drv->if_indices[i] == ifidx) {			drv->if_indices[i] = 0;			break;		}	}}static int have_ifidx(struct i802_driver_data *drv, int ifidx){	int i;	if (ifidx == drv->bridge)		return 1;	for (i = 0; i < drv->num_if_indices; i++)		if (drv->if_indices[i] == ifidx)			return 1;	return 0;}/* nl80211 code */static int ack_handler(struct nl_msg *msg, void *arg){	int *err = arg;	*err = 0;	return NL_STOP;}static int finish_handler(struct nl_msg *msg, void *arg){	int *ret = arg;	*ret = 0;	return NL_SKIP;}static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,			 void *arg){	int *ret = arg;	*ret = err->error;	return NL_SKIP;}static int send_and_recv_msgs(struct i802_driver_data *drv,			      struct nl_msg *msg,			      int (*valid_handler)(struct nl_msg *, void *),			      void *valid_data){	struct nl_cb *cb;	int err = -ENOMEM;	cb = nl_cb_clone(drv->nl_cb);	if (!cb)		goto out;	err = nl_send_auto_complete(drv->nl_handle, msg);	if (err < 0)		goto out;	err = 1;	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);	if (valid_handler)		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,			  valid_handler, valid_data);	while (err > 0)		nl_recvmsgs(drv->nl_handle, cb); out:	nl_cb_put(cb);	nlmsg_free(msg);	return err;}static int hostapd_set_iface_flags(struct i802_driver_data *drv,				   const char *ifname, int dev_up){	struct ifreq ifr;	if (drv->ioctl_sock < 0)		return -1;	memset(&ifr, 0, sizeof(ifr));	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);	if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {		perror("ioctl[SIOCGIFFLAGS]");		wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)",			   drv->iface);		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 nl_set_encr(int ifindex, struct i802_driver_data *drv,		       const char *alg, const u8 *addr, int idx, const u8 *key,		       size_t key_len, int txkey){	struct nl_msg *msg;	int ret;	msg = nlmsg_alloc();	if (!msg)		return -ENOMEM;	if (strcmp(alg, "none") == 0) {		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,			    0, NL80211_CMD_DEL_KEY, 0);	} else {		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,			    0, NL80211_CMD_NEW_KEY, 0);		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);		if (strcmp(alg, "WEP") == 0) {			if (key_len == 5)				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,					    0x000FAC01);			else				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,					    0x000FAC05);		} else if (strcmp(alg, "TKIP") == 0)			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);		else if (strcmp(alg, "CCMP") == 0)			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);		else if (strcmp(alg, "IGTK") == 0)			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);		else {			wpa_printf(MSG_ERROR, "%s: Unsupported encryption "				   "algorithm '%s'", __func__, alg);			nlmsg_free(msg);			return -1;		}	}	if (addr)		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);	ret = send_and_recv_msgs(drv, msg, NULL, NULL);	if (ret == -ENOENT)		ret = 0;	/*	 * If we failed or don't need to set the default TX key (below),	 * we're done here.	 */	if (ret || !txkey || addr)		return ret;	msg = nlmsg_alloc();	if (!msg)		return -ENOMEM;	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,		    0, NL80211_CMD_SET_KEY, 0);	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);	if (strcmp(alg, "IGTK") == 0)		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);	else		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);	ret = send_and_recv_msgs(drv, msg, NULL, NULL);	if (ret == -ENOENT)		ret = 0;	return ret; nla_put_failure:	return -ENOBUFS;}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;	int ret;	ret = nl_set_encr(if_nametoindex(iface), drv, alg, addr, idx, key,			  key_len, txkey);	if (ret < 0)		return ret;	return ret;}static inline int min_int(int a, int b){	if (a < b)		return a;	return b;}static int get_key_handler(struct nl_msg *msg, void *arg){	struct nlattr *tb[NL80211_ATTR_MAX + 1];	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),		  genlmsg_attrlen(gnlh, 0), NULL);	/*	 * TODO: validate the key index and mac address!	 * Otherwise, there's a race condition as soon as	 * the kernel starts sending key notifications.	 */	if (tb[NL80211_ATTR_KEY_SEQ])		memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),		       min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));	return NL_SKIP;}static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,			   int idx, u8 *seq){	struct i802_driver_data *drv = priv;	struct nl_msg *msg;	msg = nlmsg_alloc();	if (!msg)		return -ENOMEM;	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,		    0, NL80211_CMD_GET_KEY, 0);	if (addr)		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));	memset(seq, 0, 6);	return send_and_recv_msgs(drv, msg, get_key_handler, seq); nla_put_failure:	return -ENOBUFS;}static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,			      int mode){	struct i802_driver_data *drv = priv;	struct nl_msg *msg;	u8 rates[NL80211_MAX_SUPP_RATES];	u8 rates_len = 0;	int i;	msg = nlmsg_alloc();	if (!msg)		return -ENOMEM;	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,		    NL80211_CMD_SET_BSS, 0);	for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)		rates[rates_len++] = basic_rates[i] / 5;	NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);	/* TODO: multi-BSS support */	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));	return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure:	return -ENOBUFS;}static int i802_send_frame(void *priv, const void *data, size_t len,			   int encrypt, int flags){	__u8 rtap_hdr[] = {		0x00, 0x00, /* radiotap version */		0x0e, 0x00, /* radiotap length */		0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */		IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */		0x00,       /* padding */		0x00, 0x00, /* RX and TX flags to indicate that */		0x00, 0x00, /* this is the injected frame directly */	};	struct i802_driver_data *drv = priv;	struct iovec iov[2] = {		{			.iov_base = &rtap_hdr,			.iov_len = sizeof(rtap_hdr),		},		{			.iov_base = (void*)data,			.iov_len = len,		}	};	struct msghdr msg = {		.msg_name = NULL,		.msg_namelen = 0,		.msg_iov = iov,		.msg_iovlen = 2,		.msg_control = NULL,		.msg_controllen = 0,		.msg_flags = 0,	};	if (encrypt)		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;	return sendmsg(drv->monitor_sock, &msg, flags);}static int i802_send_mgmt_frame(void *priv, const void *data, size_t len,				int flags){	struct ieee80211_mgmt *mgmt;	int do_not_encrypt = 0;	u16 fc;	mgmt = (struct ieee80211_mgmt *) data;	fc = le_to_host16(mgmt->frame_control);	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {		/*		 * Only one of the authentication frame types is encrypted.		 * In order for static WEP encryption to work properly (i.e.,		 * to not encrypt the frame), we need to tell mac80211 about		 * the frames that must not be encrypted.		 */		u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);		u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);		if (auth_alg == WLAN_AUTH_OPEN ||		    (auth_alg == WLAN_AUTH_SHARED_KEY && auth_trans != 3))			do_not_encrypt = 1;	}	return i802_send_frame(priv, data, len, !do_not_encrypt, flags);}/* Set kernel driver on given frequency (MHz) */static int i802_set_freq2(void *priv, struct hostapd_freq_params *freq){	struct i802_driver_data *drv = priv;	struct nl_msg *msg;	msg = nlmsg_alloc();	if (!msg)		return -1;	drv->last_freq = freq->freq;	drv->last_freq_ht = freq->ht_enabled;	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,		    NL80211_CMD_SET_WIPHY, 0);	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);	if (freq->ht_enabled) {		switch (freq->sec_channel_offset) {		case -1:			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,				    NL80211_CHAN_HT40MINUS);			break;		case 1:			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,				    NL80211_CHAN_HT40PLUS);			break;		default:			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,				    NL80211_CHAN_HT20);			break;		}	}	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)		return 0; nla_put_failure:	return -1;}static int i802_set_rts(void *priv, int rts){	struct i802_driver_data *drv = priv;	struct iwreq iwr;	memset(&iwr, 0, sizeof(iwr));	os_strlcpy(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;}

⌨️ 快捷键说明

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