wifi: ipw2x00/lib80211: move remaining lib80211 into libipw
authorJohannes Berg <johannes.berg@intel.com>
Mon, 7 Oct 2024 18:26:55 +0000 (20:26 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 8 Oct 2024 19:52:26 +0000 (21:52 +0200)
There's already much code in libipw that used to be shared
with more drivers, but now with the prior cleanups, those old
Intel ipw2x00 drivers are also the only ones using whatever is
now left of lib80211. Move lib80211 entirely into libipw.

Link: https://patch.msgid.link/20241007202707.915ef7b9e7c7.Ib9876d2fe3c90f11d6df458b16d0b7d4bf551a8d@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
21 files changed:
drivers/net/wireless/intel/ipw2x00/Kconfig
drivers/net/wireless/intel/ipw2x00/Makefile
drivers/net/wireless/intel/ipw2x00/ipw2100.c
drivers/net/wireless/intel/ipw2x00/ipw2200.c
drivers/net/wireless/intel/ipw2x00/ipw2200.h
drivers/net/wireless/intel/ipw2x00/libipw.h
drivers/net/wireless/intel/ipw2x00/libipw_crypto.c [new file with mode: 0644]
drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c [new file with mode: 0644]
drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c [new file with mode: 0644]
drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c [new file with mode: 0644]
drivers/net/wireless/intel/ipw2x00/libipw_module.c
drivers/net/wireless/intel/ipw2x00/libipw_rx.c
drivers/net/wireless/intel/ipw2x00/libipw_tx.c
drivers/net/wireless/intel/ipw2x00/libipw_wx.c
include/net/lib80211.h [deleted file]
net/wireless/Kconfig
net/wireless/Makefile
net/wireless/lib80211.c [deleted file]
net/wireless/lib80211_crypt_ccmp.c [deleted file]
net/wireless/lib80211_crypt_tkip.c [deleted file]
net/wireless/lib80211_crypt_wep.c [deleted file]

index 1650d5865aa027f14eb605636474e8983439257a..d9c042772399978303e698d223b142bdf293920e 100644 (file)
@@ -10,7 +10,6 @@ config IPW2100
        select WEXT_SPY
        select WEXT_PRIV
        select FW_LOADER
-       select LIB80211
        select LIBIPW
        help
          A driver for the Intel PRO/Wireless 2100 Network
@@ -72,7 +71,6 @@ config IPW2200
        select WEXT_SPY
        select WEXT_PRIV
        select FW_LOADER
-       select LIB80211
        select LIBIPW
        help
          A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
@@ -162,10 +160,6 @@ config LIBIPW
        select CRYPTO
        select CRYPTO_MICHAEL_MIC
        select CRC32
-       select LIB80211
-       select LIB80211_CRYPT_WEP
-       select LIB80211_CRYPT_TKIP
-       select LIB80211_CRYPT_CCMP
        help
        This option enables the hardware independent IEEE 802.11
        networking stack.  This component is deprecated in favor of the
index e1ec50359dffc8a1651572c292d02666d4661569..60c5faccbe1548285165a291fd3ca321f9347bc5 100644 (file)
@@ -12,4 +12,8 @@ libipw-objs := \
        libipw_tx.o \
        libipw_rx.o \
        libipw_wx.o \
-       libipw_geo.o
+       libipw_geo.o \
+       libipw_crypto.o \
+       libipw_crypto_ccmp.o \
+       libipw_crypto_tkip.o \
+       libipw_crypto_wep.o
index b6636002c7d220eeeb08b12f2bc23c2dd924455f..a89e06c1b8eee142cfac3704549af6bc9a36b88b 100644 (file)
@@ -148,9 +148,6 @@ that only one external action is invoked at a time.
 #include <linux/acpi.h>
 #include <linux/ctype.h>
 #include <linux/pm_qos.h>
-
-#include <net/lib80211.h>
-
 #include "ipw2100.h"
 #include "ipw.h"
 
@@ -7571,7 +7568,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev,
        struct ipw2100_priv *priv = libipw_priv(dev);
        struct libipw_device *ieee = priv->ieee;
        struct iw_param *param = &wrqu->param;
-       struct lib80211_crypt_data *crypt;
+       struct libipw_crypt_data *crypt;
        unsigned long flags;
        int ret = 0;
 
@@ -7663,7 +7660,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev,
 {
        struct ipw2100_priv *priv = libipw_priv(dev);
        struct libipw_device *ieee = priv->ieee;
-       struct lib80211_crypt_data *crypt;
+       struct libipw_crypt_data *crypt;
        struct iw_param *param = &wrqu->param;
 
        switch (param->flags & IW_AUTH_INDEX) {
index eed9ef17bc29343f49f260adae89106769350263..f4fd1fc784b77c7d5081cb67c224284f0f87cbd3 100644 (file)
@@ -6549,7 +6549,7 @@ static int ipw_wx_set_auth(struct net_device *dev,
        struct ipw_priv *priv = libipw_priv(dev);
        struct libipw_device *ieee = priv->ieee;
        struct iw_param *param = &wrqu->param;
-       struct lib80211_crypt_data *crypt;
+       struct libipw_crypt_data *crypt;
        unsigned long flags;
        int ret = 0;
 
@@ -6648,7 +6648,7 @@ static int ipw_wx_get_auth(struct net_device *dev,
 {
        struct ipw_priv *priv = libipw_priv(dev);
        struct libipw_device *ieee = priv->ieee;
-       struct lib80211_crypt_data *crypt;
+       struct libipw_crypt_data *crypt;
        struct iw_param *param = &wrqu->param;
 
        switch (param->flags & IW_AUTH_INDEX) {
index 8ebf09121e173c7646580f68dac1e4e19f60bf92..46f119123b4930604b4cb12e258112618c0d4073 100644 (file)
@@ -31,8 +31,6 @@
 #include <linux/wireless.h>
 #include <linux/jiffies.h>
 #include <asm/io.h>
-
-#include <net/lib80211.h>
 #include <net/ieee80211_radiotap.h>
 
 #define DRV_NAME       "ipw2200"
index bad080d33c07fcc3629238f441993fdc25449ed3..bc727c99ff3c9faf59b2163119669718d66a5c4e 100644 (file)
@@ -25,8 +25,6 @@
 #include <linux/kernel.h>      /* ARRAY_SIZE */
 #include <linux/wireless.h>
 #include <linux/ieee80211.h>
-
-#include <net/lib80211.h>
 #include <net/cfg80211.h>
 
 #define LIBIPW_VERSION "git-1.1.13"
@@ -699,6 +697,76 @@ struct libipw_geo {
        struct libipw_channel a[LIBIPW_52GHZ_CHANNELS];
 };
 
+#define NUM_WEP_KEYS   4
+
+enum {
+       IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0),
+};
+
+struct module;
+
+struct libipw_crypto_ops {
+       const char *name;
+       struct list_head list;
+
+       /* init new crypto context (e.g., allocate private data space,
+        * select IV, etc.); returns NULL on failure or pointer to allocated
+        * private data on success */
+       void *(*init) (int keyidx);
+
+       /* deinitialize crypto context and free allocated private data */
+       void (*deinit) (void *priv);
+
+       /* encrypt/decrypt return < 0 on error or >= 0 on success. The return
+        * value from decrypt_mpdu is passed as the keyidx value for
+        * decrypt_msdu. skb must have enough head and tail room for the
+        * encryption; if not, error will be returned; these functions are
+        * called for all MPDUs (i.e., fragments).
+        */
+       int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
+       int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
+
+       /* These functions are called for full MSDUs, i.e. full frames.
+        * These can be NULL if full MSDU operations are not needed. */
+       int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv);
+       int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len,
+                            void *priv);
+
+       int (*set_key) (void *key, int len, u8 * seq, void *priv);
+       int (*get_key) (void *key, int len, u8 * seq, void *priv);
+
+       /* procfs handler for printing out key information and possible
+        * statistics */
+       void (*print_stats) (struct seq_file *m, void *priv);
+
+       /* Crypto specific flag get/set for configuration settings */
+       unsigned long (*get_flags) (void *priv);
+       unsigned long (*set_flags) (unsigned long flags, void *priv);
+
+       /* maximum number of bytes added by encryption; encrypt buf is
+        * allocated with extra_prefix_len bytes, copy of in_buf, and
+        * extra_postfix_len; encrypt need not use all this space, but
+        * the result must start at the beginning of the buffer and correct
+        * length must be returned */
+       int extra_mpdu_prefix_len, extra_mpdu_postfix_len;
+       int extra_msdu_prefix_len, extra_msdu_postfix_len;
+
+       struct module *owner;
+};
+
+struct libipw_crypt_info {
+       char *name;
+       /* Most clients will already have a lock,
+          so just point to that. */
+       spinlock_t *lock;
+
+       struct libipw_crypt_data *crypt[NUM_WEP_KEYS];
+       int tx_keyidx;          /* default TX key index (crypt[tx_keyidx]) */
+       struct list_head crypt_deinit_list;
+       struct timer_list crypt_deinit_timer;
+       int crypt_quiesced;
+};
+
 struct libipw_device {
        struct net_device *dev;
        struct wireless_dev wdev;
@@ -751,7 +819,7 @@ struct libipw_device {
        size_t wpa_ie_len;
        u8 *wpa_ie;
 
-       struct lib80211_crypt_info crypt_info;
+       struct libipw_crypt_info crypt_info;
 
        int bcrx_sta_key;       /* use individual keys to override default keys even
                                 * with RX of broad/multicast frames */
@@ -988,4 +1056,31 @@ static inline int libipw_get_scans(struct libipw_device *ieee)
        return ieee->scans;
 }
 
+struct libipw_crypt_data {
+       struct list_head list;  /* delayed deletion list */
+       const struct libipw_crypto_ops *ops;
+       void *priv;
+       atomic_t refcnt;
+};
+
+int libipw_crypt_info_init(struct libipw_crypt_info *info, char *name,
+                          spinlock_t *lock);
+void libipw_crypt_info_free(struct libipw_crypt_info *info);
+int libipw_register_crypto_ops(const struct libipw_crypto_ops *ops);
+int libipw_unregister_crypto_ops(const struct libipw_crypto_ops *ops);
+const struct libipw_crypto_ops *libipw_get_crypto_ops(const char *name);
+void libipw_crypt_delayed_deinit(struct libipw_crypt_info *info,
+                                struct libipw_crypt_data **crypt);
+
+/* must be called in the listed order */
+int libipw_crypto_init(void);
+int libipw_crypto_ccmp_init(void);
+int libipw_crypto_tkip_init(void);
+int libipw_crypto_wep_init(void);
+
+void libipw_crypto_wep_exit(void);
+void libipw_crypto_tkip_exit(void);
+void libipw_crypto_ccmp_exit(void);
+void libipw_crypto_exit(void);
+
 #endif                         /* LIBIPW_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c
new file mode 100644 (file)
index 0000000..32639e0
--- /dev/null
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * libipw -- common bits for IPW drivers
+ *
+ * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com>
+ *
+ * Portions copied from old ieee80211 component, w/ original copyright
+ * notices below:
+ *
+ * Host AP crypto routines
+ *
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+ * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/ieee80211.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "libipw.h"
+
+struct libipw_crypto_alg {
+       struct list_head list;
+       const struct libipw_crypto_ops *ops;
+};
+
+static LIST_HEAD(libipw_crypto_algs);
+static DEFINE_SPINLOCK(libipw_crypto_lock);
+
+static void libipw_crypt_deinit_entries(struct libipw_crypt_info *info,
+                                         int force);
+static void libipw_crypt_quiescing(struct libipw_crypt_info *info);
+static void libipw_crypt_deinit_handler(struct timer_list *t);
+
+int libipw_crypt_info_init(struct libipw_crypt_info *info, char *name,
+                               spinlock_t *lock)
+{
+       memset(info, 0, sizeof(*info));
+
+       info->name = name;
+       info->lock = lock;
+
+       INIT_LIST_HEAD(&info->crypt_deinit_list);
+       timer_setup(&info->crypt_deinit_timer, libipw_crypt_deinit_handler,
+                   0);
+
+       return 0;
+}
+EXPORT_SYMBOL(libipw_crypt_info_init);
+
+void libipw_crypt_info_free(struct libipw_crypt_info *info)
+{
+       int i;
+
+        libipw_crypt_quiescing(info);
+        del_timer_sync(&info->crypt_deinit_timer);
+        libipw_crypt_deinit_entries(info, 1);
+
+        for (i = 0; i < NUM_WEP_KEYS; i++) {
+                struct libipw_crypt_data *crypt = info->crypt[i];
+                if (crypt) {
+                        if (crypt->ops) {
+                                crypt->ops->deinit(crypt->priv);
+                                module_put(crypt->ops->owner);
+                        }
+                        kfree(crypt);
+                        info->crypt[i] = NULL;
+                }
+        }
+}
+EXPORT_SYMBOL(libipw_crypt_info_free);
+
+static void libipw_crypt_deinit_entries(struct libipw_crypt_info *info,
+                                       int force)
+{
+       struct libipw_crypt_data *entry, *next;
+       unsigned long flags;
+
+       spin_lock_irqsave(info->lock, flags);
+       list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
+               if (atomic_read(&entry->refcnt) != 0 && !force)
+                       continue;
+
+               list_del(&entry->list);
+
+               if (entry->ops) {
+                       entry->ops->deinit(entry->priv);
+                       module_put(entry->ops->owner);
+               }
+               kfree(entry);
+       }
+       spin_unlock_irqrestore(info->lock, flags);
+}
+
+/* After this, crypt_deinit_list won't accept new members */
+static void libipw_crypt_quiescing(struct libipw_crypt_info *info)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(info->lock, flags);
+       info->crypt_quiesced = 1;
+       spin_unlock_irqrestore(info->lock, flags);
+}
+
+static void libipw_crypt_deinit_handler(struct timer_list *t)
+{
+       struct libipw_crypt_info *info = from_timer(info, t,
+                                                   crypt_deinit_timer);
+       unsigned long flags;
+
+       libipw_crypt_deinit_entries(info, 0);
+
+       spin_lock_irqsave(info->lock, flags);
+       if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
+               printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
+                      "deletion list\n", info->name);
+               info->crypt_deinit_timer.expires = jiffies + HZ;
+               add_timer(&info->crypt_deinit_timer);
+       }
+       spin_unlock_irqrestore(info->lock, flags);
+}
+
+void libipw_crypt_delayed_deinit(struct libipw_crypt_info *info,
+                                struct libipw_crypt_data **crypt)
+{
+       struct libipw_crypt_data *tmp;
+       unsigned long flags;
+
+       if (*crypt == NULL)
+               return;
+
+       tmp = *crypt;
+       *crypt = NULL;
+
+       /* must not run ops->deinit() while there may be pending encrypt or
+        * decrypt operations. Use a list of delayed deinits to avoid needing
+        * locking. */
+
+       spin_lock_irqsave(info->lock, flags);
+       if (!info->crypt_quiesced) {
+               list_add(&tmp->list, &info->crypt_deinit_list);
+               if (!timer_pending(&info->crypt_deinit_timer)) {
+                       info->crypt_deinit_timer.expires = jiffies + HZ;
+                       add_timer(&info->crypt_deinit_timer);
+               }
+       }
+       spin_unlock_irqrestore(info->lock, flags);
+}
+EXPORT_SYMBOL(libipw_crypt_delayed_deinit);
+
+int libipw_register_crypto_ops(const struct libipw_crypto_ops *ops)
+{
+       unsigned long flags;
+       struct libipw_crypto_alg *alg;
+
+       alg = kzalloc(sizeof(*alg), GFP_KERNEL);
+       if (alg == NULL)
+               return -ENOMEM;
+
+       alg->ops = ops;
+
+       spin_lock_irqsave(&libipw_crypto_lock, flags);
+       list_add(&alg->list, &libipw_crypto_algs);
+       spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+
+       printk(KERN_DEBUG "libipw_crypt: registered algorithm '%s'\n",
+              ops->name);
+
+       return 0;
+}
+EXPORT_SYMBOL(libipw_register_crypto_ops);
+
+int libipw_unregister_crypto_ops(const struct libipw_crypto_ops *ops)
+{
+       struct libipw_crypto_alg *alg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&libipw_crypto_lock, flags);
+       list_for_each_entry(alg, &libipw_crypto_algs, list) {
+               if (alg->ops == ops)
+                       goto found;
+       }
+       spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+       return -EINVAL;
+
+      found:
+       printk(KERN_DEBUG "libipw_crypt: unregistered algorithm '%s'\n",
+              ops->name);
+       list_del(&alg->list);
+       spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+       kfree(alg);
+       return 0;
+}
+EXPORT_SYMBOL(libipw_unregister_crypto_ops);
+
+const struct libipw_crypto_ops *libipw_get_crypto_ops(const char *name)
+{
+       struct libipw_crypto_alg *alg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&libipw_crypto_lock, flags);
+       list_for_each_entry(alg, &libipw_crypto_algs, list) {
+               if (strcmp(alg->ops->name, name) == 0)
+                       goto found;
+       }
+       spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+       return NULL;
+
+      found:
+       spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+       return alg->ops;
+}
+EXPORT_SYMBOL(libipw_get_crypto_ops);
+
+static void *libipw_crypt_null_init(int keyidx)
+{
+       return (void *)1;
+}
+
+static void libipw_crypt_null_deinit(void *priv)
+{
+}
+
+static const struct libipw_crypto_ops libipw_crypt_null = {
+       .name = "NULL",
+       .init = libipw_crypt_null_init,
+       .deinit = libipw_crypt_null_deinit,
+       .owner = THIS_MODULE,
+};
+
+int __init libipw_crypto_init(void)
+{
+       return libipw_register_crypto_ops(&libipw_crypt_null);
+}
+
+void libipw_crypto_exit(void)
+{
+       libipw_unregister_crypto_ops(&libipw_crypt_null);
+       BUG_ON(!list_empty(&libipw_crypto_algs));
+}
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c
new file mode 100644 (file)
index 0000000..bf900d8
--- /dev/null
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * libipw crypt: host-based CCMP encryption implementation for libipw
+ *
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <asm/string.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/crypto.h>
+#include <crypto/aead.h>
+#include "libipw.h"
+
+#define AES_BLOCK_LEN 16
+#define CCMP_HDR_LEN 8
+#define CCMP_MIC_LEN 8
+#define CCMP_TK_LEN 16
+#define CCMP_PN_LEN 6
+
+struct libipw_ccmp_data {
+       u8 key[CCMP_TK_LEN];
+       int key_set;
+
+       u8 tx_pn[CCMP_PN_LEN];
+       u8 rx_pn[CCMP_PN_LEN];
+
+       u32 dot11RSNAStatsCCMPFormatErrors;
+       u32 dot11RSNAStatsCCMPReplays;
+       u32 dot11RSNAStatsCCMPDecryptErrors;
+
+       int key_idx;
+
+       struct crypto_aead *tfm;
+
+       /* scratch buffers for virt_to_page() (crypto API) */
+       u8 tx_aad[2 * AES_BLOCK_LEN];
+       u8 rx_aad[2 * AES_BLOCK_LEN];
+};
+
+static void *libipw_ccmp_init(int key_idx)
+{
+       struct libipw_ccmp_data *priv;
+
+       priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
+       if (priv == NULL)
+               goto fail;
+       priv->key_idx = key_idx;
+
+       priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(priv->tfm)) {
+               priv->tfm = NULL;
+               goto fail;
+       }
+
+       return priv;
+
+      fail:
+       if (priv) {
+               if (priv->tfm)
+                       crypto_free_aead(priv->tfm);
+               kfree(priv);
+       }
+
+       return NULL;
+}
+
+static void libipw_ccmp_deinit(void *priv)
+{
+       struct libipw_ccmp_data *_priv = priv;
+       if (_priv && _priv->tfm)
+               crypto_free_aead(_priv->tfm);
+       kfree(priv);
+}
+
+static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr,
+                               const u8 *pn, u8 *iv, u8 *aad)
+{
+       u8 *pos, qc = 0;
+       size_t aad_len;
+       int a4_included, qc_included;
+
+       a4_included = ieee80211_has_a4(hdr->frame_control);
+       qc_included = ieee80211_is_data_qos(hdr->frame_control);
+
+       aad_len = 22;
+       if (a4_included)
+               aad_len += 6;
+       if (qc_included) {
+               pos = (u8 *) & hdr->addr4;
+               if (a4_included)
+                       pos += 6;
+               qc = *pos & 0x0f;
+               aad_len += 2;
+       }
+
+       /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
+        * mode authentication are not allowed to collide, yet both are derived
+        * from the same vector. We only set L := 1 here to indicate that the
+        * data size can be represented in (L+1) bytes. The CCM layer will take
+        * care of storing the data length in the top (L+1) bytes and setting
+        * and clearing the other bits as is required to derive the two IVs.
+        */
+       iv[0] = 0x1;
+
+       /* Nonce: QC | A2 | PN */
+       iv[1] = qc;
+       memcpy(iv + 2, hdr->addr2, ETH_ALEN);
+       memcpy(iv + 8, pn, CCMP_PN_LEN);
+
+       /* AAD:
+        * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
+        * A1 | A2 | A3
+        * SC with bits 4..15 (seq#) masked to zero
+        * A4 (if present)
+        * QC (if present)
+        */
+       pos = (u8 *) hdr;
+       aad[0] = pos[0] & 0x8f;
+       aad[1] = pos[1] & 0xc7;
+       memcpy(aad + 2, &hdr->addrs, 3 * ETH_ALEN);
+       pos = (u8 *) & hdr->seq_ctrl;
+       aad[20] = pos[0] & 0x0f;
+       aad[21] = 0;            /* all bits masked */
+       memset(aad + 22, 0, 8);
+       if (a4_included)
+               memcpy(aad + 22, hdr->addr4, ETH_ALEN);
+       if (qc_included) {
+               aad[a4_included ? 28 : 22] = qc;
+               /* rest of QC masked */
+       }
+       return aad_len;
+}
+
+static int libipw_ccmp_hdr(struct sk_buff *skb, int hdr_len,
+                             u8 *aeskey, int keylen, void *priv)
+{
+       struct libipw_ccmp_data *key = priv;
+       int i;
+       u8 *pos;
+
+       if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len)
+               return -1;
+
+       if (aeskey != NULL && keylen >= CCMP_TK_LEN)
+               memcpy(aeskey, key->key, CCMP_TK_LEN);
+
+       pos = skb_push(skb, CCMP_HDR_LEN);
+       memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
+       pos += hdr_len;
+
+       i = CCMP_PN_LEN - 1;
+       while (i >= 0) {
+               key->tx_pn[i]++;
+               if (key->tx_pn[i] != 0)
+                       break;
+               i--;
+       }
+
+       *pos++ = key->tx_pn[5];
+       *pos++ = key->tx_pn[4];
+       *pos++ = 0;
+       *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
+       *pos++ = key->tx_pn[3];
+       *pos++ = key->tx_pn[2];
+       *pos++ = key->tx_pn[1];
+       *pos++ = key->tx_pn[0];
+
+       return CCMP_HDR_LEN;
+}
+
+static int libipw_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct libipw_ccmp_data *key = priv;
+       struct ieee80211_hdr *hdr;
+       struct aead_request *req;
+       struct scatterlist sg[2];
+       u8 *aad = key->tx_aad;
+       u8 iv[AES_BLOCK_LEN];
+       int len, data_len, aad_len;
+       int ret;
+
+       if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
+               return -1;
+
+       data_len = skb->len - hdr_len;
+       len = libipw_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
+       if (len < 0)
+               return -1;
+
+       req = aead_request_alloc(key->tfm, GFP_ATOMIC);
+       if (!req)
+               return -ENOMEM;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad);
+
+       skb_put(skb, CCMP_MIC_LEN);
+
+       sg_init_table(sg, 2);
+       sg_set_buf(&sg[0], aad, aad_len);
+       sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN,
+                  data_len + CCMP_MIC_LEN);
+
+       aead_request_set_callback(req, 0, NULL, NULL);
+       aead_request_set_ad(req, aad_len);
+       aead_request_set_crypt(req, sg, sg, data_len, iv);
+
+       ret = crypto_aead_encrypt(req);
+       aead_request_free(req);
+
+       return ret;
+}
+
+/*
+ * deal with seq counter wrapping correctly.
+ * refer to timer_after() for jiffies wrapping handling
+ */
+static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o)
+{
+       u32 iv32_n, iv16_n;
+       u32 iv32_o, iv16_o;
+
+       iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3];
+       iv16_n = (pn_n[4] << 8) | pn_n[5];
+
+       iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3];
+       iv16_o = (pn_o[4] << 8) | pn_o[5];
+
+       if ((s32)iv32_n - (s32)iv32_o < 0 ||
+           (iv32_n == iv32_o && iv16_n <= iv16_o))
+               return 1;
+       return 0;
+}
+
+static int libipw_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct libipw_ccmp_data *key = priv;
+       u8 keyidx, *pos;
+       struct ieee80211_hdr *hdr;
+       struct aead_request *req;
+       struct scatterlist sg[2];
+       u8 *aad = key->rx_aad;
+       u8 iv[AES_BLOCK_LEN];
+       u8 pn[6];
+       int aad_len, ret;
+       size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN;
+
+       if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
+               key->dot11RSNAStatsCCMPFormatErrors++;
+               return -1;
+       }
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       pos = skb->data + hdr_len;
+       keyidx = pos[3];
+       if (!(keyidx & (1 << 5))) {
+               net_dbg_ratelimited("CCMP: received packet without ExtIV flag from %pM\n",
+                                   hdr->addr2);
+               key->dot11RSNAStatsCCMPFormatErrors++;
+               return -2;
+       }
+       keyidx >>= 6;
+       if (key->key_idx != keyidx) {
+               net_dbg_ratelimited("CCMP: RX tkey->key_idx=%d frame keyidx=%d\n",
+                                   key->key_idx, keyidx);
+               return -6;
+       }
+       if (!key->key_set) {
+               net_dbg_ratelimited("CCMP: received packet from %pM with keyid=%d that does not have a configured key\n",
+                                   hdr->addr2, keyidx);
+               return -3;
+       }
+
+       pn[0] = pos[7];
+       pn[1] = pos[6];
+       pn[2] = pos[5];
+       pn[3] = pos[4];
+       pn[4] = pos[1];
+       pn[5] = pos[0];
+       pos += 8;
+
+       if (ccmp_replay_check(pn, key->rx_pn)) {
+#ifdef CONFIG_LIBIPW_DEBUG
+               net_dbg_ratelimited("CCMP: replay detected: STA=%pM previous PN %02x%02x%02x%02x%02x%02x received PN %02x%02x%02x%02x%02x%02x\n",
+                                   hdr->addr2,
+                                   key->rx_pn[0], key->rx_pn[1], key->rx_pn[2],
+                                   key->rx_pn[3], key->rx_pn[4], key->rx_pn[5],
+                                   pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
+#endif
+               key->dot11RSNAStatsCCMPReplays++;
+               return -4;
+       }
+
+       req = aead_request_alloc(key->tfm, GFP_ATOMIC);
+       if (!req)
+               return -ENOMEM;
+
+       aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad);
+
+       sg_init_table(sg, 2);
+       sg_set_buf(&sg[0], aad, aad_len);
+       sg_set_buf(&sg[1], pos, data_len);
+
+       aead_request_set_callback(req, 0, NULL, NULL);
+       aead_request_set_ad(req, aad_len);
+       aead_request_set_crypt(req, sg, sg, data_len, iv);
+
+       ret = crypto_aead_decrypt(req);
+       aead_request_free(req);
+
+       if (ret) {
+               net_dbg_ratelimited("CCMP: decrypt failed: STA=%pM (%d)\n",
+                                   hdr->addr2, ret);
+               key->dot11RSNAStatsCCMPDecryptErrors++;
+               return -5;
+       }
+
+       memcpy(key->rx_pn, pn, CCMP_PN_LEN);
+
+       /* Remove hdr and MIC */
+       memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
+       skb_pull(skb, CCMP_HDR_LEN);
+       skb_trim(skb, skb->len - CCMP_MIC_LEN);
+
+       return keyidx;
+}
+
+static int libipw_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct libipw_ccmp_data *data = priv;
+       int keyidx;
+       struct crypto_aead *tfm = data->tfm;
+
+       keyidx = data->key_idx;
+       memset(data, 0, sizeof(*data));
+       data->key_idx = keyidx;
+       data->tfm = tfm;
+       if (len == CCMP_TK_LEN) {
+               memcpy(data->key, key, CCMP_TK_LEN);
+               data->key_set = 1;
+               if (seq) {
+                       data->rx_pn[0] = seq[5];
+                       data->rx_pn[1] = seq[4];
+                       data->rx_pn[2] = seq[3];
+                       data->rx_pn[3] = seq[2];
+                       data->rx_pn[4] = seq[1];
+                       data->rx_pn[5] = seq[0];
+               }
+               if (crypto_aead_setauthsize(data->tfm, CCMP_MIC_LEN) ||
+                   crypto_aead_setkey(data->tfm, data->key, CCMP_TK_LEN))
+                       return -1;
+       } else if (len == 0)
+               data->key_set = 0;
+       else
+               return -1;
+
+       return 0;
+}
+
+static int libipw_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct libipw_ccmp_data *data = priv;
+
+       if (len < CCMP_TK_LEN)
+               return -1;
+
+       if (!data->key_set)
+               return 0;
+       memcpy(key, data->key, CCMP_TK_LEN);
+
+       if (seq) {
+               seq[0] = data->tx_pn[5];
+               seq[1] = data->tx_pn[4];
+               seq[2] = data->tx_pn[3];
+               seq[3] = data->tx_pn[2];
+               seq[4] = data->tx_pn[1];
+               seq[5] = data->tx_pn[0];
+       }
+
+       return CCMP_TK_LEN;
+}
+
+static void libipw_ccmp_print_stats(struct seq_file *m, void *priv)
+{
+       struct libipw_ccmp_data *ccmp = priv;
+
+       seq_printf(m,
+                  "key[%d] alg=CCMP key_set=%d "
+                  "tx_pn=%02x%02x%02x%02x%02x%02x "
+                  "rx_pn=%02x%02x%02x%02x%02x%02x "
+                  "format_errors=%d replays=%d decrypt_errors=%d\n",
+                  ccmp->key_idx, ccmp->key_set,
+                  ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2],
+                  ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5],
+                  ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2],
+                  ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5],
+                  ccmp->dot11RSNAStatsCCMPFormatErrors,
+                  ccmp->dot11RSNAStatsCCMPReplays,
+                  ccmp->dot11RSNAStatsCCMPDecryptErrors);
+}
+
+static const struct libipw_crypto_ops libipw_crypt_ccmp = {
+       .name = "CCMP",
+       .init = libipw_ccmp_init,
+       .deinit = libipw_ccmp_deinit,
+       .encrypt_mpdu = libipw_ccmp_encrypt,
+       .decrypt_mpdu = libipw_ccmp_decrypt,
+       .encrypt_msdu = NULL,
+       .decrypt_msdu = NULL,
+       .set_key = libipw_ccmp_set_key,
+       .get_key = libipw_ccmp_get_key,
+       .print_stats = libipw_ccmp_print_stats,
+       .extra_mpdu_prefix_len = CCMP_HDR_LEN,
+       .extra_mpdu_postfix_len = CCMP_MIC_LEN,
+       .owner = THIS_MODULE,
+};
+
+int __init libipw_crypto_ccmp_init(void)
+{
+       return libipw_register_crypto_ops(&libipw_crypt_ccmp);
+}
+
+void libipw_crypto_ccmp_exit(void)
+{
+       libipw_unregister_crypto_ops(&libipw_crypt_ccmp);
+}
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
new file mode 100644 (file)
index 0000000..3228869
--- /dev/null
@@ -0,0 +1,728 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * libipw crypt: host-based TKIP encryption implementation for libipw
+ *
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/err.h>
+#include <linux/fips.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/mm.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <asm/string.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <net/iw_handler.h>
+#include <crypto/arc4.h>
+#include <crypto/hash.h>
+#include <linux/crypto.h>
+#include <linux/crc32.h>
+#include "libipw.h"
+
+#define TKIP_HDR_LEN 8
+
+struct libipw_tkip_data {
+#define TKIP_KEY_LEN 32
+       u8 key[TKIP_KEY_LEN];
+       int key_set;
+
+       u32 tx_iv32;
+       u16 tx_iv16;
+       u16 tx_ttak[5];
+       int tx_phase1_done;
+
+       u32 rx_iv32;
+       u16 rx_iv16;
+       u16 rx_ttak[5];
+       int rx_phase1_done;
+       u32 rx_iv32_new;
+       u16 rx_iv16_new;
+
+       u32 dot11RSNAStatsTKIPReplays;
+       u32 dot11RSNAStatsTKIPICVErrors;
+       u32 dot11RSNAStatsTKIPLocalMICFailures;
+
+       int key_idx;
+
+       struct arc4_ctx rx_ctx_arc4;
+       struct arc4_ctx tx_ctx_arc4;
+       struct crypto_shash *rx_tfm_michael;
+       struct crypto_shash *tx_tfm_michael;
+
+       /* scratch buffers for virt_to_page() (crypto API) */
+       u8 rx_hdr[16], tx_hdr[16];
+
+       unsigned long flags;
+};
+
+static unsigned long libipw_tkip_set_flags(unsigned long flags, void *priv)
+{
+       struct libipw_tkip_data *_priv = priv;
+       unsigned long old_flags = _priv->flags;
+       _priv->flags = flags;
+       return old_flags;
+}
+
+static unsigned long libipw_tkip_get_flags(void *priv)
+{
+       struct libipw_tkip_data *_priv = priv;
+       return _priv->flags;
+}
+
+static void *libipw_tkip_init(int key_idx)
+{
+       struct libipw_tkip_data *priv;
+
+       if (fips_enabled)
+               return NULL;
+
+       priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
+       if (priv == NULL)
+               goto fail;
+
+       priv->key_idx = key_idx;
+
+       priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
+       if (IS_ERR(priv->tx_tfm_michael)) {
+               priv->tx_tfm_michael = NULL;
+               goto fail;
+       }
+
+       priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
+       if (IS_ERR(priv->rx_tfm_michael)) {
+               priv->rx_tfm_michael = NULL;
+               goto fail;
+       }
+
+       return priv;
+
+      fail:
+       if (priv) {
+               crypto_free_shash(priv->tx_tfm_michael);
+               crypto_free_shash(priv->rx_tfm_michael);
+               kfree(priv);
+       }
+
+       return NULL;
+}
+
+static void libipw_tkip_deinit(void *priv)
+{
+       struct libipw_tkip_data *_priv = priv;
+       if (_priv) {
+               crypto_free_shash(_priv->tx_tfm_michael);
+               crypto_free_shash(_priv->rx_tfm_michael);
+       }
+       kfree_sensitive(priv);
+}
+
+static inline u16 RotR1(u16 val)
+{
+       return (val >> 1) | (val << 15);
+}
+
+static inline u8 Lo8(u16 val)
+{
+       return val & 0xff;
+}
+
+static inline u8 Hi8(u16 val)
+{
+       return val >> 8;
+}
+
+static inline u16 Lo16(u32 val)
+{
+       return val & 0xffff;
+}
+
+static inline u16 Hi16(u32 val)
+{
+       return val >> 16;
+}
+
+static inline u16 Mk16(u8 hi, u8 lo)
+{
+       return lo | (((u16) hi) << 8);
+}
+
+static inline u16 Mk16_le(__le16 * v)
+{
+       return le16_to_cpu(*v);
+}
+
+static const u16 Sbox[256] = {
+       0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+       0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+       0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+       0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+       0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+       0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+       0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+       0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+       0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+       0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+       0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+       0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+       0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+       0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+       0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+       0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+       0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+       0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+       0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+       0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+       0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+       0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+       0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+       0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+       0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+       0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+       0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+       0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+       0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+       0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+       0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+       0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+};
+
+static inline u16 _S_(u16 v)
+{
+       u16 t = Sbox[Hi8(v)];
+       return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
+}
+
+#define PHASE1_LOOP_COUNT 8
+
+static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
+                              u32 IV32)
+{
+       int i, j;
+
+       /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
+       TTAK[0] = Lo16(IV32);
+       TTAK[1] = Hi16(IV32);
+       TTAK[2] = Mk16(TA[1], TA[0]);
+       TTAK[3] = Mk16(TA[3], TA[2]);
+       TTAK[4] = Mk16(TA[5], TA[4]);
+
+       for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
+               j = 2 * (i & 1);
+               TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
+               TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
+               TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
+               TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
+               TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
+       }
+}
+
+static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
+                              u16 IV16)
+{
+       /* Make temporary area overlap WEP seed so that the final copy can be
+        * avoided on little endian hosts. */
+       u16 *PPK = (u16 *) & WEPSeed[4];
+
+       /* Step 1 - make copy of TTAK and bring in TSC */
+       PPK[0] = TTAK[0];
+       PPK[1] = TTAK[1];
+       PPK[2] = TTAK[2];
+       PPK[3] = TTAK[3];
+       PPK[4] = TTAK[4];
+       PPK[5] = TTAK[4] + IV16;
+
+       /* Step 2 - 96-bit bijective mixing using S-box */
+       PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0]));
+       PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2]));
+       PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4]));
+       PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6]));
+       PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8]));
+       PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10]));
+
+       PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12]));
+       PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14]));
+       PPK[2] += RotR1(PPK[1]);
+       PPK[3] += RotR1(PPK[2]);
+       PPK[4] += RotR1(PPK[3]);
+       PPK[5] += RotR1(PPK[4]);
+
+       /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
+        * WEPSeed[0..2] is transmitted as WEP IV */
+       WEPSeed[0] = Hi8(IV16);
+       WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
+       WEPSeed[2] = Lo8(IV16);
+       WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1);
+
+#ifdef __BIG_ENDIAN
+       {
+               int i;
+               for (i = 0; i < 6; i++)
+                       PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
+       }
+#endif
+}
+
+static int libipw_tkip_hdr(struct sk_buff *skb, int hdr_len,
+                             u8 * rc4key, int keylen, void *priv)
+{
+       struct libipw_tkip_data *tkey = priv;
+       u8 *pos;
+       struct ieee80211_hdr *hdr;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+
+       if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len)
+               return -1;
+
+       if (rc4key == NULL || keylen < 16)
+               return -1;
+
+       if (!tkey->tx_phase1_done) {
+               tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
+                                  tkey->tx_iv32);
+               tkey->tx_phase1_done = 1;
+       }
+       tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
+
+       pos = skb_push(skb, TKIP_HDR_LEN);
+       memmove(pos, pos + TKIP_HDR_LEN, hdr_len);
+       pos += hdr_len;
+
+       *pos++ = *rc4key;
+       *pos++ = *(rc4key + 1);
+       *pos++ = *(rc4key + 2);
+       *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
+       *pos++ = tkey->tx_iv32 & 0xff;
+       *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
+       *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
+       *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
+
+       tkey->tx_iv16++;
+       if (tkey->tx_iv16 == 0) {
+               tkey->tx_phase1_done = 0;
+               tkey->tx_iv32++;
+       }
+
+       return TKIP_HDR_LEN;
+}
+
+static int libipw_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct libipw_tkip_data *tkey = priv;
+       int len;
+       u8 rc4key[16], *pos, *icv;
+       u32 crc;
+
+       if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
+               struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+               net_dbg_ratelimited("TKIP countermeasures: dropped TX packet to %pM\n",
+                                   hdr->addr1);
+               return -1;
+       }
+
+       if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
+               return -1;
+
+       len = skb->len - hdr_len;
+       pos = skb->data + hdr_len;
+
+       if ((libipw_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
+               return -1;
+
+       crc = ~crc32_le(~0, pos, len);
+       icv = skb_put(skb, 4);
+       icv[0] = crc;
+       icv[1] = crc >> 8;
+       icv[2] = crc >> 16;
+       icv[3] = crc >> 24;
+
+       arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16);
+       arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4);
+
+       return 0;
+}
+
+/*
+ * deal with seq counter wrapping correctly.
+ * refer to timer_after() for jiffies wrapping handling
+ */
+static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
+                                   u32 iv32_o, u16 iv16_o)
+{
+       if ((s32)iv32_n - (s32)iv32_o < 0 ||
+           (iv32_n == iv32_o && iv16_n <= iv16_o))
+               return 1;
+       return 0;
+}
+
+static int libipw_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct libipw_tkip_data *tkey = priv;
+       u8 rc4key[16];
+       u8 keyidx, *pos;
+       u32 iv32;
+       u16 iv16;
+       struct ieee80211_hdr *hdr;
+       u8 icv[4];
+       u32 crc;
+       int plen;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+
+       if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
+               net_dbg_ratelimited("TKIP countermeasures: dropped received packet from %pM\n",
+                                   hdr->addr2);
+               return -1;
+       }
+
+       if (skb->len < hdr_len + TKIP_HDR_LEN + 4)
+               return -1;
+
+       pos = skb->data + hdr_len;
+       keyidx = pos[3];
+       if (!(keyidx & (1 << 5))) {
+               net_dbg_ratelimited("TKIP: received packet without ExtIV flag from %pM\n",
+                                   hdr->addr2);
+               return -2;
+       }
+       keyidx >>= 6;
+       if (tkey->key_idx != keyidx) {
+               net_dbg_ratelimited("TKIP: RX tkey->key_idx=%d frame keyidx=%d\n",
+                                   tkey->key_idx, keyidx);
+               return -6;
+       }
+       if (!tkey->key_set) {
+               net_dbg_ratelimited("TKIP: received packet from %pM with keyid=%d that does not have a configured key\n",
+                                   hdr->addr2, keyidx);
+               return -3;
+       }
+       iv16 = (pos[0] << 8) | pos[2];
+       iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+       pos += TKIP_HDR_LEN;
+
+       if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
+#ifdef CONFIG_LIBIPW_DEBUG
+               net_dbg_ratelimited("TKIP: replay detected: STA=%pM previous TSC %08x%04x received TSC %08x%04x\n",
+                                   hdr->addr2, tkey->rx_iv32, tkey->rx_iv16,
+                                   iv32, iv16);
+#endif
+               tkey->dot11RSNAStatsTKIPReplays++;
+               return -4;
+       }
+
+       if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
+               tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
+               tkey->rx_phase1_done = 1;
+       }
+       tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
+
+       plen = skb->len - hdr_len - 12;
+
+       arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16);
+       arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4);
+
+       crc = ~crc32_le(~0, pos, plen);
+       icv[0] = crc;
+       icv[1] = crc >> 8;
+       icv[2] = crc >> 16;
+       icv[3] = crc >> 24;
+       if (memcmp(icv, pos + plen, 4) != 0) {
+               if (iv32 != tkey->rx_iv32) {
+                       /* Previously cached Phase1 result was already lost, so
+                        * it needs to be recalculated for the next packet. */
+                       tkey->rx_phase1_done = 0;
+               }
+#ifdef CONFIG_LIBIPW_DEBUG
+               net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n",
+                                   hdr->addr2);
+#endif
+               tkey->dot11RSNAStatsTKIPICVErrors++;
+               return -5;
+       }
+
+       /* Update real counters only after Michael MIC verification has
+        * completed */
+       tkey->rx_iv32_new = iv32;
+       tkey->rx_iv16_new = iv16;
+
+       /* Remove IV and ICV */
+       memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len);
+       skb_pull(skb, TKIP_HDR_LEN);
+       skb_trim(skb, skb->len - 4);
+
+       return keyidx;
+}
+
+static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr,
+                      u8 *data, size_t data_len, u8 *mic)
+{
+       SHASH_DESC_ON_STACK(desc, tfm_michael);
+       int err;
+
+       if (tfm_michael == NULL) {
+               pr_warn("%s(): tfm_michael == NULL\n", __func__);
+               return -1;
+       }
+
+       desc->tfm = tfm_michael;
+
+       if (crypto_shash_setkey(tfm_michael, key, 8))
+               return -1;
+
+       err = crypto_shash_init(desc);
+       if (err)
+               goto out;
+       err = crypto_shash_update(desc, hdr, 16);
+       if (err)
+               goto out;
+       err = crypto_shash_update(desc, data, data_len);
+       if (err)
+               goto out;
+       err = crypto_shash_final(desc, mic);
+
+out:
+       shash_desc_zero(desc);
+       return err;
+}
+
+static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
+{
+       struct ieee80211_hdr *hdr11;
+
+       hdr11 = (struct ieee80211_hdr *)skb->data;
+
+       switch (le16_to_cpu(hdr11->frame_control) &
+               (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+       case IEEE80211_FCTL_TODS:
+               memcpy(hdr, hdr11->addr3, ETH_ALEN);    /* DA */
+               memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+               break;
+       case IEEE80211_FCTL_FROMDS:
+               memcpy(hdr, hdr11->addr1, ETH_ALEN);    /* DA */
+               memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
+               break;
+       case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+               memcpy(hdr, hdr11->addr3, ETH_ALEN);    /* DA */
+               memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
+               break;
+       default:
+               memcpy(hdr, hdr11->addr1, ETH_ALEN);    /* DA */
+               memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+               break;
+       }
+
+       if (ieee80211_is_data_qos(hdr11->frame_control)) {
+               hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
+                       & IEEE80211_QOS_CTL_TID_MASK;
+       } else
+               hdr[12] = 0;            /* priority */
+
+       hdr[13] = hdr[14] = hdr[15] = 0;        /* reserved */
+}
+
+static int libipw_michael_mic_add(struct sk_buff *skb, int hdr_len,
+                                    void *priv)
+{
+       struct libipw_tkip_data *tkey = priv;
+       u8 *pos;
+
+       if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
+               printk(KERN_DEBUG "Invalid packet for Michael MIC add "
+                      "(tailroom=%d hdr_len=%d skb->len=%d)\n",
+                      skb_tailroom(skb), hdr_len, skb->len);
+               return -1;
+       }
+
+       michael_mic_hdr(skb, tkey->tx_hdr);
+       pos = skb_put(skb, 8);
+       if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
+                       skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
+               return -1;
+
+       return 0;
+}
+
+static void libipw_michael_mic_failure(struct net_device *dev,
+                                         struct ieee80211_hdr *hdr,
+                                         int keyidx)
+{
+       union iwreq_data wrqu;
+       struct iw_michaelmicfailure ev;
+
+       /* TODO: needed parameters: count, keyid, key type, TSC */
+       memset(&ev, 0, sizeof(ev));
+       ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
+       if (hdr->addr1[0] & 0x01)
+               ev.flags |= IW_MICFAILURE_GROUP;
+       else
+               ev.flags |= IW_MICFAILURE_PAIRWISE;
+       ev.src_addr.sa_family = ARPHRD_ETHER;
+       memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
+       memset(&wrqu, 0, sizeof(wrqu));
+       wrqu.data.length = sizeof(ev);
+       wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
+}
+
+static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx,
+                                       int hdr_len, void *priv)
+{
+       struct libipw_tkip_data *tkey = priv;
+       u8 mic[8];
+
+       if (!tkey->key_set)
+               return -1;
+
+       michael_mic_hdr(skb, tkey->rx_hdr);
+       if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
+                       skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
+               return -1;
+       if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
+               struct ieee80211_hdr *hdr;
+               hdr = (struct ieee80211_hdr *)skb->data;
+               printk(KERN_DEBUG "%s: Michael MIC verification failed for "
+                      "MSDU from %pM keyidx=%d\n",
+                      skb->dev ? skb->dev->name : "N/A", hdr->addr2,
+                      keyidx);
+               if (skb->dev)
+                       libipw_michael_mic_failure(skb->dev, hdr, keyidx);
+               tkey->dot11RSNAStatsTKIPLocalMICFailures++;
+               return -1;
+       }
+
+       /* Update TSC counters for RX now that the packet verification has
+        * completed. */
+       tkey->rx_iv32 = tkey->rx_iv32_new;
+       tkey->rx_iv16 = tkey->rx_iv16_new;
+
+       skb_trim(skb, skb->len - 8);
+
+       return 0;
+}
+
+static int libipw_tkip_set_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct libipw_tkip_data *tkey = priv;
+       int keyidx;
+       struct crypto_shash *tfm = tkey->tx_tfm_michael;
+       struct arc4_ctx *tfm2 = &tkey->tx_ctx_arc4;
+       struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
+       struct arc4_ctx *tfm4 = &tkey->rx_ctx_arc4;
+
+       keyidx = tkey->key_idx;
+       memset(tkey, 0, sizeof(*tkey));
+       tkey->key_idx = keyidx;
+       tkey->tx_tfm_michael = tfm;
+       tkey->tx_ctx_arc4 = *tfm2;
+       tkey->rx_tfm_michael = tfm3;
+       tkey->rx_ctx_arc4 = *tfm4;
+       if (len == TKIP_KEY_LEN) {
+               memcpy(tkey->key, key, TKIP_KEY_LEN);
+               tkey->key_set = 1;
+               tkey->tx_iv16 = 1;      /* TSC is initialized to 1 */
+               if (seq) {
+                       tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
+                           (seq[3] << 8) | seq[2];
+                       tkey->rx_iv16 = (seq[1] << 8) | seq[0];
+               }
+       } else if (len == 0)
+               tkey->key_set = 0;
+       else
+               return -1;
+
+       return 0;
+}
+
+static int libipw_tkip_get_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct libipw_tkip_data *tkey = priv;
+
+       if (len < TKIP_KEY_LEN)
+               return -1;
+
+       if (!tkey->key_set)
+               return 0;
+       memcpy(key, tkey->key, TKIP_KEY_LEN);
+
+       if (seq) {
+               /*
+                * Not clear if this should return the value as is
+                * or - as the code previously seemed to partially
+                * have been written as - subtract one from it. It
+                * was working this way for a long time so leave it.
+                */
+               seq[0] = tkey->tx_iv16;
+               seq[1] = tkey->tx_iv16 >> 8;
+               seq[2] = tkey->tx_iv32;
+               seq[3] = tkey->tx_iv32 >> 8;
+               seq[4] = tkey->tx_iv32 >> 16;
+               seq[5] = tkey->tx_iv32 >> 24;
+       }
+
+       return TKIP_KEY_LEN;
+}
+
+static void libipw_tkip_print_stats(struct seq_file *m, void *priv)
+{
+       struct libipw_tkip_data *tkip = priv;
+       seq_printf(m,
+                  "key[%d] alg=TKIP key_set=%d "
+                  "tx_pn=%02x%02x%02x%02x%02x%02x "
+                  "rx_pn=%02x%02x%02x%02x%02x%02x "
+                  "replays=%d icv_errors=%d local_mic_failures=%d\n",
+                  tkip->key_idx, tkip->key_set,
+                  (tkip->tx_iv32 >> 24) & 0xff,
+                  (tkip->tx_iv32 >> 16) & 0xff,
+                  (tkip->tx_iv32 >> 8) & 0xff,
+                  tkip->tx_iv32 & 0xff,
+                  (tkip->tx_iv16 >> 8) & 0xff,
+                  tkip->tx_iv16 & 0xff,
+                  (tkip->rx_iv32 >> 24) & 0xff,
+                  (tkip->rx_iv32 >> 16) & 0xff,
+                  (tkip->rx_iv32 >> 8) & 0xff,
+                  tkip->rx_iv32 & 0xff,
+                  (tkip->rx_iv16 >> 8) & 0xff,
+                  tkip->rx_iv16 & 0xff,
+                  tkip->dot11RSNAStatsTKIPReplays,
+                  tkip->dot11RSNAStatsTKIPICVErrors,
+                  tkip->dot11RSNAStatsTKIPLocalMICFailures);
+}
+
+static const struct libipw_crypto_ops libipw_crypt_tkip = {
+       .name = "TKIP",
+       .init = libipw_tkip_init,
+       .deinit = libipw_tkip_deinit,
+       .encrypt_mpdu = libipw_tkip_encrypt,
+       .decrypt_mpdu = libipw_tkip_decrypt,
+       .encrypt_msdu = libipw_michael_mic_add,
+       .decrypt_msdu = libipw_michael_mic_verify,
+       .set_key = libipw_tkip_set_key,
+       .get_key = libipw_tkip_get_key,
+       .print_stats = libipw_tkip_print_stats,
+       .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
+       .extra_mpdu_postfix_len = 4,    /* ICV */
+       .extra_msdu_postfix_len = 8,    /* MIC */
+       .get_flags = libipw_tkip_get_flags,
+       .set_flags = libipw_tkip_set_flags,
+       .owner = THIS_MODULE,
+};
+
+int __init libipw_crypto_tkip_init(void)
+{
+       return libipw_register_crypto_ops(&libipw_crypt_tkip);
+}
+
+void libipw_crypto_tkip_exit(void)
+{
+       libipw_unregister_crypto_ops(&libipw_crypt_tkip);
+}
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c
new file mode 100644 (file)
index 0000000..c3a4ccb
--- /dev/null
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * libipw crypt: host-based WEP encryption implementation for libipw
+ *
+ * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
+ */
+
+#include <linux/err.h>
+#include <linux/fips.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/skbuff.h>
+#include <linux/mm.h>
+#include <asm/string.h>
+#include <crypto/arc4.h>
+#include <linux/crc32.h>
+#include "libipw.h"
+
+struct libipw_wep_data {
+       u32 iv;
+#define WEP_KEY_LEN 13
+       u8 key[WEP_KEY_LEN + 1];
+       u8 key_len;
+       u8 key_idx;
+       struct arc4_ctx tx_ctx;
+       struct arc4_ctx rx_ctx;
+};
+
+static void *libipw_wep_init(int keyidx)
+{
+       struct libipw_wep_data *priv;
+
+       if (fips_enabled)
+               return NULL;
+
+       priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
+       if (priv == NULL)
+               return NULL;
+       priv->key_idx = keyidx;
+
+       /* start WEP IV from a random value */
+       get_random_bytes(&priv->iv, 4);
+
+       return priv;
+}
+
+static void libipw_wep_deinit(void *priv)
+{
+       kfree_sensitive(priv);
+}
+
+/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
+static int libipw_wep_build_iv(struct sk_buff *skb, int hdr_len,
+                              u8 *key, int keylen, void *priv)
+{
+       struct libipw_wep_data *wep = priv;
+       u32 klen;
+       u8 *pos;
+
+       if (skb_headroom(skb) < 4 || skb->len < hdr_len)
+               return -1;
+
+       pos = skb_push(skb, 4);
+       memmove(pos, pos + 4, hdr_len);
+       pos += hdr_len;
+
+       klen = 3 + wep->key_len;
+
+       wep->iv++;
+
+       /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
+        * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
+        * can be used to speedup attacks, so avoid using them. */
+       if ((wep->iv & 0xff00) == 0xff00) {
+               u8 B = (wep->iv >> 16) & 0xff;
+               if (B >= 3 && B < klen)
+                       wep->iv += 0x0100;
+       }
+
+       /* Prepend 24-bit IV to RC4 key and TX frame */
+       *pos++ = (wep->iv >> 16) & 0xff;
+       *pos++ = (wep->iv >> 8) & 0xff;
+       *pos++ = wep->iv & 0xff;
+       *pos++ = wep->key_idx << 6;
+
+       return 0;
+}
+
+/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
+ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
+ * so the payload length increases with 8 bytes.
+ *
+ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
+ */
+static int libipw_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct libipw_wep_data *wep = priv;
+       u32 crc, klen, len;
+       u8 *pos, *icv;
+       u8 key[WEP_KEY_LEN + 3];
+
+       /* other checks are in libipw_wep_build_iv */
+       if (skb_tailroom(skb) < 4)
+               return -1;
+
+       /* add the IV to the frame */
+       if (libipw_wep_build_iv(skb, hdr_len, NULL, 0, priv))
+               return -1;
+
+       /* Copy the IV into the first 3 bytes of the key */
+       skb_copy_from_linear_data_offset(skb, hdr_len, key, 3);
+
+       /* Copy rest of the WEP key (the secret part) */
+       memcpy(key + 3, wep->key, wep->key_len);
+
+       len = skb->len - hdr_len - 4;
+       pos = skb->data + hdr_len + 4;
+       klen = 3 + wep->key_len;
+
+       /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */
+       crc = ~crc32_le(~0, pos, len);
+       icv = skb_put(skb, 4);
+       icv[0] = crc;
+       icv[1] = crc >> 8;
+       icv[2] = crc >> 16;
+       icv[3] = crc >> 24;
+
+       arc4_setkey(&wep->tx_ctx, key, klen);
+       arc4_crypt(&wep->tx_ctx, pos, pos, len + 4);
+
+       return 0;
+}
+
+/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
+ * the frame: IV (4 bytes), encrypted payload (including SNAP header),
+ * ICV (4 bytes). len includes both IV and ICV.
+ *
+ * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
+ * failure. If frame is OK, IV and ICV will be removed.
+ */
+static int libipw_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct libipw_wep_data *wep = priv;
+       u32 crc, klen, plen;
+       u8 key[WEP_KEY_LEN + 3];
+       u8 keyidx, *pos, icv[4];
+
+       if (skb->len < hdr_len + 8)
+               return -1;
+
+       pos = skb->data + hdr_len;
+       key[0] = *pos++;
+       key[1] = *pos++;
+       key[2] = *pos++;
+       keyidx = *pos++ >> 6;
+       if (keyidx != wep->key_idx)
+               return -1;
+
+       klen = 3 + wep->key_len;
+
+       /* Copy rest of the WEP key (the secret part) */
+       memcpy(key + 3, wep->key, wep->key_len);
+
+       /* Apply RC4 to data and compute CRC32 over decrypted data */
+       plen = skb->len - hdr_len - 8;
+
+       arc4_setkey(&wep->rx_ctx, key, klen);
+       arc4_crypt(&wep->rx_ctx, pos, pos, plen + 4);
+
+       crc = ~crc32_le(~0, pos, plen);
+       icv[0] = crc;
+       icv[1] = crc >> 8;
+       icv[2] = crc >> 16;
+       icv[3] = crc >> 24;
+       if (memcmp(icv, pos + plen, 4) != 0) {
+               /* ICV mismatch - drop frame */
+               return -2;
+       }
+
+       /* Remove IV and ICV */
+       memmove(skb->data + 4, skb->data, hdr_len);
+       skb_pull(skb, 4);
+       skb_trim(skb, skb->len - 4);
+
+       return 0;
+}
+
+static int libipw_wep_set_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct libipw_wep_data *wep = priv;
+
+       if (len < 0 || len > WEP_KEY_LEN)
+               return -1;
+
+       memcpy(wep->key, key, len);
+       wep->key_len = len;
+
+       return 0;
+}
+
+static int libipw_wep_get_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct libipw_wep_data *wep = priv;
+
+       if (len < wep->key_len)
+               return -1;
+
+       memcpy(key, wep->key, wep->key_len);
+
+       return wep->key_len;
+}
+
+static void libipw_wep_print_stats(struct seq_file *m, void *priv)
+{
+       struct libipw_wep_data *wep = priv;
+       seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
+}
+
+static const struct libipw_crypto_ops libipw_crypt_wep = {
+       .name = "WEP",
+       .init = libipw_wep_init,
+       .deinit = libipw_wep_deinit,
+       .encrypt_mpdu = libipw_wep_encrypt,
+       .decrypt_mpdu = libipw_wep_decrypt,
+       .encrypt_msdu = NULL,
+       .decrypt_msdu = NULL,
+       .set_key = libipw_wep_set_key,
+       .get_key = libipw_wep_get_key,
+       .print_stats = libipw_wep_print_stats,
+       .extra_mpdu_prefix_len = 4,     /* IV */
+       .extra_mpdu_postfix_len = 4,    /* ICV */
+       .owner = THIS_MODULE,
+};
+
+int __init libipw_crypto_wep_init(void)
+{
+       return libipw_register_crypto_ops(&libipw_crypt_wep);
+}
+
+void __exit libipw_crypto_wep_exit(void)
+{
+       libipw_unregister_crypto_ops(&libipw_crypt_wep);
+}
index 43bab92a4148f23fda2620c19576670f120ed9b1..0a16127bfd68d31fa34acf1041b9198b230b3fd5 100644 (file)
@@ -169,7 +169,7 @@ struct net_device *alloc_libipw(int sizeof_priv, int monitor)
 
        spin_lock_init(&ieee->lock);
 
-       lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
+       libipw_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
 
        ieee->wpa_enabled = 0;
        ieee->drop_unencrypted = 0;
@@ -191,7 +191,7 @@ void free_libipw(struct net_device *dev, int monitor)
 {
        struct libipw_device *ieee = netdev_priv(dev);
 
-       lib80211_crypt_info_free(&ieee->crypt_info);
+       libipw_crypt_info_free(&ieee->crypt_info);
 
        libipw_networks_free(ieee);
 
@@ -251,6 +251,7 @@ static const struct proc_ops debug_level_proc_ops = {
 
 static int __init libipw_init(void)
 {
+       int err;
 #ifdef CONFIG_LIBIPW_DEBUG
        struct proc_dir_entry *e;
 
@@ -273,7 +274,33 @@ static int __init libipw_init(void)
        printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
        printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
 
+       err = libipw_crypto_init();
+       if (err)
+               goto remove_debugfs;
+       err = libipw_crypto_ccmp_init();
+       if (err)
+               goto uninit_crypto;
+       err = libipw_crypto_tkip_init();
+       if (err)
+               goto uninit_crypto_ccmp;
+       err = libipw_crypto_wep_init();
+       if (err)
+               goto uninit_crypto_tkip;
+
        return 0;
+uninit_crypto_tkip:
+       libipw_crypto_tkip_exit();
+uninit_crypto_ccmp:
+       libipw_crypto_ccmp_exit();
+uninit_crypto:
+       libipw_crypto_exit();
+remove_debugfs:
+#ifdef CONFIG_LIBIPW_DEBUG
+       remove_proc_entry("debug_level", libipw_proc);
+       remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
+       libipw_proc = NULL;
+#endif
+       return err;
 }
 
 static void __exit libipw_exit(void)
@@ -285,6 +312,11 @@ static void __exit libipw_exit(void)
                libipw_proc = NULL;
        }
 #endif                         /* CONFIG_LIBIPW_DEBUG */
+
+       libipw_crypto_ccmp_exit();
+       libipw_crypto_tkip_exit();
+       libipw_crypto_wep_exit();
+       libipw_crypto_exit();
 }
 
 #ifdef CONFIG_LIBIPW_DEBUG
