drivers/net/wireless/mediatek/mt76/mac80211.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/mediatek/mt76/mac80211.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/mediatek/mt76/mac80211.c
Extension
.c
Size
57797 bytes
Lines
2361
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 mt76_offchannel_cb_data {
	struct mt76_phy *phy;
	bool offchannel;
};

static void
mt76_offchannel_send_nullfunc(struct mt76_offchannel_cb_data *data,
			      struct ieee80211_vif *vif, int link_id)
{
	struct mt76_phy *phy = data->phy;
	struct ieee80211_tx_info *info;
	struct ieee80211_sta *sta = NULL;
	struct ieee80211_hdr *hdr;
	struct mt76_wcid *wcid;
	struct sk_buff *skb;

	skb = ieee80211_nullfunc_get(phy->hw, vif, link_id, true);
	if (!skb)
		return;

	hdr = (struct ieee80211_hdr *)skb->data;
	if (data->offchannel)
		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);

	skb->priority = 7;
	skb_set_queue_mapping(skb, IEEE80211_AC_VO);

	if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb,
				      phy->main_chandef.chan->band,
				      &sta))
		return;

	if (sta)
		wcid = (struct mt76_wcid *)sta->drv_priv;
	else
		wcid = ((struct mt76_vif_link *)vif->drv_priv)->wcid;

	if (link_id >= 0) {
		info = IEEE80211_SKB_CB(skb);
		info->control.flags &= ~IEEE80211_TX_CTRL_MLO_LINK;
		info->control.flags |=
			u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK);
	}

	mt76_tx(phy, sta, wcid, skb);
}

static void
mt76_offchannel_notify_iter(void *_data, u8 *mac, struct ieee80211_vif *vif)
{
	struct mt76_offchannel_cb_data *data = _data;
	struct mt76_vif_link *mlink;
	struct mt76_vif_data *mvif;
	int link_id;

	if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
		return;

	mlink = (struct mt76_vif_link *)vif->drv_priv;
	mvif = mlink->mvif;

	if (!ieee80211_vif_is_mld(vif)) {
		if (mt76_vif_link_phy(mlink) == data->phy) {
			if (!data->offchannel && mlink->beacon_mon_interval)
				WRITE_ONCE(mlink->beacon_mon_last, jiffies);
			mt76_offchannel_send_nullfunc(data, vif, -1);
		}
		return;
	}

	for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
		if (link_id == mvif->deflink_id)
			mlink = (struct mt76_vif_link *)vif->drv_priv;
		else
			mlink = rcu_dereference(mvif->link[link_id]);
		if (!mlink)
			continue;
		if (mt76_vif_link_phy(mlink) != data->phy)
			continue;

		if (!data->offchannel && mlink->beacon_mon_interval)
			WRITE_ONCE(mlink->beacon_mon_last, jiffies);

		mt76_offchannel_send_nullfunc(data, vif, link_id);
	}
}

void mt76_offchannel_notify(struct mt76_phy *phy, bool offchannel)
{
	struct mt76_offchannel_cb_data data = {

Annotation

Implementation Notes