~ubuntu-branches/ubuntu/natty/linux-backports-modules-2.6.38/natty-updates

« back to all changes in this revision

Viewing changes to updates/compat-wireless-2.6.36/net/mac80211/wpa.c

  • Committer: Bazaar Package Importer
  • Author(s): Tim Gardner, Tim Gardner
  • Date: 2011-06-08 10:44:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110608104409-fnl8carkdo15bwsz
Tags: 2.6.38-10.6
[ Tim Gardner ]

Shorten compat-wireless package name to cw to accomodate
CDROM file name length restrictions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2002-2004, Instant802 Networks, Inc.
3
 
 * Copyright 2008, Jouni Malinen <j@w1.fi>
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License version 2 as
7
 
 * published by the Free Software Foundation.
8
 
 */
9
 
 
10
 
#include <linux/netdevice.h>
11
 
#include <linux/types.h>
12
 
#include <linux/skbuff.h>
13
 
#include <linux/compiler.h>
14
 
#include <linux/ieee80211.h>
15
 
#include <linux/gfp.h>
16
 
#include <asm/unaligned.h>
17
 
#include <net/mac80211.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 "wpa.h"
25
 
 
26
 
ieee80211_tx_result
27
 
ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
28
 
{
29
 
        u8 *data, *key, *mic, key_offset;
30
 
        size_t data_len;
31
 
        unsigned int hdrlen;
32
 
        struct ieee80211_hdr *hdr;
33
 
        struct sk_buff *skb = tx->skb;
34
 
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
35
 
        int authenticator;
36
 
        int tail;
37
 
 
38
 
        hdr = (struct ieee80211_hdr *)skb->data;
39
 
        if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
40
 
            !ieee80211_is_data_present(hdr->frame_control))
41
 
                return TX_CONTINUE;
42
 
 
43
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
44
 
        if (skb->len < hdrlen)
45
 
                return TX_DROP;
46
 
 
47
 
        data = skb->data + hdrlen;
48
 
        data_len = skb->len - hdrlen;
49
 
 
50
 
        if (info->control.hw_key &&
51
 
            !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
52
 
            !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
53
 
                /* hwaccel - with no need for SW-generated MMIC */
54
 
                return TX_CONTINUE;
55
 
        }
56
 
 
57
 
        tail = MICHAEL_MIC_LEN;
58
 
        if (!info->control.hw_key)
59
 
                tail += TKIP_ICV_LEN;
60
 
 
61
 
        if (WARN_ON(skb_tailroom(skb) < tail ||
62
 
                    skb_headroom(skb) < TKIP_IV_LEN))
63
 
                return TX_DROP;
64
 
 
65
 
#if 0
66
 
        authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
67
 
#else
68
 
        authenticator = 1;
69
 
#endif
70
 
        key_offset = authenticator ?
71
 
                NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY :
72
 
                NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
73
 
        key = &tx->key->conf.key[key_offset];
74
 
        mic = skb_put(skb, MICHAEL_MIC_LEN);
75
 
        michael_mic(key, hdr, data, data_len, mic);
76
 
 
77
 
        return TX_CONTINUE;
78
 
}
79
 
 
80
 
 
81
 
ieee80211_rx_result
82
 
ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
83
 
{
84
 
        u8 *data, *key = NULL, key_offset;
85
 
        size_t data_len;
86
 
        unsigned int hdrlen;
87
 
        u8 mic[MICHAEL_MIC_LEN];
88
 
        struct sk_buff *skb = rx->skb;
89
 
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
90
 
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
91
 
        int authenticator = 1, wpa_test = 0;
92
 
 
93
 
        /* No way to verify the MIC if the hardware stripped it */
94
 
        if (status->flag & RX_FLAG_MMIC_STRIPPED)
95
 
                return RX_CONTINUE;
96
 
 
97
 
        if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
98
 
            !ieee80211_has_protected(hdr->frame_control) ||
99
 
            !ieee80211_is_data_present(hdr->frame_control))
100
 
                return RX_CONTINUE;
101
 
 
102
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
103
 
        if (skb->len < hdrlen + MICHAEL_MIC_LEN)
104
 
                return RX_DROP_UNUSABLE;
105
 
 
106
 
        data = skb->data + hdrlen;
107
 
        data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
108
 
 
109
 
#if 0
110
 
        authenticator = fc & IEEE80211_FCTL_TODS; /* FIX */
111
 
#else
112
 
        authenticator = 1;
113
 
#endif
114
 
        key_offset = authenticator ?
115
 
                NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
116
 
                NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
117
 
        key = &rx->key->conf.key[key_offset];
118
 
        michael_mic(key, hdr, data, data_len, mic);
119
 
        if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
120
 
                if (!(rx->flags & IEEE80211_RX_RA_MATCH))
121
 
                        return RX_DROP_UNUSABLE;
122
 
 
123
 
                mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
124
 
                                                (void *) skb->data, NULL,
125
 
                                                GFP_ATOMIC);
126
 
                return RX_DROP_UNUSABLE;
127
 
        }
128
 
 
129
 
        /* remove Michael MIC from payload */
130
 
        skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
131
 
 
132
 
        /* update IV in key information to be able to detect replays */
133
 
        rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
134
 
        rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
135
 
 
136
 
        return RX_CONTINUE;
137
 
}
138
 
 
139
 
 
140
 
static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
141
 
{
142
 
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
143
 
        struct ieee80211_key *key = tx->key;
144
 
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
145
 
        unsigned int hdrlen;
146
 
        int len, tail;
147
 
        u8 *pos;
148
 
 
149
 
        if (info->control.hw_key &&
150
 
            !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
151
 
                /* hwaccel - with no need for software-generated IV */
152
 
                return 0;
153
 
        }
154
 
 
155
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
156
 
        len = skb->len - hdrlen;
157
 
 
158
 
        if (info->control.hw_key)
159
 
                tail = 0;
160
 
        else
161
 
                tail = TKIP_ICV_LEN;
162
 
 
163
 
        if (WARN_ON(skb_tailroom(skb) < tail ||
164
 
                    skb_headroom(skb) < TKIP_IV_LEN))
165
 
                return -1;
166
 
 
167
 
        pos = skb_push(skb, TKIP_IV_LEN);
168
 
        memmove(pos, pos + TKIP_IV_LEN, hdrlen);
169
 
        pos += hdrlen;
170
 
 
171
 
        /* Increase IV for the frame */
172
 
        key->u.tkip.tx.iv16++;
173
 
        if (key->u.tkip.tx.iv16 == 0)
174
 
                key->u.tkip.tx.iv32++;
175
 
 
176
 
        pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16);
177
 
 
178
 
        /* hwaccel - with software IV */
179
 
        if (info->control.hw_key)
180
 
                return 0;
181
 
 
182
 
        /* Add room for ICV */
183
 
        skb_put(skb, TKIP_ICV_LEN);
184
 
 
185
 
        hdr = (struct ieee80211_hdr *) skb->data;
186
 
        return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
187
 
                                           key, pos, len, hdr->addr2);
188
 
}
189
 
 
190
 
 
191
 
ieee80211_tx_result
192
 
ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
193
 
{
194
 
        struct sk_buff *skb = tx->skb;
195
 
 
196
 
        ieee80211_tx_set_protected(tx);
197
 
 
198
 
        do {
199
 
                if (tkip_encrypt_skb(tx, skb) < 0)
200
 
                        return TX_DROP;
201
 
        } while ((skb = skb->next));
202
 
 
203
 
        return TX_CONTINUE;
204
 
}
205
 
 
206
 
 
207
 
ieee80211_rx_result
208
 
ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
209
 
{
210
 
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
211
 
        int hdrlen, res, hwaccel = 0, wpa_test = 0;
212
 
        struct ieee80211_key *key = rx->key;
213
 
        struct sk_buff *skb = rx->skb;
214
 
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
215
 
 
216
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
217
 
 
218
 
        if (!ieee80211_is_data(hdr->frame_control))
219
 
                return RX_CONTINUE;
220
 
 
221
 
        if (!rx->sta || skb->len - hdrlen < 12)
222
 
                return RX_DROP_UNUSABLE;
223
 
 
224
 
        if (status->flag & RX_FLAG_DECRYPTED) {
225
 
                if (status->flag & RX_FLAG_IV_STRIPPED) {
226
 
                        /*
227
 
                         * Hardware took care of all processing, including
228
 
                         * replay protection, and stripped the ICV/IV so
229
 
                         * we cannot do any checks here.
230
 
                         */
231
 
                        return RX_CONTINUE;
232
 
                }
233
 
 
234
 
                /* let TKIP code verify IV, but skip decryption */
235
 
                hwaccel = 1;
236
 
        }
237
 
 
238
 
        res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
239
 
                                          key, skb->data + hdrlen,
240
 
                                          skb->len - hdrlen, rx->sta->sta.addr,
241
 
                                          hdr->addr1, hwaccel, rx->queue,
242
 
                                          &rx->tkip_iv32,
243
 
                                          &rx->tkip_iv16);
244
 
        if (res != TKIP_DECRYPT_OK || wpa_test)
245
 
                return RX_DROP_UNUSABLE;
246
 
 
247
 
        /* Trim ICV */
248
 
        skb_trim(skb, skb->len - TKIP_ICV_LEN);
249
 
 
250
 
        /* Remove IV */
251
 
        memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
252
 
        skb_pull(skb, TKIP_IV_LEN);
253
 
 
254
 
        return RX_CONTINUE;
255
 
}
256
 
 
257
 
 
258
 
static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
259
 
                                int encrypted)
260
 
{
261
 
        __le16 mask_fc;
262
 
        int a4_included, mgmt;
263
 
        u8 qos_tid;
264
 
        u8 *b_0, *aad;
265
 
        u16 data_len, len_a;
266
 
        unsigned int hdrlen;
267
 
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
268
 
 
269
 
        b_0 = scratch + 3 * AES_BLOCK_LEN;
270
 
        aad = scratch + 4 * AES_BLOCK_LEN;
271
 
 
272
 
        /*
273
 
         * Mask FC: zero subtype b4 b5 b6 (if not mgmt)
274
 
         * Retry, PwrMgt, MoreData; set Protected
275
 
         */
276
 
        mgmt = ieee80211_is_mgmt(hdr->frame_control);
277
 
        mask_fc = hdr->frame_control;
278
 
        mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY |
279
 
                                IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA);
280
 
        if (!mgmt)
281
 
                mask_fc &= ~cpu_to_le16(0x0070);
282
 
        mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
283
 
 
284
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
285
 
        len_a = hdrlen - 2;
286
 
        a4_included = ieee80211_has_a4(hdr->frame_control);
287
 
 
288
 
        if (ieee80211_is_data_qos(hdr->frame_control))
289
 
                qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
290
 
        else
291
 
                qos_tid = 0;
292
 
 
293
 
        data_len = skb->len - hdrlen - CCMP_HDR_LEN;
294
 
        if (encrypted)
295
 
                data_len -= CCMP_MIC_LEN;
296
 
 
297
 
        /* First block, b_0 */
298
 
        b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
299
 
        /* Nonce: Nonce Flags | A2 | PN
300
 
         * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
301
 
         */
302
 
        b_0[1] = qos_tid | (mgmt << 4);
303
 
        memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
304
 
        memcpy(&b_0[8], pn, CCMP_PN_LEN);
305
 
        /* l(m) */
306
 
        put_unaligned_be16(data_len, &b_0[14]);
307
 
 
308
 
        /* AAD (extra authenticate-only data) / masked 802.11 header
309
 
         * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
310
 
        put_unaligned_be16(len_a, &aad[0]);
311
 
        put_unaligned(mask_fc, (__le16 *)&aad[2]);
312
 
        memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
313
 
 
314
 
        /* Mask Seq#, leave Frag# */
315
 
        aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
316
 
        aad[23] = 0;
317
 
 
318
 
        if (a4_included) {
319
 
                memcpy(&aad[24], hdr->addr4, ETH_ALEN);
320
 
                aad[30] = qos_tid;
321
 
                aad[31] = 0;
322
 
        } else {
323
 
                memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN);
324
 
                aad[24] = qos_tid;
325
 
        }
326
 
}
327
 
 
328
 
 
329
 
static inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id)
330
 
{
331
 
        hdr[0] = pn[5];
332
 
        hdr[1] = pn[4];
333
 
        hdr[2] = 0;
334
 
        hdr[3] = 0x20 | (key_id << 6);
335
 
        hdr[4] = pn[3];
336
 
        hdr[5] = pn[2];
337
 
        hdr[6] = pn[1];
338
 
        hdr[7] = pn[0];
339
 
}
340
 
 
341
 
 
342
 
static inline void ccmp_hdr2pn(u8 *pn, u8 *hdr)
343
 
{
344
 
        pn[0] = hdr[7];
345
 
        pn[1] = hdr[6];
346
 
        pn[2] = hdr[5];
347
 
        pn[3] = hdr[4];
348
 
        pn[4] = hdr[1];
349
 
        pn[5] = hdr[0];
350
 
}
351
 
 
352
 
 
353
 
static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
354
 
{
355
 
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
356
 
        struct ieee80211_key *key = tx->key;
357
 
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
358
 
        int hdrlen, len, tail;
359
 
        u8 *pos, *pn;
360
 
        int i;
361
 
 
362
 
        if (info->control.hw_key &&
363
 
            !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
364
 
                /*
365
 
                 * hwaccel has no need for preallocated room for CCMP
366
 
                 * header or MIC fields
367
 
                 */
368
 
                return 0;
369
 
        }
370
 
 
371
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
372
 
        len = skb->len - hdrlen;
373
 
 
374
 
        if (info->control.hw_key)
375
 
                tail = 0;
376
 
        else
377
 
                tail = CCMP_MIC_LEN;
378
 
 
379
 
        if (WARN_ON(skb_tailroom(skb) < tail ||
380
 
                    skb_headroom(skb) < CCMP_HDR_LEN))
381
 
                return -1;
382
 
 
383
 
        pos = skb_push(skb, CCMP_HDR_LEN);
384
 
        memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
385
 
        hdr = (struct ieee80211_hdr *) pos;
386
 
        pos += hdrlen;
387
 
 
388
 
        /* PN = PN + 1 */
389
 
        pn = key->u.ccmp.tx_pn;
390
 
 
391
 
        for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
392
 
                pn[i]++;
393
 
                if (pn[i])
394
 
                        break;
395
 
        }
396
 
 
397
 
        ccmp_pn2hdr(pos, pn, key->conf.keyidx);
398
 
 
399
 
        /* hwaccel - with software CCMP header */
400
 
        if (info->control.hw_key)
401
 
                return 0;
402
 
 
403
 
        pos += CCMP_HDR_LEN;
404
 
        ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0);
405
 
        ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, key->u.ccmp.tx_crypto_buf, pos, len,
406
 
                                  pos, skb_put(skb, CCMP_MIC_LEN));
407
 
 
408
 
        return 0;
409
 
}
410
 
 
411
 
 
412
 
ieee80211_tx_result
413
 
ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
414
 
{
415
 
        struct sk_buff *skb = tx->skb;
416
 
 
417
 
        ieee80211_tx_set_protected(tx);
418
 
 
419
 
        do {
420
 
                if (ccmp_encrypt_skb(tx, skb) < 0)
421
 
                        return TX_DROP;
422
 
        } while ((skb = skb->next));
423
 
 
424
 
        return TX_CONTINUE;
425
 
}
426
 
 
427
 
 
428
 
ieee80211_rx_result
429
 
ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
430
 
{
431
 
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
432
 
        int hdrlen;
433
 
        struct ieee80211_key *key = rx->key;
434
 
        struct sk_buff *skb = rx->skb;
435
 
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
436
 
        u8 pn[CCMP_PN_LEN];
437
 
        int data_len;
438
 
        int queue;
439
 
 
440
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
441
 
 
442
 
        if (!ieee80211_is_data(hdr->frame_control) &&
443
 
            !ieee80211_is_robust_mgmt_frame(hdr))
444
 
                return RX_CONTINUE;
445
 
 
446
 
        data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
447
 
        if (!rx->sta || data_len < 0)
448
 
                return RX_DROP_UNUSABLE;
449
 
 
450
 
        if ((status->flag & RX_FLAG_DECRYPTED) &&
451
 
            (status->flag & RX_FLAG_IV_STRIPPED))
452
 
                return RX_CONTINUE;
453
 
 
454
 
        ccmp_hdr2pn(pn, skb->data + hdrlen);
455
 
 
456
 
        queue = ieee80211_is_mgmt(hdr->frame_control) ?
457
 
                NUM_RX_DATA_QUEUES : rx->queue;
458
 
 
459
 
        if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) {
460
 
                key->u.ccmp.replays++;
461
 
                return RX_DROP_UNUSABLE;
462
 
        }
463
 
 
464
 
        if (!(status->flag & RX_FLAG_DECRYPTED)) {
465
 
                /* hardware didn't decrypt/verify MIC */
466
 
                ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1);
467
 
 
468
 
                if (ieee80211_aes_ccm_decrypt(
469
 
                            key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf,
470
 
                            skb->data + hdrlen + CCMP_HDR_LEN, data_len,
471
 
                            skb->data + skb->len - CCMP_MIC_LEN,
472
 
                            skb->data + hdrlen + CCMP_HDR_LEN))
473
 
                        return RX_DROP_UNUSABLE;
474
 
        }
475
 
 
476
 
        memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN);
477
 
 
478
 
        /* Remove CCMP header and MIC */
479
 
        skb_trim(skb, skb->len - CCMP_MIC_LEN);
480
 
        memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
481
 
        skb_pull(skb, CCMP_HDR_LEN);
482
 
 
483
 
        return RX_CONTINUE;
484
 
}
485
 
 
486
 
 
487
 
static void bip_aad(struct sk_buff *skb, u8 *aad)
488
 
{
489
 
        /* BIP AAD: FC(masked) || A1 || A2 || A3 */
490
 
 
491
 
        /* FC type/subtype */
492
 
        aad[0] = skb->data[0];
493
 
        /* Mask FC Retry, PwrMgt, MoreData flags to zero */
494
 
        aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6));
