* [PATCH wireless-next 1/7] wifi: cfg80211: nan: add Instant Communication support
2026-10-01 13:33 [PATCH wireless-next 0/7] wifi: cfg80211/mac80211: add NAN Instant Communication support Miri Korenblit
@ 2026-10-01 13:33 ` Miri Korenblit
2026-10-01 13:33 ` [PATCH wireless-next 2/7] wifi: mac80211: nan: Update NAN configuration copy Miri Korenblit
` (5 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Miri Korenblit @ 2026-10-01 13:33 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Ilan Peer
From: Ilan Peer <ilan.peer@intel.com>
Add NL80211_NAN_CONF_INSTANT_COMM flag to let user space request that
the NAN synchronization logic starts Instant Communication (IC) as
defined in Chapter 13 of the Wi-Fi Aware Specification v4.0.
Add NL80211_NAN_CAPA_INSTANT_COMM for drivers to advertise it. The
capability requires configurable synchronization support, and IC
requests are rejected if it isn't advertised.
When IC is enabled, user space must also configure the discovery
beacon interval. The IC schedule is expected to be configured
by user space.
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
include/net/cfg80211.h | 9 ++++++++-
include/uapi/linux/nl80211.h | 12 ++++++++++++
net/wireless/core.c | 5 +++++
net/wireless/nl80211.c | 22 ++++++++++++++++++++++
4 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b603f1804cc2..96b5bf8b8ff3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4191,9 +4191,12 @@ struct cfg80211_nan_band_config {
* that can take a value from 50-6F-9A-01-00-00 to 50-6F-9A-01-FF-FF.
* @scan_period: period (in seconds) between NAN scans.
* @scan_dwell_time: dwell time (in milliseconds) for NAN scans.
- * @discovery_beacon_interval: interval (in TUs) for discovery beacons.
+ * @discovery_beacon_interval: interval (in TUs) for discovery beacons. Must be
+ * greater than 0 when @instant_comm is true.
* @enable_dw_notification: flag to enable/disable discovery window
* notifications.
+ * @instant_comm: if true, start Instant Communication (IC) as defined in
+ * Chapter 13 of the Wi-Fi Aware Specification v4.0.
* @band_cfgs: array of band specific configurations, indexed by
* &enum nl80211_band values.
* @extra_nan_attrs: pointer to additional NAN attributes.
@@ -4209,6 +4212,7 @@ struct cfg80211_nan_conf {
u16 scan_dwell_time;
u8 discovery_beacon_interval;
bool enable_dw_notification;
+ bool instant_comm;
struct cfg80211_nan_band_config band_cfgs[NUM_NL80211_BANDS];
const u8 *extra_nan_attrs;
u16 extra_nan_attrs_len;
@@ -6305,10 +6309,13 @@ struct wiphy_radio {
* @WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC: Device supports NAN configurable
* synchronization.
* @WIPHY_NAN_FLAGS_USERSPACE_DE: Device doesn't support DE offload.
+ * @WIPHY_NAN_FLAGS_INSTANT_COMM: Device can switch to Instant Communication
+ * (IC) mode. Can only be set along with %WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC.
*/
enum wiphy_nan_flags {
WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC = BIT(0),
WIPHY_NAN_FLAGS_USERSPACE_DE = BIT(1),
+ WIPHY_NAN_FLAGS_INSTANT_COMM = BIT(2),
};
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 75d4c5d6a7a3..21d98c1ec424 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -7890,6 +7890,11 @@ enum nl80211_nan_band_conf_attributes {
* the upcoming discovery window with
* %NL80211_CMD_NAN_NEXT_DW_NOTIFICATION.
* This is a flag attribute.
+ * @NL80211_NAN_CONF_INSTANT_COMM: If set, the NAN synchronization logic will
+ * start Instant Communication (IC) as defined in Chapter 13 of the
+ * Wi-Fi Aware Specification v4.0.
+ * %NL80211_NAN_CONF_DISCOVERY_BEACON_INTERVAL must be set as well.
+ * This is a flag attribute.
* @NUM_NL80211_NAN_CONF_ATTR: Internal.
* @NL80211_NAN_CONF_ATTR_MAX: Highest NAN configuration attribute.
*
@@ -7905,6 +7910,7 @@ enum nl80211_nan_conf_attributes {
NL80211_NAN_CONF_SCAN_DWELL_TIME,
NL80211_NAN_CONF_DISCOVERY_BEACON_INTERVAL,
NL80211_NAN_CONF_NOTIFY_DW,
+ NL80211_NAN_CONF_INSTANT_COMM,
/* keep last */
NUM_NL80211_NAN_CONF_ATTR,
@@ -9121,6 +9127,11 @@ enum nl80211_s1g_short_beacon_attrs {
* specification Table 79 (Capabilities field).
* @NL80211_NAN_CAPA_PHY: nested attribute containing band-agnostic
* capabilities for NAN data path. See &enum nl80211_nan_phy_cap_attr.
+ * @NL80211_NAN_CAPA_INSTANT_COMM: Flag attribute indicating that the device
+ * can switch to Instant Communication (IC) mode, as defined in Chapter 13
+ * of the Wi-Fi Aware Specification v4.0. Can only be set if
+ * %NL80211_NAN_CAPA_CONFIGURABLE_SYNC is set. When IC is enabled, the IC
+ * schedule is expected to be configured by user space.
* @__NL80211_NAN_CAPABILITIES_LAST: Internal
* @NL80211_NAN_CAPABILITIES_MAX: Highest NAN capability attribute.
*/
@@ -9134,6 +9145,7 @@ enum nl80211_nan_capabilities {
NL80211_NAN_CAPA_MAX_CHANNEL_SWITCH_TIME,
NL80211_NAN_CAPA_CAPABILITIES,
NL80211_NAN_CAPA_PHY,
+ NL80211_NAN_CAPA_INSTANT_COMM,
/* keep last */
__NL80211_NAN_CAPABILITIES_LAST,
NL80211_NAN_CAPABILITIES_MAX = __NL80211_NAN_CAPABILITIES_LAST - 1,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index dc1e0522340a..9176659345f0 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -964,6 +964,11 @@ int wiphy_register(struct wiphy *wiphy)
(!wiphy->nan_capa.phy.ht.ht_supported || wiphy->n_radio > 1)))
return -EINVAL;
+ if (WARN_ON((wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_INSTANT_COMM) &&
+ !(wiphy->nan_capa.flags &
+ WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC)))
+ return -EINVAL;
+
if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)))
return -EINVAL;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 16c63383923b..fa4379955dea 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -687,6 +687,7 @@ nl80211_nan_conf_policy[NL80211_NAN_CONF_ATTR_MAX + 1] = {
[NL80211_NAN_CONF_DISCOVERY_BEACON_INTERVAL] =
NLA_POLICY_RANGE(NLA_U8, 50, 200),
[NL80211_NAN_CONF_NOTIFY_DW] = { .type = NLA_FLAG },
+ [NL80211_NAN_CONF_INSTANT_COMM] = { .type = NLA_FLAG },
};
static const struct netlink_range_validation nl80211_punct_bitmap_range = {
@@ -3036,6 +3037,10 @@ static int nl80211_put_nan_capa(struct wiphy *wiphy, struct sk_buff *msg)
nla_put_flag(msg, NL80211_NAN_CAPA_USERSPACE_DE))
goto fail;
+ if ((wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_INSTANT_COMM) &&
+ nla_put_flag(msg, NL80211_NAN_CAPA_INSTANT_COMM))
+ goto fail;
+
if (nla_put_u8(msg, NL80211_NAN_CAPA_OP_MODE,
wiphy->nan_capa.op_mode) ||
nla_put_u8(msg, NL80211_NAN_CAPA_NUM_ANTENNAS,
@@ -16780,6 +16785,23 @@ static int nl80211_parse_nan_conf(struct wiphy *wiphy,
conf->enable_dw_notification =
nla_get_flag(attrs[NL80211_NAN_CONF_NOTIFY_DW]);
+ conf->instant_comm = nla_get_flag(attrs[NL80211_NAN_CONF_INSTANT_COMM]);
+ if (conf->instant_comm) {
+ if (!(wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_INSTANT_COMM)) {
+ NL_SET_ERR_MSG_ATTR(info->extack,
+ attrs[NL80211_NAN_CONF_INSTANT_COMM],
+ "Instant Communication is not supported");
+ return -EOPNOTSUPP;
+ }
+
+ if (!conf->discovery_beacon_interval) {
+ NL_SET_ERR_MSG_ATTR(info->extack,
+ attrs[NL80211_NAN_CONF_INSTANT_COMM],
+ "Instant Communication requires a discovery beacon interval");
+ return -EINVAL;
+ }
+ }
+
out:
if (!conf->band_cfgs[NL80211_BAND_5GHZ].chan &&
(!conf->bands || conf->bands & BIT(NL80211_BAND_5GHZ))) {
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH wireless-next 4/7] wifi: mac80211: nan: allow Rx registration for NAN beacons
2026-10-01 13:33 [PATCH wireless-next 0/7] wifi: cfg80211/mac80211: add NAN Instant Communication support Miri Korenblit
` (2 preceding siblings ...)
2026-10-01 13:33 ` [PATCH wireless-next 3/7] wifi: cfg80211: nan: check Rx registration for NAN beacons Miri Korenblit
@ 2026-10-01 13:33 ` Miri Korenblit
2026-10-02 7:10 ` Johannes Berg
2026-10-01 13:33 ` [PATCH wireless-next 5/7] wifi: ieee80211: add NAN service ID list attribute definitions Miri Korenblit
` (2 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Miri Korenblit @ 2026-10-01 13:33 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Ilan Peer
From: Ilan Peer <ilan.peer@intel.com>
Instant Communication requires user space to track the NAN beacons, so
let it register for Rx of beacons on a NAN interface. Add support for
passing beacon on NAN Device interface when instant communication is
enabled.
Add a helper function to identify NAN beacons, based on the BSSID
and the beacon frame content. Skip NAN beacons so they would not
be used to update the BSS table.
Assisted-by: GitHubCopilot:claude-opus-5
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
include/linux/ieee80211-nan.h | 26 ++++++++++++++++++++++++++
net/mac80211/main.c | 7 ++++++-
net/mac80211/rx.c | 11 ++++++++++-
net/mac80211/scan.c | 4 ++++
4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/include/linux/ieee80211-nan.h b/include/linux/ieee80211-nan.h
index 455033955e54..b332a94671ba 100644
--- a/include/linux/ieee80211-nan.h
+++ b/include/linux/ieee80211-nan.h
@@ -74,4 +74,30 @@ struct ieee80211_nan_anchor_master_info {
_attr = (const struct ieee80211_nan_attr *) \
(_attr->data + le16_to_cpu(_attr->length)))
+static inline bool ieee80211_is_nan_beacon(const struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ const struct element *elem;
+
+ /* The NAN IE is at least 6 octets */
+ if (len < offsetofend(struct ieee80211_mgmt, u.beacon) + 6)
+ return false;
+
+ if (!ieee80211_is_beacon(mgmt->frame_control))
+ return false;
+
+ /* NAN Cluster IDs range from 50-6F-9A-01-00-00 to 50-6F-9A-01-FF-FF */
+ if (get_unaligned_be32(mgmt->bssid) != ((WLAN_OUI_WFA << 8) | 0x01))
+ return false;
+
+ elem = (const struct element *)mgmt->u.beacon.variable;
+ if (elem->id != WLAN_EID_VENDOR_SPECIFIC ||
+ elem->datalen < 4 ||
+ get_unaligned_be32(elem->data) !=
+ (WLAN_OUI_WFA << 8 | WLAN_OUI_TYPE_WFA_NAN))
+ return false;
+
+ return true;
+}
+
#endif /* LINUX_IEEE80211_NAN_H */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 7816395681fa..b889d2a7ef75 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -745,8 +745,13 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
[NL80211_IFTYPE_NAN] = {
.tx = 0xffff,
+ /*
+ * Beacon Rx registration is needed to let user space handle
+ * service discovery when Instant Communication is enabled.
+ */
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_AUTH >> 4),
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_BEACON >> 4),
},
[NL80211_IFTYPE_NAN_DATA] = {
.tx = 0xffff,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index b3990b7a7299..8dde57a9112f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4536,7 +4536,10 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
+ bool nan_beacon = ieee80211_is_nan_beacon((struct ieee80211_mgmt *)hdr,
+ skb->len);
bool multicast;
+
static const u8 nan_network_id[ETH_ALEN] __aligned(2) = {
0x51, 0x6F, 0x9A, 0x01, 0x00, 0x00
};
@@ -4545,6 +4548,9 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return sdata->vif.type == NL80211_IFTYPE_STATION && bssid;
multicast = is_multicast_ether_addr(hdr->addr1);
+ /* Only a NAN interface may handle NAN beacons */
+ if (nan_beacon && sdata->vif.type != NL80211_IFTYPE_NAN)
+ return false;
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@@ -4681,7 +4687,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
* Accept only frames that are addressed to the NAN cluster
* (based on the Cluster ID). From these frames, accept only
* - public action frames,
- * - authentication frames to the local address, and
+ * - authentication frames to the local address,
+ * - NAN beacons, when Instant Communication is enabled, and
* - robust management frames except disassoc.
*/
if (!ether_addr_equal(sdata->u.nan.conf.cluster_id, hdr->addr3))
@@ -4691,6 +4698,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
if (ieee80211_is_auth(hdr->frame_control) &&
ether_addr_equal(sdata->vif.addr, hdr->addr1))
return true;
+ if (nan_beacon)
+ return sdata->u.nan.conf.instant_comm;
if (!ieee80211_is_disassoc(hdr->frame_control) &&
ieee80211_is_robust_mgmt_frame(skb))
return true;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index a4bca412e577..fc8d090bfd7c 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -353,6 +353,10 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
if (!ieee80211_is_s1g_beacon(mgmt->frame_control) &&
!is_broadcast_ether_addr(mgmt->da))
return;
+
+ /* NAN beacons are not a BSS, don't add to the BSS table */
+ if (ieee80211_is_nan_beacon(mgmt, skb->len))
+ return;
}
/* Do not update the BSS table in case of only monitor interfaces */
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH wireless-next 7/7] wifi: mac80211_hwsim: add NAN Instant Communication support
2026-10-01 13:33 [PATCH wireless-next 0/7] wifi: cfg80211/mac80211: add NAN Instant Communication support Miri Korenblit
` (5 preceding siblings ...)
2026-10-01 13:33 ` [PATCH wireless-next 6/7] wifi: mac80211_hwsim: nan: use ieee80211_is_nan_beacon() helper Miri Korenblit
@ 2026-10-01 13:33 ` Miri Korenblit
2026-10-02 7:26 ` Johannes Berg
6 siblings, 1 reply; 13+ messages in thread
From: Miri Korenblit @ 2026-10-01 13:33 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Ilan Peer, Benjamin Berg
From: Ilan Peer <ilan.peer@intel.com>
Advertise Instant Communication 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.
In addition, 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.
When in instant communication, discovery beacons received during
non DW slots are processed 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 | 231 +++++++++++++++---
.../net/wireless/virtual/mac80211_hwsim_nan.h | 8 +
3 files changed, 217 insertions(+), 29 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 fab6bd9e3cfb..79c41a66a07e 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_nan.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_nan.c
@@ -33,6 +33,12 @@ static_assert(DW0_TSF_MASK + 1 == 8192 * 1024);
#define NAN_RSSI_CLOSE (-60)
#define NAN_RSSI_MIDDLE (-75)
+/* Size of the NAN vendor element carrying the mandatory attributes */
+#define NAN_BEACON_ELEM_LEN 27
+
+/* Space left in the NAN vendor element for the configured attributes */
+#define NAN_BEACON_EXTRA_ATTRS_LEN (255 - (NAN_BEACON_ELEM_LEN - 2))
+
/* Quiet time at the end of each slot where TX is suppressed */
#define NAN_CHAN_SWITCH_TIME_US 256
@@ -213,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)
{
@@ -263,15 +300,26 @@ void mac80211_hwsim_nan_rx(struct ieee80211_hw *hw,
slot = hwsim_nan_slot_from_tsf(rx_status.mactime);
}
+ /* (overly) simplify things, only track 2.4 GHz here */
+ if (rx_status.freq != 2437)
+ return;
+
/*
- * (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.
+ * 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 &&
- data->nan.phase != MAC80211_HWSIM_NAN_PHASE_SCAN) ||
- rx_status.freq != 2437)
- return;
+ 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)
@@ -623,10 +671,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),
@@ -685,7 +735,7 @@ mac80211_hwsim_nan_tx_beacon(struct mac80211_hwsim_data *data,
{
struct ieee80211_vendor_ie nan_ie = {
.element_id = WLAN_EID_VENDOR_SPECIFIC,
- .len = 27 - 2,
+ .len = NAN_BEACON_ELEM_LEN - 2,
.oui = { u32_get_bits(WLAN_OUI_WFA, 0xff0000),
u32_get_bits(WLAN_OUI_WFA, 0xff00),
u32_get_bits(WLAN_OUI_WFA, 0xff) },
@@ -694,23 +744,39 @@ mac80211_hwsim_nan_tx_beacon(struct mac80211_hwsim_data *data,
size_t alloc_size =
IEEE80211_TX_STATUS_HEADROOM +
offsetofend(struct ieee80211_mgmt, u.beacon) +
- 27 /* size of NAN vendor element */;
+ NAN_BEACON_ELEM_LEN;
struct ieee80211_nan_master_indication master_indication;
struct ieee80211_nan_attr nan_attr;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
+ u16 beacon_int;
/*
- * TODO: Should the configured vendor elements or NAN attributes be
- * included in some of these beacons?
+ * TODO: Should the configured vendor elements be included in some of
+ * these beacons?
*/
+ /* Allocate maximal size for NAN IE */
+ if (is_discovery)
+ alloc_size += NAN_BEACON_EXTRA_ATTRS_LEN;
+
skb = alloc_skb(alloc_size, GFP_ATOMIC);
if (!skb)
return;
spin_lock(&data->nan.state_lock);
+ /*
+ * The attributes configured by user space, e.g. the Service ID List
+ * and Subscribe Service ID List attributes (needed for Instant
+ * Communication), are appended to the mandatory ones.
+ */
+ if (is_discovery)
+ nan_ie.len += data->nan.extra_nan_attrs_len;
+
+ beacon_int = is_discovery ? data->nan.discovery_beacon_interval :
+ DWST_TU;
+
skb_reserve(skb, IEEE80211_TX_STATUS_HEADROOM);
mgmt = skb_put(skb, offsetofend(struct ieee80211_mgmt, u.beacon));
@@ -721,7 +787,7 @@ mac80211_hwsim_nan_tx_beacon(struct mac80211_hwsim_data *data,
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_BEACON);
- mgmt->u.beacon.beacon_int = cpu_to_le16(is_discovery ? 100 : DWST_TU);
+ mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int);
mgmt->u.beacon.capab_info =
cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME |
WLAN_CAPABILITY_SHORT_PREAMBLE);
@@ -752,6 +818,10 @@ mac80211_hwsim_nan_tx_beacon(struct mac80211_hwsim_data *data,
skb_put_data(skb, &data->nan.current_ami,
sizeof(data->nan.current_ami));
+ if (is_discovery && data->nan.extra_nan_attrs_len)
+ skb_put_data(skb, data->nan.extra_nan_attrs,
+ data->nan.extra_nan_attrs_len);
+
spin_unlock(&data->nan.state_lock);
mac80211_hwsim_tx_frame(data->hw, skb, channel);
@@ -856,6 +926,7 @@ mac80211_hwsim_nan_discovery_beacon_timer(struct hrtimer *timer)
struct mac80211_hwsim_data *data =
container_of(timer, struct mac80211_hwsim_data,
nan.discovery_beacon_timer);
+ u16 beacon_int;
u32 remainder;
u64 tsf_now;
u64 tbtt;
@@ -864,11 +935,21 @@ 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;
}
+ beacon_int = data->nan.discovery_beacon_interval;
+
mac80211_hwsim_nan_tx_beacon(
data, true, ieee80211_get_channel(data->hw->wiphy, 2437));
@@ -881,10 +962,10 @@ mac80211_hwsim_nan_discovery_beacon_timer(struct hrtimer *timer)
tsf_now = mac80211_hwsim_get_tsf(data->hw, data->nan.device_vif);
/* Wrap value to be after the next TBTT */
- tbtt = tsf_now + ieee80211_tu_to_usec(100);
+ tbtt = tsf_now + ieee80211_tu_to_usec(beacon_int);
/* Round TBTT down to the correct time */
- div_u64_rem(tbtt, ieee80211_tu_to_usec(100), &remainder);
+ div_u64_rem(tbtt, ieee80211_tu_to_usec(beacon_int), &remainder);
tbtt = tbtt - remainder;
hrtimer_set_expires(&data->nan.discovery_beacon_timer,
@@ -905,11 +986,51 @@ mac80211_hwsim_nan_sched_update_work(struct wiphy *wiphy,
ieee80211_nan_sched_update_done(data->nan.device_vif);
}
+static int mac80211_hwsim_nan_set_config(struct mac80211_hwsim_data *data,
+ struct cfg80211_nan_conf *conf)
+{
+ const u8 *extra_nan_attrs = NULL;
+ const u8 *old;
+
+ if (conf->extra_nan_attrs_len > NAN_BEACON_EXTRA_ATTRS_LEN)
+ return -EINVAL;
+
+ if (conf->extra_nan_attrs_len) {
+ extra_nan_attrs = kmemdup(conf->extra_nan_attrs,
+ conf->extra_nan_attrs_len,
+ GFP_KERNEL);
+ if (!extra_nan_attrs)
+ return -ENOMEM;
+ }
+
+ data->nan.notify_dw = conf->enable_dw_notification;
+
+ scoped_guard(spinlock_bh, &data->nan.state_lock) {
+ /*
+ * Fall back to the device default if user space did not
+ * configure it
+ */
+ 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;
+ }
+
+ kfree(old);
+
+ return 0;
+}
+
int mac80211_hwsim_nan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_nan_conf *conf)
{
struct mac80211_hwsim_data *data = hw->priv;
+ int err;
if (vif->type != NL80211_IFTYPE_NAN)
return -EINVAL;
@@ -917,6 +1038,10 @@ int mac80211_hwsim_nan_start(struct ieee80211_hw *hw,
if (data->nan.device_vif)
return -EALREADY;
+ err = mac80211_hwsim_nan_set_config(data, conf);
+ if (err)
+ return err;
+
/* set this before starting the timer, as preemption might occur */
data->nan.device_vif = vif;
data->nan.bands = conf->bands;
@@ -925,9 +1050,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;
@@ -945,8 +1074,6 @@ int mac80211_hwsim_nan_start(struct ieee80211_hw *hw,
ether_addr_copy(data->nan.cluster_id, conf->cluster_id);
- data->nan.notify_dw = conf->enable_dw_notification;
-
return 0;
}
@@ -954,6 +1081,7 @@ int mac80211_hwsim_nan_stop(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *data = hw->priv;
+ const u8 *old;
if (vif->type != NL80211_IFTYPE_NAN || !data->nan.device_vif ||
data->nan.device_vif != vif)
@@ -965,6 +1093,15 @@ int mac80211_hwsim_nan_stop(struct ieee80211_hw *hw,
wiphy_delayed_work_cancel(hw->wiphy, &data->nan.sched_update_work);
data->nan.device_vif = NULL;
+ scoped_guard(spinlock_bh, &data->nan.state_lock) {
+ 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);
+
return 0;
}
@@ -983,13 +1120,27 @@ int mac80211_hwsim_nan_change_config(struct ieee80211_hw *hw,
wiphy_debug(hw->wiphy, "nan_config_changed: changes=0x%x\n", changes);
+ if (changes & CFG80211_NAN_CONF_CHANGED_CONFIG) {
+ int err = mac80211_hwsim_nan_set_config(data, conf);
+
+ 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 */
if (changes & CFG80211_NAN_CONF_CHANGED_BANDS)
data->nan.bands = conf->bands;
- if (changes & CFG80211_NAN_CONF_CHANGED_CONFIG)
- data->nan.notify_dw = conf->enable_dw_notification;
-
if (changes & CFG80211_NAN_CONF_CHANGED_PREF) {
scoped_guard(spinlock_bh, &data->nan.state_lock)
data->nan.master_pref = conf->master_pref;
@@ -1172,9 +1323,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
@@ -1227,15 +1385,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 2801a1d8dcf0..7d1a05868eaa 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_nan.h
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_nan.h
@@ -32,6 +32,9 @@ struct mac80211_hwsim_nan_data {
/* Later members are protected by this lock */
spinlock_t state_lock;
+ const u8 *extra_nan_attrs;
+ u16 extra_nan_attrs_len;
+
u8 master_pref;
u8 random_factor;
@@ -53,6 +56,10 @@ struct mac80211_hwsim_nan_data {
bool tsf_adjusted;
bool tsf_discontinuity;
+ /* Wi-Fi Aware version 4.0, Section 13 */
+ bool instant_comm;
+ u8 discovery_beacon_interval;
+
/*
* Local schedule - stores channel definition for each 16TU slot.
* Derived from NMI vif->cfg.nan_schedule. chan == NULL means not
@@ -93,6 +100,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.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread