summaryrefslogtreecommitdiff
path: root/net/wireless
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@kernel.org>2026-04-07 20:06:47 -0700
committerJohannes Berg <johannes.berg@intel.com>2026-04-08 08:55:15 +0200
commit613c83766884503f0f6bfdc45964c84b5286091c (patch)
treea612b482d484953640eff73f8b954ef0483d818d /net/wireless
parentea06baf59bd4b83c2cb13698411909e5e6be001e (diff)
wifi: mac80211, cfg80211: Export michael_mic() and move it to cfg80211
Export michael_mic() so that the ath11k and ath12k drivers can call it. In addition, move it from mac80211 to cfg80211 so that the ipw2x00 drivers, which depend on cfg80211 but not mac80211, can also call it. Currently these drivers have their own local implementations of michael_mic() based on crypto_shash, which is redundant and inefficient. By consolidating all the Michael MIC code into cfg80211, we'll be able to remove the duplicate Michael MIC code in the crypto/ directory. Signed-off-by: Eric Biggers <ebiggers@kernel.org> Link: https://patch.msgid.link/20260408030651.80336-3-ebiggers@kernel.org Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/michael-mic.c86
2 files changed, 87 insertions, 1 deletions
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 62a83faf0e07..a77fd5ba6368 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
-cfg80211-y += pmsr.o
+cfg80211-y += michael-mic.o pmsr.o
cfg80211-$(CONFIG_OF) += of.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
diff --git a/net/wireless/michael-mic.c b/net/wireless/michael-mic.c
new file mode 100644
index 000000000000..50cdb67f0503
--- /dev/null
+++ b/net/wireless/michael-mic.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Michael MIC implementation - optimized for TKIP MIC operations
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ */
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/ieee80211.h>
+#include <linux/unaligned.h>
+
+struct michael_mic_ctx {
+ u32 l, r;
+};
+
+static void michael_block(struct michael_mic_ctx *mctx, u32 val)
+{
+ mctx->l ^= val;
+ mctx->r ^= rol32(mctx->l, 17);
+ mctx->l += mctx->r;
+ mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) |
+ ((mctx->l & 0x00ff00ff) << 8);
+ mctx->l += mctx->r;
+ mctx->r ^= rol32(mctx->l, 3);
+ mctx->l += mctx->r;
+ mctx->r ^= ror32(mctx->l, 2);
+ mctx->l += mctx->r;
+}
+
+static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key,
+ struct ieee80211_hdr *hdr)
+{
+ u8 *da, *sa, tid;
+
+ da = ieee80211_get_DA(hdr);
+ sa = ieee80211_get_SA(hdr);
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ tid = ieee80211_get_tid(hdr);
+ else
+ tid = 0;
+
+ mctx->l = get_unaligned_le32(key);
+ mctx->r = get_unaligned_le32(key + 4);
+
+ /*
+ * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
+ * calculation, but it is _not_ transmitted
+ */
+ michael_block(mctx, get_unaligned_le32(da));
+ michael_block(mctx, get_unaligned_le16(&da[4]) |
+ (get_unaligned_le16(sa) << 16));
+ michael_block(mctx, get_unaligned_le32(&sa[2]));
+ michael_block(mctx, tid);
+}
+
+void michael_mic(const u8 *key, struct ieee80211_hdr *hdr,
+ const u8 *data, size_t data_len, u8 *mic)
+{
+ u32 val;
+ size_t block, blocks, left;
+ struct michael_mic_ctx mctx;
+
+ michael_mic_hdr(&mctx, key, hdr);
+
+ /* Real data */
+ blocks = data_len / 4;
+ left = data_len % 4;
+
+ for (block = 0; block < blocks; block++)
+ michael_block(&mctx, get_unaligned_le32(&data[block * 4]));
+
+ /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make
+ * total length a multiple of 4. */
+ val = 0x5a;
+ while (left > 0) {
+ val <<= 8;
+ left--;
+ val |= data[blocks * 4 + left];
+ }
+
+ michael_block(&mctx, val);
+ michael_block(&mctx, 0);
+
+ put_unaligned_le32(mctx.l, mic);
+ put_unaligned_le32(mctx.r, mic + 4);
+}
+EXPORT_SYMBOL_GPL(michael_mic);