Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions config/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,77 @@
"vht_oper_centr_freq_seg0_idx={VHT_FREQ_IDX}"
]
},
"ax": {
"settings": [
"# Basic settings",
"hw_mode=a",
"# Enable 802.11n/ac",
"ieee80211d=1",
"ieee80211n=1",
"ieee80211ac=1",
"# Enable 802.11ax",
"ieee80211ax=1",
"# High efficiency capabilities",
"he_su_beamformer=1",
"he_su_beamformee=1",
"he_mu_beamformer=1",
"# BSS color for spatial reuse, value 1-63",
"he_bss_color=1",
"he_oper_chwidth=1",
"ht_capab=[HT40+][SHORT-GI-20][SHORT-GI-40]",
"vht_capab=[SHORT-GI-80]",
"he_oper_centr_freq_seg0_idx=155",
"vht_oper_centr_freq_seg0_idx=155",
"wmm_enabled=1"
]
},
"be": {
"settings": [
"# Basic settings",
"hw_mode=a",
"# Enable 802.11n/ac/ax",
"ieee80211n=1",
"ieee80211ac=1",
"ieee80211ax=1",
"vht_oper_chwidth=2 # 160 MHz for VHT",
"vht_oper_centr_freq_seg0_idx=50",
"vht_capab=[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][SHORT-GI-160][TX-STBC-2BY1][RX-STBC-1][SU-BEAMFORMER][SU-BEAMFORMEE][MU-BEAMFORMER][MU-BEAMFORMEE]",
"he_su_beamformer=1",
"he_su_beamformee=1",
"he_mu_beamformer=1",
"he_bss_color=1",
"he_oper_chwidth=2 # 160 MHz for HE",
"he_oper_centr_freq_seg0_idx=50",
"# Enable 802.11be",
"ieee80211be=1",
"# EHT configuration",
"eht_su_beamformer=1",
"eht_su_beamformee=1",
"eht_mu_beamformer=1",
"eht_oper_chwidth=2",
"# EHT operation parameters",
"eht_oper_chwidth=2 # 160 MHz, 0=20, 1=40, 2=80, 3=160, 4=320",
"eht_oper_centr_freq_seg0_idx={VHT_FREQ_IDX}",
"# WMM configuration",
"wmm_enabled=1",
"wmm_ac_bk_cwmin=4",
"wmm_ac_bk_cwmax=10",
"wmm_ac_bk_aifs=7",
"wmm_ac_bk_txop_limit=0",
"wmm_ac_be_aifs=3",
"wmm_ac_be_cwmin=4",
"wmm_ac_be_cwmax=10",
"wmm_ac_be_txop_limit=0",
"wmm_ac_vi_aifs=2",
"wmm_ac_vi_cwmin=3",
"wmm_ac_vi_cwmax=4",
"wmm_ac_vi_txop_limit=94",
"wmm_ac_vo_aifs=2",
"wmm_ac_vo_cwmin=2",
"wmm_ac_vo_cwmax=3",
"wmm_ac_vo_txop_limit=47"
]
},
"g": {
"settings": [
"hw_mode=g",
Expand Down
41 changes: 41 additions & 0 deletions src/RaspAP/Networking/Hotspot/HostapdManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ private function resolveHwMode(array $config): string
if (!empty($config['ieee80211ac']) && strval($config['ieee80211ac']) === '1') {
$selected = 'ac';
}
if (!empty($config['ieee80211ax']) && strval($config['ieee80211ax']) === '1') {
$selected = 'ax';
}
if (!empty($config['ieee80211be']) && strval($config['ieee80211be']) === '1') {
$selected = 'be';
}
if (!empty($config['ieee80211w']) && strval($config['ieee80211w']) === '2') {
$selected = 'w';
}
Expand Down Expand Up @@ -189,10 +195,24 @@ public function buildConfig(array $params, StatusMessage $status): string
$vht_freq_idx = ($params['channel'] < RASPI_5GHZ_CHANNEL_MIN) ? 42 : 155;
$hwMode = isset($params['hw_mode']) ? $params['hw_mode'] : '';

// validate channel width for 802.11ax/be
if (in_array($hwMode, ['ax', 'be'])) {
// for 6GHz band (channels 1-233) wider bandwidths are available
$is6GHz = ($params['channel'] >= 1 && $params['channel'] <= 233);

// for 802.11be, 320 MHz only available on 6GHz
if ($hwMode === 'be' && !$is6GHz && isset($params['eht_oper_chwidth']) && $params['eht_oper_chwidth'] == 4) {
// reset to 160 MHz if 320 MHz requested on non-6GHz
$params['eht_oper_chwidth'] = 2;
}
}

// fetch settings for selected mode
$modeSettings = getDefaultNetOpts('hostapd', 'modes', $hwMode);
$settings = $modeSettings[$hwMode]['settings'] ?? [];

error_log("HostapdManager::buildConfig() -> settings\n" . var_export($settings, true));

if (!empty($settings)) {
foreach ($settings as $line) {
if (!is_string($line)) {
Expand Down Expand Up @@ -457,5 +477,26 @@ private function countHostapdConfigs(): int
return is_array($configs) ? count($configs) : 0;
}

/**
* Gets capabilities for a given IEEE 802.11 mode
*
* @param string $mode
* @return array
*/
public function getModeCapabilities(string $mode): array
{
$capabilities = [
'a' => ['bands' => ['5'], 'max_width' => 20],
'b' => ['bands' => ['2.4'], 'max_width' => 22],
'g' => ['bands' => ['2.4'], 'max_width' => 20],
'n' => ['bands' => ['2.4', '5'], 'max_width' => 40],
'ac' => ['bands' => ['5'], 'max_width' => 160],
'ax' => ['bands' => ['2.4', '5', '6'], 'max_width' => 160],
'be' => ['bands' => ['2.4', '5', '6'], 'max_width' => 320]
];

return $capabilities[$mode] ?? $capabilities['g'];
}

}

74 changes: 72 additions & 2 deletions src/RaspAP/Networking/Hotspot/HotspotService.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ class HotspotService
'b' => '802.11b - 2.4 GHz',
'g' => '802.11g - 2.4 GHz',
'n' => '802.11n - 2.4/5 GHz',
'ac' => '802.11ac - 5 GHz'
'ac' => '802.11ac - 5 GHz',
'ax' => '802.11ax (Wi-Fi 6) - 2.4/5/6 GHz',
// 'be' => '802.11be (Wi-Fi 7) - 2.4/5/6 GHz'
];

// encryption types
Expand All @@ -42,6 +44,21 @@ class HotspotService
'TKIP CCMP' => 'TKIP+CCMP'
];

// 802.11ax (Wi-Fi 6) channel widths
private const HE_CHANNEL_WIDTHS = [
0 => '20/40 MHz',
1 => '80 MHz',
2 => '160 MHz'
];

// 802.11be (Wi-Fi 7) channel widths
private const EHT_CHANNEL_WIDTHS = [
0 => '20 MHz',
1 => '40 MHz',
2 => '80 MHz',
3 => '160 MHz',
4 => '320 MHz (6 GHz only)'
];

public function __construct()
{
Expand All @@ -67,7 +84,23 @@ public static function getEncTypes(): array
}

/**
* Returns translated security modes.
* Returns 802.11ax (Wi-Fi 6) channel widths
*/
public static function getHeChannelWidths(): array
{
return self::HE_CHANNEL_WIDTHS;
}

/**
* Returns 802.11be (Wi-Fi 7) channel widths
*/
public static function getEhtChannelWidths(): array
{
return self::EHT_CHANNEL_WIDTHS;
}

/**
* Returns translated security modes
*/
public static function getSecurityModes(): array
{
Expand All @@ -94,6 +127,26 @@ public static function get80211wOptions(): array
];
}

