Commit 697455ce authored by Philipp Hortmann's avatar Philipp Hortmann Committed by Greg Kroah-Hartman

staging: rtl8192u: Remove broken driver

Tests on rtl8192u hardware have shown that this driver is broken since
2016. Remove broken driver. Find fix for two bugs in second link.

Link: https://lore.kernel.org/lkml/db98d9ac-7650-4a72-8eb9-4def1f17ea0d@app.fastmail.com/
Link: https://lore.kernel.org/lkml/cover.1697089416.git.philipp.g.hortmann@gmail.com/Signed-off-by: default avatarPhilipp Hortmann <philipp.g.hortmann@gmail.com>
Link: https://lore.kernel.org/r/20231014211051.GA29518@matrix-ESPRIMO-P710Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a7e79e2b
......@@ -28,8 +28,6 @@ source "drivers/staging/wlan-ng/Kconfig"
source "drivers/staging/olpc_dcon/Kconfig"
source "drivers/staging/rtl8192u/Kconfig"
source "drivers/staging/rtl8192e/Kconfig"
source "drivers/staging/rtl8723bs/Kconfig"
......
# SPDX-License-Identifier: GPL-2.0
config RTL8192U
tristate "RealTek RTL8192U Wireless LAN NIC driver"
depends on PCI && WLAN && USB
depends on m
select WIRELESS_EXT
select WEXT_PRIV
select CRC32
select CRYPTO
select CRYPTO_AES
select CRYPTO_CCM
select CRYPTO_LIB_ARC4
# SPDX-License-Identifier: GPL-2.0
NIC_SELECT = RTL8192U
ccflags-y += -DCONFIG_FORCE_HARD_FLOAT=y
ccflags-y += -DJACKSON_NEW_8187 -DJACKSON_NEW_RX
ccflags-y += -DTHOMAS_BEACON -DTHOMAS_TASKLET -DTHOMAS_SKB -DTHOMAS_TURBO
r8192u_usb-y := r8192U_core.o r8180_93cx6.o r8192U_wx.o \
r8190_rtl8256.o r819xU_phy.o r819xU_firmware.o \
r819xU_cmdpkt.o r8192U_dm.o r819xU_firmware_img.o \
r8192U_debugfs.o \
ieee80211/ieee80211_crypt.o \
ieee80211/ieee80211_crypt_tkip.o \
ieee80211/ieee80211_crypt_ccmp.o \
ieee80211/ieee80211_crypt_wep.o \
ieee80211/ieee80211_rx.o \
ieee80211/ieee80211_softmac.o \
ieee80211/ieee80211_tx.o \
ieee80211/ieee80211_wx.o \
ieee80211/ieee80211_module.o \
ieee80211/ieee80211_softmac_wx.o \
ieee80211/rtl819x_HTProc.o \
ieee80211/rtl819x_TSProc.o \
ieee80211/rtl819x_BAProc.o \
ieee80211/dot11d.o
obj-$(CONFIG_RTL8192U) += r8192u_usb.o
To-do list:
* Correct the coding style according to Linux guidelines; please read the document
at https://www.kernel.org/doc/html/latest/process/coding-style.html.
* Remove unnecessary debugging/printing macros; for those that are still needed
use the proper kernel API (pr_debug(), dev_dbg(), netdev_dbg()).
* Remove dead code such as unusued functions, variables, fields, etc..
* Use in-kernel API and remove unnecessary wrappers where possible.
* Fix bugs due to code that sleeps in atomic context.
* Remove the HAL layer and migrate its functionality into the relevant parts of
the driver.
* Switch to use LIB80211.
* Switch to use MAC80211.
* Switch to use CFG80211.
* Improve the error handling of various functions, particularly those that use
existing kernel APIs.
Andrea Merello <andrea.merello@gmail.com>
v 0.1
First version.
This is based on the rtl8180-sa2400 pre-0.22-CVS code..
// SPDX-License-Identifier: GPL-2.0
/* Implement 802.11d. */
#include "dot11d.h"
void rtl8192u_dot11d_init(struct ieee80211_device *ieee)
{
struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
dot11d_info->dot11d_enabled = false;
dot11d_info->state = DOT11D_STATE_NONE;
dot11d_info->country_ie_len = 0;
memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
RESET_CIE_WATCHDOG(ieee);
}
EXPORT_SYMBOL(rtl8192u_dot11d_init);
/* Reset to the state as we are just entering a regulatory domain. */
void dot11d_reset(struct ieee80211_device *ieee)
{
u32 i;
struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
/* Clear old channel map */
memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
/* Set new channel map */
for (i = 1; i <= 11; i++)
(dot11d_info->channel_map)[i] = 1;
for (i = 12; i <= 14; i++)
(dot11d_info->channel_map)[i] = 2;
dot11d_info->state = DOT11D_STATE_NONE;
dot11d_info->country_ie_len = 0;
RESET_CIE_WATCHDOG(ieee);
}
EXPORT_SYMBOL(dot11d_reset);
/*
* Update country IE from Beacon or Probe Resopnse and configure PHY for
* operation in the regulatory domain.
*
* TODO: Configure Tx power.
* Assumption:
* 1. IS_DOT11D_ENABLE() is TRUE.
* 2. Input IE is an valid one.
*/
void dot11d_update_country_ie(struct ieee80211_device *dev, u8 *pTaddr,
u16 CoutryIeLen, u8 *pCoutryIe)
{
struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
u8 i, j, NumTriples, MaxChnlNum;
struct chnl_txpower_triple *pTriple;
memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
MaxChnlNum = 0;
NumTriples = (CoutryIeLen - 3) / 3; /* skip 3-byte country string. */
pTriple = (struct chnl_txpower_triple *)(pCoutryIe + 3);
for (i = 0; i < NumTriples; i++) {
if (MaxChnlNum >= pTriple->first_channel) {
/* It is not in a monotonically increasing order, so
* stop processing.
*/
netdev_err(dev->dev, "%s: Invalid country IE, skip it 1\n", __func__);
return;
}
if (MAX_CHANNEL_NUMBER < (pTriple->first_channel + pTriple->num_channels)) {
/* It is not a valid set of channel id, so stop
* processing.
*/
netdev_err(dev->dev, "%s: Invalid country IE, skip it 2\n", __func__);
return;
}
for (j = 0; j < pTriple->num_channels; j++) {
dot11d_info->channel_map[pTriple->first_channel + j] = 1;
dot11d_info->max_tx_pwr_dbm_list[pTriple->first_channel + j] = pTriple->max_tx_pwr_dbm;
MaxChnlNum = pTriple->first_channel + j;
}
pTriple = (struct chnl_txpower_triple *)((u8 *)pTriple + 3);
}
netdev_info(dev->dev, "Channel List:");
for (i = 1; i <= MAX_CHANNEL_NUMBER; i++)
if (dot11d_info->channel_map[i] > 0)
netdev_info(dev->dev, " %d", i);
netdev_info(dev->dev, "\n");
UPDATE_CIE_SRC(dev, pTaddr);
dot11d_info->country_ie_len = CoutryIeLen;
memcpy(dot11d_info->country_ie_buf, pCoutryIe, CoutryIeLen);
dot11d_info->state = DOT11D_STATE_LEARNED;
}
EXPORT_SYMBOL(dot11d_update_country_ie);
u8 dot11d_get_max_tx_pwr_in_dbm(struct ieee80211_device *dev, u8 Channel)
{
struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
u8 MaxTxPwrInDbm = 255;
if (Channel > MAX_CHANNEL_NUMBER) {
netdev_err(dev->dev, "%s: Invalid Channel\n", __func__);
return MaxTxPwrInDbm;
}
if (dot11d_info->channel_map[Channel])
MaxTxPwrInDbm = dot11d_info->max_tx_pwr_dbm_list[Channel];
return MaxTxPwrInDbm;
}
EXPORT_SYMBOL(dot11d_get_max_tx_pwr_in_dbm);
void dot11d_scan_complete(struct ieee80211_device *dev)
{
struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
switch (dot11d_info->state) {
case DOT11D_STATE_LEARNED:
dot11d_info->state = DOT11D_STATE_DONE;
break;
case DOT11D_STATE_DONE:
if (GET_CIE_WATCHDOG(dev) == 0) {
/* Reset country IE if previous one is gone. */
dot11d_reset(dev);
}
break;
case DOT11D_STATE_NONE:
break;
}
}
EXPORT_SYMBOL(dot11d_scan_complete);
int is_legal_channel(struct ieee80211_device *dev, u8 channel)
{
struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
if (channel > MAX_CHANNEL_NUMBER) {
netdev_err(dev->dev, "%s: Invalid Channel\n", __func__);
return 0;
}
if (dot11d_info->channel_map[channel] > 0)
return 1;
return 0;
}
EXPORT_SYMBOL(is_legal_channel);
int to_legal_channel(struct ieee80211_device *dev, u8 channel)
{
struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
u8 default_chn = 0;
u32 i = 0;
for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) {
if (dot11d_info->channel_map[i] > 0) {
default_chn = i;
break;
}
}
if (channel > MAX_CHANNEL_NUMBER) {
netdev_err(dev->dev, "%s: Invalid Channel\n", __func__);
return default_chn;
}
if (dot11d_info->channel_map[channel] > 0)
return channel;
return default_chn;
}
EXPORT_SYMBOL(to_legal_channel);
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __INC_DOT11D_H
#define __INC_DOT11D_H
#include "ieee80211.h"
struct chnl_txpower_triple {
u8 first_channel;
u8 num_channels;
u8 max_tx_pwr_dbm;
};
enum dot11d_state {
DOT11D_STATE_NONE = 0,
DOT11D_STATE_LEARNED,
DOT11D_STATE_DONE,
};
struct rt_dot11d_info {
u16 country_ie_len; /* > 0 if country_ie_buf[] contains valid country information element. */
/* country_ie_src_addr u16 aligned for comparison and copy */
u8 country_ie_src_addr[ETH_ALEN]; /* Source AP of the country IE. */
u8 country_ie_buf[MAX_IE_LEN];
u8 country_ie_watchdog;
u8 channel_map[MAX_CHANNEL_NUMBER + 1]; /* !Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) */
u8 max_tx_pwr_dbm_list[MAX_CHANNEL_NUMBER + 1];
enum dot11d_state state;
u8 dot11d_enabled; /* dot11MultiDomainCapabilityEnabled */
};
#define GET_DOT11D_INFO(ieee_dev) ((struct rt_dot11d_info *)((ieee_dev)->dot11d_info))
#define IS_DOT11D_ENABLE(ieee_dev) (GET_DOT11D_INFO(ieee_dev)->dot11d_enabled)
#define IS_COUNTRY_IE_VALID(ieee_dev) (GET_DOT11D_INFO(ieee_dev)->country_ie_len > 0)
#define IS_EQUAL_CIE_SRC(ieee_dev, addr) ether_addr_equal(GET_DOT11D_INFO(ieee_dev)->country_ie_src_addr, addr)
#define UPDATE_CIE_SRC(ieee_dev, addr) ether_addr_copy(GET_DOT11D_INFO(ieee_dev)->country_ie_src_addr, addr)
#define GET_CIE_WATCHDOG(ieee_dev) (GET_DOT11D_INFO(ieee_dev)->country_ie_watchdog)
#define RESET_CIE_WATCHDOG(ieee_dev) (GET_CIE_WATCHDOG(ieee_dev) = 0)
#define UPDATE_CIE_WATCHDOG(ieee_dev) (++GET_CIE_WATCHDOG(ieee_dev))
void rtl8192u_dot11d_init(struct ieee80211_device *dev);
void dot11d_reset(struct ieee80211_device *dev);
void dot11d_update_country_ie(struct ieee80211_device *dev,
u8 *addr,
u16 coutry_ie_len,
u8 *coutry_ie);
u8 dot11d_get_max_tx_pwr_in_dbm(struct ieee80211_device *dev, u8 channel);
void dot11d_scan_complete(struct ieee80211_device *dev);
int is_legal_channel(struct ieee80211_device *dev, u8 channel);
int to_legal_channel(struct ieee80211_device *dev, u8 channel);
#endif /* #ifndef __INC_DOT11D_H */
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Host AP crypto routines
*
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include "ieee80211.h"
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("HostAP crypto");
MODULE_LICENSE("GPL");
struct ieee80211_crypto_alg {
struct list_head list;
struct ieee80211_crypto_ops *ops;
};
struct ieee80211_crypto {
struct list_head algs;
spinlock_t lock;
};
static struct ieee80211_crypto *hcrypt;
void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee,
int force)
{
struct list_head *ptr, *n;
struct ieee80211_crypt_data *entry;
for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
entry = list_entry(ptr, struct ieee80211_crypt_data, list);
if (atomic_read(&entry->refcnt) != 0 && !force)
continue;
list_del(ptr);
if (entry->ops)
entry->ops->deinit(entry->priv);
kfree(entry);
}
}
void ieee80211_crypt_deinit_handler(struct timer_list *t)
{
struct ieee80211_device *ieee = from_timer(ieee, t, crypt_deinit_timer);
unsigned long flags;
spin_lock_irqsave(&ieee->lock, flags);
ieee80211_crypt_deinit_entries(ieee, 0);
if (!list_empty(&ieee->crypt_deinit_list)) {
netdev_dbg(ieee->dev, "%s: entries remaining in delayed crypt deletion list\n",
ieee->dev->name);
ieee->crypt_deinit_timer.expires = jiffies + HZ;
add_timer(&ieee->crypt_deinit_timer);
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
struct ieee80211_crypt_data **crypt)
{
struct ieee80211_crypt_data *tmp;
unsigned long flags;
if (!(*crypt))
return;
tmp = *crypt;
*crypt = NULL;
/* must not run ops->deinit() while there may be pending encrypt or
* decrypt operations. Use a list of delayed deinits to avoid needing
* locking.
*/
spin_lock_irqsave(&ieee->lock, flags);
list_add(&tmp->list, &ieee->crypt_deinit_list);
if (!timer_pending(&ieee->crypt_deinit_timer)) {
ieee->crypt_deinit_timer.expires = jiffies + HZ;
add_timer(&ieee->crypt_deinit_timer);
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops)
{
unsigned long flags;
struct ieee80211_crypto_alg *alg;
if (!hcrypt)
return -1;
alg = kzalloc(sizeof(*alg), GFP_KERNEL);
if (!alg)
return -ENOMEM;
alg->ops = ops;
spin_lock_irqsave(&hcrypt->lock, flags);
list_add(&alg->list, &hcrypt->algs);
spin_unlock_irqrestore(&hcrypt->lock, flags);
pr_debug("ieee80211_crypt: registered algorithm '%s'\n",
ops->name);
return 0;
}
int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops)
{
unsigned long flags;
struct list_head *ptr;
struct ieee80211_crypto_alg *del_alg = NULL;
if (!hcrypt)
return -1;
spin_lock_irqsave(&hcrypt->lock, flags);
for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
struct ieee80211_crypto_alg *alg =
(struct ieee80211_crypto_alg *)ptr;
if (alg->ops == ops) {
list_del(&alg->list);
del_alg = alg;
break;
}
}
spin_unlock_irqrestore(&hcrypt->lock, flags);
if (del_alg) {
pr_debug("ieee80211_crypt: unregistered algorithm '%s'\n",
ops->name);
kfree(del_alg);
}
return del_alg ? 0 : -1;
}
struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
{
unsigned long flags;
struct list_head *ptr;
struct ieee80211_crypto_alg *found_alg = NULL;
if (!hcrypt)
return NULL;
spin_lock_irqsave(&hcrypt->lock, flags);
for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
struct ieee80211_crypto_alg *alg =
(struct ieee80211_crypto_alg *)ptr;
if (strcmp(alg->ops->name, name) == 0) {
found_alg = alg;
break;
}
}
spin_unlock_irqrestore(&hcrypt->lock, flags);
if (found_alg)
return found_alg->ops;
return NULL;
}
static void *ieee80211_crypt_null_init(int keyidx) { return (void *)1; }
static void ieee80211_crypt_null_deinit(void *priv) {}
static struct ieee80211_crypto_ops ieee80211_crypt_null = {
.name = "NULL",
.init = ieee80211_crypt_null_init,
.deinit = ieee80211_crypt_null_deinit,
.encrypt_mpdu = NULL,
.decrypt_mpdu = NULL,
.encrypt_msdu = NULL,
.decrypt_msdu = NULL,
.set_key = NULL,
.get_key = NULL,
.extra_prefix_len = 0,
.extra_postfix_len = 0,
.owner = THIS_MODULE,
};
int __init ieee80211_crypto_init(void)
{
int ret = -ENOMEM;
hcrypt = kzalloc(sizeof(*hcrypt), GFP_KERNEL);
if (!hcrypt)
goto out;
INIT_LIST_HEAD(&hcrypt->algs);
spin_lock_init(&hcrypt->lock);
ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null);
if (ret < 0) {
kfree(hcrypt);
hcrypt = NULL;
}
out:
return ret;
}
void ieee80211_crypto_deinit(void)
{
struct list_head *ptr, *n;
if (!hcrypt)
return;
for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
ptr = n, n = ptr->next) {
struct ieee80211_crypto_alg *alg =
(struct ieee80211_crypto_alg *)ptr;
list_del(ptr);
pr_debug("ieee80211_crypt: unregistered algorithm '%s' (deinit)\n",
alg->ops->name);
kfree(alg);
}
kfree(hcrypt);
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Original code based on Host AP (software wireless LAN access point) driver
* for Intersil Prism2/2.5/3.
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
*
* Adaption to a generic IEEE 802.11 stack by James Ketrenos
* <jketreno@linux.intel.com>
*
* Copyright (c) 2004, Intel Corporation
*/
/*
* This file defines the interface to the ieee80211 crypto module.
*/
#ifndef IEEE80211_CRYPT_H
#define IEEE80211_CRYPT_H
#include <linux/skbuff.h>
struct ieee80211_crypto_ops {
const char *name;
/* init new crypto context (e.g., allocate private data space,
* select IV, etc.); returns NULL on failure or pointer to allocated
* private data on success
*/
void * (*init)(int keyidx);
/* deinitialize crypto context and free allocated private data */
void (*deinit)(void *priv);
/* encrypt/decrypt return < 0 on error or >= 0 on success. The return
* value from decrypt_mpdu is passed as the keyidx value for
* decrypt_msdu. skb must have enough head and tail room for the
* encryption; if not, error will be returned; these functions are
* called for all MPDUs (i.e., fragments).
*/
int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv);
int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv);
/* These functions are called for full MSDUs, i.e. full frames.
* These can be NULL if full MSDU operations are not needed.
*/
int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv);
int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len,
void *priv);
int (*set_key)(void *key, int len, u8 *seq, void *priv);
int (*get_key)(void *key, int len, u8 *seq, void *priv);
/* procfs handler for printing out key information and possible
* statistics
*/
char * (*print_stats)(char *p, void *priv);
/* maximum number of bytes added by encryption; encrypt buf is
* allocated with extra_prefix_len bytes, copy of in_buf, and
* extra_postfix_len; encrypt need not use all this space, but
* the result must start at the beginning of the buffer and correct
* length must be returned
*/
int extra_prefix_len, extra_postfix_len;
struct module *owner;
};
struct ieee80211_crypt_data {
struct list_head list; /* delayed deletion list */
struct ieee80211_crypto_ops *ops;
void *priv;
atomic_t refcnt;
};
int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops);
int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops);
struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name);
void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force);
void ieee80211_crypt_deinit_handler(struct timer_list *t);
void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
struct ieee80211_crypt_data **crypt);
#endif
// SPDX-License-Identifier: GPL-2.0
/*
* Host AP crypt: host-based WEP encryption implementation for Host AP driver
*
* Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
*/
#include <linux/fips.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/string.h>
#include "ieee80211.h"
#include <crypto/arc4.h>
#include <linux/crc32.h>
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP crypt: WEP");
MODULE_LICENSE("GPL");
struct prism2_wep_data {
u32 iv;
#define WEP_KEY_LEN 13
u8 key[WEP_KEY_LEN + 1];
u8 key_len;
u8 key_idx;
struct arc4_ctx rx_ctx_arc4;
struct arc4_ctx tx_ctx_arc4;
};
static void *prism2_wep_init(int keyidx)
{
struct prism2_wep_data *priv;
if (fips_enabled)
return NULL;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return NULL;
priv->key_idx = keyidx;
/* start WEP IV from a random value */
get_random_bytes(&priv->iv, 4);
return priv;
}
static void prism2_wep_deinit(void *priv)
{
kfree_sensitive(priv);
}
/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
* for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
* so the payload length increases with 8 bytes.
*
* WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
*/
static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct prism2_wep_data *wep = priv;
u32 klen, len;
u8 key[WEP_KEY_LEN + 3];
u8 *pos;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
u32 crc;
u8 *icv;
if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
skb->len < hdr_len)
return -1;
len = skb->len - hdr_len;
pos = skb_push(skb, 4);
memmove(pos, pos + 4, hdr_len);
pos += hdr_len;
klen = 3 + wep->key_len;
wep->iv++;
/* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
* scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
* can be used to speedup attacks, so avoid using them.
*/
if ((wep->iv & 0xff00) == 0xff00) {
u8 B = (wep->iv >> 16) & 0xff;
if (B >= 3 && B < klen)
wep->iv += 0x0100;
}
/* Prepend 24-bit IV to RC4 key and TX frame */
*pos++ = key[0] = (wep->iv >> 16) & 0xff;
*pos++ = key[1] = (wep->iv >> 8) & 0xff;
*pos++ = key[2] = wep->iv & 0xff;
*pos++ = wep->key_idx << 6;
/* Copy rest of the WEP key (the secret part) */
memcpy(key + 3, wep->key, wep->key_len);
if (!tcb_desc->bHwSec) {
/* Append little-endian CRC32 and encrypt it to produce ICV */
crc = ~crc32_le(~0, pos, len);
icv = skb_put(skb, 4);
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
arc4_setkey(&wep->tx_ctx_arc4, key, klen);
arc4_crypt(&wep->tx_ctx_arc4, pos, pos, len + 4);
}
return 0;
}
/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
* the frame: IV (4 bytes), encrypted payload (including SNAP header),
* ICV (4 bytes). len includes both IV and ICV.
*
* Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
* failure. If frame is OK, IV and ICV will be removed.
*/
static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct prism2_wep_data *wep = priv;
u32 klen, plen;
u8 key[WEP_KEY_LEN + 3];
u8 keyidx, *pos;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
u32 crc;
u8 icv[4];
if (skb->len < hdr_len + 8)
return -1;
pos = skb->data + hdr_len;
key[0] = *pos++;
key[1] = *pos++;
key[2] = *pos++;
keyidx = *pos++ >> 6;
if (keyidx != wep->key_idx)
return -1;
klen = 3 + wep->key_len;
/* Copy rest of the WEP key (the secret part) */
memcpy(key + 3, wep->key, wep->key_len);
/* Apply RC4 to data and compute CRC32 over decrypted data */
plen = skb->len - hdr_len - 8;
if (!tcb_desc->bHwSec) {
arc4_setkey(&wep->rx_ctx_arc4, key, klen);
arc4_crypt(&wep->rx_ctx_arc4, pos, pos, plen + 4);
crc = ~crc32_le(~0, pos, plen);
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
if (memcmp(icv, pos + plen, 4) != 0) {
/* ICV mismatch - drop frame */
return -2;
}
}
/* Remove IV and ICV */
memmove(skb->data + 4, skb->data, hdr_len);
skb_pull(skb, 4);
skb_trim(skb, skb->len - 4);
return 0;
}
static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
{
struct prism2_wep_data *wep = priv;
if (len < 0 || len > WEP_KEY_LEN)
return -1;
memcpy(wep->key, key, len);
wep->key_len = len;
return 0;
}
static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
{
struct prism2_wep_data *wep = priv;
if (len < wep->key_len)
return 0;
memcpy(key, wep->key, wep->key_len);
return wep->key_len;
}
static char *prism2_wep_print_stats(char *p, void *priv)
{
struct prism2_wep_data *wep = priv;
p += sprintf(p, "key[%d] alg=WEP len=%d\n",
wep->key_idx, wep->key_len);
return p;
}
static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
.name = "WEP",
.init = prism2_wep_init,
.deinit = prism2_wep_deinit,
.encrypt_mpdu = prism2_wep_encrypt,
.decrypt_mpdu = prism2_wep_decrypt,
.encrypt_msdu = NULL,
.decrypt_msdu = NULL,
.set_key = prism2_wep_set_key,
.get_key = prism2_wep_get_key,
.print_stats = prism2_wep_print_stats,
.extra_prefix_len = 4, /* IV */
.extra_postfix_len = 4, /* ICV */
.owner = THIS_MODULE,
};
int __init ieee80211_crypto_wep_init(void)
{
return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
}
void ieee80211_crypto_wep_exit(void)
{
ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
}
// SPDX-License-Identifier: GPL-2.0
/*******************************************************************************
*
* Copyright(c) 2004 Intel Corporation. All rights reserved.
*
* Portions of this file are based on the WEP enablement code provided by the
* Host AP project hostap-drivers v0.1.3
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
*
* Contact Information:
* James P. Ketrenos <ipw2100-admin@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/in6.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/tcp.h>
#include <linux/types.h>
#include <linux/wireless.h>
#include <linux/etherdevice.h>
#include <linux/uaccess.h>
#include <net/arp.h>
#include "ieee80211.h"
MODULE_DESCRIPTION("802.11 data/management/control stack");
MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation <jketreno@linux.intel.com>");
MODULE_LICENSE("GPL");
#define DRV_NAME "ieee80211"
static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
{
if (ieee->networks)
return 0;
ieee->networks = kcalloc(MAX_NETWORK_COUNT,
sizeof(struct ieee80211_network),
GFP_KERNEL);
if (!ieee->networks) {
netdev_warn(ieee->dev, "Out of memory allocating beacons\n");
return -ENOMEM;
}
return 0;
}
static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
{
if (!ieee->networks)
return;
kfree(ieee->networks);
ieee->networks = NULL;
}
static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
{
int i;
INIT_LIST_HEAD(&ieee->network_free_list);
INIT_LIST_HEAD(&ieee->network_list);
for (i = 0; i < MAX_NETWORK_COUNT; i++)
list_add_tail(&ieee->networks[i].list, &ieee->network_free_list);
}
struct net_device *alloc_ieee80211(int sizeof_priv)
{
struct ieee80211_device *ieee;
struct net_device *dev;
int i, err;
IEEE80211_DEBUG_INFO("Initializing...\n");
dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
if (!dev) {
IEEE80211_ERROR("Unable to network device.\n");
goto failed;
}
ieee = netdev_priv(dev);
ieee->dev = dev;
err = ieee80211_networks_allocate(ieee);
if (err) {
IEEE80211_ERROR("Unable to allocate beacon storage: %d\n",
err);
goto failed;
}
ieee80211_networks_initialize(ieee);
/* Default fragmentation threshold is maximum payload size */
ieee->fts = DEFAULT_FTS;
ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
ieee->open_wep = 1;
/* Default to enabling full open WEP with host based encrypt/decrypt */
ieee->host_encrypt = 1;
ieee->host_decrypt = 1;
ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
INIT_LIST_HEAD(&ieee->crypt_deinit_list);
timer_setup(&ieee->crypt_deinit_timer, ieee80211_crypt_deinit_handler,
0);
spin_lock_init(&ieee->lock);
spin_lock_init(&ieee->wpax_suitlist_lock);
spin_lock_init(&ieee->bw_spinlock);
spin_lock_init(&ieee->reorder_spinlock);
/* added by WB */
atomic_set(&ieee->atm_chnlop, 0);
atomic_set(&ieee->atm_swbw, 0);
ieee->wpax_type_set = 0;
ieee->wpa_enabled = 0;
ieee->tkip_countermeasures = 0;
ieee->drop_unencrypted = 0;
ieee->privacy_invoked = 0;
ieee->ieee802_1x = 1;
ieee->raw_tx = 0;
//ieee->hwsec_support = 1; //defalt support hw security. //use module_param instead.
ieee->hwsec_active = 0; /* disable hwsec, switch it on when necessary. */
ieee80211_softmac_init(ieee);
ieee->pHTInfo = kzalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL);
if (!ieee->pHTInfo) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
/* By this point in code ieee80211_networks_allocate() has been
* successfully called so the memory allocated should be freed
*/
ieee80211_networks_free(ieee);
goto failed;
}
HTUpdateDefaultSetting(ieee);
HTInitializeHTInfo(ieee); /* may move to other place. */
TSInitialize(ieee);
for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++)
INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]);
for (i = 0; i < 17; i++) {
ieee->last_rxseq_num[i] = -1;
ieee->last_rxfrag_num[i] = -1;
ieee->last_packet_time[i] = 0;
}
return dev;
failed:
if (dev)
free_netdev(dev);
return NULL;
}
void free_ieee80211(struct net_device *dev)
{
struct ieee80211_device *ieee = netdev_priv(dev);
int i;
/* struct list_head *p, *q; */
// del_timer_sync(&ieee->SwBwTimer);
kfree(ieee->pHTInfo);
ieee->pHTInfo = NULL;
RemoveAllTS(ieee);
ieee80211_softmac_free(ieee);
del_timer_sync(&ieee->crypt_deinit_timer);
ieee80211_crypt_deinit_entries(ieee, 1);
for (i = 0; i < WEP_KEYS; i++) {
struct ieee80211_crypt_data *crypt = ieee->crypt[i];
if (crypt) {
if (crypt->ops)
crypt->ops->deinit(crypt->priv);
kfree(crypt);
ieee->crypt[i] = NULL;
}
}
ieee80211_networks_free(ieee);
free_netdev(dev);
}
#ifdef CONFIG_IEEE80211_DEBUG
u32 ieee80211_debug_level;
static int debug = // IEEE80211_DL_INFO |
// IEEE80211_DL_WX |
// IEEE80211_DL_SCAN |
// IEEE80211_DL_STATE |
// IEEE80211_DL_MGMT |
// IEEE80211_DL_FRAG |
// IEEE80211_DL_EAP |
// IEEE80211_DL_DROP |
// IEEE80211_DL_TX |
// IEEE80211_DL_RX |
//IEEE80211_DL_QOS |
// IEEE80211_DL_HT |
// IEEE80211_DL_TS |
// IEEE80211_DL_BA |
// IEEE80211_DL_REORDER|
// IEEE80211_DL_TRACE |
//IEEE80211_DL_DATA |
IEEE80211_DL_ERR /* awayls open this flags to show error out */
;
static struct proc_dir_entry *ieee80211_proc;
static int show_debug_level(struct seq_file *m, void *v)
{
seq_printf(m, "0x%08X\n", ieee80211_debug_level);
return 0;
}
static ssize_t write_debug_level(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
unsigned long val;
int err = kstrtoul_from_user(buffer, count, 0, &val);
if (err)
return err;
ieee80211_debug_level = val;
return count;
}
static int open_debug_level(struct inode *inode, struct file *file)
{
return single_open(file, show_debug_level, NULL);
}
static const struct proc_ops debug_level_proc_ops = {
.proc_open = open_debug_level,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_write = write_debug_level,
.proc_release = single_release,
};
int __init ieee80211_debug_init(void)
{
struct proc_dir_entry *e;
ieee80211_debug_level = debug;
ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
if (!ieee80211_proc) {
IEEE80211_ERROR("Unable to create " DRV_NAME
" proc directory\n");
return -EIO;
}
e = proc_create("debug_level", 0644, ieee80211_proc, &debug_level_proc_ops);
if (!e) {
remove_proc_entry(DRV_NAME, init_net.proc_net);
ieee80211_proc = NULL;
return -EIO;
}
return 0;
}
void ieee80211_debug_exit(void)
{
if (ieee80211_proc) {
remove_proc_entry("debug_level", ieee80211_proc);
remove_proc_entry(DRV_NAME, init_net.proc_net);
ieee80211_proc = NULL;
}
}
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BATYPE_H_
#define _BATYPE_H_
#define BA_SETUP_TIMEOUT 200
#define BA_POLICY_DELAYED 0
#define BA_POLICY_IMMEDIATE 1
#define ADDBA_STATUS_SUCCESS 0
#define ADDBA_STATUS_REFUSED 37
#define ADDBA_STATUS_INVALID_PARAM 38
#define DELBA_REASON_END_BA 37
#define DELBA_REASON_UNKNOWN_BA 38
#define DELBA_REASON_TIMEOUT 39
union sequence_control {
u16 short_data;
struct {
u16 frag_num:4;
u16 seq_num:12;
} field;
};
union ba_param_set {
u16 short_data;
struct {
u16 amsdu_support:1;
u16 ba_policy:1;
u16 tid:4;
u16 buffer_size:10;
} field;
};
union delba_param_set {
u16 short_data;
struct {
u16 reserved:11;
u16 initiator:1;
u16 tid:4;
} field;
};
struct ba_record {
struct timer_list timer;
u8 valid;
u8 dialog_token;
union ba_param_set param_set;
u16 timeout_value;
union sequence_control start_seq_ctrl;
};
#endif //end _BATYPE_H_
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __INC_QOS_TYPE_H
#define __INC_QOS_TYPE_H
/*
* ACI/AIFSN Field.
* Ref: WMM spec 2.2.2: WME Parameter Element, p.12.
* Note: 1 Byte Length
*/
struct aci_aifsn {
u8 aifsn:4;
u8 acm:1;
u8 aci:2;
u8:1;
};
/*
* Direction Field Values.
* Ref: WMM spec 2.2.11: WME TSPEC Element, p.18.
*/
enum direction_value {
DIR_UP = 0, // 0x00 // UpLink
DIR_DOWN = 1, // 0x01 // DownLink
DIR_DIRECT = 2, // 0x10 // DirectLink
DIR_BI_DIR = 3, // 0x11 // Bi-Direction
};
/*
* TS Info field in WMM TSPEC Element.
* Ref:
* 1. WMM spec 2.2.11: WME TSPEC Element, p.18.
* 2. 8185 QoS code: QOS_TSINFO [def. in QoS_mp.h]
* Note: sizeof 3 Bytes
*/
struct qos_tsinfo {
u16 uc_traffic_type:1; //WMM is reserved
u16 uc_tsid:4;
u16 uc_direction:2;
u16 uc_access_policy:2; //WMM: bit8=0, bit7=1
u16 uc_aggregation:1; //WMM is reserved
u16 uc_psb:1; //WMMSA is APSD
u16 uc_up:3;
u16 uc_ts_info_ack_policy:2; //WMM is reserved
u8 uc_schedule:1; //WMM is reserved
u8:7;
};
/*
* WMM TSPEC Body.
* Ref: WMM spec 2.2.11: WME TSPEC Element, p.16.
* Note: sizeof 55 bytes
*/
struct tspec_body {
struct qos_tsinfo ts_info; //u8 TSInfo[3];
u16 nominal_msd_usize;
u16 max_msd_usize;
u32 min_service_itv;
u32 max_service_itv;
u32 inactivity_itv;
u32 suspen_itv;
u32 service_start_time;
u32 min_data_rate;
u32 mean_data_rate;
u32 peak_data_rate;
u32 max_burst_size;
u32 delay_bound;
u32 min_phy_rate;
u16 surplus_bandwidth_allowance;
u16 medium_time;
};
/*
* 802.11 Management frame Status Code field
*/
struct octet_string {
u8 *octet;
u16 length;
};
#define is_ac_valid(ac) (((ac) <= 7) ? true : false)
#endif // #ifndef __INC_QOS_TYPE_H
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TSTYPE_H_
#define _TSTYPE_H_
#include "rtl819x_Qos.h"
#define TS_ADDBA_DELAY 60
#define TOTAL_TS_NUM 16
#define TCLAS_NUM 4
/* This define the Tx/Rx directions */
enum tr_select {
TX_DIR = 0,
RX_DIR = 1,
};
union qos_tclas {
struct type_general {
u8 priority;
u8 classifier_type;
u8 mask;
} type_general;
struct type0_eth {
u8 priority;
u8 classifier_type;
u8 mask;
u8 src_addr[6];
u8 dst_addr[6];
u16 type;
} type0_eth;
struct type1_ipv4 {
u8 priority;
u8 classifier_type;
u8 mask;
u8 version;
u8 src_ip[4];
u8 dst_ip[4];
u16 src_port;
u16 dst_port;
u8 dscp;
u8 protocol;
u8 reserved;
} type1_ipv4;
struct type1_ipv6 {
u8 priority;
u8 classifier_type;
u8 mask;
u8 version;
u8 src_ip[16];
u8 dst_ip[16];
u16 src_port;
u16 dst_port;
u8 flow_label[3];
} type1_ipv6;
struct type2_8021q {
u8 priority;
u8 classifier_type;
u8 mask;
u16 tag_type;
} type2_8021q;
};
struct ts_common_info {
struct list_head list;
struct timer_list setup_timer;
struct timer_list inact_timer;
u8 addr[6];
struct tspec_body t_spec;
union qos_tclas t_class[TCLAS_NUM];
u8 t_clas_proc;
u8 t_clas_num;
};
struct tx_ts_record {
struct ts_common_info ts_common_info;
u16 tx_cur_seq;
struct ba_record tx_pending_ba_record;
struct ba_record tx_admitted_ba_record;
u8 add_ba_req_in_progress;
u8 add_ba_req_delayed;
u8 using_ba;
struct timer_list ts_add_ba_timer;
u8 num;
};
struct rx_ts_record {
struct ts_common_info ts_common_info;
u16 rx_indicate_seq;
u16 rx_timeout_indicate_seq;
struct list_head rx_pending_pkt_list;
struct timer_list rx_pkt_pending_timer;
struct ba_record rx_admitted_ba_record;
u16 rx_last_seq_num;
u8 rx_last_frag_num;
u8 num;
};
#endif
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is part of rtl8187 OpenSource driver
* Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
* Released under the terms of GPL (General Public Licence)
*
* Parts of this driver are based on the GPL part of the
* official realtek driver
* Parts of this driver are based on the rtl8180 driver skeleton
* from Patric Schenke & Andres Salomon
* Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
*
* We want to thank the Authors of such projects and the Ndiswrapper
* project Authors.
*/
/*This files contains card eeprom (93c46 or 93c56) programming routines*/
/*memory is addressed by WORDS*/
#include "r8192U.h"
#include "r8192U_hw.h"
#define EPROM_DELAY 10
int eprom_read(struct net_device *dev, u32 addr); /* reads a 16 bits word */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is part of the rtl8180-sa2400 driver
* released under the GPL (See file COPYING for details).
* Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
*
*
* This files contains programming code for the rtl8256
* radio frontend.
*
* *Many* thanks to Realtek Corp. for their great support!
*/
#ifndef RTL8225H
#define RTL8225H
#define RTL819X_TOTAL_RF_PATH 2 /* for 8192U */
void phy_set_rf8256_bandwidth(struct net_device *dev,
enum ht_channel_width bandwidth);
void phy_rf8256_config(struct net_device *dev);
void phy_set_rf8256_cck_tx_power(struct net_device *dev, u8 powerlevel);
void phy_set_rf8256_ofdm_tx_power(struct net_device *dev, u8 powerlevel);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is part of rtl8180 OpenSource driver - v 0.3
* Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com>
*
* Parts of this driver are based on the GPL part of the official realtek driver
* Parts of this driver are based on the rtl8180 driver skeleton from Patric
* Schenke & Andres Salomon
* Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
*
* We want to thank the Authors of such projects and the Ndiswrapper project
* Authors.
*/
/* this file (will) contains wireless extension handlers */
#ifndef R8180_WX_H
#define R8180_WX_H
extern const struct iw_handler_def r8192_wx_handlers_def;
/* Enable the rtl819x_core.c to share this function, david 2008.9.22 */
struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment