Search Linux Wireless

Adding EPCS Support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

We are implementing a Wi-Fi 7 feature called Emergency Preparedness Communication Services (EPCS) that provides priority to Stations (STAs) that are authorized to receive National Security and Emergency Preparedness (NSEP) Communication Services. This feature is part of Wi-Fi 7 certification, detailed in IEEE 802.11be Draft 6.0.

We have started implementation efforts for the Linux operating system (specifically Arch Linux). We have successfully implemented and tested the over-the-air behavior per Wi-Fi Alliance defined test cases by modifying the ‘hostapd’ and ‘wpa_supplicant’. However, we are facing challenges making kernel modifications related to applying EDCA parameters for channel access. Specifically, we need to modify the nl80211, mac80211, and cfg80211 components in the Linux kernel to accommodate the following behavior at the STA per IEEE 802.11be specification (Draft 6.0, Clause 35.16.3.2):

"While EPCS priority access is enabled, the STA affiliated with an EPCS non-AP MLD shall
 
- follow the contention-based channel-access procedures defined in 10.2.3.2 (HCF contention-based channel access (EDCA)) using the EDCA parameter set stored in the dot11EDCATable as described earlier in this subclause, and
- ignore the part of the procedures defined in 10.2.3.2 (HCF contention-based channel access (EDCA)) that concerns the update of the EDCA parameters that are sent by the corresponding AP in its Beacon and Probe Response frames
- if the per-STA profile of the EPCS Priority Access Multi-Link element is present in the EPCS Priority Access Enable Request or the EPCS Priority Access Enable Response frame received by a STA affiliated with the EPCS non-AP MLD and the per-STA profile contains an MU EDCA Parameter Set element:
  - follow the rules defined in 26.2.7 (EDCA operation using MU EDCA parameters) using the MU EDCA parameters stored in the dot11MUEDCATable as described earlier in this subclause, except that
    - if the MUEDCATimer[AC] of the STA reaches 0, either by counting down or due to a reset following the reception of an MU EDCA Reset frame, the STA affiliated with EPCS non-AP MLD shall update CWmin[AC], CWmax[AC], and AIFSN[AC] to the values stored in the dot11EDCATable as described earlier in this subclause
    - ignore the part of the procedures defined in 26.2.7 (EDCA operation using MU EDCA parameters) that concerns the update of the MU EDCA parameters that are sent by the corresponding AP in its Beacon and Probe Response frames 

After the EPCS priority access is torn down, the STA affiliated with an EPCS non-AP MLD
 
- shall update its CWmin[AC], CWmax[AC], AIFSN[AC], and TXOP Limit [AC] state variables following the procedures in 10.2.3.2 (HCF contention-based channel access (EDCA)). 
- shall update the dot11MUEDCATable following the procedures in 26.2.7 (EDCA operation using MU EDCA parameters)."

We took the following approach: 

- Define new nl80211 commands: NL80211_CMD_EPCS_ENABLE and NL80211_CMD_EPCS_TEARDOWN 
- Define new STA flag: WLAN_STA_EPCS_ENABLED 
- In net/mac80211/mlme.c, in ieee80211_mgd_set_link_qos_params(), if the WLAN_STA_EPCS_ENABLED flag is set, ignore the EDCA parameters from the Beacon and apply Priority EDCA parameters.

Despite our efforts, we encountered several challenges: 

1. Sending EPCS Enable/Teardown commands to the kernel (mac80211) from userspace (hostapd) via netlink.  The response was "Operation not supported on transport endpoint (-EOPNOTSUPP) (-95)".
2. Receiving, parsing and propagating the message via nl80211 and cfg80211.  Specifically, we would like guidance on storing parameters received in the NL80211_CMD_EPCS_ENABLE message and retrieving them in the net/mac80211/mlme.c module. 
3. Applying the new EDCA parameters in mac80211 module. 

We are seeking help from experts in the community who have worked with these components. Specifically, we would appreciate responses to the following questions: 

- Is the kernel the right place to implement this or are there user-space solutions that we can leverage? 
- If kernel modifications are needed, does our proposed approach make sense, or are there better alternatives we should consider? 
- Is there documented guidance on how to add such features to the kernel? 

Please see our initial work to provide basic support for EPCS messaging in Linux kernel 6.9.5 on Arch Linux in the patch below.

Note: this is a proof of concept and not a full implementation – Priority Parameters are hardcoded in the net/mac/80211/mlme.c module.  A full implementation would accept priority parameters via the “NL80211_CMD_EPCS_ENABLE” command. 

