key.c (7619B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Key management related functions. 4 * 5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc. 6 * Copyright (c) 2010, ST-Ericsson 7 */ 8#include <linux/etherdevice.h> 9#include <net/mac80211.h> 10 11#include "key.h" 12#include "wfx.h" 13#include "hif_tx_mib.h" 14 15static int wfx_alloc_key(struct wfx_dev *wdev) 16{ 17 int idx; 18 19 idx = ffs(~wdev->key_map) - 1; 20 if (idx < 0 || idx >= MAX_KEY_ENTRIES) 21 return -1; 22 23 wdev->key_map |= BIT(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 wdev->key_map &= ~BIT(idx); 31} 32 33static u8 fill_wep_pair(struct wfx_hif_wep_pairwise_key *msg, 34 struct ieee80211_key_conf *key, u8 *peer_addr) 35{ 36 WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); 37 msg->key_length = key->keylen; 38 memcpy(msg->key_data, key->key, key->keylen); 39 ether_addr_copy(msg->peer_address, peer_addr); 40 return HIF_KEY_TYPE_WEP_PAIRWISE; 41} 42 43static u8 fill_wep_group(struct wfx_hif_wep_group_key *msg, 44 struct ieee80211_key_conf *key) 45{ 46 WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); 47 msg->key_id = key->keyidx; 48 msg->key_length = key->keylen; 49 memcpy(msg->key_data, key->key, key->keylen); 50 return HIF_KEY_TYPE_WEP_DEFAULT; 51} 52 53static u8 fill_tkip_pair(struct wfx_hif_tkip_pairwise_key *msg, 54 struct ieee80211_key_conf *key, u8 *peer_addr) 55{ 56 u8 *keybuf = key->key; 57 58 WARN(key->keylen != sizeof(msg->tkip_key_data) + sizeof(msg->tx_mic_key) + 59 sizeof(msg->rx_mic_key), "inconsistent data"); 60 memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); 61 keybuf += sizeof(msg->tkip_key_data); 62 memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key)); 63 keybuf += sizeof(msg->tx_mic_key); 64 memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key)); 65 ether_addr_copy(msg->peer_address, peer_addr); 66 return HIF_KEY_TYPE_TKIP_PAIRWISE; 67} 68 69static u8 fill_tkip_group(struct wfx_hif_tkip_group_key *msg, struct ieee80211_key_conf *key, 70 struct ieee80211_key_seq *seq, enum nl80211_iftype iftype) 71{ 72 u8 *keybuf = key->key; 73 74 WARN(key->keylen != sizeof(msg->tkip_key_data) + 2 * sizeof(msg->rx_mic_key), 75 "inconsistent data"); 76 msg->key_id = key->keyidx; 77 memcpy(msg->rx_sequence_counter, &seq->tkip.iv16, sizeof(seq->tkip.iv16)); 78 memcpy(msg->rx_sequence_counter + sizeof(u16), &seq->tkip.iv32, sizeof(seq->tkip.iv32)); 79 memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); 80 keybuf += sizeof(msg->tkip_key_data); 81 if (iftype == NL80211_IFTYPE_AP) 82 /* Use Tx MIC Key */ 83 memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key)); 84 else 85 /* Use Rx MIC Key */ 86 memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key)); 87 return HIF_KEY_TYPE_TKIP_GROUP; 88} 89 90static u8 fill_ccmp_pair(struct wfx_hif_aes_pairwise_key *msg, 91 struct ieee80211_key_conf *key, u8 *peer_addr) 92{ 93 WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); 94 ether_addr_copy(msg->peer_address, peer_addr); 95 memcpy(msg->aes_key_data, key->key, key->keylen); 96 return HIF_KEY_TYPE_AES_PAIRWISE; 97} 98 99static u8 fill_ccmp_group(struct wfx_hif_aes_group_key *msg, 100 struct ieee80211_key_conf *key, struct ieee80211_key_seq *seq) 101{ 102 WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); 103 memcpy(msg->aes_key_data, key->key, key->keylen); 104 memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn)); 105 memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn)); 106 msg->key_id = key->keyidx; 107 return HIF_KEY_TYPE_AES_GROUP; 108} 109 110static u8 fill_sms4_pair(struct wfx_hif_wapi_pairwise_key *msg, 111 struct ieee80211_key_conf *key, u8 *peer_addr) 112{ 113 u8 *keybuf = key->key; 114 115 WARN(key->keylen != sizeof(msg->wapi_key_data) + sizeof(msg->mic_key_data), 116 "inconsistent data"); 117 ether_addr_copy(msg->peer_address, peer_addr); 118 memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); 119 keybuf += sizeof(msg->wapi_key_data); 120 memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); 121 msg->key_id = key->keyidx; 122 return HIF_KEY_TYPE_WAPI_PAIRWISE; 123} 124 125static u8 fill_sms4_group(struct wfx_hif_wapi_group_key *msg, 126 struct ieee80211_key_conf *key) 127{ 128 u8 *keybuf = key->key; 129 130 WARN(key->keylen != sizeof(msg->wapi_key_data) + sizeof(msg->mic_key_data), 131 "inconsistent data"); 132 memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); 133 keybuf += sizeof(msg->wapi_key_data); 134 memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); 135 msg->key_id = key->keyidx; 136 return HIF_KEY_TYPE_WAPI_GROUP; 137} 138 139static u8 fill_aes_cmac_group(struct wfx_hif_igtk_group_key *msg, 140 struct ieee80211_key_conf *key, struct ieee80211_key_seq *seq) 141{ 142 WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data"); 143 memcpy(msg->igtk_key_data, key->key, key->keylen); 144 memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn)); 145 memreverse(msg->ipn, sizeof(seq->aes_cmac.pn)); 146 msg->key_id = key->keyidx; 147 return HIF_KEY_TYPE_IGTK_GROUP; 148} 149 150static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, 151 struct ieee80211_key_conf *key) 152{ 153 int ret; 154 struct wfx_hif_req_add_key k = { }; 155 struct ieee80211_key_seq seq; 156 struct wfx_dev *wdev = wvif->wdev; 157 int idx = wfx_alloc_key(wvif->wdev); 158 bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE; 159 struct ieee80211_vif *vif = wvif_to_vif(wvif); 160 161 WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data"); 162 ieee80211_get_key_rx_seq(key, 0, &seq); 163 if (idx < 0) 164 return -EINVAL; 165 k.int_id = wvif->id; 166 k.entry_index = idx; 167 if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || 168 key->cipher == WLAN_CIPHER_SUITE_WEP104) { 169 if (pairwise) 170 k.type = fill_wep_pair(&k.key.wep_pairwise_key, key, sta->addr); 171 else 172 k.type = fill_wep_group(&k.key.wep_group_key, key); 173 } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { 174 if (pairwise) 175 k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key, sta->addr); 176 else 177 k.type = fill_tkip_group(&k.key.tkip_group_key, key, &seq, 178 vif->type); 179 } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) { 180 if (pairwise) 181 k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key, sta->addr); 182 else 183 k.type = fill_ccmp_group(&k.key.aes_group_key, key, &seq); 184 } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) { 185 if (pairwise) 186 k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key, sta->addr); 187 else 188 k.type = fill_sms4_group(&k.key.wapi_group_key, key); 189 } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { 190 k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq); 191 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; 192 } else { 193 dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher); 194 wfx_free_key(wdev, idx); 195 return -EOPNOTSUPP; 196 } 197 ret = wfx_hif_add_key(wdev, &k); 198 if (ret) { 199 wfx_free_key(wdev, idx); 200 return -EOPNOTSUPP; 201 } 202 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | IEEE80211_KEY_FLAG_RESERVE_TAILROOM; 203 key->hw_key_idx = idx; 204 return 0; 205} 206 207static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key) 208{ 209 WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx"); 210 wfx_free_key(wvif->wdev, key->hw_key_idx); 211 return wfx_hif_remove_key(wvif->wdev, key->hw_key_idx); 212} 213 214int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, 215 struct ieee80211_sta *sta, struct ieee80211_key_conf *key) 216{ 217 int ret = -EOPNOTSUPP; 218 struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; 219 220 mutex_lock(&wvif->wdev->conf_mutex); 221 if (cmd == SET_KEY) 222 ret = wfx_add_key(wvif, sta, key); 223 if (cmd == DISABLE_KEY) 224 ret = wfx_remove_key(wvif, key); 225 mutex_unlock(&wvif->wdev->conf_mutex); 226 return ret; 227}