/**
* Checks if hardware mode supports advanced features
*
* @param string $mode
* @return array capabilities
*/
public static function getModeCapabilities(string $mode): array
{
$capabilities = [
'a' => ['wifi_generation' => 1, 'max_width' => 20, 'bands' => ['5']],
'b' => ['wifi_generation' => 2, 'max_width' => 22, 'bands' => ['2.4']],
'g' => ['wifi_generation' => 3, 'max_width' => 20, 'bands' => ['2.4']],
'n' => ['wifi_generation' => 4, 'max_width' => 40, 'bands' => ['2.4', '5']],
'ac' => ['wifi_generation' => 5, 'max_width' => 160, 'bands' => ['5']],
'ax' => ['wifi_generation' => 6, 'max_width' => 160, 'bands' => ['2.4', '5', '6'], 'supports_he' => true],
'be' => ['wifi_generation' => 7, 'max_width' => 320, 'bands' => ['2.4', '5', '6'], 'supports_he' => true, 'supports_eht' => true]
];

return $capabilities[$mode] ?? $capabilities['g'];
}

/**
* Validates user input + saves configs for hostapd, dnsmasq & dhcp
Expand Down Expand Up @@ -151,6 +204,23 @@ public function saveSettings(
$validated['dualmode'] = !empty($states['DualAPEnable']);
$validated['txpower'] = $post_data['txpower'];

error_log("HotspotService::saveSettings() -> validated\n" . var_export($validated, true));

// add 802.11ax/be specific parameters if present
if (in_array($validated['hw_mode'], ['ax', 'be'])) {
// Log advanced mode configuration
error_log(sprintf(
"Configuring advanced WiFi mode: %s with channel %d",
$validated['hw_mode'],
$validated['channel']
));

// Validate WPA3 for WiFi 6/7
if ($validated['wpa'] < 4 && $validated['hw_mode'] === 'be') {
$status->addMessage('Note: WiFi 7 works best with WPA3 security', 'info');
}
}

// hostapd
$config = $this->hostapd->buildConfig($validated, $status);
$this->hostapd->saveConfig($config, $dualAPEnable, $validated['interface']);
Expand Down
109 changes: 108 additions & 1 deletion src/RaspAP/Networking/Hotspot/Validators/HostapdValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@

class HostapdValidator
{
// Valid channel widths for 802.11ax (HE)
private const HE_VALID_CHWIDTHS = [0, 1, 2]; // 20/40, 80, 160 MHz

// Valid channel widths for 802.11be (EHT)
private const EHT_VALID_CHWIDTHS = [0, 1, 2, 3, 4]; // 20, 40, 80, 160, 320 MHz

// 6 GHz channel range (US)
private const CHANNEL_6GHZ_MIN = 1;
private const CHANNEL_6GHZ_MAX = 233;

/**
* Validates full hostapd parameter set
Expand Down Expand Up @@ -64,6 +73,16 @@ public function validate(
$goodInput = false;
}

// validate 802.11ax specific parameters
if ($post['hw_mode'] === 'ax' && !$this->validateAxParams($post, $status)) {
$goodInput = false;
}

// validate 802.11be specific parameters
if ($post['hw_mode'] === 'be' && !$this->validateBeParams($post, $status)) {
$goodInput = false;
}

// validate SSID
if (empty($post['ssid']) || strlen($post['ssid']) > 32) {
$status->addMessage('SSID must be between 1 and 32 characters', 'danger');
Expand Down Expand Up @@ -200,9 +219,97 @@ public function validate(
'bridgeStaticIp' => ($post['bridgeStaticIp']),
'bridgeNetmask' => ($post['bridgeNetmask']),
'bridgeGateway' => ($post['bridgeGateway']),
'bridgeDNS' => ($post['bridgeDNS'])
'bridgeDNS' => ($post['bridgeDNS']),
'he_oper_chwidth' => $post['he_oper_chwidth'] ?? null, // 802.11ax parameters
'he_bss_color' => $post['he_bss_color'] ?? null, // 802.11be parameters
'eht_oper_chwidth' => $post['eht_oper_chwidth'] ?? null
];
}

/**
* Validates 802.11ax (Wi-Fi 6) specific parameters
*
* @param array $post
* @param StatusMessage $status
* @return bool
*/
private function validateAxParams(array $post, StatusMessage $status): bool
{
$valid = true;

// Validate HE channel width
if (isset($post['he_oper_chwidth'])) {
$chwidth = (int)$post['he_oper_chwidth'];
if (!in_array($chwidth, self::HE_VALID_CHWIDTHS, true)) {
$status->addMessage('Invalid 802.11ax channel width. Must be 0 (20/40 MHz), 1 (80 MHz), or 2 (160 MHz)', 'danger');
$valid = false;
}
}

// Validate BSS color (1-63)
if (isset($post['he_bss_color'])) {
$bssColor = (int)$post['he_bss_color'];
if ($bssColor < 1 || $bssColor > 63) {
$status->addMessage('802.11ax BSS color must be between 1 and 63', 'danger');
$valid = false;
}
}

return $valid;
}

