drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
Extension
.c
Size
10326 bytes
Lines
363
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 iwl_mvm_sta_key_update_data {
	struct ieee80211_sta *sta;
	u32 old_sta_mask;
	u32 new_sta_mask;
	int err;
};

static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
				 u32 key_flags, u32 keyidx, u32 flags)
{
	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
	struct iwl_sec_key_cmd cmd = {
		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
		.u.remove.sta_mask = cpu_to_le32(sta_mask),
		.u.remove.key_id = cpu_to_le32(keyidx),
		.u.remove.key_flags = cpu_to_le32(key_flags),
	};

	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
}

int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
			 struct ieee80211_key_conf *keyconf)
{
	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
	struct iwl_sec_key_cmd cmd = {
		.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
		.u.add.sta_mask = cpu_to_le32(sta_mask),
		.u.add.key_id = cpu_to_le32(keyconf->keyidx),
		.u.add.key_flags = cpu_to_le32(key_flags),
		.u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
	};
	int max_key_len = sizeof(cmd.u.add.key);
	int ret;

	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
		max_key_len -= IWL_SEC_WEP_KEY_OFFSET;

	if (WARN_ON(keyconf->keylen > max_key_len))
		return -EINVAL;

	if (WARN_ON(!sta_mask))
		return -EINVAL;

	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
		memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key,
		       keyconf->keylen);
	else
		memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);

	if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) {
		memcpy(cmd.u.add.tkip_mic_rx_key,
		       keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
		       8);
		memcpy(cmd.u.add.tkip_mic_tx_key,
		       keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
		       8);
	}

	ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
	if (ret)
		return ret;

	/*
	 * For WEP, the same key is used for multicast and unicast so need to
	 * upload it again. If this fails, remove the original as well.
	 */
	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
		cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY);
		ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
		if (ret)
			__iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
					      keyconf->keyidx, 0);
	}

	return ret;
}

int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
			struct ieee80211_vif *vif,
			struct ieee80211_sta *sta,
			struct ieee80211_key_conf *keyconf)
{
	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_mvm_vif_link_info *mvm_link = NULL;

Annotation

Implementation Notes