mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
[MAC80211]: Add mac80211 wireless stack.
Add mac80211, the IEEE 802.11 software MAC layer. Signed-off-by: Jiri Benc <jbenc@suse.cz> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
David S. Miller
parent
a9de8ce094
commit
f0706e828e
File diff suppressed because it is too large
Load Diff
@@ -220,6 +220,7 @@ config FIB_RULES
|
||||
menu "Wireless"
|
||||
|
||||
source "net/wireless/Kconfig"
|
||||
source "net/mac80211/Kconfig"
|
||||
source "net/ieee80211/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
+2
-2
@@ -45,6 +45,8 @@ obj-$(CONFIG_ECONET) += econet/
|
||||
obj-$(CONFIG_VLAN_8021Q) += 8021q/
|
||||
obj-$(CONFIG_IP_DCCP) += dccp/
|
||||
obj-$(CONFIG_IP_SCTP) += sctp/
|
||||
obj-y += wireless/
|
||||
obj-$(CONFIG_MAC80211) += mac80211/
|
||||
obj-$(CONFIG_IEEE80211) += ieee80211/
|
||||
obj-$(CONFIG_TIPC) += tipc/
|
||||
obj-$(CONFIG_NETLABEL) += netlabel/
|
||||
@@ -53,5 +55,3 @@ obj-$(CONFIG_IUCV) += iucv/
|
||||
ifeq ($(CONFIG_NET),y)
|
||||
obj-$(CONFIG_SYSCTL) += sysctl_net.o
|
||||
endif
|
||||
|
||||
obj-y += wireless/
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
config MAC80211
|
||||
tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
|
||||
depends on EXPERIMENTAL
|
||||
select CRYPTO
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_ARC4
|
||||
select CRYPTO_AES
|
||||
select CRC32
|
||||
select WIRELESS_EXT
|
||||
select CFG80211
|
||||
select NET_SCH_FIFO
|
||||
---help---
|
||||
This option enables the hardware independent IEEE 802.11
|
||||
networking stack.
|
||||
|
||||
config MAC80211_LEDS
|
||||
bool "Enable LED triggers"
|
||||
depends on MAC80211 && LEDS_TRIGGERS
|
||||
---help---
|
||||
This option enables a few LED triggers for different
|
||||
packet receive/transmit events.
|
||||
|
||||
config MAC80211_DEBUG
|
||||
bool "Enable debugging output"
|
||||
depends on MAC80211
|
||||
---help---
|
||||
This option will enable debug tracing output for the
|
||||
ieee80211 network stack.
|
||||
|
||||
If you are not trying to debug or develop the ieee80211
|
||||
subsystem, you most likely want to say N here.
|
||||
|
||||
config MAC80211_VERBOSE_DEBUG
|
||||
bool "Verbose debugging output"
|
||||
depends on MAC80211_DEBUG
|
||||
|
||||
config MAC80211_LOWTX_FRAME_DUMP
|
||||
bool "Debug frame dumping"
|
||||
depends on MAC80211_DEBUG
|
||||
---help---
|
||||
Selecting this option will cause the stack to
|
||||
print a message for each frame that is handed
|
||||
to the lowlevel driver for transmission. This
|
||||
message includes all MAC addresses and the
|
||||
frame control field.
|
||||
|
||||
If unsure, say N and insert the debugging code
|
||||
you require into the driver you are debugging.
|
||||
|
||||
config TKIP_DEBUG
|
||||
bool "TKIP debugging"
|
||||
depends on MAC80211_DEBUG
|
||||
|
||||
config MAC80211_DEBUG_COUNTERS
|
||||
bool "Extra statistics for TX/RX debugging"
|
||||
depends on MAC80211_DEBUG
|
||||
|
||||
config MAC80211_IBSS_DEBUG
|
||||
bool "Support for IBSS testing"
|
||||
depends on MAC80211_DEBUG
|
||||
---help---
|
||||
Say Y here if you intend to debug the IBSS code.
|
||||
|
||||
config MAC80211_VERBOSE_PS_DEBUG
|
||||
bool "Verbose powersave mode debugging"
|
||||
depends on MAC80211_DEBUG
|
||||
---help---
|
||||
Say Y here to print out verbose powersave
|
||||
mode debug messages.
|
||||
@@ -0,0 +1,19 @@
|
||||
obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
|
||||
|
||||
mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
|
||||
|
||||
mac80211-objs := \
|
||||
ieee80211.o \
|
||||
ieee80211_ioctl.o \
|
||||
sta_info.o \
|
||||
wep.o \
|
||||
wpa.o \
|
||||
ieee80211_sta.o \
|
||||
ieee80211_iface.o \
|
||||
ieee80211_rate.o \
|
||||
michael.o \
|
||||
tkip.o \
|
||||
aes_ccm.o \
|
||||
wme.o \
|
||||
ieee80211_cfg.o \
|
||||
$(mac80211-objs-y)
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/scatterlist.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_key.h"
|
||||
#include "aes_ccm.h"
|
||||
|
||||
|
||||
static void ieee80211_aes_encrypt(struct crypto_cipher *tfm,
|
||||
const u8 pt[16], u8 ct[16])
|
||||
{
|
||||
crypto_cipher_encrypt_one(tfm, ct, pt);
|
||||
}
|
||||
|
||||
|
||||
static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *b, u8 *s_0, u8 *a)
|
||||
{
|
||||
int i;
|
||||
|
||||
ieee80211_aes_encrypt(tfm, b_0, b);
|
||||
|
||||
/* Extra Authenticate-only data (always two AES blocks) */
|
||||
for (i = 0; i < AES_BLOCK_LEN; i++)
|
||||
aad[i] ^= b[i];
|
||||
ieee80211_aes_encrypt(tfm, aad, b);
|
||||
|
||||
aad += AES_BLOCK_LEN;
|
||||
|
||||
for (i = 0; i < AES_BLOCK_LEN; i++)
|
||||
aad[i] ^= b[i];
|
||||
ieee80211_aes_encrypt(tfm, aad, a);
|
||||
|
||||
/* Mask out bits from auth-only-b_0 */
|
||||
b_0[0] &= 0x07;
|
||||
|
||||
/* S_0 is used to encrypt T (= MIC) */
|
||||
b_0[14] = 0;
|
||||
b_0[15] = 0;
|
||||
ieee80211_aes_encrypt(tfm, b_0, s_0);
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *b_0, u8 *aad, u8 *data, size_t data_len,
|
||||
u8 *cdata, u8 *mic)
|
||||
{
|
||||
int i, j, last_len, num_blocks;
|
||||
u8 *pos, *cpos, *b, *s_0, *e;
|
||||
|
||||
b = scratch;
|
||||
s_0 = scratch + AES_BLOCK_LEN;
|
||||
e = scratch + 2 * AES_BLOCK_LEN;
|
||||
|
||||
num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
|
||||
last_len = data_len % AES_BLOCK_LEN;
|
||||
aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
|
||||
|
||||
/* Process payload blocks */
|
||||
pos = data;
|
||||
cpos = cdata;
|
||||
for (j = 1; j <= num_blocks; j++) {
|
||||
int blen = (j == num_blocks && last_len) ?
|
||||
last_len : AES_BLOCK_LEN;
|
||||
|
||||
/* Authentication followed by encryption */
|
||||
for (i = 0; i < blen; i++)
|
||||
b[i] ^= pos[i];
|
||||
ieee80211_aes_encrypt(tfm, b, b);
|
||||
|
||||
b_0[14] = (j >> 8) & 0xff;
|
||||
b_0[15] = j & 0xff;
|
||||
ieee80211_aes_encrypt(tfm, b_0, e);
|
||||
for (i = 0; i < blen; i++)
|
||||
*cpos++ = *pos++ ^ e[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < CCMP_MIC_LEN; i++)
|
||||
mic[i] = b[i] ^ s_0[i];
|
||||
}
|
||||
|
||||
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
|
||||
u8 *mic, u8 *data)
|
||||
{
|
||||
int i, j, last_len, num_blocks;
|
||||
u8 *pos, *cpos, *b, *s_0, *a;
|
||||
|
||||
b = scratch;
|
||||
s_0 = scratch + AES_BLOCK_LEN;
|
||||
a = scratch + 2 * AES_BLOCK_LEN;
|
||||
|
||||
num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
|
||||
last_len = data_len % AES_BLOCK_LEN;
|
||||
aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
|
||||
|
||||
/* Process payload blocks */
|
||||
cpos = cdata;
|
||||
pos = data;
|
||||
for (j = 1; j <= num_blocks; j++) {
|
||||
int blen = (j == num_blocks && last_len) ?
|
||||
last_len : AES_BLOCK_LEN;
|
||||
|
||||
/* Decryption followed by authentication */
|
||||
b_0[14] = (j >> 8) & 0xff;
|
||||
b_0[15] = j & 0xff;
|
||||
ieee80211_aes_encrypt(tfm, b_0, b);
|
||||
for (i = 0; i < blen; i++) {
|
||||
*pos = *cpos++ ^ b[i];
|
||||
a[i] ^= *pos++;
|
||||
}
|
||||
|
||||
ieee80211_aes_encrypt(tfm, a, a);
|
||||
}
|
||||
|
||||
for (i = 0; i < CCMP_MIC_LEN; i++) {
|
||||
if ((mic[i] ^ s_0[i]) != a[i])
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[])
|
||||
{
|
||||
struct crypto_cipher *tfm;
|
||||
|
||||
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
return NULL;
|
||||
|
||||
crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
|
||||
|
||||
return tfm;
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_aes_key_free(struct crypto_cipher *tfm)
|
||||
{
|
||||
if (tfm)
|
||||
crypto_free_cipher(tfm);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2006, Devicescape Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef AES_CCM_H
|
||||
#define AES_CCM_H
|
||||
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#define AES_BLOCK_LEN 16
|
||||
|
||||
struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]);
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *b_0, u8 *aad, u8 *data, size_t data_len,
|
||||
u8 *cdata, u8 *mic);
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
|
||||
u8 *mic, u8 *data);
|
||||
void ieee80211_aes_key_free(struct crypto_cipher *tfm);
|
||||
|
||||
#endif /* AES_CCM_H */
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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_IEEE_802_1X = 23,
|
||||
PRISM2_PARAM_ANTSEL_TX = 24,
|
||||
PRISM2_PARAM_ANTSEL_RX = 25,
|
||||
|
||||
/* Instant802 additions */
|
||||
PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
|
||||
PRISM2_PARAM_DROP_UNENCRYPTED = 1002,
|
||||
PRISM2_PARAM_PREAMBLE = 1003,
|
||||
PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
|
||||
PRISM2_PARAM_NEXT_MODE = 1008,
|
||||
PRISM2_PARAM_CLEAR_KEYS = 1009,
|
||||
PRISM2_PARAM_RADIO_ENABLED = 1010,
|
||||
PRISM2_PARAM_ANTENNA_MODE = 1013,
|
||||
PRISM2_PARAM_STAT_TIME = 1016,
|
||||
PRISM2_PARAM_STA_ANTENNA_SEL = 1017,
|
||||
PRISM2_PARAM_FORCE_UNICAST_RATE = 1018,
|
||||
PRISM2_PARAM_RATE_CTRL_NUM_UP = 1019,
|
||||
PRISM2_PARAM_RATE_CTRL_NUM_DOWN = 1020,
|
||||
PRISM2_PARAM_MAX_RATECTRL_RATE = 1021,
|
||||
PRISM2_PARAM_TX_POWER_REDUCTION = 1022,
|
||||
PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024,
|
||||
PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026,
|
||||
PRISM2_PARAM_WIFI_WME_NOACK_TEST = 1033,
|
||||
PRISM2_PARAM_SCAN_FLAGS = 1035,
|
||||
PRISM2_PARAM_HW_MODES = 1036,
|
||||
PRISM2_PARAM_CREATE_IBSS = 1037,
|
||||
PRISM2_PARAM_WMM_ENABLED = 1038,
|
||||
PRISM2_PARAM_MIXED_CELL = 1039,
|
||||
PRISM2_PARAM_RADAR_DETECT = 1043,
|
||||
PRISM2_PARAM_SPECTRUM_MGMT = 1044,
|
||||
};
|
||||
|
||||
enum {
|
||||
IEEE80211_KEY_MGMT_NONE = 0,
|
||||
IEEE80211_KEY_MGMT_IEEE8021X = 1,
|
||||
IEEE80211_KEY_MGMT_WPA_PSK = 2,
|
||||
IEEE80211_KEY_MGMT_WPA_EAP = 3,
|
||||
};
|
||||
|
||||
|
||||
/* Data structures used for get_hw_features ioctl */
|
||||
struct hostapd_ioctl_hw_modes_hdr {
|
||||
int mode;
|
||||
int num_channels;
|
||||
int num_rates;
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
|
||||
/* ADD_IF, REMOVE_IF, and UPDATE_IF 'type' argument */
|
||||
enum {
|
||||
HOSTAP_IF_WDS = 1, HOSTAP_IF_VLAN = 2, HOSTAP_IF_BSS = 3,
|
||||
HOSTAP_IF_STA = 4
|
||||
};
|
||||
|
||||
struct hostapd_if_wds {
|
||||
u8 remote_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct hostapd_if_vlan {
|
||||
u8 id;
|
||||
};
|
||||
|
||||
struct hostapd_if_bss {
|
||||
u8 bssid[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct hostapd_if_sta {
|
||||
};
|
||||
|
||||
#endif /* HOSTAPD_IOCTL_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* mac80211 configuration hooks for cfg80211
|
||||
*
|
||||
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This file is GPLv2 as found in COPYING.
|
||||
*/
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "ieee80211_cfg.h"
|
||||
|
||||
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
||||
unsigned int type)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
int itype;
|
||||
|
||||
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
|
||||
return -ENODEV;
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
itype = IEEE80211_IF_TYPE_STA;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
itype = IEEE80211_IF_TYPE_IBSS;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
itype = IEEE80211_IF_TYPE_STA;
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
itype = IEEE80211_IF_TYPE_MNTR;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ieee80211_if_add(local->mdev, name, NULL, itype);
|
||||
}
|
||||
|
||||
static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct net_device *dev;
|
||||
char *name;
|
||||
|
||||
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
|
||||
return -ENODEV;
|
||||
|
||||
dev = dev_get_by_index(ifindex);
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
name = dev->name;
|
||||
dev_put(dev);
|
||||
|
||||
return ieee80211_if_remove(local->mdev, name, -1);
|
||||
}
|
||||
|
||||
struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* mac80211 configuration hooks for cfg80211
|
||||
*/
|
||||
#ifndef __IEEE80211_CFG_H
|
||||
#define __IEEE80211_CFG_H
|
||||
|
||||
extern struct cfg80211_ops mac80211_config_ops;
|
||||
|
||||
#endif /* __IEEE80211_CFG_H */
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* IEEE 802.11 driver (80211.o) -- hostapd interface
|
||||
* Copyright 2002-2004, Instant802 Networks, 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 IEEE80211_COMMON_H
|
||||
#define IEEE80211_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* This is common header information with user space. It is used on all
|
||||
* frames sent to wlan#ap interface.
|
||||
*/
|
||||
|
||||
#define IEEE80211_FI_VERSION 0x80211001
|
||||
|
||||
struct ieee80211_frame_info {
|
||||
__be32 version;
|
||||
__be32 length;
|
||||
__be64 mactime;
|
||||
__be64 hosttime;
|
||||
__be32 phytype;
|
||||
__be32 channel;
|
||||
__be32 datarate;
|
||||
__be32 antenna;
|
||||
__be32 priority;
|
||||
__be32 ssi_type;
|
||||
__be32 ssi_signal;
|
||||
__be32 ssi_noise;
|
||||
__be32 preamble;
|
||||
__be32 encoding;
|
||||
|
||||
/* Note: this structure is otherwise identical to capture format used
|
||||
* in linux-wlan-ng, but this additional field is used to provide meta
|
||||
* data about the frame to hostapd. This was the easiest method for
|
||||
* providing this information, but this might change in the future. */
|
||||
__be32 msg_type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
enum ieee80211_msg_type {
|
||||
ieee80211_msg_normal = 0,
|
||||
ieee80211_msg_tx_callback_ack = 1,
|
||||
ieee80211_msg_tx_callback_fail = 2,
|
||||
ieee80211_msg_passive_scan = 3,
|
||||
ieee80211_msg_wep_frame_unknown_key = 4,
|
||||
ieee80211_msg_michael_mic_failure = 5,
|
||||
/* hole at 6, was monitor but never sent to userspace */
|
||||
ieee80211_msg_sta_not_assoc = 7,
|
||||
ieee80211_msg_set_aid_for_sta = 8 /* used by Intersil MVC driver */,
|
||||
ieee80211_msg_key_threshold_notification = 9,
|
||||
ieee80211_msg_radar = 11,
|
||||
};
|
||||
|
||||
struct ieee80211_msg_set_aid_for_sta {
|
||||
char sta_address[ETH_ALEN];
|
||||
u16 aid;
|
||||
};
|
||||
|
||||
struct ieee80211_msg_key_notification {
|
||||
int tx_rx_count;
|
||||
char ifname[IFNAMSIZ];
|
||||
u8 addr[ETH_ALEN]; /* ff:ff:ff:ff:ff:ff for broadcast keys */
|
||||
};
|
||||
|
||||
|
||||
enum ieee80211_phytype {
|
||||
ieee80211_phytype_fhss_dot11_97 = 1,
|
||||
ieee80211_phytype_dsss_dot11_97 = 2,
|
||||
ieee80211_phytype_irbaseband = 3,
|
||||
ieee80211_phytype_dsss_dot11_b = 4,
|
||||
ieee80211_phytype_pbcc_dot11_b = 5,
|
||||
ieee80211_phytype_ofdm_dot11_g = 6,
|
||||
ieee80211_phytype_pbcc_dot11_g = 7,
|
||||
ieee80211_phytype_ofdm_dot11_a = 8,
|
||||
ieee80211_phytype_dsss_dot11_turbog = 255,
|
||||
ieee80211_phytype_dsss_dot11_turbo = 256,
|
||||
};
|
||||
|
||||
enum ieee80211_ssi_type {
|
||||
ieee80211_ssi_none = 0,
|
||||
ieee80211_ssi_norm = 1, /* normalized, 0-1000 */
|
||||
ieee80211_ssi_dbm = 2,
|
||||
ieee80211_ssi_raw = 3, /* raw SSI */
|
||||
};
|
||||
|
||||
struct ieee80211_radar_info {
|
||||
int channel;
|
||||
int radar;
|
||||
int radar_type;
|
||||
};
|
||||
|
||||
#endif /* IEEE80211_COMMON_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "sta_info.h"
|
||||
|
||||
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Default values for sub-interface parameters */
|
||||
sdata->drop_unencrypted = 0;
|
||||
sdata->eapol = 1;
|
||||
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
|
||||
skb_queue_head_init(&sdata->fragments[i].skb_list);
|
||||
}
|
||||
|
||||
static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
|
||||
__skb_queue_purge(&sdata->fragments[i].skb_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called with rtnl lock held. */
|
||||
int ieee80211_if_add(struct net_device *dev, const char *name,
|
||||
struct net_device **new_dev, int type)
|
||||
{
|
||||
struct net_device *ndev;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = NULL;
|
||||
int ret;
|
||||
|
||||
ASSERT_RTNL();
|
||||
ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
|
||||
name, ieee80211_if_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);
|
||||
ndev->base_addr = dev->base_addr;
|
||||
ndev->irq = dev->irq;
|
||||
ndev->mem_start = dev->mem_start;
|
||||
ndev->mem_end = dev->mem_end;
|
||||
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
|
||||
ndev->ieee80211_ptr = &sdata->wdev;
|
||||
sdata->wdev.wiphy = local->hw.wiphy;
|
||||
sdata->type = IEEE80211_IF_TYPE_AP;
|
||||
sdata->dev = ndev;
|
||||
sdata->local = local;
|
||||
ieee80211_if_sdata_init(sdata);
|
||||
|
||||
ret = register_netdevice(ndev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ieee80211_if_set_type(ndev, type);
|
||||
|
||||
write_lock_bh(&local->sub_if_lock);
|
||||
if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
|
||||
write_unlock_bh(&local->sub_if_lock);
|
||||
__ieee80211_if_del(local, sdata);
|
||||
return -ENODEV;
|
||||
}
|
||||
list_add(&sdata->list, &local->sub_if_list);
|
||||
if (new_dev)
|
||||
*new_dev = ndev;
|
||||
write_unlock_bh(&local->sub_if_lock);
|
||||
|
||||
ieee80211_update_default_wep_only(local);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free_netdev(ndev);
|
||||
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;
|
||||
|
||||
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;
|
||||
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);
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
|
||||
sdata->type = type;
|
||||
switch (type) {
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
sdata->bss = NULL;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
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);
|
||||
sdata->bss = &sdata->u.ap;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
case IEEE80211_IF_TYPE_IBSS: {
|
||||
struct ieee80211_sub_if_data *msdata;
|
||||
struct ieee80211_if_sta *ifsta;
|
||||
|
||||
ifsta = &sdata->u.sta;
|
||||
INIT_WORK(&ifsta->work, ieee80211_sta_work);
|
||||
setup_timer(&ifsta->timer, ieee80211_sta_timer,
|
||||
(unsigned long) sdata);
|
||||
skb_queue_head_init(&ifsta->skb_queue);
|
||||
|
||||
ifsta->capab = WLAN_CAPABILITY_ESS;
|
||||
ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
|
||||
IEEE80211_AUTH_ALG_SHARED_KEY;
|
||||
ifsta->create_ibss = 1;
|
||||
ifsta->wmm_enabled = 1;
|
||||
ifsta->auto_channel_sel = 1;
|
||||
ifsta->auto_bssid_sel = 1;
|
||||
|
||||
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
|
||||
sdata->bss = &msdata->u.ap;
|
||||
break;
|
||||
}
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
dev->type = ARPHRD_IEEE80211_RADIOTAP;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
|
||||
dev->name, __FUNCTION__, type);
|
||||
}
|
||||
ieee80211_update_default_wep_only(local);
|
||||
}
|
||||
|
||||
/* Must be called with rtnl lock held. */
|
||||
void ieee80211_if_reinit(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);
|
||||
struct sta_info *sta;
|
||||
int i;
|
||||
|
||||
ASSERT_RTNL();
|
||||
ieee80211_if_sdata_deinit(sdata);
|
||||
for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
|
||||
if (!sdata->keys[i])
|
||||
continue;
|
||||
#if 0
|
||||
/* The interface is down at the moment, so there is not
|
||||
* really much point in disabling the keys at this point. */
|
||||
memset(addr, 0xff, ETH_ALEN);
|
||||
if (local->ops->set_key)
|
||||
local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr,
|
||||
local->keys[i], 0);
|
||||
#endif
|
||||
ieee80211_key_free(sdata->keys[i]);
|
||||
sdata->keys[i] = NULL;
|
||||
}
|
||||
|
||||
switch (sdata->type) {
|
||||
case IEEE80211_IF_TYPE_AP: {
|
||||
/* Remove all virtual interfaces that use this BSS
|
||||
* as their sdata->bss */
|
||||
struct ieee80211_sub_if_data *tsdata, *n;
|
||||
LIST_HEAD(tmp_list);
|
||||
|
||||
write_lock_bh(&local->sub_if_lock);
|
||||
list_for_each_entry_safe(tsdata, n, &local->sub_if_list, list) {
|
||||
if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
|
||||
printk(KERN_DEBUG "%s: removing virtual "
|
||||
"interface %s because its BSS interface"
|
||||
" is being removed\n",
|
||||
sdata->dev->name, tsdata->dev->name);
|
||||
list_move_tail(&tsdata->list, &tmp_list);
|
||||
}
|
||||
}
|
||||
write_unlock_bh(&local->sub_if_lock);
|
||||
|
||||
list_for_each_entry_safe(tsdata, n, &tmp_list, list)
|
||||
__ieee80211_if_del(local, tsdata);
|
||||
|
||||
kfree(sdata->u.ap.beacon_head);
|
||||
kfree(sdata->u.ap.beacon_tail);
|
||||
kfree(sdata->u.ap.generic_elem);
|
||||
|
||||
if (dev != local->mdev) {
|
||||
struct sk_buff *skb;
|
||||
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
|
||||
local->total_ps_buffered--;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
sta = sta_info_get(local, sdata->u.wds.remote_addr);
|
||||
if (sta) {
|
||||
sta_info_put(sta);
|
||||
sta_info_free(sta, 0);
|
||||
} else {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Someone had deleted my STA "
|
||||
"entry for the WDS link\n", dev->name);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
}
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
case IEEE80211_IF_TYPE_IBSS:
|
||||
kfree(sdata->u.sta.extra_ie);
|
||||
sdata->u.sta.extra_ie = NULL;
|
||||
kfree(sdata->u.sta.assocreq_ies);
|
||||
sdata->u.sta.assocreq_ies = NULL;
|
||||
kfree(sdata->u.sta.assocresp_ies);
|
||||
sdata->u.sta.assocresp_ies = NULL;
|
||||
if (sdata->u.sta.probe_resp) {
|
||||
dev_kfree_skb(sdata->u.sta.probe_resp);
|
||||
sdata->u.sta.probe_resp = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
dev->type = ARPHRD_ETHER;
|
||||
break;
|
||||
}
|
||||
|
||||
/* remove all STAs that are bound to this virtual interface */
|
||||
sta_info_flush(local, dev);
|
||||
|
||||
memset(&sdata->u, 0, sizeof(sdata->u));
|
||||
ieee80211_if_sdata_init(sdata);
|
||||
}
|
||||
|
||||
/* Must be called with rtnl lock held. */
|
||||
void __ieee80211_if_del(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct net_device *dev = sdata->dev;
|
||||
|
||||
unregister_netdevice(dev);
|
||||
/* Except master interface, the net_device will be freed by
|
||||
* net_device->destructor (i. e. ieee80211_if_free). */
|
||||
}
|
||||
|
||||
/* Must be called with rtnl lock held. */
|
||||
int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata, *n;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
write_lock_bh(&local->sub_if_lock);
|
||||
list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) {
|
||||
if ((sdata->type == id || id == -1) &&
|
||||
strcmp(name, sdata->dev->name) == 0 &&
|
||||
sdata->dev != local->mdev) {
|
||||
list_del(&sdata->list);
|
||||
write_unlock_bh(&local->sub_if_lock);
|
||||
__ieee80211_if_del(local, sdata);
|
||||
ieee80211_update_default_wep_only(local);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
write_unlock_bh(&local->sub_if_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 IEEE80211_KEY_H
|
||||
#define IEEE80211_KEY_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
/* ALG_TKIP
|
||||
* struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block:
|
||||
* Temporal Encryption Key (128 bits)
|
||||
* Temporal Authenticator Tx MIC Key (64 bits)
|
||||
* Temporal Authenticator Rx MIC Key (64 bits)
|
||||
*/
|
||||
|
||||
#define WEP_IV_LEN 4
|
||||
#define WEP_ICV_LEN 4
|
||||
|
||||
#define ALG_TKIP_KEY_LEN 32
|
||||
/* Starting offsets for each key */
|
||||
#define ALG_TKIP_TEMP_ENCR_KEY 0
|
||||
#define ALG_TKIP_TEMP_AUTH_TX_MIC_KEY 16
|
||||
#define ALG_TKIP_TEMP_AUTH_RX_MIC_KEY 24
|
||||
#define TKIP_IV_LEN 8
|
||||
#define TKIP_ICV_LEN 4
|
||||
|
||||
#define ALG_CCMP_KEY_LEN 16
|
||||
#define CCMP_HDR_LEN 8
|
||||
#define CCMP_MIC_LEN 8
|
||||
#define CCMP_TK_LEN 16
|
||||
#define CCMP_PN_LEN 6
|
||||
|
||||
#define NUM_RX_DATA_QUEUES 17
|
||||
|
||||
struct ieee80211_key {
|
||||
struct kref kref;
|
||||
|
||||
int hw_key_idx; /* filled and used by low-level driver */
|
||||
ieee80211_key_alg alg;
|
||||
union {
|
||||
struct {
|
||||
/* last used TSC */
|
||||
u32 iv32;
|
||||
u16 iv16;
|
||||
u16 p1k[5];
|
||||
int tx_initialized;
|
||||
|
||||
/* last received RSC */
|
||||
u32 iv32_rx[NUM_RX_DATA_QUEUES];
|
||||
u16 iv16_rx[NUM_RX_DATA_QUEUES];
|
||||
u16 p1k_rx[NUM_RX_DATA_QUEUES][5];
|
||||
int rx_initialized[NUM_RX_DATA_QUEUES];
|
||||
} tkip;
|
||||
struct {
|
||||
u8 tx_pn[6];
|
||||
u8 rx_pn[NUM_RX_DATA_QUEUES][6];
|
||||
struct crypto_cipher *tfm;
|
||||
u32 replays; /* dot11RSNAStatsCCMPReplays */
|
||||
/* scratch buffers for virt_to_page() (crypto API) */
|
||||
#ifndef AES_BLOCK_LEN
|
||||
#define AES_BLOCK_LEN 16
|
||||
#endif
|
||||
u8 tx_crypto_buf[6 * AES_BLOCK_LEN];
|
||||
u8 rx_crypto_buf[6 * AES_BLOCK_LEN];
|
||||
} ccmp;
|
||||
} u;
|
||||
int tx_rx_count; /* number of times this key has been used */
|
||||
int keylen;
|
||||
|
||||
/* if the low level driver can provide hardware acceleration it should
|
||||
* clear this flag */
|
||||
unsigned int force_sw_encrypt:1;
|
||||
unsigned int default_tx_key:1; /* This key is the new default TX key
|
||||
* (used only for broadcast keys). */
|
||||
s8 keyidx; /* WEP key index */
|
||||
|
||||
u8 key[0];
|
||||
};
|
||||
|
||||
#endif /* IEEE80211_KEY_H */
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* just for IFNAMSIZ */
|
||||
#include <linux/if.h>
|
||||
#include "ieee80211_led.h"
|
||||
|
||||
void ieee80211_led_rx(struct ieee80211_local *local)
|
||||
{
|
||||
if (unlikely(!local->rx_led))
|
||||
return;
|
||||
if (local->rx_led_counter++ % 2 == 0)
|
||||
led_trigger_event(local->rx_led, LED_OFF);
|
||||
else
|
||||
led_trigger_event(local->rx_led, LED_FULL);
|
||||
}
|
||||
|
||||
/* q is 1 if a packet was enqueued, 0 if it has been transmitted */
|
||||
void ieee80211_led_tx(struct ieee80211_local *local, int q)
|
||||
{
|
||||
if (unlikely(!local->tx_led))
|
||||
return;
|
||||
/* not sure how this is supposed to work ... */
|
||||
local->tx_led_counter += 2*q-1;
|
||||
if (local->tx_led_counter % 2 == 0)
|
||||
led_trigger_event(local->tx_led, LED_OFF);
|
||||
else
|
||||
led_trigger_event(local->tx_led, LED_FULL);
|
||||
}
|
||||
|
||||
void ieee80211_led_init(struct ieee80211_local *local)
|
||||
{
|
||||
local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
|
||||
if (!local->rx_led)
|
||||
return;
|
||||
snprintf(local->rx_led_name, sizeof(local->rx_led_name),
|
||||
"%srx", wiphy_name(local->hw.wiphy));
|
||||
local->rx_led->name = local->rx_led_name;
|
||||
if (led_trigger_register(local->rx_led)) {
|
||||
kfree(local->rx_led);
|
||||
local->rx_led = NULL;
|
||||
}
|
||||
|
||||
local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
|
||||
if (!local->tx_led)
|
||||
return;
|
||||
snprintf(local->tx_led_name, sizeof(local->tx_led_name),
|
||||
"%stx", wiphy_name(local->hw.wiphy));
|
||||
local->tx_led->name = local->tx_led_name;
|
||||
if (led_trigger_register(local->tx_led)) {
|
||||
kfree(local->tx_led);
|
||||
local->tx_led = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_led_exit(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->tx_led) {
|
||||
led_trigger_unregister(local->tx_led);
|
||||
kfree(local->tx_led);
|
||||
}
|
||||
if (local->rx_led) {
|
||||
led_trigger_unregister(local->rx_led);
|
||||
kfree(local->rx_led);
|
||||
}
|
||||
}
|
||||
|
||||
char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
if (local->tx_led)
|
||||
return local->tx_led_name;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
|
||||
|
||||
char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
if (local->rx_led)
|
||||
return local->rx_led_name;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/leds.h>
|
||||
#include "ieee80211_i.h"
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
extern void ieee80211_led_rx(struct ieee80211_local *local);
|
||||
extern void ieee80211_led_tx(struct ieee80211_local *local, int q);
|
||||
extern void ieee80211_led_init(struct ieee80211_local *local);
|
||||
extern void ieee80211_led_exit(struct ieee80211_local *local);
|
||||
#else
|
||||
static inline void ieee80211_led_rx(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_tx(struct ieee80211_local *local, int q)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_init(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_exit(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include "ieee80211_rate.h"
|
||||
#include "ieee80211_i.h"
|
||||
|
||||
struct rate_control_alg {
|
||||
struct list_head list;
|
||||
struct rate_control_ops *ops;
|
||||
};
|
||||
|
||||
static LIST_HEAD(rate_ctrl_algs);
|
||||
static DEFINE_MUTEX(rate_ctrl_mutex);
|
||||
|
||||
int ieee80211_rate_control_register(struct rate_control_ops *ops)
|
||||
{
|
||||
struct rate_control_alg *alg;
|
||||
|
||||
alg = kmalloc(sizeof(*alg), GFP_KERNEL);
|
||||
if (alg == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(alg, 0, sizeof(*alg));
|
||||
alg->ops = ops;
|
||||
|
||||
mutex_lock(&rate_ctrl_mutex);
|
||||
list_add_tail(&alg->list, &rate_ctrl_algs);
|
||||
mutex_unlock(&rate_ctrl_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_rate_control_register);
|
||||
|
||||
void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
|
||||
{
|
||||
struct rate_control_alg *alg;
|
||||
|
||||
mutex_lock(&rate_ctrl_mutex);
|
||||
list_for_each_entry(alg, &rate_ctrl_algs, list) {
|
||||
if (alg->ops == ops) {
|
||||
list_del(&alg->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&rate_ctrl_mutex);
|
||||
kfree(alg);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_rate_control_unregister);
|
||||
|
||||
static struct rate_control_ops *
|
||||
ieee80211_try_rate_control_ops_get(const char *name)
|
||||
{
|
||||
struct rate_control_alg *alg;
|
||||
struct rate_control_ops *ops = NULL;
|
||||
|
||||
mutex_lock(&rate_ctrl_mutex);
|
||||
list_for_each_entry(alg, &rate_ctrl_algs, list) {
|
||||
if (!name || !strcmp(alg->ops->name, name))
|
||||
if (try_module_get(alg->ops->module)) {
|
||||
ops = alg->ops;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&rate_ctrl_mutex);
|
||||
return ops;
|
||||
}
|
||||
|
||||
/* Get the rate control algorithm. If `name' is NULL, get the first
|
||||
* available algorithm. */
|
||||
static struct rate_control_ops *
|
||||
ieee80211_rate_control_ops_get(const char *name)
|
||||
{
|
||||
struct rate_control_ops *ops;
|
||||
|
||||
ops = ieee80211_try_rate_control_ops_get(name);
|
||||
if (!ops) {
|
||||
request_module("rc80211_%s", name ? name : "default");
|
||||
ops = ieee80211_try_rate_control_ops_get(name);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
|
||||
{
|
||||
module_put(ops->module);
|
||||
}
|
||||
|
||||
struct rate_control_ref *rate_control_alloc(const char *name,
|
||||
struct ieee80211_local *local)
|
||||
{
|
||||
struct rate_control_ref *ref;
|
||||
|
||||
ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
|
||||
if (!ref)
|
||||
goto fail_ref;
|
||||
kref_init(&ref->kref);
|
||||
ref->ops = ieee80211_rate_control_ops_get(name);
|
||||
if (!ref->ops)
|
||||
goto fail_ops;
|
||||
ref->priv = ref->ops->alloc(local);
|
||||
if (!ref->priv)
|
||||
goto fail_priv;
|
||||
return ref;
|
||||
|
||||
fail_priv:
|
||||
ieee80211_rate_control_ops_put(ref->ops);
|
||||
fail_ops:
|
||||
kfree(ref);
|
||||
fail_ref:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rate_control_release(struct kref *kref)
|
||||
{
|
||||
struct rate_control_ref *ctrl_ref;
|
||||
|
||||
ctrl_ref = container_of(kref, struct rate_control_ref, kref);
|
||||
ctrl_ref->ops->free(ctrl_ref->priv);
|
||||
ieee80211_rate_control_ops_put(ctrl_ref->ops);
|
||||
kfree(ctrl_ref);
|
||||
}
|
||||
|
||||
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
|
||||
{
|
||||
kref_get(&ref->kref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
void rate_control_put(struct rate_control_ref *ref)
|
||||
{
|
||||
kref_put(&ref->kref, rate_control_release);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005, Devicescape Software, Inc.
|
||||
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
|
||||
*
|
||||
* 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 IEEE80211_RATE_H
|
||||
#define IEEE80211_RATE_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "sta_info.h"
|
||||
|
||||
#define RATE_CONTROL_NUM_DOWN 20
|
||||
#define RATE_CONTROL_NUM_UP 15
|
||||
|
||||
|
||||
struct rate_control_extra {
|
||||
/* values from rate_control_get_rate() to the caller: */
|
||||
struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
|
||||
* probing */
|
||||
struct ieee80211_rate *nonerp;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
|
||||
struct rate_control_ops {
|
||||
struct module *module;
|
||||
const char *name;
|
||||
void (*tx_status)(void *priv, struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_tx_status *status);
|
||||
struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct rate_control_extra *extra);
|
||||
void (*rate_init)(void *priv, void *priv_sta,
|
||||
struct ieee80211_local *local, struct sta_info *sta);
|
||||
void (*clear)(void *priv);
|
||||
|
||||
void *(*alloc)(struct ieee80211_local *local);
|
||||
void (*free)(void *priv);
|
||||
void *(*alloc_sta)(void *priv, gfp_t gfp);
|
||||
void (*free_sta)(void *priv, void *priv_sta);
|
||||
|
||||
int (*add_attrs)(void *priv, struct kobject *kobj);
|
||||
void (*remove_attrs)(void *priv, struct kobject *kobj);
|
||||
};
|
||||
|
||||
struct rate_control_ref {
|
||||
struct rate_control_ops *ops;
|
||||
void *priv;
|
||||
struct kref kref;
|
||||
};
|
||||
|
||||
int ieee80211_rate_control_register(struct rate_control_ops *ops);
|
||||
void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
|
||||
|
||||
/* Get a reference to the rate control algorithm. If `name' is NULL, get the
|
||||
* first available algorithm. */
|
||||
struct rate_control_ref *rate_control_alloc(const char *name,
|
||||
struct ieee80211_local *local);
|
||||
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
|
||||
void rate_control_put(struct rate_control_ref *ref);
|
||||
|
||||
static inline void rate_control_tx_status(struct ieee80211_local *local,
|
||||
struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_tx_status *status)
|
||||
{
|
||||
struct rate_control_ref *ref = local->rate_ctrl;
|
||||
ref->ops->tx_status(ref->priv, dev, skb, status);
|
||||
}
|
||||
|
||||
|
||||
static inline struct ieee80211_rate *
|
||||
rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev,
|
||||
struct sk_buff *skb, struct rate_control_extra *extra)
|
||||
{
|
||||
struct rate_control_ref *ref = local->rate_ctrl;
|
||||
return ref->ops->get_rate(ref->priv, dev, skb, extra);
|
||||
}
|
||||
|
||||
|
||||
static inline void rate_control_rate_init(struct sta_info *sta,
|
||||
struct ieee80211_local *local)
|
||||
{
|
||||
struct rate_control_ref *ref = sta->rate_ctrl;
|
||||
ref->ops->rate_init(ref->priv, sta->rate_ctrl_priv, local, sta);
|
||||
}
|
||||
|
||||
|
||||
static inline void rate_control_clear(struct ieee80211_local *local)
|
||||
{
|
||||
struct rate_control_ref *ref = local->rate_ctrl;
|
||||
ref->ops->clear(ref->priv);
|
||||
}
|
||||
|
||||
static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
|
||||
gfp_t gfp)
|
||||
{
|
||||
return ref->ops->alloc_sta(ref->priv, gfp);
|
||||
}
|
||||
|
||||
static inline void rate_control_free_sta(struct rate_control_ref *ref,
|
||||
void *priv)
|
||||
{
|
||||
ref->ops->free_sta(ref->priv, priv);
|
||||
}
|
||||
|
||||
#endif /* IEEE80211_RATE_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user