* [PATCH wireless-next 00/18] wifi: Add Seamless Mobility Domain (SMD) AP support
@ 2026-09-07 20:29 Pooventhiran G
2026-09-07 20:29 ` [PATCH wireless-next 01/18] net: skbuff: Add SKB extension support to wireless drivers Pooventhiran G
` (17 more replies)
0 siblings, 18 replies; 19+ messages in thread
From: Pooventhiran G @ 2026-09-07 20:29 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Johannes Berg
Cc: linux-kernel, netdev, linux-wireless, Pooventhiran G
IEEE P802.11bn (Ultra High Reliability) introduces the Seamless Mobility
Domain (SMD), a mechanism by which a non-AP MLD can transfer its session
from one AP MLD to another within the same administrative domain without
losing its RSNA or experiencing a visible connection break. The key
properties of an SMD are:
- A shared domain identifier (SMD-ID, encoded as a 6-byte MAC address)
advertised in the beacon of participating AP MLDs.
- A Seamless Transition (ST) protocol in two phases: ST Preparation
(cryptographic handshake and resource reservation on the target AP)
and ST Execution (atomic handoff with optional DL draining).
- Session-context transfer: the current AP MLD collects the STA's
DL/UL sequence numbers, block-ack parameters, PN values, and QoS
descriptors and conveys them to the target AP MLD so the STA can
resume without re-association.
1. ST Discovery (37.16.2)
--------------------------
For a non-AP MLD: ST discovery of an SMD capable AP is via OTA signalling
in beacon/probe responses.
For AP MLDs: Discovery of partner AP MLDs within the same SMD is via
Inter-AP (IAP) communication (solicited and unsolicited) over the
backhaul.
IAP is housed entirely within hostapd and the communication happens
between hostapd of AP MLDs.
The spec defines only the type of data that may be exchanged via IAP but does
not define the format and method of the IAP communication protocol and
keeps it out of scope (subclause 37.16.9). So, those details are not
included part of this series.
SMD capabilities are indicated to the mac80211/driver via NL80211_CMD_START_AP.
2. Association to the SMD-ME (37.16.3)
---------------------------------------
Before roaming, the client must perform a single association and
authentication with the SMD-ME through any AP MLD in the SMD. This establishes
the PMKSA and PTKSA at the SMD level that will persist across all roams.
SMD capabilities of a non-AP MLD is indicated to the mac80211/driver via
NL80211_CMD_NEW_STATION.
3. PTK Derivation (37.16.4)
----------------------------
Key derivation have seen some standard update and its to be taken care in
hostapd/wpa_supplicant, updated PTKs are plumbed to the mac and driver using
existing legacy netlink commands. PTK derivation uses SMD MAC address
(SMD identifier) and also derives SMD KDK which is used in lieu of PMK for
multi-PTK roaming. This is accommodated within hostapd using legacy netlink
commands.
4. ST Preparation (37.16.6)
----------------------------
This is the key step that enables seamlessness. Before the actual roam, the
client pre-provisions the target AP MLD:
- The non-AP MLD sends an ST preparation request (a UHR Link Reconfiguration
Request) to its current AP MLD, identifying the target AP MLD and the links to
be set up.
- The driver in the current AP MLD, when forwarding this special frame
to mac80211, collects the station session context and appends it to the
frame skb using skb-extns so that mac80211 can deliver it via a new
NL80211_ATTR_SMD_CTX attribute in the existing NL80211_CMD_FRAME.
- This method saves the round-trip from driver -> hostapd -> driver to fetch
the context.
As the context is to be sent with the frame skb (as context is per-frame) and
may be big, SKB extensions help carry the related context within the same
frame skb.
- The context collection happens in the vendor driver and the same is passed on
to mac80211 for forwarding to hostapd.
- The current AP MLD transfers the collected session context (block-ack
agreements, sequence numbers, replay counters, SCS streams, MSCS, EPCS state,
starting PN values) to the target AP MLD over the backhaul IAP.
- If Per-AP MLD PTK mode is used, a DH key exchange occurs in the preparation
frames to derive the new PTK at the Target-AP.
- The target AP MLD sets up the links (NONE -> AUTH -> ASSOC + SET_KEY), and
enters the prepared state (4a), and sets the context via NL80211_CMD_SET_CTX.
- The target AP MLD builds the ST prep response with the target AP MLD's full
capability profile (Basic Multi-Link element with per-STA profiles for each
accepted link) and sends it over the IAP to the current-AP MLD.
- The current AP MLD responds to the station with the OTA ST prep response
and a preparation timeout is started at both the current and target AP MLDs
(duration for which the prepared state is valid).
- The client can prepare multiple target AP MLDs simultaneously (up to the Max
Number Of Prepared Target AP MLDs advertised by the current AP MLD).
6. ST Execution (37.16.7 and 37.16.8)
---------------------------------------
When the client is ready to roam, it triggers the actual switch via one of two
paths:
Via the current AP MLD (37.16.7):
- The non-AP MLD sends an ST execution request to its current AP MLD. The
current AP MLD moves the station to the execution in-progress state (4b)
and transfers the current context, notifies the target AP MLD, and sends
back an ST execution response with SUCCESS to station.
- Context collection mechanism for Execution is same as Preparation.
- The response includes a Nominal Maximum DL Draining Period — a grace period
during which the current AP MLD may continue forwarding buffered downlink data
to the non-AP MLD before the old link goes away. During draining, the current
AP MLD moves the station to the draining state (4c).
Via the target AP MLD directly (37.16.8):
- Used as a fallback when the link to the current AP MLD has deteriorated
(e.g., after ST preparation, the RSSI to the current AP drops).
- The non-AP MLD sends the ST execution request directly to the target AP MLD;
the target AP MLD fetches remaining context from the current AP MLD over the
IAP.
- The current AP MLD uses NL80211_CMD_GET_SMD_CTX to pull the STA session
context on behalf of the target AP MLD and forwards it to the target AP MLD
over IAP.
The Target AP in both cases plumbs the stations context to the mac80211 and
subsequently to the driver via NL80211_CMD_SET_CTX.
Upon successful execution:
- The non-AP MLD enters State 4 with the target AP MLD (fully
associated/connected) and State 1 (unauthenticated and unassociated) with the
former current AP MLD post draining.
- No reassociation is required; the client retains the same PTKSA and IP
address.
- TTLM (TID-to-link mapping) reverts to default mapping mode initially.
7. Context Transfer (37.16.9)
------------------------------
The following per-client state is transferred from the current AP MLD to the
target AP MLD during ST (preparation and execution):
- Block-ack parameters and timeout per TID
- Next DL sequence numbers per TID
- Duplicate receiver cache entries
- Replay counters
- Starting PN for DL individually addressed frames
- SCS stream descriptors
- MSCS Descriptor
- EPCS authorization info and priority access state
- WinStartO for existing DL block-ack agreements
The client may optionally request that sequence numbers not be transferred (to
reset SN to 0 at the target).
8. Downlink Draining Period (37.16.10)
---------------------------------------
After ST execution, the current AP MLD may continue transmitting buffered DL
data to the non-AP MLD for a controlled grace period:
- The period duration is signaled in the ST execution response.
- Both the current AP MLD and the non-AP MLD can signal early termination of
the draining period via a UHR Link Reconfiguration Notify frame.
- During draining, the non-AP MLD is not required to listen to Beacons of the
target AP.
This series adds the kernel infrastructure needed to support SMD in AP
mode. It is structured as below logical groups:
- SKB Extension definition: patch 1
- AP configuration: patches 2-4
- STA association: patch 5 and 6
- SMD BSS Transition state machine: patches 7 and 8
- SMD Context Programming: patches 9-18
RFC:
https://lore.kernel.org/linux-wireless/fbf4209c-4fd8-4047-96d7-7fa34d9ba44d@quicinc.com/
Signed-off-by: Pooventhiran G <pooventhiran.g@oss.qualcomm.com>
---
Aditya Sathish (2):
wifi: nl80211: Add kernel interfaces for Seamless Mobility Domain setup
wifi: cfg80211/mac80211: Parse SMD parameters in STA addition/modification
Pooventhiran G (13):
net: skbuff: Add SKB extension support to wireless drivers
wifi: nl80211/mac80211: Add SMD BSS Transition sub-state STA flags
wifi: mac80211: Add driver_op for SMD substate changes
wifi: mac80211: Send BlockAck policy in AMPDU action
wifi: mac80211: Define SMD BSS Transition context for transport
wifi: mac80211: Enable skb extensions along with mac80211
wifi: nl80211: Define attributes to pack SMD BSS Transition context
wifi: cfg80211/mac80211: Handle UHR Link Reconfiguration frame
wifi: nl80211: Pack SMD dynamic context along with frame
wifi: nl80211/cfg80211: Add support for SMD context programming
wifi: mac80211: Add mac80211 support to handle NL80211_CMD_SET_SMD_CTX
wifi: nl80211/cfg80211: Add support for querying SMD context for target AP MLD
wifi: mac80211: Add mac80211 support to handle NL80211_CMD_GET_SMD_CTX
Rohan Dutta (2):
wifi: cfg80211/mac80211: Configure AP with SMD capabilities
wifi: nl80211/cfg80211: Indicate STA creation via SMD BSS Transition
Sidhanta Sahu (1):
wifi: nl80211: Define Seamless Mobility Domain (SMD) device capability
include/linux/ieee80211-uhr.h | 149 +++++++
include/linux/skbuff.h | 3 +
include/linux/skbuff_wireless.h | 55 +++
include/net/cfg80211.h | 115 +++++
include/net/mac80211.h | 124 ++++++
include/uapi/linux/nl80211.h | 303 +++++++++++++
net/core/skbuff.c | 55 +++
net/mac80211/Kconfig | 1 +
net/mac80211/agg-rx.c | 1 +
net/mac80211/cfg.c | 166 +++++++
net/mac80211/debugfs_sta.c | 4 +
net/mac80211/driver-ops.c | 24 +
net/mac80211/driver-ops.h | 54 +++
net/mac80211/rx.c | 22 +
net/mac80211/sta_info.c | 146 +++++++
net/mac80211/sta_info.h | 19 +
net/mac80211/trace.h | 117 ++++-
net/wireless/core.c | 25 ++
net/wireless/mlme.c | 32 ++
net/wireless/nl80211.c | 941 +++++++++++++++++++++++++++++++++++++++-
net/wireless/nl80211.h | 9 +
net/wireless/rdev-ops.h | 28 ++
net/wireless/trace.h | 73 ++++
23 files changed, 2455 insertions(+), 11 deletions(-)
---
base-commit: 1b60ed34f712e9f606d80951f1586f4274ebadf1
change-id: 20260908-smd-16986850d725
Best regards,
--
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH wireless-next 01/18] net: skbuff: Add SKB extension support to wireless drivers
2026-09-07 20:29 [PATCH wireless-next 00/18] wifi: Add Seamless Mobility Domain (SMD) AP support Pooventhiran G
@ 2026-09-07 20:29 ` Pooventhiran G
2026-09-07 20:29 ` [PATCH wireless-next 02/18] wifi: nl80211: Define Seamless Mobility Domain (SMD) device capability Pooventhiran G
` (16 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Pooventhiran G @ 2026-09-07 20:29 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Johannes Berg
Cc: linux-kernel, netdev, linux-wireless, Pooventhiran G
IEEE P802.11bn/D2.0, Aug 2026, subclause 37.16, defines Seamless
Mobility Domain (SMD) BSS Transition, in which a station roams between
two AP MLDs within an SMD across two phases: Preparation and Execution.
During these phases, the receiving AP driver processes a query frame and
must carry the station's roaming context - per-TID sequence numbers in
downlink (DL) and uplink (UL) directions, packet number in DL and
per-TID packet numbers in UL, and per-TID BlockAck session parameters in
DL and UL, plus a variable-length driver context - up through mac80211
and nl80211 to userspace, which uses it to complete the transition.
This context does not fit in skb->cb (48 bytes). Carrying it separately,
outside the SKB, breaks when the SKB is cloned through the RX path because
the context lifetime is no longer tied to the frame; the driver would need
independent state correlated with the SKB at nl80211 encode time, adding
error-prone lifecycle management. SKB extensions avoid these problems: they
are reference-counted, copy-on-write safe, and freed automatically with the
SKB.
Add a new skbuff_wireless.h with a typed union structured to accommodate
future wireless extension types, carrying the SMD roaming context as its
first payload.
Signed-off-by: Pooventhiran G <pooventhiran.g@oss.qualcomm.com>
---
include/linux/skbuff.h | 3 +++
include/linux/skbuff_wireless.h | 55 +++++++++++++++++++++++++++++++++++++++++
net/core/skbuff.c | 55 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 113 insertions(+)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 421f6fc45451..fb686024e97d 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -5061,6 +5061,9 @@ enum skb_ext_id {
#endif
#if IS_ENABLED(CONFIG_CAN)
SKB_EXT_CAN,
+#endif
+#if IS_ENABLED(CONFIG_WIRELESS)
+ SKB_EXT_WIRELESS,
#endif
SKB_EXT_NUM, /* must be last */
};
diff --git a/include/linux/skbuff_wireless.h b/include/linux/skbuff_wireless.h
new file mode 100644
index 000000000000..2cb04bff061c
--- /dev/null
+++ b/include/linux/skbuff_wireless.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * IEEE 802.11 WLAN skb_ext definitions
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef LINUX_SKB_WIRELESS_H
+#define LINUX_SKB_WIRELESS_H
+
+#include <linux/types.h>
+#include <linux/refcount.h>
+
+/**
+ * enum wireless_skb_ext_type - type of data in wireless_skb_ext
+ * @WIRELESS_SKB_EXT_INVALID: uninitialized state
+ * @WIRELESS_SKB_EXT_UHR_SMD: payload is @uhr_smd_ctx
+ */
+enum wireless_skb_ext_type {
+ WIRELESS_SKB_EXT_INVALID,
+ WIRELESS_SKB_EXT_UHR_SMD,
+};
+
+/**
+ * struct wireless_skb_ext_smd_ctx - UHR SMD roaming context container in
+ * SKB extensions
+ * @refcnt: reference count; one count per distinct skb_ext block that holds
+ * this pointer. Plain skb_clone() shares the same skb_ext block and
+ * does not increment this counter. Only skb_ext_maybe_cow() increments
+ * this counter, when a COW produces a second independent ext block copy.
+ * @smd_ctx: pointer to the IEEE P802.11bn UHR SMD roaming context;
+ * must be a kmalloc-ed buffer, freed together with this container.
+ */
+struct wireless_skb_ext_smd_ctx {
+ refcount_t refcnt;
+ void *smd_ctx;
+};
+
+/**
+ * struct wireless_skb_ext - SKB extension data for wireless module use
+ *
+ * Carried as an skb extension (SKB_EXT_WIRELESS). The union is reserved
+ * for future wireless extension types; only one member is active per skb.
+ *
+ * @type: type of data
+ * @uhr_smd_ctx: pointer to the UHR SMD context container
+ */
+struct wireless_skb_ext {
+ enum wireless_skb_ext_type type;
+ union {
+ struct wireless_skb_ext_smd_ctx *uhr_smd_ctx;
+ };
+};
+
+#endif /* LINUX_SKB_WIRELESS_H */
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ab195b99c853..f28ab7c3c888 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -93,6 +93,10 @@
#include <linux/indirect_call_wrapper.h>
#include <linux/textsearch.h>
+#if IS_ENABLED(CONFIG_WIRELESS)
+#include <linux/skbuff_wireless.h>
+#endif
+
#include "dev.h"
#include "devmem.h"
#include "net-sysfs.h"
@@ -5169,6 +5173,9 @@ static const u8 skb_ext_type_len[] = {
#if IS_ENABLED(CONFIG_CAN)
[SKB_EXT_CAN] = SKB_EXT_CHUNKSIZEOF(struct can_skb_ext),
#endif
+#if IS_ENABLED(CONFIG_WIRELESS)
+ [SKB_EXT_WIRELESS] = SKB_EXT_CHUNKSIZEOF(struct wireless_skb_ext),
+#endif
};
static __always_inline __no_profile unsigned int skb_ext_total_length(void)
@@ -7152,6 +7159,16 @@ static struct skb_ext *skb_ext_maybe_cow(struct skb_ext *old,
if (flow->key)
refcount_inc(&flow->key->refs);
}
+#endif
+#if IS_ENABLED(CONFIG_WIRELESS)
+ if (old_active & (1 << SKB_EXT_WIRELESS)) {
+ struct wireless_skb_ext *wifi =
+ skb_ext_get_ptr(old, SKB_EXT_WIRELESS);
+
+ if (wifi->type == WIRELESS_SKB_EXT_UHR_SMD &&
+ wifi->uhr_smd_ctx)
+ refcount_inc(&wifi->uhr_smd_ctx->refcnt);
+ }
#endif
__skb_ext_put(old);
return new;
@@ -7256,6 +7273,36 @@ static void skb_ext_put_mctp(struct mctp_flow *flow)
}
#endif
+#if IS_ENABLED(CONFIG_WIRELESS)
+static void skb_ext_put_wireless(struct wireless_skb_ext *wifi)
+{
+ switch (wifi->type) {
+ case WIRELESS_SKB_EXT_UHR_SMD:
+ if (!wifi->uhr_smd_ctx)
+ break;
+
+ if (refcount_dec_and_test(&wifi->uhr_smd_ctx->refcnt)) {
+ kfree(wifi->uhr_smd_ctx->smd_ctx);
+ kfree(wifi->uhr_smd_ctx);
+ }
+
+ /*
+ * __skb_ext_del clears active_extensions but not ext->offset[],
+ * so __skb_ext_put will call skb_ext_put_wireless again;
+ * mark NULL regardless to avoid double free in __skb_ext_put.
+ */
+ wifi->uhr_smd_ctx = NULL;
+ break;
+ case WIRELESS_SKB_EXT_INVALID:
+ /* data not yet set */
+ break;
+ default:
+ WARN_ONCE(1, "unknown wireless skb extension type=%u\n",
+ wifi->type);
+ }
+}
+#endif
+
void __skb_ext_del(struct sk_buff