Staging: add rtl8187se driver

This is a driver for the Realtek 8187 "SE" wireless PCI devices in some
netbook computers (MSI Wind, and others).  It includes its own copy of
the ieee80211 stack, but it is compiled into the driver to prevend
duplicate symbol issues.

This version comes from Ralink with no authorship, but it is based
on an old version of the rtl8180 driver from Andrea Merello.  It was
hacked up a bit to get it to build properly within the kernel tree and
to properly handle the merged wireless stack within the driver.

Cc: Andrea Merello <andreamrl@tiscali.it>
Cc: linux-wireless <linux-wireless@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Greg Kroah-Hartman 2008-12-04 20:01:41 -08:00
parent c8801d8c9f
commit c8d86be387
59 changed files with 38287 additions and 0 deletions

View File

@ -81,5 +81,7 @@ source "drivers/staging/panel/Kconfig"
source "drivers/staging/altpciechdma/Kconfig"
source "drivers/staging/rtl8187se/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING

View File

@ -23,3 +23,4 @@ obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_ASUS_OLED) += asus_oled/
obj-$(CONFIG_PANEL) += panel/
obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/
obj-$(CONFIG_RTL8187SE) += rtl8187se/

View File

@ -0,0 +1,5 @@
config RTL8187SE
tristate "RealTek RTL8187SE Wireless LAN NIC driver"
depends on PCI
default N
---help---

View File

@ -0,0 +1,54 @@
#EXTRA_CFLAGS += -DCONFIG_IEEE80211_NOWEP=y
#EXTRA_CFLAGS += -DCONFIG_RTL8180_IOMAP
#EXTRA_CFLAGS += -std=gnu89
#EXTRA_CFLAGS += -O2
#CC = gcc
EXTRA_CFLAGS += -DTHOMAS_TURBO
#CFLAGS += -DCONFIG_RTL8185B
#CFLAGS += -DCONFIG_RTL818x_S
#added for EeePC testing
EXTRA_CFLAGS += -DENABLE_IPS
EXTRA_CFLAGS += -DSW_ANTE
EXTRA_CFLAGS += -DTX_TRACK
EXTRA_CFLAGS += -DHIGH_POWER
EXTRA_CFLAGS += -DSW_DIG
EXTRA_CFLAGS += -DRATE_ADAPT
EXTRA_CFLAGS += -DCONFIG_RTL8180_PM
#+YJ,080626
EXTRA_CFLAGS += -DENABLE_DOT11D
#enable it for legacy power save, disable it for leisure power save
EXTRA_CFLAGS += -DENABLE_LPS
#EXTRA_CFLAGS += -mhard-float -DCONFIG_FORCE_HARD_FLOAT=y
r8187se-objs := r8180_core.o \
r8180_sa2400.o \
r8180_93cx6.o \
r8180_wx.o \
r8180_max2820.o \
r8180_gct.o \
r8180_rtl8225.o \
r8180_rtl8255.o \
r8180_rtl8225z2.o \
r8185b_init.o \
r8180_dm.o \
r8180_pm.o \
ieee80211/dot11d.o \
ieee80211/ieee80211_softmac.o \
ieee80211/ieee80211_rx.o \
ieee80211/ieee80211_tx.o \
ieee80211/ieee80211_wx.o \
ieee80211/ieee80211_module.o \
ieee80211/ieee80211_softmac_wx.o \
ieee80211/ieee80211_crypt.o \
ieee80211/ieee80211_crypt_tkip.o \
ieee80211/ieee80211_crypt_ccmp.o \
ieee80211/ieee80211_crypt_wep.o
obj-$(CONFIG_RTL8187SE) += r8187se.o

View File

@ -0,0 +1,101 @@
#ifndef __INC_DOT11D_H
#define __INC_DOT11D_H
#include "ieee80211.h"
//#define ENABLE_DOT11D
//#define DOT11D_MAX_CHNL_NUM 83
typedef struct _CHNL_TXPOWER_TRIPLE {
u8 FirstChnl;
u8 NumChnls;
u8 MaxTxPowerInDbm;
}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
typedef enum _DOT11D_STATE {
DOT11D_STATE_NONE = 0,
DOT11D_STATE_LEARNED,
DOT11D_STATE_DONE,
}DOT11D_STATE;
typedef struct _RT_DOT11D_INFO {
//DECLARE_RT_OBJECT(RT_DOT11D_INFO);
bool bEnabled; // dot11MultiDomainCapabilityEnabled
u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element.
u8 CountryIeBuf[MAX_IE_LEN];
u8 CountryIeSrcAddr[6]; // Source AP of the country IE.
u8 CountryIeWatchdog;
u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan)
//u8 ChnlListLen; // #Bytes valid in ChnlList[].
//u8 ChnlList[DOT11D_MAX_CHNL_NUM];
u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
DOT11D_STATE State;
}RT_DOT11D_INFO, *PRT_DOT11D_INFO;
#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo))
#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled
#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0)
#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \
(((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \
FALSE : \
(!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length)))
#define CIE_WATCHDOG_TH 1
#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog
#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0
#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev)
#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE)
void
Dot11d_Init(
struct ieee80211_device *dev
);
void
Dot11d_Reset(
struct ieee80211_device *dev
);
void
Dot11d_UpdateCountryIe(
struct ieee80211_device *dev,
u8 * pTaddr,
u16 CoutryIeLen,
u8 * pCoutryIe
);
u8
DOT11D_GetMaxTxPwrInDbm(
struct ieee80211_device *dev,
u8 Channel
);
void
DOT11D_ScanComplete(
struct ieee80211_device * dev
);
int IsLegalChannel(
struct ieee80211_device * dev,
u8 channel
);
int ToLegalChannel(
struct ieee80211_device * dev,
u8 channel
);
#endif // #ifndef __INC_DOT11D_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
#EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/wireless
#EXTRA_CFLAGS += -O2
EXTRA_CFLAGS += -DTHOMAS_TURBO
EXTRA_CFLAGS += -DENABLE_IPS
ifeq ($(shell uname -r|cut -d. -f1,2,3,4), 2.6.16.60-0)
EXTRA_CFLAGS += -DOPENSUSE_SLED
endif
ifeq ($(shell uname -r|cut -d. -f1,2,3,4), 2.6.26.3-29)
EXTRA_CFLAGS += -DFEDORACORE_9
endif
#+YJ,080626
EXTRA_CFLAGS += -DENABLE_DOT11D
#enable it for legacy power save, disable it for leisure power save
#CFLAGS += -DENABLE_LPS
ieee80211-rtl-objs := dot11d.o ieee80211_softmac.o ieee80211_rx.o ieee80211_tx.o ieee80211_wx.o ieee80211_module.o ieee80211_softmac_wx.o
ieee80211_crypt-rtl-objs := ieee80211_crypt.o
ieee80211_crypt_tkip-rtl-objs := ieee80211_crypt_tkip.o
ieee80211_crypt_ccmp-rtl-objs := ieee80211_crypt_ccmp.o
ieee80211_crypt_wep-rtl-objs := ieee80211_crypt_wep.o
obj-m +=ieee80211-rtl.o
obj-m +=ieee80211_crypt-rtl.o
obj-m +=ieee80211_crypt_wep-rtl.o
obj-m +=ieee80211_crypt_tkip-rtl.o
obj-m +=ieee80211_crypt_ccmp-rtl.o

View File

@ -0,0 +1,469 @@
/*
* Cryptographic API.
*
* AES Cipher Algorithm.
*
* Based on Brian Gladman's code.
*
* Linux developers:
* Alexander Kjeldaas <astor@fast.no>
* Herbert Valerio Riedel <hvr@hvrlab.org>
* Kyle McMartin <kyle@debian.org>
* Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* ---------------------------------------------------------------------------
* Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
* All rights reserved.
*
* LICENSE TERMS
*
* The free distribution and use of this software in both source and binary
* form is allowed (with or without changes) provided that:
*
* 1. distributions of this source code include the above copyright
* notice, this list of conditions and the following disclaimer;
*
* 2. distributions in binary form include the above copyright
* notice, this list of conditions and the following disclaimer
* in the documentation and/or other associated materials;
*
* 3. the copyright holder's name is not used to endorse products
* built using this software without specific written permission.
*
* ALTERNATIVELY, provided that this notice is retained in full, this product
* may be distributed under the terms of the GNU General Public License (GPL),
* in which case the provisions of the GPL apply INSTEAD OF those given above.
*
* DISCLAIMER
*
* This software is provided 'as is' with no explicit or implied warranties
* in respect of its properties, including, but not limited to, correctness
* and/or fitness for purpose.
* ---------------------------------------------------------------------------
*/
/* Some changes from the Gladman version:
s/RIJNDAEL(e_key)/E_KEY/g
s/RIJNDAEL(d_key)/D_KEY/g
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
//#include <linux/crypto.h>
#include "rtl_crypto.h"
#include <asm/byteorder.h>
#define AES_MIN_KEY_SIZE 16
#define AES_MAX_KEY_SIZE 32
#define AES_BLOCK_SIZE 16
static inline
u32 generic_rotr32 (const u32 x, const unsigned bits)
{
const unsigned n = bits % 32;
return (x >> n) | (x << (32 - n));
}
static inline
u32 generic_rotl32 (const u32 x, const unsigned bits)
{
const unsigned n = bits % 32;
return (x << n) | (x >> (32 - n));
}
#define rotl generic_rotl32
#define rotr generic_rotr32
/*
* #define byte(x, nr) ((unsigned char)((x) >> (nr*8)))
*/
inline static u8
byte(const u32 x, const unsigned n)
{
return x >> (n << 3);
}
#define u32_in(x) le32_to_cpu(*(const u32 *)(x))
#define u32_out(to, from) (*(u32 *)(to) = cpu_to_le32(from))
struct aes_ctx {
int key_length;
u32 E[60];
u32 D[60];
};
#define E_KEY ctx->E
#define D_KEY ctx->D
static u8 pow_tab[256] __initdata;
static u8 log_tab[256] __initdata;
static u8 sbx_tab[256] __initdata;
static u8 isb_tab[256] __initdata;
static u32 rco_tab[10];
static u32 ft_tab[4][256];
static u32 it_tab[4][256];
static u32 fl_tab[4][256];
static u32 il_tab[4][256];
static inline u8 __init
f_mult (u8 a, u8 b)
{
u8 aa = log_tab[a], cc = aa + log_tab[b];
return pow_tab[cc + (cc < aa ? 1 : 0)];
}
#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0)
#define f_rn(bo, bi, n, k) \
bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
#define i_rn(bo, bi, n, k) \
bo[n] = it_tab[0][byte(bi[n],0)] ^ \
it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
#define ls_box(x) \
( fl_tab[0][byte(x, 0)] ^ \
fl_tab[1][byte(x, 1)] ^ \
fl_tab[2][byte(x, 2)] ^ \
fl_tab[3][byte(x, 3)] )
#define f_rl(bo, bi, n, k) \
bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
#define i_rl(bo, bi, n, k) \
bo[n] = il_tab[0][byte(bi[n],0)] ^ \
il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
static void __init
gen_tabs (void)
{
u32 i, t;
u8 p, q;
/* log and power tables for GF(2**8) finite field with
0x011b as modular polynomial - the simplest primitive
root is 0x03, used here to generate the tables */
for (i = 0, p = 1; i < 256; ++i) {
pow_tab[i] = (u8) p;
log_tab[p] = (u8) i;
p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
}
log_tab[1] = 0;
for (i = 0, p = 1; i < 10; ++i) {
rco_tab[i] = p;
p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
}
for (i = 0; i < 256; ++i) {
p = (i ? pow_tab[255 - log_tab[i]] : 0);
q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
sbx_tab[i] = p;
isb_tab[p] = (u8) i;
}
for (i = 0; i < 256; ++i) {
p = sbx_tab[i];
t = p;
fl_tab[0][i] = t;
fl_tab[1][i] = rotl (t, 8);
fl_tab[2][i] = rotl (t, 16);
fl_tab[3][i] = rotl (t, 24);
t = ((u32) ff_mult (2, p)) |
((u32) p << 8) |
((u32) p << 16) | ((u32) ff_mult (3, p) << 24);
ft_tab[0][i] = t;
ft_tab[1][i] = rotl (t, 8);
ft_tab[2][i] = rotl (t, 16);
ft_tab[3][i] = rotl (t, 24);
p = isb_tab[i];
t = p;
il_tab[0][i] = t;
il_tab[1][i] = rotl (t, 8);
il_tab[2][i] = rotl (t, 16);
il_tab[3][i] = rotl (t, 24);
t = ((u32) ff_mult (14, p)) |
((u32) ff_mult (9, p) << 8) |
((u32) ff_mult (13, p) << 16) |
((u32) ff_mult (11, p) << 24);
it_tab[0][i] = t;
it_tab[1][i] = rotl (t, 8);
it_tab[2][i] = rotl (t, 16);
it_tab[3][i] = rotl (t, 24);
}
}
#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
#define imix_col(y,x) \
u = star_x(x); \
v = star_x(u); \
w = star_x(v); \
t = w ^ (x); \
(y) = u ^ v ^ w; \
(y) ^= rotr(u ^ t, 8) ^ \
rotr(v ^ t, 16) ^ \
rotr(t,24)
/* initialise the key schedule from the user supplied key */
#define loop4(i) \
{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \
t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \
t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \
t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \
t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \
}
#define loop6(i) \
{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \
t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \
t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \
t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \
t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \
t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \
t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \
}
#define loop8(i) \
{ t = rotr(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \
t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \
t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \
t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \
t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \
t = E_KEY[8 * i + 4] ^ ls_box(t); \
E_KEY[8 * i + 12] = t; \
t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \
t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \
t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \
}
static int
aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
{
struct aes_ctx *ctx = ctx_arg;
u32 i, t, u, v, w;
if (key_len != 16 && key_len != 24 && key_len != 32) {
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
ctx->key_length = key_len;
E_KEY[0] = u32_in (in_key);
E_KEY[1] = u32_in (in_key + 4);
E_KEY[2] = u32_in (in_key + 8);
E_KEY[3] = u32_in (in_key + 12);
switch (key_len) {
case 16:
t = E_KEY[3];
for (i = 0; i < 10; ++i)
loop4 (i);
break;
case 24:
E_KEY[4] = u32_in (in_key + 16);
t = E_KEY[5] = u32_in (in_key + 20);
for (i = 0; i < 8; ++i)
loop6 (i);
break;
case 32:
E_KEY[4] = u32_in (in_key + 16);
E_KEY[5] = u32_in (in_key + 20);
E_KEY[6] = u32_in (in_key + 24);
t = E_KEY[7] = u32_in (in_key + 28);
for (i = 0; i < 7; ++i)
loop8 (i);
break;
}
D_KEY[0] = E_KEY[0];
D_KEY[1] = E_KEY[1];
D_KEY[2] = E_KEY[2];
D_KEY[3] = E_KEY[3];
for (i = 4; i < key_len + 24; ++i) {
imix_col (D_KEY[i], E_KEY[i]);
}
return 0;
}
/* encrypt a block of text */
#define f_nround(bo, bi, k) \
f_rn(bo, bi, 0, k); \
f_rn(bo, bi, 1, k); \
f_rn(bo, bi, 2, k); \
f_rn(bo, bi, 3, k); \
k += 4
#define f_lround(bo, bi, k) \
f_rl(bo, bi, 0, k); \
f_rl(bo, bi, 1, k); \
f_rl(bo, bi, 2, k); \
f_rl(bo, bi, 3, k)
static void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in)
{
const struct aes_ctx *ctx = ctx_arg;
u32 b0[4], b1[4];
const u32 *kp = E_KEY + 4;
b0[0] = u32_in (in) ^ E_KEY[0];
b0[1] = u32_in (in + 4) ^ E_KEY[1];
b0[2] = u32_in (in + 8) ^ E_KEY[2];
b0[3] = u32_in (in + 12) ^ E_KEY[3];
if (ctx->key_length > 24) {
f_nround (b1, b0, kp);
f_nround (b0, b1, kp);
}
if (ctx->key_length > 16) {
f_nround (b1, b0, kp);
f_nround (b0, b1, kp);
}
f_nround (b1, b0, kp);
f_nround (b0, b1, kp);
f_nround (b1, b0, kp);
f_nround (b0, b1, kp);
f_nround (b1, b0, kp);
f_nround (b0, b1, kp);
f_nround (b1, b0, kp);
f_nround (b0, b1, kp);
f_nround (b1, b0, kp);
f_lround (b0, b1, kp);
u32_out (out, b0[0]);
u32_out (out + 4, b0[1]);
u32_out (out + 8, b0[2]);
u32_out (out + 12, b0[3]);
}
/* decrypt a block of text */
#define i_nround(bo, bi, k) \
i_rn(bo, bi, 0, k); \
i_rn(bo, bi, 1, k); \
i_rn(bo, bi, 2, k); \
i_rn(bo, bi, 3, k); \
k -= 4
#define i_lround(bo, bi, k) \
i_rl(bo, bi, 0, k); \
i_rl(bo, bi, 1, k); \
i_rl(bo, bi, 2, k); \
i_rl(bo, bi, 3, k)
static void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in)
{
const struct aes_ctx *ctx = ctx_arg;
u32 b0[4], b1[4];
const int key_len = ctx->key_length;
const u32 *kp = D_KEY + key_len + 20;
b0[0] = u32_in (in) ^ E_KEY[key_len + 24];
b0[1] = u32_in (in + 4) ^ E_KEY[key_len + 25];
b0[2] = u32_in (in + 8) ^ E_KEY[key_len + 26];
b0[3] = u32_in (in + 12) ^ E_KEY[key_len + 27];
if (key_len > 24) {
i_nround (b1, b0, kp);
i_nround (b0, b1, kp);
}
if (key_len > 16) {
i_nround (b1, b0, kp);
i_nround (b0, b1, kp);
}
i_nround (b1, b0, kp);
i_nround (b0, b1, kp);
i_nround (b1, b0, kp);
i_nround (b0, b1, kp);
i_nround (b1, b0, kp);
i_nround (b0, b1, kp);
i_nround (b1, b0, kp);
i_nround (b0, b1, kp);
i_nround (b1, b0, kp);
i_lround (b0, b1, kp);
u32_out (out, b0[0]);
u32_out (out + 4, b0[1]);
u32_out (out + 8, b0[2]);
u32_out (out + 12, b0[3]);
}
static struct crypto_alg aes_alg = {
.cra_name = "aes",
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
.cra_u = {
.cipher = {
.cia_min_keysize = AES_MIN_KEY_SIZE,
.cia_max_keysize = AES_MAX_KEY_SIZE,
.cia_setkey = aes_set_key,
.cia_encrypt = aes_encrypt,
.cia_decrypt = aes_decrypt
}
}
};
static int __init aes_init(void)
{
gen_tabs();
return crypto_register_alg(&aes_alg);
}
static void __exit aes_fini(void)
{
crypto_unregister_alg(&aes_alg);
}
module_init(aes_init);
module_exit(aes_fini);
MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -0,0 +1,246 @@
/*
* Scatterlist Cryptographic API.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
* Copyright (c) 2002 David S. Miller (davem@redhat.com)
*
* Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
* and Nettle, by Niels M鰈ler.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include "kmap_types.h"
#include <linux/init.h>
#include <linux/module.h>
//#include <linux/crypto.h>
#include "rtl_crypto.h"
#include <linux/errno.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include "internal.h"
LIST_HEAD(crypto_alg_list);
DECLARE_RWSEM(crypto_alg_sem);
static inline int crypto_alg_get(struct crypto_alg *alg)
{
return try_inc_mod_count(alg->cra_module);
}
static inline void crypto_alg_put(struct crypto_alg *alg)
{
if (alg->cra_module)
__MOD_DEC_USE_COUNT(alg->cra_module);
}
struct crypto_alg *crypto_alg_lookup(const char *name)
{
struct crypto_alg *q, *alg = NULL;
if (!name)
return NULL;
down_read(&crypto_alg_sem);
list_for_each_entry(q, &crypto_alg_list, cra_list) {
if (!(strcmp(q->cra_name, name))) {
if (crypto_alg_get(q))
alg = q;
break;
}
}
up_read(&crypto_alg_sem);
return alg;
}
static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
{
tfm->crt_flags = 0;
switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER:
return crypto_init_cipher_flags(tfm, flags);
case CRYPTO_ALG_TYPE_DIGEST:
return crypto_init_digest_flags(tfm, flags);
case CRYPTO_ALG_TYPE_COMPRESS:
return crypto_init_compress_flags(tfm, flags);
default:
break;
}
BUG();
return -EINVAL;
}
static int crypto_init_ops(struct crypto_tfm *tfm)
{
switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER:
return crypto_init_cipher_ops(tfm);
case CRYPTO_ALG_TYPE_DIGEST:
return crypto_init_digest_ops(tfm);
case CRYPTO_ALG_TYPE_COMPRESS:
return crypto_init_compress_ops(tfm);
default:
break;
}
BUG();
return -EINVAL;
}
static void crypto_exit_ops(struct crypto_tfm *tfm)
{
switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER:
crypto_exit_cipher_ops(tfm);
break;
case CRYPTO_ALG_TYPE_DIGEST:
crypto_exit_digest_ops(tfm);
break;
case CRYPTO_ALG_TYPE_COMPRESS:
crypto_exit_compress_ops(tfm);
break;
default:
BUG();
}
}
struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
{
struct crypto_tfm *tfm = NULL;
struct crypto_alg *alg;
alg = crypto_alg_mod_lookup(name);
if (alg == NULL)
goto out;
tfm = kmalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL);
if (tfm == NULL)
goto out_put;
memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize);
tfm->__crt_alg = alg;
if (crypto_init_flags(tfm, flags))
goto out_free_tfm;
if (crypto_init_ops(tfm)) {
crypto_exit_ops(tfm);
goto out_free_tfm;
}
goto out;
out_free_tfm:
kfree(tfm);
tfm = NULL;
out_put:
crypto_alg_put(alg);
out:
return tfm;
}
void crypto_free_tfm(struct crypto_tfm *tfm)
{
struct crypto_alg *alg = tfm->__crt_alg;
int size = sizeof(*tfm) + alg->cra_ctxsize;
crypto_exit_ops(tfm);
crypto_alg_put(alg);
memset(tfm, 0, size);
kfree(tfm);
}
int crypto_register_alg(struct crypto_alg *alg)
{
int ret = 0;
struct crypto_alg *q;
down_write(&crypto_alg_sem);
list_for_each_entry(q, &crypto_alg_list, cra_list) {
if (!(strcmp(q->cra_name, alg->cra_name))) {
ret = -EEXIST;
goto out;
}
}
list_add_tail(&alg->cra_list, &crypto_alg_list);
out:
up_write(&crypto_alg_sem);
return ret;
}
int crypto_unregister_alg(struct crypto_alg *alg)
{
int ret = -ENOENT;
struct crypto_alg *q;
BUG_ON(!alg->cra_module);
down_write(&crypto_alg_sem);
list_for_each_entry(q, &crypto_alg_list, cra_list) {
if (alg == q) {
list_del(&alg->cra_list);
ret = 0;
goto out;
}
}
out:
up_write(&crypto_alg_sem);
return ret;
}
int crypto_alg_available(const char *name, u32 flags)
{
int ret = 0;
struct crypto_alg *alg = crypto_alg_mod_lookup(name);
if (alg) {
crypto_alg_put(alg);
ret = 1;
}
return ret;
}
static int __init init_crypto(void)
{
printk(KERN_INFO "Initializing Cryptographic API\n");
crypto_init_proc();
return 0;
}
__initcall(init_crypto);
/*
EXPORT_SYMBOL_GPL(crypto_register_alg);
EXPORT_SYMBOL_GPL(crypto_unregister_alg);
EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
EXPORT_SYMBOL_GPL(crypto_free_tfm);
EXPORT_SYMBOL_GPL(crypto_alg_available);
*/
EXPORT_SYMBOL_NOVERS(crypto_register_alg);
EXPORT_SYMBOL_NOVERS(crypto_unregister_alg);
EXPORT_SYMBOL_NOVERS(crypto_alloc_tfm);
EXPORT_SYMBOL_NOVERS(crypto_free_tfm);
EXPORT_SYMBOL_NOVERS(crypto_alg_available);

View File

@ -0,0 +1,103 @@
/*
* Cryptographic API
*
* ARC4 Cipher Algorithm
*
* Jon Oberheide <jon@oberheide.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include "rtl_crypto.h"
#define ARC4_MIN_KEY_SIZE 1
#define ARC4_MAX_KEY_SIZE 256
#define ARC4_BLOCK_SIZE 1
struct arc4_ctx {
u8 S[256];
u8 x, y;
};
static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
{
struct arc4_ctx *ctx = ctx_arg;
int i, j = 0, k = 0;
ctx->x = 1;
ctx->y = 0;
for(i = 0; i < 256; i++)
ctx->S[i] = i;
for(i = 0; i < 256; i++)
{
u8 a = ctx->S[i];
j = (j + in_key[k] + a) & 0xff;
ctx->S[i] = ctx->S[j];
ctx->S[j] = a;
if(++k >= key_len)
k = 0;
}
return 0;
}
static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in)
{
struct arc4_ctx *ctx = ctx_arg;
u8 *const S = ctx->S;
u8 x = ctx->x;
u8 y = ctx->y;
u8 a, b;
a = S[x];
y = (y + a) & 0xff;
b = S[y];
S[x] = b;
S[y] = a;
x = (x + 1) & 0xff;
*out++ = *in ^ S[(a + b) & 0xff];
ctx->x = x;
ctx->y = y;
}
static struct crypto_alg arc4_alg = {
.cra_name = "arc4",
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
.cra_blocksize = ARC4_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct arc4_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(arc4_alg.cra_list),
.cra_u = { .cipher = {
.cia_min_keysize = ARC4_MIN_KEY_SIZE,
.cia_max_keysize = ARC4_MAX_KEY_SIZE,
.cia_setkey = arc4_set_key,
.cia_encrypt = arc4_crypt,
.cia_decrypt = arc4_crypt } }
};
static int __init arc4_init(void)
{
return crypto_register_alg(&arc4_alg);
}
static void __exit arc4_exit(void)
{
crypto_unregister_alg(&arc4_alg);
}
module_init(arc4_init);
module_exit(arc4_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ARC4 Cipher Algorithm");
MODULE_AUTHOR("Jon Oberheide <jon@oberheide.org>");

View File

@ -0,0 +1,40 @@
/*
* Cryptographic API.
*
* Algorithm autoloader.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include "kmap_types.h"
#include <linux/kernel.h>
//#include <linux/crypto.h>
#include "rtl_crypto.h"
#include <linux/string.h>
#include <linux/kmod.h>
#include "internal.h"
/*
* A far more intelligent version of this is planned. For now, just
* try an exact match on the name of the algorithm.
*/
void crypto_alg_autoload(const char *name)
{
request_module(name);
}
struct crypto_alg *crypto_alg_mod_lookup(const char *name)
{
struct crypto_alg *alg = crypto_alg_lookup(name);
if (alg == NULL) {
crypto_alg_autoload(name);
alg = crypto_alg_lookup(name);
}
return alg;
}

View File

@ -0,0 +1,299 @@
/*
* Cryptographic API.
*
* Cipher operations.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include <linux/kernel.h>
//#include <linux/crypto.h>
#include "rtl_crypto.h"
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/scatterlist.h>
#include "internal.h"
#include "scatterwalk.h"
typedef void (cryptfn_t)(void *, u8 *, const u8 *);
typedef void (procfn_t)(struct crypto_tfm *, u8 *,
u8*, cryptfn_t, int enc, void *, int);
static inline void xor_64(u8 *a, const u8 *b)
{
((u32 *)a)[0] ^= ((u32 *)b)[0];
((u32 *)a)[1] ^= ((u32 *)b)[1];
}
static inline void xor_128(u8 *a, const u8 *b)
{
((u32 *)a)[0] ^= ((u32 *)b)[0];
((u32 *)a)[1] ^= ((u32 *)b)[1];
((u32 *)a)[2] ^= ((u32 *)b)[2];
((u32 *)a)[3] ^= ((u32 *)b)[3];
}
/*
* Generic encrypt/decrypt wrapper for ciphers, handles operations across
* multiple page boundaries by using temporary blocks. In user context,
* the kernel is given a chance to schedule us once per block.
*/
static int crypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes, cryptfn_t crfn,
procfn_t prfn, int enc, void *info)
{
struct scatter_walk walk_in, walk_out;
const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
u8 tmp_src[bsize];
u8 tmp_dst[bsize];
if (!nbytes)
return 0;
if (nbytes % bsize) {
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
return -EINVAL;
}
scatterwalk_start(&walk_in, src);
scatterwalk_start(&walk_out, dst);
for(;;) {
u8 *src_p, *dst_p;
int in_place;
scatterwalk_map(&walk_in, 0);
scatterwalk_map(&walk_out, 1);
src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src);
dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst);
in_place = scatterwalk_samebuf(&walk_in, &walk_out,
src_p, dst_p);
nbytes -= bsize;
scatterwalk_copychunks(src_p, &walk_in, bsize, 0);
prfn(tfm, dst_p, src_p, crfn, enc, info, in_place);
scatterwalk_done(&walk_in, 0, nbytes);
scatterwalk_copychunks(dst_p, &walk_out, bsize, 1);
scatterwalk_done(&walk_out, 1, nbytes);
if (!nbytes)
return 0;
crypto_yield(tfm);
}
}
static void cbc_process(struct crypto_tfm *tfm, u8 *dst, u8 *src,
cryptfn_t fn, int enc, void *info, int in_place)
{
u8 *iv = info;
/* Null encryption */
if (!iv)
return;
if (enc) {
tfm->crt_u.cipher.cit_xor_block(iv, src);
fn(crypto_tfm_ctx(tfm), dst, iv);
memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm));
} else {
u8 stack[in_place ? crypto_tfm_alg_blocksize(tfm) : 0];
u8 *buf = in_place ? stack : dst;
fn(crypto_tfm_ctx(tfm), buf, src);
tfm->crt_u.cipher.cit_xor_block(buf, iv);
memcpy(iv, src, crypto_tfm_alg_blocksize(tfm));
if (buf != dst)
memcpy(dst, buf, crypto_tfm_alg_blocksize(tfm));
}
}
static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src,
cryptfn_t fn, int enc, void *info, int in_place)
{
fn(crypto_tfm_ctx(tfm), dst, src);
}
static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
{
struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
} else
return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen,
&tfm->crt_flags);
}
static int ecb_encrypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src, unsigned int nbytes)
{
return crypt(tfm, dst, src, nbytes,
tfm->__crt_alg->cra_cipher.cia_encrypt,
ecb_process, 1, NULL);
}
static int ecb_decrypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes)
{
return crypt(tfm, dst, src, nbytes,
tfm->__crt_alg->cra_cipher.cia_decrypt,
ecb_process, 1, NULL);
}
static int cbc_encrypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes)
{
return crypt(tfm, dst, src, nbytes,
tfm->__crt_alg->cra_cipher.cia_encrypt,
cbc_process, 1, tfm->crt_cipher.cit_iv);
}
static int cbc_encrypt_iv(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes, u8 *iv)
{
return crypt(tfm, dst, src, nbytes,
tfm->__crt_alg->cra_cipher.cia_encrypt,
cbc_process, 1, iv);
}
static int cbc_decrypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes)
{
return crypt(tfm, dst, src, nbytes,
tfm->__crt_alg->cra_cipher.cia_decrypt,
cbc_process, 0, tfm->crt_cipher.cit_iv);
}
static int cbc_decrypt_iv(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes, u8 *iv)
{
return crypt(tfm, dst, src, nbytes,
tfm->__crt_alg->cra_cipher.cia_decrypt,
cbc_process, 0, iv);
}
static int nocrypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes)
{
return -ENOSYS;
}
static int nocrypt_iv(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes, u8 *iv)
{
return -ENOSYS;
}
int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
{
u32 mode = flags & CRYPTO_TFM_MODE_MASK;
tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB;
if (flags & CRYPTO_TFM_REQ_WEAK_KEY)
tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY;
return 0;
}
int crypto_init_cipher_ops(struct crypto_tfm *tfm)
{
int ret = 0;
struct cipher_tfm *ops = &tfm->crt_cipher;
ops->cit_setkey = setkey;
switch (tfm->crt_cipher.cit_mode) {
case CRYPTO_TFM_MODE_ECB:
ops->cit_encrypt = ecb_encrypt;
ops->cit_decrypt = ecb_decrypt;
break;
case CRYPTO_TFM_MODE_CBC:
ops->cit_encrypt = cbc_encrypt;
ops->cit_decrypt = cbc_decrypt;
ops->cit_encrypt_iv = cbc_encrypt_iv;
ops->cit_decrypt_iv = cbc_decrypt_iv;
break;
case CRYPTO_TFM_MODE_CFB:
ops->cit_encrypt = nocrypt;
ops->cit_decrypt = nocrypt;
ops->cit_encrypt_iv = nocrypt_iv;
ops->cit_decrypt_iv = nocrypt_iv;
break;
case CRYPTO_TFM_MODE_CTR:
ops->cit_encrypt = nocrypt;
ops->cit_decrypt = nocrypt;
ops->cit_encrypt_iv = nocrypt_iv;
ops->cit_decrypt_iv = nocrypt_iv;
break;
default:
BUG();
}
if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) {
switch (crypto_tfm_alg_blocksize(tfm)) {
case 8:
ops->cit_xor_block = xor_64;
break;
case 16:
ops->cit_xor_block = xor_128;
break;
default:
printk(KERN_WARNING "%s: block size %u not supported\n",
crypto_tfm_alg_name(tfm),
crypto_tfm_alg_blocksize(tfm));
ret = -EINVAL;
goto out;
}
ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm);
ops->cit_iv = kmalloc(ops->cit_ivsize, GFP_KERNEL);
if (ops->cit_iv == NULL)
ret = -ENOMEM;
}
out:
return ret;
}
void crypto_exit_cipher_ops(struct crypto_tfm *tfm)
{
if (tfm->crt_cipher.cit_iv)
kfree(tfm->crt_cipher.cit_iv);
}

View File

