^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * lib80211 crypt: host-based CCMP encryption implementation for lib80211
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/random.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/if_ether.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/if_arp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/wireless.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/ieee80211.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/crypto.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <crypto/aead.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <net/lib80211.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) MODULE_AUTHOR("Jouni Malinen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) MODULE_DESCRIPTION("Host AP crypt: CCMP");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define AES_BLOCK_LEN 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define CCMP_HDR_LEN 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define CCMP_MIC_LEN 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define CCMP_TK_LEN 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define CCMP_PN_LEN 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct lib80211_ccmp_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u8 key[CCMP_TK_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) int key_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) u8 tx_pn[CCMP_PN_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u8 rx_pn[CCMP_PN_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) u32 dot11RSNAStatsCCMPFormatErrors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) u32 dot11RSNAStatsCCMPReplays;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u32 dot11RSNAStatsCCMPDecryptErrors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) int key_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct crypto_aead *tfm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* scratch buffers for virt_to_page() (crypto API) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u8 tx_aad[2 * AES_BLOCK_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) u8 rx_aad[2 * AES_BLOCK_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void *lib80211_ccmp_init(int key_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct lib80211_ccmp_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (priv == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) priv->key_idx = key_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (IS_ERR(priv->tfm)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) priv->tfm = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (priv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (priv->tfm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) crypto_free_aead(priv->tfm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) kfree(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static void lib80211_ccmp_deinit(void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct lib80211_ccmp_data *_priv = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (_priv && _priv->tfm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) crypto_free_aead(_priv->tfm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) kfree(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) const u8 *pn, u8 *iv, u8 *aad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u8 *pos, qc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) size_t aad_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) int a4_included, qc_included;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) a4_included = ieee80211_has_a4(hdr->frame_control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) qc_included = ieee80211_is_data_qos(hdr->frame_control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) aad_len = 22;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (a4_included)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) aad_len += 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (qc_included) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) pos = (u8 *) & hdr->addr4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (a4_included)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) pos += 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) qc = *pos & 0x0f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) aad_len += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * mode authentication are not allowed to collide, yet both are derived
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * from the same vector. We only set L := 1 here to indicate that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * data size can be represented in (L+1) bytes. The CCM layer will take
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * care of storing the data length in the top (L+1) bytes and setting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * and clearing the other bits as is required to derive the two IVs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) iv[0] = 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* Nonce: QC | A2 | PN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) iv[1] = qc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) memcpy(iv + 2, hdr->addr2, ETH_ALEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) memcpy(iv + 8, pn, CCMP_PN_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* AAD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * A1 | A2 | A3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * SC with bits 4..15 (seq#) masked to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * A4 (if present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * QC (if present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) pos = (u8 *) hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) aad[0] = pos[0] & 0x8f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) aad[1] = pos[1] & 0xc7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) memcpy(aad + 2, hdr->addr1, 3 * ETH_ALEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) pos = (u8 *) & hdr->seq_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) aad[20] = pos[0] & 0x0f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) aad[21] = 0; /* all bits masked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) memset(aad + 22, 0, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (a4_included)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) memcpy(aad + 22, hdr->addr4, ETH_ALEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (qc_included) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) aad[a4_included ? 28 : 22] = qc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* rest of QC masked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return aad_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static int lib80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) u8 *aeskey, int keylen, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct lib80211_ccmp_data *key = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) u8 *pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (aeskey != NULL && keylen >= CCMP_TK_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) memcpy(aeskey, key->key, CCMP_TK_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) pos = skb_push(skb, CCMP_HDR_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) pos += hdr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) i = CCMP_PN_LEN - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) while (i >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) key->tx_pn[i]++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (key->tx_pn[i] != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) i--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) *pos++ = key->tx_pn[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) *pos++ = key->tx_pn[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) *pos++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) *pos++ = key->tx_pn[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) *pos++ = key->tx_pn[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) *pos++ = key->tx_pn[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) *pos++ = key->tx_pn[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return CCMP_HDR_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct lib80211_ccmp_data *key = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct ieee80211_hdr *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct aead_request *req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) struct scatterlist sg[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) u8 *aad = key->tx_aad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) u8 iv[AES_BLOCK_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) int len, data_len, aad_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) data_len = skb->len - hdr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) len = lib80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (len < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) req = aead_request_alloc(key->tfm, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (!req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) hdr = (struct ieee80211_hdr *)skb->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) skb_put(skb, CCMP_MIC_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) sg_init_table(sg, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) sg_set_buf(&sg[0], aad, aad_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) data_len + CCMP_MIC_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) aead_request_set_callback(req, 0, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) aead_request_set_ad(req, aad_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) aead_request_set_crypt(req, sg, sg, data_len, iv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) ret = crypto_aead_encrypt(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) aead_request_free(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * deal with seq counter wrapping correctly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * refer to timer_after() for jiffies wrapping handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) u32 iv32_n, iv16_n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) u32 iv32_o, iv16_o;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) iv16_n = (pn_n[4] << 8) | pn_n[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) iv16_o = (pn_o[4] << 8) | pn_o[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if ((s32)iv32_n - (s32)iv32_o < 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) (iv32_n == iv32_o && iv16_n <= iv16_o))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct lib80211_ccmp_data *key = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) u8 keyidx, *pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct ieee80211_hdr *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct aead_request *req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct scatterlist sg[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) u8 *aad = key->rx_aad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) u8 iv[AES_BLOCK_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) u8 pn[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int aad_len, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) key->dot11RSNAStatsCCMPFormatErrors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) hdr = (struct ieee80211_hdr *)skb->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) pos = skb->data + hdr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) keyidx = pos[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (!(keyidx & (1 << 5))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) net_dbg_ratelimited("CCMP: received packet without ExtIV flag from %pM\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) hdr->addr2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) key->dot11RSNAStatsCCMPFormatErrors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) keyidx >>= 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (key->key_idx != keyidx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) net_dbg_ratelimited("CCMP: RX tkey->key_idx=%d frame keyidx=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) key->key_idx, keyidx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return -6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (!key->key_set) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) net_dbg_ratelimited("CCMP: received packet from %pM with keyid=%d that does not have a configured key\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) hdr->addr2, keyidx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return -3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) pn[0] = pos[7];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) pn[1] = pos[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) pn[2] = pos[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) pn[3] = pos[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) pn[4] = pos[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) pn[5] = pos[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) pos += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (ccmp_replay_check(pn, key->rx_pn)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) #ifdef CONFIG_LIB80211_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 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",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) hdr->addr2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) key->rx_pn[0], key->rx_pn[1], key->rx_pn[2],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) key->rx_pn[3], key->rx_pn[4], key->rx_pn[5],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) key->dot11RSNAStatsCCMPReplays++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return -4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) req = aead_request_alloc(key->tfm, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (!req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) sg_init_table(sg, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) sg_set_buf(&sg[0], aad, aad_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) sg_set_buf(&sg[1], pos, data_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) aead_request_set_callback(req, 0, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) aead_request_set_ad(req, aad_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) aead_request_set_crypt(req, sg, sg, data_len, iv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) ret = crypto_aead_decrypt(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) aead_request_free(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) net_dbg_ratelimited("CCMP: decrypt failed: STA=%pM (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) hdr->addr2, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) key->dot11RSNAStatsCCMPDecryptErrors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return -5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) memcpy(key->rx_pn, pn, CCMP_PN_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /* Remove hdr and MIC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) skb_pull(skb, CCMP_HDR_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) skb_trim(skb, skb->len - CCMP_MIC_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return keyidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static int lib80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct lib80211_ccmp_data *data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) int keyidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct crypto_aead *tfm = data->tfm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) keyidx = data->key_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) memset(data, 0, sizeof(*data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) data->key_idx = keyidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) data->tfm = tfm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (len == CCMP_TK_LEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) memcpy(data->key, key, CCMP_TK_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) data->key_set = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (seq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) data->rx_pn[0] = seq[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) data->rx_pn[1] = seq[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) data->rx_pn[2] = seq[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) data->rx_pn[3] = seq[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) data->rx_pn[4] = seq[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) data->rx_pn[5] = seq[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (crypto_aead_setauthsize(data->tfm, CCMP_MIC_LEN) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) crypto_aead_setkey(data->tfm, data->key, CCMP_TK_LEN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) } else if (len == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) data->key_set = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) struct lib80211_ccmp_data *data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (len < CCMP_TK_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (!data->key_set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) memcpy(key, data->key, CCMP_TK_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (seq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) seq[0] = data->tx_pn[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) seq[1] = data->tx_pn[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) seq[2] = data->tx_pn[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) seq[3] = data->tx_pn[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) seq[4] = data->tx_pn[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) seq[5] = data->tx_pn[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return CCMP_TK_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) static void lib80211_ccmp_print_stats(struct seq_file *m, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct lib80211_ccmp_data *ccmp = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) seq_printf(m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) "key[%d] alg=CCMP key_set=%d "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) "tx_pn=%02x%02x%02x%02x%02x%02x "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) "rx_pn=%02x%02x%02x%02x%02x%02x "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) "format_errors=%d replays=%d decrypt_errors=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) ccmp->key_idx, ccmp->key_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) ccmp->dot11RSNAStatsCCMPFormatErrors,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) ccmp->dot11RSNAStatsCCMPReplays,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) ccmp->dot11RSNAStatsCCMPDecryptErrors);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) static struct lib80211_crypto_ops lib80211_crypt_ccmp = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) .name = "CCMP",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) .init = lib80211_ccmp_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) .deinit = lib80211_ccmp_deinit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) .encrypt_mpdu = lib80211_ccmp_encrypt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) .decrypt_mpdu = lib80211_ccmp_decrypt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) .encrypt_msdu = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .decrypt_msdu = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) .set_key = lib80211_ccmp_set_key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) .get_key = lib80211_ccmp_get_key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) .print_stats = lib80211_ccmp_print_stats,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) .extra_mpdu_prefix_len = CCMP_HDR_LEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) .extra_mpdu_postfix_len = CCMP_MIC_LEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) static int __init lib80211_crypto_ccmp_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return lib80211_register_crypto_ops(&lib80211_crypt_ccmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static void __exit lib80211_crypto_ccmp_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) lib80211_unregister_crypto_ops(&lib80211_crypt_ccmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) module_init(lib80211_crypto_ccmp_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) module_exit(lib80211_crypto_ccmp_exit);