/**
* Validates 802.11be (Wi-Fi 7) specific parameters
*
* @param array $post
* @param StatusMessage $status
* @return bool
*/
private function validateBeParams(array $post, StatusMessage $status): bool
{
$valid = true;
$channel = (int)$post['channel'];

// Validate EHT channel width
if (isset($post['eht_oper_chwidth'])) {
$chwidth = (int)$post['eht_oper_chwidth'];

if (!in_array($chwidth, self::EHT_VALID_CHWIDTHS, true)) {
$status->addMessage('Invalid 802.11be channel width. Must be 0-4 (20, 40, 80, 160, or 320 MHz)', 'danger');
$valid = false;
}

// 320 MHz only valid on 6 GHz band
if ($chwidth === 4) {
if ($channel < self::CHANNEL_6GHZ_MIN || $channel > self::CHANNEL_6GHZ_MAX) {
$status->addMessage('802.11be 320 MHz channel width is only available on 6 GHz band (channels 1-233)', 'danger');
$valid = false;
}
}
}

// Validate BSS color (same as 802.11ax, inherited)
if (isset($post['he_bss_color'])) {
$bssColor = (int)$post['he_bss_color'];
if ($bssColor < 1 || $bssColor > 63) {
$status->addMessage('BSS color must be between 1 and 63', 'danger');
$valid = false;
}
}

return $valid;
}

/**
* Checks if channel is in 6GHz band
*
* @param int $channel
* @return bool
*/
private function is6GHzChannel(int $channel): bool
{
return $channel >= self::CHANNEL_6GHZ_MIN && $channel <= self::CHANNEL_6GHZ_MAX;
}

}

Loading