index 48d6870bbf4e255444ca83d2c89d5b9a62726c3b..1fe05e73a17ca45e6ca0767054ae1257ecd8837b 100644 (file)
@@ -27,9 +27,6 @@
 #include <linux/etherdevice.h>
 #include <linux/uaccess.h>
 #include <linux/ctype.h>
-
-#include <net/lib80211.h>
-
 #include "libipw.h"
 
 static void libipw_monitor_rx(struct libipw_device *ieee,
@@ -266,7 +263,7 @@ static int libipw_is_eapol_frame(struct libipw_device *ieee,
 /* Called only as a tasklet (software IRQ), by libipw_rx */
 static int
 libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb,
-                          struct lib80211_crypt_data *crypt)
+                          struct libipw_crypt_data *crypt)
 {
        struct libipw_hdr_3addr *hdr;
        int res, hdrlen;
@@ -298,7 +295,7 @@ libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb,
 static int
 libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee,
                                struct sk_buff *skb, int keyidx,
-                               struct lib80211_crypt_data *crypt)
+                               struct libipw_crypt_data *crypt)
 {
        struct libipw_hdr_3addr *hdr;
        int res, hdrlen;
@@ -345,7 +342,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
 #endif
        u8 dst[ETH_ALEN];
        u8 src[ETH_ALEN];
-       struct lib80211_crypt_data *crypt = NULL;
+       struct libipw_crypt_data *crypt = NULL;
        int keyidx = 0;
        int can_be_decrypted = 0;
 
index e22a6732a4c3f2f3c61d04546aa862852e6a424a..80edaa3dea9c88f0340ea96f8da97bb8f984797a 100644 (file)
@@ -138,7 +138,7 @@ static int libipw_copy_snap(u8 * data, __be16 h_proto)
 static int libipw_encrypt_fragment(struct libipw_device *ieee,
                                             struct sk_buff *frag, int hdr_len)
 {
-       struct lib80211_crypt_data *crypt =
+       struct libipw_crypt_data *crypt =
                ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
        int res;
 
@@ -255,7 +255,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
                .qos_ctl = 0
        };
        u8 dest[ETH_ALEN], src[ETH_ALEN];
-       struct lib80211_crypt_data *crypt;
+       struct libipw_crypt_data *crypt;
        int priority = skb->priority;
        int snapped = 0;
 
index dbc7153d0a3d07b8f068255e9abada027baacd48..db71d81b0d4f2e0ca1c23fcb2d3720f4aa76953a 100644 (file)
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/jiffies.h>
-
-#include <net/lib80211.h>
 #include <linux/wireless.h>
-
 #include "libipw.h"
 
 static const char *libipw_modes[] = {
@@ -303,7 +300,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
                .flags = 0
        };
        int i, key, key_provided, len;
-       struct lib80211_crypt_data **crypt;
+       struct libipw_crypt_data **crypt;
        int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
 
        LIBIPW_DEBUG_WX("SET_ENCODE\n");
@@ -328,7 +325,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
                if (key_provided && *crypt) {
                        LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
                                           key);
-                       lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+                       libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt);
                } else
                        LIBIPW_DEBUG_WX("Disabling encryption.\n");
 
