static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); u8 key_type = NO_ENCRYPTION; u8 key_idx; bool group_key = false; bool wep_only = false; int err = 0; u8 mac_addr[ETH_ALEN]; u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; u8 zero_addr[ETH_ALEN] = { 0 }; if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("not open hw encryption\n")); return -ENOSPC; /*User disabled HW-crypto */ } RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("%s hardware based encryption for keyidx: %d, mac: %pM\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, sta ? sta->addr : bcast_addr)); rtlpriv->sec.being_setkey = true; rtl_ips_nic_on(hw); mutex_lock(&rtlpriv->locks.conf_mutex); /* <1> get encryption alg */ switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: key_type = WEP40_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); break; case WLAN_CIPHER_SUITE_WEP104: RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP104\n")); key_type = WEP104_ENCRYPTION; break; case WLAN_CIPHER_SUITE_TKIP: key_type = TKIP_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); break; case WLAN_CIPHER_SUITE_CCMP: key_type = AESCCMP_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("alg_err:%x!!!!:\n", key->cipher)); goto out_unlock; } if (key_type == WEP40_ENCRYPTION || key_type == WEP104_ENCRYPTION || mac->opmode == NL80211_IFTYPE_ADHOC) rtlpriv->sec.use_defaultkey = true; /* <2> get key_idx */ key_idx = (u8) (key->keyidx); if (key_idx > 3) goto out_unlock; /* <3> if pairwise key enable_hw_sec */ group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); /* wep always be group key, but there are two conditions: * 1) wep only: is just for wep enc, in this condition * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION * will be true & enable_hw_sec will be set when wep * ke setting. * 2) wep(group) + AES(pairwise): some AP like cisco * may use it, in this condition enable_hw_sec will not * be set when wep key setting */ /* we must reset sec_info after lingked before set key, * or some flag will be wrong*/ if (mac->opmode == NL80211_IFTYPE_AP) { if (!group_key || key_type == WEP40_ENCRYPTION || key_type == WEP104_ENCRYPTION) { if (group_key) wep_only = true; rtlpriv->cfg->ops->enable_hw_sec(hw); } } else { if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION && (key_type == WEP40_ENCRYPTION || key_type == WEP104_ENCRYPTION)) wep_only = true; rtlpriv->sec.pairwise_enc_algorithm = key_type; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1" " TKIP:2 AES:4 WEP104:5)\n", key_type)); rtlpriv->cfg->ops->enable_hw_sec(hw); } } /* <4> set key based on cmd */ switch (cmd) { case SET_KEY: if (wep_only) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("set WEP(group/pairwise) key\n")); /* Pairwise key with an assigned MAC address. */ rtlpriv->sec.pairwise_enc_algorithm = key_type; rtlpriv->sec.group_enc_algorithm = key_type; /*set local buf about wep key. */ memcpy(rtlpriv->sec.key_buf[key_idx], key->key, key->keylen); rtlpriv->sec.key_len[key_idx] = key->keylen; memcpy(mac_addr, zero_addr, ETH_ALEN); } else if (group_key) { /* group key */ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("set group key\n")); /* group key */ rtlpriv->sec.group_enc_algorithm = key_type; /*set local buf about group key. */ memcpy(rtlpriv->sec.key_buf[key_idx], key->key, key->keylen); rtlpriv->sec.key_len[key_idx] = key->keylen; memcpy(mac_addr, bcast_addr, ETH_ALEN); } else { /* pairwise key */ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("set pairwise key\n")); if (!sta) { RT_ASSERT(false, ("pairwise key withnot" "mac_addr\n")); err = -EOPNOTSUPP; goto out_unlock; } /* Pairwise key with an assigned MAC address. */ rtlpriv->sec.pairwise_enc_algorithm = key_type; /*set local buf about pairwise key. */ memcpy(rtlpriv->sec.key_buf[PAIRWISE_KEYIDX], key->key, key->keylen); rtlpriv->sec.key_len[PAIRWISE_KEYIDX] = key->keylen; rtlpriv->sec.pairwise_key = rtlpriv->sec.key_buf[PAIRWISE_KEYIDX]; memcpy(mac_addr, sta->addr, ETH_ALEN); } rtlpriv->cfg->ops->set_key(hw, key_idx, mac_addr, group_key, key_type, wep_only, false); /* <5> tell mac80211 do something: */ /*must use sw generate IV, or can not work !!!!. */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; key->hw_key_idx = key_idx; if (key_type == TKIP_ENCRYPTION) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; break; case DISABLE_KEY: RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("disable key delete one entry\n")); /*set local buf about wep key. */ if (mac->opmode == NL80211_IFTYPE_AP) { if (sta) rtl_cam_del_entry(hw, sta->addr); } memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); rtlpriv->sec.key_len[key_idx] = 0; memcpy(mac_addr, zero_addr, ETH_ALEN); /* *mac80211 will delete entrys one by one, *so don't use rtl_cam_reset_all_entry *or clear all entry here. */ rtl_cam_delete_one_entry(hw, mac_addr, key_idx); break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("cmd_err:%x!!!!:\n", cmd)); } out_unlock: mutex_unlock(&rtlpriv->locks.conf_mutex); rtlpriv->sec.being_setkey = false; return err; }
void rtl92c_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 *macaddr = p_macaddr; u32 entry_id = 0; bool is_pairwise = false; 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 }; if (clear_all) { u8 idx = 0; u8 cam_offset = 0; u8 clear_number = 5; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n"); for (idx = 0; idx < clear_number; idx++) { rtl_cam_mark_invalid(hw, cam_offset + idx); rtl_cam_empty_entry(hw, cam_offset + idx); if (idx < 5) { memset(rtlpriv->sec.key_buf[idx], 0, MAX_KEY_LEN); rtlpriv->sec.key_len[idx] = 0; } } } else { switch (enc_algo) { case WEP40_ENCRYPTION: enc_algo = CAM_WEP40; break; case WEP104_ENCRYPTION: enc_algo = CAM_WEP104; break; case TKIP_ENCRYPTION: enc_algo = CAM_TKIP; break; case AESCCMP_ENCRYPTION: enc_algo = CAM_AES; break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "illegal switch case\n"); enc_algo = CAM_TKIP; break; } if (is_wepkey || rtlpriv->sec.use_defaultkey) { macaddr = cam_const_addr[key_index]; entry_id = key_index; } else { if (is_group) { macaddr = cam_const_broad; entry_id = key_index; } else { if (mac->opmode == NL80211_IFTYPE_AP || mac->opmode == NL80211_IFTYPE_MESH_POINT) { entry_id = rtl_cam_get_free_entry(hw, p_macaddr); if (entry_id >= TOTAL_CAM_ENTRY) { RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, "Can not find free hw security cam entry\n"); return; } } else { entry_id = CAM_PAIRWISE_KEY_POSITION; } key_index = PAIRWISE_KEYIDX; is_pairwise = true; } } if (rtlpriv->sec.key_len[key_index] == 0) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "delete one entry\n"); if (mac->opmode == NL80211_IFTYPE_AP || mac->opmode == NL80211_IFTYPE_MESH_POINT) rtl_cam_del_entry(hw, p_macaddr); rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); } else { RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "The insert KEY length is %d\n", rtlpriv->sec.key_len[PAIRWISE_KEYIDX]); RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "The insert KEY is %x %x\n", rtlpriv->sec.key_buf[0][0], rtlpriv->sec.key_buf[0][1]); RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "add one entry\n"); if (is_pairwise) { RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, "Pairwise Key content", rtlpriv->sec.pairwise_key, rtlpriv->sec. key_len[PAIRWISE_KEYIDX]); RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set Pairwise key\n"); rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, enc_algo, CAM_CONFIG_NO_USEDK, rtlpriv->sec. key_buf[key_index]); } else { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set group key\n"); if (mac->opmode == NL80211_IFTYPE_ADHOC) { rtl_cam_add_one_entry(hw, rtlefuse->dev_addr, PAIRWISE_KEYIDX, CAM_PAIRWISE_KEY_POSITION, enc_algo, CAM_CONFIG_NO_USEDK, rtlpriv->sec.key_buf [entry_id]); } rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, enc_algo, CAM_CONFIG_NO_USEDK, rtlpriv->sec.key_buf[entry_id]); } } } }