diff --git a/ajax/networking/get_frequencies.php b/ajax/networking/get_frequencies.php index 156413b0..8926bfb1 100644 --- a/ajax/networking/get_frequencies.php +++ b/ajax/networking/get_frequencies.php @@ -1,43 +1,14 @@ parseIwInfo($iface); - // 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); + echo json_encode($supportedFrequencies); } diff --git a/ajax/networking/get_nl80211_band.php b/ajax/networking/get_nl80211_band.php new file mode 100644 index 00000000..156413b0 --- /dev/null +++ b/ajax/networking/get_nl80211_band.php @@ -0,0 +1,43 @@ +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); +} + diff --git a/app/css/custom.php b/app/css/custom.php index 33a59c58..d9dcbf1c 100644 --- a/app/css/custom.php +++ b/app/css/custom.php @@ -42,7 +42,7 @@ body { background-color: #fff; } -.btn-primary.disabled { +.btn-primary:disabled { color: !important; border-color: !important; background-color: #fff !important; diff --git a/app/js/custom.js b/app/js/custom.js index 175a609a..3c2a45f4 100644 --- a/app/js/custom.js +++ b/app/js/custom.js @@ -185,7 +185,7 @@ function contentLoaded() { setupBtns(); break; case "hostapd_conf": - loadChannel(); + getChannel(); setHardwareModeTooltip(); break; case "dhcpd_conf": @@ -264,13 +264,6 @@ function setDHCPToggles(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) { var csrfToken = $('meta[name=csrf_token]').attr('content'); $.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); }); -/* -Sets the wirelss channel select options based on hw_mode and country_code. - -Methodology: In North America up to channel 11 is the maximum allowed WiFi 2.4Ghz channel, -except for the US that allows channel 12 & 13 in low power mode with additional restrictions. -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($("").attr("value", value).text(value)); - }); - channel_select.val(selected); + // Retrieves the 'channel' value specified in hostapd.conf +function getChannel() { + $.get('ajax/networking/get_channel.php',function(data){ + jsonData = JSON.parse(data); + loadChannelSelect(jsonData); }); } -/* 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($("").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($("").attr("value", value.Channel).text(value.Channel)); + }); + channel_select.val(selected); + } + }); +} + +/* Sets hardware mode tooltip text for selected interface + * and calls loadChannelSelect() */ function setHardwareModeTooltip() { var iface = $('#cbxinterface').val(); @@ -447,7 +463,7 @@ function setHardwareModeTooltip() { if ($('#cbxhwmode').find('option[value="ac"]').prop('disabled') == true ) { 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); $('#tiphwmode').attr('data-original-title', responseText + '\n' + hwmodeText ); }); diff --git a/config/config.php b/config/config.php index cf9b7831..74b75da3 100755 --- a/config/config.php +++ b/config/config.php @@ -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_DNS', 'one.one.one.one'); -// Constants for the 5GHz wireless regulatory domain. -define('RASPI_5GHZ_ISO_ALPHA2', array('NL','US')); -define('RASPI_5GHZ_MAX_CHANNEL', 165); +// Constant for the 5GHz wireless regulatory domain +define("HOSTAPD_5GHZ_CHANNEL_MIN", 100); // Enable basic authentication for the web admin. define('RASPI_AUTH_ENABLED', true); diff --git a/config/wireless.json b/config/wireless.json deleted file mode 100644 index 7744c352..00000000 --- a/config/wireless.json +++ /dev/null @@ -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 ] - } -}} - diff --git a/includes/defaults.php b/includes/defaults.php index 871018c7..ca2bfd04 100755 --- a/includes/defaults.php +++ b/includes/defaults.php @@ -36,9 +36,11 @@ $defaults = [ 'RASPI_ACCESS_CHECK_IP' => '1.1.1.1', 'RASPI_ACCESS_CHECK_DNS' => 'one.one.one.one', - // Constants for the 5GHz wireless regulatory domain - 'RASPI_5GHZ_ISO_ALPHA2' => array('NL','US'), - 'RASPI_5GHZ_MAX_CHANNEL' => 165, + // Constant for the 5GHz wireless regulatory domain + 'HOSTAPD_5GHZ_CHANNEL_MIN' => 100, + + // Enable basic authentication for the web admin. + 'RASPI_AUTH_ENABLED' => true, // Optional services, set to true to enable. 'RASPI_WIFICLIENT_ENABLED' => true, diff --git a/includes/functions.php b/includes/functions.php index ef48dc04..cbc28f96 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -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; +} + diff --git a/includes/hostapd.php b/includes/hostapd.php index bc3f3c8b..90ac4fcc 100755 --- a/includes/hostapd.php +++ b/includes/hostapd.php @@ -22,6 +22,9 @@ function DisplayHostAPDConfig() 'n' => '802.11n - 2.4 GHz', 'ac' => '802.11ac - 5 GHz' ]; + $languageCode = strtok($_SESSION['locale'], '_'); + $countryCodes = getCountryCodes($languageCode); + $arrSecurity = array(1 => 'WPA', 2 => 'WPA2', 3 => 'WPA+WPA2', 'none' => _("None")); $arrEncType = array('TKIP' => 'TKIP', 'CCMP' => 'CCMP', 'TKIP CCMP' => 'TKIP+CCMP'); $arrTxPower = getDefaultNetOpts('txpower','dbm'); @@ -29,7 +32,7 @@ function DisplayHostAPDConfig() exec("ip -o link show | awk -F': ' '{print $2}'", $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}'"; exec($cmd, $txpower); @@ -40,7 +43,7 @@ function DisplayHostAPDConfig() } if (!RASPI_MONITOR_ENABLED) { 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'); @@ -95,10 +98,12 @@ function DisplayHostAPDConfig() } else { $arrConfig['disassoc_low_ack_bool'] = 0; } + // assign country_code from iw reg if not set in config if (empty($arrConfig['country_code']) && isset($country_code[0])) { $arrConfig['country_code'] = $country_code[0]; } + // set txpower with iw if value is non-default ('auto') if (isset($_POST['txpower'])) { if ($_POST['txpower'] != 'auto') { @@ -114,7 +119,6 @@ function DisplayHostAPDConfig() } } - $countries_5Ghz_max48ch = RASPI_5GHZ_ISO_ALPHA2; $selectedHwMode = $arrConfig['hw_mode']; if (isset($arrConfig['ieee80211n'])) { if (strval($arrConfig['ieee80211n']) === '1') { @@ -131,14 +135,6 @@ function DisplayHostAPDConfig() $selectedHwMode = 'w'; } } - if (!in_array($arrConfig['country_code'], $countries_5Ghz_max48ch)) { - $hwModeDisabled = 'ac'; - if ($selectedHwMode === $hwModeDisabled) { - unset($selectedHwMode); - } - } else { - $hwModeDisabled = null; - } echo renderTemplate( "hostapd", compact( @@ -157,7 +153,7 @@ function DisplayHostAPDConfig() "arrHostapdConf", "operatingSystem", "selectedHwMode", - "hwModeDisabled" + "countryCodes" ) ); } @@ -169,10 +165,11 @@ function DisplayHostAPDConfig() * @param array $enc_types * @param array $modes * @param string $interface + * @param string $reg_domain * @param object $status * @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. // 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) { $status->addMessage('Country code must be blank or two characters', 'danger'); $good_input = false; + } else { + $country_code = $_POST['country_code']; } if (isset($_POST['beaconintervalEnable'])) { if (!is_numeric($_POST['beacon_interval'])) { @@ -318,6 +317,10 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status) if ($good_input) { $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 $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.= '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') { $config.= 'hw_mode=g'.PHP_EOL; $config.= 'ieee80211n=1'.PHP_EOL; @@ -458,7 +469,7 @@ function updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable $config.= 'ieee80211h=0'.PHP_EOL; $config.= 'vht_capab=[MAX-AMSDU-3839][SHORT-GI-80]'.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') { $config.= 'ieee80211w=2'.PHP_EOL; $config.= 'wpa_key_mgmt=WPA-EAP-SHA256'.PHP_EOL; @@ -489,3 +500,18 @@ function updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable 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; +} + diff --git a/installers/common.sh b/installers/common.sh index 70ed7006..a4b9c17c 100755 --- a/installers/common.sh +++ b/installers/common.sh @@ -241,7 +241,7 @@ function _install_dependencies() { # Set dconf-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 - 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 } diff --git a/locale/en_US/LC_MESSAGES/messages.po b/locale/en_US/LC_MESSAGES/messages.po index fd35b6c7..31337290 100644 --- a/locale/en_US/LC_MESSAGES/messages.po +++ b/locale/en_US/LC_MESSAGES/messages.po @@ -709,6 +709,9 @@ msgstr "Routing table" msgid "raw output" msgstr "raw output" +msgid "Setting wireless regulatory domain to %s" +msgstr "Setting wireless regulatory domain to %s" + #: includes/system.php msgid "System Information" msgstr "System Information" diff --git a/src/RaspAP/Parsers/IwParser.php b/src/RaspAP/Parsers/IwParser.php new file mode 100644 index 00000000..a73a8f38 --- /dev/null +++ b/src/RaspAP/Parsers/IwParser.php @@ -0,0 +1,100 @@ + + * @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; + } + } +} + diff --git a/templates/hostapd.php b/templates/hostapd.php index 87a0c761..ce3dea1a 100755 --- a/templates/hostapd.php +++ b/templates/hostapd.php @@ -1,6 +1,6 @@ - " /> + " /> " data-toggle="modal" data-target="#hostapdModal"/> diff --git a/templates/hostapd/advanced.php b/templates/hostapd/advanced.php index d765d34c..b8ca3469 100644 --- a/templates/hostapd/advanced.php +++ b/templates/hostapd/advanced.php @@ -73,257 +73,7 @@