1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2022 Intel Corporation
4  */
5 #include <linux/kernel.h>
6 #include <net/mac80211.h>
7 #include "mvm.h"
8 #include "fw/api/context.h"
9 #include "fw/api/datapath.h"
10 
iwl_mvm_get_sec_sta_mask(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf)11 static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
12 				    struct ieee80211_vif *vif,
13 				    struct ieee80211_sta *sta,
14 				    struct ieee80211_key_conf *keyconf)
15 {
16 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
17 
18 	if (vif->type == NL80211_IFTYPE_AP &&
19 	    !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
20 		return BIT(mvmvif->mcast_sta.sta_id);
21 
22 	if (sta) {
23 		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
24 
25 		return BIT(mvmsta->sta_id);
26 	}
27 
28 	if (vif->type == NL80211_IFTYPE_STATION &&
29 	    mvmvif->ap_sta_id != IWL_MVM_INVALID_STA)
30 		return BIT(mvmvif->ap_sta_id);
31 
32 	/* invalid */
33 	return 0;
34 }
35 
iwl_mvm_get_sec_flags(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf)36 static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
37 				 struct ieee80211_vif *vif,
38 				 struct ieee80211_sta *sta,
39 				 struct ieee80211_key_conf *keyconf)
40 {
41 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
42 	u32 flags = 0;
43 
44 	if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
45 		flags |= IWL_SEC_KEY_FLAG_MCAST_KEY;
46 
47 	switch (keyconf->cipher) {
48 	case WLAN_CIPHER_SUITE_WEP104:
49 		flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
50 		fallthrough;
51 	case WLAN_CIPHER_SUITE_WEP40:
52 		flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP;
53 		break;
54 	case WLAN_CIPHER_SUITE_TKIP:
55 		flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP;
56 		break;
57 	case WLAN_CIPHER_SUITE_AES_CMAC:
58 	case WLAN_CIPHER_SUITE_CCMP:
59 		flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP;
60 		break;
61 	case WLAN_CIPHER_SUITE_GCMP_256:
62 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
63 		flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
64 		fallthrough;
65 	case WLAN_CIPHER_SUITE_GCMP:
66 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
67 		flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP;
68 		break;
69 	}
70 
71 	rcu_read_lock();
72 	if (!sta && vif->type == NL80211_IFTYPE_STATION &&
73 	    mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) {
74 		u8 sta_id = mvmvif->ap_sta_id;
75 
76 		sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
77 					    lockdep_is_held(&mvm->mutex));
78 	}
79 
80 	if (!IS_ERR_OR_NULL(sta) && sta->mfp)
81 		flags |= IWL_SEC_KEY_FLAG_MFP;
82 	rcu_read_unlock();
83 
84 	return flags;
85 }
86 
__iwl_mvm_sec_key_del(struct iwl_mvm * mvm,u32 sta_mask,u32 key_flags,u32 keyidx,u32 flags)87 static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
88 				 u32 key_flags, u32 keyidx, u32 flags)
89 {
90 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
91 	struct iwl_sec_key_cmd cmd = {
92 		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
93 		.u.remove.sta_mask = cpu_to_le32(sta_mask),
94 		.u.remove.key_id = cpu_to_le32(keyidx),
95 		.u.remove.key_flags = cpu_to_le32(key_flags),
96 	};
97 
98 	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
99 }
100 
iwl_mvm_sec_key_add(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf)101 int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
102 			struct ieee80211_vif *vif,
103 			struct ieee80211_sta *sta,
104 			struct ieee80211_key_conf *keyconf)
105 {
106 	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
107 	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
108 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
109 	struct iwl_sec_key_cmd cmd = {
110 		.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
111 		.u.add.sta_mask = cpu_to_le32(sta_mask),
112 		.u.add.key_id = cpu_to_le32(keyconf->keyidx),
113 		.u.add.key_flags = cpu_to_le32(key_flags),
114 		.u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
115 	};
116 	int ret;
117 
118 	if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key)))
119 		return -EINVAL;
120 
121 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
122 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
123 		memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key,
124 		       keyconf->keylen);
125 	else
126 		memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);
127 
128 	if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) {
129 		memcpy(cmd.u.add.tkip_mic_rx_key,
130 		       keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
131 		       8);
132 		memcpy(cmd.u.add.tkip_mic_tx_key,
133 		       keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
134 		       8);
135 	}
136 
137 	ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
138 	if (ret)
139 		return ret;
140 
141 	/*
142 	 * For WEP, the same key is used for multicast and unicast so need to
143 	 * upload it again. If this fails, remove the original as well.
144 	 */
145 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
146 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
147 		cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY);
148 		ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
149 		if (ret)
150 			__iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
151 					      keyconf->keyidx, 0);
152 	}
153 
154 	return ret;
155 }
156 
_iwl_mvm_sec_key_del(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf,u32 flags)157 static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
158 				struct ieee80211_vif *vif,
159 				struct ieee80211_sta *sta,
160 				struct ieee80211_key_conf *keyconf,
161 				u32 flags)
162 {
163 	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
164 	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
165 	int ret;
166 
167 	ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
168 				    flags);
169 	if (ret)
170 		return ret;
171 
172 	/* For WEP, delete the key again as unicast */
173 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
174 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
175 		key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY;
176 		ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
177 					    keyconf->keyidx, flags);
178 	}
179 
180 	return ret;
181 }
182 
iwl_mvm_sec_key_del(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf)183 int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
184 			struct ieee80211_vif *vif,
185 			struct ieee80211_sta *sta,
186 			struct ieee80211_key_conf *keyconf)
187 {
188 	return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0);
189 }
190 
iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key,void * data)191 static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
192 					   struct ieee80211_vif *vif,
193 					   struct ieee80211_sta *sta,
194 					   struct ieee80211_key_conf *key,
195 					   void *data)
196 {
197 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
198 
199 	if (key->hw_key_idx == STA_KEY_IDX_INVALID)
200 		return;
201 
202 	if (sta)
203 		return;
204 
205 	_iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
206 	key->hw_key_idx = STA_KEY_IDX_INVALID;
207 }
208 
iwl_mvm_sec_key_remove_ap(struct iwl_mvm * mvm,struct ieee80211_vif * vif)209 void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
210 			       struct ieee80211_vif *vif)
211 {
212 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
213 	u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
214 	u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
215 
216 	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION ||
217 		    mvmvif->ap_sta_id == IWL_MVM_INVALID_STA))
218 		return;
219 
220 	if (!sec_key_ver)
221 		return;
222 
223 	ieee80211_iter_keys_rcu(mvm->hw, vif,
224 				iwl_mvm_sec_key_remove_ap_iter,
225 				NULL);
226 }
227