243 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>4 <http://rt2x00.serialmonkey.com>5 6 */7 8/*9 Module: rt2x00lib10 Abstract: rt2x00 crypto specific routines.11 */12 13#include <linux/kernel.h>14#include <linux/module.h>15 16#include "rt2x00.h"17#include "rt2x00lib.h"18 19enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)20{21 switch (key->cipher) {22 case WLAN_CIPHER_SUITE_WEP40:23 return CIPHER_WEP64;24 case WLAN_CIPHER_SUITE_WEP104:25 return CIPHER_WEP128;26 case WLAN_CIPHER_SUITE_TKIP:27 return CIPHER_TKIP;28 case WLAN_CIPHER_SUITE_CCMP:29 return CIPHER_AES;30 default:31 return CIPHER_NONE;32 }33}34 35void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,36 struct sk_buff *skb,37 struct txentry_desc *txdesc)38{39 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);40 struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;41 42 if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || !hw_key)43 return;44 45 __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);46 47 txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);48 49 if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)50 __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);51 52 txdesc->key_idx = hw_key->hw_key_idx;53 txdesc->iv_offset = txdesc->header_length;54 txdesc->iv_len = hw_key->iv_len;55 56 if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))57 __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);58 59 if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))60 __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);61}62 63unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,64 struct sk_buff *skb)65{66 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);67 struct ieee80211_key_conf *key = tx_info->control.hw_key;68 unsigned int overhead = 0;69 70 if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || !key)71 return overhead;72 73 /*74 * Extend frame length to include IV/EIV/ICV/MMIC,75 * note that these lengths should only be added when76 * mac80211 does not generate it.77 */78 overhead += key->icv_len;79 80 if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))81 overhead += key->iv_len;82 83 if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {84 if (key->cipher == WLAN_CIPHER_SUITE_TKIP)85 overhead += 8;86 }87 88 return overhead;89}90 91void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, struct txentry_desc *txdesc)92{93 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);94 95 if (unlikely(!txdesc->iv_len))96 return;97 98 /* Copy IV/EIV data */99 memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);100}101 102void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)103{104 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);105 106 if (unlikely(!txdesc->iv_len))107 return;108 109 /* Copy IV/EIV data */110 memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);111 112 /* Move ieee80211 header */113 memmove(skb->data + txdesc->iv_len, skb->data, txdesc->iv_offset);114 115 /* Pull buffer to correct size */116 skb_pull(skb, txdesc->iv_len);117 txdesc->length -= txdesc->iv_len;118 119 /* IV/EIV data has officially been stripped */120 skbdesc->flags |= SKBDESC_IV_STRIPPED;121}122 123void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length)124{125 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);126 const unsigned int iv_len =127 ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4);128 129 if (!(skbdesc->flags & SKBDESC_IV_STRIPPED))130 return;131 132 skb_push(skb, iv_len);133 134 /* Move ieee80211 header */135 memmove(skb->data, skb->data + iv_len, header_length);136 137 /* Copy IV/EIV data */138 memcpy(skb->data + header_length, skbdesc->iv, iv_len);139 140 /* IV/EIV data has returned into the frame */141 skbdesc->flags &= ~SKBDESC_IV_STRIPPED;142}143 144void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,145 unsigned int header_length,146 struct rxdone_entry_desc *rxdesc)147{148 unsigned int payload_len = rxdesc->size - header_length;149 unsigned int align = ALIGN_SIZE(skb, header_length);150 unsigned int iv_len;151 unsigned int icv_len;152 unsigned int transfer = 0;153 154 /*155 * WEP64/WEP128: Provides IV & ICV156 * TKIP: Provides IV/EIV & ICV157 * AES: Provies IV/EIV & ICV158 */159 switch (rxdesc->cipher) {160 case CIPHER_WEP64:161 case CIPHER_WEP128:162 iv_len = 4;163 icv_len = 4;164 break;165 case CIPHER_TKIP:166 iv_len = 8;167 icv_len = 4;168 break;169 case CIPHER_AES:170 iv_len = 8;171 icv_len = 8;172 break;173 default:174 /* Unsupport type */175 return;176 }177 178 /*179 * Make room for new data. There are 2 possibilities180 * either the alignment is already present between181 * the 802.11 header and payload. In that case we182 * have to move the header less than the iv_len183 * since we can use the already available l2pad bytes184 * for the iv data.185 * When the alignment must be added manually we must186 * move the header more then iv_len since we must187 * make room for the payload move as well.188 */189 if (rxdesc->dev_flags & RXDONE_L2PAD) {190 skb_push(skb, iv_len - align);191 skb_put(skb, icv_len);192 193 /* Move ieee80211 header */194 memmove(skb->data + transfer,195 skb->data + transfer + (iv_len - align),196 header_length);197 transfer += header_length;198 } else {199 skb_push(skb, iv_len + align);200 skb_put(skb, icv_len - align);201 202 /* Move ieee80211 header */203 memmove(skb->data + transfer,204 skb->data + transfer + iv_len + align,205 header_length);206 transfer += header_length;207 }208 209 /* Copy IV/EIV data */210 memcpy(skb->data + transfer, rxdesc->iv, iv_len);211 transfer += iv_len;212 213 /*214 * Move payload for alignment purposes. Note that215 * this is only needed when no l2 padding is present.216 */217 if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {218 memmove(skb->data + transfer,219 skb->data + transfer + align,220 payload_len);221 }222 223 /*224 * NOTE: Always count the payload as transferred,225 * even when alignment was set to zero. This is required226 * for determining the correct offset for the ICV data.227 */228 transfer += payload_len;229 230 /*231 * Copy ICV data232 * AES appends 8 bytes, we can't fill the upper233 * 4 bytes, but mac80211 doesn't care about what234 * we provide here anyway and strips it immediately.235 */236 memcpy(skb->data + transfer, &rxdesc->icv, 4);237 transfer += icv_len;238 239 /* IV/EIV/ICV has been inserted into frame */240 rxdesc->size = transfer;241 rxdesc->flags &= ~RX_FLAG_IV_STRIPPED;242}243