Commit f0706e82 authored by Jiri Benc's avatar Jiri Benc Committed by David S. Miller

[MAC80211]: Add mac80211 wireless stack.

Add mac80211, the IEEE 802.11 software MAC layer.
Signed-off-by: default avatarJiri Benc <jbenc@suse.cz>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a9de8ce0
This diff is collapsed.
......@@ -220,6 +220,7 @@ config FIB_RULES
menu "Wireless"
source "net/wireless/Kconfig"
source "net/mac80211/Kconfig"
source "net/ieee80211/Kconfig"
endmenu
......
......@@ -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/
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.
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)
/*
* 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);
}
/*
* 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 */
/*
* 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 */
This diff is collapsed.
/*
* 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,
};
/*
* mac80211 configuration hooks for cfg80211
*/
#ifndef __IEEE80211_CFG_H
#define __IEEE80211_CFG_H
extern struct cfg80211_ops mac80211_config_ops;
#endif /* __IEEE80211_CFG_H */
/*
* 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 */
This diff is collapsed.
/*
* 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