@ -0,0 +1,64 @@
/*
* Cryptographic API.
*
* Compression operations.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include <linux/types.h>
//#include <linux/crypto.h>
#include "rtl_crypto.h"
#include <linux/errno.h>
#include <asm/scatterlist.h>
#include <linux/string.h>
#include "internal.h"
static int crypto_compress(struct crypto_tfm *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen)
{
return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm),
src, slen, dst,
dlen);
}
static int crypto_decompress(struct crypto_tfm *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen)
{
return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm),
src, slen, dst,
dlen);
}
int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags)
{
return flags ? -EINVAL : 0;
}
int crypto_init_compress_ops(struct crypto_tfm *tfm)
{
int ret = 0;
struct compress_tfm *ops = &tfm->crt_compress;
ret = tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm));
if (ret)
goto out;
ops->cot_compress = crypto_compress;
ops->cot_decompress = crypto_decompress;
out:
return ret;
}
void crypto_exit_compress_ops(struct crypto_tfm *tfm)
{
tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm));
}

View File

@ -0,0 +1,108 @@
/*
* Cryptographic API.
*
* Digest operations.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
//#include <linux/crypto.h>
#include "rtl_crypto.h"
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/highmem.h>
#include <asm/scatterlist.h>
#include "internal.h"
static void init(struct crypto_tfm *tfm)
{
tfm->__crt_alg->cra_digest.dia_init(crypto_tfm_ctx(tfm));
}
static void update(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg)
{
unsigned int i;
for (i = 0; i < nsg; i++) {
struct page *pg = sg[i].page;
unsigned int offset = sg[i].offset;
unsigned int l = sg[i].length;
do {
unsigned int bytes_from_page = min(l, ((unsigned int)
(PAGE_SIZE)) -
offset);
char *p = crypto_kmap(pg, 0) + offset;
tfm->__crt_alg->cra_digest.dia_update
(crypto_tfm_ctx(tfm), p,
bytes_from_page);
crypto_kunmap(p, 0);
crypto_yield(tfm);
offset = 0;
pg++;
l -= bytes_from_page;
} while (l > 0);
}
}
static void final(struct crypto_tfm *tfm, u8 *out)
{
tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out);
}
static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
{
u32 flags;
if (tfm->__crt_alg->cra_digest.dia_setkey == NULL)
return -ENOSYS;
return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm),
key, keylen, &flags);
}
static void digest(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg, u8 *out)
{
unsigned int i;
tfm->crt_digest.dit_init(tfm);
for (i = 0; i < nsg; i++) {
char *p = crypto_kmap(sg[i].page, 0) + sg[i].offset;
tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm),
p, sg[i].length);
crypto_kunmap(p, 0);
crypto_yield(tfm);
}
crypto_digest_final(tfm, out);
}
int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
{
return flags ? -EINVAL : 0;
}
int crypto_init_digest_ops(struct crypto_tfm *tfm)
{
struct digest_tfm *ops = &tfm->crt_digest;
ops->dit_init = init;
ops->dit_update = update;
ops->dit_final = final;
ops->dit_digest = digest;
ops->dit_setkey = setkey;
return crypto_alloc_hmac_block(tfm);
}
void crypto_exit_digest_ops(struct crypto_tfm *tfm)
{
crypto_free_hmac_block(tfm);
}

View File

@ -0,0 +1,246 @@
#ifdef ENABLE_DOT11D
//-----------------------------------------------------------------------------
// File:
// Dot11d.c
//
// Description:
// Implement 802.11d.
//
//-----------------------------------------------------------------------------
#include "dot11d.h"
void
Dot11d_Init(struct ieee80211_device *ieee)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
pDot11dInfo->bEnabled = 0;
pDot11dInfo->State = DOT11D_STATE_NONE;
pDot11dInfo->CountryIeLen = 0;
memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
RESET_CIE_WATCHDOG(ieee);
printk("Dot11d_Init()\n");
}
//
// Description:
// Reset to the state as we are just entering a regulatory domain.
//
void
Dot11d_Reset(struct ieee80211_device *ieee)
{
u32 i;
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
// Clear old channel map
memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
// Set new channel map
for (i=1; i<=11; i++) {
(pDot11dInfo->channel_map)[i] = 1;
}
for (i=12; i<=14; i++) {
(pDot11dInfo->channel_map)[i] = 2;
}
pDot11dInfo->State = DOT11D_STATE_NONE;
pDot11dInfo->CountryIeLen = 0;
RESET_CIE_WATCHDOG(ieee);
//printk("Dot11d_Reset()\n");
}
//
// Description:
// 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_UpdateCountryIe(
struct ieee80211_device *dev,
u8 * pTaddr,
u16 CoutryIeLen,
u8 * pCoutryIe
)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
u8 i, j, NumTriples, MaxChnlNum;
PCHNL_TXPOWER_TRIPLE pTriple;
if((CoutryIeLen - 3)%3 != 0)
{
printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
Dot11d_Reset(dev);
return;
}
memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
MaxChnlNum = 0;
NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string.
pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3);
for(i = 0; i < NumTriples; i++)
{
if(MaxChnlNum >= pTriple->FirstChnl)
{ // It is not in a monotonically increasing order, so stop processing.
printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
Dot11d_Reset(dev);
return;
}
if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls))
{ // It is not a valid set of channel id, so stop processing.
printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
Dot11d_Reset(dev);
return;
}
for(j = 0 ; j < pTriple->NumChnls; j++)
{
pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1;
pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm;
MaxChnlNum = pTriple->FirstChnl + j;
}
pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3);
}
#if 1
//printk("Dot11d_UpdateCountryIe(): Channel List:\n");
printk("Channel List:");
for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
if(pDot11dInfo->channel_map[i] > 0)
printk(" %d", i);
printk("\n");
#endif
UPDATE_CIE_SRC(dev, pTaddr);
pDot11dInfo->CountryIeLen = CoutryIeLen;
memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen);
pDot11dInfo->State = DOT11D_STATE_LEARNED;
}
void dump_chnl_map(u8 * channel_map)
{
int i;
printk("Channel List:");
for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
if(channel_map[i] > 0)
printk(" %d(%d)", i, channel_map[i]);
printk("\n");
}
u8
DOT11D_GetMaxTxPwrInDbm(
struct ieee80211_device *dev,
u8 Channel
)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
u8 MaxTxPwrInDbm = 255;
if(MAX_CHANNEL_NUMBER < Channel)
{
printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
return MaxTxPwrInDbm;
}
if(pDot11dInfo->channel_map[Channel])
{
MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel];
}
return MaxTxPwrInDbm;
}
void
DOT11D_ScanComplete(
struct ieee80211_device * dev
)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
switch(pDot11dInfo->State)
{
case DOT11D_STATE_LEARNED:
pDot11dInfo->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;
}
}
int IsLegalChannel(
struct ieee80211_device * dev,
u8 channel
)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
if(MAX_CHANNEL_NUMBER < channel)
{
printk("IsLegalChannel(): Invalid Channel\n");
return 0;
}
if(pDot11dInfo->channel_map[channel] > 0)
return 1;
return 0;
}
int ToLegalChannel(
struct ieee80211_device * dev,
u8 channel
)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
u8 default_chn = 0;
u32 i = 0;
for (i=1; i<= MAX_CHANNEL_NUMBER; i++)
{
if(pDot11dInfo->channel_map[i] > 0)
{
default_chn = i;
break;
}
}
if(MAX_CHANNEL_NUMBER < channel)
{
printk("IsLegalChannel(): Invalid Channel\n");
return default_chn;
}
if(pDot11dInfo->channel_map[channel] > 0)
return channel;
return default_chn;
}
#if 0
EXPORT_SYMBOL(Dot11d_Init);
EXPORT_SYMBOL(Dot11d_Reset);
EXPORT_SYMBOL(Dot11d_UpdateCountryIe);
EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm);
EXPORT_SYMBOL(DOT11D_ScanComplete);
EXPORT_SYMBOL(IsLegalChannel);
EXPORT_SYMBOL(ToLegalChannel);
#endif
#endif

View File

@ -0,0 +1,102 @@
#ifndef __INC_DOT11D_H
#define __INC_DOT11D_H
#include "ieee80211.h"
//#define ENABLE_DOT11D
//#define DOT11D_MAX_CHNL_NUM 83
typedef struct _CHNL_TXPOWER_TRIPLE {
u8 FirstChnl;
u8 NumChnls;
u8 MaxTxPowerInDbm;
}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
typedef enum _DOT11D_STATE {
DOT11D_STATE_NONE = 0,
DOT11D_STATE_LEARNED,
DOT11D_STATE_DONE,
}DOT11D_STATE;
typedef struct _RT_DOT11D_INFO {
//DECLARE_RT_OBJECT(RT_DOT11D_INFO);
bool bEnabled; // dot11MultiDomainCapabilityEnabled
u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element.
u8 CountryIeBuf[MAX_IE_LEN];
u8 CountryIeSrcAddr[6]; // Source AP of the country IE.
u8 CountryIeWatchdog;
u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan)
//u8 ChnlListLen; // #Bytes valid in ChnlList[].
//u8 ChnlList[DOT11D_MAX_CHNL_NUM];
u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
DOT11D_STATE State;
}RT_DOT11D_INFO, *PRT_DOT11D_INFO;
#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo))
#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled
#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0)
#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \
(((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \
FALSE : \
(!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length)))
#define CIE_WATCHDOG_TH 1
#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog
#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0
#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev)
#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE)
void
Dot11d_Init(
struct ieee80211_device *dev
);
void
Dot11d_Reset(
struct ieee80211_device *dev
);
void
Dot11d_UpdateCountryIe(
struct ieee80211_device *dev,
u8 * pTaddr,
u16 CoutryIeLen,
u8 * pCoutryIe
);
u8
DOT11D_GetMaxTxPwrInDbm(
struct ieee80211_device *dev,
u8 Channel
);
void
DOT11D_ScanComplete(
struct ieee80211_device * dev
);
int IsLegalChannel(
struct ieee80211_device * dev,
u8 channel
);
int ToLegalChannel(
struct ieee80211_device * dev,
u8 channel
);
void dump_chnl_map(u8 * channel_map);
#endif // #ifndef __INC_DOT11D_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,265 @@
/*
* Host AP crypto routines
*
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
*
* 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. See README and COPYING for
* more details.
*
*/
//#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/string.h>
#include <asm/errno.h>
#if (LINUX_VERSION_CODE<KERNEL_VERSION(2,6,18))
#include<linux/config.h>
#endif
#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);
module_put(entry->ops->owner);
}
kfree(entry);
}
}
void ieee80211_crypt_deinit_handler(unsigned long data)
{
struct ieee80211_device *ieee = (struct ieee80211_device *)data;
unsigned long flags;
spin_lock_irqsave(&ieee->lock, flags);
ieee80211_crypt_deinit_entries(ieee, 0);
if (!list_empty(&ieee->crypt_deinit_list)) {
printk(KERN_DEBUG "%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 == NULL)
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 == NULL)
return -1;
alg = kmalloc(sizeof(*alg), GFP_KERNEL);
if (alg == NULL)
return -ENOMEM;
memset(alg, 0, sizeof(*alg));
alg->ops = ops;
spin_lock_irqsave(&hcrypt->lock, flags);
list_add(&alg->list, &hcrypt->algs);
spin_unlock_irqrestore(&hcrypt->lock, flags);
printk(KERN_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 == NULL)
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) {
printk(KERN_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 == NULL)
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;
else
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 ieee80211_crypto_init(void)
{
int ret = -ENOMEM;
hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL);
if (!hcrypt)
goto out;
memset(hcrypt, 0, sizeof(*hcrypt));
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 == NULL)
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);
printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
"'%s' (deinit)\n", alg->ops->name);
kfree(alg);
}
kfree(hcrypt);
}
#if 0
EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
EXPORT_SYMBOL(ieee80211_crypt_deinit_handler);
EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit);
EXPORT_SYMBOL(ieee80211_register_crypto_ops);
EXPORT_SYMBOL(ieee80211_unregister_crypto_ops);
EXPORT_SYMBOL(ieee80211_get_crypto_ops);
#endif
//module_init(ieee80211_crypto_init);
//module_exit(ieee80211_crypto_deinit);

View File

@ -0,0 +1,86 @@
/*
* 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 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. See README and COPYING for
* more details.
*/
/*
* 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 *, int);
void ieee80211_crypt_deinit_handler(unsigned long);
void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
struct ieee80211_crypt_data **crypt);
#endif

View File

@ -0,0 +1,533 @@
/*
* Host AP crypt: host-based CCMP encryption implementation for Host AP driver
*
* Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
*
* 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. See README and COPYING for
* more details.
*/
//#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <asm/string.h>
#include <linux/wireless.h>
#include "ieee80211.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
#include "rtl_crypto.h"
#else
#include <linux/crypto.h>
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
#include <asm/scatterlist.h>
#else
#include <linux/scatterlist.h>
#endif
//#include <asm/scatterlist.h>
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP crypt: CCMP");
MODULE_LICENSE("GPL");
#ifdef OPENSUSE_SLED
#ifndef IN_OPENSUSE_SLED
#define IN_OPENSUSE_SLED 1
#endif
#endif
#define AES_BLOCK_LEN 16
#define CCMP_HDR_LEN 8
#define CCMP_MIC_LEN 8
#define CCMP_TK_LEN 16
#define CCMP_PN_LEN 6
struct ieee80211_ccmp_data {
u8 key[CCMP_TK_LEN];
int key_set;
u8 tx_pn[CCMP_PN_LEN];
u8 rx_pn[CCMP_PN_LEN];
u32 dot11RSNAStatsCCMPFormatErrors;
u32 dot11RSNAStatsCCMPReplays;
u32 dot11RSNAStatsCCMPDecryptErrors;
int key_idx;
struct crypto_tfm *tfm;
/* scratch buffers for virt_to_page() (crypto API) */
u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
};
void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
const u8 pt[16], u8 ct[16])
{
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED))
crypto_cipher_encrypt_one((void *)tfm, ct, pt);
#else
struct scatterlist src, dst;
src.page = virt_to_page(pt);
src.offset = offset_in_page(pt);
src.length = AES_BLOCK_LEN;
dst.page = virt_to_page(ct);
dst.offset = offset_in_page(ct);
dst.length = AES_BLOCK_LEN;
crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN);
#endif
}
static void * ieee80211_ccmp_init(int key_idx)
{
struct ieee80211_ccmp_data *priv;
priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
if (priv == NULL)
goto fail;
memset(priv, 0, sizeof(*priv));
priv->key_idx = key_idx;
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED))
priv->tfm = crypto_alloc_tfm("aes", 0);
if (priv->tfm == NULL) {
printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
"crypto API aes\n");
goto fail;
}
#else
priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tfm)) {
printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
"crypto API aes\n");
priv->tfm = NULL;
goto fail;
}
#endif
return priv;
fail:
if (priv) {
if (priv->tfm)
//#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED))
crypto_free_tfm(priv->tfm);
#else
crypto_free_cipher((void *)priv->tfm);
#endif
kfree(priv);
}
return NULL;
}
static void ieee80211_ccmp_deinit(void *priv)
{
struct ieee80211_ccmp_data *_priv = priv;
if (_priv && _priv->tfm)
//#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED))
crypto_free_tfm(_priv->tfm);
#else
crypto_free_cipher((void *)_priv->tfm);
#endif
kfree(priv);
}
static inline void xor_block(u8 *b, u8 *a, size_t len)
{
int i;
for (i = 0; i < len; i++)
b[i] ^= a[i];
}
#ifndef JOHN_CCMP
static void ccmp_init_blocks(struct crypto_tfm *tfm,
struct ieee80211_hdr *hdr,
u8 *pn, size_t dlen, u8 *b0, u8 *auth,
u8 *s0)
{
u8 *pos, qc = 0;
size_t aad_len;
u16 fc;
int a4_included, qc_included;
u8 aad[2 * AES_BLOCK_LEN];
fc = le16_to_cpu(hdr->frame_ctl);
a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS));
/*
qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
(WLAN_FC_GET_STYPE(fc) & 0x08));
*/
// fixed by David :2006.9.6
qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
(WLAN_FC_GET_STYPE(fc) & 0x80));
aad_len = 22;
if (a4_included)
aad_len += 6;
if (qc_included) {
pos = (u8 *) &hdr->addr4;
if (a4_included)
pos += 6;
qc = *pos & 0x0f;
aad_len += 2;
}
/* CCM Initial Block:
* Flag (Include authentication header, M=3 (8-octet MIC),
* L=1 (2-octet Dlen))
* Nonce: 0x00 | A2 | PN
* Dlen */
b0[0] = 0x59;
b0[1] = qc;
memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
memcpy(b0 + 8, pn, CCMP_PN_LEN);
b0[14] = (dlen >> 8) & 0xff;
b0[15] = dlen & 0xff;
/* AAD:
* FC with bits 4..6 and 11..13 masked to zero; 14 is always one
* A1 | A2 | A3
* SC with bits 4..15 (seq#) masked to zero
* A4 (if present)
* QC (if present)
*/
pos = (u8 *) hdr;
aad[0] = 0; /* aad_len >> 8 */
aad[1] = aad_len & 0xff;
aad[2] = pos[0] & 0x8f;
aad[3] = pos[1] & 0xc7;
memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
pos = (u8 *) &hdr->seq_ctl;
aad[22] = pos[0] & 0x0f;
aad[23] = 0; /* all bits masked */
memset(aad + 24, 0, 8);
if (a4_included)
memcpy(aad + 24, hdr->addr4, ETH_ALEN);
if (qc_included) {
aad[a4_included ? 30 : 24] = qc;
/* rest of QC masked */
}
/* Start with the first block and AAD */
ieee80211_ccmp_aes_encrypt(tfm, b0, auth);
xor_block(auth, aad, AES_BLOCK_LEN);
ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
b0[0] &= 0x07;
b0[14] = b0[15] = 0;
ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
}
#endif
static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct ieee80211_ccmp_data *key = priv;
int data_len, i;
u8 *pos;
struct ieee80211_hdr *hdr;
#ifndef JOHN_CCMP
int blocks, last, len;
u8 *mic;
u8 *b0 = key->tx_b0;
u8 *b = key->tx_b;
u8 *e = key->tx_e;
u8 *s0 = key->tx_s0;
#endif
if (skb_headroom(skb) < CCMP_HDR_LEN ||
skb_tailroom(skb) < CCMP_MIC_LEN ||
skb->len < hdr_len)
return -1;
data_len = skb->len - hdr_len;
pos = skb_push(skb, CCMP_HDR_LEN);
memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
pos += hdr_len;
// mic = skb_put(skb, CCMP_MIC_LEN);
i = CCMP_PN_LEN - 1;
while (i >= 0) {
key->tx_pn[i]++;
if (key->tx_pn[i] != 0)
break;
i--;
}
*pos++ = key->tx_pn[5];
*pos++ = key->tx_pn[4];
*pos++ = 0;
*pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */;
*pos++ = key->tx_pn[3];
*pos++ = key->tx_pn[2];
*pos++ = key->tx_pn[1];
*pos++ = key->tx_pn[0];
hdr = (struct ieee80211_hdr *) skb->data;
#ifndef JOHN_CCMP
//mic is moved to here by john
mic = skb_put(skb, CCMP_MIC_LEN);
ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
last = data_len % AES_BLOCK_LEN;
for (i = 1; i <= blocks; i++) {
len = (i == blocks && last) ? last : AES_BLOCK_LEN;
/* Authentication */
xor_block(b, pos, len);
ieee80211_ccmp_aes_encrypt(key->tfm, b, b);
/* Encryption, with counter */
b0[14] = (i >> 8) & 0xff;
b0[15] = i & 0xff;
ieee80211_ccmp_aes_encrypt(key->tfm, b0, e);
xor_block(pos, e, len);
pos += len;
}
for (i = 0; i < CCMP_MIC_LEN; i++)
mic[i] = b[i] ^ s0[i];
#endif
return 0;
}
static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct ieee80211_ccmp_data *key = priv;
u8 keyidx, *pos;
struct ieee80211_hdr *hdr;
u8 pn[6];
#ifndef JOHN_CCMP
size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN;
u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
u8 *b0 = key->rx_b0;
u8 *b = key->rx_b;
u8 *a = key->rx_a;
int i, blocks, last, len;
#endif
if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
key->dot11RSNAStatsCCMPFormatErrors++;
return -1;
}
hdr = (struct ieee80211_hdr *) skb->data;
pos = skb->data + hdr_len;
keyidx = pos[3];
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: received packet without ExtIV"
" flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
}
key->dot11RSNAStatsCCMPFormatErrors++;
return -2;
}
keyidx >>= 6;
if (key->key_idx != keyidx) {
printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame "
"keyidx=%d priv=%p\n", key->key_idx, keyidx, priv);
return -6;
}
if (!key->key_set) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT
" with keyid=%d that does not have a configured"
" key\n", MAC_ARG(hdr->addr2), keyidx);
}
return -3;
}
pn[0] = pos[7];
pn[1] = pos[6];
pn[2] = pos[5];
pn[3] = pos[4];
pn[4] = pos[1];
pn[5] = pos[0];
pos += 8;
if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
" previous PN %02x%02x%02x%02x%02x%02x "
"received PN %02x%02x%02x%02x%02x%02x\n",
MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
MAC_ARG(pn));
}
key->dot11RSNAStatsCCMPReplays++;
return -4;
}
#ifndef JOHN_CCMP
ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
xor_block(mic, b, CCMP_MIC_LEN);
blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
last = data_len % AES_BLOCK_LEN;
for (i = 1; i <= blocks; i++) {
len = (i == blocks && last) ? last : AES_BLOCK_LEN;
/* Decrypt, with counter */
b0[14] = (i >> 8) & 0xff;
b0[15] = i & 0xff;
ieee80211_ccmp_aes_encrypt(key->tfm, b0, b);
xor_block(pos, b, len);
/* Authentication */
xor_block(a, pos, len);
ieee80211_ccmp_aes_encrypt(key->tfm, a, a);
pos += len;
}
if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: decrypt failed: STA="
MAC_FMT "\n", MAC_ARG(hdr->addr2));
}
key->dot11RSNAStatsCCMPDecryptErrors++;
return -5;
}
memcpy(key->rx_pn, pn, CCMP_PN_LEN);
#endif
/* Remove hdr and MIC */
memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
skb_pull(skb, CCMP_HDR_LEN);
skb_trim(skb, skb->len - CCMP_MIC_LEN);
return keyidx;
}
static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
{
struct ieee80211_ccmp_data *data = priv;
int keyidx;
struct crypto_tfm *tfm = data->tfm;
keyidx = data->key_idx;
memset(data, 0, sizeof(*data));
data->key_idx = keyidx;
data->tfm = tfm;
if (len == CCMP_TK_LEN) {
memcpy(data->key, key, CCMP_TK_LEN);
data->key_set = 1;
if (seq) {
data->rx_pn[0] = seq[5];
data->rx_pn[1] = seq[4];
data->rx_pn[2] = seq[3];
data->rx_pn[3] = seq[2];
data->rx_pn[4] = seq[1];
data->rx_pn[5] = seq[0];
}
crypto_cipher_setkey((void *)data->tfm, data->key, CCMP_TK_LEN);
} else if (len == 0)
data->key_set = 0;
else
return -1;
return 0;
}
static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv)
{
struct ieee80211_ccmp_data *data = priv;
if (len < CCMP_TK_LEN)
return -1;
if (!data->key_set)
return 0;
memcpy(key, data->key, CCMP_TK_LEN);
if (seq) {
seq[0] = data->tx_pn[5];
seq[1] = data->tx_pn[4];
seq[2] = data->tx_pn[3];
seq[3] = data->tx_pn[2];
seq[4] = data->tx_pn[1];
seq[5] = data->tx_pn[0];
}
return CCMP_TK_LEN;
}
static char * ieee80211_ccmp_print_stats(char *p, void *priv)
{
struct ieee80211_ccmp_data *ccmp = priv;
p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
"tx_pn=%02x%02x%02x%02x%02x%02x "
"rx_pn=%02x%02x%02x%02x%02x%02x "
"format_errors=%d replays=%d decrypt_errors=%d\n",
ccmp->key_idx, ccmp->key_set,
MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
ccmp->dot11RSNAStatsCCMPFormatErrors,
ccmp->dot11RSNAStatsCCMPReplays,
ccmp->dot11RSNAStatsCCMPDecryptErrors);
return p;
}
void ieee80211_ccmp_null(void)
{
// printk("============>%s()\n", __FUNCTION__);
return;
}
static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = {
.name = "CCMP",
.init = ieee80211_ccmp_init,
.deinit = ieee80211_ccmp_deinit,
.encrypt_mpdu = ieee80211_ccmp_encrypt,
.decrypt_mpdu = ieee80211_ccmp_decrypt,
.encrypt_msdu = NULL,
.decrypt_msdu = NULL,
.set_key = ieee80211_ccmp_set_key,
.get_key = ieee80211_ccmp_get_key,
.print_stats = ieee80211_ccmp_print_stats,
.extra_prefix_len = CCMP_HDR_LEN,
.extra_postfix_len = CCMP_MIC_LEN,
.owner = THIS_MODULE,
};
int ieee80211_crypto_ccmp_init(void)
{
return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp);
}
void ieee80211_crypto_ccmp_exit(void)
{
ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp);
}
#if 0
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
EXPORT_SYMBOL(ieee80211_ccmp_null);
#else
EXPORT_SYMBOL_NOVERS(ieee80211_ccmp_null);
#endif
#endif
//module_init(ieee80211_crypto_ccmp_init);
//module_exit(ieee80211_crypto_ccmp_exit);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,394 @@
/*
* Host AP crypt: host-based WEP encryption implementation for Host AP driver
*
* Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
*
* 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. See README and COPYING for
* more details.
*/
//#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/skbuff.h>
#include <asm/string.h>
#include "ieee80211.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
#include "rtl_crypto.h"
#else
#include <linux/crypto.h>
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
#include <asm/scatterlist.h>
#else
#include <linux/scatterlist.h>
#endif
//#include <asm/scatterlist.h>
#include <linux/crc32.h>
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP crypt: WEP");
MODULE_LICENSE("GPL");
#ifdef OPENSUSE_SLED
#ifndef IN_OPENSUSE_SLED
#define IN_OPENSUSE_SLED 1
#endif
#endif
struct prism2_wep_data {
u32 iv;
#define WEP_KEY_LEN 13
u8 key[WEP_KEY_LEN + 1];
u8 key_len;
u8 key_idx;
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
struct crypto_tfm *tfm;
#else
struct crypto_blkcipher *tx_tfm;
struct crypto_blkcipher *rx_tfm;
#endif
};
static void * prism2_wep_init(int keyidx)
{
struct prism2_wep_data *priv;
priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
if (priv == NULL)
goto fail;
memset(priv, 0, sizeof(*priv));
priv->key_idx = keyidx;
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
priv->tfm = crypto_alloc_tfm("arc4", 0);
if (priv->tfm == NULL) {
printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
"crypto API arc4\n");
goto fail;
}
#else
priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm)) {
printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
"crypto API arc4\n");
priv->tx_tfm = NULL;
goto fail;
}
priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm)) {
printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
"crypto API arc4\n");
priv->rx_tfm = NULL;
goto fail;
}
#endif
/* start WEP IV from a random value */
get_random_bytes(&priv->iv, 4);
return priv;
fail:
//#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
if (priv) {
if (priv->tfm)
crypto_free_tfm(priv->tfm);
kfree(priv);
}
#else
if (priv) {
if (priv->tx_tfm)
crypto_free_blkcipher(priv->tx_tfm);
if (priv->rx_tfm)
crypto_free_blkcipher(priv->rx_tfm);
kfree(priv);
}
#endif
return NULL;
}
static void prism2_wep_deinit(void *priv)
{
struct prism2_wep_data *_priv = priv;
//#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
if (_priv && _priv->tfm)
crypto_free_tfm(_priv->tfm);
#else
if (_priv) {
if (_priv->tx_tfm)
crypto_free_blkcipher(_priv->tx_tfm);
if (_priv->rx_tfm)
crypto_free_blkcipher(_priv->rx_tfm);
}
#endif
kfree(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;
//#if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED))
struct blkcipher_desc desc = {.tfm = wep->tx_tfm};
#endif
u32 klen, len;
u8 key[WEP_KEY_LEN + 3];
u8 *pos;
#ifndef JOHN_HWSEC
u32 crc;
u8 *icv;
struct scatterlist sg;
#endif
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);
#ifndef JOHN_HWSEC
/* Append little-endian CRC32 and encrypt it to produce ICV */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
crc = ~crc32_le(~0, pos, len);
#else
crc = ~ether_crc_le(len, pos);
#endif
icv = skb_put(skb, 4);
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
//#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
crypto_cipher_setkey(wep->tfm, key, klen);
sg.page = virt_to_page(pos);
sg.offset = offset_in_page(pos);
sg.length = len + 4;
crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
return 0;
#else
crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
sg.page = virt_to_page(pos);
sg.offset = offset_in_page(pos);
sg.length = len + 4;
#else
sg_init_one(&sg, pos, len+4);
#endif
return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
#endif
#endif /* JOHN_HWSEC */
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;
//#if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED))
struct blkcipher_desc desc = {.tfm = wep->rx_tfm};
#endif
u32 klen, plen;
u8 key[WEP_KEY_LEN + 3];
u8 keyidx, *pos;
#ifndef JOHN_HWSEC
u32 crc;
u8 icv[4];
struct scatterlist sg;
#endif
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;
#ifndef JOHN_HWSEC
//#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
crypto_cipher_setkey(wep->tfm, key, klen);
sg.page = virt_to_page(pos);
sg.offset = offset_in_page(pos);
sg.length = plen + 4;
crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
#else
crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
sg.page = virt_to_page(pos);
sg.offset = offset_in_page(pos);
sg.length = plen + 4;
#else
sg_init_one(&sg, pos, plen+4);
#endif
if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
return -7;
#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
crc = ~crc32_le(~0, pos, plen);
#else
crc = ~ether_crc_le(plen, pos);
#endif
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;
}
#endif /* JOHN_HWSEC */
/* 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 -1;
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 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);
}
void ieee80211_wep_null(void)
{
// printk("============>%s()\n", __FUNCTION__);
return;
}
#if 0
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
EXPORT_SYMBOL(ieee80211_wep_null);
#else
EXPORT_SYMBOL_NOVERS(ieee80211_wep_null);
#endif
#endif
//module_init(ieee80211_crypto_wep_init);
//module_exit(ieee80211_crypto_wep_exit);

View File

@ -0,0 +1,301 @@
/*******************************************************************************
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>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
The full GNU General Public License is included in this distribution in the
file called LICENSE.
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/config.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/version.h>
#include <linux/wireless.h>
#include <linux/etherdevice.h>
#include <asm/uaccess.h>
#include <net/arp.h>
#include <net/net_namespace.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 = kmalloc(
MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
GFP_KERNEL);
if (!ieee->networks) {
printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
ieee->dev->name);
return -ENOMEM;
}
memset(ieee->networks, 0,
MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
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);
dev->hard_start_xmit = ieee80211_xmit;
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);
init_timer(&ieee->crypt_deinit_timer);
ieee->crypt_deinit_timer.data = (unsigned long)ieee;
ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
spin_lock_init(&ieee->lock);
spin_lock_init(&ieee->wpax_suitlist_lock);
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;
ieee80211_softmac_init(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;
}
//These function were added to load crypte module autoly
ieee80211_tkip_null();
ieee80211_wep_null();
ieee80211_ccmp_null();
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;
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);
module_put(crypt->ops->owner);
}
kfree(crypt);
ieee->crypt[i] = NULL;
}
}
ieee80211_networks_free(ieee);
for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) {
list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) {
kfree(list_entry(p, struct ieee_ibss_seq, list));
list_del(p);
}
}
free_netdev(dev);
}
//#ifdef CONFIG_IEEE80211_DEBUG
#if 0
static int debug = 0;
u32 ieee80211_debug_level = 0;
struct proc_dir_entry *ieee80211_proc = NULL;
static int show_debug_level(char *page, char **start, off_t offset,
int count, int *eof, void *data)
{
return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
}
static int store_debug_level(struct file *file, const char *buffer,
unsigned long count, void *data)
{
char buf[] = "0x00000000";
unsigned long len = min(sizeof(buf) - 1, (u32)count);
char *p = (char *)buf;
unsigned long val;
if (copy_from_user(buf, buffer, len))
return count;
buf[len] = 0;
if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
p++;
if (p[0] == 'x' || p[0] == 'X')
p++;
val = simple_strtoul(p, &p, 16);
} else
val = simple_strtoul(p, &p, 10);
if (p == buf)
printk(KERN_INFO DRV_NAME
": %s is not in hex or decimal form.\n", buf);
else
ieee80211_debug_level = val;
return strnlen(buf, count);
}
static int __init ieee80211_init(void)
{
struct proc_dir_entry *e;
ieee80211_debug_level = debug;
ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net);
if (ieee80211_proc == NULL) {
IEEE80211_ERROR("Unable to create " DRV_NAME
" proc directory\n");
return -EIO;
}
e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
ieee80211_proc);
if (!e) {
remove_proc_entry(DRV_NAME, proc_net);
ieee80211_proc = NULL;
return -EIO;
}
e->read_proc = show_debug_level;
e->write_proc = store_debug_level;
e->data = NULL;
return 0;
}
static void __exit ieee80211_exit(void)
{
if (ieee80211_proc) {
remove_proc_entry("debug_level", ieee80211_proc);
remove_proc_entry(DRV_NAME, proc_net);
ieee80211_proc = NULL;
}
}
#include <linux/moduleparam.h>
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
module_exit(ieee80211_exit);
module_init(ieee80211_init);
#endif
#if 0
EXPORT_SYMBOL(alloc_ieee80211);
EXPORT_SYMBOL(free_ieee80211);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,602 @@
/* IEEE 802.11 SoftMAC layer
* Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
*
* Mostly extracted from the rtl8180-sa2400 driver for the
* in-kernel generic ieee802.11 stack.
*
* Some pieces of code might be stolen from ipw2100 driver
* copyright of who own it's copyright ;-)
*
* PS wx handler mostly stolen from hostap, copyright who
* own it's copyright ;-)
*
* released under the GPL
*/
#include "ieee80211.h"
/* FIXME: add A freqs */
const long ieee80211_wlan_frequencies[] = {
2412, 2417, 2422, 2427,
2432, 2437, 2442, 2447,
2452, 2457, 2462, 2467,
2472, 2484
};
int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
int ret;
struct iw_freq *fwrq = & wrqu->freq;
// printk("in %s\n",__FUNCTION__);
down(&ieee->wx_sem);
if(ieee->iw_mode == IW_MODE_INFRA){
ret = -EOPNOTSUPP;
goto out;
}
/* if setting by freq convert to channel */
if (fwrq->e == 1) {
if ((fwrq->m >= (int) 2.412e8 &&
fwrq->m <= (int) 2.487e8)) {
int f = fwrq->m / 100000;
int c = 0;
while ((c < 14) && (f != ieee80211_wlan_frequencies[c]))
c++;
/* hack to fall through */
fwrq->e = 0;
fwrq->m = c + 1;
}
}
if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){
ret = -EOPNOTSUPP;
goto out;
}else { /* Set the channel */
ieee->current_network.channel = fwrq->m;
ieee->set_chan(ieee->dev, ieee->current_network.channel);
if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
if(ieee->state == IEEE80211_LINKED){
ieee80211_stop_send_beacons(ieee);
ieee80211_start_send_beacons(ieee);
}
}
ret = 0;
out:
up(&ieee->wx_sem);
return ret;
}
int ieee80211_wx_get_freq(struct ieee80211_device *ieee,
struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
struct iw_freq *fwrq = & wrqu->freq;
if (ieee->current_network.channel == 0)
return -1;
fwrq->m = ieee->current_network.channel;
fwrq->e = 0;
return 0;
}
int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
unsigned long flags;
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
if (ieee->iw_mode == IW_MODE_MONITOR)
return -1;
/* We want avoid to give to the user inconsistent infos*/
spin_lock_irqsave(&ieee->lock, flags);
if (ieee->state != IEEE80211_LINKED &&
ieee->state != IEEE80211_LINKED_SCANNING &&
ieee->wap_set == 0)
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
else
memcpy(wrqu->ap_addr.sa_data,
ieee->current_network.bssid, ETH_ALEN);
spin_unlock_irqrestore(&ieee->lock, flags);
return 0;
}
int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *awrq,
char *extra)
{
int ret = 0;
u8 zero[] = {0,0,0,0,0,0};
unsigned long flags;
short ifup = ieee->proto_started;//dev->flags & IFF_UP;
struct sockaddr *temp = (struct sockaddr *)awrq;
//printk("=======Set WAP:");
ieee->sync_scan_hurryup = 1;
down(&ieee->wx_sem);
/* use ifconfig hw ether */
if (ieee->iw_mode == IW_MODE_MASTER){
ret = -1;
goto out;
}
if (temp->sa_family != ARPHRD_ETHER){
ret = -EINVAL;
goto out;
}
if (ifup)
ieee80211_stop_protocol(ieee);
/* just to avoid to give inconsistent infos in the
* get wx method. not really needed otherwise
*/
spin_lock_irqsave(&ieee->lock, flags);
memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0;
//printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]);
spin_unlock_irqrestore(&ieee->lock, flags);
if (ifup)
ieee80211_start_protocol(ieee);
out:
up(&ieee->wx_sem);
return ret;
}
int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b)
{
int len,ret = 0;
unsigned long flags;
if (ieee->iw_mode == IW_MODE_MONITOR)
return -1;
/* We want avoid to give to the user inconsistent infos*/
spin_lock_irqsave(&ieee->lock, flags);
if (ieee->current_network.ssid[0] == '\0' ||
ieee->current_network.ssid_len == 0){
ret = -1;
goto out;
}
if (ieee->state != IEEE80211_LINKED &&
ieee->state != IEEE80211_LINKED_SCANNING &&
ieee->ssid_set == 0){
ret = -1;
goto out;
}
len = ieee->current_network.ssid_len;
wrqu->essid.length = len;
strncpy(b,ieee->current_network.ssid,len);
wrqu->essid.flags = 1;
out:
spin_unlock_irqrestore(&ieee->lock, flags);
return ret;
}
int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
u32 target_rate = wrqu->bitrate.value;
//added by lizhaoming for auto mode
if(target_rate == -1){
ieee->rate = 110;
} else {
ieee->rate = target_rate/100000;
}
//FIXME: we might want to limit rate also in management protocols.
return 0;
}
int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
wrqu->bitrate.value = ieee->rate * 100000;
return 0;
}
int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
ieee->sync_scan_hurryup = 1;
down(&ieee->wx_sem);
if (wrqu->mode == ieee->iw_mode)
goto out;
if (wrqu->mode == IW_MODE_MONITOR){
ieee->dev->type = ARPHRD_IEEE80211;
}else{
ieee->dev->type = ARPHRD_ETHER;
}
if (!ieee->proto_started){
ieee->iw_mode = wrqu->mode;
}else{
ieee80211_stop_protocol(ieee);
ieee->iw_mode = wrqu->mode;
ieee80211_start_protocol(ieee);
}
out:
up(&ieee->wx_sem);
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
void ieee80211_wx_sync_scan_wq(struct work_struct *work)
{
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
#else
void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee)
{
#endif
//void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee)
//{
short chan;
chan = ieee->current_network.channel;
netif_carrier_off(ieee->dev);
if (ieee->data_hard_stop)
ieee->data_hard_stop(ieee->dev);
ieee80211_stop_send_beacons(ieee);
ieee->state = IEEE80211_LINKED_SCANNING;
ieee->link_change(ieee->dev);
ieee80211_start_scan_syncro(ieee);
ieee->set_chan(ieee->dev, chan);
ieee->state = IEEE80211_LINKED;
ieee->link_change(ieee->dev);
if (ieee->data_hard_resume)
ieee->data_hard_resume(ieee->dev);
if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
ieee80211_start_send_beacons(ieee);
netif_carrier_on(ieee->dev);
//YJ,add,080828, In prevent of lossing ping packet during scanning
//ieee80211_sta_ps_send_null_frame(ieee, false);
//YJ,add,080828,end
up(&ieee->wx_sem);
}
int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
int ret = 0;
down(&ieee->wx_sem);
if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
ret = -1;
goto out;
}
//YJ,add,080828
//In prevent of lossing ping packet during scanning
//ieee80211_sta_ps_send_null_frame(ieee, true);
//YJ,add,080828,end
if ( ieee->state == IEEE80211_LINKED){
queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
/* intentionally forget to up sem */
return 0;
}
out:
up(&ieee->wx_sem);
return ret;
}
int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
struct iw_request_info *a,
union iwreq_data *wrqu, char *extra)
{
int ret=0,len;
short proto_started;
unsigned long flags;
ieee->sync_scan_hurryup = 1;
down(&ieee->wx_sem);
proto_started = ieee->proto_started;
if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
ret= -E2BIG;
goto out;
}
if (ieee->iw_mode == IW_MODE_MONITOR){
ret= -1;
goto out;
}
if(proto_started)
ieee80211_stop_protocol(ieee);
/* this is just to be sure that the GET wx callback
* has consisten infos. not needed otherwise
*/
spin_lock_irqsave(&ieee->lock, flags);
if (wrqu->essid.flags && wrqu->essid.length) {
//YJ,modified,080819
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE;
#else
len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE;
#endif
memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819
strncpy(ieee->current_network.ssid, extra, len);
ieee->current_network.ssid_len = len;
ieee->ssid_set = 1;
//YJ,modified,080819,end
//YJ,add,080819,for hidden ap
if(len == 0){
memset(ieee->current_network.bssid, 0, ETH_ALEN);
ieee->current_network.capability = 0;
}
//YJ,add,080819,for hidden ap,end
}
else{
ieee->ssid_set = 0;
ieee->current_network.ssid[0] = '\0';
ieee->current_network.ssid_len = 0;
}
//printk("==========set essid %s!\n",ieee->current_network.ssid);
spin_unlock_irqrestore(&ieee->lock, flags);
if (proto_started)
ieee80211_start_protocol(ieee);
out:
up(&ieee->wx_sem);
return ret;
}
int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
wrqu->mode = ieee->iw_mode;
return 0;
}
int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int *parms = (int *)extra;
int enable = (parms[0] > 0);
short prev = ieee->raw_tx;
down(&ieee->wx_sem);
if(enable)
ieee->raw_tx = 1;
else
ieee->raw_tx = 0;
printk(KERN_INFO"raw TX is %s\n",
ieee->raw_tx ? "enabled" : "disabled");
if(ieee->iw_mode == IW_MODE_MONITOR)
{
if(prev == 0 && ieee->raw_tx){
if (ieee->data_hard_resume)
ieee->data_hard_resume(ieee->dev);
netif_carrier_on(ieee->dev);
}
if(prev && ieee->raw_tx == 1)
netif_carrier_off(ieee->dev);
}
up(&ieee->wx_sem);
return 0;
}
int ieee80211_wx_get_name(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
strcpy(wrqu->name, "802.11");
if(ieee->modulation & IEEE80211_CCK_MODULATION){
strcat(wrqu->name, "b");
if(ieee->modulation & IEEE80211_OFDM_MODULATION)
strcat(wrqu->name, "/g");
}else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
strcat(wrqu->name, "g");
if((ieee->state == IEEE80211_LINKED) ||
(ieee->state == IEEE80211_LINKED_SCANNING))
strcat(wrqu->name," linked");
else if(ieee->state != IEEE80211_NOLINK)
strcat(wrqu->name," link..");
return 0;
}
/* this is mostly stolen from hostap */
int ieee80211_wx_set_power(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret = 0;
if(
(!ieee->sta_wake_up) ||
(!ieee->ps_request_tx_ack) ||
(!ieee->enter_sleep_state) ||
(!ieee->ps_is_queue_empty)){
printk("ERROR. PS mode is tryied to be use but\
driver missed a callback\n\n");
return -1;
}
down(&ieee->wx_sem);
if (wrqu->power.disabled){
ieee->ps = IEEE80211_PS_DISABLED;
goto exit;
}
switch (wrqu->power.flags & IW_POWER_MODE) {
case IW_POWER_UNICAST_R:
ieee->ps = IEEE80211_PS_UNICAST;
break;
case IW_POWER_ALL_R:
ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST;
break;
case IW_POWER_ON:
ieee->ps = IEEE80211_PS_DISABLED;
break;
default:
ret = -EINVAL;
goto exit;
}
if (wrqu->power.flags & IW_POWER_TIMEOUT) {
ieee->ps_timeout = wrqu->power.value / 1000;
printk("Timeout %d\n",ieee->ps_timeout);
}
if (wrqu->power.flags & IW_POWER_PERIOD) {
ret = -EOPNOTSUPP;
goto exit;
//wrq->value / 1024;
}
exit:
up(&ieee->wx_sem);
return ret;
}
/* this is stolen from hostap */
int ieee80211_wx_get_power(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret =0;
down(&ieee->wx_sem);
if(ieee->ps == IEEE80211_PS_DISABLED){
wrqu->power.disabled = 1;
goto exit;
}
wrqu->power.disabled = 0;
// if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
wrqu->power.flags = IW_POWER_TIMEOUT;
wrqu->power.value = ieee->ps_timeout * 1000;
// } else {
// ret = -EOPNOTSUPP;
// goto exit;
//wrqu->power.flags = IW_POWER_PERIOD;
//wrqu->power.value = ieee->current_network.dtim_period *
// ieee->current_network.beacon_interval * 1024;
// }
if (ieee->ps & IEEE80211_PS_MBCAST)
wrqu->power.flags |= IW_POWER_ALL_R;
else
wrqu->power.flags |= IW_POWER_UNICAST_R;
exit:
up(&ieee->wx_sem);
return ret;
}
#if 0
EXPORT_SYMBOL(ieee80211_wx_get_essid);
EXPORT_SYMBOL(ieee80211_wx_set_essid);
EXPORT_SYMBOL(ieee80211_wx_set_rate);
EXPORT_SYMBOL(ieee80211_wx_get_rate);
EXPORT_SYMBOL(ieee80211_wx_set_wap);
EXPORT_SYMBOL(ieee80211_wx_get_wap);
EXPORT_SYMBOL(ieee80211_wx_set_mode);
EXPORT_SYMBOL(ieee80211_wx_get_mode);
EXPORT_SYMBOL(ieee80211_wx_set_scan);
EXPORT_SYMBOL(ieee80211_wx_get_freq);
EXPORT_SYMBOL(ieee80211_wx_set_freq);
EXPORT_SYMBOL(ieee80211_wx_set_rawtx);
EXPORT_SYMBOL(ieee80211_wx_get_name);
EXPORT_SYMBOL(ieee80211_wx_set_power);
EXPORT_SYMBOL(ieee80211_wx_get_power);
EXPORT_SYMBOL(ieee80211_wlan_frequencies);
#endif

View File

@ -0,0 +1,828 @@
/******************************************************************************
Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
The full GNU General Public License is included in this distribution in the
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************
Few modifications for Realtek's Wi-Fi drivers by
Andrea Merello <andreamrl@tiscali.it>
A special thanks goes to Realtek for their support !
******************************************************************************/
#include <linux/compiler.h>
//#include <linux/config.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/version.h>
#include <linux/wireless.h>
#include <linux/etherdevice.h>
#include <asm/uaccess.h>
#include <linux/if_vlan.h>
#include "ieee80211.h"
/*
802.11 Data Frame
802.11 frame_contorl for data frames - 2 bytes
,-----------------------------------------------------------------------------------------.
bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e |
|----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------|
val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x |
|----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------|
desc | ^-ver-^ | ^type-^ | ^-----subtype-----^ | to |from |more |retry| pwr |more |wep |
| | | x=0 data,x=1 data+ack | DS | DS |frag | | mgm |data | |
'-----------------------------------------------------------------------------------------'
/\
|
802.11 Data Frame |
,--------- 'ctrl' expands to >-----------'
|
,--'---,-------------------------------------------------------------.
Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
|------|------|---------|---------|---------|------|---------|------|
Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
| | tion | (BSSID) | | | ence | data | |
`--------------------------------------------------| |------'
Total: 28 non-data bytes `----.----'
|
.- 'Frame data' expands to <---------------------------'
|
V
,---------------------------------------------------.
Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
|------|------|---------|----------|------|---------|
Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
| DSAP | SSAP | | | | Packet |
| 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
`-----------------------------------------| |
Total: 8 non-data bytes `----.----'
|
.- 'IP Packet' expands, if WEP enabled, to <--'
|
V
,-----------------------.
Bytes | 4 | 0-2296 | 4 |
|-----|-----------|-----|
Desc. | IV | Encrypted | ICV |
| | IP Packet | |
`-----------------------'
Total: 8 non-data bytes
802.3 Ethernet Data Frame
,-----------------------------------------.
Bytes | 6 | 6 | 2 | Variable | 4 |
|-------|-------|------|-----------|------|
Desc. | Dest. | Source| Type | IP Packet | fcs |
| MAC | MAC | | | |
`-----------------------------------------'
Total: 18 non-data bytes
In the event that fragmentation is required, the incoming payload is split into
N parts of size ieee->fts. The first fragment contains the SNAP header and the
remaining packets are just data.
If encryption is enabled, each fragment payload size is reduced by enough space
to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
So if you have 1500 bytes of payload with ieee->fts set to 500 without
encryption it will take 3 frames. With WEP it will take 4 frames as the
payload of each frame is reduced to 492 bytes.
* SKB visualization
*
* ,- skb->data
* |
* | ETHERNET HEADER ,-<-- PAYLOAD
* | | 14 bytes from skb->data
* | 2 bytes for Type --> ,T. | (sizeof ethhdr)
* | | | |
* |,-Dest.--. ,--Src.---. | | |
* | 6 bytes| | 6 bytes | | | |
* v | | | | | |
* 0 | v 1 | v | v 2
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* ^ | ^ | ^ |
* | | | | | |
* | | | | `T' <---- 2 bytes for Type
* | | | |
* | | '---SNAP--' <-------- 6 bytes for SNAP
* | |
* `-IV--' <-------------------- 4 bytes for IV (WEP)
*
* SNAP HEADER
*
*/
static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
static inline int ieee80211_put_snap(u8 *data, u16 h_proto)
{
struct ieee80211_snap_hdr *snap;
u8 *oui;
snap = (struct ieee80211_snap_hdr *)data;
snap->dsap = 0xaa;
snap->ssap = 0xaa;
snap->ctrl = 0x03;
if (h_proto == 0x8137 || h_proto == 0x80f3)
oui = P802_1H_OUI;
else
oui = RFC1042_OUI;
snap->oui[0] = oui[0];
snap->oui[1] = oui[1];
snap->oui[2] = oui[2];
*(u16 *)(data + SNAP_SIZE) = htons(h_proto);
return SNAP_SIZE + sizeof(u16);
}
int ieee80211_encrypt_fragment(
struct ieee80211_device *ieee,
struct sk_buff *frag,
int hdr_len)
{
struct ieee80211_crypt_data* crypt = ieee->crypt[ieee->tx_keyidx];
int res;
/*added to care about null crypt condition, to solve that system hangs when shared keys error*/
if (!crypt || !crypt->ops)
return -1;
#ifdef CONFIG_IEEE80211_CRYPT_TKIP
struct ieee80211_hdr *header;
if (ieee->tkip_countermeasures &&
crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
header = (struct ieee80211_hdr *) frag->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
"TX packet to " MAC_FMT "\n",
ieee->dev->name, MAC_ARG(header->addr1));
}
return -1;
}
#endif
/* To encrypt, frame format is:
* IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
// PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption.
/* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
* call both MSDU and MPDU encryption functions from here. */
atomic_inc(&crypt->refcnt);
res = 0;
if (crypt->ops->encrypt_msdu)
res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv);
if (res == 0 && crypt->ops->encrypt_mpdu)
res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
ieee->dev->name, frag->len);
ieee->ieee_stats.tx_discards++;
return -1;
}
return 0;
}
void ieee80211_txb_free(struct ieee80211_txb *txb) {
int i;
if (unlikely(!txb))
return;
for (i = 0; i < txb->nr_frags; i++)
if (txb->fragments[i])
dev_kfree_skb_any(txb->fragments[i]);
kfree(txb);
}
struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
int gfp_mask)
{
struct ieee80211_txb *txb;
int i;
txb = kmalloc(
sizeof(struct ieee80211_txb) + (sizeof(u8*) * nr_frags),
gfp_mask);
if (!txb)
return NULL;
memset(txb, 0, sizeof(struct ieee80211_txb));
txb->nr_frags = nr_frags;
txb->frag_size = txb_size;
for (i = 0; i < nr_frags; i++) {
txb->fragments[i] = dev_alloc_skb(txb_size);
if (unlikely(!txb->fragments[i])) {
i--;
break;
}
}
if (unlikely(i != nr_frags)) {
while (i >= 0)
dev_kfree_skb_any(txb->fragments[i--]);
kfree(txb);
return NULL;
}
return txb;
}
// Classify the to-be send data packet
// Need to acquire the sent queue index.
static int
ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network)
{
struct ether_header *eh = (struct ether_header*)skb->data;
unsigned int wme_UP = 0;
if(!network->QoS_Enable) {
skb->priority = 0;
return(wme_UP);
}
if(eh->ether_type == __constant_htons(ETHERTYPE_IP)) {
const struct iphdr *ih = (struct iphdr*)(skb->data + \
sizeof(struct ether_header));
wme_UP = (ih->tos >> 5)&0x07;
} else if (vlan_tx_tag_present(skb)) {//vtag packet
#ifndef VLAN_PRI_SHIFT
#define VLAN_PRI_SHIFT 13 /* Shift to find VLAN user priority */
#define VLAN_PRI_MASK 7 /* Mask for user priority bits in VLAN */
#endif
u32 tag = vlan_tx_tag_get(skb);
wme_UP = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
} else if(ETH_P_PAE == ntohs(((struct ethhdr *)skb->data)->h_proto)) {
//printk(KERN_WARNING "type = normal packet\n");
wme_UP = 7;
}
skb->priority = wme_UP;
return(wme_UP);
}
#ifdef _RTL8187_EXT_PATCH_
// based on part of ieee80211_xmit. Mainly allocate txb. ieee->lock is held
struct ieee80211_txb *ieee80211_ext_alloc_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
struct ieee80211_device *ieee = netdev_priv(dev);
#else
struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv;
#endif
struct ieee80211_txb *txb = NULL;
struct ieee80211_hdr_3addr *frag_hdr;
int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
int ether_type;
int bytes, QOS_ctl;
struct sk_buff *skb_frag;
ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
/* Advance the SKB to the start of the payload */
skb_pull(skb, sizeof(struct ethhdr));
/* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16);
/* Determine fragmentation size based on destination (multicast
* and broadcast are not fragmented) */
// if (is_multicast_ether_addr(dest) ||
// is_broadcast_ether_addr(dest)) {
if (is_multicast_ether_addr(header->addr1) ||
is_broadcast_ether_addr(header->addr1)) {
frag_size = MAX_FRAG_THRESHOLD;
QOS_ctl = QOS_CTL_NOTCONTAIN_ACK;
}
else {
//printk(KERN_WARNING "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&frag_size = %d\n", frag_size);
frag_size = ieee->fts;//default:392
QOS_ctl = 0;
}
if(isQoS) {
QOS_ctl |= skb->priority; //set in the ieee80211_classify
*pQOS_ctl = cpu_to_le16(QOS_ctl);
}
//printk(KERN_WARNING "header size = %d, QOS_ctl = %x\n", hdr_len,QOS_ctl);
/* Determine amount of payload per fragment. Regardless of if
* this stack is providing the full 802.11 header, one will
* eventually be affixed to this fragment -- so we must account for
* it when determining the amount of payload space. */
//bytes_per_frag = frag_size - (IEEE80211_3ADDR_LEN + (ieee->current_network->QoS_Enable ? 2:0));
bytes_per_frag = frag_size - hdr_len;
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
bytes_per_frag -= IEEE80211_FCS_LEN;
/* Each fragment may need to have room for encryptiong pre/postfix */
if (isEncrypt)
bytes_per_frag -= crypt->ops->extra_prefix_len +
crypt->ops->extra_postfix_len;
/* Number of fragments is the total bytes_per_frag /
* payload_per_fragment */
nr_frags = bytes / bytes_per_frag;
bytes_last_frag = bytes % bytes_per_frag;
if (bytes_last_frag)
nr_frags++;
else
bytes_last_frag = bytes_per_frag;
/* When we allocate the TXB we allocate enough space for the reserve
* and full fragment bytes (bytes_per_frag doesn't include prefix,
* postfix, header, FCS, etc.) */
txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC);
if (unlikely(!txb)) {
printk(KERN_WARNING "%s: Could not allocate TXB\n",
ieee->dev->name);
return NULL;
}
txb->encrypted = isEncrypt;
txb->payload_size = bytes;
for (i = 0; i < nr_frags; i++) {
skb_frag = txb->fragments[i];
skb_frag->priority = UP2AC(skb->priority);
if (isEncrypt)
skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
frag_hdr = (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len);
memcpy(frag_hdr, (void *)header, hdr_len);
/* If this is not the last fragment, then add the MOREFRAGS
* bit to the frame control */
if (i != nr_frags - 1) {
frag_hdr->frame_ctl = cpu_to_le16(
header->frame_ctl | IEEE80211_FCTL_MOREFRAGS);
bytes = bytes_per_frag;
} else {
/* The last fragment takes the remaining length */
bytes = bytes_last_frag;
}
frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i);
//frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl<<4 | i);
//
/* Put a SNAP header on the first fragment */
if (i == 0) {
ieee80211_put_snap(
skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), ether_type);
bytes -= SNAP_SIZE + sizeof(u16);
}
memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
/* Advance the SKB... */
skb_pull(skb, bytes);
/* Encryption routine will move the header forward in order
* to insert the IV between the header and the payload */
if (isEncrypt)
ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
skb_put(skb_frag, 4);
}
// Advance sequence number in data frame.
//printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N");
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
else
ieee->seq_ctrl[0]++;
// stanley, just for debug
/*
{
int j=0;
for(j=0;j<nr_frags;j++)
{
int i;
struct sk_buff *skb = txb->fragments[j];
printk("send(%d): ", j);
for (i=0;i<skb->len;i++)
printk("%02X ", skb->data[i]&0xff);
printk("\n");
}
}
*/
return txb;
}
// based on part of ieee80211_xmit. Mainly allocate txb. ieee->lock is held
// Assume no encryption, no FCS computing
struct ieee80211_txb *ieee80211_ext_reuse_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
struct ieee80211_device *ieee = netdev_priv(dev);
#else
struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv;
#endif
struct ieee80211_txb *txb = NULL;
struct ieee80211_hdr_3addr *frag_hdr;
int ether_type;
int bytes, QOS_ctl;
ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
/* Advance the SKB to the start of the payload */
skb_pull(skb, sizeof(struct ethhdr));
/* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16);
if (is_multicast_ether_addr(header->addr1) ||
is_broadcast_ether_addr(header->addr1)) {
QOS_ctl = QOS_CTL_NOTCONTAIN_ACK;
}
else {
QOS_ctl = 0;
}
if(isQoS) {
QOS_ctl |= skb->priority; //set in the ieee80211_classify
*pQOS_ctl = cpu_to_le16(QOS_ctl);
}
txb = kmalloc( sizeof(struct ieee80211_txb) + sizeof(u8*), GFP_ATOMIC );
if (unlikely(!txb)) {
printk(KERN_WARNING "%s: Could not allocate TXB\n",
ieee->dev->name);
return NULL;
}
txb->nr_frags = 1;
txb->frag_size = bytes;
txb->encrypted = isEncrypt;
txb->payload_size = bytes;
txb->fragments[0] = skb;
ieee80211_put_snap(
skb_push(skb, SNAP_SIZE + sizeof(u16)), ether_type);
frag_hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, hdr_len);
memcpy(frag_hdr, (void *)header, hdr_len);
frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | 0);
skb->priority = UP2AC(skb->priority);
// Advance sequence number in data frame.
//printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N");
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
else
ieee->seq_ctrl[0]++;
return txb;
}
#endif // _RTL8187_EXT_PATCH_
/* SKBs are added to the ieee->tx_queue. */
int ieee80211_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_device *ieee = netdev_priv(dev);
struct ieee80211_txb *txb = NULL;
struct ieee80211_hdr_3addr_QOS *frag_hdr;
int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
unsigned long flags;
struct net_device_stats *stats = &ieee->stats;
int ether_type, encrypt;
int bytes, fc, QOS_ctl, hdr_len;
struct sk_buff *skb_frag;
//struct ieee80211_hdr header = { /* Ensure zero initialized */
// .duration_id = 0,
// .seq_ctl = 0
//};
struct ieee80211_hdr_3addr_QOS header = { /* Ensure zero initialized */
.duration_id = 0,
.seq_ctl = 0,
.QOS_ctl = 0
};
u8 dest[ETH_ALEN], src[ETH_ALEN];
struct ieee80211_crypt_data* crypt;
//printk(KERN_WARNING "upper layer packet!\n");
spin_lock_irqsave(&ieee->lock, flags);
/* If there is no driver handler to take the TXB, dont' bother
* creating it... */
if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))||
((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) {
printk(KERN_WARNING "%s: No xmit handler.\n",
ieee->dev->name);
goto success;
}
ieee80211_classify(skb,&ieee->current_network);
if(likely(ieee->raw_tx == 0)){
if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
printk(KERN_WARNING "%s: skb too small (%d).\n",
ieee->dev->name, skb->len);
goto success;
}
#ifdef _RTL8187_EXT_PATCH_
// note, skb->priority which was set by ieee80211_classify, and used by physical tx
if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_xmit))
{
txb = ieee->ext_patch_ieee80211_xmit(skb, dev);
goto success;
}
#endif
ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
crypt = ieee->crypt[ieee->tx_keyidx];
encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
ieee->host_encrypt && crypt && crypt->ops;
if (!encrypt && ieee->ieee802_1x &&
ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
stats->tx_dropped++;
goto success;
}
#ifdef CONFIG_IEEE80211_DEBUG
if (crypt && !encrypt && ether_type == ETH_P_PAE) {
struct eapol *eap = (struct eapol *)(skb->data +
sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16));
IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n",
eap_get_type(eap->type));
}
#endif
/* Save source and destination addresses */
memcpy(&dest, skb->data, ETH_ALEN);
memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN);
/* Advance the SKB to the start of the payload */
skb_pull(skb, sizeof(struct ethhdr));
/* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16);
if(ieee->current_network.QoS_Enable) {
if (encrypt)
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA |
IEEE80211_FCTL_WEP;
else
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
} else {
if (encrypt)
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_WEP;
else
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
}
if (ieee->iw_mode == IW_MODE_INFRA) {
fc |= IEEE80211_FCTL_TODS;
/* To DS: Addr1 = BSSID, Addr2 = SA,
Addr3 = DA */
memcpy(&header.addr1, ieee->current_network.bssid, ETH_ALEN);
memcpy(&header.addr2, &src, ETH_ALEN);
memcpy(&header.addr3, &dest, ETH_ALEN);
} else if (ieee->iw_mode == IW_MODE_ADHOC) {
/* not From/To DS: Addr1 = DA, Addr2 = SA,
Addr3 = BSSID */
memcpy(&header.addr1, dest, ETH_ALEN);
memcpy(&header.addr2, src, ETH_ALEN);
memcpy(&header.addr3, ieee->current_network.bssid, ETH_ALEN);
}
// printk(KERN_WARNING "essid MAC address is "MAC_FMT, MAC_ARG(&header.addr1));
header.frame_ctl = cpu_to_le16(fc);
//hdr_len = IEEE80211_3ADDR_LEN;
/* Determine fragmentation size based on destination (multicast
* and broadcast are not fragmented) */
// if (is_multicast_ether_addr(dest) ||
// is_broadcast_ether_addr(dest)) {
if (is_multicast_ether_addr(header.addr1) ||
is_broadcast_ether_addr(header.addr1)) {
frag_size = MAX_FRAG_THRESHOLD;
QOS_ctl = QOS_CTL_NOTCONTAIN_ACK;
}
else {
//printk(KERN_WARNING "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&frag_size = %d\n", frag_size);
frag_size = ieee->fts;//default:392
QOS_ctl = 0;
}
if (ieee->current_network.QoS_Enable) {
hdr_len = IEEE80211_3ADDR_LEN + 2;
QOS_ctl |= skb->priority; //set in the ieee80211_classify
header.QOS_ctl = cpu_to_le16(QOS_ctl);
} else {
hdr_len = IEEE80211_3ADDR_LEN;
}
//printk(KERN_WARNING "header size = %d, QOS_ctl = %x\n", hdr_len,QOS_ctl);
/* Determine amount of payload per fragment. Regardless of if
* this stack is providing the full 802.11 header, one will
* eventually be affixed to this fragment -- so we must account for
* it when determining the amount of payload space. */
//bytes_per_frag = frag_size - (IEEE80211_3ADDR_LEN + (ieee->current_network->QoS_Enable ? 2:0));
bytes_per_frag = frag_size - hdr_len;
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
bytes_per_frag -= IEEE80211_FCS_LEN;
/* Each fragment may need to have room for encryptiong pre/postfix */
if (encrypt)
bytes_per_frag -= crypt->ops->extra_prefix_len +
crypt->ops->extra_postfix_len;
/* Number of fragments is the total bytes_per_frag /
* payload_per_fragment */
nr_frags = bytes / bytes_per_frag;
bytes_last_frag = bytes % bytes_per_frag;
if (bytes_last_frag)
nr_frags++;
else
bytes_last_frag = bytes_per_frag;
/* When we allocate the TXB we allocate enough space for the reserve
* and full fragment bytes (bytes_per_frag doesn't include prefix,
* postfix, header, FCS, etc.) */
txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC);
if (unlikely(!txb)) {
printk(KERN_WARNING "%s: Could not allocate TXB\n",
ieee->dev->name);
goto failed;
}
txb->encrypted = encrypt;
txb->payload_size = bytes;
for (i = 0; i < nr_frags; i++) {
skb_frag = txb->fragments[i];
skb_frag->priority = UP2AC(skb->priority);
if (encrypt)
skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
frag_hdr = (struct ieee80211_hdr_3addr_QOS *)skb_put(skb_frag, hdr_len);
memcpy(frag_hdr, &header, hdr_len);
/* If this is not the last fragment, then add the MOREFRAGS
* bit to the frame control */
if (i != nr_frags - 1) {
frag_hdr->frame_ctl = cpu_to_le16(
fc | IEEE80211_FCTL_MOREFRAGS);
bytes = bytes_per_frag;
} else {
/* The last fragment takes the remaining length */
bytes = bytes_last_frag;
}
if(ieee->current_network.QoS_Enable) {
// add 1 only indicate to corresponding seq number control 2006/7/12
frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[UP2AC(skb->priority)+1]<<4 | i);
//printk(KERN_WARNING "skb->priority = %d,", skb->priority);
//printk(KERN_WARNING "type:%d: seq = %d\n",UP2AC(skb->priority),ieee->seq_ctrl[UP2AC(skb->priority)+1]);
} else {
frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i);
}
//frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl<<4 | i);
//
/* Put a SNAP header on the first fragment */
if (i == 0) {
ieee80211_put_snap(
skb_put(skb_frag, SNAP_SIZE + sizeof(u16)),
ether_type);
bytes -= SNAP_SIZE + sizeof(u16);
}
memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
/* Advance the SKB... */
skb_pull(skb, bytes);
/* Encryption routine will move the header forward in order
* to insert the IV between the header and the payload */
if (encrypt)
ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
skb_put(skb_frag, 4);
}
// Advance sequence number in data frame.
//printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N");
if (ieee->current_network.QoS_Enable) {
if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF)
ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0;
else
ieee->seq_ctrl[UP2AC(skb->priority) + 1]++;
} else {
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
else
ieee->seq_ctrl[0]++;
}
//---
}else{
if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) {
printk(KERN_WARNING "%s: skb too small (%d).\n",
ieee->dev->name, skb->len);
goto success;
}
txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC);
if(!txb){
printk(KERN_WARNING "%s: Could not allocate TXB\n",
ieee->dev->name);
goto failed;
}
txb->encrypted = 0;
txb->payload_size = skb->len;
memcpy(skb_put(txb->fragments[0],skb->len), skb->data, skb->len);
}
success:
spin_unlock_irqrestore(&ieee->lock, flags);
#ifdef _RTL8187_EXT_PATCH_
// Sometimes, extension mode can reuse skb (by txb->fragments[0])
if( ! ((ieee->iw_mode == ieee->iw_ext_mode) && txb && (txb->fragments[0] == skb)) )
#endif
dev_kfree_skb_any(skb);
if (txb) {
if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE){
ieee80211_softmac_xmit(txb, ieee);
}else{
if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
stats->tx_packets++;
stats->tx_bytes += txb->payload_size;
return 0;
}
ieee80211_txb_free(txb);
}
}
return 0;
failed:
spin_unlock_irqrestore(&ieee->lock, flags);
netif_stop_queue(dev);
stats->tx_errors++;
return 1;
}
#if 0
EXPORT_SYMBOL(ieee80211_txb_free);
#ifdef _RTL8187_EXT_PATCH_
EXPORT_SYMBOL(ieee80211_alloc_txb);
EXPORT_SYMBOL(ieee80211_ext_alloc_txb);
EXPORT_SYMBOL(ieee80211_ext_reuse_txb);
#endif // _RTL8187_EXT_PATCH_
#endif

