Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78ac51f8 authored by Sara Sharon's avatar Sara Sharon Committed by Johannes Berg
Browse files

mac80211: support multi-bssid



Add support for multi-bssid.

This includes:
- Parsing multi-bssid element
- Overriding DTIM values
- Taking into account in various places the inner BSSID instead of
  transmitter BSSID
- Save aside some multi-bssid properties needed by drivers

Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 0cd01efb
Loading
Loading
Loading
Loading
+33 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@
 * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
 * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
 * Copyright (c) 2016 - 2017 Intel Deutschland GmbH
 * Copyright (c) 2018        Intel Corporation
 * Copyright (c) 2018 - 2019 Intel Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
@@ -2475,6 +2475,7 @@ enum ieee80211_eid_ext {
	WLAN_EID_EXT_HE_OPERATION = 36,
	WLAN_EID_EXT_UORA = 37,
	WLAN_EID_EXT_HE_MU_EDCA = 38,
	WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55,
};

/* Action category code */
@@ -2691,6 +2692,9 @@ enum ieee80211_tdls_actioncode {
#define WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT	BIT(5)
#define WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT	BIT(6)

/* Defines support for enhanced multi-bssid advertisement*/
#define WLAN_EXT_CAPA11_EMA_SUPPORT	BIT(1)

/* TDLS specific payload type in the LLC/SNAP header */
#define WLAN_TDLS_SNAP_RFTYPE	0x2

@@ -2882,6 +2886,34 @@ enum ieee80211_sa_query_action {
	WLAN_ACTION_SA_QUERY_RESPONSE = 1,
};

/**
 * struct ieee80211_bssid_index
 *
 * This structure refers to "Multiple BSSID-index element"
 *
 * @bssid_index: BSSID index
 * @dtim_period: optional, overrides transmitted BSS dtim period
 * @dtim_count: optional, overrides transmitted BSS dtim count
 */
struct ieee80211_bssid_index {
	u8 bssid_index;
	u8 dtim_period;
	u8 dtim_count;
};

/**
 * struct ieee80211_multiple_bssid_configuration
 *
 * This structure refers to "Multiple BSSID Configuration element"
 *
 * @bssid_count: total number of active BSSIDs in the set
 * @profile_periodicity: the least number of beacon frames need to be received
 *	in order to discover all the nontransmitted BSSIDs in the set.
 */
struct ieee80211_multiple_bssid_configuration {
	u8 bssid_count;
	u8 profile_periodicity;
};

#define SUITE(oui, id)	(((oui) << 8) | (id))

+15 −0
Original line number Diff line number Diff line
@@ -591,6 +591,14 @@ struct ieee80211_ftm_responder_params {
 * @ftm_responder: whether to enable or disable fine timing measurement FTM
 *	responder functionality.
 * @ftmr_params: configurable lci/civic parameter when enabling FTM responder.
 * @nontransmitted: this BSS is a nontransmitted BSS profile
 * @transmitter_bssid: the address of transmitter AP
 * @bssid_index: index inside the multiple BSSID set
 * @bssid_indicator: 2^bssid_indicator is the maximum number of APs in set
 * @ema_ap: AP supports enhancements of discovery and advertisement of
 *	nontransmitted BSSIDs
 * @profile_periodicity: the least number of beacon frames need to be received
 *	in order to discover all the nontransmitted BSSIDs in the set.
 */
struct ieee80211_bss_conf {
	const u8 *bssid;
@@ -644,6 +652,13 @@ struct ieee80211_bss_conf {
	bool protected_keep_alive;
	bool ftm_responder;
	struct ieee80211_ftm_responder_params *ftmr_params;
	/* Multiple BSSID data */
	bool nontransmitted;
	u8 transmitter_bssid[ETH_ALEN];
	u8 bssid_index;
	u8 bssid_indicator;
	bool ema_ap;
	u8 profile_periodicity;
};

/**
+7 −0
Original line number Diff line number Diff line
@@ -1495,6 +1495,12 @@ struct ieee802_11_elems {
	const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
	struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
	const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie;
	const struct ieee80211_multiple_bssid_configuration *mbssid_config_ie;
	const struct ieee80211_bssid_index *bssid_index;
	const u8 *nontransmitted_bssid_profile;
	u8 max_bssid_indicator;
	u8 dtim_count;
	u8 dtim_period;

	/* length of them, respectively */
	u8 ext_capab_len;
@@ -1513,6 +1519,7 @@ struct ieee802_11_elems {
	u8 prep_len;
	u8 perr_len;
	u8 country_elem_len;
	u8 bssid_index_len;

	/* whether a parse error occurred while retrieving these elements */
	bool parse_error;
+88 −37
Original line number Diff line number Diff line
@@ -3308,6 +3308,14 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
		/* TODO: OPEN: what happens if BSS color disable is set? */
	}

	if (cbss->transmitted_bss) {
		bss_conf->nontransmitted = true;
		ether_addr_copy(bss_conf->transmitter_bssid,
				cbss->transmitted_bss->bssid);
		bss_conf->bssid_indicator = cbss->max_bssid_indicator;
		bss_conf->bssid_index = cbss->bssid_index;
	}

	/*
	 * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
	 * in their association response, so ignore that data for our own
@@ -3692,6 +3700,16 @@ static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
	}
}

static bool ieee80211_rx_our_beacon(const u8 *tx_bssid,
				    struct cfg80211_bss *bss)
{
	if (ether_addr_equal(tx_bssid, bss->bssid))
		return true;
	if (!bss->transmitted_bss)
		return false;
	return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
}

static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
				     struct ieee80211_mgmt *mgmt, size_t len,
				     struct ieee80211_rx_status *rx_status)
@@ -3733,17 +3751,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
	rcu_read_unlock();

	if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
	    ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
	    ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->assoc_data->bss)) {
		ieee802_11_parse_elems(mgmt->u.beacon.variable,
				       len - baselen, false, &elems,
				       mgmt->bssid,
				       ifmgd->assoc_data->bss->bssid);

		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
		if (elems.tim && !elems.parse_error) {
			const struct ieee80211_tim_ie *tim_ie = elems.tim;
			ifmgd->dtim_period = tim_ie->dtim_period;
		}

		if (elems.dtim_period)
			ifmgd->dtim_period = elems.dtim_period;
		ifmgd->have_beacon = true;
		ifmgd->assoc_data->need_beacon = false;
		if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
@@ -3751,12 +3768,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
				le64_to_cpu(mgmt->u.beacon.timestamp);
			sdata->vif.bss_conf.sync_device_ts =
				rx_status->device_timestamp;
			if (elems.tim)
				sdata->vif.bss_conf.sync_dtim_count =
					elems.tim->dtim_count;
			else
				sdata->vif.bss_conf.sync_dtim_count = 0;
			sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
		}

		if (elems.mbssid_config_ie)
			bss_conf->profile_periodicity =
				elems.mbssid_config_ie->profile_periodicity;

		if (elems.ext_capab_len >= 11 &&
		    (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
			bss_conf->ema_ap = true;

		/* continue assoc process */
		ifmgd->assoc_data->timeout = jiffies;
		ifmgd->assoc_data->timeout_started = true;
@@ -3765,7 +3787,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
	}

	if (!ifmgd->associated ||
	    !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
	    !ieee80211_rx_our_beacon(mgmt->bssid,  ifmgd->associated))
		return;
	bssid = ifmgd->associated->bssid;

@@ -3861,11 +3883,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
			le64_to_cpu(mgmt->u.beacon.timestamp);
		sdata->vif.bss_conf.sync_device_ts =
			rx_status->device_timestamp;
		if (elems.tim)
			sdata->vif.bss_conf.sync_dtim_count =
				elems.tim->dtim_count;
		else
			sdata->vif.bss_conf.sync_dtim_count = 0;
		sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
	}

	if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
@@ -3891,10 +3909,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
	 */
	if (!ifmgd->have_beacon) {
		/* a few bogus AP send dtim_period = 0 or no TIM IE */
		if (elems.tim)
			bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
		else
			bss_conf->dtim_period = 1;
		bss_conf->dtim_period = elems.dtim_period ?: 1;

		changed |= BSS_CHANGED_BEACON_INFO;
		ifmgd->have_beacon = true;
@@ -4761,6 +4776,40 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
	return ret;
}

static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies,
			       u8 *dtim_count, u8 *dtim_period)
{
	const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
	const u8 *idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, ies->data,
					 ies->len);
	const struct ieee80211_tim_ie *tim = NULL;
	const struct ieee80211_bssid_index *idx;
	bool valid = tim_ie && tim_ie[1] >= 2;

	if (valid)
		tim = (void *)(tim_ie + 2);

	if (dtim_count)
		*dtim_count = valid ? tim->dtim_count : 0;

	if (dtim_period)
		*dtim_period = valid ? tim->dtim_period : 0;

	/* Check if value is overridden by non-transmitted profile */
	if (!idx_ie || idx_ie[1] < 3)
		return valid;

	idx = (void *)(idx_ie + 2);

	if (dtim_count)
		*dtim_count = idx->dtim_count;

	if (dtim_period)
		*dtim_period = idx->dtim_period;

	return true;
}

