fix up hostapd for mac80211

SVN-Revision: 9554
This commit is contained in:
Felix Fietkau 2007-11-16 03:10:56 +00:00
parent 224760dee7
commit 67dd9a73dc
85 changed files with 5802 additions and 171 deletions

View file

@ -9,14 +9,15 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=hostapd
PKG_VERSION:=0.5.8
PKG_REV:=03ec0ec5cdb974d51a4a2a566bea4c4568138576
PKG_VERSION:=20071107_$(PKG_REV)
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://hostap.epitest.fi/releases/
PKG_MD5SUM:=40416b48cae9c78e5a2452caf214aff3
PKG_BUILD_DEPENDS:=madwifi
PKG_SOURCE_URL:=git://w1.fi/srv/git/hostap.git
PKG_SOURCE_SUBDIR:=hostapd-$(PKG_VERSION)
PKG_SOURCE_VERSION:=$(PKG_REV)
PKG_BUILD_DEPENDS:=madwifi mac80211
include $(INCLUDE_DIR)/package.mk
@ -25,7 +26,7 @@ define Package/hostapd/Default
CATEGORY:=Network
TITLE:=IEEE 802.1x Authenticator
URL:=http://hostap.epitest.fi/
DEPENDS:=@!TARGET_avr32 @!TARGET_etrax
DEPENDS:=@!TARGET_avr32 @!TARGET_etrax $(if $(DUMP)$(CONFIG_LINUX_2_6_23),+libnl)
endef
define Package/hostapd
@ -34,9 +35,9 @@ $(call Package/hostapd/Default)
DEPENDS+= +libopenssl
endef
define Package/hostapd/conffiles
/etc/hostapd.conf
endef
#define Package/hostapd/conffiles
#/etc/hostapd.conf
#endef
define Package/hostapd/description
This package contains a full featured IEEE 802.1x/WPA/EAP/RADIUS
@ -48,9 +49,9 @@ $(call Package/hostapd/Default)
TITLE+= (WPA-PSK only)
endef
define Package/hostapd-mini/conffiles
/etc/hostapd.conf
endef
#define Package/hostapd-mini/conffiles
#/etc/hostapd.conf
#endef
define Package/hostapd-mini/description
This package contains a minimal IEEE 802.1x/WPA/EAP/RADIUS Authenticator
@ -69,38 +70,31 @@ define Package/hostapd-utils/description
endef
define Build/ConfigureTarget
$(CP) $(PKG_BUILD_DIR) $(PKG_BUILD_DIR)_$(1)
$(CP) ./files/$(1).config $(PKG_BUILD_DIR)_$(1)/.config
ifneq ($(CONFIG_PACKAGE_kmod-madwifi),)
echo "CONFIG_DRIVER_MADWIFI=y" >> $(PKG_BUILD_DIR)_$(1)/.config
endif
rm -rf $(PKG_BUILD_DIR)/hostapd.$(1)
$(CP) $(PKG_BUILD_DIR)/hostapd $(PKG_BUILD_DIR)/hostapd.$(1)
$(CP) ./files/$(1).config $(PKG_BUILD_DIR)/hostapd.$(1)/.config
[ -d $(STAGING_DIR)/usr/include/mac80211 ] || $(SED) 's,^CONFIG_DRIVER_DEVICESCAPE,#CONFIG_DRIVER_DEVICESCAPE,g' $(PKG_BUILD_DIR)/hostapd.$(1)/.config
[ -d $(STAGING_DIR)/usr/include/madwifi ] || $(SED) 's,^CONFIG_DRIVER_MADWIFI,#CONFIG_DRIVER_MADWIFI,g' $(PKG_BUILD_DIR)/hostapd.$(1)/.config
endef
define Build/CompileTarget
$(MAKE) -C $(PKG_BUILD_DIR)_$(1) \
CFLAGS="$(TARGET_CFLAGS) -I$(STAGING_DIR)/usr/include/madwifi -I$(STAGING_DIR)/usr/include/mac80211 -I$(STAGING_DIR)/usr/include" \
$(MAKE) -C $(PKG_BUILD_DIR)/hostapd.$(1) \
$(TARGET_CONFIGURE_OPTS) \
OPTFLAGS="$(TARGET_CFLAGS)" \
CPPFLAGS="$(TARGET_CPPFLAGS) -I$(STAGING_DIR)/usr/include/madwifi" \
LDFLAGS="$(TARGET_LDFLAGS)" \
LIBS="$(TARGET_LDFLAGS) -L$(STAGING_DIR)/usr/lib \
$(if $(wildcard $(STAGING_DIR)/usr/include/mac80211/*),-lnl)" \
hostapd hostapd_cli
$(CP) $(PKG_BUILD_DIR)_$(1)/hostapd_cli $(PKG_BUILD_DIR)/
$(CP) $(PKG_BUILD_DIR)/hostapd.$(1)/hostapd_cli $(PKG_BUILD_DIR)/
endef
define Package/InstallTemplate
if [ \! -f "$(PKG_BUILD_DIR)_$(2)/hostapd" ]; then \
rm -f $(PKG_BUILD_DIR)/.built; \
$(MAKE) $(PKG_BUILD_DIR)/.built; \
fi
$(INSTALL_DIR) $$(1)/lib/wifi
$(INSTALL_DATA) ./files/hostapd.sh $$(1)/lib/wifi/hostapd.sh
$(INSTALL_DIR) $$(1)/etc
ifneq ($(CONFIG_PACKAGE_kmod-madwifi),)
$(INSTALL_CONF) $(PKG_BUILD_DIR)_$(2)/madwifi.conf $$(1)/etc/hostapd.conf
else
$(INSTALL_CONF) $(PKG_BUILD_DIR)_$(2)/hostapd.conf $$(1)/etc/hostapd.conf
endif
# config is managed through uci
# $(INSTALL_DIR) $$(1)/etc
# $(INSTALL_CONF) $(PKG_BUILD_DIR)/hostapd.$(2)/hostapd.conf $$(1)/etc/hostapd.conf
$(INSTALL_DIR) $$(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)_$(2)/hostapd $$(1)/usr/sbin/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/hostapd.$(2)/hostapd $$(1)/usr/sbin/
endef
define Package/Template

View file

@ -13,15 +13,29 @@
CONFIG_DRIVER_HOSTAP=y
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
CONFIG_DRIVER_WIRED=y
# Driver interface for madwifi driver
#CONFIG_DRIVER_MADWIFI=y
CONFIG_DRIVER_MADWIFI=y
#CFLAGS += -I../head # change to reflect local setup; directory for madwifi src
# Driver interface for Prism54 driver
#CONFIG_DRIVER_PRISM54=y
# Driver interface for drivers using Devicescape IEEE 802.11 stack
CONFIG_DRIVER_DEVICESCAPE=y
# Currently, driver_devicescape.c build requires some additional parameters
# to be able to include some of the kernel header files. Following lines can
# be used to set these (WIRELESS_DEV must point to the root directory of the
# wireless-dev.git tree).
#WIRELESS_DEV=/usr/src/wireless-dev
#CFLAGS += -I$(WIRELESS_DEV)/net/mac80211
# driver_devicescape.c requires a rather new libnl, probably not
# shipped with your distribution yet
#LIBNL=/usr/src/libnl
#CFLAGS += -I$(LIBNL)/include
#LIBS += -L$(LIBNL)/lib
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@ -33,37 +47,76 @@ CONFIG_IAPP=y
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
# Integrated EAP authenticator
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
# IEEE 802.11w (management frame protection)
# This version is an experimental implementation based on IEEE 802.11w/D1.0
# draft and is subject to change since the standard has not yet been finalized.
# Driver support is also needed for IEEE 802.11w.
#CONFIG_IEEE80211W=y
# Integrated EAP server
CONFIG_EAP=y
# EAP-MD5 for the integrated EAP authenticator
# EAP-MD5 for the integrated EAP server
CONFIG_EAP_MD5=y
# EAP-TLS for the integrated EAP authenticator
# EAP-TLS for the integrated EAP server
CONFIG_EAP_TLS=y
# EAP-MSCHAPv2 for the integrated EAP authenticator
# EAP-MSCHAPv2 for the integrated EAP server
CONFIG_EAP_MSCHAPV2=y
# EAP-PEAP for the integrated EAP authenticator
# EAP-PEAP for the integrated EAP server
CONFIG_EAP_PEAP=y
# EAP-PSK for the integrated EAP authenticator
CONFIG_EAP_PSK=y
# EAP-GTC for the integrated EAP authenticator
# EAP-GTC for the integrated EAP server
CONFIG_EAP_GTC=y
# EAP-TTLS for the integrated EAP authenticator
# EAP-TTLS for the integrated EAP server
CONFIG_EAP_TTLS=y
# EAP-SIM for the integrated EAP authenticator
# EAP-SIM for the integrated EAP server
#CONFIG_EAP_SIM=y
# EAP-AKA for the integrated EAP server
#CONFIG_EAP_AKA=y
# EAP-PAX for the integrated EAP server
#CONFIG_EAP_PAX=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
# EAP-SAKE for the integrated EAP server
#CONFIG_EAP_SAKE=y
# EAP-GPSK for the integrated EAP server
#CONFIG_EAP_GPSK=y
# Include support for optional SHA256 cipher suite in EAP-GPSK
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
# Note: Default OpenSSL package does not include support for all the
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
# to add the needed functions.
#CONFIG_EAP_FAST=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
# RADIUS authentication server. This provides access to the integrated EAP
# authenticator from external hosts using RADIUS.
# server from external hosts using RADIUS.
#CONFIG_RADIUS_SERVER=y
# Build IPv6 support for RADIUS operations
CONFIG_IPV6=y
# IEEE 802.11r/D4.1 (Fast BSS Transition)
# This enables an experimental implementation of a draft version of
# IEEE 802.11r. This draft is still subject to change, so it should be noted
# that this version may not comply with the final standard.
#CONFIG_IEEE80211R=y

View file

@ -13,15 +13,29 @@
CONFIG_DRIVER_HOSTAP=y
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
CONFIG_DRIVER_WIRED=y
# Driver interface for madwifi driver
#CONFIG_DRIVER_MADWIFI=y
CONFIG_DRIVER_MADWIFI=y
#CFLAGS += -I../head # change to reflect local setup; directory for madwifi src
# Driver interface for Prism54 driver
#CONFIG_DRIVER_PRISM54=y
# Driver interface for drivers using Devicescape IEEE 802.11 stack
CONFIG_DRIVER_DEVICESCAPE=y
# Currently, driver_devicescape.c build requires some additional parameters
# to be able to include some of the kernel header files. Following lines can
# be used to set these (WIRELESS_DEV must point to the root directory of the
# wireless-dev.git tree).
#WIRELESS_DEV=/usr/src/wireless-dev
#CFLAGS += -I$(WIRELESS_DEV)/net/mac80211
# driver_devicescape.c requires a rather new libnl, probably not
# shipped with your distribution yet
#LIBNL=/usr/src/libnl
#CFLAGS += -I$(LIBNL)/include
#LIBS += -L$(LIBNL)/lib
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@ -33,37 +47,76 @@ CONFIG_IAPP=y
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
# Integrated EAP authenticator
CONFIG_EAP=y
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
# EAP-MD5 for the integrated EAP authenticator
# IEEE 802.11w (management frame protection)
# This version is an experimental implementation based on IEEE 802.11w/D1.0
# draft and is subject to change since the standard has not yet been finalized.
# Driver support is also needed for IEEE 802.11w.
#CONFIG_IEEE80211W=y
# Integrated EAP server
#CONFIG_EAP=y
# EAP-MD5 for the integrated EAP server
#CONFIG_EAP_MD5=y
# EAP-TLS for the integrated EAP authenticator
# EAP-TLS for the integrated EAP server
#CONFIG_EAP_TLS=y
# EAP-MSCHAPv2 for the integrated EAP authenticator
# EAP-MSCHAPv2 for the integrated EAP server
#CONFIG_EAP_MSCHAPV2=y
# EAP-PEAP for the integrated EAP authenticator
# EAP-PEAP for the integrated EAP server
#CONFIG_EAP_PEAP=y
# EAP-PSK for the integrated EAP authenticator
CONFIG_EAP_PSK=y
# EAP-GTC for the integrated EAP authenticator
# EAP-GTC for the integrated EAP server
#CONFIG_EAP_GTC=y
# EAP-TTLS for the integrated EAP authenticator
# EAP-TTLS for the integrated EAP server
#CONFIG_EAP_TTLS=y
# EAP-SIM for the integrated EAP authenticator
# EAP-SIM for the integrated EAP server
#CONFIG_EAP_SIM=y
# EAP-AKA for the integrated EAP server
#CONFIG_EAP_AKA=y
# EAP-PAX for the integrated EAP server
#CONFIG_EAP_PAX=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
# EAP-SAKE for the integrated EAP server
#CONFIG_EAP_SAKE=y
# EAP-GPSK for the integrated EAP server
#CONFIG_EAP_GPSK=y
# Include support for optional SHA256 cipher suite in EAP-GPSK
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
# Note: Default OpenSSL package does not include support for all the
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
# to add the needed functions.
#CONFIG_EAP_FAST=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
#CONFIG_PKCS12=y
# RADIUS authentication server. This provides access to the integrated EAP
# authenticator from external hosts using RADIUS.
# server from external hosts using RADIUS.
#CONFIG_RADIUS_SERVER=y
# Build IPv6 support for RADIUS operations
#CONFIG_IPV6=y
# IEEE 802.11r/D4.1 (Fast BSS Transition)
# This enables an experimental implementation of a draft version of
# IEEE 802.11r. This draft is still subject to change, so it should be noted
# that this version may not comply with the final standard.
#CONFIG_IEEE80211R=y

View file

@ -1,36 +0,0 @@
Common subdirectories: hostapd-0.5.2/logwatch and hostapd-0.5.2.new/logwatch
Index: hostapd-0.5.7/Makefile
===================================================================
--- hostapd-0.5.7.orig/Makefile 2007-06-04 13:22:31.790022464 +0200
+++ hostapd-0.5.7/Makefile 2007-06-04 13:22:31.856012432 +0200
@@ -2,7 +2,7 @@
DIR_WPA_SUPPLICANT=.
ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
+CFLAGS = -MMD $(OPTFLAGS) $(CPPFLAGS)
endif
# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
@@ -336,7 +336,7 @@
for i in $(ALL); do cp $$i /usr/local/bin/$$i; done
hostapd: $(OBJS)
- $(CC) -o hostapd $(OBJS) $(LIBS)
+ $(CC) -o hostapd $(OBJS) $(LDFLAGS) $(LIBS)
driver_conf.c: Makefile .config
rm -f driver_conf.c
@@ -400,10 +400,10 @@
endif
nt_password_hash: $(NOBJS)
- $(CC) -o nt_password_hash $(NOBJS) $(LIBS_n)
+ $(CC) -o nt_password_hash $(NOBJS) $(LDFLAGS) $(LIBS_n)
hlr_auc_gw: $(HOBJS)
- $(CC) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
+ $(CC) -o hlr_auc_gw $(HOBJS) $(LDFLAGS) $(LIBS_h)
clean:
rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw

View file

@ -0,0 +1,18 @@
---
hostapd/driver_devicescape.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:08.000000000 +0100
+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:12.000000000 +0100
@@ -1386,10 +1386,10 @@ static void handle_frame(struct hostapd_
case ieee80211_msg_wep_frame_unknown_key:
ieee802_11_rx_unknown_key(hapd, buf, data_len);
return;
- */
case ieee80211_msg_michael_mic_failure:
hostapd_michael_mic_failure(hapd, buf, data_len);
return;
+ */
/*
* TODO
* We should be telling them to go away. But we don't support that now.

View file

@ -0,0 +1,112 @@
---
hostapd/driver_devicescape.c | 93 ++++++++++++++++++++++++++++++-------------
1 file changed, 67 insertions(+), 26 deletions(-)
--- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:12.000000000 +0100
+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:13.000000000 +0100
@@ -150,38 +150,79 @@ static int i802_set_encryption(const cha
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;
+ struct nl_msg *msg;
+ int ret = -1;
+ int err = 0;
- blen = sizeof(*param) + key_len;
- buf = os_zalloc(blen);
- if (buf == NULL)
- return -1;
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
- 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);
- os_strlcpy((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 (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
+ goto out;
+ }
- 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;
+ 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));
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
+ if (err != -ENOENT) {
+ err = 0;
+ goto out;
+ }
}
- free(buf);
+ if (!txkey) {
+ ret = 0;
+ goto out;
+ }
+
+ nlmsg_free(msg);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+ 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, if_nametoindex(iface));
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
+ if (err != -ENOENT) {
+ err = 0;
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
return ret;
}

View file

@ -0,0 +1,149 @@
---
hostapd/driver_devicescape.c | 111 +++++++++++++++++++++++++++++++------------
1 file changed, 82 insertions(+), 29 deletions(-)
--- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:13.000000000 +0100
+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:13.000000000 +0100
@@ -68,6 +68,8 @@ struct i802_driver_data {
struct nl_handle *nl_handle;
struct nl_cache *nl_cache;
struct genl_family *nl80211;
+ int dtim_period;
+ unsigned int beacon_set:1;
};
@@ -908,37 +910,44 @@ static int i802_bss_remove(void *priv, c
}
-static int i802_set_beacon(const char *ifname, void *priv,
+static int i802_set_beacon(const char *iface, void *priv,
u8 *head, size_t head_len,
u8 *tail, size_t tail_len)
{
struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param *param;
- int len, ret = 0;
+ struct nl_msg *msg;
+ u8 cmd = NL80211_CMD_NEW_BEACON;
+ int ret = -1;
- param = os_zalloc(sizeof(*param) + head_len + tail_len);
- if (param == NULL) {
- printf("Failed to alloc memory for beacon ioctl\n");
- return -1;
- }
- len = (&param->u.beacon.data[0] - (u8 *) param) + head_len + tail_len;
- param->cmd = PRISM2_HOSTAPD_SET_BEACON;
- param->u.beacon.head_len = head_len;
- param->u.beacon.tail_len = tail_len;
- memcpy(&param->u.beacon.data[0], head, head_len);
- memcpy(&param->u.beacon.data[0] + head_len, tail, tail_len);
-
- if (len < (int) sizeof(*param))
- len = sizeof(*param);
- if (hostapd_ioctl_iface(ifname, drv, param, len)) {
- printf("Could not set beacon data to kernel driver.\n");
- printf("ifname='%s' head=%p head_len=%d tail=%p tail_len=%d "
- "cmd=%d\n",
- ifname, head, head_len, tail, tail_len, param->cmd);
- ret = -1;
- }
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
- free(param);
+ if (drv->beacon_set)
+ cmd = NL80211_CMD_SET_BEACON;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, cmd, 0);
+ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
+ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, 1000);
+
+ if (!drv->dtim_period)
+ drv->dtim_period = 2;
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ goto out;
+
+ ret = 0;
+
+ drv->beacon_set = 1;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
return ret;
}
@@ -985,15 +994,59 @@ static int i802_set_internal_bridge(void
static int i802_set_beacon_int(void *priv, int value)
{
struct i802_driver_data *drv = priv;
- return hostap_ioctl_prism2param(drv, PRISM2_PARAM_BEACON_INT, value);
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
}
-static int i802_set_dtim_period(const char *ifname, void *priv, int value)
+static int i802_set_dtim_period(const char *iface, void *priv, int value)
{
struct i802_driver_data *drv = priv;
- return hostap_ioctl_prism2param_iface(ifname, drv,
- PRISM2_PARAM_DTIM_PERIOD, value);
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+
+ drv->dtim_period = value;
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
}

View file

@ -0,0 +1,116 @@
---
hostapd/driver_devicescape.c | 96 ++++++++++++++++++++++++++++++++++---------
1 file changed, 76 insertions(+), 20 deletions(-)
--- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:13.000000000 +0100
+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:14.000000000 +0100
@@ -228,33 +228,89 @@ static int i802_set_encryption(const cha
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];
+ 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 ack_wait_handler(struct nl_msg *msg, void *arg)
+{
+ int *finished = arg;
+
+ *finished = 1;
+ return NL_STOP;
+}
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;
+ struct nl_msg *msg;
+ struct nl_cb *cb = NULL;
+ int ret = -1;
+ int err = 0;
+ int finished = 0;
- param_len = sizeof(struct prism2_hostapd_param) + 32;
- param = os_zalloc(param_len);
- if (param == NULL)
- return -1;
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
- 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);
+ 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));
+
+ cb = nl_cb_alloc(NL_CB_CUSTOM);
+ if (!cb)
+ goto out;
+
+ memset(seq, 0, 6);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0)
+ goto out;
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_key_handler, seq);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished);
+
+ err = nl_recvmsgs(drv->nl_handle, cb);
+
+ if (!finished)
+ err = nl_wait_for_ack(drv->nl_handle);
+
+ if (err < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nl_cb_put(cb);
+ nla_put_failure:
+ nlmsg_free(msg);
return ret;
}

View file

@ -0,0 +1,173 @@
---
hostapd/driver.h | 8 ++++----
hostapd/driver_bsd.c | 3 ++-
hostapd/driver_devicescape.c | 6 +++---
hostapd/driver_hostap.c | 4 ++--
hostapd/driver_madwifi.c | 3 ++-
hostapd/driver_prism54.c | 3 ++-
hostapd/ieee802_11.c | 4 ++--
hostapd/ieee802_1x.c | 4 ++--
hostapd/wme.c | 6 ++++--
9 files changed, 23 insertions(+), 18 deletions(-)
--- hostap.orig/hostapd/driver.h 2007-11-09 13:41:07.000000000 +0100
+++ hostap/hostapd/driver.h 2007-11-09 13:41:15.000000000 +0100
@@ -92,7 +92,7 @@ struct wpa_driver_ops {
int (*get_retry)(void *priv, int *short_retry, int *long_retry);
int (*sta_set_flags)(void *priv, const u8 *addr,
- int flags_or, int flags_and);
+ int total_flags, int flags_or, int flags_and);
int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
int mode);
int (*set_channel_flag)(void *priv, int mode, int chan, int flag,
@@ -427,12 +427,12 @@ hostapd_get_retry(struct hostapd_data *h
static inline int
hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
- int flags_or, int flags_and)
+ int total_flags, int flags_or, int flags_and)
{
if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
return 0;
- return hapd->driver->sta_set_flags(hapd->drv_priv, addr, flags_or,
- flags_and);
+ return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
+ flags_or, flags_and);
}
static inline int
--- hostap.orig/hostapd/driver_bsd.c 2007-11-09 13:41:07.000000000 +0100
+++ hostap/hostapd/driver_bsd.c 2007-11-09 13:41:15.000000000 +0100
@@ -322,7 +322,8 @@ bsd_set_sta_authorized(void *priv, const
}
static int
-bsd_sta_set_flags(void *priv, const u8 *addr, int flags_or, int flags_and)
+bsd_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or,
+ int flags_and)
{
/* For now, only support setting Authorized flag */
if (flags_or & WLAN_STA_AUTHORIZED)
--- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:14.000000000 +0100
+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:15.000000000 +0100
@@ -76,7 +76,7 @@ struct i802_driver_data {
#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);
+ int total_flags, int flags_or, int flags_and);
static int hostapd_set_iface_flags(struct i802_driver_data *drv, int dev_up)
@@ -765,7 +765,7 @@ static int i802_sta_remove(void *priv, c
struct i802_driver_data *drv = priv;
struct prism2_hostapd_param param;
- i802_sta_set_flags(drv, addr, 0, ~WLAN_STA_AUTHORIZED);
+ i802_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED);
memset(&param, 0, sizeof(param));
param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
@@ -777,7 +777,7 @@ static int i802_sta_remove(void *priv, c
static int i802_sta_set_flags(void *priv, const u8 *addr,
- int flags_or, int flags_and)
+ int total_flags, int flags_or, int flags_and)
{
struct i802_driver_data *drv = priv;
struct prism2_hostapd_param param;
--- hostap.orig/hostapd/driver_hostap.c 2007-11-09 13:41:07.000000000 +0100
+++ hostap/hostapd/driver_hostap.c 2007-11-09 13:41:15.000000000 +0100
@@ -374,7 +374,7 @@ static int hostap_send_eapol(void *priv,
static int hostap_sta_set_flags(void *priv, const u8 *addr,
- int flags_or, int flags_and)
+ int total_flags, int flags_or, int flags_and)
{
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param param;
@@ -694,7 +694,7 @@ static int hostap_sta_remove(void *priv,
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param param;
- hostap_sta_set_flags(drv, addr, 0, ~WLAN_STA_AUTHORIZED);
+ hostap_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED);
memset(&param, 0, sizeof(param));
param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
--- hostap.orig/hostapd/driver_madwifi.c 2007-11-09 13:41:07.000000000 +0100
+++ hostap/hostapd/driver_madwifi.c 2007-11-09 13:41:15.000000000 +0100
@@ -410,7 +410,8 @@ madwifi_set_sta_authorized(void *priv, c
}
static int
-madwifi_sta_set_flags(void *priv, const u8 *addr, int flags_or, int flags_and)
+madwifi_sta_set_flags(void *priv, const u8 *addr, int total_flags,
+ int flags_or, int flags_and)
{
/* For now, only support setting Authorized flag */
if (flags_or & WLAN_STA_AUTHORIZED)
--- hostap.orig/hostapd/driver_prism54.c 2007-11-09 13:41:07.000000000 +0100
+++ hostap/hostapd/driver_prism54.c 2007-11-09 13:41:15.000000000 +0100
@@ -187,7 +187,8 @@ static int prism54_set_sta_authorized(vo
static int
-prism54_sta_set_flags(void *priv, const u8 *addr, int flags_or, int flags_and)
+prism54_sta_set_flags(void *priv, const u8 *addr, int total_flags,
+ int flags_or, int flags_and)
{
/* For now, only support setting Authorized flag */
if (flags_or & WLAN_STA_AUTHORIZED)
--- hostap.orig/hostapd/ieee802_11.c 2007-11-09 13:41:07.000000000 +0100
+++ hostap/hostapd/ieee802_11.c 2007-11-09 13:41:15.000000000 +0100
@@ -1625,10 +1625,10 @@ static void handle_assoc_cb(struct hosta
ap_sta_bind_vlan(hapd, sta, 0);
}
if (sta->flags & WLAN_STA_SHORT_PREAMBLE) {
- hostapd_sta_set_flags(hapd, sta->addr,
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
WLAN_STA_SHORT_PREAMBLE, ~0);
} else {
- hostapd_sta_set_flags(hapd, sta->addr,
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
0, ~WLAN_STA_SHORT_PREAMBLE);
}
--- hostap.orig/hostapd/ieee802_1x.c 2007-11-09 13:41:07.000000000 +0100
+++ hostap/hostapd/ieee802_1x.c 2007-11-09 13:41:15.000000000 +0100
@@ -94,13 +94,13 @@ void ieee802_1x_set_sta_authorized(struc
if (authorized) {
sta->flags |= WLAN_STA_AUTHORIZED;
- res = hostapd_sta_set_flags(hapd, sta->addr,
+ res = hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
WLAN_STA_AUTHORIZED, ~0);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "authorizing port");
} else {
sta->flags &= ~WLAN_STA_AUTHORIZED;
- res = hostapd_sta_set_flags(hapd, sta->addr,
+ res = hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
0, ~WLAN_STA_AUTHORIZED);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
--- hostap.orig/hostapd/wme.c 2007-11-09 13:41:07.000000000 +0100
+++ hostap/hostapd/wme.c 2007-11-09 13:41:15.000000000 +0100
@@ -110,9 +110,11 @@ int hostapd_wme_sta_config(struct hostap
{
/* update kernel STA data for WME related items (WLAN_STA_WPA flag) */
if (sta->flags & WLAN_STA_WME)
- hostapd_sta_set_flags(hapd, sta->addr, WLAN_STA_WME, ~0);
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ WLAN_STA_WME, ~0);
else
- hostapd_sta_set_flags(hapd, sta->addr, 0, ~WLAN_STA_WME);
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ 0, ~WLAN_STA_WME);
return 0;
}

View file

@ -0,0 +1,411 @@
---
hostapd/driver_devicescape.c | 330 ++++++++++++++++++++++++++++++++-----------
1 file changed, 249 insertions(+), 81 deletions(-)
--- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:15.000000000 +0100
+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:16.000000000 +0100
@@ -75,8 +75,14 @@ struct i802_driver_data {
#define HAPD_DECL struct hostapd_data *hapd = iface->bss[0]
-static int i802_sta_set_flags(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and);
+/* helper for netlink get routines */
+static int ack_wait_handler(struct nl_msg *msg, void *arg)
+{
+ int *finished = arg;
+
+ *finished = 1;
+ return NL_STOP;
+}
static int hostapd_set_iface_flags(struct i802_driver_data *drv, int dev_up)
@@ -255,14 +261,6 @@ static int get_key_handler(struct nl_msg
return NL_SKIP;
}
-static int ack_wait_handler(struct nl_msg *msg, void *arg)
-{
- int *finished = arg;
-
- *finished = 1;
- return NL_STOP;
-}
-
static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
int idx, u8 *seq)
{
@@ -629,43 +627,126 @@ static int i802_get_retry(void *priv, in
static int i802_flush(void *priv)
{
struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param param;
+ struct nl_msg *msg;
+ int ret = -1;
- memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_FLUSH;
- return hostapd_ioctl(drv, &param, sizeof(param));
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_STATION, 0);
+
+ /*
+ * XXX: FIX! this needs to flush all VLANs too
+ */
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
}
+static int get_sta_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct hostap_sta_driver_data *data = arg;
+ struct nlattr *stats[NL80211_STA_STAT_MAX + 1];
+ static struct nla_policy stats_policy[NL80211_STA_STAT_MAX + 1] = {
+ [NL80211_STA_STAT_INACTIVE_TIME] = { .type = NLA_U32 },
+ [NL80211_STA_STAT_RX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_STAT_TX_BYTES] = { .type = NLA_U32 },
+ };
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the interface and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending station notifications.
+ */
+
+ if (!tb[NL80211_ATTR_STA_STATS]) {
+ printf("sta stats missing!\n");
+ return NL_SKIP;
+ }
+ if (nla_parse_nested(stats, NL80211_STA_STAT_MAX,
+ tb[NL80211_ATTR_STA_STATS],
+ stats_policy)) {
+ printf("failed to parse nested attributes!\n");
+ return NL_SKIP;
+ }
+
+ if (stats[NL80211_STA_STAT_INACTIVE_TIME])
+ data->inactive_msec =
+ nla_get_u32(stats[NL80211_STA_STAT_INACTIVE_TIME]);
+ if (stats[NL80211_STA_STAT_RX_BYTES])
+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_RX_BYTES]);
+ if (stats[NL80211_STA_STAT_TX_BYTES])
+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_TX_BYTES]);
+
+ return NL_SKIP;
+}
+
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;
+ struct nl_msg *msg;
+ struct nl_cb *cb = NULL;
+ int ret = -1;
+ int err = 0;
+ int finished = 0;
- memset(data, 0, sizeof(*data));
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
- memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
- memcpy(param.sta_addr, addr, ETH_ALEN);
- if (hostapd_ioctl(drv, &param, sizeof(param))) {
- printf(" Could not get station info from kernel driver.\n");
- return -1;
- }
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_STATION, 0);
+
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ cb = nl_cb_alloc(NL_CB_CUSTOM);
+ if (!cb)
+ goto out;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0)
+ goto out;
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished);
+
+ err = nl_recvmsgs(drv->nl_handle, cb);
+
+ if (!finished)
+ err = nl_wait_for_ack(drv->nl_handle);
+
+ if (err < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nl_cb_put(cb);
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
- 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;
}
@@ -744,35 +825,68 @@ static int i802_sta_add(const char *ifna
size_t supp_rates_len, int flags)
{
struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param param;
- size_t len;
+ struct nl_msg *msg;
+ int ret = -1;
- memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_ADD_STA;
- memcpy(param.sta_addr, addr, ETH_ALEN);
- param.u.add_sta.aid = aid;
- param.u.add_sta.capability = capability;
- len = supp_rates_len;
- if (len > sizeof(param.u.add_sta.supp_rates))
- len = sizeof(param.u.add_sta.supp_rates);
- memcpy(param.u.add_sta.supp_rates, supp_rates, len);
- return hostapd_ioctl_iface(ifname, drv, &param, sizeof(param));
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, aid);
+ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len,
+ supp_rates);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 0);
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
}
static int i802_sta_remove(void *priv, const u8 *addr)
{
struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param param;
+ struct nl_msg *msg;
+ int ret = -1;
- i802_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED);
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
- memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
- memcpy(param.sta_addr, addr, ETH_ALEN);
- if (hostapd_ioctl(drv, &param, sizeof(param)))
- return -1;
- return 0;
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
}
@@ -780,14 +894,51 @@ static int i802_sta_set_flags(void *priv
int total_flags, int flags_or, int flags_and)
{
struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param param;
+ struct nl_msg *msg, *flags = NULL;
+ int ret = -1;
- memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA;
- memcpy(param.sta_addr, addr, ETH_ALEN);
- param.u.set_flags_sta.flags_or = flags_or;
- param.u.set_flags_sta.flags_and = flags_and;
- return hostapd_ioctl(drv, &param, sizeof(param));
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ flags = nlmsg_alloc();
+ if (!flags)
+ goto free_msg;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ if (total_flags & WLAN_STA_AUTHORIZED)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+
+ if (total_flags & WLAN_STA_WME)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+
+ if (total_flags & WLAN_STA_SHORT_PREAMBLE)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+
+ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
+ goto nla_put_failure;
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(flags);
+
+ free_msg:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
}
@@ -1257,18 +1408,38 @@ static struct hostapd_hw_modes * i802_ge
}
-static int i802_set_sta_vlan(void *priv, const u8 *addr, const char *ifname,
- int vlan_id)
+static int i802_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
{
struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param param;
+ struct nl_msg *msg;
+ int ret = -1;
- memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_SET_STA_VLAN;
- memcpy(param.sta_addr, addr, ETH_ALEN);
- os_strlcpy(param.u.set_sta_vlan.vlan_name, ifname, IFNAMSIZ);
- param.u.set_sta_vlan.vlan_id = vlan_id;
- return hostapd_ioctl(drv, &param, sizeof(param));
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(ifname));
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
}
@@ -1750,17 +1921,14 @@ static int i802_init_sockets(struct i802
static int i802_get_inact_sec(void *priv, const u8 *addr)
{
- struct i802_driver_data *drv = priv;
- struct prism2_hostapd_param param;
+ struct hostap_sta_driver_data data;
+ int ret;
- memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
- memcpy(param.sta_addr, addr, ETH_ALEN);
- if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ data.inactive_msec = -1;
+ ret = i802_read_sta_data(priv, &data, addr);
+ if (ret || data.inactive_msec == -1)
return -1;
- }
-
- return param.u.get_info_sta.inactive_msec / 1000;
+ return data.inactive_msec / 1000;
}

View file

@ -1,54 +0,0 @@
Index: hostapd-0.5.7/driver_madwifi.c
===================================================================
--- hostapd-0.5.7.orig/driver_madwifi.c 2007-06-04 13:22:31.768025808 +0200
+++ hostapd-0.5.7/driver_madwifi.c 2007-06-04 13:22:32.051982640 +0200
@@ -21,12 +21,9 @@
#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>
+#endif /* WME_NUM_AC */
#ifdef IEEE80211_IOCTL_SETWMMPARAMS
/* Assume this is built against madwifi-ng */
@@ -169,6 +166,11 @@
return 0;
}
+static int madwifi_get_inact_sec(void *priv, const u8 *addr)
+{
+ return 0;
+}
+
static int
set80211param(struct madwifi_driver_data *drv, int op, int arg)
{
@@ -1258,7 +1260,6 @@
goto bad;
}
- madwifi_set_iface_flags(drv, 0); /* mark down during setup */
madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */
hapd->driver = &drv->ops;
@@ -1281,7 +1282,6 @@
drv->hapd->driver = NULL;
- (void) madwifi_set_iface_flags(drv, 0);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
@@ -1367,6 +1367,7 @@
.get_ssid = madwifi_get_ssid,
.set_countermeasures = madwifi_set_countermeasures,
.sta_clear_stats = madwifi_sta_clear_stats,
+ .get_inact_sec = madwifi_get_inact_sec,
.commit = madwifi_commit,
};

View file