View File

@ -0,0 +1,884 @@
/******************************************************************************
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>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
The full GNU General Public License is included in this distribution in the
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
#include <linux/wireless.h>
#include <linux/version.h>
#include <linux/kmod.h>
#include <linux/module.h>
#include "ieee80211.h"
static const char *ieee80211_modes[] = {
"?", "a", "b", "ab", "g", "ag", "bg", "abg"
};
#ifdef FEDORACORE_9
#define IN_FEDORACORE_9 1
#else
#define IN_FEDORACORE_9 0
#endif
#define MAX_CUSTOM_LEN 64
static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
char *start, char *stop,
struct ieee80211_network *network,
struct iw_request_info *info)
{
char custom[MAX_CUSTOM_LEN];
char *p;
struct iw_event iwe;
int i, j;
u8 max_rate, rate;
/* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
#else
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
#endif
/* Remaining entries will be displayed in the order we provide them */
/* Add the ESSID */
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
//YJ,modified,080903,for hidden ap
//if (network->flags & NETWORK_EMPTY_ESSID) {
if (network->ssid_len == 0) {
//YJ,modified,080903,end
iwe.u.data.length = sizeof("<hidden>");
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
#else
start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
#endif
} else {
iwe.u.data.length = min(network->ssid_len, (u8)32);
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
#else
start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
#endif
}
//printk("ESSID: %s\n",network->ssid);
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]);
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
#else
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
#endif
/* Add mode */
iwe.cmd = SIOCGIWMODE;
if (network->capability &
(WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
if (network->capability & WLAN_CAPABILITY_BSS)
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
#else
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
#endif
}
/* Add frequency/channel */
iwe.cmd = SIOCGIWFREQ;
/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
iwe.u.freq.e = 3; */
iwe.u.freq.m = network->channel;
iwe.u.freq.e = 0;
iwe.u.freq.i = 0;
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
#else
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
#endif
/* Add encryption capability */
iwe.cmd = SIOCGIWENCODE;
if (network->capability & WLAN_CAPABILITY_PRIVACY)
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
#else
start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
#endif
/* Add basic and extended rates */
max_rate = 0;
p = custom;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
for (i = 0, j = 0; i < network->rates_len; ) {
if (j < network->rates_ex_len &&
((network->rates_ex[j] & 0x7F) <
(network->rates[i] & 0x7F)))
rate = network->rates_ex[j++] & 0x7F;
else
rate = network->rates[i++] & 0x7F;
if (rate > max_rate)
max_rate = rate;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
"%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
}
for (; j < network->rates_ex_len; j++) {
rate = network->rates_ex[j] & 0x7F;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
"%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
if (rate > max_rate)
max_rate = rate;
}
iwe.cmd = SIOCGIWRATE;
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
iwe.u.bitrate.value = max_rate * 500000;
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN);
#else
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN);
#endif
iwe.cmd = IWEVCUSTOM;
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
#else
start = iwe_stream_add_point(start, stop, &iwe, custom);
#endif
/* Add quality statistics */
/* TODO: Fix these values... */
if (network->stats.signal == 0 || network->stats.rssi == 0)
printk("========>signal:%d, rssi:%d\n", network->stats.signal, network->stats.rssi);
iwe.cmd = IWEVQUAL;
// printk("SIGNAL: %d,RSSI: %d,NOISE: %d\n",network->stats.signal,network->stats.rssi,network->stats.noise);
iwe.u.qual.qual = network->stats.signalstrength;
iwe.u.qual.level = network->stats.signal;
iwe.u.qual.noise = network->stats.noise;
iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
iwe.u.qual.updated = 7;
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
#else
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
#endif
iwe.cmd = IWEVCUSTOM;
p = custom;
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
#else
start = iwe_stream_add_point(start, stop, &iwe, custom);
#endif
#if 0
if (ieee->wpa_enabled && network->wpa_ie_len){
char buf[MAX_WPA_IE_LEN * 2 + 30];
// printk("WPA IE\n");
u8 *p = buf;
p += sprintf(p, "wpa_ie=");
for (i = 0; i < network->wpa_ie_len; i++) {
p += sprintf(p, "%02x", network->wpa_ie[i]);
}
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVCUSTOM;
iwe.u.data.length = strlen(buf);
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
#else
start = iwe_stream_add_point(start, stop, &iwe, buf);
#endif
}
if (ieee->wpa_enabled && network->rsn_ie_len){
char buf[MAX_WPA_IE_LEN * 2 + 30];
u8 *p = buf;
p += sprintf(p, "rsn_ie=");
for (i = 0; i < network->rsn_ie_len; i++) {
p += sprintf(p, "%02x", network->rsn_ie[i]);
}
#else
memset(&iwe, 0, sizeof(iwe));
if (network->wpa_ie_len) {
// printk("wpa_ie_len:%d\n", network->wpa_ie_len);
char buf[MAX_WPA_IE_LEN];
memcpy(buf, network->wpa_ie, network->wpa_ie_len);
iwe.cmd = IWEVGENIE;
iwe.u.data.length = network->wpa_ie_len;
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
#else
start = iwe_stream_add_point(start, stop, &iwe, buf);
#endif
}
memset(&iwe, 0, sizeof(iwe));
if (network->rsn_ie_len) {
// printk("=====>rsn_ie_len:\n", network->rsn_ie_len);
#if 0
{
int i;
for (i=0; i<network->rsn_ie_len; i++);
printk("%2x ", network->rsn_ie[i]);
printk("\n");
}
#endif
char buf[MAX_WPA_IE_LEN];
memcpy(buf, network->rsn_ie, network->rsn_ie_len);
iwe.cmd = IWEVGENIE;
iwe.u.data.length = network->rsn_ie_len;
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
#else
start = iwe_stream_add_point(start, stop, &iwe, buf);
#endif
}
#endif
/* Add EXTRA: Age to display seconds since last beacon/probe response
* for given network. */
iwe.cmd = IWEVCUSTOM;
p = custom;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
" Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9)
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
#else
start = iwe_stream_add_point(start, stop, &iwe, custom);
#endif
return start;
}
int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ieee80211_network *network;
unsigned long flags;
int err = 0;
char *ev = extra;
char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
//char *stop = ev + IW_SCAN_MAX_DATA;
int i = 0;
IEEE80211_DEBUG_WX("Getting scan\n");
down(&ieee->wx_sem);
spin_lock_irqsave(&ieee->lock, flags);
if(!ieee->bHwRadioOff)
{
list_for_each_entry(network, &ieee->network_list, list) {
i++;
if((stop-ev)<200)
{
err = -E2BIG;
break;
}
if (ieee->scan_age == 0 ||
time_after(network->last_scanned + ieee->scan_age, jiffies))
{
ev = rtl818x_translate_scan(ieee, ev, stop, network, info);
}
else
IEEE80211_DEBUG_SCAN(
"Not showing network '%s ("
MAC_FMT ")' due to age (%lums).\n",
escape_essid(network->ssid,
network->ssid_len),
MAC_ARG(network->bssid),
(jiffies - network->last_scanned) / (HZ / 100));
}
}
spin_unlock_irqrestore(&ieee->lock, flags);
up(&ieee->wx_sem);
wrqu->data.length = ev - extra;
wrqu->data.flags = 0;
IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
return err;
}
int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *keybuf)
{
struct iw_point *erq = &(wrqu->encoding);
struct net_device *dev = ieee->dev;
struct ieee80211_security sec = {
.flags = 0
};
int i, key, key_provided, len;
struct ieee80211_crypt_data **crypt;
IEEE80211_DEBUG_WX("SET_ENCODE\n");
key = erq->flags & IW_ENCODE_INDEX;
if (key) {
if (key > WEP_KEYS)
return -EINVAL;
key--;
key_provided = 1;
} else {
key_provided = 0;
key = ieee->tx_keyidx;
}
IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
"provided" : "default");
crypt = &ieee->crypt[key];
if (erq->flags & IW_ENCODE_DISABLED) {
if (key_provided && *crypt) {
IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
key);
ieee80211_crypt_delayed_deinit(ieee, crypt);
} else
IEEE80211_DEBUG_WX("Disabling encryption.\n");
/* Check all the keys to see if any are still configured,
* and if no key index was provided, de-init them all */
for (i = 0; i < WEP_KEYS; i++) {
if (ieee->crypt[i] != NULL) {
if (key_provided)
break;
ieee80211_crypt_delayed_deinit(
ieee, &ieee->crypt[i]);
}
}
if (i == WEP_KEYS) {
sec.enabled = 0;
sec.level = SEC_LEVEL_0;
sec.flags |= SEC_ENABLED | SEC_LEVEL;
}
goto done;
}
sec.enabled = 1;
sec.flags |= SEC_ENABLED;
if (*crypt != NULL && (*crypt)->ops != NULL &&
strcmp((*crypt)->ops->name, "WEP") != 0) {
/* changing to use WEP; deinit previously used algorithm
* on this key */
ieee80211_crypt_delayed_deinit(ieee, crypt);
}
if (*crypt == NULL) {
struct ieee80211_crypt_data *new_crypt;
/* take WEP into use */
new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
GFP_KERNEL);
if (new_crypt == NULL)
return -ENOMEM;
memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ieee80211_get_crypto_ops("WEP");
if (!new_crypt->ops) {
request_module("ieee80211_crypt_wep");
new_crypt->ops = ieee80211_get_crypto_ops("WEP");
}
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
new_crypt->priv = new_crypt->ops->init(key);
if (!new_crypt->ops || !new_crypt->priv) {
kfree(new_crypt);
new_crypt = NULL;
printk(KERN_WARNING "%s: could not initialize WEP: "
"load module ieee80211_crypt_wep\n",
dev->name);
return -EOPNOTSUPP;
}
*crypt = new_crypt;
}
/* If a new key was provided, set it up */
if (erq->length > 0) {
len = erq->length <= 5 ? 5 : 13;
memcpy(sec.keys[key], keybuf, erq->length);
if (len > erq->length)
memset(sec.keys[key] + erq->length, 0,
len - erq->length);
IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
key, escape_essid(sec.keys[key], len),
erq->length, len);
sec.key_sizes[key] = len;
(*crypt)->ops->set_key(sec.keys[key], len, NULL,
(*crypt)->priv);
sec.flags |= (1 << key);
/* This ensures a key will be activated if no key is
* explicitely set */
if (key == sec.active_key)
sec.flags |= SEC_ACTIVE_KEY;
ieee->tx_keyidx = key;//by wb 080312
} else {
len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
NULL, (*crypt)->priv);
if (len == 0) {
/* Set a default key of all 0 */
IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
key);
memset(sec.keys[key], 0, 13);
(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
(*crypt)->priv);
sec.key_sizes[key] = 13;
sec.flags |= (1 << key);
}
/* No key data - just set the default TX key index */
if (key_provided) {
IEEE80211_DEBUG_WX(
"Setting key %d to default Tx key.\n", key);
ieee->tx_keyidx = key;
sec.active_key = key;
sec.flags |= SEC_ACTIVE_KEY;
}
}
done:
ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
sec.flags |= SEC_AUTH_MODE;
IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
"OPEN" : "SHARED KEY");
/* For now we just support WEP, so only set that security level...
* TODO: When WPA is added this is one place that needs to change */
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
if (ieee->set_security)
ieee->set_security(dev, &sec);
/* Do not reset port if card is in Managed mode since resetting will
* generate new IEEE 802.11 authentication which may end up in looping
* with IEEE 802.1X. If your hardware requires a reset after WEP
* configuration (for example... Prism2), implement the reset_port in
* the callbacks structures used to initialize the 802.11 stack. */
if (ieee->reset_on_keychange &&
ieee->iw_mode != IW_MODE_INFRA &&
ieee->reset_port && ieee->reset_port(dev)) {
printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
return -EINVAL;
}
return 0;
}
int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *keybuf)
{
struct iw_point *erq = &(wrqu->encoding);
int len, key;
struct ieee80211_crypt_data *crypt;
IEEE80211_DEBUG_WX("GET_ENCODE\n");
if(ieee->iw_mode == IW_MODE_MONITOR)
return -1;
key = erq->flags & IW_ENCODE_INDEX;
if (key) {
if (key > WEP_KEYS)
return -EINVAL;
key--;
} else
key = ieee->tx_keyidx;
crypt = ieee->crypt[key];
erq->flags = key + 1;
if (crypt == NULL || crypt->ops == NULL) {
erq->length = 0;
erq->flags |= IW_ENCODE_DISABLED;
return 0;
}
if (strcmp(crypt->ops->name, "WEP") != 0) {
/* only WEP is supported with wireless extensions, so just
* report that encryption is used */
erq->length = 0;
erq->flags |= IW_ENCODE_ENABLED;
return 0;
}
len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
erq->length = (len >= 0 ? len : 0);
erq->flags |= IW_ENCODE_ENABLED;
if (ieee->open_wep)
erq->flags |= IW_ENCODE_OPEN;
else
erq->flags |= IW_ENCODE_RESTRICTED;
return 0;
}
int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct net_device *dev = ieee->dev;
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int i, idx, ret = 0;
int group_key = 0;
const char *alg, *module;
struct ieee80211_crypto_ops *ops;
struct ieee80211_crypt_data **crypt;
struct ieee80211_security sec = {
.flags = 0,
};
//printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
if (idx < 1 || idx > WEP_KEYS)
return -EINVAL;
idx--;
} else
idx = ieee->tx_keyidx;
if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
crypt = &ieee->crypt[idx];
group_key = 1;
} else {
/* some Cisco APs use idx>0 for unicast in dynamic WEP */
//printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
return -EINVAL;
if (ieee->iw_mode == IW_MODE_INFRA)
crypt = &ieee->crypt[idx];
else
return -EINVAL;
}
sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
if ((encoding->flags & IW_ENCODE_DISABLED) ||
ext->alg == IW_ENCODE_ALG_NONE) {
if (*crypt)
ieee80211_crypt_delayed_deinit(ieee, crypt);
for (i = 0; i < WEP_KEYS; i++)
if (ieee->crypt[i] != NULL)
break;
if (i == WEP_KEYS) {
sec.enabled = 0;
// sec.encrypt = 0;
sec.level = SEC_LEVEL_0;
sec.flags |= SEC_LEVEL;
}
//printk("disabled: flag:%x\n", encoding->flags);
goto done;
}
sec.enabled = 1;
// sec.encrypt = 1;
#if 0
if (group_key ? !ieee->host_mc_decrypt :
!(ieee->host_encrypt || ieee->host_decrypt ||
ieee->host_encrypt_msdu))
goto skip_host_crypt;
#endif
switch (ext->alg) {
case IW_ENCODE_ALG_WEP:
alg = "WEP";
module = "ieee80211_crypt_wep";
break;
case IW_ENCODE_ALG_TKIP:
alg = "TKIP";
module = "ieee80211_crypt_tkip";
break;
case IW_ENCODE_ALG_CCMP:
alg = "CCMP";
module = "ieee80211_crypt_ccmp";
break;
default:
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
ret = -EINVAL;
goto done;
}
// printk("8-09-08-9=====>%s, alg name:%s\n",__FUNCTION__, alg);
ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL) {
request_module(module);
ops = ieee80211_get_crypto_ops(alg);
}
if (ops == NULL) {
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
printk("========>unknown crypto alg %d\n", ext->alg);
ret = -EINVAL;
goto done;
}
if (*crypt == NULL || (*crypt)->ops != ops) {
struct ieee80211_crypt_data *new_crypt;
ieee80211_crypt_delayed_deinit(ieee, crypt);
new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
if (new_crypt == NULL) {
ret = -ENOMEM;
goto done;
}
new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
new_crypt->priv = new_crypt->ops->init(idx);
if (new_crypt->priv == NULL) {
kfree(new_crypt);
ret = -EINVAL;
goto done;
}
*crypt = new_crypt;
}
if (ext->key_len > 0 && (*crypt)->ops->set_key &&
(*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
(*crypt)->priv) < 0) {
IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
printk("key setting failed\n");
ret = -EINVAL;
goto done;
}
#if 1
//skip_host_crypt:
//printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
ieee->tx_keyidx = idx;
sec.active_key = idx;
sec.flags |= SEC_ACTIVE_KEY;
}
if (ext->alg != IW_ENCODE_ALG_NONE) {
memcpy(sec.keys[idx], ext->key, ext->key_len);
sec.key_sizes[idx] = ext->key_len;
sec.flags |= (1 << idx);
if (ext->alg == IW_ENCODE_ALG_WEP) {
// sec.encode_alg[idx] = SEC_ALG_WEP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_1;
} else if (ext->alg == IW_ENCODE_ALG_TKIP) {
// sec.encode_alg[idx] = SEC_ALG_TKIP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_2;
} else if (ext->alg == IW_ENCODE_ALG_CCMP) {
// sec.encode_alg[idx] = SEC_ALG_CCMP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_3;
}
/* Don't set sec level for group keys. */
if (group_key)
sec.flags &= ~SEC_LEVEL;
}
#endif
done:
if (ieee->set_security)
ieee->set_security(ieee->dev, &sec);
if (ieee->reset_on_keychange &&
ieee->iw_mode != IW_MODE_INFRA &&
ieee->reset_port && ieee->reset_port(dev)) {
IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
return -EINVAL;
}
return ret;
}
int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct iw_mlme *mlme = (struct iw_mlme *) extra;
// printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __FUNCTION__, mlme->cmd);
#if 1
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
case IW_MLME_DISASSOC:
// printk("disassoc now\n");
ieee80211_disassociate(ieee);
break;
default:
return -EOPNOTSUPP;
}
#endif
return 0;
}
int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
/*
struct ieee80211_security sec = {
.flags = SEC_AUTH_MODE,
}
*/
//printk("set auth:flag:%x, data value:%x\n", data->flags, data->value);
switch (data->flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
/*need to support wpa2 here*/
//printk("wpa version:%x\n", data->value);
break;
case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP:
case IW_AUTH_KEY_MGMT:
/*
* * Host AP driver does not use these parameters and allows
* * wpa_supplicant to control them internally.
* */
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
ieee->tkip_countermeasures = data->value;
break;
case IW_AUTH_DROP_UNENCRYPTED:
ieee->drop_unencrypted = data->value;
break;
case IW_AUTH_80211_AUTH_ALG:
ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
//printk("open_wep:%d\n", ieee->open_wep);
break;
#if 1
case IW_AUTH_WPA_ENABLED:
ieee->wpa_enabled = (data->value)?1:0;
//printk("enalbe wpa:%d\n", ieee->wpa_enabled);
break;
#endif
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
ieee->ieee802_1x = data->value;
break;
case IW_AUTH_PRIVACY_INVOKED:
ieee->privacy_invoked = data->value;
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
#if 1
int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
{
#if 0
printk("====>%s()\n", __FUNCTION__);
{
int i;
for (i=0; i<len; i++)
printk("%2x ", ie[i]&0xff);
printk("\n");
}
#endif
u8 *buf = NULL;
if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
{
printk("return error out, len:%d\n", len);
return -EINVAL;
}
if (len)
{
if (len != ie[1]+2){
printk("len:%d, ie:%d\n", len, ie[1]);
return -EINVAL;
}
buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
memcpy(buf, ie, len);
kfree(ieee->wpa_ie);
ieee->wpa_ie = buf;
ieee->wpa_ie_len = len;
}
else{
if (ieee->wpa_ie)
kfree(ieee->wpa_ie);
ieee->wpa_ie = NULL;
ieee->wpa_ie_len = 0;
}
// printk("<=====out %s()\n", __FUNCTION__);
return 0;
}
#endif
#if 0
EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
EXPORT_SYMBOL(ieee80211_wx_set_mlme);
EXPORT_SYMBOL(ieee80211_wx_set_auth);
EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
EXPORT_SYMBOL(ieee80211_wx_get_scan);
EXPORT_SYMBOL(ieee80211_wx_set_encode);
EXPORT_SYMBOL(ieee80211_wx_get_encode);
#endif

View File

@ -0,0 +1,115 @@
/*
* Cryptographic API.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#ifndef _CRYPTO_INTERNAL_H
#define _CRYPTO_INTERNAL_H
//#include <linux/crypto.h>
#include "rtl_crypto.h"
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
#include <asm/kmap_types.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20))
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next))
static inline void cond_resched(void)
{
if (need_resched()) {
set_current_state(TASK_RUNNING);
schedule();
}
}
#endif
extern enum km_type crypto_km_types[];
static inline enum km_type crypto_kmap_type(int out)
{
return crypto_km_types[(in_softirq() ? 2 : 0) + out];
}
static inline void *crypto_kmap(struct page *page, int out)
{
return kmap_atomic(page, crypto_kmap_type(out));
}
static inline void crypto_kunmap(void *vaddr, int out)
{
kunmap_atomic(vaddr, crypto_kmap_type(out));
}
static inline void crypto_yield(struct crypto_tfm *tfm)
{
if (!in_softirq())
cond_resched();
}
static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
{
return (void *)&tfm[1];
}
struct crypto_alg *crypto_alg_lookup(const char *name);
#ifdef CONFIG_KMOD
void crypto_alg_autoload(const char *name);
struct crypto_alg *crypto_alg_mod_lookup(const char *name);
#else
static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
{
return crypto_alg_lookup(name);
}
#endif
#ifdef CONFIG_CRYPTO_HMAC
int crypto_alloc_hmac_block(struct crypto_tfm *tfm);
void crypto_free_hmac_block(struct crypto_tfm *tfm);
#else
static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
{
return 0;
}
static inline void crypto_free_hmac_block(struct crypto_tfm *tfm)
{ }
#endif
#ifdef CONFIG_PROC_FS
void __init crypto_init_proc(void);
#else
static inline void crypto_init_proc(void)
{ }
#endif
int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_digest_ops(struct crypto_tfm *tfm);
int crypto_init_cipher_ops(struct crypto_tfm *tfm);
int crypto_init_compress_ops(struct crypto_tfm *tfm);
void crypto_exit_digest_ops(struct crypto_tfm *tfm);
void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
void crypto_exit_compress_ops(struct crypto_tfm *tfm);
#endif /* _CRYPTO_INTERNAL_H */

View File

@ -0,0 +1,20 @@
#ifndef __KMAP_TYPES_H
#define __KMAP_TYPES_H
enum km_type {
KM_BOUNCE_READ,
KM_SKB_SUNRPC_DATA,
KM_SKB_DATA_SOFTIRQ,
KM_USER0,
KM_USER1,
KM_BH_IRQ,
KM_SOFTIRQ0,
KM_SOFTIRQ1,
KM_TYPE_NR
};
#define _ASM_KMAP_TYPES_H
#endif

View File

@ -0,0 +1,194 @@
/*
* Cryptographic API
*
* Michael MIC (IEEE 802.11i/TKIP) keyed digest
*
* Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
*
* 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/init.h>
#include <linux/module.h>
#include <linux/string.h>
//#include <linux/crypto.h>
#include "rtl_crypto.h"
struct michael_mic_ctx {
u8 pending[4];
size_t pending_len;
u32 l, r;
};
static inline u32 rotl(u32 val, int bits)
{
return (val << bits) | (val >> (32 - bits));
}
static inline u32 rotr(u32 val, int bits)
{
return (val >> bits) | (val << (32 - bits));
}
static inline u32 xswap(u32 val)
{
return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
}
#define michael_block(l, r) \
do { \
r ^= rotl(l, 17); \
l += r; \
r ^= xswap(l); \
l += r; \
r ^= rotl(l, 3); \
l += r; \
r ^= rotr(l, 2); \
l += r; \
} while (0)
static inline u32 get_le32(const u8 *p)
{
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
static inline void put_le32(u8 *p, u32 v)
{
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
}
static void michael_init(void *ctx)
{
struct michael_mic_ctx *mctx = ctx;
mctx->pending_len = 0;
}
static void michael_update(void *ctx, const u8 *data, unsigned int len)
{
struct michael_mic_ctx *mctx = ctx;
if (mctx->pending_len) {
int flen = 4 - mctx->pending_len;
if (flen > len)
flen = len;
memcpy(&mctx->pending[mctx->pending_len], data, flen);
mctx->pending_len += flen;
data += flen;
len -= flen;
if (mctx->pending_len < 4)
return;
mctx->l ^= get_le32(mctx->pending);
michael_block(mctx->l, mctx->r);
mctx->pending_len = 0;
}
while (len >= 4) {
mctx->l ^= get_le32(data);
michael_block(mctx->l, mctx->r);
data += 4;
len -= 4;
}
if (len > 0) {
mctx->pending_len = len;
memcpy(mctx->pending, data, len);
}
}
static void michael_final(void *ctx, u8 *out)
{
struct michael_mic_ctx *mctx = ctx;
u8 *data = mctx->pending;
/* Last block and padding (0x5a, 4..7 x 0) */
switch (mctx->pending_len) {
case 0:
mctx->l ^= 0x5a;
break;
case 1:
mctx->l ^= data[0] | 0x5a00;
break;
case 2:
mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000;
break;
case 3:
mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) |
0x5a000000;
break;
}
michael_block(mctx->l, mctx->r);
/* l ^= 0; */
michael_block(mctx->l, mctx->r);
put_le32(out, mctx->l);
put_le32(out + 4, mctx->r);
}
static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen,
u32 *flags)
{
struct michael_mic_ctx *mctx = ctx;
if (keylen != 8) {
if (flags)
*flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
mctx->l = get_le32(key);
mctx->r = get_le32(key + 4);
return 0;
}
static struct crypto_alg michael_mic_alg = {
.cra_name = "michael_mic",
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = 8,
.cra_ctxsize = sizeof(struct michael_mic_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(michael_mic_alg.cra_list),
.cra_u = { .digest = {
.dia_digestsize = 8,
.dia_init = michael_init,
.dia_update = michael_update,
.dia_final = michael_final,
.dia_setkey = michael_setkey } }
};
static int __init michael_mic_init(void)
{
return crypto_register_alg(&michael_mic_alg);
}
static void __exit michael_mic_exit(void)
{
crypto_unregister_alg(&michael_mic_alg);
}
module_init(michael_mic_init);
module_exit(michael_mic_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Michael MIC");
MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");

View File

@ -0,0 +1,116 @@
/*
* Scatterlist Cryptographic API.
*
* Procfs information.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include <linux/init.h>
//#include <linux/crypto.h>
#include "rtl_crypto.h"
#include <linux/rwsem.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include "internal.h"
extern struct list_head crypto_alg_list;
extern struct rw_semaphore crypto_alg_sem;
static void *c_start(struct seq_file *m, loff_t *pos)
{
struct list_head *v;
loff_t n = *pos;
down_read(&crypto_alg_sem);
list_for_each(v, &crypto_alg_list)
if (!n--)
return list_entry(v, struct crypto_alg, cra_list);
return NULL;
}
static void *c_next(struct seq_file *m, void *p, loff_t *pos)
{
struct list_head *v = p;
(*pos)++;
v = v->next;
return (v == &crypto_alg_list) ?
NULL : list_entry(v, struct crypto_alg, cra_list);
}
static void c_stop(struct seq_file *m, void *p)
{
up_read(&crypto_alg_sem);
}
static int c_show(struct seq_file *m, void *p)
{
struct crypto_alg *alg = (struct crypto_alg *)p;
seq_printf(m, "name : %s\n", alg->cra_name);
seq_printf(m, "module : %s\n",
(alg->cra_module ?
alg->cra_module->name :
"kernel"));
switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_CIPHER:
seq_printf(m, "type : cipher\n");
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
seq_printf(m, "min keysize : %u\n",
alg->cra_cipher.cia_min_keysize);
seq_printf(m, "max keysize : %u\n",
alg->cra_cipher.cia_max_keysize);
break;
case CRYPTO_ALG_TYPE_DIGEST:
seq_printf(m, "type : digest\n");
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
seq_printf(m, "digestsize : %u\n",
alg->cra_digest.dia_digestsize);
break;
case CRYPTO_ALG_TYPE_COMPRESS:
seq_printf(m, "type : compression\n");
break;
default:
seq_printf(m, "type : unknown\n");
break;
}
seq_putc(m, '\n');
return 0;
}
static struct seq_operations crypto_seq_ops = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = c_show
};
static int crypto_info_open(struct inode *inode, struct file *file)
{
return seq_open(file, &crypto_seq_ops);
}
static struct file_operations proc_crypto_ops = {
.open = crypto_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
void __init crypto_init_proc(void)
{
struct proc_dir_entry *proc;
proc = create_proc_entry("crypto", 0, NULL);
if (proc)
proc->proc_fops = &proc_crypto_ops;
}

View File

@ -0,0 +1,399 @@
/*
* Scatterlist Cryptographic API.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
* Copyright (c) 2002 David S. Miller (davem@redhat.com)
*
* Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
* and Nettle, by Niels M鰈ler.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#ifndef _LINUX_CRYPTO_H
#define _LINUX_CRYPTO_H
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/string.h>
#include <asm/page.h>
#include <asm/errno.h>
#define crypto_register_alg crypto_register_alg_rtl
#define crypto_unregister_alg crypto_unregister_alg_rtl
#define crypto_alloc_tfm crypto_alloc_tfm_rtl
#define crypto_free_tfm crypto_free_tfm_rtl
#define crypto_alg_available crypto_alg_available_rtl
/*
* Algorithm masks and types.
*/
#define CRYPTO_ALG_TYPE_MASK 0x000000ff
#define CRYPTO_ALG_TYPE_CIPHER 0x00000001
#define CRYPTO_ALG_TYPE_DIGEST 0x00000002
#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004
/*
* Transform masks and values (for crt_flags).
*/
#define CRYPTO_TFM_MODE_MASK 0x000000ff
#define CRYPTO_TFM_REQ_MASK 0x000fff00
#define CRYPTO_TFM_RES_MASK 0xfff00000
#define CRYPTO_TFM_MODE_ECB 0x00000001
#define CRYPTO_TFM_MODE_CBC 0x00000002
#define CRYPTO_TFM_MODE_CFB 0x00000004
#define CRYPTO_TFM_MODE_CTR 0x00000008
#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100
#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000
#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000
#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000
#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000
#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000
/*
* Miscellaneous stuff.
*/
#define CRYPTO_UNSPEC 0
#define CRYPTO_MAX_ALG_NAME 64
struct scatterlist;
/*
* Algorithms: modular crypto algorithm implementations, managed
* via crypto_register_alg() and crypto_unregister_alg().
*/
struct cipher_alg {
unsigned int cia_min_keysize;
unsigned int cia_max_keysize;
int (*cia_setkey)(void *ctx, const u8 *key,
unsigned int keylen, u32 *flags);
void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src);
void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src);
};
struct digest_alg {
unsigned int dia_digestsize;
void (*dia_init)(void *ctx);
void (*dia_update)(void *ctx, const u8 *data, unsigned int len);
void (*dia_final)(void *ctx, u8 *out);
int (*dia_setkey)(void *ctx, const u8 *key,
unsigned int keylen, u32 *flags);
};
struct compress_alg {
int (*coa_init)(void *ctx);
void (*coa_exit)(void *ctx);
int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen);
int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen);
};
#define cra_cipher cra_u.cipher
#define cra_digest cra_u.digest
#define cra_compress cra_u.compress
struct crypto_alg {
struct list_head cra_list;
u32 cra_flags;
unsigned int cra_blocksize;
unsigned int cra_ctxsize;
const char cra_name[CRYPTO_MAX_ALG_NAME];
union {
struct cipher_alg cipher;
struct digest_alg digest;
struct compress_alg compress;
} cra_u;
struct module *cra_module;
};
/*
* Algorithm registration interface.
*/
int crypto_register_alg(struct crypto_alg *alg);
int crypto_unregister_alg(struct crypto_alg *alg);
/*
* Algorithm query interface.
*/
int crypto_alg_available(const char *name, u32 flags);
/*
* Transforms: user-instantiated objects which encapsulate algorithms
* and core processing logic. Managed via crypto_alloc_tfm() and
* crypto_free_tfm(), as well as the various helpers below.
*/
struct crypto_tfm;
struct cipher_tfm {
void *cit_iv;
unsigned int cit_ivsize;
u32 cit_mode;
int (*cit_setkey)(struct crypto_tfm *tfm,
const u8 *key, unsigned int keylen);
int (*cit_encrypt)(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes);
int (*cit_encrypt_iv)(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes, u8 *iv);
int (*cit_decrypt)(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes);
int (*cit_decrypt_iv)(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes, u8 *iv);
void (*cit_xor_block)(u8 *dst, const u8 *src);
};
struct digest_tfm {
void (*dit_init)(struct crypto_tfm *tfm);
void (*dit_update)(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg);
void (*dit_final)(struct crypto_tfm *tfm, u8 *out);
void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg,
unsigned int nsg, u8 *out);
int (*dit_setkey)(struct crypto_tfm *tfm,
const u8 *key, unsigned int keylen);
#ifdef CONFIG_CRYPTO_HMAC
void *dit_hmac_block;
#endif
};
struct compress_tfm {
int (*cot_compress)(struct crypto_tfm *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen);
int (*cot_decompress)(struct crypto_tfm *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen);
};
#define crt_cipher crt_u.cipher
#define crt_digest crt_u.digest
#define crt_compress crt_u.compress
struct crypto_tfm {
u32 crt_flags;
union {
struct cipher_tfm cipher;
struct digest_tfm digest;
struct compress_tfm compress;
} crt_u;
struct crypto_alg *__crt_alg;
};
/*
* Transform user interface.
*/
/*
* crypto_alloc_tfm() will first attempt to locate an already loaded algorithm.
* If that fails and the kernel supports dynamically loadable modules, it
* will then attempt to load a module of the same name or alias. A refcount
* is grabbed on the algorithm which is then associated with the new transform.
*
* crypto_free_tfm() frees up the transform and any associated resources,
* then drops the refcount on the associated algorithm.
*/
struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags);
void crypto_free_tfm(struct crypto_tfm *tfm);
/*
* Transform helpers which query the underlying algorithm.
*/
static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm)
{
return tfm->__crt_alg->cra_name;
}
static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm)
{
struct crypto_alg *alg = tfm->__crt_alg;
if (alg->cra_module)
return alg->cra_module->name;
else
return NULL;
}
static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm)
{
return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK;
}
static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
return tfm->__crt_alg->cra_cipher.cia_min_keysize;
}
static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
return tfm->__crt_alg->cra_cipher.cia_max_keysize;
}
static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
return tfm->crt_cipher.cit_ivsize;
}
static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm)
{
return tfm->__crt_alg->cra_blocksize;
}
static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
return tfm->__crt_alg->cra_digest.dia_digestsize;
}
/*
* API wrappers.
*/
static inline void crypto_digest_init(struct crypto_tfm *tfm)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
tfm->crt_digest.dit_init(tfm);
}
static inline void crypto_digest_update(struct crypto_tfm *tfm,
struct scatterlist *sg,
unsigned int nsg)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
tfm->crt_digest.dit_update(tfm, sg, nsg);
}
static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
tfm->crt_digest.dit_final(tfm, out);
}
static inline void crypto_digest_digest(struct crypto_tfm *tfm,
struct scatterlist *sg,
unsigned int nsg, u8 *out)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
tfm->crt_digest.dit_digest(tfm, sg, nsg, out);
}
static inline int crypto_digest_setkey(struct crypto_tfm *tfm,
const u8 *key, unsigned int keylen)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
if (tfm->crt_digest.dit_setkey == NULL)
return -ENOSYS;
return tfm->crt_digest.dit_setkey(tfm, key, keylen);
}
static inline int crypto_cipher_setkey(struct crypto_tfm *tfm,
const u8 *key, unsigned int keylen)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
return tfm->crt_cipher.cit_setkey(tfm, key, keylen);
}
static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes);
}
static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes, u8 *iv)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB);
return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv);
}
static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes);
}
static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src,
unsigned int nbytes, u8 *iv)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB);
return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv);
}
static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm,
const u8 *src, unsigned int len)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
memcpy(tfm->crt_cipher.cit_iv, src, len);
}
static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm,
u8 *dst, unsigned int len)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
memcpy(dst, tfm->crt_cipher.cit_iv, len);
}
static inline int crypto_comp_compress(struct crypto_tfm *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS);
return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen);
}
static inline int crypto_comp_decompress(struct crypto_tfm *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen)
{
BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS);
return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen);
}
/*
* HMAC support.
*/
#ifdef CONFIG_CRYPTO_HMAC
void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen);
void crypto_hmac_update(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg);
void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
unsigned int *keylen, u8 *out);
void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
struct scatterlist *sg, unsigned int nsg, u8 *out);
#endif /* CONFIG_CRYPTO_HMAC */
#endif /* _LINUX_CRYPTO_H */

