From 89d288129ee5ad3d87e684e16efe6485f75befae Mon Sep 17 00:00:00 2001 From: Ashok Ponnaiah Date: Fri, 17 Feb 2017 22:10:20 +0530 Subject: [PATCH] qcacmn: Add crypto service files Add crypto service files Change-Id: I6efa8e633ca414a819c0ede05c44e89aebde8ad3 --- .../crypto/inc/wlan_crypto_global_api.h | 345 +++ .../crypto/inc/wlan_crypto_global_def.h | 296 +++ .../crypto/src/wlan_crypto_ccmp.c | 331 +++ .../crypto/src/wlan_crypto_def_i.h | 300 +++ .../crypto/src/wlan_crypto_global_api.c | 2055 +++++++++++++++++ .../crypto/src/wlan_crypto_main.c | 44 + .../crypto/src/wlan_crypto_main.h | 40 + .../crypto/src/wlan_crypto_main_i.h | 40 + .../crypto/src/wlan_crypto_none.c | 82 + .../crypto/src/wlan_crypto_obj_mgr.c | 307 +++ .../crypto/src/wlan_crypto_obj_mgr_i.h | 48 + .../crypto/src/wlan_crypto_param_handling.c | 310 +++ .../crypto/src/wlan_crypto_param_handling_i.h | 196 ++ .../crypto/src/wlan_crypto_tkip.c | 208 ++ .../crypto/src/wlan_crypto_wapi.c | 83 + .../cmn_services/crypto/src/wlan_crypto_wep.c | 162 ++ 16 files changed, 4847 insertions(+) create mode 100644 umac/cmn_services/crypto/inc/wlan_crypto_global_api.h create mode 100644 umac/cmn_services/crypto/inc/wlan_crypto_global_def.h create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_ccmp.c create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_def_i.h create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_global_api.c create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_main.c create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_main.h create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_main_i.h create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_none.c create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_obj_mgr_i.h create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_param_handling.c create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_param_handling_i.h create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_tkip.c create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_wapi.c create mode 100644 umac/cmn_services/crypto/src/wlan_crypto_wep.c diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h new file mode 100644 index 000000000000..67d35cd3ed94 --- /dev/null +++ b/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public APIs for crypto service + */ +#ifndef _WLAN_CRYPTO_GLOBAL_API_H_ +#define _WLAN_CRYPTO_GLOBAL_API_H_ + + +/** + * wlan_crypto_set_param - called by ucfg to set crypto param + * + * @vdev: vdev + * @param: param to be set. + * @value: value + * + * This function gets called from ucfg to set param + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_param(struct wlan_objmgr_vdev *vdev, + wlan_crypto_param_type param, + uint32_t value); + +/** + * wlan_crypto_get_param - called by ucfg to get crypto param + * + * @vdev: vdev + * @param: param to be get. + * + * This function gets called from ucfg to get param + * + * Return: value or -1 for failure + */ +int32_t wlan_crypto_get_param(struct wlan_objmgr_vdev *vdev, + wlan_crypto_param_type param); +/** + * wlan_crypto_setkey - called by ucfg to setkey + * + * @vdev: vdev + * @req_key: req_key with cipher type, key macaddress + * + * This function gets called from ucfg to sey key + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_req_key *req_key); + +/** + * wlan_crypto_getkey - called by ucfg to get key + * + * @vdev: vdev + * @req_key: key value will be copied in this req_key + * @mac_address: mac address of the peer for unicast key + * or broadcast address if group key is requested. + * This function gets called from ucfg to get key + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_getkey(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_req_key *req_key, + uint8_t *mac_addr); + +/** + * wlan_crypto_delkey - called by ucfg to delete key + * + * @vdev: vdev + * @mac_address: mac address of the peer for unicast key + * or broadcast address if group key is deleted. + * @key_idx: key index to be deleted + * This function gets called from ucfg to delete key + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_delkey(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr, + uint8_t key_idx); + +/** + * wlan_crypto_default_key - called by ucfg to set default tx key + * + * @vdev: vdev + * @mac_address: mac address of the peer for unicast key + * or broadcast address if group key need to made default. + * @key_idx: key index to be made as default key + * @unicast: is key was unicast or group key. + * This function gets called from ucfg to set default key + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_default_key(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr, + uint8_t key_idx, + bool unicast); + +/** + * wlan_crypto_encap - called by mgmt for encap the frame based on cipher + * + * @vdev: vdev + * @wbuf: wbuf + * @macaddr: macaddr + * @encapdone: is encapdone already or not. + * This function gets called from mgmt txrx to encap frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_encap(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, + uint8_t *macaddr, + uint8_t encapdone); + +/** + * wlan_crypto_decap - called by mgmt for decap the frame based on cipher + * + * @vdev: vdev + * @wbuf: wbuf + * @macaddr: macaddr + * @tid: tid of the packet. + * This function gets called from mgmt txrx to decap frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_decap(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, + uint8_t *macaddr, + uint8_t tid); + +/** + * wlan_crypto_enmic - called by mgmt for adding mic in frame based on cipher + * + * @vdev: vdev + * @wbuf: wbuf + * @macaddr: macaddr + * @encapdone: is encapdone already or not. + * This function gets called from mgmt txrx to adding mic to the frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_enmic(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, + uint8_t *macaddr, + uint8_t encapdone); + +/** + * wlan_crypto_demic - called by mgmt for remove and check mic for + * the frame based on cipher + * + * @vdev: vdev + * @wbuf: wbuf + * @macaddr: macaddr + * @tid: tid of the frame + * This function gets called from mgmt txrx to decap frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, + uint8_t *macaddr, + uint8_t tid); + +/** + * wlan_crypto_is_pmf_enabled - called by mgmt txrx to check is pmf enabled + * + * @vdev: vdev + * @peer: peer + * + * This function gets called by mgmt txrx to check is pmf enabled or not. + * + * Return: true or false + */ +bool wlan_crypto_is_pmf_enabled(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer); + +/** + * wlan_crypto_add_mmie - called by mgmt txrx to add mmie in frame + * + * @vdev: vdev + * @frm: frame starting pointer + * @len: length of the frame + * + * This function gets called by mgmt txrx to add mmie in frame + * + * Return: end of frame or NULL in case failure + */ +uint8_t *wlan_crypto_add_mmie(struct wlan_objmgr_vdev *vdev, + uint8_t *frm, + uint32_t len); + +/** + * wlan_crypto_is_mmie_valid - called by mgmt txrx to check mmie of the frame + * + * @vdev: vdev + * @frm: frame starting pointer + * @efrm: end of frame pointer + * + * This function gets called by mgmt txrx to check mmie of the frame + * + * Return: true or false + */ +bool wlan_crypto_is_mmie_valid(struct wlan_objmgr_vdev *vdev, + uint8_t *frm, + uint8_t *efrm); + +/** + * wlan_crypto_wpaie_check - called by mlme to check the wpaie + * + * + * @crypto params: crypto params + * @iebuf: ie buffer + * + * This function gets called by mlme to check the contents of wpa is + * matching with given crypto params + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_wpaie_check(struct wlan_crypto_params *, uint8_t *frm); + +/** + * wlan_crypto_rsnie_check - called by mlme to check the rsnie + * + * @crypto params: crypto params + * @iebuf: ie buffer + * + * This function gets called by mlme to check the contents of rsn is + * matching with given crypto params + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_rsnie_check(struct wlan_crypto_params *, uint8_t *frm); +/** + * wlan_crypto_build_wpaie - called by mlme to build wpaie + * + * @crypto params: crypto params + * @iebuf: ie buffer + * + * This function gets called by mlme to build wpaie from given crypto params + * + * Return: end of buffer + */ +uint8_t *wlan_crypto_build_wpaie(struct wlan_crypto_params *, + uint8_t *iebuf); +/** + * wlan_crypto_build_rsnie - called by mlme to build rsnie + * + * @crypto params: crypto params + * @iebuf: ie buffer + * + * This function gets called by mlme to build rsnie from given crypto params + * + * Return: end of buffer + */ +uint8_t *wlan_crypto_build_rsnie(struct wlan_crypto_params *, + uint8_t *iebuf); + +/** + * wlan_crypto_rsn_info - check is given params matching with vdev params. + * + * @vdev: vdev + * @crypto params: crypto params + * + * This function gets called by mlme to check is given params matching with + * vdev params. + * + * Return: true success or false for failure. + */ +bool wlan_crypto_rsn_info(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_params *crypto_params); +/** + * wlan_crypto_pn_check - called by data patch for PN check + * + * @vdev: vdev + * @wbuf: wbuf + * + * This function gets called by data patch for PN check + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_crypto_pn_check(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf); +/** + * wlan_crypto_vdev_get_crypto_params - called by mlme to get crypto params + * + * @vdev:vdev + * + * This function gets called by mlme to get crypto params + * + * Return: wlan_crypto_params or NULL in case of failure + */ +struct wlan_crypto_params *wlan_crypto_vdev_get_crypto_params( + struct wlan_objmgr_vdev *vdev); +/** + * wlan_crypto_peer_get_crypto_params - called by mlme to get crypto params + * + * @peer:peer + * + * This function gets called by mlme to get crypto params + * + * Return: wlan_crypto_params or NULL in case of failure + */ +struct wlan_crypto_params *wlan_crypto_peer_get_crypto_params( + struct wlan_objmgr_peer *peer); + +/** + * wlan_crypto_set_peer_wep_keys - set wep keys into peer entries + * + * @peer:peer + * + * This function gets called by mlme, when auth frame is received. + * this helps in setting wep keys into peer data structure. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_crypto_set_peer_wep_keys(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr); + +/** + * wlan_crypto_register_crypto_rx_ops - set crypto_rx_ops + * + * @crypto_rx_ops: crypto_rx_ops + * + * This function gets called by object manger to register crypto rx ops. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_crypto_register_crypto_rx_ops( + struct wlan_lmac_if_crypto_rx_ops *crypto_rx_ops); + +#endif /* end of _WLAN_CRYPTO_GLOBAL_API_H_ */ diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h new file mode 100644 index 000000000000..9704534c8635 --- /dev/null +++ b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public definations for crypto service + */ + +#ifndef _WLAN_CRYPTO_GLOBAL_DEF_H_ +#define _WLAN_CRYPTO_GLOBAL_DEF_H_ + +#define WLAN_CRYPTO_TID_SIZE (17) +#define WLAN_CRYPTO_KEYBUF_SIZE (32) +#define WLAN_CRYPTO_MICBUF_SIZE (16) +#define WLAN_CRYPTO_MIC_LEN (8) +#define WLAN_CRYPTO_MIC256_LEN (16) +#define WLAN_CRYPTO_TXMIC_OFFSET (0) +#define WLAN_CRYPTO_RXMIC_OFFSET (WLAN_CRYPTO_TXMIC_OFFSET + \ + WLAN_CRYPTO_MIC_LEN) +#define WLAN_CRYPTO_WAPI_IV_SIZE (16) +#define WLAN_CRYPTO_CRC_LEN (4) +#define WLAN_CRYPTO_IV_LEN (3) +#define WLAN_CRYPTO_KEYID_LEN (1) +#define WLAN_CRYPTO_EXT_IV_LEN (4) +#define WLAN_CRYPTO_EXT_IV_BIT (0x20) +#define WLAN_CRYPTO_KEYIX_NONE ((uint16_t)-1) +#define WLAN_CRYPTO_MAXKEYIDX (4) + +/* 40 bit wep key len */ +#define WLAN_CRYPTO_KEY_WEP40_LEN (5) +/* 104 bit wep key len */ +#define WLAN_CRYPTO_KEY_WEP104_LEN (13) +/* 128 bit wep key len */ +#define WLAN_CRYPTO_KEY_WEP128_LEN (16) + +#define WLAN_CRYPTO_WPI_SMS4_IVLEN (16) +#define WLAN_CRYPTO_WPI_SMS4_KIDLEN (1) +#define WLAN_CRYPTO_WPI_SMS4_PADLEN (1) +#define WLAN_CRYPTO_WPI_SMS4_MICLEN (16) + +/* key used for xmit */ +#define WLAN_CRYPTO_KEY_XMIT (0x01) +/* key used for recv */ +#define WLAN_CRYPTO_KEY_RECV (0x02) +/* key used for WPA group operation */ +#define WLAN_CRYPTO_KEY_GROUP (0x04) +/* key also used for management frames */ +#define WLAN_CRYPTO_KEY_MFP (0x08) +/* host-based encryption */ +#define WLAN_CRYPTO_KEY_SWENCRYPT (0x10) +/* host-based enmic */ +#define WLAN_CRYPTO_KEY_SWENMIC (0x20) +/* do not remove unless OS commands us to do so */ +#define WLAN_CRYPTO_KEY_PERSISTENT (0x40) +/* per STA default key */ +#define WLAN_CRYPTO_KEY_DEFAULT (0x80) +/* host-based decryption */ +#define WLAN_CRYPTO_KEY_SWDECRYPT (0x100) +/* host-based demic */ +#define WLAN_CRYPTO_KEY_SWDEMIC (0x200) + +#define WLAN_CRYPTO_KEY_SWCRYPT (WLAN_CRYPTO_KEY_SWENCRYPT \ + | WLAN_CRYPTO_KEY_SWDECRYPT) + +#define WLAN_CRYPTO_KEY_SWMIC (WLAN_CRYPTO_KEY_SWENMIC \ + | WLAN_CRYPTO_KEY_SWDEMIC) + +/* + * Cipher types +*/ +typedef enum wlan_crypto_cipher_type { + WLAN_CRYPTO_CIPHER_WEP = 0, + WLAN_CRYPTO_CIPHER_TKIP = 1, + WLAN_CRYPTO_CIPHER_AES_OCB = 2, + WLAN_CRYPTO_CIPHER_AES_CCM = 3, + WLAN_CRYPTO_CIPHER_WAPI_SMS4 = 4, + WLAN_CRYPTO_CIPHER_CKIP = 5, + WLAN_CRYPTO_CIPHER_AES_CMAC = 6, + WLAN_CRYPTO_CIPHER_AES_CCM_256 = 7, + WLAN_CRYPTO_CIPHER_AES_CMAC_256 = 8, + WLAN_CRYPTO_CIPHER_AES_GCM = 9, + WLAN_CRYPTO_CIPHER_AES_GCM_256 = 10, + WLAN_CRYPTO_CIPHER_AES_GMAC = 11, + WLAN_CRYPTO_CIPHER_AES_GMAC_256 = 12, + WLAN_CRYPTO_CIPHER_WAPI_GCM4 = 13, + WLAN_CRYPTO_CIPHER_NONE = 14, + WLAN_CRYPTO_CIPHER_MAX = WLAN_CRYPTO_CIPHER_NONE, +} wlan_crypto_cipher_type; + +/* Auth types */ +typedef enum wlan_crypto_auth_mode { + WLAN_CRYPTO_AUTH_NONE = 0, + WLAN_CRYPTO_AUTH_OPEN = 1, + WLAN_CRYPTO_AUTH_SHARED = 2, + WLAN_CRYPTO_AUTH_8021X = 3, + WLAN_CRYPTO_AUTH_AUTO = 4, + WLAN_CRYPTO_AUTH_WPA = 5, + WLAN_CRYPTO_AUTH_RSNA = 6, + WLAN_CRYPTO_AUTH_CCKM = 7, + WLAN_CRYPTO_AUTH_WAPI = 8, +} wlan_crypto_auth_mode; + +/* crypto capabilities */ +typedef enum wlan_crypto_cap { + WLAN_CRYPTO_CAP_PRIVACY = 0, + WLAN_CRYPTO_CAP_WPA1 = 1, + WLAN_CRYPTO_CAP_WPA2 = 2, + WLAN_CRYPTO_CAP_WPA = 3, + WLAN_CRYPTO_CAP_AES = 4, + WLAN_CRYPTO_CAP_WEP = 5, + WLAN_CRYPTO_CAP_CKIP = 6, + WLAN_CRYPTO_CAP_TKIP_MIC = 7, + WLAN_CRYPTO_CAP_CCM256 = 8, + WLAN_CRYPTO_CAP_GCM = 9, + WLAN_CRYPTO_CAP_GCM_256 = 10, + WLAN_CRYPTO_CAP_WAPI_SMS4 = 11, + WLAN_CRYPTO_CAP_WAPI_GCM4 = 12, + WLAN_CRYPTO_CAP_KEY_MGMT_OFFLOAD = 13, + WLAN_CRYPTO_CAP_PMF = 14, + WLAN_CRYPTO_CAP_PMF_OFFLOAD = 15, + WLAN_CRYPTO_CAP_PN_TID_BASED = 16, +} wlan_crypto_cap; + +typedef enum wlan_crypto_rsn_cap { + WLAN_CRYPTO_RSN_CAP_PREAUTH = 0x01, + WLAN_CRYPTO_RSN_CAP_MFP_ENABLED = 0x80, + WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED = 0x40, +} wlan_crypto_rsn_cap; + +typedef enum wlan_crypto_key_mgmt { + WLAN_CRYPTO_KEY_MGMT_IEEE8021X = 0, + WLAN_CRYPTO_KEY_MGMT_PSK = 1, + WLAN_CRYPTO_KEY_MGMT_NONE = 2, + WLAN_CRYPTO_KEY_MGMT_IEEE8021X_NO_WPA = 3, + WLAN_CRYPTO_KEY_MGMT_WPA_NONE = 4, + WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X = 5, + WLAN_CRYPTO_KEY_MGMT_FT_PSK = 6, + WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256 = 7, + WLAN_CRYPTO_KEY_MGMT_PSK_SHA256 = 8, + WLAN_CRYPTO_KEY_MGMT_WPS = 9, + WLAN_CRYPTO_KEY_MGMT_SAE = 10, + WLAN_CRYPTO_KEY_MGMT_FT_SAE = 11, + WLAN_CRYPTO_KEY_MGMT_WAPI_PSK = 12, + WLAN_CRYPTO_KEY_MGMT_WAPI_CERT = 13, + WLAN_CRYPTO_KEY_MGMT_CCKM = 14, + WLAN_CRYPTO_KEY_MGMT_OSEN = 15, + WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B = 16, + WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192 = 17, +} wlan_crypto_key_mgmt; + +/* crypto parames for vdev and peers */ +struct wlan_crypto_params { + /* authentication mode set*/ + uint32_t authmodeset; + /* unicast cipher set*/ + uint32_t ucastcipherset; + /* mcast/group cipher set*/ + uint32_t mcastcipherset; + /* management frames cipher set */ + uint32_t mgmtcipherset; + /* cipher capabilities */ + uint32_t cipher_caps; + /* rsn caps*/ + uint16_t rsn_caps; + /* key mgmt used*/ + uint16_t key_mgmt; +}; + +typedef enum wlan_crypto_param_type { + WLAN_CRYPTO_PARAM_AUTH_MODE, + WLAN_CRYPTO_PARAM_UCAST_CIPHER, + WLAN_CRYPTO_PARAM_MCAST_CIPHER, + WLAN_CRYPTO_PARAM_MGMT_CIPHER, + WLAN_CRYPTO_PARAM_CIPHER_CAP, + WLAN_CRYPTO_PARAM_RSN_CAP, + WLAN_CRYPTO_PARAM_KEY_MGMT, +} wlan_crypto_param_type; + +/* key structure */ +struct wlan_crypto_key { + uint8_t keylen; + /* key valid to indicate key is valid or not */; + bool valid; + /* key flags */; + uint16_t flags; + uint16_t keyix; + /* cipher ops table*/ + void *cipher_table; + /* cipher context*/ + void *private; + qdf_spinlock_t keylock; + /* WAPI key receive sequence counter */ + uint8_t recviv[WLAN_CRYPTO_WAPI_IV_SIZE]; + /* WAPI key transmit sequence counter */ + uint8_t txiv[WLAN_CRYPTO_WAPI_IV_SIZE]; + /* key transmit sequence counter */ + uint64_t keytsc; + /* key receive sequence counter */ + uint64_t keyrsc[WLAN_CRYPTO_TID_SIZE]; + /* key receive sequence counter under suspect when pN jump is detected*/ + uint64_t keyrsc_suspect[WLAN_CRYPTO_TID_SIZE]; + /* key receive sequence counter */ + uint64_t keyglobal; + /* key value */ + uint8_t keyval[WLAN_CRYPTO_KEYBUF_SIZE + + WLAN_CRYPTO_MICBUF_SIZE]; +#define txmic (keyval + WLAN_CRYPTO_KEYBUF_SIZE \ + + WLAN_CRYPTO_TXMIC_OFFSET) +#define rxmic (keyval + WLAN_CRYPTO_KEYBUF_SIZE \ + + WLAN_CRYPTO_RXMIC_OFFSET) +}; + +struct wlan_crypto_req_key { + /* key/cipher type */ + uint8_t type; + uint8_t pad; + /* key index */ + uint16_t keyix + /* key length in bytes */; + uint8_t keylen; + /* key flags */; + uint8_t flags; + uint8_t macaddr[WLAN_MACADDR_LEN]; + /* key receive sequence counter */ + uint64_t keyrsc; + /* key transmit sequence counter */ + uint64_t keytsc; + /* key value */ + uint8_t keydata[WLAN_CRYPTO_KEYBUF_SIZE + WLAN_CRYPTO_MICBUF_SIZE]; +}; + +/** + * struct wlan_lmac_if_crypto_tx_ops - structure of crypto function + * pointers + * @allockey: function pointer to alloc key in hw + * @setkey: function pointer to setkey in hw + * @delkey: function pointer to delkey in hw + * @defaultkey: function pointer to set default key + */ + +struct wlan_lmac_if_crypto_tx_ops { + QDF_STATUS(*allockey)(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_key *key, + uint8_t *macaddr, uint32_t key_type); + QDF_STATUS(*setkey)(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_key *key, + uint8_t *macaddr, uint32_t key_type); + QDF_STATUS(*delkey)(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_key *key, + uint8_t *macaddr, uint32_t key_type); + QDF_STATUS(*defaultkey)(struct wlan_objmgr_vdev *vdev, + uint8_t keyix, uint8_t *macaddr); +}; + + +/** + * struct wlan_lmac_if_crypto_rx_ops - structure of crypto rx function + * pointers + * @encap: function pointer to encap tx frame + * @decap: function pointer to decap rx frame in hw + * @enmic: function pointer to enmic tx frame + * @demic: function pointer to demic rx frame + */ + +struct wlan_lmac_if_crypto_rx_ops { + QDF_STATUS(*crypto_encap)(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, uint8_t *macaddr, + uint8_t encapdone); + QDF_STATUS(*crypto_decap)(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, uint8_t *macaddr, + uint8_t tid); + QDF_STATUS(*crypto_enmic)(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, uint8_t *macaddr, + uint8_t encapdone); + QDF_STATUS(*crypto_demic)(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, uint8_t *macaddr, + uint8_t tid); + QDF_STATUS(*set_peer_wep_keys)(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr); +}; + +#endif /* end of _WLAN_CRYPTO_GLOBAL_DEF_H_ */ diff --git a/umac/cmn_services/crypto/src/wlan_crypto_ccmp.c b/umac/cmn_services/crypto/src/wlan_crypto_ccmp.c new file mode 100644 index 000000000000..7bf073d0236c --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_ccmp.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Private API for handling CCMP related operations + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wlan_crypto_global_def.h" +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_main_i.h" +#include "wlan_crypto_obj_mgr_i.h" +#include "wlan_crypto_ccmp_i.h" + +#define MAX_CCMP_PN_GAP_ERR_CHECK 0 + +static QDF_STATUS ccmp_setkey(struct wlan_crypto_key *key) +{ + + struct wlan_crypto_ccmp_ctx *ctx; + + if (key->private == NULL) { + key->private = qdf_mem_malloc( + sizeof(struct wlan_crypto_ccmp_ctx)); + if (key->private == NULL) + return QDF_STATUS_E_NOMEM; + } + + ctx = key->private; + wlan_crypto_rijndael_set_key(&ctx->cc_aes, key->keyval, + (key->keylen*NBBY)); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS ccmp_encap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t encapdone, + uint8_t hdrlen){ + uint8_t *ivp; + struct ieee80211_frame *wh; + struct wlan_crypto_cipher *cipher_table; + + cipher_table = (struct wlan_crypto_cipher *)key->cipher_table; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(wbuf); + + /* + * Copy down 802.11 header and add the IV, KeyID, and ExtIV. + */ + + if (encapdone) { + ivp = (uint8_t *)qdf_nbuf_data(wbuf); + } else { + ivp = (uint8_t *)qdf_nbuf_push_head(wbuf, + cipher_table->header); + qdf_mem_move(ivp, ivp + cipher_table->header, hdrlen); + /* recompute wh */ + wh = (struct ieee80211_frame *) qdf_nbuf_data(wbuf); + } + + ivp += hdrlen; + /* XXX wrap at 48 bits */ + key->keytsc++; + + + ivp[0] = key->keytsc >> 0; /* PN0 */ + ivp[1] = key->keytsc >> 8; /* PN1 */ + ivp[2] = 0; /* Reserved */ + ivp[3] = key->keyix | WLAN_CRYPTO_EXT_IV_BIT; /* KeyID | ExtID */ + ivp[4] = key->keytsc >> 16; /* PN2 */ + ivp[5] = key->keytsc >> 24; /* PN3 */ + ivp[6] = key->keytsc >> 32; /* PN4 */ + ivp[7] = key->keytsc >> 40; /* PN5 */ + + /* + * Finally, do software encrypt if neeed. + */ + if (key->flags & WLAN_CRYPTO_KEY_SWENCRYPT) { + if (!wlan_crypto_ccmp_encrypt(key, wbuf, hdrlen, + IEEE80211_IS_MFP_FRAME(wh))) { + return 0; + } + } + + return QDF_STATUS_SUCCESS; +} + +#define WLAN_CRYPTO_CCMP_PN_MAX(pn) (pn + MAX_CCMP_PN_GAP_ERR_CHECK) + +static QDF_STATUS ccmp_decap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + struct ieee80211_frame *wh; + uint8_t *ivp, *origHdr; + uint64_t pn; + uint8_t update_keyrsc = 1; + struct wlan_crypto_cipher *cipher_table; + + cipher_table = (struct wlan_crypto_cipher *)key->cipher_table; + + /* + * Header should have extended IV and sequence number; + * verify the former and validate the latter. + */ + origHdr = (uint8_t *)qdf_nbuf_data(wbuf); + wh = (struct ieee80211_frame *)origHdr; + + ivp = origHdr + hdrlen; + + if ((ivp[WLAN_CRYPTO_IV_LEN] & WLAN_CRYPTO_EXT_IV_BIT) == 0) { + /*invalid CCMP iv*/ + return QDF_STATUS_E_INVAL; + } + + tid = IEEE80211_NON_QOS_SEQ; + + if (IEEE80211_QOS_HAS_SEQ(wh)) { + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) + == IEEE80211_FC1_DIR_DSTODS) { + tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] + & IEEE80211_QOS_TID; + } else { + tid = ((struct ieee80211_qosframe *)wh)->i_qos[0] + & IEEE80211_QOS_TID; + } + } + + /* NB: assume IEEEE80211_WEP_MINLEN covers the extended IV */ + pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); + + if (pn <= key->keyrsc[tid]) { + /* + * Replay violation. + */ + return QDF_STATUS_CRYPTO_PN_ERROR; + } + + if ((key->flags & WLAN_CRYPTO_KEY_SWDECRYPT)) { + if (!wlan_crypto_ccmp_decrypt(key, + pn, wbuf, hdrlen, IEEE80211_IS_MFP_FRAME(wh))) { + return QDF_STATUS_CRYPTO_DECRYPT_FAILED; + } + } + + /* we can get corrupted frame that has a bad PN. + * The PN upper bits tend to get corrupted. + * The PN should be a monotically increasing counter. + * if we detected a big jump, then we will throw away this frame. + */ + if ((key->keyrsc[tid] > 1) && + (pn > (WLAN_CRYPTO_CCMP_PN_MAX(key->keyrsc[tid])))) { + /* PN jump wrt keyrsc is > MAX_CCMP_PN_GAP_ERR_CHECK - + * PN of current frame is suspected + */ + if (key->keyrsc_suspect[tid]) { + /* Check whether PN of the current frame + * is following prev PN seq or not + */ + if (pn < key->keyrsc_suspect[tid]) { + /* PN number of the curr frame < PN no of prev + * rxed frame. As we are not sure about prev + * suspect PN, to detect replay, check the + * current PN with global PN + */ + if (pn < key->keyglobal) + /* Replay violation */ + return QDF_STATUS_CRYPTO_PN_ERROR; + else { + /* Current PN is following global PN, + * so mark this as suspected PN + * Don't update keyrsc & keyglobal + */ + key->keyrsc_suspect[tid] = pn; + update_keyrsc = 0; + } + } else if (pn < + (WLAN_CRYPTO_CCMP_PN_MAX(key->keyrsc_suspect[tid]))) { + /* Current PN is following prev suspected + * PN seq Update keyrsc & keyglobal + * (update_keyrsc = 1;) + */ + } else { + /* Current PN is neither following prev + * suspected PN nor prev Keyrsc. + * Mark this as new suspect and + * don't update keyrsc & keyglobal + */ + key->keyrsc_suspect[tid] = pn; + update_keyrsc = 0; + } + } else { + /* New Jump in PN observed + * So mark this PN as suspected and + * don't update keyrsc/keyglobal */ + key->keyrsc_suspect[tid] = pn; + update_keyrsc = 0; + } + } else { + /* Valid PN, update keyrsc & keyglobal (update_keyrsc = 1;) */ + } + + /* + * Copy up 802.11 header and strip crypto bits. + */ + qdf_mem_move(origHdr + cipher_table->header, origHdr, hdrlen); + qdf_nbuf_pull_head(wbuf, cipher_table->header); + qdf_nbuf_trim_tail(wbuf, cipher_table->trailer); + + if (update_keyrsc) { + /* + * Ok to update rsc now. + */ + key->keyrsc[tid] = pn; + key->keyglobal = pn; + key->keyrsc_suspect[tid] = 0; + } + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS ccmp_enmic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t keyid, + uint8_t hdrlen){ + + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS ccmp_demic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t keyid, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} + + +const struct wlan_crypto_cipher ccmp_cipher_table = { + "AES-CCM", + WLAN_CRYPTO_CIPHER_AES_CCM, + WLAN_CRYPTO_IV_LEN + WLAN_CRYPTO_KEYID_LEN + WLAN_CRYPTO_EXT_IV_LEN, + WLAN_CRYPTO_MIC_LEN, + 0, + 128, + ccmp_setkey, + ccmp_encap, + ccmp_decap, + ccmp_enmic, + ccmp_demic, +}; + + +const struct wlan_crypto_cipher ccmp256_cipher_table = { + "AES-CCM256", + WLAN_CRYPTO_CIPHER_AES_CCM_256, + WLAN_CRYPTO_IV_LEN + WLAN_CRYPTO_KEYID_LEN + WLAN_CRYPTO_EXT_IV_LEN, + WLAN_CRYPTO_MIC256_LEN, + 0, + 256, + ccmp_setkey, + ccmp_encap, + ccmp_decap, + ccmp_enmic, + ccmp_demic, +}; + + +const struct wlan_crypto_cipher gcmp_cipher_table = { + "AES-GCM", + WLAN_CRYPTO_CIPHER_AES_GCM, + WLAN_CRYPTO_IV_LEN + WLAN_CRYPTO_KEYID_LEN + WLAN_CRYPTO_EXT_IV_LEN, + WLAN_CRYPTO_MIC_LEN, + 0, + 128, + ccmp_setkey, + ccmp_encap, + ccmp_decap, + ccmp_enmic, + ccmp_demic, +}; + + +const struct wlan_crypto_cipher gcmp256_cipher_table = { + "AES-GCM256", + WLAN_CRYPTO_CIPHER_AES_GCM_256, + WLAN_CRYPTO_IV_LEN + WLAN_CRYPTO_KEYID_LEN + WLAN_CRYPTO_EXT_IV_LEN, + WLAN_CRYPTO_MIC256_LEN, + 0, + 256, + ccmp_setkey, + ccmp_encap, + ccmp_decap, + ccmp_enmic, + ccmp_demic, +}; + +const struct wlan_crypto_cipher *ccmp_register(void){ + return &ccmp_cipher_table; +} + +const struct wlan_crypto_cipher *ccmp256_register(void){ + return &ccmp256_cipher_table; +} + +const struct wlan_crypto_cipher *gcmp_register(void){ + return &gcmp_cipher_table; +} + +const struct wlan_crypto_cipher *gcmp256_register(void){ + return &gcmp256_cipher_table; +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_def_i.h b/umac/cmn_services/crypto/src/wlan_crypto_def_i.h new file mode 100644 index 000000000000..132befc698e8 --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_def_i.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Private definations for handling crypto params + */ +#ifndef _WLAN_CRYPTO_DEF_I_H_ +#define _WLAN_CRYPTO_DEF_I_H_ + +#define WLAN_CRYPTO_TX_OPS_ALLOCKEY(psoc) \ + (psoc->soc_cb.tx_ops.crypto_tx_ops.allockey) +#define WLAN_CRYPTO_TX_OPS_SETKEY(psoc) \ + (psoc->soc_cb.tx_ops.crypto_tx_ops.setkey) +#define WLAN_CRYPTO_TX_OPS_DELKEY(psoc) \ + (psoc->soc_cb.tx_ops.crypto_tx_ops.delkey) +#define WLAN_CRYPTO_TX_OPS_DEFAULTKEY(psoc) \ + (psoc->soc_cb.tx_ops.crypto_tx_ops.defaultkey) + +/* unalligned little endian access */ +#ifndef LE_READ_2 +#define LE_READ_2(p) \ + ((uint16_t) \ + ((((const uint8_t *)(p))[0]) | \ + (((const uint8_t *)(p))[1] << 8))) +#endif + +#ifndef LE_READ_4 +#define LE_READ_4(p) \ + ((uint32_t) \ + ((((const uint8_t *)(p))[0]) | \ + (((const uint8_t *)(p))[1] << 8) | \ + (((const uint8_t *)(p))[2] << 16) | \ + (((const uint8_t *)(p))[3] << 24))) +#endif + +#ifndef BE_READ_4 +#define BE_READ_4(p) \ + ((uint32_t) \ + ((((const uint8_t *)(p))[0] << 24) | \ + (((const uint8_t *)(p))[1] << 16) | \ + (((const uint8_t *)(p))[2] << 8) | \ + (((const uint8_t *)(p))[3]))) +#endif + +#ifndef READ_6 +#define READ_6(b0, b1, b2, b3, b4, b5) ({ \ + uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);\ + uint16_t iv16 = (b4 << 0) | (b5 << 8);\ + (((uint64_t)iv16) << 32) | iv32;\ +}) +#endif + +#define OUI_SIZE (4) +#define WLAN_CRYPTO_ADDSHORT(frm, v) \ + do {frm[0] = (v) & 0xff; frm[1] = (v) >> 8; frm += 2; } while (0) + +#define WLAN_CRYPTO_ADDSELECTOR(frm, sel) \ + do {qdf_mem_copy(frm, (uint8_t *)sel, OUI_SIZE); \ + frm += OUI_SIZE; } while (0) + +#define WLAN_CRYPTO_SELECTOR(a, b, c, d) \ + ((((uint32_t) (a)) << 24) | \ + (((uint32_t) (b)) << 16) | \ + (((uint32_t) (c)) << 8) | \ + (uint32_t) (d)) + +#define WPA_TYPE_OUI WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 1) + +#define WPA_AUTH_KEY_MGMT_NONE \ + WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 0) +#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X \ + WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 1) +#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X \ + WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 2) +#define WPA_AUTH_KEY_MGMT_CCKM \ + WLAN_CRYPTO_SELECTOR(0x00, 0x40, 0x96, 0) + +#define WPA_CIPHER_SUITE_NONE WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 0) +#define WPA_CIPHER_SUITE_WEP40 WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 1) +#define WPA_CIPHER_SUITE_WEP104 WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 5) +#define WPA_CIPHER_SUITE_TKIP WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 2) +#define WPA_CIPHER_SUITE_CCMP WLAN_CRYPTO_SELECTOR(0x00, 0x50, 0xf2, 4) + +#define RSN_AUTH_KEY_MGMT_NONE WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 0) +#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 1) +#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 2) +#define RSN_AUTH_KEY_MGMT_FT_802_1X \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 3) +#define RSN_AUTH_KEY_MGMT_FT_PSK \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 4) +#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 5) +#define RSN_AUTH_KEY_MGMT_PSK_SHA256 \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 6) +#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 7) +#define RSN_AUTH_KEY_MGMT_SAE WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 8) +#define RSN_AUTH_KEY_MGMT_FT_SAE WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 9) +#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 11) +#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 12) +#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 13) +#define RSN_AUTH_KEY_MGMT_CCKM WLAN_CRYPTO_SELECTOR(0x00, 0x40, 0x96, 0x00) +#define RSN_AUTH_KEY_MGMT_OSEN WLAN_CRYPTO_SELECTOR(0x50, 0x6f, 0x9a, 0x01) + +#define RSN_CIPHER_SUITE_NONE WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 0) +#define RSN_CIPHER_SUITE_WEP40 WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 1) +#define RSN_CIPHER_SUITE_TKIP WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 2) +#define RSN_CIPHER_SUITE_WEP104 WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 5) +#define RSN_CIPHER_SUITE_CCMP WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 4) +#define RSN_CIPHER_SUITE_AES_CMAC WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 6) +#define RSN_CIPHER_SUITE_GCMP WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 8) +#define RSN_CIPHER_SUITE_GCMP_256 WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 9) +#define RSN_CIPHER_SUITE_CCMP_256 WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 10) +#define RSN_CIPHER_SUITE_BIP_GMAC_128 \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 11) +#define RSN_CIPHER_SUITE_BIP_GMAC_256 \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 12) +#define RSN_CIPHER_SUITE_BIP_CMAC_256 \ + WLAN_CRYPTO_SELECTOR(0x00, 0x0f, 0xac, 13) + +#define RESET_PARAM(__param) ((__param) = 0) +#define SET_PARAM(__param, __val) ((__param) |= (1<<(__val))) +#define HAS_PARAM(__param, __val) ((__param) & (1<<(__val))) +#define CLEAR_PARAM(__param, __val) ((__param) &= ((~1) << (__val))) + + +#define RESET_AUTHMODE(_param) ((_param)->authmodeset = 0) +#define SET_AUTHMODE(_param, _mode) ((_param)->authmodeset |= (1<<(_mode))) +#define HAS_AUTHMODE(_param, _mode) ((_param)->authmodeset & (1<<(_mode))) + +#define AUTH_IS_OPEN(_param) HAS_AUTHMODE((_param), WLAN_CRYPTO_AUTH_OPEN) +#define AUTH_IS_SHARED_KEY(_param) \ + HAS_AUTHMODE((_param), WLAN_CRYPTO_AUTH_SHARED) +#define AUTH_IS_8021X(_param) HAS_AUTHMODE((_param), WLAN_CRYPTO_AUTH_8021X) +#define AUTH_IS_WPA(_param) HAS_AUTHMODE((_param), WLAN_CRYPTO_AUTH_WPA) +#define AUTH_IS_RSNA(_param) HAS_AUTHMODE((_param), WLAN_CRYPTO_AUTH_RSNA) +#define AUTH_IS_CCKM(_param) HAS_AUTHMODE((_param), WLAN_CRYPTO_AUTH_CCKM) +#define AUTH_IS_WAI(_param) HAS_AUTHMODE((_param), WLAN_CRYPTO_AUTH_WAPI) +#define AUTH_IS_WPA2(_param) AUTH_IS_RSNA(_param) + +#define AUTH_MATCH(_param1, _param2) \ + (((_param1)->authmodeset & (_param2)->authmodeset) != 0) + + +#define RESET_UCAST_CIPHERS(_param) ((_param)->ucastcipherset = 0) +#define SET_UCAST_CIPHER(_param, _c) ((_param)->ucastcipherset |= (1<<(_c))) +#define HAS_UCAST_CIPHER(_param, _c) ((_param)->ucastcipherset & (1<<(_c))) + +#define UCIPHER_IS_CLEAR(_param) \ + HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_NONE) +#define UCIPHER_IS_WEP(_param) \ + HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_WEP) +#define UCIPHER_IS_TKIP(_param) \ + HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_TKIP) +#define UCIPHER_IS_CCMP128(_param) \ + HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_CCM) +#define UCIPHER_IS_CCMP256(_param) \ + HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_CCM_256) +#define UCIPHER_IS_GCMP128(_param) \ + HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_GCM) +#define UCIPHER_IS_GCMP256(_param) \ + HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_GCM_256) +#define UCIPHER_IS_SMS4(_param) \ + HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_WAPI) + +#define RESET_MCAST_CIPHERS(_param) ((_param)->mcastcipherset = 0) +#define SET_MCAST_CIPHER(_param, _c) ((_param)->mcastcipherset |= (1<<(_c))) +#define HAS_MCAST_CIPHER(_param, _c) ((_param)->mcastcipherset & (1<<(_c))) +#define HAS_ANY_MCAST_CIPHER(_param) ((_param)->mcastcipherset) +#define CLEAR_MCAST_CIPHER(_param, _c) \ + ((_param)->mcastcipherset &= (~(1)<<(_c))) + +#define MCIPHER_IS_CLEAR(_param) \ + HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_NONE) +#define MCIPHER_IS_WEP(_param) \ + HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_WEP) +#define MCIPHER_IS_TKIP(_param) \ + HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_TKIP) +#define MCIPHER_IS_CCMP128(_param) \ + HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_CCM) +#define MCIPHER_IS_CCMP256(_param) \ + HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_CCM_256) +#define MCIPHER_IS_GCMP128(_param) \ + HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_GCM) +#define MCIPHER_IS_GCMP256(_param) \ + HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_GCM_256) +#define MCIPHER_IS_SMS4(_param) \ + HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_WAPI) + +#define RESET_MGMT_CIPHERS(_param) ((_param)->mgmtcipherset = 0) +#define SET_MGMT_CIPHER(_param, _c) ((_param)->mgmtcipherset |= (1<<(_c))) +#define HAS_MGMT_CIPHER(_param, _c) ((_param)->mgmtcipherset & (1<<(_c))) +#define IS_MGMT_CIPHER(_c) ((_c == WLAN_CRYPTO_CIPHER_AES_CMAC) || \ + (_c == WLAN_CRYPTO_CIPHER_AES_CMAC_256) || \ + (_c == WLAN_CRYPTO_CIPHER_AES_GMAC) || \ + (_c == WLAN_CRYPTO_CIPHER_AES_GMAC_256)) + +#define MGMT_CIPHER_IS_CMAC(_param) \ + HAS_MGMT_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_CMAC) +#define MGMT_CIPHER_IS_CMAC256(_param) \ + HAS_MGMT_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_CMAC_256) +#define MGMT_CIPHER_IS_GMAC(_param) \ + HAS_MGMT_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_GMAC) +#define MGMT_CIPHER_IS_GMAC256(_param) \ + HAS_MGMT_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_GMAC_256) + +#define RESET_KEY_MGMT(_param) ((_param)->key_mgmt = 0) +#define SET_KEY_MGMT(_param, _c) ((_param)->key_mgmt |= (1<<(_c))) +#define HAS_KEY_MGMT(_param, _c) ((_param)->key_mgmt & (1<<(_c))) + +#define UCAST_CIPHER_MATCH(_param1, _param2) \ + (((_param1)->ucastcipherset & (_param2)->ucastcipherset) != 0) + +#define MCAST_CIPHER_MATCH(_param1, _param2) \ + (((_param1)->mcastcipherset & (_param2)->mcastcipherset) != 0) + +#define MGMT_CIPHER_MATCH(_param1, _param2) \ + (((_param1)->mgmtcipherset & (_param2)->mgmtcipherset) != 0) + +#define KEY_MGMTSET_MATCH(_param1, _param2) \ + (((_param1)->key_mgmt & (_param2)->key_mgmt) != 0 || \ + (!(_param1)->key_mgmt && !(_param2)->key_mgmt)) + +#define RESET_CIPHER_CAP(_param) ((_param)->cipher_caps = 0) +#define SET_CIPHER_CAP(_param, _c) ((_param)->cipher_caps |= (1<<(_c))) +#define HAS_CIPHER_CAP(_param, _c) ((_param)->cipher_caps & (1<<(_c))) +#define HAS_ANY_CIPHER_CAP(_param) ((_param)->cipher_caps) + +struct wlan_crypto_comp_priv { + struct wlan_crypto_params crypto_params; + struct wlan_crypto_key *key[4]; + struct wlan_crypto_key *igtk_key; + uint8_t def_tx_keyid; +}; + + +struct wlan_crypto_cipher { + /* printable name */ + const char *cipher_name; + /* WLAN_CRYPTO_CIPHER_* */ + wlan_crypto_cipher_type cipher; + /* size of privacy header (bytes) */ + const uint8_t header; + /* size of privacy trailer (bytes) */ + const uint8_t trailer; + /* size of mic trailer (bytes) */ + const uint8_t miclen; + /* max key length */ + const uint32_t keylen; + QDF_STATUS(*setkey)(struct wlan_crypto_key *); + QDF_STATUS(*encap)(struct wlan_crypto_key *, + qdf_nbuf_t, uint8_t, uint8_t); + QDF_STATUS(*decap)(struct wlan_crypto_key *, + qdf_nbuf_t, uint8_t, uint8_t); + QDF_STATUS(*enmic)(struct wlan_crypto_key *, + qdf_nbuf_t, uint8_t, uint8_t); + QDF_STATUS(*demic)(struct wlan_crypto_key *, + qdf_nbuf_t, uint8_t, uint8_t); +}; + +/* +* Return the size of the 802.11 header for a management or data frame. +*/ +static inline int ieee80211_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + int16_t size = sizeof(struct ieee80211_frame); + + if ((wh->i_fc[1] & 0x03) == 0x03) + size += 6; + + if ((((wh)->i_fc[0] & (0x0c | 0x80)) == (0x00 | 0x80))) { + size += sizeof(uint16_t); + /* Qos frame with Order bit set indicates an HTC frame */ + if (wh->i_fc[1] & 0x80) + size += (sizeof(uint8_t)*4); + } + return size; +} +#endif /* end of _WLAN_CRYPTO_DEF_I_H_ */ diff --git a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c new file mode 100644 index 000000000000..acb9f28f7dff --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c @@ -0,0 +1,2055 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public APIs for crypto service + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wlan_crypto_global_def.h" +#include "wlan_crypto_global_api.h" +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_param_handling_i.h" +#include "wlan_crypto_obj_mgr_i.h" +#include "wlan_crypto_pmf_i.h" + + +const struct wlan_crypto_cipher *wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_MAX]; + + +/** + * wlan_crypto_vdev_get_crypto_params - called by mlme to get crypto params + * + * @vdev:vdev + * + * This function gets called by mlme to get crypto params + * + * Return: wlan_crypto_params or NULL in case of failure + */ +static struct wlan_crypto_params *wlan_crypto_vdev_get_comp_params( + struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_comp_priv **crypto_priv){ + *crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_vdev_crypto_obj(vdev); + if (*crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return NULL; + } + + return &((*crypto_priv)->crypto_params); +} + +/** + * wlan_crypto_peer_get_crypto_params - called by mlme to get crypto params + * + * @peer:peer + * + * This function gets called by mlme to get crypto params + * + * Return: wlan_crypto_params or NULL in case of failure + */ +static struct wlan_crypto_params *wlan_crypto_peer_get_comp_params( + struct wlan_objmgr_peer *peer, + struct wlan_crypto_comp_priv **crypto_priv){ + + *crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_peer_crypto_obj(peer); + if (*crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return NULL; + } + + return &((*crypto_priv)->crypto_params); +} + +/** + * wlan_crypto_set_param - called by ucfg to set crypto param + * + * @vdev: vdev + * @param: param to be set. + * @value: value + * + * This function gets called from ucfg to set param + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_param(struct wlan_objmgr_vdev *vdev, + wlan_crypto_param_type param, + uint32_t value){ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + + crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_vdev_crypto_obj(vdev); + + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + crypto_params = &(crypto_priv->crypto_params); + switch (param) { + case WLAN_CRYPTO_PARAM_AUTH_MODE: + status = wlan_crypto_set_authmode(crypto_params, value); + break; + case WLAN_CRYPTO_PARAM_UCAST_CIPHER: + status = wlan_crypto_set_ucastciphers(crypto_params, value); + break; + case WLAN_CRYPTO_PARAM_MCAST_CIPHER: + status = wlan_crypto_set_mcastcipher(crypto_params, value); + break; + case WLAN_CRYPTO_PARAM_MGMT_CIPHER: + status = wlan_crypto_set_mgmtcipher(crypto_params, value); + break; + case WLAN_CRYPTO_PARAM_CIPHER_CAP: + status = wlan_crypto_set_cipher_cap(crypto_params, value); + break; + case WLAN_CRYPTO_PARAM_RSN_CAP: + status = wlan_crypto_set_rsn_cap(crypto_params, value); + break; + case WLAN_CRYPTO_PARAM_KEY_MGMT: + status = wlan_crypto_set_key_mgmt(crypto_params, value); + break; + default: + status = QDF_STATUS_E_INVAL; + } + + return status; +} + +/** + * wlan_crypto_get_param - called by ucfg to get crypto param + * + * @vdev: vdev + * @param: param to be get. + * + * This function gets called from ucfg to get param + * + * Return: value or -1 for failure + */ +int32_t wlan_crypto_get_param(struct wlan_objmgr_vdev *vdev, + wlan_crypto_param_type param){ + int32_t value = -1; + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_vdev_crypto_obj(vdev); + + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + crypto_params = &(crypto_priv->crypto_params); + switch (param) { + case WLAN_CRYPTO_PARAM_AUTH_MODE: + value = wlan_crypto_get_authmode(crypto_params); + break; + case WLAN_CRYPTO_PARAM_UCAST_CIPHER: + value = wlan_crypto_get_ucastciphers(crypto_params); + break; + case WLAN_CRYPTO_PARAM_MCAST_CIPHER: + value = wlan_crypto_get_mcastcipher(crypto_params); + break; + case WLAN_CRYPTO_PARAM_MGMT_CIPHER: + value = wlan_crypto_get_mgmtciphers(crypto_params); + break; + case WLAN_CRYPTO_PARAM_CIPHER_CAP: + value = wlan_crypto_get_cipher_cap(crypto_params); + break; + case WLAN_CRYPTO_PARAM_RSN_CAP: + value = wlan_crypto_get_rsn_cap(crypto_params); + break; + case WLAN_CRYPTO_PARAM_KEY_MGMT: + value = wlan_crypto_get_key_mgmt(crypto_params); + break; + default: + value = QDF_STATUS_E_INVAL; + } + + return value; +} + +static void initialize_send_iv(uint8_t *iv, uint8_t *init_iv) +{ + int8_t i = 0; + + for (i = 0; i < WLAN_CRYPTO_WAPI_IV_SIZE/4; i++) { + *(((uint32_t *)iv)+i) = + qdf_be32_to_cpu(*(((uint32_t *)(init_iv))+i)); + } +} +/** + * wlan_crypto_setkey - called by ucfg to setkey + * + * @vdev: vdev + * @req_key: req_key with cipher type, key macaddress + * + * This function gets called from ucfg to sey key + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_req_key *req_key){ + + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + const struct wlan_crypto_cipher *cipher; + uint8_t *macaddr = NULL; + bool isbcast; + + if (!req_key || req_key->keylen > (sizeof(req_key->keydata))) { + qdf_print("%s[%d] req_key invalid\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + isbcast = qdf_is_macaddr_broadcast( + (struct qdf_mac_addr *)req_key->macaddr); + if (req_key->keylen == 0) { + /* zero length keys, only set default key id if flags are set*/ + if ((req_key->flags & WLAN_CRYPTO_KEY_DEFAULT) + && (req_key->keyix != WLAN_CRYPTO_KEYIX_NONE) + && (!IS_MGMT_CIPHER(req_key->type))) { + wlan_crypto_default_key(vdev, + req_key->macaddr, + req_key->keyix, + !isbcast); + return QDF_STATUS_SUCCESS; + } + qdf_print("%s[%d] req_key len zero\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + cipher = wlan_crypto_cipher_ops[req_key->type]; + + if (!cipher && !IS_MGMT_CIPHER(req_key->type)) { + qdf_print("%s[%d] cipher invalid\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + if ((IS_MGMT_CIPHER(req_key->type)) + || ((req_key->keylen != (cipher->keylen/NBBY)) + && (req_key->type != WLAN_CRYPTO_CIPHER_WEP))) { + qdf_print("%s[%d] cipher invalid\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } else if ((req_key->type == WLAN_CRYPTO_CIPHER_WEP) && + !((req_key->keylen != WLAN_CRYPTO_KEY_WEP40_LEN) + || (req_key->keylen != WLAN_CRYPTO_KEY_WEP104_LEN) + || (req_key->keylen != WLAN_CRYPTO_KEY_WEP128_LEN))) { + qdf_print("%s[%d] cipher invalid\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + if (req_key->keyix == WLAN_CRYPTO_KEYIX_NONE) { + if (req_key->flags != (WLAN_CRYPTO_KEY_XMIT + | WLAN_CRYPTO_KEY_RECV)) { + req_key->flags = (WLAN_CRYPTO_KEY_XMIT + | WLAN_CRYPTO_KEY_RECV); + } + } else { + if ((req_key->keyix > WLAN_CRYPTO_MAXKEYIDX) + && (!IS_MGMT_CIPHER(req_key->type))) { + return QDF_STATUS_E_INVAL; + } + + req_key->flags = (WLAN_CRYPTO_KEY_XMIT + | WLAN_CRYPTO_KEY_RECV); + req_key->flags |= WLAN_CRYPTO_KEY_GROUP; + } + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)req_key->macaddr)) { + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + wlan_vdev_obj_lock(vdev); + macaddr = wlan_vdev_mlme_get_macaddr(vdev); + wlan_vdev_obj_unlock(vdev); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + if (IS_MGMT_CIPHER(req_key->type)) { + key = crypto_priv->igtk_key; + } else { + if (!HAS_MCAST_CIPHER(crypto_params, req_key->type) + && (req_key->type != WLAN_CRYPTO_CIPHER_WEP)) { + return QDF_STATUS_E_INVAL; + } + if (!crypto_priv->key[req_key->keyix]) { + crypto_priv->key[req_key->keyix] + = qdf_mem_malloc( + sizeof(struct wlan_crypto_key)); + if (!crypto_priv->key[req_key->keyix]) + return QDF_STATUS_E_NOMEM; + } + key = crypto_priv->key[req_key->keyix]; + } + } else { + struct wlan_objmgr_peer *peer; + + wlan_vdev_obj_lock(vdev); + peer = wlan_objmgr_get_peer_by_mac_n_vdev( + wlan_vdev_get_psoc(vdev), + req_key->macaddr, + wlan_vdev_mlme_get_macaddr(vdev), + WLAN_CRYPTO_ID); + wlan_vdev_obj_unlock(vdev); + macaddr = req_key->macaddr; + if (peer == NULL) { + qdf_print("%s[%d] peer NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID); + + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + if (IS_MGMT_CIPHER(req_key->type)) { + key = crypto_priv->igtk_key; + } else { + uint16_t kid = req_key->keyix; + if (kid == WLAN_CRYPTO_KEYIX_NONE) + kid = 0; + if (!crypto_priv->key[kid]) { + crypto_priv->key[kid] + = qdf_mem_malloc( + sizeof(struct wlan_crypto_key)); + if (!crypto_priv->key[kid]) + return QDF_STATUS_E_NOMEM; + } + key = crypto_priv->key[kid]; + } + } + + /* alloc key might not required as it is already there */ + key->cipher_table = (void *)cipher; + key->keylen = req_key->keylen; + key->flags = req_key->flags; + + if (req_key->keyix == WLAN_CRYPTO_KEYIX_NONE) + key->keyix = 0; + else + key->keyix = req_key->keyix; + + if ((req_key->type == WLAN_CRYPTO_CIPHER_WAPI_SMS4) + || (req_key->type == WLAN_CRYPTO_CIPHER_WAPI_GCM4)) { + uint8_t iv_AP[16] = { 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x37}; + uint8_t iv_STA[16] = { 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x36}; + + /* During Tx PN should be increment and + * send but as per our implementation we increment only after + * Tx complete. So First packet PN check will be failed. + * To compensate increment the PN here by 2 + */ + wlan_vdev_obj_lock(vdev); + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { + iv_AP[15] += 2; + wlan_vdev_obj_unlock(vdev); + qdf_mem_copy(key->recviv, iv_STA, + WLAN_CRYPTO_WAPI_IV_SIZE); + /*initialize send iv */ + qdf_mem_zero((uint8_t *)(key->txiv), + WLAN_CRYPTO_WAPI_IV_SIZE); + initialize_send_iv(key->txiv, iv_AP); + } else { + iv_STA[15] += 2; + wlan_vdev_obj_unlock(vdev); + qdf_mem_copy(key->recviv, iv_AP, + WLAN_CRYPTO_WAPI_IV_SIZE); + /*initialize send iv */ + qdf_mem_zero((uint8_t *)(key->txiv), + WLAN_CRYPTO_WAPI_IV_SIZE); + initialize_send_iv(key->txiv, iv_STA); + } + } else { + uint8_t i = 0; + qdf_mem_copy((uint8_t *)(&key->keytsc), + (uint8_t *)(&req_key->keytsc), sizeof(key->keytsc)); + for (i = 0; i < WLAN_CRYPTO_TID_SIZE; i++) { + qdf_mem_copy((uint8_t *)(&key->keyrsc[i]), + (uint8_t *)(&req_key->keyrsc), + sizeof(key->keyrsc[0])); + } + } + + qdf_mem_copy(key->keyval, req_key->keydata, sizeof(key->keyval)); + key->valid = 1; + + if (!macaddr) { + qdf_print("%s[%d] macaddr invalid\n", __func__, __LINE__); + return QDF_STATUS_E_NULL_VALUE; + } + + if ((IS_MGMT_CIPHER(req_key->type)) + && HAS_MGMT_CIPHER(crypto_params, req_key->type)) { + if (HAS_CIPHER_CAP(crypto_params, + WLAN_CRYPTO_CAP_PMF_OFFLOAD)) { + struct wlan_objmgr_psoc *psoc; + wlan_vdev_obj_lock(vdev); + psoc = wlan_vdev_get_psoc(vdev); + wlan_vdev_obj_unlock(vdev); + + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) { + WLAN_CRYPTO_TX_OPS_SETKEY(psoc)(vdev, + key, macaddr, req_key->type); + } + } + status = wlan_crypto_set_igtk_key(key); + return status; + } else { + struct wlan_objmgr_psoc *psoc; + wlan_vdev_obj_lock(vdev); + psoc = wlan_vdev_get_psoc(vdev); + wlan_vdev_obj_unlock(vdev); + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) { + WLAN_CRYPTO_TX_OPS_SETKEY(psoc)(vdev, key, + macaddr, req_key->type); + } + } + status = cipher->setkey(key); + + return status; +} + +/** + * wlan_crypto_getkey - called by ucfg to get key + * + * @vdev: vdev + * @req_key: key value will be copied in this req_key + * @mac_address: mac address of the peer for unicast key + * or broadcast address if group key is requested. + * This function gets called from ucfg to get key + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_getkey(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_req_key *req_key, + uint8_t *mac_addr){ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) { + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + } + return QDF_STATUS_E_INVAL; + + if (!HAS_MCAST_CIPHER(crypto_params, req_key->type)) + return QDF_STATUS_E_INVAL; + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + } else { + struct wlan_objmgr_peer *peer; + + wlan_vdev_obj_lock(vdev); + peer = wlan_objmgr_get_peer_by_mac_n_vdev( + wlan_vdev_get_psoc(vdev), + mac_addr, + wlan_vdev_mlme_get_macaddr(vdev), + WLAN_CRYPTO_ID); + wlan_vdev_obj_unlock(vdev); + if (peer == NULL) { + qdf_print("%s[%d] peer NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + if (!HAS_UCAST_CIPHER(crypto_params, req_key->type)) + return QDF_STATUS_E_INVAL; + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + } + + if (key->valid) { + qdf_mem_copy(req_key->keydata, + key->keyval, sizeof(key->keyval)); + qdf_mem_copy((uint8_t *)(&req_key->keytsc), + (uint8_t *)(&key->keytsc), + sizeof(req_key->keytsc)); + qdf_mem_copy((uint8_t *)(&req_key->keyrsc), + (uint8_t *)(&key->keyrsc[0]), + sizeof(req_key->keyrsc)); + req_key->keylen = key->keylen; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_delkey - called by ucfg to delete key + * + * @vdev: vdev + * @mac_address: mac address of the peer for unicast key + * or broadcast address if group key is deleted. + * @key_idx: key index to be deleted + * This function gets called from ucfg to delete key + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_delkey(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr, + uint8_t key_idx){ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + struct wlan_crypto_cipher *cipher_table; + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)macaddr)) { + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[key_idx]; + if (!key) + return QDF_STATUS_E_INVAL; + crypto_priv->key[key_idx] = NULL; + } else { + struct wlan_objmgr_peer *peer; + + wlan_vdev_obj_lock(vdev); + peer = wlan_objmgr_get_peer_by_mac_n_vdev( + wlan_vdev_get_psoc(vdev), macaddr, + wlan_vdev_mlme_get_macaddr(vdev), + WLAN_CRYPTO_ID); + wlan_vdev_obj_unlock(vdev); + if (peer == NULL) { + qdf_print("%s[%d] peer NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[key_idx]; + if (!key) + return QDF_STATUS_E_INVAL; + crypto_priv->key[key_idx] = NULL; + } + if (key->valid) { + struct wlan_objmgr_psoc *psoc; + wlan_vdev_obj_lock(vdev); + psoc = wlan_vdev_get_psoc(vdev); + wlan_vdev_obj_unlock(vdev); + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + cipher_table = (struct wlan_crypto_cipher *)key->cipher_table; + + if (WLAN_CRYPTO_TX_OPS_DELKEY(psoc)) { + WLAN_CRYPTO_TX_OPS_DELKEY(psoc)(vdev, key, + macaddr, cipher_table->cipher); + } + } + qdf_mem_free(key); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_default_key - called by ucfg to set default tx key + * + * @vdev: vdev + * @mac_address: mac address of the peer for unicast key + * or broadcast address if group key need to made default. + * @key_idx: key index to be made as default key + * @unicast: is key was unicast or group key. + * This function gets called from ucfg to set default key + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_default_key(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr, + uint8_t key_idx, + bool unicast){ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + struct wlan_objmgr_psoc *psoc; + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)macaddr)) { + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[key_idx]; + if (!key) + return QDF_STATUS_E_INVAL; + } else { + struct wlan_objmgr_peer *peer; + wlan_vdev_obj_lock(vdev); + peer = wlan_objmgr_get_peer_by_mac_n_vdev( + wlan_vdev_get_psoc(vdev), macaddr, + wlan_vdev_mlme_get_macaddr(vdev), + WLAN_CRYPTO_ID); + wlan_vdev_obj_unlock(vdev); + + if (peer == NULL) { + qdf_print("%s[%d] peer NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[key_idx]; + if (!key) + return QDF_STATUS_E_INVAL; + } + if (!key->valid) + return QDF_STATUS_E_INVAL; + + wlan_vdev_obj_lock(vdev); + psoc = wlan_vdev_get_psoc(vdev); + wlan_vdev_obj_unlock(vdev); + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + if (WLAN_CRYPTO_TX_OPS_DEFAULTKEY(psoc)) { + WLAN_CRYPTO_TX_OPS_DEFAULTKEY(psoc)(vdev, key_idx, + macaddr); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_encap - called by mgmt for encap the frame based on cipher + * + * @vdev: vdev + * @wbuf: wbuf + * @macaddr: macaddr + * @encapdone: is encapdone already or not. + * This function gets called from mgmt txrx to encap frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_encap(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, + uint8_t *mac_addr, + uint8_t encapdone){ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + QDF_STATUS status; + struct wlan_crypto_cipher *cipher_table; + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) { + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + + } else { + struct wlan_objmgr_peer *peer; + + wlan_vdev_obj_lock(vdev); + peer = wlan_objmgr_get_peer_by_mac_n_vdev( + wlan_vdev_get_psoc(vdev), mac_addr, + wlan_vdev_mlme_get_macaddr(vdev), + WLAN_CRYPTO_ID); + wlan_vdev_obj_unlock(vdev); + + if (peer == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID); + + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + } + /* if tkip, is counter measures enabled, then drop the frame */ + cipher_table = (struct wlan_crypto_cipher *)key->cipher_table; + status = cipher_table->encap(key, wbuf, encapdone, + ieee80211_hdrsize(wbuf)); + + return status; +} +EXPORT_SYMBOL(wlan_crypto_encap); + +/** + * wlan_crypto_decap - called by mgmt for decap the frame based on cipher + * + * @vdev: vdev + * @wbuf: wbuf + * @macaddr: macaddr + * @tid: tid of the frame + * This function gets called from mgmt txrx to decap frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_decap(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, + uint8_t *mac_addr, + uint8_t tid){ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + QDF_STATUS status; + struct wlan_crypto_cipher *cipher_table; + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) { + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + + } else { + struct wlan_objmgr_peer *peer; + + wlan_vdev_obj_lock(vdev); + peer = wlan_objmgr_get_peer_by_mac_n_vdev( + wlan_vdev_get_psoc(vdev), + mac_addr, + wlan_vdev_mlme_get_macaddr(vdev), + WLAN_CRYPTO_ID); + wlan_vdev_obj_unlock(vdev); + if (peer == NULL) { + qdf_print("%s[%d] peer NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID); + + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + } + /* if tkip, is counter measures enabled, then drop the frame */ + cipher_table = (struct wlan_crypto_cipher *)key->cipher_table; + status = cipher_table->decap(key, wbuf, tid, ieee80211_hdrsize(wbuf)); + + return status; +} +EXPORT_SYMBOL(wlan_crypto_decap); +/** + * wlan_crypto_enmic - called by mgmt for adding mic in frame based on cipher + * + * @vdev: vdev + * @wbuf: wbuf + * @macaddr: macaddr + * @encapdone: is encapdone already or not. + * This function gets called from mgmt txrx to adding mic to the frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_enmic(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, + uint8_t *mac_addr, + uint8_t encapdone){ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + QDF_STATUS status; + struct wlan_crypto_cipher *cipher_table; + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) { + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + + } else { + struct wlan_objmgr_peer *peer; + + wlan_vdev_obj_lock(vdev); + peer = wlan_objmgr_get_peer_by_mac_n_vdev( + wlan_vdev_get_psoc(vdev), + mac_addr, + wlan_vdev_mlme_get_macaddr(vdev), + WLAN_CRYPTO_ID); + wlan_vdev_obj_unlock(vdev); + if (peer == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID); + + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + } + /* if tkip, is counter measures enabled, then drop the frame */ + cipher_table = (struct wlan_crypto_cipher *)key->cipher_table; + status = cipher_table->enmic(key, wbuf, encapdone, + ieee80211_hdrsize(wbuf)); + + return status; +} + +/** + * wlan_crypto_demic - called by mgmt for remove and check mic for + * the frame based on cipher + * + * @vdev: vdev + * @wbuf: wbuf + * @macaddr: macaddr + * @tid: tid of the frame + * This function gets called from mgmt txrx to decap frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf, + uint8_t *mac_addr, + uint8_t tid){ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + QDF_STATUS status; + struct wlan_crypto_cipher *cipher_table; + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) { + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + + } else { + struct wlan_objmgr_peer *peer; + + wlan_vdev_obj_lock(vdev); + peer = wlan_objmgr_get_peer_by_mac_n_vdev( + wlan_vdev_get_psoc(vdev), + mac_addr, + wlan_vdev_mlme_get_macaddr(vdev), + WLAN_CRYPTO_ID); + wlan_vdev_obj_unlock(vdev); + if (peer == NULL) { + qdf_print("%s[%d] peer NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID); + + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", + __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + key = crypto_priv->key[crypto_priv->def_tx_keyid]; + if (!key) + return QDF_STATUS_E_INVAL; + } + /* if tkip, is counter measures enabled, then drop the frame */ + cipher_table = (struct wlan_crypto_cipher *)key->cipher_table; + status = cipher_table->demic(key, wbuf, tid, ieee80211_hdrsize(wbuf)); + + return status; +} + +/** + * wlan_crypto_is_pmf_enabled - called by mgmt txrx to check is pmf enabled + * + * @vdev: vdev + * @peer: peer + * + * This function gets called by mgmt txrx to check is pmf enabled or not. + * + * Return: true or false + */ +bool wlan_crypto_is_pmf_enabled(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer){ + + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *vdev_crypto_params; + struct wlan_crypto_params *peer_crypto_params; + + if (!vdev || !peer) + return false; + vdev_crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + + peer_crypto_params = wlan_crypto_peer_get_comp_params(peer, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return QDF_STATUS_E_INVAL; + } + if (((vdev_crypto_params->rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) && + (vdev_crypto_params->rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) + || (vdev_crypto_params->rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)) { + return true; + } + + return false; +} + +/** + * wlan_crypto_add_mmie - called by mgmt txrx to add mmie in frame + * + * @vdev: vdev + * @bfrm: frame starting pointer + * @len: length of the frame + * + * This function gets called by mgmt txrx to add mmie in frame + * + * Return: end of frame or NULL in case failure + */ +uint8_t *wlan_crypto_add_mmie(struct wlan_objmgr_vdev *vdev, + uint8_t *bfrm, + uint32_t len) { + struct wlan_crypto_key *key; + struct ieee80211_ath_mmie *mmie; + uint8_t *pn, aad[20], *efrm, nounce[12]; + struct ieee80211_frame *wh; + uint32_t i, hdrlen; + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return NULL; + } + + key = crypto_priv->igtk_key; + if (!key) + return NULL; + + if (!key && !bfrm) { + /* Invalid Key or frame */ + return NULL; + } + + efrm = bfrm + len; + len += sizeof(*mmie); + hdrlen = sizeof(*wh); + + mmie = (struct ieee80211_ath_mmie *) efrm; + mmie->element_id = IEEE80211_ELEMID_MMIE; + mmie->length = sizeof(*mmie) - 2; + mmie->key_id = qdf_cpu_to_le16(key->keyix); + + /* PN = PN + 1 */ + pn = (uint8_t *)&key->keytsc; + + for (i = 0; i <= 5; i++) { + pn[i]++; + if (pn[i]) + break; + } + + /* Copy IPN */ + qdf_mem_copy(mmie->sequence_number, pn, 6); + + wh = (struct ieee80211_frame *) bfrm; + + /* generate BIP AAD: FC(masked) || A1 || A2 || A3 */ + + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT + | IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + qdf_mem_copy(aad + 2, wh->i_addr1, IEEE80211_ADDR_LEN); + qdf_mem_copy(aad + 8, wh->i_addr2, IEEE80211_ADDR_LEN); + qdf_mem_copy(aad + 14, wh->i_addr3, IEEE80211_ADDR_LEN); + /* + * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) + */ + + if ((HAS_MGMT_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CMAC)) + || HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_CMAC_256)) { + /* size of MIC is 16 for GMAC, size of mic for CMAC is 8 */ + len -= 8; + mmie->length -= 8; + wlan_crypto_cmac_calc_mic(key, aad, bfrm + hdrlen, + len - hdrlen, mmie->mic); + } else if ((HAS_MGMT_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_GMAC)) + || HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_GMAC_256)) { + qdf_mem_copy(nounce, wh->i_addr2, IEEE80211_ADDR_LEN); + qdf_mem_copy(nounce + 6, pn, 6); + wlan_crypto_gmac_calc_mic(key, aad, bfrm + hdrlen, 20, + mmie->mic, nounce); + } else { + qdf_print("%s CMAC/GMAC Not valid rsn\n", __func__); + return NULL; + } + + return bfrm + len; +} + +/** + * wlan_crypto_is_mmie_valid - called by mgmt txrx to check mmie of the frame + * + * @vdev: vdev + * @frm: frame starting pointer + * @efrm: end of frame pointer + * + * This function gets called by mgmt txrx to check mmie of the frame + * + * Return: true or false + */ +bool wlan_crypto_is_mmie_valid(struct wlan_objmgr_vdev *vdev, + uint8_t *frm, + uint8_t *efrm){ + struct ieee80211_ath_mmie *mmie = NULL; + uint8_t *ipn, aad[20], mic[16], nounce[12]; + struct wlan_crypto_key *key; + struct ieee80211_frame *wh; + uint8_t mic_length; + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + + /* check if frame is illegal length */ + if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) + return false; + + crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_vdev_crypto_obj(vdev); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return false; + } + + crypto_params = &(crypto_priv->crypto_params); + key = crypto_priv->igtk_key; + if (!key) + return false; + + if ((HAS_MGMT_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CMAC)) + || HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_CMAC_256)) { + mmie = (struct ieee80211_ath_mmie *)(efrm - sizeof(*mmie) + 8); + } else if ((HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_GMAC)) + || HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_GMAC_256)) { + mmie = (struct ieee80211_ath_mmie *)(efrm - sizeof(*mmie)); + } + /* check Elem ID*/ + if ((mmie == NULL) || (mmie->element_id != IEEE80211_ELEMID_MMIE)) { + /* IE is not Mgmt MIC IE */ + return false; + } + + /* validate ipn */ + ipn = mmie->sequence_number; + if (qdf_mem_cmp(ipn, key->keyrsc, 6) <= 0) { + /* replay error */ + return false; + } + + /* construct AAD */ + wh = (struct ieee80211_frame *)frm; + /* generate BIP AAD: FC(masked) || A1 || A2 || A3 */ + + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT + | IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + /* + * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) + */ + if ((HAS_MGMT_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CMAC)) + || HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_CMAC_256)) { + mic_length = 8; + wlan_crypto_cmac_calc_mic(key, aad, (uint8_t *)(wh+1), + (efrm - (uint8_t *)(wh+1)), mic); + } else if ((HAS_MGMT_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_GMAC)) + || HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_GMAC_256)) { + mic_length = 16; + qdf_mem_copy(nounce, wh->i_addr2, IEEE80211_ADDR_LEN); + qdf_mem_copy(nounce + 6, ipn, 6); + wlan_crypto_gmac_calc_mic(key, aad, (uint8_t *)(wh+1), + 20, mic, nounce); + } else + return false; + + if (qdf_mem_cmp(mic, mmie->mic, mic_length) != 0) + /* MMIE MIC mismatch */ + return false; + + /* Update the receive sequence number */ + qdf_mem_copy(key->keyrsc, ipn, 6); + + return true; +} + + +static int32_t wlan_crypto_wpa_cipher_to_suite(uint32_t cipher) +{ + int32_t status = -1; + + switch (cipher) { + case WLAN_CRYPTO_CIPHER_TKIP: + return WPA_CIPHER_SUITE_TKIP; + case WLAN_CRYPTO_CIPHER_AES_CCM: + return WPA_CIPHER_SUITE_CCMP; + case WLAN_CRYPTO_CIPHER_NONE: + return WPA_CIPHER_SUITE_NONE; + } + + return status; +} + +static int32_t wlan_crypto_rsn_cipher_to_suite(uint32_t cipher) +{ + int32_t status = -1; + + switch (cipher) { + case WLAN_CRYPTO_CIPHER_TKIP: + return RSN_CIPHER_SUITE_TKIP; + case WLAN_CRYPTO_CIPHER_AES_CCM: + return RSN_CIPHER_SUITE_CCMP; + case WLAN_CRYPTO_CIPHER_AES_CCM_256: + return RSN_CIPHER_SUITE_CCMP_256; + case WLAN_CRYPTO_CIPHER_AES_GCM: + return RSN_CIPHER_SUITE_GCMP; + case WLAN_CRYPTO_CIPHER_AES_GCM_256: + return RSN_CIPHER_SUITE_GCMP_256; + case WLAN_CRYPTO_CIPHER_AES_CMAC: + return RSN_CIPHER_SUITE_AES_CMAC; + case WLAN_CRYPTO_CIPHER_AES_CMAC_256: + return RSN_CIPHER_SUITE_BIP_CMAC_256; + case WLAN_CRYPTO_CIPHER_AES_GMAC: + return RSN_CIPHER_SUITE_BIP_GMAC_128; + case WLAN_CRYPTO_CIPHER_AES_GMAC_256: + return RSN_CIPHER_SUITE_BIP_GMAC_256; + case WLAN_CRYPTO_CIPHER_NONE: + return RSN_CIPHER_SUITE_NONE; + } + + return status; +} + +/* + * Convert an RSN key management/authentication algorithm + * to an internal code. + */ +static int32_t +wlan_crypto_rsn_keymgmt_to_suite(uint32_t keymgmt) +{ + int32_t status = -1; + + switch (keymgmt) { + case WLAN_CRYPTO_KEY_MGMT_NONE: + return RSN_AUTH_KEY_MGMT_NONE; + case WLAN_CRYPTO_KEY_MGMT_IEEE8021X: + return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; + case WLAN_CRYPTO_KEY_MGMT_PSK: + return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; + case WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X: + return RSN_AUTH_KEY_MGMT_FT_802_1X; + case WLAN_CRYPTO_KEY_MGMT_FT_PSK: + return RSN_AUTH_KEY_MGMT_FT_PSK; + case WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256: + return RSN_AUTH_KEY_MGMT_802_1X_SHA256; + case WLAN_CRYPTO_KEY_MGMT_PSK_SHA256: + return RSN_AUTH_KEY_MGMT_PSK_SHA256; + case WLAN_CRYPTO_KEY_MGMT_SAE: + return RSN_AUTH_KEY_MGMT_SAE; + case WLAN_CRYPTO_KEY_MGMT_FT_SAE: + return RSN_AUTH_KEY_MGMT_FT_SAE; + case WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B: + return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; + case WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192: + return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; + case WLAN_CRYPTO_KEY_MGMT_CCKM: + return RSN_AUTH_KEY_MGMT_CCKM; + case WLAN_CRYPTO_KEY_MGMT_OSEN: + return RSN_AUTH_KEY_MGMT_OSEN; + } + + return status; +} + +/* + * Convert an RSN key management/authentication algorithm + * to an internal code. + */ +static int32_t +wlan_crypto_wpa_keymgmt_to_suite(uint32_t keymgmt) +{ + int32_t status = -1; + + switch (keymgmt) { + case WLAN_CRYPTO_KEY_MGMT_NONE: + return WPA_AUTH_KEY_MGMT_NONE; + case WLAN_CRYPTO_KEY_MGMT_IEEE8021X: + return WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; + case WLAN_CRYPTO_KEY_MGMT_PSK: + return WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; + case WLAN_CRYPTO_KEY_MGMT_CCKM: + return WPA_AUTH_KEY_MGMT_CCKM; + } + + return status; +} +/** + * + * Convert a WPA cipher selector OUI to an internal + * cipher algorithm. Where appropriate we also + * record any key length. + */ +static int32_t wlan_crypto_wpa_suite_to_cipher(uint8_t *sel, uint8_t *keylen) +{ + uint32_t w = LE_READ_4(sel); + int32_t status = -1; + + switch (w) { + case WPA_CIPHER_SUITE_TKIP: + return WLAN_CRYPTO_CIPHER_TKIP; + case WPA_CIPHER_SUITE_CCMP: + return WLAN_CRYPTO_CIPHER_AES_CCM; + case WPA_CIPHER_SUITE_NONE: + return WLAN_CRYPTO_CIPHER_NONE; + } + + return status; +} + +/* + * Convert a WPA key management/authentication algorithm + * to an internal code. + */ +static int32_t wlan_crypto_wpa_suite_to_keymgmt(uint8_t *sel) +{ + uint32_t w = LE_READ_4(sel); + int32_t status = -1; + + switch (w) { + case WPA_AUTH_KEY_MGMT_UNSPEC_802_1X: + return WLAN_CRYPTO_KEY_MGMT_IEEE8021X; + case WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X: + return WLAN_CRYPTO_KEY_MGMT_PSK; + case WPA_AUTH_KEY_MGMT_CCKM: + return WLAN_CRYPTO_KEY_MGMT_CCKM; + case WPA_AUTH_KEY_MGMT_NONE: + return WLAN_CRYPTO_KEY_MGMT_NONE; + } + return status; +} + +/* + * Convert a RSN cipher selector OUI to an internal + * cipher algorithm. Where appropriate we also + * record any key length. + */ +static int32_t wlan_crypto_rsn_suite_to_cipher(uint8_t *sel) +{ + uint32_t w = LE_READ_4(sel); + int32_t status = -1; + + switch (w) { + case RSN_CIPHER_SUITE_TKIP: + return WLAN_CRYPTO_CIPHER_TKIP; + case RSN_CIPHER_SUITE_CCMP: + return WLAN_CRYPTO_CIPHER_AES_CCM; + case RSN_CIPHER_SUITE_CCMP_256: + return WLAN_CRYPTO_CIPHER_AES_CCM_256; + case RSN_CIPHER_SUITE_GCMP: + return WLAN_CRYPTO_CIPHER_AES_GCM; + case RSN_CIPHER_SUITE_GCMP_256: + return WLAN_CRYPTO_CIPHER_AES_GCM_256; + case RSN_CIPHER_SUITE_AES_CMAC: + return WLAN_CRYPTO_CIPHER_AES_CMAC; + case RSN_CIPHER_SUITE_BIP_CMAC_256: + return WLAN_CRYPTO_CIPHER_AES_CMAC_256; + case RSN_CIPHER_SUITE_BIP_GMAC_128: + return WLAN_CRYPTO_CIPHER_AES_GMAC; + case RSN_CIPHER_SUITE_BIP_GMAC_256: + return WLAN_CRYPTO_CIPHER_AES_GMAC_256; + case RSN_CIPHER_SUITE_NONE: + return WLAN_CRYPTO_CIPHER_NONE; + } + + return status; +} +/* + * Convert an RSN key management/authentication algorithm + * to an internal code. + */ +static int32_t wlan_crypto_rsn_suite_to_keymgmt(uint8_t *sel) +{ + uint32_t w = LE_READ_4(sel); + int32_t status = -1; + + switch (w) { + case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X: + return WLAN_CRYPTO_KEY_MGMT_IEEE8021X; + case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X: + return WLAN_CRYPTO_KEY_MGMT_PSK; + case RSN_AUTH_KEY_MGMT_FT_802_1X: + return WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X; + case RSN_AUTH_KEY_MGMT_FT_PSK: + return WLAN_CRYPTO_KEY_MGMT_FT_PSK; + case RSN_AUTH_KEY_MGMT_802_1X_SHA256: + return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256; + case RSN_AUTH_KEY_MGMT_PSK_SHA256: + return WLAN_CRYPTO_KEY_MGMT_PSK_SHA256; + case RSN_AUTH_KEY_MGMT_SAE: + return WLAN_CRYPTO_KEY_MGMT_SAE; + case RSN_AUTH_KEY_MGMT_FT_SAE: + return WLAN_CRYPTO_KEY_MGMT_FT_SAE; + case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B: + return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B; + case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192: + return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192; + case RSN_AUTH_KEY_MGMT_CCKM: + return WLAN_CRYPTO_KEY_MGMT_CCKM; + case RSN_AUTH_KEY_MGMT_OSEN: + return WLAN_CRYPTO_KEY_MGMT_OSEN; + } + + return status; +} + +/** + * wlan_crypto_wpaie_check - called by mlme to check the wpaie + * + * + * @crypto params: crypto params + * @iebuf: ie buffer + * + * This function gets called by mlme to check the contents of wpa is + * matching with given crypto params + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_wpaie_check(struct wlan_crypto_params *crypto_params, + uint8_t *frm){ + uint8_t len = frm[1]; + int32_t w; + int n; + uint8_t cipher_length; + /* + * Check the length once for fixed parts: OUI, type, + * version, mcast cipher, and 2 selector counts. + * Other, variable-length data, must be checked separately. + */ + RESET_AUTHMODE(crypto_params); + SET_AUTHMODE(crypto_params, WLAN_CRYPTO_AUTH_WPA); + + if (len < 14) + return QDF_STATUS_E_INVAL; + + frm += 6, len -= 4; /* NB: len is payload only */ + /* NB: iswapoui already validated the OUI and type */ + w = LE_READ_2(frm); + if (w != WPA_VERSION) + return QDF_STATUS_E_INVAL; + + frm += 2, len -= 2; + + /* multicast/group cipher */ + RESET_MCAST_CIPHERS(crypto_params); + w = wlan_crypto_wpa_suite_to_cipher(frm, &cipher_length); + if (w < 0) + return QDF_STATUS_E_INVAL; + SET_MCAST_CIPHER(crypto_params, w); + frm += 4, len -= 4; + + /* unicast ciphers */ + n = LE_READ_2(frm); + frm += 2, len -= 2; + if (len < n*4+2) + return QDF_STATUS_E_INVAL; + + RESET_UCAST_CIPHERS(crypto_params); + for (; n > 0; n--) { + w = wlan_crypto_wpa_suite_to_cipher(frm, &cipher_length); + if (w < 0) + return QDF_STATUS_E_INVAL; + SET_UCAST_CIPHER(crypto_params, w); + frm += 4, len -= 4; + } + + if (!crypto_params->ucastcipherset) + return QDF_STATUS_E_INVAL; + + /* key management algorithms */ + n = LE_READ_2(frm); + frm += 2, len -= 2; + if (len < n*4) + return QDF_STATUS_E_INVAL; + + w = 0; + RESET_KEY_MGMT(crypto_params); + for (; n > 0; n--) { + w = wlan_crypto_wpa_suite_to_keymgmt(frm); + if (w < 0) + return QDF_STATUS_E_INVAL; + SET_KEY_MGMT(crypto_params, w); + frm += 4, len -= 4; + } + + /* optional capabilities */ + if (len >= 2) { + crypto_params->rsn_caps = LE_READ_2(frm); + frm += 2, len -= 2; + } + + return 0; +} + +/** + * wlan_crypto_rsnie_check - called by mlme to check the rsnie + * + * + * @crypto params: crypto params + * @iebuf: ie buffer + * + * This function gets called by mlme to check the contents of wpa is + * matching with given crypto params + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_rsnie_check(struct wlan_crypto_params *crypto_params, + uint8_t *frm){ + uint8_t len = frm[1]; + int32_t w; + int n; + uint8_t cipher_length; + /* + * Check the length once for fixed parts: OUI, type, + * version, mcast cipher, and 2 selector counts. + * Other, variable-length data, must be checked separately. + */ + RESET_AUTHMODE(crypto_params); + SET_AUTHMODE(crypto_params, WLAN_CRYPTO_AUTH_RSNA); + + if (len < 14) + return QDF_STATUS_E_INVAL; + + frm += 6, len -= 4; + /* NB: iswapoui already validated the OUI and type */ + w = LE_READ_2(frm); + if (w != RSN_VERSION) + return QDF_STATUS_E_INVAL; + + frm += 2, len -= 2; + + /* multicast/group cipher */ + RESET_MCAST_CIPHERS(crypto_params); + w = wlan_crypto_rsn_suite_to_cipher(frm); + if (w < 0) + return QDF_STATUS_E_INVAL; + SET_MCAST_CIPHER(crypto_params, w); + frm += 4, len -= 4; + + /* unicast ciphers */ + n = LE_READ_2(frm); + frm += 2, len -= 2; + if (len < n*4+2) + return QDF_STATUS_E_INVAL; + + RESET_UCAST_CIPHERS(crypto_params); + for (; n > 0; n--) { + SET_UCAST_CIPHER(crypto_params, + wlan_crypto_rsn_suite_to_cipher(frm)); + w = wlan_crypto_wpa_suite_to_cipher(frm, &cipher_length); + if (w < 0) + return QDF_STATUS_E_INVAL; + frm += 4, len -= 4; + } + + if (crypto_params->ucastcipherset == 0) + return QDF_STATUS_E_INVAL; + + /* key management algorithms */ + n = LE_READ_2(frm); + frm += 2, len -= 2; + if (len < n*4) + return QDF_STATUS_E_INVAL; + w = 0; + + RESET_KEY_MGMT(crypto_params); + for (; n > 0; n--) { + w = wlan_crypto_rsn_suite_to_keymgmt(frm); + if (w < 0) + return QDF_STATUS_E_INVAL; + SET_KEY_MGMT(crypto_params, w); + frm += 4, len -= 4; + } + + /* optional capabilities */ + if (len >= 2) { + crypto_params->rsn_caps = LE_READ_2(frm); + frm += 2, len -= 2; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_build_wpaie - called by mlme to build wpaie + * + * @crypto params: crypto params + * @iebuf: ie buffer + * + * This function gets called by mlme to build wpaie from given crypto params + * + * Return: end of buffer + */ +uint8_t *wlan_crypto_build_wpaie(struct wlan_crypto_params *crypto_params, + uint8_t *iebuf){ + uint8_t *frm = iebuf; + uint8_t *selcnt; + uint32_t mcastcipher; + + *frm++ = IEEE80211_ELEMID_VENDOR; + *frm++ = 0; + WLAN_CRYPTO_ADDSELECTOR(frm, WPA_TYPE_OUI); + WLAN_CRYPTO_ADDSHORT(frm, WPA_VERSION); + + + /* multicast cipher */ + mcastcipher = wlan_crypto_get_mcastcipher(crypto_params); + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_wpa_cipher_to_suite(mcastcipher)); + + /* unicast cipher list */ + selcnt = frm; + WLAN_CRYPTO_ADDSHORT(frm, 0); + /* do not use CCMP unicast cipher in WPA mode */ + if (UCIPHER_IS_TKIP(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_wpa_cipher_to_suite( + WLAN_CRYPTO_CIPHER_TKIP)); + } + if (UCIPHER_IS_CCMP128(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_wpa_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_CCM)); + } + if (UCIPHER_IS_CLEAR(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_wpa_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_CCM)); + } + + /* authenticator selector list */ + selcnt = frm; + WLAN_CRYPTO_ADDSHORT(frm, 0); + + if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_wpa_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_IEEE8021X)); + } else if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_PSK)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_wpa_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_PSK)); + } else if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_CCKM)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_wpa_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_CCKM)); + } else { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_wpa_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_NONE)); + } + + /* calculate element length */ + iebuf[1] = frm - iebuf - 2; + + return frm; +} + +/** + * wlan_crypto_build_rsnie - called by mlme to build rsnie + * + * @crypto params: crypto params + * @iebuf: ie buffer + * + * This function gets called by mlme to build rsnie from given crypto params + * + * Return: end of buffer + */ +uint8_t *wlan_crypto_build_rsnie(struct wlan_crypto_params *crypto_params, + uint8_t *iebuf){ + uint8_t *frm = iebuf; + uint8_t *selcnt; + uint32_t mcastcipher; + + *frm++ = IEEE80211_ELEMID_RSN; + *frm++ = 0; + WLAN_CRYPTO_ADDSHORT(frm, RSN_VERSION); + + + /* multicast cipher */ + mcastcipher = wlan_crypto_get_mcastcipher(crypto_params); + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite(mcastcipher)); + + /* unicast cipher list */ + selcnt = frm; + WLAN_CRYPTO_ADDSHORT(frm, 0); + /* do not use CCMP unicast cipher in WPA mode */ + if (UCIPHER_IS_TKIP(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_TKIP)); + } + if (UCIPHER_IS_CCMP128(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_CCM)); + } + if (UCIPHER_IS_CCMP256(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_CCM_256)); + } + + if (UCIPHER_IS_GCMP128(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_GCM)); + } + if (UCIPHER_IS_GCMP256(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_GCM_256)); + } + if (UCIPHER_IS_CLEAR(crypto_params)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_CCM)); + } + + + /* authenticator selector list */ + selcnt = frm; + WLAN_CRYPTO_ADDSHORT(frm, 0); + if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_CCKM)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_CCKM)); + } else { + if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_PSK)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_PSK)); + } + if (HAS_KEY_MGMT(crypto_params, + WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_IEEE8021X)); + } + if (HAS_KEY_MGMT(crypto_params, + WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X)); + } + if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_FT_PSK)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_FT_PSK)); + } + if (HAS_KEY_MGMT(crypto_params, + WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)); + } + if (HAS_KEY_MGMT(crypto_params, + WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)); + } + if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_OSEN)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_keymgmt_to_suite( + WLAN_CRYPTO_KEY_MGMT_OSEN)); + } + } + + /* optional capabilities */ + if (crypto_params->rsn_caps != 0 && + crypto_params->rsn_caps != WLAN_CRYPTO_RSN_CAP_PREAUTH){ + + WLAN_CRYPTO_ADDSHORT(frm, crypto_params->rsn_caps); + + if (HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_CMAC)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_CMAC)); + } + if (HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_GMAC)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_GMAC)); + } + if (HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_CMAC_256)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_CMAC_256)); + } + + if (HAS_MGMT_CIPHER(crypto_params, + WLAN_CRYPTO_CIPHER_AES_GMAC_256)) { + selcnt[0]++; + WLAN_CRYPTO_ADDSELECTOR(frm, + wlan_crypto_rsn_cipher_to_suite( + WLAN_CRYPTO_CIPHER_AES_GMAC_256)); + } + } + /* calculate element length */ + iebuf[1] = frm - iebuf - 2; + + return frm; +} +bool wlan_crypto_rsn_info(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_params *crypto_params){ + struct wlan_crypto_params *my_crypto_params; + my_crypto_params = wlan_crypto_vdev_get_crypto_params(vdev); + + /* + * Check peer's pairwise ciphers. + * At least one must match with our unicast cipher + */ + if (!UCAST_CIPHER_MATCH(crypto_params, my_crypto_params)) + return false; + /* + * Check peer's group cipher is our enabled multicast cipher. + */ + if (!MCAST_CIPHER_MATCH(crypto_params, my_crypto_params)) + return false; + /* + * Check peer's key management class set (PSK or UNSPEC) + */ + if (!KEY_MGMTSET_MATCH(crypto_params, my_crypto_params)) + return false; + + return true; +} + +/** + * wlan_crypto_pn_check - called by data patch for PN check + * + * @vdev: vdev + * @wbuf: wbuf + * + * This function gets called by data patch for PN check + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_crypto_pn_check(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf){ + /* Need to check is there real requirement for this function + * as PN check is already handled in decap function. + */ + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_vdev_get_crypto_params - called by mlme to get crypto params + * + * @vdev:vdev + * + * This function gets called by mlme to get crypto params + * + * Return: wlan_crypto_params or NULL in case of failure + */ +struct wlan_crypto_params *wlan_crypto_vdev_get_crypto_params( + struct wlan_objmgr_vdev *vdev){ + struct wlan_crypto_comp_priv *crypto_priv; + + return wlan_crypto_vdev_get_comp_params(vdev, &crypto_priv); +} + +/** + * wlan_crypto_peer_get_crypto_params - called by mlme to get crypto params + * + * @peer:peer + * + * This function gets called by mlme to get crypto params + * + * Return: wlan_crypto_params or NULL in case of failure + */ +struct wlan_crypto_params *wlan_crypto_peer_get_crypto_params( + struct wlan_objmgr_peer *peer){ + struct wlan_crypto_comp_priv *crypto_priv; + + return wlan_crypto_peer_get_comp_params(peer, &crypto_priv); +} + + +QDF_STATUS wlan_crypto_set_peer_wep_keys(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr){ + uint8_t keymac[IEEE80211_ADDR_LEN]; + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + struct wlan_crypto_key *key; + struct wlan_crypto_key *tmp_key; + struct wlan_crypto_cipher *cipher_table; + struct wlan_objmgr_psoc *psoc; + int i; + enum tQDF_ADAPTER_MODE opmode; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + wlan_vdev_obj_lock(vdev); + psoc = wlan_vdev_get_psoc(vdev); + wlan_vdev_obj_unlock(vdev); + + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + crypto_params = wlan_crypto_vdev_get_comp_params(vdev, + &crypto_priv); + if (crypto_priv == NULL) { + qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__); + return QDF_STATUS_E_NULL_VALUE; + } + + /* push only valid static WEP keys from vap */ + if (AUTH_IS_8021X(crypto_params)) + return QDF_STATUS_E_INVAL; + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) + return QDF_STATUS_E_INVAL; + + tmp_key = (struct wlan_crypto_key *)qdf_mem_malloc( + sizeof(struct wlan_crypto_key)); + + if (!tmp_key) + return QDF_STATUS_E_NULL_VALUE; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + + /* push only valid static WEP keys from vap */ + + for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) { + if (crypto_priv->key[i]) { + key = crypto_priv->key[i]; + if (!key || !key->valid) + continue; + + cipher_table = (struct wlan_crypto_cipher *) + key->cipher_table; + + if (cipher_table->cipher == WLAN_CRYPTO_CIPHER_WEP) { + qdf_mem_copy(tmp_key, key, + sizeof(struct wlan_crypto_key)); + qdf_copy_macaddr((struct qdf_mac_addr *)keymac, + (struct qdf_mac_addr *)mac_addr); + + /* setting the broadcast/multicast key for sta*/ + if (opmode == QDF_STA_MODE || + opmode == QDF_IBSS_MODE){ + if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) { + WLAN_CRYPTO_TX_OPS_SETKEY(psoc)( + vdev, tmp_key, mac_addr, + cipher_table->cipher); + } + } + + /* setting unicast key */ + tmp_key->flags &= ~WLAN_CRYPTO_KEY_GROUP; + if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) { + WLAN_CRYPTO_TX_OPS_SETKEY(psoc)(vdev, + tmp_key, mac_addr, + cipher_table->cipher); + } + } + } + } + qdf_mem_free(tmp_key); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_register_crypto_rx_ops - set crypto_rx_ops + * + * @crypto_rx_ops: crypto_rx_ops + * + * This function gets called by object manger to register crypto rx ops. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_crypto_register_crypto_rx_ops( + struct wlan_lmac_if_crypto_rx_ops *crypto_rx_ops){ + crypto_rx_ops->crypto_encap = wlan_crypto_encap; + crypto_rx_ops->crypto_decap = wlan_crypto_decap; + crypto_rx_ops->crypto_enmic = wlan_crypto_enmic; + crypto_rx_ops->crypto_demic = wlan_crypto_demic; + crypto_rx_ops->set_peer_wep_keys = wlan_crypto_set_peer_wep_keys; + + return QDF_STATUS_SUCCESS; +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_main.c b/umac/cmn_services/crypto/src/wlan_crypto_main.c new file mode 100644 index 000000000000..55c42f4d0a02 --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_main.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public API intialization of crypto service with object manager + */ +#include +#include "wlan_crypto_main_i.h" +#include "wlan_crypto_main.h" + +/** + * wlan_crypto_init - Init the crypto service with object manager + * Called from umac init context. + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_init(void) +{ + return __wlan_crypto_init(); +} + +/** + * wlan_crypto_deinit - Deinit the crypto service with object manager + * Called from umac deinit context. + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_deinit(void) +{ + return __wlan_crypto_deinit(); +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_main.h b/umac/cmn_services/crypto/src/wlan_crypto_main.h new file mode 100644 index 000000000000..e830b9f4d0a5 --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_main.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Private API for crypto service with object manager handler + */ +#ifndef _WLAN_CRYPTO_MAIN_H_ +#define _WLAN_CRYPTO_MAIN_H_ + +/** + * wlan_crypto_init - Init the crypto service with object manager + * Called from umac init context. + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_init(void); + +/** + * wlan_crypto_deinit - Deinit the crypto service with object manager + * Called from umac deinit context. + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_deinit(void); + + +#endif /* end of _WLAN_CRYPTO_MAIN_H_ */ diff --git a/umac/cmn_services/crypto/src/wlan_crypto_main_i.h b/umac/cmn_services/crypto/src/wlan_crypto_main_i.h new file mode 100644 index 000000000000..f9cce8eb8ba3 --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_main_i.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Private API for crypto service with object manager handler + */ +#ifndef _WLAN_CRYPTO_MAIN_I_H_ +#define _WLAN_CRYPTO_MAIN_I_H_ + +/** + * wlan_crypto_init - Init the crypto service with object manager + * Called from umac init context. + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS __wlan_crypto_init(void); + +/** + * wlan_crypto_deinit - Deinit the crypto service with object manager + * Called from umac deinit context. + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS __wlan_crypto_deinit(void); + + +#endif /* end of _WLAN_CRYPTO_MAIN_I_H_ */ diff --git a/umac/cmn_services/crypto/src/wlan_crypto_none.c b/umac/cmn_services/crypto/src/wlan_crypto_none.c new file mode 100644 index 000000000000..fc7205a3914c --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_none.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public API intialization of crypto service with object manager + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wlan_crypto_global_def.h" +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_main_i.h" +#include "wlan_crypto_obj_mgr_i.h" + + +static QDF_STATUS none_setkey(struct wlan_crypto_key *key) +{ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS none_encap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t encapdone, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS none_decap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS none_enmic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t encapdone, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS none_demic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} + +const struct wlan_crypto_cipher none_cipher_table = { + "NONE", + WLAN_CRYPTO_CIPHER_NONE, + 0, + 0, + 0, + 0, + none_setkey, + none_encap, + none_decap, + none_enmic, + none_demic, +}; + +const struct wlan_crypto_cipher *none_register(void){ + return &none_cipher_table; +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c b/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c new file mode 100644 index 000000000000..aba8d0d90032 --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public API intialization of crypto service with object manager + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "wlan_crypto_global_def.h" +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_main_i.h" +#include "wlan_crypto_obj_mgr_i.h" + + +extern const struct wlan_crypto_cipher *wep_register(void); +extern const struct wlan_crypto_cipher *tkip_register(void); +extern const struct wlan_crypto_cipher *ccmp_register(void); +extern const struct wlan_crypto_cipher *ccmp256_register(void); +extern const struct wlan_crypto_cipher *gcmp_register(void); +extern const struct wlan_crypto_cipher *gcmp256_register(void); +extern const struct wlan_crypto_cipher *wapi_register(void); + +extern const struct wlan_crypto_cipher + *wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_MAX]; + +static QDF_STATUS wlan_crypto_register_all_ciphers( + struct wlan_crypto_params *crypto_param) +{ + + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_WEP] = wep_register(); + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_TKIP] = tkip_register(); + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_CCM] + = ccmp_register(); + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_CCM_256] + = ccmp256_register(); + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_GCM] + = gcmp_register(); + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_GCM_256] + = gcmp256_register(); + if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WEP)) { + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_WEP] + = wep_register(); + } + if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_TKIP_MIC)) { + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_TKIP] + = tkip_register(); + } + if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_AES)) { + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_CCM] + = ccmp_register(); + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_CCM_256] + = ccmp256_register(); + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_GCM] + = gcmp_register(); + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_GCM_256] + = gcmp256_register(); + } + if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WAPI_SMS4)) { + wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_WAPI_SMS4] + = wapi_register(); + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wlan_crypto_psoc_obj_create_handler( + struct wlan_objmgr_psoc *psoc, + void *arg) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wlan_crypto_pdev_obj_create_handler( + struct wlan_objmgr_pdev *pdev, + void *arg) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wlan_crypto_vdev_obj_create_handler( + struct wlan_objmgr_vdev *vdev, + void *arg) +{ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_objmgr_pdev *pdev; + struct wlan_crypto_params *crypto_param; + + if (!vdev) + return QDF_STATUS_E_INVAL; + + crypto_priv = qdf_mem_malloc(sizeof(struct wlan_crypto_comp_priv)); + if (!crypto_priv) + return QDF_STATUS_E_NOMEM; + + crypto_param = &(crypto_priv->crypto_params); + pdev = wlan_vdev_get_pdev(vdev); + + wlan_pdev_obj_lock(pdev); + if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_WEP)) + SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WEP); + if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_TKIP)) + SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_TKIP_MIC); + if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_AES)) + SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_AES); + if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_CKIP)) + SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_CKIP); + if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_WAPI)) + SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WAPI_SMS4); + wlan_pdev_obj_unlock(pdev); + + /* update the crypto cipher table based on the fw caps*/ + /* update the fw_caps into ciphercaps then attach to objmgr*/ + wlan_crypto_register_all_ciphers(crypto_param); + + return wlan_objmgr_vdev_component_obj_attach(vdev, + WLAN_UMAC_COMP_CRYPTO, + (void *)crypto_priv, + QDF_STATUS_SUCCESS); +} + +static QDF_STATUS wlan_crypto_peer_obj_create_handler( + struct wlan_objmgr_peer *peer, + void *arg) +{ + struct wlan_crypto_comp_priv *crypto_priv; + + if (!peer) + return QDF_STATUS_E_INVAL; + + crypto_priv = qdf_mem_malloc(sizeof(struct wlan_crypto_comp_priv)); + if (!crypto_priv) + return QDF_STATUS_E_NOMEM; + + return wlan_objmgr_peer_component_obj_attach(peer, + WLAN_UMAC_COMP_CRYPTO, + (void *)crypto_priv, + QDF_STATUS_SUCCESS); +} + +static QDF_STATUS wlan_crypto_psoc_obj_destroy_handler( + struct wlan_objmgr_psoc *psoc, + void *arg){ + + return QDF_STATUS_COMP_DISABLED; +} + +static QDF_STATUS wlan_crypto_pdev_obj_destroy_handler( + struct wlan_objmgr_pdev *pdev, + void *arg){ + + return QDF_STATUS_SUCCESS; +} + +static void wlan_crypto_free_key(struct wlan_crypto_comp_priv *crypto_priv) +{ + uint8_t i; + + for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) { + if (crypto_priv->key[i]) + qdf_mem_free(crypto_priv->key[i]); + } + + if (crypto_priv->igtk_key) + qdf_mem_free(crypto_priv->igtk_key); + +} + +static QDF_STATUS wlan_crypto_vdev_obj_destroy_handler( + struct wlan_objmgr_vdev *vdev, + void *arg){ + struct wlan_crypto_comp_priv *crypto_priv; + + crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_vdev_crypto_obj(vdev); + + wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_CRYPTO, + (void *)crypto_priv); + wlan_crypto_free_key(crypto_priv); + qdf_mem_free(crypto_priv); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wlan_crypto_peer_obj_destroy_handler( + struct wlan_objmgr_peer *peer, + void *arg){ + struct wlan_crypto_comp_priv *crypto_priv; + + crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_peer_crypto_obj(peer); + + wlan_objmgr_peer_component_obj_detach(peer, + WLAN_UMAC_COMP_CRYPTO, + (void *)crypto_priv); + wlan_crypto_free_key(crypto_priv); + qdf_mem_free(crypto_priv); + + return QDF_STATUS_SUCCESS; +} +/** + * wlan_crypto_init - Init the crypto service with object manager + * Called from umac init context. + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS __wlan_crypto_init(void) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_vdev_obj_create_handler, NULL); + if (status != QDF_STATUS_SUCCESS) + goto err_vdev_create; + + status = wlan_objmgr_register_peer_create_handler( + WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_peer_obj_create_handler, NULL); + if (status != QDF_STATUS_SUCCESS) + goto err_peer_create; + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_vdev_obj_destroy_handler, NULL); + if (status != QDF_STATUS_SUCCESS) + goto err_vdev_delete; + + status = wlan_objmgr_register_peer_destroy_handler( + WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_peer_obj_destroy_handler, NULL); + if (status != QDF_STATUS_SUCCESS) + goto err_peer_delete; + + goto register_success; +err_peer_delete: + wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_vdev_obj_destroy_handler, NULL); +err_vdev_delete: + wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_peer_obj_create_handler, NULL); +err_peer_create: + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_vdev_obj_create_handler, NULL); +err_vdev_create: + wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_pdev_obj_create_handler, NULL); +register_success: + return status; +} + +/** + * wlan_crypto_deinit - Deinit the crypto service with object manager + * Called from umac deinit context. + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS __wlan_crypto_deinit(void) +{ + + if (wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_vdev_obj_create_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + + if (wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_peer_obj_create_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + + if (wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_vdev_obj_destroy_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + + if (wlan_objmgr_unregister_peer_destroy_handler(WLAN_UMAC_COMP_CRYPTO, + wlan_crypto_peer_obj_destroy_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr_i.h b/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr_i.h new file mode 100644 index 000000000000..aa28062ebbfe --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr_i.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public API intialization of crypto service with object manager + */ + +#ifndef __WLAN_CRYPTO_OBJ_MGR_I_ +#define __WLAN_CRYPTO_OBJ_MGR_I_ + + +static inline void *wlan_get_vdev_crypto_obj(struct wlan_objmgr_vdev *vdev) +{ + void *crypto_priv; + wlan_vdev_obj_lock(vdev); + crypto_priv = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_CRYPTO); + wlan_vdev_obj_unlock(vdev); + + return crypto_priv; +} + +static inline void *wlan_get_peer_crypto_obj(struct wlan_objmgr_peer *peer) +{ + void *crypto_priv; + wlan_peer_obj_lock(peer); + crypto_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_CRYPTO); + wlan_peer_obj_unlock(peer); + + return crypto_priv; +} +#endif /* end of __WLAN_CRYPTO_OBJ_MGR_I_*/ diff --git a/umac/cmn_services/crypto/src/wlan_crypto_param_handling.c b/umac/cmn_services/crypto/src/wlan_crypto_param_handling.c new file mode 100644 index 000000000000..018dd1792e32 --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_param_handling.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public APIs for crypto service + */ +/* include files */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "wlan_crypto_global_def.h" +#include "wlan_crypto_global_api.h" +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_param_handling_i.h" + +static uint32_t +cipher2cap(int cipher) +{ + switch (cipher) { + case WLAN_CRYPTO_CIPHER_WEP: return WLAN_CRYPTO_CAP_WEP; + case WLAN_CRYPTO_CIPHER_AES_OCB: return WLAN_CRYPTO_CAP_AES; + case WLAN_CRYPTO_CIPHER_AES_CCM: return WLAN_CRYPTO_CAP_AES; + case WLAN_CRYPTO_CIPHER_AES_CCM_256: return WLAN_CRYPTO_CAP_AES; + case WLAN_CRYPTO_CIPHER_AES_GCM: return WLAN_CRYPTO_CAP_AES; + case WLAN_CRYPTO_CIPHER_AES_GCM_256: return WLAN_CRYPTO_CAP_AES; + case WLAN_CRYPTO_CIPHER_CKIP: return WLAN_CRYPTO_CAP_CKIP; + case WLAN_CRYPTO_CIPHER_TKIP: return WLAN_CRYPTO_CAP_TKIP_MIC; + case WLAN_CRYPTO_CIPHER_WAPI_SMS4: return WLAN_CRYPTO_CAP_WAPI_SMS4; + case WLAN_CRYPTO_CIPHER_WAPI_GCM4: return WLAN_CRYPTO_CAP_WAPI_GCM4; + } + return 0; +} + +/** + * wlan_crypto_set_authmode - called by ucfg to configure authmode for vdev + * + * @vdev: vdev + * @authmode: authmode + * + * This function gets called from ucfg to configure authmode for vdev. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_authmode(struct wlan_crypto_params *crypto_params, + uint32_t authmode){ + crypto_params->authmodeset = authmode; + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_get_authmode - called by ucfg to get authmode of particular vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get authmode of particular vdev + * + * Return: authmode + */ +int32_t wlan_crypto_get_authmode(struct wlan_crypto_params *crypto_params) +{ + return crypto_params->authmodeset; +} + +/** + * wlan_crypto_set_mcastcipher - called by ucfg to configure mcastcipher in vdev + * + * @vdev: vdev + * @wlan_crypto_cipher_type: mcast cipher value. + * + * This function gets called from ucfg to configure mcastcipher in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_mcastcipher(struct wlan_crypto_params *crypto_params, + wlan_crypto_cipher_type cipher){ + uint16_t i; + uint32_t cap; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + RESET_MCAST_CIPHERS(crypto_params); + + for (i = 0; i < WLAN_CRYPTO_CIPHER_MAX; i++) { + if (HAS_PARAM(cipher, i)) { + cap = cipher2cap(cipher & i); + if (cap && HAS_CIPHER_CAP(crypto_params, cap)) { + SET_MCAST_CIPHER(crypto_params, i); + status = QDF_STATUS_SUCCESS; + } + } + CLEAR_PARAM(cipher, i); + } + return status; +} +/** + * wlan_crypto_get_mcastcipher - called by ucfg to get mcastcipher from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get mcastcipher of particular vdev + * + * Return: mcast cipher + */ +int32_t wlan_crypto_get_mcastcipher(struct wlan_crypto_params *crypto_params) +{ + return crypto_params->mcastcipherset; +} + +/** + * wlan_crypto_set_ucastciphers - called by ucfg to configure + * unicast ciphers in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_ucastciphers( + struct wlan_crypto_params *crypto_params, + uint32_t cipher){ + uint16_t i; + uint32_t cap; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + RESET_UCAST_CIPHERS(crypto_params); + + for (i = 0; i < WLAN_CRYPTO_CIPHER_MAX ; i++) { + if (HAS_PARAM(cipher, i)) { + cap = cipher2cap(cipher & i); + if (cap && HAS_CIPHER_CAP(crypto_params, cap)) { + SET_UCAST_CIPHER(crypto_params, i); + status = QDF_STATUS_SUCCESS; + } + } + CLEAR_PARAM(cipher, i); + } + return status; +} + +/** + * wlan_crypto_get_ucastciphers - called by ucfg to get ucastcipher from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_ucastciphers(struct wlan_crypto_params *crypto_params) +{ + return crypto_params->ucastcipherset; +} + +/** + * wlan_crypto_set_mgmtcipher - called by ucfg to configure + * mgmt ciphers in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_mgmtcipher( + struct wlan_crypto_params *crypto_params, + uint32_t value){ + + if (HAS_CIPHER_CAP(crypto_params, WLAN_CRYPTO_CAP_PMF) || + HAS_CIPHER_CAP(crypto_params, WLAN_CRYPTO_CAP_PMF_OFFLOAD)) { + SET_MGMT_CIPHER(crypto_params, value); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_INVAL; +} + +/** + * wlan_crypto_get_mgmtciphers - called by ucfg to get mgmtcipher from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_mgmtciphers(struct wlan_crypto_params *crypto_params) +{ + return crypto_params->mgmtcipherset; +} + +/** + * wlan_crypto_set_cipher_cap - called by ucfg to configure + * cipher cap in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_cipher_cap( + struct wlan_crypto_params *crypto_params, + uint32_t value){ + crypto_params->cipher_caps = value; + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_get_cipher_cap - called by ucfg to get cipher caps from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_cipher_cap(struct wlan_crypto_params *crypto_params) +{ + return crypto_params->cipher_caps; +} + +/** + * wlan_crypto_set_rsn_cap - called by ucfg to configure + * cipher cap in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_rsn_cap( + struct wlan_crypto_params *crypto_params, + uint32_t value){ + crypto_params->rsn_caps = value; + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_get_rsn_cap - called by ucfg to get rsn caps from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_rsn_cap(struct wlan_crypto_params *crypto_params) +{ + return crypto_params->rsn_caps; +} + + +/** + * wlan_crypto_set_key_mgmt - called by ucfg to configure + * key_mgmt in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_key_mgmt( + struct wlan_crypto_params *crypto_params, + uint32_t value){ + crypto_params->key_mgmt = value; + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_crypto_get_key_mgmt - called by ucfg to get key mgmt from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_key_mgmt(struct wlan_crypto_params *crypto_params) +{ + return crypto_params->key_mgmt; +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_param_handling_i.h b/umac/cmn_services/crypto/src/wlan_crypto_param_handling_i.h new file mode 100644 index 000000000000..010e2ab80eeb --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_param_handling_i.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public APIs for crypto service + */ +/* include files */ +#ifndef __WLAN_CRYPTO_PARAM_HANDLING_I_H_ +#define __WLAN_CRYPTO_PARAM_HANDLING_I_H_ +/** + * wlan_crypto_set_authmode - called by ucfg to configure authmode for vdev + * + * @vdev: vdev + * @authmode: authmode + * + * This function gets called from ucfg to configure authmode for vdev. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_authmode(struct wlan_crypto_params *crypto_params, + uint32_t authmode); + +/** + * wlan_crypto_get_authmode - called by ucfg to get authmode of particular vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get authmode of particular vdev + * + * Return: authmode + */ +int32_t wlan_crypto_get_authmode(struct wlan_crypto_params *crypto_params); + +/** + * wlan_crypto_set_mcastcipher - called by ucfg to configure mcastcipher in vdev + * + * @vdev: vdev + * @wlan_crypto_cipher_type: mcast cipher value. + * + * This function gets called from ucfg to configure mcastcipher in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_mcastcipher(struct wlan_crypto_params *crypto_params, + wlan_crypto_cipher_type cipher); +/** + * wlan_crypto_get_mcastcipher - called by ucfg to get mcastcipher from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get mcastcipher of particular vdev + * + * Return: mcast cipher + */ +int32_t wlan_crypto_get_mcastcipher(struct wlan_crypto_params *crypto_params); + +/** + * wlan_crypto_set_ucastciphers - called by ucfg to configure + * unicast ciphers in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_ucastciphers(struct wlan_crypto_params *, + uint32_t ciphers); +/** + * wlan_crypto_get_ucastciphers - called by ucfg to get ucastcipher from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_ucastciphers(struct wlan_crypto_params *crypto_params); + +/** + * wlan_crypto_set_mgmtcipher - called by ucfg to configure + * mgmt ciphers in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_mgmtcipher(struct wlan_crypto_params *crypto_params, + uint32_t ciphers); + +/** + * wlan_crypto_get_mgmtciphers - called by ucfg to get mgmtcipher from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_mgmtciphers(struct wlan_crypto_params *crypto_params); + +/** + * wlan_crypto_set_cipher_cap - called by ucfg to configure + * cipher cap in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_cipher_cap(struct wlan_crypto_params *crypto_params, + uint32_t ciphers); + +/** + * wlan_crypto_get_cipher_cap - called by ucfg to get cipher caps from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_cipher_cap(struct wlan_crypto_params *crypto_params); + +/** + * wlan_crypto_set_rsn_cap - called by ucfg to configure + * cipher cap in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_rsn_cap(struct wlan_crypto_params *crypto_params, + uint32_t ciphers); + +/** + * wlan_crypto_get_rsn_cap - called by ucfg to get rsn caps from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_rsn_cap(struct wlan_crypto_params *crypto_params); + + +/** + * wlan_crypto_set_key_mgmt - called by ucfg to configure + * key_mgmt in vdev + * + * @vdev: vdev + * @ciphers: bitmap value of all supported unicast ciphers + * + * This function gets called from ucfg to configure unicast ciphers in vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_key_mgmt(struct wlan_crypto_params *crypto_params, + uint32_t ciphers); + +/** + * wlan_crypto_get_key_mgmt - called by ucfg to get key mgmt from vdev + * + * @vdev: vdev + * + * This function gets called from ucfg to get supported unicast ciphers + * + * Return: bitmap value of all supported unicast ciphers + */ +int32_t wlan_crypto_get_key_mgmt(struct wlan_crypto_params *crypto_params); +#endif /* __WLAN_CRYPTO_PARAM_HANDLING_I_H_ */ diff --git a/umac/cmn_services/crypto/src/wlan_crypto_tkip.c b/umac/cmn_services/crypto/src/wlan_crypto_tkip.c new file mode 100644 index 000000000000..ee41f87eacc4 --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_tkip.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public API intialization of crypto service with object manager + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wlan_crypto_global_def.h" +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_main_i.h" +#include "wlan_crypto_obj_mgr_i.h" +#include "wlan_crypto_tkip_i.h" + + +static QDF_STATUS tkip_enmic(struct wlan_crypto_key *key, qdf_nbuf_t wbuf, + uint8_t encapdone, uint8_t hdrlen); +static QDF_STATUS tkip_demic(struct wlan_crypto_key *key, qdf_nbuf_t wbuf, + uint8_t tid, uint8_t hdrlen); + + +static QDF_STATUS tkip_setkey(struct wlan_crypto_key *key) +{ + struct wlan_crypto_tkip_ctx *ctx; + + if (key->private == NULL) { + key->private = qdf_mem_malloc( + sizeof(struct wlan_crypto_tkip_ctx)); + if (key->private == NULL) + return QDF_STATUS_E_NOMEM; + } + + ctx = key->private; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS tkip_encap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t encapdone, + uint8_t hdrlen){ + uint8_t *ivp; + struct ieee80211_frame *wh; + qdf_nbuf_t wbuf0; + uint16_t pktlen; + struct wlan_crypto_cipher *cipher_table; + + cipher_table = key->cipher_table; + wh = (struct ieee80211_frame *)qdf_nbuf_data(wbuf); + + /* + * Copy down 802.11 header and add the IV, KeyID, and ExtIV. + */ + if (encapdone) { + ivp = (uint8_t *)qdf_nbuf_data(wbuf); + } else { + ivp = (uint8_t *)qdf_nbuf_push_head(wbuf, cipher_table->header); + qdf_mem_move(ivp, (ivp + cipher_table->header), hdrlen); + wh = (struct ieee80211_frame *) qdf_nbuf_data(wbuf); + } + + ivp += hdrlen; + key->keytsc++; /* XXX wrap at 48 bits */ + + ivp[0] = key->keytsc >> 8; /* TSC1 */ + ivp[1] = (ivp[0] | 0x20) & 0x7f; /* WEP seed */ + ivp[2] = key->keytsc >> 0; /* TSC0*/ + ivp[3] = key->keyix | WLAN_CRYPTO_EXT_IV_BIT; /* KeyID | ExtID */ + ivp[4] = key->keytsc >> 16; /* PN2 */ + ivp[5] = key->keytsc >> 24; /* PN3 */ + ivp[6] = key->keytsc >> 32; /* PN4 */ + ivp[7] = key->keytsc >> 40; /* PN5 */ + + wbuf0 = wbuf; + pktlen = qdf_nbuf_len(wbuf); + while (qdf_nbuf_queue_next(wbuf0) != NULL) { + wbuf = qdf_nbuf_queue_next(wbuf0); + pktlen += qdf_nbuf_len(wbuf0); + } + + /* + * Finally, do software encrypt if neeed. + */ + if (key->flags & WLAN_CRYPTO_KEY_SWENCRYPT) { + /*if not frag frame then do mic calculation */ + if (tkip_enmic(key, wbuf, encapdone, hdrlen) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_CRYPTO_ENCRYPT_FAILED; + } + if (!wlan_crypto_tkip_encrypt(key, wbuf, hdrlen)) + return QDF_STATUS_CRYPTO_ENCRYPT_FAILED; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS tkip_decap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + struct ieee80211_frame *wh; + uint8_t *ivp, *origHdr; + uint64_t pn; + struct wlan_crypto_cipher *cipher_table; + + cipher_table = key->cipher_table; + + /* + * Header should have extended IV and sequence number; + * verify the former and validate the latter. + */ + origHdr = (uint8_t *)qdf_nbuf_data(wbuf); + wh = (struct ieee80211_frame *)origHdr; + + ivp = origHdr + hdrlen; + + if ((ivp[WLAN_CRYPTO_IV_LEN] & WLAN_CRYPTO_EXT_IV_BIT) == 0) + return 0; + + tid = 16; /* non QoS*/ + if ((((wh)->i_fc[0] & (0x0c | 0x80)) == (0x00 | 0x80))) { + if ((wh->i_fc[1] & 0x03) == 0x03) { + tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] + & 0x0f; + } else { + tid = ((struct ieee80211_qosframe *)wh)->i_qos[0] + & 0x0f; + } + } + + /* NB: assume IEEEE80211_WEP_MINLEN covers the extended IV */ + pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); + + if (pn <= key->keyrsc[tid]) { + /* Replay violation.*/ + return 0; + } + + if ((key->flags & WLAN_CRYPTO_KEY_SWDECRYPT)) { + if (!wlan_crypto_tkip_decrypt(key, wbuf, hdrlen) == 0) + return QDF_STATUS_CRYPTO_DECRYPT_FAILED; + } + /* PN will be updated in tkip_demic*/ + + /* + * Copy up 802.11 header and strip crypto bits. + */ + qdf_mem_move(origHdr + cipher_table->header, origHdr, hdrlen); + + qdf_nbuf_pull_head(wbuf, cipher_table->header); + while (qdf_nbuf_queue_next(wbuf) != NULL) + wbuf = qdf_nbuf_queue_next(wbuf); + qdf_nbuf_trim_tail(wbuf, cipher_table->trailer); + + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS tkip_enmic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t encapdone, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS tkip_demic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} + +const struct wlan_crypto_cipher tkip_cipher_table = { + "TKIP", + WLAN_CRYPTO_CIPHER_TKIP, + WLAN_CRYPTO_IV_LEN + WLAN_CRYPTO_KEYID_LEN, + WLAN_CRYPTO_CRC_LEN, + WLAN_CRYPTO_MIC_LEN, + 256, + tkip_setkey, + tkip_encap, + tkip_decap, + tkip_enmic, + tkip_demic, +}; + +const struct wlan_crypto_cipher *tkip_register(void){ + return &tkip_cipher_table; +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_wapi.c b/umac/cmn_services/crypto/src/wlan_crypto_wapi.c new file mode 100644 index 000000000000..20f0fa178453 --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_wapi.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public API intialization of crypto service with object manager + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wlan_crypto_global_def.h" +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_main_i.h" +#include "wlan_crypto_obj_mgr_i.h" + + +static QDF_STATUS wapi_setkey(struct wlan_crypto_key *key) +{ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS wapi_encap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t encapdone, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS wapi_decap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS wapi_enmic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t encapdone, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS wapi_demic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + return QDF_STATUS_SUCCESS; +} + +const struct wlan_crypto_cipher wapi_cipher_table = { + "WPI_SMS4", + WLAN_CRYPTO_CIPHER_WAPI_SMS4, + WLAN_CRYPTO_WPI_SMS4_IVLEN + WLAN_CRYPTO_WPI_SMS4_KIDLEN + + WLAN_CRYPTO_WPI_SMS4_PADLEN, + WLAN_CRYPTO_WPI_SMS4_MICLEN, + 0, + 256, + wapi_setkey, + wapi_encap, + wapi_decap, + wapi_enmic, + wapi_demic, +}; + +const struct wlan_crypto_cipher *wapi_register(void){ + return &wapi_cipher_table; +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_wep.c b/umac/cmn_services/crypto/src/wlan_crypto_wep.c new file mode 100644 index 000000000000..f2d95aa4408c --- /dev/null +++ b/umac/cmn_services/crypto/src/wlan_crypto_wep.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + /** + * DOC: Public API intialization of crypto service with object manager + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wlan_crypto_global_def.h" +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_main_i.h" +#include "wlan_crypto_obj_mgr_i.h" + +#include "wlan_crypto_rijndael.h" +#include "wlan_crypto_tkip_i.h" + + +static QDF_STATUS wep_setkey(struct wlan_crypto_key *key) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wep_encap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t encapdone, + uint8_t hdrlen) +{ + uint8_t *ivp; + struct ieee80211_frame *wh; + struct wlan_crypto_cipher *cipher_table; + uint16_t off, data_len; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(wbuf); + cipher_table = key->cipher_table; + /* + * Copy down 802.11 header and add the IV, KeyID, and ExtIV. + */ + + if (encapdone) { + ivp = (uint8_t *)qdf_nbuf_data(wbuf); + } else { + ivp = (uint8_t *)qdf_nbuf_push_head(wbuf, + cipher_table->header); + memmove(ivp, ivp + cipher_table->header, hdrlen); + /* recompute wh */ + wh = (struct ieee80211_frame *) qdf_nbuf_data(wbuf); + } + + ivp += hdrlen; + +#if _BYTE_ORDER == _BIG_ENDIAN + ivp[2] = key->keyrsc[0] >> 0; + ivp[1] = key->keyrsc[0] >> 8; + ivp[0] = key->keyrsc[0] >> 16; +#else + ivp[0] = key->keyrsc[0] >> 0; + ivp[1] = key->keyrsc[0] >> 8; + ivp[2] = key->keyrsc[0] >> 16; +#endif + ivp[3] = key->keyix; + + /* + * Finally, do software encrypt if neeed. + */ + off = hdrlen + cipher_table->header; + data_len = qdf_nbuf_len(wbuf) - off; + if ((key->flags & WLAN_CRYPTO_KEY_SWENCRYPT) && + !wlan_crypto_wep_encrypt(key->keyval, wbuf, off, data_len)) { + return QDF_STATUS_CRYPTO_ENCRYPT_FAILED; + } + + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS wep_decap(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen) +{ + struct ieee80211_frame *wh; + struct wlan_crypto_cipher *cipher_table; + uint8_t *origHdr = (uint8_t *)qdf_nbuf_data(wbuf); + uint16_t off, data_len; + + wh = (struct ieee80211_frame *)origHdr; + cipher_table = key->cipher_table; + + /* + * Check if the device handled the decrypt in hardware. + * If so we just strip the header; otherwise we need to + * handle the decrypt in software. + */ + + off = hdrlen + cipher_table->header; + data_len = qdf_nbuf_len(wbuf) - off - cipher_table->trailer; + if ((key->flags & WLAN_CRYPTO_KEY_SWDECRYPT) && + !wlan_crypto_wep_decrypt(key->keyval, wbuf, off, data_len)) { + return 0; + } + /* + * Copy up 802.11 header and strip crypto bits. + */ + qdf_mem_move(origHdr + cipher_table->header, origHdr, hdrlen); + qdf_nbuf_pull_head(wbuf, cipher_table->header); + qdf_nbuf_trim_tail(wbuf, cipher_table->trailer); + + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS wep_enmic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + + return QDF_STATUS_SUCCESS; +} +static QDF_STATUS wep_demic(struct wlan_crypto_key *key, + qdf_nbuf_t wbuf, + uint8_t tid, + uint8_t hdrlen){ + + return QDF_STATUS_SUCCESS; +} + +const struct wlan_crypto_cipher wep_cipher_table = { + "WEP", + WLAN_CRYPTO_CIPHER_WEP, + WLAN_CRYPTO_IV_LEN + WLAN_CRYPTO_KEYID_LEN, + WLAN_CRYPTO_CRC_LEN, + 0, + 152, + wep_setkey, + wep_encap, + wep_decap, + wep_enmic, + wep_demic, +}; + +const struct wlan_crypto_cipher *wep_register(void){ + return &wep_cipher_table; +} +