495
 
        /* A1 || A2 || A3 */
496
 
        memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN);
497
 
}
498
 
 
499
 
 
500
 
static inline void bip_ipn_swap(u8 *d, const u8 *s)
501
 
{
502
 
        *d++ = s[5];
503
 
        *d++ = s[4];
504
 
        *d++ = s[3];
505
 
        *d++ = s[2];
506
 
        *d++ = s[1];
507
 
        *d = s[0];
508
 
}
509
 
 
510
 
 
511
 
ieee80211_tx_result
512
 
ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
513
 
{
514
 
        struct sk_buff *skb = tx->skb;
515
 
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
516
 
        struct ieee80211_key *key = tx->key;
517
 
        struct ieee80211_mmie *mmie;
518
 
        u8 *pn, aad[20];
519
 
        int i;
520
 
 
521
 
        if (info->control.hw_key)
522
 
                return 0;
523
 
 
524
 
        if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
525
 
                return TX_DROP;
526
 
 
527
 
        mmie = (struct ieee80211_mmie *) skb_put(skb, sizeof(*mmie));
528
 
        mmie->element_id = WLAN_EID_MMIE;
529
 
        mmie->length = sizeof(*mmie) - 2;
530
 
        mmie->key_id = cpu_to_le16(key->conf.keyidx);
531
 
 
532
 
        /* PN = PN + 1 */
533
 
        pn = key->u.aes_cmac.tx_pn;
534
 
 
535
 
        for (i = sizeof(key->u.aes_cmac.tx_pn) - 1; i >= 0; i--) {
536
 
                pn[i]++;
537
 
                if (pn[i])
538
 
                        break;
539
 
        }
540
 
        bip_ipn_swap(mmie->sequence_number, pn);
541
 
 
542
 
        bip_aad(skb, aad);
543
 
 
544
 
        /*
545
 
         * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
546
 
         */
547
 
        ieee80211_aes_cmac(key->u.aes_cmac.tfm, key->u.aes_cmac.tx_crypto_buf,
548
 
                           aad, skb->data + 24, skb->len - 24, mmie->mic);
549
 
 
550
 
        return TX_CONTINUE;
551
 
}
552
 
 
553
 
 
554
 
ieee80211_rx_result
555
 
ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
556
 
{
557
 
        struct sk_buff *skb = rx->skb;
558
 
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
559
 
        struct ieee80211_key *key = rx->key;
560
 
        struct ieee80211_mmie *mmie;
561
 
        u8 aad[20], mic[8], ipn[6];
562
 
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
563
 
 
564
 
        if (!ieee80211_is_mgmt(hdr->frame_control))
565
 
                return RX_CONTINUE;
566
 
 
567
 
        if ((status->flag & RX_FLAG_DECRYPTED) &&
568
 
            (status->flag & RX_FLAG_IV_STRIPPED))
569
 
                return RX_CONTINUE;
570
 
 
571
 
        if (skb->len < 24 + sizeof(*mmie))
572
 
                return RX_DROP_UNUSABLE;
573
 
 
574
 
        mmie = (struct ieee80211_mmie *)
575
 
                (skb->data + skb->len - sizeof(*mmie));
576
 
        if (mmie->element_id != WLAN_EID_MMIE ||
577
 
            mmie->length != sizeof(*mmie) - 2)
578
 
                return RX_DROP_UNUSABLE; /* Invalid MMIE */
579
 
 
580
 
        bip_ipn_swap(ipn, mmie->sequence_number);
581
 
 
582
 
        if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
583
 
                key->u.aes_cmac.replays++;
584
 
                return RX_DROP_UNUSABLE;
585
 
        }
586
 
 
587
 
        if (!(status->flag & RX_FLAG_DECRYPTED)) {
588
 
                /* hardware didn't decrypt/verify MIC */
589
 
                bip_aad(skb, aad);
590
 
                ieee80211_aes_cmac(key->u.aes_cmac.tfm,
591
 
                                   key->u.aes_cmac.rx_crypto_buf, aad,
592
 
                                   skb->data + 24, skb->len - 24, mic);
593
 
                if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) {
594
 
                        key->u.aes_cmac.icverrors++;
595
 
                        return RX_DROP_UNUSABLE;
596
 
                }
597
 
        }
598
 
 
599
 
        memcpy(key->u.aes_cmac.rx_pn, ipn, 6);
600
 
 
601
 
        /* Remove MMIE */
602
 
        skb_trim(skb, skb->len - sizeof(*mmie));
603
 
 
604
 
        return RX_CONTINUE;
605
 
}