drivers/net/wireless/intel/iwlwifi/mvm/tdls.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
Extension
.c
Size
18972 bytes
Lines
665
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

if (vif) {
			mvmsta = iwl_mvm_sta_from_mac80211(sta);
			if (mvmsta->vif != vif)
				continue;
		}

		count++;
	}

	return count;
}

static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
	struct iwl_rx_packet *pkt;
	struct iwl_tdls_config_res *resp;
	struct iwl_tdls_config_cmd tdls_cfg_cmd = {};
	struct iwl_host_cmd cmd = {
		.id = TDLS_CONFIG_CMD,
		.flags = CMD_WANT_SKB,
		.data = { &tdls_cfg_cmd, },
		.len = { sizeof(struct iwl_tdls_config_cmd), },
	};
	struct ieee80211_sta *sta;
	int ret, i, cnt;
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

	lockdep_assert_held(&mvm->mutex);

	tdls_cfg_cmd.id_and_color =
		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
	tdls_cfg_cmd.tx_to_ap_tid = IWL_MVM_TDLS_FW_TID;
	tdls_cfg_cmd.tx_to_ap_ssn = cpu_to_le16(0); /* not used for now */

	/* for now the Tx cmd is empty and unused */

	/* populate TDLS peer data */
	cnt = 0;
	for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
						lockdep_is_held(&mvm->mutex));
		if (IS_ERR_OR_NULL(sta) || !sta->tdls)
			continue;

		tdls_cfg_cmd.sta_info[cnt].sta_id = i;
		tdls_cfg_cmd.sta_info[cnt].tx_to_peer_tid =
							IWL_MVM_TDLS_FW_TID;
		tdls_cfg_cmd.sta_info[cnt].tx_to_peer_ssn = cpu_to_le16(0);
		tdls_cfg_cmd.sta_info[cnt].is_initiator =
				cpu_to_le32(sta->tdls_initiator ? 1 : 0);

		cnt++;
	}

	tdls_cfg_cmd.tdls_peer_count = cnt;
	IWL_DEBUG_TDLS(mvm, "send TDLS config to FW for %d peers\n", cnt);

	ret = iwl_mvm_send_cmd(mvm, &cmd);
	if (WARN_ON_ONCE(ret))
		return;

	pkt = cmd.resp_pkt;

	WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp));

	/* we don't really care about the response at this point */

	iwl_free_resp(&cmd);
}

void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
			       bool sta_added)
{
	int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);

	/* when the first peer joins, send a power update first */
	if (tdls_sta_cnt == 1 && sta_added)
		iwl_mvm_power_update_mac(mvm);

	/* Configure the FW with TDLS peer info only if TDLS channel switch
	 * capability is set.
	 * TDLS config data is used currently only in TDLS channel switch code.
	 * Supposed to serve also TDLS buffer station which is not implemneted
	 * yet in FW*/
	if (fw_has_capa(&mvm->fw->ucode_capa,
			IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH))
		iwl_mvm_tdls_config(mvm, vif);

	/* when the last peer leaves, send a power update last */
	if (tdls_sta_cnt == 0 && !sta_added)

Annotation

Implementation Notes