18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2002-2004, Instant802 Networks, Inc. 48c2ecf20Sopenharmony_ci * Copyright 2008, Jouni Malinen <j@w1.fi> 58c2ecf20Sopenharmony_ci * Copyright (C) 2016-2017 Intel Deutschland GmbH 68c2ecf20Sopenharmony_ci * Copyright (C) 2020-2021 Intel Corporation 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 128c2ecf20Sopenharmony_ci#include <linux/compiler.h> 138c2ecf20Sopenharmony_ci#include <linux/ieee80211.h> 148c2ecf20Sopenharmony_ci#include <linux/gfp.h> 158c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 168c2ecf20Sopenharmony_ci#include <net/mac80211.h> 178c2ecf20Sopenharmony_ci#include <crypto/aes.h> 188c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "ieee80211_i.h" 218c2ecf20Sopenharmony_ci#include "michael.h" 228c2ecf20Sopenharmony_ci#include "tkip.h" 238c2ecf20Sopenharmony_ci#include "aes_ccm.h" 248c2ecf20Sopenharmony_ci#include "aes_cmac.h" 258c2ecf20Sopenharmony_ci#include "aes_gmac.h" 268c2ecf20Sopenharmony_ci#include "aes_gcm.h" 278c2ecf20Sopenharmony_ci#include "wpa.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciieee80211_tx_result 308c2ecf20Sopenharmony_ciieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci u8 *data, *key, *mic; 338c2ecf20Sopenharmony_ci size_t data_len; 348c2ecf20Sopenharmony_ci unsigned int hdrlen; 358c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 368c2ecf20Sopenharmony_ci struct sk_buff *skb = tx->skb; 378c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 388c2ecf20Sopenharmony_ci int tail; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 418c2ecf20Sopenharmony_ci if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || 428c2ecf20Sopenharmony_ci skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control)) 438c2ecf20Sopenharmony_ci return TX_CONTINUE; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 468c2ecf20Sopenharmony_ci if (skb->len < hdrlen) 478c2ecf20Sopenharmony_ci return TX_DROP; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci data = skb->data + hdrlen; 508c2ecf20Sopenharmony_ci data_len = skb->len - hdrlen; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) { 538c2ecf20Sopenharmony_ci /* Need to use software crypto for the test */ 548c2ecf20Sopenharmony_ci info->control.hw_key = NULL; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (info->control.hw_key && 588c2ecf20Sopenharmony_ci (info->flags & IEEE80211_TX_CTL_DONTFRAG || 598c2ecf20Sopenharmony_ci ieee80211_hw_check(&tx->local->hw, SUPPORTS_TX_FRAG)) && 608c2ecf20Sopenharmony_ci !(tx->key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | 618c2ecf20Sopenharmony_ci IEEE80211_KEY_FLAG_PUT_MIC_SPACE))) { 628c2ecf20Sopenharmony_ci /* hwaccel - with no need for SW-generated MMIC or MIC space */ 638c2ecf20Sopenharmony_ci return TX_CONTINUE; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci tail = MICHAEL_MIC_LEN; 678c2ecf20Sopenharmony_ci if (!info->control.hw_key) 688c2ecf20Sopenharmony_ci tail += IEEE80211_TKIP_ICV_LEN; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (WARN(skb_tailroom(skb) < tail || 718c2ecf20Sopenharmony_ci skb_headroom(skb) < IEEE80211_TKIP_IV_LEN, 728c2ecf20Sopenharmony_ci "mmic: not enough head/tail (%d/%d,%d/%d)\n", 738c2ecf20Sopenharmony_ci skb_headroom(skb), IEEE80211_TKIP_IV_LEN, 748c2ecf20Sopenharmony_ci skb_tailroom(skb), tail)) 758c2ecf20Sopenharmony_ci return TX_DROP; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci mic = skb_put(skb, MICHAEL_MIC_LEN); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (tx->key->conf.flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) { 808c2ecf20Sopenharmony_ci /* Zeroed MIC can help with debug */ 818c2ecf20Sopenharmony_ci memset(mic, 0, MICHAEL_MIC_LEN); 828c2ecf20Sopenharmony_ci return TX_CONTINUE; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]; 868c2ecf20Sopenharmony_ci michael_mic(key, hdr, data, data_len, mic); 878c2ecf20Sopenharmony_ci if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) 888c2ecf20Sopenharmony_ci mic[0]++; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return TX_CONTINUE; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ciieee80211_rx_result 958c2ecf20Sopenharmony_ciieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci u8 *data, *key = NULL; 988c2ecf20Sopenharmony_ci size_t data_len; 998c2ecf20Sopenharmony_ci unsigned int hdrlen; 1008c2ecf20Sopenharmony_ci u8 mic[MICHAEL_MIC_LEN]; 1018c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 1028c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 1038c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * it makes no sense to check for MIC errors on anything other 1078c2ecf20Sopenharmony_ci * than data frames. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci if (!ieee80211_is_data_present(hdr->frame_control)) 1108c2ecf20Sopenharmony_ci return RX_CONTINUE; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* 1138c2ecf20Sopenharmony_ci * No way to verify the MIC if the hardware stripped it or 1148c2ecf20Sopenharmony_ci * the IV with the key index. In this case we have solely rely 1158c2ecf20Sopenharmony_ci * on the driver to set RX_FLAG_MMIC_ERROR in the event of a 1168c2ecf20Sopenharmony_ci * MIC failure report. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ci if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { 1198c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_MMIC_ERROR) 1208c2ecf20Sopenharmony_ci goto mic_fail_no_key; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key && 1238c2ecf20Sopenharmony_ci rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP) 1248c2ecf20Sopenharmony_ci goto update_iv; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return RX_CONTINUE; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * Some hardware seems to generate Michael MIC failure reports; even 1318c2ecf20Sopenharmony_ci * though, the frame was not encrypted with TKIP and therefore has no 1328c2ecf20Sopenharmony_ci * MIC. Ignore the flag them to avoid triggering countermeasures. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || 1358c2ecf20Sopenharmony_ci !(status->flag & RX_FLAG_DECRYPTED)) 1368c2ecf20Sopenharmony_ci return RX_CONTINUE; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) { 1398c2ecf20Sopenharmony_ci /* 1408c2ecf20Sopenharmony_ci * APs with pairwise keys should never receive Michael MIC 1418c2ecf20Sopenharmony_ci * errors for non-zero keyidx because these are reserved for 1428c2ecf20Sopenharmony_ci * group keys and only the AP is sending real multicast 1438c2ecf20Sopenharmony_ci * frames in the BSS. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_MMIC_ERROR) 1498c2ecf20Sopenharmony_ci goto mic_fail; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 1528c2ecf20Sopenharmony_ci if (skb->len < hdrlen + MICHAEL_MIC_LEN) 1538c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (skb_linearize(rx->skb)) 1568c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 1578c2ecf20Sopenharmony_ci hdr = (void *)skb->data; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci data = skb->data + hdrlen; 1608c2ecf20Sopenharmony_ci data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; 1618c2ecf20Sopenharmony_ci key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; 1628c2ecf20Sopenharmony_ci michael_mic(key, hdr, data, data_len, mic); 1638c2ecf20Sopenharmony_ci if (crypto_memneq(mic, data + data_len, MICHAEL_MIC_LEN)) 1648c2ecf20Sopenharmony_ci goto mic_fail; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* remove Michael MIC from payload */ 1678c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - MICHAEL_MIC_LEN); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ciupdate_iv: 1708c2ecf20Sopenharmony_ci /* update IV in key information to be able to detect replays */ 1718c2ecf20Sopenharmony_ci rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip.iv32; 1728c2ecf20Sopenharmony_ci rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip.iv16; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return RX_CONTINUE; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cimic_fail: 1778c2ecf20Sopenharmony_ci rx->key->u.tkip.mic_failures++; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cimic_fail_no_key: 1808c2ecf20Sopenharmony_ci /* 1818c2ecf20Sopenharmony_ci * In some cases the key can be unset - e.g. a multicast packet, in 1828c2ecf20Sopenharmony_ci * a driver that supports HW encryption. Send up the key idx only if 1838c2ecf20Sopenharmony_ci * the key is set. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci cfg80211_michael_mic_failure(rx->sdata->dev, hdr->addr2, 1868c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1) ? 1878c2ecf20Sopenharmony_ci NL80211_KEYTYPE_GROUP : 1888c2ecf20Sopenharmony_ci NL80211_KEYTYPE_PAIRWISE, 1898c2ecf20Sopenharmony_ci rx->key ? rx->key->conf.keyidx : -1, 1908c2ecf20Sopenharmony_ci NULL, GFP_ATOMIC); 1918c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1978c2ecf20Sopenharmony_ci struct ieee80211_key *key = tx->key; 1988c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1998c2ecf20Sopenharmony_ci unsigned int hdrlen; 2008c2ecf20Sopenharmony_ci int len, tail; 2018c2ecf20Sopenharmony_ci u64 pn; 2028c2ecf20Sopenharmony_ci u8 *pos; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (info->control.hw_key && 2058c2ecf20Sopenharmony_ci !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && 2068c2ecf20Sopenharmony_ci !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { 2078c2ecf20Sopenharmony_ci /* hwaccel - with no need for software-generated IV */ 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 2128c2ecf20Sopenharmony_ci len = skb->len - hdrlen; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (info->control.hw_key) 2158c2ecf20Sopenharmony_ci tail = 0; 2168c2ecf20Sopenharmony_ci else 2178c2ecf20Sopenharmony_ci tail = IEEE80211_TKIP_ICV_LEN; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (WARN_ON(skb_tailroom(skb) < tail || 2208c2ecf20Sopenharmony_ci skb_headroom(skb) < IEEE80211_TKIP_IV_LEN)) 2218c2ecf20Sopenharmony_ci return -1; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); 2248c2ecf20Sopenharmony_ci memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); 2258c2ecf20Sopenharmony_ci pos += hdrlen; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* the HW only needs room for the IV, but not the actual IV */ 2288c2ecf20Sopenharmony_ci if (info->control.hw_key && 2298c2ecf20Sopenharmony_ci (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Increase IV for the frame */ 2338c2ecf20Sopenharmony_ci pn = atomic64_inc_return(&key->conf.tx_pn); 2348c2ecf20Sopenharmony_ci pos = ieee80211_tkip_add_iv(pos, &key->conf, pn); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* hwaccel - with software IV */ 2378c2ecf20Sopenharmony_ci if (info->control.hw_key) 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Add room for ICV */ 2418c2ecf20Sopenharmony_ci skb_put(skb, IEEE80211_TKIP_ICV_LEN); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return ieee80211_tkip_encrypt_data(&tx->local->wep_tx_ctx, 2448c2ecf20Sopenharmony_ci key, skb, pos, len); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ciieee80211_tx_result 2498c2ecf20Sopenharmony_ciieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct sk_buff *skb; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ieee80211_tx_set_protected(tx); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci skb_queue_walk(&tx->skbs, skb) { 2568c2ecf20Sopenharmony_ci if (tkip_encrypt_skb(tx, skb) < 0) 2578c2ecf20Sopenharmony_ci return TX_DROP; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return TX_CONTINUE; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciieee80211_rx_result 2658c2ecf20Sopenharmony_ciieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; 2688c2ecf20Sopenharmony_ci int hdrlen, res, hwaccel = 0; 2698c2ecf20Sopenharmony_ci struct ieee80211_key *key = rx->key; 2708c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 2718c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control)) 2768c2ecf20Sopenharmony_ci return RX_CONTINUE; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!rx->sta || skb->len - hdrlen < 12) 2798c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* it may be possible to optimize this a bit more */ 2828c2ecf20Sopenharmony_ci if (skb_linearize(rx->skb)) 2838c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 2848c2ecf20Sopenharmony_ci hdr = (void *)skb->data; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Let TKIP code verify IV, but skip decryption. 2888c2ecf20Sopenharmony_ci * In the case where hardware checks the IV as well, 2898c2ecf20Sopenharmony_ci * we don't even get here, see ieee80211_rx_h_decrypt() 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) 2928c2ecf20Sopenharmony_ci hwaccel = 1; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci res = ieee80211_tkip_decrypt_data(&rx->local->wep_rx_ctx, 2958c2ecf20Sopenharmony_ci key, skb->data + hdrlen, 2968c2ecf20Sopenharmony_ci skb->len - hdrlen, rx->sta->sta.addr, 2978c2ecf20Sopenharmony_ci hdr->addr1, hwaccel, rx->security_idx, 2988c2ecf20Sopenharmony_ci &rx->tkip.iv32, 2998c2ecf20Sopenharmony_ci &rx->tkip.iv16); 3008c2ecf20Sopenharmony_ci if (res != TKIP_DECRYPT_OK) 3018c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Trim ICV */ 3048c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_ICV_STRIPPED)) 3058c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* Remove IV */ 3088c2ecf20Sopenharmony_ci memmove(skb->data + IEEE80211_TKIP_IV_LEN, skb->data, hdrlen); 3098c2ecf20Sopenharmony_ci skb_pull(skb, IEEE80211_TKIP_IV_LEN); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return RX_CONTINUE; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci __le16 mask_fc; 3188c2ecf20Sopenharmony_ci int a4_included, mgmt; 3198c2ecf20Sopenharmony_ci u8 qos_tid; 3208c2ecf20Sopenharmony_ci u16 len_a; 3218c2ecf20Sopenharmony_ci unsigned int hdrlen; 3228c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* 3258c2ecf20Sopenharmony_ci * Mask FC: zero subtype b4 b5 b6 (if not mgmt) 3268c2ecf20Sopenharmony_ci * Retry, PwrMgt, MoreData; set Protected 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci mgmt = ieee80211_is_mgmt(hdr->frame_control); 3298c2ecf20Sopenharmony_ci mask_fc = hdr->frame_control; 3308c2ecf20Sopenharmony_ci mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | 3318c2ecf20Sopenharmony_ci IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); 3328c2ecf20Sopenharmony_ci if (!mgmt) 3338c2ecf20Sopenharmony_ci mask_fc &= ~cpu_to_le16(0x0070); 3348c2ecf20Sopenharmony_ci mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 3378c2ecf20Sopenharmony_ci len_a = hdrlen - 2; 3388c2ecf20Sopenharmony_ci a4_included = ieee80211_has_a4(hdr->frame_control); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 3418c2ecf20Sopenharmony_ci qos_tid = ieee80211_get_tid(hdr); 3428c2ecf20Sopenharmony_ci else 3438c2ecf20Sopenharmony_ci qos_tid = 0; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC 3468c2ecf20Sopenharmony_ci * mode authentication are not allowed to collide, yet both are derived 3478c2ecf20Sopenharmony_ci * from this vector b_0. We only set L := 1 here to indicate that the 3488c2ecf20Sopenharmony_ci * data size can be represented in (L+1) bytes. The CCM layer will take 3498c2ecf20Sopenharmony_ci * care of storing the data length in the top (L+1) bytes and setting 3508c2ecf20Sopenharmony_ci * and clearing the other bits as is required to derive the two IVs. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci b_0[0] = 0x1; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* Nonce: Nonce Flags | A2 | PN 3558c2ecf20Sopenharmony_ci * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7) 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci b_0[1] = qos_tid | (mgmt << 4); 3588c2ecf20Sopenharmony_ci memcpy(&b_0[2], hdr->addr2, ETH_ALEN); 3598c2ecf20Sopenharmony_ci memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* AAD (extra authenticate-only data) / masked 802.11 header 3628c2ecf20Sopenharmony_ci * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ 3638c2ecf20Sopenharmony_ci put_unaligned_be16(len_a, &aad[0]); 3648c2ecf20Sopenharmony_ci put_unaligned(mask_fc, (__le16 *)&aad[2]); 3658c2ecf20Sopenharmony_ci memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Mask Seq#, leave Frag# */ 3688c2ecf20Sopenharmony_ci aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f; 3698c2ecf20Sopenharmony_ci aad[23] = 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (a4_included) { 3728c2ecf20Sopenharmony_ci memcpy(&aad[24], hdr->addr4, ETH_ALEN); 3738c2ecf20Sopenharmony_ci aad[30] = qos_tid; 3748c2ecf20Sopenharmony_ci aad[31] = 0; 3758c2ecf20Sopenharmony_ci } else { 3768c2ecf20Sopenharmony_ci memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN); 3778c2ecf20Sopenharmony_ci aad[24] = qos_tid; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci hdr[0] = pn[5]; 3858c2ecf20Sopenharmony_ci hdr[1] = pn[4]; 3868c2ecf20Sopenharmony_ci hdr[2] = 0; 3878c2ecf20Sopenharmony_ci hdr[3] = 0x20 | (key_id << 6); 3888c2ecf20Sopenharmony_ci hdr[4] = pn[3]; 3898c2ecf20Sopenharmony_ci hdr[5] = pn[2]; 3908c2ecf20Sopenharmony_ci hdr[6] = pn[1]; 3918c2ecf20Sopenharmony_ci hdr[7] = pn[0]; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic inline void ccmp_hdr2pn(u8 *pn, u8 *hdr) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci pn[0] = hdr[7]; 3988c2ecf20Sopenharmony_ci pn[1] = hdr[6]; 3998c2ecf20Sopenharmony_ci pn[2] = hdr[5]; 4008c2ecf20Sopenharmony_ci pn[3] = hdr[4]; 4018c2ecf20Sopenharmony_ci pn[4] = hdr[1]; 4028c2ecf20Sopenharmony_ci pn[5] = hdr[0]; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb, 4078c2ecf20Sopenharmony_ci unsigned int mic_len) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 4108c2ecf20Sopenharmony_ci struct ieee80211_key *key = tx->key; 4118c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 4128c2ecf20Sopenharmony_ci int hdrlen, len, tail; 4138c2ecf20Sopenharmony_ci u8 *pos; 4148c2ecf20Sopenharmony_ci u8 pn[6]; 4158c2ecf20Sopenharmony_ci u64 pn64; 4168c2ecf20Sopenharmony_ci u8 aad[CCM_AAD_LEN]; 4178c2ecf20Sopenharmony_ci u8 b_0[AES_BLOCK_SIZE]; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (info->control.hw_key && 4208c2ecf20Sopenharmony_ci !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && 4218c2ecf20Sopenharmony_ci !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && 4228c2ecf20Sopenharmony_ci !((info->control.hw_key->flags & 4238c2ecf20Sopenharmony_ci IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) && 4248c2ecf20Sopenharmony_ci ieee80211_is_mgmt(hdr->frame_control))) { 4258c2ecf20Sopenharmony_ci /* 4268c2ecf20Sopenharmony_ci * hwaccel has no need for preallocated room for CCMP 4278c2ecf20Sopenharmony_ci * header or MIC fields 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 4338c2ecf20Sopenharmony_ci len = skb->len - hdrlen; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (info->control.hw_key) 4368c2ecf20Sopenharmony_ci tail = 0; 4378c2ecf20Sopenharmony_ci else 4388c2ecf20Sopenharmony_ci tail = mic_len; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (WARN_ON(skb_tailroom(skb) < tail || 4418c2ecf20Sopenharmony_ci skb_headroom(skb) < IEEE80211_CCMP_HDR_LEN)) 4428c2ecf20Sopenharmony_ci return -1; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); 4458c2ecf20Sopenharmony_ci memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* the HW only needs room for the IV, but not the actual IV */ 4488c2ecf20Sopenharmony_ci if (info->control.hw_key && 4498c2ecf20Sopenharmony_ci (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) pos; 4538c2ecf20Sopenharmony_ci pos += hdrlen; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci pn64 = atomic64_inc_return(&key->conf.tx_pn); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci pn[5] = pn64; 4588c2ecf20Sopenharmony_ci pn[4] = pn64 >> 8; 4598c2ecf20Sopenharmony_ci pn[3] = pn64 >> 16; 4608c2ecf20Sopenharmony_ci pn[2] = pn64 >> 24; 4618c2ecf20Sopenharmony_ci pn[1] = pn64 >> 32; 4628c2ecf20Sopenharmony_ci pn[0] = pn64 >> 40; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci ccmp_pn2hdr(pos, pn, key->conf.keyidx); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* hwaccel - with software CCMP header */ 4678c2ecf20Sopenharmony_ci if (info->control.hw_key) 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci pos += IEEE80211_CCMP_HDR_LEN; 4718c2ecf20Sopenharmony_ci ccmp_special_blocks(skb, pn, b_0, aad); 4728c2ecf20Sopenharmony_ci return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, 4738c2ecf20Sopenharmony_ci skb_put(skb, mic_len)); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ciieee80211_tx_result 4788c2ecf20Sopenharmony_ciieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx, 4798c2ecf20Sopenharmony_ci unsigned int mic_len) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct sk_buff *skb; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci ieee80211_tx_set_protected(tx); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci skb_queue_walk(&tx->skbs, skb) { 4868c2ecf20Sopenharmony_ci if (ccmp_encrypt_skb(tx, skb, mic_len) < 0) 4878c2ecf20Sopenharmony_ci return TX_DROP; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return TX_CONTINUE; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ciieee80211_rx_result 4958c2ecf20Sopenharmony_ciieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, 4968c2ecf20Sopenharmony_ci unsigned int mic_len) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 4998c2ecf20Sopenharmony_ci int hdrlen; 5008c2ecf20Sopenharmony_ci struct ieee80211_key *key = rx->key; 5018c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 5028c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 5038c2ecf20Sopenharmony_ci u8 pn[IEEE80211_CCMP_PN_LEN]; 5048c2ecf20Sopenharmony_ci int data_len; 5058c2ecf20Sopenharmony_ci int queue; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control) && 5108c2ecf20Sopenharmony_ci !ieee80211_is_robust_mgmt_frame(skb)) 5118c2ecf20Sopenharmony_ci return RX_CONTINUE; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) { 5148c2ecf20Sopenharmony_ci if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_CCMP_HDR_LEN)) 5158c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 5168c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_MIC_STRIPPED) 5178c2ecf20Sopenharmony_ci mic_len = 0; 5188c2ecf20Sopenharmony_ci } else { 5198c2ecf20Sopenharmony_ci if (skb_linearize(rx->skb)) 5208c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* reload hdr - skb might have been reallocated */ 5248c2ecf20Sopenharmony_ci hdr = (void *)rx->skb->data; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - mic_len; 5278c2ecf20Sopenharmony_ci if (!rx->sta || data_len < 0) 5288c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_PN_VALIDATED)) { 5318c2ecf20Sopenharmony_ci int res; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci ccmp_hdr2pn(pn, skb->data + hdrlen); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci queue = rx->security_idx; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci res = memcmp(pn, key->u.ccmp.rx_pn[queue], 5388c2ecf20Sopenharmony_ci IEEE80211_CCMP_PN_LEN); 5398c2ecf20Sopenharmony_ci if (res < 0 || 5408c2ecf20Sopenharmony_ci (!res && !(status->flag & RX_FLAG_ALLOW_SAME_PN))) { 5418c2ecf20Sopenharmony_ci key->u.ccmp.replays++; 5428c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_DECRYPTED)) { 5468c2ecf20Sopenharmony_ci u8 aad[2 * AES_BLOCK_SIZE]; 5478c2ecf20Sopenharmony_ci u8 b_0[AES_BLOCK_SIZE]; 5488c2ecf20Sopenharmony_ci /* hardware didn't decrypt/verify MIC */ 5498c2ecf20Sopenharmony_ci ccmp_special_blocks(skb, pn, b_0, aad); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (ieee80211_aes_ccm_decrypt( 5528c2ecf20Sopenharmony_ci key->u.ccmp.tfm, b_0, aad, 5538c2ecf20Sopenharmony_ci skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN, 5548c2ecf20Sopenharmony_ci data_len, 5558c2ecf20Sopenharmony_ci skb->data + skb->len - mic_len)) 5568c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN); 5608c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_frag(hdr))) 5618c2ecf20Sopenharmony_ci memcpy(rx->ccm_gcm.pn, pn, IEEE80211_CCMP_PN_LEN); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* Remove CCMP header and MIC */ 5658c2ecf20Sopenharmony_ci if (pskb_trim(skb, skb->len - mic_len)) 5668c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 5678c2ecf20Sopenharmony_ci memmove(skb->data + IEEE80211_CCMP_HDR_LEN, skb->data, hdrlen); 5688c2ecf20Sopenharmony_ci skb_pull(skb, IEEE80211_CCMP_HDR_LEN); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return RX_CONTINUE; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci __le16 mask_fc; 5768c2ecf20Sopenharmony_ci u8 qos_tid; 5778c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci memcpy(j_0, hdr->addr2, ETH_ALEN); 5808c2ecf20Sopenharmony_ci memcpy(&j_0[ETH_ALEN], pn, IEEE80211_GCMP_PN_LEN); 5818c2ecf20Sopenharmony_ci j_0[13] = 0; 5828c2ecf20Sopenharmony_ci j_0[14] = 0; 5838c2ecf20Sopenharmony_ci j_0[AES_BLOCK_SIZE - 1] = 0x01; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* AAD (extra authenticate-only data) / masked 802.11 header 5868c2ecf20Sopenharmony_ci * FC | A1 | A2 | A3 | SC | [A4] | [QC] 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci put_unaligned_be16(ieee80211_hdrlen(hdr->frame_control) - 2, &aad[0]); 5898c2ecf20Sopenharmony_ci /* Mask FC: zero subtype b4 b5 b6 (if not mgmt) 5908c2ecf20Sopenharmony_ci * Retry, PwrMgt, MoreData; set Protected 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ci mask_fc = hdr->frame_control; 5938c2ecf20Sopenharmony_ci mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | 5948c2ecf20Sopenharmony_ci IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); 5958c2ecf20Sopenharmony_ci if (!ieee80211_is_mgmt(hdr->frame_control)) 5968c2ecf20Sopenharmony_ci mask_fc &= ~cpu_to_le16(0x0070); 5978c2ecf20Sopenharmony_ci mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci put_unaligned(mask_fc, (__le16 *)&aad[2]); 6008c2ecf20Sopenharmony_ci memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* Mask Seq#, leave Frag# */ 6038c2ecf20Sopenharmony_ci aad[22] = *((u8 *)&hdr->seq_ctrl) & 0x0f; 6048c2ecf20Sopenharmony_ci aad[23] = 0; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 6078c2ecf20Sopenharmony_ci qos_tid = ieee80211_get_tid(hdr); 6088c2ecf20Sopenharmony_ci else 6098c2ecf20Sopenharmony_ci qos_tid = 0; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (ieee80211_has_a4(hdr->frame_control)) { 6128c2ecf20Sopenharmony_ci memcpy(&aad[24], hdr->addr4, ETH_ALEN); 6138c2ecf20Sopenharmony_ci aad[30] = qos_tid; 6148c2ecf20Sopenharmony_ci aad[31] = 0; 6158c2ecf20Sopenharmony_ci } else { 6168c2ecf20Sopenharmony_ci memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN); 6178c2ecf20Sopenharmony_ci aad[24] = qos_tid; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic inline void gcmp_pn2hdr(u8 *hdr, const u8 *pn, int key_id) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci hdr[0] = pn[5]; 6248c2ecf20Sopenharmony_ci hdr[1] = pn[4]; 6258c2ecf20Sopenharmony_ci hdr[2] = 0; 6268c2ecf20Sopenharmony_ci hdr[3] = 0x20 | (key_id << 6); 6278c2ecf20Sopenharmony_ci hdr[4] = pn[3]; 6288c2ecf20Sopenharmony_ci hdr[5] = pn[2]; 6298c2ecf20Sopenharmony_ci hdr[6] = pn[1]; 6308c2ecf20Sopenharmony_ci hdr[7] = pn[0]; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic inline void gcmp_hdr2pn(u8 *pn, const u8 *hdr) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci pn[0] = hdr[7]; 6368c2ecf20Sopenharmony_ci pn[1] = hdr[6]; 6378c2ecf20Sopenharmony_ci pn[2] = hdr[5]; 6388c2ecf20Sopenharmony_ci pn[3] = hdr[4]; 6398c2ecf20Sopenharmony_ci pn[4] = hdr[1]; 6408c2ecf20Sopenharmony_ci pn[5] = hdr[0]; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 6468c2ecf20Sopenharmony_ci struct ieee80211_key *key = tx->key; 6478c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 6488c2ecf20Sopenharmony_ci int hdrlen, len, tail; 6498c2ecf20Sopenharmony_ci u8 *pos; 6508c2ecf20Sopenharmony_ci u8 pn[6]; 6518c2ecf20Sopenharmony_ci u64 pn64; 6528c2ecf20Sopenharmony_ci u8 aad[GCM_AAD_LEN]; 6538c2ecf20Sopenharmony_ci u8 j_0[AES_BLOCK_SIZE]; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (info->control.hw_key && 6568c2ecf20Sopenharmony_ci !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && 6578c2ecf20Sopenharmony_ci !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && 6588c2ecf20Sopenharmony_ci !((info->control.hw_key->flags & 6598c2ecf20Sopenharmony_ci IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) && 6608c2ecf20Sopenharmony_ci ieee80211_is_mgmt(hdr->frame_control))) { 6618c2ecf20Sopenharmony_ci /* hwaccel has no need for preallocated room for GCMP 6628c2ecf20Sopenharmony_ci * header or MIC fields 6638c2ecf20Sopenharmony_ci */ 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 6688c2ecf20Sopenharmony_ci len = skb->len - hdrlen; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (info->control.hw_key) 6718c2ecf20Sopenharmony_ci tail = 0; 6728c2ecf20Sopenharmony_ci else 6738c2ecf20Sopenharmony_ci tail = IEEE80211_GCMP_MIC_LEN; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (WARN_ON(skb_tailroom(skb) < tail || 6768c2ecf20Sopenharmony_ci skb_headroom(skb) < IEEE80211_GCMP_HDR_LEN)) 6778c2ecf20Sopenharmony_ci return -1; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci pos = skb_push(skb, IEEE80211_GCMP_HDR_LEN); 6808c2ecf20Sopenharmony_ci memmove(pos, pos + IEEE80211_GCMP_HDR_LEN, hdrlen); 6818c2ecf20Sopenharmony_ci skb_set_network_header(skb, skb_network_offset(skb) + 6828c2ecf20Sopenharmony_ci IEEE80211_GCMP_HDR_LEN); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* the HW only needs room for the IV, but not the actual IV */ 6858c2ecf20Sopenharmony_ci if (info->control.hw_key && 6868c2ecf20Sopenharmony_ci (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)pos; 6908c2ecf20Sopenharmony_ci pos += hdrlen; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci pn64 = atomic64_inc_return(&key->conf.tx_pn); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci pn[5] = pn64; 6958c2ecf20Sopenharmony_ci pn[4] = pn64 >> 8; 6968c2ecf20Sopenharmony_ci pn[3] = pn64 >> 16; 6978c2ecf20Sopenharmony_ci pn[2] = pn64 >> 24; 6988c2ecf20Sopenharmony_ci pn[1] = pn64 >> 32; 6998c2ecf20Sopenharmony_ci pn[0] = pn64 >> 40; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci gcmp_pn2hdr(pos, pn, key->conf.keyidx); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* hwaccel - with software GCMP header */ 7048c2ecf20Sopenharmony_ci if (info->control.hw_key) 7058c2ecf20Sopenharmony_ci return 0; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci pos += IEEE80211_GCMP_HDR_LEN; 7088c2ecf20Sopenharmony_ci gcmp_special_blocks(skb, pn, j_0, aad); 7098c2ecf20Sopenharmony_ci return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len, 7108c2ecf20Sopenharmony_ci skb_put(skb, IEEE80211_GCMP_MIC_LEN)); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ciieee80211_tx_result 7148c2ecf20Sopenharmony_ciieee80211_crypto_gcmp_encrypt(struct ieee80211_tx_data *tx) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct sk_buff *skb; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ieee80211_tx_set_protected(tx); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci skb_queue_walk(&tx->skbs, skb) { 7218c2ecf20Sopenharmony_ci if (gcmp_encrypt_skb(tx, skb) < 0) 7228c2ecf20Sopenharmony_ci return TX_DROP; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return TX_CONTINUE; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ciieee80211_rx_result 7298c2ecf20Sopenharmony_ciieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 7328c2ecf20Sopenharmony_ci int hdrlen; 7338c2ecf20Sopenharmony_ci struct ieee80211_key *key = rx->key; 7348c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 7358c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 7368c2ecf20Sopenharmony_ci u8 pn[IEEE80211_GCMP_PN_LEN]; 7378c2ecf20Sopenharmony_ci int data_len, queue, mic_len = IEEE80211_GCMP_MIC_LEN; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control) && 7428c2ecf20Sopenharmony_ci !ieee80211_is_robust_mgmt_frame(skb)) 7438c2ecf20Sopenharmony_ci return RX_CONTINUE; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) { 7468c2ecf20Sopenharmony_ci if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_GCMP_HDR_LEN)) 7478c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 7488c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_MIC_STRIPPED) 7498c2ecf20Sopenharmony_ci mic_len = 0; 7508c2ecf20Sopenharmony_ci } else { 7518c2ecf20Sopenharmony_ci if (skb_linearize(rx->skb)) 7528c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* reload hdr - skb might have been reallocated */ 7568c2ecf20Sopenharmony_ci hdr = (void *)rx->skb->data; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci data_len = skb->len - hdrlen - IEEE80211_GCMP_HDR_LEN - mic_len; 7598c2ecf20Sopenharmony_ci if (!rx->sta || data_len < 0) 7608c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_PN_VALIDATED)) { 7638c2ecf20Sopenharmony_ci int res; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci gcmp_hdr2pn(pn, skb->data + hdrlen); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci queue = rx->security_idx; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci res = memcmp(pn, key->u.gcmp.rx_pn[queue], 7708c2ecf20Sopenharmony_ci IEEE80211_GCMP_PN_LEN); 7718c2ecf20Sopenharmony_ci if (res < 0 || 7728c2ecf20Sopenharmony_ci (!res && !(status->flag & RX_FLAG_ALLOW_SAME_PN))) { 7738c2ecf20Sopenharmony_ci key->u.gcmp.replays++; 7748c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_DECRYPTED)) { 7788c2ecf20Sopenharmony_ci u8 aad[2 * AES_BLOCK_SIZE]; 7798c2ecf20Sopenharmony_ci u8 j_0[AES_BLOCK_SIZE]; 7808c2ecf20Sopenharmony_ci /* hardware didn't decrypt/verify MIC */ 7818c2ecf20Sopenharmony_ci gcmp_special_blocks(skb, pn, j_0, aad); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (ieee80211_aes_gcm_decrypt( 7848c2ecf20Sopenharmony_ci key->u.gcmp.tfm, j_0, aad, 7858c2ecf20Sopenharmony_ci skb->data + hdrlen + IEEE80211_GCMP_HDR_LEN, 7868c2ecf20Sopenharmony_ci data_len, 7878c2ecf20Sopenharmony_ci skb->data + skb->len - 7888c2ecf20Sopenharmony_ci IEEE80211_GCMP_MIC_LEN)) 7898c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci memcpy(key->u.gcmp.rx_pn[queue], pn, IEEE80211_GCMP_PN_LEN); 7938c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_frag(hdr))) 7948c2ecf20Sopenharmony_ci memcpy(rx->ccm_gcm.pn, pn, IEEE80211_CCMP_PN_LEN); 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* Remove GCMP header and MIC */ 7988c2ecf20Sopenharmony_ci if (pskb_trim(skb, skb->len - mic_len)) 7998c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 8008c2ecf20Sopenharmony_ci memmove(skb->data + IEEE80211_GCMP_HDR_LEN, skb->data, hdrlen); 8018c2ecf20Sopenharmony_ci skb_pull(skb, IEEE80211_GCMP_HDR_LEN); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return RX_CONTINUE; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic ieee80211_tx_result 8078c2ecf20Sopenharmony_ciieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, 8088c2ecf20Sopenharmony_ci struct sk_buff *skb) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 8118c2ecf20Sopenharmony_ci struct ieee80211_key *key = tx->key; 8128c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 8138c2ecf20Sopenharmony_ci int hdrlen; 8148c2ecf20Sopenharmony_ci u8 *pos, iv_len = key->conf.iv_len; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (info->control.hw_key && 8178c2ecf20Sopenharmony_ci !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { 8188c2ecf20Sopenharmony_ci /* hwaccel has no need for preallocated head room */ 8198c2ecf20Sopenharmony_ci return TX_CONTINUE; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (unlikely(skb_headroom(skb) < iv_len && 8238c2ecf20Sopenharmony_ci pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC))) 8248c2ecf20Sopenharmony_ci return TX_DROP; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci pos = skb_push(skb, iv_len); 8298c2ecf20Sopenharmony_ci memmove(pos, pos + iv_len, hdrlen); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return TX_CONTINUE; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci int i; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* pn is little endian */ 8398c2ecf20Sopenharmony_ci for (i = len - 1; i >= 0; i--) { 8408c2ecf20Sopenharmony_ci if (pn1[i] < pn2[i]) 8418c2ecf20Sopenharmony_ci return -1; 8428c2ecf20Sopenharmony_ci else if (pn1[i] > pn2[i]) 8438c2ecf20Sopenharmony_ci return 1; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic ieee80211_rx_result 8508c2ecf20Sopenharmony_ciieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci struct ieee80211_key *key = rx->key; 8538c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 8548c2ecf20Sopenharmony_ci const struct ieee80211_cipher_scheme *cs = NULL; 8558c2ecf20Sopenharmony_ci int hdrlen = ieee80211_hdrlen(hdr->frame_control); 8568c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 8578c2ecf20Sopenharmony_ci int data_len; 8588c2ecf20Sopenharmony_ci u8 *rx_pn; 8598c2ecf20Sopenharmony_ci u8 *skb_pn; 8608c2ecf20Sopenharmony_ci u8 qos_tid; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (!rx->sta || !rx->sta->cipher_scheme || 8638c2ecf20Sopenharmony_ci !(status->flag & RX_FLAG_DECRYPTED)) 8648c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control)) 8678c2ecf20Sopenharmony_ci return RX_CONTINUE; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci cs = rx->sta->cipher_scheme; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci data_len = rx->skb->len - hdrlen - cs->hdr_len; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (data_len < 0) 8748c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 8778c2ecf20Sopenharmony_ci qos_tid = ieee80211_get_tid(hdr); 8788c2ecf20Sopenharmony_ci else 8798c2ecf20Sopenharmony_ci qos_tid = 0; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (skb_linearize(rx->skb)) 8828c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)rx->skb->data; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci rx_pn = key->u.gen.rx_pn[qos_tid]; 8878c2ecf20Sopenharmony_ci skb_pn = rx->skb->data + hdrlen + cs->pn_off; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) 8908c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci memcpy(rx_pn, skb_pn, cs->pn_len); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* remove security header and MIC */ 8958c2ecf20Sopenharmony_ci if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) 8968c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); 8998c2ecf20Sopenharmony_ci skb_pull(rx->skb, cs->hdr_len); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return RX_CONTINUE; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic void bip_aad(struct sk_buff *skb, u8 *aad) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci __le16 mask_fc; 9078c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* BIP AAD: FC(masked) || A1 || A2 || A3 */ 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* FC type/subtype */ 9128c2ecf20Sopenharmony_ci /* Mask FC Retry, PwrMgt, MoreData flags to zero */ 9138c2ecf20Sopenharmony_ci mask_fc = hdr->frame_control; 9148c2ecf20Sopenharmony_ci mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM | 9158c2ecf20Sopenharmony_ci IEEE80211_FCTL_MOREDATA); 9168c2ecf20Sopenharmony_ci put_unaligned(mask_fc, (__le16 *) &aad[0]); 9178c2ecf20Sopenharmony_ci /* A1 || A2 || A3 */ 9188c2ecf20Sopenharmony_ci memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic inline void bip_ipn_set64(u8 *d, u64 pn) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci *d++ = pn; 9258c2ecf20Sopenharmony_ci *d++ = pn >> 8; 9268c2ecf20Sopenharmony_ci *d++ = pn >> 16; 9278c2ecf20Sopenharmony_ci *d++ = pn >> 24; 9288c2ecf20Sopenharmony_ci *d++ = pn >> 32; 9298c2ecf20Sopenharmony_ci *d = pn >> 40; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic inline void bip_ipn_swap(u8 *d, const u8 *s) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci *d++ = s[5]; 9358c2ecf20Sopenharmony_ci *d++ = s[4]; 9368c2ecf20Sopenharmony_ci *d++ = s[3]; 9378c2ecf20Sopenharmony_ci *d++ = s[2]; 9388c2ecf20Sopenharmony_ci *d++ = s[1]; 9398c2ecf20Sopenharmony_ci *d = s[0]; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ciieee80211_tx_result 9448c2ecf20Sopenharmony_ciieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct sk_buff *skb; 9478c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 9488c2ecf20Sopenharmony_ci struct ieee80211_key *key = tx->key; 9498c2ecf20Sopenharmony_ci struct ieee80211_mmie *mmie; 9508c2ecf20Sopenharmony_ci u8 aad[20]; 9518c2ecf20Sopenharmony_ci u64 pn64; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) 9548c2ecf20Sopenharmony_ci return TX_DROP; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci skb = skb_peek(&tx->skbs); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (info->control.hw_key && 9618c2ecf20Sopenharmony_ci !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIE)) 9628c2ecf20Sopenharmony_ci return TX_CONTINUE; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) 9658c2ecf20Sopenharmony_ci return TX_DROP; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci mmie = skb_put(skb, sizeof(*mmie)); 9688c2ecf20Sopenharmony_ci mmie->element_id = WLAN_EID_MMIE; 9698c2ecf20Sopenharmony_ci mmie->length = sizeof(*mmie) - 2; 9708c2ecf20Sopenharmony_ci mmie->key_id = cpu_to_le16(key->conf.keyidx); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* PN = PN + 1 */ 9738c2ecf20Sopenharmony_ci pn64 = atomic64_inc_return(&key->conf.tx_pn); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci bip_ipn_set64(mmie->sequence_number, pn64); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (info->control.hw_key) 9788c2ecf20Sopenharmony_ci return TX_CONTINUE; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci bip_aad(skb, aad); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* 9838c2ecf20Sopenharmony_ci * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) 9848c2ecf20Sopenharmony_ci */ 9858c2ecf20Sopenharmony_ci ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, 9868c2ecf20Sopenharmony_ci skb->data + 24, skb->len - 24, mmie->mic); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return TX_CONTINUE; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ciieee80211_tx_result 9928c2ecf20Sopenharmony_ciieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci struct sk_buff *skb; 9958c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 9968c2ecf20Sopenharmony_ci struct ieee80211_key *key = tx->key; 9978c2ecf20Sopenharmony_ci struct ieee80211_mmie_16 *mmie; 9988c2ecf20Sopenharmony_ci u8 aad[20]; 9998c2ecf20Sopenharmony_ci u64 pn64; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) 10028c2ecf20Sopenharmony_ci return TX_DROP; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci skb = skb_peek(&tx->skbs); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (info->control.hw_key) 10098c2ecf20Sopenharmony_ci return TX_CONTINUE; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) 10128c2ecf20Sopenharmony_ci return TX_DROP; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci mmie = skb_put(skb, sizeof(*mmie)); 10158c2ecf20Sopenharmony_ci mmie->element_id = WLAN_EID_MMIE; 10168c2ecf20Sopenharmony_ci mmie->length = sizeof(*mmie) - 2; 10178c2ecf20Sopenharmony_ci mmie->key_id = cpu_to_le16(key->conf.keyidx); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* PN = PN + 1 */ 10208c2ecf20Sopenharmony_ci pn64 = atomic64_inc_return(&key->conf.tx_pn); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci bip_ipn_set64(mmie->sequence_number, pn64); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci bip_aad(skb, aad); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128) 10278c2ecf20Sopenharmony_ci */ 10288c2ecf20Sopenharmony_ci ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, 10298c2ecf20Sopenharmony_ci skb->data + 24, skb->len - 24, mmie->mic); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci return TX_CONTINUE; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ciieee80211_rx_result 10358c2ecf20Sopenharmony_ciieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 10388c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 10398c2ecf20Sopenharmony_ci struct ieee80211_key *key = rx->key; 10408c2ecf20Sopenharmony_ci struct ieee80211_mmie *mmie; 10418c2ecf20Sopenharmony_ci u8 aad[20], mic[8], ipn[6]; 10428c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (!ieee80211_is_mgmt(hdr->frame_control)) 10458c2ecf20Sopenharmony_ci return RX_CONTINUE; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* management frames are already linear */ 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (skb->len < 24 + sizeof(*mmie)) 10508c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci mmie = (struct ieee80211_mmie *) 10538c2ecf20Sopenharmony_ci (skb->data + skb->len - sizeof(*mmie)); 10548c2ecf20Sopenharmony_ci if (mmie->element_id != WLAN_EID_MMIE || 10558c2ecf20Sopenharmony_ci mmie->length != sizeof(*mmie) - 2) 10568c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; /* Invalid MMIE */ 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci bip_ipn_swap(ipn, mmie->sequence_number); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) { 10618c2ecf20Sopenharmony_ci key->u.aes_cmac.replays++; 10628c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_DECRYPTED)) { 10668c2ecf20Sopenharmony_ci /* hardware didn't decrypt/verify MIC */ 10678c2ecf20Sopenharmony_ci bip_aad(skb, aad); 10688c2ecf20Sopenharmony_ci ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, 10698c2ecf20Sopenharmony_ci skb->data + 24, skb->len - 24, mic); 10708c2ecf20Sopenharmony_ci if (crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) { 10718c2ecf20Sopenharmony_ci key->u.aes_cmac.icverrors++; 10728c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci memcpy(key->u.aes_cmac.rx_pn, ipn, 6); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* Remove MMIE */ 10798c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - sizeof(*mmie)); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci return RX_CONTINUE; 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ciieee80211_rx_result 10858c2ecf20Sopenharmony_ciieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 10888c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 10898c2ecf20Sopenharmony_ci struct ieee80211_key *key = rx->key; 10908c2ecf20Sopenharmony_ci struct ieee80211_mmie_16 *mmie; 10918c2ecf20Sopenharmony_ci u8 aad[20], mic[16], ipn[6]; 10928c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (!ieee80211_is_mgmt(hdr->frame_control)) 10958c2ecf20Sopenharmony_ci return RX_CONTINUE; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* management frames are already linear */ 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (skb->len < 24 + sizeof(*mmie)) 11008c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci mmie = (struct ieee80211_mmie_16 *) 11038c2ecf20Sopenharmony_ci (skb->data + skb->len - sizeof(*mmie)); 11048c2ecf20Sopenharmony_ci if (mmie->element_id != WLAN_EID_MMIE || 11058c2ecf20Sopenharmony_ci mmie->length != sizeof(*mmie) - 2) 11068c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; /* Invalid MMIE */ 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci bip_ipn_swap(ipn, mmie->sequence_number); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) { 11118c2ecf20Sopenharmony_ci key->u.aes_cmac.replays++; 11128c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_DECRYPTED)) { 11168c2ecf20Sopenharmony_ci /* hardware didn't decrypt/verify MIC */ 11178c2ecf20Sopenharmony_ci bip_aad(skb, aad); 11188c2ecf20Sopenharmony_ci ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, 11198c2ecf20Sopenharmony_ci skb->data + 24, skb->len - 24, mic); 11208c2ecf20Sopenharmony_ci if (crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) { 11218c2ecf20Sopenharmony_ci key->u.aes_cmac.icverrors++; 11228c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci memcpy(key->u.aes_cmac.rx_pn, ipn, 6); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* Remove MMIE */ 11298c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - sizeof(*mmie)); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci return RX_CONTINUE; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ciieee80211_tx_result 11358c2ecf20Sopenharmony_ciieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci struct sk_buff *skb; 11388c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 11398c2ecf20Sopenharmony_ci struct ieee80211_key *key = tx->key; 11408c2ecf20Sopenharmony_ci struct ieee80211_mmie_16 *mmie; 11418c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 11428c2ecf20Sopenharmony_ci u8 aad[GMAC_AAD_LEN]; 11438c2ecf20Sopenharmony_ci u64 pn64; 11448c2ecf20Sopenharmony_ci u8 nonce[GMAC_NONCE_LEN]; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) 11478c2ecf20Sopenharmony_ci return TX_DROP; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci skb = skb_peek(&tx->skbs); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (info->control.hw_key) 11548c2ecf20Sopenharmony_ci return TX_CONTINUE; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) 11578c2ecf20Sopenharmony_ci return TX_DROP; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci mmie = skb_put(skb, sizeof(*mmie)); 11608c2ecf20Sopenharmony_ci mmie->element_id = WLAN_EID_MMIE; 11618c2ecf20Sopenharmony_ci mmie->length = sizeof(*mmie) - 2; 11628c2ecf20Sopenharmony_ci mmie->key_id = cpu_to_le16(key->conf.keyidx); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* PN = PN + 1 */ 11658c2ecf20Sopenharmony_ci pn64 = atomic64_inc_return(&key->conf.tx_pn); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci bip_ipn_set64(mmie->sequence_number, pn64); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci bip_aad(skb, aad); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 11728c2ecf20Sopenharmony_ci memcpy(nonce, hdr->addr2, ETH_ALEN); 11738c2ecf20Sopenharmony_ci bip_ipn_swap(nonce + ETH_ALEN, mmie->sequence_number); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* MIC = AES-GMAC(IGTK, AAD || Management Frame Body || MMIE, 128) */ 11768c2ecf20Sopenharmony_ci if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce, 11778c2ecf20Sopenharmony_ci skb->data + 24, skb->len - 24, mmie->mic) < 0) 11788c2ecf20Sopenharmony_ci return TX_DROP; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return TX_CONTINUE; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ciieee80211_rx_result 11848c2ecf20Sopenharmony_ciieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx) 11858c2ecf20Sopenharmony_ci{ 11868c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 11878c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 11888c2ecf20Sopenharmony_ci struct ieee80211_key *key = rx->key; 11898c2ecf20Sopenharmony_ci struct ieee80211_mmie_16 *mmie; 11908c2ecf20Sopenharmony_ci u8 aad[GMAC_AAD_LEN], *mic, ipn[6], nonce[GMAC_NONCE_LEN]; 11918c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (!ieee80211_is_mgmt(hdr->frame_control)) 11948c2ecf20Sopenharmony_ci return RX_CONTINUE; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* management frames are already linear */ 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci if (skb->len < 24 + sizeof(*mmie)) 11998c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci mmie = (struct ieee80211_mmie_16 *) 12028c2ecf20Sopenharmony_ci (skb->data + skb->len - sizeof(*mmie)); 12038c2ecf20Sopenharmony_ci if (mmie->element_id != WLAN_EID_MMIE || 12048c2ecf20Sopenharmony_ci mmie->length != sizeof(*mmie) - 2) 12058c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; /* Invalid MMIE */ 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci bip_ipn_swap(ipn, mmie->sequence_number); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (memcmp(ipn, key->u.aes_gmac.rx_pn, 6) <= 0) { 12108c2ecf20Sopenharmony_ci key->u.aes_gmac.replays++; 12118c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_DECRYPTED)) { 12158c2ecf20Sopenharmony_ci /* hardware didn't decrypt/verify MIC */ 12168c2ecf20Sopenharmony_ci bip_aad(skb, aad); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci memcpy(nonce, hdr->addr2, ETH_ALEN); 12198c2ecf20Sopenharmony_ci memcpy(nonce + ETH_ALEN, ipn, 6); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci mic = kmalloc(GMAC_MIC_LEN, GFP_ATOMIC); 12228c2ecf20Sopenharmony_ci if (!mic) 12238c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 12248c2ecf20Sopenharmony_ci if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce, 12258c2ecf20Sopenharmony_ci skb->data + 24, skb->len - 24, 12268c2ecf20Sopenharmony_ci mic) < 0 || 12278c2ecf20Sopenharmony_ci crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) { 12288c2ecf20Sopenharmony_ci key->u.aes_gmac.icverrors++; 12298c2ecf20Sopenharmony_ci kfree(mic); 12308c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci kfree(mic); 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci memcpy(key->u.aes_gmac.rx_pn, ipn, 6); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci /* Remove MMIE */ 12388c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - sizeof(*mmie)); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci return RX_CONTINUE; 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ciieee80211_tx_result 12448c2ecf20Sopenharmony_ciieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci struct sk_buff *skb; 12478c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = NULL; 12488c2ecf20Sopenharmony_ci ieee80211_tx_result res; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci skb_queue_walk(&tx->skbs, skb) { 12518c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci /* handle hw-only algorithm */ 12548c2ecf20Sopenharmony_ci if (!info->control.hw_key) 12558c2ecf20Sopenharmony_ci return TX_DROP; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (tx->key->flags & KEY_FLAG_CIPHER_SCHEME) { 12588c2ecf20Sopenharmony_ci res = ieee80211_crypto_cs_encrypt(tx, skb); 12598c2ecf20Sopenharmony_ci if (res != TX_CONTINUE) 12608c2ecf20Sopenharmony_ci return res; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci ieee80211_tx_set_protected(tx); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci return TX_CONTINUE; 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ciieee80211_rx_result 12708c2ecf20Sopenharmony_ciieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci if (rx->sta && rx->sta->cipher_scheme) 12738c2ecf20Sopenharmony_ci return ieee80211_crypto_cs_decrypt(rx); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 12768c2ecf20Sopenharmony_ci} 1277