static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
				     struct cfg80211_bss *cbss, bool assoc,
				     bool override)
@@ -4852,17 +4901,13 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
		rcu_read_lock();
		ies = rcu_dereference(cbss->beacon_ies);
		if (ies) {
			const u8 *tim_ie;

			sdata->vif.bss_conf.sync_tsf = ies->tsf;
			sdata->vif.bss_conf.sync_device_ts =
				bss->device_ts_beacon;
			tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
						  ies->data, ies->len);
			if (tim_ie && tim_ie[1] >= 2)
				sdata->vif.bss_conf.sync_dtim_count = tim_ie[2];
			else
				sdata->vif.bss_conf.sync_dtim_count = 0;

			ieee80211_get_dtim(ies,
					   &sdata->vif.bss_conf.sync_dtim_count,
					   NULL);
		} else if (!ieee80211_hw_check(&sdata->local->hw,
					       TIMING_BEACON_ONLY)) {
			ies = rcu_dereference(cbss->proberesp_ies);
@@ -5332,17 +5377,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
		assoc_data->timeout_started = true;
		assoc_data->need_beacon = true;
	} else if (beacon_ies) {
		const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
						    beacon_ies->data,
						    beacon_ies->len);
		const u8 *ie;
		u8 dtim_count = 0;

		if (tim_ie && tim_ie[1] >= sizeof(struct ieee80211_tim_ie)) {
			const struct ieee80211_tim_ie *tim;
			tim = (void *)(tim_ie + 2);
			ifmgd->dtim_period = tim->dtim_period;
			dtim_count = tim->dtim_count;
		}
		ieee80211_get_dtim(beacon_ies, &dtim_count,
				   &ifmgd->dtim_period);

		ifmgd->have_beacon = true;
		assoc_data->timeout = jiffies;
		assoc_data->timeout_started = true;
