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