at v5.7 268 lines 8.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Key management related functions. 4 * 5 * Copyright (c) 2017-2019, Silicon Laboratories, Inc. 6 * Copyright (c) 2010, ST-Ericsson 7 */ 8#include <net/mac80211.h> 9 10#include "key.h" 11#include "wfx.h" 12#include "hif_tx_mib.h" 13 14static int wfx_alloc_key(struct wfx_dev *wdev) 15{ 16 int idx; 17 18 idx = ffs(~wdev->key_map) - 1; 19 if (idx < 0 || idx >= MAX_KEY_ENTRIES) 20 return -1; 21 22 wdev->key_map |= BIT(idx); 23 wdev->keys[idx].entry_index = idx; 24 return idx; 25} 26 27static void wfx_free_key(struct wfx_dev *wdev, int idx) 28{ 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); 32} 33 34static u8 fill_wep_pair(struct hif_wep_pairwise_key *msg, 35 struct ieee80211_key_conf *key, u8 *peer_addr) 36{ 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; 42} 43 44static u8 fill_wep_group(struct hif_wep_group_key *msg, 45 struct ieee80211_key_conf *key) 46{ 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; 52} 53 54static u8 fill_tkip_pair(struct hif_tkip_pairwise_key *msg, 55 struct ieee80211_key_conf *key, u8 *peer_addr) 56{ 57 u8 *keybuf = key->key; 58 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; 69} 70 71static 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) 75{ 76 u8 *keybuf = key->key; 77 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; 94} 95 96static u8 fill_ccmp_pair(struct hif_aes_pairwise_key *msg, 97 struct ieee80211_key_conf *key, u8 *peer_addr) 98{ 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; 103} 104 105static u8 fill_ccmp_group(struct hif_aes_group_key *msg, 106 struct ieee80211_key_conf *key, 107 struct ieee80211_key_seq *seq) 108{ 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; 115} 116 117static u8 fill_sms4_pair(struct hif_wapi_pairwise_key *msg, 118 struct ieee80211_key_conf *key, u8 *peer_addr) 119{ 120 u8 *keybuf = key->key; 121 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; 130} 131 132static u8 fill_sms4_group(struct hif_wapi_group_key *msg, 133 struct ieee80211_key_conf *key) 134{ 135 u8 *keybuf = key->key; 136 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; 144} 145 146static u8 fill_aes_cmac_group(struct hif_igtk_group_key *msg, 147 struct ieee80211_key_conf *key, 148 struct ieee80211_key_seq *seq) 149{ 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; 156} 157 158static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, 159 struct ieee80211_key_conf *key) 160{ 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; 167 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; 208 } 209 ret = hif_add_key(wdev, k); 210 if (ret) { 211 wfx_free_key(wdev, idx); 212 return -EOPNOTSUPP; 213 } 214 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | 215 IEEE80211_KEY_FLAG_RESERVE_TAILROOM; 216 key->hw_key_idx = idx; 217 return 0; 218} 219 220static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key) 221{ 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); 225} 226 227int 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) 230{ 231 int ret = -EOPNOTSUPP; 232 struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; 233 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; 241} 242 243int wfx_upload_keys(struct wfx_vif *wvif) 244{ 245 int i; 246 struct hif_req_add_key *key; 247 struct wfx_dev *wdev = wvif->wdev; 248 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); 254 } 255 } 256 return 0; 257} 258 259void wfx_wep_key_work(struct work_struct *work) 260{ 261 struct wfx_vif *wvif = container_of(work, struct wfx_vif, wep_key_work); 262 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); 268}