@@ -5353,6 +5393,17 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
				bss->device_ts_beacon;
			sdata->vif.bss_conf.sync_dtim_count = dtim_count;
		}

		ie = cfg80211_find_ext_ie(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION,
					  beacon_ies->data, beacon_ies->len);
		if (ie && ie[1] >= 3)
			sdata->vif.bss_conf.profile_periodicity = ie[4];

		ie = cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY,
				      beacon_ies->data, beacon_ies->len);
		if (ie && ie[1] >= 11 &&
		    (ie[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
			sdata->vif.bss_conf.ema_ap = true;
	} else {
		assoc_data->timeout = jiffies;
		assoc_data->timeout_started = true;
+9 −2
Original line number Diff line number Diff line
@@ -144,8 +144,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
			  struct ieee80211_channel *channel)
{
	bool beacon = ieee80211_is_beacon(mgmt->frame_control);
	struct cfg80211_bss *cbss;
	struct ieee80211_bss *bss;
	struct cfg80211_bss *cbss, *non_tx_cbss;
	struct ieee80211_bss *bss, *non_tx_bss;
	struct cfg80211_inform_bss bss_meta = {
		.boottime_ns = rx_status->boottime_ns,
	};
@@ -212,6 +212,13 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
	bss = (void *)cbss->priv;
	ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon);

	list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) {
		non_tx_bss = (void *)non_tx_cbss->priv;

		ieee80211_update_bss_from_elems(local, non_tx_bss, &elems,
						rx_status, beacon);
	}

	return bss;
}

Loading