View File

@ -0,0 +1,126 @@
/*
* Cryptographic API.
*
* Cipher operations.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
* 2002 Adam J. Richter <adam@yggdrasil.com>
* 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include "kmap_types.h"
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <asm/scatterlist.h>
#include "internal.h"
#include "scatterwalk.h"
enum km_type crypto_km_types[] = {
KM_USER0,
KM_USER1,
KM_SOFTIRQ0,
KM_SOFTIRQ1,
};
void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch)
{
if (nbytes <= walk->len_this_page &&
(((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <=
PAGE_CACHE_SIZE)
return walk->data;
else
return scratch;
}
static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
{
if (out)
memcpy(sgdata, buf, nbytes);
else
memcpy(buf, sgdata, nbytes);
}
void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg)
{
unsigned int rest_of_page;
walk->sg = sg;
walk->page = sg->page;
walk->len_this_segment = sg->length;
rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1));
walk->len_this_page = min(sg->length, rest_of_page);
walk->offset = sg->offset;
}
void scatterwalk_map(struct scatter_walk *walk, int out)
{
walk->data = crypto_kmap(walk->page, out) + walk->offset;
}
static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
unsigned int more)
{
/* walk->data may be pointing the first byte of the next page;
however, we know we transfered at least one byte. So,
walk->data - 1 will be a virtual address in the mapped page. */
if (out)
flush_dcache_page(walk->page);
if (more) {
walk->len_this_segment -= walk->len_this_page;
if (walk->len_this_segment) {
walk->page++;
walk->len_this_page = min(walk->len_this_segment,
(unsigned)PAGE_CACHE_SIZE);
walk->offset = 0;
}
else
scatterwalk_start(walk, sg_next(walk->sg));
}
}
void scatterwalk_done(struct scatter_walk *walk, int out, int more)
{
crypto_kunmap(walk->data, out);
if (walk->len_this_page == 0 || !more)
scatterwalk_pagedone(walk, out, more);
}
/*
* Do not call this unless the total length of all of the fragments
* has been verified as multiple of the block size.
*/
int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
size_t nbytes, int out)
{
if (buf != walk->data) {
while (nbytes > walk->len_this_page) {
memcpy_dir(buf, walk->data, walk->len_this_page, out);
buf += walk->len_this_page;
nbytes -= walk->len_this_page;
crypto_kunmap(walk->data, out);
scatterwalk_pagedone(walk, out, 1);
scatterwalk_map(walk, out);
}
memcpy_dir(buf, walk->data, nbytes, out);
}
walk->offset += nbytes;
walk->len_this_page -= nbytes;
walk->len_this_segment -= nbytes;
return 0;
}

View File

@ -0,0 +1,51 @@
/*
* Cryptographic API.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
* Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com>
* Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#ifndef _CRYPTO_SCATTERWALK_H
#define _CRYPTO_SCATTERWALK_H
#include <linux/mm.h>
#include <asm/scatterlist.h>
struct scatter_walk {
struct scatterlist *sg;
struct page *page;
void *data;
unsigned int len_this_page;
unsigned int len_this_segment;
unsigned int offset;
};
/* Define sg_next is an inline routine now in case we want to change
scatterlist to a linked list later. */
static inline struct scatterlist *sg_next(struct scatterlist *sg)
{
return sg + 1;
}
static inline int scatterwalk_samebuf(struct scatter_walk *walk_in,
struct scatter_walk *walk_out,
void *src_p, void *dst_p)
{
return walk_in->page == walk_out->page &&
walk_in->offset == walk_out->offset &&
walk_in->data == src_p && walk_out->data == dst_p;
}
void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch);
void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out);
void scatterwalk_map(struct scatter_walk *walk, int out);
void scatterwalk_done(struct scatter_walk *walk, int out, int more);
#endif /* _CRYPTO_SCATTERWALK_H */

View File

@ -0,0 +1,86 @@
/*
* 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 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. See README and COPYING for
* more details.
*/
/*
* 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 *, int);
void ieee80211_crypt_deinit_handler(unsigned long);
void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
struct ieee80211_crypt_data **crypt);
#endif

View File

@ -0,0 +1,761 @@
/*
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
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 tanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
#ifndef R8180H
#define R8180H
#define RTL8180_MODULE_NAME "rtl8180"
#define DMESG(x,a...) printk(KERN_INFO RTL8180_MODULE_NAME ": " x "\n", ## a)
#define DMESGW(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": WW:" x "\n", ## a)
#define DMESGE(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": EE:" x "\n", ## a)
#include <linux/module.h>
#include <linux/kernel.h>
//#include <linux/config.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/rtnetlink.h> //for rtnl_lock()
#include <linux/wireless.h>
#include <linux/timer.h>
#include <linux/proc_fs.h> // Necessary because we use the proc fs
#include <linux/if_arp.h>
#include "ieee80211.h"
#include <asm/io.h>
//#include <asm/semaphore.h>
#define EPROM_93c46 0
#define EPROM_93c56 1
#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
#define DEFAULT_FRAG_THRESHOLD 2342U
#define MIN_FRAG_THRESHOLD 256U
//#define MAX_FRAG_THRESHOLD 2342U
#define DEFAULT_RTS_THRESHOLD 2342U
#define MIN_RTS_THRESHOLD 0U
#define MAX_RTS_THRESHOLD 2342U
#define DEFAULT_BEACONINTERVAL 0x64U
#define DEFAULT_BEACON_ESSID "Rtl8180"
#define DEFAULT_SSID ""
#define DEFAULT_RETRY_RTS 7
#define DEFAULT_RETRY_DATA 7
#define PRISM_HDR_SIZE 64
#ifdef CONFIG_RTL8185B
#define MGNT_QUEUE 0
#define BK_QUEUE 1
#define BE_QUEUE 2
#define VI_QUEUE 3
#define VO_QUEUE 4
#define HIGH_QUEUE 5
#define BEACON_QUEUE 6
#define LOW_QUEUE BE_QUEUE
#define NORMAL_QUEUE MGNT_QUEUE
#define aSifsTime 10
#define sCrcLng 4
#define sAckCtsLng 112 // bits in ACK and CTS frames
//+by amy 080312
#define RATE_ADAPTIVE_TIMER_PERIOD 300
typedef enum _WIRELESS_MODE {
WIRELESS_MODE_UNKNOWN = 0x00,
WIRELESS_MODE_A = 0x01,
WIRELESS_MODE_B = 0x02,
WIRELESS_MODE_G = 0x04,
WIRELESS_MODE_AUTO = 0x08,
} WIRELESS_MODE;
typedef enum _VERSION_8185{
// RTL8185
VERSION_8185_UNKNOWN,
VERSION_8185_C, // C-cut
VERSION_8185_D, // D-cut
// RTL8185B
VERSION_8185B_B, // B-cut
VERSION_8185B_D, // D-cut
VERSION_8185B_E, // E-cut
//RTL8187S-PCIE
VERSION_8187S_B, // B-cut
VERSION_8187S_C, // C-cut
VERSION_8187S_D, // D-cut
}VERSION_8185,*PVERSION_8185;
typedef struct ChnlAccessSetting {
u16 SIFS_Timer;
u16 DIFS_Timer;
u16 SlotTimeTimer;
u16 EIFS_Timer;
u16 CWminIndex;
u16 CWmaxIndex;
}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING;
typedef enum{
NIC_8185 = 1,
NIC_8185B
} nic_t;
typedef u32 AC_CODING;
#define AC0_BE 0 // ACI: 0x00 // Best Effort
#define AC1_BK 1 // ACI: 0x01 // Background
#define AC2_VI 2 // ACI: 0x10 // Video
#define AC3_VO 3 // ACI: 0x11 // Voice
#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum.
//
// ECWmin/ECWmax field.
// Ref: WMM spec 2.2.2: WME Parameter Element, p.13.
//
typedef union _ECW{
u8 charData;
struct
{
u8 ECWmin:4;
u8 ECWmax:4;
}f; // Field
}ECW, *PECW;
//
// ACI/AIFSN Field.
// Ref: WMM spec 2.2.2: WME Parameter Element, p.12.
//
typedef union _ACI_AIFSN{
u8 charData;
struct
{
u8 AIFSN:4;
u8 ACM:1;
u8 ACI:2;
u8 Reserved:1;
}f; // Field
}ACI_AIFSN, *PACI_AIFSN;
//
// AC Parameters Record Format.
// Ref: WMM spec 2.2.2: WME Parameter Element, p.12.
//
typedef union _AC_PARAM{
u32 longData;
u8 charData[4];
struct
{
ACI_AIFSN AciAifsn;
ECW Ecw;
u16 TXOPLimit;
}f; // Field
}AC_PARAM, *PAC_PARAM;
/* it is a wrong definition. -xiong-2006-11-17
typedef struct ThreeWireReg {
u16 longData;
struct {
u8 enableB;
u8 data;
u8 clk;
u8 read_write;
} struc;
} ThreeWireReg;
*/
typedef union _ThreeWire{
struct _ThreeWireStruc{
u16 data:1;
u16 clk:1;
u16 enableB:1;
u16 read_write:1;
u16 resv1:12;
// u2Byte resv2:14;
// u2Byte ThreeWireEnable:1;
// u2Byte resv3:1;
}struc;
u16 longData;
}ThreeWireReg;
#endif
typedef struct buffer
{
struct buffer *next;
u32 *buf;
dma_addr_t dma;
} buffer;
//YJ,modified,080828
typedef struct Stats
{
unsigned long txrdu;
unsigned long rxrdu;
unsigned long rxnolast;
unsigned long rxnodata;
// unsigned long rxreset;
// unsigned long rxwrkaround;
unsigned long rxnopointer;
unsigned long txnperr;
unsigned long txresumed;
unsigned long rxerr;
unsigned long rxoverflow;
unsigned long rxint;
unsigned long txbkpokint;
unsigned long txbepoking;
unsigned long txbkperr;
unsigned long txbeperr;
unsigned long txnpokint;
unsigned long txhpokint;
unsigned long txhperr;
unsigned long ints;
unsigned long shints;
unsigned long txoverflow;
unsigned long rxdmafail;
unsigned long txbeacon;
unsigned long txbeaconerr;
unsigned long txlpokint;
unsigned long txlperr;
unsigned long txretry;//retry number tony 20060601
unsigned long rxcrcerrmin;//crc error (0-500)
unsigned long rxcrcerrmid;//crc error (500-1000)
unsigned long rxcrcerrmax;//crc error (>1000)
unsigned long rxicverr;//ICV error
} Stats;
#define MAX_LD_SLOT_NUM 10
#define KEEP_ALIVE_INTERVAL 20 // in seconds.
#define CHECK_FOR_HANG_PERIOD 2 //be equal to watchdog check time
#define DEFAULT_KEEP_ALIVE_LEVEL 1
#define DEFAULT_SLOT_NUM 2
#define POWER_PROFILE_AC 0
#define POWER_PROFILE_BATTERY 1
typedef struct _link_detect_t
{
u32 RxFrameNum[MAX_LD_SLOT_NUM]; // number of Rx Frame / CheckForHang_period to determine link status
u16 SlotNum; // number of CheckForHang period to determine link status, default is 2
u16 SlotIndex;
u32 NumTxOkInPeriod; //number of packet transmitted during CheckForHang
u32 NumRxOkInPeriod; //number of packet received during CheckForHang
u8 IdleCount; // (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)
u32 LastNumTxUnicast;
u32 LastNumRxUnicast;
bool bBusyTraffic; //when it is set to 1, UI cann't scan at will.
}link_detect_t, *plink_detect_t;
//YJ,modified,080828,end
//by amy for led
//================================================================================
// LED customization.
//================================================================================
typedef enum _LED_STRATEGY_8185{
SW_LED_MODE0, //
SW_LED_MODE1, //
HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes)
}LED_STRATEGY_8185, *PLED_STRATEGY_8185;
//by amy for led
//by amy for power save
typedef enum _LED_CTL_MODE{
LED_CTL_POWER_ON = 1,
LED_CTL_LINK = 2,
LED_CTL_NO_LINK = 3,
LED_CTL_TX = 4,
LED_CTL_RX = 5,
LED_CTL_SITE_SURVEY = 6,
LED_CTL_POWER_OFF = 7
}LED_CTL_MODE;
typedef enum _RT_RF_POWER_STATE
{
eRfOn,
eRfSleep,
eRfOff
}RT_RF_POWER_STATE;
enum _ReasonCode{
unspec_reason = 0x1,
auth_not_valid = 0x2,
deauth_lv_ss = 0x3,
inactivity = 0x4,
ap_overload = 0x5,
class2_err = 0x6,
class3_err = 0x7,
disas_lv_ss = 0x8,
asoc_not_auth = 0x9,
//----MIC_CHECK
mic_failure = 0xe,
//----END MIC_CHECK
// Reason code defined in 802.11i D10.0 p.28.
invalid_IE = 0x0d,
four_way_tmout = 0x0f,
two_way_tmout = 0x10,
IE_dismatch = 0x11,
invalid_Gcipher = 0x12,
invalid_Pcipher = 0x13,
invalid_AKMP = 0x14,
unsup_RSNIEver = 0x15,
invalid_RSNIE = 0x16,
auth_802_1x_fail= 0x17,
ciper_reject = 0x18,
// Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15.
QoS_unspec = 0x20, // 32
QAP_bandwidth = 0x21, // 33
poor_condition = 0x22, // 34
no_facility = 0x23, // 35
// Where is 36???
req_declined = 0x25, // 37
invalid_param = 0x26, // 38
req_not_honored= 0x27, // 39
TS_not_created = 0x2F, // 47
DL_not_allowed = 0x30, // 48
dest_not_exist = 0x31, // 49
dest_not_QSTA = 0x32, // 50
};
typedef enum _RT_PS_MODE
{
eActive, // Active/Continuous access.
eMaxPs, // Max power save mode.
eFastPs // Fast power save mode.
}RT_PS_MODE;
//by amy for power save
typedef struct r8180_priv
{
struct pci_dev *pdev;
short epromtype;
int irq;
struct ieee80211_device *ieee80211;
short card_8185; /* O: rtl8180, 1:rtl8185 V B/C, 2:rtl8185 V D, 3:rtl8185B */
short card_8185_Bversion; /* if TCR reports card V B/C this discriminates */
short phy_ver; /* meaningful for rtl8225 1:A 2:B 3:C */
short enable_gpio0;
enum card_type {PCI,MINIPCI,CARDBUS,USB/*rtl8187*/}card_type;
short hw_plcp_len;
short plcp_preamble_mode; // 0:auto 1:short 2:long
spinlock_t irq_lock;
spinlock_t irq_th_lock;
spinlock_t tx_lock;
spinlock_t ps_lock;
spinlock_t rf_ps_lock;
u16 irq_mask;
short irq_enabled;
struct net_device *dev;
short chan;
short sens;
short max_sens;
u8 chtxpwr[15]; //channels from 1 to 14, 0 not used
u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used
//u8 challow[15]; //channels from 1 to 14, 0 not used
u8 channel_plan; // it's the channel plan index
short up;
short crcmon; //if 1 allow bad crc frame reception in monitor mode
short prism_hdr;
struct timer_list scan_timer;
/*short scanpending;
short stopscan;*/
spinlock_t scan_lock;
u8 active_probe;
//u8 active_scan_num;
struct semaphore wx_sem;
struct semaphore rf_state;
short hw_wep;
short digphy;
short antb;
short diversity;
u8 cs_treshold;
short rcr_csense;
short rf_chip;
u32 key0[4];
short (*rf_set_sens)(struct net_device *dev,short sens);
void (*rf_set_chan)(struct net_device *dev,short ch);
void (*rf_close)(struct net_device *dev);
void (*rf_init)(struct net_device *dev);
void (*rf_sleep)(struct net_device *dev);
void (*rf_wakeup)(struct net_device *dev);
//short rate;
short promisc;
/*stats*/
struct Stats stats;
struct _link_detect_t link_detect; //YJ,add,080828
struct iw_statistics wstats;
struct proc_dir_entry *dir_dev;
/*RX stuff*/
u32 *rxring;
u32 *rxringtail;
dma_addr_t rxringdma;
struct buffer *rxbuffer;
struct buffer *rxbufferhead;
int rxringcount;
u16 rxbuffersize;
struct sk_buff *rx_skb;
short rx_skb_complete;
u32 rx_prevlen;
/*TX stuff*/
/*
u32 *txlpring;
u32 *txhpring;
u32 *txnpring;
dma_addr_t txlpringdma;
dma_addr_t txhpringdma;
dma_addr_t txnpringdma;
u32 *txlpringtail;
u32 *txhpringtail;
u32 *txnpringtail;
u32 *txlpringhead;
u32 *txhpringhead;
u32 *txnpringhead;
struct buffer *txlpbufs;
struct buffer *txhpbufs;
struct buffer *txnpbufs;
struct buffer *txlpbufstail;
struct buffer *txhpbufstail;
struct buffer *txnpbufstail;
*/
u32 *txmapring;
u32 *txbkpring;
u32 *txbepring;
u32 *txvipring;
u32 *txvopring;
u32 *txhpring;
dma_addr_t txmapringdma;
dma_addr_t txbkpringdma;
dma_addr_t txbepringdma;
dma_addr_t txvipringdma;
dma_addr_t txvopringdma;
dma_addr_t txhpringdma;
u32 *txmapringtail;
u32 *txbkpringtail;
u32 *txbepringtail;
u32 *txvipringtail;
u32 *txvopringtail;
u32 *txhpringtail;
u32 *txmapringhead;
u32 *txbkpringhead;
u32 *txbepringhead;
u32 *txvipringhead;
u32 *txvopringhead;
u32 *txhpringhead;
struct buffer *txmapbufs;
struct buffer *txbkpbufs;
struct buffer *txbepbufs;
struct buffer *txvipbufs;
struct buffer *txvopbufs;
struct buffer *txhpbufs;
struct buffer *txmapbufstail;
struct buffer *txbkpbufstail;
struct buffer *txbepbufstail;
struct buffer *txvipbufstail;
struct buffer *txvopbufstail;
struct buffer *txhpbufstail;
int txringcount;
int txbuffsize;
//struct tx_pendingbuf txnp_pending;
//struct tasklet_struct irq_tx_tasklet;
struct tasklet_struct irq_rx_tasklet;
u8 dma_poll_mask;
//short tx_suspend;
/* adhoc/master mode stuff */
u32 *txbeaconringtail;
dma_addr_t txbeaconringdma;
u32 *txbeaconring;
int txbeaconcount;
struct buffer *txbeaconbufs;
struct buffer *txbeaconbufstail;
//char *master_essid;
//u16 master_beaconinterval;
//u32 master_beaconsize;
//u16 beacon_interval;
u8 retry_data;
u8 retry_rts;
u16 rts;
//add for RF power on power off by lizhaoming 080512
u8 RegThreeWireMode; // See "Three wire mode" defined above, 2006.05.31, by rcnjko.
//by amy for led
LED_STRATEGY_8185 LedStrategy;
//by amy for led
//by amy for power save
struct timer_list watch_dog_timer;
bool bInactivePs;
bool bSwRfProcessing;
RT_RF_POWER_STATE eInactivePowerState;
RT_RF_POWER_STATE eRFPowerState;
u32 RfOffReason;
bool RFChangeInProgress;
bool bInHctTest;
bool SetRFPowerStateInProgress;
u8 RFProgType;
bool bLeisurePs;
RT_PS_MODE dot11PowerSaveMode;
//u32 NumRxOkInPeriod; //YJ,del,080828
//u32 NumTxOkInPeriod; //YJ,del,080828
u8 TxPollingTimes;
bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake untill receive data or timeout.
u8 WaitBufDataBcnCount;
u8 WaitBufDataTimeOut;
//by amy for power save
//by amy for antenna
u8 EEPROMSwAntennaDiversity;
bool EEPROMDefaultAntenna1;
u8 RegSwAntennaDiversityMechanism;
bool bSwAntennaDiverity;
u8 RegDefaultAntenna;
bool bDefaultAntenna1;
u8 SignalStrength;
long Stats_SignalStrength;
long LastSignalStrengthInPercent; // In percentange, used for smoothing, e.g. Moving Average.
u8 SignalQuality; // in 0-100 index.
long Stats_SignalQuality;
long RecvSignalPower; // in dBm.
long Stats_RecvSignalPower;
u8 LastRxPktAntenna; // +by amy 080312 Antenn which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25.
u32 AdRxOkCnt;
long AdRxSignalStrength;
u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx).
u8 AdTickCount; // Times of SwAntennaDiversityTimer happened.
u8 AdCheckPeriod; // # of period SwAntennaDiversityTimer to check Rx signal strength for SW Antenna Diversity.
u8 AdMinCheckPeriod; // Min value of AdCheckPeriod.
u8 AdMaxCheckPeriod; // Max value of AdCheckPeriod.
long AdRxSsThreshold; // Signal strength threshold to switch antenna.
long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold.
bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna.
long AdRxSsBeforeSwitched; // Rx signal strength before we swithed antenna.
struct timer_list SwAntennaDiversityTimer;
//by amy for antenna
//{by amy 080312
//
// Crystal calibration.
// Added by Roger, 2007.12.11.
//
bool bXtalCalibration; // Crystal calibration.
u8 XtalCal_Xin; // Crystal calibration for Xin. 0~7.5pF
u8 XtalCal_Xout; // Crystal calibration for Xout. 0~7.5pF
//
// Tx power tracking with thermal meter indication.
// Added by Roger, 2007.12.11.
//
bool bTxPowerTrack; // Tx Power tracking.
u8 ThermalMeter; // Thermal meter reference indication.
//
// Dynamic Initial Gain Adjustment Mechanism. Added by Bruce, 2007-02-14.
//
bool bDigMechanism; // TRUE if DIG is enabled, FALSE ow.
bool bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko.
u32 FalseAlarmRegValue;
u8 RegDigOfdmFaUpTh; // Upper threhold of OFDM false alarm, which is used in DIG.
u8 DIG_NumberFallbackVote;
u8 DIG_NumberUpgradeVote;
// For HW antenna diversity, added by Roger, 2008.01.30.
u32 AdMainAntennaRxOkCnt; // Main antenna Rx OK count.
u32 AdAuxAntennaRxOkCnt; // Aux antenna Rx OK count.
bool bHWAdSwitched; // TRUE if we has switched default antenna by HW evaluation.
// RF High Power upper/lower threshold.
u8 RegHiPwrUpperTh;
u8 RegHiPwrLowerTh;
// RF RSSI High Power upper/lower Threshold.
u8 RegRSSIHiPwrUpperTh;
u8 RegRSSIHiPwrLowerTh;
// Current CCK RSSI value to determine CCK high power, asked by SD3 DZ, by Bruce, 2007-04-12.
u8 CurCCKRSSI;
bool bCurCCKPkt;
//
// High Power Mechanism. Added by amy, 080312.
//
bool bToUpdateTxPwr;
long UndecoratedSmoothedSS;
long UndercorateSmoothedRxPower;
u8 RSSI;
char RxPower;
u8 InitialGain;
//For adjust Dig Threshhold during Legacy/Leisure Power Save Mode
u32 DozePeriodInPast2Sec;
// Don't access BB/RF under disable PLL situation.
u8 InitialGainBackUp;
u8 RegBModeGainStage;
//by amy for rate adaptive
struct timer_list rateadapter_timer;
u32 RateAdaptivePeriod;
bool bEnhanceTxPwr;
bool bUpdateARFR;
int ForcedDataRate; // Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M.)
u32 NumTxUnicast; //YJ,add,080828,for keep alive
u8 keepAliveLevel; //YJ,add,080828,for KeepAlive
unsigned long NumTxOkTotal;
u16 LastRetryCnt;
u16 LastRetryRate;
unsigned long LastTxokCnt;
unsigned long LastRxokCnt;
u16 CurrRetryCnt;
unsigned long LastTxOKBytes;
unsigned long NumTxOkBytesTotal;
u8 LastFailTxRate;
long LastFailTxRateSS;
u8 FailTxRateCount;
u32 LastTxThroughput;
//for up rate
unsigned short bTryuping;
u8 CurrTxRate; //the rate before up
u16 CurrRetryRate;
u16 TryupingCount;
u8 TryDownCountLowData;
u8 TryupingCountNoData;
u8 CurrentOperaRate;
//by amy for rate adaptive
//by amy 080312}
// short wq_hurryup;
// struct workqueue_struct *workqueue;
struct work_struct reset_wq;
struct work_struct watch_dog_wq;
struct work_struct tx_irq_wq;
short ack_tx_to_ieee;
u8 PowerProfile;
#ifdef CONFIG_RTL8185B
u32 CSMethod;
u8 cck_txpwr_base;
u8 ofdm_txpwr_base;
u8 dma_poll_stop_mask;
//u8 RegThreeWireMode;
u8 MWIEnable;
u16 ShortRetryLimit;
u16 LongRetryLimit;
u16 EarlyRxThreshold;
u32 TransmitConfig;
u32 ReceiveConfig;
u32 IntrMask;
struct ChnlAccessSetting ChannelAccessSetting;
#endif
}r8180_priv;
#define MANAGE_PRIORITY 0
#define BK_PRIORITY 1
#define BE_PRIORITY 2
#define VI_PRIORITY 3
#define VO_PRIORITY 4
#define HI_PRIORITY 5
#define BEACON_PRIORITY 6
#define LOW_PRIORITY VI_PRIORITY
#define NORM_PRIORITY VO_PRIORITY
//AC2Queue mapping
#define AC2Q(_ac) (((_ac) == WME_AC_VO) ? VO_PRIORITY : \
((_ac) == WME_AC_VI) ? VI_PRIORITY : \
((_ac) == WME_AC_BK) ? BK_PRIORITY : \
BE_PRIORITY)
short rtl8180_tx(struct net_device *dev,u8* skbuf, int len,int priority,
short morefrag,short fragdesc,int rate);
u8 read_nic_byte(struct net_device *dev, int x);
u32 read_nic_dword(struct net_device *dev, int x);
u16 read_nic_word(struct net_device *dev, int x) ;
void write_nic_byte(struct net_device *dev, int x,u8 y);
void write_nic_word(struct net_device *dev, int x,u16 y);
void write_nic_dword(struct net_device *dev, int x,u32 y);
void force_pci_posting(struct net_device *dev);
void rtl8180_rtx_disable(struct net_device *);
void rtl8180_rx_enable(struct net_device *);
void rtl8180_tx_enable(struct net_device *);
void rtl8180_start_scanning(struct net_device *dev);
void rtl8180_start_scanning_s(struct net_device *dev);
void rtl8180_stop_scanning(struct net_device *dev);
void rtl8180_disassociate(struct net_device *dev);
//void fix_rx_fifo(struct net_device *dev);
void rtl8180_set_anaparam(struct net_device *dev,u32 a);
void rtl8185_set_anaparam2(struct net_device *dev,u32 a);
void rtl8180_set_hw_wep(struct net_device *dev);
void rtl8180_no_hw_wep(struct net_device *dev);
void rtl8180_update_msr(struct net_device *dev);
//void rtl8180_BSS_create(struct net_device *dev);
void rtl8180_beacon_tx_disable(struct net_device *dev);
void rtl8180_beacon_rx_disable(struct net_device *dev);
void rtl8180_conttx_enable(struct net_device *dev);
void rtl8180_conttx_disable(struct net_device *dev);
int rtl8180_down(struct net_device *dev);
int rtl8180_up(struct net_device *dev);
void rtl8180_commit(struct net_device *dev);
void rtl8180_set_chan(struct net_device *dev,short ch);
void rtl8180_set_master_essid(struct net_device *dev,char *essid);
void rtl8180_update_beacon_security(struct net_device *dev);
void write_phy(struct net_device *dev, u8 adr, u8 data);
void write_phy_cck(struct net_device *dev, u8 adr, u32 data);
void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data);
void rtl8185_tx_antenna(struct net_device *dev, u8 ant);
void rtl8185_rf_pins_enable(struct net_device *dev);
void IBSS_randomize_cell(struct net_device *dev);
void IPSEnter(struct net_device *dev);
void IPSLeave(struct net_device *dev);
int get_curr_tx_free_desc(struct net_device *dev, int priority);
void UpdateInitialGain(struct net_device *dev);
bool SetAntennaConfig87SE(struct net_device *dev, u8 DefaultAnt, bool bAntDiversity);
//#ifdef CONFIG_RTL8185B
void rtl8185b_adapter_start(struct net_device *dev);
void rtl8185b_rx_enable(struct net_device *dev);
void rtl8185b_tx_enable(struct net_device *dev);
void rtl8180_reset(struct net_device *dev);
void rtl8185b_irq_enable(struct net_device *dev);
void fix_rx_fifo(struct net_device *dev);
void fix_tx_fifo(struct net_device *dev);
void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch);
#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20)
void rtl8180_rate_adapter(struct work_struct * work);
#else
void rtl8180_rate_adapter(struct net_device *dev);
#endif
//#endif
bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet, u32 ChangeSource);
#endif

View File

