treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / staging / wfx / key.c
blob96adfa33060473d8e71937f69c585528b3989787
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Key management related functions.
5 * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
7 */
8 #include <net/mac80211.h>
10 #include "key.h"
11 #include "wfx.h"
12 #include "hif_tx_mib.h"
14 static int wfx_alloc_key(struct wfx_dev *wdev)
16 int idx;
18 idx = ffs(~wdev->key_map) - 1;
19 if (idx < 0 || idx >= MAX_KEY_ENTRIES)
20 return -1;
22 wdev->key_map |= BIT(idx);
23 wdev->keys[idx].entry_index = idx;
24 return idx;
27 static void wfx_free_key(struct wfx_dev *wdev, int idx)
29 WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation");
30 memset(&wdev->keys[idx], 0, sizeof(wdev->keys[idx]));
31 wdev->key_map &= ~BIT(idx);
34 static u8 fill_wep_pair(struct hif_wep_pairwise_key *msg,
35 struct ieee80211_key_conf *key, u8 *peer_addr)
37 WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
38 msg->key_length = key->keylen;
39 memcpy(msg->key_data, key->key, key->keylen);
40 ether_addr_copy(msg->peer_address, peer_addr);
41 return HIF_KEY_TYPE_WEP_PAIRWISE;
44 static u8 fill_wep_group(struct hif_wep_group_key *msg,
45 struct ieee80211_key_conf *key)
47 WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
48 msg->key_id = key->keyidx;
49 msg->key_length = key->keylen;
50 memcpy(msg->key_data, key->key, key->keylen);
51 return HIF_KEY_TYPE_WEP_DEFAULT;
54 static u8 fill_tkip_pair(struct hif_tkip_pairwise_key *msg,
55 struct ieee80211_key_conf *key, u8 *peer_addr)
57 u8 *keybuf = key->key;
59 WARN(key->keylen != sizeof(msg->tkip_key_data)
60 + sizeof(msg->tx_mic_key)
61 + sizeof(msg->rx_mic_key), "inconsistent data");
62 memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
63 keybuf += sizeof(msg->tkip_key_data);
64 memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key));
65 keybuf += sizeof(msg->tx_mic_key);
66 memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key));
67 ether_addr_copy(msg->peer_address, peer_addr);
68 return HIF_KEY_TYPE_TKIP_PAIRWISE;
71 static u8 fill_tkip_group(struct hif_tkip_group_key *msg,
72 struct ieee80211_key_conf *key,
73 struct ieee80211_key_seq *seq,
74 enum nl80211_iftype iftype)
76 u8 *keybuf = key->key;
78 WARN(key->keylen != sizeof(msg->tkip_key_data)
79 + 2 * sizeof(msg->rx_mic_key), "inconsistent data");
80 msg->key_id = key->keyidx;
81 memcpy(msg->rx_sequence_counter,
82 &seq->tkip.iv16, sizeof(seq->tkip.iv16));
83 memcpy(msg->rx_sequence_counter + sizeof(u16),
84 &seq->tkip.iv32, sizeof(seq->tkip.iv32));
85 memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
86 keybuf += sizeof(msg->tkip_key_data);
87 if (iftype == NL80211_IFTYPE_AP)
88 // Use Tx MIC Key
89 memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key));
90 else
91 // Use Rx MIC Key
92 memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key));
93 return HIF_KEY_TYPE_TKIP_GROUP;
96 static u8 fill_ccmp_pair(struct hif_aes_pairwise_key *msg,
97 struct ieee80211_key_conf *key, u8 *peer_addr)
99 WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
100 ether_addr_copy(msg->peer_address, peer_addr);
101 memcpy(msg->aes_key_data, key->key, key->keylen);
102 return HIF_KEY_TYPE_AES_PAIRWISE;
105 static u8 fill_ccmp_group(struct hif_aes_group_key *msg,
106 struct ieee80211_key_conf *key,
107 struct ieee80211_key_seq *seq)
109 WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
110 memcpy(msg->aes_key_data, key->key, key->keylen);
111 memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn));
112 memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn));
113 msg->key_id = key->keyidx;
114 return HIF_KEY_TYPE_AES_GROUP;
117 static u8 fill_sms4_pair(struct hif_wapi_pairwise_key *msg,
118 struct ieee80211_key_conf *key, u8 *peer_addr)
120 u8 *keybuf = key->key;
122 WARN(key->keylen != sizeof(msg->wapi_key_data)
123 + sizeof(msg->mic_key_data), "inconsistent data");
124 ether_addr_copy(msg->peer_address, peer_addr);
125 memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
126 keybuf += sizeof(msg->wapi_key_data);
127 memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
128 msg->key_id = key->keyidx;
129 return HIF_KEY_TYPE_WAPI_PAIRWISE;
132 static u8 fill_sms4_group(struct hif_wapi_group_key *msg,
133 struct ieee80211_key_conf *key)
135 u8 *keybuf = key->key;
137 WARN(key->keylen != sizeof(msg->wapi_key_data)
138 + sizeof(msg->mic_key_data), "inconsistent data");
139 memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
140 keybuf += sizeof(msg->wapi_key_data);
141 memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
142 msg->key_id = key->keyidx;
143 return HIF_KEY_TYPE_WAPI_GROUP;
146 static u8 fill_aes_cmac_group(struct hif_igtk_group_key *msg,
147 struct ieee80211_key_conf *key,
148 struct ieee80211_key_seq *seq)
150 WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data");
151 memcpy(msg->igtk_key_data, key->key, key->keylen);
152 memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn));
153 memreverse(msg->ipn, sizeof(seq->aes_cmac.pn));
154 msg->key_id = key->keyidx;
155 return HIF_KEY_TYPE_IGTK_GROUP;
158 static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta,
159 struct ieee80211_key_conf *key)
161 int ret;
162 struct hif_req_add_key *k;
163 struct ieee80211_key_seq seq;
164 struct wfx_dev *wdev = wvif->wdev;
165 int idx = wfx_alloc_key(wvif->wdev);
166 bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE;
168 WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data");
169 ieee80211_get_key_rx_seq(key, 0, &seq);
170 if (idx < 0)
171 return -EINVAL;
172 k = &wdev->keys[idx];
173 k->int_id = wvif->id;
174 if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
175 key->cipher == WLAN_CIPHER_SUITE_WEP104) {
176 if (pairwise)
177 k->type = fill_wep_pair(&k->key.wep_pairwise_key, key,
178 sta->addr);
179 else
180 k->type = fill_wep_group(&k->key.wep_group_key, key);
181 } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
182 if (pairwise)
183 k->type = fill_tkip_pair(&k->key.tkip_pairwise_key, key,
184 sta->addr);
185 else
186 k->type = fill_tkip_group(&k->key.tkip_group_key, key,
187 &seq, wvif->vif->type);
188 } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) {
189 if (pairwise)
190 k->type = fill_ccmp_pair(&k->key.aes_pairwise_key, key,
191 sta->addr);
192 else
193 k->type = fill_ccmp_group(&k->key.aes_group_key, key,
194 &seq);
195 } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) {
196 if (pairwise)
197 k->type = fill_sms4_pair(&k->key.wapi_pairwise_key, key,
198 sta->addr);
199 else
200 k->type = fill_sms4_group(&k->key.wapi_group_key, key);
201 } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
202 k->type = fill_aes_cmac_group(&k->key.igtk_group_key, key,
203 &seq);
204 } else {
205 dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher);
206 wfx_free_key(wdev, idx);
207 return -EOPNOTSUPP;
209 ret = hif_add_key(wdev, k);
210 if (ret) {
211 wfx_free_key(wdev, idx);
212 return -EOPNOTSUPP;
214 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE |
215 IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
216 key->hw_key_idx = idx;
217 return 0;
220 static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key)
222 WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx");
223 wfx_free_key(wvif->wdev, key->hw_key_idx);
224 return hif_remove_key(wvif->wdev, key->hw_key_idx);
227 int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
228 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
229 struct ieee80211_key_conf *key)
231 int ret = -EOPNOTSUPP;
232 struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv;
234 mutex_lock(&wvif->wdev->conf_mutex);
235 if (cmd == SET_KEY)
236 ret = wfx_add_key(wvif, sta, key);
237 if (cmd == DISABLE_KEY)
238 ret = wfx_remove_key(wvif, key);
239 mutex_unlock(&wvif->wdev->conf_mutex);
240 return ret;
243 int wfx_upload_keys(struct wfx_vif *wvif)
245 int i;
246 struct hif_req_add_key *key;
247 struct wfx_dev *wdev = wvif->wdev;
249 for (i = 0; i < ARRAY_SIZE(wdev->keys); i++) {
250 if (wdev->key_map & BIT(i)) {
251 key = &wdev->keys[i];
252 if (key->int_id == wvif->id)
253 hif_add_key(wdev, key);
256 return 0;
259 void wfx_wep_key_work(struct work_struct *work)
261 struct wfx_vif *wvif = container_of(work, struct wfx_vif, wep_key_work);
263 wfx_tx_flush(wvif->wdev);
264 hif_wep_default_key_id(wvif, wvif->wep_default_key_id);
265 wfx_pending_requeue(wvif->wdev, wvif->wep_pending_skb);
266 wvif->wep_pending_skb = NULL;
267 wfx_tx_unlock(wvif->wdev);