aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/rtl8187se/ieee80211
diff options
context:
space:
mode:
authormerge <null@invalid>2009-01-22 13:55:32 +0000
committerAndy Green <agreen@octopus.localdomain>2009-01-22 13:55:32 +0000
commitaa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 (patch)
treefbb786d0ac6f8a774fd834e9ce951197e60fbffa /drivers/staging/rtl8187se/ieee80211
parentf2d78193eae5dccd3d588d2c8ea0866efc368332 (diff)
MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141
pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage: From: merge <null@invalid> MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage: From: merge <null@invalid> MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage: From: Andy Green <andy@openmoko.com> fix-stray-endmenu.patch Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/staging/rtl8187se/ieee80211')
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.c246
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.h102
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h1755
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c265
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h86
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c533
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c1001
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c394
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_module.c301
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c1971
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c4029
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c602
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c828
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c884
-rw-r--r--drivers/staging/rtl8187se/ieee80211/internal.h115
-rw-r--r--drivers/staging/rtl8187se/ieee80211/rtl_crypto.h399
16 files changed, 13511 insertions, 0 deletions
diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.c b/drivers/staging/rtl8187se/ieee80211/dot11d.c
new file mode 100644
index 00000000000..5d8b752fc0f
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/dot11d.c
@@ -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
diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.h b/drivers/staging/rtl8187se/ieee80211/dot11d.h
new file mode 100644
index 00000000000..64bcf15bd21
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/dot11d.h
@@ -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
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
new file mode 100644
index 00000000000..58336080ad5
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -0,0 +1,1755 @@
+/*
+ * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
+ * remains copyright by the original authors
+ *
+ * Portions of the merged code are 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
+ *
+ * Modified for Realtek's wi-fi cards by Andrea Merello
+ * <andreamrl@tiscali.it>
+ *
+ * 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.
+ */
+#ifndef IEEE80211_H
+#define IEEE80211_H
+#include <linux/if_ether.h> /* ETH_ALEN */
+#include <linux/kernel.h> /* ARRAY_SIZE */
+#include <linux/version.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13))
+#include <linux/wireless.h>
+#endif
+
+/*
+#ifndef bool
+#define bool int
+#endif
+
+#ifndef true
+#define true 1
+#endif
+
+#ifndef false
+#define false 0
+#endif
+*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
+#ifndef bool
+typedef enum{false = 0, true} bool;
+#endif
+#endif
+//#ifdef JOHN_HWSEC
+#define KEY_TYPE_NA 0x0
+#define KEY_TYPE_WEP40 0x1
+#define KEY_TYPE_TKIP 0x2
+#define KEY_TYPE_CCMP 0x4
+#define KEY_TYPE_WEP104 0x5
+//#endif
+
+
+#define aSifsTime 10
+
+#define MGMT_QUEUE_NUM 5
+
+
+#define IEEE_CMD_SET_WPA_PARAM 1
+#define IEEE_CMD_SET_WPA_IE 2
+#define IEEE_CMD_SET_ENCRYPTION 3
+#define IEEE_CMD_MLME 4
+
+#define IEEE_PARAM_WPA_ENABLED 1
+#define IEEE_PARAM_TKIP_COUNTERMEASURES 2
+#define IEEE_PARAM_DROP_UNENCRYPTED 3
+#define IEEE_PARAM_PRIVACY_INVOKED 4
+#define IEEE_PARAM_AUTH_ALGS 5
+#define IEEE_PARAM_IEEE_802_1X 6
+//It should consistent with the driver_XXX.c
+// David, 2006.9.26
+#define IEEE_PARAM_WPAX_SELECT 7
+//Added for notify the encryption type selection
+// David, 2006.9.26
+#define IEEE_PROTO_WPA 1
+#define IEEE_PROTO_RSN 2
+//Added for notify the encryption type selection
+// David, 2006.9.26
+#define IEEE_WPAX_USEGROUP 0
+#define IEEE_WPAX_WEP40 1
+#define IEEE_WPAX_TKIP 2
+#define IEEE_WPAX_WRAP 3
+#define IEEE_WPAX_CCMP 4
+#define IEEE_WPAX_WEP104 5
+
+#define IEEE_KEY_MGMT_IEEE8021X 1
+#define IEEE_KEY_MGMT_PSK 2
+
+
+
+#define IEEE_MLME_STA_DEAUTH 1
+#define IEEE_MLME_STA_DISASSOC 2
+
+
+#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2
+#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3
+#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5
+#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7
+
+
+#define IEEE_CRYPT_ALG_NAME_LEN 16
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10))
+#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rtl
+#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rtl
+#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rtl
+////////////////////////////////
+// added for kernel conflict under FC5
+#define ieee80211_wx_get_name ieee80211_wx_get_name_rtl
+#define free_ieee80211 free_ieee80211_rtl
+#define alloc_ieee80211 alloc_ieee80211_rtl
+///////////////////////////////
+#endif
+//error in ubuntu2.6.22,so add these
+#define ieee80211_wake_queue ieee80211_wake_queue_rtl
+#define ieee80211_stop_queue ieee80211_stop_queue_rtl
+
+#define ieee80211_rx ieee80211_rx_rtl
+
+#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rtl
+#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rtl
+#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rtl
+#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rtl
+#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rtl
+#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rtl
+
+#define ieee80211_txb_free ieee80211_txb_free_rtl
+#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rtl
+#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rtl
+#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rtl
+#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rtl
+#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rtl
+#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rtl
+#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rtl
+#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rtl
+#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rtl
+#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rtl
+#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rtl
+#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rtl
+#define ieee80211_wx_set_power ieee80211_wx_set_power_rtl
+#define ieee80211_wx_get_power ieee80211_wx_get_power_rtl
+#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rtl
+#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rtl
+#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rtl
+#define ieee80211_start_protocol ieee80211_start_protocol_rtl
+#define ieee80211_stop_protocol ieee80211_stop_protocol_rtl
+#define ieee80211_rx_mgt ieee80211_rx_mgt_rtl
+
+#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rtl
+//by amy for ps
+#define notify_wx_assoc_event notify_wx_assoc_event_rtl
+#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rtl
+#define ieee80211_disassociate ieee80211_disassociate_rtl
+#define ieee80211_start_scan ieee80211_start_scan_rtl
+//by amy for ps
+typedef struct ieee_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u8 name;
+ u32 value;
+ } wpa_param;
+ struct {
+ u32 len;
+ u8 reserved[32];
+ u8 data[0];
+ } wpa_ie;
+ struct{
+ int command;
+ int reason_code;
+ } mlme;
+ struct {
+ u8 alg[IEEE_CRYPT_ALG_NAME_LEN];
+ u8 set_tx;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+
+ } u;
+}ieee_param;
+
+
+#if WIRELESS_EXT < 17
+#define IW_QUAL_QUAL_INVALID 0x10
+#define IW_QUAL_LEVEL_INVALID 0x20
+#define IW_QUAL_NOISE_INVALID 0x40
+#define IW_QUAL_QUAL_UPDATED 0x1
+#define IW_QUAL_LEVEL_UPDATED 0x2
+#define IW_QUAL_NOISE_UPDATED 0x4
+#endif
+
+// linux under 2.6.9 release may not support it, so modify it for common use
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9))
+#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
+static inline unsigned long msleep_interruptible_rtl(unsigned int msecs)
+{
+ unsigned long timeout = MSECS(msecs) + 1;
+
+ while (timeout) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ timeout = schedule_timeout(timeout);
+ }
+ return timeout;
+}
+#else
+#define MSECS(t) msecs_to_jiffies(t)
+#define msleep_interruptible_rtl msleep_interruptible
+#endif
+
+#define IEEE80211_DATA_LEN 2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+ 6.2.1.1.2.
+
+ The figure in section 7.1.2 suggests a body size of up to 2312
+ bytes is allowed, which is a bit confusing, I suspect this
+ represents the 2304 bytes of real data, plus a possible 8 bytes of
+ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+
+#define IEEE80211_HLEN 30
+#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+/* this is stolen and modified from the madwifi driver*/
+#define IEEE80211_FC0_TYPE_MASK 0x0c
+#define IEEE80211_FC0_TYPE_DATA 0x08
+#define IEEE80211_FC0_SUBTYPE_MASK 0xB0
+#define IEEE80211_FC0_SUBTYPE_QOS 0x80
+
+#define IEEE80211_QOS_HAS_SEQ(fc) \
+ (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \
+ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS))
+
+/* this is stolen from ipw2200 driver */
+#define IEEE_IBSS_MAC_HASH_SIZE 31
+struct ieee_ibss_seq {
+ u8 mac[ETH_ALEN];
+ u16 seq_num[17];
+ u16 frag_num[17];
+ unsigned long packet_time[17];
+ struct list_head list;
+};
+
+struct ieee80211_hdr {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct ieee80211_hdr_QOS {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+ u16 QOS_ctl;
+} __attribute__ ((packed));
+
+struct ieee80211_hdr_3addr {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+} __attribute__ ((packed));
+
+struct ieee80211_hdr_3addr_QOS {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u16 QOS_ctl;
+} __attribute__ ((packed));
+
+enum eap_type {
+ EAP_PACKET = 0,
+ EAPOL_START,
+ EAPOL_LOGOFF,
+ EAPOL_KEY,
+ EAPOL_ENCAP_ASF_ALERT
+};
+
+static const char *eap_types[] = {
+ [EAP_PACKET] = "EAP-Packet",
+ [EAPOL_START] = "EAPOL-Start",
+ [EAPOL_LOGOFF] = "EAPOL-Logoff",
+ [EAPOL_KEY] = "EAPOL-Key",
+ [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert"
+};
+
+static inline const char *eap_get_type(int type)
+{
+ return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type];
+}
+
+struct eapol {
+ u8 snap[6];
+ u16 ethertype;
+ u8 version;
+ u8 type;
+ u16 length;
+} __attribute__ ((packed));
+
+#define IEEE80211_3ADDR_LEN 24
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_FCS_LEN 4
+
+#define MIN_FRAG_THRESHOLD 256U
+#define MAX_FRAG_THRESHOLD 2346U
+
+/* Frame control field constants */
+#define IEEE80211_FCTL_VERS 0x0002
+#define IEEE80211_FCTL_FTYPE 0x000c
+#define IEEE80211_FCTL_STYPE 0x00f0
+#define IEEE80211_FCTL_TODS 0x0100
+#define IEEE80211_FCTL_FROMDS 0x0200
+#define IEEE80211_FCTL_DSTODS 0x0300 //added by david
+#define IEEE80211_FCTL_MOREFRAGS 0x0400
+#define IEEE80211_FCTL_RETRY 0x0800
+#define IEEE80211_FCTL_PM 0x1000
+#define IEEE80211_FCTL_MOREDATA 0x2000
+#define IEEE80211_FCTL_WEP 0x4000
+#define IEEE80211_FCTL_ORDER 0x8000
+
+#define IEEE80211_FTYPE_MGMT 0x0000
+#define IEEE80211_FTYPE_CTL 0x0004
+#define IEEE80211_FTYPE_DATA 0x0008
+
+/* management */
+#define IEEE80211_STYPE_ASSOC_REQ 0x0000
+#define IEEE80211_STYPE_ASSOC_RESP 0x0010
+#define IEEE80211_STYPE_REASSOC_REQ 0x0020
+#define IEEE80211_STYPE_REASSOC_RESP 0x0030
+#define IEEE80211_STYPE_PROBE_REQ 0x0040
+#define IEEE80211_STYPE_PROBE_RESP 0x0050
+#define IEEE80211_STYPE_BEACON 0x0080
+#define IEEE80211_STYPE_ATIM 0x0090
+#define IEEE80211_STYPE_DISASSOC 0x00A0
+#define IEEE80211_STYPE_AUTH 0x00B0
+#define IEEE80211_STYPE_DEAUTH 0x00C0
+#define IEEE80211_STYPE_MANAGE_ACT 0x00D0
+
+/* control */
+#define IEEE80211_STYPE_PSPOLL 0x00A0
+#define IEEE80211_STYPE_RTS 0x00B0
+#define IEEE80211_STYPE_CTS 0x00C0
+#define IEEE80211_STYPE_ACK 0x00D0
+#define IEEE80211_STYPE_CFEND 0x00E0
+#define IEEE80211_STYPE_CFENDACK 0x00F0
+
+/* data */
+#define IEEE80211_STYPE_DATA 0x0000
+#define IEEE80211_STYPE_DATA_CFACK 0x0010
+#define IEEE80211_STYPE_DATA_CFPOLL 0x0020
+#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
+#define IEEE80211_STYPE_NULLFUNC 0x0040
+#define IEEE80211_STYPE_CFACK 0x0050
+#define IEEE80211_STYPE_CFPOLL 0x0060
+#define IEEE80211_STYPE_CFACKPOLL 0x0070
+#define IEEE80211_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2
+#define IEEE80211_STYPE_QOS_NULL 0x00C0
+
+
+#define IEEE80211_SCTL_FRAG 0x000F
+#define IEEE80211_SCTL_SEQ 0xFFF0
+
+
+/* debug macros */
+
+#ifdef CONFIG_IEEE80211_DEBUG
+extern u32 ieee80211_debug_level;
+#define IEEE80211_DEBUG(level, fmt, args...) \
+do { if (ieee80211_debug_level & (level)) \
+ printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
+#else
+#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
+#endif /* CONFIG_IEEE80211_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IEEE80211_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry. xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your
+ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw/debug_level
+ *
+ * you simply need to add your entry to the ipw_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw then you do not have
+ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IEEE80211_DL_INFO (1<<0)
+#define IEEE80211_DL_WX (1<<1)
+#define IEEE80211_DL_SCAN (1<<2)
+#define IEEE80211_DL_STATE (1<<3)
+#define IEEE80211_DL_MGMT (1<<4)
+#define IEEE80211_DL_FRAG (1<<5)
+#define IEEE80211_DL_EAP (1<<6)
+#define IEEE80211_DL_DROP (1<<7)
+
+#define IEEE80211_DL_TX (1<<8)
+#define IEEE80211_DL_RX (1<<9)
+
+#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
+#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
+#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a)
+
+#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a)
+#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a)
+//#define IEEE_DEBUG_SCAN IEEE80211_WARNING
+#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
+#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
+#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
+#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
+#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
+#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
+#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h> /* ARPHRD_ETHER */
+
+#ifndef WIRELESS_SPY
+#define WIRELESS_SPY // enable iwspy support
+#endif
+#include <net/iw_handler.h> // new driver API
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
+#endif
+
+/* IEEE 802.11 defines */
+
+#define P80211_OUI_LEN 3
+
+struct ieee80211_snap_hdr {
+
+ u8 dsap; /* always 0xAA */
+ u8 ssap; /* always 0xAA */
+ u8 ctrl; /* always 0x03 */
+ u8 oui[P80211_OUI_LEN]; /* organizational universal id */
+
+} __attribute__ ((packed));
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
+#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ)
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_IBSS (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
+#define WLAN_CAPABILITY_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+#define WLAN_CAPABILITY_SHORT_SLOT (1<<10)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_CHALLENGE 16
+#define WLAN_EID_RSN 48
+#define WLAN_EID_GENERIC 221
+
+#define IEEE80211_MGMT_HDR_LEN 24
+#define IEEE80211_DATA_HDR3_LEN 24
+#define IEEE80211_DATA_HDR4_LEN 30
+
+
+#define IEEE80211_STATMASK_SIGNAL (1<<0)
+#define IEEE80211_STATMASK_RSSI (1<<1)
+#define IEEE80211_STATMASK_NOISE (1<<2)
+#define IEEE80211_STATMASK_RATE (1<<3)
+#define IEEE80211_STATMASK_WEMASK 0x7
+
+
+#define IEEE80211_CCK_MODULATION (1<<0)
+#define IEEE80211_OFDM_MODULATION (1<<1)
+
+#define IEEE80211_24GHZ_BAND (1<<0)
+#define IEEE80211_52GHZ_BAND (1<<1)
+
+#define IEEE80211_CCK_RATE_LEN 4
+#define IEEE80211_CCK_RATE_1MB 0x02
+#define IEEE80211_CCK_RATE_2MB 0x04
+#define IEEE80211_CCK_RATE_5MB 0x0B
+#define IEEE80211_CCK_RATE_11MB 0x16
+#define IEEE80211_OFDM_RATE_LEN 8
+#define IEEE80211_OFDM_RATE_6MB 0x0C
+#define IEEE80211_OFDM_RATE_9MB 0x12
+#define IEEE80211_OFDM_RATE_12MB 0x18
+#define IEEE80211_OFDM_RATE_18MB 0x24
+#define IEEE80211_OFDM_RATE_24MB 0x30
+#define IEEE80211_OFDM_RATE_36MB 0x48
+#define IEEE80211_OFDM_RATE_48MB 0x60
+#define IEEE80211_OFDM_RATE_54MB 0x6C
+#define IEEE80211_BASIC_RATE_MASK 0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK (1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK (1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK (1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK (1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11)
+
+#define IEEE80211_CCK_RATES_MASK 0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
+ IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \
+ IEEE80211_CCK_RATE_5MB_MASK | \
+ IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK 0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \
+ IEEE80211_OFDM_RATE_12MB_MASK | \
+ IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \
+ IEEE80211_OFDM_RATE_9MB_MASK | \
+ IEEE80211_OFDM_RATE_18MB_MASK | \
+ IEEE80211_OFDM_RATE_36MB_MASK | \
+ IEEE80211_OFDM_RATE_48MB_MASK | \
+ IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
+ IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+#define IEEE80211_NUM_OFDM_RATES 8
+#define IEEE80211_NUM_CCK_RATES 4
+#define IEEE80211_OFDM_SHIFT_MASK_A 4
+
+
+
+
+/* NOTE: This data is for statistical purposes; not all hardware provides this
+ * information for frames received. Not setting these will not cause
+ * any adverse affects. */
+struct ieee80211_rx_stats {
+ u32 mac_time[2];
+ u8 signalstrength;
+ s8 rssi;
+ u8 signal;
+ u8 noise;
+ u16 rate; /* in 100 kbps */
+ u8 received_channel;
+ u8 control;
+ u8 mask;
+ u8 freq;
+ u16 len;
+ u8 nic_type;
+};
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define IEEE80211_FRAG_CACHE_LEN 4
+
+struct ieee80211_frag_entry {
+ unsigned long first_frag_time;
+ unsigned int seq;
+ unsigned int last_frag;
+ struct sk_buff *skb;
+ u8 src_addr[ETH_ALEN];
+ u8 dst_addr[ETH_ALEN];
+};
+
+struct ieee80211_stats {
+ unsigned int tx_unicast_frames;
+ unsigned int tx_multicast_frames;
+ unsigned int tx_fragments;
+ unsigned int tx_unicast_octets;
+ unsigned int tx_multicast_octets;
+ unsigned int tx_deferred_transmissions;
+ unsigned int tx_single_retry_frames;
+ unsigned int tx_multiple_retry_frames;
+ unsigned int tx_retry_limit_exceeded;
+ unsigned int tx_discards;
+ unsigned int rx_unicast_frames;
+ unsigned int rx_multicast_frames;
+ unsigned int rx_fragments;
+ unsigned int rx_unicast_octets;
+ unsigned int rx_multicast_octets;
+ unsigned int rx_fcs_errors;
+ unsigned int rx_discards_no_buffer;
+ unsigned int tx_discards_wrong_sa;
+ unsigned int rx_discards_undecryptable;
+ unsigned int rx_message_in_msg_fragments;
+ unsigned int rx_message_in_bad_msg_fragments;
+};
+
+struct ieee80211_softmac_stats{
+ unsigned int rx_ass_ok;
+ unsigned int rx_ass_err;
+ unsigned int rx_probe_rq;
+ unsigned int tx_probe_rs;
+ unsigned int tx_beacons;
+ unsigned int rx_auth_rq;
+ unsigned int rx_auth_rs_ok;
+ unsigned int rx_auth_rs_err;
+ unsigned int tx_auth_rq;
+ unsigned int no_auth_rs;
+ unsigned int no_ass_rs;
+ unsigned int tx_ass_rq;
+ unsigned int rx_ass_rq;
+ unsigned int tx_probe_rq;
+ unsigned int reassoc;
+ unsigned int swtxstop;
+ unsigned int swtxawake;
+};
+
+struct ieee80211_device;
+
+#include "ieee80211_crypt.h"
+
+#define SEC_KEY_1 (1<<0)
+#define SEC_KEY_2 (1<<1)
+#define SEC_KEY_3 (1<<2)
+#define SEC_KEY_4 (1<<3)
+#define SEC_ACTIVE_KEY (1<<4)
+#define SEC_AUTH_MODE (1<<5)
+#define SEC_UNICAST_GROUP (1<<6)
+#define SEC_LEVEL (1<<7)
+#define SEC_ENABLED (1<<8)
+
+#define SEC_LEVEL_0 0 /* None */
+#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
+#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
+#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
+#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+
+#define WEP_KEY_LEN_MODIF 32
+
+struct ieee80211_security {
+ u16 active_key:2,
+ enabled:1,
+ auth_mode:2,
+ auth_algo:4,
+ unicast_uses_group:1;
+ u8 key_sizes[WEP_KEYS];
+ u8 keys[WEP_KEYS][WEP_KEY_LEN_MODIF];
+ u8 level;
+ u16 flags;
+} __attribute__ ((packed));
+
+
+/*
+
+ 802.11 data frame from AP
+
+ ,-------------------------------------------------------------------.
+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-2340 bytes
+
+*/
+
+struct ieee80211_header_data {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[6];
+ u8 addr2[6];
+ u8 addr3[6];
+ u16 seq_ctrl;
+};
+
+#define BEACON_PROBE_SSID_ID_POSITION 12
+
+/* Management Frame Information Element Types */
+#define MFIE_TYPE_SSID 0
+#define MFIE_TYPE_RATES 1
+#define MFIE_TYPE_FH_SET 2
+#define MFIE_TYPE_DS_SET 3
+#define MFIE_TYPE_CF_SET 4
+#define MFIE_TYPE_TIM 5
+#define MFIE_TYPE_IBSS_SET 6
+#define MFIE_TYPE_COUNTRY 7 //+YJ,080625
+#define MFIE_TYPE_CHALLENGE 16
+#define MFIE_TYPE_ERP 42
+#define MFIE_TYPE_RSN 48
+#define MFIE_TYPE_RATES_EX 50
+#define MFIE_TYPE_GENERIC 221
+
+#ifdef ENABLE_DOT11D
+typedef enum
+{
+ COUNTRY_CODE_FCC = 0,
+ COUNTRY_CODE_IC = 1,
+ COUNTRY_CODE_ETSI = 2,
+ COUNTRY_CODE_SPAIN = 3,
+ COUNTRY_CODE_FRANCE = 4,
+ COUNTRY_CODE_MKK = 5,
+ COUNTRY_CODE_MKK1 = 6,
+ COUNTRY_CODE_ISRAEL = 7,
+ COUNTRY_CODE_TELEC = 8,
+ COUNTRY_CODE_GLOBAL_DOMAIN = 9,
+ COUNTRY_CODE_WORLD_WIDE_13_INDEX = 10
+}country_code_type_t;
+#endif
+
+struct ieee80211_info_element_hdr {
+ u8 id;
+ u8 len;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+ u8 id;
+ u8 len;
+ u8 data[0];
+} __attribute__ ((packed));
+
+/*
+ * These are the data types that can make up management packets
+ *
+ u16 auth_algorithm;
+ u16 auth_sequence;
+ u16 beacon_interval;
+ u16 capability;
+ u8 current_ap[ETH_ALEN];
+ u16 listen_interval;
+ struct {
+ u16 association_id:14, reserved:2;
+ } __attribute__ ((packed));
+ u32 time_stamp[2];
+ u16 reason;
+ u16 status;
+*/
+
+#define IEEE80211_DEFAULT_TX_ESSID "Penguin"
+#define IEEE80211_DEFAULT_BASIC_RATE 10
+
+struct ieee80211_authentication {
+ struct ieee80211_header_data header;
+ u16 algorithm;
+ u16 transaction;
+ u16 status;
+ //struct ieee80211_info_element_hdr info_element;
+} __attribute__ ((packed));
+
+
+struct ieee80211_probe_response {
+ struct ieee80211_header_data header;
+ u32 time_stamp[2];
+ u16 beacon_interval;
+ u16 capability;
+ struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_probe_request {
+ struct ieee80211_header_data header;
+ /*struct ieee80211_info_element info_element;*/
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_request_frame {
+ struct ieee80211_hdr_3addr header;
+ u16 capability;
+ u16 listen_interval;
+ //u8 current_ap[ETH_ALEN];
+ struct ieee80211_info_element_hdr info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_response_frame {
+ struct ieee80211_hdr_3addr header;
+ u16 capability;
+ u16 status;
+ u16 aid;
+ struct ieee80211_info_element info_element; /* supported rates */
+} __attribute__ ((packed));
+
+struct ieee80211_disassoc_frame{
+ struct ieee80211_hdr_3addr header;
+ u16 reasoncode;
+}__attribute__ ((packed));
+
+struct ieee80211_txb {
+ u8 nr_frags;
+ u8 encrypted;
+ u16 reserved;
+ u16 frag_size;
+ u16 payload_size;
+ struct sk_buff *fragments[0];
+};
+
+struct ieee80211_wmm_ac_param {
+ u8 ac_aci_acm_aifsn;
+ u8 ac_ecwmin_ecwmax;
+ u16 ac_txop_limit;
+};
+
+struct ieee80211_wmm_ts_info {
+ u8 ac_dir_tid;
+ u8 ac_up_psb;
+ u8 reserved;
+} __attribute__ ((packed));
+
+struct ieee80211_wmm_tspec_elem {
+ struct ieee80211_wmm_ts_info ts_info;
+ u16 norm_msdu_size;
+ u16 max_msdu_size;
+ u32 min_serv_inter;
+ u32 max_serv_inter;
+ u32 inact_inter;
+ u32 suspen_inter;
+ u32 serv_start_time;
+ u32 min_data_rate;
+ u32 mean_data_rate;
+ u32 peak_data_rate;
+ u32 max_burst_size;
+ u32 delay_bound;
+ u32 min_phy_rate;
+ u16 surp_band_allow;
+ u16 medium_time;
+}__attribute__((packed));
+
+enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame};
+#define MAX_SP_Len (WMM_all_frame << 4)
+#define IEEE80211_QOS_TID 0x0f
+#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5)
+
+/* SWEEP TABLE ENTRIES NUMBER*/
+#define MAX_SWEEP_TAB_ENTRIES 42
+#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
+/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
+ * only use 8, and then use extended rates for the remaining supported
+ * rates. Other APs, however, stick all of their supported rates on the
+ * main rates information element... */
+#define MAX_RATES_LENGTH ((u8)12)
+#define MAX_RATES_EX_LENGTH ((u8)16)
+#define MAX_NETWORK_COUNT 128
+//#define MAX_CHANNEL_NUMBER 161
+#define MAX_CHANNEL_NUMBER 165 //YJ,modified,080625
+#define MAX_IE_LEN 0xFF //+YJ,080625
+
+typedef struct _CHANNEL_LIST{
+ u8 Channel[MAX_CHANNEL_NUMBER + 1];
+ u8 Len;
+}CHANNEL_LIST, *PCHANNEL_LIST;
+
+#define IEEE80211_SOFTMAC_SCAN_TIME 100//400
+//(HZ / 2)
+//by amy for ps
+#define IEEE80211_WATCH_DOG_TIME 2000
+//by amy for ps
+//by amy for antenna
+#define ANTENNA_DIVERSITY_TIMER_PERIOD 1000 // 1000 m
+//by amy for antenna
+#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2)
+
+#define CRC_LENGTH 4U
+
+#define MAX_WPA_IE_LEN 64
+
+#define NETWORK_EMPTY_ESSID (1<<0)
+#define NETWORK_HAS_OFDM (1<<1)
+#define NETWORK_HAS_CCK (1<<2)
+
+#define IEEE80211_DTIM_MBCAST 4
+#define IEEE80211_DTIM_UCAST 2
+#define IEEE80211_DTIM_VALID 1
+#define IEEE80211_DTIM_INVALID 0
+
+#define IEEE80211_PS_DISABLED 0
+#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST
+#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST
+#define IEEE80211_PS_ENABLE IEEE80211_DTIM_VALID
+//added by David for QoS 2006/6/30
+//#define WMM_Hang_8187
+#ifdef WMM_Hang_8187
+#undef WMM_Hang_8187
+#endif
+
+#define WME_AC_BE 0x00
+#define WME_AC_BK 0x01
+#define WME_AC_VI 0x02
+#define WME_AC_VO 0x03
+#define WME_ACI_MASK 0x03
+#define WME_AIFSN_MASK 0x03
+#define WME_AC_PRAM_LEN 16
+
+//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP
+//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1))
+#define UP2AC(up) ( \
+ ((up) < 1) ? WME_AC_BE : \
+ ((up) < 3) ? WME_AC_BK : \
+ ((up) < 4) ? WME_AC_BE : \
+ ((up) < 6) ? WME_AC_VI : \
+ WME_AC_VO)
+//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue
+#define AC2UP(_ac) ( \
+ ((_ac) == WME_AC_VO) ? 6 : \
+ ((_ac) == WME_AC_VI) ? 5 : \
+ ((_ac) == WME_AC_BK) ? 1 : \
+ 0)
+
+#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */
+struct ether_header {
+ u8 ether_dhost[ETHER_ADDR_LEN];
+ u8 ether_shost[ETHER_ADDR_LEN];
+ u16 ether_type;
+} __attribute__((packed));
+
+#ifndef ETHERTYPE_PAE
+#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */
+#endif
+#ifndef ETHERTYPE_IP
+#define ETHERTYPE_IP 0x0800 /* IP protocol */
+#endif
+
+struct ieee80211_network {
+ /* These entries are used to identify a unique network */
+ u8 bssid[ETH_ALEN];
+ u8 channel;
+ /* Ensure null-terminated for any debug msgs */
+ u8 ssid[IW_ESSID_MAX_SIZE + 1];
+ u8 ssid_len;
+
+ /* These are network statistics */
+ struct ieee80211_rx_stats stats;
+ u16 capability;
+ u8 rates[MAX_RATES_LENGTH];
+ u8 rates_len;
+ u8 rates_ex[MAX_RATES_EX_LENGTH];
+ u8 rates_ex_len;
+ unsigned long last_scanned;
+ u8 mode;
+ u8 flags;
+ u32 last_associate;
+ u32 time_stamp[2];
+ u16 beacon_interval;
+ u16 listen_interval;
+ u16 atim_window;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
+ u8 rsn_ie[MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+ u8 dtim_period;
+ u8 dtim_data;
+ u32 last_dtim_sta_time[2];
+ struct list_head list;
+ //appeded for QoS
+ u8 wmm_info;
+ struct ieee80211_wmm_ac_param wmm_param[4];
+ u8 QoS_Enable;
+ u8 SignalStrength;
+//by amy 080312
+ u8 HighestOperaRate;
+//by amy 080312
+#ifdef THOMAS_TURBO
+ u8 Turbo_Enable;//enable turbo mode, added by thomas
+#endif
+#ifdef ENABLE_DOT11D
+ u16 CountryIeLen;
+ u8 CountryIeBuf[MAX_IE_LEN];
+#endif
+};
+
+enum ieee80211_state {
+
+ /* the card is not linked at all */
+ IEEE80211_NOLINK = 0,
+
+ /* IEEE80211_ASSOCIATING* are for BSS client mode
+ * the driver shall not perform RX filtering unless
+ * the state is LINKED.
+ * The driver shall just check for the state LINKED and
+ * defaults to NOLINK for ALL the other states (including
+ * LINKED_SCANNING)
+ */
+
+ /* the association procedure will start (wq scheduling)*/
+ IEEE80211_ASSOCIATING,
+ IEEE80211_ASSOCIATING_RETRY,
+
+ /* the association procedure is sending AUTH request*/
+ IEEE80211_ASSOCIATING_AUTHENTICATING,
+
+ /* the association procedure has successfully authentcated
+ * and is sending association request
+ */
+ IEEE80211_ASSOCIATING_AUTHENTICATED,
+
+ /* the link is ok. the card associated to a BSS or linked
+ * to a ibss cell or acting as an AP and creating the bss
+ */
+ IEEE80211_LINKED,
+
+ /* same as LINKED, but the driver shall apply RX filter
+ * rules as we are in NO_LINK mode. As the card is still
+ * logically linked, but it is doing a syncro site survey
+ * then it will be back to LINKED state.
+ */
+ IEEE80211_LINKED_SCANNING,
+
+};
+
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+#define DEFAULT_FTS 2346
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
+
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11))
+extern inline int is_multicast_ether_addr(const u8 *addr)
+{
+ return ((addr[0] != 0xff) && (0x01 & addr[0]));
+}
+#endif
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13))
+extern inline int is_broadcast_ether_addr(const u8 *addr)
+{
+ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \
+ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff));
+}
+#endif
+
+#define CFG_IEEE80211_RESERVE_FCS (1<<0)
+#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
+
+typedef struct tx_pending_t{
+ int frag;
+ struct ieee80211_txb *txb;
+}tx_pending_t;
+
+
+struct ieee80211_device {
+ struct net_device *dev;
+
+ /* Bookkeeping structures */
+ struct net_device_stats stats;
+ struct ieee80211_stats ieee_stats;
+ struct ieee80211_softmac_stats softmac_stats;
+
+ /* Probe / Beacon management */
+ struct list_head network_free_list;
+ struct list_head network_list;
+ struct ieee80211_network *networks;
+ int scans;
+ int scan_age;
+
+ int iw_mode; /* operating mode (IW_MODE_*) */
+
+ spinlock_t lock;
+ spinlock_t wpax_suitlist_lock;
+
+ int tx_headroom; /* Set to size of any additional room needed at front
+ * of allocated Tx SKBs */
+ u32 config;
+
+ /* WEP and other encryption related settings at the device level */
+ int open_wep; /* Set to 1 to allow unencrypted frames */
+
+ int reset_on_keychange; /* Set to 1 if the HW needs to be reset on
+ * WEP key changes */
+
+ /* If the host performs {en,de}cryption, then set to 1 */
+ int host_encrypt;
+ int host_decrypt;
+ int ieee802_1x; /* is IEEE 802.1X used */
+
+ /* WPA data */
+ int wpa_enabled;
+ int drop_unencrypted;
+ int tkip_countermeasures;
+ int privacy_invoked;
+ size_t wpa_ie_len;
+ u8 *wpa_ie;
+
+ u8 ap_mac_addr[6];
+ u16 pairwise_key_type;
+ u16 broadcast_key_type;
+
+ struct list_head crypt_deinit_list;
+ struct ieee80211_crypt_data *crypt[WEP_KEYS];
+ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
+ struct timer_list crypt_deinit_timer;
+
+ int bcrx_sta_key; /* use individual keys to override default keys even
+ * with RX of broad/multicast frames */
+
+ /* Fragmentation structures */
+ // each streaming contain a entry
+ struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN];
+ unsigned int frag_next_idx[17];
+ u16 fts; /* Fragmentation Threshold */
+
+ /* This stores infos for the current network.
+ * Either the network we are associated in INFRASTRUCTURE
+ * or the network that we are creating in MASTER mode.
+ * ad-hoc is a mixture ;-).
+ * Note that in infrastructure mode, even when not associated,
+ * fields bssid and essid may be valid (if wpa_set and essid_set
+ * are true) as thy carry the value set by the user via iwconfig
+ */
+ struct ieee80211_network current_network;
+
+
+ enum ieee80211_state state;
+
+ int short_slot;
+ int mode; /* A, B, G */
+ int modulation; /* CCK, OFDM */
+ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */
+ int abg_true; /* ABG flag */
+
+ /* used for forcing the ibss workqueue to terminate
+ * without wait for the syncro scan to terminate
+ */
+ short sync_scan_hurryup;
+
+#ifdef ENABLE_DOT11D
+ void * pDot11dInfo;
+ bool bGlobalDomain;
+
+ // For Liteon Ch12~13 passive scan
+ u8 MinPassiveChnlNum;
+ u8 IbssStartChnl;
+#else
+ /* map of allowed channels. 0 is dummy */
+ // FIXME: remeber to default to a basic channel plan depending of the PHY type
+ int channel_map[MAX_CHANNEL_NUMBER+1];
+#endif
+
+ int rate; /* current rate */
+ int basic_rate;
+ //FIXME: pleace callback, see if redundant with softmac_features
+ short active_scan;
+
+ /* this contains flags for selectively enable softmac support */
+ u16 softmac_features;
+
+ /* if the sequence control field is not filled by HW */
+ u16 seq_ctrl[5];
+
+ /* association procedure transaction sequence number */
+ u16 associate_seq;
+
+ /* AID for RTXed association responses */
+ u16 assoc_id;
+
+ /* power save mode related*/
+ short ps;
+ short sta_sleep;
+ int ps_timeout;
+ struct tasklet_struct ps_task;
+ u32 ps_th;
+ u32 ps_tl;
+
+ short raw_tx;
+ /* used if IEEE_SOFTMAC_TX_QUEUE is set */
+ short queue_stop;
+ short scanning;
+ short proto_started;
+
+ struct semaphore wx_sem;
+ struct semaphore scan_sem;
+
+ spinlock_t mgmt_tx_lock;
+ spinlock_t beacon_lock;
+
+ short beacon_txing;
+
+ short wap_set;
+ short ssid_set;
+
+ u8 wpax_type_set; //{added by David, 2006.9.28}
+ u32 wpax_type_notify; //{added by David, 2006.9.26}
+
+ /* QoS related flag */
+ char init_wmmparam_flag;
+
+ /* for discarding duplicated packets in IBSS */
+ struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE];
+
+ /* for discarding duplicated packets in BSS */
+ u16 last_rxseq_num[17]; /* rx seq previous per-tid */
+ u16 last_rxfrag_num[17];/* tx frag previous per-tid */
+ unsigned long last_packet_time[17];
+
+ /* for PS mode */
+ unsigned long last_rx_ps_time;
+
+ /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */
+ struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM];
+ int mgmt_queue_head;
+ int mgmt_queue_tail;
+
+
+ /* used if IEEE_SOFTMAC_TX_QUEUE is set */
+ struct tx_pending_t tx_pending;
+
+ /* used if IEEE_SOFTMAC_ASSOCIATE is set */
+ struct timer_list associate_timer;
+
+ /* used if IEEE_SOFTMAC_BEACONS is set */
+ struct timer_list beacon_timer;
+
+ struct work_struct associate_complete_wq;
+// struct work_struct associate_retry_wq;
+ struct work_struct associate_procedure_wq;
+// struct work_struct softmac_scan_wq;
+ struct work_struct wx_sync_scan_wq;
+ struct work_struct wmm_param_update_wq;
+ struct work_struct ps_request_tx_ack_wq;//for ps
+// struct work_struct hw_wakeup_wq;
+// struct work_struct hw_sleep_wq;
+// struct work_struct watch_dog_wq;
+ bool bInactivePs;
+ bool actscanning;
+ bool beinretry;
+ u16 ListenInterval;
+ unsigned long NumRxDataInPeriod; //YJ,add,080828
+ unsigned long NumRxBcnInPeriod; //YJ,add,080828
+ unsigned long NumRxOkTotal;
+ unsigned long NumRxUnicast;//YJ,add,080828,for keep alive
+ bool bHwRadioOff;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ struct delayed_work softmac_scan_wq;
+ struct delayed_work associate_retry_wq;
+ struct delayed_work hw_wakeup_wq;
+ struct delayed_work hw_sleep_wq;//+by amy 080324
+ struct delayed_work watch_dog_wq;
+ struct delayed_work sw_antenna_wq;
+ struct delayed_work start_ibss_wq;
+//by amy for rate adaptive 080312
+ struct delayed_work rate_adapter_wq;
+//by amy for rate adaptive
+ struct delayed_work hw_dig_wq;
+ struct delayed_work tx_pw_wq;
+
+//Added for RF power on power off by lizhaoming 080512
+ struct delayed_work GPIOChangeRFWorkItem;
+#else
+
+ struct work_struct start_ibss_wq;
+ struct work_struct softmac_scan_wq;
+ struct work_struct associate_retry_wq;
+ struct work_struct hw_wakeup_wq;
+ struct work_struct hw_sleep_wq;
+ struct work_struct watch_dog_wq;
+ struct work_struct sw_antenna_wq;
+//by amy for rate adaptive 080312
+ struct work_struct rate_adapter_wq;
+//by amy for rate adaptive
+ struct work_struct hw_dig_wq;
+ struct work_struct tx_pw_wq;
+
+//Added for RF power on power off by lizhaoming 080512
+ struct work_struct GPIOChangeRFWorkItem;
+#endif
+ struct workqueue_struct *wq;
+
+ /* Callback functions */
+ void (*set_security)(struct net_device *dev,
+ struct ieee80211_security *sec);
+
+ /* Used to TX data frame by using txb structs.
+ * this is not used if in the softmac_features
+ * is set the flag IEEE_SOFTMAC_TX_QUEUE
+ */
+ int (*hard_start_xmit)(struct ieee80211_txb *txb,
+ struct net_device *dev);
+
+ int (*reset_port)(struct net_device *dev);
+
+ /* Softmac-generated frames (mamagement) are TXed via this
+ * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
+ * not set. As some cards may have different HW queues that
+ * one might want to use for data and management frames
+ * the option to have two callbacks might be useful.
+ * This fucntion can't sleep.
+ */
+ int (*softmac_hard_start_xmit)(struct sk_buff *skb,
+ struct net_device *dev);
+
+ /* used instead of hard_start_xmit (not softmac_hard_start_xmit)
+ * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
+ * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
+ * then also management frames are sent via this callback.
+ * This function can't sleep.
+ */
+ void (*softmac_data_hard_start_xmit)(struct sk_buff *skb,
+ struct net_device *dev,int rate);
+
+ /* stops the HW queue for DATA frames. Useful to avoid
+ * waste time to TX data frame when we are reassociating
+ * This function can sleep.
+ */
+ void (*data_hard_stop)(struct net_device *dev);
+
+ /* OK this is complementar to data_poll_hard_stop */
+ void (*data_hard_resume)(struct net_device *dev);
+
+ /* ask to the driver to retune the radio .
+ * This function can sleep. the driver should ensure
+ * the radio has been swithced before return.
+ */
+ void (*set_chan)(struct net_device *dev,short ch);
+
+ /* These are not used if the ieee stack takes care of
+ * scanning (IEEE_SOFTMAC_SCAN feature set).
+ * In this case only the set_chan is used.
+ *
+ * The syncro version is similar to the start_scan but
+ * does not return until all channels has been scanned.
+ * this is called in user context and should sleep,
+ * it is called in a work_queue when swithcing to ad-hoc mode
+ * or in behalf of iwlist scan when the card is associated
+ * and root user ask for a scan.
+ * the fucntion stop_scan should stop both the syncro and
+ * background scanning and can sleep.
+ * The fucntion start_scan should initiate the background
+ * scanning and can't sleep.
+ */
+ void (*scan_syncro)(struct net_device *dev);
+ void (*start_scan)(struct net_device *dev);
+ void (*stop_scan)(struct net_device *dev);
+
+ /* indicate the driver that the link state is changed
+ * for example it may indicate the card is associated now.
+ * Driver might be interested in this to apply RX filter
+ * rules or simply light the LINK led
+ */
+ void (*link_change)(struct net_device *dev);
+
+ /* these two function indicates to the HW when to start
+ * and stop to send beacons. This is used when the
+ * IEEE_SOFTMAC_BEACONS is not set. For now the
+ * stop_send_bacons is NOT guaranteed to be called only
+ * after start_send_beacons.
+ */
+ void (*start_send_beacons) (struct net_device *dev);
+ void (*stop_send_beacons) (struct net_device *dev);
+
+ /* power save mode related */
+ void (*sta_wake_up) (struct net_device *dev);
+ void (*ps_request_tx_ack) (struct net_device *dev);
+ void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl);
+ short (*ps_is_queue_empty) (struct net_device *dev);
+
+ /* QoS related */
+ //void (*wmm_param_update) (struct net_device *dev, u8 *ac_param);
+ //void (*wmm_param_update) (struct ieee80211_device *ieee);
+
+ /* This must be the last item so that it points to the data
+ * allocated beyond this structure by alloc_ieee80211 */
+ u8 priv[0];
+};
+
+#define IEEE_A (1<<0)
+#define IEEE_B (1<<1)
+#define IEEE_G (1<<2)
+#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
+
+/* Generate a 802.11 header */
+
+/* Uses the channel change callback directly
+ * instead of [start/stop] scan callbacks
+ */
+#define IEEE_SOFTMAC_SCAN (1<<2)
+
+/* Perform authentication and association handshake */
+#define IEEE_SOFTMAC_ASSOCIATE (1<<3)
+
+/* Generate probe requests */
+#define IEEE_SOFTMAC_PROBERQ (1<<4)
+
+/* Generate respones to probe requests */
+#define IEEE_SOFTMAC_PROBERS (1<<5)
+
+/* The ieee802.11 stack will manages the netif queue
+ * wake/stop for the driver, taking care of 802.11
+ * fragmentation. See softmac.c for details. */
+#define IEEE_SOFTMAC_TX_QUEUE (1<<7)
+
+/* Uses only the softmac_data_hard_start_xmit
+ * even for TX management frames.
+ */
+#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8)
+
+/* Generate beacons. The stack will enqueue beacons
+ * to the card
+ */
+#define IEEE_SOFTMAC_BEACONS (1<<6)
+
+
+
+static inline void *ieee80211_priv(struct net_device *dev)
+{
+ return ((struct ieee80211_device *)netdev_priv(dev))->priv;
+}
+
+extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
+{
+ /* Single white space is for Linksys APs */
+ if (essid_len == 1 && essid[0] == ' ')
+ return 1;
+
+ /* Otherwise, if the entire essid is 0, we assume it is hidden */
+ while (essid_len) {
+ essid_len--;
+ if (essid[essid_len] != '\0')
+ return 0;
+ }
+
+ return 1;
+}
+
+extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode)
+{
+ /*
+ * It is possible for both access points and our device to support
+ * combinations of modes, so as long as there is one valid combination
+ * of ap/device supported modes, then return success
+ *
+ */
+ if ((mode & IEEE_A) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+ (ieee->freq_band & IEEE80211_52GHZ_BAND))
+ return 1;
+
+ if ((mode & IEEE_G) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+ (ieee->freq_band & IEEE80211_24GHZ_BAND))
+ return 1;
+
+ if ((mode & IEEE_B) &&
+ (ieee->modulation & IEEE80211_CCK_MODULATION) &&
+ (ieee->freq_band & IEEE80211_24GHZ_BAND))
+ return 1;
+
+ return 0;
+}
+
+extern inline int ieee80211_get_hdrlen(u16 fc)
+{
+ int hdrlen = 24;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case IEEE80211_FTYPE_DATA:
+ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+ hdrlen = 30; /* Addr4 */
+ if(IEEE80211_QOS_HAS_SEQ(fc))
+ hdrlen += 2; /* QOS ctrl*/
+ break;
+ case IEEE80211_FTYPE_CTL:
+ switch (WLAN_FC_GET_STYPE(fc)) {
+ case IEEE80211_STYPE_CTS:
+ case IEEE80211_STYPE_ACK:
+ hdrlen = 10;
+ break;
+ default:
+ hdrlen = 16;
+ break;
+ }
+ break;
+ }
+
+ return hdrlen;
+}
+
+
+
+/* ieee80211.c */
+extern void free_ieee80211(struct net_device *dev);
+extern struct net_device *alloc_ieee80211(int sizeof_priv);
+
+extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
+
+/* ieee80211_tx.c */
+
+extern int ieee80211_encrypt_fragment(
+ struct ieee80211_device *ieee,
+ struct sk_buff *frag,
+ int hdr_len);
+
+extern int ieee80211_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+extern void ieee80211_txb_free(struct ieee80211_txb *);
+
+
+/* ieee80211_rx.c */
+extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats);
+extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *header,
+ struct ieee80211_rx_stats *stats);
+
+/* ieee80211_wx.c */
+extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data* wrqu, char *extra);
+int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra);
+int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+
+int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len);
+/* ieee80211_softmac.c */
+extern short ieee80211_is_54g(struct ieee80211_network net);
+extern short ieee80211_is_shortslot(struct ieee80211_network net);
+extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats, u16 type,
+ u16 stype);
+extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net);
+
+extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee);
+extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee);
+extern void ieee80211_start_bss(struct ieee80211_device *ieee);
+extern void ieee80211_start_master_bss(struct ieee80211_device *ieee);
+extern void ieee80211_start_ibss(struct ieee80211_device *ieee);
+extern void ieee80211_softmac_init(struct ieee80211_device *ieee);
+extern void ieee80211_softmac_free(struct ieee80211_device *ieee);
+extern void ieee80211_associate_abort(struct ieee80211_device *ieee);
+extern void ieee80211_disassociate(struct ieee80211_device *ieee);
+extern void ieee80211_stop_scan(struct ieee80211_device *ieee);
+extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee);
+extern void ieee80211_check_all_nets(struct ieee80211_device *ieee);
+extern void ieee80211_start_protocol(struct ieee80211_device *ieee);
+extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
+extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
+extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
+extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
+extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
+extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
+extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
+extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
+extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
+extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p);
+extern void notify_wx_assoc_event(struct ieee80211_device *ieee);
+extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success);
+extern void SendDisassociation(struct ieee80211_device *ieee,u8* asSta,u8 asRsn);
+extern void ieee80211_start_scan(struct ieee80211_device *ieee);
+
+//Add for RF power on power off by lizhaoming 080512
+extern void SendDisassociation(struct ieee80211_device *ieee,
+ u8* asSta,
+ u8 asRsn);
+
+/* ieee80211_crypt_ccmp&tkip&wep.c */
+extern void ieee80211_tkip_null(void);
+extern void ieee80211_wep_null(void);
+extern void ieee80211_ccmp_null(void);
+/* ieee80211_softmac_wx.c */
+
+extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *ext);
+
+extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *awrq,
+ char *extra);
+
+extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b);
+
+extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+
+extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+
+extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b);
+
+extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b);
+
+extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra);
+
+extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b);
+
+extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b);
+
+extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+extern void ieee80211_wx_sync_scan_wq(struct work_struct *work);
+#else
+ extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee);
+#endif
+//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee);
+
+extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+
+extern int ieee80211_wx_get_name(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+
+extern int ieee80211_wx_set_power(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+
+extern int ieee80211_wx_get_power(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+
+extern void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee);
+
+extern void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr);
+
+extern const long ieee80211_wlan_frequencies[];
+
+extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
+{
+ ieee->scans++;
+}
+
+extern inline int ieee80211_get_scans(struct ieee80211_device *ieee)
+{
+ return ieee->scans;
+}
+
+static inline const char *escape_essid(const char *essid, u8 essid_len) {
+ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ const char *s = essid;
+ char *d = escaped;
+
+ if (ieee80211_is_empty_essid(essid, essid_len)) {
+ memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+ return escaped;
+ }
+
+ essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
+ while (essid_len--) {
+ if (*s == '\0') {
+ *d++ = '\\';
+ *d++ = '0';
+ s++;
+ } else {
+ *d++ = *s++;
+ }
+ }
+ *d = '\0';
+ return escaped;
+}
+#endif /* IEEE80211_H */
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c
new file mode 100644
index 00000000000..af64cfbe16d
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c
@@ -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);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h
new file mode 100644
index 00000000000..b58a3bcc0dc
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h
@@ -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
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
new file mode 100644
index 00000000000..08add385790
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
@@ -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", __func__);
+ 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);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
new file mode 100644
index 00000000000..de97bbec0da
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
@@ -0,0 +1,1001 @@
+/*
+ * Host AP crypt: host-based TKIP 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 "ieee80211.h"
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include "rtl_crypto.h"
+#else
+#include <linux/crypto.h>
+#endif
+//#include <asm/scatterlist.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
+ #include <asm/scatterlist.h>
+#else
+ #include <linux/scatterlist.h>
+#endif
+
+#include <linux/crc32.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP crypt: TKIP");
+MODULE_LICENSE("GPL");
+
+#ifdef OPENSUSE_SLED
+#ifndef IN_OPENSUSE_SLED
+#define IN_OPENSUSE_SLED 1
+#endif
+#endif
+
+struct ieee80211_tkip_data {
+#define TKIP_KEY_LEN 32
+ u8 key[TKIP_KEY_LEN];
+ int key_set;
+
+ u32 tx_iv32;
+ u16 tx_iv16;
+ u16 tx_ttak[5];
+ int tx_phase1_done;
+
+ u32 rx_iv32;
+ u16 rx_iv16;
+ u16 rx_ttak[5];
+ int rx_phase1_done;
+ u32 rx_iv32_new;
+ u16 rx_iv16_new;
+
+ u32 dot11RSNAStatsTKIPReplays;
+ u32 dot11RSNAStatsTKIPICVErrors;
+ u32 dot11RSNAStatsTKIPLocalMICFailures;
+
+ int key_idx;
+
+ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED))
+ struct crypto_blkcipher *rx_tfm_arc4;
+ struct crypto_hash *rx_tfm_michael;
+ struct crypto_blkcipher *tx_tfm_arc4;
+ struct crypto_hash *tx_tfm_michael;
+ #endif
+
+ struct crypto_tfm *tfm_arc4;
+ struct crypto_tfm *tfm_michael;
+
+ /* scratch buffers for virt_to_page() (crypto API) */
+ u8 rx_hdr[16], tx_hdr[16];
+};
+
+static void * ieee80211_tkip_init(int key_idx)
+{
+ struct ieee80211_tkip_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_arc4 = crypto_alloc_tfm("arc4", 0);
+ if (priv->tfm_arc4 == NULL) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API arc4\n");
+ goto fail;
+ }
+
+ priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0);
+ if (priv->tfm_michael == NULL) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API michael_mic\n");
+ goto fail;
+ }
+
+ #else
+ priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(priv->tx_tfm_arc4)) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API arc4\n");
+ priv->tx_tfm_arc4 = NULL;
+ goto fail;
+ }
+
+ priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(priv->tx_tfm_michael)) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API michael_mic\n");
+ priv->tx_tfm_michael = NULL;
+ goto fail;
+ }
+
+ priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(priv->rx_tfm_arc4)) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API arc4\n");
+ priv->rx_tfm_arc4 = NULL;
+ goto fail;
+ }
+
+ priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(priv->rx_tfm_michael)) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API michael_mic\n");
+ priv->rx_tfm_michael = NULL;
+ goto fail;
+ }
+ #endif
+ return priv;
+
+fail:
+ if (priv) {
+ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ if (priv->tfm_michael)
+ crypto_free_tfm(priv->tfm_michael);
+ if (priv->tfm_arc4)
+ crypto_free_tfm(priv->tfm_arc4);
+ #else
+ if (priv->tx_tfm_michael)
+ crypto_free_hash(priv->tx_tfm_michael);
+ if (priv->tx_tfm_arc4)
+ crypto_free_blkcipher(priv->tx_tfm_arc4);
+ if (priv->rx_tfm_michael)
+ crypto_free_hash(priv->rx_tfm_michael);
+ if (priv->rx_tfm_arc4)
+ crypto_free_blkcipher(priv->rx_tfm_arc4);
+ #endif
+ kfree(priv);
+ }
+
+ return NULL;
+}
+
+
+static void ieee80211_tkip_deinit(void *priv)
+{
+ struct ieee80211_tkip_data *_priv = priv;
+ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ if (_priv && _priv->tfm_michael)
+ crypto_free_tfm(_priv->tfm_michael);
+ if (_priv && _priv->tfm_arc4)
+ crypto_free_tfm(_priv->tfm_arc4);
+ #else
+ if (_priv) {
+ if (_priv->tx_tfm_michael)
+ crypto_free_hash(_priv->tx_tfm_michael);
+ if (_priv->tx_tfm_arc4)
+ crypto_free_blkcipher(_priv->tx_tfm_arc4);
+ if (_priv->rx_tfm_michael)
+ crypto_free_hash(_priv->rx_tfm_michael);
+ if (_priv->rx_tfm_arc4)
+ crypto_free_blkcipher(_priv->rx_tfm_arc4);
+ }
+ #endif
+ kfree(priv);
+}
+
+
+static inline u16 RotR1(u16 val)
+{
+ return (val >> 1) | (val << 15);
+}
+
+
+static inline u8 Lo8(u16 val)
+{
+ return val & 0xff;
+}
+
+
+static inline u8 Hi8(u16 val)
+{
+ return val >> 8;
+}
+
+
+static inline u16 Lo16(u32 val)
+{
+ return val & 0xffff;
+}
+
+
+static inline u16 Hi16(u32 val)
+{
+ return val >> 16;
+}
+
+
+static inline u16 Mk16(u8 hi, u8 lo)
+{
+ return lo | (((u16) hi) << 8);
+}
+
+
+static inline u16 Mk16_le(u16 *v)
+{
+ return le16_to_cpu(*v);
+}
+
+
+static const u16 Sbox[256] =
+{
+ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+};
+
+
+static inline u16 _S_(u16 v)
+{
+ u16 t = Sbox[Hi8(v)];
+ return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
+}
+
+#ifndef JOHN_TKIP
+#define PHASE1_LOOP_COUNT 8
+
+static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
+{
+ int i, j;
+
+ /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
+ TTAK[0] = Lo16(IV32);
+ TTAK[1] = Hi16(IV32);
+ TTAK[2] = Mk16(TA[1], TA[0]);
+ TTAK[3] = Mk16(TA[3], TA[2]);
+ TTAK[4] = Mk16(TA[5], TA[4]);
+
+ for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
+ j = 2 * (i & 1);
+ TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
+ TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
+ TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
+ TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
+ TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
+ }
+}
+
+
+static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
+ u16 IV16)
+{
+ /* Make temporary area overlap WEP seed so that the final copy can be
+ * avoided on little endian hosts. */
+ u16 *PPK = (u16 *) &WEPSeed[4];
+
+ /* Step 1 - make copy of TTAK and bring in TSC */
+ PPK[0] = TTAK[0];
+ PPK[1] = TTAK[1];
+ PPK[2] = TTAK[2];
+ PPK[3] = TTAK[3];
+ PPK[4] = TTAK[4];
+ PPK[5] = TTAK[4] + IV16;
+
+ /* Step 2 - 96-bit bijective mixing using S-box */
+ PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0]));
+ PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2]));
+ PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4]));
+ PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6]));
+ PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8]));
+ PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10]));
+
+ PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12]));
+ PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14]));
+ PPK[2] += RotR1(PPK[1]);
+ PPK[3] += RotR1(PPK[2]);
+ PPK[4] += RotR1(PPK[3]);
+ PPK[5] += RotR1(PPK[4]);
+
+ /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
+ * WEPSeed[0..2] is transmitted as WEP IV */
+ WEPSeed[0] = Hi8(IV16);
+ WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
+ WEPSeed[2] = Lo8(IV16);
+ WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1);
+
+#ifdef __BIG_ENDIAN
+ {
+ int i;
+ for (i = 0; i < 6; i++)
+ PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
+ }
+#endif
+}
+#endif
+static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED))
+ struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4};
+ #endif
+ int len;
+ u8 *pos;
+ struct ieee80211_hdr *hdr;
+#ifndef JOHN_TKIP
+ u8 rc4key[16],*icv;
+ u32 crc;
+ struct scatterlist sg;
+#endif
+ int ret;
+
+ ret = 0;
+ if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
+ skb->len < hdr_len)
+ return -1;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+#if 0
+printk("@@ tkey\n");
+printk("%x|", ((u32*)tkey->key)[0]);
+printk("%x|", ((u32*)tkey->key)[1]);
+printk("%x|", ((u32*)tkey->key)[2]);
+printk("%x|", ((u32*)tkey->key)[3]);
+printk("%x|", ((u32*)tkey->key)[4]);
+printk("%x|", ((u32*)tkey->key)[5]);
+printk("%x|", ((u32*)tkey->key)[6]);
+printk("%x\n", ((u32*)tkey->key)[7]);
+#endif
+
+#ifndef JOHN_TKIP
+ if (!tkey->tx_phase1_done) {
+ tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
+ tkey->tx_iv32);
+ tkey->tx_phase1_done = 1;
+ }
+ tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
+
+#else
+ tkey->tx_phase1_done = 1;
+#endif /*JOHN_TKIP*/
+
+ len = skb->len - hdr_len;
+ pos = skb_push(skb, 8);
+ memmove(pos, pos + 8, hdr_len);
+ pos += hdr_len;
+
+#ifdef JOHN_TKIP
+ *pos++ = Hi8(tkey->tx_iv16);
+ *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F;
+ *pos++ = Lo8(tkey->tx_iv16);
+#else
+ *pos++ = rc4key[0];
+ *pos++ = rc4key[1];
+ *pos++ = rc4key[2];
+#endif
+ *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */;
+ *pos++ = tkey->tx_iv32 & 0xff;
+ *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
+ *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
+ *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
+#ifndef JOHN_TKIP
+ icv = skb_put(skb, 4);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ crc = ~crc32_le(~0, pos, len);
+#else
+ crc = ~ether_crc_le(len, pos);
+#endif
+ icv[0] = crc;
+ icv[1] = crc >> 8;
+ icv[2] = crc >> 16;
+ icv[3] = crc >> 24;
+ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = len + 4;
+ crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);
+ #else
+ crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
+ #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
+ ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
+ #endif
+#endif
+ tkey->tx_iv16++;
+ if (tkey->tx_iv16 == 0) {
+ tkey->tx_phase1_done = 0;
+ tkey->tx_iv32++;
+ }
+#ifndef JOHN_TKIP
+ #if((LINUX_VERSION_CODE <KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ return 0;
+ #else
+ return ret;
+ #endif
+#else
+ return 0;
+#endif
+}
+
+static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ||(IN_OPENSUSE_SLED))
+ struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4};
+ #endif
+ u8 keyidx, *pos;
+ u32 iv32;
+ u16 iv16;
+ struct ieee80211_hdr *hdr;
+#ifndef JOHN_TKIP
+ u8 icv[4];
+ u32 crc;
+ struct scatterlist sg;
+ u8 rc4key[16];
+ int plen;
+#endif
+ if (skb->len < hdr_len + 8 + 4)
+ 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 "TKIP: received packet without ExtIV"
+ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ }
+ return -2;
+ }
+ keyidx >>= 6;
+ if (tkey->key_idx != keyidx) {
+ printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
+ "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
+ return -6;
+ }
+ if (!tkey->key_set) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
+ " with keyid=%d that does not have a configured"
+ " key\n", MAC_ARG(hdr->addr2), keyidx);
+ }
+ return -3;
+ }
+ iv16 = (pos[0] << 8) | pos[2];
+ iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+ pos += 8;
+#ifndef JOHN_TKIP
+
+ if (iv32 < tkey->rx_iv32 ||
+ (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ " previous TSC %08x%04x received TSC "
+ "%08x%04x\n", MAC_ARG(hdr->addr2),
+ tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
+ }
+ tkey->dot11RSNAStatsTKIPReplays++;
+ return -4;
+ }
+
+ if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
+ tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
+ tkey->rx_phase1_done = 1;
+ }
+ tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
+
+ plen = skb->len - hdr_len - 12;
+ #if((LINUX_VERSION_CODE <KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = plen + 4;
+ crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4);
+ #else
+ crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
+ #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)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG ": TKIP: failed to decrypt "
+ "received packet from " MAC_FMT "\n",
+ MAC_ARG(hdr->addr2));
+ }
+ 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) {
+ if (iv32 != tkey->rx_iv32) {
+ /* Previously cached Phase1 result was already lost, so
+ * it needs to be recalculated for the next packet. */
+ tkey->rx_phase1_done = 0;
+ }
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+ MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ }
+ tkey->dot11RSNAStatsTKIPICVErrors++;
+ return -5;
+ }
+
+#endif /* JOHN_TKIP */
+
+ /* Update real counters only after Michael MIC verification has
+ * completed */
+ tkey->rx_iv32_new = iv32;
+ tkey->rx_iv16_new = iv16;
+
+ /* Remove IV and ICV */
+ memmove(skb->data + 8, skb->data, hdr_len);
+ skb_pull(skb, 8);
+ skb_trim(skb, skb->len - 4);
+
+//john's test
+#ifdef JOHN_DUMP
+if( ((u16*)skb->data)[0] & 0x4000){
+ printk("@@ rx decrypted skb->data");
+ int i;
+ for(i=0;i<skb->len;i++){
+ if( (i%24)==0 ) printk("\n");
+ printk("%2x ", ((u8*)skb->data)[i]);
+ }
+ printk("\n");
+}
+#endif /*JOHN_DUMP*/
+ return keyidx;
+}
+
+#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED))
+static int michael_mic(struct ieee80211_tkip_data *tkey, u8 *key, u8 *hdr,
+ u8 *data, size_t data_len, u8 *mic)
+{
+ struct scatterlist sg[2];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ struct hash_desc desc;
+ int ret=0;
+#endif
+ if (tkey->tfm_michael == NULL) {
+ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
+ return -1;
+ }
+ sg[0].page = virt_to_page(hdr);
+ sg[0].offset = offset_in_page(hdr);
+ sg[0].length = 16;
+
+ sg[1].page = virt_to_page(data);
+ sg[1].offset = offset_in_page(data);
+ sg[1].length = data_len;
+
+ //crypto_digest_init(tkey->tfm_michael);
+ //crypto_digest_setkey(tkey->tfm_michael, key, 8);
+ //crypto_digest_update(tkey->tfm_michael, sg, 2);
+ //crypto_digest_final(tkey->tfm_michael, mic);
+
+ //return 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ crypto_digest_init(tkey->tfm_michael);
+ crypto_digest_setkey(tkey->tfm_michael, key, 8);
+ crypto_digest_update(tkey->tfm_michael, sg, 2);
+ crypto_digest_final(tkey->tfm_michael, mic);
+
+ return 0;
+#else
+if (crypto_hash_setkey(tkey->tfm_michael, key, 8))
+ return -1;
+
+// return 0;
+ desc.tfm = tkey->tfm_michael;
+ desc.flags = 0;
+ ret = crypto_hash_digest(&desc, sg, data_len + 16, mic);
+ return ret;
+#endif
+}
+#else
+static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
+ u8 * data, size_t data_len, u8 * mic)
+{
+ struct hash_desc desc;
+ struct scatterlist sg[2];
+
+ if (tfm_michael == NULL) {
+ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
+ return -1;
+ }
+ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
+ sg[0].page = virt_to_page(hdr);
+ sg[0].offset = offset_in_page(hdr);
+ sg[0].length = 16;
+ sg[1].page = virt_to_page(data);
+ sg[1].offset = offset_in_page(data);
+ sg[1].length = data_len;
+ #else
+ sg_init_table(sg, 2);
+ sg_set_buf(&sg[0], hdr, 16);
+ sg_set_buf(&sg[1], data, data_len);
+ #endif
+
+ if (crypto_hash_setkey(tfm_michael, key, 8))
+ return -1;
+
+ desc.tfm = tfm_michael;
+ desc.flags = 0;
+ return crypto_hash_digest(&desc, sg, data_len + 16, mic);
+}
+#endif
+
+
+
+static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr)
+{
+ struct ieee80211_hdr *hdr11;
+
+ hdr11 = (struct ieee80211_hdr *) skb->data;
+ switch (le16_to_cpu(hdr11->frame_ctl) &
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+ case IEEE80211_FCTL_TODS:
+ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
+ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+ break;
+ case IEEE80211_FCTL_FROMDS:
+ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
+ memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
+ break;
+ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
+ memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
+ break;
+ case 0:
+ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
+ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+ break;
+ }
+
+ hdr[12] = 0; /* priority */
+
+ hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
+}
+
+
+static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ u8 *pos;
+ struct ieee80211_hdr *hdr;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
+ printk(KERN_DEBUG "Invalid packet for Michael MIC add "
+ "(tailroom=%d hdr_len=%d skb->len=%d)\n",
+ skb_tailroom(skb), hdr_len, skb->len);
+ return -1;
+ }
+
+ michael_mic_hdr(skb, tkey->tx_hdr);
+
+ // { david, 2006.9.1
+ // fix the wpa process with wmm enabled.
+ if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) {
+ tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
+ }
+ // }
+ pos = skb_put(skb, 8);
+ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
+ #else
+ if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
+ #endif
+ return -1;
+
+ return 0;
+}
+
+
+#if WIRELESS_EXT >= 18
+static void ieee80211_michael_mic_failure(struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ int keyidx)
+{
+ union iwreq_data wrqu;
+ struct iw_michaelmicfailure ev;
+
+ /* TODO: needed parameters: count, keyid, key type, TSC */
+ memset(&ev, 0, sizeof(ev));
+ ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
+ if (hdr->addr1[0] & 0x01)
+ ev.flags |= IW_MICFAILURE_GROUP;
+ else
+ ev.flags |= IW_MICFAILURE_PAIRWISE;
+ ev.src_addr.sa_family = ARPHRD_ETHER;
+ memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(ev);
+ wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev);
+}
+#elif WIRELESS_EXT >= 15
+static void ieee80211_michael_mic_failure(struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ int keyidx)
+{
+ union iwreq_data wrqu;
+ char buf[128];
+
+ /* TODO: needed parameters: count, keyid, key type, TSC */
+ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr="
+ MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
+ MAC_ARG(hdr->addr2));
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+}
+#else /* WIRELESS_EXT >= 15 */
+static inline void ieee80211_michael_mic_failure(struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ int keyidx)
+{
+}
+#endif /* WIRELESS_EXT >= 15 */
+
+
+static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
+ int hdr_len, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ u8 mic[8];
+ struct ieee80211_hdr *hdr;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ if (!tkey->key_set)
+ return -1;
+
+ michael_mic_hdr(skb, tkey->rx_hdr);
+ // { david, 2006.9.1
+ // fix the wpa process with wmm enabled.
+ if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) {
+ tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
+ }
+ // }
+ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
+ #else
+ if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
+ #endif
+ return -1;
+ if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
+ struct ieee80211_hdr *hdr;
+ hdr = (struct ieee80211_hdr *) skb->data;
+ printk(KERN_DEBUG "%s: Michael MIC verification failed for "
+ "MSDU from " MAC_FMT " keyidx=%d\n",
+ skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
+ keyidx);
+ if (skb->dev)
+ ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
+ tkey->dot11RSNAStatsTKIPLocalMICFailures++;
+ return -1;
+ }
+
+ /* Update TSC counters for RX now that the packet verification has
+ * completed. */
+ tkey->rx_iv32 = tkey->rx_iv32_new;
+ tkey->rx_iv16 = tkey->rx_iv16_new;
+
+ skb_trim(skb, skb->len - 8);
+
+ return 0;
+}
+
+
+static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ int keyidx;
+ #if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ struct crypto_tfm *tfm = tkey->tfm_michael;
+ struct crypto_tfm *tfm2 = tkey->tfm_arc4;
+ #else
+ struct crypto_hash *tfm = tkey->tx_tfm_michael;
+ struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
+ struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
+ struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
+ #endif
+
+ keyidx = tkey->key_idx;
+ memset(tkey, 0, sizeof(*tkey));
+ tkey->key_idx = keyidx;
+
+ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED))
+ tkey->tfm_michael = tfm;
+ tkey->tfm_arc4 = tfm2;
+ #else
+ tkey->tx_tfm_michael = tfm;
+ tkey->tx_tfm_arc4 = tfm2;
+ tkey->rx_tfm_michael = tfm3;
+ tkey->rx_tfm_arc4 = tfm4;
+ #endif
+
+ if (len == TKIP_KEY_LEN) {
+ memcpy(tkey->key, key, TKIP_KEY_LEN);
+ tkey->key_set = 1;
+ tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
+ if (seq) {
+ tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
+ (seq[3] << 8) | seq[2];
+ tkey->rx_iv16 = (seq[1] << 8) | seq[0];
+ }
+ } else if (len == 0)
+ tkey->key_set = 0;
+ else
+ return -1;
+
+ return 0;
+}
+
+
+static int ieee80211_tkip_get_key(void *key, int len, u8 *seq, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+
+ if (len < TKIP_KEY_LEN)
+ return -1;
+
+ if (!tkey->key_set)
+ return 0;
+ memcpy(key, tkey->key, TKIP_KEY_LEN);
+
+ if (seq) {
+ /* Return the sequence number of the last transmitted frame. */
+ u16 iv16 = tkey->tx_iv16;
+ u32 iv32 = tkey->tx_iv32;
+ if (iv16 == 0)
+ iv32--;
+ iv16--;
+ seq[0] = tkey->tx_iv16;
+ seq[1] = tkey->tx_iv16 >> 8;
+ seq[2] = tkey->tx_iv32;
+ seq[3] = tkey->tx_iv32 >> 8;
+ seq[4] = tkey->tx_iv32 >> 16;
+ seq[5] = tkey->tx_iv32 >> 24;
+ }
+
+ return TKIP_KEY_LEN;
+}
+
+
+static char * ieee80211_tkip_print_stats(char *p, void *priv)
+{
+ struct ieee80211_tkip_data *tkip = priv;
+ p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
+ "tx_pn=%02x%02x%02x%02x%02x%02x "
+ "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "replays=%d icv_errors=%d local_mic_failures=%d\n",
+ tkip->key_idx, tkip->key_set,
+ (tkip->tx_iv32 >> 24) & 0xff,
+ (tkip->tx_iv32 >> 16) & 0xff,
+ (tkip->tx_iv32 >> 8) & 0xff,
+ tkip->tx_iv32 & 0xff,
+ (tkip->tx_iv16 >> 8) & 0xff,
+ tkip->tx_iv16 & 0xff,
+ (tkip->rx_iv32 >> 24) & 0xff,
+ (tkip->rx_iv32 >> 16) & 0xff,
+ (tkip->rx_iv32 >> 8) & 0xff,
+ tkip->rx_iv32 & 0xff,
+ (tkip->rx_iv16 >> 8) & 0xff,
+ tkip->rx_iv16 & 0xff,
+ tkip->dot11RSNAStatsTKIPReplays,
+ tkip->dot11RSNAStatsTKIPICVErrors,
+ tkip->dot11RSNAStatsTKIPLocalMICFailures);
+ return p;
+}
+
+
+static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
+ .name = "TKIP",
+ .init = ieee80211_tkip_init,
+ .deinit = ieee80211_tkip_deinit,
+ .encrypt_mpdu = ieee80211_tkip_encrypt,
+ .decrypt_mpdu = ieee80211_tkip_decrypt,
+ .encrypt_msdu = ieee80211_michael_mic_add,
+ .decrypt_msdu = ieee80211_michael_mic_verify,
+ .set_key = ieee80211_tkip_set_key,
+ .get_key = ieee80211_tkip_get_key,
+ .print_stats = ieee80211_tkip_print_stats,
+ .extra_prefix_len = 4 + 4, /* IV + ExtIV */
+ .extra_postfix_len = 8 + 4, /* MIC + ICV */
+ .owner = THIS_MODULE,
+};
+
+
+int ieee80211_crypto_tkip_init(void)
+{
+ return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
+}
+
+
+void ieee80211_crypto_tkip_exit(void)
+{
+ ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
+}
+
+
+void ieee80211_tkip_null(void)
+{
+// printk("============>%s()\n", __func__);
+ return;
+}
+
+#if 0
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+EXPORT_SYMBOL(ieee80211_tkip_null);
+#else
+EXPORT_SYMBOL_NOVERS(ieee80211_tkip_null);
+#endif
+#endif
+
+
+//module_init(ieee80211_crypto_tkip_init);
+//module_exit(ieee80211_crypto_tkip_exit);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c
new file mode 100644
index 00000000000..68a22b32fcf
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c
@@ -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", __func__);
+ 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);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c
new file mode 100644
index 00000000000..0c9fef0b4e3
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c
@@ -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
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
new file mode 100644
index 00000000000..23519b37538
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
@@ -0,0 +1,1971 @@
+/*
+ * Original code based Host AP (software wireless LAN access point) driver
+ * for Intersil Prism2/2.5/3 - hostap.o module, common routines
+ *
+ * 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>
+ * 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.
+ ******************************************************************************
+
+ 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/ctype.h>
+
+#include "ieee80211.h"
+#ifdef ENABLE_DOT11D
+#include "dot11d.h"
+#endif
+static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee,
+ struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ u16 fc = le16_to_cpu(hdr->frame_ctl);
+
+ skb->dev = ieee->dev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ skb_reset_mac_header(skb);
+#else
+ skb->mac.raw = skb->data;
+#endif
+ skb_pull(skb, ieee80211_get_hdrlen(fc));
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_80211_RAW);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static struct ieee80211_frag_entry *
+ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq,
+ unsigned int frag, u8 tid,u8 *src, u8 *dst)
+{
+ struct ieee80211_frag_entry *entry;
+ int i;
+
+ for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {
+ entry = &ieee->frag_cache[tid][i];
+ if (entry->skb != NULL &&
+ time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
+ IEEE80211_DEBUG_FRAG(
+ "expiring fragment cache entry "
+ "seq=%u last_frag=%u\n",
+ entry->seq, entry->last_frag);
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+ }
+
+ if (entry->skb != NULL && entry->seq == seq &&
+ (entry->last_frag + 1 == frag || frag == -1) &&
+ memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
+ memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+/* Called only as a tasklet (software IRQ) */
+static struct sk_buff *
+ieee80211_frag_cache_get(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *hdr)
+{
+ struct sk_buff *skb = NULL;
+ u16 fc = le16_to_cpu(hdr->frame_ctl);
+ u16 sc = le16_to_cpu(hdr->seq_ctl);
+ unsigned int frag = WLAN_GET_SEQ_FRAG(sc);
+ unsigned int seq = WLAN_GET_SEQ_SEQ(sc);
+ struct ieee80211_frag_entry *entry;
+ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS;
+ struct ieee80211_hdr_QOS *hdr_4addr_QoS;
+ u8 tid;
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->iw_mode == ieee->iw_ext_mode)
+ {
+ tid = (hdr->addr2[ETH_ALEN-2] ^ hdr->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID;
+ }
+ else
+#endif
+ if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)hdr;
+ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID;
+ tid = UP2AC(tid);
+ tid ++;
+ } else if (IEEE80211_QOS_HAS_SEQ(fc)) {
+ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS *)hdr;
+ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID;
+ tid = UP2AC(tid);
+ tid ++;
+ } else {
+ tid = 0;
+ }
+
+ if (frag == 0) {
+ /* Reserve enough space to fit maximum frame length */
+ skb = dev_alloc_skb(ieee->dev->mtu +
+ sizeof(struct ieee80211_hdr) +
+ 8 /* LLC */ +
+ 2 /* alignment */ +
+ 8 /* WEP */ +
+ ETH_ALEN /* WDS */ +
+ (IEEE80211_QOS_HAS_SEQ(fc)?2:0) /* QOS Control */);
+ if (skb == NULL)
+ return NULL;
+
+ entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]];
+ ieee->frag_next_idx[tid]++;
+ if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN)
+ ieee->frag_next_idx[tid] = 0;
+
+ if (entry->skb != NULL)
+ dev_kfree_skb_any(entry->skb);
+
+ entry->first_frag_time = jiffies;
+ entry->seq = seq;
+ entry->last_frag = frag;
+ entry->skb = skb;
+ memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
+ memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
+ } else {
+ /* received a fragment of a frame for which the head fragment
+ * should have already been received */
+ entry = ieee80211_frag_cache_find(ieee, seq, frag, tid,hdr->addr2,
+ hdr->addr1);
+ if (entry != NULL) {
+ entry->last_frag = frag;
+ skb = entry->skb;
+ }
+ }
+
+ return skb;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *hdr)
+{
+ u16 fc = le16_to_cpu(hdr->frame_ctl);
+ u16 sc = le16_to_cpu(hdr->seq_ctl);
+ unsigned int seq = WLAN_GET_SEQ_SEQ(sc);
+ struct ieee80211_frag_entry *entry;
+ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS;
+ struct ieee80211_hdr_QOS *hdr_4addr_QoS;
+ u8 tid;
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->iw_mode == ieee->iw_ext_mode)
+ {
+ tid = (hdr->addr2[ETH_ALEN-2] ^ hdr->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID;
+ }
+ else
+#endif
+ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)hdr;
+ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID;
+ tid = UP2AC(tid);
+ tid ++;
+ } else if (IEEE80211_QOS_HAS_SEQ(fc)) {
+ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS *)hdr;
+ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID;
+ tid = UP2AC(tid);
+ tid ++;
+ } else {
+ tid = 0;
+ }
+
+ entry = ieee80211_frag_cache_find(ieee, seq, -1, tid,hdr->addr2,
+ hdr->addr1);
+
+ if (entry == NULL) {
+ IEEE80211_DEBUG_FRAG(
+ "could not invalidate fragment cache "
+ "entry (seq=%u)\n", seq);
+ return -1;
+ }
+
+ entry->skb = NULL;
+ return 0;
+}
+
+
+
+/* ieee80211_rx_frame_mgtmt
+ *
+ * Responsible for handling management control frames
+ *
+ * Called by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats, u16 type,
+ u16 stype)
+{
+ struct ieee80211_hdr *hdr;
+
+ // cheat the the hdr type
+ hdr = (struct ieee80211_hdr *)skb->data;
+
+ /* On the struct stats definition there is written that
+ * this is not mandatory.... but seems that the probe
+ * response parser uses it
+ */
+ rx_stats->len = skb->len;
+ ieee80211_rx_mgt(ieee,(struct ieee80211_hdr *)skb->data,rx_stats);
+
+ if((ieee->state == IEEE80211_LINKED)&&(memcmp(hdr->addr3,ieee->current_network.bssid,ETH_ALEN))) {
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ ieee80211_rx_frame_softmac(ieee, skb, rx_stats, type, stype);
+
+ dev_kfree_skb_any(skb);
+
+ return 0;
+
+ #ifdef NOT_YET
+ if (ieee->iw_mode == IW_MODE_MASTER) {
+ printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",
+ ieee->dev->name);
+ return 0;
+/*
+ hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *)
+ skb->data);*/
+ }
+
+ if (ieee->hostapd && type == IEEE80211_TYPE_MGMT) {
+ if (stype == WLAN_FC_STYPE_BEACON &&
+ ieee->iw_mode == IW_MODE_MASTER) {
+ struct sk_buff *skb2;
+ /* Process beacon frames also in kernel driver to
+ * update STA(AP) table statistics */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2)
+ hostap_rx(skb2->dev, skb2, rx_stats);
+ }
+
+ /* send management frames to the user space daemon for
+ * processing */
+ ieee->apdevstats.rx_packets++;
+ ieee->apdevstats.rx_bytes += skb->len;
+ prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);
+ return 0;
+ }
+
+ if (ieee->iw_mode == IW_MODE_MASTER) {
+ if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
+ printk(KERN_DEBUG "%s: unknown management frame "
+ "(type=0x%02x, stype=0x%02x) dropped\n",
+ skb->dev->name, type, stype);
+ return -1;
+ }
+
+ hostap_rx(skb->dev, skb, rx_stats);
+ return 0;
+ }
+
+ printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "
+ "received in non-Host AP mode\n", skb->dev->name);
+ return -1;
+ #endif
+}
+
+
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static unsigned char rfc1042_header[] =
+{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static unsigned char bridge_tunnel_header[] =
+{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+/* No encapsulation header if EtherType < 0x600 (=length) */
+
+/* Called by ieee80211_rx_frame_decrypt */
+static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
+ struct sk_buff *skb, size_t hdrlen)
+{
+ struct net_device *dev = ieee->dev;
+ u16 fc, ethertype;
+ struct ieee80211_hdr *hdr;
+ u8 *pos;
+
+ if (skb->len < 24)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ /* check that the frame is unicast frame to us */
+ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_TODS &&
+ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 &&
+ memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
+ /* ToDS frame with own addr BSSID and DA */
+ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_FROMDS &&
+ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+ /* FromDS frame with own addr as DA */
+ } else
+ return 0;
+
+ if (skb->len < 24 + 8)
+ return 0;
+
+ /* check for port access entity Ethernet type */
+// pos = skb->data + 24;
+ pos = skb->data + hdrlen;
+ ethertype = (pos[6] << 8) | pos[7];
+ if (ethertype == ETH_P_PAE)
+ return 1;
+
+ return 0;
+}
+
+/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
+ struct ieee80211_crypt_data *crypt)
+{
+ struct ieee80211_hdr *hdr;
+ int res, hdrlen;
+
+ if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen))
+ {
+ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb);
+ }
+ else
+#endif
+ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+#ifdef CONFIG_IEEE80211_CRYPT_TKIP
+ if (ieee->tkip_countermeasures &&
+ strcmp(crypt->ops->name, "TKIP") == 0) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+ "received packet from " MAC_FMT "\n",
+ ieee->dev->name, MAC_ARG(hdr->addr2));
+ }
+ return -1;
+ }
+#endif
+
+ atomic_inc(&crypt->refcnt);
+ res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ IEEE80211_DEBUG_DROP(
+ "decryption failed (SA=" MAC_FMT
+ ") res=%d\n", MAC_ARG(hdr->addr2), res);
+ if (res == -2)
+ IEEE80211_DEBUG_DROP("Decryption failed ICV "
+ "mismatch (key %d)\n",
+ skb->data[hdrlen + 3] >> 6);
+ ieee->ieee_stats.rx_discards_undecryptable++;
+ return -1;
+ }
+
+ return res;
+}
+
+
+/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *skb,
+ int keyidx, struct ieee80211_crypt_data *crypt)
+{
+ struct ieee80211_hdr *hdr;
+ int res, hdrlen;
+
+ if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen))
+ {
+ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb);
+ }
+ else
+#endif
+ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+ atomic_inc(&crypt->refcnt);
+ res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
+ " (SA=" MAC_FMT " keyidx=%d)\n",
+ ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* this function is stolen from ipw2200 driver*/
+#define IEEE_PACKET_RETRY_TIME (5*HZ)
+static int is_duplicate_packet(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *header)
+{
+ u16 fc = le16_to_cpu(header->frame_ctl);
+ u16 sc = le16_to_cpu(header->seq_ctl);
+ u16 seq = WLAN_GET_SEQ_SEQ(sc);
+ u16 frag = WLAN_GET_SEQ_FRAG(sc);
+ u16 *last_seq, *last_frag;
+ unsigned long *last_time;
+ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS;
+ struct ieee80211_hdr_QOS *hdr_4addr_QoS;
+ u8 tid;
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->iw_mode == ieee->iw_ext_mode)
+ {
+ tid = (header->addr2[ETH_ALEN-2] ^ header->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID;
+ }
+ else
+#endif
+ //TO2DS and QoS
+ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)header;
+ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID;
+ tid = UP2AC(tid);
+ tid ++;
+ } else if(IEEE80211_QOS_HAS_SEQ(fc)) { //QoS
+ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS*)header;
+ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID;
+ tid = UP2AC(tid);
+ tid ++;
+ } else { // no QoS
+ tid = 0;
+ }
+ switch (ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ {
+ struct list_head *p;
+ struct ieee_ibss_seq *entry = NULL;
+ u8 *mac = header->addr2;
+ int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE;
+ //for (pos = (head)->next; pos != (head); pos = pos->next)
+ __list_for_each(p, &ieee->ibss_mac_hash[index]) {
+ entry = list_entry(p, struct ieee_ibss_seq, list);
+ if (!memcmp(entry->mac, mac, ETH_ALEN))
+ break;
+ }
+ // if (memcmp(entry->mac, mac, ETH_ALEN)){
+ if (p == &ieee->ibss_mac_hash[index]) {
+ entry = kmalloc(sizeof(struct ieee_ibss_seq), GFP_ATOMIC);
+ if (!entry) {
+ printk(KERN_WARNING "Cannot malloc new mac entry\n");
+ return 0;
+ }
+ memcpy(entry->mac, mac, ETH_ALEN);
+ entry->seq_num[tid] = seq;
+ entry->frag_num[tid] = frag;
+ entry->packet_time[tid] = jiffies;
+ list_add(&entry->list, &ieee->ibss_mac_hash[index]);
+ return 0;
+ }
+ last_seq = &entry->seq_num[tid];
+ last_frag = &entry->frag_num[tid];
+ last_time = &entry->packet_time[tid];
+ break;
+ }
+
+ case IW_MODE_INFRA:
+ last_seq = &ieee->last_rxseq_num[tid];
+ last_frag = &ieee->last_rxfrag_num[tid];
+ last_time = &ieee->last_packet_time[tid];
+
+ break;
+ default:
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->iw_mode == ieee->iw_ext_mode)
+ {
+ last_seq = &ieee->last_rxseq_num[tid];
+ last_frag = &ieee->last_rxfrag_num[tid];
+ last_time = &ieee->last_packet_time[tid];
+ break;
+ }
+ else
+#endif
+ return 0;
+ }
+
+// if(tid != 0) {
+// printk(KERN_WARNING ":)))))))))))%x %x %x, fc(%x)\n", tid, *last_seq, seq, header->frame_ctl);
+// }
+ if ((*last_seq == seq) &&
+ time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) {
+ if (*last_frag == frag){
+ //printk(KERN_WARNING "[1] go drop!\n");
+ goto drop;
+
+ }
+ if (*last_frag + 1 != frag)
+ /* out-of-order fragment */
+ //printk(KERN_WARNING "[2] go drop!\n");
+ goto drop;
+ } else
+ *last_seq = seq;
+
+ *last_frag = frag;
+ *last_time = jiffies;
+ return 0;
+
+drop:
+// BUG_ON(!(fc & IEEE80211_FCTL_RETRY));
+// printk("DUP\n");
+
+ return 1;
+}
+
+
+/* All received frames are sent to this function. @skb contains the frame in
+ * IEEE 802.11 format, i.e., in the format it was sent over air.
+ * This function is called only as a tasklet (software IRQ). */
+int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats)
+{
+ struct net_device *dev = ieee->dev;
+ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ struct ieee80211_hdr *hdr;
+ //struct ieee80211_hdr_3addr_QOS *hdr;
+
+ size_t hdrlen;
+ u16 fc, type, stype, sc;
+ struct net_device_stats *stats;
+ unsigned int frag;
+ u8 *payload;
+ u16 ethertype;
+#ifdef NOT_YET
+ struct net_device *wds = NULL;
+ struct sk_buff *skb2 = NULL;
+ struct net_device *wds = NULL;
+ int frame_authorized = 0;
+ int from_assoc_ap = 0;
+ void *sta = NULL;
+#endif
+// u16 QOS_ctl = 0;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ struct ieee80211_crypt_data *crypt = NULL;
+ int keyidx = 0;
+
+ //Added for mesh by Lawrence.
+#ifdef _RTL8187_EXT_PATCH_
+ u8 status;
+ u32 flags;
+#endif
+ // cheat the the hdr type
+ hdr = (struct ieee80211_hdr *)skb->data;
+ stats = &ieee->stats;
+
+ if (skb->len < 10) {
+ printk(KERN_INFO "%s: SKB length < 10\n",
+ dev->name);
+ goto rx_dropped;
+ }
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+ sc = le16_to_cpu(hdr->seq_ctl);
+
+ frag = WLAN_GET_SEQ_FRAG(sc);
+
+//YJ,add,080828,for keep alive
+ if((fc & IEEE80211_FCTL_TODS) != IEEE80211_FCTL_TODS)
+ {
+ if(!memcmp(hdr->addr1,dev->dev_addr, ETH_ALEN))
+ {
+ ieee->NumRxUnicast++;
+ }
+ }
+ else
+ {
+ if(!memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN))
+ {
+ ieee->NumRxUnicast++;
+ }
+ }
+//YJ,add,080828,for keep alive,end
+
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen))
+ {
+ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb);
+ if(skb->len < hdrlen)
+ goto rx_dropped;
+ }
+ else
+#endif
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+#ifdef NOT_YET
+#if WIRELESS_EXT > 15
+ /* Put this code here so that we avoid duplicating it in all
+ * Rx paths. - Jean II */
+#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
+ /* If spy monitoring on */
+ if (iface->spy_data.spy_number > 0) {
+ struct iw_quality wstats;
+ wstats.level = rx_stats->signal;
+ wstats.noise = rx_stats->noise;
+ wstats.updated = 6; /* No qual value */
+ /* Update spy records */
+ wireless_spy_update(dev, hdr->addr2, &wstats);
+ }
+#endif /* IW_WIRELESS_SPY */
+#endif /* WIRELESS_EXT > 15 */
+ hostap_update_rx_stats(local->ap, hdr, rx_stats);
+#endif
+
+#if WIRELESS_EXT > 15
+ if (ieee->iw_mode == IW_MODE_MONITOR) {
+ ieee80211_monitor_rx(ieee, skb, rx_stats);
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+ return 1;
+ }
+#endif
+ if (ieee->host_decrypt) {
+ int idx = 0;
+ if (skb->len >= hdrlen + 3)
+ idx = skb->data[hdrlen + 3] >> 6;
+ crypt = ieee->crypt[idx];
+#ifdef NOT_YET
+ sta = NULL;
+
+ /* Use station specific key to override default keys if the
+ * receiver address is a unicast address ("individual RA"). If
+ * bcrx_sta_key parameter is set, station specific key is used
+ * even with broad/multicast targets (this is against IEEE
+ * 802.11, but makes it easier to use different keys with
+ * stations that do not support WEP key mapping). */
+
+ if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
+ (void) hostap_handle_sta_crypto(local, hdr, &crypt,
+ &sta);
+#endif
+
+ /* allow NULL decrypt to indicate an station specific override
+ * for default encryption */
+ if (crypt && (crypt->ops == NULL ||
+ crypt->ops->decrypt_mpdu == NULL))
+ crypt = NULL;
+
+ if (!crypt && (fc & IEEE80211_FCTL_WEP)) {
+ /* This seems to be triggered by some (multicast?)
+ * frames from other than current BSS, so just drop the
+ * frames silently instead of filling system log with
+ * these reports. */
+ IEEE80211_DEBUG_DROP("Decryption failed (not set)"
+ " (SA=" MAC_FMT ")\n",
+ MAC_ARG(hdr->addr2));
+ ieee->ieee_stats.rx_discards_undecryptable++;
+ goto rx_dropped;
+ }
+ }
+
+ if (skb->len < IEEE80211_DATA_HDR3_LEN)
+ goto rx_dropped;
+
+#ifdef _RTL8187_EXT_PATCH_
+ if( ieee->iw_mode == ieee->iw_ext_mode && ieee->ext_patch_ieee80211_rx_mgt_update_expire )
+ ieee->ext_patch_ieee80211_rx_mgt_update_expire( ieee, skb );
+#endif
+
+ // if QoS enabled, should check the sequence for each of the AC
+ if (is_duplicate_packet(ieee, hdr))
+ goto rx_dropped;
+
+
+ if (type == IEEE80211_FTYPE_MGMT) {
+
+ #if 0
+ if ( stype == IEEE80211_STYPE_AUTH &&
+ fc & IEEE80211_FCTL_WEP && ieee->host_decrypt &&
+ (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0)
+ {
+ printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
+ "from " MAC_FMT "\n", dev->name,
+ MAC_ARG(hdr->addr2));
+ /* TODO: could inform hostapd about this so that it
+ * could send auth failure report */
+ goto rx_dropped;
+ }
+ #endif
+
+
+ if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
+ goto rx_dropped;
+ else
+ goto rx_exit;
+ }
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_on_rx)
+ {
+ if(ieee->ext_patch_ieee80211_rx_on_rx(ieee, skb, rx_stats, type, stype)==0)
+ {
+ goto rx_exit;
+ }
+ }
+#endif
+
+ /* Data frame - extract src/dst addresses */
+ switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+ case IEEE80211_FCTL_FROMDS:
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr3, ETH_ALEN);
+ memcpy(bssid,hdr->addr2,ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_TODS:
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+ memcpy(bssid,hdr->addr1,ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+ if (skb->len < IEEE80211_DATA_HDR4_LEN)
+ goto rx_dropped;
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr4, ETH_ALEN);
+ memcpy(bssid, ieee->current_network.bssid, ETH_ALEN);
+ break;
+ case 0:
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+ memcpy(bssid,hdr->addr3,ETH_ALEN);
+ break;
+ }
+
+#ifdef NOT_YET
+ if (hostap_rx_frame_wds(ieee, hdr, fc, &wds))
+ goto rx_dropped;
+ if (wds) {
+ skb->dev = dev = wds;
+ stats = hostap_get_stats(dev);
+ }
+
+ if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
+ (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS &&
+ ieee->stadev &&
+ memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) {
+ /* Frame from BSSID of the AP for which we are a client */
+ skb->dev = dev = ieee->stadev;
+ stats = hostap_get_stats(dev);
+ from_assoc_ap = 1;
+ }
+#endif
+
+ dev->last_rx = jiffies;
+
+#ifdef NOT_YET
+ if ((ieee->iw_mode == IW_MODE_MASTER ||
+ ieee->iw_mode == IW_MODE_REPEAT) &&
+ !from_assoc_ap) {
+ switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
+ wds != NULL)) {
+ case AP_RX_CONTINUE_NOT_AUTHORIZED:
+ frame_authorized = 0;
+ break;
+ case AP_RX_CONTINUE:
+ frame_authorized = 1;
+ break;
+ case AP_RX_DROP:
+ goto rx_dropped;
+ case AP_RX_EXIT:
+ goto rx_exit;
+ }
+ }
+#endif
+
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_is_valid_framectl)
+ {
+ if(ieee->ext_patch_ieee80211_rx_is_valid_framectl(ieee, fc, type, stype)==0)
+ goto rx_dropped;
+ }
+ else
+#endif
+ /* Nullfunc frames may have PS-bit set, so they must be passed to
+ * hostap_handle_sta_rx() before being dropped here. */
+ if (stype != IEEE80211_STYPE_DATA &&
+ stype != IEEE80211_STYPE_DATA_CFACK &&
+ stype != IEEE80211_STYPE_DATA_CFPOLL &&
+ stype != IEEE80211_STYPE_DATA_CFACKPOLL&&
+ stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4
+ ) {
+ if (stype != IEEE80211_STYPE_NULLFUNC)
+ IEEE80211_DEBUG_DROP(
+ "RX: dropped data frame "
+ "with no data (type=0x%02x, "
+ "subtype=0x%02x, len=%d)\n",
+ type, stype, skb->len);
+ goto rx_dropped;
+ }
+ if(memcmp(bssid,ieee->current_network.bssid,ETH_ALEN)) {
+ goto rx_dropped;
+ }
+
+ ieee->NumRxDataInPeriod++;
+ ieee->NumRxOkTotal++;
+ /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
+
+ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) &&
+ (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
+ goto rx_dropped;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ /* skb: hdr + (possibly fragmented) plaintext payload */
+ // PR: FIXME: hostap has additional conditions in the "if" below:
+ // ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) &&
+ if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
+ int flen;
+ struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
+ IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
+
+ if (!frag_skb) {
+ IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG,
+ "Rx cannot get skb from fragment "
+ "cache (morefrag=%d seq=%u frag=%u)\n",
+ (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
+ WLAN_GET_SEQ_SEQ(sc), frag);
+ goto rx_dropped;
+ }
+ flen = skb->len;
+ if (frag != 0)
+ flen -= hdrlen;
+
+ if (frag_skb->tail + flen > frag_skb->end) {
+ printk(KERN_WARNING "%s: host decrypted and "
+ "reassembled frame did not fit skb\n",
+ dev->name);
+ ieee80211_frag_cache_invalidate(ieee, hdr);
+ goto rx_dropped;
+ }
+
+ if (frag == 0) {
+ /* copy first fragment (including full headers) into
+ * beginning of the fragment cache skb */
+ memcpy(skb_put(frag_skb, flen), skb->data, flen);
+ } else {
+ /* append frame payload to the end of the fragment
+ * cache skb */
+ memcpy(skb_put(frag_skb, flen), skb->data + hdrlen,
+ flen);
+ }
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+
+ if (fc & IEEE80211_FCTL_MOREFRAGS) {
+ /* more fragments expected - leave the skb in fragment
+ * cache for now; it will be delivered to upper layers
+ * after all fragments have been received */
+ goto rx_exit;
+ }
+
+ /* this was the last fragment and the frame will be
+ * delivered, so remove skb from fragment cache */
+ skb = frag_skb;
+ hdr = (struct ieee80211_hdr *) skb->data;
+ ieee80211_frag_cache_invalidate(ieee, hdr);
+ }
+
+ /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
+ * encrypted/authenticated */
+ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) &&
+ ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
+ goto rx_dropped;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) {
+ if (/*ieee->ieee802_1x &&*/
+ ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
+
+#ifdef CONFIG_IEEE80211_DEBUG
+ /* pass unencrypted EAPOL frames even if encryption is
+ * configured */
+ struct eapol *eap = (struct eapol *)(skb->data +
+ 24);
+ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n",
+ eap_get_type(eap->type));
+#endif
+ } else {
+ IEEE80211_DEBUG_DROP(
+ "encryption configured, but RX "
+ "frame not encrypted (SA=" MAC_FMT ")\n",
+ MAC_ARG(hdr->addr2));
+ goto rx_dropped;
+ }
+ }
+
+#ifdef CONFIG_IEEE80211_DEBUG
+ if (crypt && !(fc & IEEE80211_FCTL_WEP) &&
+ ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
+ struct eapol *eap = (struct eapol *)(skb->data +
+ 24);
+ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n",
+ eap_get_type(eap->type));
+ }
+#endif
+
+ if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep &&
+ !ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
+ IEEE80211_DEBUG_DROP(
+ "dropped unencrypted RX data "
+ "frame from " MAC_FMT
+ " (drop_unencrypted=1)\n",
+ MAC_ARG(hdr->addr2));
+ goto rx_dropped;
+ }
+/*
+ if(ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
+ printk(KERN_WARNING "RX: IEEE802.1X EPAOL frame!\n");
+ }
+*/
+ /* skb: hdr + (possible reassembled) full plaintext payload */
+ payload = skb->data + hdrlen;
+ ethertype = (payload[6] << 8) | payload[7];
+
+#ifdef NOT_YET
+ /* If IEEE 802.1X is used, check whether the port is authorized to send
+ * the received frame. */
+ if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) {
+ if (ethertype == ETH_P_PAE) {
+ printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n",
+ dev->name);
+ if (ieee->hostapd && ieee->apdev) {
+ /* Send IEEE 802.1X frames to the user
+ * space daemon for processing */
+ prism2_rx_80211(ieee->apdev, skb, rx_stats,
+ PRISM2_RX_MGMT);
+ ieee->apdevstats.rx_packets++;
+ ieee->apdevstats.rx_bytes += skb->len;
+ goto rx_exit;
+ }
+ } else if (!frame_authorized) {
+ printk(KERN_DEBUG "%s: dropped frame from "
+ "unauthorized port (IEEE 802.1X): "
+ "ethertype=0x%04x\n",
+ dev->name, ethertype);
+ goto rx_dropped;
+ }
+ }
+#endif
+
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_process_dataframe)
+ {
+ //Added for mesh rx interrupt.
+ //spin_lock_irqsave(&ieee->lock,flags);
+ status = ieee->ext_patch_ieee80211_rx_process_dataframe(ieee, skb, rx_stats);
+ //spin_unlock_irqrestore(&ieee->lock,flags);
+
+ if(status)
+// if(ieee->ext_patch_ieee80211_rx_process_dataframe(ieee, skb, rx_stats))
+ goto rx_exit;
+ else
+ goto rx_dropped;
+ }
+#endif
+
+ /* convert hdr + possible LLC headers into Ethernet header */
+ if (skb->len - hdrlen >= 8 &&
+ ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 &&
+ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+ memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and
+ * replace EtherType */
+ skb_pull(skb, hdrlen + SNAP_SIZE);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ } else {
+ u16 len;
+ /* Leave Ethernet header part of hdr and full payload */
+ skb_pull(skb, hdrlen);
+ len = htons(skb->len);
+ memcpy(skb_push(skb, 2), &len, 2);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ }
+
+#ifdef NOT_YET
+ if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_TODS) &&
+ skb->len >= ETH_HLEN + ETH_ALEN) {
+ /* Non-standard frame: get addr4 from its bogus location after
+ * the payload */
+ memcpy(skb->data + ETH_ALEN,
+ skb->data + skb->len - ETH_ALEN, ETH_ALEN);
+ skb_trim(skb, skb->len - ETH_ALEN);
+ }
+#endif
+
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+
+#ifdef NOT_YET
+ if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
+ ieee->ap->bridge_packets) {
+ if (dst[0] & 0x01) {
+ /* copy multicast frame both to the higher layers and
+ * to the wireless media */
+ ieee->ap->bridged_multicast++;
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ printk(KERN_DEBUG "%s: skb_clone failed for "
+ "multicast frame\n", dev->name);
+ } else if (hostap_is_sta_assoc(ieee->ap, dst)) {
+ /* send frame directly to the associated STA using
+ * wireless media and not passing to higher layers */
+ ieee->ap->bridged_unicast++;
+ skb2 = skb;
+ skb = NULL;
+ }
+ }
+
+ if (skb2 != NULL) {
+ /* send to wireless media */
+ skb2->protocol = __constant_htons(ETH_P_802_3);
+ skb2->mac.raw = skb2->nh.raw = skb2->data;
+ /* skb2->nh.raw = skb2->data + ETH_HLEN; */
+ skb2->dev = dev;
+ dev_queue_xmit(skb2);
+ }
+
+#endif
+ if (skb) {
+ skb->protocol = eth_type_trans(skb, dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
+ ieee->last_rx_ps_time = jiffies;
+ netif_rx(skb);
+ }
+
+ rx_exit:
+#ifdef NOT_YET
+ if (sta)
+ hostap_handle_sta_release(sta);
+#endif
+ return 1;
+
+ rx_dropped:
+ stats->rx_dropped++;
+
+ /* Returning 0 indicates to caller that we have not handled the SKB--
+ * so it is still allocated and can be used again by underlying
+ * hardware as a DMA target */
+ return 0;
+}
+
+#ifdef _RTL8187_EXT_PATCH_
+int ieee_ext_skb_p80211_to_ether(struct sk_buff *skb, int hdrlen, u8 *dst, u8 *src)
+{
+ u8 *payload;
+ u16 ethertype;
+
+ /* skb: hdr + (possible reassembled) full plaintext payload */
+ payload = skb->data + hdrlen;
+ ethertype = (payload[6] << 8) | payload[7];
+
+ /* convert hdr + possible LLC headers into Ethernet header */
+ if (skb->len - hdrlen >= 8 &&
+ ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 &&
+ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+ memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and
+ * replace EtherType */
+ skb_pull(skb, hdrlen + SNAP_SIZE);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ } else {
+ u16 len;
+ /* Leave Ethernet header part of hdr and full payload */
+ skb_pull(skb, hdrlen);
+ len = htons(skb->len);
+ memcpy(skb_push(skb, 2), &len, 2);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ }
+
+ return 1;
+}
+#endif // _RTL8187_EXT_PATCH_
+
+
+#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
+
+static inline int ieee80211_is_ofdm_rate(u8 rate)
+{
+ switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
+ case IEEE80211_OFDM_RATE_6MB:
+ case IEEE80211_OFDM_RATE_9MB:
+ case IEEE80211_OFDM_RATE_12MB:
+ case IEEE80211_OFDM_RATE_18MB:
+ case IEEE80211_OFDM_RATE_24MB:
+ case IEEE80211_OFDM_RATE_36MB:
+ case IEEE80211_OFDM_RATE_48MB:
+ case IEEE80211_OFDM_RATE_54MB:
+ return 1;
+ }
+ return 0;
+}
+
+static inline int ieee80211_SignalStrengthTranslate(
+ int CurrSS
+ )
+{
+ int RetSS;
+
+ // Step 1. Scale mapping.
+ if(CurrSS >= 71 && CurrSS <= 100)
+ {
+ RetSS = 90 + ((CurrSS - 70) / 3);
+ }
+ else if(CurrSS >= 41 && CurrSS <= 70)
+ {
+ RetSS = 78 + ((CurrSS - 40) / 3);
+ }
+ else if(CurrSS >= 31 && CurrSS <= 40)
+ {
+ RetSS = 66 + (CurrSS - 30);
+ }
+ else if(CurrSS >= 21 && CurrSS <= 30)
+ {
+ RetSS = 54 + (CurrSS - 20);
+ }
+ else if(CurrSS >= 5 && CurrSS <= 20)
+ {
+ RetSS = 42 + (((CurrSS - 5) * 2) / 3);
+ }
+ else if(CurrSS == 4)
+ {
+ RetSS = 36;
+ }
+ else if(CurrSS == 3)
+ {
+ RetSS = 27;
+ }
+ else if(CurrSS == 2)
+ {
+ RetSS = 18;
+ }
+ else if(CurrSS == 1)
+ {
+ RetSS = 9;
+ }
+ else
+ {
+ RetSS = CurrSS;
+ }
+ //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS));
+
+ // Step 2. Smoothing.
+
+ //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS));
+
+ return RetSS;
+}
+
+#ifdef ENABLE_DOT11D
+static inline void ieee80211_extract_country_ie(
+ struct ieee80211_device *ieee,
+ struct ieee80211_info_element *info_element,
+ struct ieee80211_network *network,
+ u8 * addr2
+)
+{
+#if 0
+ u32 i = 0;
+ u8 * p = (u8*)info_element->data;
+ printk("-----------------------\n");
+ printk("%s Country IE:", network->ssid);
+ for(i=0; i<info_element->len; i++)
+ printk("\t%2.2x", *(p+i));
+ printk("\n-----------------------\n");
+#endif
+ if(IS_DOT11D_ENABLE(ieee))
+ {
+ if(info_element->len!= 0)
+ {
+ memcpy(network->CountryIeBuf, info_element->data, info_element->len);
+ network->CountryIeLen = info_element->len;
+
+ if(!IS_COUNTRY_IE_VALID(ieee))
+ {
+ Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data);
+ }
+ }
+
+ //
+ // 070305, rcnjko: I update country IE watch dog here because
+ // some AP (e.g. Cisco 1242) don't include country IE in their
+ // probe response frame.
+ //
+ if(IS_EQUAL_CIE_SRC(ieee, addr2) )
+ {
+ UPDATE_CIE_WATCHDOG(ieee);
+ }
+ }
+
+}
+#endif
+
+int
+ieee80211_TranslateToDbm(
+ unsigned char SignalStrengthIndex // 0-100 index.
+ )
+{
+ unsigned char SignalPower; // in dBm.
+
+ // Translate to dBm (x=0.5y-95).
+ SignalPower = (int)SignalStrengthIndex * 7 / 10;
+ SignalPower -= 95;
+
+ return SignalPower;
+}
+inline int ieee80211_network_init(
+ struct ieee80211_device *ieee,
+ struct ieee80211_probe_response *beacon,
+ struct ieee80211_network *network,
+ struct ieee80211_rx_stats *stats)
+{
+#ifdef CONFIG_IEEE80211_DEBUG
+ char rates_str[64];
+ char *p;
+#endif
+ struct ieee80211_info_element *info_element;
+ u16 left;
+ u8 i;
+ short offset;
+ u8 curRate = 0,hOpRate = 0,curRate_ex = 0;
+
+ /* Pull out fixed field data */
+ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
+ network->capability = beacon->capability;
+ network->last_scanned = jiffies;
+ network->time_stamp[0] = beacon->time_stamp[0];
+ network->time_stamp[1] = beacon->time_stamp[1];
+ network->beacon_interval = beacon->beacon_interval;
+ /* Where to pull this? beacon->listen_interval;*/
+ network->listen_interval = 0x0A;
+ network->rates_len = network->rates_ex_len = 0;
+ network->last_associate = 0;
+ network->ssid_len = 0;
+ network->flags = 0;
+ network->atim_window = 0;
+ network->QoS_Enable = 0;
+//by amy 080312
+ network->HighestOperaRate = 0;
+//by amy 080312
+#ifdef THOMAS_TURBO
+ network->Turbo_Enable = 0;
+#endif
+#ifdef ENABLE_DOT11D
+ network->CountryIeLen = 0;
+ memset(network->CountryIeBuf, 0, MAX_IE_LEN);
+#endif
+
+ if (stats->freq == IEEE80211_52GHZ_BAND) {
+ /* for A band (No DS info) */
+ network->channel = stats->received_channel;
+ } else
+ network->flags |= NETWORK_HAS_CCK;
+
+ network->wpa_ie_len = 0;
+ network->rsn_ie_len = 0;
+
+ info_element = &beacon->info_element;
+ left = stats->len - ((void *)info_element - (void *)beacon);
+ while (left >= sizeof(struct ieee80211_info_element_hdr)) {
+ if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) {
+ IEEE80211_DEBUG_SCAN("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%d left=%d.\n",
+ info_element->len + sizeof(struct ieee80211_info_element),
+ left);
+ return 1;
+ }
+
+ switch (info_element->id) {
+ case MFIE_TYPE_SSID:
+ if (ieee80211_is_empty_essid(info_element->data,
+ info_element->len)) {
+ network->flags |= NETWORK_EMPTY_ESSID;
+ break;
+ }
+
+ network->ssid_len = min(info_element->len,
+ (u8)IW_ESSID_MAX_SIZE);
+ memcpy(network->ssid, info_element->data, network->ssid_len);
+ if (network->ssid_len < IW_ESSID_MAX_SIZE)
+ memset(network->ssid + network->ssid_len, 0,
+ IW_ESSID_MAX_SIZE - network->ssid_len);
+
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n",
+ network->ssid, network->ssid_len);
+ break;
+
+ case MFIE_TYPE_RATES:
+#ifdef CONFIG_IEEE80211_DEBUG
+ p = rates_str;
+#endif
+ network->rates_len = min(info_element->len, MAX_RATES_LENGTH);
+ for (i = 0; i < network->rates_len; i++) {
+ network->rates[i] = info_element->data[i];
+ curRate = network->rates[i] & 0x7f;
+ if( hOpRate < curRate )
+ hOpRate = curRate;
+#ifdef CONFIG_IEEE80211_DEBUG
+ p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]);
+#endif
+ if (ieee80211_is_ofdm_rate(info_element->data[i])) {
+ network->flags |= NETWORK_HAS_OFDM;
+ if (info_element->data[i] &
+ IEEE80211_BASIC_RATE_MASK)
+ network->flags &=
+ ~NETWORK_HAS_CCK;
+ }
+ }
+
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n",
+ rates_str, network->rates_len);
+ break;
+
+ case MFIE_TYPE_RATES_EX:
+#ifdef CONFIG_IEEE80211_DEBUG
+ p = rates_str;
+#endif
+ network->rates_ex_len = min(info_element->len, MAX_RATES_EX_LENGTH);
+ for (i = 0; i < network->rates_ex_len; i++) {
+ network->rates_ex[i] = info_element->data[i];
+ curRate_ex = network->rates_ex[i] & 0x7f;
+ if( hOpRate < curRate_ex )
+ hOpRate = curRate_ex;
+#ifdef CONFIG_IEEE80211_DEBUG
+ p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]);
+#endif
+ if (ieee80211_is_ofdm_rate(info_element->data[i])) {
+ network->flags |= NETWORK_HAS_OFDM;
+ if (info_element->data[i] &
+ IEEE80211_BASIC_RATE_MASK)
+ network->flags &=
+ ~NETWORK_HAS_CCK;
+ }
+ }
+
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
+ rates_str, network->rates_ex_len);
+ break;
+
+ case MFIE_TYPE_DS_SET:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n",
+ info_element->data[0]);
+ if (stats->freq == IEEE80211_24GHZ_BAND)
+ network->channel = info_element->data[0];
+ break;
+
+ case MFIE_TYPE_FH_SET:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n");
+ break;
+
+ case MFIE_TYPE_CF_SET:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n");
+ break;
+
+ case MFIE_TYPE_TIM:
+
+ if(info_element->len < 4)
+ break;
+
+ network->dtim_period = info_element->data[1];
+
+ if(ieee->state != IEEE80211_LINKED)
+ break;
+#if 0
+ network->last_dtim_sta_time[0] = stats->mac_time[0];
+#else
+ network->last_dtim_sta_time[0] = jiffies;
+#endif
+ network->last_dtim_sta_time[1] = stats->mac_time[1];
+
+ network->dtim_data = IEEE80211_DTIM_VALID;
+
+ if(info_element->data[0] != 0)
+ break;
+
+ if(info_element->data[2] & 1)
+ network->dtim_data |= IEEE80211_DTIM_MBCAST;
+
+ offset = (info_element->data[2] >> 1)*2;
+
+ //printk("offset1:%x aid:%x\n",offset, ieee->assoc_id);
+
+ /* add and modified for ps 2008.1.22 */
+ if(ieee->assoc_id < 8*offset ||
+ ieee->assoc_id > 8*(offset + info_element->len -3)) {
+ break;
+ }
+
+ offset = (ieee->assoc_id/8) - offset;// + ((aid % 8)? 0 : 1) ;
+
+ // printk("offset:%x data:%x, ucast:%d\n", offset,
+ // info_element->data[3+offset] ,
+ // info_element->data[3+offset] & (1<<(ieee->assoc_id%8)));
+
+ if(info_element->data[3+offset] & (1<<(ieee->assoc_id%8))) {
+ network->dtim_data |= IEEE80211_DTIM_UCAST;
+ }
+ break;
+
+ case MFIE_TYPE_IBSS_SET:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n");
+ break;
+
+ case MFIE_TYPE_CHALLENGE:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n");
+ break;
+
+ case MFIE_TYPE_GENERIC:
+ //nic is 87B
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n",
+ info_element->len);
+ if (info_element->len >= 4 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0x50 &&
+ info_element->data[2] == 0xf2 &&
+ info_element->data[3] == 0x01) {
+ network->wpa_ie_len = min(info_element->len + 2,
+ MAX_WPA_IE_LEN);
+ memcpy(network->wpa_ie, info_element,
+ network->wpa_ie_len);
+ }
+
+#ifdef THOMAS_TURBO
+ if (info_element->len == 7 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0xe0 &&
+ info_element->data[2] == 0x4c &&
+ info_element->data[3] == 0x01 &&
+ info_element->data[4] == 0x02) {
+ network->Turbo_Enable = 1;
+ }
+#endif
+ if (1 == stats->nic_type) {//nic 87
+ break;
+ }
+
+ if (info_element->len >= 5 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0x50 &&
+ info_element->data[2] == 0xf2 &&
+ info_element->data[3] == 0x02 &&
+ info_element->data[4] == 0x00) {
+ //printk(KERN_WARNING "wmm info updated: %x\n", info_element->data[6]);
+ //WMM Information Element
+ network->wmm_info = info_element->data[6];
+ network->QoS_Enable = 1;
+ }
+
+ if (info_element->len >= 8 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0x50 &&
+ info_element->data[2] == 0xf2 &&
+ info_element->data[3] == 0x02 &&
+ info_element->data[4] == 0x01) {
+ // Not care about version at present.
+ //WMM Information Element
+ //printk(KERN_WARNING "wmm info&param updated: %x\n", info_element->data[6]);
+ network->wmm_info = info_element->data[6];
+ //WMM Parameter Element
+ memcpy(network->wmm_param, (u8 *)(info_element->data + 8),(info_element->len - 8));
+ network->QoS_Enable = 1;
+ }
+ break;
+
+ case MFIE_TYPE_RSN:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n",
+ info_element->len);
+ network->rsn_ie_len = min(info_element->len + 2,
+ MAX_WPA_IE_LEN);
+ memcpy(network->rsn_ie, info_element,
+ network->rsn_ie_len);
+ break;
+#ifdef ENABLE_DOT11D
+ case MFIE_TYPE_COUNTRY:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n",
+ info_element->len);
+// printk("=====>Receive <%s> Country IE\n",network->ssid);
+ ieee80211_extract_country_ie(ieee, info_element, network, beacon->header.addr2);
+ break;
+#endif
+ default:
+ IEEE80211_DEBUG_SCAN("unsupported IE %d\n",
+ info_element->id);
+ break;
+ }
+
+ left -= sizeof(struct ieee80211_info_element_hdr) +
+ info_element->len;
+ info_element = (struct ieee80211_info_element *)
+ &info_element->data[info_element->len];
+ }
+//by amy 080312
+ network->HighestOperaRate = hOpRate;
+//by amy 080312
+ network->mode = 0;
+ if (stats->freq == IEEE80211_52GHZ_BAND)
+ network->mode = IEEE_A;
+ else {
+ if (network->flags & NETWORK_HAS_OFDM)
+ network->mode |= IEEE_G;
+ if (network->flags & NETWORK_HAS_CCK)
+ network->mode |= IEEE_B;
+ }
+
+ if (network->mode == 0) {
+ IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' "
+ "network.\n",
+ escape_essid(network->ssid,
+ network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 1;
+ }
+
+ if (ieee80211_is_empty_essid(network->ssid, network->ssid_len))
+ network->flags |= NETWORK_EMPTY_ESSID;
+#if 0
+ stats->signal = ieee80211_SignalStrengthTranslate(stats->signal);
+#endif
+ stats->signal = ieee80211_TranslateToDbm(stats->signalstrength);
+ //stats->noise = stats->signal - stats->noise;
+ stats->noise = ieee80211_TranslateToDbm(100 - stats->signalstrength) - 25;
+ memcpy(&network->stats, stats, sizeof(network->stats));
+
+ return 0;
+}
+
+static inline int is_same_network(struct ieee80211_network *src,
+ struct ieee80211_network *dst,
+ struct ieee80211_device * ieee)
+{
+ /* A network is only a duplicate if the channel, BSSID, ESSID
+ * and the capability field (in particular IBSS and BSS) all match.
+ * We treat all <hidden> with the same BSSID and channel
+ * as one network */
+ return (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap
+ //((src->ssid_len == dst->ssid_len) &&
+ (src->channel == dst->channel) &&
+ !memcmp(src->bssid, dst->bssid, ETH_ALEN) &&
+ (!memcmp(src->ssid, dst->ssid, src->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap
+ //!memcmp(src->ssid, dst->ssid, src->ssid_len) &&
+ ((src->capability & WLAN_CAPABILITY_IBSS) ==
+ (dst->capability & WLAN_CAPABILITY_IBSS)) &&
+ ((src->capability & WLAN_CAPABILITY_BSS) ==
+ (dst->capability & WLAN_CAPABILITY_BSS)));
+}
+
+inline void update_network(struct ieee80211_network *dst,
+ struct ieee80211_network *src)
+{
+ unsigned char quality = src->stats.signalstrength;
+ unsigned char signal = 0;
+ unsigned char noise = 0;
+ if(dst->stats.signalstrength > 0) {
+ quality = (dst->stats.signalstrength * 5 + src->stats.signalstrength + 5)/6;
+ }
+ signal = ieee80211_TranslateToDbm(quality);
+ //noise = signal - src->stats.noise;
+ if(dst->stats.noise > 0)
+ noise = (dst->stats.noise * 5 + src->stats.noise)/6;
+ //if(strcmp(dst->ssid, "linksys_lzm000") == 0)
+// printk("ssid:%s, quality:%d, signal:%d\n", dst->ssid, quality, signal);
+ memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
+ dst->stats.signalstrength = quality;
+ dst->stats.signal = signal;
+// printk("==================>stats.signal is %d\n",dst->stats.signal);
+ dst->stats.noise = noise;
+
+
+ dst->capability = src->capability;
+ memcpy(dst->rates, src->rates, src->rates_len);
+ dst->rates_len = src->rates_len;
+ memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
+ dst->rates_ex_len = src->rates_ex_len;
+ dst->HighestOperaRate= src->HighestOperaRate;
+ //printk("==========>in %s: src->ssid is %s,chan is %d\n",__func__,src->ssid,src->channel);
+
+ //YJ,add,080819,for hidden ap
+ if(src->ssid_len > 0)
+ {
+ //if(src->ssid_len == 13)
+ // printk("=====================>>>>>>>> Dst ssid: %s Src ssid: %s\n", dst->ssid, src->ssid);
+ memset(dst->ssid, 0, dst->ssid_len);
+ dst->ssid_len = src->ssid_len;
+ memcpy(dst->ssid, src->ssid, src->ssid_len);
+ }
+ //YJ,add,080819,for hidden ap,end
+
+ dst->channel = src->channel;
+ dst->mode = src->mode;
+ dst->flags = src->flags;
+ dst->time_stamp[0] = src->time_stamp[0];
+ dst->time_stamp[1] = src->time_stamp[1];
+
+ dst->beacon_interval = src->beacon_interval;
+ dst->listen_interval = src->listen_interval;
+ dst->atim_window = src->atim_window;
+ dst->dtim_period = src->dtim_period;
+ dst->dtim_data = src->dtim_data;
+ dst->last_dtim_sta_time[0] = src->last_dtim_sta_time[0];
+ dst->last_dtim_sta_time[1] = src->last_dtim_sta_time[1];
+// printk("update:%s, dtim_period:%x, dtim_data:%x\n", src->ssid, src->dtim_period, src->dtim_data);
+ memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
+ dst->wpa_ie_len = src->wpa_ie_len;
+ memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
+ dst->rsn_ie_len = src->rsn_ie_len;
+
+ dst->last_scanned = jiffies;
+ /* dst->last_associate is not overwritten */
+// disable QoS process now, added by David 2006/7/25
+#if 1
+ dst->wmm_info = src->wmm_info; //sure to exist in beacon or probe response frame.
+/*
+ if((dst->wmm_info^src->wmm_info)&0x0f) {//Param Set Count change, update Parameter
+ memcpy(dst->wmm_param, src->wmm_param, IEEE80211_AC_PRAM_LEN);
+ }
+*/
+ if(src->wmm_param[0].ac_aci_acm_aifsn|| \
+ src->wmm_param[1].ac_aci_acm_aifsn|| \
+ src->wmm_param[2].ac_aci_acm_aifsn|| \
+ src->wmm_param[1].ac_aci_acm_aifsn) {
+ memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN);
+ }
+ dst->QoS_Enable = src->QoS_Enable;
+#else
+ dst->QoS_Enable = 1;//for Rtl8187 simulation
+#endif
+ dst->SignalStrength = src->SignalStrength;
+#ifdef THOMAS_TURBO
+ dst->Turbo_Enable = src->Turbo_Enable;
+#endif
+#ifdef ENABLE_DOT11D
+ dst->CountryIeLen = src->CountryIeLen;
+ memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen);
+#endif
+}
+
+
+inline void ieee80211_process_probe_response(
+ struct ieee80211_device *ieee,
+ struct ieee80211_probe_response *beacon,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ieee80211_network network;
+ struct ieee80211_network *target;
+ struct ieee80211_network *oldest = NULL;
+#ifdef CONFIG_IEEE80211_DEBUG
+ struct ieee80211_info_element *info_element = &beacon->info_element;
+#endif
+ unsigned long flags;
+ short renew;
+ u8 wmm_info;
+ u8 is_beacon = (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_BEACON)? 1:0; //YJ,add,080819,for hidden ap
+
+ memset(&network, 0, sizeof(struct ieee80211_network));
+//rz
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_process_probe_response_1) {
+ ieee->ext_patch_ieee80211_process_probe_response_1(ieee, beacon, stats);
+ return;
+ }
+#endif
+
+ IEEE80211_DEBUG_SCAN(
+ "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+ escape_essid(info_element->data, info_element->len),
+ MAC_ARG(beacon->header.addr3),
+ (beacon->capability & (1<<0xf)) ? '1' : '0',
+ (beacon->capability & (1<<0xe)) ? '1' : '0',
+ (beacon->capability & (1<<0xd)) ? '1' : '0',
+ (beacon->capability & (1<<0xc)) ? '1' : '0',
+ (beacon->capability & (1<<0xb)) ? '1' : '0',
+ (beacon->capability & (1<<0xa)) ? '1' : '0',
+ (beacon->capability & (1<<0x9)) ? '1' : '0',
+ (beacon->capability & (1<<0x8)) ? '1' : '0',
+ (beacon->capability & (1<<0x7)) ? '1' : '0',
+ (beacon->capability & (1<<0x6)) ? '1' : '0',
+ (beacon->capability & (1<<0x5)) ? '1' : '0',
+ (beacon->capability & (1<<0x4)) ? '1' : '0',
+ (beacon->capability & (1<<0x3)) ? '1' : '0',
+ (beacon->capability & (1<<0x2)) ? '1' : '0',
+ (beacon->capability & (1<<0x1)) ? '1' : '0',
+ (beacon->capability & (1<<0x0)) ? '1' : '0');
+#if 0
+ if(strcmp(escape_essid(beacon->info_element.data, beacon->info_element.len), "rtl_softap") == 0)
+ {
+ if(WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_BEACON)
+ {
+ u32 i = 0, len = stats->len;
+ u8 * p = (u8*)beacon;
+ printk("-----------------------\n");
+ printk("rtl_softap Beacon:");
+ for(i=0; i<len; i++)
+ printk("\t%2.2x", *(p+i));
+ printk("\n-----------------------\n");
+ }
+ }
+#endif
+ if (ieee80211_network_init(ieee, beacon, &network, stats)) {
+ IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n",
+ escape_essid(info_element->data,
+ info_element->len),
+ MAC_ARG(beacon->header.addr3),
+ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
+ IEEE80211_STYPE_PROBE_RESP ?
+ "PROBE RESPONSE" : "BEACON");
+ return;
+ }
+
+#ifdef ENABLE_DOT11D
+ // For Asus EeePc request,
+ // (1) if wireless adapter receive get any 802.11d country code in AP beacon,
+ // wireless adapter should follow the country code.
+ // (2) If there is no any country code in beacon,
+ // then wireless adapter should do active scan from ch1~11 and
+ // passive scan from ch12~14
+ if(ieee->bGlobalDomain)
+ {
+ if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP)
+ {
+ // Case 1: Country code
+ if(IS_COUNTRY_IE_VALID(ieee) )
+ {
+ if( !IsLegalChannel(ieee, network.channel) )
+ {
+ printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network.channel);
+ return;
+ }
+ }
+ // Case 2: No any country code.
+ else
+ {
+ // Filter over channel ch12~14
+ if(network.channel > 11)
+ {
+ printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network.channel);
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Case 1: Country code
+ if(IS_COUNTRY_IE_VALID(ieee) )
+ {
+ if( !IsLegalChannel(ieee, network.channel) )
+ {
+ printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network.channel);
+ return;
+ }
+ }
+ // Case 2: No any country code.
+ else
+ {
+ // Filter over channel ch12~14
+ if(network.channel > 14)
+ {
+ printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network.channel);
+ return;
+ }
+ }
+ }
+ }
+#endif
+ /* The network parsed correctly -- so now we scan our known networks
+ * to see if we can find it in our list.
+ *
+ * NOTE: This search is definitely not optimized. Once its doing
+ * the "right thing" we'll optimize it for efficiency if
+ * necessary */
+
+ /* Search for this entry in the list and update it if it is
+ * already there. */
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ if(is_same_network(&ieee->current_network, &network, ieee)) {
+ wmm_info = ieee->current_network.wmm_info;
+ //YJ,add,080819,for hidden ap
+ if(is_beacon == 0)
+ network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags);
+ else if(ieee->state == IEEE80211_LINKED)
+ ieee->NumRxBcnInPeriod++;
+ //YJ,add,080819,for hidden ap,end
+ //printk("====>network.ssid=%s cur_ssid=%s\n", network.ssid, ieee->current_network.ssid);
+ update_network(&ieee->current_network, &network);
+ }
+
+ list_for_each_entry(target, &ieee->network_list, list) {
+ if (is_same_network(target, &network, ieee))
+ break;
+ if ((oldest == NULL) ||
+ (target->last_scanned < oldest->last_scanned))
+ oldest = target;
+ }
+
+ /* If we didn't find a match, then get a new network slot to initialize
+ * with this beacon's information */
+ if (&target->list == &ieee->network_list) {
+ if (list_empty(&ieee->network_free_list)) {
+ /* If there are no more slots, expire the oldest */
+ list_del(&oldest->list);
+ target = oldest;
+ IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from "
+ "network list.\n",
+ escape_essid(target->ssid,
+ target->ssid_len),
+ MAC_ARG(target->bssid));
+ } else {
+ /* Otherwise just pull from the free list */
+ target = list_entry(ieee->network_free_list.next,
+ struct ieee80211_network, list);
+ list_del(ieee->network_free_list.next);
+ }
+
+
+#ifdef CONFIG_IEEE80211_DEBUG
+ IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n",
+ escape_essid(network.ssid,
+ network.ssid_len),
+ MAC_ARG(network.bssid),
+ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
+ IEEE80211_STYPE_PROBE_RESP ?
+ "PROBE RESPONSE" : "BEACON");
+#endif
+
+#ifdef _RTL8187_EXT_PATCH_
+ network.ext_entry = target->ext_entry;
+#endif
+ memcpy(target, &network, sizeof(*target));
+ list_add_tail(&target->list, &ieee->network_list);
+ if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
+ ieee80211_softmac_new_net(ieee,&network);
+ } else {
+ IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
+ escape_essid(target->ssid,
+ target->ssid_len),
+ MAC_ARG(target->bssid),
+ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
+ IEEE80211_STYPE_PROBE_RESP ?
+ "PROBE RESPONSE" : "BEACON");
+
+ /* we have an entry and we are going to update it. But this entry may
+ * be already expired. In this case we do the same as we found a new
+ * net and call the new_net handler
+ */
+ renew = !time_after(target->last_scanned + ieee->scan_age, jiffies);
+ //YJ,add,080819,for hidden ap
+ if(is_beacon == 0)
+ network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags);
+ //if(strncmp(network.ssid, "linksys-c",9) == 0)
+ // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags);
+ if(((network.flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \
+ && (((network.ssid_len > 0) && (strncmp(target->ssid, network.ssid, network.ssid_len)))\
+ ||((ieee->current_network.ssid_len == network.ssid_len)&&(strncmp(ieee->current_network.ssid, network.ssid, network.ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK))))
+ renew = 1;
+ //YJ,add,080819,for hidden ap,end
+ update_network(target, &network);
+ if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE))
+ ieee80211_softmac_new_net(ieee,&network);
+ }
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+}
+
+void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *header,
+ struct ieee80211_rx_stats *stats)
+{
+ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
+
+ case IEEE80211_STYPE_BEACON:
+ IEEE80211_DEBUG_MGMT("received BEACON (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ IEEE80211_DEBUG_SCAN("Beacon\n");
+ ieee80211_process_probe_response(
+ ieee, (struct ieee80211_probe_response *)header, stats);
+ break;
+
+ case IEEE80211_STYPE_PROBE_RESP:
+ IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ IEEE80211_DEBUG_SCAN("Probe response\n");
+ ieee80211_process_probe_response(
+ ieee, (struct ieee80211_probe_response *)header, stats);
+ break;
+//rz
+#ifdef _RTL8187_EXT_PATCH_
+ case IEEE80211_STYPE_PROBE_REQ:
+ IEEE80211_DEBUG_MGMT("received PROBE REQUEST (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ IEEE80211_DEBUG_SCAN("Probe request\n");
+ ///
+ if( ieee->iw_mode == ieee->iw_ext_mode && ieee->ext_patch_ieee80211_rx_mgt_on_probe_req )
+ ieee->ext_patch_ieee80211_rx_mgt_on_probe_req( ieee, (struct ieee80211_probe_request *)header, stats);
+ break;
+#endif // _RTL8187_EXT_PATCH_
+
+ }
+}
+
+#if 0
+EXPORT_SYMBOL(ieee80211_rx_mgt);
+EXPORT_SYMBOL(ieee80211_rx);
+EXPORT_SYMBOL(ieee80211_network_init);
+#ifdef _RTL8187_EXT_PATCH_
+EXPORT_SYMBOL(ieee_ext_skb_p80211_to_ether);
+#endif
+#endif
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
new file mode 100644
index 00000000000..e5752f615e0
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -0,0 +1,4029 @@
+/* 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.
+ *
+ * Few lines might be stolen from other part of the ieee80211
+ * stack. Copyright who own it's copyright
+ *
+ * WPA code stolen from the ipw2200 driver.
+ * Copyright who own it's copyright.
+ *
+ * released under the GPL
+ */
+
+
+#include "ieee80211.h"
+
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#ifdef ENABLE_DOT11D
+#include "dot11d.h"
+#endif
+u8 rsn_authen_cipher_suite[16][4] = {
+ {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved
+ {0x00,0x0F,0xAC,0x01}, //WEP-40 //RSNA default
+ {0x00,0x0F,0xAC,0x02}, //TKIP //NONE //{used just as default}
+ {0x00,0x0F,0xAC,0x03}, //WRAP-historical
+ {0x00,0x0F,0xAC,0x04}, //CCMP
+ {0x00,0x0F,0xAC,0x05}, //WEP-104
+};
+
+short ieee80211_is_54g(struct ieee80211_network net)
+{
+ return ((net.rates_ex_len > 0) || (net.rates_len > 4));
+}
+
+short ieee80211_is_shortslot(struct ieee80211_network net)
+{
+ return (net.capability & WLAN_CAPABILITY_SHORT_SLOT);
+}
+
+/* returns the total length needed for pleacing the RATE MFIE
+ * tag and the EXTENDED RATE MFIE tag if needed.
+ * It encludes two bytes per tag for the tag itself and its len
+ */
+unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
+{
+ unsigned int rate_len = 0;
+
+ if (ieee->modulation & IEEE80211_CCK_MODULATION)
+ rate_len = IEEE80211_CCK_RATE_LEN + 2;
+
+ if (ieee->modulation & IEEE80211_OFDM_MODULATION)
+
+ rate_len += IEEE80211_OFDM_RATE_LEN + 2;
+
+ return rate_len;
+}
+
+/* pleace the MFIE rate, tag to the memory (double) poined.
+ * Then it updates the pointer so that
+ * it points after the new MFIE tag added.
+ */
+void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p)
+{
+ u8 *tag = *tag_p;
+
+ if (ieee->modulation & IEEE80211_CCK_MODULATION){
+ *tag++ = MFIE_TYPE_RATES;
+ *tag++ = 4;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
+ }
+
+ /* We may add an option for custom rates that specific HW might support */
+ *tag_p = tag;
+}
+
+void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p)
+{
+ u8 *tag = *tag_p;
+
+ if (ieee->modulation & IEEE80211_OFDM_MODULATION){
+
+ *tag++ = MFIE_TYPE_RATES_EX;
+ *tag++ = 8;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
+ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
+
+ }
+
+ /* We may add an option for custom rates that specific HW might support */
+ *tag_p = tag;
+}
+
+
+void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) {
+ u8 *tag = *tag_p;
+
+ *tag++ = MFIE_TYPE_GENERIC; //0
+ *tag++ = 7;
+ *tag++ = 0x00;
+ *tag++ = 0x50;
+ *tag++ = 0xf2;
+ *tag++ = 0x02;//5
+ *tag++ = 0x00;
+ *tag++ = 0x01;
+#ifdef SUPPORT_USPD
+ if(ieee->current_network.wmm_info & 0x80) {
+ *tag++ = 0x0f|MAX_SP_Len;
+ } else {
+ *tag++ = MAX_SP_Len;
+ }
+#else
+ *tag++ = MAX_SP_Len;
+#endif
+ *tag_p = tag;
+}
+
+#ifdef THOMAS_TURBO
+void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) {
+ u8 *tag = *tag_p;
+
+ *tag++ = MFIE_TYPE_GENERIC; //0
+ *tag++ = 7;
+ *tag++ = 0x00;
+ *tag++ = 0xe0;
+ *tag++ = 0x4c;
+ *tag++ = 0x01;//5
+ *tag++ = 0x02;
+ *tag++ = 0x11;
+ *tag++ = 0x00;
+
+ *tag_p = tag;
+ printk(KERN_ALERT "This is enable turbo mode IE process\n");
+}
+#endif
+
+void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb)
+{
+ int nh;
+ nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM;
+
+/*
+ * if the queue is full but we have newer frames then
+ * just overwrites the oldest.
+ *
+ * if (nh == ieee->mgmt_queue_tail)
+ * return -1;
+ */
+ ieee->mgmt_queue_head = nh;
+ ieee->mgmt_queue_ring[nh] = skb;
+
+ //return 0;
+}
+
+struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee)
+{
+ struct sk_buff *ret;
+
+ if(ieee->mgmt_queue_tail == ieee->mgmt_queue_head)
+ return NULL;
+
+ ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail];
+
+ ieee->mgmt_queue_tail =
+ (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM;
+
+ return ret;
+}
+
+void init_mgmt_queue(struct ieee80211_device *ieee)
+{
+ ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0;
+}
+
+
+void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl);
+
+inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee)
+{
+ unsigned long flags;
+ short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
+ struct ieee80211_hdr_3addr *header=
+ (struct ieee80211_hdr_3addr *) skb->data;
+
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ /* called with 2nd param 0, no mgmt lock required */
+ ieee80211_sta_wakeup(ieee,0);
+
+ if(single){
+ if(ieee->queue_stop){
+
+ enqueue_mgmt(ieee,skb);
+ }else{
+ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
+
+ if (ieee->seq_ctrl[0] == 0xFFF)
+ ieee->seq_ctrl[0] = 0;
+ else
+ ieee->seq_ctrl[0]++;
+
+ /* avoid watchdog triggers */
+ ieee->dev->trans_start = jiffies;
+ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
+ }
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ }else{
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
+
+ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+
+ if (ieee->seq_ctrl[0] == 0xFFF)
+ ieee->seq_ctrl[0] = 0;
+ else
+ ieee->seq_ctrl[0]++;
+
+ /* avoid watchdog triggers */
+ ieee->dev->trans_start = jiffies;
+ ieee->softmac_hard_start_xmit(skb,ieee->dev);
+
+ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags);
+ }
+}
+
+
+inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee)
+{
+
+ short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
+ struct ieee80211_hdr_3addr *header =
+ (struct ieee80211_hdr_3addr *) skb->data;
+
+
+ if(single){
+
+ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+
+ if (ieee->seq_ctrl[0] == 0xFFF)
+ ieee->seq_ctrl[0] = 0;
+ else
+ ieee->seq_ctrl[0]++;
+
+ /* avoid watchdog triggers */
+ ieee->dev->trans_start = jiffies;
+ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
+
+ }else{
+
+ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+
+ if (ieee->seq_ctrl[0] == 0xFFF)
+ ieee->seq_ctrl[0] = 0;
+ else
+ ieee->seq_ctrl[0]++;
+
+ /* avoid watchdog triggers */
+ ieee->dev->trans_start = jiffies;
+ ieee->softmac_hard_start_xmit(skb,ieee->dev);
+
+ }
+// dev_kfree_skb_any(skb);//edit by thomas
+}
+//by amy for power save
+inline struct sk_buff *ieee80211_disassociate_skb(
+ struct ieee80211_network *beacon,
+ struct ieee80211_device *ieee,
+ u8 asRsn)
+{
+ struct sk_buff *skb;
+ struct ieee80211_disassoc_frame *disass;
+
+ skb = dev_alloc_skb(sizeof(struct ieee80211_disassoc_frame));
+ if (!skb)
+ return NULL;
+
+ disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame));
+ disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
+ disass->header.duration_id = 0;
+
+ memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN);
+ memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN);
+
+ disass->reasoncode = asRsn;
+ return skb;
+}
+void
+SendDisassociation(
+ struct ieee80211_device *ieee,
+ u8* asSta,
+ u8 asRsn
+)
+{
+ struct ieee80211_network *beacon = &ieee->current_network;
+ struct sk_buff *skb;
+ skb = ieee80211_disassociate_skb(beacon,ieee,asRsn);
+ if (skb){
+ softmac_mgmt_xmit(skb, ieee);
+ //dev_kfree_skb_any(skb);//edit by thomas
+ }
+}
+
+//by amy for power save
+inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee)
+{
+ unsigned int len,rate_len;
+ u8 *tag;
+ struct sk_buff *skb;
+ struct ieee80211_probe_request *req;
+
+#ifdef _RTL8187_EXT_PATCH_
+ short extMore = 0;
+ if(ieee->ext_patch_ieee80211_probe_req_1)
+ extMore = ieee->ext_patch_ieee80211_probe_req_1(ieee);
+#endif
+
+ len = ieee->current_network.ssid_len;
+
+ rate_len = ieee80211_MFIE_rate_len(ieee);
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(!extMore)
+#endif
+ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) +
+ 2 + len + rate_len);
+#ifdef _RTL8187_EXT_PATCH_
+ else
+ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) +
+ 2 + len + rate_len+128); // MESHID + CAP
+#endif
+
+ if (!skb)
+ return NULL;
+
+ req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request));
+ req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+ req->header.duration_id = 0; //FIXME: is this OK ?
+
+ memset(req->header.addr1, 0xff, ETH_ALEN);
+ memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memset(req->header.addr3, 0xff, ETH_ALEN);
+
+ tag = (u8 *) skb_put(skb,len+2+rate_len);
+
+ *tag++ = MFIE_TYPE_SSID;
+ *tag++ = len;
+ memcpy(tag, ieee->current_network.ssid, len);
+ tag += len;
+ ieee80211_MFIE_Brate(ieee,&tag);
+ ieee80211_MFIE_Grate(ieee,&tag);
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(extMore)
+ ieee->ext_patch_ieee80211_probe_req_2(ieee, skb, tag);
+#endif
+ return skb;
+}
+
+struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee);
+
+//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+//void ext_ieee80211_send_beacon_wq(struct work_struct *work)
+//{
+// struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ext_send_beacon_wq);
+//#else
+void ext_ieee80211_send_beacon_wq(struct ieee80211_device *ieee)
+{
+//#endif
+
+ struct sk_buff *skb;
+
+ //unsigned long flags;
+
+ skb = ieee80211_get_beacon_(ieee);
+
+ if (skb){
+ softmac_mgmt_xmit(skb, ieee);
+ ieee->softmac_stats.tx_beacons++;
+ dev_kfree_skb_any(skb);//edit by thomas
+ }
+
+
+ //printk(KERN_WARNING "[1] beacon sending!\n");
+ ieee->beacon_timer.expires = jiffies +
+ (MSECS( ieee->current_network.beacon_interval -5));
+
+ //spin_lock_irqsave(&ieee->beacon_lock,flags);
+ if(ieee->beacon_txing)
+ add_timer(&ieee->beacon_timer);
+ //spin_unlock_irqrestore(&ieee->beacon_lock,flags);
+}
+
+void ieee80211_send_beacon(struct ieee80211_device *ieee)
+{
+ struct sk_buff *skb;
+
+ //unsigned long flags;
+
+ skb = ieee80211_get_beacon_(ieee);
+
+ if (skb){
+ softmac_mgmt_xmit(skb, ieee);
+ ieee->softmac_stats.tx_beacons++;
+ dev_kfree_skb_any(skb);//edit by thomas
+ }
+
+ //printk(KERN_WARNING "[1] beacon sending!\n");
+ ieee->beacon_timer.expires = jiffies +
+ (MSECS( ieee->current_network.beacon_interval -5));
+
+ //spin_lock_irqsave(&ieee->beacon_lock,flags);
+ if(ieee->beacon_txing)
+ add_timer(&ieee->beacon_timer);
+ //spin_unlock_irqrestore(&ieee->beacon_lock,flags);
+}
+
+
+void ieee80211_send_beacon_cb(unsigned long _ieee)
+{
+ struct ieee80211_device *ieee =
+ (struct ieee80211_device *) _ieee;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ieee->beacon_lock, flags);
+ ieee80211_send_beacon(ieee);
+ spin_unlock_irqrestore(&ieee->beacon_lock, flags);
+}
+
+#ifdef _RTL8187_EXT_PATCH_
+
+inline struct sk_buff *ieee80211_probe_req_with_SSID(struct ieee80211_device *ieee, char *ssid, int len_ssid)
+{
+ unsigned int len,rate_len;
+ u8 *tag;
+ struct sk_buff *skb;
+ struct ieee80211_probe_request *req;
+
+#ifdef _RTL8187_EXT_PATCH_
+ short extMore = 0;
+ if(ieee->ext_patch_ieee80211_probe_req_1)
+ extMore = ieee->ext_patch_ieee80211_probe_req_1(ieee);
+#endif
+
+ len = len_ssid;
+
+ rate_len = ieee80211_MFIE_rate_len(ieee);
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(!extMore)
+#endif
+ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) +
+ 2 + len + rate_len);
+#ifdef _RTL8187_EXT_PATCH_
+ else
+ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) +
+ 2 + len + rate_len+128); // MESHID + CAP
+#endif
+
+ if (!skb)
+ return NULL;
+
+ req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request));
+ req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+ req->header.duration_id = 0; //FIXME: is this OK ?
+
+ memset(req->header.addr1, 0xff, ETH_ALEN);
+ memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memset(req->header.addr3, 0xff, ETH_ALEN);
+
+ tag = (u8 *) skb_put(skb,len+2+rate_len);
+
+ *tag++ = MFIE_TYPE_SSID;
+ *tag++ = len;
+ if(len)
+ {
+ memcpy(tag, ssid, len);
+ tag += len;
+ }
+
+ ieee80211_MFIE_Brate(ieee,&tag);
+ ieee80211_MFIE_Grate(ieee,&tag);
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(extMore)
+ ieee->ext_patch_ieee80211_probe_req_2(ieee, skb, tag);
+#endif
+ return skb;
+}
+
+#endif // _RTL8187_EXT_PATCH_
+
+
+void ieee80211_send_probe(struct ieee80211_device *ieee)
+{
+ struct sk_buff *skb;
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->iw_mode == ieee->iw_ext_mode)
+ skb = ieee80211_probe_req_with_SSID(ieee, NULL, 0);
+ else
+#endif
+ skb = ieee80211_probe_req(ieee);
+ if (skb){
+ softmac_mgmt_xmit(skb, ieee);
+ ieee->softmac_stats.tx_probe_rq++;
+ //dev_kfree_skb_any(skb);//edit by thomas
+ }
+}
+
+void ieee80211_send_probe_requests(struct ieee80211_device *ieee)
+{
+ if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)){
+ ieee80211_send_probe(ieee);
+ ieee80211_send_probe(ieee);
+ }
+}
+
+/* this performs syncro scan blocking the caller until all channels
+ * in the allowed channel map has been checked.
+ */
+void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
+{
+ short ch = 0;
+#ifdef ENABLE_DOT11D
+ u8 channel_map[MAX_CHANNEL_NUMBER+1];
+ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
+#endif
+ down(&ieee->scan_sem);
+// printk("==================> Sync scan\n");
+// dump_chnl_map(channel_map);
+
+ while(1)
+ {
+
+ do{
+ ch++;
+ if (ch > MAX_CHANNEL_NUMBER)
+ goto out; /* scan completed */
+
+#ifdef ENABLE_DOT11D
+ }while(!channel_map[ch]);
+#else
+ }while(!ieee->channel_map[ch]);
+#endif
+ /* this fuction can be called in two situations
+ * 1- We have switched to ad-hoc mode and we are
+ * performing a complete syncro scan before conclude
+ * there are no interesting cell and to create a
+ * new one. In this case the link state is
+ * IEEE80211_NOLINK until we found an interesting cell.
+ * If so the ieee8021_new_net, called by the RX path
+ * will set the state to IEEE80211_LINKED, so we stop
+ * scanning
+ * 2- We are linked and the root uses run iwlist scan.
+ * So we switch to IEEE80211_LINKED_SCANNING to remember
+ * that we are still logically linked (not interested in
+ * new network events, despite for updating the net list,
+ * but we are temporarly 'unlinked' as the driver shall
+ * not filter RX frames and the channel is changing.
+ * So the only situation in witch are interested is to check
+ * if the state become LINKED because of the #1 situation
+ */
+
+ if (ieee->state == IEEE80211_LINKED)
+ goto out;
+
+ ieee->set_chan(ieee->dev, ch);
+// printk("=====>channel=%d ",ch);
+#ifdef ENABLE_DOT11D
+ if(channel_map[ch] == 1)
+#endif
+ {
+// printk("====send probe request\n");
+ ieee80211_send_probe_requests(ieee);
+ }
+ /* this prevent excessive time wait when we
+ * need to wait for a syncro scan to end..
+ */
+ if (ieee->sync_scan_hurryup)
+ goto out;
+
+
+ msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME);
+
+ }
+out:
+ ieee->sync_scan_hurryup = 0;
+ up(&ieee->scan_sem);
+#ifdef ENABLE_DOT11D
+ if(IS_DOT11D_ENABLE(ieee))
+ DOT11D_ScanComplete(ieee);
+#endif
+}
+
+void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee)
+{
+ int ch;
+ unsigned int watch_dog = 0;
+#ifdef ENABLE_DOT11D
+ u8 channel_map[MAX_CHANNEL_NUMBER+1];
+ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
+#endif
+ down(&ieee->scan_sem);
+ ch = ieee->current_network.channel;
+// if(ieee->sync_scan_hurryup)
+// {
+
+// printk("stop scan sync\n");
+// goto out;
+// }
+// printk("=======hh===============>ips scan\n");
+ while(1)
+ {
+ /* this fuction can be called in two situations
+ * 1- We have switched to ad-hoc mode and we are
+ * performing a complete syncro scan before conclude
+ * there are no interesting cell and to create a
+ * new one. In this case the link state is
+ * IEEE80211_NOLINK until we found an interesting cell.
+ * If so the ieee8021_new_net, called by the RX path
+ * will set the state to IEEE80211_LINKED, so we stop
+ * scanning
+ * 2- We are linked and the root uses run iwlist scan.
+ * So we switch to IEEE80211_LINKED_SCANNING to remember
+ * that we are still logically linked (not interested in
+ * new network events, despite for updating the net list,
+ * but we are temporarly 'unlinked' as the driver shall
+ * not filter RX frames and the channel is changing.
+ * So the only situation in witch are interested is to check
+ * if the state become LINKED because of the #1 situation
+ */
+ if (ieee->state == IEEE80211_LINKED)
+ {
+ goto out;
+ }
+#ifdef ENABLE_DOT11D
+ if(channel_map[ieee->current_network.channel] > 0)
+#endif
+ {
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+// printk("======>channel=%d ",ieee->current_network.channel);
+ }
+#ifdef ENABLE_DOT11D
+ if(channel_map[ieee->current_network.channel] == 1)
+#endif
+ {
+// printk("====send probe request\n");
+ ieee80211_send_probe_requests(ieee);
+ }
+ /* this prevent excessive time wait when we
+ * need to wait for a syncro scan to end..
+ */
+// if (ieee->sync_scan_hurryup)
+// goto out;
+
+ msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME);
+
+ do{
+ if (watch_dog++ >= MAX_CHANNEL_NUMBER)
+ // if (++watch_dog >= 15);//MAX_CHANNEL_NUMBER) //YJ,modified,080630
+ goto out; /* scan completed */
+
+ ieee->current_network.channel = (ieee->current_network.channel + 1)%MAX_CHANNEL_NUMBER;
+#ifdef ENABLE_DOT11D
+ }while(!channel_map[ieee->current_network.channel]);
+#else
+ }while(!ieee->channel_map[ieee->current_network.channel]);
+#endif
+ }
+out:
+ //ieee->sync_scan_hurryup = 0;
+ //ieee->set_chan(ieee->dev, ch);
+ //ieee->current_network.channel = ch;
+ ieee->actscanning = false;
+ up(&ieee->scan_sem);
+#ifdef ENABLE_DOT11D
+ if(IS_DOT11D_ENABLE(ieee))
+ DOT11D_ScanComplete(ieee);
+#endif
+}
+
+
+#if 0
+/* called both by wq with ieee->lock held */
+void ieee80211_softmac_scan(struct ieee80211_device *ieee)
+{
+ short watchdog = 0;
+
+ do{
+ ieee->current_network.channel =
+ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER;
+ if (watchdog++ > MAX_CHANNEL_NUMBER)
+ return; /* no good chans */
+
+ }while(!ieee->channel_map[ieee->current_network.channel]);
+
+
+ schedule_work(&ieee->softmac_scan_wq);
+}
+#endif
+#ifdef ENABLE_IPS
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void ieee80211_softmac_scan_wq(struct work_struct *work)
+{
+ struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
+#else
+void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
+{
+#endif
+ static short watchdog = 0;
+#ifdef ENABLE_DOT11D
+ u8 channel_map[MAX_CHANNEL_NUMBER+1];
+ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
+#endif
+// printk("ieee80211_softmac_scan_wq ENABLE_IPS\n");
+// printk("in %s\n",__func__);
+ down(&ieee->scan_sem);
+
+ do{
+ ieee->current_network.channel =
+ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER;
+ if (watchdog++ > MAX_CHANNEL_NUMBER)
+ goto out; /* no good chans */
+
+#ifdef ENABLE_DOT11D
+ }while(!channel_map[ieee->current_network.channel]);
+#else
+ }while(!ieee->channel_map[ieee->current_network.channel]);
+#endif
+
+ //printk("current_network.channel:%d\n", ieee->current_network.channel);
+ if (ieee->scanning == 0 )
+ {
+ printk("error out, scanning = 0\n");
+ goto out;
+ }
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+#ifdef ENABLE_DOT11D
+ if(channel_map[ieee->current_network.channel] == 1)
+#endif
+ ieee80211_send_probe_requests(ieee);
+
+ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME);
+ up(&ieee->scan_sem);
+ return;
+out:
+ ieee->actscanning = false;
+ watchdog = 0;
+ ieee->scanning = 0;
+ up(&ieee->scan_sem);
+
+#ifdef ENABLE_DOT11D
+ if(IS_DOT11D_ENABLE(ieee))
+ DOT11D_ScanComplete(ieee);
+#endif
+ return;
+}
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void ieee80211_softmac_scan_wq(struct work_struct *work)
+{
+ struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, softmac_scan_wq);
+#else
+void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
+{
+#endif
+
+ short watchdog = 0;
+#ifdef ENABLE_DOT11D
+ u8 channel_map[MAX_CHANNEL_NUMBER+1];
+ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
+#endif
+// printk("enter scan wq,watchdog is %d\n",watchdog);
+ down(&ieee->scan_sem);
+
+ do{
+ ieee->current_network.channel =
+ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER;
+ if (watchdog++ > MAX_CHANNEL_NUMBER)
+ goto out; /* no good chans */
+
+#ifdef ENABLE_DOT11D
+ }while(!channel_map[ieee->current_network.channel]);
+#else
+ }while(!ieee->channel_map[ieee->current_network.channel]);
+#endif
+
+// printk("current_network.channel:%d\n", ieee->current_network.channel);
+ if (ieee->scanning == 0 )
+ {
+ printk("error out, scanning = 0\n");
+ goto out;
+ }
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+#ifdef ENABLE_DOT11D
+ if(channel_map[ieee->current_network.channel] == 1)
+#endif
+ ieee80211_send_probe_requests(ieee);
+
+ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME);
+out:
+ up(&ieee->scan_sem);
+#ifdef ENABLE_DOT11D
+ if(IS_DOT11D_ENABLE(ieee))
+ DOT11D_ScanComplete(ieee);
+#endif
+}
+
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+void ieee80211_softmac_scan_cb(unsigned long _dev)
+{
+ unsigned long flags;
+ struct ieee80211_device *ieee = (struct ieee80211_device *)_dev;
+
+ spin_lock_irqsave(&ieee->lock, flags);
+ ieee80211_softmac_scan(ieee);
+ spin_unlock_irqrestore(&ieee->lock, flags);
+}
+#endif
+
+
+void ieee80211_beacons_start(struct ieee80211_device *ieee)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ieee->beacon_lock,flags);
+
+ ieee->beacon_txing = 1;
+ ieee80211_send_beacon(ieee);
+
+ spin_unlock_irqrestore(&ieee->beacon_lock,flags);
+}
+
+void ieee80211_beacons_stop(struct ieee80211_device *ieee)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ieee->beacon_lock,flags);
+
+ ieee->beacon_txing = 0;
+ del_timer_sync(&ieee->beacon_timer);
+
+ spin_unlock_irqrestore(&ieee->beacon_lock,flags);
+
+}
+
+
+void ieee80211_stop_send_beacons(struct ieee80211_device *ieee)
+{
+ if(ieee->stop_send_beacons)
+ ieee->stop_send_beacons(ieee->dev);
+ if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS)
+ ieee80211_beacons_stop(ieee);
+}
+
+
+void ieee80211_start_send_beacons(struct ieee80211_device *ieee)
+{
+ if(ieee->start_send_beacons)
+ ieee->start_send_beacons(ieee->dev);
+ if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS)
+ ieee80211_beacons_start(ieee);
+}
+
+
+void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee)
+{
+// unsigned long flags;
+
+ //ieee->sync_scan_hurryup = 1;
+
+ down(&ieee->scan_sem);
+// spin_lock_irqsave(&ieee->lock, flags);
+
+ if (ieee->scanning == 1){
+ ieee->scanning = 0;
+ //del_timer_sync(&ieee->scan_timer);
+ cancel_delayed_work(&ieee->softmac_scan_wq);
+ }
+
+// spin_unlock_irqrestore(&ieee->lock, flags);
+ up(&ieee->scan_sem);
+}
+
+void ieee80211_stop_scan(struct ieee80211_device *ieee)
+{
+ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
+ ieee80211_softmac_stop_scan(ieee);
+ else
+ ieee->stop_scan(ieee->dev);
+}
+
+/* called with ieee->lock held */
+void ieee80211_start_scan(struct ieee80211_device *ieee)
+{
+#ifdef ENABLE_DOT11D
+ if(IS_DOT11D_ENABLE(ieee) )
+ {
+ if(IS_COUNTRY_IE_VALID(ieee))
+ {
+ RESET_CIE_WATCHDOG(ieee);
+ }
+ }
+#endif
+ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){
+ if (ieee->scanning == 0)
+ {
+ ieee->scanning = 1;
+ //ieee80211_softmac_scan(ieee);
+ // queue_work(ieee->wq, &ieee->softmac_scan_wq);
+ //care this,1203,2007,by lawrence
+#if 1
+ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq,0);
+#endif
+ }
+ }else
+ ieee->start_scan(ieee->dev);
+
+}
+
+/* called with wx_sem held */
+void ieee80211_start_scan_syncro(struct ieee80211_device *ieee)
+{
+#ifdef ENABLE_DOT11D
+ if(IS_DOT11D_ENABLE(ieee) )
+ {
+ if(IS_COUNTRY_IE_VALID(ieee))
+ {
+ RESET_CIE_WATCHDOG(ieee);
+ }
+ }
+#endif
+ ieee->sync_scan_hurryup = 0;
+
+ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
+ ieee80211_softmac_scan_syncro(ieee);
+ else
+ ieee->scan_syncro(ieee->dev);
+
+}
+
+inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *beacon,
+ struct ieee80211_device *ieee, int challengelen)
+{
+ struct sk_buff *skb;
+ struct ieee80211_authentication *auth;
+
+ skb = dev_alloc_skb(sizeof(struct ieee80211_authentication) + challengelen);
+
+ if (!skb) return NULL;
+
+ auth = (struct ieee80211_authentication *)
+ skb_put(skb, sizeof(struct ieee80211_authentication));
+
+ auth->header.frame_ctl = IEEE80211_STYPE_AUTH;
+ if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP;
+
+ auth->header.duration_id = 0x013a; //FIXME
+
+ memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN);
+ memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN);
+
+ auth->algorithm = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
+
+ auth->transaction = cpu_to_le16(ieee->associate_seq);
+ ieee->associate_seq++;
+
+ auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS);
+
+ return skb;
+
+}
+
+static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *dest)
+{
+ u8 *tag;
+ int beacon_size;
+ struct ieee80211_probe_response *beacon_buf;
+ struct sk_buff *skb;
+ int encrypt;
+ int atim_len,erp_len;
+ struct ieee80211_crypt_data* crypt;
+
+ char *ssid = ieee->current_network.ssid;
+ int ssid_len = ieee->current_network.ssid_len;
+ int rate_len = ieee->current_network.rates_len+2;
+ int rate_ex_len = ieee->current_network.rates_ex_len;
+ int wpa_ie_len = ieee->wpa_ie_len;
+ if(rate_ex_len > 0) rate_ex_len+=2;
+
+ if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS)
+ atim_len = 4;
+ else
+ atim_len = 0;
+
+ if(ieee80211_is_54g(ieee->current_network))
+ erp_len = 3;
+ else
+ erp_len = 0;
+
+ beacon_size = sizeof(struct ieee80211_probe_response)+
+ ssid_len
+ +3 //channel
+ +rate_len
+ +rate_ex_len
+ +atim_len
+ +wpa_ie_len
+ +erp_len;
+
+ skb = dev_alloc_skb(beacon_size);
+
+ if (!skb)
+ return NULL;
+
+ beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size);
+
+ memcpy (beacon_buf->header.addr1, dest,ETH_ALEN);
+ memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN);
+
+ beacon_buf->header.duration_id = 0; //FIXME
+ beacon_buf->beacon_interval =
+ cpu_to_le16(ieee->current_network.beacon_interval);
+ beacon_buf->capability =
+ cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS);
+
+ if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT))
+ cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT));
+
+ crypt = ieee->crypt[ieee->tx_keyidx];
+
+ encrypt = ieee->host_encrypt && crypt && crypt->ops &&
+ ((0 == strcmp(crypt->ops->name, "WEP")) || wpa_ie_len);
+
+ if (encrypt)
+ beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
+
+
+ beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP);
+
+ beacon_buf->info_element.id = MFIE_TYPE_SSID;
+ beacon_buf->info_element.len = ssid_len;
+
+ tag = (u8*) beacon_buf->info_element.data;
+
+ memcpy(tag, ssid, ssid_len);
+
+ tag += ssid_len;
+
+ *(tag++) = MFIE_TYPE_RATES;
+ *(tag++) = rate_len-2;
+ memcpy(tag,ieee->current_network.rates,rate_len-2);
+ tag+=rate_len-2;
+
+ *(tag++) = MFIE_TYPE_DS_SET;
+ *(tag++) = 1;
+ *(tag++) = ieee->current_network.channel;
+
+ if(atim_len){
+ *(tag++) = MFIE_TYPE_IBSS_SET;
+ *(tag++) = 2;
+ *((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window);
+ tag+=2;
+ }
+
+ if(erp_len){
+ *(tag++) = MFIE_TYPE_ERP;
+ *(tag++) = 1;
+ *(tag++) = 0;
+ }
+
+ if(rate_ex_len){
+ *(tag++) = MFIE_TYPE_RATES_EX;
+ *(tag++) = rate_ex_len-2;
+ memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2);
+ tag+=rate_ex_len-2;
+ }
+
+ if (wpa_ie_len)
+ {
+ if (ieee->iw_mode == IW_MODE_ADHOC)
+ {//as Windows will set pairwise key same as the group key which is not allowed in Linux, so set this for IOT issue. WB 2008.07.07
+ memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4);
+ }
+
+ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len);
+ }
+
+ skb->dev = ieee->dev;
+ return skb;
+}
+#ifdef _RTL8187_EXT_PATCH_
+struct sk_buff* ieee80211_ext_probe_resp_by_net(struct ieee80211_device *ieee, u8 *dest, struct ieee80211_network *net)
+{
+ u8 *tag;
+ int beacon_size;
+ struct ieee80211_probe_response *beacon_buf;
+ struct sk_buff *skb;
+ int encrypt;
+ int atim_len,erp_len;
+ struct ieee80211_crypt_data* crypt;
+ u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+ int wpa_ie_len = ieee->wpa_ie_len;
+ char *ssid = net->ssid;
+ int ssid_len = net->ssid_len;
+
+ int rate_len = ieee->current_network.rates_len+2;
+ int rate_ex_len = ieee->current_network.rates_ex_len;
+ if(rate_ex_len > 0) rate_ex_len+=2;
+
+ if( ieee->meshScanMode&4)
+ ieee->current_network.channel = ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee);
+ if( ieee->meshScanMode&6)
+ {
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ queue_work(ieee->wq, &ieee->ext_stop_scan_wq);
+#else
+ schedule_task(&ieee->ext_stop_scan_wq);
+#endif
+ }
+ if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) // use current_network here
+ atim_len = 4;
+ else
+ atim_len = 0;
+
+ if(ieee80211_is_54g(*net))
+ erp_len = 3;
+ else
+ erp_len = 0;
+
+ beacon_size = sizeof(struct ieee80211_probe_response)+
+ ssid_len
+ +3 //channel
+ +rate_len
+ +rate_ex_len
+ +atim_len
+ +erp_len;
+//b
+ skb = dev_alloc_skb(beacon_size+196);
+
+ if (!skb)
+ return NULL;
+
+ beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size);
+
+ memcpy (beacon_buf->header.addr1, dest,ETH_ALEN);
+ memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN);
+
+ beacon_buf->header.duration_id = 0; //FIXME
+
+ beacon_buf->beacon_interval =
+ cpu_to_le16(ieee->current_network.beacon_interval); // use current_network here
+ beacon_buf->capability =
+ cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS);
+
+ if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT))
+ cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT));
+
+ crypt = ieee->crypt[ieee->tx_keyidx];
+
+ encrypt = ieee->host_encrypt && crypt && crypt->ops &&
+ ((0 == strcmp(crypt->ops->name, "WEP"))||wpa_ie_len);
+
+ if (encrypt)
+ beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
+
+
+ beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP);
+
+ beacon_buf->info_element.id = MFIE_TYPE_SSID;
+ beacon_buf->info_element.len = ssid_len;
+
+ tag = (u8*) beacon_buf->info_element.data;
+
+ // brocad cast / probe rsp
+ if(memcmp(dest, broadcast_addr, ETH_ALEN ))
+ memcpy(tag, ssid, ssid_len);
+ else
+ ssid_len=0;
+
+ tag += ssid_len;
+
+//get_bssrate_set(priv, _SUPPORTEDRATES_IE_, &pbssrate, &bssrate_len);
+//pbuf = set_ie(pbuf, _SUPPORTEDRATES_IE_, bssrate_len, pbssrate, &frlen);
+
+ *(tag++) = MFIE_TYPE_RATES;
+ *(tag++) = rate_len-2;
+ memcpy(tag,ieee->current_network.rates,rate_len-2);
+ tag+=rate_len-2;
+
+ *(tag++) = MFIE_TYPE_DS_SET;
+ *(tag++) = 1;
+ *(tag++) = ieee->current_network.channel; // use current_network here
+
+
+ if(atim_len){
+ *(tag++) = MFIE_TYPE_IBSS_SET;
+ *(tag++) = 2;
+ *((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); // use current_network here
+ tag+=2;
+ }
+
+ if(erp_len){
+ *(tag++) = MFIE_TYPE_ERP;
+ *(tag++) = 1;
+ *(tag++) = 0;
+ }
+
+ if(rate_ex_len){
+ *(tag++) = MFIE_TYPE_RATES_EX;
+ *(tag++) = rate_ex_len-2;
+ memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2);
+ tag+=rate_ex_len-2;
+ }
+ if (wpa_ie_len)
+ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len);
+
+ skb->dev = ieee->dev;
+ return skb;
+}
+#endif // _RTL8187_EXT_PATCH_
+
+struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
+{
+ struct sk_buff *skb;
+ u8* tag;
+
+ struct ieee80211_crypt_data* crypt;
+ struct ieee80211_assoc_response_frame *assoc;
+ short encrypt;
+
+ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee);
+ int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len;
+
+ skb = dev_alloc_skb(len);
+
+ if (!skb)
+ return NULL;
+
+ assoc = (struct ieee80211_assoc_response_frame *)
+ skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
+
+ assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
+ memcpy(assoc->header.addr1, dest,ETH_ALEN);
+ memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ?
+ WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS);
+
+
+ if(ieee->short_slot)
+ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
+
+ if (ieee->host_encrypt)
+ crypt = ieee->crypt[ieee->tx_keyidx];
+ else crypt = NULL;
+
+ encrypt = ( crypt && crypt->ops);
+
+ if (encrypt)
+ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
+
+ assoc->status = 0;
+ assoc->aid = cpu_to_le16(ieee->assoc_id);
+ if (ieee->assoc_id == 0x2007) ieee->assoc_id=0;
+ else ieee->assoc_id++;
+
+ tag = (u8*) skb_put(skb, rate_len);
+
+ ieee80211_MFIE_Brate(ieee, &tag);
+ ieee80211_MFIE_Grate(ieee, &tag);
+
+ return skb;
+}
+
+struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 *dest)
+{
+ struct sk_buff *skb;
+ struct ieee80211_authentication *auth;
+
+ skb = dev_alloc_skb(sizeof(struct ieee80211_authentication)+1);
+
+ if (!skb)
+ return NULL;
+
+ skb->len = sizeof(struct ieee80211_authentication);
+
+ auth = (struct ieee80211_authentication *)skb->data;
+
+ auth->status = cpu_to_le16(status);
+ auth->transaction = cpu_to_le16(2);
+ auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN);
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->iw_mode == ieee->iw_ext_mode)
+ memcpy(auth->header.addr3, dest, ETH_ALEN);
+#else
+ memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
+#endif
+ memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy(auth->header.addr1, dest, ETH_ALEN);
+ auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH);
+ return skb;
+
+
+}
+
+struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr_3addr* hdr;
+
+ skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr));
+
+ if (!skb)
+ return NULL;
+
+ hdr = (struct ieee80211_hdr_3addr*)skb_put(skb,sizeof(struct ieee80211_hdr_3addr));
+
+ memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN);
+ memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN);
+
+ hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS |
+ (pwr ? IEEE80211_FCTL_PM:0));
+
+ return skb;
+
+
+}
+
+
+void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8* dest)
+{
+ struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest);
+
+ if (buf){
+ softmac_mgmt_xmit(buf, ieee);
+ dev_kfree_skb_any(buf);//edit by thomas
+ }
+}
+
+
+void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8* dest)
+{
+ struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest);
+
+ if (buf){
+ softmac_mgmt_xmit(buf, ieee);
+ dev_kfree_skb_any(buf);//edit by thomas
+ }
+}
+
+
+void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest)
+{
+
+ struct sk_buff *buf = ieee80211_probe_resp(ieee, dest);
+
+ if (buf) {
+ softmac_mgmt_xmit(buf, ieee);
+ dev_kfree_skb_any(buf);//edit by thomas
+ }
+}
+
+
+inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beacon,struct ieee80211_device *ieee)
+{
+ struct sk_buff *skb;
+ //unsigned long flags;
+
+ struct ieee80211_assoc_request_frame *hdr;
+ u8 *tag;
+ //short info_addr = 0;
+ //int i;
+ //u16 suite_count = 0;
+ //u8 suit_select = 0;
+ unsigned int wpa_len = beacon->wpa_ie_len;
+ //struct net_device *dev = ieee->dev;
+ //union iwreq_data wrqu;
+ //u8 *buff;
+ //u8 *p;
+#if 1
+ // for testing purpose
+ unsigned int rsn_len = beacon->rsn_ie_len;
+#else
+ unsigned int rsn_len = beacon->rsn_ie_len - 4;
+#endif
+ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee);
+ unsigned int wmm_info_len = beacon->QoS_Enable?9:0;
+#ifdef THOMAS_TURBO
+ unsigned int turbo_info_len = beacon->Turbo_Enable?9:0;
+#endif
+
+ u8 encry_proto = ieee->wpax_type_notify & 0xff;
+ //u8 pairwise_type = (ieee->wpax_type_notify >> 8) & 0xff;
+ //u8 authen_type = (ieee->wpax_type_notify >> 16) & 0xff;
+
+ int len = 0;
+
+ //[0] Notify type of encryption: WPA/WPA2
+ //[1] pair wise type
+ //[2] authen type
+ if(ieee->wpax_type_set) {
+ if (IEEE_PROTO_WPA == encry_proto) {
+ rsn_len = 0;
+ } else if (IEEE_PROTO_RSN == encry_proto) {
+ wpa_len = 0;
+ }
+ }
+#ifdef THOMAS_TURBO
+ len = sizeof(struct ieee80211_assoc_request_frame)+
+ + beacon->ssid_len//essid tagged val
+ + rate_len//rates tagged val
+ + wpa_len
+ + rsn_len
+ + wmm_info_len
+ + turbo_info_len;
+#else
+ len = sizeof(struct ieee80211_assoc_request_frame)+
+ + beacon->ssid_len//essid tagged val
+ + rate_len//rates tagged val
+ + wpa_len
+ + rsn_len
+ + wmm_info_len;
+#endif
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->iw_mode == ieee->iw_ext_mode)
+ skb = dev_alloc_skb(len+256); // stanley
+ else
+#endif
+ skb = dev_alloc_skb(len);
+
+ if (!skb)
+ return NULL;
+
+ hdr = (struct ieee80211_assoc_request_frame *)
+ skb_put(skb, sizeof(struct ieee80211_assoc_request_frame));
+
+
+ hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ;
+ hdr->header.duration_id= 37; //FIXME
+ memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN);
+ memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN);
+ memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN);//for HW security, John
+
+ hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS);
+ if (beacon->capability & WLAN_CAPABILITY_PRIVACY )
+ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
+ if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
+
+ if(ieee->short_slot)
+ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
+
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_association_req_1)
+ ieee->ext_patch_ieee80211_association_req_1(hdr);
+#endif
+
+ hdr->listen_interval = 0xa; //FIXME
+
+ hdr->info_element.id = MFIE_TYPE_SSID;
+
+ hdr->info_element.len = beacon->ssid_len;
+ tag = skb_put(skb, beacon->ssid_len);
+ memcpy(tag, beacon->ssid, beacon->ssid_len);
+
+ tag = skb_put(skb, rate_len);
+
+ ieee80211_MFIE_Brate(ieee, &tag);
+ ieee80211_MFIE_Grate(ieee, &tag);
+
+ //add rsn==0 condition for ap's mix security mode(wpa+wpa2), john2007.8.9
+ //choose AES encryption as default algorithm while using mixed mode
+#if 0
+ if(rsn_len == 0){
+
+ tag = skb_put(skb,wpa_len);
+
+ if(wpa_len) {
+
+
+ //{add by david. 2006.8.31
+ //fix linksys compatibility bug
+ //}
+ if(wpa_len > 24) {//22+2, mean include the capability
+ beacon->wpa_ie[wpa_len - 2] = 0;
+ }
+ //multicast cipher OUI
+ if( beacon->wpa_ie[11]==0x2 ){ //0x0050f202 is the oui of tkip
+ ieee->broadcast_key_type = KEY_TYPE_TKIP;
+ }
+ else if( beacon->wpa_ie[11]==0x4 ){//0x0050f204 is the oui of ccmp
+ ieee->broadcast_key_type = KEY_TYPE_CCMP;
+ }
+ //unicast cipher OUI
+ if( beacon->wpa_ie[14]==0
+ && beacon->wpa_ie[15]==0x50
+ && beacon->wpa_ie[16]==0xf2
+ && beacon->wpa_ie[17]==0x2 ){ //0x0050f202 is the oui of tkip
+ ieee->pairwise_key_type = KEY_TYPE_TKIP;
+ }
+
+ else if( beacon->wpa_ie[14]==0
+ && beacon->wpa_ie[15]==0x50
+ && beacon->wpa_ie[16]==0xf2
+ && beacon->wpa_ie[17]==0x4 ){//0x0050f204 is the oui of ccmp
+ ieee->pairwise_key_type = KEY_TYPE_CCMP;
+ }
+ //indicate the wpa_ie content to WPA_SUPPLICANT
+ buff = kmalloc(IW_CUSTOM_MAX, GFP_ATOMIC);
+ memset(buff, 0, IW_CUSTOM_MAX);
+ p=buff;
+ p += sprintf(p, "ASSOCINFO(ReqIEs=");
+ for(i=0;i<wpa_len;i++){
+ p += sprintf(p, "%02x", beacon->wpa_ie[i]);
+ }
+ p += sprintf(p, ")");
+ memset(&wrqu, 0, sizeof(wrqu) );
+ wrqu.data.length = p - buff;
+
+ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buff);
+ memcpy(tag,beacon->wpa_ie,wpa_len);
+ }
+
+ }
+
+ if(rsn_len > 22) {
+
+ if( beacon->rsn_ie[4]==0x0 &&
+ beacon->rsn_ie[5]==0xf &&
+ beacon->rsn_ie[6]==0xac){
+
+ switch(beacon->rsn_ie[7]){
+ case 0x1:
+ ieee->broadcast_key_type = KEY_TYPE_WEP40;
+ break;
+ case 0x2:
+ ieee->broadcast_key_type = KEY_TYPE_TKIP;
+ break;
+ case 0x4:
+ ieee->broadcast_key_type = KEY_TYPE_CCMP;
+ break;
+ case 0x5:
+ ieee->broadcast_key_type = KEY_TYPE_WEP104;
+ break;
+ default:
+ printk("fault suite type in RSN broadcast key\n");
+ break;
+ }
+ }
+
+ if( beacon->rsn_ie[10]==0x0 &&
+ beacon->rsn_ie[11]==0xf &&
+ beacon->rsn_ie[12]==0xac){
+ if(beacon->rsn_ie[8]==1){//not mixed mode
+ switch(beacon->rsn_ie[13]){
+ case 0x2:
+ ieee->pairwise_key_type = KEY_TYPE_TKIP;
+ break;
+ case 0x4:
+ ieee->pairwise_key_type = KEY_TYPE_CCMP;
+ break;
+ default:
+ printk("fault suite type in RSN pairwise key\n");
+ break;
+ }
+ }
+ else if(beacon->rsn_ie[8]==2){//mixed mode
+ ieee->pairwise_key_type = KEY_TYPE_CCMP;
+ }
+ }
+
+
+
+ tag = skb_put(skb,22);
+ memcpy(tag,(beacon->rsn_ie + info_addr),8);
+ tag[1] = 20;
+ tag += 8;
+ info_addr += 8;
+
+ spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags);
+ for (i = 0; i < 2; i++) {
+ tag[0] = 1;
+ tag[1] = 0;
+ tag += 2;
+ suite_count = beacon->rsn_ie[info_addr] + \
+ (beacon->rsn_ie[info_addr + 1] << 8);
+ info_addr += 2;
+ if(1 == suite_count) {
+ memcpy(tag,(beacon->rsn_ie + info_addr),4);
+ info_addr += 4;
+ } else {
+ // if the wpax_type_notify has been set by the application,
+ // just use it, otherwise just use the default one.
+ if(ieee->wpax_type_set) {
+ suit_select = ((0 == i) ? pairwise_type:authen_type)&0x0f ;
+ memcpy(tag,rsn_authen_cipher_suite[suit_select],4);
+ } else {
+ //default set as ccmp, or none authentication
+ if(i == 0) {
+ memcpy(tag,rsn_authen_cipher_suite[4],4);
+ } else {
+ memcpy(tag,rsn_authen_cipher_suite[2],4);
+ }
+
+ }
+
+ info_addr += (suite_count * 4);
+ }
+ tag += 4;
+ }
+ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags);
+
+ tag[0] = 0;
+ tag[1] = beacon->rsn_ie[info_addr+1];
+
+ } else {
+ tag = skb_put(skb,rsn_len);
+ if(rsn_len) {
+
+
+ if( beacon->rsn_ie[4]==0x0 &&
+ beacon->rsn_ie[5]==0xf &&
+ beacon->rsn_ie[6]==0xac){
+ switch(beacon->rsn_ie[7]){
+ case 0x1:
+ ieee->broadcast_key_type = KEY_TYPE_WEP40;
+ break;
+ case 0x2:
+ ieee->broadcast_key_type = KEY_TYPE_TKIP;
+ break;
+ case 0x4:
+ ieee->broadcast_key_type = KEY_TYPE_CCMP;
+ break;
+ case 0x5:
+ ieee->broadcast_key_type = KEY_TYPE_WEP104;
+ break;
+ default:
+ printk("fault suite type in RSN broadcast key\n");
+ break;
+ }
+ }
+ if( beacon->rsn_ie[10]==0x0 &&
+ beacon->rsn_ie[11]==0xf &&
+ beacon->rsn_ie[12]==0xac){
+ if(beacon->rsn_ie[8]==1){//not mixed mode
+ switch(beacon->rsn_ie[13]){
+ case 0x2:
+ ieee->pairwise_key_type = KEY_TYPE_TKIP;
+ break;
+ case 0x4:
+ ieee->pairwise_key_type = KEY_TYPE_CCMP;
+ break;
+ default:
+ printk("fault suite type in RSN pairwise key\n");
+ break;
+ }
+
+ }
+ else if(beacon->rsn_ie[8]==2){//mixed mode
+ ieee->pairwise_key_type = KEY_TYPE_CCMP;
+ }
+ }
+
+
+ beacon->rsn_ie[rsn_len - 2] = 0;
+ memcpy(tag,beacon->rsn_ie,rsn_len);
+ }
+ }
+#else
+ tag = skb_put(skb,ieee->wpa_ie_len);
+ memcpy(tag,ieee->wpa_ie,ieee->wpa_ie_len);
+#endif
+ tag = skb_put(skb,wmm_info_len);
+ if(wmm_info_len) {
+ ieee80211_WMM_Info(ieee, &tag);
+ }
+#ifdef THOMAS_TURBO
+ tag = skb_put(skb,turbo_info_len);
+ if(turbo_info_len) {
+ ieee80211_TURBO_Info(ieee, &tag);
+ }
+#endif
+
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_association_req_2)
+ ieee->ext_patch_ieee80211_association_req_2(ieee, beacon, skb);
+#endif
+
+ return skb;
+}
+
+void ieee80211_associate_abort(struct ieee80211_device *ieee)
+{
+
+ unsigned long flags;
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ ieee->associate_seq++;
+
+ /* don't scan, and avoid to have the RX path possibily
+ * try again to associate. Even do not react to AUTH or
+ * ASSOC response. Just wait for the retry wq to be scheduled.
+ * Here we will check if there are good nets to associate
+ * with, so we retry or just get back to NO_LINK and scanning
+ */
+ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING){
+ IEEE80211_DEBUG_MGMT("Authentication failed\n");
+ ieee->softmac_stats.no_auth_rs++;
+ }else{
+ IEEE80211_DEBUG_MGMT("Association failed\n");
+ ieee->softmac_stats.no_ass_rs++;
+ }
+
+ ieee->state = IEEE80211_ASSOCIATING_RETRY;
+
+ queue_delayed_work(ieee->wq, &ieee->associate_retry_wq,IEEE80211_SOFTMAC_ASSOC_RETRY_TIME);
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+}
+
+void ieee80211_associate_abort_cb(unsigned long dev)
+{
+ ieee80211_associate_abort((struct ieee80211_device *) dev);
+}
+
+
+void ieee80211_associate_step1(struct ieee80211_device *ieee)
+{
+ struct ieee80211_network *beacon = &ieee->current_network;
+ struct sk_buff *skb;
+
+ IEEE80211_DEBUG_MGMT("Stopping scan\n");
+ ieee->softmac_stats.tx_auth_rq++;
+ skb=ieee80211_authentication_req(beacon, ieee, 0);
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->iw_mode == ieee->iw_ext_mode ) {
+ if(skb)
+ softmac_mgmt_xmit(skb, ieee);
+ return;
+ }else
+#endif
+ if (!skb){
+
+ ieee80211_associate_abort(ieee);
+ }
+ else{
+ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ;
+ IEEE80211_DEBUG_MGMT("Sending authentication request\n");
+ //printk("---Sending authentication request\n");
+ softmac_mgmt_xmit(skb, ieee);
+ //BUGON when you try to add_timer twice, using mod_timer may be better, john0709
+ if(!timer_pending(&ieee->associate_timer)){
+ ieee->associate_timer.expires = jiffies + (HZ / 2);
+ add_timer(&ieee->associate_timer);
+ }
+ //If call dev_kfree_skb_any,a warning will ocur....
+ //KERNEL: assertion (!atomic_read(&skb->users)) failed at net/core/dev.c (1708)
+ //So ... 1204 by lawrence.
+ //printk("\nIn %s,line %d call kfree skb.",__func__,__LINE__);
+ //dev_kfree_skb_any(skb);//edit by thomas
+ }
+}
+
+void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
+{
+ u8 *c;
+ struct sk_buff *skb;
+ struct ieee80211_network *beacon = &ieee->current_network;
+// int hlen = sizeof(struct ieee80211_authentication);
+ del_timer_sync(&ieee->associate_timer);
+ ieee->associate_seq++;
+ ieee->softmac_stats.tx_auth_rq++;
+
+ skb = ieee80211_authentication_req(beacon, ieee, chlen+2);
+ if (!skb)
+ ieee80211_associate_abort(ieee);
+ else{
+ c = skb_put(skb, chlen+2);
+ *(c++) = MFIE_TYPE_CHALLENGE;
+ *(c++) = chlen;
+ memcpy(c, challenge, chlen);
+
+ IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n");
+
+ ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr ));
+
+ softmac_mgmt_xmit(skb, ieee);
+ if (!timer_pending(&ieee->associate_timer)){
+ //printk("=========>add timer again, to crash\n");
+ ieee->associate_timer.expires = jiffies + (HZ / 2);
+ add_timer(&ieee->associate_timer);
+ }
+ dev_kfree_skb_any(skb);//edit by thomas
+ }
+ kfree(challenge);
+}
+
+#ifdef _RTL8187_EXT_PATCH_
+
+// based on ieee80211_assoc_resp
+struct sk_buff* ieee80211_assoc_resp_by_net(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type)
+{
+ struct sk_buff *skb;
+ u8* tag;
+
+ struct ieee80211_crypt_data* crypt;
+ struct ieee80211_assoc_response_frame *assoc;
+ short encrypt;
+
+ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee);
+ int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len;
+
+ if(ieee->iw_mode == ieee->iw_ext_mode)
+ skb = dev_alloc_skb(len+256); // stanley
+ else
+ skb = dev_alloc_skb(len);
+
+ if (!skb)
+ return NULL;
+
+ assoc = (struct ieee80211_assoc_response_frame *)
+ skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
+
+ assoc->header.frame_ctl = cpu_to_le16(pkt_type);
+
+ memcpy(assoc->header.addr1, dest,ETH_ALEN);
+ memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ?
+ WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS);
+
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_assoc_resp_by_net_1)
+ ieee->ext_patch_ieee80211_assoc_resp_by_net_1(assoc);
+
+ if(ieee->short_slot)
+ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
+
+ if (ieee->host_encrypt)
+ crypt = ieee->crypt[ieee->tx_keyidx];
+ else crypt = NULL;
+
+ encrypt = ( crypt && crypt->ops);
+
+ if (encrypt)
+ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
+
+ assoc->status = 0;
+ assoc->aid = cpu_to_le16(ieee->assoc_id);
+ if (ieee->assoc_id == 0x2007) ieee->assoc_id=0;
+ else ieee->assoc_id++;
+
+ assoc->info_element.id = 230; // Stanley, an unused id (just a hot fix)
+ assoc->info_element.len = 0;
+
+ tag = (u8*) skb_put(skb, rate_len);
+
+ ieee80211_MFIE_Brate(ieee, &tag);
+ ieee80211_MFIE_Grate(ieee, &tag);
+
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_assoc_resp_by_net_2)
+ ieee->ext_patch_ieee80211_assoc_resp_by_net_2(ieee, pstat, pkt_type, skb);
+
+ return skb;
+}
+
+// based on ieee80211_resp_to_assoc_rq
+void ieee80211_ext_issue_assoc_rsp(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type)
+{
+ struct sk_buff *buf = ieee80211_assoc_resp_by_net(ieee, dest, status, pstat, pkt_type);
+
+ if (buf)
+ softmac_mgmt_xmit(buf, ieee);
+}
+
+// based on ieee80211_associate_step2
+void ieee80211_ext_issue_assoc_req(struct ieee80211_device *ieee, struct ieee80211_network *pstat)
+{
+
+ struct sk_buff* skb;
+
+ // printk("@@@@@ ieee80211_ext_issue_assoc_req on channel: %d\n", ieee->current_network.channel);
+
+ ieee->softmac_stats.tx_ass_rq++;
+ skb=ieee80211_association_req(pstat, ieee);
+ if (skb)
+ softmac_mgmt_xmit(skb, ieee);
+}
+
+void ieee80211_ext_issue_disassoc(struct ieee80211_device *ieee, struct ieee80211_network *pstat, int reason, unsigned char extReason)
+{
+ // do nothing
+ // printk("@@@@@ ieee80211_ext_issue_disassoc\n");
+ return;
+}
+#endif // _RTL8187_EXT_PATCH_
+
+void ieee80211_associate_step2(struct ieee80211_device *ieee)
+{
+ struct sk_buff* skb;
+ struct ieee80211_network *beacon = &ieee->current_network;
+
+ del_timer_sync(&ieee->associate_timer);
+
+ IEEE80211_DEBUG_MGMT("Sending association request\n");
+ ieee->softmac_stats.tx_ass_rq++;
+ skb=ieee80211_association_req(beacon, ieee);
+ if (!skb)
+ ieee80211_associate_abort(ieee);
+ else{
+ softmac_mgmt_xmit(skb, ieee);
+ if (!timer_pending(&ieee->associate_timer)){
+ ieee->associate_timer.expires = jiffies + (HZ / 2);
+ add_timer(&ieee->associate_timer);
+ }
+ //dev_kfree_skb_any(skb);//edit by thomas
+ }
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void ieee80211_associate_complete_wq(struct work_struct *work)
+{
+ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq);
+#else
+void ieee80211_associate_complete_wq(struct ieee80211_device *ieee)
+{
+#endif
+ printk(KERN_INFO "Associated successfully\n");
+ if(ieee80211_is_54g(ieee->current_network) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION)){
+
+ ieee->rate = 540;
+ printk(KERN_INFO"Using G rates\n");
+ }else{
+ ieee->rate = 110;
+ printk(KERN_INFO"Using B rates\n");
+ }
+ ieee->link_change(ieee->dev);
+ notify_wx_assoc_event(ieee);
+ if (ieee->data_hard_resume)
+ ieee->data_hard_resume(ieee->dev);
+ netif_carrier_on(ieee->dev);
+}
+
+void ieee80211_associate_complete(struct ieee80211_device *ieee)
+{
+ int i;
+ del_timer_sync(&ieee->associate_timer);
+
+ for(i = 0; i < 6; i++) {
+ //ieee->seq_ctrl[i] = 0;
+ }
+ ieee->state = IEEE80211_LINKED;
+ IEEE80211_DEBUG_MGMT("Successfully associated\n");
+
+ queue_work(ieee->wq, &ieee->associate_complete_wq);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void ieee80211_associate_procedure_wq(struct work_struct *work)
+{
+ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq);
+#else
+void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee)
+{
+#endif
+ ieee->sync_scan_hurryup = 1;
+ down(&ieee->wx_sem);
+
+ if (ieee->data_hard_stop)
+ ieee->data_hard_stop(ieee->dev);
+
+ ieee80211_stop_scan(ieee);
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+
+ ieee->associate_seq = 1;
+ ieee80211_associate_step1(ieee);
+
+ up(&ieee->wx_sem);
+}
+#ifdef _RTL8187_EXT_PATCH_
+// based on ieee80211_associate_procedure_wq
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+void ieee80211_ext_stop_scan_wq(struct work_struct *work)
+{
+ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ext_stop_scan_wq);
+#else
+void ieee80211_ext_stop_scan_wq(struct ieee80211_device *ieee)
+{
+#endif
+ if (ieee->scanning == 0)
+ {
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel
+ && ( ieee->current_network.channel == ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee) ) )
+ return;
+ }
+
+ ieee->sync_scan_hurryup = 1;
+
+ down(&ieee->wx_sem);
+
+ // printk("@@@@@@@@@@ ieee80211_ext_stop_scan_wq\n");
+ if (ieee->data_hard_stop)
+ ieee->data_hard_stop(ieee->dev);
+
+ ieee80211_stop_scan(ieee);
+
+ // set channel
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel)
+ ieee->set_chan(ieee->dev, ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee));
+ else
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+ //
+ up(&ieee->wx_sem);
+}
+
+
+void ieee80211_ext_send_11s_beacon(struct ieee80211_device *ieee)
+{
+ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ queue_work(ieee->wq, &ieee->ext_send_beacon_wq);
+ #else
+ schedule_task(&ieee->ext_send_beacon_wq);
+ #endif
+
+}
+
+#endif // _RTL8187_EXT_PATCH_
+
+inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net)
+{
+ u8 tmp_ssid[IW_ESSID_MAX_SIZE+1];
+ int tmp_ssid_len = 0;
+
+ short apset,ssidset,ssidbroad,apmatch,ssidmatch;
+
+ /* we are interested in new new only if we are not associated
+ * and we are not associating / authenticating
+ */
+ if (ieee->state != IEEE80211_NOLINK)
+ return;
+
+ if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_BSS))
+ return;
+
+ if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS))
+ return;
+
+
+ if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){
+ /* if the user specified the AP MAC, we need also the essid
+ * This could be obtained by beacons or, if the network does not
+ * broadcast it, it can be put manually.
+ */
+ apset = ieee->wap_set;//(memcmp(ieee->current_network.bssid, zero,ETH_ALEN)!=0 );
+ ssidset = ieee->ssid_set;//ieee->current_network.ssid[0] != '\0';
+ ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0');
+ apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0);
+
+ if(ieee->current_network.ssid_len != net->ssid_len)
+ ssidmatch = 0;
+ else
+ ssidmatch = (0==strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len));
+
+ //printk("cur: %s, %d, net:%s, %d\n", ieee->current_network.ssid, ieee->current_network.ssid_len, net->ssid, net->ssid_len);
+ //printk("apset=%d apmatch=%d ssidset=%d ssidbroad=%d ssidmatch=%d\n",apset,apmatch,ssidset,ssidbroad,ssidmatch);
+
+ if ( /* if the user set the AP check if match.
+ * if the network does not broadcast essid we check the user supplyed ANY essid
+ * if the network does broadcast and the user does not set essid it is OK
+ * if the network does broadcast and the user did set essid chech if essid match
+ */
+ ( apset && apmatch &&
+ ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) ||
+ /* if the ap is not set, check that the user set the bssid
+ * and the network does bradcast and that those two bssid matches
+ */
+ (!apset && ssidset && ssidbroad && ssidmatch)
+ ){
+
+
+ /* if the essid is hidden replace it with the
+ * essid provided by the user.
+ */
+ if (!ssidbroad){
+ strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE);
+ tmp_ssid_len = ieee->current_network.ssid_len;
+ }
+ memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network));
+
+ if (!ssidbroad){
+ strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE);
+ ieee->current_network.ssid_len = tmp_ssid_len;
+ }
+ printk(KERN_INFO"Linking with %s: channel is %d\n",ieee->current_network.ssid,ieee->current_network.channel);
+
+ if (ieee->iw_mode == IW_MODE_INFRA){
+ ieee->state = IEEE80211_ASSOCIATING;
+ ieee->beinretry = false;
+ queue_work(ieee->wq, &ieee->associate_procedure_wq);
+ }else{
+ if(ieee80211_is_54g(ieee->current_network) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION)){
+ ieee->rate = 540;
+ printk(KERN_INFO"Using G rates\n");
+ }else{
+ ieee->rate = 110;
+ printk(KERN_INFO"Using B rates\n");
+ }
+ ieee->state = IEEE80211_LINKED;
+ ieee->beinretry = false;
+ }
+
+ }
+ }
+
+}
+
+void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee)
+{
+ unsigned long flags;
+ struct ieee80211_network *target;
+
+ spin_lock_irqsave(&ieee->lock, flags);
+ list_for_each_entry(target, &ieee->network_list, list) {
+
+ /* if the state become different that NOLINK means
+ * we had found what we are searching for
+ */
+
+ if (ieee->state != IEEE80211_NOLINK)
+ break;
+
+ if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies))
+ ieee80211_softmac_new_net(ieee, target);
+ }
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+}
+
+
+static inline u16 auth_parse(struct sk_buff *skb, u8** challenge, int *chlen)
+{
+ struct ieee80211_authentication *a;
+ u8 *t;
+ if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){
+ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len);
+ return 0xcafe;
+ }
+ *challenge = NULL;
+ a = (struct ieee80211_authentication*) skb->data;
+ if(skb->len > (sizeof(struct ieee80211_authentication) +3)){
+ t = skb->data + sizeof(struct ieee80211_authentication);
+
+ if(*(t++) == MFIE_TYPE_CHALLENGE){
+ *chlen = *(t++);
+ *challenge = (u8*)kmalloc(*chlen, GFP_ATOMIC);
+ memcpy(*challenge, t, *chlen);
+ }
+ }
+
+ return cpu_to_le16(a->status);
+
+}
+
+
+int auth_rq_parse(struct sk_buff *skb,u8* dest)
+{
+ struct ieee80211_authentication *a;
+
+ if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){
+ IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len);
+ return -1;
+ }
+ a = (struct ieee80211_authentication*) skb->data;
+
+ memcpy(dest,a->header.addr2, ETH_ALEN);
+
+ if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN)
+ return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *src)
+{
+ u8 *tag;
+ u8 *skbend;
+ u8 *ssid=NULL;
+ u8 ssidlen = 0;
+
+ struct ieee80211_hdr_3addr *header =
+ (struct ieee80211_hdr_3addr *) skb->data;
+
+ if (skb->len < sizeof (struct ieee80211_hdr_3addr ))
+ return -1; /* corrupted */
+
+ memcpy(src,header->addr2, ETH_ALEN);
+
+ skbend = (u8*)skb->data + skb->len;
+
+ tag = skb->data + sizeof (struct ieee80211_hdr_3addr );
+
+ while (tag+1 < skbend){
+ if (*tag == 0){
+ ssid = tag+2;
+ ssidlen = *(tag+1);
+ break;
+ }
+ tag++; /* point to the len field */
+ tag = tag + *(tag); /* point to the last data byte of the tag */
+ tag++; /* point to the next tag */
+ }
+
+ //IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src));
+ if (ssidlen == 0) return 1;
+
+ if (!ssid) return 1; /* ssid not found in tagged param */
+ return (!strncmp(ssid, ieee->current_network.ssid, ssidlen));
+
+}
+
+int assoc_rq_parse(struct sk_buff *skb,u8* dest)
+{
+ struct ieee80211_assoc_request_frame *a;
+
+ if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) -
+ sizeof(struct ieee80211_info_element))) {
+
+ IEEE80211_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len);
+ return -1;
+ }
+
+ a = (struct ieee80211_assoc_request_frame*) skb->data;
+
+ memcpy(dest,a->header.addr2,ETH_ALEN);
+
+ return 0;
+}
+
+static inline u16 assoc_parse(struct sk_buff *skb, int *aid)
+{
+ struct ieee80211_assoc_response_frame *a;
+ if (skb->len < sizeof(struct ieee80211_assoc_response_frame)){
+ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len);
+ return 0xcafe;
+ }
+
+ a = (struct ieee80211_assoc_response_frame*) skb->data;
+ *aid = le16_to_cpu(a->aid) & 0x3fff;
+ return le16_to_cpu(a->status);
+}
+
+static inline void
+ieee80211_rx_probe_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
+{
+ u8 dest[ETH_ALEN];
+
+ //IEEE80211DMESG("Rx probe");
+ ieee->softmac_stats.rx_probe_rq++;
+ //DMESG("Dest is "MACSTR, MAC2STR(dest));
+ if (probe_rq_parse(ieee, skb, dest)){
+ //IEEE80211DMESG("Was for me!");
+ ieee->softmac_stats.tx_probe_rs++;
+ ieee80211_resp_to_probe(ieee, dest);
+ }
+}
+
+inline void
+ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
+{
+ u8 dest[ETH_ALEN];
+ int status;
+ //IEEE80211DMESG("Rx probe");
+ ieee->softmac_stats.rx_auth_rq++;
+
+ if ((status = auth_rq_parse(skb, dest))!= -1){
+ ieee80211_resp_to_auth(ieee, status, dest);
+ }
+ //DMESG("Dest is "MACSTR, MAC2STR(dest));
+
+}
+
+ inline void
+ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
+{
+
+ u8 dest[ETH_ALEN];
+ //unsigned long flags;
+
+ ieee->softmac_stats.rx_ass_rq++;
+ if (assoc_rq_parse(skb,dest) != -1){
+ ieee80211_resp_to_assoc_rq(ieee, dest);
+ }
+
+ printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest));
+ //FIXME
+ #if 0
+ spin_lock_irqsave(&ieee->lock,flags);
+ add_associate(ieee,dest);
+ spin_unlock_irqrestore(&ieee->lock,flags);
+ #endif
+}
+
+
+
+void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr)
+{
+
+ struct sk_buff *buf = ieee80211_null_func(ieee, pwr);
+
+ if (buf)
+ softmac_ps_mgmt_xmit(buf, ieee);
+
+}
+
+
+short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l)
+{
+#if 0
+ int timeout = ieee->ps_timeout;
+#else
+ int timeout = 0;
+#endif
+ u8 dtim;
+ /*if(ieee->ps == IEEE80211_PS_DISABLED ||
+ ieee->iw_mode != IW_MODE_INFRA ||
+ ieee->state != IEEE80211_LINKED)
+
+ return 0;
+ */
+ dtim = ieee->current_network.dtim_data;
+ //printk("DTIM\n");
+
+ if(!(dtim & IEEE80211_DTIM_VALID))
+ return 0;
+ else
+ timeout = ieee->current_network.beacon_interval;
+
+ //printk("VALID\n");
+ ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID;
+
+ if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps))
+ return 2;
+
+ if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout)))
+ return 0;
+
+ if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout)))
+ return 0;
+
+ if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) &&
+ (ieee->mgmt_queue_tail != ieee->mgmt_queue_head))
+ return 0;
+#if 0
+ if(time_l){
+ *time_l = ieee->current_network.last_dtim_sta_time[0]
+ + (ieee->current_network.beacon_interval
+ * ieee->current_network.dtim_period) * 1000;
+ }
+#else
+ if(time_l){
+ *time_l = ieee->current_network.last_dtim_sta_time[0]
+ + MSECS((ieee->current_network.beacon_interval));
+ //* ieee->current_network.dtim_period));
+ //printk("beacon_interval:%x, dtim_period:%x, totol to Msecs:%x, HZ:%x\n", ieee->current_network.beacon_interval, ieee->current_network.dtim_period, MSECS(((ieee->current_network.beacon_interval * ieee->current_network.dtim_period))), HZ);
+ }
+
+#endif
+ if(time_h){
+ *time_h = ieee->current_network.last_dtim_sta_time[1];
+ if(time_l && *time_l < ieee->current_network.last_dtim_sta_time[0])
+ *time_h += 1;
+ }
+
+ return 1;
+
+
+}
+
+inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
+{
+
+ u32 th,tl;
+ short sleep;
+
+ unsigned long flags,flags2;
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ if((ieee->ps == IEEE80211_PS_DISABLED ||
+
+ ieee->iw_mode != IW_MODE_INFRA ||
+ ieee->state != IEEE80211_LINKED)){
+
+ //#warning CHECK_LOCK_HERE
+ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
+
+ ieee80211_sta_wakeup(ieee, 1);
+
+ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
+ }
+
+ sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl);
+// printk("===>%s,%d[2 wake, 1 sleep, 0 do nothing], ieee->sta_sleep = %d\n",__func__, sleep,ieee->sta_sleep);
+ /* 2 wake, 1 sleep, 0 do nothing */
+ if(sleep == 0)
+ goto out;
+
+ if(sleep == 1){
+
+ if(ieee->sta_sleep == 1)
+ ieee->enter_sleep_state(ieee->dev,th,tl);
+
+ else if(ieee->sta_sleep == 0){
+ // printk("send null 1\n");
+ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
+
+ if(ieee->ps_is_queue_empty(ieee->dev)){
+
+
+ ieee->sta_sleep = 2;
+
+ ieee->ps_request_tx_ack(ieee->dev);
+
+ ieee80211_sta_ps_send_null_frame(ieee,1);
+
+ ieee->ps_th = th;
+ ieee->ps_tl = tl;
+ }
+ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
+
+ }
+
+
+ }else if(sleep == 2){
+//#warning CHECK_LOCK_HERE
+ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
+
+ // printk("send wakeup packet\n");
+ ieee80211_sta_wakeup(ieee,1);
+
+ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
+ }
+
+out:
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+}
+
+void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl)
+{
+ if(ieee->sta_sleep == 0){
+ if(nl){
+ // printk("Warning: driver is probably failing to report TX ps error\n");
+ ieee->ps_request_tx_ack(ieee->dev);
+ ieee80211_sta_ps_send_null_frame(ieee, 0);
+ }
+ return;
+
+ }
+
+ if(ieee->sta_sleep == 1)
+ ieee->sta_wake_up(ieee->dev);
+
+ ieee->sta_sleep = 0;
+
+ if(nl){
+ ieee->ps_request_tx_ack(ieee->dev);
+ ieee80211_sta_ps_send_null_frame(ieee, 0);
+ }
+}
+
+void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success)
+{
+ unsigned long flags,flags2;
+
+ spin_lock_irqsave(&ieee->lock, flags);
+ if(ieee->sta_sleep == 2){
+ /* Null frame with PS bit set */
+ if(success){
+
+ // printk("==================> %s::enter sleep state\n",__func__);
+ ieee->sta_sleep = 1;
+ ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl);
+ }
+ /* if the card report not success we can't be sure the AP
+ * has not RXed so we can't assume the AP believe us awake
+ */
+ }
+ /* 21112005 - tx again null without PS bit if lost */
+ else {
+
+ if((ieee->sta_sleep == 0) && !success){
+ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
+ ieee80211_sta_ps_send_null_frame(ieee, 0);
+ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
+ }
+ }
+ spin_unlock_irqrestore(&ieee->lock, flags);
+}
+
+inline int
+ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats, u16 type,
+ u16 stype)
+{
+ struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data;
+ u16 errcode;
+ u8* challenge=NULL;
+ int chlen=0;
+ int aid=0;
+ struct ieee80211_assoc_response_frame *assoc_resp;
+ struct ieee80211_info_element *info_element;
+
+ if(!ieee->proto_started)
+ return 0;
+
+ if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED &&
+ ieee->iw_mode == IW_MODE_INFRA &&
+ ieee->state == IEEE80211_LINKED))
+
+ tasklet_schedule(&ieee->ps_task);
+
+ if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP &&
+ WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON)
+ ieee->last_rx_ps_time = jiffies;
+
+ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
+
+ case IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_STYPE_REASSOC_RESP:
+
+ IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
+ ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED &&
+ ieee->iw_mode == IW_MODE_INFRA){
+ if (0 == (errcode=assoc_parse(skb, &aid))){
+ u16 left;
+
+ ieee->state=IEEE80211_LINKED;
+ ieee->assoc_id = aid;
+ ieee->softmac_stats.rx_ass_ok++;
+
+ //printk(KERN_WARNING "nic_type = %s", (rx_stats->nic_type == 1)?"rtl8187":"rtl8187B");
+ if(1 == rx_stats->nic_type) //card type is 8187
+ {
+ goto associate_complete;
+ }
+ assoc_resp = (struct ieee80211_assoc_response_frame*)skb->data;
+ info_element = &assoc_resp->info_element;
+ left = skb->len - ((void*)info_element - (void*)assoc_resp);
+
+ while (left >= sizeof(struct ieee80211_info_element_hdr)) {
+ if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) {
+ printk(KERN_WARNING "[re]associate reeponse error!");
+ return 1;
+ }
+ switch (info_element->id) {
+ case MFIE_TYPE_GENERIC:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", info_element->len);
+ if (info_element->len >= 8 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0x50 &&
+ info_element->data[2] == 0xf2 &&
+ info_element->data[3] == 0x02 &&
+ info_element->data[4] == 0x01) {
+ // Not care about version at present.
+ //WMM Parameter Element
+ memcpy(ieee->current_network.wmm_param,(u8*)(info_element->data\
+ + 8),(info_element->len - 8));
+
+ if (((ieee->current_network.wmm_info^info_element->data[6])& \
+ 0x0f)||(!ieee->init_wmmparam_flag)) {
+ //refresh paramete element for current network
+ // update the register parameter for hardware
+ ieee->init_wmmparam_flag = 1;
+ queue_work(ieee->wq, &ieee->wmm_param_update_wq);
+
+ }
+ //update info_element for current network
+ ieee->current_network.wmm_info = info_element->data[6];
+ }
+ break;
+ default:
+ //nothing to do at present!!!
+ break;
+ }
+
+ left -= sizeof(struct ieee80211_info_element_hdr) +
+ info_element->len;
+ info_element = (struct ieee80211_info_element *)
+ &info_element->data[info_element->len];
+ }
+ if(!ieee->init_wmmparam_flag) //legacy AP, reset the AC_xx_param register
+ {
+ queue_work(ieee->wq,&ieee->wmm_param_update_wq);
+ ieee->init_wmmparam_flag = 1;//indicate AC_xx_param upated since last associate
+ }
+associate_complete:
+ ieee80211_associate_complete(ieee);
+ }else{
+ ieee->softmac_stats.rx_ass_err++;
+ IEEE80211_DEBUG_MGMT(
+ "Association response status code 0x%x\n",
+ errcode);
+ ieee80211_associate_abort(ieee);
+ }
+ }
+#ifdef _RTL8187_EXT_PATCH_
+ else if ((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp)
+ {
+ ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp(ieee, skb);
+ }
+#endif
+ break;
+
+ case IEEE80211_STYPE_ASSOC_REQ:
+ case IEEE80211_STYPE_REASSOC_REQ:
+
+ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
+ ieee->iw_mode == IW_MODE_MASTER)
+
+ ieee80211_rx_assoc_rq(ieee, skb);
+#ifdef _RTL8187_EXT_PATCH_
+ else if ((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req)
+ {
+ ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req(ieee, skb);
+ }
+#endif
+ break;
+
+ case IEEE80211_STYPE_AUTH:
+
+#ifdef _RTL8187_EXT_PATCH_
+printk("IEEE80211_STYPE_AUTH\n");
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_auth)
+ if( ieee->ext_patch_ieee80211_rx_frame_softmac_on_auth(ieee, skb, rx_stats) );
+#endif
+ if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){
+ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING &&
+ ieee->iw_mode == IW_MODE_INFRA){
+
+ IEEE80211_DEBUG_MGMT("Received authentication response");
+
+ if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){
+ if(ieee->open_wep || !challenge){
+ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED;
+ ieee->softmac_stats.rx_auth_rs_ok++;
+
+ ieee80211_associate_step2(ieee);
+ }else{
+ ieee80211_auth_challenge(ieee, challenge, chlen);
+ }
+ }else{
+ ieee->softmac_stats.rx_auth_rs_err++;
+ IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode);
+ ieee80211_associate_abort(ieee);
+ }
+
+ }else if (ieee->iw_mode == IW_MODE_MASTER){
+ ieee80211_rx_auth_rq(ieee, skb);
+ }
+ }
+ break;
+
+ case IEEE80211_STYPE_PROBE_REQ:
+
+ if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) &&
+ ((ieee->iw_mode == IW_MODE_ADHOC ||
+ ieee->iw_mode == IW_MODE_MASTER) &&
+ ieee->state == IEEE80211_LINKED))
+
+ ieee80211_rx_probe_rq(ieee, skb);
+ break;
+
+ case IEEE80211_STYPE_DISASSOC:
+ case IEEE80211_STYPE_DEAUTH:
+#ifdef _RTL8187_EXT_PATCH_
+printk("IEEE80211_STYPE_DEAUTH\n");
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_deauth)
+ if( ieee->ext_patch_ieee80211_rx_frame_softmac_on_deauth(ieee, skb, rx_stats) ) ;
+#endif
+ /* FIXME for now repeat all the association procedure
+ * both for disassociation and deauthentication
+ */
+ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
+ (ieee->state == IEEE80211_LINKED) &&
+ (ieee->iw_mode == IW_MODE_INFRA) &&
+ (!memcmp(header->addr2,ieee->current_network.bssid,ETH_ALEN))){
+ ieee->state = IEEE80211_ASSOCIATING;
+ ieee->softmac_stats.reassoc++;
+
+ //notify_wx_assoc_event(ieee); //YJ,del,080828, do not notify os here
+ queue_work(ieee->wq, &ieee->associate_procedure_wq);
+ }
+
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ //dev_kfree_skb_any(skb);
+ return 0;
+}
+
+
+
+/* following are for a simplier TX queue management.
+ * Instead of using netif_[stop/wake]_queue the driver
+ * will uses these two function (plus a reset one), that
+ * will internally uses the kernel netif_* and takes
+ * care of the ieee802.11 fragmentation.
+ * So the driver receives a fragment per time and might
+ * call the stop function when it want without take care
+ * to have enought room to TX an entire packet.
+ * This might be useful if each fragment need it's own
+ * descriptor, thus just keep a total free memory > than
+ * the max fragmentation treshold is not enought.. If the
+ * ieee802.11 stack passed a TXB struct then you needed
+ * to keep N free descriptors where
+ * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD
+ * In this way you need just one and the 802.11 stack
+ * will take care of buffering fragments and pass them to
+ * to the driver later, when it wakes the queue.
+ */
+
+void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee)
+{
+
+
+ unsigned long flags;
+ int i;
+#ifdef _RTL8187_EXT_PATCH_
+ int rate = ieee->rate;
+#endif
+
+ spin_lock_irqsave(&ieee->lock,flags);
+ #if 0
+ if(ieee->queue_stop){
+ IEEE80211DMESG("EE: IEEE hard_start_xmit invoked when kernel queue should be stopped");
+ netif_stop_queue(ieee->dev);
+ ieee->ieee_stats.swtxstop++;
+ //dev_kfree_skb_any(skb);
+ err = 1;
+ goto exit;
+ }
+
+ ieee->stats.tx_bytes+=skb->len;
+
+
+ txb=ieee80211_skb_to_txb(ieee,skb);
+
+
+ if(txb==NULL){
+ IEEE80211DMESG("WW: IEEE stack failed to provide txb");
+ //dev_kfree_skb_any(skb);
+ err = 1;
+ goto exit;
+ }
+ #endif
+
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_softmac_xmit_get_rate && txb->nr_frags)
+ {
+ rate = ieee->ext_patch_ieee80211_softmac_xmit_get_rate(ieee, txb->fragments[0]);
+ }
+#endif
+ /* called with 2nd parm 0, no tx mgmt lock required */
+ ieee80211_sta_wakeup(ieee,0);
+
+ for(i = 0; i < txb->nr_frags; i++) {
+
+ if (ieee->queue_stop){
+ ieee->tx_pending.txb = txb;
+ ieee->tx_pending.frag = i;
+ goto exit;
+ }else{
+ ieee->softmac_data_hard_start_xmit(
+ txb->fragments[i],
+#ifdef _RTL8187_EXT_PATCH_
+ ieee->dev, rate);
+#else
+ ieee->dev,ieee->rate);
+#endif
+ //(i+1)<txb->nr_frags);
+ ieee->stats.tx_packets++;
+ ieee->stats.tx_bytes += txb->fragments[i]->len;
+ ieee->dev->trans_start = jiffies;
+ }
+ }
+
+ ieee80211_txb_free(txb);
+
+ exit:
+ spin_unlock_irqrestore(&ieee->lock,flags);
+
+}
+
+/* called with ieee->lock acquired */
+void ieee80211_resume_tx(struct ieee80211_device *ieee)
+{
+ int i;
+ for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) {
+
+ if (ieee->queue_stop){
+ ieee->tx_pending.frag = i;
+ return;
+ }else{
+
+ ieee->softmac_data_hard_start_xmit(
+ ieee->tx_pending.txb->fragments[i],
+ ieee->dev,ieee->rate);
+ //(i+1)<ieee->tx_pending.txb->nr_frags);
+ ieee->stats.tx_packets++;
+ ieee->dev->trans_start = jiffies;
+ }
+ }
+
+
+ ieee80211_txb_free(ieee->tx_pending.txb);
+ ieee->tx_pending.txb = NULL;
+}
+
+
+void ieee80211_reset_queue(struct ieee80211_device *ieee)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ieee->lock,flags);
+ init_mgmt_queue(ieee);
+ if (ieee->tx_pending.txb){
+ ieee80211_txb_free(ieee->tx_pending.txb);
+ ieee->tx_pending.txb = NULL;
+ }
+ ieee->queue_stop = 0;
+ spin_unlock_irqrestore(&ieee->lock,flags);
+
+}
+
+void ieee80211_wake_queue(struct ieee80211_device *ieee)
+{
+
+ unsigned long flags;
+ struct sk_buff *skb;
+ struct ieee80211_hdr_3addr *header;
+
+ spin_lock_irqsave(&ieee->lock,flags);
+ if (! ieee->queue_stop) goto exit;
+
+ ieee->queue_stop = 0;
+
+ if(ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){
+ while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){
+
+ header = (struct ieee80211_hdr_3addr *) skb->data;
+
+ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+
+ if (ieee->seq_ctrl[0] == 0xFFF)
+ ieee->seq_ctrl[0] = 0;
+ else
+ ieee->seq_ctrl[0]++;
+
+ //printk(KERN_ALERT "ieee80211_wake_queue \n");
+ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
+ dev_kfree_skb_any(skb);//edit by thomas
+ }
+ }
+ if (!ieee->queue_stop && ieee->tx_pending.txb)
+ ieee80211_resume_tx(ieee);
+
+ if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){
+ ieee->softmac_stats.swtxawake++;
+ netif_wake_queue(ieee->dev);
+ }
+
+exit :
+ spin_unlock_irqrestore(&ieee->lock,flags);
+}
+
+
+void ieee80211_stop_queue(struct ieee80211_device *ieee)
+{
+ //unsigned long flags;
+ //spin_lock_irqsave(&ieee->lock,flags);
+
+ if (! netif_queue_stopped(ieee->dev)){
+ netif_stop_queue(ieee->dev);
+ ieee->softmac_stats.swtxstop++;
+ }
+ ieee->queue_stop = 1;
+ //spin_unlock_irqrestore(&ieee->lock,flags);
+
+}
+
+
+inline void ieee80211_randomize_cell(struct ieee80211_device *ieee)
+{
+
+ get_random_bytes(ieee->current_network.bssid, ETH_ALEN);
+
+ /* an IBSS cell address must have the two less significant
+ * bits of the first byte = 2
+ */
+ ieee->current_network.bssid[0] &= ~0x01;
+ ieee->current_network.bssid[0] |= 0x02;
+}
+
+/* called in user context only */
+void ieee80211_start_master_bss(struct ieee80211_device *ieee)
+{
+ ieee->assoc_id = 1;
+
+ if (ieee->current_network.ssid_len == 0){
+ strncpy(ieee->current_network.ssid,
+ IEEE80211_DEFAULT_TX_ESSID,
+ IW_ESSID_MAX_SIZE);
+
+ ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID);
+ ieee->ssid_set = 1;
+ }
+
+ memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN);
+
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+ ieee->state = IEEE80211_LINKED;
+ ieee->link_change(ieee->dev);
+ notify_wx_assoc_event(ieee);
+
+ if (ieee->data_hard_resume)
+ ieee->data_hard_resume(ieee->dev);
+
+ netif_carrier_on(ieee->dev);
+}
+
+void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
+{
+ if(ieee->raw_tx){
+
+ if (ieee->data_hard_resume)
+ ieee->data_hard_resume(ieee->dev);
+
+ netif_carrier_on(ieee->dev);
+ }
+}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void ieee80211_start_ibss_wq(struct work_struct *work)
+{
+ struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq);
+#else
+void ieee80211_start_ibss_wq(struct ieee80211_device *ieee)
+{
+#endif
+
+ /* iwconfig mode ad-hoc will schedule this and return
+ * on the other hand this will block further iwconfig SET
+ * operations because of the wx_sem hold.
+ * Anyway some most set operations set a flag to speed-up
+ * (abort) this wq (when syncro scanning) before sleeping
+ * on the semaphore
+ */
+
+ down(&ieee->wx_sem);
+
+
+ if (ieee->current_network.ssid_len == 0){
+ strcpy(ieee->current_network.ssid,IEEE80211_DEFAULT_TX_ESSID);
+ ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID);
+ ieee->ssid_set = 1;
+ }
+
+ /* check if we have this cell in our network list */
+ ieee80211_softmac_check_all_nets(ieee);
+
+#ifdef ENABLE_DOT11D
+ if(ieee->state == IEEE80211_NOLINK)
+ ieee->current_network.channel = 10;
+#endif
+ /* if not then the state is not linked. Maybe the user swithced to
+ * ad-hoc mode just after being in monitor mode, or just after
+ * being very few time in managed mode (so the card have had no
+ * time to scan all the chans..) or we have just run up the iface
+ * after setting ad-hoc mode. So we have to give another try..
+ * Here, in ibss mode, should be safe to do this without extra care
+ * (in bss mode we had to make sure no-one tryed to associate when
+ * we had just checked the ieee->state and we was going to start the
+ * scan) beacause in ibss mode the ieee80211_new_net function, when
+ * finds a good net, just set the ieee->state to IEEE80211_LINKED,
+ * so, at worst, we waste a bit of time to initiate an unneeded syncro
+ * scan, that will stop at the first round because it sees the state
+ * associated.
+ */
+ if (ieee->state == IEEE80211_NOLINK)
+ ieee80211_start_scan_syncro(ieee);
+
+ /* the network definitively is not here.. create a new cell */
+ if (ieee->state == IEEE80211_NOLINK){
+ printk("creating new IBSS cell\n");
+ if(!ieee->wap_set)
+ ieee80211_randomize_cell(ieee);
+
+ if(ieee->modulation & IEEE80211_CCK_MODULATION){
+
+ ieee->current_network.rates_len = 4;
+
+ ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
+ ieee->current_network.rates[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
+ ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
+ ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
+
+ }else
+ ieee->current_network.rates_len = 0;
+
+ if(ieee->modulation & IEEE80211_OFDM_MODULATION){
+ ieee->current_network.rates_ex_len = 8;
+
+ ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
+ ieee->current_network.rates_ex[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
+ ieee->current_network.rates_ex[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
+ ieee->current_network.rates_ex[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
+ ieee->current_network.rates_ex[4] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
+ ieee->current_network.rates_ex[5] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
+ ieee->current_network.rates_ex[6] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
+ ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
+
+ ieee->rate = 540;
+ }else{
+ ieee->current_network.rates_ex_len = 0;
+ ieee->rate = 110;
+ }
+
+ // By default, WMM function will be disabled in IBSS mode
+ ieee->current_network.QoS_Enable = 0;
+
+ ieee->current_network.atim_window = 0;
+ ieee->current_network.capability = WLAN_CAPABILITY_IBSS;
+ if(ieee->short_slot)
+ ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT;
+
+ }
+
+ ieee->state = IEEE80211_LINKED;
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+ ieee->link_change(ieee->dev);
+
+ notify_wx_assoc_event(ieee);
+
+ ieee80211_start_send_beacons(ieee);
+ printk(KERN_WARNING "after sending beacon packet!\n");
+
+ if (ieee->data_hard_resume)
+ ieee->data_hard_resume(ieee->dev);
+
+ netif_carrier_on(ieee->dev);
+
+ up(&ieee->wx_sem);
+}
+inline void ieee80211_start_ibss(struct ieee80211_device *ieee)
+{
+ queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 100);
+}
+
+/* this is called only in user context, with wx_sem held */
+void ieee80211_start_bss(struct ieee80211_device *ieee)
+{
+ unsigned long flags;
+#ifdef ENABLE_DOT11D
+ //
+ // Ref: 802.11d 11.1.3.3
+ // STA shall not start a BSS unless properly formed Beacon frame including a Country IE.
+ //
+ if(IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee))
+ {
+ if(! ieee->bGlobalDomain)
+ {
+ return;
+ }
+ }
+#endif
+ /* check if we have already found the net we
+ * are interested in (if any).
+ * if not (we are disassociated and we are not
+ * in associating / authenticating phase) start the background scanning.
+ */
+ ieee80211_softmac_check_all_nets(ieee);
+
+ /* ensure no-one start an associating process (thus setting
+ * the ieee->state to ieee80211_ASSOCIATING) while we
+ * have just cheked it and we are going to enable scan.
+ * The ieee80211_new_net function is always called with
+ * lock held (from both ieee80211_softmac_check_all_nets and
+ * the rx path), so we cannot be in the middle of such function
+ */
+ spin_lock_irqsave(&ieee->lock, flags);
+
+//#ifdef ENABLE_IPS
+// printk("start bss ENABLE_IPS\n");
+//#else
+ if (ieee->state == IEEE80211_NOLINK){
+ ieee->actscanning = true;
+ ieee80211_start_scan(ieee);
+ }
+//#endif
+ spin_unlock_irqrestore(&ieee->lock, flags);
+}
+
+/* called only in userspace context */
+void ieee80211_disassociate(struct ieee80211_device *ieee)
+{
+ netif_carrier_off(ieee->dev);
+
+ if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)
+ ieee80211_reset_queue(ieee);
+
+ if (ieee->data_hard_stop)
+ ieee->data_hard_stop(ieee->dev);
+
+#ifdef ENABLE_DOT11D
+ if(IS_DOT11D_ENABLE(ieee))
+ Dot11d_Reset(ieee);
+#endif
+ ieee->state = IEEE80211_NOLINK;
+ ieee->link_change(ieee->dev);
+ notify_wx_assoc_event(ieee);
+
+}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void ieee80211_associate_retry_wq(struct work_struct *work)
+{
+ struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq);
+#else
+void ieee80211_associate_retry_wq(struct ieee80211_device *ieee)
+{
+#endif
+ unsigned long flags;
+ down(&ieee->wx_sem);
+ if(!ieee->proto_started)
+ goto exit;
+ if(ieee->state != IEEE80211_ASSOCIATING_RETRY)
+ goto exit;
+ /* until we do not set the state to IEEE80211_NOLINK
+ * there are no possibility to have someone else trying
+ * to start an association procdure (we get here with
+ * ieee->state = IEEE80211_ASSOCIATING).
+ * When we set the state to IEEE80211_NOLINK it is possible
+ * that the RX path run an attempt to associate, but
+ * both ieee80211_softmac_check_all_nets and the
+ * RX path works with ieee->lock held so there are no
+ * problems. If we are still disassociated then start a scan.
+ * the lock here is necessary to ensure no one try to start
+ * an association procedure when we have just checked the
+ * state and we are going to start the scan.
+ */
+ ieee->state = IEEE80211_NOLINK;
+ ieee->beinretry = true;
+ ieee80211_softmac_check_all_nets(ieee);
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ if(ieee->state == IEEE80211_NOLINK){
+ ieee->beinretry = false;
+ ieee->actscanning = true;
+ ieee80211_start_scan(ieee);
+ }
+ //YJ,add,080828, notify os here
+ if(ieee->state == IEEE80211_NOLINK)
+ {
+ notify_wx_assoc_event(ieee);
+ }
+ //YJ,add,080828,end
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+exit:
+ up(&ieee->wx_sem);
+}
+
+struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee)
+{
+ u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+
+ struct sk_buff *skb = NULL;
+ struct ieee80211_probe_response *b;
+
+//rz
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_get_beacon_get_probersp )
+ skb = ieee->ext_patch_get_beacon_get_probersp(ieee, broadcast_addr, &(ieee->current_network));
+ else
+ skb = ieee80211_probe_resp(ieee, broadcast_addr);
+#else
+ skb = ieee80211_probe_resp(ieee, broadcast_addr);
+#endif
+//
+ if (!skb)
+ return NULL;
+
+ b = (struct ieee80211_probe_response *) skb->data;
+ b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON);
+
+ return skb;
+
+}
+
+struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee)
+{
+ struct sk_buff *skb;
+ struct ieee80211_probe_response *b;
+
+ skb = ieee80211_get_beacon_(ieee);
+ if(!skb)
+ return NULL;
+
+ b = (struct ieee80211_probe_response *) skb->data;
+ b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+
+ if (ieee->seq_ctrl[0] == 0xFFF)
+ ieee->seq_ctrl[0] = 0;
+ else
+ ieee->seq_ctrl[0]++;
+
+ return skb;
+}
+
+void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee)
+{
+ ieee->sync_scan_hurryup = 1;
+ down(&ieee->wx_sem);
+ ieee80211_stop_protocol(ieee);
+ up(&ieee->wx_sem);
+}
+
+
+void ieee80211_stop_protocol(struct ieee80211_device *ieee)
+{
+ if (!ieee->proto_started)
+ return;
+
+ ieee->proto_started = 0;
+
+#ifdef _RTL8187_EXT_PATCH_
+ if(ieee->ext_patch_ieee80211_stop_protocol)
+ ieee->ext_patch_ieee80211_stop_protocol(ieee);
+//if call queue_delayed_work,can call this,or do nothing..
+//edit by lawrence,20071118
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+// cancel_delayed_work(&ieee->ext_stop_scan_wq);
+// cancel_delayed_work(&ieee->ext_send_beacon_wq);
+#endif
+#endif // _RTL8187_EXT_PATCH_
+
+ ieee80211_stop_send_beacons(ieee);
+ if((ieee->iw_mode == IW_MODE_INFRA)&&(ieee->state == IEEE80211_LINKED)) {
+ SendDisassociation(ieee,NULL,WLAN_REASON_DISASSOC_STA_HAS_LEFT);
+ }
+ del_timer_sync(&ieee->associate_timer);
+ cancel_delayed_work(&ieee->associate_retry_wq);
+ cancel_delayed_work(&ieee->start_ibss_wq);
+ ieee80211_stop_scan(ieee);
+
+ ieee80211_disassociate(ieee);
+}
+
+void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee)
+{
+ ieee->sync_scan_hurryup = 0;
+ down(&ieee->wx_sem);
+ ieee80211_start_protocol(ieee);
+ up(&ieee->wx_sem);
+}
+
+void ieee80211_start_protocol(struct ieee80211_device *ieee)
+{
+ short ch = 0;
+ int i = 0;
+
+ if (ieee->proto_started)
+ return;
+
+ ieee->proto_started = 1;
+
+ if (ieee->current_network.channel == 0){
+ do{
+ ch++;
+ if (ch > MAX_CHANNEL_NUMBER)
+ return; /* no channel found */
+
+#ifdef ENABLE_DOT11D
+ }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]);
+#else
+ }while(!ieee->channel_map[ch]);
+#endif
+
+ ieee->current_network.channel = ch;
+ }
+
+ if (ieee->current_network.beacon_interval == 0)
+ ieee->current_network.beacon_interval = 100;
+ ieee->set_chan(ieee->dev,ieee->current_network.channel);
+
+ for(i = 0; i < 17; i++) {
+ ieee->last_rxseq_num[i] = -1;
+ ieee->last_rxfrag_num[i] = -1;
+ ieee->last_packet_time[i] = 0;
+ }
+
+ ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers.
+
+
+ /* if the user set the MAC of the ad-hoc cell and then
+ * switch to managed mode, shall we make sure that association
+ * attempts does not fail just because the user provide the essid
+ * and the nic is still checking for the AP MAC ??
+ */
+ switch (ieee->iw_mode) {
+ case IW_MODE_AUTO:
+ ieee->iw_mode = IW_MODE_INFRA;
+ //not set break here intentionly
+ case IW_MODE_INFRA:
+ ieee80211_start_bss(ieee);
+ break;
+
+ case IW_MODE_ADHOC:
+ ieee80211_start_ibss(ieee);
+ break;
+
+ case IW_MODE_MASTER:
+ ieee80211_start_master_bss(ieee);
+ break;
+
+ case IW_MODE_MONITOR:
+ ieee80211_start_monitor_mode(ieee);
+ break;
+
+ default:
+#ifdef _RTL8187_EXT_PATCH_
+ if((ieee->iw_mode == ieee->iw_ext_mode) &&\
+ ieee->ext_patch_ieee80211_start_protocol &&\
+ ieee->ext_patch_ieee80211_start_protocol(ieee)) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ queue_work(ieee->wq, &ieee->ext_stop_scan_wq);
+#endif
+ // By default, WMM function will be disabled in
+ // EXTENSION mode
+ ieee->current_network.QoS_Enable = 0;
+
+ if(ieee->modulation & IEEE80211_CCK_MODULATION){
+ ieee->current_network.rates_len = 4;
+ ieee->current_network.rates[0] = \
+ IEEE80211_BASIC_RATE_MASK | \
+ IEEE80211_CCK_RATE_1MB;
+ ieee->current_network.rates[1] = \
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_CCK_RATE_2MB;
+ ieee->current_network.rates[2] = \
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_CCK_RATE_5MB;
+ ieee->current_network.rates[3] = \
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_CCK_RATE_11MB;
+ }else
+ ieee->current_network.rates_len = 0;
+
+ if(ieee->modulation & IEEE80211_OFDM_MODULATION){
+ ieee->current_network.rates_ex_len = 8;
+ ieee->current_network.rates_ex[0] = \
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_OFDM_RATE_6MB;
+ ieee->current_network.rates_ex[1] = \
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_OFDM_RATE_9MB;
+ ieee->current_network.rates_ex[2] = \
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_OFDM_RATE_12MB;
+ ieee->current_network.rates_ex[3] = \
+ IEEE80211_BASIC_RATE_MASK | \
+ IEEE80211_OFDM_RATE_18MB;
+ ieee->current_network.rates_ex[4] =\
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_OFDM_RATE_24MB;
+ ieee->current_network.rates_ex[5] =\
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_OFDM_RATE_36MB;
+ ieee->current_network.rates_ex[6] = \
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_OFDM_RATE_48MB;
+ ieee->current_network.rates_ex[7] =\
+ IEEE80211_BASIC_RATE_MASK |\
+ IEEE80211_OFDM_RATE_54MB;
+ ieee->rate = 540;
+ }else{
+ ieee->current_network.rates_ex_len = 0;
+ ieee->rate = 110;
+ }
+
+ /*
+ spin_lock_irqsave(&ieee->lock, flags);
+ if (ieee->state == IEEE80211_NOLINK)
+ ieee80211_start_scan(ieee);
+ // ieee->set_chan(ieee->dev, 8);
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ */
+ memcpy(ieee->current_network.bssid, ieee->dev->dev_addr,\
+ ETH_ALEN);
+ ieee->link_change(ieee->dev);
+ notify_wx_assoc_event(ieee);
+
+ if (ieee->data_hard_resume)
+ ieee->data_hard_resume(ieee->dev);
+
+ netif_carrier_on(ieee->dev);
+ } else {
+ ieee->iw_mode = IW_MODE_INFRA;
+ ieee80211_start_bss(ieee);
+ }
+#else
+ ieee->iw_mode = IW_MODE_INFRA;
+ ieee80211_start_bss(ieee);
+
+#endif
+ break;
+ }
+}
+
+
+#define DRV_NAME "Ieee80211"
+void ieee80211_softmac_init(struct ieee80211_device *ieee)
+{
+ int i;
+ memset(&ieee->current_network, 0, sizeof(struct ieee80211_network));
+
+ ieee->state = IEEE80211_NOLINK;
+ ieee->sync_scan_hurryup = 0;
+ for(i = 0; i < 5; i++) {
+ ieee->seq_ctrl[i] = 0;
+ }
+
+ ieee->assoc_id = 0;
+ ieee->queue_stop = 0;
+ ieee->scanning = 0;
+ ieee->softmac_features = 0; //so IEEE2100-like driver are happy
+ ieee->wap_set = 0;
+ ieee->ssid_set = 0;
+ ieee->proto_started = 0;
+ ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE;
+ ieee->rate = 3;
+//#ifdef ENABLE_LPS
+ ieee->ps = IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST;
+//#else
+// ieee->ps = IEEE80211_PS_DISABLED;
+//#endif
+ ieee->sta_sleep = 0;
+//by amy
+ ieee->bInactivePs = false;
+ ieee->actscanning = false;
+ ieee->ListenInterval = 2;
+ ieee->NumRxDataInPeriod = 0; //YJ,add,080828
+ ieee->NumRxBcnInPeriod = 0; //YJ,add,080828
+ ieee->NumRxOkTotal = 0;//+by amy 080312
+ ieee->NumRxUnicast = 0;//YJ,add,080828,for keep alive
+ ieee->beinretry = false;
+ ieee->bHwRadioOff = false;
+//by amy
+#ifdef _RTL8187_EXT_PATCH_
+ ieee->iw_ext_mode = 999;
+#endif
+
+ init_mgmt_queue(ieee);
+#if 0
+ init_timer(&ieee->scan_timer);
+ ieee->scan_timer.data = (unsigned long)ieee;
+ ieee->scan_timer.function = ieee80211_softmac_scan_cb;
+#endif
+ ieee->tx_pending.txb = NULL;
+
+ init_timer(&ieee->associate_timer);
+ ieee->associate_timer.data = (unsigned long)ieee;
+ ieee->associate_timer.function = ieee80211_associate_abort_cb;
+
+ init_timer(&ieee->beacon_timer);
+ ieee->beacon_timer.data = (unsigned long) ieee;
+ ieee->beacon_timer.function = ieee80211_send_beacon_cb;
+
+#ifdef PF_SYNCTHREAD
+ ieee->wq = create_workqueue(DRV_NAME,0);
+#else
+ ieee->wq = create_workqueue(DRV_NAME);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)//added by lawrence,070702
+ INIT_DELAYED_WORK(&ieee->start_ibss_wq,(void*) ieee80211_start_ibss_wq);
+ INIT_WORK(&ieee->associate_complete_wq,(void*) ieee80211_associate_complete_wq);
+ INIT_WORK(&ieee->associate_procedure_wq,(void*) ieee80211_associate_procedure_wq);
+ INIT_DELAYED_WORK(&ieee->softmac_scan_wq,(void*) ieee80211_softmac_scan_wq);
+ INIT_DELAYED_WORK(&ieee->associate_retry_wq,(void*) ieee80211_associate_retry_wq);
+ INIT_WORK(&ieee->wx_sync_scan_wq,(void*) ieee80211_wx_sync_scan_wq);
+// INIT_WORK(&ieee->watch_dog_wq,(void*) ieee80211_watch_dog_wq);
+//added by lawrence,20071118
+#ifdef _RTL8187_EXT_PATCH_
+ INIT_WORK(&ieee->ext_stop_scan_wq,(void*) ieee80211_ext_stop_scan_wq);
+ //INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ieee80211_beacons_start,ieee);
+ INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ext_ieee80211_send_beacon_wq);
+#endif //_RTL8187_EXT_PATCH_
+#else
+ INIT_WORK(&ieee->start_ibss_wq,(void*) ieee80211_start_ibss_wq,ieee);
+ INIT_WORK(&ieee->associate_retry_wq,(void*) ieee80211_associate_retry_wq,ieee);
+ INIT_WORK(&ieee->associate_complete_wq,(void*) ieee80211_associate_complete_wq,ieee);
+ INIT_WORK(&ieee->associate_procedure_wq,(void*) ieee80211_associate_procedure_wq,ieee);
+ INIT_WORK(&ieee->softmac_scan_wq,(void*) ieee80211_softmac_scan_wq,ieee);
+ INIT_WORK(&ieee->wx_sync_scan_wq,(void*) ieee80211_wx_sync_scan_wq,ieee);
+// INIT_WORK(&ieee->watch_dog_wq,(void*) ieee80211_watch_dog_wq,ieee);
+#ifdef _RTL8187_EXT_PATCH_
+ INIT_WORK(&ieee->ext_stop_scan_wq,(void*) ieee80211_ext_stop_scan_wq,ieee);
+ //INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ieee80211_beacons_start,ieee);
+ INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ext_ieee80211_send_beacon_wq,ieee);
+#endif
+#endif
+ sema_init(&ieee->wx_sem, 1);
+ sema_init(&ieee->scan_sem, 1);
+
+ spin_lock_init(&ieee->mgmt_tx_lock);
+ spin_lock_init(&ieee->beacon_lock);
+
+ tasklet_init(&ieee->ps_task,
+ (void(*)(unsigned long)) ieee80211_sta_ps,
+ (unsigned long)ieee);
+#ifdef ENABLE_DOT11D
+ ieee->pDot11dInfo = kmalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC);
+#endif
+}
+
+void ieee80211_softmac_free(struct ieee80211_device *ieee)
+{
+ down(&ieee->wx_sem);
+
+ del_timer_sync(&ieee->associate_timer);
+ cancel_delayed_work(&ieee->associate_retry_wq);
+
+
+ //add for RF power on power of by lizhaoming 080512
+ cancel_delayed_work(&ieee->GPIOChangeRFWorkItem);
+
+#ifdef _RTL8187_EXT_PATCH_
+ cancel_delayed_work(&ieee->ext_stop_scan_wq);
+ cancel_delayed_work(&ieee->ext_send_beacon_wq);
+#endif
+ destroy_workqueue(ieee->wq);
+#ifdef ENABLE_DOT11D
+ if(NULL != ieee->pDot11dInfo)
+ kfree(ieee->pDot11dInfo);
+#endif
+ up(&ieee->wx_sem);
+}
+
+/********************************************************
+ * Start of WPA code. *
+ * this is stolen from the ipw2200 driver *
+ ********************************************************/
+
+
+static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value)
+{
+ /* This is called when wpa_supplicant loads and closes the driver
+ * interface. */
+ printk("%s WPA\n",value ? "enabling" : "disabling");
+ ieee->wpa_enabled = value;
+ return 0;
+}
+
+
+void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, int wpa_ie_len)
+{
+ /* make sure WPA is enabled */
+ ieee80211_wpa_enable(ieee, 1);
+
+ ieee80211_disassociate(ieee);
+}
+
+
+static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command, int reason)
+{
+
+ int ret = 0;
+
+ switch (command) {
+ case IEEE_MLME_STA_DEAUTH:
+ // silently ignore
+ break;
+
+ case IEEE_MLME_STA_DISASSOC:
+ ieee80211_disassociate(ieee);
+ break;
+
+ default:
+ printk("Unknown MLME request: %d\n", command);
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+
+static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee,
+ struct ieee_param *param, int plen)
+{
+ u8 *buf;
+
+ if (param->u.wpa_ie.len > MAX_WPA_IE_LEN ||
+ (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL))
+ return -EINVAL;
+
+ if (param->u.wpa_ie.len) {
+ buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len);
+ kfree(ieee->wpa_ie);
+ ieee->wpa_ie = buf;
+ ieee->wpa_ie_len = param->u.wpa_ie.len;
+ } else {
+ kfree(ieee->wpa_ie);
+ ieee->wpa_ie = NULL;
+ ieee->wpa_ie_len = 0;
+ }
+
+ ieee80211_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len);
+ return 0;
+}
+
+#define AUTH_ALG_OPEN_SYSTEM 0x1
+#define AUTH_ALG_SHARED_KEY 0x2
+
+static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value)
+{
+
+ struct ieee80211_security sec = {
+ .flags = SEC_AUTH_MODE,
+ };
+ int ret = 0;
+
+ if (value & AUTH_ALG_SHARED_KEY) {
+ sec.auth_mode = WLAN_AUTH_SHARED_KEY;
+ ieee->open_wep = 0;
+ } else {
+ sec.auth_mode = WLAN_AUTH_OPEN;
+ ieee->open_wep = 1;
+ }
+
+ if (ieee->set_security)
+ ieee->set_security(ieee->dev, &sec);
+ else
+ ret = -EOPNOTSUPP;
+
+ return ret;
+}
+
+static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, u32 value)
+{
+ int ret=0;
+ unsigned long flags;
+
+ switch (name) {
+ case IEEE_PARAM_WPA_ENABLED:
+ ret = ieee80211_wpa_enable(ieee, value);
+ break;
+
+ case IEEE_PARAM_TKIP_COUNTERMEASURES:
+ ieee->tkip_countermeasures=value;
+ break;
+
+ case IEEE_PARAM_DROP_UNENCRYPTED: {
+ /* HACK:
+ *
+ * wpa_supplicant calls set_wpa_enabled when the driver
+ * is loaded and unloaded, regardless of if WPA is being
+ * used. No other calls are made which can be used to
+ * determine if encryption will be used or not prior to
+ * association being expected. If encryption is not being
+ * used, drop_unencrypted is set to false, else true -- we
+ * can use this to determine if the CAP_PRIVACY_ON bit should
+ * be set.
+ */
+ struct ieee80211_security sec = {
+ .flags = SEC_ENABLED,
+ .enabled = value,
+ };
+ ieee->drop_unencrypted = value;
+ /* We only change SEC_LEVEL for open mode. Others
+ * are set by ipw_wpa_set_encryption.
+ */
+ if (!value) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_0;
+ }
+ else {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ }
+ if (ieee->set_security)
+ ieee->set_security(ieee->dev, &sec);
+ break;
+ }
+
+ case IEEE_PARAM_PRIVACY_INVOKED:
+ ieee->privacy_invoked=value;
+ break;
+
+ case IEEE_PARAM_AUTH_ALGS:
+ ret = ieee80211_wpa_set_auth_algs(ieee, value);
+ break;
+
+ case IEEE_PARAM_IEEE_802_1X:
+ ieee->ieee802_1x=value;
+ break;
+ case IEEE_PARAM_WPAX_SELECT:
+ // added for WPA2 mixed mode
+ //printk(KERN_WARNING "------------------------>wpax value = %x\n", value);
+ spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags);
+ ieee->wpax_type_set = 1;
+ ieee->wpax_type_notify = value;
+ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags);
+ break;
+
+ default:
+ printk("Unknown WPA param: %d\n",name);
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+/* implementation borrowed from hostap driver */
+
+static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
+ struct ieee_param *param, int param_len)
+{
+ int ret = 0;
+
+ struct ieee80211_crypto_ops *ops;
+ struct ieee80211_crypt_data **crypt;
+
+ struct ieee80211_security sec = {
+ .flags = 0,
+ };
+
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+ if (param_len !=
+ (int) ((char *) param->u.crypt.key - (char *) param) +
+ param->u.crypt.key_len) {
+ printk("Len mismatch %d, %d\n", param_len,
+ param->u.crypt.key_len);
+ return -EINVAL;
+ }
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (param->u.crypt.idx >= WEP_KEYS)
+ return -EINVAL;
+ crypt = &ieee->crypt[param->u.crypt.idx];
+ } else {
+ return -EINVAL;
+ }
+
+ if (strcmp(param->u.crypt.alg, "none") == 0) {
+ if (crypt) {
+ sec.enabled = 0;
+ // FIXME FIXME
+ //sec.encrypt = 0;
+ sec.level = SEC_LEVEL_0;
+ sec.flags |= SEC_ENABLED | SEC_LEVEL;
+ ieee80211_crypt_delayed_deinit(ieee, crypt);
+ }
+ goto done;
+ }
+ sec.enabled = 1;
+// FIXME FIXME
+// sec.encrypt = 1;
+ sec.flags |= SEC_ENABLED;
+
+ /* IPW HW cannot build TKIP MIC, host decryption still needed. */
+ if (!(ieee->host_encrypt || ieee->host_decrypt) &&
+ strcmp(param->u.crypt.alg, "TKIP"))
+ goto skip_host_crypt;
+
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
+ request_module("ieee80211_crypt_wep");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ request_module("ieee80211_crypt_tkip");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ request_module("ieee80211_crypt_ccmp");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ }
+ if (ops == NULL) {
+ printk("unknown crypto alg '%s'\n", param->u.crypt.alg);
+ param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_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 = (struct ieee80211_crypt_data *)
+ kmalloc(sizeof(*new_crypt), GFP_KERNEL);
+ if (new_crypt == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+ new_crypt->ops = ops;
+ if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+ new_crypt->priv =
+ new_crypt->ops->init(param->u.crypt.idx);
+
+ if (new_crypt->priv == NULL) {
+ kfree(new_crypt);
+ param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ *crypt = new_crypt;
+ }
+
+ if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key &&
+ (*crypt)->ops->set_key(param->u.crypt.key,
+ param->u.crypt.key_len, param->u.crypt.seq,
+ (*crypt)->priv) < 0) {
+ printk("key setting failed\n");
+ param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ skip_host_crypt:
+ if (param->u.crypt.set_tx) {
+ ieee->tx_keyidx = param->u.crypt.idx;
+ sec.active_key = param->u.crypt.idx;
+ sec.flags |= SEC_ACTIVE_KEY;
+ } else
+ sec.flags &= ~SEC_ACTIVE_KEY;
+
+ if (param->u.crypt.alg != NULL) {
+ memcpy(sec.keys[param->u.crypt.idx],
+ param->u.crypt.key,
+ param->u.crypt.key_len);
+ sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
+ sec.flags |= (1 << param->u.crypt.idx);
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_2;
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_3;
+ }
+ }
+ done:
+ if (ieee->set_security)
+ ieee->set_security(ieee->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(ieee->dev)) {
+ printk("reset_port failed\n");
+ param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED;
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p)
+{
+ struct ieee_param *param;
+ int ret=0;
+
+ down(&ieee->wx_sem);
+ //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length);
+
+ if (p->length < sizeof(struct ieee_param) || !p->pointer){
+ ret = -EINVAL;
+ goto out;
+ }
+
+ param = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL);
+ if (param == NULL){
+ ret = -ENOMEM;
+ goto out;
+ }
+ if (copy_from_user(param, p->pointer, p->length)) {
+ kfree(param);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ switch (param->cmd) {
+
+ case IEEE_CMD_SET_WPA_PARAM:
+ ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name,
+ param->u.wpa_param.value);
+ break;
+
+ case IEEE_CMD_SET_WPA_IE:
+ ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length);
+ break;
+
+ case IEEE_CMD_SET_ENCRYPTION:
+ ret = ieee80211_wpa_set_encryption(ieee, param, p->length);
+ break;
+
+ case IEEE_CMD_MLME:
+ ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command,
+ param->u.mlme.reason_code);
+ break;
+
+ default:
+ printk("Unknown WPA supplicant request: %d\n",param->cmd);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+ ret = -EFAULT;
+
+ kfree(param);
+out:
+ up(&ieee->wx_sem);
+
+ return ret;
+}
+
+void notify_wx_assoc_event(struct ieee80211_device *ieee)
+{
+ union iwreq_data wrqu;
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ if (ieee->state == IEEE80211_LINKED)
+ memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN);
+ else
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+
+#if 0
+EXPORT_SYMBOL(ieee80211_get_beacon);
+EXPORT_SYMBOL(ieee80211_wake_queue);
+EXPORT_SYMBOL(ieee80211_stop_queue);
+EXPORT_SYMBOL(ieee80211_reset_queue);
+EXPORT_SYMBOL(ieee80211_softmac_stop_protocol);
+EXPORT_SYMBOL(ieee80211_softmac_start_protocol);
+EXPORT_SYMBOL(ieee80211_is_shortslot);
+EXPORT_SYMBOL(ieee80211_is_54g);
+EXPORT_SYMBOL(ieee80211_wpa_supplicant_ioctl);
+EXPORT_SYMBOL(ieee80211_ps_tx_ack);
+EXPORT_SYMBOL(ieee80211_start_protocol);
+EXPORT_SYMBOL(ieee80211_stop_protocol);
+EXPORT_SYMBOL(notify_wx_assoc_event);
+EXPORT_SYMBOL(ieee80211_stop_send_beacons);
+EXPORT_SYMBOL(SendDisassociation);
+EXPORT_SYMBOL(ieee80211_disassociate);
+EXPORT_SYMBOL(ieee80211_start_scan);
+EXPORT_SYMBOL(ieee80211_softmac_ips_scan_syncro);
+#ifdef _RTL8187_EXT_PATCH_
+EXPORT_SYMBOL(ieee80211_ext_issue_assoc_req);
+EXPORT_SYMBOL(ieee80211_ext_issue_disassoc);
+EXPORT_SYMBOL(ieee80211_ext_issue_assoc_rsp);
+EXPORT_SYMBOL(softmac_mgmt_xmit);
+EXPORT_SYMBOL(ieee80211_ext_probe_resp_by_net);
+EXPORT_SYMBOL(ieee80211_start_scan);
+EXPORT_SYMBOL(ieee80211_stop_scan);
+EXPORT_SYMBOL(ieee80211_ext_send_11s_beacon);
+EXPORT_SYMBOL(ieee80211_rx_auth_rq);
+EXPORT_SYMBOL(ieee80211_associate_step1);
+#endif // _RTL8187_EXT_PATCH_
+EXPORT_SYMBOL(ieee80211_sta_ps_send_null_frame);
+#endif
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
new file mode 100644
index 00000000000..93af37e2d31
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -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",__func__);
+ 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
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
new file mode 100644
index 00000000000..33a0687252a
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -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
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
new file mode 100644
index 00000000000..6aad61e7804
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
@@ -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",__func__, 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", __func__, 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", __func__);
+ {
+ 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", __func__);
+
+ 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
diff --git a/drivers/staging/rtl8187se/ieee80211/internal.h b/drivers/staging/rtl8187se/ieee80211/internal.h
new file mode 100644
index 00000000000..ddc22350d00
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/internal.h
@@ -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 */
+
diff --git a/drivers/staging/rtl8187se/ieee80211/rtl_crypto.h b/drivers/staging/rtl8187se/ieee80211/rtl_crypto.h
new file mode 100644
index 00000000000..9ed0ca42085
--- /dev/null
+++ b/drivers/staging/rtl8187se/ieee80211/rtl_crypto.h
@@ -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 */
+