@@ -338,7 +335,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
                        if (ieee->crypt_info.crypt[i] != NULL) {
                                if (key_provided)
                                        break;
-                               lib80211_crypt_delayed_deinit(&ieee->crypt_info,
+                               libipw_crypt_delayed_deinit(&ieee->crypt_info,
                                                               &ieee->crypt_info.crypt[i]);
                        }
                }
@@ -361,21 +358,21 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
            strcmp((*crypt)->ops->name, "WEP") != 0) {
                /* changing to use WEP; deinit previously used algorithm
                 * on this key */
-               lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+               libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt);
        }
 
        if (*crypt == NULL && host_crypto) {
-               struct lib80211_crypt_data *new_crypt;
+               struct libipw_crypt_data *new_crypt;
 
                /* take WEP into use */
-               new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
+               new_crypt = kzalloc(sizeof(struct libipw_crypt_data),
                                    GFP_KERNEL);
                if (new_crypt == NULL)
                        return -ENOMEM;
-               new_crypt->ops = lib80211_get_crypto_ops("WEP");
+               new_crypt->ops = libipw_get_crypto_ops("WEP");
                if (!new_crypt->ops) {
-                       request_module("lib80211_crypt_wep");
-                       new_crypt->ops = lib80211_get_crypto_ops("WEP");
+                       request_module("libipw_crypt_wep");
+                       new_crypt->ops = libipw_get_crypto_ops("WEP");
                }
 
                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
@@ -386,7 +383,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
                        new_crypt = NULL;
 
                        printk(KERN_WARNING "%s: could not initialize WEP: "
-                              "load module lib80211_crypt_wep\n", dev->name);
+                              "load module libipw_crypt_wep\n", dev->name);
                        return -EOPNOTSUPP;
                }
                *crypt = new_crypt;
