net/mac80211/mesh_ps.c

Source file repositories/reference/linux-study-clean/net/mac80211/mesh_ps.c

File Facts

System
Linux kernel
Corpus path
net/mac80211/mesh_ps.c
Extension
.c
Size
16935 bytes
Lines
613
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

switch (sta->mesh->plink_state) {
		case NL80211_PLINK_OPN_SNT:
		case NL80211_PLINK_OPN_RCVD:
		case NL80211_PLINK_CNF_RCVD:
			peering = true;
			break;
		case NL80211_PLINK_ESTAB:
			if (sta->mesh->local_pm == NL80211_MESH_POWER_LIGHT_SLEEP)
				light_sleep_cnt++;
			else if (sta->mesh->local_pm == NL80211_MESH_POWER_DEEP_SLEEP)
				deep_sleep_cnt++;
			break;
		default:
			break;
		}
	}
	rcu_read_unlock();

	/*
	 * Set non-peer mode to active during peering/scanning/authentication
	 * (see IEEE802.11-2012 13.14.8.3). The non-peer mesh power mode is
	 * deep sleep if the local STA is in light or deep sleep towards at
	 * least one mesh peer (see 13.14.3.1). Otherwise, set it to the
	 * user-configured default value.
	 */
	if (peering) {
		mps_dbg(sdata, "setting non-peer PM to active for peering\n");
		nonpeer_pm = NL80211_MESH_POWER_ACTIVE;
	} else if (light_sleep_cnt || deep_sleep_cnt) {
		mps_dbg(sdata, "setting non-peer PM to deep sleep\n");
		nonpeer_pm = NL80211_MESH_POWER_DEEP_SLEEP;
	} else {
		mps_dbg(sdata, "setting non-peer PM to user value\n");
		nonpeer_pm = ifmsh->mshcfg.power_mode;
	}

	/* need update if sleep counts move between 0 and non-zero */
	if (ifmsh->nonpeer_pm != nonpeer_pm ||
	    !ifmsh->ps_peers_light_sleep != !light_sleep_cnt ||
	    !ifmsh->ps_peers_deep_sleep != !deep_sleep_cnt)
		changed = BSS_CHANGED_BEACON;

	ifmsh->nonpeer_pm = nonpeer_pm;
	ifmsh->ps_peers_light_sleep = light_sleep_cnt;
	ifmsh->ps_peers_deep_sleep = deep_sleep_cnt;

	return changed;
}

/**
 * ieee80211_mps_set_sta_local_pm - set local PM towards a mesh STA
 *
 * @sta: mesh STA
 * @pm: the power mode to set
 * Returns: BSS_CHANGED_BEACON if a beacon update is in order.
 */
u64 ieee80211_mps_set_sta_local_pm(struct sta_info *sta,
				   enum nl80211_mesh_power_mode pm)
{
	struct ieee80211_sub_if_data *sdata = sta->sdata;

	if (sta->mesh->local_pm == pm)
		return 0;

	mps_dbg(sdata, "local STA operates in mode %d with %pM\n",
		pm, sta->sta.addr);

	sta->mesh->local_pm = pm;

	/*
	 * announce peer-specific power mode transition
	 * (see IEEE802.11-2012 13.14.3.2 and 13.14.3.3)
	 */
	if (sta->mesh->plink_state == NL80211_PLINK_ESTAB)
		mps_qos_null_tx(sta);

	return ieee80211_mps_local_status_update(sdata);
}

/**
 * ieee80211_mps_set_frame_flags - set mesh PS flags in FC (and QoS Control)
 *
 * @sdata: local mesh subif
 * @sta: mesh STA
 * @hdr: 802.11 frame header
 *
 * see IEEE802.11-2012 8.2.4.1.7 and 8.2.4.5.11
 *
 * NOTE: sta must be given when an individually-addressed QoS frame header
 * is handled, for group-addressed and management frames it is not used

Annotation

Implementation Notes