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