Patch to Kernel 6.9.5
---------------------- 
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h 
index 1e09329ac..33c123b1d 100644 
--- a/include/net/cfg80211.h 
+++ b/include/net/cfg80211.h 
@@ -4855,6 +4855,10 @@ struct cfg80211_ops { 
int	(*del_tx_ts)(struct wiphy *wiphy, struct net_device *dev, 
     u8 tsid, const u8 *peer); 
  
+    /* JY: PLABS ADDED */ 
+    int (*epcs_enable)(struct wiphy *wiphy, struct wireless_dev *wdev); 
+    int (*epcs_teardown)(struct wiphy *wiphy, struct wireless_dev *wdev); 
+ 
int	(*tdls_channel_switch)(struct wiphy *wiphy, 
       struct net_device *dev, 
       const u8 *addr, u8 oper_class, 
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h 
index f23ecbdd8..69ddd2092 100644 
--- a/include/uapi/linux/nl80211.h 
+++ b/include/uapi/linux/nl80211.h 
@@ -1592,6 +1592,9 @@ enum nl80211_commands { 
NL80211_CMD_SET_TID_TO_LINK_MAPPING, 
  
/* add new commands above here */ 
+    /* JY: PLABS ADDED */ 
+    NL80211_CMD_EPCS_ENABLE, 
+    NL80211_CMD_EPCS_TEARDOWN, 
  
/* used to define NL80211_CMD_MAX below */ 
__NL80211_CMD_AFTER_LAST, 
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c 
index 07abaf782..a3d979909 100644 
--- a/net/mac80211/cfg.c 
+++ b/net/mac80211/cfg.c 
@@ -4347,6 +4347,32 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, 
return ret; 
} 
  
+/* JY: PLABS BEGIN */ 
+ 
+static int ieee80211_epcs_enable(struct wiphy *wiphy, struct wireless_dev *wdev) 
+{ 
+    struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); 
+    struct sta_info *sta; 
+ 
+    sta = sta_info_get_bss(sdata, sdata->deflink.u.mgd.bssid); 
+    set_sta_flag(sta, WLAN_STA_EPCS_ENABLED); 
+ 
+    return 0; 
+} 
+ 
+static int ieee80211_epcs_teardown(struct wiphy *wiphy, struct wireless_dev *wdev) 
+{ 
+    struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); 
+    struct sta_info *sta; 
+ 
+    sta = sta_info_get_bss(sdata, sdata->deflink.u.mgd.bssid); 
+    clear_sta_flag(sta, WLAN_STA_EPCS_ENABLED); 
+ 
+    return 0; 
+} 
+ 
+/* JY: PLABS END */ 
+ 
static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev, 
       u8 tsid, const u8 *peer, u8 up, 
       u16 admitted_time) 
@@ -5165,4 +5191,7 @@ const struct cfg80211_ops mac80211_config_ops = { 
.del_link_station = ieee80211_del_link_station, 
.set_hw_timestamp = ieee80211_set_hw_timestamp, 
.set_ttlm = ieee80211_set_ttlm, 
+    /* JY: PLABS ADDED */ 
+    .epcs_enable = ieee80211_epcs_enable, 
+    .epcs_teardown = ieee80211_epcs_teardown, 
}; 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c 
index 1e9389c49..100e26729 100644 
--- a/net/mac80211/debugfs_sta.c 
+++ b/net/mac80211/debugfs_sta.c 
@@ -80,6 +80,8 @@ static const char * const sta_flag_names[] = { 
FLAG(PS_DELIVER), 
FLAG(USES_ENCRYPTION), 
FLAG(DECAP_OFFLOAD), 
+    /* JY: PLABS ADDED */ 
+    FLAG(EPCS_ENABLED), 
#undef FLAG 
}; 
  
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c 
index 497677e3d..aba87d1d4 100644 
--- a/net/mac80211/mlme.c 
+++ b/net/mac80211/mlme.c 
@@ -2720,7 +2720,30 @@ void ieee80211_mgd_set_link_qos_params(struct ieee80211_link_data *link) 
struct ieee80211_tx_queue_params *params = link->tx_conf; 
u8 ac; 
  
+    /* PLABS JY: Changes BEGIN */ 
+    bool epcs_enabled = false; 
+    struct sta_info *sta = NULL;     
+       
+    /* New flag lives in the Station Info */ 
+    sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); 
+ 
+    /* Get result 0 or 1 */ 
+    epcs_enabled = test_sta_flag(sta, WLAN_STA_EPCS_ENABLED); 
+   
+    mlme_dbg(sdata, "JY: PLABS mac80211 module changes\n"); 
+    mlme_dbg(sdata, "EPCS Enabled=%s\n", epcs_enabled ? "true" : "false"); 
+ 
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 
+        if (epcs_enabled) { 
+            mlme_dbg(sdata, "JY: PLABS We are entering priority mode!\n"); 
+            // Setting EDCA parameter to Voice 
+            params[ac].aifs = 3; 
+            params[ac].cw_min = 4; 
+            params[ac].cw_max = 5; 
+            params[ac].txop = 65; 
+            params[ac].acm = 0; 
+          } 
+ 
mlme_dbg(sdata, 
 "WMM AC=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n", 
 ac, params[ac].acm, 
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h 
index a52fb7638..ac2a39d57 100644 
--- a/net/mac80211/sta_info.h 
+++ b/net/mac80211/sta_info.h 
@@ -104,6 +104,8 @@ enum ieee80211_sta_info_flags { 
WLAN_STA_PS_DELIVER, 
WLAN_STA_USES_ENCRYPTION, 
WLAN_STA_DECAP_OFFLOAD, 
+    /* JY: PLABS ADDED */ 
+    WLAN_STA_EPCS_ENABLED, 
  
NUM_WLAN_STA_FLAGS, 
}; 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c 
index 65c416e8d..8be612b49 100644 
--- a/net/wireless/nl80211.c 
+++ b/net/wireless/nl80211.c 
@@ -2641,6 +2641,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, 
if (rdev->wiphy.features & 
NL80211_FEATURE_SUPPORTS_WMM_ADMISSION) 
CMD(add_tx_ts, ADD_TX_TS); 
+            // PLABS Added 
+            CMD(epcs_enable, EPCS_ENABLE); 
CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST); 
CMD(update_connect_params, UPDATE_CONNECT_PARAMS); 
CMD(update_ft_ies, UPDATE_FT_IES); 
@@ -15299,6 +15301,30 @@ static int nl80211_set_qos_map(struct sk_buff *skb, 
return ret; 
} 
  
