drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c
Extension
.c
Size
10631 bytes
Lines
439
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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_obj(*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);

Annotation

Implementation Notes