@@ -509,8 +506,8 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
        int i, idx, ret = 0;
        int group_key = 0;
        const char *alg, *module;
-       const struct lib80211_crypto_ops *ops;
-       struct lib80211_crypt_data **crypt;
+       const struct libipw_crypto_ops *ops;
+       struct libipw_crypt_data **crypt;
 
        struct libipw_security sec = {
                .flags = 0,
@@ -541,7 +538,7 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
        if ((encoding->flags & IW_ENCODE_DISABLED) ||
            ext->alg == IW_ENCODE_ALG_NONE) {
                if (*crypt)
-                       lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+                       libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt);
 
                for (i = 0; i < WEP_KEYS; i++)
                        if (ieee->crypt_info.crypt[i] != NULL)
@@ -567,15 +564,15 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
        switch (ext->alg) {
        case IW_ENCODE_ALG_WEP:
                alg = "WEP";
-               module = "lib80211_crypt_wep";
+               module = "libipw_crypt_wep";
                break;
        case IW_ENCODE_ALG_TKIP:
                alg = "TKIP";
-               module = "lib80211_crypt_tkip";
+               module = "libipw_crypt_tkip";
                break;
        case IW_ENCODE_ALG_CCMP:
                alg = "CCMP";
-               module = "lib80211_crypt_ccmp";
+               module = "libipw_crypt_ccmp";
                break;
        default:
                LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
@@ -584,10 +581,10 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
                goto done;
        }
 
-       ops = lib80211_get_crypto_ops(alg);
+       ops = libipw_get_crypto_ops(alg);
        if (ops == NULL) {
                request_module(module);
-               ops = lib80211_get_crypto_ops(alg);
+               ops = libipw_get_crypto_ops(alg);
        }
        if (ops == NULL) {
                LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
@@ -597,9 +594,9 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
        }
 
        if (*crypt == NULL || (*crypt)->ops != ops) {
-               struct lib80211_crypt_data *new_crypt;
+               struct libipw_crypt_data *new_crypt;
 
-               lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+               libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt);
 
                new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
                if (new_crypt == NULL) {
diff --git a/include/net/lib80211.h b/include/net/lib80211.h
deleted file mode 100644 (file)
index fd0f15d..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * lib80211.h -- common bits for IEEE802.11 wireless drivers
- *
- * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
- *
- * Some bits copied from old ieee80211 component, w/ original copyright
- * notices below:
- *
- * Original code based on Host AP (software wireless LAN access point) driver
- * for Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <j@w1.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
- *
- * Adaption to a generic IEEE 802.11 stack by James Ketrenos
- * <jketreno@linux.intel.com>
- *
- * Copyright (c) 2004, Intel Corporation
- *
- */
-
-#ifndef LIB80211_H
-#define LIB80211_H
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/atomic.h>
-#include <linux/if.h>
-#include <linux/skbuff.h>
-#include <linux/ieee80211.h>
-#include <linux/timer.h>
-#include <linux/seq_file.h>
-
-#define NUM_WEP_KEYS   4
-
-enum {
-       IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0),
-};
-
-struct module;
-
-struct lib80211_crypto_ops {
-       const char *name;
-       struct list_head list;
-
-       /* init new crypto context (e.g., allocate private data space,
-        * select IV, etc.); returns NULL on failure or pointer to allocated
-        * private data on success */
-       void *(*init) (int keyidx);
-
-       /* deinitialize crypto context and free allocated private data */
-       void (*deinit) (void *priv);
-
-       /* encrypt/decrypt return < 0 on error or >= 0 on success. The return
-        * value from decrypt_mpdu is passed as the keyidx value for
-        * decrypt_msdu. skb must have enough head and tail room for the
-        * encryption; if not, error will be returned; these functions are
-        * called for all MPDUs (i.e., fragments).
-        */
-       int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
-       int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
-
-       /* These functions are called for full MSDUs, i.e. full frames.
-        * These can be NULL if full MSDU operations are not needed. */
-       int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv);
-       int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len,
-                            void *priv);
-
-       int (*set_key) (void *key, int len, u8 * seq, void *priv);
-       int (*get_key) (void *key, int len, u8 * seq, void *priv);
-
-       /* procfs handler for printing out key information and possible
-        * statistics */
-       void (*print_stats) (struct seq_file *m, void *priv);
-
-       /* Crypto specific flag get/set for configuration settings */
-       unsigned long (*get_flags) (void *priv);
-       unsigned long (*set_flags) (unsigned long flags, void *priv);
-
-       /* maximum number of bytes added by encryption; encrypt buf is
-        * allocated with extra_prefix_len bytes, copy of in_buf, and
-        * extra_postfix_len; encrypt need not use all this space, but
-        * the result must start at the beginning of the buffer and correct
-        * length must be returned */
-       int extra_mpdu_prefix_len, extra_mpdu_postfix_len;
-       int extra_msdu_prefix_len, extra_msdu_postfix_len;
-
-       struct module *owner;
-};
-
-struct lib80211_crypt_data {
-       struct list_head list;  /* delayed deletion list */
-       const struct lib80211_crypto_ops *ops;
-       void *priv;
-       atomic_t refcnt;
-};
-
-struct lib80211_crypt_info {
-       char *name;
-       /* Most clients will already have a lock,
-          so just point to that. */
-       spinlock_t *lock;
-
-       struct lib80211_crypt_data *crypt[NUM_WEP_KEYS];
-       int tx_keyidx;          /* default TX key index (crypt[tx_keyidx]) */
-       struct list_head crypt_deinit_list;
-       struct timer_list crypt_deinit_timer;
-       int crypt_quiesced;
-};
-
-int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
-                                spinlock_t *lock);
-void lib80211_crypt_info_free(struct lib80211_crypt_info *info);
-int lib80211_register_crypto_ops(const struct lib80211_crypto_ops *ops);
-int lib80211_unregister_crypto_ops(const struct lib80211_crypto_ops *ops);
-const struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name);
-void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
-                                   struct lib80211_crypt_data **crypt);
-
-#endif /* LIB80211_H */
index 10345388ad139f5f9b35025b2336c548bd3344be..733c53ad4de51768b0a7218eeedf19207f24c04c 100644 (file)
@@ -212,36 +212,3 @@ config CFG80211_KUNIT_TEST
          If unsure, say N.
 
 endif # CFG80211
-
-config LIB80211
-       tristate
-       default n
-       help
-         This options enables a library of common routines used
-         by IEEE802.11 wireless LAN drivers.
-
-         Drivers should select this themselves if needed.
-
-config LIB80211_CRYPT_WEP
-       tristate
-       select CRYPTO_LIB_ARC4
-
-config LIB80211_CRYPT_CCMP
-       tristate
-       select CRYPTO
-       select CRYPTO_AES
-       select CRYPTO_CCM
-
-config LIB80211_CRYPT_TKIP
-       tristate
-       select CRYPTO_LIB_ARC4
-
-config LIB80211_DEBUG
-       bool "lib80211 debugging messages"
-       depends on LIB80211
-       default n
-       help
-         You can enable this if you want verbose debugging messages
-         from lib80211.
-
-         If unsure, say N.
index 1d49cc8b6da1562f0d3ed5e807a7c2fd940fe392..27f211bd9954599d1d9d74efe5c983a61b2a9fd7 100644 (file)
@@ -1,9 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_CFG80211) += cfg80211.o
-obj-$(CONFIG_LIB80211) += lib80211.o
-obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
-obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
-obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
 obj-y += tests/
 
 obj-$(CONFIG_WEXT_CORE) += wext-core.o
