Merge pull request #1443 from RaspAP/feat/iw-parser

Refactor ISO countries + create IW parsing class
This commit is contained in:
Bill Zimmerman 2023-11-07 09:06:57 +01:00 committed by GitHub
commit fbec4501ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 302 additions and 379 deletions

View file

@ -1,43 +1,14 @@
<?php <?php
require '../../includes/csrf.php'; require '../../includes/csrf.php';
require_once '../../includes/config.php'; require '../../src/RaspAP/Parsers/IwParser.php';
require_once '../../includes/locale.php';
if (isset($_POST['interface'])) { if (isset($_POST['interface'])) {
define( 'NL80211_BAND_24GHZ', 0x1 );
define( 'NL80211_BAND_5GHZ', 0x2 );
$iface = escapeshellcmd($_POST['interface']); $iface = escapeshellcmd($_POST['interface']);
$flags = 0; $parser = new \RaspAP\Parsers\IwParser($iface);
$supportedFrequencies = $parser->parseIwInfo($iface);
// get physical device for selected interface echo json_encode($supportedFrequencies);
exec("iw dev | awk -v iface=".$iface." '/^phy#/ { phy = $0 } $1 == \"Interface\" { interface = $2 } interface == iface { print phy }'", $return);
$phy = $return[0];
// get frequencies supported by device
exec('iw '.$phy.' info | sed -rn "s/^.*\*\s([0-9]{4})\sMHz.*/\1/p"', $frequencies);
if (count(preg_grep('/^24[0-9]{2}/i', $frequencies)) >0) {
$flags += NL80211_BAND_24GHZ;
}
if (count(preg_grep('/^5[0-9]{3}/i', $frequencies)) >0) {
$flags += NL80211_BAND_5GHZ;
}
switch ($flags) {
case NL80211_BAND_24GHZ:
$msg = sprintf(_("The selected interface (%s) has support for the 2.4 GHz wireless band only."), $iface);
break;
case NL80211_BAND_5GHZ:
$msg = sprintf(_("The selected interface (%s) has support for the 5 GHz wireless band only."), $iface);
break;
case NL80211_BAND_24GHZ | NL80211_BAND_5GHZ:
$msg = sprintf(_("The selected interface (%s) has support for both the 2.4 and 5 GHz wireless bands."), $iface);
break;
default:
$msg = sprintf(_("The selected interface (%s) does not support wireless mode operation."), $iface);
}
echo json_encode($msg);
} }

View file

@ -0,0 +1,43 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/config.php';
require_once '../../includes/locale.php';
if (isset($_POST['interface'])) {
define( 'NL80211_BAND_24GHZ', 0x1 );
define( 'NL80211_BAND_5GHZ', 0x2 );
$iface = escapeshellcmd($_POST['interface']);
$flags = 0;
// get physical device for selected interface
exec("iw dev | awk -v iface=".$iface." '/^phy#/ { phy = $0 } $1 == \"Interface\" { interface = $2 } interface == iface { print phy }'", $return);
$phy = $return[0];
// get frequencies supported by device
exec('iw '.$phy.' info | sed -rn "s/^.*\*\s([0-9]{4})\sMHz.*/\1/p"', $frequencies);
if (count(preg_grep('/^24[0-9]{2}/i', $frequencies)) >0) {
$flags += NL80211_BAND_24GHZ;
}
if (count(preg_grep('/^5[0-9]{3}/i', $frequencies)) >0) {
$flags += NL80211_BAND_5GHZ;
}
switch ($flags) {
case NL80211_BAND_24GHZ:
$msg = sprintf(_("The selected interface (%s) has support for the 2.4 GHz wireless band only."), $iface);
break;
case NL80211_BAND_5GHZ:
$msg = sprintf(_("The selected interface (%s) has support for the 5 GHz wireless band only."), $iface);
break;
case NL80211_BAND_24GHZ | NL80211_BAND_5GHZ:
$msg = sprintf(_("The selected interface (%s) has support for both the 2.4 and 5 GHz wireless bands."), $iface);
break;
default:
$msg = sprintf(_("The selected interface (%s) does not support wireless mode operation."), $iface);
}
echo json_encode($msg);
}

View file

