1 /* 2 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: defines crypto driver functions interfacing with linux kernel 22 */ 23 #include <wlan_crypto_global_def.h> 24 #include <wlan_crypto_global_api.h> 25 #include <wlan_objmgr_vdev_obj.h> 26 #include <wlan_crypto_main_i.h> 27 #include <wlan_objmgr_pdev_obj.h> 28 #include <wlan_objmgr_peer_obj.h> 29 #include <wlan_crypto_def_i.h> 30 #include <wlan_crypto_obj_mgr_i.h> 31 #include <net/cfg80211.h> 32 #include <wlan_nl_to_crypto_params.h> 33 #include "wlan_cfg80211_crypto.h" 34 #include <wlan_cfg80211.h> 35 #include <wlan_osif_request_manager.h> 36 37 void wlan_cfg80211_translate_ml_sta_key(uint8_t key_index, 38 enum wlan_crypto_key_type key_type, 39 const u8 *mac_addr, 40 struct key_params *params, 41 struct wlan_crypto_key *crypto_key) 42 { 43 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 44 crypto_key->keylen = params->key_len; 45 crypto_key->keyix = key_index; 46 osif_debug("key_type %d, key_len %d, seq_len %d", 47 key_type, 48 params->key_len, params->seq_len); 49 qdf_mem_copy(&crypto_key->keyval[0], params->key, params->key_len); 50 qdf_mem_copy(&crypto_key->keyrsc[0], params->seq, params->seq_len); 51 52 crypto_key->key_type = key_type; 53 crypto_key->cipher_type = osif_nl_to_crypto_cipher_type(params->cipher); 54 55 qdf_mem_copy(&crypto_key->macaddr, mac_addr, 56 QDF_MAC_ADDR_SIZE); 57 osif_debug("crypto key mac " QDF_MAC_ADDR_FMT, 58 QDF_MAC_ADDR_REF(crypto_key->macaddr)); 59 } 60 61 void wlan_cfg80211_translate_key(struct wlan_objmgr_vdev *vdev, 62 uint8_t key_index, 63 enum wlan_crypto_key_type key_type, 64 const u8 *mac_addr, 65 struct key_params *params, 66 struct wlan_crypto_key *crypto_key) 67 { 68 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 69 crypto_key->keylen = params->key_len; 70 crypto_key->keyix = key_index; 71 osif_debug("key_type %d, opmode %d, key_len %d, seq_len %d", 72 key_type, vdev->vdev_mlme.vdev_opmode, 73 params->key_len, params->seq_len); 74 qdf_mem_copy(&crypto_key->keyval[0], params->key, params->key_len); 75 qdf_mem_copy(&crypto_key->keyrsc[0], params->seq, params->seq_len); 76 77 crypto_key->key_type = key_type; 78 crypto_key->cipher_type = osif_nl_to_crypto_cipher_type(params->cipher); 79 if (IS_WEP_CIPHER(crypto_key->cipher_type) && !mac_addr) { 80 /* 81 * This is a valid scenario in case of WEP, where-in the 82 * keys are passed by the user space during the connect request 83 * but since we did not connect yet, so we do not know the peer 84 * address yet. 85 */ 86 osif_debug("No Mac Address to copy"); 87 return; 88 } 89 if (key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) { 90 qdf_mem_copy(&crypto_key->macaddr, mac_addr, QDF_MAC_ADDR_SIZE); 91 } else { 92 if ((vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE) || 93 (vdev->vdev_mlme.vdev_opmode == QDF_P2P_CLIENT_MODE)) 94 qdf_mem_copy(&crypto_key->macaddr, mac_addr, 95 QDF_MAC_ADDR_SIZE); 96 else 97 qdf_mem_copy(&crypto_key->macaddr, 98 vdev->vdev_mlme.macaddr, 99 QDF_MAC_ADDR_SIZE); 100 } 101 osif_debug("mac "QDF_MAC_ADDR_FMT, 102 QDF_MAC_ADDR_REF(crypto_key->macaddr)); 103 } 104 105 int wlan_cfg80211_store_key(struct wlan_objmgr_vdev *vdev, 106 uint8_t key_index, 107 enum wlan_crypto_key_type key_type, 108 const u8 *mac_addr, struct key_params *params) 109 { 110 struct wlan_crypto_key *crypto_key = NULL; 111 enum wlan_crypto_cipher_type cipher; 112 int cipher_len; 113 QDF_STATUS status; 114 115 if (!vdev) { 116 osif_err("vdev is NULL"); 117 return -EINVAL; 118 } 119 if (!params) { 120 osif_err("Key params is NULL"); 121 return -EINVAL; 122 } 123 cipher_len = osif_nl_to_crypto_cipher_len(params->cipher); 124 if (cipher_len < 0 || params->key_len < cipher_len) { 125 osif_err("cipher length %d less than reqd len %d", 126 params->key_len, cipher_len); 127 return -EINVAL; 128 } 129 cipher = osif_nl_to_crypto_cipher_type(params->cipher); 130 if (!IS_WEP_CIPHER(cipher)) { 131 if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) && 132 !mac_addr) { 133 osif_err("mac_addr is NULL for pairwise Key"); 134 return -EINVAL; 135 } 136 } 137 status = wlan_crypto_validate_key_params(cipher, key_index, 138 params->key_len, 139 params->seq_len); 140 if (QDF_IS_STATUS_ERROR(status)) { 141 osif_err("Invalid key params"); 142 return -EINVAL; 143 } 144 145 /* 146 * key may already exist at times and may be retrieved only to 147 * update it. 148 */ 149 crypto_key = wlan_crypto_get_key(vdev, key_index); 150 if (!crypto_key) { 151 crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); 152 if (!crypto_key) 153 return -EINVAL; 154 } 155 156 wlan_cfg80211_translate_key(vdev, key_index, key_type, mac_addr, 157 params, crypto_key); 158 159 status = wlan_crypto_save_key(vdev, key_index, crypto_key); 160 if (QDF_IS_STATUS_ERROR(status)) { 161 osif_err("Failed to save key"); 162 qdf_mem_free(crypto_key); 163 return -EINVAL; 164 } 165 return 0; 166 } 167 168 #define WLAN_WAIT_TIME_ADD_KEY 100 169 170 static void 171 wlan_cfg80211_crypto_add_key_cb(void *context, 172 struct crypto_add_key_result *result) 173 { 174 struct osif_request *request; 175 struct crypto_add_key_result *priv; 176 177 request = osif_request_get(context); 178 if (!request) { 179 osif_err("Obsolete request"); 180 return; 181 } 182 183 priv = osif_request_priv(request); 184 qdf_mem_copy(priv, result, sizeof(*priv)); 185 osif_request_complete(request); 186 osif_request_put(request); 187 } 188 189 int wlan_cfg80211_crypto_add_key(struct wlan_objmgr_vdev *vdev, 190 enum wlan_crypto_key_type key_type, 191 uint8_t key_index, bool sync) 192 { 193 struct wlan_crypto_key *crypto_key; 194 QDF_STATUS status; 195 struct osif_request *request; 196 struct crypto_add_key_result *result; 197 struct wlan_crypto_comp_priv *priv; 198 int ret; 199 static const struct osif_request_params params = { 200 .priv_size = sizeof(*result), 201 .timeout_ms = WLAN_WAIT_TIME_ADD_KEY, 202 }; 203 204 crypto_key = wlan_crypto_get_key(vdev, key_index); 205 if (!crypto_key) { 206 osif_err("Crypto KEY is NULL"); 207 return -EINVAL; 208 } 209 210 if (sync) { 211 priv = wlan_get_vdev_crypto_obj(vdev); 212 if (!priv) { 213 osif_err("Invalid crypto_priv"); 214 return -EINVAL; 215 } 216 217 request = osif_request_alloc(¶ms); 218 if (!request) { 219 osif_err("Request allocation failure"); 220 return -ENOMEM; 221 } 222 223 priv->add_key_ctx = osif_request_cookie(request);; 224 priv->add_key_cb = wlan_cfg80211_crypto_add_key_cb; 225 226 status = ucfg_crypto_set_key_req(vdev, crypto_key, key_type); 227 if (QDF_IS_STATUS_SUCCESS(status)) { 228 ret = osif_request_wait_for_response(request); 229 if (ret) { 230 osif_err("Target response timed out"); 231 } else { 232 result = osif_request_priv(request); 233 osif_debug("complete, vdev_id %u, ix: %u, flags: %u, status: %u", 234 result->vdev_id, result->key_ix, 235 result->key_flags, result->status); 236 } 237 } 238 239 priv->add_key_ctx = NULL; 240 priv->add_key_cb = NULL; 241 osif_request_put(request); 242 } else { 243 status = ucfg_crypto_set_key_req(vdev, crypto_key, key_type); 244 } 245 246 return qdf_status_to_os_return(status); 247 } 248 249 int wlan_cfg80211_set_default_key(struct wlan_objmgr_vdev *vdev, 250 uint8_t key_index, struct qdf_mac_addr *bssid) 251 { 252 return wlan_crypto_default_key(vdev, (uint8_t *)bssid, 253 key_index, true); 254 } 255