1 /* 2 * Copyright (c) 2019 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: offload lmac interface APIs definitions for crypto 21 */ 22 23 #include <qdf_mem.h> 24 #include <qdf_status.h> 25 #include <target_if_crypto.h> 26 #include <wmi_unified_priv.h> 27 #include <wmi_unified_param.h> 28 #include <wlan_objmgr_psoc_obj.h> 29 #include <target_if.h> 30 #include <wlan_crypto_global_def.h> 31 #include <wlan_crypto_global_api.h> 32 #include <wlan_objmgr_vdev_obj.h> 33 #include <cdp_txrx_cmn_struct.h> 34 #include <cds_api.h> 35 #include <cdp_txrx_cmn.h> 36 #include <wmi_unified_api.h> 37 #include <wmi_unified_crypto_api.h> 38 #include <cdp_txrx_peer_ops.h> 39 40 #ifdef FEATURE_WLAN_WAPI 41 static void wlan_crypto_set_wapi_key(struct wlan_objmgr_vdev *vdev, 42 bool pairwise, 43 enum wlan_crypto_cipher_type cipher_type, 44 struct set_key_params *params) 45 { 46 static const unsigned char tx_iv[16] = {0x36, 0x5c, 0x36, 0x5c, 0x36, 47 0x5c, 0x36, 0x5c, 0x36, 0x5c, 48 0x36, 0x5c, 0x36, 0x5c, 0x36, 49 0x5c}; 50 51 static const unsigned char rx_iv[16] = {0x5c, 0x36, 0x5c, 0x36, 0x5c, 52 0x36, 0x5c, 0x36, 0x5c, 0x36, 53 0x5c, 0x36, 0x5c, 0x36, 0x5c, 54 0x37}; 55 56 if (cipher_type != WLAN_CRYPTO_CIPHER_WAPI_SMS4 || 57 cipher_type != WLAN_CRYPTO_CIPHER_WAPI_GCM4) 58 return; 59 60 qdf_mem_copy(¶ms->rx_iv, &rx_iv, 61 WLAN_CRYPTO_WAPI_IV_SIZE); 62 qdf_mem_copy(¶ms->tx_iv, &tx_iv, 63 WLAN_CRYPTO_WAPI_IV_SIZE); 64 65 if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE) { 66 if (pairwise) 67 params->tx_iv[0] = 0x37; 68 69 params->rx_iv[WLAN_CRYPTO_WAPI_IV_SIZE - 1] = 0x36; 70 } else { 71 if (!pairwise) 72 params->rx_iv[WLAN_CRYPTO_WAPI_IV_SIZE - 1] = 0x36; 73 } 74 75 params->key_txmic_len = WLAN_CRYPTO_MIC_LEN; 76 params->key_rxmic_len = WLAN_CRYPTO_MIC_LEN; 77 } 78 #else 79 static inline void wlan_crypto_set_wapi_key(struct wlan_objmgr_vdev *vdev, 80 bool pairwise, 81 enum wlan_crypto_cipher_type cipher, 82 struct set_key_params *params) 83 { 84 } 85 #endif /* FEATURE_WLAN_WAPI */ 86 87 #ifdef BIG_ENDIAN_HOST 88 static void wlan_crypto_endianness_conversion(uint8_t *dest, uint8_t *src, 89 uint32_t keylen) 90 { 91 int8_t i; 92 93 for (i = 0; i < roundup(keylen, sizeof(uint32_t)) / 4; i++) { 94 *dest = le32_to_cpu(*src); 95 dest++; 96 src++; 97 } 98 } 99 #else 100 static void wlan_crypto_endianness_conversion(uint8_t *dest, uint8_t *src, 101 uint32_t keylen) 102 { 103 qdf_mem_copy(dest, src, keylen); 104 } 105 #endif 106 107 QDF_STATUS target_if_crypto_set_key(struct wlan_objmgr_vdev *vdev, 108 struct wlan_crypto_key *req, 109 enum wlan_crypto_key_type key_type) 110 { 111 struct set_key_params params = {0}; 112 struct wlan_objmgr_psoc *psoc; 113 struct wlan_objmgr_pdev *pdev; 114 enum cdp_sec_type sec_type = cdp_sec_type_none; 115 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 116 struct cdp_pdev *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); 117 struct cdp_vdev *txrx_vdev; 118 uint32_t pn[4] = {0, 0, 0, 0}; 119 struct cdp_peer *peer = NULL; 120 uint8_t peer_id; 121 uint8_t def_tx_idx; 122 wmi_unified_t pdev_wmi_handle; 123 bool pairwise; 124 QDF_STATUS status; 125 126 pdev = wlan_vdev_get_pdev(vdev); 127 if (!pdev) { 128 target_if_err("Invalid PDEV"); 129 return QDF_STATUS_E_FAILURE; 130 } 131 psoc = wlan_vdev_get_psoc(vdev); 132 if (!psoc) { 133 target_if_err("Invalid PSOC"); 134 return QDF_STATUS_E_FAILURE; 135 } 136 soc = wlan_psoc_get_dp_handle(psoc); 137 if (!soc) { 138 target_if_err("Invalid DP Handle"); 139 return QDF_STATUS_E_FAILURE; 140 } 141 params.vdev_id = wlan_vdev_get_id(vdev); 142 params.key_idx = req->keyix; 143 qdf_mem_copy(params.peer_mac, req->macaddr, QDF_MAC_ADDR_SIZE); 144 pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 145 if (!pdev_wmi_handle) { 146 target_if_err("Invalid PDEV WMI handle"); 147 return QDF_STATUS_E_FAILURE; 148 } 149 150 params.key_flags = req->flags; 151 if (key_type != WLAN_CRYPTO_KEY_TYPE_UNICAST) { 152 pairwise = false; 153 params.key_flags |= GROUP_USAGE; 154 155 } else { 156 pairwise = true; 157 params.key_flags |= PAIRWISE_USAGE; 158 } 159 qdf_mem_copy(¶ms.key_rsc_ctr, 160 &req->keyrsc[0], sizeof(uint64_t)); 161 txrx_vdev = (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc, 162 (struct cdp_pdev *)txrx_pdev, params.vdev_id); 163 peer = cdp_peer_find_by_addr(soc, txrx_pdev, req->macaddr, &peer_id); 164 165 if (!txrx_vdev) { 166 target_if_err("Invalid txrx vdev"); 167 return QDF_STATUS_E_FAILURE; 168 } 169 170 target_if_debug("key_type %d, mac: %02x:%02x:%02x:%02x:%02x:%02x", 171 key_type, req->macaddr[0], req->macaddr[1], 172 req->macaddr[2], req->macaddr[3], req->macaddr[4], 173 req->macaddr[5]); 174 175 if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) && !peer) { 176 target_if_err("Invalid peer"); 177 return QDF_STATUS_E_FAILURE; 178 } 179 180 params.key_cipher = wlan_crypto_cipher_to_wmi_cipher(req->cipher_type); 181 sec_type = wlan_crypto_cipher_to_cdp_sec_type(req->cipher_type); 182 wlan_crypto_set_wapi_key(vdev, pairwise, req->cipher_type, ¶ms); 183 184 switch (req->cipher_type) { 185 case WLAN_CRYPTO_CIPHER_WEP: 186 case WLAN_CRYPTO_CIPHER_WEP_40: 187 case WLAN_CRYPTO_CIPHER_WEP_104: 188 def_tx_idx = wlan_crypto_get_default_key_idx(vdev, false); 189 if (pairwise && params.key_idx == def_tx_idx) 190 params.key_flags |= TX_USAGE; 191 else if ((vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE) && 192 (params.key_idx == def_tx_idx)) 193 params.key_flags |= TX_USAGE; 194 break; 195 case WLAN_CRYPTO_CIPHER_TKIP: 196 params.key_txmic_len = WLAN_CRYPTO_MIC_LEN; 197 params.key_rxmic_len = WLAN_CRYPTO_MIC_LEN; 198 break; 199 default: 200 break; 201 } 202 203 wlan_crypto_endianness_conversion(¶ms.key_data[0], 204 &req->keyval[0], 205 req->keylen); 206 params.key_len = req->keylen; 207 if (peer) { 208 /* Set PN check & security type in data path */ 209 qdf_mem_copy(&pn[0], ¶ms.key_rsc_ctr, sizeof(pn)); 210 cdp_set_pn_check(soc, txrx_vdev, peer, sec_type, pn); 211 cdp_set_key(soc, peer, pairwise, (uint32_t *)(req->keyval + 212 WLAN_CRYPTO_IV_SIZE + WLAN_CRYPTO_MIC_LEN)); 213 } else { 214 target_if_info("peer not found"); 215 } 216 217 target_if_debug("vdev_id:%d, key: idx:%d,len:%d", params.vdev_id, 218 params.key_idx, params.key_len); 219 target_if_debug("peer mac %pM", params.peer_mac); 220 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_CRYPTO, QDF_TRACE_LEVEL_DEBUG, 221 ¶ms.key_rsc_ctr, sizeof(uint64_t)); 222 status = wmi_unified_setup_install_key_cmd(pdev_wmi_handle, ¶ms); 223 224 return status; 225 } 226 227 QDF_STATUS target_if_crypto_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 228 { 229 struct wlan_lmac_if_crypto_tx_ops *crypto; 230 231 if (!tx_ops) { 232 target_if_err("txops NULL"); 233 return QDF_STATUS_E_FAILURE; 234 } 235 crypto = &tx_ops->crypto_tx_ops; 236 237 crypto->set_key = target_if_crypto_set_key; 238 239 return QDF_STATUS_SUCCESS; 240 } 241 242