@ -36,8 +36,10 @@ define Build/Compile
install
endef
ifneq ($(CONFIG_LINUX_2_6_23),)
define Build/InstallDev
$(CP) $(PKG_INSTALL_DIR)/* $(1)/
$(CP) $(PKG_BUILD_DIR)/include/linux $(1)/usr/include/
endef
define Build/UninstallDev
@ -47,5 +49,6 @@ define Package/libnl/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/libnl.so.1 $(1)/usr/lib/
endef
endif
$(eval $(call BuildPackage,libnl))

View file

@ -19,10 +19,9 @@ define KernelPackage/mac80211
TITLE:=Linux 802.11 Wireless Networking Stack
DEPENDS:=@LINUX_2_6_23 +kmod-crypto-arc4 +kmod-crypto-aes +wireless-tools
FILES:= \
$(PKG_BUILD_DIR)/mac80211/mac80211.$(LINUX_KMOD_SUFFIX) \
$(PKG_BUILD_DIR)/mac80211/rc80211_simple.$(LINUX_KMOD_SUFFIX) \
$(PKG_BUILD_DIR)/wireless/cfg80211.$(LINUX_KMOD_SUFFIX)
AUTOLOAD:=$(call AutoLoad,20,cfg80211 mac80211 rc80211_simple)
$(PKG_BUILD_DIR)/net/mac80211/mac80211.$(LINUX_KMOD_SUFFIX) \
$(PKG_BUILD_DIR)/net/wireless/cfg80211.$(LINUX_KMOD_SUFFIX)
AUTOLOAD:=$(call AutoLoad,20,cfg80211 mac80211)
endef
define KernelPackage/mac80211/description
@ -32,7 +31,7 @@ endef
CONFOPTS:=MAC80211 CFG80211 NL80211
BUILDFLAGS:= \
$(foreach opt,$(CONFOPTS),-DCONFIG_$(opt) ) \
$(foreach opt,$(CONFOPTS),-DCONFIG_$(opt) -DCONFIG_MAC80211_RCSIMPLE=1) \
$(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS)
MAKE_OPTS:= \
@ -41,24 +40,26 @@ MAKE_OPTS:= \
EXTRA_CFLAGS="$(BUILDFLAGS)" \
$(foreach opt,$(CONFOPTS),CONFIG_$(opt)=m) \
CONFIG_NL80211=y \
CONFIG_MAC80211_RCSIMPLE=y \
CONFIG_MAC80211_LEDS=$(CONFIG_LEDS_TRIGGERS) \
LINUXINCLUDE="-I${CURDIR}/src/include -I$(LINUX_DIR)/include -include linux/autoconf.h" \
LINUXINCLUDE="-I$(PKG_BUILD_DIR)/include -I$(LINUX_DIR)/include -include linux/autoconf.h" \
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)/mac80211
$(CP) ./src/mac80211/* $(PKG_BUILD_DIR)/mac80211/
mkdir -p $(PKG_BUILD_DIR)/wireless
$(CP) ./src/wireless/* $(PKG_BUILD_DIR)/wireless/
rm -rf $(PKG_BUILD_DIR)
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
$(Build/Patch)
$(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
endef
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) SUBDIRS="$(PKG_BUILD_DIR)/wireless" modules
$(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) SUBDIRS="$(PKG_BUILD_DIR)/mac80211" modules
$(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) SUBDIRS="$(PKG_BUILD_DIR)/net/wireless" modules
$(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) SUBDIRS="$(PKG_BUILD_DIR)/net/mac80211" modules
endef
define Build/InstallDev
mkdir -p $(1)/usr/include/mac80211
$(CP) ./src/include/* $(1)/usr/include/mac80211/
$(CP) $(PKG_BUILD_DIR)/net/mac80211/*.h $(PKG_BUILD_DIR)/include/* $(1)/usr/include/mac80211/
endef
define Build/UninstallDev

View file

@ -0,0 +1,933 @@
Index: mac80211/include/linux/ieee80211.h
===================================================================
--- mac80211.orig/include/linux/ieee80211.h 2007-11-11 15:45:23.153490050 +0100
+++ mac80211/include/linux/ieee80211.h 2007-11-11 15:45:30.417904025 +0100
@@ -81,18 +81,18 @@
/* miscellaneous IEEE 802.11 constants */
-#define IEEE80211_MAX_FRAG_THRESHOLD 2346
-#define IEEE80211_MAX_RTS_THRESHOLD 2347
+#define IEEE80211_MAX_FRAG_THRESHOLD 2352
+#define IEEE80211_MAX_RTS_THRESHOLD 2353
#define IEEE80211_MAX_AID 2007
#define IEEE80211_MAX_TIM_LEN 251
-#define IEEE80211_MAX_DATA_LEN 2304
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
6.2.1.1.2.
- The figure in section 7.1.2 suggests a body size of up to 2312
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+ 802.11e clarifies the figure in section 7.1.2. The frame body is
+ up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */
+#define IEEE80211_MAX_DATA_LEN 2304
+/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
+#define IEEE80211_MAX_FRAME_LEN 2352
#define IEEE80211_MAX_SSID_LEN 32
Index: mac80211/include/linux/nl80211.h
===================================================================
--- mac80211.orig/include/linux/nl80211.h 2007-11-11 15:45:23.161490506 +0100
+++ mac80211/include/linux/nl80211.h 2007-11-11 15:45:30.421904255 +0100
@@ -25,7 +25,7 @@
* either a dump request on a %NL80211_ATTR_WIPHY or a specific get
* on an %NL80211_ATTR_IFINDEX is supported.
* @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
- %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
* @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
* to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
* %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
Index: mac80211/include/net/mac80211.h
===================================================================
--- mac80211.orig/include/net/mac80211.h 2007-11-11 15:45:23.169490961 +0100
+++ mac80211/include/net/mac80211.h 2007-11-11 15:45:30.429904707 +0100
@@ -706,11 +706,16 @@
*
* @queues: number of available hardware transmit queues for
* data packets. WMM/QoS requires at least four.
+ *
+ * @rate_control_algorithm: rate control algorithm for this hardware.
+ * If unset (NULL), the default algorithm will be used. Must be
+ * set before calling ieee80211_register_hw().
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
struct wiphy *wiphy;
struct workqueue_struct *workqueue;
+ const char *rate_control_algorithm;
void *priv;
u32 flags;
unsigned int extra_tx_headroom;
@@ -936,27 +941,11 @@
* and remove_interface calls, i.e. while the interface with the
* given local_address is enabled.
*
- * @set_ieee8021x: Enable/disable IEEE 802.1X. This item requests wlan card
- * to pass unencrypted EAPOL-Key frames even when encryption is
- * configured. If the wlan card does not require such a configuration,
- * this function pointer can be set to NULL.
- *
- * @set_port_auth: Set port authorization state (IEEE 802.1X PAE) to be
- * authorized (@authorized=1) or unauthorized (=0). This function can be
- * used if the wlan hardware or low-level driver implements PAE.
- * mac80211 will filter frames based on authorization state in any case,
- * so this function pointer can be NULL if low-level driver does not
- * require event notification about port state changes.
- *
* @hw_scan: Ask the hardware to service the scan request, no need to start
* the scan state machine in stack.
*
* @get_stats: return low-level statistics
*
- * @set_privacy_invoked: For devices that generate their own beacons and probe
- * response or association responses this updates the state of privacy_invoked
- * returns 0 for success or an error number.
- *
* @get_sequence_counter: For devices that have internal sequence counters this
* callback allows mac80211 to access the current value of a counter.
* This callback seems not well-defined, tell us if you need it.
@@ -1029,14 +1018,9 @@
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *local_address, const u8 *address,
struct ieee80211_key_conf *key);
- int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x);
- int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr,
- int authorized);
int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
int (*get_stats)(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
- int (*set_privacy_invoked)(struct ieee80211_hw *hw,
- int privacy_invoked);
int (*get_sequence_counter)(struct ieee80211_hw *hw,
u8* addr, u8 keyidx, u8 txrx,
u32* iv32, u16* iv16);
Index: mac80211/net/mac80211/aes_ccm.c
===================================================================
--- mac80211.orig/net/mac80211/aes_ccm.c 2007-11-11 15:45:23.177491419 +0100
+++ mac80211/net/mac80211/aes_ccm.c 2007-11-11 15:45:30.433904936 +0100
@@ -7,10 +7,10 @@
* published by the Free Software Foundation.
*/
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/err.h>
-#include <asm/scatterlist.h>
#include <net/mac80211.h>
#include "ieee80211_key.h"
@@ -63,7 +63,7 @@
s_0 = scratch + AES_BLOCK_LEN;
e = scratch + 2 * AES_BLOCK_LEN;
- num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
last_len = data_len % AES_BLOCK_LEN;
aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
@@ -102,7 +102,7 @@
s_0 = scratch + AES_BLOCK_LEN;
a = scratch + 2 * AES_BLOCK_LEN;
- num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
last_len = data_len % AES_BLOCK_LEN;
aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
Index: mac80211/net/mac80211/ieee80211.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211.c 2007-11-11 15:45:23.185491871 +0100
+++ mac80211/net/mac80211/ieee80211.c 2007-11-11 15:45:30.437905164 +0100
@@ -1061,7 +1061,8 @@
ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
- result = ieee80211_init_rate_ctrl_alg(local, NULL);
+ result = ieee80211_init_rate_ctrl_alg(local,
+ hw->rate_control_algorithm);
if (result < 0) {
printk(KERN_DEBUG "%s: Failed to initialize rate control "
"algorithm\n", wiphy_name(local->hw.wiphy));
@@ -1222,8 +1223,17 @@
BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
+#ifdef CONFIG_MAC80211_RCSIMPLE
+ ret = ieee80211_rate_control_register(&mac80211_rcsimple);
+ if (ret)
+ return ret;
+#endif
+
ret = ieee80211_wme_register();
if (ret) {
+#ifdef CONFIG_MAC80211_RCSIMPLE
+ ieee80211_rate_control_unregister(&mac80211_rcsimple);
+#endif
printk(KERN_DEBUG "ieee80211_init: failed to "
"initialize WME (err=%d)\n", ret);
return ret;
@@ -1237,6 +1247,10 @@
static void __exit ieee80211_exit(void)
{
+#ifdef CONFIG_MAC80211_RCSIMPLE
+ ieee80211_rate_control_unregister(&mac80211_rcsimple);
+#endif
+
ieee80211_wme_unregister();
ieee80211_debugfs_netdev_exit();
}
Index: mac80211/net/mac80211/ieee80211_i.h
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:45:23.189492100 +0100
+++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:45:30.441905395 +0100
@@ -232,6 +232,7 @@
#define IEEE80211_STA_AUTO_SSID_SEL BIT(10)
#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11)
#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
+#define IEEE80211_STA_PRIVACY_INVOKED BIT(13)
struct ieee80211_if_sta {
enum {
IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
@@ -261,7 +262,6 @@
unsigned long request;
struct sk_buff_head skb_queue;
- int key_management_enabled;
unsigned long last_probe;
#define IEEE80211_AUTH_ALG_OPEN BIT(0)
Index: mac80211/net/mac80211/ieee80211_ioctl.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:45:23.197492559 +0100
+++ mac80211/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:45:30.441905395 +0100
@@ -305,9 +305,12 @@
((chan->chan == channel) || (chan->freq == freq))) {
local->oper_channel = chan;
local->oper_hw_mode = mode;
- set++;
+ set = 1;
+ break;
}
}
+ if (set)
+ break;
}
if (set) {
@@ -507,10 +510,11 @@
static int ieee80211_ioctl_siwscan(struct net_device *dev,
struct iw_request_info *info,
- struct iw_point *data, char *extra)
+ union iwreq_data *wrqu, char *extra)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct iw_scan_req *req = NULL;
u8 *ssid = NULL;
size_t ssid_len = 0;
@@ -535,6 +539,14 @@
return -EOPNOTSUPP;
}
+ /* if SSID was specified explicitly then use that */
+ if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+ wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ req = (struct iw_scan_req *)extra;
+ ssid = req->essid;
+ ssid_len = req->essid_len;
+ }
+
return ieee80211_sta_req_scan(dev, ssid, ssid_len);
}
@@ -621,22 +633,35 @@
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
bool need_reconfig = 0;
+ u8 new_power_level;
if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
return -EINVAL;
if (data->txpower.flags & IW_TXPOW_RANGE)
return -EINVAL;
- if (!data->txpower.fixed)
- return -EINVAL;
- if (local->hw.conf.power_level != data->txpower.value) {
- local->hw.conf.power_level = data->txpower.value;
+ if (data->txpower.fixed) {
+ new_power_level = data->txpower.value;
+ } else {
+ /* Automatic power level. Get the px power from the current
+ * channel. */
+ struct ieee80211_channel* chan = local->oper_channel;
+ if (!chan)
+ return -EINVAL;
+
+ new_power_level = chan->power_level;
+ }
+
+ if (local->hw.conf.power_level != new_power_level) {
+ local->hw.conf.power_level = new_power_level;
need_reconfig = 1;
}
+
if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
local->hw.conf.radio_enabled = !(data->txpower.disabled);
need_reconfig = 1;
}
+
if (need_reconfig) {
ieee80211_hw_config(local);
/* The return value of hw_config is not of big interest here,
@@ -904,7 +929,6 @@
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int ret = 0;
@@ -914,18 +938,21 @@
case IW_AUTH_CIPHER_GROUP:
case IW_AUTH_WPA_ENABLED:
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- break;
case IW_AUTH_KEY_MGMT:
+ break;
+ case IW_AUTH_PRIVACY_INVOKED:
if (sdata->type != IEEE80211_IF_TYPE_STA)
ret = -EINVAL;
else {
+ sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
/*
- * Key management was set by wpa_supplicant,
- * we only need this to associate to a network
- * that has privacy enabled regardless of not
- * having a key.
+ * Privacy invoked by wpa_supplicant, store the
+ * value and allow associating to a protected
+ * network without having a key up front.
*/
- sdata->u.sta.key_management_enabled = !!data->value;
+ if (data->value)
+ sdata->u.sta.flags |=
+ IEEE80211_STA_PRIVACY_INVOKED;
}
break;
case IW_AUTH_80211_AUTH_ALG:
@@ -935,11 +962,6 @@
else
ret = -EOPNOTSUPP;
break;
- case IW_AUTH_PRIVACY_INVOKED:
- if (local->ops->set_privacy_invoked)
- ret = local->ops->set_privacy_invoked(
- local_to_hw(local), data->value);
- break;
default:
ret = -EOPNOTSUPP;
break;
Index: mac80211/net/mac80211/ieee80211_rate.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_rate.c 2007-11-11 15:45:23.205493011 +0100
+++ mac80211/net/mac80211/ieee80211_rate.c 2007-11-11 15:45:30.441905395 +0100
@@ -25,13 +25,25 @@
{
struct rate_control_alg *alg;
+ if (!ops->name)
+ return -EINVAL;
+
+ mutex_lock(&rate_ctrl_mutex);
+ list_for_each_entry(alg, &rate_ctrl_algs, list) {
+ if (!strcmp(alg->ops->name, ops->name)) {
+ /* don't register an algorithm twice */
+ WARN_ON(1);
+ return -EALREADY;
+ }
+ }
+
alg = kzalloc(sizeof(*alg), GFP_KERNEL);
if (alg == NULL) {
+ mutex_unlock(&rate_ctrl_mutex);
return -ENOMEM;
}
alg->ops = ops;
- mutex_lock(&rate_ctrl_mutex);
list_add_tail(&alg->list, &rate_ctrl_algs);
mutex_unlock(&rate_ctrl_mutex);
@@ -61,9 +73,12 @@
struct rate_control_alg *alg;
struct rate_control_ops *ops = NULL;
+ if (!name)
+ return NULL;
+
mutex_lock(&rate_ctrl_mutex);
list_for_each_entry(alg, &rate_ctrl_algs, list) {
- if (!name || !strcmp(alg->ops->name, name))
+ if (!strcmp(alg->ops->name, name))
if (try_module_get(alg->ops->module)) {
ops = alg->ops;
break;
@@ -80,9 +95,12 @@
{
struct rate_control_ops *ops;
+ if (!name)
+ name = "simple";
+
ops = ieee80211_try_rate_control_ops_get(name);
if (!ops) {
- request_module("rc80211_%s", name ? name : "default");
+ request_module("rc80211_%s", name);
ops = ieee80211_try_rate_control_ops_get(name);
}
return ops;
Index: mac80211/net/mac80211/ieee80211_rate.h
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_rate.h 2007-11-11 15:45:23.213493469 +0100
+++ mac80211/net/mac80211/ieee80211_rate.h 2007-11-11 15:45:30.445905621 +0100
@@ -65,6 +65,9 @@
struct kref kref;
};
+/* default 'simple' algorithm */
+extern struct rate_control_ops mac80211_rcsimple;
+
int ieee80211_rate_control_register(struct rate_control_ops *ops);
void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
Index: mac80211/net/mac80211/ieee80211_sta.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_sta.c 2007-11-11 15:45:23.217493699 +0100
+++ mac80211/net/mac80211/ieee80211_sta.c 2007-11-11 15:46:32.885463850 +0100
@@ -12,7 +12,6 @@
*/
/* TODO:
- * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs
* order BSS list by RSSI(?) ("quality of AP")
* scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
* SSID)
@@ -61,7 +60,8 @@
static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
u8 *ssid, size_t ssid_len);
static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
+ u8 *ssid, u8 ssid_len);
static void ieee80211_rx_bss_put(struct net_device *dev,
struct ieee80211_sta_bss *bss);
static int ieee80211_sta_find_ibss(struct net_device *dev,
@@ -108,14 +108,11 @@
u8 wmm_param_len;
};
-enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 };
-
-static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
- struct ieee802_11_elems *elems)
+static void ieee802_11_parse_elems(u8 *start, size_t len,
+ struct ieee802_11_elems *elems)
{
size_t left = len;
u8 *pos = start;
- int unknown = 0;
memset(elems, 0, sizeof(*elems));
@@ -126,15 +123,8 @@
elen = *pos++;
left -= 2;
- if (elen > left) {
-#if 0
- if (net_ratelimit())
- printk(KERN_DEBUG "IEEE 802.11 element parse "
- "failed (id=%d elen=%d left=%d)\n",
- id, elen, left);
-#endif
- return ParseFailed;
- }
+ if (elen > left)
+ return;
switch (id) {
case WLAN_EID_SSID:
@@ -201,28 +191,15 @@
elems->ext_supp_rates_len = elen;
break;
default:
-#if 0
- printk(KERN_DEBUG "IEEE 802.11 element parse ignored "
- "unknown element (id=%d elen=%d)\n",
- id, elen);
-#endif
- unknown++;
break;
}
left -= elen;
pos += elen;
}
-
- /* Do not trigger error if left == 1 as Apple Airport base stations
- * send AssocResps that are one spurious byte too long. */
-
- return unknown ? ParseUnknown : ParseOK;
}
-
-
static int ecw2cw(int ecw)
{
int cw = 1;
@@ -426,7 +403,9 @@
if (sdata->type != IEEE80211_IF_TYPE_STA)
return;
- bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+ local->hw.conf.channel,
+ ifsta->ssid, ifsta->ssid_len);
if (bss) {
if (bss->has_erp_value)
ieee80211_handle_erp_ie(dev, bss->erp_value);
@@ -571,7 +550,8 @@
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
WLAN_CAPABILITY_SHORT_PREAMBLE;
}
- bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
+ ifsta->ssid, ifsta->ssid_len);
if (bss) {
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;
@@ -719,24 +699,30 @@
static int ieee80211_privacy_mismatch(struct net_device *dev,
struct ieee80211_if_sta *ifsta)
{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
- int res = 0;
+ int bss_privacy;
+ int wep_privacy;
+ int privacy_invoked;
- if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) ||
- ifsta->key_management_enabled)
+ if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
return 0;
- bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
+ ifsta->ssid, ifsta->ssid_len);
if (!bss)
return 0;
- if (ieee80211_sta_wep_configured(dev) !=
- !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
- res = 1;
+ bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
+ wep_privacy = !!ieee80211_sta_wep_configured(dev);
+ privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
ieee80211_rx_bss_put(dev, bss);
- return res;
+ if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
+ return 0;
+
+ return 1;
}
@@ -920,12 +906,7 @@
printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
pos = mgmt->u.auth.variable;
- if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
- == ParseFailed) {
- printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n",
- dev->name);
- return;
- }
+ ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
if (!elems.challenge) {
printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
"frame\n", dev->name);
@@ -1214,12 +1195,7 @@
}
pos = mgmt->u.assoc_resp.variable;
- if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
- == ParseFailed) {
- printk(KERN_DEBUG "%s: failed to parse AssocResp\n",
- dev->name);
- return;
- }
+ ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
if (!elems.supp_rates) {
printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
@@ -1231,7 +1207,9 @@
* update our stored copy */
if (elems.erp_info && elems.erp_info_len >= 1) {
struct ieee80211_sta_bss *bss
- = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ = ieee80211_rx_bss_get(dev, ifsta->bssid,
+ local->hw.conf.channel,
+ ifsta->ssid, ifsta->ssid_len);
if (bss) {
bss->erp_value = elems.erp_info[0];
bss->has_erp_value = 1;
@@ -1261,7 +1239,9 @@
" AP\n", dev->name);
return;
}
- bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+ local->hw.conf.channel,
+ ifsta->ssid, ifsta->ssid_len);
if (bss) {
sta->last_rssi = bss->rssi;
sta->last_signal = bss->signal;
@@ -1337,7 +1317,8 @@
static struct ieee80211_sta_bss *
-ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel,
+ u8 *ssid, u8 ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
@@ -1348,6 +1329,11 @@
atomic_inc(&bss->users);
atomic_inc(&bss->users);
memcpy(bss->bssid, bssid, ETH_ALEN);
+ bss->channel = channel;
+ if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
+ memcpy(bss->ssid, ssid, ssid_len);
+ bss->ssid_len = ssid_len;
+ }
spin_lock_bh(&local->sta_bss_lock);
/* TODO: order by RSSI? */
@@ -1359,7 +1345,8 @@
static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
+ u8 *ssid, u8 ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
@@ -1367,7 +1354,10 @@
spin_lock_bh(&local->sta_bss_lock);
bss = local->sta_bss_hash[STA_HASH(bssid)];
while (bss) {
- if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
+ if (!memcmp(bss->bssid, bssid, ETH_ALEN) &&
+ bss->channel == channel &&
+ bss->ssid_len == ssid_len &&
+ (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
atomic_inc(&bss->users);
break;
}
@@ -1429,7 +1419,7 @@
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee802_11_elems elems;
size_t baselen;
- int channel, invalid = 0, clen;
+ int channel, clen;
struct ieee80211_sta_bss *bss;
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1473,9 +1463,7 @@
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
}
- if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
- &elems) == ParseFailed)
- invalid = 1;
+ ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
@@ -1533,9 +1521,11 @@
else
channel = rx_status->channel;
- bss = ieee80211_rx_bss_get(dev, mgmt->bssid);
+ bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel,
+ elems.ssid, elems.ssid_len);
if (!bss) {
- bss = ieee80211_rx_bss_add(dev, mgmt->bssid);
+ bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel,
+ elems.ssid, elems.ssid_len);
if (!bss)
return;
} else {
@@ -1561,10 +1551,6 @@
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
- if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
- memcpy(bss->ssid, elems.ssid, elems.ssid_len);
- bss->ssid_len = elems.ssid_len;
- }
bss->supp_rates_len = 0;
if (elems.supp_rates) {
@@ -1635,7 +1621,6 @@
bss->hw_mode = rx_status->phymode;
- bss->channel = channel;
bss->freq = rx_status->freq;
if (channel != rx_status->channel &&
(bss->hw_mode == MODE_IEEE80211G ||
@@ -1695,9 +1680,7 @@
if (baselen > len)
return;
- if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
- &elems) == ParseFailed)
- return;
+ ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
if (elems.erp_info && elems.erp_info_len >= 1)
ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
@@ -2098,7 +2081,8 @@
{
int tmp, hidden_ssid;
- if (!memcmp(ifsta->ssid, ssid, ssid_len))
+ if (ssid_len == ifsta->ssid_len &&
+ !memcmp(ifsta->ssid, ssid, ssid_len))
return 1;
if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
@@ -2357,7 +2341,7 @@
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_hw_mode *mode;
u8 bssid[ETH_ALEN], *pos;
int i;
@@ -2379,18 +2363,17 @@
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n",
dev->name, MAC_ARG(bssid));
- bss = ieee80211_rx_bss_add(dev, bssid);
+ bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel,
+ sdata->u.sta.ssid, sdata->u.sta.ssid_len);
if (!bss)
return -ENOMEM;
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
mode = local->oper_hw_mode;
if (local->hw.conf.beacon_int == 0)
local->hw.conf.beacon_int = 100;
bss->beacon_int = local->hw.conf.beacon_int;
bss->hw_mode = local->hw.conf.phymode;
- bss->channel = local->hw.conf.channel;
bss->freq = local->hw.conf.freq;
bss->last_update = jiffies;
bss->capability = WLAN_CAPABILITY_IBSS;
@@ -2448,7 +2431,8 @@
MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid));
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
- (bss = ieee80211_rx_bss_get(dev, bssid))) {
+ (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel,
+ ifsta->ssid, ifsta->ssid_len))) {
printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT
" based on configured SSID\n",
dev->name, MAC_ARG(bssid));
Index: mac80211/net/mac80211/Kconfig
===================================================================
--- mac80211.orig/net/mac80211/Kconfig 2007-11-11 15:45:23.225494151 +0100
+++ mac80211/net/mac80211/Kconfig 2007-11-11 15:45:30.449905846 +0100
@@ -13,6 +13,18 @@
This option enables the hardware independent IEEE 802.11
networking stack.
+config MAC80211_RCSIMPLE
+ bool "'simple' rate control algorithm" if EMBEDDED
+ default y
+ depends on MAC80211
+ help
+ This option allows you to turn off the 'simple' rate
+ control algorithm in mac80211. If you do turn it off,
+ you absolutely need another rate control algorithm.
+
+ Say Y unless you know you will have another algorithm
+ available.
+
config MAC80211_LEDS
bool "Enable LED triggers"
depends on MAC80211 && LEDS_TRIGGERS
Index: mac80211/net/mac80211/Makefile
===================================================================
--- mac80211.orig/net/mac80211/Makefile 2007-11-11 15:45:23.233494609 +0100
+++ mac80211/net/mac80211/Makefile 2007-11-11 15:45:30.449905846 +0100
@@ -1,8 +1,9 @@
-obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
+obj-$(CONFIG_MAC80211) += mac80211.o
mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
mac80211-objs-$(CONFIG_NET_SCHED) += wme.o
+mac80211-objs-$(CONFIG_MAC80211_RCSIMPLE) += rc80211_simple.o
mac80211-objs := \
ieee80211.o \
Index: mac80211/net/mac80211/rc80211_simple.c
===================================================================
--- mac80211.orig/net/mac80211/rc80211_simple.c 2007-11-11 15:45:23.237494839 +0100
+++ mac80211/net/mac80211/rc80211_simple.c 2007-11-11 15:45:30.449905846 +0100
@@ -7,7 +7,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/types.h>
@@ -29,8 +28,6 @@
#define RATE_CONTROL_INTERVAL (HZ / 20)
#define RATE_CONTROL_MIN_TX 10
-MODULE_ALIAS("rc80211_default");
-
static void rate_control_rate_inc(struct ieee80211_local *local,
struct sta_info *sta)
{
@@ -393,8 +390,7 @@
}
#endif
-static struct rate_control_ops rate_control_simple = {
- .module = THIS_MODULE,
+struct rate_control_ops mac80211_rcsimple = {
.name = "simple",
.tx_status = rate_control_simple_tx_status,
.get_rate = rate_control_simple_get_rate,
@@ -409,22 +405,3 @@
.remove_sta_debugfs = rate_control_simple_remove_sta_debugfs,
#endif
};
-
-
-static int __init rate_control_simple_init(void)
-{
- return ieee80211_rate_control_register(&rate_control_simple);
-}
-
-
-static void __exit rate_control_simple_exit(void)
-{
- ieee80211_rate_control_unregister(&rate_control_simple);
-}
-
-
-subsys_initcall(rate_control_simple_init);
-module_exit(rate_control_simple_exit);
-
-MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
-MODULE_LICENSE("GPL");
Index: mac80211/net/mac80211/rx.c
===================================================================
--- mac80211.orig/net/mac80211/rx.c 2007-11-11 15:45:23.245495291 +0100
+++ mac80211/net/mac80211/rx.c 2007-11-11 15:45:30.449905846 +0100
@@ -509,9 +509,11 @@
rx->key->tx_rx_count++;
/* TODO: add threshold stuff again */
} else {
+#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: RX protected frame,"
" but have no key\n", rx->dev->name);
+#endif /* CONFIG_MAC80211_DEBUG */
return TXRX_DROP;
}
Index: mac80211/net/mac80211/wep.c
===================================================================
--- mac80211.orig/net/mac80211/wep.c 2007-11-11 15:45:23.253495749 +0100
+++ mac80211/net/mac80211/wep.c 2007-11-11 15:45:30.449905846 +0100
@@ -16,7 +16,7 @@
#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/mm.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
@@ -138,9 +138,7 @@
*icv = cpu_to_le32(~crc32_le(~0, data, data_len));
crypto_blkcipher_setkey(tfm, rc4key, klen);
- sg.page = virt_to_page(data);
- sg.offset = offset_in_page(data);
- sg.length = data_len + WEP_ICV_LEN;
+ sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
}
@@ -204,9 +202,7 @@
__le32 crc;
crypto_blkcipher_setkey(tfm, rc4key, klen);
- sg.page = virt_to_page(data);
- sg.offset = offset_in_page(data);
- sg.length = data_len + WEP_ICV_LEN;
+ sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
crc = cpu_to_le32(~crc32_le(~0, data, data_len));
@@ -318,9 +314,11 @@
if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
+#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
"failed\n", rx->dev->name);
+#endif /* CONFIG_MAC80211_DEBUG */
return TXRX_DROP;
}
} else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
Index: mac80211/net/wireless/Kconfig
===================================================================
--- mac80211.orig/net/wireless/Kconfig 2007-11-11 15:45:23.261496205 +0100
+++ mac80211/net/wireless/Kconfig 2007-11-11 15:45:30.453906075 +0100
@@ -3,7 +3,7 @@
config NL80211
bool "nl80211 new netlink interface support"
- depends CFG80211
+ depends on CFG80211
default y
---help---
This option turns on the new netlink interface

View file

@ -0,0 +1,110 @@
---
net/mac80211/hostapd_ioctl.h | 103 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 103 insertions(+)
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ everything/net/mac80211/hostapd_ioctl.h 2007-11-07 13:19:23.031516330 +0100
@@ -0,0 +1,103 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver
+ * Copyright 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright 2005, 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.
+ */
+
+#ifndef HOSTAPD_IOCTL_H
+#define HOSTAPD_IOCTL_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif /* __KERNEL__ */
+
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3)
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes:
+ * This table is no longer added to, the whole sub-ioctl
+ * mess shall be deleted completely. */
+enum {
+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+ PRISM2_PARAM_IEEE_802_1X = 23,
+
+ /* Instant802 additions */
+ PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
+ PRISM2_PARAM_PREAMBLE = 1003,
+ PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
+ PRISM2_PARAM_NEXT_MODE = 1008,
+ PRISM2_PARAM_PRIVACY_INVOKED = 1014,
+ PRISM2_PARAM_EAPOL = 1023,
+ PRISM2_PARAM_MGMT_IF = 1046,
+};
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd:
+ * This table is no longer added to, the hostapd ioctl
+ * shall be deleted completely. */
+enum {
+ PRISM2_HOSTAPD_FLUSH = 1,
+
+ /* Instant802 additions */
+ PRISM2_HOSTAPD_GET_HW_FEATURES = 1002,
+ PRISM2_HOSTAPD_SET_RATE_SETS = 1005,
+ PRISM2_HOSTAPD_SET_CHANNEL_FLAG = 1012,
+ PRISM2_HOSTAPD_SET_REGULATORY_DOMAIN = 1013,
+ PRISM2_HOSTAPD_SET_TX_QUEUE_PARAMS = 1014,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 2048
+#define ALIGNED __attribute__ ((aligned))
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ u8 pad[2];
+ union {
+ struct {
+ u16 num_modes;
+ u16 flags;
+ u8 data[0] ALIGNED; /* num_modes * feature data */
+ } hw_features;
+ struct {
+ u16 mode; /* MODE_* */
+ u16 num_supported_rates;
+ u16 num_basic_rates;
+ u8 data[0] ALIGNED; /* num_supported_rates * u16 +
+ * num_basic_rates * u16 */
+ } set_rate_sets;
+ struct {
+ u16 mode; /* MODE_* */
+ u16 chan;
+ u32 flag;
+ u8 power_level; /* regulatory limit in dBm */
+ u8 antenna_max;
+ } set_channel_flag;
+ struct {
+ u32 rd;
+ } set_regulatory_domain;
+ struct {
+ u32 queue;
+ s32 aifs;
+ u32 cw_min;
+ u32 cw_max;
+ u32 burst_time; /* maximum burst time in 0.1 ms, i.e.,
+ * 10 = 1 ms */
+ } tx_queue_params;
+ } u;
+};
+
+/* Data structures used for get_hw_features ioctl */
+struct hostapd_ioctl_hw_modes_hdr {
+ int mode;
+ int num_channels;
+ int num_rates;
+};
+
+#endif /* HOSTAPD_IOCTL_H */

View file

@ -0,0 +1,187 @@
---
net/mac80211/ieee80211.c | 5 +
net/mac80211/ieee80211_ioctl.c | 121 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 126 insertions(+)
--- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:06:34.902124618 +0100
+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:24.311521482 +0100
@@ -21,6 +21,7 @@
#include <net/mac80211.h>
#include "ieee80211_i.h"
+#include "hostapd_ioctl.h"
#include "ieee80211_rate.h"
#include "wpa.h"
#include "aes_ccm.h"
@@ -124,6 +125,47 @@ static int ieee80211_ioctl_siwgenie(stru
return -EOPNOTSUPP;
}
+
+static int ieee80211_ioctl_priv_hostapd(struct net_device *dev,
+ struct iw_point *p)
+{
+ struct prism2_hostapd_param *param;
+ int ret = 0;
+
+ if (p->length < sizeof(struct prism2_hostapd_param) ||
+ p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) {
+ printk(KERN_DEBUG "%s: hostapd ioctl: ptr=%p len=%d min=%d "
+ "max=%d\n", dev->name, p->pointer, p->length,
+ (int)sizeof(struct prism2_hostapd_param),
+ PRISM2_HOSTAPD_MAX_BUF_SIZE);
+ return -EINVAL;
+ }
+
+ param = kmalloc(p->length, GFP_KERNEL);
+ if (!param)
+ return -ENOMEM;
+
+ if (copy_from_user(param, p->pointer, p->length)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ switch (param->cmd) {
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ if (copy_to_user(p->pointer, param, p->length))
+ ret = -EFAULT;
+
+ out:
+ kfree(param);
+
+ return ret;
+}
+
+
static int ieee80211_ioctl_giwname(struct net_device *dev,
struct iw_request_info *info,
char *name, char *extra)
@@ -819,6 +861,49 @@ static int ieee80211_ioctl_giwretry(stru
return 0;
}
+static int ieee80211_ioctl_prism2_param(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata;
+ int *i = (int *) extra;
+ int param = *i;
+ int ret = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ switch (param) {
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata;
+ int *param = (int *) extra;
+ int ret = 0;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ switch (*param) {
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
static int ieee80211_ioctl_siwmlme(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
@@ -1073,6 +1158,32 @@ static int ieee80211_ioctl_siwencodeext(
}
+static const struct iw_priv_args ieee80211_ioctl_priv[] = {
+ { PRISM2_IOCTL_PRISM2_PARAM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
+ { PRISM2_IOCTL_GET_PRISM2_PARAM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
+};
+
+
+int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct iwreq *wrq = (struct iwreq *) rq;
+
+ switch (cmd) {
+ /* Private ioctls (iwpriv) that have not yet been converted
+ * into new wireless extensions API */
+ case PRISM2_IOCTL_HOSTAPD:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ return ieee80211_ioctl_priv_hostapd(dev, &wrq->u.data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
/* Structures to export the Wireless Handlers */
static const iw_handler ieee80211_handler[] =
@@ -1135,9 +1246,19 @@ static const iw_handler ieee80211_handle
(iw_handler) NULL, /* -- hole -- */
};
+static const iw_handler ieee80211_private_handler[] =
+{ /* SIOCIWFIRSTPRIV + */
+ (iw_handler) ieee80211_ioctl_prism2_param, /* 0 */
+ (iw_handler) ieee80211_ioctl_get_prism2_param, /* 1 */
+};
+
const struct iw_handler_def ieee80211_iw_handler_def =
{
.num_standard = ARRAY_SIZE(ieee80211_handler),
+ .num_private = ARRAY_SIZE(ieee80211_private_handler),
+ .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
.standard = (iw_handler *) ieee80211_handler,
+ .private = (iw_handler *) ieee80211_private_handler,
+ .private_args = (struct iw_priv_args *) ieee80211_ioctl_priv,
.get_wireless_stats = ieee80211_get_wireless_stats,
};
--- everything.orig/net/mac80211/ieee80211.c 2007-11-07 13:18:36.001511500 +0100
+++ everything/net/mac80211/ieee80211.c 2007-11-07 13:19:24.311521482 +0100
@@ -413,6 +413,9 @@ static const struct header_ops ieee80211
.cache_update = eth_header_cache_update,
};
+/* HACK */
+extern int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+
/* Must not be called for mdev */
void ieee80211_if_setup(struct net_device *dev)
{
@@ -425,6 +428,8 @@ void ieee80211_if_setup(struct net_devic
dev->open = ieee80211_open;
dev->stop = ieee80211_stop;
dev->destructor = ieee80211_if_free;
+
+ dev->do_ioctl = ieee80211_ioctl;
}
/* WDS specialties */

View file

@ -0,0 +1,688 @@
---
include/net/mac80211.h | 1
net/mac80211/ieee80211.c | 198 ++++++++++++++++++++++++++++++++++++++--
net/mac80211/ieee80211_common.h | 64 ++++++++++++
net/mac80211/ieee80211_i.h | 9 +
net/mac80211/ieee80211_iface.c | 66 +++++++++++++
net/mac80211/ieee80211_ioctl.c | 21 ++++
net/mac80211/ieee80211_rate.c | 3
net/mac80211/ieee80211_rate.h | 2
net/mac80211/ieee80211_sta.c | 2
net/mac80211/rx.c | 29 ++++-
net/mac80211/tx.c | 14 ++
net/mac80211/wme.c | 10 +-
12 files changed, 399 insertions(+), 20 deletions(-)
Index: mac80211/include/net/mac80211.h
===================================================================
--- mac80211.orig/include/net/mac80211.h 2007-11-11 15:15:42.824034853 +0100
+++ mac80211/include/net/mac80211.h 2007-11-11 15:15:53.784659457 +0100
@@ -472,6 +472,7 @@
enum ieee80211_if_types {
IEEE80211_IF_TYPE_INVALID,
IEEE80211_IF_TYPE_AP,
+ IEEE80211_IF_TYPE_MGMT,
IEEE80211_IF_TYPE_STA,
IEEE80211_IF_TYPE_IBSS,
IEEE80211_IF_TYPE_MNTR,
Index: mac80211/net/mac80211/ieee80211.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211.c 2007-11-11 15:15:51.536531354 +0100
+++ mac80211/net/mac80211/ieee80211.c 2007-11-11 15:16:22.214279577 +0100
@@ -23,6 +23,7 @@
#include <linux/bitmap.h>
#include <net/cfg80211.h>
+#include "ieee80211_common.h"
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
#include "wep.h"
@@ -121,6 +122,152 @@
ieee80211_configure_filter(local);
}
+/* management interface */
+
+static void
+ieee80211_fill_frame_info(struct ieee80211_local *local,
+ struct ieee80211_frame_info *fi,
+ struct ieee80211_rx_status *status)
+{
+ if (status) {
+ struct timespec ts;
+ struct ieee80211_rate *rate;
+
+ jiffies_to_timespec(jiffies, &ts);
+ fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 +
+ ts.tv_nsec / 1000);
+ fi->mactime = cpu_to_be64(status->mactime);
+ switch (status->phymode) {
+ case MODE_IEEE80211A:
+ fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a);
+ break;
+ case MODE_IEEE80211B:
+ fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b);
+ break;
+ case MODE_IEEE80211G:
+ fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g);
+ break;
+ default:
+ fi->phytype = htonl(0xAAAAAAAA);
+ break;
+ }
+ fi->channel = htonl(status->channel);
+ rate = ieee80211_get_rate(local, status->phymode,
+ status->rate);
+ if (rate) {
+ fi->datarate = htonl(rate->rate);
+ if (rate->flags & IEEE80211_RATE_PREAMBLE2) {
+ if (status->rate == rate->val)
+ fi->preamble = htonl(2); /* long */
+ else if (status->rate == rate->val2)
+ fi->preamble = htonl(1); /* short */
+ } else
+ fi->preamble = htonl(0);
+ } else {
+ fi->datarate = htonl(0);
+ fi->preamble = htonl(0);
+ }
+
+ fi->antenna = htonl(status->antenna);
+ fi->priority = htonl(0xffffffff); /* no clue */
+ fi->ssi_type = htonl(ieee80211_ssi_raw);
+ fi->ssi_signal = htonl(status->ssi);
+ fi->ssi_noise = 0x00000000;
+ fi->encoding = 0;
+ } else {
+ /* clear everything because we really don't know.
+ * the msg_type field isn't present on monitor frames
+ * so we don't know whether it will be present or not,
+ * but it's ok to not clear it since it'll be assigned
+ * anyway */
+ memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type));
+
+ fi->ssi_type = htonl(ieee80211_ssi_none);
+ }
+ fi->version = htonl(IEEE80211_FI_VERSION);
+ fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type));
+}
+
+/* this routine is actually not just for this, but also
+ * for pushing fake 'management' frames into userspace.
+ * it shall be replaced by a netlink-based system. */
+void
+ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_rx_status *status, u32 msg_type)
+{
+ struct ieee80211_frame_info *fi;
+ const size_t hlen = sizeof(struct ieee80211_frame_info);
+ struct net_device *dev = local->apdev;
+
+ skb->dev = dev;
+
+ if (skb_headroom(skb) < hlen) {
+ I802_DEBUG_INC(local->rx_expand_skb_head);
+ if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
+
+ fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
+
+ ieee80211_fill_frame_info(local, fi, status);
+ fi->msg_type = htonl(msg_type);
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+
+ skb_set_mac_header(skb, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+static int ieee80211_mgmt_open(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (!netif_running(local->mdev))
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static int ieee80211_mgmt_stop(struct net_device *dev)
+{
+ return 0;
+}
+
+static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu)
+{
+ /* FIX: what would be proper limits for MTU?
+ * This interface uses 802.11 frames. */
+ if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) {
+ printk(KERN_WARNING "%s: invalid MTU %d\n",
+ dev->name, new_mtu);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+void ieee80211_if_mgmt_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
+ dev->change_mtu = ieee80211_change_mtu_apdev;
+ dev->open = ieee80211_mgmt_open;
+ dev->stop = ieee80211_mgmt_stop;
+ dev->type = ARPHRD_IEEE80211_PRISM;
+ dev->hard_header_parse = &header_parse_80211;
+ dev->destructor = ieee80211_if_free;
+}
+
/* regular interfaces */
static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
@@ -198,6 +345,7 @@
return -ENOLINK;
break;
case IEEE80211_IF_TYPE_AP:
+ case IEEE80211_IF_TYPE_MGMT:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_IBSS:
@@ -262,6 +410,10 @@
if (local->open_count == 0) {
res = dev_open(local->mdev);
WARN_ON(res);
+ if (local->apdev) {
+ res = dev_open(local->apdev);
+ WARN_ON(res);
+ }
tasklet_enable(&local->tx_pending_tasklet);
tasklet_enable(&local->tasklet);
}
@@ -347,6 +499,9 @@
if (netif_running(local->mdev))
dev_close(local->mdev);
+ if (local->apdev)
+ dev_close(local->apdev);
+
if (local->ops->stop)
local->ops->stop(local_to_hw(local));
@@ -646,6 +801,8 @@
pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
if (control->flags & IEEE80211_TXCTL_REQUEUE)
pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+ if (control->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
pkt_data->queue = control->queue;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -698,6 +855,7 @@
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_local *local = hw_to_local(hw);
u16 frag, type;
+ u32 msg_type;
struct ieee80211_tx_status_rtap_hdr *rthdr;
struct ieee80211_sub_if_data *sdata;
int monitors;
@@ -812,9 +970,29 @@
local->dot11FailedCount++;
}
+ msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
+ ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
+
/* this was a transmitted frame, but now we want to reuse it */
skb_orphan(skb);
+ if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) &&
+ local->apdev) {
+ if (local->monitors) {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ } else {
+ skb2 = skb;
+ skb = NULL;
+ }
+
+ if (skb2)
+ /* Send frame to hostapd */
+ ieee80211_rx_mgmt(local, skb2, NULL, msg_type);
+
+ if (!skb)
+ return;
+ }
+
if (!local->monitors) {
dev_kfree_skb(skb);
return;
@@ -1161,6 +1339,8 @@
BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
local->reg_state = IEEE80211_DEV_UNREGISTERED;
+ if (local->apdev)
+ ieee80211_if_del_mgmt(local);
/*
* At this point, interface list manipulations are fine
Index: mac80211/net/mac80211/ieee80211_i.h
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:15:42.840035769 +0100
+++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:15:53.792659922 +0100
@@ -142,6 +142,7 @@
* when using CTS protection with IEEE 802.11g. */
struct ieee80211_rate *last_frag_rate;
int last_frag_hwrate;
+ int mgmt_interface;
/* Extra fragments (in addition to the first fragment
* in skb) */
@@ -163,6 +164,7 @@
#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0)
#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
#define IEEE80211_TXPD_REQUEUE BIT(2)
+#define IEEE80211_TXPD_MGMT_IFACE BIT(3)
/* Stored in sk_buff->cb */
struct ieee80211_tx_packet_data {
int ifindex;
@@ -408,6 +410,7 @@
struct list_head modes_list;
struct net_device *mdev; /* wmaster# - "master" 802.11 device */
+ struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
int open_count;
int monitors;
unsigned int filter_flags; /* FIF_* */
@@ -701,11 +704,14 @@
int ieee80211_hw_config(struct ieee80211_local *local);
int ieee80211_if_config(struct net_device *dev);
int ieee80211_if_config_beacon(struct net_device *dev);
+void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_rx_status *status, u32 msg_type);
void ieee80211_prepare_rates(struct ieee80211_local *local,
struct ieee80211_hw_mode *mode);
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
void ieee80211_if_setup(struct net_device *dev);
+void ieee80211_if_mgmt_setup(struct net_device *dev);
struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
int phymode, int hwrate);
@@ -772,6 +778,8 @@
int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
void ieee80211_if_free(struct net_device *dev);
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
+int ieee80211_if_add_mgmt(struct ieee80211_local *local);
+void ieee80211_if_del_mgmt(struct ieee80211_local *local);
/* regdomain.c */
void ieee80211_regdomain_init(void);
@@ -788,6 +796,7 @@
int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
+int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
/* utility functions/constants */
extern void *mac80211_wiphy_privid; /* for wiphy privid */
Index: mac80211/net/mac80211/ieee80211_iface.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:42.848036222 +0100
+++ mac80211/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:53.796660158 +0100
@@ -96,6 +96,66 @@
return ret;
}
+int ieee80211_if_add_mgmt(struct ieee80211_local *local)
+{
+ struct net_device *ndev;
+ struct ieee80211_sub_if_data *nsdata;
+ int ret;
+
+ ASSERT_RTNL();
+
+ ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d",
+ ieee80211_if_mgmt_setup);
+ if (!ndev)
+ return -ENOMEM;
+ ret = dev_alloc_name(ndev, ndev->name);
+ if (ret < 0)
+ goto fail;
+
+ memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+ SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
+
+ nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ ndev->ieee80211_ptr = &nsdata->wdev;
+ nsdata->wdev.wiphy = local->hw.wiphy;
+ nsdata->type = IEEE80211_IF_TYPE_MGMT;
+ nsdata->dev = ndev;
+ nsdata->local = local;
+ ieee80211_if_sdata_init(nsdata);
+
+ ret = register_netdevice(ndev);
+ if (ret)
+ goto fail;
+
+ /*
+ * Called even when register_netdevice fails, it would
+ * oops if assigned before initialising the rest.
+ */
+ ndev->uninit = ieee80211_if_reinit;
+
+ ieee80211_debugfs_add_netdev(nsdata);
+
+ if (local->open_count > 0)
+ dev_open(ndev);
+ local->apdev = ndev;
+ return 0;
+
+fail:
+ free_netdev(ndev);
+ return ret;
+}
+
+void ieee80211_if_del_mgmt(struct ieee80211_local *local)
+{
+ struct net_device *apdev;
+
+ ASSERT_RTNL();
+ apdev = local->apdev;
+ ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev));
+ local->apdev = NULL;
+ unregister_netdevice(apdev);
+}
+
void ieee80211_if_set_type(struct net_device *dev, int type)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -183,6 +243,9 @@
ieee80211_if_sdata_deinit(sdata);
switch (sdata->type) {
+ case IEEE80211_IF_TYPE_MGMT:
+ /* nothing to do */
+ break;
case IEEE80211_IF_TYPE_INVALID:
/* cannot happen */
WARN_ON(1);
@@ -294,8 +357,11 @@
void ieee80211_if_free(struct net_device *dev)
{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ /* local->apdev must be NULL when freeing management interface */
+ BUG_ON(dev == local->apdev);
ieee80211_if_sdata_deinit(sdata);
free_netdev(dev);
}
Index: mac80211/net/mac80211/ieee80211_rate.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_rate.c 2007-11-11 15:15:42.852036451 +0100
+++ mac80211/net/mac80211/ieee80211_rate.c 2007-11-11 15:15:53.800660386 +0100
@@ -145,7 +145,8 @@
struct rate_control_ref *ref, *old;
ASSERT_RTNL();
- if (local->open_count || netif_running(local->mdev))
+ if (local->open_count || netif_running(local->mdev) ||
+ (local->apdev && netif_running(local->apdev)))
return -EBUSY;
ref = rate_control_alloc(name, local);
Index: mac80211/net/mac80211/ieee80211_rate.h
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_rate.h 2007-11-11 15:15:42.860036908 +0100
+++ mac80211/net/mac80211/ieee80211_rate.h 2007-11-11 15:15:53.800660386 +0100
@@ -30,6 +30,8 @@
/* parameters from the caller to rate_control_get_rate(): */
struct ieee80211_hw_mode *mode;
+ int mgmt_data; /* this is data frame that is used for management
+ * (e.g., IEEE 802.1X EAPOL) */
u16 ethertype;
};
Index: mac80211/net/mac80211/ieee80211_sta.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:42.868037362 +0100
+++ mac80211/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:53.800660386 +0100
@@ -475,6 +475,8 @@
pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
pkt_data->ifindex = sdata->dev->ifindex;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
if (!encrypt)
pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
Index: mac80211/net/mac80211/rx.c
===================================================================
--- mac80211.orig/net/mac80211/rx.c 2007-11-11 15:15:42.872037591 +0100
+++ mac80211/net/mac80211/rx.c 2007-11-11 15:15:53.804660611 +0100
@@ -19,6 +19,7 @@
#include "ieee80211_i.h"
#include "ieee80211_led.h"
+#include "ieee80211_common.h"
#include "wep.h"
#include "wpa.h"
#include "tkip.h"
@@ -411,7 +412,12 @@
return TXRX_DROP;
}
- return TXRX_DROP;
+ if (!rx->local->apdev)
+ return TXRX_DROP;
+
+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_sta_not_assoc);
+ return TXRX_QUEUED;
}
return TXRX_CONTINUE;
@@ -953,8 +959,15 @@
{
if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
rx->sdata->type != IEEE80211_IF_TYPE_STA &&
- (rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
- return TXRX_CONTINUE;
+ (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+ /* Pass both encrypted and unencrypted EAPOL frames to user
+ * space for processing. */
+ if (!rx->local->apdev)
+ return TXRX_DROP;
+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_normal);
+ return TXRX_QUEUED;
+ }
if (unlikely(rx->sdata->ieee802_1x &&
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
@@ -1196,8 +1209,13 @@
sdata->type == IEEE80211_IF_TYPE_IBSS) &&
!(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
- else
- return TXRX_DROP;
+ else {
+ /* Management frames are sent to hostapd for processing */
+ if (!rx->local->apdev)
+ return TXRX_DROP;
+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_normal);
+ }
return TXRX_QUEUED;
}
@@ -1407,6 +1425,7 @@
/* take everything */
break;
case IEEE80211_IF_TYPE_INVALID:
+ case IEEE80211_IF_TYPE_MGMT:
/* should never get here */
WARN_ON(1);
break;
Index: mac80211/net/mac80211/tx.c
===================================================================
--- mac80211.orig/net/mac80211/tx.c 2007-11-11 15:15:42.880038048 +0100
+++ mac80211/net/mac80211/tx.c 2007-11-11 15:15:53.804660611 +0100
@@ -258,7 +258,7 @@
return TXRX_CONTINUE;
}
- if (unlikely(/* !injected && */ tx->sdata->ieee802_1x &&
+ if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x &&
!(sta_flags & WLAN_STA_AUTHORIZED))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT
@@ -568,6 +568,8 @@
memset(&extra, 0, sizeof(extra));
extra.mode = tx->u.tx.mode;
extra.ethertype = tx->ethertype;
+ extra.mgmt_data = tx->sdata &&
+ tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev,
tx->skb, &extra);
@@ -1076,7 +1078,7 @@
}
static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct ieee80211_tx_control *control, int mgmt)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
@@ -1107,6 +1109,7 @@
rcu_read_lock();
sta = tx.sta;
+ tx.u.tx.mgmt_interface = mgmt;
tx.u.tx.mode = local->hw.conf.mode;
for (handler = local->tx_handlers; *handler != NULL;
@@ -1253,7 +1256,8 @@
control.flags |= IEEE80211_TXCTL_REQUEUE;
control.queue = pkt_data->queue;
- ret = ieee80211_tx(odev, skb, &control);
+ ret = ieee80211_tx(odev, skb, &control,
+ control.type == IEEE80211_IF_TYPE_MGMT);
dev_put(odev);
return ret;
@@ -1498,6 +1502,8 @@
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
pkt_data->ifindex = dev->ifindex;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
skb->dev = local->mdev;
dev->stats.tx_packets++;
@@ -1555,6 +1561,8 @@
pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
pkt_data->ifindex = sdata->dev->ifindex;
+ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
+ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
skb->dev = sdata->local->mdev;
Index: mac80211/net/mac80211/wme.c
===================================================================
--- mac80211.orig/net/mac80211/wme.c 2007-11-11 15:15:42.888038502 +0100
+++ mac80211/net/mac80211/wme.c 2007-11-11 15:15:53.804660611 +0100
@@ -94,6 +94,8 @@
static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
{
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_tx_packet_data *pkt_data =
+ (struct ieee80211_tx_packet_data *) skb->cb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
unsigned short fc = le16_to_cpu(hdr->frame_control);
int qos;
@@ -106,8 +108,12 @@
return IEEE80211_TX_QUEUE_DATA0;
}
- if (0 /* injected */) {
- /* use AC from radiotap */
+ if (unlikely(pkt_data->flags & IEEE80211_TXPD_MGMT_IFACE)) {
+ /* Data frames from hostapd (mainly, EAPOL) use AC_VO
+ * and they will include QoS control fields if
+ * the target STA is using WME. */
+ skb->priority = 7;
+ return ieee802_1d_to_ac[skb->priority];
}
/* is this a QoS frame? */
Index: mac80211/net/mac80211/ieee80211_ioctl.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:15:51.532531127 +0100
+++ mac80211/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:15:53.808660833 +0100
@@ -840,16 +840,29 @@
void *wrqu, char *extra)
{
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_local *local;
int *i = (int *) extra;
int param = *i;
+ int value = *(i + 1);
int ret = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ local = sdata->local;
switch (param) {
+ case PRISM2_PARAM_MGMT_IF:
+ if (value == 1) {
+ if (!local->apdev)
+ ret = ieee80211_if_add_mgmt(local);
+ } else if (value == 0) {
+ if (local->apdev)
+ ieee80211_if_del_mgmt(local);
+ } else
+ ret = -EINVAL;
+ break;
default:
ret = -EOPNOTSUPP;
break;
@@ -864,12 +877,20 @@
void *wrqu, char *extra)
{
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_local *local;
int *param = (int *) extra;
int ret = 0;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ local = sdata->local;
switch (*param) {
+ case PRISM2_PARAM_MGMT_IF:
+ if (local->apdev)
+ *param = local->apdev->ifindex;
+ else
+ ret = -ENOENT;
+ break;
default:
ret = -EOPNOTSUPP;
break;

View file

@ -0,0 +1,37 @@
Subject: mac80211: allow AP and VLAN modes
This adds AP/VLAN modes to the list of modes that a mac80211
interface can be created in/switched into.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/cfg.c | 4 ++++
net/mac80211/ieee80211_ioctl.c | 3 +++
2 files changed, 7 insertions(+)
--- everything.orig/net/mac80211/cfg.c 2007-10-30 15:33:43.227379286 +0100
+++ everything/net/mac80211/cfg.c 2007-11-07 13:19:27.981515569 +0100
@@ -25,6 +25,10 @@ nl80211_type_to_mac80211_type(enum nl802
return IEEE80211_IF_TYPE_STA;
case NL80211_IFTYPE_MONITOR:
return IEEE80211_IF_TYPE_MNTR;
+ case NL80211_IFTYPE_AP:
+ return IEEE80211_IF_TYPE_AP;
+ case NL80211_IFTYPE_AP_VLAN:
+ return IEEE80211_IF_TYPE_VLAN;
default:
return IEEE80211_IF_TYPE_INVALID;
}
--- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:25.851524684 +0100
+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:27.981515569 +0100
@@ -284,6 +284,9 @@ static int ieee80211_ioctl_siwmode(struc
case IW_MODE_MONITOR:
type = IEEE80211_IF_TYPE_MNTR;
break;
+ case IW_MODE_MASTER:
+ type = IEEE80211_IF_TYPE_AP;
+ break;
default:
return -EINVAL;
}

View file

@ -0,0 +1,22 @@
Subject: mac80211: allow WDS mode
This allows creating interfaces in WDS mode or switching
existing ones into WDS mode (both via cfg80211.)
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/cfg.c | 2 ++
1 file changed, 2 insertions(+)
--- everything.orig/net/mac80211/cfg.c 2007-11-07 13:19:27.981515569 +0100
+++ everything/net/mac80211/cfg.c 2007-11-07 13:19:29.441515732 +0100
@@ -29,6 +29,8 @@ nl80211_type_to_mac80211_type(enum nl802
return IEEE80211_IF_TYPE_AP;
case NL80211_IFTYPE_AP_VLAN:
return IEEE80211_IF_TYPE_VLAN;
+ case NL80211_IFTYPE_WDS:
+ return IEEE80211_IF_TYPE_WDS;
default:
return IEEE80211_IF_TYPE_INVALID;
}

View file

@ -0,0 +1,26 @@
---
net/mac80211/ieee80211_ioctl.c | 6 ++++++
1 file changed, 6 insertions(+)
--- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:27.981515569 +0100
+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:30.781513182 +0100
@@ -882,6 +882,9 @@ static int ieee80211_ioctl_prism2_param(
local = sdata->local;
switch (param) {
+ case PRISM2_PARAM_AP_BRIDGE_PACKETS:
+ local->bridge_packets = value;
+ break;
case PRISM2_PARAM_MGMT_IF:
if (value == 1) {
if (!local->apdev)
@@ -914,6 +917,9 @@ static int ieee80211_ioctl_get_prism2_pa
local = sdata->local;
switch (*param) {
+ case PRISM2_PARAM_AP_BRIDGE_PACKETS:
+ *param = local->bridge_packets;
+ break;
case PRISM2_PARAM_MGMT_IF:
if (local->apdev)
*param = local->apdev->ifindex;

View file

@ -0,0 +1,26 @@
---
net/mac80211/ieee80211_ioctl.c | 6 ++++++
1 file changed, 6 insertions(+)
--- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:30.781513182 +0100
+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:32.281514919 +0100
@@ -882,6 +882,9 @@ static int ieee80211_ioctl_prism2_param(
local = sdata->local;
switch (param) {
+ case PRISM2_PARAM_IEEE_802_1X:
+ sdata->ieee802_1x = value;
+ break;
case PRISM2_PARAM_AP_BRIDGE_PACKETS:
local->bridge_packets = value;
break;
@@ -917,6 +920,9 @@ static int ieee80211_ioctl_get_prism2_pa
local = sdata->local;
switch (*param) {
+ case PRISM2_PARAM_IEEE_802_1X:
+ *param = sdata->ieee802_1x;
+ break;
case PRISM2_PARAM_AP_BRIDGE_PACKETS:
*param = local->bridge_packets;
break;

View file

@ -0,0 +1,122 @@
---
net/mac80211/ieee80211_ioctl.c | 102 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
--- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:32.281514919 +0100
+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:33.681513453 +0100
@@ -125,6 +125,105 @@ static int ieee80211_ioctl_siwgenie(stru
return -EOPNOTSUPP;
}
+/*
+ * Wow. This ioctl interface is such crap, it's tied
+ * to internal definitions. I hope it dies soon.
+ */
+static int mode_to_hostapd_mode(enum ieee80211_phymode mode)
+{
+ switch (mode) {
+ case MODE_IEEE80211A:
+ return 0;
+ case MODE_IEEE80211B:
+ return 1;
+ case MODE_IEEE80211G:
+ return 3;
+ case NUM_IEEE80211_MODES:
+ WARN_ON(1);
+ break;
+ }
+ WARN_ON(1);
+ return -1;
+}
+
+static int channel_flags_to_hostapd_flags(int flags)
+{
+ int res = 0;
+
+ if (flags & IEEE80211_CHAN_W_SCAN)
+ res |= 1;
+ if (flags & IEEE80211_CHAN_W_ACTIVE_SCAN)
+ res |= 2;
+ if (flags & IEEE80211_CHAN_W_IBSS)
+ res |= 4;
+
+ return res;
+}
+
+struct ieee80211_channel_data {
+ short chan; /* channel number (IEEE 802.11) */
+ short freq; /* frequency in MHz */
+ int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
+};
+
+struct ieee80211_rate_data {
+ int rate; /* rate in 100 kbps */
+ int flags; /* IEEE80211_RATE_ flags */
+};
+
+static int ieee80211_ioctl_get_hw_features(struct net_device *dev,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ u8 *pos = param->u.hw_features.data;
+ int left = param_len - (pos - (u8 *) param);
+ int i;
+ struct hostapd_ioctl_hw_modes_hdr *hdr;
+ struct ieee80211_rate_data *rate;
+ struct ieee80211_channel_data *chan;
+ struct ieee80211_hw_mode *mode;
+
+ param->u.hw_features.flags = 0;
+
+ param->u.hw_features.num_modes = 0;
+ list_for_each_entry(mode, &local->modes_list, list) {
+ int clen, rlen;
+
+ param->u.hw_features.num_modes++;
+ clen =
+ mode->num_channels * sizeof(struct ieee80211_channel_data);
+ rlen = mode->num_rates * sizeof(struct ieee80211_rate_data);
+ if (left < sizeof(*hdr) + clen + rlen)
+ return -E2BIG;
+ left -= sizeof(*hdr) + clen + rlen;
+
+ hdr = (struct hostapd_ioctl_hw_modes_hdr *)pos;
+ hdr->mode = mode_to_hostapd_mode(mode->mode);
+ hdr->num_channels = mode->num_channels;
+ hdr->num_rates = mode->num_rates;
+
+ pos = (u8 *) (hdr + 1);
+ chan = (struct ieee80211_channel_data *)pos;
+ for (i = 0; i < mode->num_channels; i++) {
+ chan[i].chan = mode->channels[i].chan;
+ chan[i].freq = mode->channels[i].freq;
+ chan[i].flag = channel_flags_to_hostapd_flags(
+ mode->channels[i].flag);
+ }
+ pos += clen;
+
+ rate = (struct ieee80211_rate_data *)pos;
+ for (i = 0; i < mode->num_rates; i++) {
+ rate[i].rate = mode->rates[i].rate;
+ rate[i].flags = mode->rates[i].flags;
+ }
+ pos += rlen;
+ }
+
+ return 0;
+}
+
static int ieee80211_ioctl_priv_hostapd(struct net_device *dev,
struct iw_point *p)
@@ -151,6 +250,9 @@ static int ieee80211_ioctl_priv_hostapd(
}
switch (param->cmd) {
+ case PRISM2_HOSTAPD_GET_HW_FEATURES:
+ ret = ieee80211_ioctl_get_hw_features(dev, param, p->length);
+ break;
default:
ret = -EOPNOTSUPP;
break;

View file

@ -0,0 +1,26 @@
---
net/mac80211/ieee80211_ioctl.c | 6 ++++++
1 file changed, 6 insertions(+)
--- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:33.681513453 +0100
+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:35.171517576 +0100
@@ -984,6 +984,9 @@ static int ieee80211_ioctl_prism2_param(
local = sdata->local;
switch (param) {
+ case PRISM2_PARAM_EAPOL:
+ sdata->eapol = value;
+ break;
case PRISM2_PARAM_IEEE_802_1X:
sdata->ieee802_1x = value;
break;
@@ -1022,6 +1025,9 @@ static int ieee80211_ioctl_get_prism2_pa
local = sdata->local;
switch (*param) {
+ case PRISM2_PARAM_EAPOL:
+ *param = sdata->eapol;
+ break;
case PRISM2_PARAM_IEEE_802_1X:
*param = sdata->ieee802_1x;
break;

View file

@ -0,0 +1,470 @@
Subject: cfg80211/nl80211: introduce key handling
This introduces key handling to cfg80211/nl80211. Default
and group keys can be added, changed and removed; sequence
counters for each key can be retrieved.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/nl80211.h | 34 +++++
include/net/cfg80211.h | 44 +++++++
net/wireless/core.c | 3
net/wireless/nl80211.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 370 insertions(+)
--- everything.orig/include/linux/nl80211.h 2007-10-30 15:33:43.587381346 +0100
+++ everything/include/linux/nl80211.h 2007-11-07 13:19:37.861516599 +0100
@@ -37,6 +37,16 @@
* userspace to request deletion of a virtual interface, then requires
* attribute %NL80211_ATTR_IFINDEX.
*
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
+ * %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
+ * attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ * or %NL80211_ATTR_MAC.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -54,6 +64,11 @@ enum nl80211_commands {
NL80211_CMD_NEW_INTERFACE,
NL80211_CMD_DEL_INTERFACE,
+ NL80211_CMD_GET_KEY,
+ NL80211_CMD_SET_KEY,
+ NL80211_CMD_NEW_KEY,
+ NL80211_CMD_DEL_KEY,
+
/* add commands here */
/* used to define NL80211_CMD_MAX below */
@@ -75,6 +90,17 @@ enum nl80211_commands {
* @NL80211_ATTR_IFNAME: network interface name
* @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
*
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -89,6 +115,14 @@ enum nl80211_attrs {
NL80211_ATTR_IFNAME,
NL80211_ATTR_IFTYPE,
+ NL80211_ATTR_MAC,
+
+ NL80211_ATTR_KEY_DATA,
+ NL80211_ATTR_KEY_IDX,
+ NL80211_ATTR_KEY_CIPHER,
+ NL80211_ATTR_KEY_SEQ,
+ NL80211_ATTR_KEY_DEFAULT,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
--- everything.orig/net/wireless/nl80211.c 2007-10-30 15:33:43.637380153 +0100
+++ everything/net/wireless/nl80211.c 2007-11-07 13:19:38.201511066 +0100
@@ -61,6 +61,14 @@ static struct nla_policy nl80211_policy[
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
+
+ [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
+
+ [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
+ .len = WLAN_MAX_KEY_LEN },
+ [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
+ [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
+ [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
};
/* message building helper */
@@ -335,6 +343,263 @@ static int nl80211_del_interface(struct
return err;
}
+struct get_key_cookie {
+ struct sk_buff *msg;
+ int error;
+};
+
+static void get_key_callback(void *c, struct key_params *params)
+{
+ struct get_key_cookie *cookie = c;
+
+ if (params->key)
+ NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
+ params->key_len, params->key);
+
+ if (params->seq)
+ NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
+ params->seq_len, params->seq);
+
+ if (params->cipher)
+ NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
+ params->cipher);
+
+ return;
+ nla_put_failure:
+ cookie->error = 1;
+}
+
+static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 key_idx = 0;
+ u8 *mac_addr = NULL;
+ struct get_key_cookie cookie = {
+ .error = 0,
+ };
+ void *hdr;
+ struct sk_buff *msg;
+
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ if (key_idx > 3)
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->get_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_NEW_KEY);
+
+ if (IS_ERR(hdr)) {
+ err = PTR_ERR(hdr);
+ goto out;
+ }
+
+ cookie.msg = msg;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ if (mac_addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+
+ rtnl_lock();
+ err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
+ &cookie, get_key_callback);
+ rtnl_unlock();
+
+ if (err)
+ goto out;
+
+ if (cookie.error)
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto out;
+
+ nla_put_failure:
+ err = -ENOBUFS;
+ nlmsg_free(msg);
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 key_idx;
+
+ if (!info->attrs[NL80211_ATTR_KEY_IDX])
+ return -EINVAL;
+
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ if (key_idx > 3)
+ return -EINVAL;
+
+ /* currently only support setting default key */
+ if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
+ return -EINVAL;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->set_default_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct key_params params;
+ u8 key_idx = 0;
+ u8 *mac_addr = NULL;
+
+ memset(&params, 0, sizeof(params));
+
+ if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_KEY_DATA]) {
+ params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
+ params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
+ }
+
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (key_idx > 3)
+ return -EINVAL;
+
+ /*
+ * Disallow pairwise keys with non-zero index unless it's WEP
+ * (because current deployments use pairwise WEP keys with
+ * non-zero indizes but 802.11i clearly specifies to use zero)
+ */
+ if (mac_addr && key_idx &&
+ params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ params.cipher != WLAN_CIPHER_SUITE_WEP104)
+ return -EINVAL;
+
+ /* TODO: add definitions for the lengths to linux/ieee80211.h */
+ switch (params.cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ if (params.key_len != 5)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (params.key_len != 32)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (params.key_len != 16)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ if (params.key_len != 13)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->add_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 key_idx = 0;
+ u8 *mac_addr = NULL;
+
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ if (key_idx > 3)
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->del_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -374,6 +639,30 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_GET_KEY,
+ .doit = nl80211_get_key,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_SET_KEY,
+ .doit = nl80211_set_key,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_NEW_KEY,
+ .doit = nl80211_new_key,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_KEY,
+ .doit = nl80211_del_key,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */
--- everything.orig/net/wireless/core.c 2007-10-30 15:33:43.677380478 +0100
+++ everything/net/wireless/core.c 2007-11-07 13:19:38.221513833 +0100
@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_
struct cfg80211_registered_device *drv;
int alloc_size;
+ WARN_ON(!ops->add_key && ops->del_key);
+ WARN_ON(ops->add_key && !ops->del_key);
+
alloc_size = sizeof(*drv) + sizeof_priv;
drv = kzalloc(alloc_size, GFP_KERNEL);
--- everything.orig/include/net/cfg80211.h 2007-10-30 15:33:43.617381780 +0100
+++ everything/include/net/cfg80211.h 2007-11-07 13:19:38.231512748 +0100
@@ -49,6 +49,26 @@ extern int ieee80211_radiotap_iterator_n
struct ieee80211_radiotap_iterator *iterator);
+ /**
+ * struct key_params - key information
+ *
+ * Information about a key
+ *
+ * @key: key material
+ * @key_len: length of key material
+ * @cipher: cipher suite selector
+ * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
+ * with the get_key() callback, must be in little endian,
+ * length given by @seq_len.
+ */
+struct key_params {
+ u8 *key;
+ u8 *seq;
+ int key_len;
+ int seq_len;
+ u32 cipher;
+};
+
/* from net/wireless.h */
struct wiphy;
@@ -71,6 +91,18 @@ struct wiphy;
*
* @change_virtual_intf: change type of virtual interface
*
+ * @add_key: add a key with the given parameters. @mac_addr will be %NULL
+ * when adding a group key.
+ *
+ * @get_key: get information about the key with the given parameters.
+ * @mac_addr will be %NULL when requesting information for a group
+ * key. All pointers given to the @callback function need not be valid
+ * after it returns.
+ *
+ * @del_key: remove a key given the @mac_addr (%NULL for a group key)
+ * and @key_index
+ *
+ * @set_default_key: set the default key on an interface
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -78,6 +110,18 @@ struct cfg80211_ops {
int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
enum nl80211_iftype type);
+
+ int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, u8 *mac_addr,
+ struct key_params *params);
+ int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params*));
+ int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, u8 *mac_addr);
+ int (*set_default_key)(struct wiphy *wiphy,
+ struct net_device *netdev,
+ u8 key_index);
};
#endif /* __NET_CFG80211_H */

View file

@ -0,0 +1,120 @@
Subject: mac80211: support adding/removing keys via cfg80211
This adds the necessary hooks to mac80211 to allow userspace
to edit keys with cfg80211 (through nl80211.)
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/cfg.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
--- everything.orig/net/mac80211/cfg.c 2007-11-07 13:19:29.441515732 +0100
+++ everything/net/mac80211/cfg.c 2007-11-07 13:19:39.531517685 +0100
@@ -6,6 +6,7 @@
* This file is GPLv2 as found in COPYING.
*/
+#include <linux/ieee80211.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <net/net_namespace.h>
@@ -105,8 +106,98 @@ static int ieee80211_change_iface(struct
return 0;
}
+static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, u8 *mac_addr,
+ struct key_params *params)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta = NULL;
+ enum ieee80211_key_alg alg;
+ int ret;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ alg = ALG_WEP;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ alg = ALG_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ alg = ALG_CCMP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mac_addr) {
+ sta = sta_info_get(sdata->local, mac_addr);
+ if (!sta)
+ return -ENOENT;
+ }
+
+ ret = 0;
+ if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
+ params->key_len, params->key))
+ ret = -ENOMEM;
+
+ if (sta)
+ sta_info_put(sta);
+
+ return ret;
+}
+
+static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, u8 *mac_addr)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+ int ret;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (mac_addr) {
+ sta = sta_info_get(sdata->local, mac_addr);
+ if (!sta)
+ return -ENOENT;
+
+ ret = 0;
+ if (sta->key)
+ ieee80211_key_free(sta->key);
+ else
+ ret = -ENOENT;
+
+ sta_info_put(sta);
+ return ret;
+ }
+
+ if (!sdata->keys[key_idx])
+ return -ENOENT;
+
+ ieee80211_key_free(sdata->keys[key_idx]);
+
+ return 0;
+}
+
+static int ieee80211_config_default_key(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 key_idx)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ieee80211_set_default_key(sdata, key_idx);
+
+ return 0;
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
.change_virtual_intf = ieee80211_change_iface,
+ .add_key = ieee80211_add_key,
+ .del_key = ieee80211_del_key,
+ .set_default_key = ieee80211_config_default_key,
};

View file

@ -0,0 +1,161 @@
Subject: mac80211: support getting key sequence counters via cfg80211
This implements cfg80211's get_key() to allow retrieving the sequence
counter for a TKIP or CCMP key from userspace. It also cleans up and
documents the associated low-level driver interface.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/net/mac80211.h | 14 ++------
net/mac80211/cfg.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 89 insertions(+), 10 deletions(-)
Index: mac80211/net/mac80211/cfg.c
===================================================================
--- mac80211.orig/net/mac80211/cfg.c 2007-11-11 15:46:41.497954646 +0100
+++ mac80211/net/mac80211/cfg.c 2007-11-11 15:46:51.346515884 +0100
@@ -1,7 +1,7 @@
/*
* mac80211 configuration hooks for cfg80211
*
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*
* This file is GPLv2 as found in COPYING.
*/
@@ -180,6 +180,88 @@
return 0;
}
+static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie,
+ struct key_params *params))
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sta_info *sta = NULL;
+ u8 seq[6] = {0};
+ struct key_params params;
+ struct ieee80211_key *key;
+ u32 iv32;
+ u16 iv16;
+ int err = -ENOENT;
+
+ if (mac_addr) {
+ sta = sta_info_get(sdata->local, mac_addr);
+ if (!sta)
+ goto out;
+
+ key = sta->key;
+ } else
+ key = sdata->keys[key_idx];
+
+ if (!key)
+ goto out;
+
+ memset(&params, 0, sizeof(params));
+
+ switch (key->conf.alg) {
+ case ALG_TKIP:
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
+
+ iv32 = key->u.tkip.iv32;
+ iv16 = key->u.tkip.iv16;
+
+ if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+ sdata->local->ops->get_tkip_seq)
+ sdata->local->ops->get_tkip_seq(
+ local_to_hw(sdata->local),
+ key->conf.hw_key_idx,
+ &iv32, &iv16);
+
+ seq[0] = iv16 & 0xff;
+ seq[1] = (iv16 >> 8) & 0xff;
+ seq[2] = iv32 & 0xff;
+ seq[3] = (iv32 >> 8) & 0xff;
+ seq[4] = (iv32 >> 16) & 0xff;
+ seq[5] = (iv32 >> 24) & 0xff;
+ params.seq = seq;
+ params.seq_len = 6;
+ break;
+ case ALG_CCMP:
+ params.cipher = WLAN_CIPHER_SUITE_CCMP;
+ seq[0] = key->u.ccmp.tx_pn[5];
+ seq[1] = key->u.ccmp.tx_pn[4];
+ seq[2] = key->u.ccmp.tx_pn[3];
+ seq[3] = key->u.ccmp.tx_pn[2];
+ seq[4] = key->u.ccmp.tx_pn[1];
+ seq[5] = key->u.ccmp.tx_pn[0];
+ params.seq = seq;
+ params.seq_len = 6;
+ break;
+ case ALG_WEP:
+ if (key->conf.keylen == 5)
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ else
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ break;
+ }
+
+ params.key = key->conf.key;
+ params.key_len = key->conf.keylen;
+
+ callback(cookie, &params);
+ err = 0;
+
+ out:
+ if (sta)
+ sta_info_put(sta);
+ return err;
+}
+
static int ieee80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev,
u8 key_idx)
@@ -198,5 +280,6 @@
.change_virtual_intf = ieee80211_change_iface,
.add_key = ieee80211_add_key,
.del_key = ieee80211_del_key,
+ .get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key,
};
Index: mac80211/include/net/mac80211.h
===================================================================
--- mac80211.orig/include/net/mac80211.h 2007-11-11 15:46:41.377947807 +0100
+++ mac80211/include/net/mac80211.h 2007-11-11 15:47:08.183475366 +0100
@@ -598,9 +598,6 @@
u8 key[0];
};
-#define IEEE80211_SEQ_COUNTER_RX 0
-#define IEEE80211_SEQ_COUNTER_TX 1
-
/**
* enum set_key_cmd - key command
*
@@ -947,9 +944,9 @@
*
* @get_stats: return low-level statistics
*
- * @get_sequence_counter: For devices that have internal sequence counters this
- * callback allows mac80211 to access the current value of a counter.
- * This callback seems not well-defined, tell us if you need it.
+ * @get_tkip_seq: If your device implements TKIP encryption in hardware this
+ * callback should be provided to read the TKIP transmit IVs (both IV32
+ * and IV16) for the given key from hardware.
*
* @set_rts_threshold: Configuration of RTS threshold (if device needs it)
*
@@ -1022,9 +1019,8 @@
int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
int (*get_stats)(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
- int (*get_sequence_counter)(struct ieee80211_hw *hw,
- u8* addr, u8 keyidx, u8 txrx,
- u32* iv32, u16* iv16);
+ void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
+ u32 *iv32, u16 *iv16);
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
int (*set_retry_limit)(struct ieee80211_hw *hw,

View file

@ -0,0 +1,279 @@
Subject: cfg80211/nl80211: add beacon settings
This adds the necessary API to cfg80211/nl80211 to allow
changing beaconing settings.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/nl80211.h | 24 ++++++++
include/net/cfg80211.h | 33 +++++++++++
net/wireless/nl80211.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 190 insertions(+)
--- everything.orig/include/net/cfg80211.h 2007-11-08 11:50:57.412840007 +0100
+++ everything/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100
@@ -69,6 +69,26 @@ struct key_params {
u32 cipher;
};
+/**
+ * struct beacon_parameters - beacon parameters
+ *
+ * Used to configure the beacon for an interface.
+ *
+ * @head: head portion of beacon (before TIM IE)
+ * or %NULL if not changed
+ * @tail: tail portion of beacon (after TIM IE)
+ * or %NULL if not changed
+ * @interval: beacon interval or zero if not changed
+ * @dtim_period: DTIM period or zero if not changed
+ * @head_len: length of @head
+ * @tail_len: length of @tail
+ */
+struct beacon_parameters {
+ u8 *head, *tail;
+ int interval, dtim_period;
+ int head_len, tail_len;
+};
+
/* from net/wireless.h */
struct wiphy;
@@ -103,6 +123,13 @@ struct wiphy;
* and @key_index
*
* @set_default_key: set the default key on an interface
+ *
+ * @add_beacon: Add a beacon with given parameters, @head, @interval
+ * and @dtim_period will be valid, @tail is optional.
+ * @set_beacon: Change the beacon parameters for an access point mode
+ * interface. This should reject the call when no beacon has been
+ * configured.
+ * @del_beacon: Remove beacon configuration and stop sending the beacon.
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -122,6 +149,12 @@ struct cfg80211_ops {
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);
+
+ int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info);
+ int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info);
+ int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
};
#endif /* __NET_CFG80211_H */
--- everything.orig/include/linux/nl80211.h 2007-11-08 11:50:57.362839952 +0100
+++ everything/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100
@@ -47,6 +47,15 @@
* @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
* or %NL80211_ATTR_MAC.
*
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ * %NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ * parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -69,6 +78,11 @@ enum nl80211_commands {
NL80211_CMD_NEW_KEY,
NL80211_CMD_DEL_KEY,
+ NL80211_CMD_GET_BEACON,
+ NL80211_CMD_SET_BEACON,
+ NL80211_CMD_NEW_BEACON,
+ NL80211_CMD_DEL_BEACON,
+
/* add commands here */
/* used to define NL80211_CMD_MAX below */
@@ -101,6 +115,11 @@ enum nl80211_commands {
* @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
* CCMP keys, each six bytes in little endian
*
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -123,6 +142,11 @@ enum nl80211_attrs {
NL80211_ATTR_KEY_SEQ,
NL80211_ATTR_KEY_DEFAULT,
+ NL80211_ATTR_BEACON_INTERVAL,
+ NL80211_ATTR_DTIM_PERIOD,
+ NL80211_ATTR_BEACON_HEAD,
+ NL80211_ATTR_BEACON_TAIL,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
--- everything.orig/net/wireless/nl80211.c 2007-11-08 11:50:57.382836589 +0100
+++ everything/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100
@@ -69,6 +69,13 @@ static struct nla_policy nl80211_policy[
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
+
+ [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
+ [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
+ [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
};
/* message building helper */
@@ -600,6 +607,114 @@ static int nl80211_del_key(struct sk_buf
return err;
}
+static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+ int (*call)(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info);
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct beacon_parameters params;
+ int haveinfo = 0;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ switch (info->genlhdr->cmd) {
+ case NL80211_CMD_NEW_BEACON:
+ /* these are required for NEW_BEACON */
+ if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+ !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+ !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ call = drv->ops->add_beacon;
+ break;
+ case NL80211_CMD_SET_BEACON:
+ call = drv->ops->set_beacon;
+ break;
+ default:
+ WARN_ON(1);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!call) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ memset(&params, 0, sizeof(params));
+
+ if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+ params.interval =
+ nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+ haveinfo = 1;
+ }
+
+ if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
+ params.dtim_period =
+ nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+ haveinfo = 1;
+ }
+
+ if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
+ params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ params.head_len =
+ nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ haveinfo = 1;
+ }
+
+ if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
+ params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+ params.tail_len =
+ nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+ haveinfo = 1;
+ }
+
+ if (!haveinfo) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = call(&drv->wiphy, dev, &params);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->del_beacon) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->del_beacon(&drv->wiphy, dev);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -663,6 +778,24 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_SET_BEACON,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .doit = nl80211_addset_beacon,
+ },
+ {
+ .cmd = NL80211_CMD_NEW_BEACON,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .doit = nl80211_addset_beacon,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_BEACON,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .doit = nl80211_del_beacon,
+ },
};
/* multicast groups */

View file

@ -0,0 +1,484 @@
Subject: mac80211: add beacon configuration via cfg80211
This patch implements the cfg80211 hooks for configuring beaconing
on an access point interface in mac80211. While doing so, it fixes
a number of races that could badly crash the machine when the
beacon is changed while being requested by the driver.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
The dtim_count field should possibly also be part of the beacon
structure, but the possible race there doesn't really matter,
worst thing is that one beacon will be sent with a wrong dtim
count if (and only if) userspace changes the dtim period during
operation.
net/mac80211/cfg.c | 156 +++++++++++++++++++++++++++++++++++++++++
net/mac80211/debugfs_netdev.c | 27 -------
net/mac80211/ieee80211_i.h | 14 ++-
net/mac80211/ieee80211_iface.c | 4 -
net/mac80211/tx.c | 63 ++++++++++------
5 files changed, 204 insertions(+), 60 deletions(-)
Index: mac80211/net/mac80211/cfg.c
===================================================================
--- mac80211.orig/net/mac80211/cfg.c 2007-11-11 15:17:12.837164411 +0100
+++ mac80211/net/mac80211/cfg.c 2007-11-11 15:18:36.853952256 +0100
@@ -9,6 +9,7 @@
#include <linux/ieee80211.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
+#include <linux/rcupdate.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "cfg.h"
@@ -274,6 +275,158 @@
return 0;
}
+/*
+ * This handles both adding a beacon and setting new beacon info
+ */
+static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
+ struct beacon_parameters *params)
+{
+ struct beacon_data *new, *old;
+ int new_head_len, new_tail_len;
+ int size;
+ int err = -EINVAL;
+
+ old = sdata->u.ap.beacon;
+
+ /* head must not be zero-length */
+ if (params->head && !params->head_len)
+ return -EINVAL;
+
+ /*
+ * This is a kludge. beacon interval should really be part
+ * of the beacon information.
+ */
+ if (params->interval) {
+ sdata->local->hw.conf.beacon_int = params->interval;
+ if (ieee80211_hw_config(sdata->local))
+ return -EINVAL;
+ /*
+ * We updated some parameter so if below bails out
+ * it's not an error.
+ */
+ err = 0;
+ }
+
+ /* Need to have a beacon head if we don't have one yet */
+ if (!params->head && !old)
+ return err;
+
+ /* sorry, no way to start beaconing without dtim period */
+ if (!params->dtim_period && !old)
+ return err;
+
+ /* new or old head? */
+ if (params->head)
+ new_head_len = params->head_len;
+ else
+ new_head_len = old->head_len;
+
+ /* new or old tail? */
+ if (params->tail || !old)
+ /* params->tail_len will be zero for !params->tail */
+ new_tail_len = params->tail_len;
+ else
+ new_tail_len = old->tail_len;
+
+ size = sizeof(*new) + new_head_len + new_tail_len;
+
+ new = kzalloc(size, GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ /* start filling the new info now */
+
+ /* new or old dtim period? */
+ if (params->dtim_period)
+ new->dtim_period = params->dtim_period;
+ else
+ new->dtim_period = old->dtim_period;
+
+ /*
+ * pointers go into the block we allocated,
+ * memory is | beacon_data | head | tail |
+ */
+ new->head = ((u8 *) new) + sizeof(*new);
+ new->tail = new->head + new_head_len;
+ new->head_len = new_head_len;
+ new->tail_len = new_tail_len;
+
+ /* copy in head */
+ if (params->head)
+ memcpy(new->head, params->head, new_head_len);
+ else
+ memcpy(new->head, old->head, new_head_len);
+
+ /* copy in optional tail */
+ if (params->tail)
+ memcpy(new->tail, params->tail, new_tail_len);
+ else
+ if (old)
+ memcpy(new->tail, old->tail, new_tail_len);
+
+ rcu_assign_pointer(sdata->u.ap.beacon, new);
+
+ synchronize_rcu();
+
+ kfree(old);
+
+ return ieee80211_if_config_beacon(sdata->dev);
+}
+
+static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *params)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct beacon_data *old;
+
+ if (sdata->type != IEEE80211_IF_TYPE_AP)
+ return -EINVAL;
+
+ old = sdata->u.ap.beacon;
+
+ if (old)
+ return -EALREADY;
+
+ return ieee80211_config_beacon(sdata, params);
+}
+
+static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *params)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct beacon_data *old;
+
+ if (sdata->type != IEEE80211_IF_TYPE_AP)
+ return -EINVAL;
+
+ old = sdata->u.ap.beacon;
+
+ if (!old)
+ return -ENOENT;
+
+ return ieee80211_config_beacon(sdata, params);
+}
+
+static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct beacon_data *old;
+
+ if (sdata->type != IEEE80211_IF_TYPE_AP)
+ return -EINVAL;
+
+ old = sdata->u.ap.beacon;
+
+ if (!old)
+ return -ENOENT;
+
+ rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+ synchronize_rcu();
+ kfree(old);
+
+ return ieee80211_if_config_beacon(dev);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -282,4 +435,7 @@
.del_key = ieee80211_del_key,
.get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key,
+ .add_beacon = ieee80211_add_beacon,
+ .set_beacon = ieee80211_set_beacon,
+ .del_beacon = ieee80211_del_beacon,
};
Index: mac80211/net/mac80211/debugfs_netdev.c
===================================================================
--- mac80211.orig/net/mac80211/debugfs_netdev.c 2007-10-14 00:42:30.054156000 +0200
+++ mac80211/net/mac80211/debugfs_netdev.c 2007-11-11 15:18:11.852527505 +0100
@@ -124,7 +124,6 @@
/* AP attributes */
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
-IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
@@ -138,26 +137,6 @@
}
__IEEE80211_IF_FILE(num_buffered_multicast);
-static ssize_t ieee80211_if_fmt_beacon_head_len(
- const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
- if (sdata->u.ap.beacon_head)
- return scnprintf(buf, buflen, "%d\n",
- sdata->u.ap.beacon_head_len);
- return scnprintf(buf, buflen, "\n");
-}
-__IEEE80211_IF_FILE(beacon_head_len);
-
-static ssize_t ieee80211_if_fmt_beacon_tail_len(
- const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
- if (sdata->u.ap.beacon_tail)
- return scnprintf(buf, buflen, "%d\n",
- sdata->u.ap.beacon_tail_len);
- return scnprintf(buf, buflen, "\n");
-}
-__IEEE80211_IF_FILE(beacon_tail_len);
-
/* WDS attributes */
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
@@ -194,14 +173,11 @@
DEBUGFS_ADD(eapol, ap);
DEBUGFS_ADD(ieee8021_x, ap);
DEBUGFS_ADD(num_sta_ps, ap);
- DEBUGFS_ADD(dtim_period, ap);
DEBUGFS_ADD(dtim_count, ap);
DEBUGFS_ADD(num_beacons, ap);
DEBUGFS_ADD(force_unicast_rateidx, ap);
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
DEBUGFS_ADD(num_buffered_multicast, ap);
- DEBUGFS_ADD(beacon_head_len, ap);
- DEBUGFS_ADD(beacon_tail_len, ap);
}
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
@@ -287,14 +263,11 @@
DEBUGFS_DEL(eapol, ap);
DEBUGFS_DEL(ieee8021_x, ap);
DEBUGFS_DEL(num_sta_ps, ap);
- DEBUGFS_DEL(dtim_period, ap);
DEBUGFS_DEL(dtim_count, ap);
DEBUGFS_DEL(num_beacons, ap);
DEBUGFS_DEL(force_unicast_rateidx, ap);
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
DEBUGFS_DEL(num_buffered_multicast, ap);
- DEBUGFS_DEL(beacon_head_len, ap);
- DEBUGFS_DEL(beacon_tail_len, ap);
}
static void del_wds_files(struct ieee80211_sub_if_data *sdata)
Index: mac80211/net/mac80211/ieee80211_i.h
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:15:53.792659922 +0100
+++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:18:11.864528190 +0100
@@ -190,9 +190,14 @@
typedef ieee80211_txrx_result (*ieee80211_rx_handler)
(struct ieee80211_txrx_data *rx);
+struct beacon_data {
+ u8 *head, *tail;
+ int head_len, tail_len;
+ int dtim_period;
+};
+
struct ieee80211_if_ap {
- u8 *beacon_head, *beacon_tail;
- int beacon_head_len, beacon_tail_len;
+ struct beacon_data *beacon;
struct list_head vlans;
@@ -205,7 +210,7 @@
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
atomic_t num_sta_ps; /* number of stations in PS mode */
struct sk_buff_head ps_bc_buf;
- int dtim_period, dtim_count;
+ int dtim_count;
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
int num_beacons; /* number of TXed beacon frames for this BSS */
@@ -361,14 +366,11 @@
struct dentry *eapol;
struct dentry *ieee8021_x;
struct dentry *num_sta_ps;
- struct dentry *dtim_period;
struct dentry *dtim_count;
struct dentry *num_beacons;
struct dentry *force_unicast_rateidx;
struct dentry *max_ratectrl_rateidx;
struct dentry *num_buffered_multicast;
- struct dentry *beacon_head_len;
- struct dentry *beacon_tail_len;
} ap;
struct {
struct dentry *channel_use;
Index: mac80211/net/mac80211/ieee80211_iface.c
===================================================================
--- mac80211.orig/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:53.796660158 +0100
+++ mac80211/net/mac80211/ieee80211_iface.c 2007-11-11 15:18:11.868528415 +0100
@@ -187,7 +187,6 @@
sdata->u.vlan.ap = NULL;
break;
case IEEE80211_IF_TYPE_AP:
- sdata->u.ap.dtim_period = 2;
sdata->u.ap.force_unicast_rateidx = -1;
sdata->u.ap.max_ratectrl_rateidx = -1;
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
@@ -271,8 +270,7 @@
}
}
- kfree(sdata->u.ap.beacon_head);
- kfree(sdata->u.ap.beacon_tail);
+ kfree(sdata->u.ap.beacon);
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
local->total_ps_buffered--;
Index: mac80211/net/mac80211/tx.c
===================================================================
--- mac80211.orig/net/mac80211/tx.c 2007-11-11 15:15:53.804660611 +0100
+++ mac80211/net/mac80211/tx.c 2007-11-11 15:18:11.868528415 +0100
@@ -1656,7 +1656,8 @@
static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
struct ieee80211_if_ap *bss,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ struct beacon_data *beacon)
{
u8 *pos, *tim;
int aid0 = 0;
@@ -1672,7 +1673,7 @@
IEEE80211_MAX_AID+1);
if (bss->dtim_count == 0)
- bss->dtim_count = bss->dtim_period - 1;
+ bss->dtim_count = beacon->dtim_period - 1;
else
bss->dtim_count--;
@@ -1680,7 +1681,7 @@
*pos++ = WLAN_EID_TIM;
*pos++ = 4;
*pos++ = bss->dtim_count;
- *pos++ = bss->dtim_period;
+ *pos++ = beacon->dtim_period;
if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
aid0 = 1;
@@ -1728,8 +1729,9 @@
struct ieee80211_if_ap *ap = NULL;
struct ieee80211_rate *rate;
struct rate_control_extra extra;
- u8 *b_head, *b_tail;
- int bh_len, bt_len;
+ struct beacon_data *beacon;
+
+ rcu_read_lock();
bdev = dev_get_by_index(if_id);
if (bdev) {
@@ -1738,37 +1740,35 @@
dev_put(bdev);
}
- if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
- !ap->beacon_head) {
+ beacon = rcu_dereference(ap->beacon);
+
+ if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || !beacon) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "no beacon data avail for idx=%d "
"(%s)\n", if_id, bdev ? bdev->name : "N/A");
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
- return NULL;
+ skb = NULL;
+ goto out;
}
- /* Assume we are generating the normal beacon locally */
- b_head = ap->beacon_head;
- b_tail = ap->beacon_tail;
- bh_len = ap->beacon_head_len;
- bt_len = ap->beacon_tail_len;
-
- skb = dev_alloc_skb(local->tx_headroom +
- bh_len + bt_len + 256 /* maximum TIM len */);
+ /* headroom, head length, tail length and maximum TIM length */
+ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
+ beacon->tail_len + 256);
if (!skb)
- return NULL;
+ goto out;
skb_reserve(skb, local->tx_headroom);
- memcpy(skb_put(skb, bh_len), b_head, bh_len);
+ memcpy(skb_put(skb, beacon->head_len), beacon->head,
+ beacon->head_len);
ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
- ieee80211_beacon_add_tim(local, ap, skb);
+ ieee80211_beacon_add_tim(local, ap, skb, beacon);
- if (b_tail) {
- memcpy(skb_put(skb, bt_len), b_tail, bt_len);
- }
+ if (beacon->tail)
+ memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
+ beacon->tail_len);
if (control) {
memset(&extra, 0, sizeof(extra));
@@ -1781,7 +1781,8 @@
"found\n", wiphy_name(local->hw.wiphy));
}
dev_kfree_skb(skb);
- return NULL;
+ skb = NULL;
+ goto out;
}
control->tx_rate =
@@ -1796,6 +1797,9 @@
}
ap->num_beacons++;
+
+ out:
+ rcu_read_unlock();
return skb;
}
EXPORT_SYMBOL(ieee80211_beacon_get);
@@ -1844,6 +1848,7 @@
struct net_device *bdev;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_ap *bss = NULL;
+ struct beacon_data *beacon;
bdev = dev_get_by_index(if_id);
if (bdev) {
@@ -1851,9 +1856,19 @@
bss = &sdata->u.ap;
dev_put(bdev);
}
- if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
+
+ if (!bss)
return NULL;
+ rcu_read_lock();
+ beacon = rcu_dereference(bss->beacon);
+
+ if (sdata->type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head) {
+ rcu_read_unlock();
+ return NULL;
+ }
+ rcu_read_unlock();
+
if (bss->dtim_count != 0)
return NULL; /* send buffered bc/mc only after DTIM beacon */
memset(control, 0, sizeof(*control));

