Merge tag 'irq-urgent-2023-10-28' of git://git.kernel.org/pub/scm/linux/kernel/git...
[platform/kernel/linux-starfive.git] / net / mac80211 / michael.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Michael MIC implementation - optimized for TKIP MIC operations
4  * Copyright 2002-2003, Instant802 Networks, Inc.
5  */
6 #include <linux/types.h>
7 #include <linux/bitops.h>
8 #include <linux/ieee80211.h>
9 #include <asm/unaligned.h>
10
11 #include "michael.h"
12
13 static void michael_block(struct michael_mic_ctx *mctx, u32 val)
14 {
15         mctx->l ^= val;
16         mctx->r ^= rol32(mctx->l, 17);
17         mctx->l += mctx->r;
18         mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) |
19                    ((mctx->l & 0x00ff00ff) << 8);
20         mctx->l += mctx->r;
21         mctx->r ^= rol32(mctx->l, 3);
22         mctx->l += mctx->r;
23         mctx->r ^= ror32(mctx->l, 2);
24         mctx->l += mctx->r;
25 }
26
27 static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key,
28                             struct ieee80211_hdr *hdr)
29 {
30         u8 *da, *sa, tid;
31
32         da = ieee80211_get_DA(hdr);
33         sa = ieee80211_get_SA(hdr);
34         if (ieee80211_is_data_qos(hdr->frame_control))
35                 tid = ieee80211_get_tid(hdr);
36         else
37                 tid = 0;
38
39         mctx->l = get_unaligned_le32(key);
40         mctx->r = get_unaligned_le32(key + 4);
41
42         /*
43          * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
44          * calculation, but it is _not_ transmitted
45          */
46         michael_block(mctx, get_unaligned_le32(da));
47         michael_block(mctx, get_unaligned_le16(&da[4]) |
48                             (get_unaligned_le16(sa) << 16));
49         michael_block(mctx, get_unaligned_le32(&sa[2]));
50         michael_block(mctx, tid);
51 }
52
53 void michael_mic(const u8 *key, struct ieee80211_hdr *hdr,
54                  const u8 *data, size_t data_len, u8 *mic)
55 {
56         u32 val;
57         size_t block, blocks, left;
58         struct michael_mic_ctx mctx;
59
60         michael_mic_hdr(&mctx, key, hdr);
61
62         /* Real data */
63         blocks = data_len / 4;
64         left = data_len % 4;
65
66         for (block = 0; block < blocks; block++)
67                 michael_block(&mctx, get_unaligned_le32(&data[block * 4]));
68
69         /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make
70          * total length a multiple of 4. */
71         val = 0x5a;
72         while (left > 0) {
73                 val <<= 8;
74                 left--;
75                 val |= data[blocks * 4 + left];
76         }
77
78         michael_block(&mctx, val);
79         michael_block(&mctx, 0);
80
81         put_unaligned_le32(mctx.l, mic);
82         put_unaligned_le32(mctx.r, mic + 4);
83 }