linux/drivers/staging/rtlwifi/cam.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2009-2012  Realtek Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of version 2 of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * The full GNU General Public License is included in this distribution in the
  15 * file called LICENSE.
  16 *
  17 * Contact Information:
  18 * wlanfae <wlanfae@realtek.com>
  19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  20 * Hsinchu 300, Taiwan.
  21 *
  22 * Larry Finger <Larry.Finger@lwfinger.net>
  23 *
  24 *****************************************************************************/
  25#include "wifi.h"
  26#include "cam.h"
  27#include <linux/export.h>
  28
  29void rtl_cam_reset_sec_info(struct ieee80211_hw *hw)
  30{
  31        struct rtl_priv *rtlpriv = rtl_priv(hw);
  32
  33        rtlpriv->sec.use_defaultkey = false;
  34        rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION;
  35        rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION;
  36        memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN);
  37        memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE);
  38        rtlpriv->sec.pairwise_key = NULL;
  39}
  40
  41static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
  42                                  u8 *mac_addr, u8 *key_cont_128, u16 us_config)
  43{
  44        struct rtl_priv *rtlpriv = rtl_priv(hw);
  45
  46        u32 target_command;
  47        u32 target_content = 0;
  48        int entry_i;
  49
  50        RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content :",
  51                      key_cont_128, 16);
  52
  53        /* 0-1 config + mac, 2-5 fill 128key,6-7 are reserved */
  54        for (entry_i = CAM_CONTENT_COUNT - 1; entry_i >= 0; entry_i--) {
  55                target_command = entry_i + CAM_CONTENT_COUNT * entry_no;
  56                target_command = target_command | BIT(31) | BIT(16);
  57
  58                if (entry_i == 0) {
  59                        target_content = (u32)(*(mac_addr + 0)) << 16 |
  60                                         (u32)(*(mac_addr + 1)) << 24 |
  61                                         (u32)us_config;
  62
  63                        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
  64                                        target_content);
  65                        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
  66                                        target_command);
  67
  68                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
  69                                 "WRITE %x: %x\n",
  70                                 rtlpriv->cfg->maps[WCAMI], target_content);
  71                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
  72                                 "The Key ID is %d\n", entry_no);
  73                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
  74                                 "WRITE %x: %x\n",
  75                                 rtlpriv->cfg->maps[RWCAM], target_command);
  76
  77                } else if (entry_i == 1) {
  78                        target_content = (u32)(*(mac_addr + 5)) << 24 |
  79                                         (u32)(*(mac_addr + 4)) << 16 |
  80                                         (u32)(*(mac_addr + 3)) << 8 |
  81                                         (u32)(*(mac_addr + 2));
  82
  83                        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
  84                                        target_content);
  85                        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
  86                                        target_command);
  87
  88                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
  89                                 "WRITE A4: %x\n", target_content);
  90                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
  91                                 "WRITE A0: %x\n", target_command);
  92                } else {
  93                        target_content =
  94                            (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 3)) <<
  95                            24 | (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 2))
  96                            << 16 |
  97                            (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8
  98                            | (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 0));
  99
 100                        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
 101                                        target_content);
 102                        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
 103                                        target_command);
 104
 105                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 106                                 "WRITE A4: %x\n", target_content);
 107                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 108                                 "WRITE A0: %x\n", target_command);
 109                }
 110        }
 111
 112        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 113                 "after set key, usconfig:%x\n", us_config);
 114}
 115
 116u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
 117                         u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
 118                         u32 ul_default_key, u8 *key_content)
 119{
 120        u32 us_config;
 121        struct rtl_priv *rtlpriv = rtl_priv(hw);
 122
 123        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 124                 "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n",
 125                 ul_entry_idx, ul_key_id, ul_enc_alg,
 126                 ul_default_key, mac_addr);
 127
 128        if (ul_key_id == TOTAL_CAM_ENTRY) {
 129                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 130                         "ulKeyId exceed!\n");
 131                return 0;
 132        }
 133
 134        if (ul_default_key == 1)
 135                us_config = CFG_VALID | ((u16)(ul_enc_alg) << 2);
 136        else
 137                us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id;
 138
 139        rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,
 140                              (u8 *)key_content, us_config);
 141
 142        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "end\n");
 143
 144        return 1;
 145}
 146
 147int rtl_cam_delete_one_entry(struct ieee80211_hw *hw,
 148                             u8 *mac_addr, u32 ul_key_id)
 149{
 150        u32 ul_command;
 151        struct rtl_priv *rtlpriv = rtl_priv(hw);
 152
 153        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "key_idx:%d\n", ul_key_id);
 154
 155        ul_command = ul_key_id * CAM_CONTENT_COUNT;
 156        ul_command = ul_command | BIT(31) | BIT(16);
 157
 158        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0);
 159        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
 160
 161        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 162                 "%s(): WRITE A4: %x\n", __func__, 0);
 163        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 164                 "%s(): WRITE A0: %x\n", __func__, ul_command);
 165
 166        return 0;
 167}
 168
 169void rtl_cam_reset_all_entry(struct ieee80211_hw *hw)
 170{
 171        u32 ul_command;
 172        struct rtl_priv *rtlpriv = rtl_priv(hw);
 173
 174        ul_command = BIT(31) | BIT(30);
 175        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
 176}
 177
 178void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index)
 179{
 180        struct rtl_priv *rtlpriv = rtl_priv(hw);
 181
 182        u32 ul_command;
 183        u32 ul_content;
 184        u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
 185
 186        switch (rtlpriv->sec.pairwise_enc_algorithm) {
 187        case WEP40_ENCRYPTION:
 188                ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
 189                break;
 190        case WEP104_ENCRYPTION:
 191                ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
 192                break;
 193        case TKIP_ENCRYPTION:
 194                ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
 195                break;
 196        case AESCCMP_ENCRYPTION:
 197                ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
 198                break;
 199        default:
 200                ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
 201        }
 202
 203        ul_content = (uc_index & 3) | ((u16)(ul_enc_algo) << 2);
 204
 205        ul_content |= BIT(15);
 206        ul_command = CAM_CONTENT_COUNT * uc_index;
 207        ul_command = ul_command | BIT(31) | BIT(16);
 208
 209        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
 210        rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
 211
 212        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 213                 "%s(): WRITE A4: %x\n", __func__, ul_content);
 214        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 215                 "%s(): WRITE A0: %x\n", __func__, ul_command);
 216}
 217
 218void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)
 219{
 220        struct rtl_priv *rtlpriv = rtl_priv(hw);
 221
 222        u32 ul_command;
 223        u32 ul_content;
 224        u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
 225        u8 entry_i;
 226
 227        switch (rtlpriv->sec.pairwise_enc_algorithm) {
 228        case WEP40_ENCRYPTION:
 229                ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
 230                break;
 231        case WEP104_ENCRYPTION:
 232                ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
 233                break;
 234        case TKIP_ENCRYPTION:
 235                ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
 236                break;
 237        case AESCCMP_ENCRYPTION:
 238                ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
 239                break;
 240        default:
 241                ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
 242        }
 243
 244        for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
 245                if (entry_i == 0) {
 246                        ul_content =
 247                            (uc_index & 0x03) | ((u16)(ul_encalgo) << 2);
 248                        ul_content |= BIT(15);
 249                } else {
 250                        ul_content = 0;
 251                }
 252
 253                ul_command = CAM_CONTENT_COUNT * uc_index + entry_i;
 254                ul_command = ul_command | BIT(31) | BIT(16);
 255
 256                rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
 257                rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
 258
 259                RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 260                         "%s(): WRITE A4: %x\n", __func__, ul_content);
 261                RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 262                         "%s(): WRITE A0: %x\n", __func__, ul_command);
 263        }
 264}
 265
 266u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr)
 267{
 268        struct rtl_priv *rtlpriv = rtl_priv(hw);
 269        u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4;
 270        u8 entry_idx = 0;
 271        u8 i, *addr;
 272
 273        if (!sta_addr) {
 274                pr_err("sta_addr is NULL.\n");
 275                return TOTAL_CAM_ENTRY;
 276        }
 277        /* Does STA already exist? */
 278        for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
 279                addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
 280                if (ether_addr_equal_unaligned(addr, sta_addr))
 281                        return i;
 282        }
 283        /* Get a free CAM entry. */
 284        for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) {
 285                if ((bitmap & BIT(0)) == 0) {
 286                        pr_err("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n",
 287                               rtlpriv->sec.hwsec_cam_bitmap, entry_idx);
 288                        rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx;
 289                        memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx],
 290                               sta_addr, ETH_ALEN);
 291                        return entry_idx;
 292                }
 293                bitmap = bitmap >> 1;
 294        }
 295        return TOTAL_CAM_ENTRY;
 296}
 297
 298void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
 299{
 300        struct rtl_priv *rtlpriv = rtl_priv(hw);
 301        u32 bitmap;
 302        u8 i, *addr;
 303
 304        if (!sta_addr) {
 305                pr_err("sta_addr is NULL.\n");
 306                return;
 307        }
 308
 309        if (is_zero_ether_addr(sta_addr)) {
 310                pr_err("sta_addr is %pM\n", sta_addr);
 311                return;
 312        }
 313        /* Does STA already exist? */
 314        for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
 315                addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
 316                bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i;
 317                if (((bitmap & BIT(0)) == BIT(0)) &&
 318                    (ether_addr_equal_unaligned(addr, sta_addr))) {
 319                        /* Remove from HW Security CAM */
 320                        eth_zero_addr(rtlpriv->sec.hwsec_cam_sta_addr[i]);
 321                        rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
 322                        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 323                                 "&&&&&&&&&del entry %d\n", i);
 324                }
 325        }
 326}
 327