+/* JY: PLABS ADDED */           
+static int nl80211_epcs_enable(struct sk_buff *skb, struct genl_info *info) 
+{ 
+    struct cfg80211_registered_device *rdev = info->user_ptr[0]; 
+    struct net_device *dev = info->user_ptr[1]; 
+    struct wireless_dev *wdev = dev->ieee80211_ptr; 
+       
+    rdev_epcs_enable(rdev, wdev);    
+                                                                                                                                         
+    return 1;                   
+}  
+       
+/* JY: PLABS ADDED */           
+static int nl80211_epcs_teardown(struct sk_buff *skb, struct genl_info *info) 
+{      
+    struct cfg80211_registered_device *rdev = info->user_ptr[0]; 
+    struct net_device *dev = info->user_ptr[1]; 
+    struct wireless_dev *wdev = dev->ieee80211_ptr; 
+ 
+    rdev_epcs_teardown(rdev, wdev);  
+                                                                                                                                         
+    return 1; 
+} 
+ 
static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) 
{ 
struct cfg80211_registered_device *rdev = info->user_ptr[0]; 
@@ -17488,6 +17514,24 @@ static const struct genl_small_ops nl80211_small_ops[] = { 
.flags = GENL_UNS_ADMIN_PERM, 
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), 
}, 
+    /* JY: PLABS ADDED */ 
+    { 
+        .cmd = NL80211_CMD_EPCS_ENABLE, 
+        // PLABS: If we encounter issues, remove validate 
+        .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 
+        .doit = nl80211_epcs_enable, 
+        .flags = GENL_UNS_ADMIN_PERM, 
+        .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_MLO_UNSUPPORTED), 
+    }, 
+    /* JY: PLABS ADDED */ 
+    { 
+        .cmd = NL80211_CMD_EPCS_TEARDOWN, 
+        // PLABS: If we encounter issues, remove validate 
+        .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 
+        .doit = nl80211_epcs_teardown, 
+        .flags = GENL_UNS_ADMIN_PERM, 
+        .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_MLO_UNSUPPORTED), 
+    }, 
}; 
  
static struct genl_family nl80211_fam __ro_after_init = { 
@@ -17504,7 +17548,9 @@ static struct genl_family nl80211_fam __ro_after_init = { 
.n_ops = ARRAY_SIZE(nl80211_ops), 
.small_ops = nl80211_small_ops, 
.n_small_ops = ARRAY_SIZE(nl80211_small_ops), 
-	.resv_start_op = NL80211_CMD_REMOVE_LINK_STA + 1, 
+    // PLABS Changed 
+	//.resv_start_op = NL80211_CMD_REMOVE_LINK_STA + 1, 
+	.resv_start_op = NL80211_CMD_MAX + 1, 
.mcgrps = nl80211_mcgrps, 
.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps), 
.parallel_ops = true, 
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h 
index 43897a526..8aec66206 100644 
--- a/net/wireless/rdev-ops.h 
+++ b/net/wireless/rdev-ops.h 
@@ -637,6 +637,17 @@ static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev) 
trace_rdev_return_void(&rdev->wiphy); 
} 
  
+/* JY: PLABS ADDED */           
+static inline void rdev_epcs_enable(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) 
+{ 
+    rdev->ops->epcs_enable(&rdev->wiphy, wdev); 
+} 
+  
+/* JY: PLABS ADDED */ 
+static inline void rdev_epcs_teardown(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) 
+{ 
+    rdev->ops->epcs_teardown(&rdev->wiphy, wdev); 
+} 
  
#ifdef CONFIG_NL80211_TESTMODE 
static inline int rdev_testmode_cmd(struct cfg80211_registered_device *rdev, 
 
Thanks in advance, 
Jason 





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux