Linux wireless drivers development
 help / color / mirror / Atom feed
From: Ilan Peer <ilan.peer@intel.com>
To: johannes@sipsolutions.net
Cc: linux-wireless@vger.kernel.org, Ilan Peer <ilan.peer@intel.com>,
	Benjamin Berg <benjamin.berg@intel.com>,
	Miri Korenblit <miriam.rachel.korenblit@intel.com>
Subject: [PATCH v3 11/11] wifi: mac80211_hwsim: add NAN Instant Communication support
Date: Mon,  5 Oct 2026 11:44:58 +0300	[thread overview]
Message-ID: <20261005084458.3666739-12-ilan.peer@intel.com> (raw)
In-Reply-To: <20261005084458.3666739-1-ilan.peer@intel.com>

Advertise Instant Communication (IC) support, and when it is enabled:

- Transmit the discovery beacons disregarding the role and the state,
  with the configured beacon interval and the NAN attributes set by
  user space.
- Accept beacons that carry a Service ID List or a Subscribe Service
  ID List attribute at any time, so that they are forwarded to
  mac80211.
- Process discovery beacons received during non DW slots for anchor
  master tracking and synchronization.

Assisted-by: GitHubCopilot:claude-opus-5
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Reviewed-by: Benjamin Berg <benjamin.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../wireless/virtual/mac80211_hwsim_main.c    |   7 +-
 .../net/wireless/virtual/mac80211_hwsim_nan.c | 129 ++++++++++++++++--
 .../net/wireless/virtual/mac80211_hwsim_nan.h |   2 +
 3 files changed, 122 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index 762f99eb15e4..7e65474c9df1 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -1775,6 +1775,7 @@ struct tx_iter_data {
 	struct ieee80211_channel *channel;
 	struct ieee80211_rx_status *rx_status;
 	struct ieee80211_hw *hw;
+	struct sk_buff *skb;
 	bool receive;
 };
 
@@ -1787,6 +1788,7 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
 	if (vif->type == NL80211_IFTYPE_NAN ||
 	    vif->type == NL80211_IFTYPE_NAN_DATA) {
 		data->receive = mac80211_hwsim_nan_receive(data->hw,
+							   data->skb,
 							   data->channel,
 							   data->rx_status);
 		return;
@@ -1968,6 +1970,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
 			.hw = data2->hw,
 			.channel = chan,
 			.rx_status = &rx_status,
+			.skb = skb,
 		};
 
 		if (data == data2)
@@ -5841,7 +5844,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 						 BIT(NL80211_BAND_5GHZ);
 
 		hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC |
-					    WIPHY_NAN_FLAGS_USERSPACE_DE;
+					    WIPHY_NAN_FLAGS_USERSPACE_DE |
+					    WIPHY_NAN_FLAGS_INSTANT_COMM;
 		hw->wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK |
 					      NAN_OP_MODE_80P80MHZ |
 					      NAN_OP_MODE_160MHZ;
@@ -6643,6 +6647,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
 		struct tx_iter_data iter_data = {
 			.hw = data2->hw,
 			.rx_status = &rx_status,
+			.skb = skb,
 		};
 
 		/* throw away off-channel packets, but allow both the temporary
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_nan.c b/drivers/net/wireless/virtual/mac80211_hwsim_nan.c
index e7815eb95c55..6f90856099e8 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_nan.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_nan.c
@@ -219,6 +219,37 @@ mac80211_hwsim_nan_schedule_slot(struct mac80211_hwsim_data *data, u8 slot,
 			    mac80211_hwsim_tsf_to_boottime(data, tsf));
 }
 
+static bool hwsim_nan_beacon_has_service_ids(struct sk_buff *skb)
+{
+	const struct ieee80211_mgmt *mgmt = (void *)skb->data;
+	const struct ieee80211_nan_attr *nan_attr;
+	const struct element *elem;
+	size_t len;
+
+	if (skb->len < offsetofend(struct ieee80211_mgmt, u.beacon) ||
+	    !ieee80211_is_beacon(mgmt->frame_control))
+		return false;
+
+	len = skb->len - offsetofend(struct ieee80211_mgmt, u.beacon);
+
+	/* TODO: fragmented NAN elements are not supported */
+	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC,
+			    mgmt->u.beacon.variable, len) {
+		if (elem->datalen < 4 ||
+		    get_unaligned_be32(elem->data) !=
+		    (WLAN_OUI_WFA << 8 | WLAN_OUI_TYPE_WFA_NAN))
+			continue;
+
+		for_each_nan_attr(nan_attr, elem->data + 4, elem->datalen - 4)
+			if (nan_attr->attr == NAN_ATTR_SERVICE_ID_LIST ||
+			    nan_attr->attr ==
+			    NAN_ATTR_SUBSCRIBE_SERVICE_ID_LIST)
+				return true;
+	}
+
+	return false;
+}
+
 void mac80211_hwsim_nan_rx(struct ieee80211_hw *hw,
 			   struct sk_buff *skb)
 {
@@ -270,15 +301,32 @@ void mac80211_hwsim_nan_rx(struct ieee80211_hw *hw,
 	}
 
 	/*
-	 * (overly) simplify things, only track 2.4 GHz here. Also, ignore
-	 * frames outside of the 2.4 GHz DW slot, unless in the initial SCAN
-	 * phase.
+	 * Only sync on 2.4 GHz, which all NAN devices attend. The slot number
+	 * is derived from the local TSF, so before being synchronized a 5 GHz
+	 * beacon from a different device may fall into the local 2.4 GHz DW
+	 * slot. Filter by frequency to keep such beacons out of master
+	 * selection and synchronization.
 	 */
-	if ((slot != SLOT_24GHZ_DW &&
-	     data->nan.phase != MAC80211_HWSIM_NAN_PHASE_SCAN) ||
-	    rx_status.freq != 2437)
+	if (rx_status.freq != 2437)
 		return;
 
+	/*
+	 * Ignore frames outside of the 2.4 GHz DW slot, unless in the initial
+	 * SCAN phase or in Instant Communication, where discovery beacons are
+	 * received outside the DW.
+	 */
+	if (slot != SLOT_24GHZ_DW) {
+		bool rx_outside_dw;
+
+		scoped_guard(spinlock_bh, &data->nan.state_lock)
+			rx_outside_dw = data->nan.instant_comm ||
+				data->nan.phase ==
+				MAC80211_HWSIM_NAN_PHASE_SCAN;
+
+		if (!rx_outside_dw)
+			return;
+	}
+
 	/* Just ignore low RSSI beacons that we cannot sync to */
 	if (rx_status.signal < NAN_RSSI_MIDDLE)
 		return;
@@ -629,10 +677,12 @@ mac80211_hwsim_nan_exec_state_transitions(struct mac80211_hwsim_data *data)
 
 	/*
 	 * The discovery beacon timer will stop automatically. Make sure it is
-	 * running if we are master. Do not bother with a proper alignment it
-	 * will sync itself to the TSF after the first TX.
+	 * running if we are master or if Instant Communication is enabled. Do
+	 * not bother with a proper alignment it will sync itself to the TSF
+	 * after the first TX.
 	 */
-	if (data->nan.role == MAC80211_HWSIM_NAN_ROLE_MASTER &&
+	if ((data->nan.role == MAC80211_HWSIM_NAN_ROLE_MASTER ||
+	     data->nan.instant_comm) &&
 	    !hrtimer_active(&data->nan.discovery_beacon_timer))
 		hrtimer_start(&data->nan.discovery_beacon_timer,
 			      ns_to_ktime(10 * NSEC_PER_USEC),
@@ -887,7 +937,15 @@ mac80211_hwsim_nan_discovery_beacon_timer(struct hrtimer *timer)
 		return HRTIMER_NORESTART;
 
 	scoped_guard(spinlock, &data->nan.state_lock) {
-		if (data->nan.phase == MAC80211_HWSIM_NAN_PHASE_SCAN ||
+		if (data->nan.phase == MAC80211_HWSIM_NAN_PHASE_SCAN)
+			return HRTIMER_NORESTART;
+
+		/*
+		 * With Instant Communication the discovery beacons are
+		 * transmitted disregarding the role and the state, see
+		 * Wi-Fi Aware version 4.0 section 13.
+		 */
+		if (!data->nan.instant_comm &&
 		    data->nan.role != MAC80211_HWSIM_NAN_ROLE_MASTER)
 			return HRTIMER_NORESTART;
 	}
@@ -956,6 +1014,8 @@ static int mac80211_hwsim_nan_set_config(struct mac80211_hwsim_data *data,
 		data->nan.discovery_beacon_interval =
 			conf->discovery_beacon_interval ? : 100;
 
+		data->nan.instant_comm = conf->instant_comm;
+
 		old = data->nan.extra_nan_attrs;
 		data->nan.extra_nan_attrs = extra_nan_attrs;
 		data->nan.extra_nan_attrs_len = conf->extra_nan_attrs_len;
@@ -991,9 +1051,13 @@ int mac80211_hwsim_nan_start(struct ieee80211_hw *hw,
 				mac80211_hwsim_nan_sched_update_work);
 
 	scoped_guard(spinlock_bh, &data->nan.state_lock) {
-		/* Start in the "scan" phase and stay there for a little bit */
+		/*
+		 * Start in the "scan" phase and stay there for a little bit,
+		 * unless Instant Communication is configured, in which case an
+		 * own cluster is started immediately.
+		 */
 		data->nan.phase = MAC80211_HWSIM_NAN_PHASE_SCAN;
-		data->nan.random_factor_valid_dwst = 1;
+		data->nan.random_factor_valid_dwst = conf->instant_comm ? 0 : 1;
 		data->nan.random_factor = 0;
 		data->nan.master_pref = conf->master_pref;
 		data->nan.role = MAC80211_HWSIM_NAN_ROLE_MASTER;
@@ -1034,6 +1098,7 @@ int mac80211_hwsim_nan_stop(struct ieee80211_hw *hw,
 		old = data->nan.extra_nan_attrs;
 		data->nan.extra_nan_attrs = NULL;
 		data->nan.extra_nan_attrs_len = 0;
+		data->nan.instant_comm = false;
 	}
 
 	kfree(old);
@@ -1061,6 +1126,16 @@ int mac80211_hwsim_nan_change_config(struct ieee80211_hw *hw,
 
 		if (err)
 			return err;
+
+		/*
+		 * When Instant Communication is enabled discovery beacons are
+		 * transmitted regardless of the role and the state.
+		 */
+		if (conf->instant_comm &&
+		    !hrtimer_active(&data->nan.discovery_beacon_timer))
+			hrtimer_start(&data->nan.discovery_beacon_timer,
+				      ns_to_ktime(10 * NSEC_PER_USEC),
+				      HRTIMER_MODE_REL_SOFT);
 	}
 
 	/* Handle only the changes we care about for simulation purposes */
@@ -1249,9 +1324,16 @@ bool mac80211_hwsim_nan_txq_transmitting(struct ieee80211_hw *hw,
 	is_dw_slot = mac80211_hwsim_nan_is_dw_slot(data, slot);
 
 	if (!txq->sta) {
-		/* Non-STA TXQ: allow management frames during DW */
-		if (txq->vif->type == NL80211_IFTYPE_NAN)
-			return is_dw_slot;
+		/* Non-STA TXQ: allow management frames during DW or IC */
+		if (txq->vif->type == NL80211_IFTYPE_NAN) {
+			if (is_dw_slot)
+				return true;
+
+			/* Outside the DW the local schedule must allow it */
+			guard(spinlock_bh)(&data->nan.state_lock);
+			return data->nan.instant_comm &&
+				data->nan.local_sched[slot].chan;
+		}
 
 		/* Allow multicast data when all the peers are available
 		 * on this slot
@@ -1304,15 +1386,32 @@ void mac80211_hwsim_nan_get_tx_chandef(struct ieee80211_hw *hw,
 }
 
 bool mac80211_hwsim_nan_receive(struct ieee80211_hw *hw,
+				struct sk_buff *skb,
 				struct ieee80211_channel *channel,
 				struct ieee80211_rx_status *rx_status)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
+	bool instant_comm;
 	u8 slot;
 
 	if (WARN_ON_ONCE(!data->nan.device_vif))
 		return false;
 
+	scoped_guard(spinlock_bh, &data->nan.state_lock)
+		instant_comm = data->nan.instant_comm;
+
+	/*
+	 * During Instant Communication a peer advertises its services in the
+	 * discovery beacons, which are transmitted disregarding the roles and
+	 * the states, see Section 13 in Wi-Fi Aware v4.0.
+	 * Note that while according to the specification Instant communication
+	 * should be enabled only on the NAN discovery channels, do not force
+	 * this here, and allow receiving NAN frames on any channel if Instant
+	 * Communication is enabled.
+	 */
+	if (instant_comm && hwsim_nan_beacon_has_service_ids(skb))
+		return true;
+
 	if (data->nan.phase == MAC80211_HWSIM_NAN_PHASE_SCAN)
 		return channel->center_freq == 2437;
 
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_nan.h b/drivers/net/wireless/virtual/mac80211_hwsim_nan.h
index e73634e479e8..0684f9b823ba 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_nan.h
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_nan.h
@@ -56,6 +56,7 @@ struct mac80211_hwsim_nan_data {
 	bool tsf_adjusted;
 	bool tsf_discontinuity;
 
+	bool instant_comm;
 	u8 discovery_beacon_interval;
 
 	/*
@@ -98,6 +99,7 @@ void mac80211_hwsim_nan_get_tx_chandef(struct ieee80211_hw *hw,
 				       struct cfg80211_chan_def *chandef);
 
 bool mac80211_hwsim_nan_receive(struct ieee80211_hw *hw,
+				struct sk_buff *skb,
 				struct ieee80211_channel *channel,
 				struct ieee80211_rx_status *rx_status);
 
-- 
2.55.0


      parent reply	other threads:[~2026-10-04 14:30 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-05  8:44 [PATCH v3 00/11] wifi: cfg80211/mac80211: add NAN Instant Communication support Ilan Peer
2026-10-05  8:44 ` [PATCH v3 01/11] wifi: cfg80211: nan: add " Ilan Peer
2026-10-05  8:44 ` [PATCH v3 02/11] wifi: mac80211: nan: Update NAN configuration copy Ilan Peer
2026-10-05  8:44 ` [PATCH v3 03/11] wifi: cfg80211: nan: check Rx registration for NAN beacons Ilan Peer
2026-10-05  8:44 ` [PATCH v3 04/11] wifi: cfg80211: do not use NAN beacons to update the BSS table Ilan Peer
2026-10-05  8:44 ` [PATCH v3 05/11] wifi: mac80211: nan: allow Rx registration for NAN beacons Ilan Peer
2026-10-05  8:44 ` [PATCH v3 06/11] wifi: mac80211: accept NAN beacons only when IC is enabled Ilan Peer
2026-10-05  8:44 ` [PATCH v3 07/11] wifi: ieee80211: add NAN service ID list attribute definitions Ilan Peer
2026-10-05  8:44 ` [PATCH v3 08/11] wifi: mac80211_hwsim: nan: use ieee80211_is_nan_beacon() helper Ilan Peer
2026-10-05  8:44 ` [PATCH v3 09/11] wifi: mac80211_hwsim: nan: prepare for more configurable NAN settings Ilan Peer
2026-10-05  8:44 ` [PATCH v3 10/11] wifi: mac80211_hwsim: nan: Handle more of the NAN configuration Ilan Peer
2026-10-05  8:44 ` Ilan Peer [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261005084458.3666739-12-ilan.peer@intel.com \
    --to=ilan.peer@intel.com \
    --cc=benjamin.berg@intel.com \
    --cc=johannes@sipsolutions.net \
    --cc=linux-wireless@vger.kernel.org \
    --cc=miriam.rachel.korenblit@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox