blob: baf3b6342e440dbb8c77faf41619e844f28a7738 [file] [log] [blame]
/******************************************************************************
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
* Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
******************************************************************************/
#include "rtl_core.h"
#include "r8192E_phy.h"
#include "r8192E_phyreg.h"
#include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */
#include "r8192E_cmdpkt.h"
extern int hwwep;
void CamResetAllEntry(struct net_device *dev)
{
u32 ulcommand = 0;
ulcommand |= BIT31|BIT30;
write_nic_dword(dev, RWCAM, ulcommand);
}
void write_cam(struct net_device *dev, u8 addr, u32 data)
{
write_nic_dword(dev, WCAMI, data);
write_nic_dword(dev, RWCAM, BIT31|BIT16|(addr&0xff));
}
u32 read_cam(struct net_device *dev, u8 addr)
{
write_nic_dword(dev, RWCAM, 0x80000000|(addr&0xff));
return read_nic_dword(dev, 0xa8);
}
void EnableHWSecurityConfig8192(struct net_device *dev)
{
u8 SECR_value = 0x0;
struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
struct rtllib_device *ieee = priv->rtllib;
SECR_value = SCR_TxEncEnable | SCR_RxDecEnable;
if (((KEY_TYPE_WEP40 == ieee->pairwise_key_type) ||
(KEY_TYPE_WEP104 == ieee->pairwise_key_type)) &&
(priv->rtllib->auth_mode != 2)) {
SECR_value |= SCR_RxUseDK;
SECR_value |= SCR_TxUseDK;
} else if ((ieee->iw_mode == IW_MODE_ADHOC) &&
(ieee->pairwise_key_type & (KEY_TYPE_CCMP |
KEY_TYPE_TKIP))) {
SECR_value |= SCR_RxUseDK;
SECR_value |= SCR_TxUseDK;
}
ieee->hwsec_active = 1;
if ((ieee->pHTInfo->IOTAction&HT_IOT_ACT_PURE_N_MODE) || !hwwep) {
ieee->hwsec_active = 0;
SECR_value &= ~SCR_RxDecEnable;
}
RT_TRACE(COMP_SEC, "%s:, hwsec:%d, pairwise_key:%d, SECR_value:%x\n",
__func__, ieee->hwsec_active, ieee->pairwise_key_type,
SECR_value);
write_nic_byte(dev, SECR, SECR_value);
}
void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType,
u8 *MacAddr, u8 DefaultKey, u32 *KeyContent, u8 is_mesh)
{
struct r8192_priv *priv = rtllib_priv(dev);
struct rtllib_device *ieee = priv->rtllib;
RT_TRACE(COMP_DBG, "===========>%s():EntryNo is %d,KeyIndex is "
"%d,KeyType is %d,is_mesh is %d\n", __func__, EntryNo,
KeyIndex, KeyType, is_mesh);
if (!is_mesh) {
ieee->swcamtable[EntryNo].bused = true;
ieee->swcamtable[EntryNo].key_index = KeyIndex;
ieee->swcamtable[EntryNo].key_type = KeyType;
memcpy(ieee->swcamtable[EntryNo].macaddr, MacAddr, 6);
ieee->swcamtable[EntryNo].useDK = DefaultKey;
memcpy(ieee->swcamtable[EntryNo].key_buf, (u8 *)KeyContent, 16);
}
}
void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType,
u8 *MacAddr, u8 DefaultKey, u32 *KeyContent)
{
u32 TargetCommand = 0;
u32 TargetContent = 0;
u16 usConfig = 0;
u8 i;
struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
enum rt_rf_power_state rtState;
rtState = priv->rtllib->eRFPowerState;
if (priv->rtllib->PowerSaveControl.bInactivePs) {
if (rtState == eRfOff) {
if (priv->rtllib->RfOffReason > RF_CHANGE_BY_IPS) {
RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",
__func__);
return ;
} else {
down(&priv->rtllib->ips_sem);
IPSLeave(dev);
up(&priv->rtllib->ips_sem);
}
}
}
priv->rtllib->is_set_key = true;
if (EntryNo >= TOTAL_CAM_ENTRY)
RT_TRACE(COMP_ERR, "cam entry exceeds in setKey()\n");
RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d,"
"KeyType:%d, MacAddr %pM\n", dev, EntryNo, KeyIndex,
KeyType, MacAddr);
if (DefaultKey)
usConfig |= BIT15 | (KeyType<<2);
else
usConfig |= BIT15 | (KeyType<<2) | KeyIndex;
for (i = 0; i < CAM_CONTENT_COUNT; i++) {
TargetCommand = i + CAM_CONTENT_COUNT * EntryNo;
TargetCommand |= BIT31|BIT16;
if (i == 0) {
TargetContent = (u32)(*(MacAddr+0)) << 16 |
(u32)(*(MacAddr+1)) << 24 |
(u32)usConfig;
write_nic_dword(dev, WCAMI, TargetContent);
write_nic_dword(dev, RWCAM, TargetCommand);
} else if (i == 1) {
TargetContent = (u32)(*(MacAddr+2)) |
(u32)(*(MacAddr+3)) << 8 |
(u32)(*(MacAddr+4)) << 16 |
(u32)(*(MacAddr+5)) << 24;
write_nic_dword(dev, WCAMI, TargetContent);
write_nic_dword(dev, RWCAM, TargetCommand);
} else {
if (KeyContent != NULL) {
write_nic_dword(dev, WCAMI,
(u32)(*(KeyContent+i-2)));
write_nic_dword(dev, RWCAM, TargetCommand);
udelay(100);
}
}
}
RT_TRACE(COMP_SEC, "=========>after set key, usconfig:%x\n", usConfig);
}
void CAM_read_entry(struct net_device *dev, u32 iIndex)
{
u32 target_command = 0;
u32 target_content = 0;
u8 entry_i = 0;
u32 ulStatus;
s32 i = 100;
for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
target_command = entry_i+CAM_CONTENT_COUNT*iIndex;
target_command = target_command | BIT31;
while ((i--) >= 0) {
ulStatus = read_nic_dword(dev, RWCAM);
if (ulStatus & BIT31)
continue;
else
break;
}
write_nic_dword(dev, RWCAM, target_command);
RT_TRACE(COMP_SEC, "CAM_read_entry(): WRITE A0: %x\n",
target_command);
target_content = read_nic_dword(dev, RCAMO);
RT_TRACE(COMP_SEC, "CAM_read_entry(): WRITE A8: %x\n",
target_content);
}
printk(KERN_INFO "\n");
}
void CamRestoreAllEntry(struct net_device *dev)
{
u8 EntryId = 0;
struct r8192_priv *priv = rtllib_priv(dev);
u8 *MacAddr = priv->rtllib->current_network.bssid;
static u8 CAM_CONST_ADDR[4][6] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
};
static u8 CAM_CONST_BROAD[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
RT_TRACE(COMP_SEC, "CamRestoreAllEntry:\n");
if ((priv->rtllib->pairwise_key_type == KEY_TYPE_WEP40) ||
(priv->rtllib->pairwise_key_type == KEY_TYPE_WEP104)) {
for (EntryId = 0; EntryId < 4; EntryId++) {
MacAddr = CAM_CONST_ADDR[EntryId];
if (priv->rtllib->swcamtable[EntryId].bused) {
setKey(dev, EntryId , EntryId,
priv->rtllib->pairwise_key_type, MacAddr,
0, (u32 *)(&priv->rtllib->swcamtable
[EntryId].key_buf[0]));
}
}
} else if (priv->rtllib->pairwise_key_type == KEY_TYPE_TKIP) {
if (priv->rtllib->iw_mode == IW_MODE_ADHOC) {
setKey(dev, 4, 0, priv->rtllib->pairwise_key_type,
(u8 *)dev->dev_addr, 0,
(u32 *)(&priv->rtllib->swcamtable[4].key_buf[0]));
} else {
setKey(dev, 4, 0, priv->rtllib->pairwise_key_type,
MacAddr, 0,
(u32 *)(&priv->rtllib->swcamtable[4].key_buf[0]));
}
} else if (priv->rtllib->pairwise_key_type == KEY_TYPE_CCMP) {
if (priv->rtllib->iw_mode == IW_MODE_ADHOC) {
setKey(dev, 4, 0,
priv->rtllib->pairwise_key_type,
(u8 *)dev->dev_addr, 0,
(u32 *)(&priv->rtllib->swcamtable[4].
key_buf[0]));
} else {
setKey(dev, 4, 0,
priv->rtllib->pairwise_key_type, MacAddr,
0, (u32 *)(&priv->rtllib->swcamtable[4].
key_buf[0]));
}
}
if (priv->rtllib->group_key_type == KEY_TYPE_TKIP) {
MacAddr = CAM_CONST_BROAD;
for (EntryId = 1; EntryId < 4; EntryId++) {
if (priv->rtllib->swcamtable[EntryId].bused) {
setKey(dev, EntryId, EntryId,
priv->rtllib->group_key_type,
MacAddr, 0,
(u32 *)(&priv->rtllib->swcamtable[EntryId].key_buf[0])
);
}
}
if (priv->rtllib->iw_mode == IW_MODE_ADHOC) {
if (priv->rtllib->swcamtable[0].bused) {
setKey(dev, 0, 0,
priv->rtllib->group_key_type,
CAM_CONST_ADDR[0], 0,
(u32 *)(&priv->rtllib->swcamtable[0].key_buf[0])
);
} else {
RT_TRACE(COMP_ERR, "===>%s():ERR!! ADHOC TKIP "
",but 0 entry is have no data\n",
__func__);
return;
}
}
} else if (priv->rtllib->group_key_type == KEY_TYPE_CCMP) {
MacAddr = CAM_CONST_BROAD;
for (EntryId = 1; EntryId < 4; EntryId++) {
if (priv->rtllib->swcamtable[EntryId].bused) {
setKey(dev, EntryId , EntryId,
priv->rtllib->group_key_type,
MacAddr, 0,
(u32 *)(&priv->rtllib->swcamtable[EntryId].key_buf[0]));
}
}
if (priv->rtllib->iw_mode == IW_MODE_ADHOC) {
if (priv->rtllib->swcamtable[0].bused) {
setKey(dev, 0 , 0,
priv->rtllib->group_key_type,
CAM_CONST_ADDR[0], 0,
(u32 *)(&priv->rtllib->swcamtable[0].key_buf[0]));
} else {
RT_TRACE(COMP_ERR, "===>%s():ERR!! ADHOC CCMP ,"
"but 0 entry is have no data\n",
__func__);
return;
}
}
}
}