Skip to content

Commit ae40b28

Browse files
authored
Merge pull request #2076 from RaspAP/feat/wireless-mode-suggestion
Feature: Wireless Mode Suggestion
2 parents 24a2429 + 8e2e5e8 commit ae40b28

5 files changed

Lines changed: 186 additions & 0 deletions

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
require_once '../../includes/autoload.php';
3+
require_once '../../includes/CSRF.php';
4+
require_once '../../includes/session.php';
5+
require_once '../../includes/config.php';
6+
require_once '../../includes/authenticate.php';
7+
8+
header('Content-Type: application/json');
9+
10+
$interface = $_POST['interface'] ?? '';
11+
12+
if (empty($interface)) {
13+
http_response_code(400);
14+
echo json_encode(['error' => 'Missing interface parameter']);
15+
exit;
16+
}
17+
18+
$suggestedHWMode = suggestWifiHwMode($interface);
19+
$supportedModes = supportedModes($suggestedHWMode);
20+
21+
$data = [
22+
'interface' => $interface,
23+
'suggested_hw_mode' => $suggestedHWMode,
24+
'supported_modes' => $supportedModes,
25+
];
26+
27+
function suggestWifiHwMode(string $interface): string {
28+
$interface = escapeshellarg($interface);
29+
30+
$phyCmd = "iw dev $interface info 2>/dev/null | grep -oP 'phy\\s*\\K\\S+'";
31+
$phy = trim(shell_exec($phyCmd));
32+
33+
if ($phy === '') {
34+
http_response_code(400);
35+
header('Content-Type: application/json');
36+
echo json_encode(['error' => 'No valid phy for ' . $interface]);
37+
exit;
38+
}
39+
40+
$cmd = "iw phy phy$phy info 2>/dev/null";
41+
$text = shell_exec($cmd);
42+
43+
if (empty($text)) {
44+
http_response_code(500);
45+
echo json_encode(['error' => 'No phy info retrieved']);
46+
exit;
47+
}
48+
49+
// --- Capability presence ---
50+
$hasEHT = preg_match('/EHT\s+(?:Capabilities|MAC Capabilities|PHY Capabilities)/i', $text);
51+
$hasHE = preg_match('/HE\s+(?:Capabilities|MAC Capabilities|PHY Capabilities)/i', $text);
52+
$hasVHT = preg_match('/VHT\s+Capabilities/i', $text);
53+
$hasHT = preg_match('/HT\s+(?:Capabilities|MCS rate indexes supported)/i', $text);
54+
55+
// --- Band / frequency detection ---
56+
$has24GHz = preg_match('/Band\s+1:|2412\s*MHz|2437\s*MHz|2462\s*MHz/i', $text);
57+
$has5GHz = preg_match('/Band\s+2:|5180\s*MHz|5500\s*MHz|5745\s*MHz/i', $text);
58+
$has6GHz = preg_match('/Band\s+[34]:|5955\s*MHz|6[0-9]{3}\s*MHz/i', $text);
59+
60+
// Decision - prioritize explicit capability blocks over bands
61+
if ($hasEHT) {
62+
$suggested = 'be';
63+
} elseif ($hasHE) {
64+
$suggested = 'ax';
65+
} elseif ($hasVHT) {
66+
$suggested = 'ac';
67+
} elseif ($hasHT) {
68+
$suggested = 'n';
69+
} elseif ($has5GHz) {
70+
$suggested = 'a';
71+
} else {
72+
$suggested = 'g';
73+
}
74+
75+
// Return debug info in JSON for now
76+
// header('Content-Type: application/json');
77+
// echo json_encode([
78+
// 'phy' => $phy,
79+
// 'cmd' => $cmd,
80+
// 'suggested' => $suggested,
81+
// 'text' => $text,
82+
// 'debug' => [
83+
// 'hasEHT' => (bool)$hasEHT,
84+
// 'hasHE' => (bool)$hasHE,
85+
// 'hasVHT' => (bool)$hasVHT,
86+
// 'hasHT' => (bool)$hasHT,
87+
// 'has5GHz' => (bool)$has5GHz,
88+
// 'has6GHz' => (bool)$has6GHz,
89+
// 'heMatches' => $heMatches,
90+
// ],
91+
// 'label' => match($suggested) {
92+
// 'be' => '802.11be - 2.4/5/6 GHz',
93+
// 'ax' => '802.11ax - 2.4/5/6 GHz',
94+
// 'ac' => '802.11ac - 5 GHz',
95+
// 'n' => '802.11n - 2.4/5 GHz',
96+
// 'a' => '802.11a - 5 GHz',
97+
// 'g' => '802.11g - 2.4 GHz',
98+
// default => 'Unknown'
99+
// }
100+
// ]);
101+
102+
// Comment out the above echo and uncomment below for production:
103+
return $suggested;
104+
}
105+
106+
function supportedModes(string $highestMode, bool $incl = true): array {
107+
$standards = HotspotService::get80211Standards();
108+
109+
$standardsCodes = array_keys($standards);
110+
111+
$i = array_search($highestMode, $standardsCodes, true);
112+
113+
return $i === false ? $arr : array_slice($standardsCodes, 0, $incl ? $i + 1 : $i);
114+
}
115+
116+
echo json_encode($data, JSON_PRETTY_PRINT);
117+

app/js/ajax/main.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,65 @@ function loadInterfaceDHCPSelect() {
130130
});
131131
}
132132

133+
// Retrieves the suggested hw_mode for the selected interface
134+
function getSuggestedHwMode() {
135+
if ($('#suggested-hw-mode').length === 0) {
136+
return;
137+
}
138+
139+
var iface = $('#cbxinterface').val();
140+
var csrfToken = $('meta[name=csrf_token]').attr('content');
141+
$.post('ajax/networking/get_suggested_hw_mode.php', {
142+
'interface': iface,
143+
'csrf_token': csrfToken
144+
}, function (data) {
145+
let jsonData;
146+
try {
147+
jsonData = typeof data === 'object' ? data : JSON.parse(data);
148+
} catch (e) {
149+
console.warn('Invalid JSON:', e);
150+
$('#suggested-hw-mode-text').hide();
151+
$('#cbxhwmode option').removeAttr('disabled');
152+
return;
153+
}
154+
155+
if (jsonData.error) {
156+
console.warn('Error occurred:', jsonData.error);
157+
$('#suggested-hw-mode-text').hide();
158+
$('#cbxhwmode option').removeAttr('disabled');
159+
return;
160+
}
161+
162+
if (jsonData?.suggested_hw_mode && jsonData?.supported_modes) {
163+
$('#suggested-hw-mode').text(jsonData.suggested_hw_mode);
164+
$('#suggested-hw-mode-text').show();
165+
166+
const hwModeOptions = $('#cbxhwmode option');
167+
for (const option of hwModeOptions) {
168+
if (!jsonData.supported_modes.includes($(option).val())) {
169+
$(option).prop('disabled', true);
170+
}
171+
}
172+
173+
// if current selected mode isn't in the supported modes of the new selected interface
174+
// default to suggested hw mode
175+
if (!jsonData.supported_modes.includes($('#cbxhwmode option[selected="selected"]').val())) {
176+
$('#cbxhwmode').val(jsonData.suggested_hw_mode).trigger('change');
177+
}
178+
}
179+
}).catch(function (error) {
180+
$('#suggested-hw-mode-text').hide();
181+
$('#cbxhwmode option').removeAttr('disabled');
182+
});
183+
}
184+
185+
$('#cbxinterface').on('change', function () {
186+
getSuggestedHwMode();
187+
});
188+
if ($('#cbxinterface').length > 0) {
189+
getSuggestedHwMode();
190+
}
191+
133192
$('#debugModal').on('shown.bs.modal', function (e) {
134193
var csrfToken = $('meta[name=csrf_token]').attr('content');
135194
$.post('ajax/system/sys_debug.php',{'csrf_token': csrfToken},function(data){
300 Bytes
Binary file not shown.

locale/en_US/LC_MESSAGES/messages.po

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,12 @@ msgstr "Enable AP isolation"
948948
msgid "Blocks wireless clients from seeing or connecting to each other. Recommended for guest networks and public access points."
949949
msgstr "Blocks wireless clients from seeing or connecting to each other. Recommended for guest networks and public access points."
950950

951+
msgid "Wireless standards which are not compatible with your adapter may be disabled"
952+
msgstr "Wireless standards which are not compatible with your adapter may be disabled"
953+
954+
msgid "Based on the selected interface, 802.11%s is suggested."
955+
msgstr "Based on the selected interface, 802.11%s is suggested."
956+
951957
#: includes/networking.php
952958
msgid "Summary"
953959
msgstr "Summary"

templates/hostapd/basic.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
<div class="row">
1919
<div class="mb-3 col-md-6">
2020
<label for="cbxhwmode"><?php echo _("Wireless Mode") ;?></label>
21+
<i class="fas fa-info-circle" data-bs-toggle="tooltip" data-bs-placement="right" title="<?php echo _('Wireless standards which are not compatible with your adapter may be disabled') ?>"></i>
2122
<?php SelectorOptions('hw_mode', $arr80211Standard, $arrConfig['selected_hw_mode'], 'cbxhwmode', 'getChannel'); ?>
23+
<span id="suggested-hw-mode-text" class="form-text text-muted" style="display: none;">
24+
<?php echo sprintf(_('Based on the selected interface, 802.11%s is suggested.'), '<span id="suggested-hw-mode"></span>') ?>
25+
</span>
2226
</div>
2327
</div>
2428
<div class="row">

0 commit comments

Comments
 (0)