1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28
29#include "rt2x00.h"
30#include "rt2x00lib.h"
31
32enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
33{
34 switch (key->cipher) {
35 case WLAN_CIPHER_SUITE_WEP40:
36 return CIPHER_WEP64;
37 case WLAN_CIPHER_SUITE_WEP104:
38 return CIPHER_WEP128;
39 case WLAN_CIPHER_SUITE_TKIP:
40 return CIPHER_TKIP;
41 case WLAN_CIPHER_SUITE_CCMP:
42 return CIPHER_AES;
43 default:
44 return CIPHER_NONE;
45 }
46}
47
48void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
49 struct sk_buff *skb,
50 struct txentry_desc *txdesc)
51{
52 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
53 struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
54
55 if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key)
56 return;
57
58 __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
59
60 txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
61
62 if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
63 __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
64
65 txdesc->key_idx = hw_key->hw_key_idx;
66 txdesc->iv_offset = txdesc->header_length;
67 txdesc->iv_len = hw_key->iv_len;
68
69 if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
70 __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
71
72 if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
73 __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
74}
75
76unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
77 struct sk_buff *skb)
78{
79 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
80 struct ieee80211_key_conf *key = tx_info->control.hw_key;
81 unsigned int overhead = 0;
82
83 if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !key)
84 return overhead;
85
86
87
88
89
90
91 overhead += key->icv_len;
92
93 if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
94 overhead += key->iv_len;
95
96 if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
97 if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
98 overhead += 8;
99 }
100
101 return overhead;
102}
103
104void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
105{
106 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
107
108 if (unlikely(!txdesc->iv_len))
109 return;
110
111
112 memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
113}
114
115void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
116{
117 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
118
119 if (unlikely(!txdesc->iv_len))
120 return;
121
122
123 memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
124
125
126 memmove(skb->data + txdesc->iv_len, skb->data, txdesc->iv_offset);
127
128
129 skb_pull(skb, txdesc->iv_len);
130 txdesc->length -= txdesc->iv_len;
131
132
133 skbdesc->flags |= SKBDESC_IV_STRIPPED;
134}
135
136void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length)
137{
138 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
139 const unsigned int iv_len =
140 ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4);
141
142 if (!(skbdesc->flags & SKBDESC_IV_STRIPPED))
143 return;
144
145 skb_push(skb, iv_len);
146
147
148 memmove(skb->data, skb->data + iv_len, header_length);
149
150
151 memcpy(skb->data + header_length, skbdesc->iv, iv_len);
152
153
154 skbdesc->flags &= ~SKBDESC_IV_STRIPPED;
155}
156
157void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
158 unsigned int header_length,
159 struct rxdone_entry_desc *rxdesc)
160{
161 unsigned int payload_len = rxdesc->size - header_length;
162 unsigned int align = ALIGN_SIZE(skb, header_length);
163 unsigned int iv_len;
164 unsigned int icv_len;
165 unsigned int transfer = 0;
166
167
168
169
170
171
172 switch (rxdesc->cipher) {
173 case CIPHER_WEP64:
174 case CIPHER_WEP128:
175 iv_len = 4;
176 icv_len = 4;
177 break;
178 case CIPHER_TKIP:
179 iv_len = 8;
180 icv_len = 4;
181 break;
182 case CIPHER_AES:
183 iv_len = 8;
184 icv_len = 8;
185 break;
186 default:
187
188 return;
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202 if (rxdesc->dev_flags & RXDONE_L2PAD) {
203 skb_push(skb, iv_len - align);
204 skb_put(skb, icv_len);
205
206
207 memmove(skb->data + transfer,
208 skb->data + transfer + (iv_len - align),
209 header_length);
210 transfer += header_length;
211 } else {
212 skb_push(skb, iv_len + align);
213 if (align < icv_len)
214 skb_put(skb, icv_len - align);
215 else if (align > icv_len)
216 skb_trim(skb, rxdesc->size + iv_len + icv_len);
217
218
219 memmove(skb->data + transfer,
220 skb->data + transfer + iv_len + align,
221 header_length);
222 transfer += header_length;
223 }
224
225
226 memcpy(skb->data + transfer, rxdesc->iv, iv_len);
227 transfer += iv_len;
228
229
230
231
232
233 if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
234 memmove(skb->data + transfer,
235 skb->data + transfer + align,
236 payload_len);
237 }
238
239
240
241
242
243
244 transfer += payload_len;
245
246
247
248
249
250
251
252 memcpy(skb->data + transfer, &rxdesc->icv, 4);
253 transfer += icv_len;
254
255
256 rxdesc->size = transfer;
257 rxdesc->flags &= ~RX_FLAG_IV_STRIPPED;
258}
259