diff --git a/net/wireless/lib80211.c b/net/wireless/lib80211.c
deleted file mode 100644 (file)
index 64c4470..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * lib80211 -- common bits for IEEE802.11 drivers
- *
- * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com>
- *
- * Portions copied from old ieee80211 component, w/ original copyright
- * notices below:
- *
- * Host AP crypto routines
- *
- * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
- * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/ieee80211.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <net/lib80211.h>
-
-#define DRV_DESCRIPTION        "common routines for IEEE802.11 drivers"
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
-MODULE_LICENSE("GPL");
-
-struct lib80211_crypto_alg {
-       struct list_head list;
-       const struct lib80211_crypto_ops *ops;
-};
-
-static LIST_HEAD(lib80211_crypto_algs);
-static DEFINE_SPINLOCK(lib80211_crypto_lock);
-
-static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
-                                         int force);
-static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
-static void lib80211_crypt_deinit_handler(struct timer_list *t);
-
-int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
-                               spinlock_t *lock)
-{
-       memset(info, 0, sizeof(*info));
-
-       info->name = name;
-       info->lock = lock;
-
-       INIT_LIST_HEAD(&info->crypt_deinit_list);
-       timer_setup(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler,
-                   0);
-
-       return 0;
-}
-EXPORT_SYMBOL(lib80211_crypt_info_init);
-
-void lib80211_crypt_info_free(struct lib80211_crypt_info *info)
-{
-       int i;
-
-        lib80211_crypt_quiescing(info);
-        del_timer_sync(&info->crypt_deinit_timer);
-        lib80211_crypt_deinit_entries(info, 1);
-
-        for (i = 0; i < NUM_WEP_KEYS; i++) {
-                struct lib80211_crypt_data *crypt = info->crypt[i];
-                if (crypt) {
-                        if (crypt->ops) {
-                                crypt->ops->deinit(crypt->priv);
-                                module_put(crypt->ops->owner);
-                        }
-                        kfree(crypt);
-                        info->crypt[i] = NULL;
-                }
-        }
-}
-EXPORT_SYMBOL(lib80211_crypt_info_free);
-
-static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
-                                         int force)
-{
-       struct lib80211_crypt_data *entry, *next;
-       unsigned long flags;
-
-       spin_lock_irqsave(info->lock, flags);
-       list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
-               if (atomic_read(&entry->refcnt) != 0 && !force)
-                       continue;
-
-               list_del(&entry->list);
-
-               if (entry->ops) {
-                       entry->ops->deinit(entry->priv);
-                       module_put(entry->ops->owner);
-               }
-               kfree(entry);
-       }
-       spin_unlock_irqrestore(info->lock, flags);
-}
-
-/* After this, crypt_deinit_list won't accept new members */
-static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(info->lock, flags);
-       info->crypt_quiesced = 1;
-       spin_unlock_irqrestore(info->lock, flags);
-}
-
-static void lib80211_crypt_deinit_handler(struct timer_list *t)
-{
-       struct lib80211_crypt_info *info = from_timer(info, t,
-                                                     crypt_deinit_timer);
-       unsigned long flags;
-
-       lib80211_crypt_deinit_entries(info, 0);
-
-       spin_lock_irqsave(info->lock, flags);
-       if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
-               printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
-                      "deletion list\n", info->name);
-               info->crypt_deinit_timer.expires = jiffies + HZ;
-               add_timer(&info->crypt_deinit_timer);
-       }
-       spin_unlock_irqrestore(info->lock, flags);
-}
-
-void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
-                                   struct lib80211_crypt_data **crypt)
-{
-       struct lib80211_crypt_data *tmp;
-       unsigned long flags;
-
-       if (*crypt == NULL)
-               return;
-
-       tmp = *crypt;
-       *crypt = NULL;
-
-       /* must not run ops->deinit() while there may be pending encrypt or
-        * decrypt operations. Use a list of delayed deinits to avoid needing
-        * locking. */
-
-       spin_lock_irqsave(info->lock, flags);
-       if (!info->crypt_quiesced) {
-               list_add(&tmp->list, &info->crypt_deinit_list);
-               if (!timer_pending(&info->crypt_deinit_timer)) {
-                       info->crypt_deinit_timer.expires = jiffies + HZ;
-                       add_timer(&info->crypt_deinit_timer);
-               }
-       }
-       spin_unlock_irqrestore(info->lock, flags);
-}
-EXPORT_SYMBOL(lib80211_crypt_delayed_deinit);
-
-int lib80211_register_crypto_ops(const struct lib80211_crypto_ops *ops)
-{
-       unsigned long flags;
-       struct lib80211_crypto_alg *alg;
-
-       alg = kzalloc(sizeof(*alg), GFP_KERNEL);
-       if (alg == NULL)
-               return -ENOMEM;
-
-       alg->ops = ops;
-
-       spin_lock_irqsave(&lib80211_crypto_lock, flags);
-       list_add(&alg->list, &lib80211_crypto_algs);
-       spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
-
-       printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n",
-              ops->name);
-
-       return 0;
-}
-EXPORT_SYMBOL(lib80211_register_crypto_ops);
-
-int lib80211_unregister_crypto_ops(const struct lib80211_crypto_ops *ops)
-{
-       struct lib80211_crypto_alg *alg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&lib80211_crypto_lock, flags);
-       list_for_each_entry(alg, &lib80211_crypto_algs, list) {
-               if (alg->ops == ops)
-                       goto found;
-       }
-       spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
-       return -EINVAL;
-
-      found:
-       printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n",
-              ops->name);
-       list_del(&alg->list);
-       spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
-       kfree(alg);
-       return 0;
-}
-EXPORT_SYMBOL(lib80211_unregister_crypto_ops);
-
-const struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name)
-{
-       struct lib80211_crypto_alg *alg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&lib80211_crypto_lock, flags);
-       list_for_each_entry(alg, &lib80211_crypto_algs, list) {
-               if (strcmp(alg->ops->name, name) == 0)
-                       goto found;
-       }
-       spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
-       return NULL;
-
-      found:
-       spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
-       return alg->ops;
-}
-EXPORT_SYMBOL(lib80211_get_crypto_ops);
-
-static void *lib80211_crypt_null_init(int keyidx)
-{
-       return (void *)1;
-}
-
-static void lib80211_crypt_null_deinit(void *priv)
-{
-}
-
-static const struct lib80211_crypto_ops lib80211_crypt_null = {
-       .name = "NULL",
-       .init = lib80211_crypt_null_init,
-       .deinit = lib80211_crypt_null_deinit,
-       .owner = THIS_MODULE,
-};
-
-static int __init lib80211_init(void)
-{
-       pr_info(DRV_DESCRIPTION "\n");
-       return lib80211_register_crypto_ops(&lib80211_crypt_null);
-}
-
-static void __exit lib80211_exit(void)
-{
-       lib80211_unregister_crypto_ops(&lib80211_crypt_null);
-       BUG_ON(!list_empty(&lib80211_crypto_algs));
-}
-
-module_init(lib80211_init);
-module_exit(lib80211_exit);
diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c
deleted file mode 100644 (file)
index 5aad139..0000000
+++ /dev/null
@@ -1,448 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * lib80211 crypt: host-based CCMP encryption implementation for lib80211
- *
- * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <asm/string.h>
-#include <linux/wireless.h>
-
-#include <linux/ieee80211.h>
-
-#include <linux/crypto.h>
-#include <crypto/aead.h>
-
-#include <net/lib80211.h>
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Host AP crypt: CCMP");
-MODULE_LICENSE("GPL");
-
-#define AES_BLOCK_LEN 16
-#define CCMP_HDR_LEN 8
-#define CCMP_MIC_LEN 8
-#define CCMP_TK_LEN 16
-#define CCMP_PN_LEN 6
-
-struct lib80211_ccmp_data {
-       u8 key[CCMP_TK_LEN];
-       int key_set;
-
-       u8 tx_pn[CCMP_PN_LEN];
-       u8 rx_pn[CCMP_PN_LEN];
-
-       u32 dot11RSNAStatsCCMPFormatErrors;
-       u32 dot11RSNAStatsCCMPReplays;
-       u32 dot11RSNAStatsCCMPDecryptErrors;
-
-       int key_idx;
-
-       struct crypto_aead *tfm;
-
-       /* scratch buffers for virt_to_page() (crypto API) */
-       u8 tx_aad[2 * AES_BLOCK_LEN];
-       u8 rx_aad[2 * AES_BLOCK_LEN];
-};
-
-static void *lib80211_ccmp_init(int key_idx)
-{
-       struct lib80211_ccmp_data *priv;
-
-       priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
-       if (priv == NULL)
-               goto fail;
-       priv->key_idx = key_idx;
-
-       priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(priv->tfm)) {
-               priv->tfm = NULL;
-               goto fail;
-       }
-
-       return priv;
-
-      fail:
-       if (priv) {
-               if (priv->tfm)
-                       crypto_free_aead(priv->tfm);
-               kfree(priv);
-       }
-
-       return NULL;
-}
-
-static void lib80211_ccmp_deinit(void *priv)
-{
-       struct lib80211_ccmp_data *_priv = priv;
-       if (_priv && _priv->tfm)
-               crypto_free_aead(_priv->tfm);
-       kfree(priv);
-}
-
-static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr,
-                               const u8 *pn, u8 *iv, u8 *aad)
-{
-       u8 *pos, qc = 0;
-       size_t aad_len;
-       int a4_included, qc_included;
-
-       a4_included = ieee80211_has_a4(hdr->frame_control);
-       qc_included = ieee80211_is_data_qos(hdr->frame_control);
-
-       aad_len = 22;
-       if (a4_included)
-               aad_len += 6;
-       if (qc_included) {
-               pos = (u8 *) & hdr->addr4;
-               if (a4_included)
-                       pos += 6;
-               qc = *pos & 0x0f;
-               aad_len += 2;
-       }
-
-       /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
-        * mode authentication are not allowed to collide, yet both are derived
-        * from the same vector. We only set L := 1 here to indicate that the
-        * data size can be represented in (L+1) bytes. The CCM layer will take
-        * care of storing the data length in the top (L+1) bytes and setting
-        * and clearing the other bits as is required to derive the two IVs.
-        */
-       iv[0] = 0x1;
-
-       /* Nonce: QC | A2 | PN */
-       iv[1] = qc;
-       memcpy(iv + 2, hdr->addr2, ETH_ALEN);
-       memcpy(iv + 8, pn, CCMP_PN_LEN);
-
-       /* AAD:
-        * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
-        * A1 | A2 | A3
-        * SC with bits 4..15 (seq#) masked to zero
-        * A4 (if present)
-        * QC (if present)
-        */
-       pos = (u8 *) hdr;
-       aad[0] = pos[0] & 0x8f;
-       aad[1] = pos[1] & 0xc7;
-       memcpy(aad + 2, &hdr->addrs, 3 * ETH_ALEN);
-       pos = (u8 *) & hdr->seq_ctrl;
-       aad[20] = pos[0] & 0x0f;
-       aad[21] = 0;            /* all bits masked */
-       memset(aad + 22, 0, 8);
-       if (a4_included)
-               memcpy(aad + 22, hdr->addr4, ETH_ALEN);
-       if (qc_included) {
-               aad[a4_included ? 28 : 22] = qc;
-               /* rest of QC masked */
-       }
-       return aad_len;
-}
-
-static int lib80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
-                             u8 *aeskey, int keylen, void *priv)
-{
-       struct lib80211_ccmp_data *key = priv;
-       int i;
-       u8 *pos;
-
-       if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len)
-               return -1;
-
-       if (aeskey != NULL && keylen >= CCMP_TK_LEN)
-               memcpy(aeskey, key->key, CCMP_TK_LEN);
-
-       pos = skb_push(skb, CCMP_HDR_LEN);
-       memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
-       pos += hdr_len;
-
-       i = CCMP_PN_LEN - 1;
-       while (i >= 0) {
-               key->tx_pn[i]++;
-               if (key->tx_pn[i] != 0)
-                       break;
-               i--;
-       }
-
-       *pos++ = key->tx_pn[5];
-       *pos++ = key->tx_pn[4];
-       *pos++ = 0;
-       *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
-       *pos++ = key->tx_pn[3];
-       *pos++ = key->tx_pn[2];
-       *pos++ = key->tx_pn[1];
-       *pos++ = key->tx_pn[0];
-
-       return CCMP_HDR_LEN;
-}
-
-static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
-       struct lib80211_ccmp_data *key = priv;
-       struct ieee80211_hdr *hdr;
-       struct aead_request *req;
-       struct scatterlist sg[2];
-       u8 *aad = key->tx_aad;
-       u8 iv[AES_BLOCK_LEN];
-       int len, data_len, aad_len;
-       int ret;
-
-       if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
-               return -1;
-
-       data_len = skb->len - hdr_len;
-       len = lib80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
-       if (len < 0)
-               return -1;
-
-       req = aead_request_alloc(key->tfm, GFP_ATOMIC);
-       if (!req)
-               return -ENOMEM;
-
-       hdr = (struct ieee80211_hdr *)skb->data;
-       aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad);
-
-       skb_put(skb, CCMP_MIC_LEN);
-
-       sg_init_table(sg, 2);
-       sg_set_buf(&sg[0], aad, aad_len);
-       sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN,
-                  data_len + CCMP_MIC_LEN);
-
-       aead_request_set_callback(req, 0, NULL, NULL);
-       aead_request_set_ad(req, aad_len);
-       aead_request_set_crypt(req, sg, sg, data_len, iv);
-
-       ret = crypto_aead_encrypt(req);
-       aead_request_free(req);
-
-       return ret;
-}
-
-/*
- * deal with seq counter wrapping correctly.
- * refer to timer_after() for jiffies wrapping handling
- */
-static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o)
-{
-       u32 iv32_n, iv16_n;
-       u32 iv32_o, iv16_o;
-
-       iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3];
-       iv16_n = (pn_n[4] << 8) | pn_n[5];
-
-       iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3];
-       iv16_o = (pn_o[4] << 8) | pn_o[5];
-
-       if ((s32)iv32_n - (s32)iv32_o < 0 ||
-           (iv32_n == iv32_o && iv16_n <= iv16_o))
-               return 1;
-       return 0;
-}
-
-static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
-       struct lib80211_ccmp_data *key = priv;
-       u8 keyidx, *pos;
-       struct ieee80211_hdr *hdr;
-       struct aead_request *req;
-       struct scatterlist sg[2];
-       u8 *aad = key->rx_aad;
-       u8 iv[AES_BLOCK_LEN];
-       u8 pn[6];
-       int aad_len, ret;
-       size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN;
-
-       if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
-               key->dot11RSNAStatsCCMPFormatErrors++;
-               return -1;
-       }
-
-       hdr = (struct ieee80211_hdr *)skb->data;
-       pos = skb->data + hdr_len;
-       keyidx = pos[3];
-       if (!(keyidx & (1 << 5))) {
-               net_dbg_ratelimited("CCMP: received packet without ExtIV flag from %pM\n",
-                                   hdr->addr2);
-               key->dot11RSNAStatsCCMPFormatErrors++;
-               return -2;
-       }
-       keyidx >>= 6;
-       if (key->key_idx != keyidx) {
-               net_dbg_ratelimited("CCMP: RX tkey->key_idx=%d frame keyidx=%d\n",
-                                   key->key_idx, keyidx);
-               return -6;
-       }
-       if (!key->key_set) {
-               net_dbg_ratelimited("CCMP: received packet from %pM with keyid=%d that does not have a configured key\n",
-                                   hdr->addr2, keyidx);
-               return -3;
-       }
-
-       pn[0] = pos[7];
-       pn[1] = pos[6];
-       pn[2] = pos[5];
-       pn[3] = pos[4];
-       pn[4] = pos[1];
-       pn[5] = pos[0];
-       pos += 8;
-
-       if (ccmp_replay_check(pn, key->rx_pn)) {
-#ifdef CONFIG_LIB80211_DEBUG
-               net_dbg_ratelimited("CCMP: replay detected: STA=%pM previous PN %02x%02x%02x%02x%02x%02x received PN %02x%02x%02x%02x%02x%02x\n",
-                                   hdr->addr2,
-                                   key->rx_pn[0], key->rx_pn[1], key->rx_pn[2],
-                                   key->rx_pn[3], key->rx_pn[4], key->rx_pn[5],
-                                   pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
-#endif
-               key->dot11RSNAStatsCCMPReplays++;
-               return -4;
-       }
-
-       req = aead_request_alloc(key->tfm, GFP_ATOMIC);
-       if (!req)
-               return -ENOMEM;
-
-       aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad);
-
-       sg_init_table(sg, 2);
-       sg_set_buf(&sg[0], aad, aad_len);
-       sg_set_buf(&sg[1], pos, data_len);
-
-       aead_request_set_callback(req, 0, NULL, NULL);
-       aead_request_set_ad(req, aad_len);
-       aead_request_set_crypt(req, sg, sg, data_len, iv);
-
-       ret = crypto_aead_decrypt(req);
-       aead_request_free(req);
-
-       if (ret) {
-               net_dbg_ratelimited("CCMP: decrypt failed: STA=%pM (%d)\n",
-                                   hdr->addr2, ret);
-               key->dot11RSNAStatsCCMPDecryptErrors++;
-               return -5;
-       }
-
-       memcpy(key->rx_pn, pn, CCMP_PN_LEN);
-
-       /* Remove hdr and MIC */
-       memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
-       skb_pull(skb, CCMP_HDR_LEN);
-       skb_trim(skb, skb->len - CCMP_MIC_LEN);
-
-       return keyidx;
-}
-
-static int lib80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
-{
-       struct lib80211_ccmp_data *data = priv;
-       int keyidx;
-       struct crypto_aead *tfm = data->tfm;
-
-       keyidx = data->key_idx;
-       memset(data, 0, sizeof(*data));
-       data->key_idx = keyidx;
-       data->tfm = tfm;
-       if (len == CCMP_TK_LEN) {
-               memcpy(data->key, key, CCMP_TK_LEN);
-               data->key_set = 1;
-               if (seq) {
-                       data->rx_pn[0] = seq[5];
-                       data->rx_pn[1] = seq[4];
-                       data->rx_pn[2] = seq[3];
-                       data->rx_pn[3] = seq[2];
-                       data->rx_pn[4] = seq[1];
-                       data->rx_pn[5] = seq[0];
-               }
-               if (crypto_aead_setauthsize(data->tfm, CCMP_MIC_LEN) ||
-                   crypto_aead_setkey(data->tfm, data->key, CCMP_TK_LEN))
-                       return -1;
-       } else if (len == 0)
-               data->key_set = 0;
-       else
-               return -1;
-
-       return 0;
-}
-
-static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
-{
-       struct lib80211_ccmp_data *data = priv;
-
-       if (len < CCMP_TK_LEN)
-               return -1;
-
-       if (!data->key_set)
-               return 0;
-       memcpy(key, data->key, CCMP_TK_LEN);
-
-       if (seq) {
-               seq[0] = data->tx_pn[5];
-               seq[1] = data->tx_pn[4];
-               seq[2] = data->tx_pn[3];
-               seq[3] = data->tx_pn[2];
-               seq[4] = data->tx_pn[1];
-               seq[5] = data->tx_pn[0];
-       }
-
-       return CCMP_TK_LEN;
-}
-
-static void lib80211_ccmp_print_stats(struct seq_file *m, void *priv)
-{
-       struct lib80211_ccmp_data *ccmp = priv;
-
-       seq_printf(m,
-                  "key[%d] alg=CCMP key_set=%d "
-                  "tx_pn=%02x%02x%02x%02x%02x%02x "
-                  "rx_pn=%02x%02x%02x%02x%02x%02x "
-                  "format_errors=%d replays=%d decrypt_errors=%d\n",
-                  ccmp->key_idx, ccmp->key_set,
-                  ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2],
-                  ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5],
-                  ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2],
-                  ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5],
-                  ccmp->dot11RSNAStatsCCMPFormatErrors,
-                  ccmp->dot11RSNAStatsCCMPReplays,
-                  ccmp->dot11RSNAStatsCCMPDecryptErrors);
-}
-
-static const struct lib80211_crypto_ops lib80211_crypt_ccmp = {
-       .name = "CCMP",
-       .init = lib80211_ccmp_init,
-       .deinit = lib80211_ccmp_deinit,
-       .encrypt_mpdu = lib80211_ccmp_encrypt,
-       .decrypt_mpdu = lib80211_ccmp_decrypt,
-       .encrypt_msdu = NULL,
-       .decrypt_msdu = NULL,
-       .set_key = lib80211_ccmp_set_key,
-       .get_key = lib80211_ccmp_get_key,
-       .print_stats = lib80211_ccmp_print_stats,
-       .extra_mpdu_prefix_len = CCMP_HDR_LEN,
-       .extra_mpdu_postfix_len = CCMP_MIC_LEN,
-       .owner = THIS_MODULE,
-};
-
-static int __init lib80211_crypto_ccmp_init(void)
-{
-       return lib80211_register_crypto_ops(&lib80211_crypt_ccmp);
-}
-
-static void __exit lib80211_crypto_ccmp_exit(void)
-{
-       lib80211_unregister_crypto_ops(&lib80211_crypt_ccmp);
-}
-
-module_init(lib80211_crypto_ccmp_init);
-module_exit(lib80211_crypto_ccmp_exit);
diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c
deleted file mode 100644 (file)
index 63e68e5..0000000
+++ /dev/null
@@ -1,738 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * lib80211 crypt: host-based TKIP encryption implementation for lib80211
- *
- * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/err.h>
-#include <linux/fips.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/scatterlist.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/mm.h>
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <asm/string.h>
-
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <net/iw_handler.h>
-
-#include <crypto/arc4.h>
-#include <crypto/hash.h>
-#include <linux/crypto.h>
-#include <linux/crc32.h>
-
-#include <net/lib80211.h>
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("lib80211 crypt: TKIP");
-MODULE_LICENSE("GPL");
-
-#define TKIP_HDR_LEN 8
-
-struct lib80211_tkip_data {
-#define TKIP_KEY_LEN 32
-       u8 key[TKIP_KEY_LEN];
-       int key_set;
-
-       u32 tx_iv32;
-       u16 tx_iv16;
-       u16 tx_ttak[5];
-       int tx_phase1_done;
-
-       u32 rx_iv32;
-       u16 rx_iv16;
-       u16 rx_ttak[5];
-       int rx_phase1_done;
-       u32 rx_iv32_new;
-       u16 rx_iv16_new;
-
-       u32 dot11RSNAStatsTKIPReplays;
-       u32 dot11RSNAStatsTKIPICVErrors;
-       u32 dot11RSNAStatsTKIPLocalMICFailures;
-
-       int key_idx;
-
-       struct arc4_ctx rx_ctx_arc4;
-       struct arc4_ctx tx_ctx_arc4;
-       struct crypto_shash *rx_tfm_michael;
-       struct crypto_shash *tx_tfm_michael;
-
-       /* scratch buffers for virt_to_page() (crypto API) */
-       u8 rx_hdr[16], tx_hdr[16];
-
-       unsigned long flags;
-};
-
-static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv)
-{
-       struct lib80211_tkip_data *_priv = priv;
-       unsigned long old_flags = _priv->flags;
-       _priv->flags = flags;
-       return old_flags;
-}
-
-static unsigned long lib80211_tkip_get_flags(void *priv)
-{
-       struct lib80211_tkip_data *_priv = priv;
-       return _priv->flags;
-}
-
-static void *lib80211_tkip_init(int key_idx)
-{
-       struct lib80211_tkip_data *priv;
-
-       if (fips_enabled)
-               return NULL;
-
-       priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
-       if (priv == NULL)
-               goto fail;
-
-       priv->key_idx = key_idx;
-
-       priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
-       if (IS_ERR(priv->tx_tfm_michael)) {
-               priv->tx_tfm_michael = NULL;
-               goto fail;
-       }
-
-       priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
-       if (IS_ERR(priv->rx_tfm_michael)) {
-               priv->rx_tfm_michael = NULL;
-               goto fail;
-       }
-
-       return priv;
-
-      fail:
-       if (priv) {
-               crypto_free_shash(priv->tx_tfm_michael);
-               crypto_free_shash(priv->rx_tfm_michael);
-               kfree(priv);
-       }
-
-       return NULL;
-}
-
-static void lib80211_tkip_deinit(void *priv)
-{
-       struct lib80211_tkip_data *_priv = priv;
-       if (_priv) {
-               crypto_free_shash(_priv->tx_tfm_michael);
-               crypto_free_shash(_priv->rx_tfm_michael);
-       }
-       kfree_sensitive(priv);
-}
-
-static inline u16 RotR1(u16 val)
-{
-       return (val >> 1) | (val << 15);
-}
-
-static inline u8 Lo8(u16 val)
-{
-       return val & 0xff;
-}
-
-static inline u8 Hi8(u16 val)
-{
-       return val >> 8;
-}
-
-static inline u16 Lo16(u32 val)
-{
-       return val & 0xffff;
-}
-
-static inline u16 Hi16(u32 val)
-{
-       return val >> 16;
-}
-
-static inline u16 Mk16(u8 hi, u8 lo)
-{
-       return lo | (((u16) hi) << 8);
-}
-
-static inline u16 Mk16_le(__le16 * v)
-{
-       return le16_to_cpu(*v);
-}
-
-static const u16 Sbox[256] = {
-       0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
-       0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
-       0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
-       0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
-       0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
-       0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
-       0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
-       0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
-       0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
-       0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
-       0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
-       0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
-       0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
-       0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
-       0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
-       0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
-       0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
-       0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
-       0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
-       0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
-       0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
-       0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
-       0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
-       0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
-       0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
-       0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
-       0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
-       0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
-       0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
-       0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
-       0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
-       0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
-};
-
-static inline u16 _S_(u16 v)
-{
-       u16 t = Sbox[Hi8(v)];
-       return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
-}
-
-#define PHASE1_LOOP_COUNT 8
-
-static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
-                              u32 IV32)
-{
-       int i, j;
-
-       /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
-       TTAK[0] = Lo16(IV32);
-       TTAK[1] = Hi16(IV32);
-       TTAK[2] = Mk16(TA[1], TA[0]);
-       TTAK[3] = Mk16(TA[3], TA[2]);
-       TTAK[4] = Mk16(TA[5], TA[4]);
-
-       for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
-               j = 2 * (i & 1);
-               TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
-               TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
-               TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
-               TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
-               TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
-       }
-}
-
-static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
-                              u16 IV16)
-{
-       /* Make temporary area overlap WEP seed so that the final copy can be
-        * avoided on little endian hosts. */
-       u16 *PPK = (u16 *) & WEPSeed[4];
-
-       /* Step 1 - make copy of TTAK and bring in TSC */
-       PPK[0] = TTAK[0];
-       PPK[1] = TTAK[1];
-       PPK[2] = TTAK[2];
-       PPK[3] = TTAK[3];
-       PPK[4] = TTAK[4];
-       PPK[5] = TTAK[4] + IV16;
-
-       /* Step 2 - 96-bit bijective mixing using S-box */
-       PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0]));
-       PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2]));
-       PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4]));
-       PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6]));
-       PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8]));
-       PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10]));
-
-       PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12]));
-       PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14]));
-       PPK[2] += RotR1(PPK[1]);
-       PPK[3] += RotR1(PPK[2]);
-       PPK[4] += RotR1(PPK[3]);
-       PPK[5] += RotR1(PPK[4]);
-
-       /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
-        * WEPSeed[0..2] is transmitted as WEP IV */
-       WEPSeed[0] = Hi8(IV16);
-       WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
-       WEPSeed[2] = Lo8(IV16);
-       WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1);
-
-#ifdef __BIG_ENDIAN
-       {
-               int i;
-               for (i = 0; i < 6; i++)
-                       PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
-       }
-#endif
-}
-
-static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
-                             u8 * rc4key, int keylen, void *priv)
-{
-       struct lib80211_tkip_data *tkey = priv;
-       u8 *pos;
-       struct ieee80211_hdr *hdr;
-
-       hdr = (struct ieee80211_hdr *)skb->data;
-
-       if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len)
-               return -1;
-
-       if (rc4key == NULL || keylen < 16)
-               return -1;
-
-       if (!tkey->tx_phase1_done) {
-               tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
-                                  tkey->tx_iv32);
-               tkey->tx_phase1_done = 1;
-       }
-       tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
-
-       pos = skb_push(skb, TKIP_HDR_LEN);
-       memmove(pos, pos + TKIP_HDR_LEN, hdr_len);
-       pos += hdr_len;
-
-       *pos++ = *rc4key;
-       *pos++ = *(rc4key + 1);
-       *pos++ = *(rc4key + 2);
-       *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
-       *pos++ = tkey->tx_iv32 & 0xff;
-       *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
-       *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
-       *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
-
-       tkey->tx_iv16++;
-       if (tkey->tx_iv16 == 0) {
-               tkey->tx_phase1_done = 0;
-               tkey->tx_iv32++;
-       }
-
-       return TKIP_HDR_LEN;
-}
-
-static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
-       struct lib80211_tkip_data *tkey = priv;
-       int len;
-       u8 rc4key[16], *pos, *icv;
-       u32 crc;
-
-       if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
-               struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-               net_dbg_ratelimited("TKIP countermeasures: dropped TX packet to %pM\n",
-                                   hdr->addr1);
-               return -1;
-       }
-
-       if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
-               return -1;
-
-       len = skb->len - hdr_len;
-       pos = skb->data + hdr_len;
-
-       if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
-               return -1;
-
-       crc = ~crc32_le(~0, pos, len);
-       icv = skb_put(skb, 4);
-       icv[0] = crc;
-       icv[1] = crc >> 8;
-       icv[2] = crc >> 16;
-       icv[3] = crc >> 24;
-
-       arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16);
-       arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4);
-
-       return 0;
-}
-
-/*
- * deal with seq counter wrapping correctly.
- * refer to timer_after() for jiffies wrapping handling
- */
-static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
-                                   u32 iv32_o, u16 iv16_o)
-{
-       if ((s32)iv32_n - (s32)iv32_o < 0 ||
-           (iv32_n == iv32_o && iv16_n <= iv16_o))
-               return 1;
-       return 0;
-}
-
-static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
-       struct lib80211_tkip_data *tkey = priv;
-       u8 rc4key[16];
-       u8 keyidx, *pos;
-       u32 iv32;
-       u16 iv16;
-       struct ieee80211_hdr *hdr;
-       u8 icv[4];
-       u32 crc;
-       int plen;
-
-       hdr = (struct ieee80211_hdr *)skb->data;
-
-       if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
-               net_dbg_ratelimited("TKIP countermeasures: dropped received packet from %pM\n",
-                                   hdr->addr2);
-               return -1;
-       }
-
-       if (skb->len < hdr_len + TKIP_HDR_LEN + 4)
-               return -1;
-
-       pos = skb->data + hdr_len;
-       keyidx = pos[3];
-       if (!(keyidx & (1 << 5))) {
-               net_dbg_ratelimited("TKIP: received packet without ExtIV flag from %pM\n",
-                                   hdr->addr2);
-               return -2;
-       }
-       keyidx >>= 6;
-       if (tkey->key_idx != keyidx) {
-               net_dbg_ratelimited("TKIP: RX tkey->key_idx=%d frame keyidx=%d\n",
-                                   tkey->key_idx, keyidx);
-               return -6;
-       }
-       if (!tkey->key_set) {
-               net_dbg_ratelimited("TKIP: received packet from %pM with keyid=%d that does not have a configured key\n",
-                                   hdr->addr2, keyidx);
-               return -3;
-       }
-       iv16 = (pos[0] << 8) | pos[2];
-       iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
-       pos += TKIP_HDR_LEN;
-
-       if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
-#ifdef CONFIG_LIB80211_DEBUG
-               net_dbg_ratelimited("TKIP: replay detected: STA=%pM previous TSC %08x%04x received TSC %08x%04x\n",
-                                   hdr->addr2, tkey->rx_iv32, tkey->rx_iv16,
-                                   iv32, iv16);
-#endif
-               tkey->dot11RSNAStatsTKIPReplays++;
-               return -4;
-       }
-
-       if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
-               tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
-               tkey->rx_phase1_done = 1;
-       }
-       tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
-
-       plen = skb->len - hdr_len - 12;
-
-       arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16);
-       arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4);
-
-       crc = ~crc32_le(~0, pos, plen);
-       icv[0] = crc;
-       icv[1] = crc >> 8;
-       icv[2] = crc >> 16;
-       icv[3] = crc >> 24;
-       if (memcmp(icv, pos + plen, 4) != 0) {
-               if (iv32 != tkey->rx_iv32) {
-                       /* Previously cached Phase1 result was already lost, so
-                        * it needs to be recalculated for the next packet. */
-                       tkey->rx_phase1_done = 0;
-               }
-#ifdef CONFIG_LIB80211_DEBUG
-               net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n",
-                                   hdr->addr2);
-#endif
-               tkey->dot11RSNAStatsTKIPICVErrors++;
-               return -5;
-       }
-
-       /* Update real counters only after Michael MIC verification has
-        * completed */
-       tkey->rx_iv32_new = iv32;
-       tkey->rx_iv16_new = iv16;
-
-       /* Remove IV and ICV */
-       memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len);
-       skb_pull(skb, TKIP_HDR_LEN);
-       skb_trim(skb, skb->len - 4);
-
-       return keyidx;
-}
-
-static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr,
-                      u8 *data, size_t data_len, u8 *mic)
-{
-       SHASH_DESC_ON_STACK(desc, tfm_michael);
-       int err;
-
-       if (tfm_michael == NULL) {
-               pr_warn("%s(): tfm_michael == NULL\n", __func__);
-               return -1;
-       }
-
-       desc->tfm = tfm_michael;
-
-       if (crypto_shash_setkey(tfm_michael, key, 8))
-               return -1;
-
-       err = crypto_shash_init(desc);
-       if (err)
-               goto out;
-       err = crypto_shash_update(desc, hdr, 16);
-       if (err)
-               goto out;
-       err = crypto_shash_update(desc, data, data_len);
-       if (err)
-               goto out;
-       err = crypto_shash_final(desc, mic);
-
-out:
-       shash_desc_zero(desc);
-       return err;
-}
-
-static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
-{
-       struct ieee80211_hdr *hdr11;
-
-       hdr11 = (struct ieee80211_hdr *)skb->data;
-
-       switch (le16_to_cpu(hdr11->frame_control) &
-               (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
-       case IEEE80211_FCTL_TODS:
-               memcpy(hdr, hdr11->addr3, ETH_ALEN);    /* DA */
-               memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
-               break;
-       case IEEE80211_FCTL_FROMDS:
-               memcpy(hdr, hdr11->addr1, ETH_ALEN);    /* DA */
-               memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
-               break;
-       case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
-               memcpy(hdr, hdr11->addr3, ETH_ALEN);    /* DA */
-               memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
-               break;
-       default:
-               memcpy(hdr, hdr11->addr1, ETH_ALEN);    /* DA */
-               memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
-               break;
-       }
-
-       if (ieee80211_is_data_qos(hdr11->frame_control)) {
-               hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
-                       & IEEE80211_QOS_CTL_TID_MASK;
-       } else
-               hdr[12] = 0;            /* priority */
-
-       hdr[13] = hdr[14] = hdr[15] = 0;        /* reserved */
-}
-
-static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
-                                    void *priv)
-{
-       struct lib80211_tkip_data *tkey = priv;
-       u8 *pos;
-
-       if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
-               printk(KERN_DEBUG "Invalid packet for Michael MIC add "
-                      "(tailroom=%d hdr_len=%d skb->len=%d)\n",
-                      skb_tailroom(skb), hdr_len, skb->len);
-               return -1;
-       }
-
-       michael_mic_hdr(skb, tkey->tx_hdr);
-       pos = skb_put(skb, 8);
-       if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
-                       skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
-               return -1;
-
-       return 0;
-}
-
-static void lib80211_michael_mic_failure(struct net_device *dev,
-                                         struct ieee80211_hdr *hdr,
-                                         int keyidx)
-{
-       union iwreq_data wrqu;
-       struct iw_michaelmicfailure ev;
-
-       /* TODO: needed parameters: count, keyid, key type, TSC */
-       memset(&ev, 0, sizeof(ev));
-       ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
-       if (hdr->addr1[0] & 0x01)
-               ev.flags |= IW_MICFAILURE_GROUP;
-       else
-               ev.flags |= IW_MICFAILURE_PAIRWISE;
-       ev.src_addr.sa_family = ARPHRD_ETHER;
-       memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
-       memset(&wrqu, 0, sizeof(wrqu));
-       wrqu.data.length = sizeof(ev);
-       wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
-}
-
-static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
-                                       int hdr_len, void *priv)
-{
-       struct lib80211_tkip_data *tkey = priv;
-       u8 mic[8];
-
-       if (!tkey->key_set)
-               return -1;
-
-       michael_mic_hdr(skb, tkey->rx_hdr);
-       if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
-                       skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
-               return -1;
-       if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
-               struct ieee80211_hdr *hdr;
-               hdr = (struct ieee80211_hdr *)skb->data;
-               printk(KERN_DEBUG "%s: Michael MIC verification failed for "
-                      "MSDU from %pM keyidx=%d\n",
-                      skb->dev ? skb->dev->name : "N/A", hdr->addr2,
-                      keyidx);
-               if (skb->dev)
-                       lib80211_michael_mic_failure(skb->dev, hdr, keyidx);
-               tkey->dot11RSNAStatsTKIPLocalMICFailures++;
-               return -1;
-       }
-
-       /* Update TSC counters for RX now that the packet verification has
-        * completed. */
-       tkey->rx_iv32 = tkey->rx_iv32_new;
-       tkey->rx_iv16 = tkey->rx_iv16_new;
-
-       skb_trim(skb, skb->len - 8);
-
-       return 0;
-}
-
-static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
-{
-       struct lib80211_tkip_data *tkey = priv;
-       int keyidx;
-       struct crypto_shash *tfm = tkey->tx_tfm_michael;
-       struct arc4_ctx *tfm2 = &tkey->tx_ctx_arc4;
-       struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
-       struct arc4_ctx *tfm4 = &tkey->rx_ctx_arc4;
-
-       keyidx = tkey->key_idx;
-       memset(tkey, 0, sizeof(*tkey));
-       tkey->key_idx = keyidx;
-       tkey->tx_tfm_michael = tfm;
-       tkey->tx_ctx_arc4 = *tfm2;
-       tkey->rx_tfm_michael = tfm3;
-       tkey->rx_ctx_arc4 = *tfm4;
-       if (len == TKIP_KEY_LEN) {
-               memcpy(tkey->key, key, TKIP_KEY_LEN);
-               tkey->key_set = 1;
-               tkey->tx_iv16 = 1;      /* TSC is initialized to 1 */
-               if (seq) {
-                       tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
-                           (seq[3] << 8) | seq[2];
-                       tkey->rx_iv16 = (seq[1] << 8) | seq[0];
-               }
-       } else if (len == 0)
-               tkey->key_set = 0;
-       else
-               return -1;
-
-       return 0;
-}
-
-static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
-{
-       struct lib80211_tkip_data *tkey = priv;
-
-       if (len < TKIP_KEY_LEN)
-               return -1;
-
-       if (!tkey->key_set)
-               return 0;
-       memcpy(key, tkey->key, TKIP_KEY_LEN);
-
-       if (seq) {
-               /*
-                * Not clear if this should return the value as is
-                * or - as the code previously seemed to partially
-                * have been written as - subtract one from it. It
-                * was working this way for a long time so leave it.
-                */
-               seq[0] = tkey->tx_iv16;
-               seq[1] = tkey->tx_iv16 >> 8;
-               seq[2] = tkey->tx_iv32;
-               seq[3] = tkey->tx_iv32 >> 8;
-               seq[4] = tkey->tx_iv32 >> 16;
-               seq[5] = tkey->tx_iv32 >> 24;
-       }
-
-       return TKIP_KEY_LEN;
-}
-
-static void lib80211_tkip_print_stats(struct seq_file *m, void *priv)
-{
-       struct lib80211_tkip_data *tkip = priv;
-       seq_printf(m,
-                  "key[%d] alg=TKIP key_set=%d "
-                  "tx_pn=%02x%02x%02x%02x%02x%02x "
-                  "rx_pn=%02x%02x%02x%02x%02x%02x "
-                  "replays=%d icv_errors=%d local_mic_failures=%d\n",
-                  tkip->key_idx, tkip->key_set,
-                  (tkip->tx_iv32 >> 24) & 0xff,
-                  (tkip->tx_iv32 >> 16) & 0xff,
-                  (tkip->tx_iv32 >> 8) & 0xff,
-                  tkip->tx_iv32 & 0xff,
-                  (tkip->tx_iv16 >> 8) & 0xff,
-                  tkip->tx_iv16 & 0xff,
-                  (tkip->rx_iv32 >> 24) & 0xff,
-                  (tkip->rx_iv32 >> 16) & 0xff,
-                  (tkip->rx_iv32 >> 8) & 0xff,
-                  tkip->rx_iv32 & 0xff,
-                  (tkip->rx_iv16 >> 8) & 0xff,
-                  tkip->rx_iv16 & 0xff,
-                  tkip->dot11RSNAStatsTKIPReplays,
-                  tkip->dot11RSNAStatsTKIPICVErrors,
-                  tkip->dot11RSNAStatsTKIPLocalMICFailures);
-}
-
-static const struct lib80211_crypto_ops lib80211_crypt_tkip = {
-       .name = "TKIP",
-       .init = lib80211_tkip_init,
-       .deinit = lib80211_tkip_deinit,
-       .encrypt_mpdu = lib80211_tkip_encrypt,
-       .decrypt_mpdu = lib80211_tkip_decrypt,
-       .encrypt_msdu = lib80211_michael_mic_add,
-       .decrypt_msdu = lib80211_michael_mic_verify,
-       .set_key = lib80211_tkip_set_key,
-       .get_key = lib80211_tkip_get_key,
-       .print_stats = lib80211_tkip_print_stats,
-       .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
-       .extra_mpdu_postfix_len = 4,    /* ICV */
-       .extra_msdu_postfix_len = 8,    /* MIC */
-       .get_flags = lib80211_tkip_get_flags,
-       .set_flags = lib80211_tkip_set_flags,
-       .owner = THIS_MODULE,
-};
-
-static int __init lib80211_crypto_tkip_init(void)
-{
-       return lib80211_register_crypto_ops(&lib80211_crypt_tkip);
-}
-
-static void __exit lib80211_crypto_tkip_exit(void)
-{
-       lib80211_unregister_crypto_ops(&lib80211_crypt_tkip);
-}
-
-module_init(lib80211_crypto_tkip_init);
-module_exit(lib80211_crypto_tkip_exit);
diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c
deleted file mode 100644 (file)
index 3b148c7..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * lib80211 crypt: host-based WEP encryption implementation for lib80211
- *
- * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
- */
-
-#include <linux/err.h>
-#include <linux/fips.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/scatterlist.h>
-#include <linux/skbuff.h>
-#include <linux/mm.h>
-#include <asm/string.h>
-
-#include <net/lib80211.h>
-
-#include <crypto/arc4.h>
-#include <linux/crc32.h>
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("lib80211 crypt: WEP");
-MODULE_LICENSE("GPL");
-
-struct lib80211_wep_data {
-       u32 iv;
-#define WEP_KEY_LEN 13
-       u8 key[WEP_KEY_LEN + 1];
-       u8 key_len;
-       u8 key_idx;
-       struct arc4_ctx tx_ctx;
-       struct arc4_ctx rx_ctx;
-};
-
-static void *lib80211_wep_init(int keyidx)
-{
-       struct lib80211_wep_data *priv;
-
-       if (fips_enabled)
-               return NULL;
-
-       priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
-       if (priv == NULL)
-               return NULL;
-       priv->key_idx = keyidx;
-
-       /* start WEP IV from a random value */
-       get_random_bytes(&priv->iv, 4);
-
-       return priv;
-}
-
-static void lib80211_wep_deinit(void *priv)
-{
-       kfree_sensitive(priv);
-}
-
-/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
-static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len,
-                              u8 *key, int keylen, void *priv)
-{
-       struct lib80211_wep_data *wep = priv;
-       u32 klen;
-       u8 *pos;
-
-       if (skb_headroom(skb) < 4 || skb->len < hdr_len)
-               return -1;
-
-       pos = skb_push(skb, 4);
-       memmove(pos, pos + 4, hdr_len);
-       pos += hdr_len;
-
-       klen = 3 + wep->key_len;
-
-       wep->iv++;
-
-       /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
-        * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
-        * can be used to speedup attacks, so avoid using them. */
-       if ((wep->iv & 0xff00) == 0xff00) {
-               u8 B = (wep->iv >> 16) & 0xff;
-               if (B >= 3 && B < klen)
-                       wep->iv += 0x0100;
-       }
-
-       /* Prepend 24-bit IV to RC4 key and TX frame */
-       *pos++ = (wep->iv >> 16) & 0xff;
-       *pos++ = (wep->iv >> 8) & 0xff;
-       *pos++ = wep->iv & 0xff;
-       *pos++ = wep->key_idx << 6;
-
-       return 0;
-}
-
-/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
- * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
- * so the payload length increases with 8 bytes.
- *
- * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
- */
-static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
-       struct lib80211_wep_data *wep = priv;
-       u32 crc, klen, len;
-       u8 *pos, *icv;
-       u8 key[WEP_KEY_LEN + 3];
-
-       /* other checks are in lib80211_wep_build_iv */
-       if (skb_tailroom(skb) < 4)
-               return -1;
-
-       /* add the IV to the frame */
-       if (lib80211_wep_build_iv(skb, hdr_len, NULL, 0, priv))
-               return -1;
-
-       /* Copy the IV into the first 3 bytes of the key */
-       skb_copy_from_linear_data_offset(skb, hdr_len, key, 3);
-
-       /* Copy rest of the WEP key (the secret part) */
-       memcpy(key + 3, wep->key, wep->key_len);
-
-       len = skb->len - hdr_len - 4;
-       pos = skb->data + hdr_len + 4;
-       klen = 3 + wep->key_len;
-
-       /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */
-       crc = ~crc32_le(~0, pos, len);
-       icv = skb_put(skb, 4);
-       icv[0] = crc;
-       icv[1] = crc >> 8;
-       icv[2] = crc >> 16;
-       icv[3] = crc >> 24;
-
-       arc4_setkey(&wep->tx_ctx, key, klen);
-       arc4_crypt(&wep->tx_ctx, pos, pos, len + 4);
-
-       return 0;
-}
-
-/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
- * the frame: IV (4 bytes), encrypted payload (including SNAP header),
- * ICV (4 bytes). len includes both IV and ICV.
- *
- * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
- * failure. If frame is OK, IV and ICV will be removed.
- */
-static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
-       struct lib80211_wep_data *wep = priv;
-       u32 crc, klen, plen;
-       u8 key[WEP_KEY_LEN + 3];
-       u8 keyidx, *pos, icv[4];
-
-       if (skb->len < hdr_len + 8)
-               return -1;
-
-       pos = skb->data + hdr_len;
-       key[0] = *pos++;
-       key[1] = *pos++;
-       key[2] = *pos++;
-       keyidx = *pos++ >> 6;
-       if (keyidx != wep->key_idx)
-               return -1;
-
-       klen = 3 + wep->key_len;
-
-       /* Copy rest of the WEP key (the secret part) */
-       memcpy(key + 3, wep->key, wep->key_len);
-
-       /* Apply RC4 to data and compute CRC32 over decrypted data */
-       plen = skb->len - hdr_len - 8;
-
-       arc4_setkey(&wep->rx_ctx, key, klen);
-       arc4_crypt(&wep->rx_ctx, pos, pos, plen + 4);
-
-       crc = ~crc32_le(~0, pos, plen);
-       icv[0] = crc;
-       icv[1] = crc >> 8;
-       icv[2] = crc >> 16;
-       icv[3] = crc >> 24;
-       if (memcmp(icv, pos + plen, 4) != 0) {
-               /* ICV mismatch - drop frame */
-               return -2;
-       }
-
-       /* Remove IV and ICV */
-       memmove(skb->data + 4, skb->data, hdr_len);
-       skb_pull(skb, 4);
-       skb_trim(skb, skb->len - 4);
-
-       return 0;
-}
-
-static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv)
-{
-       struct lib80211_wep_data *wep = priv;
-
-       if (len < 0 || len > WEP_KEY_LEN)
-               return -1;
-
-       memcpy(wep->key, key, len);
-       wep->key_len = len;
-
-       return 0;
-}
-
-static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv)
-{
-       struct lib80211_wep_data *wep = priv;
-
-       if (len < wep->key_len)
-               return -1;
-
-       memcpy(key, wep->key, wep->key_len);
-
-       return wep->key_len;
-}
-
-static void lib80211_wep_print_stats(struct seq_file *m, void *priv)
-{
-       struct lib80211_wep_data *wep = priv;
-       seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
-}
-
-static const struct lib80211_crypto_ops lib80211_crypt_wep = {
-       .name = "WEP",
-       .init = lib80211_wep_init,
-       .deinit = lib80211_wep_deinit,
-       .encrypt_mpdu = lib80211_wep_encrypt,
-       .decrypt_mpdu = lib80211_wep_decrypt,
-       .encrypt_msdu = NULL,
-       .decrypt_msdu = NULL,
-       .set_key = lib80211_wep_set_key,
-       .get_key = lib80211_wep_get_key,
-       .print_stats = lib80211_wep_print_stats,
-       .extra_mpdu_prefix_len = 4,     /* IV */
-       .extra_mpdu_postfix_len = 4,    /* ICV */
-       .owner = THIS_MODULE,
-};
-
-static int __init lib80211_crypto_wep_init(void)
-{
-       return lib80211_register_crypto_ops(&lib80211_crypt_wep);
-}
-
-static void __exit lib80211_crypto_wep_exit(void)
-{
-       lib80211_unregister_crypto_ops(&lib80211_crypt_wep);
-}
-
-module_init(lib80211_crypto_wep_init);
-module_exit(lib80211_crypto_wep_exit);