@ -0,0 +1,146 @@
/*
This files contains card eeprom (93c46 or 93c56) programming routines,
memory is addressed by 16 bits words.
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
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 tanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
#include "r8180_93cx6.h"
void eprom_cs(struct net_device *dev, short bit)
{
if(bit)
write_nic_byte(dev, EPROM_CMD,
(1<<EPROM_CS_SHIFT) | \
read_nic_byte(dev, EPROM_CMD)); //enable EPROM
else
write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev, EPROM_CMD)\
&~(1<<EPROM_CS_SHIFT)); //disable EPROM
force_pci_posting(dev);
udelay(EPROM_DELAY);
}
void eprom_ck_cycle(struct net_device *dev)
{
write_nic_byte(dev, EPROM_CMD,
(1<<EPROM_CK_SHIFT) | read_nic_byte(dev,EPROM_CMD));
force_pci_posting(dev);
udelay(EPROM_DELAY);
write_nic_byte(dev, EPROM_CMD,
read_nic_byte(dev, EPROM_CMD) &~ (1<<EPROM_CK_SHIFT));
force_pci_posting(dev);
udelay(EPROM_DELAY);
}
void eprom_w(struct net_device *dev,short bit)
{
if(bit)
write_nic_byte(dev, EPROM_CMD, (1<<EPROM_W_SHIFT) | \
read_nic_byte(dev,EPROM_CMD));
else
write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev,EPROM_CMD)\
&~(1<<EPROM_W_SHIFT));
force_pci_posting(dev);
udelay(EPROM_DELAY);
}
short eprom_r(struct net_device *dev)
{
short bit;
bit=(read_nic_byte(dev, EPROM_CMD) & (1<<EPROM_R_SHIFT) );
udelay(EPROM_DELAY);
if(bit) return 1;
return 0;
}
void eprom_send_bits_string(struct net_device *dev, short b[], int len)
{
int i;
for(i=0; i<len; i++){
eprom_w(dev, b[i]);
eprom_ck_cycle(dev);
}
}
u32 eprom_read(struct net_device *dev, u32 addr)
{
struct r8180_priv *priv = ieee80211_priv(dev);
short read_cmd[]={1,1,0};
short addr_str[8];
int i;
int addr_len;
u32 ret;
ret=0;
//enable EPROM programming
write_nic_byte(dev, EPROM_CMD,
(EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT));
force_pci_posting(dev);
udelay(EPROM_DELAY);
if (priv->epromtype==EPROM_93c56){
addr_str[7]=addr & 1;
addr_str[6]=addr & (1<<1);
addr_str[5]=addr & (1<<2);
addr_str[4]=addr & (1<<3);
addr_str[3]=addr & (1<<4);
addr_str[2]=addr & (1<<5);
addr_str[1]=addr & (1<<6);
addr_str[0]=addr & (1<<7);
addr_len=8;
}else{
addr_str[5]=addr & 1;
addr_str[4]=addr & (1<<1);
addr_str[3]=addr & (1<<2);
addr_str[2]=addr & (1<<3);
addr_str[1]=addr & (1<<4);
addr_str[0]=addr & (1<<5);
addr_len=6;
}
eprom_cs(dev, 1);
eprom_ck_cycle(dev);
eprom_send_bits_string(dev, read_cmd, 3);
eprom_send_bits_string(dev, addr_str, addr_len);
//keep chip pin D to low state while reading.
//I'm unsure if it is necessary, but anyway shouldn't hurt
eprom_w(dev, 0);
for(i=0;i<16;i++){
//eeprom needs a clk cycle between writing opcode&adr
//and reading data. (eeprom outs a dummy 0)
eprom_ck_cycle(dev);
ret |= (eprom_r(dev)<<(15-i));
}
eprom_cs(dev, 0);
eprom_ck_cycle(dev);
//disable EPROM programming
write_nic_byte(dev, EPROM_CMD,
(EPROM_CMD_NORMAL<<EPROM_CMD_OPERATING_MODE_SHIFT));
return ret;
}

View File

@ -0,0 +1,59 @@
/*
This is part of rtl8180 OpenSource driver
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
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 tanks 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 "r8180.h"
#include "r8180_hw.h"
#define EPROM_DELAY 10
#define EPROM_ANAPARAM_ADDRLWORD 0xd
#define EPROM_ANAPARAM_ADDRHWORD 0xe
#define RFCHIPID 0x6
#define RFCHIPID_INTERSIL 1
#define RFCHIPID_RFMD 2
#define RFCHIPID_PHILIPS 3
#define RFCHIPID_MAXIM 4
#define RFCHIPID_GCT 5
#define RFCHIPID_RTL8225 9
#ifdef CONFIG_RTL8185B
#define RF_ZEBRA2 11
#define EPROM_TXPW_BASE 0x05
#define RF_ZEBRA4 12
#endif
#define RFCHIPID_RTL8255 0xa
#define RF_PARAM 0x19
#define RF_PARAM_DIGPHY_SHIFT 0
#define RF_PARAM_ANTBDEFAULT_SHIFT 1
#define RF_PARAM_CARRIERSENSE_SHIFT 2
#define RF_PARAM_CARRIERSENSE_MASK (3<<2)
#define ENERGY_TRESHOLD 0x17
#define EPROM_VERSION 0x1E
#define MAC_ADR 0x7
#define CIS 0x18
#define EPROM_TXPW_OFDM_CH1_2 0x20
//#define EPROM_TXPW_CH1_2 0x10
#define EPROM_TXPW_CH1_2 0x30
#define EPROM_TXPW_CH3_4 0x11
#define EPROM_TXPW_CH5_6 0x12
#define EPROM_TXPW_CH7_8 0x13
#define EPROM_TXPW_CH9_10 0x14
#define EPROM_TXPW_CH11_12 0x15
#define EPROM_TXPW_CH13_14 0x16
u32 eprom_read(struct net_device *dev,u32 addr); //reads a 16 bits word

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
#ifndef R8180_DM_H
#define R8180_DM_H
#include "r8180.h"
//#include "r8180_hw.h"
//#include "r8180_93cx6.h"
void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength);
bool SetAntenna8185(struct net_device *dev, u8 u1bAntennaIndex);
bool SwitchAntenna( struct net_device *dev);
void SwAntennaDiversity(struct net_device *dev );
void SwAntennaDiversityTimerCallback(struct net_device *dev);
bool CheckDig(struct net_device *dev);
bool CheckHighPower(struct net_device *dev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
void rtl8180_hw_dig_wq (struct work_struct *work);
#else
void rtl8180_hw_dig_wq(struct net_device *dev);
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
void rtl8180_tx_pw_wq (struct work_struct *work);
#else
void rtl8180_tx_pw_wq(struct net_device *dev);
#endif
#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20)
void rtl8180_rate_adapter(struct work_struct * work);
#else
void rtl8180_rate_adapter(struct net_device *dev);
#endif
void TxPwrTracking87SE(struct net_device *dev);
bool CheckTxPwrTracking(struct net_device *dev);
#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20)
void rtl8180_rate_adapter(struct work_struct * work);
#else
void rtl8180_rate_adapter(struct net_device *dev);
#endif
void timer_rate_adaptive(unsigned long data);
#endif

View File

@ -0,0 +1,296 @@
/*
This files contains GCT radio frontend programming routines.
This is part of rtl8180 OpenSource driver
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
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.
Code from Rtw8180 NetBSD driver by David Young has been really useful to
understand some things and gets some ideas
Code from rtl8181 project has been useful to me to understand some things.
Some code from 'Deuce' work
We want to tanks the Authors of such projects and the Ndiswrapper
project Authors.
*/
#include "r8180.h"
#include "r8180_hw.h"
#include "r8180_gct.h"
//#define DEBUG_GCT
/* the following experiment are just experiments.
* this means if you enable them you can have every kind
* of result, included damage the RF chip, so don't
* touch them if you don't know what you are doing.
* In any case, if you do it, do at your own risk
*/
//#define GCT_EXPERIMENT1 //improve RX sensivity
//#define GCT_EXPERIMENT2
//#define GCT_EXPERIMENT3 //iprove a bit RX signal quality ?
//#define GCT_EXPERIMENT4 //maybe solve some brokeness with experiment1 ?
//#define GCT_EXPERIMENT5
//#define GCT_EXPERIMENT6 //not good
u32 gct_chan[] = {
0x0, //dummy channel 0
0x0, //1
0x1, //2
0x2, //3
0x3, //4
0x4, //5
0x5, //6
0x6, //7
0x7, //8
0x8, //9
0x9, //10
0xa, //11
0xb, //12
0xc, //13
0xd, //14
};
int gct_encode[16] = {
0, 8, 4, 0xC,
2, 0xA, 6, 0xE,
1, 9, 5, 0xD,
3, 0xB, 7, 0xF
};
void gct_rf_stabilize(struct net_device *dev)
{
force_pci_posting(dev);
mdelay(3); //for now use a great value.. we may optimize in future
}
void write_gct(struct net_device *dev, u8 adr, u32 data)
{
// struct r8180_priv *priv = ieee80211_priv(dev);
u32 phy_config;
phy_config = gct_encode[(data & 0xf00) >> 8];
phy_config |= gct_encode[(data & 0xf0) >> 4 ] << 4;
phy_config |= gct_encode[(data & 0xf) ] << 8;
phy_config |= gct_encode[(adr >> 1) & 0xf ] << 12;
phy_config |= (adr & 1 ) << 16;
phy_config |= gct_encode[(data & 0xf000)>>12] << 24;
phy_config |= 0x90000000; // MAC will bang bits to the chip
write_nic_dword(dev,PHY_CONFIG,phy_config);
#ifdef DEBUG_GCT
DMESG("Writing GCT: %x (adr %x)",phy_config,adr);
#endif
gct_rf_stabilize(dev);
}
void gct_write_phy_antenna(struct net_device *dev,short ch)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u8 ant;
ant = GCT_ANTENNA;
if(priv->antb) /*default antenna is antenna B */
ant |= BB_ANTENNA_B;
if(ch == 14)
ant |= BB_ANTATTEN_CHAN14;
write_phy(dev,0x10,ant);
//DMESG("BB antenna %x ",ant);
}
void gct_rf_set_chan(struct net_device *dev, short ch)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 txpw = 0xff & priv->chtxpwr[ch];
u32 chan = gct_chan[ch];
//write_phy(dev,3,txpw);
#ifdef DEBUG_GCT
DMESG("Gct set channel");
#endif
/* set TX power */
write_gct(dev,0x15,0);
write_gct(dev,6, txpw);
write_gct(dev,0x15, 0x10);
write_gct(dev,0x15,0);
/*set frequency*/
write_gct(dev,7, 0);
write_gct(dev,0xB, chan);
write_gct(dev,7, 0x1000);
#ifdef DEBUG_GCT
DMESG("Gct set channel > write phy antenna");
#endif
gct_write_phy_antenna(dev,ch);
}
void gct_rf_close(struct net_device *dev)
{
u32 anaparam;
anaparam = read_nic_dword(dev,ANAPARAM);
anaparam &= 0x000fffff;
anaparam |= 0x3f900000;
rtl8180_set_anaparam(dev, anaparam);
write_gct(dev, 0x7, 0);
write_gct(dev, 0x1f, 0x45);
write_gct(dev, 0x1f, 0x5);
write_gct(dev, 0x0, 0x8e4);
}
void gct_rf_init(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
//u32 anaparam;
write_nic_byte(dev,PHY_DELAY,0x6); //this is general
write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general
//DMESG("%x", read_nic_dword(dev,ANAPARAM));
/* we should set anaparm here*/
//rtl8180_set_anaparam(dev,anaparam);
write_gct(dev,0x1f,0);
write_gct(dev,0x1f,0);
write_gct(dev,0x1f,0x40);
write_gct(dev,0x1f,0x60);
write_gct(dev,0x1f,0x61);
write_gct(dev,0x1f,0x61);
write_gct(dev,0x0,0xae4);
write_gct(dev,0x1f,0x1);
write_gct(dev,0x1f,0x41);
write_gct(dev,0x1f,0x61);
write_gct(dev,0x1,0x1a23);
write_gct(dev,0x2,0x4971);
write_gct(dev,0x3,0x41de);
write_gct(dev,0x4,0x2d80);
#ifdef GCT_EXPERIMENT1
//write_gct(dev,0x5,0x6810); // from zydas driver. sens+ but quite slow
//write_gct(dev,0x5,0x681f); //good+ (somewhat stable, better sens, performance decent)
write_gct(dev,0x5,0x685f); //good performances, not sure sens is really so beeter
//write_gct(dev,0x5,0x687f); //good performances, maybe sens is not improved
//write_gct(dev,0x5,0x689f); //like above
//write_gct(dev,0x5,0x685e); //bad
//write_gct(dev,0x5,0x68ff); //good+ (somewhat stable, better sens(?), performance decent)
//write_gct(dev,0x5,0x68f0); //bad
//write_gct(dev,0x5,0x6cff); //sens+ but not so good
//write_gct(dev,0x5,0x6dff); //sens+,apparentely very good but broken
//write_gct(dev,0x5,0x65ff); //sens+,good
//write_gct(dev,0x5,0x78ff); //sens + but almost broken
//write_gct(dev,0x5,0x7810); //- //snes + but broken
//write_gct(dev,0x5,0x781f); //-- //sens +
//write_gct(dev,0x5,0x78f0); //low sens
#else
write_gct(dev,0x5,0x61ff); //best performance but weak sensitivity
#endif
#ifdef GCT_EXPERIMENT2
write_gct(dev,0x6,0xe);
#else
write_gct(dev,0x6,0x0);
#endif
write_gct(dev,0x7,0x0);
write_gct(dev,0x8,0x7533);
write_gct(dev,0x9,0xc401);
write_gct(dev,0xa,0x0);
write_gct(dev,0xc,0x1c7);
write_gct(dev,0xd,0x29d3);
write_gct(dev,0xe,0x2e8);
write_gct(dev,0x10,0x192);
#ifdef GCT_EXPERIMENT3
write_gct(dev,0x11,0x246);
#else
write_gct(dev,0x11,0x248);
#endif
write_gct(dev,0x12,0x0);
write_gct(dev,0x13,0x20c4);
#ifdef GCT_EXPERIMENT4
write_gct(dev,0x14,0xf488);
#else
write_gct(dev,0x14,0xf4fc);
#endif
#ifdef GCT_EXPERIMENT5
write_gct(dev,0x15,0xb152);
#else
write_gct(dev,0x15,0x0);
#endif
#ifdef GCT_EXPERIMENT6
write_gct(dev,0x1e,0x1);
#endif
write_gct(dev,0x16,0x1500);
write_gct(dev,0x7,0x1000);
/*write_gct(dev,0x15,0x0);
write_gct(dev,0x6,0x15);
write_gct(dev,0x15,0x8);
write_gct(dev,0x15,0x0);
*/
write_phy(dev,0,0xa8);
/* write_gct(dev,0x15,0x0);
write_gct(dev,0x6,0x12);
write_gct(dev,0x15,0x8);
write_gct(dev,0x15,0x0);
*/
write_phy(dev,3,0x0);
write_phy(dev,4,0xc0); /* lna det*/
write_phy(dev,5,0x90);
write_phy(dev,6,0x1e);
write_phy(dev,7,0x64);
#ifdef DEBUG_GCT
DMESG("Gct init> write phy antenna");
#endif
gct_write_phy_antenna(dev,priv->chan);
write_phy(dev,0x11,0x88);
if(!priv->diversity)
write_phy(dev,0x12,0xc0);
else
write_phy(dev,0x12,0x40);
write_phy(dev,0x13,0x90 | priv->cs_treshold );
write_phy(dev,0x19,0x0);
write_phy(dev,0x1a,0xa0);
write_phy(dev,0x1b,0x44);
#ifdef DEBUG_GCT
DMESG("Gct init > set channel2");
#endif
gct_rf_set_chan(dev,priv->chan);
}

View File

@ -0,0 +1,25 @@
/*
This is part of rtl8180 OpenSource driver - v 0.20
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
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 tanks the Authors of such projects and the Ndiswrapper project Authors.
*/
#define GCT_ANTENNA 0xA3
// we use the untouched eeprom value- cross your finger ;-)
#define GCT_ANAPARAM_PWR1_ON ??
#define GCT_ANAPARAM_PWR0_ON ??
void gct_rf_init(struct net_device *dev);
void gct_rf_set_chan(struct net_device *dev,short ch);
void gct_rf_close(struct net_device *dev);

View File

