LCOV - code coverage report
Current view: top level - net/mac80211 - wpa.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 439 0.0 %
Date: 2022-03-28 13:20:08 Functions: 0 17 0.0 %
Branches: 0 316 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Copyright 2002-2004, Instant802 Networks, Inc.
       4                 :            :  * Copyright 2008, Jouni Malinen <j@w1.fi>
       5                 :            :  * Copyright (C) 2016-2017 Intel Deutschland GmbH
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/netdevice.h>
       9                 :            : #include <linux/types.h>
      10                 :            : #include <linux/skbuff.h>
      11                 :            : #include <linux/compiler.h>
      12                 :            : #include <linux/ieee80211.h>
      13                 :            : #include <linux/gfp.h>
      14                 :            : #include <asm/unaligned.h>
      15                 :            : #include <net/mac80211.h>
      16                 :            : #include <crypto/aes.h>
      17                 :            : #include <crypto/algapi.h>
      18                 :            : 
      19                 :            : #include "ieee80211_i.h"
      20                 :            : #include "michael.h"
      21                 :            : #include "tkip.h"
      22                 :            : #include "aes_ccm.h"
      23                 :            : #include "aes_cmac.h"
      24                 :            : #include "aes_gmac.h"
      25                 :            : #include "aes_gcm.h"
      26                 :            : #include "wpa.h"
      27                 :            : 
      28                 :            : ieee80211_tx_result
      29                 :          0 : ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
      30                 :            : {
      31                 :          0 :         u8 *data, *key, *mic;
      32                 :          0 :         size_t data_len;
      33                 :          0 :         unsigned int hdrlen;
      34                 :          0 :         struct ieee80211_hdr *hdr;
      35                 :          0 :         struct sk_buff *skb = tx->skb;
      36         [ #  # ]:          0 :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
      37                 :          0 :         int tail;
      38                 :            : 
      39                 :          0 :         hdr = (struct ieee80211_hdr *)skb->data;
      40   [ #  #  #  # ]:          0 :         if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
      41   [ #  #  #  # ]:          0 :             skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control))
      42                 :            :                 return TX_CONTINUE;
      43                 :            : 
      44                 :          0 :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
      45         [ #  # ]:          0 :         if (skb->len < hdrlen)
      46                 :            :                 return TX_DROP;
      47                 :            : 
      48                 :          0 :         data = skb->data + hdrlen;
      49                 :          0 :         data_len = skb->len - hdrlen;
      50                 :            : 
      51         [ #  # ]:          0 :         if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) {
      52                 :            :                 /* Need to use software crypto for the test */
      53                 :          0 :                 info->control.hw_key = NULL;
      54                 :            :         }
      55                 :            : 
      56         [ #  # ]:          0 :         if (info->control.hw_key &&
      57   [ #  #  #  # ]:          0 :             (info->flags & IEEE80211_TX_CTL_DONTFRAG ||
      58                 :          0 :              ieee80211_hw_check(&tx->local->hw, SUPPORTS_TX_FRAG)) &&
      59         [ #  # ]:          0 :             !(tx->key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
      60                 :            :                                      IEEE80211_KEY_FLAG_PUT_MIC_SPACE))) {
      61                 :            :                 /* hwaccel - with no need for SW-generated MMIC or MIC space */
      62                 :            :                 return TX_CONTINUE;
      63                 :            :         }
      64                 :            : 
      65                 :          0 :         tail = MICHAEL_MIC_LEN;
      66         [ #  # ]:          0 :         if (!info->control.hw_key)
      67                 :          0 :                 tail += IEEE80211_TKIP_ICV_LEN;
      68                 :            : 
      69   [ #  #  #  #  :          0 :         if (WARN(skb_tailroom(skb) < tail ||
          #  #  #  #  #  
                      # ]
      70                 :            :                  skb_headroom(skb) < IEEE80211_TKIP_IV_LEN,
      71                 :            :                  "mmic: not enough head/tail (%d/%d,%d/%d)\n",
      72                 :            :                  skb_headroom(skb), IEEE80211_TKIP_IV_LEN,
      73                 :            :                  skb_tailroom(skb), tail))
      74                 :            :                 return TX_DROP;
      75                 :            : 
      76                 :          0 :         mic = skb_put(skb, MICHAEL_MIC_LEN);
      77                 :            : 
      78         [ #  # ]:          0 :         if (tx->key->conf.flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) {
      79                 :            :                 /* Zeroed MIC can help with debug */
      80                 :          0 :                 memset(mic, 0, MICHAEL_MIC_LEN);
      81                 :          0 :                 return TX_CONTINUE;
      82                 :            :         }
      83                 :            : 
      84                 :          0 :         key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY];
      85                 :          0 :         michael_mic(key, hdr, data, data_len, mic);
      86         [ #  # ]:          0 :         if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE))
      87                 :          0 :                 mic[0]++;
      88                 :            : 
      89                 :            :         return TX_CONTINUE;
      90                 :            : }
      91                 :            : 
      92                 :            : 
      93                 :            : ieee80211_rx_result
      94                 :          0 : ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
      95                 :            : {
      96                 :          0 :         u8 *data, *key = NULL;
      97                 :          0 :         size_t data_len;
      98                 :          0 :         unsigned int hdrlen;
      99                 :          0 :         u8 mic[MICHAEL_MIC_LEN];
     100                 :          0 :         struct sk_buff *skb = rx->skb;
     101         [ #  # ]:          0 :         struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
     102                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
     103                 :            : 
     104                 :            :         /*
     105                 :            :          * it makes no sense to check for MIC errors on anything other
     106                 :            :          * than data frames.
     107                 :            :          */
     108         [ #  # ]:          0 :         if (!ieee80211_is_data_present(hdr->frame_control))
     109                 :            :                 return RX_CONTINUE;
     110                 :            : 
     111                 :            :         /*
     112                 :            :          * No way to verify the MIC if the hardware stripped it or
     113                 :            :          * the IV with the key index. In this case we have solely rely
     114                 :            :          * on the driver to set RX_FLAG_MMIC_ERROR in the event of a
     115                 :            :          * MIC failure report.
     116                 :            :          */
     117         [ #  # ]:          0 :         if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) {
     118         [ #  # ]:          0 :                 if (status->flag & RX_FLAG_MMIC_ERROR)
     119                 :          0 :                         goto mic_fail_no_key;
     120                 :            : 
     121   [ #  #  #  # ]:          0 :                 if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key &&
     122         [ #  # ]:          0 :                     rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
     123                 :          0 :                         goto update_iv;
     124                 :            : 
     125                 :            :                 return RX_CONTINUE;
     126                 :            :         }
     127                 :            : 
     128                 :            :         /*
     129                 :            :          * Some hardware seems to generate Michael MIC failure reports; even
     130                 :            :          * though, the frame was not encrypted with TKIP and therefore has no
     131                 :            :          * MIC. Ignore the flag them to avoid triggering countermeasures.
     132                 :            :          */
     133   [ #  #  #  # ]:          0 :         if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
     134         [ #  # ]:          0 :             !(status->flag & RX_FLAG_DECRYPTED))
     135                 :            :                 return RX_CONTINUE;
     136                 :            : 
     137   [ #  #  #  # ]:          0 :         if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) {
     138                 :            :                 /*
     139                 :            :                  * APs with pairwise keys should never receive Michael MIC
     140                 :            :                  * errors for non-zero keyidx because these are reserved for
     141                 :            :                  * group keys and only the AP is sending real multicast
     142                 :            :                  * frames in the BSS.
     143                 :            :                  */
     144                 :            :                 return RX_DROP_UNUSABLE;
     145                 :            :         }
     146                 :            : 
     147         [ #  # ]:          0 :         if (status->flag & RX_FLAG_MMIC_ERROR)
     148                 :          0 :                 goto mic_fail;
     149                 :            : 
     150                 :          0 :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     151         [ #  # ]:          0 :         if (skb->len < hdrlen + MICHAEL_MIC_LEN)
     152                 :            :                 return RX_DROP_UNUSABLE;
     153                 :            : 
     154         [ #  # ]:          0 :         if (skb_linearize(rx->skb))
     155                 :            :                 return RX_DROP_UNUSABLE;
     156                 :          0 :         hdr = (void *)skb->data;
     157                 :            : 
     158                 :          0 :         data = skb->data + hdrlen;
     159                 :          0 :         data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
     160                 :          0 :         key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
     161                 :          0 :         michael_mic(key, hdr, data, data_len, mic);
     162         [ #  # ]:          0 :         if (crypto_memneq(mic, data + data_len, MICHAEL_MIC_LEN))
     163                 :          0 :                 goto mic_fail;
     164                 :            : 
     165                 :            :         /* remove Michael MIC from payload */
     166                 :          0 :         skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
     167                 :            : 
     168                 :          0 : update_iv:
     169                 :            :         /* update IV in key information to be able to detect replays */
     170                 :          0 :         rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32;
     171                 :          0 :         rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16;
     172                 :            : 
     173                 :          0 :         return RX_CONTINUE;
     174                 :            : 
     175                 :          0 : mic_fail:
     176                 :          0 :         rx->key->u.tkip.mic_failures++;
     177                 :            : 
     178                 :          0 : mic_fail_no_key:
     179                 :            :         /*
     180                 :            :          * In some cases the key can be unset - e.g. a multicast packet, in
     181                 :            :          * a driver that supports HW encryption. Send up the key idx only if
     182                 :            :          * the key is set.
     183                 :            :          */
     184                 :          0 :         cfg80211_michael_mic_failure(rx->sdata->dev, hdr->addr2,
     185                 :            :                                      is_multicast_ether_addr(hdr->addr1) ?
     186                 :          0 :                                      NL80211_KEYTYPE_GROUP :
     187                 :            :                                      NL80211_KEYTYPE_PAIRWISE,
     188         [ #  # ]:          0 :                                      rx->key ? rx->key->conf.keyidx : -1,
     189                 :            :                                      NULL, GFP_ATOMIC);
     190                 :          0 :         return RX_DROP_UNUSABLE;
     191                 :            : }
     192                 :            : 
     193                 :            : static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
     194                 :            : {
     195                 :            :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
     196                 :            :         struct ieee80211_key *key = tx->key;
     197                 :            :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
     198                 :            :         unsigned int hdrlen;
     199                 :            :         int len, tail;
     200                 :            :         u64 pn;
     201                 :            :         u8 *pos;
     202                 :            : 
     203                 :            :         if (info->control.hw_key &&
     204                 :            :             !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
     205                 :            :             !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
     206                 :            :                 /* hwaccel - with no need for software-generated IV */
     207                 :            :                 return 0;
     208                 :            :         }
     209                 :            : 
     210                 :            :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     211                 :            :         len = skb->len - hdrlen;
     212                 :            : 
     213                 :            :         if (info->control.hw_key)
     214                 :            :                 tail = 0;
     215                 :            :         else
     216                 :            :                 tail = IEEE80211_TKIP_ICV_LEN;
     217                 :            : 
     218                 :            :         if (WARN_ON(skb_tailroom(skb) < tail ||
     219                 :            :                     skb_headroom(skb) < IEEE80211_TKIP_IV_LEN))
     220                 :            :                 return -1;
     221                 :            : 
     222                 :            :         pos = skb_push(skb, IEEE80211_TKIP_IV_LEN);
     223                 :            :         memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen);
     224                 :            :         pos += hdrlen;
     225                 :            : 
     226                 :            :         /* the HW only needs room for the IV, but not the actual IV */
     227                 :            :         if (info->control.hw_key &&
     228                 :            :             (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
     229                 :            :                 return 0;
     230                 :            : 
     231                 :            :         /* Increase IV for the frame */
     232                 :            :         pn = atomic64_inc_return(&key->conf.tx_pn);
     233                 :            :         pos = ieee80211_tkip_add_iv(pos, &key->conf, pn);
     234                 :            : 
     235                 :            :         /* hwaccel - with software IV */
     236                 :            :         if (info->control.hw_key)
     237                 :            :                 return 0;
     238                 :            : 
     239                 :            :         /* Add room for ICV */
     240                 :            :         skb_put(skb, IEEE80211_TKIP_ICV_LEN);
     241                 :            : 
     242                 :            :         return ieee80211_tkip_encrypt_data(&tx->local->wep_tx_ctx,
     243                 :            :                                            key, skb, pos, len);
     244                 :            : }
     245                 :            : 
     246                 :            : 
     247                 :            : ieee80211_tx_result
     248                 :          0 : ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
     249                 :            : {
     250                 :          0 :         struct sk_buff *skb;
     251                 :            : 
     252                 :          0 :         ieee80211_tx_set_protected(tx);
     253                 :            : 
     254         [ #  # ]:          0 :         skb_queue_walk(&tx->skbs, skb) {
     255         [ #  # ]:          0 :                 if (tkip_encrypt_skb(tx, skb) < 0)
     256                 :            :                         return TX_DROP;
     257                 :            :         }
     258                 :            : 
     259                 :            :         return TX_CONTINUE;
     260                 :            : }
     261                 :            : 
     262                 :            : 
     263                 :            : ieee80211_rx_result
     264                 :          0 : ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
     265                 :            : {
     266                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
     267                 :          0 :         int hdrlen, res, hwaccel = 0;
     268                 :          0 :         struct ieee80211_key *key = rx->key;
     269                 :          0 :         struct sk_buff *skb = rx->skb;
     270         [ #  # ]:          0 :         struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
     271                 :            : 
     272                 :          0 :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     273                 :            : 
     274         [ #  # ]:          0 :         if (!ieee80211_is_data(hdr->frame_control))
     275                 :            :                 return RX_CONTINUE;
     276                 :            : 
     277   [ #  #  #  # ]:          0 :         if (!rx->sta || skb->len - hdrlen < 12)
     278                 :            :                 return RX_DROP_UNUSABLE;
     279                 :            : 
     280                 :            :         /* it may be possible to optimize this a bit more */
     281         [ #  # ]:          0 :         if (skb_linearize(rx->skb))
     282                 :            :                 return RX_DROP_UNUSABLE;
     283                 :          0 :         hdr = (void *)skb->data;
     284                 :            : 
     285                 :            :         /*
     286                 :            :          * Let TKIP code verify IV, but skip decryption.
     287                 :            :          * In the case where hardware checks the IV as well,
     288                 :            :          * we don't even get here, see ieee80211_rx_h_decrypt()
     289                 :            :          */
     290         [ #  # ]:          0 :         if (status->flag & RX_FLAG_DECRYPTED)
     291                 :          0 :                 hwaccel = 1;
     292                 :            : 
     293                 :          0 :         res = ieee80211_tkip_decrypt_data(&rx->local->wep_rx_ctx,
     294                 :          0 :                                           key, skb->data + hdrlen,
     295                 :          0 :                                           skb->len - hdrlen, rx->sta->sta.addr,
     296                 :          0 :                                           hdr->addr1, hwaccel, rx->security_idx,
     297                 :            :                                           &rx->tkip_iv32,
     298                 :            :                                           &rx->tkip_iv16);
     299         [ #  # ]:          0 :         if (res != TKIP_DECRYPT_OK)
     300                 :            :                 return RX_DROP_UNUSABLE;
     301                 :            : 
     302                 :            :         /* Trim ICV */
     303         [ #  # ]:          0 :         if (!(status->flag & RX_FLAG_ICV_STRIPPED))
     304                 :          0 :                 skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN);
     305                 :            : 
     306                 :            :         /* Remove IV */
     307                 :          0 :         memmove(skb->data + IEEE80211_TKIP_IV_LEN, skb->data, hdrlen);
     308                 :          0 :         skb_pull(skb, IEEE80211_TKIP_IV_LEN);
     309                 :            : 
     310                 :          0 :         return RX_CONTINUE;
     311                 :            : }
     312                 :            : 
     313                 :            : 
     314                 :            : static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad)
     315                 :            : {
     316                 :            :         __le16 mask_fc;
     317                 :            :         int a4_included, mgmt;
     318                 :            :         u8 qos_tid;
     319                 :            :         u16 len_a;
     320                 :            :         unsigned int hdrlen;
     321                 :            :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
     322                 :            : 
     323                 :            :         /*
     324                 :            :          * Mask FC: zero subtype b4 b5 b6 (if not mgmt)
     325                 :            :          * Retry, PwrMgt, MoreData; set Protected
     326                 :            :          */
     327                 :            :         mgmt = ieee80211_is_mgmt(hdr->frame_control);
     328                 :            :         mask_fc = hdr->frame_control;
     329                 :            :         mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY |
     330                 :            :                                 IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA);
     331                 :            :         if (!mgmt)
     332                 :            :                 mask_fc &= ~cpu_to_le16(0x0070);
     333                 :            :         mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
     334                 :            : 
     335                 :            :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     336                 :            :         len_a = hdrlen - 2;
     337                 :            :         a4_included = ieee80211_has_a4(hdr->frame_control);
     338                 :            : 
     339                 :            :         if (ieee80211_is_data_qos(hdr->frame_control))
     340                 :            :                 qos_tid = ieee80211_get_tid(hdr);
     341                 :            :         else
     342                 :            :                 qos_tid = 0;
     343                 :            : 
     344                 :            :         /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
     345                 :            :          * mode authentication are not allowed to collide, yet both are derived
     346                 :            :          * from this vector b_0. We only set L := 1 here to indicate that the
     347                 :            :          * data size can be represented in (L+1) bytes. The CCM layer will take
     348                 :            :          * care of storing the data length in the top (L+1) bytes and setting
     349                 :            :          * and clearing the other bits as is required to derive the two IVs.
     350                 :            :          */
     351                 :            :         b_0[0] = 0x1;
     352                 :            : 
     353                 :            :         /* Nonce: Nonce Flags | A2 | PN
     354                 :            :          * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
     355                 :            :          */
     356                 :            :         b_0[1] = qos_tid | (mgmt << 4);
     357                 :            :         memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
     358                 :            :         memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
     359                 :            : 
     360                 :            :         /* AAD (extra authenticate-only data) / masked 802.11 header
     361                 :            :          * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
     362                 :            :         put_unaligned_be16(len_a, &aad[0]);
     363                 :            :         put_unaligned(mask_fc, (__le16 *)&aad[2]);
     364                 :            :         memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
     365                 :            : 
     366                 :            :         /* Mask Seq#, leave Frag# */
     367                 :            :         aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
     368                 :            :         aad[23] = 0;
     369                 :            : 
     370                 :            :         if (a4_included) {
     371                 :            :                 memcpy(&aad[24], hdr->addr4, ETH_ALEN);
     372                 :            :                 aad[30] = qos_tid;
     373                 :            :                 aad[31] = 0;
     374                 :            :         } else {
     375                 :            :                 memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN);
     376                 :            :                 aad[24] = qos_tid;
     377                 :            :         }
     378                 :            : }
     379                 :            : 
     380                 :            : 
     381                 :            : static inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id)
     382                 :            : {
     383                 :            :         hdr[0] = pn[5];
     384                 :            :         hdr[1] = pn[4];
     385                 :            :         hdr[2] = 0;
     386                 :            :         hdr[3] = 0x20 | (key_id << 6);
     387                 :            :         hdr[4] = pn[3];
     388                 :            :         hdr[5] = pn[2];
     389                 :            :         hdr[6] = pn[1];
     390                 :            :         hdr[7] = pn[0];
     391                 :            : }
     392                 :            : 
     393                 :            : 
     394                 :          0 : static inline void ccmp_hdr2pn(u8 *pn, u8 *hdr)
     395                 :            : {
     396                 :          0 :         pn[0] = hdr[7];
     397                 :          0 :         pn[1] = hdr[6];
     398                 :          0 :         pn[2] = hdr[5];
     399                 :          0 :         pn[3] = hdr[4];
     400                 :          0 :         pn[4] = hdr[1];
     401                 :          0 :         pn[5] = hdr[0];
     402                 :            : }
     403                 :            : 
     404                 :            : 
     405                 :            : static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
     406                 :            :                             unsigned int mic_len)
     407                 :            : {
     408                 :            :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
     409                 :            :         struct ieee80211_key *key = tx->key;
     410                 :            :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
     411                 :            :         int hdrlen, len, tail;
     412                 :            :         u8 *pos;
     413                 :            :         u8 pn[6];
     414                 :            :         u64 pn64;
     415                 :            :         u8 aad[CCM_AAD_LEN];
     416                 :            :         u8 b_0[AES_BLOCK_SIZE];
     417                 :            : 
     418                 :            :         if (info->control.hw_key &&
     419                 :            :             !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
     420                 :            :             !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
     421                 :            :             !((info->control.hw_key->flags &
     422                 :            :                IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) &&
     423                 :            :               ieee80211_is_mgmt(hdr->frame_control))) {
     424                 :            :                 /*
     425                 :            :                  * hwaccel has no need for preallocated room for CCMP
     426                 :            :                  * header or MIC fields
     427                 :            :                  */
     428                 :            :                 return 0;
     429                 :            :         }
     430                 :            : 
     431                 :            :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     432                 :            :         len = skb->len - hdrlen;
     433                 :            : 
     434                 :            :         if (info->control.hw_key)
     435                 :            :                 tail = 0;
     436                 :            :         else
     437                 :            :                 tail = mic_len;
     438                 :            : 
     439                 :            :         if (WARN_ON(skb_tailroom(skb) < tail ||
     440                 :            :                     skb_headroom(skb) < IEEE80211_CCMP_HDR_LEN))
     441                 :            :                 return -1;
     442                 :            : 
     443                 :            :         pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN);
     444                 :            :         memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen);
     445                 :            : 
     446                 :            :         /* the HW only needs room for the IV, but not the actual IV */
     447                 :            :         if (info->control.hw_key &&
     448                 :            :             (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
     449                 :            :                 return 0;
     450                 :            : 
     451                 :            :         hdr = (struct ieee80211_hdr *) pos;
     452                 :            :         pos += hdrlen;
     453                 :            : 
     454                 :            :         pn64 = atomic64_inc_return(&key->conf.tx_pn);
     455                 :            : 
     456                 :            :         pn[5] = pn64;
     457                 :            :         pn[4] = pn64 >> 8;
     458                 :            :         pn[3] = pn64 >> 16;
     459                 :            :         pn[2] = pn64 >> 24;
     460                 :            :         pn[1] = pn64 >> 32;
     461                 :            :         pn[0] = pn64 >> 40;
     462                 :            : 
     463                 :            :         ccmp_pn2hdr(pos, pn, key->conf.keyidx);
     464                 :            : 
     465                 :            :         /* hwaccel - with software CCMP header */
     466                 :            :         if (info->control.hw_key)
     467                 :            :                 return 0;
     468                 :            : 
     469                 :            :         pos += IEEE80211_CCMP_HDR_LEN;
     470                 :            :         ccmp_special_blocks(skb, pn, b_0, aad);
     471                 :            :         return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
     472                 :            :                                          skb_put(skb, mic_len));
     473                 :            : }
     474                 :            : 
     475                 :            : 
     476                 :            : ieee80211_tx_result
     477                 :          0 : ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx,
     478                 :            :                               unsigned int mic_len)
     479                 :            : {
     480                 :          0 :         struct sk_buff *skb;
     481                 :            : 
     482                 :          0 :         ieee80211_tx_set_protected(tx);
     483                 :            : 
     484         [ #  # ]:          0 :         skb_queue_walk(&tx->skbs, skb) {
     485         [ #  # ]:          0 :                 if (ccmp_encrypt_skb(tx, skb, mic_len) < 0)
     486                 :            :                         return TX_DROP;
     487                 :            :         }
     488                 :            : 
     489                 :            :         return TX_CONTINUE;
     490                 :            : }
     491                 :            : 
     492                 :            : 
     493                 :            : ieee80211_rx_result
     494                 :          0 : ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx,
     495                 :            :                               unsigned int mic_len)
     496                 :            : {
     497                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
     498                 :          0 :         int hdrlen;
     499                 :          0 :         struct ieee80211_key *key = rx->key;
     500                 :          0 :         struct sk_buff *skb = rx->skb;
     501         [ #  # ]:          0 :         struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
     502                 :          0 :         u8 pn[IEEE80211_CCMP_PN_LEN];
     503                 :          0 :         int data_len;
     504                 :          0 :         int queue;
     505                 :            : 
     506                 :          0 :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     507                 :            : 
     508   [ #  #  #  # ]:          0 :         if (!ieee80211_is_data(hdr->frame_control) &&
     509         [ #  # ]:          0 :             !ieee80211_is_robust_mgmt_frame(skb))
     510                 :            :                 return RX_CONTINUE;
     511                 :            : 
     512         [ #  # ]:          0 :         if (status->flag & RX_FLAG_DECRYPTED) {
     513         [ #  # ]:          0 :                 if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_CCMP_HDR_LEN))
     514                 :            :                         return RX_DROP_UNUSABLE;
     515         [ #  # ]:          0 :                 if (status->flag & RX_FLAG_MIC_STRIPPED)
     516                 :          0 :                         mic_len = 0;
     517                 :            :         } else {
     518         [ #  # ]:          0 :                 if (skb_linearize(rx->skb))
     519                 :            :                         return RX_DROP_UNUSABLE;
     520                 :            :         }
     521                 :            : 
     522                 :          0 :         data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - mic_len;
     523   [ #  #  #  # ]:          0 :         if (!rx->sta || data_len < 0)
     524                 :            :                 return RX_DROP_UNUSABLE;
     525                 :            : 
     526         [ #  # ]:          0 :         if (!(status->flag & RX_FLAG_PN_VALIDATED)) {
     527                 :          0 :                 int res;
     528                 :            : 
     529                 :          0 :                 ccmp_hdr2pn(pn, skb->data + hdrlen);
     530                 :            : 
     531                 :          0 :                 queue = rx->security_idx;
     532                 :            : 
     533                 :          0 :                 res = memcmp(pn, key->u.ccmp.rx_pn[queue],
     534                 :            :                              IEEE80211_CCMP_PN_LEN);
     535   [ #  #  #  # ]:          0 :                 if (res < 0 ||
     536         [ #  # ]:          0 :                     (!res && !(status->flag & RX_FLAG_ALLOW_SAME_PN))) {
     537                 :          0 :                         key->u.ccmp.replays++;
     538                 :          0 :                         return RX_DROP_UNUSABLE;
     539                 :            :                 }
     540                 :            : 
     541         [ #  # ]:          0 :                 if (!(status->flag & RX_FLAG_DECRYPTED)) {
     542                 :          0 :                         u8 aad[2 * AES_BLOCK_SIZE];
     543                 :          0 :                         u8 b_0[AES_BLOCK_SIZE];
     544                 :            :                         /* hardware didn't decrypt/verify MIC */
     545                 :          0 :                         ccmp_special_blocks(skb, pn, b_0, aad);
     546                 :            : 
     547         [ #  # ]:          0 :                         if (ieee80211_aes_ccm_decrypt(
     548                 :            :                                     key->u.ccmp.tfm, b_0, aad,
     549                 :          0 :                                     skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN,
     550                 :            :                                     data_len,
     551                 :          0 :                                     skb->data + skb->len - mic_len))
     552                 :          0 :                                 return RX_DROP_UNUSABLE;
     553                 :            :                 }
     554                 :            : 
     555                 :          0 :                 memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN);
     556                 :            :         }
     557                 :            : 
     558                 :            :         /* Remove CCMP header and MIC */
     559         [ #  # ]:          0 :         if (pskb_trim(skb, skb->len - mic_len))
     560                 :            :                 return RX_DROP_UNUSABLE;
     561                 :          0 :         memmove(skb->data + IEEE80211_CCMP_HDR_LEN, skb->data, hdrlen);
     562                 :          0 :         skb_pull(skb, IEEE80211_CCMP_HDR_LEN);
     563                 :            : 
     564                 :          0 :         return RX_CONTINUE;
     565                 :            : }
     566                 :            : 
     567                 :            : static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad)
     568                 :            : {
     569                 :            :         __le16 mask_fc;
     570                 :            :         u8 qos_tid;
     571                 :            :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
     572                 :            : 
     573                 :            :         memcpy(j_0, hdr->addr2, ETH_ALEN);
     574                 :            :         memcpy(&j_0[ETH_ALEN], pn, IEEE80211_GCMP_PN_LEN);
     575                 :            :         j_0[13] = 0;
     576                 :            :         j_0[14] = 0;
     577                 :            :         j_0[AES_BLOCK_SIZE - 1] = 0x01;
     578                 :            : 
     579                 :            :         /* AAD (extra authenticate-only data) / masked 802.11 header
     580                 :            :          * FC | A1 | A2 | A3 | SC | [A4] | [QC]
     581                 :            :          */
     582                 :            :         put_unaligned_be16(ieee80211_hdrlen(hdr->frame_control) - 2, &aad[0]);
     583                 :            :         /* Mask FC: zero subtype b4 b5 b6 (if not mgmt)
     584                 :            :          * Retry, PwrMgt, MoreData; set Protected
     585                 :            :          */
     586                 :            :         mask_fc = hdr->frame_control;
     587                 :            :         mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY |
     588                 :            :                                 IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA);
     589                 :            :         if (!ieee80211_is_mgmt(hdr->frame_control))
     590                 :            :                 mask_fc &= ~cpu_to_le16(0x0070);
     591                 :            :         mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
     592                 :            : 
     593                 :            :         put_unaligned(mask_fc, (__le16 *)&aad[2]);
     594                 :            :         memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
     595                 :            : 
     596                 :            :         /* Mask Seq#, leave Frag# */
     597                 :            :         aad[22] = *((u8 *)&hdr->seq_ctrl) & 0x0f;
     598                 :            :         aad[23] = 0;
     599                 :            : 
     600                 :            :         if (ieee80211_is_data_qos(hdr->frame_control))
     601                 :            :                 qos_tid = ieee80211_get_tid(hdr);
     602                 :            :         else
     603                 :            :                 qos_tid = 0;
     604                 :            : 
     605                 :            :         if (ieee80211_has_a4(hdr->frame_control)) {
     606                 :            :                 memcpy(&aad[24], hdr->addr4, ETH_ALEN);
     607                 :            :                 aad[30] = qos_tid;
     608                 :            :                 aad[31] = 0;
     609                 :            :         } else {
     610                 :            :                 memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN);
     611                 :            :                 aad[24] = qos_tid;
     612                 :            :         }
     613                 :            : }
     614                 :            : 
     615                 :            : static inline void gcmp_pn2hdr(u8 *hdr, const u8 *pn, int key_id)
     616                 :            : {
     617                 :            :         hdr[0] = pn[5];
     618                 :            :         hdr[1] = pn[4];
     619                 :            :         hdr[2] = 0;
     620                 :            :         hdr[3] = 0x20 | (key_id << 6);
     621                 :            :         hdr[4] = pn[3];
     622                 :            :         hdr[5] = pn[2];
     623                 :            :         hdr[6] = pn[1];
     624                 :            :         hdr[7] = pn[0];
     625                 :            : }
     626                 :            : 
     627                 :          0 : static inline void gcmp_hdr2pn(u8 *pn, const u8 *hdr)
     628                 :            : {
     629                 :          0 :         pn[0] = hdr[7];
     630                 :          0 :         pn[1] = hdr[6];
     631                 :          0 :         pn[2] = hdr[5];
     632                 :          0 :         pn[3] = hdr[4];
     633                 :          0 :         pn[4] = hdr[1];
     634                 :          0 :         pn[5] = hdr[0];
     635                 :            : }
     636                 :            : 
     637                 :            : static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
     638                 :            : {
     639                 :            :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
     640                 :            :         struct ieee80211_key *key = tx->key;
     641                 :            :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
     642                 :            :         int hdrlen, len, tail;
     643                 :            :         u8 *pos;
     644                 :            :         u8 pn[6];
     645                 :            :         u64 pn64;
     646                 :            :         u8 aad[GCM_AAD_LEN];
     647                 :            :         u8 j_0[AES_BLOCK_SIZE];
     648                 :            : 
     649                 :            :         if (info->control.hw_key &&
     650                 :            :             !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
     651                 :            :             !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
     652                 :            :             !((info->control.hw_key->flags &
     653                 :            :                IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) &&
     654                 :            :               ieee80211_is_mgmt(hdr->frame_control))) {
     655                 :            :                 /* hwaccel has no need for preallocated room for GCMP
     656                 :            :                  * header or MIC fields
     657                 :            :                  */
     658                 :            :                 return 0;
     659                 :            :         }
     660                 :            : 
     661                 :            :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     662                 :            :         len = skb->len - hdrlen;
     663                 :            : 
     664                 :            :         if (info->control.hw_key)
     665                 :            :                 tail = 0;
     666                 :            :         else
     667                 :            :                 tail = IEEE80211_GCMP_MIC_LEN;
     668                 :            : 
     669                 :            :         if (WARN_ON(skb_tailroom(skb) < tail ||
     670                 :            :                     skb_headroom(skb) < IEEE80211_GCMP_HDR_LEN))
     671                 :            :                 return -1;
     672                 :            : 
     673                 :            :         pos = skb_push(skb, IEEE80211_GCMP_HDR_LEN);
     674                 :            :         memmove(pos, pos + IEEE80211_GCMP_HDR_LEN, hdrlen);
     675                 :            :         skb_set_network_header(skb, skb_network_offset(skb) +
     676                 :            :                                     IEEE80211_GCMP_HDR_LEN);
     677                 :            : 
     678                 :            :         /* the HW only needs room for the IV, but not the actual IV */
     679                 :            :         if (info->control.hw_key &&
     680                 :            :             (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
     681                 :            :                 return 0;
     682                 :            : 
     683                 :            :         hdr = (struct ieee80211_hdr *)pos;
     684                 :            :         pos += hdrlen;
     685                 :            : 
     686                 :            :         pn64 = atomic64_inc_return(&key->conf.tx_pn);
     687                 :            : 
     688                 :            :         pn[5] = pn64;
     689                 :            :         pn[4] = pn64 >> 8;
     690                 :            :         pn[3] = pn64 >> 16;
     691                 :            :         pn[2] = pn64 >> 24;
     692                 :            :         pn[1] = pn64 >> 32;
     693                 :            :         pn[0] = pn64 >> 40;
     694                 :            : 
     695                 :            :         gcmp_pn2hdr(pos, pn, key->conf.keyidx);
     696                 :            : 
     697                 :            :         /* hwaccel - with software GCMP header */
     698                 :            :         if (info->control.hw_key)
     699                 :            :                 return 0;
     700                 :            : 
     701                 :            :         pos += IEEE80211_GCMP_HDR_LEN;
     702                 :            :         gcmp_special_blocks(skb, pn, j_0, aad);
     703                 :            :         return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len,
     704                 :            :                                          skb_put(skb, IEEE80211_GCMP_MIC_LEN));
     705                 :            : }
     706                 :            : 
     707                 :            : ieee80211_tx_result
     708                 :          0 : ieee80211_crypto_gcmp_encrypt(struct ieee80211_tx_data *tx)
     709                 :            : {
     710                 :          0 :         struct sk_buff *skb;
     711                 :            : 
     712                 :          0 :         ieee80211_tx_set_protected(tx);
     713                 :            : 
     714         [ #  # ]:          0 :         skb_queue_walk(&tx->skbs, skb) {
     715         [ #  # ]:          0 :                 if (gcmp_encrypt_skb(tx, skb) < 0)
     716                 :            :                         return TX_DROP;
     717                 :            :         }
     718                 :            : 
     719                 :            :         return TX_CONTINUE;
     720                 :            : }
     721                 :            : 
     722                 :            : ieee80211_rx_result
     723                 :          0 : ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx)
     724                 :            : {
     725                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
     726                 :          0 :         int hdrlen;
     727                 :          0 :         struct ieee80211_key *key = rx->key;
     728                 :          0 :         struct sk_buff *skb = rx->skb;
     729         [ #  # ]:          0 :         struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
     730                 :          0 :         u8 pn[IEEE80211_GCMP_PN_LEN];
     731                 :          0 :         int data_len, queue, mic_len = IEEE80211_GCMP_MIC_LEN;
     732                 :            : 
     733                 :          0 :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     734                 :            : 
     735   [ #  #  #  # ]:          0 :         if (!ieee80211_is_data(hdr->frame_control) &&
     736         [ #  # ]:          0 :             !ieee80211_is_robust_mgmt_frame(skb))
     737                 :            :                 return RX_CONTINUE;
     738                 :            : 
     739         [ #  # ]:          0 :         if (status->flag & RX_FLAG_DECRYPTED) {
     740         [ #  # ]:          0 :                 if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_GCMP_HDR_LEN))
     741                 :            :                         return RX_DROP_UNUSABLE;
     742         [ #  # ]:          0 :                 if (status->flag & RX_FLAG_MIC_STRIPPED)
     743                 :          0 :                         mic_len = 0;
     744                 :            :         } else {
     745         [ #  # ]:          0 :                 if (skb_linearize(rx->skb))
     746                 :            :                         return RX_DROP_UNUSABLE;
     747                 :            :         }
     748                 :            : 
     749                 :          0 :         data_len = skb->len - hdrlen - IEEE80211_GCMP_HDR_LEN - mic_len;
     750   [ #  #  #  # ]:          0 :         if (!rx->sta || data_len < 0)
     751                 :            :                 return RX_DROP_UNUSABLE;
     752                 :            : 
     753         [ #  # ]:          0 :         if (!(status->flag & RX_FLAG_PN_VALIDATED)) {
     754                 :          0 :                 int res;
     755                 :            : 
     756                 :          0 :                 gcmp_hdr2pn(pn, skb->data + hdrlen);
     757                 :            : 
     758                 :          0 :                 queue = rx->security_idx;
     759                 :            : 
     760                 :          0 :                 res = memcmp(pn, key->u.gcmp.rx_pn[queue],
     761                 :            :                              IEEE80211_GCMP_PN_LEN);
     762   [ #  #  #  # ]:          0 :                 if (res < 0 ||
     763         [ #  # ]:          0 :                     (!res && !(status->flag & RX_FLAG_ALLOW_SAME_PN))) {
     764                 :          0 :                         key->u.gcmp.replays++;
     765                 :          0 :                         return RX_DROP_UNUSABLE;
     766                 :            :                 }
     767                 :            : 
     768         [ #  # ]:          0 :                 if (!(status->flag & RX_FLAG_DECRYPTED)) {
     769                 :          0 :                         u8 aad[2 * AES_BLOCK_SIZE];
     770                 :          0 :                         u8 j_0[AES_BLOCK_SIZE];
     771                 :            :                         /* hardware didn't decrypt/verify MIC */
     772                 :          0 :                         gcmp_special_blocks(skb, pn, j_0, aad);
     773                 :            : 
     774         [ #  # ]:          0 :                         if (ieee80211_aes_gcm_decrypt(
     775                 :            :                                     key->u.gcmp.tfm, j_0, aad,
     776                 :          0 :                                     skb->data + hdrlen + IEEE80211_GCMP_HDR_LEN,
     777                 :            :                                     data_len,
     778                 :          0 :                                     skb->data + skb->len -
     779                 :            :                                     IEEE80211_GCMP_MIC_LEN))
     780                 :          0 :                                 return RX_DROP_UNUSABLE;
     781                 :            :                 }
     782                 :            : 
     783                 :          0 :                 memcpy(key->u.gcmp.rx_pn[queue], pn, IEEE80211_GCMP_PN_LEN);
     784                 :            :         }
     785                 :            : 
     786                 :            :         /* Remove GCMP header and MIC */
     787         [ #  # ]:          0 :         if (pskb_trim(skb, skb->len - mic_len))
     788                 :            :                 return RX_DROP_UNUSABLE;
     789                 :          0 :         memmove(skb->data + IEEE80211_GCMP_HDR_LEN, skb->data, hdrlen);
     790                 :          0 :         skb_pull(skb, IEEE80211_GCMP_HDR_LEN);
     791                 :            : 
     792                 :          0 :         return RX_CONTINUE;
     793                 :            : }
     794                 :            : 
     795                 :            : static ieee80211_tx_result
     796                 :            : ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
     797                 :            :                             struct sk_buff *skb)
     798                 :            : {
     799                 :            :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
     800                 :            :         struct ieee80211_key *key = tx->key;
     801                 :            :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
     802                 :            :         int hdrlen;
     803                 :            :         u8 *pos, iv_len = key->conf.iv_len;
     804                 :            : 
     805                 :            :         if (info->control.hw_key &&
     806                 :            :             !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
     807                 :            :                 /* hwaccel has no need for preallocated head room */
     808                 :            :                 return TX_CONTINUE;
     809                 :            :         }
     810                 :            : 
     811                 :            :         if (unlikely(skb_headroom(skb) < iv_len &&
     812                 :            :                      pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC)))
     813                 :            :                 return TX_DROP;
     814                 :            : 
     815                 :            :         hdrlen = ieee80211_hdrlen(hdr->frame_control);
     816                 :            : 
     817                 :            :         pos = skb_push(skb, iv_len);
     818                 :            :         memmove(pos, pos + iv_len, hdrlen);
     819                 :            : 
     820                 :            :         return TX_CONTINUE;
     821                 :            : }
     822                 :            : 
     823                 :          0 : static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len)
     824                 :            : {
     825                 :          0 :         int i;
     826                 :            : 
     827                 :            :         /* pn is little endian */
     828         [ #  # ]:          0 :         for (i = len - 1; i >= 0; i--) {
     829         [ #  # ]:          0 :                 if (pn1[i] < pn2[i])
     830                 :            :                         return -1;
     831         [ #  # ]:          0 :                 else if (pn1[i] > pn2[i])
     832                 :            :                         return 1;
     833                 :            :         }
     834                 :            : 
     835                 :            :         return 0;
     836                 :            : }
     837                 :            : 
     838                 :            : static ieee80211_rx_result
     839                 :          0 : ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx)
     840                 :            : {
     841                 :          0 :         struct ieee80211_key *key = rx->key;
     842                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
     843                 :          0 :         const struct ieee80211_cipher_scheme *cs = NULL;
     844                 :          0 :         int hdrlen = ieee80211_hdrlen(hdr->frame_control);
     845         [ #  # ]:          0 :         struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
     846                 :          0 :         int data_len;
     847                 :          0 :         u8 *rx_pn;
     848                 :          0 :         u8 *skb_pn;
     849                 :          0 :         u8 qos_tid;
     850                 :            : 
     851   [ #  #  #  # ]:          0 :         if (!rx->sta || !rx->sta->cipher_scheme ||
     852         [ #  # ]:          0 :             !(status->flag & RX_FLAG_DECRYPTED))
     853                 :            :                 return RX_DROP_UNUSABLE;
     854                 :            : 
     855         [ #  # ]:          0 :         if (!ieee80211_is_data(hdr->frame_control))
     856                 :            :                 return RX_CONTINUE;
     857                 :            : 
     858                 :          0 :         cs = rx->sta->cipher_scheme;
     859                 :            : 
     860                 :          0 :         data_len = rx->skb->len - hdrlen - cs->hdr_len;
     861                 :            : 
     862         [ #  # ]:          0 :         if (data_len < 0)
     863                 :            :                 return RX_DROP_UNUSABLE;
     864                 :            : 
     865         [ #  # ]:          0 :         if (ieee80211_is_data_qos(hdr->frame_control))
     866         [ #  # ]:          0 :                 qos_tid = ieee80211_get_tid(hdr);
     867                 :            :         else
     868                 :            :                 qos_tid = 0;
     869                 :            : 
     870         [ #  # ]:          0 :         if (skb_linearize(rx->skb))
     871                 :            :                 return RX_DROP_UNUSABLE;
     872                 :            : 
     873                 :          0 :         hdr = (struct ieee80211_hdr *)rx->skb->data;
     874                 :            : 
     875                 :          0 :         rx_pn = key->u.gen.rx_pn[qos_tid];
     876                 :          0 :         skb_pn = rx->skb->data + hdrlen + cs->pn_off;
     877                 :            : 
     878         [ #  # ]:          0 :         if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0)
     879                 :            :                 return RX_DROP_UNUSABLE;
     880                 :            : 
     881                 :          0 :         memcpy(rx_pn, skb_pn, cs->pn_len);
     882                 :            : 
     883                 :            :         /* remove security header and MIC */
     884         [ #  # ]:          0 :         if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len))
     885                 :            :                 return RX_DROP_UNUSABLE;
     886                 :            : 
     887                 :          0 :         memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen);
     888                 :          0 :         skb_pull(rx->skb, cs->hdr_len);
     889                 :            : 
     890                 :          0 :         return RX_CONTINUE;
     891                 :            : }
     892                 :            : 
     893                 :          0 : static void bip_aad(struct sk_buff *skb, u8 *aad)
     894                 :            : {
     895                 :          0 :         __le16 mask_fc;
     896                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
     897                 :            : 
     898                 :            :         /* BIP AAD: FC(masked) || A1 || A2 || A3 */
     899                 :            : 
     900                 :            :         /* FC type/subtype */
     901                 :            :         /* Mask FC Retry, PwrMgt, MoreData flags to zero */
     902                 :          0 :         mask_fc = hdr->frame_control;
     903                 :          0 :         mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM |
     904                 :            :                                 IEEE80211_FCTL_MOREDATA);
     905                 :          0 :         put_unaligned(mask_fc, (__le16 *) &aad[0]);
     906                 :            :         /* A1 || A2 || A3 */
     907                 :          0 :         memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN);
     908                 :            : }
     909                 :            : 
     910                 :            : 
     911                 :          0 : static inline void bip_ipn_set64(u8 *d, u64 pn)
     912                 :            : {
     913                 :          0 :         *d++ = pn;
     914                 :          0 :         *d++ = pn >> 8;
     915                 :          0 :         *d++ = pn >> 16;
     916                 :          0 :         *d++ = pn >> 24;
     917                 :          0 :         *d++ = pn >> 32;
     918                 :          0 :         *d = pn >> 40;
     919                 :            : }
     920                 :            : 
     921                 :          0 : static inline void bip_ipn_swap(u8 *d, const u8 *s)
     922                 :            : {
     923                 :          0 :         *d++ = s[5];
     924                 :          0 :         *d++ = s[4];
     925                 :          0 :         *d++ = s[3];
     926                 :          0 :         *d++ = s[2];
     927                 :          0 :         *d++ = s[1];
     928                 :          0 :         *d = s[0];
     929                 :            : }
     930                 :            : 
     931                 :            : 
     932                 :            : ieee80211_tx_result
     933                 :          0 : ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
     934                 :            : {
     935                 :          0 :         struct sk_buff *skb;
     936                 :          0 :         struct ieee80211_tx_info *info;
     937                 :          0 :         struct ieee80211_key *key = tx->key;
     938                 :          0 :         struct ieee80211_mmie *mmie;
     939                 :          0 :         u8 aad[20];
     940                 :          0 :         u64 pn64;
     941                 :            : 
     942   [ #  #  #  # ]:          0 :         if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
     943                 :            :                 return TX_DROP;
     944                 :            : 
     945         [ #  # ]:          0 :         skb = skb_peek(&tx->skbs);
     946                 :            : 
     947         [ #  # ]:          0 :         info = IEEE80211_SKB_CB(skb);
     948                 :            : 
     949         [ #  # ]:          0 :         if (info->control.hw_key &&
     950         [ #  # ]:          0 :             !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIE))
     951                 :            :                 return TX_CONTINUE;
     952                 :            : 
     953   [ #  #  #  #  :          0 :         if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
                   #  # ]
     954                 :            :                 return TX_DROP;
     955                 :            : 
     956                 :          0 :         mmie = skb_put(skb, sizeof(*mmie));
     957                 :          0 :         mmie->element_id = WLAN_EID_MMIE;
     958                 :          0 :         mmie->length = sizeof(*mmie) - 2;
     959                 :          0 :         mmie->key_id = cpu_to_le16(key->conf.keyidx);
     960                 :            : 
     961                 :            :         /* PN = PN + 1 */
     962                 :          0 :         pn64 = atomic64_inc_return(&key->conf.tx_pn);
     963                 :            : 
     964                 :          0 :         bip_ipn_set64(mmie->sequence_number, pn64);
     965                 :            : 
     966         [ #  # ]:          0 :         if (info->control.hw_key)
     967                 :            :                 return TX_CONTINUE;
     968                 :            : 
     969                 :          0 :         bip_aad(skb, aad);
     970                 :            : 
     971                 :            :         /*
     972                 :            :          * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
     973                 :            :          */
     974                 :          0 :         ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad,
     975                 :          0 :                            skb->data + 24, skb->len - 24, mmie->mic);
     976                 :            : 
     977                 :          0 :         return TX_CONTINUE;
     978                 :            : }
     979                 :            : 
     980                 :            : ieee80211_tx_result
     981                 :          0 : ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx)
     982                 :            : {
     983                 :          0 :         struct sk_buff *skb;
     984                 :          0 :         struct ieee80211_tx_info *info;
     985                 :          0 :         struct ieee80211_key *key = tx->key;
     986                 :          0 :         struct ieee80211_mmie_16 *mmie;
     987                 :          0 :         u8 aad[20];
     988                 :          0 :         u64 pn64;
     989                 :            : 
     990   [ #  #  #  # ]:          0 :         if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
     991                 :            :                 return TX_DROP;
     992                 :            : 
     993         [ #  # ]:          0 :         skb = skb_peek(&tx->skbs);
     994                 :            : 
     995         [ #  # ]:          0 :         info = IEEE80211_SKB_CB(skb);
     996                 :            : 
     997         [ #  # ]:          0 :         if (info->control.hw_key)
     998                 :            :                 return TX_CONTINUE;
     999                 :            : 
    1000   [ #  #  #  #  :          0 :         if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
                   #  # ]
    1001                 :            :                 return TX_DROP;
    1002                 :            : 
    1003                 :          0 :         mmie = skb_put(skb, sizeof(*mmie));
    1004                 :          0 :         mmie->element_id = WLAN_EID_MMIE;
    1005                 :          0 :         mmie->length = sizeof(*mmie) - 2;
    1006                 :          0 :         mmie->key_id = cpu_to_le16(key->conf.keyidx);
    1007                 :            : 
    1008                 :            :         /* PN = PN + 1 */
    1009                 :          0 :         pn64 = atomic64_inc_return(&key->conf.tx_pn);
    1010                 :            : 
    1011                 :          0 :         bip_ipn_set64(mmie->sequence_number, pn64);
    1012                 :            : 
    1013                 :          0 :         bip_aad(skb, aad);
    1014                 :            : 
    1015                 :            :         /* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128)
    1016                 :            :          */
    1017                 :          0 :         ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad,
    1018                 :          0 :                                skb->data + 24, skb->len - 24, mmie->mic);
    1019                 :            : 
    1020                 :          0 :         return TX_CONTINUE;
    1021                 :            : }
    1022                 :            : 
    1023                 :            : ieee80211_rx_result
    1024                 :          0 : ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
    1025                 :            : {
    1026                 :          0 :         struct sk_buff *skb = rx->skb;
    1027         [ #  # ]:          0 :         struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
    1028                 :          0 :         struct ieee80211_key *key = rx->key;
    1029                 :          0 :         struct ieee80211_mmie *mmie;
    1030                 :          0 :         u8 aad[20], mic[8], ipn[6];
    1031                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
    1032                 :            : 
    1033         [ #  # ]:          0 :         if (!ieee80211_is_mgmt(hdr->frame_control))
    1034                 :            :                 return RX_CONTINUE;
    1035                 :            : 
    1036                 :            :         /* management frames are already linear */
    1037                 :            : 
    1038         [ #  # ]:          0 :         if (skb->len < 24 + sizeof(*mmie))
    1039                 :            :                 return RX_DROP_UNUSABLE;
    1040                 :            : 
    1041                 :          0 :         mmie = (struct ieee80211_mmie *)
    1042                 :          0 :                 (skb->data + skb->len - sizeof(*mmie));
    1043         [ #  # ]:          0 :         if (mmie->element_id != WLAN_EID_MMIE ||
    1044         [ #  # ]:          0 :             mmie->length != sizeof(*mmie) - 2)
    1045                 :            :                 return RX_DROP_UNUSABLE; /* Invalid MMIE */
    1046                 :            : 
    1047                 :          0 :         bip_ipn_swap(ipn, mmie->sequence_number);
    1048                 :            : 
    1049         [ #  # ]:          0 :         if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
    1050                 :          0 :                 key->u.aes_cmac.replays++;
    1051                 :          0 :                 return RX_DROP_UNUSABLE;
    1052                 :            :         }
    1053                 :            : 
    1054         [ #  # ]:          0 :         if (!(status->flag & RX_FLAG_DECRYPTED)) {
    1055                 :            :                 /* hardware didn't decrypt/verify MIC */
    1056                 :          0 :                 bip_aad(skb, aad);
    1057                 :          0 :                 ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad,
    1058                 :          0 :                                    skb->data + 24, skb->len - 24, mic);
    1059         [ #  # ]:          0 :                 if (crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) {
    1060                 :          0 :                         key->u.aes_cmac.icverrors++;
    1061                 :          0 :                         return RX_DROP_UNUSABLE;
    1062                 :            :                 }
    1063                 :            :         }
    1064                 :            : 
    1065                 :          0 :         memcpy(key->u.aes_cmac.rx_pn, ipn, 6);
    1066                 :            : 
    1067                 :            :         /* Remove MMIE */
    1068                 :          0 :         skb_trim(skb, skb->len - sizeof(*mmie));
    1069                 :            : 
    1070                 :          0 :         return RX_CONTINUE;
    1071                 :            : }
    1072                 :            : 
    1073                 :            : ieee80211_rx_result
    1074                 :          0 : ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx)
    1075                 :            : {
    1076                 :          0 :         struct sk_buff *skb = rx->skb;
    1077         [ #  # ]:          0 :         struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
    1078                 :          0 :         struct ieee80211_key *key = rx->key;
    1079                 :          0 :         struct ieee80211_mmie_16 *mmie;
    1080                 :          0 :         u8 aad[20], mic[16], ipn[6];
    1081                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
    1082                 :            : 
    1083         [ #  # ]:          0 :         if (!ieee80211_is_mgmt(hdr->frame_control))
    1084                 :            :                 return RX_CONTINUE;
    1085                 :            : 
    1086                 :            :         /* management frames are already linear */
    1087                 :            : 
    1088         [ #  # ]:          0 :         if (skb->len < 24 + sizeof(*mmie))
    1089                 :            :                 return RX_DROP_UNUSABLE;
    1090                 :            : 
    1091                 :          0 :         mmie = (struct ieee80211_mmie_16 *)
    1092                 :          0 :                 (skb->data + skb->len - sizeof(*mmie));
    1093         [ #  # ]:          0 :         if (mmie->element_id != WLAN_EID_MMIE ||
    1094         [ #  # ]:          0 :             mmie->length != sizeof(*mmie) - 2)
    1095                 :            :                 return RX_DROP_UNUSABLE; /* Invalid MMIE */
    1096                 :            : 
    1097                 :          0 :         bip_ipn_swap(ipn, mmie->sequence_number);
    1098                 :            : 
    1099         [ #  # ]:          0 :         if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
    1100                 :          0 :                 key->u.aes_cmac.replays++;
    1101                 :          0 :                 return RX_DROP_UNUSABLE;
    1102                 :            :         }
    1103                 :            : 
    1104         [ #  # ]:          0 :         if (!(status->flag & RX_FLAG_DECRYPTED)) {
    1105                 :            :                 /* hardware didn't decrypt/verify MIC */
    1106                 :          0 :                 bip_aad(skb, aad);
    1107                 :          0 :                 ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad,
    1108                 :          0 :                                        skb->data + 24, skb->len - 24, mic);
    1109         [ #  # ]:          0 :                 if (crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) {
    1110                 :          0 :                         key->u.aes_cmac.icverrors++;
    1111                 :          0 :                         return RX_DROP_UNUSABLE;
    1112                 :            :                 }
    1113                 :            :         }
    1114                 :            : 
    1115                 :          0 :         memcpy(key->u.aes_cmac.rx_pn, ipn, 6);
    1116                 :            : 
    1117                 :            :         /* Remove MMIE */
    1118                 :          0 :         skb_trim(skb, skb->len - sizeof(*mmie));
    1119                 :            : 
    1120                 :          0 :         return RX_CONTINUE;
    1121                 :            : }
    1122                 :            : 
    1123                 :            : ieee80211_tx_result
    1124                 :          0 : ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx)
    1125                 :            : {
    1126                 :          0 :         struct sk_buff *skb;
    1127                 :          0 :         struct ieee80211_tx_info *info;
    1128                 :          0 :         struct ieee80211_key *key = tx->key;
    1129                 :          0 :         struct ieee80211_mmie_16 *mmie;
    1130                 :          0 :         struct ieee80211_hdr *hdr;
    1131                 :          0 :         u8 aad[GMAC_AAD_LEN];
    1132                 :          0 :         u64 pn64;
    1133                 :          0 :         u8 nonce[GMAC_NONCE_LEN];
    1134                 :            : 
    1135   [ #  #  #  # ]:          0 :         if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
    1136                 :            :                 return TX_DROP;
    1137                 :            : 
    1138         [ #  # ]:          0 :         skb = skb_peek(&tx->skbs);
    1139                 :            : 
    1140         [ #  # ]:          0 :         info = IEEE80211_SKB_CB(skb);
    1141                 :            : 
    1142         [ #  # ]:          0 :         if (info->control.hw_key)
    1143                 :            :                 return TX_CONTINUE;
    1144                 :            : 
    1145   [ #  #  #  #  :          0 :         if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
                   #  # ]
    1146                 :            :                 return TX_DROP;
    1147                 :            : 
    1148                 :          0 :         mmie = skb_put(skb, sizeof(*mmie));
    1149                 :          0 :         mmie->element_id = WLAN_EID_MMIE;
    1150                 :          0 :         mmie->length = sizeof(*mmie) - 2;
    1151                 :          0 :         mmie->key_id = cpu_to_le16(key->conf.keyidx);
    1152                 :            : 
    1153                 :            :         /* PN = PN + 1 */
    1154                 :          0 :         pn64 = atomic64_inc_return(&key->conf.tx_pn);
    1155                 :            : 
    1156                 :          0 :         bip_ipn_set64(mmie->sequence_number, pn64);
    1157                 :            : 
    1158                 :          0 :         bip_aad(skb, aad);
    1159                 :            : 
    1160                 :          0 :         hdr = (struct ieee80211_hdr *)skb->data;
    1161                 :          0 :         memcpy(nonce, hdr->addr2, ETH_ALEN);
    1162                 :          0 :         bip_ipn_swap(nonce + ETH_ALEN, mmie->sequence_number);
    1163                 :            : 
    1164                 :            :         /* MIC = AES-GMAC(IGTK, AAD || Management Frame Body || MMIE, 128) */
    1165         [ #  # ]:          0 :         if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce,
    1166                 :          0 :                                skb->data + 24, skb->len - 24, mmie->mic) < 0)
    1167                 :          0 :                 return TX_DROP;
    1168                 :            : 
    1169                 :            :         return TX_CONTINUE;
    1170                 :            : }
    1171                 :            : 
    1172                 :            : ieee80211_rx_result
    1173                 :          0 : ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx)
    1174                 :            : {
    1175                 :          0 :         struct sk_buff *skb = rx->skb;
    1176         [ #  # ]:          0 :         struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
    1177                 :          0 :         struct ieee80211_key *key = rx->key;
    1178                 :          0 :         struct ieee80211_mmie_16 *mmie;
    1179                 :          0 :         u8 aad[GMAC_AAD_LEN], *mic, ipn[6], nonce[GMAC_NONCE_LEN];
    1180                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
    1181                 :            : 
    1182         [ #  # ]:          0 :         if (!ieee80211_is_mgmt(hdr->frame_control))
    1183                 :            :                 return RX_CONTINUE;
    1184                 :            : 
    1185                 :            :         /* management frames are already linear */
    1186                 :            : 
    1187         [ #  # ]:          0 :         if (skb->len < 24 + sizeof(*mmie))
    1188                 :            :                 return RX_DROP_UNUSABLE;
    1189                 :            : 
    1190                 :          0 :         mmie = (struct ieee80211_mmie_16 *)
    1191                 :          0 :                 (skb->data + skb->len - sizeof(*mmie));
    1192         [ #  # ]:          0 :         if (mmie->element_id != WLAN_EID_MMIE ||
    1193         [ #  # ]:          0 :             mmie->length != sizeof(*mmie) - 2)
    1194                 :            :                 return RX_DROP_UNUSABLE; /* Invalid MMIE */
    1195                 :            : 
    1196                 :          0 :         bip_ipn_swap(ipn, mmie->sequence_number);
    1197                 :            : 
    1198         [ #  # ]:          0 :         if (memcmp(ipn, key->u.aes_gmac.rx_pn, 6) <= 0) {
    1199                 :          0 :                 key->u.aes_gmac.replays++;
    1200                 :          0 :                 return RX_DROP_UNUSABLE;
    1201                 :            :         }
    1202                 :            : 
    1203         [ #  # ]:          0 :         if (!(status->flag & RX_FLAG_DECRYPTED)) {
    1204                 :            :                 /* hardware didn't decrypt/verify MIC */
    1205                 :          0 :                 bip_aad(skb, aad);
    1206                 :            : 
    1207                 :          0 :                 memcpy(nonce, hdr->addr2, ETH_ALEN);
    1208                 :          0 :                 memcpy(nonce + ETH_ALEN, ipn, 6);
    1209                 :            : 
    1210                 :          0 :                 mic = kmalloc(GMAC_MIC_LEN, GFP_ATOMIC);
    1211         [ #  # ]:          0 :                 if (!mic)
    1212                 :            :                         return RX_DROP_UNUSABLE;
    1213         [ #  # ]:          0 :                 if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce,
    1214                 :          0 :                                        skb->data + 24, skb->len - 24,
    1215         [ #  # ]:          0 :                                        mic) < 0 ||
    1216                 :          0 :                     crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) {
    1217                 :          0 :                         key->u.aes_gmac.icverrors++;
    1218                 :          0 :                         kfree(mic);
    1219                 :          0 :                         return RX_DROP_UNUSABLE;
    1220                 :            :                 }
    1221                 :          0 :                 kfree(mic);
    1222                 :            :         }
    1223                 :            : 
    1224                 :          0 :         memcpy(key->u.aes_gmac.rx_pn, ipn, 6);
    1225                 :            : 
    1226                 :            :         /* Remove MMIE */
    1227                 :          0 :         skb_trim(skb, skb->len - sizeof(*mmie));
    1228                 :            : 
    1229                 :          0 :         return RX_CONTINUE;
    1230                 :            : }
    1231                 :            : 
    1232                 :            : ieee80211_tx_result
    1233                 :          0 : ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
    1234                 :            : {
    1235                 :          0 :         struct sk_buff *skb;
    1236                 :          0 :         struct ieee80211_tx_info *info = NULL;
    1237                 :          0 :         ieee80211_tx_result res;
    1238                 :            : 
    1239         [ #  # ]:          0 :         skb_queue_walk(&tx->skbs, skb) {
    1240         [ #  # ]:          0 :                 info  = IEEE80211_SKB_CB(skb);
    1241                 :            : 
    1242                 :            :                 /* handle hw-only algorithm */
    1243         [ #  # ]:          0 :                 if (!info->control.hw_key)
    1244                 :            :                         return TX_DROP;
    1245                 :            : 
    1246         [ #  # ]:          0 :                 if (tx->key->flags & KEY_FLAG_CIPHER_SCHEME) {
    1247                 :          0 :                         res = ieee80211_crypto_cs_encrypt(tx, skb);
    1248         [ #  # ]:          0 :                         if (res != TX_CONTINUE)
    1249                 :          0 :                                 return res;
    1250                 :            :                 }
    1251                 :            :         }
    1252                 :            : 
    1253                 :          0 :         ieee80211_tx_set_protected(tx);
    1254                 :            : 
    1255                 :          0 :         return TX_CONTINUE;
    1256                 :            : }
    1257                 :            : 
    1258                 :            : ieee80211_rx_result
    1259                 :          0 : ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx)
    1260                 :            : {
    1261   [ #  #  #  # ]:          0 :         if (rx->sta && rx->sta->cipher_scheme)
    1262                 :          0 :                 return ieee80211_crypto_cs_decrypt(rx);
    1263                 :            : 
    1264                 :            :         return RX_DROP_UNUSABLE;
    1265                 :            : }

Generated by: LCOV version 1.14