View file

@ -0,0 +1,464 @@
Subject: cfg80211/nl80211: station handling
This patch adds station handling to cfg80211/nl80211.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/nl80211.h | 68 +++++++++++++
include/net/cfg80211.h | 54 ++++++++++
net/wireless/nl80211.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 358 insertions(+)
--- everything.orig/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100
+++ everything/include/linux/nl80211.h 2007-11-08 17:15:15.961529840 +0100
@@ -7,6 +7,18 @@
*/
/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -56,6 +68,16 @@
* parameters are like for %NL80211_CMD_SET_BEACON.
* @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
*
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all stations, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -83,6 +105,11 @@ enum nl80211_commands {
NL80211_CMD_NEW_BEACON,
NL80211_CMD_DEL_BEACON,
+ NL80211_CMD_GET_STATION,
+ NL80211_CMD_SET_STATION,
+ NL80211_CMD_NEW_STATION,
+ NL80211_CMD_DEL_STATION,
+
/* add commands here */
/* used to define NL80211_CMD_MAX below */
@@ -120,6 +147,17 @@ enum nl80211_commands {
* @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
* @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
*
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_sta_flags.
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ * IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ * rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ * to, or the AP interface the station was originally added to to.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -147,12 +185,20 @@ enum nl80211_attrs {
NL80211_ATTR_BEACON_HEAD,
NL80211_ATTR_BEACON_TAIL,
+ NL80211_ATTR_STA_AID,
+ NL80211_ATTR_STA_FLAGS,
+ NL80211_ATTR_STA_LISTEN_INTERVAL,
+ NL80211_ATTR_STA_SUPPORTED_RATES,
+ NL80211_ATTR_STA_VLAN,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};
+#define NL80211_MAX_SUPP_RATES 32
+
/**
* enum nl80211_iftype - (virtual) interface types
*
@@ -184,4 +230,26 @@ enum nl80211_iftype {
NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
};
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ * with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ */
+enum nl80211_sta_flags {
+ __NL80211_STA_FLAG_INVALID,
+ NL80211_STA_FLAG_AUTHORIZED,
+ NL80211_STA_FLAG_SHORT_PREAMBLE,
+ NL80211_STA_FLAG_WME,
+
+ /* keep last */
+ __NL80211_STA_FLAG_AFTER_LAST,
+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
#endif /* __LINUX_NL80211_H */
--- everything.orig/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100
+++ everything/include/net/cfg80211.h 2007-11-08 17:15:15.971532444 +0100
@@ -89,6 +89,47 @@ struct beacon_parameters {
int head_len, tail_len;
};
+/**
+ * enum station_flags - station flags
+ *
+ * Station capability flags. Note that these must be the bits
+ * according to the nl80211 flags.
+ *
+ * @STATION_FLAG_CHANGED: station flags were changed
+ * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
+ * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ * with short preambles
+ * @STATION_FLAG_WME: station is WME/QoS capable
+ */
+enum station_flags {
+ STATION_FLAG_CHANGED = 1<<0,
+ STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED,
+ STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
+ STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME,
+};
+
+/**
+ * struct station_parameters - station parameters
+ *
+ * Used to change and create a new station.
+ *
+ * @vlan: vlan interface station should belong to
+ * @supported_rates: supported rates in IEEE 802.11 format
+ * (or NULL for no change)
+ * @supported_rates_len: number of supported rates
+ * @station_flags: station flags (see &enum station_flags)
+ * @listen_interval: listen interval or -1 for no change
+ * @aid: AID or zero for no change
+ */
+struct station_parameters {
+ u8 *supported_rates;
+ struct net_device *vlan;
+ u32 station_flags;
+ int listen_interval;
+ u16 aid;
+ u8 supported_rates_len;
+};
+
/* from net/wireless.h */
struct wiphy;
@@ -130,6 +171,12 @@ struct wiphy;
* interface. This should reject the call when no beacon has been
* configured.
* @del_beacon: Remove beacon configuration and stop sending the beacon.
+ *
+ * @add_station: Add a new station.
+ *
+ * @del_station: Remove a station; @mac may be NULL to remove all stations.
+ *
+ * @change_station: Modify a given station.
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -155,6 +202,13 @@ struct cfg80211_ops {
int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info);
int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
+
+ int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params);
+ int (*del_station)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac);
+ int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params);
};
#endif /* __NET_CFG80211_H */
--- everything.orig/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100
+++ everything/net/wireless/nl80211.c 2007-11-08 17:15:15.981533909 +0100
@@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
+ [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_RATES },
+ [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
};
/* message building helper */
@@ -715,6 +721,211 @@ static int nl80211_del_beacon(struct sk_
return err;
}
+static
+struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] __read_mostly = {
+ [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
+ [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
+ [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
+};
+
+static int parse_station_flags(struct nlattr *nla, u32 *staflags)
+{
+ struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
+ int flag;
+
+ *staflags = 0;
+
+ if (!nla)
+ return 0;
+
+ if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
+ nla, sta_flags_policy))
+ return -EINVAL;
+
+ *staflags = STATION_FLAG_CHANGED;
+
+ for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
+ if (flags[flag])
+ *staflags |= (1<<flag);
+
+ return 0;
+}
+
+static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
+{
+ return -EOPNOTSUPP;
+}
+
+/*
+ * Get vlan interface making sure it is on the right wiphy.
+ */
+static int get_vlan(struct nlattr *vlanattr,
+ struct cfg80211_registered_device *rdev,
+ struct net_device **vlan)
+{
+ *vlan = NULL;
+
+ if (vlanattr) {
+ *vlan = dev_get_by_index(nla_get_u32(vlanattr));
+ if (!*vlan)
+ return -ENODEV;
+ if (!(*vlan)->ieee80211_ptr)
+ return -EINVAL;
+ if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct station_parameters params;
+ u8 *mac_addr = NULL;
+
+ memset(&params, 0, sizeof(params));
+
+ params.listen_interval = -1;
+
+ if (info->attrs[NL80211_ATTR_STA_AID])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
+ params.supported_rates =
+ nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ params.supported_rates_len =
+ nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ }
+
+ if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+ params.listen_interval =
+ nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+
+ if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
+ &params.station_flags))
+ return -EINVAL;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+ if (err)
+ goto out;
+
+ if (!drv->ops->change_station) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
+ rtnl_unlock();
+
+ out:
+ if (params.vlan)
+ dev_put(params.vlan);
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct station_parameters params;
+ u8 *mac_addr = NULL;
+
+ memset(&params, 0, sizeof(params));
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_STA_AID])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
+ return -EINVAL;
+
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ params.supported_rates =
+ nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ params.supported_rates_len =
+ nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ params.listen_interval =
+ nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+ params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
+
+ if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
+ &params.station_flags))
+ return -EINVAL;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+ if (err)
+ goto out;
+
+ if (!drv->ops->add_station) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
+ rtnl_unlock();
+
+ out:
+ if (params.vlan)
+ dev_put(params.vlan);
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 *mac_addr = NULL;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->del_station) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -796,6 +1007,31 @@ static struct genl_ops nl80211_ops[] = {
.flags = GENL_ADMIN_PERM,
.doit = nl80211_del_beacon,
},
+ {
+ .cmd = NL80211_CMD_GET_STATION,
+ .doit = nl80211_get_station,
+ /* TODO: implement dumpit */
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_SET_STATION,
+ .doit = nl80211_set_station,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_NEW_STATION,
+ .doit = nl80211_new_station,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_STATION,
+ .doit = nl80211_del_station,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */

View file

@ -0,0 +1,224 @@
Subject: mac80211: implement cfg80211's station handling
This implements station handling from userspace via cfg80211
in mac80211.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/cfg.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 192 insertions(+)
--- everything.orig/net/mac80211/cfg.c 2007-11-08 17:11:52.351521702 +0100
+++ everything/net/mac80211/cfg.c 2007-11-08 17:15:51.801523493 +0100
@@ -14,6 +14,7 @@
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "cfg.h"
+#include "ieee80211_rate.h"
static enum ieee80211_if_types
nl80211_type_to_mac80211_type(enum nl80211_iftype type)
@@ -428,6 +429,194 @@ static int ieee80211_del_beacon(struct w
return ieee80211_if_config_beacon(dev);
}
+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
+struct iapp_layer2_update {
+ u8 da[ETH_ALEN]; /* broadcast */
+ u8 sa[ETH_ALEN]; /* STA addr */
+ __be16 len; /* 6 */
+ u8 dsap; /* 0 */
+ u8 ssap; /* 0 */
+ u8 control;
+ u8 xid_info[3];
+} __attribute__ ((packed));
+
+static void ieee80211_send_layer2_update(struct sta_info *sta)
+{
+ struct iapp_layer2_update *msg;
+ struct sk_buff *skb;
+
+ /* Send Level 2 Update Frame to update forwarding tables in layer 2
+ * bridge devices */
+
+ skb = dev_alloc_skb(sizeof(*msg));
+ if (!skb)
+ return;
+ msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
+
+ /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
+ * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
+
+ memset(msg->da, 0xff, ETH_ALEN);
+ memcpy(msg->sa, sta->addr, ETH_ALEN);
+ msg->len = htons(6);
+ msg->dsap = 0;
+ msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
+ msg->control = 0xaf; /* XID response lsb.1111F101.
+ * F=0 (no poll command; unsolicited frame) */
+ msg->xid_info[0] = 0x81; /* XID format identifier */
+ msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
+ msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
+
+ skb->dev = sta->dev;
+ skb->protocol = eth_type_trans(skb, sta->dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+static void sta_apply_parameters(struct ieee80211_local *local,
+ struct sta_info *sta,
+ struct station_parameters *params)
+{
+ u32 rates;
+ int i, j;
+ struct ieee80211_hw_mode *mode;
+
+ if (params->station_flags & STATION_FLAG_CHANGED) {
+ sta->flags &= ~WLAN_STA_AUTHORIZED;
+ if (params->station_flags & STATION_FLAG_AUTHORIZED)
+ sta->flags |= WLAN_STA_AUTHORIZED;
+
+ sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+ if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
+ sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+
+ sta->flags &= ~WLAN_STA_WME;
+ if (params->station_flags & STATION_FLAG_WME)
+ sta->flags |= WLAN_STA_WME;
+ }
+
+ if (params->aid) {
+ sta->aid = params->aid;
+ if (sta->aid > IEEE80211_MAX_AID)
+ sta->aid = 0; /* XXX: should this be an error? */
+ }
+
+ if (params->listen_interval >= 0)
+ sta->listen_interval = params->listen_interval;
+
+ if (params->supported_rates) {
+ rates = 0;
+ mode = local->oper_hw_mode;
+ for (i = 0; i < params->supported_rates_len; i++) {
+ int rate = (params->supported_rates[i] & 0x7f) * 5;
+ for (j = 0; j < mode->num_rates; j++) {
+ if (mode->rates[j].rate == rate)
+ rates |= BIT(j);
+ }
+ }
+ sta->supp_rates = rates;
+ }
+}
+
+static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata;
+
+ /* Prevent a race with changing the rate control algorithm */
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ /* XXX: get sta belonging to dev */
+ sta = sta_info_get(local, mac);
+ if (sta) {
+ sta_info_put(sta);
+ return -EEXIST;
+ }
+
+ if (params->vlan) {
+ sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
+
+ if (sdata->type != IEEE80211_IF_TYPE_VLAN ||
+ sdata->type != IEEE80211_IF_TYPE_AP)
+ return -EINVAL;
+ } else
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ sta = sta_info_add(local, dev, mac, GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
+
+ sta->dev = sdata->dev;
+ if (sdata->type == IEEE80211_IF_TYPE_VLAN ||
+ sdata->type == IEEE80211_IF_TYPE_AP)
+ ieee80211_send_layer2_update(sta);
+
+ sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+
+ sta_apply_parameters(local, sta, params);
+
+ rate_control_rate_init(sta, local);
+
+ sta_info_put(sta);
+
+ return 0;
+}
+
+static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+
+ if (mac) {
+ /* XXX: get sta belonging to dev */
+ sta = sta_info_get(local, mac);
+ if (!sta)
+ return -ENOENT;
+
+ sta_info_free(sta);
+ sta_info_put(sta);
+ } else
+ sta_info_flush(local, dev);
+
+ return 0;
+}
+
+static int ieee80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 *mac,
+ struct station_parameters *params)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *vlansdata;
+
+ /* XXX: get sta belonging to dev */
+ sta = sta_info_get(local, mac);
+ if (!sta)
+ return -ENOENT;
+
+ if (params->vlan && params->vlan != sta->dev) {
+ vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
+
+ if (vlansdata->type != IEEE80211_IF_TYPE_VLAN ||
+ vlansdata->type != IEEE80211_IF_TYPE_AP)
+ return -EINVAL;
+
+ sta->dev = params->vlan;
+ ieee80211_send_layer2_update(sta);
+ }
+
+ sta_apply_parameters(local, sta, params);
+
+ sta_info_put(sta);
+
+ return 0;
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -439,4 +628,7 @@ struct cfg80211_ops mac80211_config_ops
.add_beacon = ieee80211_add_beacon,
.set_beacon = ieee80211_set_beacon,
.del_beacon = ieee80211_del_beacon,
+ .add_station = ieee80211_add_station,
+ .del_station = ieee80211_del_station,
+ .change_station = ieee80211_change_station,
};

View file

@ -0,0 +1,208 @@
Subject: cfg80211/nl80211: implement station attribute retrieval
After a station is added to the kernel's structures, userspace
has to be able to retrieve statistics about that station, especially
whether the station was idle and how much bytes were transferred
to and from it. This adds the necessary code to nl80211.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/nl80211.h | 28 ++++++++++++++++
include/net/cfg80211.h | 35 ++++++++++++++++++++
net/wireless/nl80211.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 144 insertions(+), 1 deletion(-)
--- everything.orig/include/linux/nl80211.h 2007-11-08 17:15:15.961529840 +0100
+++ everything/include/linux/nl80211.h 2007-11-08 17:17:00.891547364 +0100
@@ -157,6 +157,9 @@ enum nl80211_commands {
* restriction (at most %NL80211_MAX_SUPP_RATES).
* @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
* to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
+ * given for %NL80211_CMD_GET_STATION, nested attribute containing
+ * info as possible, see &enum nl80211_sta_stats.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -190,6 +193,7 @@ enum nl80211_attrs {
NL80211_ATTR_STA_LISTEN_INTERVAL,
NL80211_ATTR_STA_SUPPORTED_RATES,
NL80211_ATTR_STA_VLAN,
+ NL80211_ATTR_STA_STATS,
/* add attributes here, update the policy in nl80211.c */
@@ -252,4 +256,28 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
};
+/**
+ * enum nl80211_sta_stats - station statistics
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_STATS
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_STAT_AFTER_LAST: internal
+ * @NL80211_STA_STAT_MAX: highest possible station stats attribute
+ */
+enum nl80211_sta_stats {
+ __NL80211_STA_STAT_INVALID,
+ NL80211_STA_STAT_INACTIVE_TIME,
+ NL80211_STA_STAT_RX_BYTES,
+ NL80211_STA_STAT_TX_BYTES,
+
+ /* keep last */
+ __NL80211_STA_STAT_AFTER_LAST,
+ NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
+};
+
#endif /* __LINUX_NL80211_H */
--- everything.orig/include/net/cfg80211.h 2007-11-08 17:15:15.971532444 +0100
+++ everything/include/net/cfg80211.h 2007-11-08 17:17:00.891547364 +0100
@@ -130,6 +130,39 @@ struct station_parameters {
u8 supported_rates_len;
};
+/**
+ * enum station_stats_flags - station statistics flags
+ *
+ * Used by the driver to indicate which info in &struct station_stats
+ * it has filled in during get_station().
+ *
+ * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
+ * @STATION_STAT_RX_BYTES: @rx_bytes filled
+ * @STATION_STAT_TX_BYTES: @tx_bytes filled
+ */
+enum station_stats_flags {
+ STATION_STAT_INACTIVE_TIME = 1<<0,
+ STATION_STAT_RX_BYTES = 1<<1,
+ STATION_STAT_TX_BYTES = 1<<2,
+};
+
+/**
+ * struct station_stats - station statistics
+ *
+ * Station information filled by driver for get_station().
+ *
+ * @filled: bitflag of flags from &enum station_stats_flags
+ * @inactive_time: time since last station activity (tx/rx) in milliseconds
+ * @rx_bytes: bytes received from this station
+ * @tx_bytes: bytes transmitted to this station
+ */
+struct station_stats {
+ u32 filled;
+ u32 inactive_time;
+ u32 rx_bytes;
+ u32 tx_bytes;
+};
+
/* from net/wireless.h */
struct wiphy;
@@ -209,6 +242,8 @@ struct cfg80211_ops {
u8 *mac);
int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_parameters *params);
+ int (*get_station)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_stats *stats);
};
#endif /* __NET_CFG80211_H */
--- everything.orig/net/wireless/nl80211.c 2007-11-08 17:15:15.981533909 +0100
+++ everything/net/wireless/nl80211.c 2007-11-08 17:17:00.901534235 +0100
@@ -751,9 +751,89 @@ static int parse_station_flags(struct nl
return 0;
}
+static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
+ int flags, struct net_device *dev,
+ u8 *mac_addr, struct station_stats *stats)
+{
+ void *hdr;
+ struct nlattr *statsattr;
+
+ hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
+ if (!hdr)
+ return -1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+
+ statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
+ if (!statsattr)
+ goto nla_put_failure;
+ if (stats->filled & STATION_STAT_INACTIVE_TIME)
+ NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
+ stats->inactive_time);
+ if (stats->filled & STATION_STAT_RX_BYTES)
+ NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
+ stats->rx_bytes);
+ if (stats->filled & STATION_STAT_TX_BYTES)
+ NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
+ stats->tx_bytes);
+
+ nla_nest_end(msg, statsattr);
+
+ return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+ return genlmsg_cancel(msg, hdr);
+}
+
+
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
{
- return -EOPNOTSUPP;
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct station_stats stats;
+ struct sk_buff *msg;
+ u8 *mac_addr = NULL;
+
+ memset(&stats, 0, sizeof(stats));
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->get_station) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
+ rtnl_unlock();
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ goto out;
+
+ if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
+ dev, mac_addr, &stats) < 0)
+ goto out_free;
+
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto out;
+
+ out_free:
+ nlmsg_free(msg);
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
}
/*

View file

@ -0,0 +1,51 @@
Subject: mac80211: implement station stats retrieval
This implements the required cfg80211 callback in mac80211
to allow userspace to get station statistics.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/cfg.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
--- everything.orig/net/mac80211/cfg.c 2007-11-08 17:15:51.801523493 +0100
+++ everything/net/mac80211/cfg.c 2007-11-08 17:17:01.921529351 +0100
@@ -617,6 +617,31 @@ static int ieee80211_change_station(stru
return 0;
}
+static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_stats *stats)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+
+ sta = sta_info_get(local, mac);
+ if (!sta)
+ return -ENOENT;
+
+ /* XXX: verify sta->dev == dev */
+
+ stats->filled = STATION_STAT_INACTIVE_TIME |
+ STATION_STAT_RX_BYTES |
+ STATION_STAT_TX_BYTES;
+
+ stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+ stats->rx_bytes = sta->rx_bytes;
+ stats->tx_bytes = sta->tx_bytes;
+
+ sta_info_put(sta);
+
+ return 0;
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -631,4 +656,5 @@ struct cfg80211_ops mac80211_config_ops
.add_station = ieee80211_add_station,
.del_station = ieee80211_del_station,
.change_station = ieee80211_change_station,
+ .get_station = ieee80211_get_station,
};