@ -0,0 +1,956 @@
/*
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
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 tanks the Authors of those projects
and the Ndiswrapper project Authors.
*/
/* Mariusz Matuszek added full registers definition with Realtek's name */
/* this file contains register definitions for the rtl8180 MAC controller */
#ifndef R8180_HW
#define R8180_HW
#define CONFIG_RTL8185B //support for rtl8185B, xiong-2006-11-15
#define CONFIG_RTL818X_S
#define BIT0 0x00000001
#define BIT1 0x00000002
#define BIT2 0x00000004
#define BIT3 0x00000008
#define BIT4 0x00000010
#define BIT5 0x00000020
#define BIT6 0x00000040
#define BIT7 0x00000080
#define BIT8 0x00000100
#define BIT9 0x00000200
#define BIT10 0x00000400
#define BIT11 0x00000800
#define BIT12 0x00001000
#define BIT13 0x00002000
#define BIT14 0x00004000
#define BIT15 0x00008000
#define BIT16 0x00010000
#define BIT17 0x00020000
#define BIT18 0x00040000
#define BIT19 0x00080000
#define BIT20 0x00100000
#define BIT21 0x00200000
#define BIT22 0x00400000
#define BIT23 0x00800000
#define BIT24 0x01000000
#define BIT25 0x02000000
#define BIT26 0x04000000
#define BIT27 0x08000000
#define BIT28 0x10000000
#define BIT29 0x20000000
#define BIT30 0x40000000
#define BIT31 0x80000000
#define MAX_SLEEP_TIME (10000)
#define MIN_SLEEP_TIME (50)
#define BB_ANTATTEN_CHAN14 0x0c
#define BB_ANTENNA_B 0x40
#define BB_HOST_BANG (1<<30)
#define BB_HOST_BANG_EN (1<<2)
#define BB_HOST_BANG_CLK (1<<1)
#define BB_HOST_BANG_DATA 1
#define ANAPARAM_TXDACOFF_SHIFT 27
#define ANAPARAM_PWR0_MASK ((1<<30)|(1<<29)|(1<<28))
#define ANAPARAM_PWR0_SHIFT 28
#define ANAPARAM_PWR1_MASK ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20))
#define ANAPARAM_PWR1_SHIFT 20
#define MAC0 0
#define MAC1 1
#define MAC2 2
#define MAC3 3
#define MAC4 4
#define MAC5 5
#define CMD 0x37
#define CMD_RST_SHIFT 4
#define CMD_RESERVED_MASK ((1<<1) | (1<<5) | (1<<6) | (1<<7))
#define CMD_RX_ENABLE_SHIFT 3
#define CMD_TX_ENABLE_SHIFT 2
#define EPROM_CMD 0x50
#define EPROM_CMD_RESERVED_MASK ((1<<5)|(1<<4))
#define EPROM_CMD_OPERATING_MODE_SHIFT 6
#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6))
#define EPROM_CMD_CONFIG 0x3
#define EPROM_CMD_NORMAL 0
#define EPROM_CMD_LOAD 1
#define EPROM_CMD_PROGRAM 2
#define EPROM_CS_SHIFT 3
#define EPROM_CK_SHIFT 2
#define EPROM_W_SHIFT 1
#define EPROM_R_SHIFT 0
#define CONFIG2_DMA_POLLING_MODE_SHIFT 3
#define INTA 0x3e
#define INTA_TXOVERFLOW (1<<15)
#define INTA_TIMEOUT (1<<14)
#define INTA_BEACONTIMEOUT (1<<13)
#define INTA_ATIM (1<<12)
#define INTA_BEACONDESCERR (1<<11)
#define INTA_BEACONDESCOK (1<<10)
#define INTA_HIPRIORITYDESCERR (1<<9)
#define INTA_HIPRIORITYDESCOK (1<<8)
#define INTA_NORMPRIORITYDESCERR (1<<7)
#define INTA_NORMPRIORITYDESCOK (1<<6)
#define INTA_RXOVERFLOW (1<<5)
#define INTA_RXDESCERR (1<<4)
#define INTA_LOWPRIORITYDESCERR (1<<3)
#define INTA_LOWPRIORITYDESCOK (1<<2)
#define INTA_RXCRCERR (1<<1)
#define INTA_RXOK (1)
#define INTA_MASK 0x3c
#define RXRING_ADDR 0xe4 // page 0
#define PGSELECT 0x5e
#define PGSELECT_PG_SHIFT 0
#define RX_CONF 0x44
#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \
(1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23))
#define RX_CHECK_BSSID_SHIFT 23
#define ACCEPT_PWR_FRAME_SHIFT 22
#define ACCEPT_MNG_FRAME_SHIFT 20
#define ACCEPT_CTL_FRAME_SHIFT 19
#define ACCEPT_DATA_FRAME_SHIFT 18
#define ACCEPT_ICVERR_FRAME_SHIFT 12
#define ACCEPT_CRCERR_FRAME_SHIFT 5
#define ACCEPT_BCAST_FRAME_SHIFT 3
#define ACCEPT_MCAST_FRAME_SHIFT 2
#define ACCEPT_ALLMAC_FRAME_SHIFT 0
#define ACCEPT_NICMAC_FRAME_SHIFT 1
#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15))
#define RX_FIFO_THRESHOLD_SHIFT 13
#define RX_FIFO_THRESHOLD_128 3
#define RX_FIFO_THRESHOLD_256 4
#define RX_FIFO_THRESHOLD_512 5
#define RX_FIFO_THRESHOLD_1024 6
#define RX_FIFO_THRESHOLD_NONE 7
#define RX_AUTORESETPHY_SHIFT 28
#define EPROM_TYPE_SHIFT 6
#define TX_CONF 0x40
#define TX_CONF_HEADER_AUTOICREMENT_SHIFT 30
#define TX_LOOPBACK_SHIFT 17
#define TX_LOOPBACK_MAC 1
#define TX_LOOPBACK_BASEBAND 2
#define TX_LOOPBACK_NONE 0
#define TX_LOOPBACK_CONTINUE 3
#define TX_LOOPBACK_MASK ((1<<17)|(1<<18))
#define TX_DPRETRY_SHIFT 0
#define R8180_MAX_RETRY 255
#define TX_RTSRETRY_SHIFT 8
#define TX_NOICV_SHIFT 19
#define TX_NOCRC_SHIFT 16
#define TX_DMA_POLLING 0xd9
#define TX_DMA_POLLING_BEACON_SHIFT 7
#define TX_DMA_POLLING_HIPRIORITY_SHIFT 6
#define TX_DMA_POLLING_NORMPRIORITY_SHIFT 5
#define TX_DMA_POLLING_LOWPRIORITY_SHIFT 4
#define TX_DMA_STOP_BEACON_SHIFT 3
#define TX_DMA_STOP_HIPRIORITY_SHIFT 2
#define TX_DMA_STOP_NORMPRIORITY_SHIFT 1
#define TX_DMA_STOP_LOWPRIORITY_SHIFT 0
#define TX_MANAGEPRIORITY_RING_ADDR 0x0C
#define TX_BKPRIORITY_RING_ADDR 0x10
#define TX_BEPRIORITY_RING_ADDR 0x14
#define TX_VIPRIORITY_RING_ADDR 0x20
#define TX_VOPRIORITY_RING_ADDR 0x24
#define TX_HIGHPRIORITY_RING_ADDR 0x28
//AC_VI and Low priority share the sane queue
#define TX_LOWPRIORITY_RING_ADDR TX_VIPRIORITY_RING_ADDR
//AC_VO and Norm priority share the same queue
#define TX_NORMPRIORITY_RING_ADDR TX_VOPRIORITY_RING_ADDR
#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10))
#define MAX_RX_DMA_2048 7
#define MAX_RX_DMA_1024 6
#define MAX_RX_DMA_SHIFT 10
#define INT_TIMEOUT 0x48
#define CONFIG3_CLKRUN_SHIFT 2
#define CONFIG3_ANAPARAM_W_SHIFT 6
#define ANAPARAM 0x54
#define BEACON_INTERVAL 0x70
#define BEACON_INTERVAL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)| \
(1<<6)|(1<<7)|(1<<8)|(1<<9))
#define ATIM_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)| \
(1<<8)|(1<<9))
#define ATIM 0x72
#define EPROM_CS_SHIFT 3
#define EPROM_CK_SHIFT 2
#define PHY_DELAY 0x78
#define PHY_CONFIG 0x80
#define PHY_ADR 0x7c
#define PHY_READ 0x7e
#define CARRIER_SENSE_COUNTER 0x79 //byte
#define SECURITY 0x5f //1209 this is sth wrong
#define SECURITY_WEP_TX_ENABLE_SHIFT 1
#define SECURITY_WEP_RX_ENABLE_SHIFT 0
#define SECURITY_ENCRYP_104 1
#define SECURITY_ENCRYP_SHIFT 4
#define SECURITY_ENCRYP_MASK ((1<<4)|(1<<5))
#define KEY0 0x90 //1209 this is sth wrong
#define CONFIG2_ANTENNA_SHIFT 6
#define TX_BEACON_RING_ADDR 0x4c
#define CONFIG0_WEP40_SHIFT 7
#define CONFIG0_WEP104_SHIFT 6
#define AGCRESET_SHIFT 5
/*
* Operational registers offsets in PCI (I/O) space.
* RealTek names are used.
*/
#define IDR0 0x0000
#define IDR1 0x0001
#define IDR2 0x0002
#define IDR3 0x0003
#define IDR4 0x0004
#define IDR5 0x0005
/* 0x0006 - 0x0007 - reserved */
#define MAR0 0x0008
#define MAR1 0x0009
#define MAR2 0x000A
#define MAR3 0x000B
#define MAR4 0x000C
#define MAR5 0x000D
#define MAR6 0x000E
#define MAR7 0x000F
/* 0x0010 - 0x0017 - reserved */
#define TSFTR 0x0018
#define TSFTR_END 0x001F
#define TLPDA 0x0020
#define TLPDA_END 0x0023
#define TNPDA 0x0024
#define TNPDA_END 0x0027
#define THPDA 0x0028
#define THPDA_END 0x002B
#define BSSID 0x002E
#define BSSID_END 0x0033
#define CR 0x0037
#ifdef CONFIG_RTL8185B
#define RF_SW_CONFIG 0x8 // store data which is transmitted to RF for driver
#define RF_SW_CFG_SI BIT1
#define PIFS 0x2C // PCF InterFrame Spacing Timer Setting.
#define EIFS 0x2D // Extended InterFrame Space Timer, in unit of 4 us.
#define BRSR 0x34 // Basic rate set
#define IMR 0x006C
#define ISR 0x003C
#else
#define BRSR 0x002C
#define BRSR_END 0x002D
/* 0x0034 - 0x0034 - reserved */
#define EIFS 0x0035
#define IMR 0x003C
#define IMR_END 0x003D
#define ISR 0x003E
#define ISR_END 0x003F
#endif
#define TCR 0x0040
#define TCR_END 0x0043
#define RCR 0x0044
#define RCR_END 0x0047
#define TimerInt 0x0048
#define TimerInt_END 0x004B
#define TBDA 0x004C
#define TBDA_END 0x004F
#define CR9346 0x0050
#define CONFIG0 0x0051
#define CONFIG1 0x0052
#define CONFIG2 0x0053
#define ANA_PARM 0x0054
#define ANA_PARM_END 0x0x0057
#define MSR 0x0058
#define CONFIG3 0x0059
#define CONFIG4 0x005A
#ifdef CONFIG_RTL8185B
#ifdef CONFIG_RTL818X_S
// SD3 szuyitasi: Mac0x57= CC -> B0 Mac0x60= D1 -> C6
// Mac0x60 = 0x000004C6 power save parameters
#define ANAPARM_ASIC_ON 0xB0054D00
#define ANAPARM2_ASIC_ON 0x000004C6
#define ANAPARM_ON ANAPARM_ASIC_ON
#define ANAPARM2_ON ANAPARM2_ASIC_ON
#else
// SD3 CMLin:
#define ANAPARM_ASIC_ON 0x45090658
#define ANAPARM2_ASIC_ON 0x727f3f52
#define ANAPARM_ON ANAPARM_ASIC_ON
#define ANAPARM2_ON ANAPARM2_ASIC_ON
#endif
#endif
#define TESTR 0x005B
/* 0x005C - 0x005D - reserved */
#define PSR 0x005E
/* 0x0060 - 0x006F - reserved */
#define BcnItv 0x0070
#define BcnItv_END 0x0071
#define AtimWnd 0x0072
#define AtimWnd_END 0x0073
#define BintrItv 0x0074
#define BintrItv_END 0x0075
#define AtimtrItv 0x0076
#define AtimtrItv_END 0x0077
#define PhyDelay 0x0078
#define CRCount 0x0079
/* 0x007A - 0x007B - reserved */
#define PhyAddr 0x007C
#define PhyDataW 0x007D
#define PhyDataR 0x007E
#define PhyCFG 0x0080
#define PhyCFG_END 0x0083
/* following are for rtl8185 */
#define RFPinsOutput 0x80
#define RFPinsEnable 0x82
#define RF_TIMING 0x8c
#define RFPinsSelect 0x84
#define ANAPARAM2 0x60
#define RF_PARA 0x88
#define RFPinsInput 0x86
#define GP_ENABLE 0x90
#define GPIO 0x91
#define SW_CONTROL_GPIO 0x400
#define TX_ANTENNA 0x9f
#define TX_GAIN_OFDM 0x9e
#define TX_GAIN_CCK 0x9d
#define WPA_CONFIG 0xb0
#define TX_AGC_CTL 0x9c
#define TX_AGC_CTL_PERPACKET_GAIN_SHIFT 0
#define TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT 1
#define TX_AGC_CTL_FEEDBACK_ANT 2
#define RESP_RATE 0x34
#define SIFS 0xb4
#define DIFS 0xb5
#define SLOT 0xb6
#define CW_CONF 0xbc
#define CW_CONF_PERPACKET_RETRY_SHIFT 1
#define CW_CONF_PERPACKET_CW_SHIFT 0
#define CW_VAL 0xbd
#define MAX_RESP_RATE_SHIFT 4
#define MIN_RESP_RATE_SHIFT 0
#define RATE_FALLBACK 0xbe
/*
* 0x0084 - 0x00D3 is selected to page 1 when PSEn bit (bit0, PSR)
* is set to 1
*/
#define Wakeup0 0x0084
#define Wakeup0_END 0x008B
#define Wakeup1 0x008C
#define Wakeup1_END 0x0093
#define Wakeup2LD 0x0094
#define Wakeup2LD_END 0x009B
#define Wakeup2HD 0x009C
#define Wakeup2HD_END 0x00A3
#define Wakeup3LD 0x00A4
#define Wakeup3LD_END 0x00AB
#define Wakeup3HD 0x00AC
#define Wakeup3HD_END 0x00B3
#define Wakeup4LD 0x00B4
#define Wakeup4LD_END 0x00BB
#define Wakeup4HD 0x00BC
#define Wakeup4HD_END 0x00C3
#define CRC0 0x00C4
#define CRC0_END 0x00C5
#define CRC1 0x00C6
#define CRC1_END 0x00C7
#define CRC2 0x00C8
#define CRC2_END 0x00C9
#define CRC3 0x00CA
#define CRC3_END 0x00CB
#define CRC4 0x00CC
#define CRC4_END 0x00CD
/* 0x00CE - 0x00D3 - reserved */
/*
* 0x0084 - 0x00D3 is selected to page 0 when PSEn bit (bit0, PSR)
* is set to 0
*/
/* 0x0084 - 0x008F - reserved */
#define DK0 0x0090
#define DK0_END 0x009F
#define DK1 0x00A0
#define DK1_END 0x00AF
#define DK2 0x00B0
#define DK2_END 0x00BF
#define DK3 0x00C0
#define DK3_END 0x00CF
/* 0x00D0 - 0x00D3 - reserved */
/* 0x00D4 - 0x00D7 - reserved */
#define CONFIG5 0x00D8
#define TPPoll 0x00D9
/* 0x00DA - 0x00DB - reserved */
#ifdef CONFIG_RTL818X_S
#define PHYPR 0xDA //0xDA - 0x0B PHY Parameter Register.
#endif
#define CWR 0x00DC
#define CWR_END 0x00DD
#define RetryCTR 0x00DE
/* 0x00DF - 0x00E3 - reserved */
#define RDSAR 0x00E4
#define RDSAR_END 0x00E7
/* 0x00E8 - 0x00EF - reserved */
#ifdef CONFIG_RTL818X_S
#define LED_CONTROL 0xED
#endif
#define FER 0x00F0
#define FER_END 0x00F3
#ifdef CONFIG_RTL8185B
#define FEMR 0x1D4 // Function Event Mask register
#else
#define FEMR 0x00F4
#define FEMR_END 0x00F7
#endif
#define FPSR 0x00F8
#define FPSR_END 0x00FB
#define FFER 0x00FC
#define FFER_END 0x00FF
/*
* Bitmasks for specific register functions.
* Names are derived from the register name and function name.
*
* <REGISTER>_<FUNCTION>[<bit>]
*
* this leads to some awkward names...
*/
#define BRSR_BPLCP ((1<< 8))
#define BRSR_MBR ((1<< 1)|(1<< 0))
#define BRSR_MBR_8185 ((1<< 11)|(1<< 10)|(1<< 9)|(1<< 8)|(1<< 7)|(1<< 6)|(1<< 5)|(1<< 4)|(1<< 3)|(1<< 2)|(1<< 1)|(1<< 0))
#define BRSR_MBR0 ((1<< 0))
#define BRSR_MBR1 ((1<< 1))
#define CR_RST ((1<< 4))
#define CR_RE ((1<< 3))
#define CR_TE ((1<< 2))
#define CR_MulRW ((1<< 0))
#ifdef CONFIG_RTL8185B
#define IMR_Dot11hInt ((1<< 25)) // 802.11h Measurement Interrupt
#define IMR_BcnDmaInt ((1<< 24)) // Beacon DMA Interrupt // What differenct between BcnDmaInt and BcnInt???
#define IMR_WakeInt ((1<< 23)) // Wake Up Interrupt
#define IMR_TXFOVW ((1<< 22)) // Tx FIFO Overflow Interrupt
#define IMR_TimeOut1 ((1<< 21)) // Time Out Interrupt 1
#define IMR_BcnInt ((1<< 20)) // Beacon Time out Interrupt
#define IMR_ATIMInt ((1<< 19)) // ATIM Time Out Interrupt
#define IMR_TBDER ((1<< 18)) // Tx Beacon Descriptor Error Interrupt
#define IMR_TBDOK ((1<< 17)) // Tx Beacon Descriptor OK Interrupt
#define IMR_THPDER ((1<< 16)) // Tx High Priority Descriptor Error Interrupt
#define IMR_THPDOK ((1<< 15)) // Tx High Priority Descriptor OK Interrupt
#define IMR_TVODER ((1<< 14)) // Tx AC_VO Descriptor Error Interrupt
#define IMR_TVODOK ((1<< 13)) // Tx AC_VO Descriptor OK Interrupt
#define IMR_FOVW ((1<< 12)) // Rx FIFO Overflow Interrupt
#define IMR_RDU ((1<< 11)) // Rx Descriptor Unavailable Interrupt
#define IMR_TVIDER ((1<< 10)) // Tx AC_VI Descriptor Error Interrupt
#define IMR_TVIDOK ((1<< 9)) // Tx AC_VI Descriptor OK Interrupt
#define IMR_RER ((1<< 8)) // Rx Error Interrupt
#define IMR_ROK ((1<< 7)) // Receive OK Interrupt
#define IMR_TBEDER ((1<< 6)) // Tx AC_BE Descriptor Error Interrupt
#define IMR_TBEDOK ((1<< 5)) // Tx AC_BE Descriptor OK Interrupt
#define IMR_TBKDER ((1<< 4)) // Tx AC_BK Descriptor Error Interrupt
#define IMR_TBKDOK ((1<< 3)) // Tx AC_BK Descriptor OK Interrupt
#define IMR_RQoSOK ((1<< 2)) // Rx QoS OK Interrupt
#define IMR_TimeOut2 ((1<< 1)) // Time Out Interrupt 2
#define IMR_TimeOut3 ((1<< 0)) // Time Out Interrupt 3
#define IMR_TMGDOK ((1<<30))
#define ISR_Dot11hInt ((1<< 25)) // 802.11h Measurement Interrupt
#define ISR_BcnDmaInt ((1<< 24)) // Beacon DMA Interrupt // What differenct between BcnDmaInt and BcnInt???
#define ISR_WakeInt ((1<< 23)) // Wake Up Interrupt
#define ISR_TXFOVW ((1<< 22)) // Tx FIFO Overflow Interrupt
#define ISR_TimeOut1 ((1<< 21)) // Time Out Interrupt 1
#define ISR_BcnInt ((1<< 20)) // Beacon Time out Interrupt
#define ISR_ATIMInt ((1<< 19)) // ATIM Time Out Interrupt
#define ISR_TBDER ((1<< 18)) // Tx Beacon Descriptor Error Interrupt
#define ISR_TBDOK ((1<< 17)) // Tx Beacon Descriptor OK Interrupt
#define ISR_THPDER ((1<< 16)) // Tx High Priority Descriptor Error Interrupt
#define ISR_THPDOK ((1<< 15)) // Tx High Priority Descriptor OK Interrupt
#define ISR_TVODER ((1<< 14)) // Tx AC_VO Descriptor Error Interrupt
#define ISR_TVODOK ((1<< 13)) // Tx AC_VO Descriptor OK Interrupt
#define ISR_FOVW ((1<< 12)) // Rx FIFO Overflow Interrupt
#define ISR_RDU ((1<< 11)) // Rx Descriptor Unavailable Interrupt
#define ISR_TVIDER ((1<< 10)) // Tx AC_VI Descriptor Error Interrupt
#define ISR_TVIDOK ((1<< 9)) // Tx AC_VI Descriptor OK Interrupt
#define ISR_RER ((1<< 8)) // Rx Error Interrupt
#define ISR_ROK ((1<< 7)) // Receive OK Interrupt
#define ISR_TBEDER ((1<< 6)) // Tx AC_BE Descriptor Error Interrupt
#define ISR_TBEDOK ((1<< 5)) // Tx AC_BE Descriptor OK Interrupt
#define ISR_TBKDER ((1<< 4)) // Tx AC_BK Descriptor Error Interrupt
#define ISR_TBKDOK ((1<< 3)) // Tx AC_BK Descriptor OK Interrupt
#define ISR_RQoSOK ((1<< 2)) // Rx QoS OK Interrupt
#define ISR_TimeOut2 ((1<< 1)) // Time Out Interrupt 2
#define ISR_TimeOut3 ((1<< 0)) // Time Out Interrupt 3
//these definition is used for Tx/Rx test temporarily
#define ISR_TLPDER ISR_TVIDER
#define ISR_TLPDOK ISR_TVIDOK
#define ISR_TNPDER ISR_TVODER
#define ISR_TNPDOK ISR_TVODOK
#define ISR_TimeOut ISR_TimeOut1
#define ISR_RXFOVW ISR_FOVW
#else
#define IMR_TXFOVW ((1<<15))
#define IMR_TimeOut ((1<<14))
#define IMR_BcnInt ((1<<13))
#define IMR_ATIMInt ((1<<12))
#define IMR_TBDER ((1<<11))
#define IMR_TBDOK ((1<<10))
#define IMR_THPDER ((1<< 9))
#define IMR_THPDOK ((1<< 8))
#define IMR_TNPDER ((1<< 7))
#define IMR_TNPDOK ((1<< 6))
#define IMR_RXFOVW ((1<< 5))
#define IMR_RDU ((1<< 4))
#define IMR_TLPDER ((1<< 3))
#define IMR_TLPDOK ((1<< 2))
#define IMR_RER ((1<< 1))
#define IMR_ROK ((1<< 0))
#define ISR_TXFOVW ((1<<15))
#define ISR_TimeOut ((1<<14))
#define ISR_BcnInt ((1<<13))
#define ISR_ATIMInt ((1<<12))
#define ISR_TBDER ((1<<11))
#define ISR_TBDOK ((1<<10))
#define ISR_THPDER ((1<< 9))
#define ISR_THPDOK ((1<< 8))
#define ISR_TNPDER ((1<< 7))
#define ISR_TNPDOK ((1<< 6))
#define ISR_RXFOVW ((1<< 5))
#define ISR_RDU ((1<< 4))
#define ISR_TLPDER ((1<< 3))
#define ISR_TLPDOK ((1<< 2))
#define ISR_RER ((1<< 1))
#define ISR_ROK ((1<< 0))
#endif
#define HW_VERID_R8180_F 3
#define HW_VERID_R8180_ABCD 2
#define HW_VERID_R8185_ABC 4
#define HW_VERID_R8185_D 5
#ifdef CONFIG_RTL8185B
#define HW_VERID_R8185B_B 6
#endif
#define TCR_CWMIN ((1<<31))
#define TCR_SWSEQ ((1<<30))
#define TCR_HWVERID_MASK ((1<<27)|(1<<26)|(1<<25))
#define TCR_HWVERID_SHIFT 25
#define TCR_SAT ((1<<24))
#define TCR_PLCP_LEN TCR_SAT // rtl8180
#define TCR_MXDMA_MASK ((1<<23)|(1<<22)|(1<<21))
#define TCR_MXDMA_1024 6
#define TCR_MXDMA_2048 7
#define TCR_MXDMA_SHIFT 21
#define TCR_DISCW ((1<<20))
#define TCR_ICV ((1<<19))
#define TCR_LBK ((1<<18)|(1<<17))
#define TCR_LBK1 ((1<<18))
#define TCR_LBK0 ((1<<17))
#define TCR_CRC ((1<<16))
#define TCR_DPRETRY_MASK ((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8))
#define TCR_RTSRETRY_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7))
#define TCR_PROBE_NOTIMESTAMP_SHIFT 29 //rtl8185
#define RCR_ONLYERLPKT ((1<<31))
#define RCR_CS_SHIFT 29
#define RCR_CS_MASK ((1<<30) | (1<<29))
#define RCR_ENMARP ((1<<28))
#define RCR_CBSSID ((1<<23))
#define RCR_APWRMGT ((1<<22))
#define RCR_ADD3 ((1<<21))
#define RCR_AMF ((1<<20))
#define RCR_ACF ((1<<19))
#define RCR_ADF ((1<<18))
#define RCR_RXFTH ((1<<15)|(1<<14)|(1<<13))
#define RCR_RXFTH2 ((1<<15))
#define RCR_RXFTH1 ((1<<14))
#define RCR_RXFTH0 ((1<<13))
#define RCR_AICV ((1<<12))
#define RCR_MXDMA ((1<<10)|(1<< 9)|(1<< 8))
#define RCR_MXDMA2 ((1<<10))
#define RCR_MXDMA1 ((1<< 9))
#define RCR_MXDMA0 ((1<< 8))
#define RCR_9356SEL ((1<< 6))
#define RCR_ACRC32 ((1<< 5))
#define RCR_AB ((1<< 3))
#define RCR_AM ((1<< 2))
#define RCR_APM ((1<< 1))
#define RCR_AAP ((1<< 0))
#define CR9346_EEM ((1<<7)|(1<<6))
#define CR9346_EEM1 ((1<<7))
#define CR9346_EEM0 ((1<<6))
#define CR9346_EECS ((1<<3))
#define CR9346_EESK ((1<<2))
#define CR9346_EED1 ((1<<1))
#define CR9346_EED0 ((1<<0))
#define CONFIG0_WEP104 ((1<<6))
#define CONFIG0_LEDGPO_En ((1<<4))
#define CONFIG0_Aux_Status ((1<<3))
#define CONFIG0_GL ((1<<1)|(1<<0))
#define CONFIG0_GL1 ((1<<1))
#define CONFIG0_GL0 ((1<<0))
#define CONFIG1_LEDS ((1<<7)|(1<<6))
#define CONFIG1_LEDS1 ((1<<7))
#define CONFIG1_LEDS0 ((1<<6))
#define CONFIG1_LWACT ((1<<4))
#define CONFIG1_MEMMAP ((1<<3))
#define CONFIG1_IOMAP ((1<<2))
#define CONFIG1_VPD ((1<<1))
#define CONFIG1_PMEn ((1<<0))
#define CONFIG2_LCK ((1<<7))
#define CONFIG2_ANT ((1<<6))
#define CONFIG2_DPS ((1<<3))
#define CONFIG2_PAPE_sign ((1<<2))
#define CONFIG2_PAPE_time ((1<<1)|(1<<0))
#define CONFIG2_PAPE_time1 ((1<<1))
#define CONFIG2_PAPE_time0 ((1<<0))
#define CONFIG3_GNTSel ((1<<7))
#define CONFIG3_PARM_En ((1<<6))
#define CONFIG3_Magic ((1<<5))
#define CONFIG3_CardB_En ((1<<3))
#define CONFIG3_CLKRUN_En ((1<<2))
#define CONFIG3_FuncRegEn ((1<<1))
#define CONFIG3_FBtbEn ((1<<0))
#define CONFIG4_VCOPDN ((1<<7))
#define CONFIG4_PWROFF ((1<<6))
#define CONFIG4_PWRMGT ((1<<5))
#define CONFIG4_LWPME ((1<<4))
#define CONFIG4_LWPTN ((1<<2))
#define CONFIG4_RFTYPE ((1<<1)|(1<<0))
#define CONFIG4_RFTYPE1 ((1<<1))
#define CONFIG4_RFTYPE0 ((1<<0))
#define CONFIG5_TX_FIFO_OK ((1<<7))
#define CONFIG5_RX_FIFO_OK ((1<<6))
#define CONFIG5_CALON ((1<<5))
#define CONFIG5_EACPI ((1<<2))
#define CONFIG5_LANWake ((1<<1))
#define CONFIG5_PME_STS ((1<<0))
#define MSR_LINK_MASK ((1<<2)|(1<<3))
#define MSR_LINK_MANAGED 2
#define MSR_LINK_NONE 0
#define MSR_LINK_SHIFT 2
#define MSR_LINK_ADHOC 1
#define MSR_LINK_MASTER 3
#define PSR_GPO ((1<<7))
#define PSR_GPI ((1<<6))
#define PSR_LEDGPO1 ((1<<5))
#define PSR_LEDGPO0 ((1<<4))
#define PSR_UWF ((1<<1))
#define PSR_PSEn ((1<<0))
#define SCR_KM ((1<<5)|(1<<4))
#define SCR_KM1 ((1<<5))
#define SCR_KM0 ((1<<4))
#define SCR_TXSECON ((1<<1))
#define SCR_RXSECON ((1<<0))
#define BcnItv_BcnItv (0x01FF)
#define AtimWnd_AtimWnd (0x01FF)
#define BintrItv_BintrItv (0x01FF)
#define AtimtrItv_AtimtrItv (0x01FF)
#define PhyDelay_PhyDelay ((1<<2)|(1<<1)|(1<<0))
#define TPPoll_BQ ((1<<7))
#define TPPoll_HPQ ((1<<6))
#define TPPoll_NPQ ((1<<5))
#define TPPoll_LPQ ((1<<4))
#define TPPoll_SBQ ((1<<3))
#define TPPoll_SHPQ ((1<<2))
#define TPPoll_SNPQ ((1<<1))
#define TPPoll_SLPQ ((1<<0))
#define CWR_CW (0x01FF)
#define FER_INTR ((1<<15))
#define FER_GWAKE ((1<< 4))
#define FEMR_INTR ((1<<15))
#define FEMR_WKUP ((1<<14))
#define FEMR_GWAKE ((1<< 4))
#define FPSR_INTR ((1<<15))
#define FPSR_GWAKE ((1<< 4))
#define FFER_INTR ((1<<15))
#define FFER_GWAKE ((1<< 4))
#ifdef CONFIG_RTL8185B
// Three wire mode.
#define SW_THREE_WIRE 0
#define HW_THREE_WIRE 2
//RTL8187S by amy
#define HW_THREE_WIRE_PI 5
#define HW_THREE_WIRE_SI 6
//by amy
#define TCR_LRL_OFFSET 0
#define TCR_SRL_OFFSET 8
#define TCR_MXDMA_OFFSET 21
#define TCR_DISReqQsize_OFFSET 28
#define TCR_DurProcMode_OFFSET 30
#define RCR_MXDMA_OFFSET 8
#define RCR_FIFO_OFFSET 13
#define TMGDS 0x0C // Tx Management Descriptor Address
#define TBKDS 0x10 // Tx AC_BK Descriptor Address
#define TBEDS 0x14 // Tx AC_BE Descriptor Address
#define TLPDS 0x20 // Tx AC_VI Descriptor Address
#define TNPDS 0x24 // Tx AC_VO Descriptor Address
#define THPDS 0x28 // Tx Hign Priority Descriptor Address
#define TBDS 0x4c // Beacon descriptor queue start address
#define RDSA 0xE4 // Receive descriptor queue start address
#define AckTimeOutReg 0x79 // ACK timeout register, in unit of 4 us.
#define RFTiming 0x8C
#define TPPollStop 0x93
#define TXAGC_CTL 0x9C // <RJ_TODO_8185B> TX_AGC_CONTROL (0x9C seems be removed at 8185B, see p37).
#define CCK_TXAGC 0x9D
#define OFDM_TXAGC 0x9E
#define ANTSEL 0x9F
#define ACM_CONTROL 0x00BF // ACM Control Registe
#define RTL8185B_VER_REG 0xE1
#define IntMig 0xE2 // Interrupt Migration (0xE2 ~ 0xE3)
#define TID_AC_MAP 0xE8 // TID to AC Mapping Register
#define ANAPARAM3 0xEE // <RJ_TODO_8185B> How to use it?
#define AC_VO_PARAM 0xF0 // AC_VO Parameters Record
#define AC_VI_PARAM 0xF4 // AC_VI Parameters Record
#define AC_BE_PARAM 0xF8 // AC_BE Parameters Record
#define AC_BK_PARAM 0xFC // AC_BK Parameters Record
#ifdef CONFIG_RTL818X_S
#define BcnTimingAdjust 0x16A // Beacon Timing Adjust Register.
#define GPIOCtrl 0x16B // GPIO Control Register.
#define PSByGC 0x180 // 0x180 - 0x183 Power Saving by Gated Clock.
#endif
#define ARFR 0x1E0 // Auto Rate Fallback Register (0x1e0 ~ 0x1e2)
#define RFSW_CTRL 0x272 // 0x272-0x273.
#define SW_3W_DB0 0x274 // Software 3-wire data buffer bit 31~0.
#define SW_3W_DB1 0x278 // Software 3-wire data buffer bit 63~32.
#define SW_3W_CMD0 0x27C // Software 3-wire Control/Status Register.
#define SW_3W_CMD1 0x27D // Software 3-wire Control/Status Register.
#ifdef CONFIG_RTL818X_S
#define PI_DATA_READ 0X360 // 0x360 - 0x361 Parallel Interface Data Register.
#define SI_DATA_READ 0x362 // 0x362 - 0x363 Serial Interface Data Register.
#endif
//----------------------------------------------------------------------------
// 8185B TPPoll bits (offset 0xd9, 1 byte)
//----------------------------------------------------------------------------
#define TPPOLL_BQ (0x01 << 7)
#define TPPOLL_HPQ (0x01 << 6)
#define TPPOLL_AC_VOQ (0x01 << 5)
#define TPPOLL_AC_VIQ (0x01 << 4)
#define TPPOLL_AC_BEQ (0x01 << 3)
#define TPPOLL_AC_BKQ (0x01 << 2)
#define TPPOLL_AC_MGQ (0x01 << 1)
//----------------------------------------------------------------------------
// 8185B TPPollStop bits (offset 0x93, 1 byte)
//----------------------------------------------------------------------------
#define TPPOLLSTOP_BQ (0x01 << 7)
#define TPPOLLSTOP_HPQ (0x01 << 6)
#define TPPOLLSTOP_AC_VOQ (0x01 << 5)
#define TPPOLLSTOP_AC_VIQ (0x01 << 4)
#define TPPOLLSTOP_AC_BEQ (0x01 << 3)
#define TPPOLLSTOP_AC_BKQ (0x01 << 2)
#define TPPOLLSTOP_AC_MGQ (0x01 << 1)
#define MSR_LINK_ENEDCA (1<<4)
//----------------------------------------------------------------------------
// 8187B AC_XX_PARAM bits
//----------------------------------------------------------------------------
#define AC_PARAM_TXOP_LIMIT_OFFSET 16
#define AC_PARAM_ECW_MAX_OFFSET 12
#define AC_PARAM_ECW_MIN_OFFSET 8
#define AC_PARAM_AIFS_OFFSET 0
//----------------------------------------------------------------------------
// 8187B ACM_CONTROL bits (Offset 0xBF, 1 Byte)
//----------------------------------------------------------------------------
#define VOQ_ACM_EN (0x01 << 7) //BIT7
#define VIQ_ACM_EN (0x01 << 6) //BIT6
#define BEQ_ACM_EN (0x01 << 5) //BIT5
#define ACM_HW_EN (0x01 << 4) //BIT4
#define TXOPSEL (0x01 << 3) //BIT3
#define VOQ_ACM_CTL (0x01 << 2) //BIT2 // Set to 1 when AC_VO used time reaches or exceeds the admitted time
#define VIQ_ACM_CTL (0x01 << 1) //BIT1 // Set to 1 when AC_VI used time reaches or exceeds the admitted time
#define BEQ_ACM_CTL (0x01 << 0) //BIT0 // Set to 1 when AC_BE used time reaches or exceeds the admitted time
//----------------------------------------------------------------------------
// 8185B SW_3W_CMD bits (Offset 0x27C-0x27D, 16bit)
//----------------------------------------------------------------------------
#define SW_3W_CMD0_HOLD ((1<< 7))
#define SW_3W_CMD1_RE ((1<< 0)) // BIT8
#define SW_3W_CMD1_WE ((1<< 1)) // BIT9
#define SW_3W_CMD1_DONE ((1<< 2)) // BIT10
#define BB_HOST_BANG_RW (1<<3)
//----------------------------------------------------------------------------
// 8185B RATE_FALLBACK_CTL bits (Offset 0xBE, 8bit)
//----------------------------------------------------------------------------
#define RATE_FALLBACK_CTL_ENABLE ((1<< 7))
#define RATE_FALLBACK_CTL_ENABLE_RTSCTS ((1<< 6))
// Auto rate fallback per 2^n retry.
#define RATE_FALLBACK_CTL_AUTO_STEP0 0x00
#define RATE_FALLBACK_CTL_AUTO_STEP1 0x01
#define RATE_FALLBACK_CTL_AUTO_STEP2 0x02
#define RATE_FALLBACK_CTL_AUTO_STEP3 0x03
#define RTL8225z2_ANAPARAM_OFF 0x55480658
#define RTL8225z2_ANAPARAM2_OFF 0x72003f70
//by amy for power save
#define RF_CHANGE_BY_SW BIT31
#define RF_CHANGE_BY_HW BIT30
#define RF_CHANGE_BY_PS BIT29
#define RF_CHANGE_BY_IPS BIT28
//by amy for power save
//by amy for antenna
#define EEPROM_SW_REVD_OFFSET 0x3f
// BIT[8-9] is for SW Antenna Diversity. Only the value EEPROM_SW_AD_ENABLE means enable, other values are diable.
#define EEPROM_SW_AD_MASK 0x0300
#define EEPROM_SW_AD_ENABLE 0x0100
// BIT[10-11] determine if Antenna 1 is the Default Antenna. Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE.
#define EEPROM_DEF_ANT_MASK 0x0C00
#define EEPROM_DEF_ANT_1 0x0400
//by amy for antenna
//{by amy 080312
//0x7C, 0x7D Crystal calibration and Tx Power tracking mechanism. Added by Roger. 2007.12.10.
#define EEPROM_RSV 0x7C
#define EEPROM_XTAL_CAL_MASK 0x00FF // 0x7C[7:0], Crystal calibration mask.
#define EEPROM_XTAL_CAL_XOUT_MASK 0x0F // 0x7C[3:0], Crystal calibration for Xout.
#define EEPROM_XTAL_CAL_XIN_MASK 0xF0 // 0x7C[7:4], Crystal calibration for Xin.
#define EEPROM_THERMAL_METER_MASK 0x0F00 // 0x7D[3:0], Thermal meter reference level.
#define EEPROM_XTAL_CAL_ENABLE 0x1000 // 0x7D[4], Crystal calibration enabled/disabled BIT.
#define EEPROM_THERMAL_METER_ENABLE 0x2000 // 0x7D[5], Thermal meter enabled/disabled BIT.
#define EEPROM_CID_RSVD1 0x3F
#define EN_LPF_CAL 0x238 // Enable LPF Calibration.
#define PWR_METER_EN BIT1
// <RJ_TODO_8185B> where are false alarm counters in 8185B?
#define CCK_FALSE_ALARM 0xD0
#define OFDM_FALSE_ALARM 0xD2
//by amy 080312}
//YJ,add for Country IE, 080630
#define EEPROM_COUNTRY_CODE 0x2E
//YJ,add,080630,end
#endif
#endif

View File

@ -0,0 +1,240 @@
/*
This files contains MAXIM MAX2820 radio frontend programming routines.
This is part of rtl8180 OpenSource driver
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
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.
NetBSD rtl8180 driver from Dave Young has been really useful to
understand how to program the MAXIM radio. Thanks a lot!!!
'The Deuce' tested this and fixed some bugs.
Code from rtl8181 project has been useful to me to understand some things.
We want to tanks the Authors of such projects and the Ndiswrapper
project Authors.
*/
#include "r8180.h"
#include "r8180_hw.h"
#include "r8180_max2820.h"
//#define DEBUG_MAXIM
u32 maxim_chan[] = {
0, //dummy channel 0
12, //1
17, //2
22, //3
27, //4
32, //5
37, //6
42, //7
47, //8
52, //9
57, //10
62, //11
67, //12
72, //13
84, //14
};
#if 0
/* maxim expects 4 bit address MSF, then 12 bit data MSF*/
void write_maxim(struct net_device *dev,u8 adr, u32 data)
{
int shift;
short bit;
u16 word;
adr = adr &0xf;
word = (u16)data & 0xfff;
word |= (adr<<12);
/*write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | BB_HOST_BANG_EN);
read_nic_dword(dev,PHY_CONFIG);
mdelay(1);
write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | BB_HOST_BANG_EN | BB_HOST_BANG_CLK);
read_nic_dword(dev,PHY_CONFIG);
mdelay(1);
*/
/* MAX2820 will sample data on rising edge of clock */
for(shift = 15;shift >=0; shift--){
bit = word>>shift & 1;
write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<<BB_HOST_BANG_DATA));
read_nic_dword(dev,PHY_CONFIG);
mdelay(2);
write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG |
(bit<<BB_HOST_BANG_DATA) | BB_HOST_BANG_CLK); /* sample data */
read_nic_dword(dev,PHY_CONFIG);
mdelay(1);
write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG |
(bit<<BB_HOST_BANG_DATA));
read_nic_dword(dev,PHY_CONFIG);
mdelay(2);
}
write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<<BB_HOST_BANG_DATA)|
BB_HOST_BANG_EN);
read_nic_dword(dev,PHY_CONFIG);
mdelay(2);
/* The shift register fill flush to the requested register the
* last 12 bits data shifted in
*/
write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<<BB_HOST_BANG_DATA)|
BB_HOST_BANG_EN | BB_HOST_BANG_CLK);
read_nic_dword(dev,PHY_CONFIG);
mdelay(2);
write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<<BB_HOST_BANG_DATA)|
BB_HOST_BANG_EN);
read_nic_dword(dev,PHY_CONFIG);
mdelay(2);
#ifdef DEBUG_MAXIM
DMESG("Writing maxim: %x (adr %x)",phy_config,adr);
#endif
}
#endif
void write_maxim(struct net_device *dev,u8 adr, u32 data) {
u32 temp;
temp = 0x90 + (data & 0xf);
temp <<= 16;
temp += adr;
temp <<= 8;
temp += (data >> 4) & 0xff;
#ifdef DEBUG_MAXIM
DMESG("write_maxim: %08x", temp);
#endif
write_nic_dword(dev, PHY_CONFIG, temp);
force_pci_posting(dev);
mdelay(1);
}
void maxim_write_phy_antenna(struct net_device *dev,short ch)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u8 ant;
ant = MAXIM_ANTENNA;
if(priv->antb) /*default antenna is antenna B */
ant |= BB_ANTENNA_B;
if(ch == 14)
ant |= BB_ANTATTEN_CHAN14;
write_phy(dev,0x10,ant);
//DMESG("BB antenna %x ",ant);
}
void maxim_rf_set_chan(struct net_device *dev, short ch)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 txpw = 0xff & priv->chtxpwr[ch];
u32 chan = maxim_chan[ch];
/*While philips SA2400 drive the PA bias
*seems that for MAXIM we delegate this
*to the BB
*/
//write_maxim(dev,5,txpw);
write_phy(dev,3,txpw);
maxim_write_phy_antenna(dev,ch);
write_maxim(dev,3,chan);
}
void maxim_rf_close(struct net_device *dev)
{
write_phy(dev, 3, 0x8);
write_maxim(dev, 1, 0);
}
void maxim_rf_init(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 anaparam;
write_nic_byte(dev,PHY_DELAY,0x6); //this is general
write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general
/*these are maxim specific*/
anaparam = read_nic_dword(dev,ANAPARAM);
anaparam = anaparam &~ (ANAPARAM_TXDACOFF_SHIFT);
anaparam = anaparam &~ANAPARAM_PWR1_MASK;
anaparam = anaparam &~ANAPARAM_PWR0_MASK;
anaparam |= (MAXIM_ANAPARAM_PWR1_ON<<ANAPARAM_PWR1_SHIFT);
anaparam |= (MAXIM_ANAPARAM_PWR0_ON<<ANAPARAM_PWR0_SHIFT);
//rtl8180_set_anaparam(dev,anaparam);
/* MAXIM from netbsd driver */
write_maxim(dev,0, 7); /* test mode as indicated in datasheet*/
write_maxim(dev,1, 0x1e); /* enable register*/
write_maxim(dev,2, 1); /* synt register */
maxim_rf_set_chan(dev,priv->chan);
write_maxim(dev,4, 0x313); /* rx register*/
/* PA is driven directly by the BB, we keep the MAXIM bias
* at the highest value in the boubt tha pleacing it to lower
* values may introduce some further attenuation somewhere..
*/
write_maxim(dev,5, 0xf);
/*baseband configuration*/
write_phy(dev,0,0x88); //sys1
write_phy(dev,3,0x8); //txagc
write_phy(dev,4,0xf8); // lnadet
write_phy(dev,5,0x90); // ifagcinit
write_phy(dev,6,0x1a); // ifagclimit
write_phy(dev,7,0x64); // ifagcdet
/*Should be done something more here??*/
maxim_write_phy_antenna(dev,priv->chan);
write_phy(dev,0x11,0x88); //trl
if(priv->diversity)
write_phy(dev,0x12,0xc7);
else
write_phy(dev,0x12,0x47);
write_phy(dev,0x13,0x9b);
write_phy(dev,0x19,0x0); //CHESTLIM
write_phy(dev,0x1a,0x9f); //CHSQLIM
maxim_rf_set_chan(dev,priv->chan);
}

View File

@ -0,0 +1,21 @@
/*
This is part of rtl8180 OpenSource driver
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
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 tanks the Authors of such projects and the Ndiswrapper project Authors.
*/
#define MAXIM_ANTENNA 0xb3
#define MAXIM_ANAPARAM_PWR1_ON 0x8
#define MAXIM_ANAPARAM_PWR0_ON 0x0
void maxim_rf_init(struct net_device *dev);
void maxim_rf_set_chan(struct net_device *dev,short ch);
void maxim_rf_close(struct net_device *dev);

View File

@ -0,0 +1,90 @@
/*
Power management interface routines.
Written by Mariusz Matuszek.
This code is currently just a placeholder for later work and
does not do anything useful.
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public Licence)
*/
#ifdef CONFIG_RTL8180_PM
#include "r8180_hw.h"
#include "r8180_pm.h"
#include "r8180.h"
int rtl8180_save_state (struct pci_dev *dev, u32 state)
{
printk(KERN_NOTICE "r8180 save state call (state %u).\n", state);
return(-EAGAIN);
}
int rtl8180_suspend (struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
// struct r8180_priv *priv = ieee80211_priv(dev);
if (!netif_running(dev))
goto out_pci_suspend;
dev->stop(dev);
netif_device_detach(dev);
out_pci_suspend:
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev,pci_choose_state(pdev,state));
return 0;
}
int rtl8180_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
// struct r8180_priv *priv = ieee80211_priv(dev);
int err;
u32 val;
pci_set_power_state(pdev, PCI_D0);
err = pci_enable_device(pdev);
if(err) {
printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
dev->name);
return err;
}
pci_restore_state(pdev);
/*
* Suspend/Resume resets the PCI configuration space, so we have to
* re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
* from interfering with C3 CPU state. pci_restore_state won't help
* here since it only restores the first 64 bytes pci config header.
*/
pci_read_config_dword(pdev, 0x40, &val);
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
if(!netif_running(dev))
goto out;
dev->open(dev);
netif_device_attach(dev);
out:
return 0;
}
int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable)
{
printk(KERN_NOTICE "r8180 enable wake call (state %u, enable %d).\n",
state, enable);
return(-EAGAIN);
}
#endif //CONFIG_RTL8180_PM

View File

@ -0,0 +1,28 @@
/*
Power management interface routines.
Written by Mariusz Matuszek.
This code is currently just a placeholder for later work and
does not do anything useful.
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public Licence)
*/
#ifdef CONFIG_RTL8180_PM
#ifndef R8180_PM_H
#define R8180_PM_H
#include <linux/types.h>
#include <linux/pci.h>
int rtl8180_save_state (struct pci_dev *dev, u32 state);
int rtl8180_suspend (struct pci_dev *pdev, pm_message_t state);
int rtl8180_resume (struct pci_dev *pdev);
int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable);
#endif //R8180_PM_H
#endif // CONFIG_RTL8180_PM

View File

@ -0,0 +1,933 @@
/*
This is part of the rtl8180-sa2400 driver
released under the GPL (See file COPYING for details).
Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
This files contains programming code for the rtl8225
radio frontend.
*Many* thanks to Realtek Corp. for their great support!
*/
#include "r8180_hw.h"
#include "r8180_rtl8225.h"
u8 rtl8225_gain[]={
0x23,0x88,0x7c,0xa5,// -82dbm
0x23,0x88,0x7c,0xb5,// -82dbm
0x23,0x88,0x7c,0xc5,// -82dbm
0x33,0x80,0x79,0xc5,// -78dbm
0x43,0x78,0x76,0xc5,// -74dbm
0x53,0x60,0x73,0xc5,// -70dbm
0x63,0x58,0x70,0xc5,// -66dbm
};
#if 0
u8 rtl8225_init_gain[]={
//0x00,0x00,0x00,0x00,//0x00,0x00,0x00,0x00,
0x33,0x80,0x6c,0xc5,//0x00,0x49,0x06,0xb5,//Gain = 0 ~ -78dbm
0x43,0x78,0x69,0xc5,//0x00,0x45,0x06,0xb1,//Gain = 1 ~ -74dbm
0x53,0x60,0x66,0xc5,//0x00,0x41,0x06,0xab,//Gain = 2 ~ -70dbm
0x63,0x58,0x63,0xc5,//0x00,0x3d,0x06,0xa5,//Gain = 3 ~ -66dbm
0x73,0x50,0x62,0xc5,//0x00,0x39,0x06,0xa1,//Gain = 4 ~ -62dbm
0x83,0x43,0x61,0xc5,//0x00,0x35,0x06,0x9b,//Gain = 5 ~ -58dbm
0x93,0x38,0x5a,0xc5,//0x00,0x31,0x06,0x99,//Gain = 6 ~ -54dbm
};
#endif
#ifdef CONFIG_RTL818X_S
u32 rtl8225_chan[] ={
0,
0x0080, //ch1
0x0100, //ch2
0x0180, //ch3
0x0200, //ch4
0x0280,
0x0300,
0x0380,
0x0400,
0x0480,
0x0500,
0x0580,
0x0600,
0x0680,
0x074A, //ch14
};
#else
u32 rtl8225_chan[] = {
0, //dummy channel 0
0x085c, //1
0x08dc, //2
0x095c, //3
0x09dc, //4
0x0a5c, //5
0x0adc, //6
0x0b5c, //7
0x0bdc, //8
0x0c5c, //9
0x0cdc, //10
0x0d5c, //11
0x0ddc, //12
0x0e5c, //13
//0x0f5c, //14
0x0f72, // 14
};
#endif
u16 rtl8225bcd_rxgain[]={
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
};
#if 0
u16 rtl8225bc_rxgain[]={
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
0x0794, 0x0795, 0x0798, 0x0799, 0x039a, 0x039b, 0x039c, 0x039d,
0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
};
u16 rtl8225a_rxgain[]={
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad,
0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad
};
#endif
u8 rtl8225_agc[]={
0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96,
0x95,0x94,0x93,0x92,0x91,0x90,0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86,
0x85,0x84,0x83,0x82,0x81,0x80,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,
0x35,0x34,0x33,0x32,0x31,0x30,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,
0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,
0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,
0x05,0x04,0x03,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
};
u8 rtl8225_tx_gain_cck_ofdm[]={
0x02,0x06,0x0e,0x1e,0x3e,0x7e
};
u8 rtl8225_tx_power_ofdm[]={
0x80,0x90,0xa2,0xb5,0xcb,0xe4
};
u8 rtl8225_tx_power_cck_ch14[]={
0x18,0x17,0x15,0x0c,0x00,0x00,0x00,0x00,
0x1b,0x1a,0x17,0x0e,0x00,0x00,0x00,0x00,
0x1f,0x1e,0x1a,0x0f,0x00,0x00,0x00,0x00,
0x22,0x21,0x1d,0x11,0x00,0x00,0x00,0x00,
0x26,0x25,0x21,0x13,0x00,0x00,0x00,0x00,
0x2b,0x2a,0x25,0x15,0x00,0x00,0x00,0x00
};
u8 rtl8225_tx_power_cck[]={
0x18,0x17,0x15,0x11,0x0c,0x08,0x04,0x02,
0x1b,0x1a,0x17,0x13,0x0e,0x09,0x04,0x02,
0x1f,0x1e,0x1a,0x15,0x10,0x0a,0x05,0x02,
0x22,0x21,0x1d,0x18,0x11,0x0b,0x06,0x02,
0x26,0x25,0x21,0x1b,0x14,0x0d,0x06,0x03,
0x2b,0x2a,0x25,0x1e,0x16,0x0e,0x07,0x03
};
void rtl8225_set_gain(struct net_device *dev, short gain)
{
write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]);
write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]);
write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]);
write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]);
}
#if 0
void rtl8225_set_gain(struct net_device *dev, short gain)
{
struct r8180_priv *priv = ieee80211_priv(dev);
rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON);
if(priv->card_8185 == 2)
write_phy_ofdm(dev, 0x21, 0x27);
else
write_phy_ofdm(dev, 0x21, 0x37);
write_phy_ofdm(dev, 0x25, 0x20);
write_phy_ofdm(dev, 0x11, 0x6);
if(priv->card_8185 == 1 && priv->card_8185_Bversion)
write_phy_ofdm(dev, 0x27, 0x8);
else
write_phy_ofdm(dev, 0x27, 0x88);
write_phy_ofdm(dev, 0x14, 0);
write_phy_ofdm(dev, 0x16, 0);
write_phy_ofdm(dev, 0x15, 0x40);
write_phy_ofdm(dev, 0x17, 0x40);
write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]);
write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]);
write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]);
write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]);
//rtl8225_set_gain_usb(dev, gain);
}
#endif
void write_rtl8225(struct net_device *dev, u8 adr, u16 data)
{
int i;
u16 out,select;
u8 bit;
u32 bangdata = (data << 4) | (adr & 0xf);
struct r8180_priv *priv = ieee80211_priv(dev);
out = read_nic_word(dev, RFPinsOutput) & 0xfff3;
write_nic_word(dev,RFPinsEnable,
(read_nic_word(dev,RFPinsEnable) | 0x7));
select = read_nic_word(dev, RFPinsSelect);
write_nic_word(dev, RFPinsSelect, select | 0x7 |
((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO));
force_pci_posting(dev);
udelay(10);
write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff);
force_pci_posting(dev);
udelay(2);
write_nic_word(dev, RFPinsOutput, out);
force_pci_posting(dev);
udelay(10);
for(i=15; i>=0;i--){
bit = (bangdata & (1<<i)) >> i;
write_nic_word(dev, RFPinsOutput, bit | out);
write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK);
write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK);
i--;
bit = (bangdata & (1<<i)) >> i;
write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK);
write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK);
write_nic_word(dev, RFPinsOutput, bit | out);
}
write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN);
force_pci_posting(dev);
udelay(10);
write_nic_word(dev, RFPinsOutput, out |
((priv->card_type == USB) ? 4 : BB_HOST_BANG_EN));
write_nic_word(dev, RFPinsSelect, select |
((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO));
if(priv->card_type == USB)
mdelay(2);
else
rtl8185_rf_pins_enable(dev);
}
void rtl8225_rf_close(struct net_device *dev)
{
write_rtl8225(dev, 0x4, 0x1f);
force_pci_posting(dev);
mdelay(1);
rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_OFF);
rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_OFF);
}
void rtl8225_SetTXPowerLevel(struct net_device *dev, short ch)
{
struct r8180_priv *priv = ieee80211_priv(dev);
int GainIdx;
int GainSetting;
int i;
u8 power;
u8 *cck_power_table;
u8 max_cck_power_level;
u8 max_ofdm_power_level;
u8 min_ofdm_power_level;
u8 cck_power_level = 0xff & priv->chtxpwr[ch];
u8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch];
if(priv->card_type == USB){
max_cck_power_level = 11;
max_ofdm_power_level = 25; // 12 -> 25
min_ofdm_power_level = 10;
}else{
max_cck_power_level = 35;
max_ofdm_power_level = 35;
min_ofdm_power_level = 0;
}
/* CCK power setting */
if(cck_power_level > max_cck_power_level)
cck_power_level = max_cck_power_level;
GainIdx=cck_power_level % 6;
GainSetting=cck_power_level / 6;
if(ch == 14)
cck_power_table = rtl8225_tx_power_cck_ch14;
else
cck_power_table = rtl8225_tx_power_cck;
// if(priv->card_8185 == 1 && priv->card_8185_Bversion ){
/*Ver B*/
// write_nic_byte(dev, TX_GAIN_CCK, rtl8225_tx_gain_cck_ofdm[GainSetting]);
// }else{
/*Ver C - D */
write_nic_byte(dev, TX_GAIN_CCK, rtl8225_tx_gain_cck_ofdm[GainSetting]>>1);
// }
for(i=0;i<8;i++){
power = cck_power_table[GainIdx * 8 + i];
write_phy_cck(dev, 0x44 + i, power);
}
/* FIXME Is this delay really needeed ? */
force_pci_posting(dev);
mdelay(1);
/* OFDM power setting */
// Old:
// if(ofdm_power_level > max_ofdm_power_level)
// ofdm_power_level = 35;
// ofdm_power_level += min_ofdm_power_level;
// Latest:
if(ofdm_power_level > (max_ofdm_power_level - min_ofdm_power_level))
ofdm_power_level = max_ofdm_power_level;
else
ofdm_power_level += min_ofdm_power_level;
if(ofdm_power_level > 35)
ofdm_power_level = 35;
//
GainIdx=ofdm_power_level % 6;
GainSetting=ofdm_power_level / 6;
#if 1
// if(priv->card_type == USB){
rtl8185_set_anaparam2(dev,RTL8225_ANAPARAM2_ON);
write_phy_ofdm(dev,2,0x42);
write_phy_ofdm(dev,6,0);
write_phy_ofdm(dev,8,0);
// }
#endif
// if(priv->card_8185 == 1 && priv->card_8185_Bversion){
// /*Ver B*/
// write_nic_byte(dev, TX_GAIN_OFDM, rtl8225_tx_gain_cck_ofdm[GainSetting]);
// }else{
/*Ver C - D */
write_nic_byte(dev, TX_GAIN_OFDM, rtl8225_tx_gain_cck_ofdm[GainSetting]>>1);
// }
power = rtl8225_tx_power_ofdm[GainIdx];
write_phy_ofdm(dev, 0x5, power);
write_phy_ofdm(dev, 0x7, power);
force_pci_posting(dev);
mdelay(1);
//write_nic_byte(dev, TX_AGC_CONTROL,4);
}
#if 0
/* switch between mode B and G */
void rtl8225_set_mode(struct net_device *dev, short modeb)
{
write_phy_ofdm(dev, 0x15, (modeb ? 0x0 : 0x40));
write_phy_ofdm(dev, 0x17, (modeb ? 0x0 : 0x40));
}
#endif
void rtl8225_rf_set_chan(struct net_device *dev, short ch)
{
struct r8180_priv *priv = ieee80211_priv(dev);
short gset = (priv->ieee80211->state == IEEE80211_LINKED &&
ieee80211_is_54g(priv->ieee80211->current_network)) ||
priv->ieee80211->iw_mode == IW_MODE_MONITOR;
rtl8225_SetTXPowerLevel(dev, ch);
write_rtl8225(dev, 0x7, rtl8225_chan[ch]);
force_pci_posting(dev);
mdelay(10);
// A mode sifs 0x44, difs 34-14, slot 9, eifs 23, cwm 3, cwM 7, ctstoself 0x10
if(gset){
write_nic_byte(dev,SIFS,0x22);// SIFS: 0x22
write_nic_byte(dev,DIFS,0x14); //DIFS: 20
//write_nic_byte(dev,DIFS,20); //DIFS: 20
}else{
write_nic_byte(dev,SIFS,0x44);// SIFS: 0x22
write_nic_byte(dev,DIFS,50 - 14); //DIFS: 36
}
if(priv->ieee80211->state == IEEE80211_LINKED &&
ieee80211_is_shortslot(priv->ieee80211->current_network))
write_nic_byte(dev,SLOT,0x9); //SLOT: 9
else
write_nic_byte(dev,SLOT,0x14); //SLOT: 20 (0x14)
if(gset){
write_nic_byte(dev,EIFS,81);//91 - 20); // EIFS: 91 (0x5B)
write_nic_byte(dev,CW_VAL,0x73); //CW VALUE: 0x37
//DMESG("using G net params");
}else{
write_nic_byte(dev,EIFS,81); // EIFS: 91 (0x5B)
write_nic_byte(dev,CW_VAL,0xa5); //CW VALUE: 0x37
//DMESG("using B net params");
}
}
void rtl8225_host_pci_init(struct net_device *dev)
{
write_nic_word(dev, RFPinsOutput, 0x480);
rtl8185_rf_pins_enable(dev);
//if(priv->card_8185 == 2 && priv->enable_gpio0 ) /* version D */
//write_nic_word(dev, RFPinsSelect, 0x88);
//else
write_nic_word(dev, RFPinsSelect, 0x88 | SW_CONTROL_GPIO); /* 0x488 | SW_CONTROL_GPIO */
write_nic_byte(dev, GP_ENABLE, 0);
force_pci_posting(dev);
mdelay(200);
write_nic_word(dev, GP_ENABLE, 0xff & (~(1<<6))); /* bit 6 is for RF on/off detection */
}
void rtl8225_host_usb_init(struct net_device *dev)
{
#if 0
write_nic_byte(dev,RFPinsSelect+1,0);
write_nic_byte(dev,GPIO,0);
write_nic_byte_E(dev,0x53,read_nic_byte_E(dev,0x53) | (1<<7));
write_nic_byte(dev,RFPinsSelect+1,4);
write_nic_byte(dev,GPIO,0x20);
write_nic_byte(dev,GP_ENABLE,0);
/* Config BB & RF */
write_nic_word(dev, RFPinsOutput, 0x80);
write_nic_word(dev, RFPinsSelect, 0x80);
write_nic_word(dev, RFPinsEnable, 0x80);
mdelay(100);
mdelay(1000);
#endif
}
void rtl8225_rf_sleep(struct net_device *dev)
{
write_rtl8225(dev,0x4,0xdff);
force_pci_posting(dev);
mdelay(1);
rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_SLEEP);
rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_SLEEP);
force_pci_posting(dev);
}
void rtl8225_rf_wakeup(struct net_device *dev)
{
write_rtl8225(dev,0x4,0x9ff);
rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON);
rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON);
force_pci_posting(dev);
}
void rtl8225_rf_init(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
int i;
short channel = 1;
u16 brsr;
priv->chan = channel;
rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON);
if(priv->card_type == USB)
rtl8225_host_usb_init(dev);
else
rtl8225_host_pci_init(dev);
write_nic_dword(dev, RF_TIMING, 0x000a8008);
brsr = read_nic_word(dev, BRSR);
write_nic_word(dev, BRSR, 0xffff);
#if 0
if(priv->card_8185 == 1){/* version C or B */
if(priv->card_8185_Bversion) /* version B*/
write_nic_dword(dev, RF_PARA, 0x44);
else /* version C */
write_nic_dword(dev, RF_PARA, 0x100044);
}else{ /* version D */
if(priv->enable_gpio0)
write_nic_dword(dev, RF_PARA, 0x20100044);
else /* also USB */
write_nic_dword(dev, RF_PARA, 0x100044);
}
#endif
write_nic_dword(dev, RF_PARA, 0x100044);
#if 1 //0->1
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
write_nic_byte(dev, CONFIG3, 0x44);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
#endif
if(priv->card_type == USB){
rtl8185_rf_pins_enable(dev);
mdelay(1000);
}
write_rtl8225(dev, 0x0, 0x67); mdelay(1);
write_rtl8225(dev, 0x1, 0xfe0); mdelay(1);
write_rtl8225(dev, 0x2, 0x44d); mdelay(1);
write_rtl8225(dev, 0x3, 0x441); mdelay(1);
if(priv->card_type == USB)
write_rtl8225(dev, 0x4, 0x486);
else
write_rtl8225(dev, 0x4, 0x8be);
mdelay(1);
#if 0
}else if(priv->phy_ver == 1){
/* version A */
write_rtl8225(dev, 0x5, 0xbc0 + 2);
}else{
#endif
/* version B & C */
if(priv->card_type == USB)
write_rtl8225(dev, 0x5, 0xbc0);
else if(priv->card_type == MINIPCI)
write_rtl8225(dev, 0x5, 0xbc0 + 3 +(6<<3));
else
write_rtl8225(dev, 0x5, 0xbc0 + (6<<3));
mdelay(1);
// }
write_rtl8225(dev, 0x6, 0xae6); mdelay(1);
write_rtl8225(dev, 0x7, ((priv->card_type == USB)? 0x82a : rtl8225_chan[channel])); mdelay(1);
write_rtl8225(dev, 0x8, 0x1f); mdelay(1);
write_rtl8225(dev, 0x9, 0x334); mdelay(1);
write_rtl8225(dev, 0xa, 0xfd4); mdelay(1);
write_rtl8225(dev, 0xb, 0x391); mdelay(1);
write_rtl8225(dev, 0xc, 0x50); mdelay(1);
write_rtl8225(dev, 0xd, 0x6db); mdelay(1);
write_rtl8225(dev, 0xe, 0x29); mdelay(1);
write_rtl8225(dev, 0xf, 0x914);
if(priv->card_type == USB){
//force_pci_posting(dev);
mdelay(100);
}
write_rtl8225(dev, 0x2, 0xc4d);
if(priv->card_type == USB){
// force_pci_posting(dev);
mdelay(200);
write_rtl8225(dev, 0x2, 0x44d);
// force_pci_posting(dev);
mdelay(100);
}//End of if(priv->card_type == USB)
/* FIXME!! rtl8187 we have to check if calibrarion
* is successful and eventually cal. again (repeat
* the two write on reg 2)
*/
force_pci_posting(dev);
mdelay(100); //200 for 8187
//if(priv->card_type != USB) /* maybe not needed even for 8185 */
// write_rtl8225(dev, 0x7, rtl8225_chan[channel]);
write_rtl8225(dev, 0x0, 0x127);
for(i=0;i<95;i++){
write_rtl8225(dev, 0x1, (u8)(i+1));
#if 0
if(priv->phy_ver == 1)
/* version A */
write_rtl8225(dev, 0x2, rtl8225a_rxgain[i]);
else
#endif
/* version B & C & D*/
write_rtl8225(dev, 0x2, rtl8225bcd_rxgain[i]);
}
write_rtl8225(dev, 0x0, 0x27);
// //if(priv->card_type != USB){
// write_rtl8225(dev, 0x2, 0x44d);
// write_rtl8225(dev, 0x7, rtl8225_chan[channel]);
// write_rtl8225(dev, 0x2, 0x47d);
//
// force_pci_posting(dev);
// mdelay(100);
//
// write_rtl8225(dev, 0x2, 0x44d);
// //}
write_rtl8225(dev, 0x0, 0x22f);
if(priv->card_type != USB)
rtl8185_rf_pins_enable(dev);
for(i=0;i<128;i++){
write_phy_ofdm(dev, 0xb, rtl8225_agc[i]);
mdelay(1);
write_phy_ofdm(dev, 0xa, (u8)i+ 0x80);
mdelay(1);
}
force_pci_posting(dev);
mdelay(1);
write_phy_ofdm(dev, 0x0, 0x1); mdelay(1);
write_phy_ofdm(dev, 0x1, 0x2); mdelay(1);
write_phy_ofdm(dev, 0x2, ((priv->card_type == USB)? 0x42 : 0x62)); mdelay(1);
write_phy_ofdm(dev, 0x3, 0x0); mdelay(1);
write_phy_ofdm(dev, 0x4, 0x0); mdelay(1);
write_phy_ofdm(dev, 0x5, 0x0); mdelay(1);
write_phy_ofdm(dev, 0x6, 0x40); mdelay(1);
write_phy_ofdm(dev, 0x7, 0x0); mdelay(1);
write_phy_ofdm(dev, 0x8, 0x40); mdelay(1);
write_phy_ofdm(dev, 0x9, 0xfe); mdelay(1);
#if 0
if(priv->card_type == USB){
write_phy_ofdm(dev, 0xa, 0x9);
}else{
if(priv->card_8185 == 1 && priv->card_8185_Bversion){
/* Ver B
* maybe later version can accept this also?
*/
write_phy_ofdm(dev, 0xa, 0x6);
write_phy_ofdm(dev, 0x18, 0x6f);
}else{
#endif
/* ver C & D */
write_phy_ofdm(dev, 0xa, 0x9); mdelay(1);
//write_phy_ofdm(dev, 0x18, 0xef);
// }
//}
write_phy_ofdm(dev, 0xb, 0x80); mdelay(1);
write_phy_ofdm(dev, 0xc, 0x1);mdelay(1);
//if(priv->card_type != USB)
//write_phy_ofdm(dev, 0xd, 0x33); // <>
write_phy_ofdm(dev, 0xe, 0xd3);mdelay(1);
#if 0
if(priv->card_8185 == 1){
if(priv->card_8185_Bversion)
write_phy_ofdm(dev, 0xf, 0x20);/*ver B*/
else
write_phy_ofdm(dev, 0xf, 0x28);/*ver C*/
}else{
#endif
write_phy_ofdm(dev, 0xf, 0x38);mdelay(1);
/*ver D & 8187*/
// }
// if(priv->card_8185 == 1 && priv->card_8185_Bversion)
// write_phy_ofdm(dev, 0x10, 0x04);/*ver B*/
// else
write_phy_ofdm(dev, 0x10, 0x84);mdelay(1);
/*ver C & D & 8187*/
write_phy_ofdm(dev, 0x11, 0x06);mdelay(1);
/*agc resp time 700*/
// if(priv->card_8185 == 2){
/* Ver D & 8187*/
write_phy_ofdm(dev, 0x12, 0x20);mdelay(1);
write_phy_ofdm(dev, 0x13, 0x20);mdelay(1);
#if 0
}else{
/* Ver B & C*/
write_phy_ofdm(dev, 0x12, 0x0);
write_phy_ofdm(dev, 0x13, 0x0);
}
#endif
write_phy_ofdm(dev, 0x14, 0x0); mdelay(1);
write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
write_phy_ofdm(dev, 0x16, 0x0); mdelay(1);
write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
// if (priv->card_type == USB)
// write_phy_ofdm(dev, 0x18, 0xef);
write_phy_ofdm(dev, 0x18, 0xef);mdelay(1);
write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
// if (priv->card_type != USB){
// if(priv->card_8185 == 1 && priv->card_8185_Bversion)
// write_phy_ofdm(dev, 0x1b, 0x66); /* Ver B */
// else
write_phy_ofdm(dev, 0x1b, 0x76);mdelay(1);
/* Ver C & D */ //FIXME:MAYBE not needed
// }
write_phy_ofdm(dev, 0x1c, 0x4);mdelay(1);
#if 0
if(priv->card_8185 == 1){
if(priv->card_8185_Bversion){
/*ver B*/
write_phy_ofdm(dev, 0x1e, 0x95);
write_phy_ofdm(dev, 0x1f, 0x55);
}else{
/*ver C*/
write_phy_ofdm(dev, 0x1e, 0x90);
write_phy_ofdm(dev, 0x1f, 0x34);
}
}else{
#endif
/*ver D & 8187*/
write_phy_ofdm(dev, 0x1e, 0x95);mdelay(1);
write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
// }
write_phy_ofdm(dev, 0x20, 0x1f);mdelay(1);
write_phy_ofdm(dev, 0x21, 0x27);mdelay(1);
write_phy_ofdm(dev, 0x22, 0x16);mdelay(1);
// if(priv->card_type != USB)
//write_phy_ofdm(dev, 0x23, 0x43); //FIXME maybe not needed // <>
write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
write_phy_ofdm(dev, 0x25, 0x20); mdelay(1);
write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
#if 0
if(priv->card_8185 == 1 && priv->card_8185_Bversion)
write_phy_ofdm(dev, 0x27, 0x08); /* Ver B. might work also fo ver C&D ?*/
else
#endif
write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
/* Ver C & D & 8187*/
// <> Set init. gain to m74dBm.
write_phy_ofdm(dev, 0x0d, 0x43); mdelay(1);
write_phy_ofdm(dev, 0x1b, 0x76); mdelay(1);
write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1);
write_phy_ofdm(dev, 0x23, 0x78); mdelay(1);
//if(priv->card_type == USB);
// rtl8225_set_gain_usb(dev, 1); /* FIXME this '2' is random */
write_phy_cck(dev, 0x0, 0x98); mdelay(1);
write_phy_cck(dev, 0x3, 0x20); mdelay(1);
write_phy_cck(dev, 0x4, 0x7e); mdelay(1);
write_phy_cck(dev, 0x5, 0x12); mdelay(1);
write_phy_cck(dev, 0x6, 0xfc); mdelay(1);
#if 0
if(priv->card_8185 == 1 && priv->card_8185_Bversion)
write_phy_cck(dev, 0x7, 0xd8); /* Ver B */
else
#endif
write_phy_cck(dev, 0x7, 0x78);mdelay(1);
/* Ver C & D & 8187*/
write_phy_cck(dev, 0x8, 0x2e);mdelay(1);
write_phy_cck(dev, 0x10, ((priv->card_type == USB) ? 0x9b: 0x93)); mdelay(1);
write_phy_cck(dev, 0x11, 0x88); mdelay(1);
write_phy_cck(dev, 0x12, 0x47); mdelay(1);
#if 0
if(priv->card_8185 == 1 && priv->card_8185_Bversion)
write_phy_cck(dev, 0x13, 0x98); /* Ver B */
else
#endif
write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/
write_phy_cck(dev, 0x19, 0x0);
write_phy_cck(dev, 0x1a, 0xa0);
write_phy_cck(dev, 0x1b, 0x8);
write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */
write_phy_cck(dev, 0x41, 0x8d);mdelay(1);
write_phy_cck(dev, 0x42, 0x15); mdelay(1);
write_phy_cck(dev, 0x43, 0x18); mdelay(1);
write_phy_cck(dev, 0x44, 0x1f); mdelay(1);
write_phy_cck(dev, 0x45, 0x1e); mdelay(1);
write_phy_cck(dev, 0x46, 0x1a); mdelay(1);
write_phy_cck(dev, 0x47, 0x15); mdelay(1);
write_phy_cck(dev, 0x48, 0x10); mdelay(1);
write_phy_cck(dev, 0x49, 0xa); mdelay(1);
write_phy_cck(dev, 0x4a, 0x5); mdelay(1);
write_phy_cck(dev, 0x4b, 0x2); mdelay(1);
write_phy_cck(dev, 0x4c, 0x5);mdelay(1);
write_nic_byte(dev, 0x5b, 0x0d); mdelay(1);
// <>
// // TESTR 0xb 8187
// write_phy_cck(dev, 0x10, 0x93);// & 0xfb);
//
// //if(priv->card_type != USB){
// write_phy_ofdm(dev, 0x2, 0x62);
// write_phy_ofdm(dev, 0x6, 0x0);
// write_phy_ofdm(dev, 0x8, 0x0);
// //}
rtl8225_SetTXPowerLevel(dev, channel);
write_phy_cck(dev, 0x10, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */
write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); /* Rx ant A, 0x10 for B */
rtl8185_tx_antenna(dev, 0x3); /* TX ant A, 0x0 for B */
/* switch to high-speed 3-wire
* last digit. 2 for both cck and ofdm
*/
if(priv->card_type == USB)
write_nic_dword(dev, 0x94, 0x3dc00002);
else{
write_nic_dword(dev, 0x94, 0x15c00002);
rtl8185_rf_pins_enable(dev);
}
// if(priv->card_type != USB)
// rtl8225_set_gain(dev, 4); /* FIXME this '1' is random */ // <>
// rtl8225_set_mode(dev, 1); /* FIXME start in B mode */ // <>
//
// /* make sure is waken up! */
// write_rtl8225(dev,0x4, 0x9ff);
// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON);
// rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON);
rtl8225_rf_set_chan(dev, priv->chan);
write_nic_word(dev,BRSR,brsr);
}

View File

@ -0,0 +1,44 @@
/*
This is part of the rtl8180-sa2400 driver
released under the GPL (See file COPYING for details).
Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
This files contains programming code for the rtl8225
radio frontend.
*Many* thanks to Realtek Corp. for their great support!
*/
#include "r8180.h"
#define RTL8225_ANAPARAM_ON 0xa0000b59
#define RTL8225_ANAPARAM_OFF 0xa00beb59
#define RTL8225_ANAPARAM2_OFF 0x840dec11
#define RTL8225_ANAPARAM2_ON 0x860dec11
#define RTL8225_ANAPARAM_SLEEP 0xa00bab59
#define RTL8225_ANAPARAM2_SLEEP 0x840dec11
#ifdef CONFIG_RTL8185B
void rtl8225z2_rf_init(struct net_device *dev);
void rtl8225z2_rf_set_chan(struct net_device *dev,short ch);
void rtl8225z2_rf_close(struct net_device *dev);
void rtl8225_host_pci_init(struct net_device *dev);
void rtl8225_host_usb_init(struct net_device *dev);
void write_rtl8225(struct net_device *dev, u8 adr, u16 data);
void RF_WriteReg(struct net_device *dev, u8 offset, u32 data);
u32 RF_ReadReg(struct net_device *dev, u8 offset);
#endif
void rtl8225_rf_init(struct net_device *dev);
void rtl8225_rf_set_chan(struct net_device *dev,short ch);
void rtl8225_rf_close(struct net_device *dev);
void rtl8225_rf_sleep(struct net_device *dev);
void rtl8225_rf_wakeup(struct net_device *dev);
void rtl8180_set_mode(struct net_device *dev,int mode);
void rtl8180_set_mode(struct net_device *dev,int mode);
bool SetZebraRFPowerState8185(struct net_device *dev,RT_RF_POWER_STATE eRFPowerState);
void rtl8225z4_rf_sleep(struct net_device *dev);
void rtl8225z4_rf_wakeup(struct net_device *dev);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
/*
This is part of the rtl8180-sa2400 driver
released under the GPL (See file COPYING for details).
Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
This files contains programming code for the rtl8255
radio frontend.
*Many* thanks to Realtek Corp. for their great support!
*/
#define RTL8255_ANAPARAM_ON 0xa0000b59
#define RTL8255_ANAPARAM2_ON 0x840cf311
void rtl8255_rf_init(struct net_device *dev);
void rtl8255_rf_set_chan(struct net_device *dev,short ch);
void rtl8255_rf_close(struct net_device *dev);

View File

@ -0,0 +1,233 @@
/*
This files contains PHILIPS SA2400 radio frontend programming routines.
This is part of rtl8180 OpenSource driver
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
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.
Code at http://che.ojctech.com/~dyoung/rtw/ has been useful to me to
understand some things.
Code from rtl8181 project has been useful to me to understand some things.
We want to tanks the Authors of such projects and the Ndiswrapper
project Authors.
*/
#include "r8180.h"
#include "r8180_hw.h"
#include "r8180_sa2400.h"
//#define DEBUG_SA2400
u32 sa2400_chan[] = {
0x0, //dummy channel 0
0x00096c, //1
0x080970, //2
0x100974, //3
0x180978, //4
0x000980, //5
0x080984, //6
0x100988, //7
0x18098c, //8
0x000994, //9
0x080998, //10
0x10099c, //11
0x1809a0, //12
0x0009a8, //13
0x0009b4, //14
};
void rf_stabilize(struct net_device *dev)
{
force_pci_posting(dev);
mdelay(3); //for now use a great value.. we may optimize in future
}
void write_sa2400(struct net_device *dev,u8 adr, u32 data)
{
// struct r8180_priv *priv = ieee80211_priv(dev);
u32 phy_config;
// philips sa2400 expects 24 bits data
/*if(adr == 4 && priv->digphy){
phy_config=0x60000000;
}else{
phy_config=0xb0000000;
}*/
phy_config = 0xb0000000; // MAC will bang bits to the sa2400
phy_config |= (((u32)(adr&0xf))<< 24);
phy_config |= (data & 0xffffff);
write_nic_dword(dev,PHY_CONFIG,phy_config);
#ifdef DEBUG_SA2400
DMESG("Writing sa2400: %x (adr %x)",phy_config,adr);
#endif
rf_stabilize(dev);
}
void sa2400_write_phy_antenna(struct net_device *dev,short ch)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u8 ant;
ant = SA2400_ANTENNA;
if(priv->antb) /*default antenna is antenna B */
ant |= BB_ANTENNA_B;
if(ch == 14)
ant |= BB_ANTATTEN_CHAN14;
write_phy(dev,0x10,ant);
//DMESG("BB antenna %x ",ant);
}
/* from the rtl8181 embedded driver */
short sa2400_rf_set_sens(struct net_device *dev, short sens)
{
u8 finetune = 0;
if ((sens > 85) || (sens < 54)) return -1;
write_sa2400(dev,5,0x1dfb | (sens-54) << 15 |(finetune<<20)); // AGC 0xc9dfb
return 0;
}
void sa2400_rf_set_chan(struct net_device *dev, short ch)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 txpw = 0xff & priv->chtxpwr[ch];
u32 chan = sa2400_chan[ch];
write_sa2400(dev,7,txpw);
//write_phy(dev,0x10,0xd1);
sa2400_write_phy_antenna(dev,ch);
write_sa2400(dev,0,chan);
write_sa2400(dev,1,0xbb50);
write_sa2400(dev,2,0x80);
write_sa2400(dev,3,0);
}
void sa2400_rf_close(struct net_device *dev)
{
write_sa2400(dev, 4, 0);
}
void sa2400_rf_init(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 anaparam;
u8 firdac;
write_nic_byte(dev,PHY_DELAY,0x6); //this is general
write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general
/*these are philips sa2400 specific*/
anaparam = read_nic_dword(dev,ANAPARAM);
anaparam = anaparam &~ (1<<ANAPARAM_TXDACOFF_SHIFT);
anaparam = anaparam &~ANAPARAM_PWR1_MASK;
anaparam = anaparam &~ANAPARAM_PWR0_MASK;
if(priv->digphy){
anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON<<ANAPARAM_PWR1_SHIFT);
anaparam |= (SA2400_ANAPARAM_PWR0_ON<<ANAPARAM_PWR0_SHIFT);
}else{
anaparam |= (SA2400_ANA_ANAPARAM_PWR1_ON<<ANAPARAM_PWR1_SHIFT);
}
rtl8180_set_anaparam(dev,anaparam);
firdac = (priv->digphy) ? (1<<SA2400_REG4_FIRDAC_SHIFT) : 0;
write_sa2400(dev,0,sa2400_chan[priv->chan]);
write_sa2400(dev,1,0xbb50);
write_sa2400(dev,2,0x80);
write_sa2400(dev,3,0);
write_sa2400(dev,4,0x19340 | firdac);
write_sa2400(dev,5,0xc9dfb); // AGC
write_sa2400(dev,4,0x19348 | firdac); //calibrates VCO
if(priv->digphy)
write_sa2400(dev,4,0x1938c); /*???*/
write_sa2400(dev,4,0x19340 | firdac);
write_sa2400(dev,0,sa2400_chan[priv->chan]);
write_sa2400(dev,1,0xbb50);
write_sa2400(dev,2,0x80);
write_sa2400(dev,3,0);
write_sa2400(dev,4,0x19344 | firdac); //calibrates filter
/* new from rtl8180 embedded driver (rtl8181 project) */
write_sa2400(dev,6,0x13ff | (1<<23)); // MANRX
write_sa2400(dev,8,0); //VCO
if(!priv->digphy)
{
rtl8180_set_anaparam(dev, anaparam | \
(1<<ANAPARAM_TXDACOFF_SHIFT));
rtl8180_conttx_enable(dev);
write_sa2400(dev, 4, 0x19341); // calibrates DC
/* a 5us sleep is required here,
we rely on the 3ms delay introduced in write_sa2400
*/
write_sa2400(dev, 4, 0x19345);
/* a 20us sleep is required here,
we rely on the 3ms delay introduced in write_sa2400
*/
rtl8180_conttx_disable(dev);
rtl8180_set_anaparam(dev, anaparam);
}
/* end new */
write_sa2400(dev,4,0x19341 | firdac ); //RTX MODE
// Set tx power level !?
/*baseband configuration*/
write_phy(dev,0,0x98);
write_phy(dev,3,0x38);
write_phy(dev,4,0xe0);
write_phy(dev,5,0x90);
write_phy(dev,6,0x1a);
write_phy(dev,7,0x64);
/*Should be done something more here??*/
sa2400_write_phy_antenna(dev,priv->chan);
write_phy(dev,0x11,0x80);
if(priv->diversity)
write_phy(dev,0x12,0xc7);
else
write_phy(dev,0x12,0x47);
write_phy(dev,0x13,0x90 | priv->cs_treshold );
write_phy(dev,0x19,0x0);
write_phy(dev,0x1a,0xa0);
sa2400_rf_set_chan(dev,priv->chan);
}

View File

@ -0,0 +1,26 @@
/*
This is part of rtl8180 OpenSource driver - v 0.7
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
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 tanks the Authors of such projects and the Ndiswrapper project Authors.
*/
#define SA2400_ANTENNA 0x91
#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8
#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28
#define SA2400_ANAPARAM_PWR0_ON 0x3
#define SA2400_RF_MAX_SENS 85
#define SA2400_RF_DEF_SENS 80
#define SA2400_REG4_FIRDAC_SHIFT 7
void sa2400_rf_init(struct net_device *dev);
void sa2400_rf_set_chan(struct net_device *dev,short ch);
short sa2400_rf_set_sens(struct net_device *dev,short sens);
void sa2400_rf_close(struct net_device *dev);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
/*
This is part of rtl8180 OpenSource driver - v 0.3
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
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 tanks 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
#include <linux/wireless.h>
#include "ieee80211.h"
extern struct iw_handler_def r8180_wx_handlers_def;
#endif

File diff suppressed because it is too large Load Diff