1 /* 2 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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_key(struct wlan_objmgr_vdev *vdev, 38 uint8_t key_index, 39 enum wlan_crypto_key_type key_type, 40 const u8 *mac_addr, 41 struct key_params *params, 42 struct wlan_crypto_key *crypto_key) 43 { 44 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 45 crypto_key->keylen = params->key_len; 46 crypto_key->keyix = key_index; 47 osif_debug("key_type %d, opmode %d, key_len %d, seq_len %d", 48 key_type, vdev->vdev_mlme.vdev_opmode, 49 params->key_len, params->seq_len); 50 qdf_mem_copy(&crypto_key->keyval[0], params->key, params->key_len); 51 qdf_mem_copy(&crypto_key->keyrsc[0], params->seq, params->seq_len); 52 53 crypto_key->key_type = key_type; 54 crypto_key->cipher_type = osif_nl_to_crypto_cipher_type(params->cipher); 55 if (IS_WEP_CIPHER(crypto_key->cipher_type) && !mac_addr) { 56 /* 57 * This is a valid scenario in case of WEP, where-in the 58 * keys are passed by the user space during the connect request 59 * but since we did not connect yet, so we do not know the peer 60 * address yet. 61 */ 62 osif_debug("No Mac Address to copy"); 63 return; 64 } 65 if (key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) { 66 qdf_mem_copy(&crypto_key->macaddr, mac_addr, QDF_MAC_ADDR_SIZE); 67 } else { 68 if ((vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE) || 69 (vdev->vdev_mlme.vdev_opmode == QDF_P2P_CLIENT_MODE)) 70 qdf_mem_copy(&crypto_key->macaddr, mac_addr, 71 QDF_MAC_ADDR_SIZE); 72 else 73 qdf_mem_copy(&crypto_key->macaddr, 74 vdev->vdev_mlme.macaddr, 75 QDF_MAC_ADDR_SIZE); 76 } 77 osif_debug("mac "QDF_MAC_ADDR_FMT, 78 QDF_MAC_ADDR_REF(crypto_key->macaddr)); 79 } 80 81 int wlan_cfg80211_store_key(struct wlan_objmgr_vdev *vdev, 82 uint8_t key_index, 83 enum wlan_crypto_key_type key_type, 84 const u8 *mac_addr, struct key_params *params) 85 { 86 struct wlan_crypto_key *crypto_key = NULL; 87 enum wlan_crypto_cipher_type cipher; 88 int cipher_len; 89 QDF_STATUS status; 90 91 if (!vdev) { 92 osif_err("vdev is NULL"); 93 return -EINVAL; 94 } 95 if (!params) { 96 osif_err("Key params is NULL"); 97 return -EINVAL; 98 } 99 cipher_len = osif_nl_to_crypto_cipher_len(params->cipher); 100 if (cipher_len < 0 || params->key_len < cipher_len) { 101 osif_err("cipher length %d less than reqd len %d", 102 params->key_len, cipher_len); 103 return -EINVAL; 104 } 105 cipher = osif_nl_to_crypto_cipher_type(params->cipher); 106 if (!IS_WEP_CIPHER(cipher)) { 107 if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) && 108 !mac_addr) { 109 osif_err("mac_addr is NULL for pairwise Key"); 110 return -EINVAL; 111 } 112 } 113 status = wlan_crypto_validate_key_params(cipher, key_index, 114 params->key_len, 115 params->seq_len); 116 if (QDF_IS_STATUS_ERROR(status)) { 117 osif_err("Invalid key params"); 118 return -EINVAL; 119 } 120 121 /* 122 * key may already exist at times and may be retrieved only to 123 * update it. 124 */ 125 crypto_key = wlan_crypto_get_key(vdev, key_index); 126 if (!crypto_key) { 127 crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); 128 if (!crypto_key) 129 return -EINVAL; 130 } 131 132 wlan_cfg80211_translate_key(vdev, key_index, key_type, mac_addr, 133 params, crypto_key); 134 135 status = wlan_crypto_save_key(vdev, key_index, crypto_key); 136 if (QDF_IS_STATUS_ERROR(status)) { 137 osif_err("Failed to save key"); 138 qdf_mem_free(crypto_key); 139 return -EINVAL; 140 } 141 return 0; 142 } 143 144 #define WLAN_WAIT_TIME_ADD_KEY 100 145 146 static void 147 wlan_cfg80211_crypto_add_key_cb(void *context, 148 struct crypto_add_key_result *result) 149 { 150 struct osif_request *request; 151 struct crypto_add_key_result *priv; 152 153 request = osif_request_get(context); 154 if (!request) { 155 osif_err("Obsolete request"); 156 return; 157 } 158 159 priv = osif_request_priv(request); 160 qdf_mem_copy(priv, result, sizeof(*priv)); 161 osif_request_complete(request); 162 osif_request_put(request); 163 } 164 165 int wlan_cfg80211_crypto_add_key(struct wlan_objmgr_vdev *vdev, 166 enum wlan_crypto_key_type key_type, 167 uint8_t key_index, bool sync) 168 { 169 struct wlan_crypto_key *crypto_key; 170 QDF_STATUS status; 171 struct osif_request *request; 172 struct crypto_add_key_result *result; 173 struct wlan_crypto_comp_priv *priv; 174 int ret; 175 static const struct osif_request_params params = { 176 .priv_size = sizeof(*result), 177 .timeout_ms = WLAN_WAIT_TIME_ADD_KEY, 178 }; 179 180 crypto_key = wlan_crypto_get_key(vdev, key_index); 181 if (!crypto_key) { 182 osif_err("Crypto KEY is NULL"); 183 return -EINVAL; 184 } 185 186 if (sync) { 187 priv = wlan_get_vdev_crypto_obj(vdev); 188 if (!priv) { 189 osif_err("Invalid crypto_priv"); 190 return -EINVAL; 191 } 192 193 request = osif_request_alloc(¶ms); 194 if (!request) { 195 osif_err("Request allocation failure"); 196 return -ENOMEM; 197 } 198 199 priv->add_key_ctx = osif_request_cookie(request);; 200 priv->add_key_cb = wlan_cfg80211_crypto_add_key_cb; 201 202 status = ucfg_crypto_set_key_req(vdev, crypto_key, key_type); 203 if (QDF_IS_STATUS_SUCCESS(status)) { 204 ret = osif_request_wait_for_response(request); 205 if (ret) { 206 osif_err("Target response timed out"); 207 } else { 208 result = osif_request_priv(request); 209 osif_debug("complete, vdev_id %u, ix: %u, flags: %u, status: %u", 210 result->vdev_id, result->key_ix, 211 result->key_flags, result->status); 212 } 213 } 214 215 priv->add_key_ctx = NULL; 216 priv->add_key_cb = NULL; 217 osif_request_put(request); 218 } else { 219 status = ucfg_crypto_set_key_req(vdev, crypto_key, key_type); 220 } 221 222 return qdf_status_to_os_return(status); 223 } 224 225 int wlan_cfg80211_set_default_key(struct wlan_objmgr_vdev *vdev, 226 uint8_t key_index, struct qdf_mac_addr *bssid) 227 { 228 return wlan_crypto_default_key(vdev, (uint8_t *)bssid, 229 key_index, true); 230 } 231