From 54e0b80b654f89843c7cfbe56bbcf426b6bd7de5 Mon Sep 17 00:00:00 2001 From: dingsen-Greenhorn Date: Sun, 8 Jun 2025 04:16:49 +0800 Subject: [PATCH 1/7] Implement dynamic MCS selection based on signal strength in vWIFI driver This commit enhances the vWIFI driver by implementing dynamic Modulation and Coding Scheme (MCS) selection in the `vwifi_get_station` function, adjusting the MCS index based on signal strength. After implement dynamic MCS can avoid TX power waste for a bad channel quality. --- vwifi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/vwifi.c b/vwifi.c index d57a4f3..d8fd186 100644 --- a/vwifi.c +++ b/vwifi.c @@ -1403,8 +1403,18 @@ static int vwifi_get_station(struct wiphy *wiphy, sinfo->tx_failed = vif->stats.tx_dropped; sinfo->tx_bytes = vif->stats.tx_bytes; sinfo->rx_bytes = vif->stats.rx_bytes; + + /* Log byte counters for debugging */ + pr_info( + "vwifi: Station %pM tx_bytes %llu, rx_bytes %llu, tx_packets %u, " + "rx_packets %u, tx_failed %u\n", + mac, sinfo->tx_bytes, sinfo->rx_bytes, sinfo->tx_packets, + sinfo->rx_packets, sinfo->tx_failed); + /* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in dBm */ sinfo->signal = rand_int_smooth(-100, -30, jiffies); + pr_info("vwifi: Station %pM signal %d dBm (raw)\n", mac, + sinfo->signal); sinfo->inactive_time = jiffies_to_msecs(jiffies - vif->active_time); /* * Using 802.11n (HT) as the PHY, configure as follows: @@ -1425,15 +1435,53 @@ static int vwifi_get_station(struct wiphy *wiphy, * https://semfionetworks.com/blog/mcs-table-updated-with-80211ax-data-rates/ * IEEE 802.11n : https://zh.wikipedia.org/zh-tw/IEEE_802.11n */ - sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; - sinfo->rxrate.mcs = 31; + /* Log byte counters for debugging */ + pr_info("vwifi: Station %pM tx_bytes %llu, rx_bytes %llu\n", mac, + sinfo->tx_bytes, sinfo->rx_bytes); + + /* Dynamic modulation based on signal strength */ + int mcs_index; + const char *modulation; + unsigned int data_rate_mbps; + if (sinfo->signal > -50) { + /* Strong signal: 64-QAM, MCS 31 */ + mcs_index = 31; + modulation = "64-QAM"; + } else if (sinfo->signal > -70 && sinfo->signal <= -50) { + /* Medium signal: 16-QAM, MCS 23 */ + mcs_index = 23; + modulation = "16-QAM"; + } else if (sinfo->signal > -90 && sinfo->signal <= -70) { + /* Weak signal: QPSK, MCS 15 */ + mcs_index = 15; + modulation = "QPSK"; + } else { + /* Very weak signal: BPSK, MCS 7 */ + mcs_index = 7; + modulation = "BPSK"; + } + + /* Log signal, modulation, and data rate for debugging */ + pr_info( + "vwifi: Station %pM signal %d dBm, using modulation %s (MCS %d, %u " + "Mbps)\n", + mac, sinfo->signal, modulation, mcs_index, data_rate_mbps); + + /* Configure RX and TX rates */ + sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS; + sinfo->rxrate.mcs = mcs_index; sinfo->rxrate.bw = RATE_INFO_BW_20; sinfo->rxrate.n_bonded_ch = 1; - sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; - sinfo->txrate.mcs = 31; + sinfo->txrate.flags = RATE_INFO_FLAGS_MCS; + sinfo->txrate.mcs = mcs_index; sinfo->txrate.bw = RATE_INFO_BW_20; sinfo->txrate.n_bonded_ch = 1; + + /* Log rate configuration for verification */ + pr_info("vwifi: Station %pM txrate MCS %d, rxrate MCS %d\n", mac, + sinfo->txrate.mcs, sinfo->rxrate.mcs); + return 0; } From 91768108d6c6bac5cec2cd56cc855bf07b8d7b87 Mon Sep 17 00:00:00 2001 From: dingsen-Greenhorn Date: Sun, 8 Jun 2025 23:14:02 +0800 Subject: [PATCH 2/7] Add manual MCS configuration via set_bitrate_mask Implement the set_bitrate_mask callback in cfg80211_ops to support manual MCS settings using `iw dev set bitrates ht-mcs-2.4 `, addressing reviewer feedback. Store the selected MCS in vwifi_vif->manual_mcs and track its state with vwifi_vif->manual_mcs_set. Support MCS indices 7, 15, 23, and 31, with validation and logging. Tested with `iw dev vw1 set bitrates ht-mcs-2.4 15`, achieving MCS 15 at 130.0 MBit/s (bitrate calculation pending refinement to ~52 MBit/s). Test commands format $sudo ip netns exec ns1 iw dev vw1 link $sudo ip netns exec ns1 iw dev vw1 set bitrates ht-mcs-2.4 15 /*(changable 7,15,23,31)*/ $sudo ip netns exec ns1 iw dev vw1 link --- vwifi.c | 155 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 126 insertions(+), 29 deletions(-) diff --git a/vwifi.c b/vwifi.c index d8fd186..a38a5cb 100644 --- a/vwifi.c +++ b/vwifi.c @@ -88,6 +88,8 @@ struct vwifi_vif { struct wireless_dev wdev; struct net_device *ndev; struct net_device_stats stats; + int manual_mcs; + bool manual_mcs_set; size_t ssid_len; /* Currently connected BSS id */ @@ -1435,38 +1437,52 @@ static int vwifi_get_station(struct wiphy *wiphy, * https://semfionetworks.com/blog/mcs-table-updated-with-80211ax-data-rates/ * IEEE 802.11n : https://zh.wikipedia.org/zh-tw/IEEE_802.11n */ - /* Log byte counters for debugging */ - pr_info("vwifi: Station %pM tx_bytes %llu, rx_bytes %llu\n", mac, - sinfo->tx_bytes, sinfo->rx_bytes); - - /* Dynamic modulation based on signal strength */ + /* Check vif->manual_mcs_set to use vif->manual_mcs if set; + * Assign modulation string for manual MCS ; else auto change based + * on signal strength + */ int mcs_index; const char *modulation; - unsigned int data_rate_mbps; - if (sinfo->signal > -50) { - /* Strong signal: 64-QAM, MCS 31 */ - mcs_index = 31; - modulation = "64-QAM"; - } else if (sinfo->signal > -70 && sinfo->signal <= -50) { - /* Medium signal: 16-QAM, MCS 23 */ - mcs_index = 23; - modulation = "16-QAM"; - } else if (sinfo->signal > -90 && sinfo->signal <= -70) { - /* Weak signal: QPSK, MCS 15 */ - mcs_index = 15; - modulation = "QPSK"; + if (vif->manual_mcs_set) { + mcs_index = vif->manual_mcs; + switch (mcs_index) { + case 7: + modulation = "BPSK"; + break; + case 15: + modulation = "QPSK"; + break; + case 23: + modulation = "16-QAM"; + break; + case 31: + modulation = "64-QAM"; + break; + default: + modulation = "Unknown"; + break; + } + pr_info("vwifi: Station %pM using manual MCS %d (%s)\n", mac, mcs_index, + modulation); } else { - /* Very weak signal: BPSK, MCS 7 */ - mcs_index = 7; - modulation = "BPSK"; + if (sinfo->signal > -50) { + mcs_index = 31; + modulation = "64-QAM"; + } else if (sinfo->signal > -70 && sinfo->signal <= -50) { + mcs_index = 23; + modulation = "16-QAM"; + } else if (sinfo->signal > -90 && sinfo->signal <= -70) { + mcs_index = 15; + modulation = "QPSK"; + } else { + mcs_index = 7; + modulation = "BPSK"; + } + pr_info( + "vwifi: Station %pM signal %d dBm, using modulation %s (MCS %d)\n", + mac, sinfo->signal, modulation, mcs_index); } - /* Log signal, modulation, and data rate for debugging */ - pr_info( - "vwifi: Station %pM signal %d dBm, using modulation %s (MCS %d, %u " - "Mbps)\n", - mac, sinfo->signal, modulation, mcs_index, data_rate_mbps); - /* Configure RX and TX rates */ sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS; sinfo->rxrate.mcs = mcs_index; @@ -2209,6 +2225,66 @@ static int vwifi_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) return 0; } +/* Callback to handle manual bitrate configuration via iw */ +static int vwifi_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + unsigned int link_id, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +{ + struct vwifi_vif *vif = netdev_priv(dev); + int mcs_index = -1; + + if (!vif) { + pr_err("vwifi: Failed to get vwifi_vif for dev %s\n", dev->name); + return -EINVAL; + } + + if (vif->sme_state != SME_CONNECTED) { + pr_err("vwifi: Dev %s not connected, cannot set bitrate\n", dev->name); + return -EINVAL; + } + + pr_info("vwifi: set_bitrate_mask called for dev %s, link_id %u, peer %pM\n", + dev->name, link_id, peer ? peer : vif->bssid); + pr_info("vwifi: 2.4GHz MCS mask: %02x %02x %02x %02x\n", + mask->control[NL80211_BAND_2GHZ].ht_mcs[0], + mask->control[NL80211_BAND_2GHZ].ht_mcs[1], + mask->control[NL80211_BAND_2GHZ].ht_mcs[2], + mask->control[NL80211_BAND_2GHZ].ht_mcs[3]); + + /* Find the requested MCS index */ + for (int i = 0; i < 4; i++) { + if (mask->control[NL80211_BAND_2GHZ].ht_mcs[i]) { + for (int j = 0; j < 8; j++) { + if (mask->control[NL80211_BAND_2GHZ].ht_mcs[i] & (1 << j)) { + mcs_index = i * 8 + j; + pr_info("vwifi: Requested MCS index %d\n", mcs_index); + break; + } + } + if (mcs_index != -1) + break; + } + } + + if (mcs_index == -1) { + pr_err("vwifi: No valid MCS index found\n"); + return -EINVAL; + } + + if (mcs_index != 7 && mcs_index != 15 && mcs_index != 23 && + mcs_index != 31) { + pr_err("vwifi: Unsupported MCS index %d\n", mcs_index); + return -EINVAL; + } + + vif->manual_mcs = mcs_index; + vif->manual_mcs_set = true; + pr_info("vwifi: Set manual MCS %d for dev %s\n", mcs_index, dev->name); + + return 0; +} /* Structure of functions for FullMAC 80211 drivers. Functions implemented * along with fields/flags in the wiphy structure represent driver features. @@ -2234,6 +2310,7 @@ static struct cfg80211_ops vwifi_cfg_ops = { .get_tx_power = vwifi_get_tx_power, .join_ibss = vwifi_join_ibss, .leave_ibss = vwifi_leave_ibss, + .set_bitrate_mask = vwifi_set_bitrate_mask, }; /* Macro for defining 2GHZ channel array */ @@ -2288,8 +2365,28 @@ static const struct ieee80211_rate vwifi_supported_rates[] = { }; /* Describes supported band of 2GHz. */ -static struct ieee80211_supported_band nf_band_2ghz; - +static struct ieee80211_supported_band nf_band_2ghz = { + .band = NL80211_BAND_2GHZ, + .channels = vwifi_supported_channels_2ghz, + .n_channels = ARRAY_SIZE(vwifi_supported_channels_2ghz), + .bitrates = vwifi_supported_rates, + .n_bitrates = ARRAY_SIZE(vwifi_supported_rates), + .ht_cap = + { + .ht_supported = true, + .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_MAX_AMSDU | + IEEE80211_HT_CAP_SUP_WIDTH_20_40, + .mcs = + { + .rx_mask = {0xff, 0xff, 0xff, 0xff}, /* MCS 0-31 */ + .rx_highest = cpu_to_le16(300), + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + }, +}; /* Describes supported band of 5GHz. */ static struct ieee80211_supported_band nf_band_5ghz; From b38d0373813ddcec1b746de04580fc1e6df5f707 Mon Sep 17 00:00:00 2001 From: dingsen-Greenhorn Date: Thu, 12 Jun 2025 23:10:56 +0800 Subject: [PATCH 3/7] =?UTF-8?q?Expand=20MCS=20support=20manual=2024?= =?UTF-8?q?=E2=80=9331=20range=20for=204-stream?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the vwifi_set_bitrate_mask callback to support the full range of MCS indices 24 through 31, aligning with the 4-spatial-stream configuration in nf_band_2ghz. This change enabling support for manual MCS from 24-31 coding schemes (1/2, 3/4, 2/3, 5/6) and modulations (BPSK, QPSK,16-QAM, 64-QAM) as defined by the IEEE 802.11n specification. The callback now rejects indices outside 24–31, ensuring compliance with 4-stream capabilities and allowing comprehensive rate testing (26–260 Mbps). The auto MCS selection, due to this function is based on only signal strength, while the MCS should construct with modulation and coding scheme, which the coding scheme is related with BER (bite error rate), previous vWiFI only implement random signal strength, meaning that bit error rate should also based on the channel state info. --- vwifi.c | 68 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/vwifi.c b/vwifi.c index a38a5cb..c312684 100644 --- a/vwifi.c +++ b/vwifi.c @@ -88,8 +88,8 @@ struct vwifi_vif { struct wireless_dev wdev; struct net_device *ndev; struct net_device_stats stats; - int manual_mcs; - bool manual_mcs_set; + int manual_mcs; + bool manual_mcs_set; size_t ssid_len; /* Currently connected BSS id */ @@ -1406,7 +1406,7 @@ static int vwifi_get_station(struct wiphy *wiphy, sinfo->tx_bytes = vif->stats.tx_bytes; sinfo->rx_bytes = vif->stats.rx_bytes; - /* Log byte counters for debugging */ + /* Log byte counters for debugging */ pr_info( "vwifi: Station %pM tx_bytes %llu, rx_bytes %llu, tx_packets %u, " "rx_packets %u, tx_failed %u\n", @@ -1415,8 +1415,7 @@ static int vwifi_get_station(struct wiphy *wiphy, /* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in dBm */ sinfo->signal = rand_int_smooth(-100, -30, jiffies); - pr_info("vwifi: Station %pM signal %d dBm (raw)\n", mac, - sinfo->signal); + pr_info("vwifi: Station %pM signal %d dBm (raw)\n", mac, sinfo->signal); sinfo->inactive_time = jiffies_to_msecs(jiffies - vif->active_time); /* * Using 802.11n (HT) as the PHY, configure as follows: @@ -1437,52 +1436,79 @@ static int vwifi_get_station(struct wiphy *wiphy, * https://semfionetworks.com/blog/mcs-table-updated-with-80211ax-data-rates/ * IEEE 802.11n : https://zh.wikipedia.org/zh-tw/IEEE_802.11n */ + /* Check vif->manual_mcs_set to use vif->manual_mcs if set; * Assign modulation string for manual MCS ; else auto change based * on signal strength */ int mcs_index; const char *modulation; + const char *coding_rate; if (vif->manual_mcs_set) { mcs_index = vif->manual_mcs; switch (mcs_index) { - case 7: + case 24: modulation = "BPSK"; + coding_rate = "1/2"; break; - case 15: + case 25: modulation = "QPSK"; + coding_rate = "1/2"; break; - case 23: + case 26: + modulation = "QPSK"; + coding_rate = "3/4"; + break; + case 27: + modulation = "16-QAM"; + coding_rate = "1/2"; + break; + case 28: modulation = "16-QAM"; + coding_rate = "3/4"; + break; + case 29: + modulation = "64-QAM"; + coding_rate = "2/3"; + break; + case 30: + modulation = "64-QAM"; + coding_rate = "3/4"; break; case 31: modulation = "64-QAM"; + coding_rate = "5/6"; break; default: - modulation = "Unknown"; + pr_err("vwifi: Unsupported MCS index %d\n", mcs_index); + mcs_index = 24; /* Default to lowest 4-stream MCS */ + modulation = "BPSK"; + coding_rate = "1/2"; break; } - pr_info("vwifi: Station %pM using manual MCS %d (%s)\n", mac, mcs_index, - modulation); + pr_info("vwifi: Station %pM using manual MCS %d (%s, %s)\n", mac, + mcs_index, modulation, coding_rate); } else { if (sinfo->signal > -50) { mcs_index = 31; modulation = "64-QAM"; + coding_rate = "5/6"; } else if (sinfo->signal > -70 && sinfo->signal <= -50) { - mcs_index = 23; + mcs_index = 28; modulation = "16-QAM"; + coding_rate = "3/4"; } else if (sinfo->signal > -90 && sinfo->signal <= -70) { - mcs_index = 15; + mcs_index = 25; modulation = "QPSK"; + coding_rate = "1/2"; } else { - mcs_index = 7; + mcs_index = 24; modulation = "BPSK"; + coding_rate = "1/2"; } - pr_info( - "vwifi: Station %pM signal %d dBm, using modulation %s (MCS %d)\n", - mac, sinfo->signal, modulation, mcs_index); + pr_info("vwifi: Station %pM signal %d dBm, using MCS %d (%s, %s)\n", + mac, sinfo->signal, mcs_index, modulation, coding_rate); } - /* Configure RX and TX rates */ sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS; sinfo->rxrate.mcs = mcs_index; @@ -1497,7 +1523,6 @@ static int vwifi_get_station(struct wiphy *wiphy, /* Log rate configuration for verification */ pr_info("vwifi: Station %pM txrate MCS %d, rxrate MCS %d\n", mac, sinfo->txrate.mcs, sinfo->rxrate.mcs); - return 0; } @@ -2273,8 +2298,8 @@ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, return -EINVAL; } - if (mcs_index != 7 && mcs_index != 15 && mcs_index != 23 && - mcs_index != 31) { + /* Restrict to supported 4-stream MCS indices 24–31 */ + if (mcs_index < 24 || mcs_index > 31) { pr_err("vwifi: Unsupported MCS index %d\n", mcs_index); return -EINVAL; } @@ -2364,7 +2389,6 @@ static const struct ieee80211_rate vwifi_supported_rates[] = { RATE_ENT(360, 0x200), RATE_ENT(480, 0x400), RATE_ENT(540, 0x800), }; -/* Describes supported band of 2GHz. */ static struct ieee80211_supported_band nf_band_2ghz = { .band = NL80211_BAND_2GHZ, .channels = vwifi_supported_channels_2ghz, From 421b0b69dbd74ba6c98c9020990d30941643edee Mon Sep 17 00:00:00 2001 From: dingsen-Greenhorn Date: Sat, 21 Jun 2025 01:18:18 +0800 Subject: [PATCH 4/7] Update dynamic auto MCS selection logic to align with reference table - Adjust MCS indices 24 to 31 to match spec table's modulation (BPSK to 64-QAM) and coding rates (1/2 to 5/6). - Revise signal strength thresholds (-45 to -75 dBm) to reflect realistic SNR requirements for each modulation scheme. - Preserve random signal generation logic using rand_int_smooth. - Ensure consistency with the reference table's structure and parameters. --- vwifi.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/vwifi.c b/vwifi.c index c312684..e3b3dd8 100644 --- a/vwifi.c +++ b/vwifi.c @@ -1435,9 +1435,8 @@ static int vwifi_get_station(struct wiphy *wiphy, * MCS table, Data Rate Formula : * https://semfionetworks.com/blog/mcs-table-updated-with-80211ax-data-rates/ * IEEE 802.11n : https://zh.wikipedia.org/zh-tw/IEEE_802.11n - */ - - /* Check vif->manual_mcs_set to use vif->manual_mcs if set; + * + * Check vif->manual_mcs_set to use vif->manual_mcs if set; * Assign modulation string for manual MCS ; else auto change based * on signal strength */ @@ -1489,15 +1488,31 @@ static int vwifi_get_station(struct wiphy *wiphy, pr_info("vwifi: Station %pM using manual MCS %d (%s, %s)\n", mac, mcs_index, modulation, coding_rate); } else { - if (sinfo->signal > -50) { + if (sinfo->signal > -45) { mcs_index = 31; modulation = "64-QAM"; coding_rate = "5/6"; - } else if (sinfo->signal > -70 && sinfo->signal <= -50) { + } else if (sinfo->signal > -50 && sinfo->signal <= -45) { + mcs_index = 30; + modulation = "64-QAM"; + coding_rate = "3/4"; + } else if (sinfo->signal > -55 && sinfo->signal <= -50) { + mcs_index = 29; + modulation = "64-QAM"; + coding_rate = "2/3"; + } else if (sinfo->signal > -60 && sinfo->signal <= -55) { mcs_index = 28; modulation = "16-QAM"; coding_rate = "3/4"; - } else if (sinfo->signal > -90 && sinfo->signal <= -70) { + } else if (sinfo->signal > -65 && sinfo->signal <= -60) { + mcs_index = 27; + modulation = "16-QAM"; + coding_rate = "1/2"; + } else if (sinfo->signal > -70 && sinfo->signal <= -65) { + mcs_index = 26; + modulation = "QPSK"; + coding_rate = "3/4"; + } else if (sinfo->signal > -75 && sinfo->signal <= -70) { mcs_index = 25; modulation = "QPSK"; coding_rate = "1/2"; From 93eb878a342df1fa459e732042cb5425777783f9 Mon Sep 17 00:00:00 2001 From: dingsen-Greenhorn Date: Sun, 22 Jun 2025 03:32:21 +0800 Subject: [PATCH 5/7] Add Manual dynamic MCS and GI support and enhance vwifi testing for MCS 0-31 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit enhances the vwifi driver and test script to fully support HT mode with MCS 0-31, dynamic guard interval (GI) selection (0.8 µs and 0.4 µs), and robust testing. Also, for dump station simplify sta_vif validation and remove ambiguous sta_vif == ap_vif check. Key changes: - Adde `gi_mode` module parameter to vwifi.c to enable dynamic switching between long GI (0.8 µs) and short GI (0.4 µs), replacing hardcoded `vif->gi = VWIFI_TXRATE_GI_800NS` in `vwifi_set_bitrate_mask`. - Update `vwifi_set_bitrate_mask` to use `gi_mode` and added logging for GI and MCS settings. - Enhance `vwifi_get_station` to report GI correctly in `sinfo->txrate` and `sinfo->rxrate` with `RATE_INFO_FLAGS_SHORT_GI`. - Update `test_vwifi_bitrates.sh` to: - Test MCS 0-31 with both long and short GI on `vw1` and `vw2`. - Validate bitrates against `ht_mcs_table` (`rate_800ns`, `rate_400ns`). - Add error handling for `gi_mode` writes and connection checks. - Include debug output for `wpa_supplicant` and `iw dev link`. - Suggested debugfs fallback for per-interface GI control if `gi_mode` fails. - Replaced the sta_vif == ap_vif check with a direct null check on sta_vif. The previous comparison between station and access point virtual interfaces (sta_vif == ap_vif) was logically unsound, as these represent distinct roles in Wi-Fi operation and should not be equated. Returning -ENONET when sta_vif equals ap_vif was unclear and potentially masked deeper issues. The new logic simplifies the flow: if no valid sta_vif is found after iterating, return -ENONET; otherwise, continue normally. Also removed an unused assignment to `ret = 0`. These changes ensure compliance with reviewer requirements for HT mode, MCS 0-31, GI selection, and dynamic MCS selection, with robust testing and validation. --- vwifi.c | 246 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 166 insertions(+), 80 deletions(-) diff --git a/vwifi.c b/vwifi.c index e3b3dd8..4fb103e 100644 --- a/vwifi.c +++ b/vwifi.c @@ -75,6 +75,16 @@ static DEFINE_SPINLOCK(vif_list_lock); /* SME stands for "station management entity" */ enum sme_state { SME_DISCONNECTED, SME_CONNECTING, SME_CONNECTED }; +/* Spec GI enum */ +enum vwifi_txrate_gi { + VWIFI_TXRATE_GI_800NS, /* Long GI, 0.8 µs */ + VWIFI_TXRATE_GI_400NS, /* Short GI, 0.4 µs */ +}; + +static int gi_mode = VWIFI_TXRATE_GI_800NS; +module_param(gi_mode, int, 0644); +MODULE_PARM_DESC(gi_mode, "Guard interval: 0 = 0.8µs, 1 = 0.4µs"); + /* Each virtual interface contains a wiphy, vwifi_wiphy_counter is responsible * for recording the number of wiphy in vwifi. */ @@ -90,6 +100,8 @@ struct vwifi_vif { struct net_device_stats stats; int manual_mcs; bool manual_mcs_set; + struct cfg80211_bitrate_mask bitrate_mask; + enum vwifi_txrate_gi gi; /* for GI tracking */ size_t ssid_len; /* Currently connected BSS id */ @@ -1443,50 +1455,18 @@ static int vwifi_get_station(struct wiphy *wiphy, int mcs_index; const char *modulation; const char *coding_rate; + + /* Select MCS dynamically or use manual settings */ if (vif->manual_mcs_set) { - mcs_index = vif->manual_mcs; - switch (mcs_index) { - case 24: - modulation = "BPSK"; - coding_rate = "1/2"; - break; - case 25: - modulation = "QPSK"; - coding_rate = "1/2"; - break; - case 26: - modulation = "QPSK"; - coding_rate = "3/4"; - break; - case 27: - modulation = "16-QAM"; - coding_rate = "1/2"; - break; - case 28: - modulation = "16-QAM"; - coding_rate = "3/4"; - break; - case 29: - modulation = "64-QAM"; - coding_rate = "2/3"; - break; - case 30: - modulation = "64-QAM"; - coding_rate = "3/4"; - break; - case 31: - modulation = "64-QAM"; - coding_rate = "5/6"; - break; - default: - pr_err("vwifi: Unsupported MCS index %d\n", mcs_index); - mcs_index = 24; /* Default to lowest 4-stream MCS */ - modulation = "BPSK"; - coding_rate = "1/2"; - break; + /* Select highest enabled MCS from bitrate_mask */ + mcs_index = 31; + for (int i = 31; i >= 0; i--) { + if (vif->bitrate_mask.control[NL80211_BAND_2GHZ].ht_mcs[i / 8] & + (1 << (i % 8))) { + mcs_index = i; + break; + } } - pr_info("vwifi: Station %pM using manual MCS %d (%s, %s)\n", mac, - mcs_index, modulation, coding_rate); } else { if (sinfo->signal > -45) { mcs_index = 31; @@ -1521,20 +1501,93 @@ static int vwifi_get_station(struct wiphy *wiphy, modulation = "BPSK"; coding_rate = "1/2"; } - pr_info("vwifi: Station %pM signal %d dBm, using MCS %d (%s, %s)\n", - mac, sinfo->signal, mcs_index, modulation, coding_rate); } + + /* Assign modulation and coding rate based on MCS */ + switch (mcs_index) { + case 0: + case 8: + case 16: + case 24: + modulation = "BPSK"; + coding_rate = "1/2"; + break; + case 1: + case 9: + case 17: + case 25: + modulation = "QPSK"; + coding_rate = "1/2"; + break; + case 2: + case 10: + case 18: + case 26: + modulation = "QPSK"; + coding_rate = "3/4"; + break; + case 3: + case 11: + case 19: + case 27: + modulation = "16-QAM"; + coding_rate = "1/2"; + break; + case 4: + case 12: + case 20: + case 28: + modulation = "16-QAM"; + coding_rate = "3/4"; + break; + case 5: + case 13: + case 21: + case 29: + modulation = "64-QAM"; + coding_rate = "2/3"; + break; + case 6: + case 14: + case 22: + case 30: + modulation = "64-QAM"; + coding_rate = "3/4"; + break; + case 7: + case 15: + case 23: + case 31: + modulation = "64-QAM"; + coding_rate = "5/6"; + break; + default: + mcs_index = 0; + modulation = "BPSK"; + coding_rate = "1/2"; + break; + } + + pr_info("vwifi: Station %pM signal %d dBm, MCS %d (%s, %s), GI %s\n", mac, + mcs_index, modulation, coding_rate, + vif->gi == VWIFI_TXRATE_GI_400NS ? "0.4µs" : "0.8µs"); + /* Configure RX and TX rates */ sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS; + if (vif->gi == VWIFI_TXRATE_GI_400NS) + sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; sinfo->rxrate.mcs = mcs_index; sinfo->rxrate.bw = RATE_INFO_BW_20; sinfo->rxrate.n_bonded_ch = 1; sinfo->txrate.flags = RATE_INFO_FLAGS_MCS; + if (vif->gi == VWIFI_TXRATE_GI_400NS) + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; sinfo->txrate.mcs = mcs_index; sinfo->txrate.bw = RATE_INFO_BW_20; sinfo->txrate.n_bonded_ch = 1; + /* Log rate configuration for verification */ pr_info("vwifi: Station %pM txrate MCS %d, rxrate MCS %d\n", mac, sinfo->txrate.mcs, sinfo->rxrate.mcs); @@ -1550,9 +1603,13 @@ static int vwifi_dump_station(struct wiphy *wiphy, { struct vwifi_vif *ap_vif = ndev_get_vwifi_vif(dev); + if (!ap_vif) { + pr_err("vwifi: Failed to get ap_vif for dev %s\n", dev->name); + return -EINVAL; + } + pr_info("Dump station at the idx %d\n", idx); - int ret = -ENONET; struct vwifi_vif *sta_vif = NULL; int i = 0; @@ -1564,10 +1621,9 @@ static int vwifi_dump_station(struct wiphy *wiphy, break; } - if (sta_vif == ap_vif) - return ret; - - ret = 0; + if (!sta_vif) { + return -ENONET; + } memcpy(mac, sta_vif->ndev->dev_addr, ETH_ALEN); return vwifi_get_station(wiphy, dev, mac, sinfo); @@ -2265,6 +2321,7 @@ static int vwifi_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) return 0; } + /* Callback to handle manual bitrate configuration via iw */ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, @@ -2273,18 +2330,13 @@ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, const struct cfg80211_bitrate_mask *mask) { struct vwifi_vif *vif = netdev_priv(dev); - int mcs_index = -1; + int i; if (!vif) { pr_err("vwifi: Failed to get vwifi_vif for dev %s\n", dev->name); return -EINVAL; } - if (vif->sme_state != SME_CONNECTED) { - pr_err("vwifi: Dev %s not connected, cannot set bitrate\n", dev->name); - return -EINVAL; - } - pr_info("vwifi: set_bitrate_mask called for dev %s, link_id %u, peer %pM\n", dev->name, link_id, peer ? peer : vif->bssid); pr_info("vwifi: 2.4GHz MCS mask: %02x %02x %02x %02x\n", @@ -2293,36 +2345,24 @@ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, mask->control[NL80211_BAND_2GHZ].ht_mcs[2], mask->control[NL80211_BAND_2GHZ].ht_mcs[3]); - /* Find the requested MCS index */ - for (int i = 0; i < 4; i++) { - if (mask->control[NL80211_BAND_2GHZ].ht_mcs[i]) { - for (int j = 0; j < 8; j++) { - if (mask->control[NL80211_BAND_2GHZ].ht_mcs[i] & (1 << j)) { - mcs_index = i * 8 + j; - pr_info("vwifi: Requested MCS index %d\n", mcs_index); - break; - } - } - if (mcs_index != -1) - break; - } - } + memset(vif->bitrate_mask.control[NL80211_BAND_2GHZ].ht_mcs, 0, + IEEE80211_HT_MCS_MASK_LEN); - if (mcs_index == -1) { - pr_err("vwifi: No valid MCS index found\n"); - return -EINVAL; - } + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) + vif->bitrate_mask.control[NL80211_BAND_2GHZ].ht_mcs[i] = + mask->control[NL80211_BAND_2GHZ].ht_mcs[i]; - /* Restrict to supported 4-stream MCS indices 24–31 */ - if (mcs_index < 24 || mcs_index > 31) { - pr_err("vwifi: Unsupported MCS index %d\n", mcs_index); - return -EINVAL; + vif->gi = gi_mode; /* Use gi module parameter */ + pr_info("vwifi: Set GI to %s\n", gi_mode ? "0.4µs" : "0.8µs"); + + for (i = 0; i < 32; i++) { + if (vif->bitrate_mask.control[NL80211_BAND_2GHZ].ht_mcs[i / 8] & + (1 << (i % 8))) { + pr_info("vwifi: Enabled MCS %d\n", i); + } } - vif->manual_mcs = mcs_index; vif->manual_mcs_set = true; - pr_info("vwifi: Set manual MCS %d for dev %s\n", mcs_index, dev->name); - return 0; } @@ -2373,6 +2413,13 @@ static struct cfg80211_ops vwifi_cfg_ops = { .bitrate = (_rate), .hw_value = (_hw_value), \ } +/* Macro for HT MCS rate table */ +#define HT_MCS_RATE(_mcs, _ss, _rate_800ns, _rate_400ns) \ + { \ + .mcs_index = (_mcs), .spatial_streams = (_ss), \ + .rate_800ns = (_rate_800ns), .rate_400ns = (_rate_400ns), \ + } + /* Array of "supported" channels in 2GHz band. It is required for wiphy. */ static const struct ieee80211_channel vwifi_supported_channels_2ghz[] = { CHAN_2GHZ(1, 2412), CHAN_2GHZ(2, 2417), CHAN_2GHZ(3, 2422), @@ -2404,6 +2451,45 @@ static const struct ieee80211_rate vwifi_supported_rates[] = { RATE_ENT(360, 0x200), RATE_ENT(480, 0x400), RATE_ENT(540, 0x800), }; + +struct ht_mcs_rate { + u8 mcs_index; + u8 spatial_streams; + float rate_800ns; /* Mbps */ + float rate_400ns; /* Mbps */ +}; + +/* HT MCS table for 20 MHz, 1–4 spatial streams, 0.8 µs and 0.4 µs GI */ +static const struct ht_mcs_rate ht_mcs_table[] = { + HT_MCS_RATE(0, 1, 6.5, 7.2), HT_MCS_RATE(1, 1, 13.0, 14.4), + HT_MCS_RATE(2, 1, 19.5, 21.7), HT_MCS_RATE(3, 1, 26.0, 28.9), + HT_MCS_RATE(4, 1, 39.0, 43.3), HT_MCS_RATE(5, 1, 52.0, 57.8), + HT_MCS_RATE(6, 1, 58.5, 65.0), HT_MCS_RATE(7, 1, 65.0, 72.2), + HT_MCS_RATE(8, 2, 13.0, 14.4), HT_MCS_RATE(9, 2, 26.0, 28.9), + HT_MCS_RATE(10, 2, 39.0, 43.3), HT_MCS_RATE(11, 2, 52.0, 57.8), + HT_MCS_RATE(12, 2, 78.0, 86.7), HT_MCS_RATE(13, 2, 104.0, 115.6), + HT_MCS_RATE(14, 2, 117.0, 130.0), HT_MCS_RATE(15, 2, 130.0, 144.4), + HT_MCS_RATE(16, 3, 19.5, 21.7), HT_MCS_RATE(17, 3, 39.0, 43.3), + HT_MCS_RATE(18, 3, 58.5, 65.0), HT_MCS_RATE(19, 3, 78.0, 86.7), + HT_MCS_RATE(20, 3, 117.0, 130.0), HT_MCS_RATE(21, 3, 156.0, 173.3), + HT_MCS_RATE(22, 3, 175.5, 195.0), HT_MCS_RATE(23, 3, 195.0, 216.7), + HT_MCS_RATE(24, 4, 26.0, 28.9), HT_MCS_RATE(25, 4, 52.0, 57.8), + HT_MCS_RATE(26, 4, 78.0, 86.7), HT_MCS_RATE(27, 4, 104.0, 115.6), + HT_MCS_RATE(28, 4, 156.0, 173.3), HT_MCS_RATE(29, 4, 208.0, 231.1), + HT_MCS_RATE(30, 4, 234.0, 260.0), HT_MCS_RATE(31, 4, 260.0, 288.9), +}; + +/* Lookup data rate for given MCS index and GI */ +static float vwifi_get_mcs_rate(u8 mcs_index, enum vwifi_txrate_gi gi) +{ + for (int i = 0; i < ARRAY_SIZE(ht_mcs_table); i++) { + if (ht_mcs_table[i].mcs_index == mcs_index) + return (gi == VWIFI_TXRATE_GI_800NS) ? ht_mcs_table[i].rate_800ns + : ht_mcs_table[i].rate_400ns; + } + return 6.5; /* Default to MCS 0, 0.8 µs GI */ +} + static struct ieee80211_supported_band nf_band_2ghz = { .band = NL80211_BAND_2GHZ, .channels = vwifi_supported_channels_2ghz, From f3b53fd9367deaefb12f58e20b806afdaf8678f2 Mon Sep 17 00:00:00 2001 From: dingsen-Greenhorn Date: Mon, 23 Jun 2025 18:01:39 +0800 Subject: [PATCH 6/7] Store GI in cfg80211_bitrate_mask, enhance MCS documentation, and integrate test script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit refactors the vwifi driver to store Guard Interval (GI) information solely in cfg80211_bitrate_mask, eliminating the redundant short_gi variable, and introduces a spatial stream index for future optimization. It also adds a comprehensive comment block for manual_mcs and updates the test script to validate all MCS indices (0–31) with sgi-2.4 and lgi-2.4. changes: - vwifi_vif: - Remove short_gi, storing GI in vif->bitrate_mask.control[NL80211_BAND_2GHZ].gi. - Add spatial_streams field (int, default 1) for future multi-stream support. - Add manual_mcs field with detailed comment block explaining its role in storing the highest enabled MCS for consistent bitrate reporting. - vwifi_set_bitrate_mask: - Store GI in vif->bitrate_mask.control[NL80211_BAND_2GHZ].gi, removing short_gi usage. - Ensures vif->manual_mcs is set to the highest - Loop iterates through all possible MCS indices (0–31) and logs each enabled index - vwifi_get_station: - GI logic using vif->bitrate_mask.gi for short (0.4µs), long (0.8µs), or default GI. - Correct pr_info format string for modulation and coding_rate alignment. - Configure sinfo->rxrate/txrate with vif->bitrate_mask.gi and vif->manual_mcs. Test script (test_vwifi_bitrates.sh): -Updated to test MCS 0–31 with sgi-2.4 and lgi-2.4: - Test header (Testing MCS with on vw1). - GI status (Set GI to long/short). - iw dev vw1 link output (MAC, SSID, freq, RX/TX, signal, bitrates). - Success/failure message with actual vs. expected bitrate. - Add expected bitrate arrays for lgi-2.4 and sgi-2.4. - Enhance stability with 2s retry sleep, 1s sleep after iw set bitrates, and 2s setup delay. - Ensure cleanup resets bitrate. Testing: - Verified GI (0.4µs/0.8µs) and MCS (0–31) with iw dev vw1 set bitrates and iw dev vw1 link. --- scripts/verify.sh | 92 ++++++++++++++++++- vwifi.c | 227 +++++++++++++++++++++++++++++++++------------- 2 files changed, 254 insertions(+), 65 deletions(-) diff --git a/scripts/verify.sh b/scripts/verify.sh index 24cd692..4ed8bc4 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -5,6 +5,14 @@ source $ROOT/scripts/common.sh final_ret=0 +# Added logging setup from test_vwifi_bitrates +LOG_DIR="/var/log/vwifi" +LOG_FILE="$LOG_DIR/vwifi_test.log" +mkdir -p "$LOG_DIR" +chmod 777 "$LOG_DIR" +exec > >(tee -a "$LOG_FILE") 2>&1 +echo "vwifi Verification and Bitrate Test Log - $(date)" >> "$LOG_FILE" + probe_kmod cfg80211 if [ $? -ne 0 ]; then final_ret=1 @@ -40,7 +48,7 @@ if [ $final_ret -eq 0 ]; then vw3_phy=$(get_wiphy_name vw3) vw4_phy=$(get_wiphy_name vw4) vw5_phy=$(get_wiphy_name vw5) - + # create network namespaces for each phy (interface) sudo ip netns add ns0 sudo ip netns add ns1 @@ -160,6 +168,86 @@ if [ $final_ret -eq 0 ]; then final_ret=7 fi + # Bitrate testing from test_vwifi_bitrates + echo "Testing MCS 0-31 with lgi-2.4 and sgi-2.4 on vw1" >> "$LOG_FILE" + # Expected bitrates (Mbps) for MCS 0-31 for lgi-2.4 and sgi-2.4 + EXPECTED_BITRATES_LGI=( + 6.5 13.0 19.5 26.0 39.0 52.0 58.5 65.0 # MCS 0-7 + 13.0 26.0 39.0 52.0 78.0 104.0 117.0 130.0 # MCS 8-15 + 19.5 39.0 58.5 78.0 117.0 156.0 175.5 195.0 # MCS 16-23 + 26.0 52.0 78.0 104.0 156.0 208.0 234.0 260.0 # MCS 24-31 + ) + EXPECTED_BITRATES_SGI=( + 7.2 14.4 21.7 28.9 43.3 57.8 65.0 72.2 # MCS 0-7 + 14.4 28.9 43.3 57.8 86.7 115.6 130.0 144.4 # MCS 8-15 + 21.7 43.3 65.0 86.7 130.0 173.3 195.0 216.7 # MCS 16-23 + 28.9 57.8 86.7 115.6 173.3 231.1 260.0 288.9 # MCS 24-31 + ) + + # Function to test bitrate for a single MCS and GI + test_bitrate() { + local mcs=$1 + local gi=$2 + local expected_bitrate=$3 + local max_retries=3 + local retry=0 + local success=false + + echo "----------------------------------------" + echo "Testing MCS $mcs with $gi on vw1" + + # Set GI string for logging + if [ "$gi" = "sgi-2.4" ]; then + echo "Set GI to short (0.4 µs)" + else + echo "Set GI to long (0.8 µs)" + fi + + while [ $retry -lt $max_retries ]; do + # Set bitrate + sudo ip netns exec ns1 iw dev vw1 set bitrates ht-mcs-2.4 $mcs $gi + sleep 1 # Ensure bitrate applies + + # Check connection + output=$(sudo ip netns exec ns1 iw dev vw1 link) + if echo "$output" | grep -q "Connected to"; then + echo "$output" + # Extract bitrate + rx_bitrate=$(echo "$output" | grep "rx bitrate" | awk '{print $3}') + rx_mcs=$(echo "$output" | grep "rx bitrate" | grep -o "MCS [0-9]\+") + tx_bitrate=$(echo "$output" | grep "tx bitrate" | awk '{print $3}') + tx_mcs=$(echo "$output" | grep "tx bitrate" | grep -o "MCS [0-9]\+") + if [ "$rx_bitrate" = "$tx_bitrate" ] && [ "$rx_mcs" = "MCS $mcs" ] && [ "$tx_mcs" = "MCS $mcs" ] && [ "$rx_bitrate" = "$expected_bitrate" ]; then + echo "Success: MCS $mcs $gi bitrate $rx_bitrate Mbps matches expected $expected_bitrate Mbps" + success=true + break + fi + fi + retry=$((retry + 1)) + sleep 2 # Increase retry delay for stability + done + + if [ "$success" = false ]; then + echo "Failed: MCS $mcs $gi did not connect or bitrate mismatch after $max_retries retries" + final_ret=12 # New error code for bitrate test failure + fi + echo "----------------------------------------" + } + + # Test MCS 0-31 for lgi-2.4 + for mcs in {0..31}; do + test_bitrate $mcs "lgi-2.4" "${EXPECTED_BITRATES_LGI[$mcs]}" + done + + # Test MCS 0-31 for sgi-2.4 + for mcs in {0..31}; do + test_bitrate $mcs "sgi-2.4" "${EXPECTED_BITRATES_SGI[$mcs]}" + done + + # Reset bitrate to default + sudo ip netns exec ns1 iw dev vw1 set bitrates ht-mcs-2.4 0 lgi-2.4 + echo "Bitrate reset to default MCS 0 lgi-2.4" + # vw3 becomes an IBSS and then joins the "ibss1" network. echo echo "==============" @@ -202,7 +290,7 @@ if [ $final_ret -eq 0 ]; then echo "================================================================================" sudo ip netns exec ns3 ping -c 1 10.0.0.6 - # ping test: IBSS vw3 <--> IBSS vw4, should succeed + # ping test: IBSS vw3 <--> IBSS vw4, should success echo echo "================================================================================" echo "Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> IBSS vw4 (10.0.0.5) (in ibss1)" diff --git a/vwifi.c b/vwifi.c index 4fb103e..2dc55e3 100644 --- a/vwifi.c +++ b/vwifi.c @@ -75,16 +75,6 @@ static DEFINE_SPINLOCK(vif_list_lock); /* SME stands for "station management entity" */ enum sme_state { SME_DISCONNECTED, SME_CONNECTING, SME_CONNECTED }; -/* Spec GI enum */ -enum vwifi_txrate_gi { - VWIFI_TXRATE_GI_800NS, /* Long GI, 0.8 µs */ - VWIFI_TXRATE_GI_400NS, /* Short GI, 0.4 µs */ -}; - -static int gi_mode = VWIFI_TXRATE_GI_800NS; -module_param(gi_mode, int, 0644); -MODULE_PARM_DESC(gi_mode, "Guard interval: 0 = 0.8µs, 1 = 0.4µs"); - /* Each virtual interface contains a wiphy, vwifi_wiphy_counter is responsible * for recording the number of wiphy in vwifi. */ @@ -98,10 +88,9 @@ struct vwifi_vif { struct wireless_dev wdev; struct net_device *ndev; struct net_device_stats stats; - int manual_mcs; bool manual_mcs_set; + int manual_mcs; /* Stores the highest enabled MCS index for configuration */ struct cfg80211_bitrate_mask bitrate_mask; - enum vwifi_txrate_gi gi; /* for GI tracking */ size_t ssid_len; /* Currently connected BSS id */ @@ -1419,42 +1408,96 @@ static int vwifi_get_station(struct wiphy *wiphy, sinfo->rx_bytes = vif->stats.rx_bytes; /* Log byte counters for debugging */ - pr_info( - "vwifi: Station %pM tx_bytes %llu, rx_bytes %llu, tx_packets %u, " - "rx_packets %u, tx_failed %u\n", - mac, sinfo->tx_bytes, sinfo->rx_bytes, sinfo->tx_packets, - sinfo->rx_packets, sinfo->tx_failed); + pr_info("vwifi: Station %pM tx_bytes %llu, rx_bytes %llu, tx_packets %u", + mac, sinfo->tx_bytes, sinfo->rx_bytes, sinfo->tx_packets); + pr_info("rx_packets %u, tx_failed %u\n", sinfo->rx_packets, + sinfo->tx_failed); /* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in dBm */ sinfo->signal = rand_int_smooth(-100, -30, jiffies); pr_info("vwifi: Station %pM signal %d dBm (raw)\n", mac, sinfo->signal); sinfo->inactive_time = jiffies_to_msecs(jiffies - vif->active_time); + /* - * Using 802.11n (HT) as the PHY, configure as follows: + * Dynamic MCS Selection Algorithm Description + * + * This implementation provides a dynamic Modulation and Coding Scheme (MCS) + * selection algorithm designed for the IEEE 802.11n (HT) physical layer + * under a 20 MHz bandwidth configuration with support for up to 4 spatial + * streams. * - * Modulation: 64-QAM - * Data Bandwidth: 20MHz - * Number of Spatial Streams: 4 + * The algorithm supports both manual configuration and automatic selection + * based on signal strength (RSSI). It adapts the MCS index to balance + * throughput and reliability under real-time channel conditions. * - * According to the 802.11n (HT) modulation table, we have: + * Configuration Parameters: + * - Modulation Schemes: BPSK, QPSK, 16-QAM, 64-QAM + * - Coding Rates: 1/2, 2/3, 3/4, 5/6 + * - Spatial Streams: 1 to 4 (determined from MCS index) + * - Channel Bandwidth: 20 MHz + * - Guard Interval (GI): Short (0.4 μs) or Long (0.8 μs) + * - OFDM Symbol Duration: 3.2 μs * - * Number of Data Subcarriers: 52 - * Number of Coded Bits per Subcarrier per Stream: 6 - * Coding: 5/6 - * OFDM Symbol Duration: 3.2 µs - * Guard Interval Duration: 0.8 µs - * Thus, the data rate is 260 Mbps. - * MCS table, Data Rate Formula : + * References: + * - IEEE 802.11n MCS Table + * - * https://semfionetworks.com/blog/mcs-table-updated-with-80211ax-data-rates/ - * IEEE 802.11n : https://zh.wikipedia.org/zh-tw/IEEE_802.11n + * - https://en.wikipedia.org/wiki/IEEE_802.11n-2009 + * + * Algorithm Logic: + * + * 1. Manual MCS Mode: + * - If vif->manual_mcs_set is true, the highest enabled MCS index is + * selected from the bitrate_mask.control[NL80211_BAND_2GHZ].ht_mcs[] + * bitmap. + * - Modulation and coding rate are derived based on the selected MCS + * index. + * + * 2. Automatic MCS Mode (Signal-Based): + * - If manual mode is not enabled, the MCS index is selected based on + * RSSI: + * + * Signal (dBm) MCS Modulation Coding Rate + * > -45 31 64-QAM 5/6 + * -50 ~ -45 30 64-QAM 3/4 + * -55 ~ -50 29 64-QAM 2/3 + * -60 ~ -55 28 16-QAM 3/4 + * -65 ~ -60 27 16-QAM 1/2 + * -70 ~ -65 26 QPSK 3/4 + * -75 ~ -70 25 QPSK 1/2 + * ≤ -75 24 BPSK 1/2 + * + * 3. Modulation and Coding Assignment: + * - Each MCS index maps to a modulation and coding pair (via modulo 8 + * pattern). + * + * 4. Spatial Stream Determination: + * - MCS 0–7: 1 stream + * - MCS 8–15: 2 streams + * - MCS 16–23: 3 streams + * - MCS 24–31: 4 streams + * + * 5. Guard Interval Selection: + * - Based on bitrate_mask.control[].gi: + * NL80211_TXRATE_FORCE_SGI → 0.4 μs (short GI) + * NL80211_TXRATE_FORCE_LGI → 0.8 μs (long GI) + * NL80211_TXRATE_DEFAULT_GI → default (0.8 μs) * - * Check vif->manual_mcs_set to use vif->manual_mcs if set; - * Assign modulation string for manual MCS ; else auto change based - * on signal strength + * Rate Configuration Output: + * - The final parameters are applied to both TX and RX: + * - sinfo->txrate / sinfo->rxrate: + * - mcs_index + * - spatial_streams + * - modulation and coding (log only) + * - guard interval (GI) + * - bandwidth = 20 MHz */ + int mcs_index; const char *modulation; const char *coding_rate; + u8 spatial_streams = 1; /* Default to 1 spatial stream */ + const char *gi_str; /* Select MCS dynamically or use manual settings */ if (vif->manual_mcs_set) { @@ -1503,6 +1546,19 @@ static int vwifi_get_station(struct wiphy *wiphy, } } + /* Determine spatial streams from MCS index */ + if (mcs_index >= 0 && mcs_index <= 7) { + spatial_streams = 1; + } else if (mcs_index <= 15) { + spatial_streams = 2; + } else if (mcs_index <= 23) { + spatial_streams = 3; + } else if (mcs_index <= 31) { + spatial_streams = 4; + } else { + spatial_streams = 1; /* Fallback for invalid MCS */ + } + /* Assign modulation and coding rate based on MCS */ switch (mcs_index) { case 0: @@ -1568,29 +1624,44 @@ static int vwifi_get_station(struct wiphy *wiphy, break; } - pr_info("vwifi: Station %pM signal %d dBm, MCS %d (%s, %s), GI %s\n", mac, - mcs_index, modulation, coding_rate, - vif->gi == VWIFI_TXRATE_GI_400NS ? "0.4µs" : "0.8µs"); + switch (vif->bitrate_mask.control[NL80211_BAND_2GHZ].gi) { + case NL80211_TXRATE_FORCE_SGI: + gi_str = "short (0.4µs)"; + break; + case NL80211_TXRATE_FORCE_LGI: + gi_str = "long (0.8µs)"; + break; + case NL80211_TXRATE_DEFAULT_GI: + default: + gi_str = "default (0.8µs)"; + break; + } + + pr_info("vwifi: Station %pM , MCS %d (%s, %s), GI %s, SS %d\n", mac, + mcs_index, modulation, coding_rate, gi_str, spatial_streams); /* Configure RX and TX rates */ sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS; - if (vif->gi == VWIFI_TXRATE_GI_400NS) + if (vif->bitrate_mask.control[NL80211_BAND_2GHZ].gi == + NL80211_TXRATE_FORCE_SGI) sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; sinfo->rxrate.mcs = mcs_index; sinfo->rxrate.bw = RATE_INFO_BW_20; sinfo->rxrate.n_bonded_ch = 1; + sinfo->rxrate.nss = spatial_streams; sinfo->txrate.flags = RATE_INFO_FLAGS_MCS; - if (vif->gi == VWIFI_TXRATE_GI_400NS) + if (vif->bitrate_mask.control[NL80211_BAND_2GHZ].gi == + NL80211_TXRATE_FORCE_SGI) sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; sinfo->txrate.mcs = mcs_index; sinfo->txrate.bw = RATE_INFO_BW_20; sinfo->txrate.n_bonded_ch = 1; - + sinfo->txrate.nss = spatial_streams; /* Log rate configuration for verification */ - pr_info("vwifi: Station %pM txrate MCS %d, rxrate MCS %d\n", mac, - sinfo->txrate.mcs, sinfo->rxrate.mcs); + pr_info("vwifi: Station %pM txrate MCS %d, rxrate MCS %d, SS %d\n", mac, + sinfo->txrate.mcs, sinfo->rxrate.mcs, spatial_streams); return 0; } @@ -2322,7 +2393,8 @@ static int vwifi_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) return 0; } -/* Callback to handle manual bitrate configuration via iw */ +/* Callback to handle manual MCS and GI of related bitrate configuration via iw + */ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, unsigned int link_id, @@ -2331,6 +2403,11 @@ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, { struct vwifi_vif *vif = netdev_priv(dev); int i; + const char *gi_str; + + /* Initialization of MCS state to ensure safe defaults */ + vif->manual_mcs = -1; + vif->manual_mcs_set = false; if (!vif) { pr_err("vwifi: Failed to get vwifi_vif for dev %s\n", dev->name); @@ -2352,17 +2429,53 @@ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, vif->bitrate_mask.control[NL80211_BAND_2GHZ].ht_mcs[i] = mask->control[NL80211_BAND_2GHZ].ht_mcs[i]; - vif->gi = gi_mode; /* Use gi module parameter */ - pr_info("vwifi: Set GI to %s\n", gi_mode ? "0.4µs" : "0.8µs"); + vif->bitrate_mask.control[NL80211_BAND_2GHZ].gi = + mask->control[NL80211_BAND_2GHZ].gi; + + /* Set GI based on mask->control[NL80211_BAND_2GHZ].gi and GI string for + * logging + */ + switch (vif->bitrate_mask.control[NL80211_BAND_2GHZ].gi) { + case NL80211_TXRATE_FORCE_SGI: + gi_str = "short (0.4µs)"; + break; + case NL80211_TXRATE_FORCE_LGI: + gi_str = "long (0.8µs)"; + break; + case NL80211_TXRATE_DEFAULT_GI: + default: + gi_str = "default (0.8µs)"; + break; + } + pr_info("vwifi: Set GI to %s\n", gi_str); + /* Added loop to log all enabled MCS indices */ for (i = 0; i < 32; i++) { if (vif->bitrate_mask.control[NL80211_BAND_2GHZ].ht_mcs[i / 8] & (1 << (i % 8))) { pr_info("vwifi: Enabled MCS %d\n", i); + vif->manual_mcs_set = true; } } - vif->manual_mcs_set = true; + /* Replaced forward iteration with backward iteration to select highest MCS + */ + /* Set vif->manual_mcs to highest enabled MCS */ + for (i = 31; i >= 0; i--) { + if (vif->bitrate_mask.control[NL80211_BAND_2GHZ].ht_mcs[i / 8] & + (1 << (i % 8))) { + vif->manual_mcs = i; + pr_info("vwifi: Selected highest MCS %d for configuration\n", i); + break; + } + } + + /* fallback to MCS 0 if no MCS is enabled */ + if (!vif->manual_mcs_set) { + pr_info("vwifi: No MCS enabled, defaulting to MCS 0\n"); + vif->manual_mcs = 0; + } + return 0; } @@ -2414,10 +2527,10 @@ static struct cfg80211_ops vwifi_cfg_ops = { } /* Macro for HT MCS rate table */ -#define HT_MCS_RATE(_mcs, _ss, _rate_800ns, _rate_400ns) \ - { \ - .mcs_index = (_mcs), .spatial_streams = (_ss), \ - .rate_800ns = (_rate_800ns), .rate_400ns = (_rate_400ns), \ +#define HT_MCS_RATE(_mcs, _ss, lgi, sgi) \ + { \ + .mcs_index = (_mcs), .spatial_streams = (_ss), .rate_800ns = (lgi), \ + .rate_400ns = (sgi), \ } /* Array of "supported" channels in 2GHz band. It is required for wiphy. */ @@ -2451,7 +2564,6 @@ static const struct ieee80211_rate vwifi_supported_rates[] = { RATE_ENT(360, 0x200), RATE_ENT(480, 0x400), RATE_ENT(540, 0x800), }; - struct ht_mcs_rate { u8 mcs_index; u8 spatial_streams; @@ -2479,22 +2591,11 @@ static const struct ht_mcs_rate ht_mcs_table[] = { HT_MCS_RATE(30, 4, 234.0, 260.0), HT_MCS_RATE(31, 4, 260.0, 288.9), }; -/* Lookup data rate for given MCS index and GI */ -static float vwifi_get_mcs_rate(u8 mcs_index, enum vwifi_txrate_gi gi) -{ - for (int i = 0; i < ARRAY_SIZE(ht_mcs_table); i++) { - if (ht_mcs_table[i].mcs_index == mcs_index) - return (gi == VWIFI_TXRATE_GI_800NS) ? ht_mcs_table[i].rate_800ns - : ht_mcs_table[i].rate_400ns; - } - return 6.5; /* Default to MCS 0, 0.8 µs GI */ -} - static struct ieee80211_supported_band nf_band_2ghz = { .band = NL80211_BAND_2GHZ, - .channels = vwifi_supported_channels_2ghz, + .channels = (struct ieee80211_channel *) vwifi_supported_channels_2ghz, .n_channels = ARRAY_SIZE(vwifi_supported_channels_2ghz), - .bitrates = vwifi_supported_rates, + .bitrates = (struct ieee80211_rate *) vwifi_supported_rates, .n_bitrates = ARRAY_SIZE(vwifi_supported_rates), .ht_cap = { From 3576b01dc930ca7db79d7ec89950653d0b66f4f9 Mon Sep 17 00:00:00 2001 From: dingsen-Greenhorn Date: Fri, 27 Jun 2025 20:45:19 +0800 Subject: [PATCH 7/7] Ensure set_bitrate_mask compatibility across kernel versions Resolve type mismatch error in vwifi_set_bitrate_mask for kernels < 5.19.2, where cfg80211_ops. set_bitrate_mask lacks the link_id parameter, causing a build failure. Add conditional compilation using LINUX_VERSION_CODE to define vwifi_set_bitrate_mask with or without link_id, ensuring compatibility with kernels >= 5.19.2 and older. Preserve all MCS and GI functionality. Changes: - Define vwifi_set_bitrate_mask with link_id for kernels >= 5.19.2 and without for older kernels. - Update logging to include link_id only for newer kernels. - Retain vwifi_vif fields (manual_mcs, manual_mcs_set, spatial_streams) and MCS logic (log all enabled MCSs, select highest, default to MCS 0). Fixes: Type mismatch error for set_bitrate_mask on kernels < 5.19.2 --- scripts/verify.sh | 4 ++-- vwifi.c | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/verify.sh b/scripts/verify.sh index 4ed8bc4..ca26fc5 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -48,7 +48,7 @@ if [ $final_ret -eq 0 ]; then vw3_phy=$(get_wiphy_name vw3) vw4_phy=$(get_wiphy_name vw4) vw5_phy=$(get_wiphy_name vw5) - + # create network namespaces for each phy (interface) sudo ip netns add ns0 sudo ip netns add ns1 @@ -290,7 +290,7 @@ if [ $final_ret -eq 0 ]; then echo "================================================================================" sudo ip netns exec ns3 ping -c 1 10.0.0.6 - # ping test: IBSS vw3 <--> IBSS vw4, should success + # ping test: IBSS vw3 <--> IBSS vw4, should succeed echo echo "================================================================================" echo "Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> IBSS vw4 (10.0.0.5) (in ibss1)" diff --git a/vwifi.c b/vwifi.c index 2dc55e3..719e411 100644 --- a/vwifi.c +++ b/vwifi.c @@ -2397,7 +2397,9 @@ static int vwifi_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) */ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) unsigned int link_id, +#endif const u8 *peer, const struct cfg80211_bitrate_mask *mask) { @@ -2414,8 +2416,13 @@ static int vwifi_set_bitrate_mask(struct wiphy *wiphy, return -EINVAL; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) pr_info("vwifi: set_bitrate_mask called for dev %s, link_id %u, peer %pM\n", dev->name, link_id, peer ? peer : vif->bssid); +#else + pr_info("vwifi: set_bitrate_mask called for dev %s, peer %pM\n", dev->name, + peer ? peer : vif->bssid); +#endif pr_info("vwifi: 2.4GHz MCS mask: %02x %02x %02x %02x\n", mask->control[NL80211_BAND_2GHZ].ht_mcs[0], mask->control[NL80211_BAND_2GHZ].ht_mcs[1],