void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
		   bool tidstats)
{
	struct ieee80211_sub_if_data *sdata = sta->sdata;
	struct ieee80211_local *local = sdata->local;
	u32 thr = 0;
	int i, ac, cpu;
	struct ieee80211_sta_rx_stats *last_rxstats;

	last_rxstats = sta_get_last_rx_stats(sta);

	sinfo->generation = sdata->local->sta_generation;

	/* do before driver, so beacon filtering drivers have a
	 * chance to e.g. just add the number of filtered beacons
	 * (or just modify the value entirely, of course)
	 */
	if (sdata->vif.type == NL80211_IFTYPE_STATION)
		sinfo->rx_beacon = sdata->u.mgd.count_beacon_signal;

	drv_sta_statistics(local, sdata, &sta->sta, sinfo);

	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) |
			 BIT_ULL(NL80211_STA_INFO_STA_FLAGS) |
			 BIT_ULL(NL80211_STA_INFO_BSS_PARAM) |
			 BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME) |
			 BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC);

	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
		sinfo->beacon_loss_count = sdata->u.mgd.beacon_loss_count;
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_LOSS);
	}

	sinfo->connected_time = ktime_get_seconds() - sta->last_connected;
	sinfo->inactive_time =
		jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta));

	if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
			       BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {
		sinfo->tx_bytes = 0;
		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
			sinfo->tx_bytes += sta->tx_stats.bytes[ac];
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_PACKETS))) {
		sinfo->tx_packets = 0;
		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
			sinfo->tx_packets += sta->tx_stats.packets[ac];
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
	}

	if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES64) |
			       BIT_ULL(NL80211_STA_INFO_RX_BYTES)))) {
		sinfo->rx_bytes += sta_get_stats_bytes(&sta->rx_stats);

		if (sta->pcpu_rx_stats) {
			for_each_possible_cpu(cpu) {
				struct ieee80211_sta_rx_stats *cpurxs;

				cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
				sinfo->rx_bytes += sta_get_stats_bytes(cpurxs);
			}
		}

		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_PACKETS))) {
		sinfo->rx_packets = sta->rx_stats.packets;
		if (sta->pcpu_rx_stats) {
			for_each_possible_cpu(cpu) {
				struct ieee80211_sta_rx_stats *cpurxs;

				cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
				sinfo->rx_packets += cpurxs->packets;
			}
		}
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_RETRIES))) {
		sinfo->tx_retries = sta->status_stats.retry_count;
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED))) {
		sinfo->tx_failed = sta->status_stats.retry_failed;
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) {
		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
			sinfo->rx_duration += sta->airtime[ac].rx_airtime;
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) {
		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
			sinfo->tx_duration += sta->airtime[ac].tx_airtime;
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
		sinfo->airtime_weight = sta->airtime_weight;
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
	}

	sinfo->rx_dropped_misc = sta->rx_stats.dropped;
	if (sta->pcpu_rx_stats) {
		for_each_possible_cpu(cpu) {
			struct ieee80211_sta_rx_stats *cpurxs;

			cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
			sinfo->rx_dropped_misc += cpurxs->dropped;
		}
	}

	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
	    !(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) {
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX) |
				 BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
		sinfo->rx_beacon_signal_avg = ieee80211_ave_rssi(&sdata->vif);
	}

	if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) ||
	    ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) {
		if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL))) {
			sinfo->signal = (s8)last_rxstats->last_signal;
			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
		}

		if (!sta->pcpu_rx_stats &&
		    !(sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG))) {
			sinfo->signal_avg =
				-ewma_signal_read(&sta->rx_stats_avg.signal);
			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
		}
	}

	/* for the average - if pcpu_rx_stats isn't set - rxstats must point to
	 * the sta->rx_stats struct, so the check here is fine with and without
	 * pcpu statistics
	 */
	if (last_rxstats->chains &&
	    !(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL) |
			       BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
		if (!sta->pcpu_rx_stats)
			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);

		sinfo->chains = last_rxstats->chains;

		for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
			sinfo->chain_signal[i] =
				last_rxstats->chain_signal_last[i];
			sinfo->chain_signal_avg[i] =
				-ewma_signal_read(&sta->rx_stats_avg.chain_signal[i]);
		}
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE))) {
		sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate,
				     &sinfo->txrate);
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE))) {
		if (sta_set_rate_info_rx(sta, &sinfo->rxrate) == 0)
			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
	}

	if (tidstats && !cfg80211_sinfo_alloc_tid_stats(sinfo, GFP_KERNEL)) {
		for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
			sta_set_tidstats(sta, &sinfo->pertid[i], i);
	}

	if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_LLID) |
				 BIT_ULL(NL80211_STA_INFO_PLID) |
				 BIT_ULL(NL80211_STA_INFO_PLINK_STATE) |
				 BIT_ULL(NL80211_STA_INFO_LOCAL_PM) |
				 BIT_ULL(NL80211_STA_INFO_PEER_PM) |
				 BIT_ULL(NL80211_STA_INFO_NONPEER_PM) |
				 BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_GATE);

		sinfo->llid = sta->mesh->llid;
		sinfo->plid = sta->mesh->plid;
		sinfo->plink_state = sta->mesh->plink_state;
		if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_T_OFFSET);
			sinfo->t_offset = sta->mesh->t_offset;
		}
		sinfo->local_pm = sta->mesh->local_pm;
		sinfo->peer_pm = sta->mesh->peer_pm;
		sinfo->nonpeer_pm = sta->mesh->nonpeer_pm;
		sinfo->connected_to_gate = sta->mesh->connected_to_gate;
#endif
	}

	sinfo->bss_param.flags = 0;
	if (sdata->vif.bss_conf.use_cts_prot)
		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
	if (sdata->vif.bss_conf.use_short_preamble)
		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
	if (sdata->vif.bss_conf.use_short_slot)
		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
	sinfo->bss_param.dtim_period = sdata->vif.bss_conf.dtim_period;
	sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;

	sinfo->sta_flags.set = 0;
	sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
				BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
				BIT(NL80211_STA_FLAG_WME) |
				BIT(NL80211_STA_FLAG_MFP) |
				BIT(NL80211_STA_FLAG_AUTHENTICATED) |
				BIT(NL80211_STA_FLAG_ASSOCIATED) |
				BIT(NL80211_STA_FLAG_TDLS_PEER);
	if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
	if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
	if (sta->sta.wme)
		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
	if (test_sta_flag(sta, WLAN_STA_MFP))
		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
	if (test_sta_flag(sta, WLAN_STA_AUTH))
		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
	if (test_sta_flag(sta, WLAN_STA_ASSOC))
		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);

	thr = sta_get_expected_throughput(sta);

	if (thr != 0) {
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
		sinfo->expected_throughput = thr;
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL)) &&
	    sta->status_stats.ack_signal_filled) {
		sinfo->ack_signal = sta->status_stats.last_ack_signal;
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
	}

	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG)) &&
	    sta->status_stats.ack_signal_filled) {
		sinfo->avg_ack_signal =
			-(s8)ewma_avg_signal_read(
				&sta->status_stats.avg_ack_signal);
		sinfo->filled |=
			BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
	}

	if (ieee80211_vif_is_mesh(&sdata->vif)) {
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC);
		sinfo->airtime_link_metric =
			airtime_link_metric_get(local, sta);
	}
}