@ -42,7 +42,7 @@ body {
background-color: #fff; background-color: #fff;
} }
.btn-primary.disabled { .btn-primary:disabled {
color: <?php echo $color; ?> !important; color: <?php echo $color; ?> !important;
border-color: <?php echo $color; ?> !important; border-color: <?php echo $color; ?> !important;
background-color: #fff !important; background-color: #fff !important;

View file

@ -185,7 +185,7 @@ function contentLoaded() {
setupBtns(); setupBtns();
break; break;
case "hostapd_conf": case "hostapd_conf":
loadChannel(); getChannel();
setHardwareModeTooltip(); setHardwareModeTooltip();
break; break;
case "dhcpd_conf": case "dhcpd_conf":
@ -264,13 +264,6 @@ function setDHCPToggles(state) {
$('#dhcp-iface').prop('disabled', !state); $('#dhcp-iface').prop('disabled', !state);
} }
function loadChannel() {
$.get('ajax/networking/get_channel.php',function(data){
jsonData = JSON.parse(data);
loadChannelSelect(jsonData);
});
}
$('#debugModal').on('shown.bs.modal', function (e) { $('#debugModal').on('shown.bs.modal', function (e) {
var csrfToken = $('meta[name=csrf_token]').attr('content'); var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/system/sys_debug.php',{'csrf_token': csrfToken},function(data){ $.post('ajax/system/sys_debug.php',{'csrf_token': csrfToken},function(data){
@ -391,53 +384,76 @@ $(".custom-file-input").on("change", function() {
$(this).siblings(".custom-file-label").addClass("selected").html(fileName); $(this).siblings(".custom-file-label").addClass("selected").html(fileName);
}); });
/* // Retrieves the 'channel' value specified in hostapd.conf
Sets the wirelss channel select options based on hw_mode and country_code. function getChannel() {
$.get('ajax/networking/get_channel.php',function(data){
Methodology: In North America up to channel 11 is the maximum allowed WiFi 2.4Ghz channel, jsonData = JSON.parse(data);
except for the US that allows channel 12 & 13 in low power mode with additional restrictions. loadChannelSelect(jsonData);
Canada allows channel 12 in low power mode. Because it's unsure if low powered mode can be
supported the channels are not selectable for those countries. Also Uzbekistan and Colombia
allow up to channel 11 as maximum channel on the 2.4Ghz WiFi band.
Source: https://en.wikipedia.org/wiki/List_of_WLAN_channels
Additional: https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
*/
function loadChannelSelect(selected) {
// Fetch wireless regulatory data
$.getJSON("config/wireless.json", function(json) {
var hw_mode = $('#cbxhwmode').val();
var country_code = $('#cbxcountries').val();
var channel_select = $('#cbxchannel');
var data = json["wireless_regdb"];
var selectablechannels = Array.range(1,14);
// Assign array of countries to valid frequencies (channels)
var countries_2_4Ghz_max11ch = data["2_4GHz_max11ch"].countries;
var countries_2_4Ghz_max14ch = data["2_4GHz_max14ch"].countries;
var countries_5Ghz_max48ch = data["5Ghz_max48ch"].countries;
// Map selected hw_mode and country to determine channel list
if (hw_mode === 'a') {
selectablechannels = data["5Ghz_max48ch"].channels;
} else if (($.inArray(country_code, countries_2_4Ghz_max11ch) !== -1) && (hw_mode !== 'ac') ) {
selectablechannels = data["2_4GHz_max11ch"].channels;
} else if (($.inArray(country_code, countries_2_4Ghz_max14ch) !== -1) && (hw_mode === 'b')) {
selectablechannels = data["2_4GHz_max14ch"].channels;
} else if (($.inArray(country_code, countries_5Ghz_max48ch) !== -1) && (hw_mode === 'ac')) {
selectablechannels = data["5Ghz_max48ch"].channels;
}
// Set channel select with available values
selected = (typeof selected === 'undefined') ? selectablechannels[0] : selected;
channel_select.empty();
$.each(selectablechannels, function(key,value) {
channel_select.append($("<option></option>").attr("value", value).text(value));
});
channel_select.val(selected);
}); });
} }
/* Sets hardware mode tooltip text for selected interface. /*
Sets the wirelss channel select options based on frequencies reported by iw.
See: https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
Also: https://en.wikipedia.org/wiki/List_of_WLAN_channels
*/
function loadChannelSelect(selected) {
var iface = $('#cbxinterface').val();
var hwmodeText = '';
var csrfToken = $('meta[name=csrf_token]').attr('content');
// update hardware mode tooltip
setHardwareModeTooltip();
$.post('ajax/networking/get_frequencies.php',{'interface': iface, 'csrf_token': csrfToken, 'selected': selected},function(response){
var hw_mode = $('#cbxhwmode').val();
var country_code = $('#cbxcountries').val();
var channel_select = $('#cbxchannel');
var btn_save = $('#btnSaveHostapd');
var data = JSON.parse(response);
var selectableChannels = [];
// Map selected hw_mode to available channels
if (hw_mode === 'a') {
selectableChannels = data.filter(item => item.MHz.toString().startsWith('5'));
} else if (hw_mode !== 'ac') {
selectableChannels = data.filter(item => item.MHz.toString().startsWith('24'));
} else if (hw_mode === 'b') {
selectableChannels = data.filter(item => item.MHz.toString().startsWith('24'));
} else if (hw_mode === 'ac') {
selectableChannels = data.filter(item => item.MHz.toString().startsWith('5'));
}
// If selected channel doeesn't exist in allowed channels, set default or null (unsupported)
if (!selectableChannels.find(item => item.Channel === selected)) {
if (selectableChannels.length === 0) {
selectableChannels[0] = { Channel: null };
} else {
defaultChannel = selectableChannels[0].Channel;
selected = defaultChannel
}
}
// Set channel select with available values
channel_select.empty();
if (selectableChannels[0].Channel === null) {
channel_select.append($("<option></option>").attr("value", "").text("---"));
channel_select.prop("disabled", true);
btn_save.prop("disabled", true);
} else {
channel_select.prop("disabled", false);
btn_save.prop("disabled", false);
$.each(selectableChannels, function(key,value) {
channel_select.append($("<option></option>").attr("value", value.Channel).text(value.Channel));
});
channel_select.val(selected);
}
});
}
/* Sets hardware mode tooltip text for selected interface
* and calls loadChannelSelect()
*/ */
function setHardwareModeTooltip() { function setHardwareModeTooltip() {
var iface = $('#cbxinterface').val(); var iface = $('#cbxinterface').val();
@ -447,7 +463,7 @@ function setHardwareModeTooltip() {
if ($('#cbxhwmode').find('option[value="ac"]').prop('disabled') == true ) { if ($('#cbxhwmode').find('option[value="ac"]').prop('disabled') == true ) {
var hwmodeText = $('#hwmode').attr('data-tooltip'); var hwmodeText = $('#hwmode').attr('data-tooltip');
} }
$.post('ajax/networking/get_frequencies.php?',{'interface': iface, 'csrf_token': csrfToken},function(data){ $.post('ajax/networking/get_nl80211_band.php?',{'interface': iface, 'csrf_token': csrfToken},function(data){
var responseText = JSON.parse(data); var responseText = JSON.parse(data);
$('#tiphwmode').attr('data-original-title', responseText + '\n' + hwmodeText ); $('#tiphwmode').attr('data-original-title', responseText + '\n' + hwmodeText );
}); });

View file

@ -31,9 +31,8 @@ define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf');
define('RASPI_ACCESS_CHECK_IP', '1.1.1.1'); define('RASPI_ACCESS_CHECK_IP', '1.1.1.1');
define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one'); define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one');
// Constants for the 5GHz wireless regulatory domain. // Constant for the 5GHz wireless regulatory domain
define('RASPI_5GHZ_ISO_ALPHA2', array('NL','US')); define("HOSTAPD_5GHZ_CHANNEL_MIN", 100);
define('RASPI_5GHZ_MAX_CHANNEL', 165);
// Enable basic authentication for the web admin. // Enable basic authentication for the web admin.
define('RASPI_AUTH_ENABLED', true); define('RASPI_AUTH_ENABLED', true);

View file

@ -1,17 +0,0 @@
{"wireless_regdb": {
"debug": "off",
"2_4GHz_max11ch": {
"countries": [ "AG", "BS", "BB", "BZ", "CR", "CU", "DM", "DO", "SV", "GD", "GT",
"HT", "HN", "JM", "MX", "NI", "PA", "KN", "LC", "VC", "TT", "US", "CA", "UZ", "CO" ],
"channels": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
},
"2_4GHz_max14ch": {
"countries": [ "JP", "NL" ],
"channels": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ]
},
"5Ghz_max48ch": {
"countries": [ "NL","US" ],
"channels": [ 36, 40, 44, 48 ]
}
}}

View file

@ -36,9 +36,11 @@ $defaults = [
'RASPI_ACCESS_CHECK_IP' => '1.1.1.1', 'RASPI_ACCESS_CHECK_IP' => '1.1.1.1',
'RASPI_ACCESS_CHECK_DNS' => 'one.one.one.one', 'RASPI_ACCESS_CHECK_DNS' => 'one.one.one.one',
// Constants for the 5GHz wireless regulatory domain // Constant for the 5GHz wireless regulatory domain
'RASPI_5GHZ_ISO_ALPHA2' => array('NL','US'), 'HOSTAPD_5GHZ_CHANNEL_MIN' => 100,
'RASPI_5GHZ_MAX_CHANNEL' => 165,
// Enable basic authentication for the web admin.
'RASPI_AUTH_ENABLED' => true,
// Optional services, set to true to enable. // Optional services, set to true to enable.
'RASPI_WIFICLIENT_ENABLED' => true, 'RASPI_WIFICLIENT_ENABLED' => true,

View file

@ -862,3 +862,33 @@ function loadFooterScripts($extraFooterScripts)
} }
} }
/**
* Returns ISO standard 2-letter country codes
*
* @param string $locale
* @param boolean $flag
*/
function getCountryCodes($locale = 'en', $flag = true) {
$output = [];
if ($flag) {
$opt = '--flag';
}
exec("isoquery $opt --locale $locale | awk -F'\t' '{print $5 \"\t\" $0}' | sort | cut -f2-", $output);
$countryData = [];
foreach ($output as $line) {
$parts = explode("\t", $line);
if (count($parts) >= 2) {
$countryCode = $parts[0];
if ($flag) {
$countryFlag = $parts[3];
$countryName = $parts[4] .' ';
} else {
$countryName = $parts[3];
}
$countryData[$countryCode] = $countryName.$countryFlag;
}
}
return $countryData;
}

View file

@ -22,6 +22,9 @@ function DisplayHostAPDConfig()
'n' => '802.11n - 2.4 GHz', 'n' => '802.11n - 2.4 GHz',
'ac' => '802.11ac - 5 GHz' 'ac' => '802.11ac - 5 GHz'
]; ];
$languageCode = strtok($_SESSION['locale'], '_');
$countryCodes = getCountryCodes($languageCode);
$arrSecurity = array(1 => 'WPA', 2 => 'WPA2', 3 => 'WPA+WPA2', 'none' => _("None")); $arrSecurity = array(1 => 'WPA', 2 => 'WPA2', 3 => 'WPA+WPA2', 'none' => _("None"));
$arrEncType = array('TKIP' => 'TKIP', 'CCMP' => 'CCMP', 'TKIP CCMP' => 'TKIP+CCMP'); $arrEncType = array('TKIP' => 'TKIP', 'CCMP' => 'CCMP', 'TKIP CCMP' => 'TKIP+CCMP');
$arrTxPower = getDefaultNetOpts('txpower','dbm'); $arrTxPower = getDefaultNetOpts('txpower','dbm');
@ -29,7 +32,7 @@ function DisplayHostAPDConfig()
exec("ip -o link show | awk -F': ' '{print $2}'", $interfaces); exec("ip -o link show | awk -F': ' '{print $2}'", $interfaces);
sort($interfaces); sort($interfaces);
exec("iw reg get | awk '/country / { sub(/:/,\"\",$2); print $2 }'", $country_code); $reg_domain = shell_exec("iw reg get | grep -o 'country [A-Z]\{2\}' | awk 'NR==1{print $2}'");
$cmd = "iw dev ".$_SESSION['ap_interface']." info | awk '$1==\"txpower\" {print $2}'"; $cmd = "iw dev ".$_SESSION['ap_interface']." info | awk '$1==\"txpower\" {print $2}'";
exec($cmd, $txpower); exec($cmd, $txpower);
@ -40,7 +43,7 @@ function DisplayHostAPDConfig()
} }
if (!RASPI_MONITOR_ENABLED) { if (!RASPI_MONITOR_ENABLED) {
if (isset($_POST['SaveHostAPDSettings'])) { if (isset($_POST['SaveHostAPDSettings'])) {
SaveHostAPDConfig($arrSecurity, $arrEncType, $arr80211Standard, $interfaces, $status); SaveHostAPDConfig($arrSecurity, $arrEncType, $arr80211Standard, $interfaces, $reg_domain, $status);
} }
} }
$arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini');
@ -95,10 +98,12 @@ function DisplayHostAPDConfig()
} else { } else {
$arrConfig['disassoc_low_ack_bool'] = 0; $arrConfig['disassoc_low_ack_bool'] = 0;
} }
// assign country_code from iw reg if not set in config // assign country_code from iw reg if not set in config
if (empty($arrConfig['country_code']) && isset($country_code[0])) { if (empty($arrConfig['country_code']) && isset($country_code[0])) {
$arrConfig['country_code'] = $country_code[0]; $arrConfig['country_code'] = $country_code[0];
} }
// set txpower with iw if value is non-default ('auto') // set txpower with iw if value is non-default ('auto')
if (isset($_POST['txpower'])) { if (isset($_POST['txpower'])) {
if ($_POST['txpower'] != 'auto') { if ($_POST['txpower'] != 'auto') {
@ -114,7 +119,6 @@ function DisplayHostAPDConfig()
} }
} }
$countries_5Ghz_max48ch = RASPI_5GHZ_ISO_ALPHA2;
$selectedHwMode = $arrConfig['hw_mode']; $selectedHwMode = $arrConfig['hw_mode'];
if (isset($arrConfig['ieee80211n'])) { if (isset($arrConfig['ieee80211n'])) {
if (strval($arrConfig['ieee80211n']) === '1') { if (strval($arrConfig['ieee80211n']) === '1') {
@ -131,14 +135,6 @@ function DisplayHostAPDConfig()
$selectedHwMode = 'w'; $selectedHwMode = 'w';
} }
} }
if (!in_array($arrConfig['country_code'], $countries_5Ghz_max48ch)) {
$hwModeDisabled = 'ac';
if ($selectedHwMode === $hwModeDisabled) {
unset($selectedHwMode);
}
} else {
$hwModeDisabled = null;
}
echo renderTemplate( echo renderTemplate(
"hostapd", compact( "hostapd", compact(
@ -157,7 +153,7 @@ function DisplayHostAPDConfig()
"arrHostapdConf", "arrHostapdConf",
"operatingSystem", "operatingSystem",
"selectedHwMode", "selectedHwMode",
"hwModeDisabled" "countryCodes"
) )
); );
} }
@ -169,10 +165,11 @@ function DisplayHostAPDConfig()
* @param array $enc_types * @param array $enc_types
* @param array $modes * @param array $modes
* @param string $interface * @param string $interface
* @param string $reg_domain
* @param object $status * @param object $status
* @return boolean * @return boolean
*/ */
function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status) function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $reg_domain, $status)
{ {
// It should not be possible to send bad data for these fields. // It should not be possible to send bad data for these fields.
// If wpa fields are absent, return false and log securely. // If wpa fields are absent, return false and log securely.
@ -301,6 +298,8 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
if (strlen($_POST['country_code']) !== 0 && strlen($_POST['country_code']) != 2) { if (strlen($_POST['country_code']) !== 0 && strlen($_POST['country_code']) != 2) {
$status->addMessage('Country code must be blank or two characters', 'danger'); $status->addMessage('Country code must be blank or two characters', 'danger');
$good_input = false; $good_input = false;
} else {
$country_code = $_POST['country_code'];
} }
if (isset($_POST['beaconintervalEnable'])) { if (isset($_POST['beaconintervalEnable'])) {
if (!is_numeric($_POST['beacon_interval'])) { if (!is_numeric($_POST['beacon_interval'])) {
@ -318,6 +317,10 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
if ($good_input) { if ($good_input) {
$return = updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable); $return = updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable);
if (trim($country_code) != trim($reg_domain)) {
$return = iwRegSet($country_code, $status);
}
// Fetch dhcp-range, lease time from system config // Fetch dhcp-range, lease time from system config
$syscfg = parse_ini_file(RASPI_DNSMASQ_PREFIX.$ap_iface.'.conf', false, INI_SCANNER_RAW); $syscfg = parse_ini_file(RASPI_DNSMASQ_PREFIX.$ap_iface.'.conf', false, INI_SCANNER_RAW);
@ -440,6 +443,14 @@ function updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable
} }
$config.= 'ssid='.$_POST['ssid'].PHP_EOL; $config.= 'ssid='.$_POST['ssid'].PHP_EOL;
$config.= 'channel='.$_POST['channel'].PHP_EOL; $config.= 'channel='.$_POST['channel'].PHP_EOL;
// Set VHT center frequency segment value
if ((int)$_POST['channel'] < HOSTAPD_5GHZ_CHANNEL_MIN) {
$vht_freq_idx = 42;
} else {
$vht_freq_idx = 155;
}
if ($_POST['hw_mode'] === 'n') { if ($_POST['hw_mode'] === 'n') {
$config.= 'hw_mode=g'.PHP_EOL; $config.= 'hw_mode=g'.PHP_EOL;
$config.= 'ieee80211n=1'.PHP_EOL; $config.= 'ieee80211n=1'.PHP_EOL;
@ -458,7 +469,7 @@ function updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable
$config.= 'ieee80211h=0'.PHP_EOL; $config.= 'ieee80211h=0'.PHP_EOL;
$config.= 'vht_capab=[MAX-AMSDU-3839][SHORT-GI-80]'.PHP_EOL; $config.= 'vht_capab=[MAX-AMSDU-3839][SHORT-GI-80]'.PHP_EOL;
$config.= 'vht_oper_chwidth=1'.PHP_EOL; $config.= 'vht_oper_chwidth=1'.PHP_EOL;
$config.= 'vht_oper_centr_freq_seg0_idx=42'.PHP_EOL.PHP_EOL; $config.= 'vht_oper_centr_freq_seg0_idx='.$vht_freq_idx.PHP_EOL.PHP_EOL;
} elseif ($_POST['hw_mode'] === 'w') { } elseif ($_POST['hw_mode'] === 'w') {
$config.= 'ieee80211w=2'.PHP_EOL; $config.= 'ieee80211w=2'.PHP_EOL;
$config.= 'wpa_key_mgmt=WPA-EAP-SHA256'.PHP_EOL; $config.= 'wpa_key_mgmt=WPA-EAP-SHA256'.PHP_EOL;
@ -489,3 +500,18 @@ function updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable
return $result; return $result;
} }
/**
* Executes iw to set the specified ISO 2-letter country code
*
* @param string $country_code
* @param object $status
* @return boolean $result
*/
function iwRegSet(string $country_code, $status)
{
$country_code = escapeshellarg($country_code);
$result = shell_exec("sudo iw reg set $country_code");
$status->addMessage(sprintf(_('Setting wireless regulatory domain to %s'), $country_code, 'success'));
return $result;
}

View file

@ -241,7 +241,7 @@ function _install_dependencies() {
# Set dconf-set-selections # Set dconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections
sudo apt-get install -y lighttpd git hostapd dnsmasq iptables-persistent $php_package $dhcpcd_package $iw_package vnstat qrencode jq || _install_status 1 "Unable to install dependencies" sudo apt-get install -y lighttpd git hostapd dnsmasq iptables-persistent $php_package $dhcpcd_package $iw_package vnstat qrencode jq isoquery || _install_status 1 "Unable to install dependencies"
_install_status 0 _install_status 0
} }

View file

@ -709,6 +709,9 @@ msgstr "Routing table"
msgid "raw output" msgid "raw output"
msgstr "raw output" msgstr "raw output"
msgid "Setting wireless regulatory domain to %s"
msgstr "Setting wireless regulatory domain to %s"
#: includes/system.php #: includes/system.php
msgid "System Information" msgid "System Information"
msgstr "System Information" msgstr "System Information"

View file

@ -0,0 +1,100 @@
<?php
/**
* Linux iw parser class
*
* @description Parses output of iw to determine properties of a given physical device (phy)
* @author Bill Zimmerman <billzimmerman@gmail.com>
* @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE
* @see https://wireless.wiki.kernel.org/en/users/Documentation/iw
*/
declare(strict_types=1);
namespace RaspAP\Parsers;
class IwParser
{
private $iw_output;
public function __construct(string $interface = 'wlan0')
{
// Resolve physical device for selected interface
$iface = escapeshellarg($interface);
$pattern = "iw dev | awk -v iface=".$iface." '/^phy#/ { phy = $0 } $1 == \"Interface\" { interface = $2 } interface == iface { print phy }'";
exec($pattern, $return);
$phy = $return[0];
// Fetch 'iw info' output for phy
$this->iw_output = shell_exec("iw $phy info");
}
/**
* Parses raw output of 'iw info' command, filtering supported frequencies.
*
* Frequencies with the following regulatory restrictions are excluded:
* (no IR): the AP won't Initiate Radiation until a DFS scan (or similar) is complete on these bands.
* (radar detection): the specified channels are shared with radar equipment.
* (disabled): self-explanatory.
*/
public function parseIwInfo()
{
$excluded = [
"(no IR, radar detection)",
"(radar detection)",
"(disabled)",
"(no IR)"
];
$excluded_pattern = implode('|', array_map('preg_quote', $excluded));
$pattern = '/\*\s+(\d+)\s+MHz \[(\d+)\] \(([\d.]+) dBm\)\s(?!' .$excluded_pattern. ')/';
$supportedFrequencies = [];
// Match iw_output containing supported frequencies
preg_match_all($pattern, $this->iw_output, $matches, PREG_SET_ORDER, 0);
/* For frequencies > 5500 MHz only the following "channels" are allowed:
* 100 108 116 124 132 140 149 157 184 192
* @see https://w1.fi/cgit/hostap/tree/src/common/hw_features_common.c
*/
$allowed = [100, 108, 116, 124, 132, 140, 149, 157, 184, 192];
foreach ($matches as $match) {
$frequency = [
'MHz' => (int)$match[1],
'Channel' => (int)$match[2],
'dBm' => (float)$match[3],
];
if ( ($frequency['MHz'] >= 5500 && in_array($frequency['Channel'], $allowed))
|| $frequency['MHz'] < 5500 ) {
$supportedFrequencies[] = $frequency;
}
}
return $supportedFrequencies;
}
/**
* Converts an ieee80211 frequency to a channel value
* Adapted from iw source
* @param int $freq
* @see https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/tree/util.c
*/
public function ieee80211_frequency_to_channel(int $freq)
{
/* see 802.11-2007 17.3.8.3.2 and Annex J */
if ($freq == 2484) {
return 14;
} else if ($freq < 2484) {
return ($freq - 2407) / 5;
} else if ($freq >= 4910 && $freq <= 4980) {
return ($freq - 4000) / 5;
} else if ($freq <= 45000) { /* DMG band lower limit */
return ($freq - 5000) / 5;
} else if ($freq >= 58320 && $freq <= 64800) {
return ($freq - 56160) / 2160;
} else {
return 0;
}
}
}

View file

@ -1,6 +1,6 @@
<?php ob_start() ?> <?php ob_start() ?>
<?php if (!RASPI_MONITOR_ENABLED) : ?> <?php if (!RASPI_MONITOR_ENABLED) : ?>
<input type="submit" class="btn btn-outline btn-primary" name="SaveHostAPDSettings" value="<?php echo _("Save settings"); ?>" /> <input type="submit" class="btn btn-outline btn-primary" id="btnSaveHostapd" name="SaveHostAPDSettings" value="<?php echo _("Save settings"); ?>" />
<?php if ($hostapdstatus[0] == 0) : ?> <?php if ($hostapdstatus[0] == 0) : ?>
<input type="submit" class="btn btn-success" name="StartHotspot" value="<?php echo _("Start hotspot"); $msg=_("Starting hotspot"); ?>" data-toggle="modal" data-target="#hostapdModal"/> <input type="submit" class="btn btn-success" name="StartHotspot" value="<?php echo _("Start hotspot"); $msg=_("Starting hotspot"); ?>" data-toggle="modal" data-target="#hostapdModal"/>
<?php else : ?> <?php else : ?>

View file

@ -73,257 +73,7 @@
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="cbxcountries"><?php echo _("Country Code"); ?></label> <label for="cbxcountries"><?php echo _("Country Code"); ?></label>
<input type="hidden" id="selected_country" value="<?php echo htmlspecialchars($arrConfig['country_code'], ENT_QUOTES); ?>"> <input type="hidden" id="selected_country" value="<?php echo htmlspecialchars($arrConfig['country_code'], ENT_QUOTES); ?>">
<select class="form-control" id="cbxcountries" name="country_code" onchange="loadChannelSelect()"> <?php SelectorOptions('country_code', $countryCodes, $arrConfig['country_code'], 'cbxcountries', 'loadChannelSelect'); ?>
<option value="AF">Afghanistan</option>
<option value="AX">Åland Islands</option>
<option value="AL">Albania</option>
<option value="DZ">Algeria</option>
<option value="AS">American Samoa</option>
<option value="AD">Andorra</option>
<option value="AO">Angola</option>
<option value="AI">Anguilla</option>
<option value="AQ">Antarctica</option>
<option value="AG">Antigua and Barbuda</option>
<option value="AR">Argentina</option>
<option value="AM">Armenia</option>
<option value="AW">Aruba</option>
<option value="AU">Australia</option>
<option value="AT">Austria</option>
<option value="AZ">Azerbaijan</option>
<option value="BS">Bahamas</option>
<option value="BH">Bahrain</option>
<option value="BD">Bangladesh</option>
<option value="BB">Barbados</option>
<option value="BY">Belarus</option>
<option value="BE">Belgium</option>
<option value="BZ">Belize</option>
<option value="BJ">Benin</option>
<option value="BM">Bermuda</option>
<option value="BT">Bhutan</option>
<option value="BO">Bolivia, Plurinational State of</option>
<option value="BQ">Bonaire, Sint Eustatius and Saba</option>
<option value="BA">Bosnia and Herzegovina</option>
<option value="BW">Botswana</option>
<option value="BV">Bouvet Island</option>
<option value="BR">Brazil</option>
<option value="IO">British Indian Ocean Territory</option>
<option value="BN">Brunei Darussalam</option>
<option value="BG">Bulgaria</option>
<option value="BF">Burkina Faso</option>
<option value="BI">Burundi</option>
<option value="KH">Cambodia</option>
<option value="CM">Cameroon</option>
<option value="CA">Canada</option>
<option value="CV">Cape Verde</option>
<option value="KY">Cayman Islands</option>
<option value="CF">Central African Republic</option>
<option value="TD">Chad</option>
<option value="CL">Chile</option>
<option value="CN">China</option>
<option value="CX">Christmas Island</option>
<option value="CC">Cocos (Keeling) Islands</option>
<option value="CO">Colombia</option>
<option value="KM">Comoros</option>
<option value="CG">Congo</option>
<option value="CD">Congo, the Democratic Republic of the</option>
<option value="CK">Cook Islands</option>
<option value="CR">Costa Rica</option>
<option value="CI">Côte d'Ivoire</option>
<option value="HR">Croatia</option>
<option value="CU">Cuba</option>
<option value="CW">Curaçao</option>
<option value="CY">Cyprus</option>
<option value="CZ">Czech Republic</option>
<option value="DK">Denmark</option>
<option value="DJ">Djibouti</option>
<option value="DM">Dominica</option>
<option value="DO">Dominican Republic</option>
<option value="EC">Ecuador</option>
<option value="EG">Egypt</option>
<option value="SV">El Salvador</option>
<option value="GQ">Equatorial Guinea</option>
<option value="ER">Eritrea</option>
<option value="EE">Estonia</option>
<option value="ET">Ethiopia</option>
<option value="FK">Falkland Islands (Malvinas)</option>
<option value="FO">Faroe Islands</option>
<option value="FJ">Fiji</option>
<option value="FI">Finland</option>
<option value="FR">France</option>
<option value="GF">French Guiana</option>
<option value="PF">French Polynesia</option>
<option value="TF">French Southern Territories</option>
<option value="GA">Gabon</option>
<option value="GM">Gambia</option>
<option value="GE">Georgia</option>
<option value="DE">Germany</option>
<option value="GH">Ghana</option>
<option value="GI">Gibraltar</option>
<option value="GR">Greece</option>
<option value="GL">Greenland</option>
<option value="GD">Grenada</option>
<option value="GP">Guadeloupe</option>
<option value="GU">Guam</option>
<option value="GT">Guatemala</option>
<option value="GG">Guernsey</option>
<option value="GN">Guinea</option>
<option value="GW">Guinea-Bissau</option>
<option value="GY">Guyana</option>
<option value="HT">Haiti</option>
<option value="HM">Heard Island and McDonald Islands</option>
<option value="VA">Holy See (Vatican City State)</option>
<option value="HN">Honduras</option>
<option value="HK">Hong Kong</option>
<option value="HU">Hungary</option>
<option value="IS">Iceland</option>
<option value="IN">India</option>
<option value="ID">Indonesia</option>
<option value="IR">Iran, Islamic Republic of</option>
<option value="IQ">Iraq</option>
<option value="IE">Ireland</option>
<option value="IM">Isle of Man</option>
<option value="IL">Israel</option>
<option value="IT">Italy</option>
<option value="JM">Jamaica</option>
<option value="JP">Japan</option>
<option value="JE">Jersey</option>
<option value="JO">Jordan</option>
<option value="KZ">Kazakhstan</option>
<option value="KE">Kenya</option>
<option value="KI">Kiribati</option>
<option value="KP">Korea, Democratic People's Republic of</option>
<option value="KR">Korea, Republic of</option>
<option value="KW">Kuwait</option>
<option value="KG">Kyrgyzstan</option>
<option value="LA">Lao People's Democratic Republic</option>
<option value="LV">Latvia</option>
<option value="LB">Lebanon</option>
<option value="LS">Lesotho</option>
<option value="LR">Liberia</option>
<option value="LY">Libya</option>
<option value="LI">Liechtenstein</option>
<option value="LT">Lithuania</option>
<option value="LU">Luxembourg</option>
<option value="MO">Macao</option>
<option value="MK">Macedonia, the former Yugoslav Republic of</option>
<option value="MG">Madagascar</option>
<option value="MW">Malawi</option>
<option value="MY">Malaysia</option>
<option value="MV">Maldives</option>
<option value="ML">Mali</option>
<option value="MT">Malta</option>
<option value="MH">Marshall Islands</option>
<option value="MQ">Martinique</option>
<option value="MR">Mauritania</option>
<option value="MU">Mauritius</option>
<option value="YT">Mayotte</option>
<option value="MX">Mexico</option>
<option value="FM">Micronesia, Federated States of</option>
<option value="MD">Moldova, Republic of</option>
<option value="MC">Monaco</option>
<option value="MN">Mongolia</option>
<option value="ME">Montenegro</option>
<option value="MS">Montserrat</option>
<option value="MA">Morocco</option>
<option value="MZ">Mozambique</option>
<option value="MM">Myanmar</option>
<option value="NA">Namibia</option>
<option value="NR">Nauru</option>
<option value="NP">Nepal</option>
<option value="NL">Netherlands</option>
<option value="NC">New Caledonia</option>
<option value="NZ">New Zealand</option>
<option value="NI">Nicaragua</option>
<option value="NE">Niger</option>
<option value="NG">Nigeria</option>
<option value="NU">Niue</option>
<option value="NF">Norfolk Island</option>
<option value="MP">Northern Mariana Islands</option>
<option value="NO">Norway</option>
<option value="OM">Oman</option>
<option value="PK">Pakistan</option>
<option value="PW">Palau</option>
<option value="PS">Palestinian Territory</option>
<option value="PA">Panama</option>
<option value="PG">Papua New Guinea</option>
<option value="PY">Paraguay</option>
<option value="PE">Peru</option>
<option value="PH">Philippines</option>
<option value="PN">Pitcairn</option>
<option value="PL">Poland</option>
<option value="PT">Portugal</option>
<option value="PR">Puerto Rico</option>
<option value="QA">Qatar</option>
<option value="RE">Réunion</option>
<option value="RO">Romania</option>
<option value="RU">Russian Federation</option>
<option value="RW">Rwanda</option>
<option value="BL">Saint Barthélemy</option>
<option value="SH">Saint Helena, Ascension and Tristan da Cunha</option>
<option value="KN">Saint Kitts and Nevis</option>
<option value="LC">Saint Lucia</option>
<option value="MF">Saint Martin (French part)</option>
<option value="PM">Saint Pierre and Miquelon</option>
<option value="VC">Saint Vincent and the Grenadines</option>
<option value="WS">Samoa</option>
<option value="SM">San Marino</option>
<option value="ST">Sao Tome and Principe</option>
<option value="SA">Saudi Arabia</option>
<option value="SN">Senegal</option>
<option value="RS">Serbia</option>
<option value="SC">Seychelles</option>
<option value="SL">Sierra Leone</option>
<option value="SG">Singapore</option>
<option value="SX">Sint Maarten (Dutch part)</option>
<option value="SK">Slovakia</option>
<option value="SI">Slovenia</option>
<option value="SB">Solomon Islands</option>
<option value="SO">Somalia</option>
<option value="ZA">South Africa</option>
<option value="GS">South Georgia and the South Sandwich Islands</option>
<option value="SS">South Sudan</option>
<option value="ES">Spain</option>
<option value="LK">Sri Lanka</option>
<option value="SD">Sudan</option>
<option value="SR">Suriname</option>
<option value="SJ">Svalbard and Jan Mayen</option>
<option value="SZ">Swaziland</option>
<option value="SE">Sweden</option>
<option value="CH">Switzerland</option>
<option value="SY">Syrian Arab Republic</option>
<option value="TW">Taiwan</option>
<option value="TJ">Tajikistan</option>
<option value="TZ">Tanzania, United Republic of</option>
<option value="TH">Thailand</option>
<option value="TL">Timor-Leste</option>
<option value="TG">Togo</option>
<option value="TK">Tokelau</option>
<option value="TO">Tonga</option>
<option value="TT">Trinidad and Tobago</option>
<option value="TN">Tunisia</option>
<option value="TR">Turkey</option>
<option value="TM">Turkmenistan</option>
<option value="TC">Turks and Caicos Islands</option>
<option value="TV">Tuvalu</option>
<option value="UG">Uganda</option>
<option value="UA">Ukraine</option>
<option value="AE">United Arab Emirates</option>
<option value="GB">United Kingdom</option>
<option value="US">United States</option>
<option value="UM">United States Minor Outlying Islands</option>
<option value="UY">Uruguay</option>
<option value="UZ">Uzbekistan</option>
<option value="VU">Vanuatu</option>
<option value="VE">Venezuela, Bolivarian Republic of</option>
<option value="VN">Viet Nam</option>
<option value="VG">Virgin Islands, British</option>
<option value="VI">Virgin Islands, U.S.</option>
<option value="WF">Wallis and Futuna</option>
<option value="EH">Western Sahara</option>
<option value="YE">Yemen</option>
<option value="ZM">Zambia</option>
<option value="ZW">Zimbabwe</option>
</select>
<script type="text/javascript"> <script type="text/javascript">
var country = document.getElementById("selected_country").value; var country = document.getElementById("selected_country").value;
var countries = document.getElementById("cbxcountries"); var countries = document.getElementById("cbxcountries");

View file

@ -3,7 +3,7 @@
<div class="row"> <div class="row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="cbxinterface"><?php echo _("Interface") ;?></label> <label for="cbxinterface"><?php echo _("Interface") ;?></label>
<?php SelectorOptions('interface', $interfaces, $arrConfig['interface'], 'cbxinterface', 'setHardwareModeTooltip'); ?> <?php SelectorOptions('interface', $interfaces, $arrConfig['interface'], 'cbxinterface', 'getChannel'); ?>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -16,7 +16,7 @@
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="cbxhwmode"><?php echo _("Wireless Mode") ;?></label> <label for="cbxhwmode"><?php echo _("Wireless Mode") ;?></label>
<?php getTooltip(null, 'tiphwmode', true); ?> <?php getTooltip(null, 'tiphwmode', true); ?>
<?php SelectorOptions('hw_mode', $arr80211Standard, $selectedHwMode, 'cbxhwmode', 'loadChannelSelect', $hwModeDisabled); ?> <?php SelectorOptions('hw_mode', $arr80211Standard, $selectedHwMode, 'cbxhwmode', 'getChannel'); ?>
<div id="hwmode" data-tooltip="<?php echo _("The 802.11ac 5 GHz option is disabled until a compatible wireless regulatory domain is set."); ?>"></div> <div id="hwmode" data-tooltip="<?php echo _("The 802.11ac 5 GHz option is disabled until a compatible wireless regulatory domain is set."); ?>"></div>
</div> </div>
</div> </div>