Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
0004     <http://rt2x00.serialmonkey.com>
0005 
0006  */
0007 
0008 /*
0009     Module: rt2x00lib
0010     Abstract: rt2x00 crypto specific routines.
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 
0016 #include "rt2x00.h"
0017 #include "rt2x00lib.h"
0018 
0019 enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
0020 {
0021     switch (key->cipher) {
0022     case WLAN_CIPHER_SUITE_WEP40:
0023         return CIPHER_WEP64;
0024     case WLAN_CIPHER_SUITE_WEP104:
0025         return CIPHER_WEP128;
0026     case WLAN_CIPHER_SUITE_TKIP:
0027         return CIPHER_TKIP;
0028     case WLAN_CIPHER_SUITE_CCMP:
0029         return CIPHER_AES;
0030     default:
0031         return CIPHER_NONE;
0032     }
0033 }
0034 
0035 void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
0036                        struct sk_buff *skb,
0037                        struct txentry_desc *txdesc)
0038 {
0039     struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
0040     struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
0041 
0042     if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || !hw_key)
0043         return;
0044 
0045     __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
0046 
0047     txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
0048 
0049     if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
0050         __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
0051 
0052     txdesc->key_idx = hw_key->hw_key_idx;
0053     txdesc->iv_offset = txdesc->header_length;
0054     txdesc->iv_len = hw_key->iv_len;
0055 
0056     if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
0057         __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
0058 
0059     if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
0060         __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
0061 }
0062 
0063 unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
0064                       struct sk_buff *skb)
0065 {
0066     struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
0067     struct ieee80211_key_conf *key = tx_info->control.hw_key;
0068     unsigned int overhead = 0;
0069 
0070     if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || !key)
0071         return overhead;
0072 
0073     /*
0074      * Extend frame length to include IV/EIV/ICV/MMIC,
0075      * note that these lengths should only be added when
0076      * mac80211 does not generate it.
0077      */
0078     overhead += key->icv_len;
0079 
0080     if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
0081         overhead += key->iv_len;
0082 
0083     if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
0084         if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
0085             overhead += 8;
0086     }
0087 
0088     return overhead;
0089 }
0090 
0091 void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
0092 {
0093     struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
0094 
0095     if (unlikely(!txdesc->iv_len))
0096         return;
0097 
0098     /* Copy IV/EIV data */
0099     memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
0100 }
0101 
0102 void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
0103 {
0104     struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
0105 
0106     if (unlikely(!txdesc->iv_len))
0107         return;
0108 
0109     /* Copy IV/EIV data */
0110     memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
0111 
0112     /* Move ieee80211 header */
0113     memmove(skb->data + txdesc->iv_len, skb->data, txdesc->iv_offset);
0114 
0115     /* Pull buffer to correct size */
0116     skb_pull(skb, txdesc->iv_len);
0117     txdesc->length -= txdesc->iv_len;
0118 
0119     /* IV/EIV data has officially been stripped */
0120     skbdesc->flags |= SKBDESC_IV_STRIPPED;
0121 }
0122 
0123 void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length)
0124 {
0125     struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
0126     const unsigned int iv_len =
0127         ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4);
0128 
0129     if (!(skbdesc->flags & SKBDESC_IV_STRIPPED))
0130         return;
0131 
0132     skb_push(skb, iv_len);
0133 
0134     /* Move ieee80211 header */
0135     memmove(skb->data, skb->data + iv_len, header_length);
0136 
0137     /* Copy IV/EIV data */
0138     memcpy(skb->data + header_length, skbdesc->iv, iv_len);
0139 
0140     /* IV/EIV data has returned into the frame */
0141     skbdesc->flags &= ~SKBDESC_IV_STRIPPED;
0142 }
0143 
0144 void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
0145                    unsigned int header_length,
0146                    struct rxdone_entry_desc *rxdesc)
0147 {
0148     unsigned int payload_len = rxdesc->size - header_length;
0149     unsigned int align = ALIGN_SIZE(skb, header_length);
0150     unsigned int iv_len;
0151     unsigned int icv_len;
0152     unsigned int transfer = 0;
0153 
0154     /*
0155      * WEP64/WEP128: Provides IV & ICV
0156      * TKIP: Provides IV/EIV & ICV
0157      * AES: Provies IV/EIV & ICV
0158      */
0159     switch (rxdesc->cipher) {
0160     case CIPHER_WEP64:
0161     case CIPHER_WEP128:
0162         iv_len = 4;
0163         icv_len = 4;
0164         break;
0165     case CIPHER_TKIP:
0166         iv_len = 8;
0167         icv_len = 4;
0168         break;
0169     case CIPHER_AES:
0170         iv_len = 8;
0171         icv_len = 8;
0172         break;
0173     default:
0174         /* Unsupport type */
0175         return;
0176     }
0177 
0178     /*
0179      * Make room for new data. There are 2 possibilities
0180      * either the alignment is already present between
0181      * the 802.11 header and payload. In that case we
0182      * have to move the header less than the iv_len
0183      * since we can use the already available l2pad bytes
0184      * for the iv data.
0185      * When the alignment must be added manually we must
0186      * move the header more then iv_len since we must
0187      * make room for the payload move as well.
0188      */
0189     if (rxdesc->dev_flags & RXDONE_L2PAD) {
0190         skb_push(skb, iv_len - align);
0191         skb_put(skb, icv_len);
0192 
0193         /* Move ieee80211 header */
0194         memmove(skb->data + transfer,
0195             skb->data + transfer + (iv_len - align),
0196             header_length);
0197         transfer += header_length;
0198     } else {
0199         skb_push(skb, iv_len + align);
0200         if (align < icv_len)
0201             skb_put(skb, icv_len - align);
0202         else if (align > icv_len)
0203             skb_trim(skb, rxdesc->size + iv_len + icv_len);
0204 
0205         /* Move ieee80211 header */
0206         memmove(skb->data + transfer,
0207             skb->data + transfer + iv_len + align,
0208             header_length);
0209         transfer += header_length;
0210     }
0211 
0212     /* Copy IV/EIV data */
0213     memcpy(skb->data + transfer, rxdesc->iv, iv_len);
0214     transfer += iv_len;
0215 
0216     /*
0217      * Move payload for alignment purposes. Note that
0218      * this is only needed when no l2 padding is present.
0219      */
0220     if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
0221         memmove(skb->data + transfer,
0222             skb->data + transfer + align,
0223             payload_len);
0224     }
0225 
0226     /*
0227      * NOTE: Always count the payload as transferred,
0228      * even when alignment was set to zero. This is required
0229      * for determining the correct offset for the ICV data.
0230      */
0231     transfer += payload_len;
0232 
0233     /*
0234      * Copy ICV data
0235      * AES appends 8 bytes, we can't fill the upper
0236      * 4 bytes, but mac80211 doesn't care about what
0237      * we provide here anyway and strips it immediately.
0238      */
0239     memcpy(skb->data + transfer, &rxdesc->icv, 4);
0240     transfer += icv_len;
0241 
0242     /* IV/EIV/ICV has been inserted into frame */
0243     rxdesc->size = transfer;
0244     rxdesc->flags &= ~RX_FLAG_IV_STRIPPED;
0245 }