mirror of https://github.com/aredn/aredn.git
1072 lines
33 KiB
Perl
Executable File
1072 lines
33 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
=for comment
|
|
|
|
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
|
|
Copyright (C) 2015 Conrad Lara
|
|
See Contributors file for additional contributors
|
|
|
|
Copyright (c) 2013 David Rivenburg et al. BroadBand-HamNet
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation version 3 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Additional Terms:
|
|
|
|
Additional use restrictions exist on the AREDN(TM) trademark and logo.
|
|
See AREDNLicense.txt for more info.
|
|
|
|
Attributions to the AREDN Project must be retained in the source code.
|
|
If importing this code into a new or existing project attribution
|
|
to the AREDN project must be added to the source code.
|
|
|
|
You must not misrepresent the origin of the material contained within.
|
|
|
|
Modified versions must be modified to attribute to the original source
|
|
and be marked in reasonable ways as differentiate it from the original
|
|
version.
|
|
|
|
=cut
|
|
|
|
$debug = 0;
|
|
|
|
BEGIN {push @INC, '/www/cgi-bin'};
|
|
use perlfunc;
|
|
use channelmaps;
|
|
use ucifunc;
|
|
#
|
|
# load the config parms
|
|
#
|
|
|
|
# test for web connectivity (for maps)
|
|
$pingOk=is_online();
|
|
|
|
@output = ();
|
|
@errors = ();
|
|
|
|
read_postdata();
|
|
|
|
my $tz_db_strings = tz_names_hash();
|
|
my $tz_db_names = tz_names_array();
|
|
$wifiintf = get_interface("wifi");
|
|
$phy = get_wlan2phy("$wifiintf");
|
|
chomp ($phycount = `ls -1d /sys/class/ieee80211/* | wc -l`);
|
|
|
|
my @ctwo=(1,2,3,4,5,6,7,8,9,10,11);
|
|
my @cfive=(36,40,44,48,149,153,157,161,165);
|
|
|
|
if($parms{button_uploaddata})
|
|
{
|
|
my $si=`curl 'http://localnode:8080/cgi-bin/sysinfo.json?hosts=1' 2>/dev/null`;
|
|
# strip closing }\n from si
|
|
chomp($si);
|
|
chop($si);
|
|
|
|
# get olsrd topo information
|
|
my $topo=`curl 'http://localnode:9090/links' 2>/dev/null`;
|
|
chomp($topo);
|
|
# add topo subdoc and close root doc
|
|
my $newsi= sprintf "%s,\"olsr\": %s}",$si, $topo;
|
|
|
|
# PUT it to the server
|
|
my $upcurl=`curl -H 'Accept: application/json' -X PUT -d '$newsi' http://data.arednmesh.org/sysinfo`;
|
|
if($? == 0) {
|
|
push @output, "AREDN online map updated";
|
|
} else {
|
|
push @errors, "ERROR: Cannot update online map. Please ensure this node has access to the internet.";
|
|
}
|
|
}
|
|
|
|
# convert the %parms into scalars for convenience
|
|
if($parms{button_default})
|
|
{
|
|
load_cfg("/etc/config.mesh/_setup.default");
|
|
foreach(keys %cfg)
|
|
{
|
|
eval (sprintf "\$$_ = \"%s\"", quotemeta $cfg{$_});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach(keys %parms)
|
|
{
|
|
next unless /^\w+$/;
|
|
$parms{$_} =~ s/^\s+//;
|
|
$parms{$_} =~ s/\s+$//;
|
|
eval (sprintf "\$$_ = \"%s\"", quotemeta $parms{$_});
|
|
}
|
|
|
|
if($button_reset or not keys %parms)
|
|
{
|
|
load_cfg("/etc/config.mesh/_setup");
|
|
foreach(keys %cfg)
|
|
{
|
|
eval (sprintf "\$$_ = \"%s\"", quotemeta $cfg{$_});
|
|
}
|
|
$wifi2_key =~ s/([a-f0-9][a-f0-9])/chr(hex($1))/eg;
|
|
$wifi2_ssid =~ s/([a-f0-9][a-f0-9])/chr(hex($1))/eg;
|
|
}
|
|
}
|
|
|
|
if($parms{button_reset} or $parms{button_default} or (not $nodetac and not keys %parms))
|
|
{
|
|
$nodetac = nvram_get("node");
|
|
$tactical = nvram_get("tactical");
|
|
$nodetac .= " / $tactical" if $tactical;
|
|
}
|
|
else
|
|
{
|
|
$nodetac = $parms{nodetac};
|
|
}
|
|
|
|
# make sure unchecked checkboxes are accounted for
|
|
foreach(qw(lan_dhcp olsrd_bridge olsrd_gw wifi2_enable lan_dhcp_noroute))
|
|
{
|
|
$parms{$_} = 0 unless $parms{$_};
|
|
}
|
|
|
|
# lan is always static
|
|
$lan_proto = "static";
|
|
|
|
# enforce direct mode settings
|
|
# (formerly known as dmz mode)
|
|
$dmz_mode = 2 if $dmz_mode != 0 and $dmz_mode < 2;
|
|
$dmz_mode = 5 if $dmz_mode > 5;
|
|
|
|
if($dmz_mode)
|
|
{
|
|
$ipshift = (ip2decimal($wifi_ip) << $dmz_mode) & 0xffffff;
|
|
$dmz_lan_ip = add_ip_address("1" . decimal2ip($ipshift), 1);
|
|
$dmz_lan_mask = decimal2ip(0xffffffff << $dmz_mode);
|
|
($octet) = $dmz_lan_ip =~ /\d+\.\d+\.\d+\.(\d+)/;
|
|
$dmz_dhcp_start = $octet + 1;
|
|
$dmz_dhcp_end = $dmz_dhcp_start + (1 << $dmz_mode) - 4;
|
|
$parms{dmz_lan_ip} = $dmz_lan_ip;
|
|
$parms{dmz_lan_mask} = $dmz_lan_mask;
|
|
$parms{dmz_dhcp_start} = $dmz_dhcp_start;
|
|
$parms{dmz_dhcp_end} = $dmz_dhcp_end;
|
|
}
|
|
|
|
# derive values which are not explicitly defined
|
|
$parms{dhcp_limit} = $dhcp_end - $dhcp_start + 1;
|
|
$parms{dmz_dhcp_limit} = $dmz_dhcp_end - $dmz_dhcp_start + 1;
|
|
|
|
#
|
|
# get the active wifi settings on a fresh page load
|
|
#
|
|
|
|
unless($parms{reload})
|
|
{
|
|
($wifi_txpower) = `iwinfo $wifiintf info 2>/dev/null` =~ /Tx-Power: (\d+)/;
|
|
(my $doesiwoffset) = `iwinfo $wifiintf info 2>/dev/null` =~ /TX power offset: (\d+)/;
|
|
if ( $doesiwoffset ) {
|
|
$wifi_txpower -= $1;
|
|
}
|
|
}
|
|
|
|
# sanitize the active settings
|
|
$wifi_txpower = wifi_maxpower($wifi_channel) if not defined $wifi_txpower or $wifi_txpower > wifi_maxpower($wifi_channel);
|
|
$wifi_txpower = 1 if $wifi_txpower < 1;
|
|
$wifi_distance = 0 unless defined $wifi_distance;
|
|
$wifi_distance = 0 if $wifi_distance =~ /\D/;
|
|
|
|
# stuff the sanitized data back into the parms hash
|
|
# so they get saved correctly
|
|
$parms{wifi_distance} = $wifi_distance;
|
|
$parms{wifi_txpower} = $wifi_txpower;
|
|
|
|
#
|
|
# apply the wifi settings
|
|
#
|
|
|
|
if($parms{button_apply} or $parms{button_save})
|
|
{
|
|
if($wifi_distance < 1 or $wifi_distance =~ /\D/)
|
|
{
|
|
push (@errors, "invalid distance value");
|
|
} else {
|
|
$cmd = "";
|
|
$cmd .= "iw phy ${phy} set distance $wifi_distance >/dev/null 2>&1;";
|
|
$cmd .= "iw dev $wifiintf set txpower fixed ${wifi_txpower}00 >/dev/null 2>&1;";
|
|
system $cmd;
|
|
}
|
|
|
|
}
|
|
|
|
if($parms{button_updatelocation})
|
|
{
|
|
# Process gridsquare -----------------------------------
|
|
if($parms{gridsquare})
|
|
{
|
|
# validate values
|
|
if($parms{gridsquare} =~ /^[A-Z][A-Z]\d\d[a-z][a-z]$/)
|
|
{
|
|
# delete/define file
|
|
unlink("/etc/gridsquare") if(-f "/etc/gridsquare");
|
|
my $rcgood=open(my $gs, ">", "/etc/gridsquare");
|
|
push @errors, "Cannot open gridsquare file" unless $rcgood;
|
|
print $gs "$parms{gridsquare}\n";
|
|
close($gs);
|
|
push @output, "Gridsquare updated.\n";
|
|
} else {
|
|
push @errors, "ERROR: Gridsquare format is: 2-uppercase letters, 2-digits, 2-lowercase letters. (AB12cd)\n";
|
|
}
|
|
} else {
|
|
unlink("/etc/gridsquare") if(-f "/etc/gridsquare");
|
|
push @output, "Gridsquare purged.\n";
|
|
}
|
|
|
|
# Process LAT/LNG ---------------------------------------------
|
|
if($parms{latitude} and $parms{longitude})
|
|
{
|
|
# validate values
|
|
if($parms{latitude} =~ /^([-+]?\d{1,2}([.]\d+)?)$/ and $parms{longitude} =~ /^([-+]?\d{1,3}([.]\d+)?)$/) {
|
|
if($parms{latitude} >= -90 and $parms{latitude} <= 90 and $parms{longitude} >= -180 and $parms{longitude} <= 180) {
|
|
# delete/define file
|
|
unlink("/etc/latlon") if(-f "/etc/latlon");
|
|
$rcgood=open(my $ll, ">", "/etc/latlon");
|
|
push @errors, "Cannot open lat/lon file" unless $rcgood;
|
|
print $ll "$parms{latitude}\n";
|
|
print $ll "$parms{longitude}\n";
|
|
close($ll);
|
|
push @output, "Lat/lon updated.\n";
|
|
} else {
|
|
push @errors, "ERROR: Lat/lon values must be between -90/90 and -180/180, respectively.\n";
|
|
}
|
|
} else {
|
|
push @errors, "ERROR: Lat/lon format is decimal: (ex. 30.121456 or -95.911154)\n";
|
|
}
|
|
} else {
|
|
unlink("/etc/latlon") if(-f "/etc/latlon");
|
|
push @output, "Lat/lon purged.\n";
|
|
}
|
|
}
|
|
|
|
#
|
|
# retrieve location data
|
|
#
|
|
if(-f "/etc/latlon")
|
|
{
|
|
$rcgood=open(FILE, "/etc/latlon");
|
|
push @errors, "ERROR: reading lat/lon data\n" unless $rcgood;
|
|
while(<FILE>){
|
|
chomp;
|
|
push @lines,$_;
|
|
}
|
|
close(FILE);
|
|
$lat=$lines[0];
|
|
$lon=$lines[1];
|
|
}
|
|
|
|
@lines=();
|
|
if(-f "/etc/gridsquare")
|
|
{
|
|
$rcgood=open(FILE, "/etc/gridsquare");
|
|
push @errors, "ERROR: reading gridsquare data\n" unless $rcgood;
|
|
while(<FILE>){
|
|
chomp;
|
|
push @lines,$_;
|
|
}
|
|
close(FILE);
|
|
$gridsquare=$lines[0];
|
|
}
|
|
|
|
|
|
# validate and save configuration
|
|
if($parms{button_save})
|
|
{
|
|
# lookup the tz string for the selected time_zone
|
|
$time_zone = $$tz_db_strings{$time_zone_name};
|
|
$parms{time_zone} = $time_zone;
|
|
|
|
if(not validate_netmask($wifi_mask))
|
|
{
|
|
push @errors, "invalid Mesh netmask";
|
|
}
|
|
elsif(not validate_ip_netmask($wifi_ip, $wifi_mask))
|
|
{
|
|
push @errors, "invalid Mesh IP address";
|
|
}
|
|
|
|
push (@errors, "invalid Mesh RF SSID") unless length $wifi_ssid <= 32;
|
|
|
|
if ( is_channel_valid($wifi_channel) != 1 )
|
|
{
|
|
push (@errors, "invalid Mesh RF channel")
|
|
}
|
|
|
|
if ( !is_wifi_chanbw_valid($wifi_chanbw,$wifi_ssid) )
|
|
{
|
|
push (@errors, "Invalid Mesh RF channel width");
|
|
$wifi_chanbw = 20;
|
|
}
|
|
|
|
$wifi_country_validated=0;
|
|
foreach my $testcountry (split(',',"00,HX,AD,AE,AL,AM,AN,AR,AT,AU,AW,AZ,BA,BB,BD,BE,BG,BH,BL,BN,BO,BR,BY,BZ,CA,CH,CL,CN,CO,CR,CY,CZ,DE,DK,DO,DZ,EC,EE,EG,ES,FI,FR,GE,GB,GD,GR,GL,GT,GU,HN,HK,HR,HT,HU,ID,IE,IL,IN,IS,IR,IT,JM,JP,JO,KE,KH,KP,KR,KW,KZ,LB,LI,LK,LT,LU,LV,MC,MA,MO,MK,MT,MY,MX,NL,NO,NP,NZ,OM,PA,PE,PG,PH,PK,PL,PT,PR,QA,RO,RS,RU,RW,SA,SE,SG,SI,SK,SV,SY,TW,TH,TT,TN,TR,UA,US,UY,UZ,VE,VN,YE,ZA,ZW")) {
|
|
if ( $testcountry eq $wifi_country ) {
|
|
$wifi_country_validated=1;
|
|
last;
|
|
}
|
|
}
|
|
if ( $wifi_country_validated ne 1 ) {
|
|
$wifi_country="00";
|
|
push (@errors, "Invalid country");
|
|
}
|
|
|
|
|
|
if($lan_proto eq "static")
|
|
{
|
|
if(not validate_netmask($lan_mask))
|
|
{
|
|
push @errors, "invalid LAN netmask";
|
|
}
|
|
elsif($lan_mask !~ /^255\.255\.255\./)
|
|
{
|
|
push @errors, "LAN netmask must begin with 255.255.255";
|
|
}
|
|
elsif(not validate_ip_netmask($lan_ip, $lan_mask))
|
|
{
|
|
push @errors, "invalid LAN IP address";
|
|
}
|
|
else
|
|
{
|
|
if($lan_dhcp)
|
|
{
|
|
my $start_addr = change_ip_address($lan_ip, $dhcp_start);
|
|
my $end_addr = change_ip_address($lan_ip, $dhcp_end);
|
|
|
|
unless(validate_ip_netmask($start_addr, $lan_mask) and
|
|
validate_same_subnet($start_addr, $lan_ip, $lan_mask))
|
|
{
|
|
push @errors, "invalid DHCP start address";
|
|
}
|
|
|
|
unless(validate_ip_netmask($end_addr, $lan_mask) and
|
|
validate_same_subnet($end_addr, $lan_ip, $lan_mask))
|
|
{
|
|
push @errors, "invalid DHCP end address";
|
|
}
|
|
|
|
if($dhcp_start > $dhcp_end)
|
|
{
|
|
push @errors, "invalid DHCP start/end addresses";
|
|
}
|
|
}
|
|
|
|
if($lan_gw and not
|
|
(validate_ip_netmask($lan_gw, $lan_mask) and
|
|
validate_same_subnet($lan_ip, $lan_gw, $lan_mask)))
|
|
{
|
|
push @errors, "invalid LAN gateway";
|
|
}
|
|
}
|
|
}
|
|
|
|
if($wan_proto eq "static")
|
|
{
|
|
if(not validate_netmask($wan_mask))
|
|
{
|
|
push @errors, "invalid WAN netmask";
|
|
}
|
|
elsif(not validate_ip_netmask($wan_ip, $wan_mask))
|
|
{
|
|
push @errors, "invalid WAN IP address";
|
|
}
|
|
else
|
|
{
|
|
unless (validate_ip_netmask($wan_gw, $wan_mask) and
|
|
validate_same_subnet($wan_ip, $wan_gw, $wan_mask))
|
|
{
|
|
push @errors, "invalid WAN gateway";
|
|
}
|
|
}
|
|
}
|
|
|
|
push (@errors, "invalid WAN DNS 1") unless validate_ip($wan_dns1);
|
|
push (@errors, "invalid WAN DNS 2") if $wan_dns2 ne "" and not validate_ip($wan_dns2);
|
|
|
|
|
|
if($passwd1 or $passwd2)
|
|
{
|
|
push (@errors, "passwords do not match") if $passwd1 ne $passwd2;
|
|
push (@errors, "passwords cannot contain '#'") if $passwd1 =~ /#/;
|
|
push (@errors, "password must be changed") if $passwd1 eq "hsmm";
|
|
}
|
|
elsif(-f "/etc/config/unconfigured")
|
|
{
|
|
push @errors, "password must be changed during initial configuration";
|
|
}
|
|
|
|
if($nodetac =~ /\//)
|
|
{
|
|
$nodetac =~ /^\s*([\w\-]+)\s*\/\s*([\w\-]+)\s*$/;
|
|
$node = $1;
|
|
$tactical = $2;
|
|
push(@errors, "invalid node/tactical name") if not $2;
|
|
}
|
|
else
|
|
{
|
|
$node = $nodetac;
|
|
$tactical = "";
|
|
push(@errors, "you must set the node name") if $node eq "";
|
|
}
|
|
|
|
if($node and ($node =~ /[^\w\-]/ or $node =~ /_/))
|
|
{
|
|
push(@errors, "invalid node name");
|
|
}
|
|
|
|
if($tactical =~ /[^\w\-]/ or $tactical =~ /_/)
|
|
{
|
|
push(@errors, "invalid tactical name");
|
|
}
|
|
|
|
if($ntp_server eq '' || validate_fqdn($ntp_server) == 0)
|
|
{
|
|
push(@errors, "invalid ntp server");
|
|
}
|
|
|
|
if( length( $wifi2_ssid ) > 32 )
|
|
{
|
|
push (@errors, "LAN Access Point SSID must be 32 or less characters ");
|
|
}
|
|
|
|
if( "$wifi2_enable" eq "1" and (length( $wifi2_key ) < 8 or length($wifi2_key) > 64) )
|
|
{
|
|
push (@errors, "LAN Access Point Password must be at least 8 charaters, up to 64");
|
|
}
|
|
if( "$wifi2_enable" eq "1" and ( $wifi2_key =~ /\'/ or $wifi2_ssid =~ /\'/ ))
|
|
{
|
|
push (@errors, "The password and ssid may not contain a single quote character.");
|
|
}
|
|
|
|
if($debug == 3) # don't save the config, just validate it
|
|
{
|
|
push (@errors, "OK") unless @errors;
|
|
}
|
|
|
|
unless(@errors)
|
|
{
|
|
$parms{node} = $node;
|
|
$parms{tactical} = $tactical;
|
|
system "touch /tmp/unconfigured" if -f "/etc/config/unconfigured";
|
|
$parms{wifi2_key} =~ s/(.)/sprintf("%x",ord($1))/eg;
|
|
$parms{wifi2_ssid} =~ s/(.)/sprintf("%x",ord($1))/eg;
|
|
$rc = save_setup("/etc/config.mesh/_setup");
|
|
$rc2 = &uci_commit("system");
|
|
if(-s "/tmp/web/save/node-setup.out")
|
|
{
|
|
push @errors, `cat /tmp/web/save/node-setup.out`;
|
|
}
|
|
elsif(not $rc)
|
|
{
|
|
push @errors, "error saving setup";
|
|
}
|
|
reboot_page("/cgi-bin/status") if -f "/tmp/unconfigured" and not @errors;
|
|
}
|
|
}
|
|
|
|
system "rm -rf /tmp/web/save";
|
|
|
|
reboot_page("/cgi-bin/status") if $parms{button_reboot};
|
|
|
|
#
|
|
# retrieve node description
|
|
#
|
|
$desc = &uci_get_indexed_option("system", "system", 0, "description");
|
|
#
|
|
# Retreive map url, css, and js locations
|
|
#
|
|
my ($rc, $maptiles, $leafletcss, $leafletjs);
|
|
($rc, $maptiles)=&uci_get_indexed_option("aredn","map",0,"maptiles");
|
|
($rc, $leafletcss)=&uci_get_indexed_option("aredn","map",0,"leafletcss");
|
|
($rc, $leafletjs)=&uci_get_indexed_option("aredn","map",0,"leafletjs");
|
|
|
|
#
|
|
# generate the page
|
|
#
|
|
|
|
http_header() unless $debug == 2;
|
|
html_header(nvram_get("node") . " setup", 0);
|
|
print "<link rel='stylesheet' href='${leafletcss}' />\n" if $pingOk;
|
|
print "<script src='${leafletjs}'></script>\n" if $pingOk;
|
|
print "</head>";
|
|
print "<body><center>\n";
|
|
|
|
print "
|
|
<script>
|
|
|
|
function findLocation() {
|
|
navigator.geolocation.getCurrentPosition(foundLocation, noLocation);
|
|
}
|
|
|
|
function foundLocation(position)
|
|
{
|
|
var jlat = position.coords.latitude;
|
|
var jlon = position.coords.longitude;
|
|
// update the fields
|
|
document.getElementsByName('latitude')[0].value=jlat.toFixed(6).toString();
|
|
document.getElementsByName('longitude')[0].value=jlon.toFixed(6).toString();
|
|
|
|
// try to update the map if Javascript libs have been loaded
|
|
if (typeof L != 'undefined') {
|
|
var latlng = L.latLng(jlat, jlon);
|
|
marker.setLatLng(latlng);
|
|
map.setView(latlng,13);
|
|
}
|
|
}
|
|
|
|
function noLocation()
|
|
{
|
|
alert('Could not find location. Try pinning it on the map.');
|
|
}
|
|
function updDist(x) {
|
|
var dvs= calcDistance(x);
|
|
var xcm=dvs['miles'];
|
|
var xc=dvs['meters'];
|
|
var xck=dvs['kilometers'];
|
|
|
|
var distBox = document.getElementById('dist');
|
|
var dist_meters=document.getElementsByName('wifi_distance')[0];
|
|
document.getElementsByName('wifi_distance_disp_miles')[0].value = xcm;
|
|
document.getElementsByName('wifi_distance_disp_km')[0].value = xck;
|
|
document.getElementsByName('wifi_distance_disp_meters')[0].value = xc;
|
|
dist_meters.value = xc;
|
|
|
|
// if default, then ALERT!
|
|
if(dist_meters.value==0) {
|
|
distBox.className = 'dist-alert';
|
|
} else {
|
|
distBox.className = 'dist-norm';
|
|
}
|
|
}
|
|
|
|
|
|
function calcDistance(x) {
|
|
// x is in KILOMETERS
|
|
var dvs = new Object();
|
|
dvs['miles']=(x*0.621371192).toFixed(2);
|
|
dvs['meters']=Math.ceil(x*1000);
|
|
dvs['kilometers']=x;
|
|
return dvs;
|
|
}";
|
|
|
|
print "
|
|
function toggleMap(toggleButton) {
|
|
var mapdiv=document.getElementById('map');
|
|
if(toggleButton.value=='hide') {
|
|
// HIDE IT
|
|
mapdiv.style.display='none';
|
|
toggleButton.value='show';
|
|
toggleButton.innerHTML='Show Map';
|
|
} else {
|
|
// SHOW IT
|
|
mapdiv.style.display='block';
|
|
toggleButton.value='hide';
|
|
toggleButton.innerHTML='Hide Map';
|
|
}
|
|
// force the map to redraw
|
|
map.invalidateSize();
|
|
return false;
|
|
}";
|
|
|
|
print "</script>";
|
|
|
|
alert_banner();
|
|
print "<form onSubmit='doSubmit();' name='mainForm' method=post action=/cgi-bin/setup enctype='multipart/form-data'>\n" unless $debug == 2;
|
|
print "<form method=post action=test>\n" if $debug == 2;
|
|
|
|
print "<table width=790>\n";
|
|
print "<tr><td>\n";
|
|
navbar("setup");
|
|
print "</td></tr>\n";
|
|
|
|
#
|
|
# control buttons
|
|
#
|
|
|
|
print "<tr><td align=center>
|
|
<a href='/help.html#setup' target='_blank'>Help</a>
|
|
|
|
<input type=submit name=button_save value='Save Changes' title='Store these settings'>
|
|
<input type=submit name=button_reset value='Reset Values' title='Revert to the last saved settings'>
|
|
<input type=submit name=button_default value='Default Values' title='Set all values to their default'>
|
|
<input type=submit name=button_reboot value=Reboot style='font-weight:bold' title='Immediately reboot this node'>
|
|
</td></tr>
|
|
<tr><td> </td></tr>\n";
|
|
|
|
# messages
|
|
if(@output)
|
|
{
|
|
# print "<tr><th>Configuration NOT saved!</th></tr>\n";
|
|
print "<tr><td align=center><table>\n";
|
|
print "<tr><td><ul style='padding-left:0'>\n";
|
|
foreach(@output) { print "<li>$_</li>\n" }
|
|
print "</ul></td></tr></table>\n";
|
|
print "</td></tr>\n";
|
|
}
|
|
|
|
if(@errors)
|
|
{
|
|
print "<tr><th>Configuration NOT saved!</th></tr>\n";
|
|
print "<tr><td align=center><table>\n";
|
|
print "<tr><td><ul style='padding-left:0'>\n";
|
|
foreach(@errors) { print "<li>$_</li>\n" }
|
|
print "</ul></td></tr></table>\n";
|
|
print "</td></tr>\n";
|
|
}
|
|
elsif($parms{button_save})
|
|
{
|
|
print "<tr><td align=center>";
|
|
print "<b>Configuration saved.</b><br><br>\n";
|
|
print "</td></tr>\n";
|
|
}
|
|
|
|
if(not @errors and -f "/tmp/reboot-required")
|
|
{
|
|
print "<tr><td align=center><h3>Reboot is required for changes to take effect</h3></td></tr>";
|
|
}
|
|
|
|
#
|
|
# node name and type, password
|
|
#
|
|
|
|
print "<tr><td align=center>\n";
|
|
print "<table cellpadding=5 border=0>
|
|
|
|
<tr>
|
|
<td>Node Name</td>
|
|
<td><input type=text name=nodetac value='$nodetac' tabindex=1 size='50'></td>
|
|
<td align=right>Password</td>
|
|
<td><input type=password name=passwd1 value='$passwd1' size=8 tabindex=2></td>";
|
|
|
|
if(0)# disable for now
|
|
{
|
|
print "<td> </td>";
|
|
print "<td align=right>Latitude</td>";
|
|
print "<td><input type=text size=8 name=aprs_lat value='$aprs_lat' tabindex=4></td>\n";
|
|
}
|
|
|
|
print "
|
|
</tr>
|
|
<tr>
|
|
<td>Node Description (optional)</td>
|
|
<td><textarea rows='2' cols='60' wrap='soft' maxlength='210' id='node_description_entry' name='description_node' tabindex='4'>$desc</textarea></td>";
|
|
push @hidden, "<input type=hidden name=config value='mesh'>";
|
|
print "
|
|
<td>Verify Password</td>
|
|
<td><input type=password name=passwd2 value='$passwd2' size=8 tabindex=3></td>";
|
|
|
|
print "
|
|
</tr>
|
|
</table>
|
|
</td></tr>";
|
|
|
|
print "<tr><td><br>";
|
|
print "<table cellpadding=5 border=1 width=100%><tr><td valign=top width=33%>\n";
|
|
|
|
#
|
|
# MESH RF settings
|
|
#
|
|
|
|
print "<table width=100% style='border-collapse: collapse;'>
|
|
<tr><th colspan=2>Mesh RF</th></tr>";
|
|
|
|
push @hidden, "<input type=hidden name=wifi_proto value='static'>";
|
|
|
|
print "<tr><td><nobr>IP Address</nobr></td>\n";
|
|
print "<td><input type=text size=15 name=wifi_ip value='$wifi_ip'></td></tr>\n";
|
|
print "<tr><td>Netmask</td>\n";
|
|
print "<td><input type=text size=15 name=wifi_mask value='$wifi_mask'></td></tr>\n";
|
|
|
|
# Reset wifi channel/bandwidth to default
|
|
if ( -f "/etc/config/unconfigured" || $parms{button_reset} ) {
|
|
my $defaultwifi = rf_default_channel();
|
|
$wifi_channel = $defaultwifi->{'channel'};
|
|
$wifi_chanbw = $defaultwifi->{'chanbw'};
|
|
}
|
|
|
|
print "<tr><td>SSID</td>\n";
|
|
print "<td><input type=text size=15 name=wifi_ssid value='$wifi_ssid'>";
|
|
print "-$wifi_chanbw-v3</td></tr>\n";
|
|
|
|
push @hidden, "<input type=hidden name=wifi_mode value='$wifi_mode'>";
|
|
|
|
print "<tr><td>Channel</td>\n";
|
|
print "<td><select name=wifi_channel>\n";
|
|
my $rfchannels=rf_channels_list();
|
|
foreach $channelnumber (sort {$a <=> $b} keys %{$rfchannels} )
|
|
{
|
|
selopt($rfchannels->{$channelnumber}, $channelnumber, $wifi_channel);
|
|
}
|
|
print "</select></td></tr>\n";
|
|
|
|
print "<tr><td>Channel Width</td>\n";
|
|
print "<td><select name=wifi_chanbw>\n";
|
|
selopt("20 MHz","20",$wifi_chanbw);
|
|
selopt("10 MHz","10",$wifi_chanbw);
|
|
selopt("5 MHz","5",$wifi_chanbw);
|
|
print "</select></td></tr>\n";
|
|
|
|
push (@hidden, "<input type=hidden name=wifi_country value='HX'>");
|
|
|
|
print "<tr><td colspan=2 align=center><hr><small>Active Settings</small></td></tr>\n";
|
|
|
|
print "<tr><td><nobr>Tx Power</nobr></td>\n";
|
|
print "<td><select name=wifi_txpower>\n";
|
|
my $txpoweroffset = wifi_txpoweroffset();
|
|
for($i = wifi_maxpower($wifi_channel); $i >= 1; --$i) { selopt($i+$txpoweroffset ." dBm", $i, $wifi_txpower) }
|
|
print "</select> <a href=\"/help.html\#power\" target=\"_blank\"><img src=\"/qmark.png\"></a></td></tr>\n";
|
|
|
|
print "<tr id='dist' class='dist-norm'><td>Distance to<br />FARTHEST Neighbor</td>\n";
|
|
|
|
$wifi_distance=int($wifi_distance); # in meters
|
|
$wifi_distance_disp_km=int($wifi_distance/1000);
|
|
$wifi_distance_disp_miles=sprintf("%.2f",$wifi_distance_disp_km*.621371192);
|
|
|
|
print "<td><input disabled size=6 type=text name='wifi_distance_disp_miles' value='$wifi_distance_disp_miles' title='Distance to the farthest neighbor'> miles<br />";
|
|
print "<input disabled size=6 type=text size=4 name='wifi_distance_disp_km' value='$wifi_distance_disp_km' title='Distance to the farthest neighbor'> kilometers<br />";
|
|
print "<input disabled size=6 type=text size=4 name='wifi_distance_disp_meters' value='$wifi_distance' title='Distance to the farthest neighbor'> meters<br />";
|
|
|
|
print "<input id='distance_slider' type='range' min='0' max='150' step='1' value='$wifi_distance_disp_km' oninput='updDist(this.value)' onchange='updDist(this.value)' /><br />";
|
|
print "<input type='hidden' size='6' name='wifi_distance' value='$wifi_distance' />";
|
|
print "</td></tr>\n";
|
|
|
|
print "<tr><td></td><td><input type=submit name=button_apply value=Apply title='Immediately use these active settings'></td></tr>\n";
|
|
|
|
print "</table></td>\n";
|
|
|
|
#
|
|
# LAN settings
|
|
#
|
|
|
|
print "<td valign=top width=33%><table width=100%>
|
|
<tr><th colspan=2>LAN</th></tr>
|
|
<tr>
|
|
<td>LAN Mode</td>
|
|
<td><select name=dmz_mode onChange='form.submit()'";
|
|
print ">\n";
|
|
selopt("NAT", 0, $dmz_mode);
|
|
selopt("1 host Direct", 2, $dmz_mode);
|
|
selopt("5 host Direct", 3, $dmz_mode);
|
|
selopt("13 host Direct", 4, $dmz_mode);
|
|
selopt("29 host Direct", 5, $dmz_mode);
|
|
print "</select></td>\n</tr>\n";
|
|
push @hidden, "<input type=hidden name=lan_proto value='static'>";
|
|
|
|
if($dmz_mode)
|
|
{
|
|
print "<tr><td><nobr>IP Address</nobr></td>";
|
|
#print "<td><input type=text size=15 name=dmz_lan_ip value='$dmz_lan_ip' disabled></td></tr>\n";
|
|
print "<td>$dmz_lan_ip</td></tr>\n";
|
|
push @hidden, "<input type=hidden name=dmz_lan_ip value='$dmz_lan_ip'>";
|
|
|
|
print "<tr><td>Netmask</td>";
|
|
#print "<td><input type=text size=15 name=dmz_lan_mask value='$dmz_lan_mask' disabled></td></tr>\n";
|
|
print "<td>$dmz_lan_mask</td></tr>\n";
|
|
push @hidden, "<input type=hidden name=dmz_lan_mask value='$dmz_lan_mask'>";
|
|
|
|
print "<tr><td><nobr>DHCP Server</nobr></td>";
|
|
print "<td><input type=checkbox name=lan_dhcp value=1";
|
|
print " checked" if $lan_dhcp;
|
|
print "></td></tr>\n";
|
|
|
|
print "<tr><td><nobr>DHCP Start</nobr></td>";
|
|
#print "<td><input type=text size=4 name=dmz_dhcp_start value='$dmz_dhcp_start' disabled></td></tr>\n";
|
|
print "<td>$dmz_dhcp_start</td></tr>\n";
|
|
push @hidden, "<input type=hidden name=dmz_dhcp_start value='$dmz_dhcp_start'>";
|
|
|
|
print "<tr><td><nobr>DHCP End</nobr></td>";
|
|
#print "<td><input type=text size=4 name=dmz_dhcp_end value='$dmz_dhcp_end' disabled></td></tr>\n";
|
|
print "<td>$dmz_dhcp_end</td></tr>\n";
|
|
|
|
push @hidden, "<input type=hidden name=lan_ip value='$lan_ip'>";
|
|
push @hidden, "<input type=hidden name=lan_mask value='$lan_mask'>";
|
|
push @hidden, "<input type=hidden name=dhcp_start value='$dhcp_start'>";
|
|
push @hidden, "<input type=hidden name=dhcp_end value='$dhcp_end'>";
|
|
push @hidden, "<input type=hidden name=lan_gw value='$lan_gw'>";
|
|
}
|
|
else
|
|
{
|
|
print "<tr><td><nobr>IP Address</nobr></td>";
|
|
print "<td><input type=text size=15 name=lan_ip value='$lan_ip'></td></tr>\n";
|
|
|
|
print "<tr><td>Netmask</td>";
|
|
print "<td><input type=text size=15 name=lan_mask value='$lan_mask'></td></tr>\n";
|
|
|
|
if($wan_proto eq "disabled")
|
|
{
|
|
print "<tr><td>Gateway</td>";
|
|
print "<td><input type=text size=15 name=lan_gw value='$lan_gw' title='leave blank if not needed'></td></tr>\n";
|
|
}
|
|
else
|
|
{
|
|
push @hidden, "<input type=hidden name=lan_gw value='$lan_gw'>";
|
|
}
|
|
print "<tr><td><nobr>DHCP Server</nobr></td>";
|
|
print "<td><input type=checkbox name=lan_dhcp value=1";
|
|
print " checked" if $lan_dhcp;
|
|
print "></td></tr>\n";
|
|
|
|
print "<tr><td><nobr>DHCP Start</nobr></td>";
|
|
print "<td><input type=text size=4 name=dhcp_start value='$dhcp_start'";
|
|
print "></td></tr>\n";
|
|
|
|
print "<tr><td><nobr>DHCP End</nobr></td>";
|
|
print "<td><input type=text size=4 name=dhcp_end value='$dhcp_end'";
|
|
print "></td></tr>\n";
|
|
|
|
push @hidden, "<input type=hidden name=dmz_lan_ip value='$dmz_lan_ip'>";
|
|
push @hidden, "<input type=hidden name=dmz_lan_mask value='$dmz_lan_mask'>";
|
|
push @hidden, "<input type=hidden name=dmz_dhcp_start value='$dmz_dhcp_start'>";
|
|
push @hidden, "<input type=hidden name=dmz_dhcp_end value='$dmz_dhcp_end'>";
|
|
|
|
}
|
|
|
|
print "<tr><td colspan=2><hr></hr></td></tr>";
|
|
|
|
if ( $phycount > 1 ) {
|
|
|
|
# determine AP's band
|
|
if ( "$phy" eq "phy0" ) { $APphy="phy1"; }
|
|
else { $APphy="phy0"; }
|
|
$rc3 = system("iw phy ${APphy} info | grep -q '5180 MHz > /dev/null");
|
|
undef @chan;
|
|
if ( $rc3 ) {
|
|
@chan=@cfive;
|
|
}
|
|
else {
|
|
@chan=@ctwo;
|
|
}
|
|
|
|
print "<tr><th colspan=2>LAN Access Point</th></tr>";
|
|
print "<tr><td>Enable</td>";
|
|
print "<td><input type=checkbox name=wifi2_enable value=1";
|
|
print " checked" if $wifi2_enable;
|
|
print "></td></tr>\n";
|
|
|
|
print "<tr><td>SSID</td>\n";
|
|
print "<td><input type=text size=15 name=wifi2_ssid value='$wifi2_ssid'></td></tr>\n";
|
|
|
|
print "<tr><td>Channel</td>\n";
|
|
print "<td><select name=wifi2_channel>\n";
|
|
for my $i (0 .. $#chan )
|
|
{
|
|
selopt($chan[$i], $chan[$i], $wifi2_channel);
|
|
}
|
|
|
|
print "</select></td></tr>\n";
|
|
|
|
print "<tr><td>Encryption</td>\n";
|
|
print "<td><select name=wifi2_encryption>\n";
|
|
selopt("WPA2 PSK", "psk2", $wifi2_encryption);
|
|
selopt("WPA PSK", "psk", $wifi2_encryption);
|
|
print "</select></td></tr>\n";
|
|
print "<tr><td>Password</td>\n";
|
|
print "<td><input type=password size=15 name=wifi2_key value='$wifi2_key'>";
|
|
print "</td></tr>\n";
|
|
}
|
|
|
|
if(0) # disable for now
|
|
{
|
|
print "<tr><td colspan=2><hr></td></tr>\n";
|
|
print "<tr><td><nobr><i>Mesh Bridge</i></nobr></td>\n";
|
|
print "<td><input type=checkbox name=olsrd_bridge value=1";
|
|
print " checked" if $olsrd_bridge;
|
|
print "></td></tr>\n";
|
|
}
|
|
|
|
print "</table></td>\n";
|
|
|
|
#
|
|
# WAN settings
|
|
#
|
|
|
|
print "<td valign=top width=33%><table width=100%>
|
|
<tr><th colspan=2>WAN</th></tr>
|
|
<tr>
|
|
<td width=50%>Protocol</td>\n";
|
|
|
|
print "<td><select name=wan_proto onChange='form.submit()'>\n";
|
|
|
|
selopt("Static", "static", $wan_proto);
|
|
selopt("DHCP", "dhcp", $wan_proto);
|
|
selopt("disabled", "disabled", $wan_proto);
|
|
print "</select></td>\n</tr>\n";
|
|
|
|
if($wan_proto eq "static")
|
|
{
|
|
print "<tr><td><nobr>IP Address</nobr></td>\n";
|
|
print "<td><input type=text size=15 name=wan_ip value='$wan_ip'></td></tr>\n";
|
|
print "<tr><td>Netmask</td>\n";
|
|
print "<td><input type=text size=15 name=wan_mask value='$wan_mask'></td></tr>\n";
|
|
print "<tr><td>Gateway</td>\n";
|
|
print "<td><input type=text size=15 name=wan_gw value='$wan_gw'></td></tr>\n";
|
|
}
|
|
else
|
|
{
|
|
push @hidden, "<input type=hidden name=wan_ip value='$wan_ip'>";
|
|
push @hidden, "<input type=hidden name=wan_mask value='$wan_mask'>";
|
|
push @hidden, "<input type=hidden name=wan_gw value='$wan_gw'>";
|
|
}
|
|
|
|
print "<tr><td><nobr>DNS 1</nobr></td>\n";
|
|
print "<td><input type=text size=15 name=wan_dns1 value='$wan_dns1'></td></tr>\n";
|
|
print "<tr><td><nobr>DNS 2</nobr></td>\n";
|
|
print "<td><input type=text size=15 name=wan_dns2 value='$wan_dns2'></td></tr>\n";
|
|
|
|
print "<tr><td colspan=2><hr></td></tr>\n";
|
|
print "<tr><th colspan=2>Advanced WAN Access</th></tr>";
|
|
if ( $wan_proto ne "disabled" ) {
|
|
print "<tr><td><nobr>Allow others to<br>use my WAN</td>\n";
|
|
print "<td><input type=checkbox name=olsrd_gw value=1 title='Allow this node to provide internet access to other mesh users'";
|
|
print " checked" if $olsrd_gw;
|
|
print "></td></tr>\n";
|
|
} else {
|
|
push @hidden, "<input type=hidden name=olsrd_gw value='0'>";
|
|
}
|
|
print "<tr><td><nobr>Prevent LAN devices<br>from accessing WAN</td>\n";
|
|
print "<td><input type=checkbox name=lan_dhcp_noroute value=1 title='Disable LAN devices to access the internet'";
|
|
print " checked" if ($lan_dhcp_noroute);
|
|
print "></td></tr>\n";
|
|
|
|
print "</table>
|
|
|
|
</td></tr>
|
|
</table><br>
|
|
|
|
</td></tr>\n";
|
|
|
|
#
|
|
# Optional Settings
|
|
#
|
|
|
|
print "<tr><td align=center>\n";
|
|
print "<table cellpadding=5 border=0><tr><th colspan=4>Optional Settings</th></tr>";
|
|
print "<tr><td colspan=4><hr /></td></tr>";
|
|
print "<tr><td align=left>Latitude</td><td><input type=text name=latitude size=10 value='$lat' title='Latitude value (in decimal) (ie. 30.312354)' /></td>";
|
|
print "<td align='right' colspan='2'>";
|
|
|
|
print "<button type='button' id='findlocation' value='findloc' onClick='findLocation();'>Find Me!</button> ";
|
|
print "<input type=submit name='button_updatelocation' value='Apply Location Settings' title='Immediately use these location settings'>";
|
|
print " <button type='button' id='hideshowmap' value='show' onClick='toggleMap(this);'>Show Map</button> ";
|
|
if($pingOk)
|
|
{
|
|
print "<input type='submit' name='button_uploaddata' value='Upload data to AREDN Servers' /> ";
|
|
} else {
|
|
print "<button disabled type='button' title='Only available if this node has internet access'>Upload data to AREDN Servers</button> ";
|
|
}
|
|
|
|
print "</td>\n";
|
|
print "<tr><td align=left>Longitude</td><td><input type=text name=longitude size=10 value='$lon' title='Longitude value (in decimal) (ie. -95.334454)' /></td>";
|
|
print "<td align=left>Grid Square</td><td align='left'><input type=text name=gridsquare maxlength=6 size=6 value='$gridsquare' title='Gridsquare value (ie. AB12cd)' /></td></tr>\n";
|
|
print "<tr><td colspan=4><div id='map' style='height: 200px; display: none;'></div></td></tr>";
|
|
print "<tr><td colspan=4><hr /></td></tr>";
|
|
print "<tr>
|
|
<td>Timezone</td>
|
|
<td><select name=time_zone_name tabindex=10>\n";
|
|
|
|
foreach my $tz (@$tz_db_names) {
|
|
$name = $tz;
|
|
$name =~ s/\_/ /g;
|
|
selopt($name, $tz, $time_zone_name);
|
|
}
|
|
|
|
print "</select></td><td align=left>NTP Server</td><td><input type=text name=ntp_server size=20 value='$ntp_server'></td>";
|
|
|
|
print "</table></td></tr>";
|
|
|
|
|
|
|
|
print "</table>\n";
|
|
|
|
push @hidden, "<input type=hidden name=reload value=1>";
|
|
push @hidden, "<input type=hidden name=dtdlink_ip value='$dtdlink_ip'>";
|
|
foreach(@hidden) { print "$_\n" }
|
|
|
|
print "</form></center>\n";
|
|
|
|
show_debug_info();
|
|
|
|
if($debug)
|
|
{
|
|
print "<br><b>config</b><br>\n";
|
|
foreach(sort keys %cfg)
|
|
{
|
|
$tmp = $cfg{$_};
|
|
$tmp =~ s/ /\(space\)/g;
|
|
if($cfg{$_} eq "") { print "$_ = (null)<br>\n" }
|
|
else { print "$_ = $tmp<br>\n" }
|
|
}
|
|
}
|
|
|
|
show_parse_errors();
|
|
|
|
page_footer();
|
|
|
|
print <<EOF;
|
|
<script>
|
|
|
|
function doSubmit() {
|
|
var desc_text = document.mainForm.description_node.value;
|
|
var singleLine = desc_text.replace(new RegExp( "\\n", "g" ), " ");
|
|
document.mainForm.description_node.value = singleLine;
|
|
return true;
|
|
}
|
|
|
|
var map = L.map('map').setView([0.0, 0.0], 1);
|
|
var dotIcon = L.icon({iconUrl: '/dot.png'});
|
|
EOF
|
|
print "L.tileLayer('$maptiles',";
|
|
print <<EOF;
|
|
{
|
|
maxZoom: 18,
|
|
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
|
|
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
|
|
'Imagery ©<a href="http://mapbox.com">Mapbox</a>',
|
|
id: 'mapbox.streets'
|
|
}).addTo(map);
|
|
|
|
var marker;
|
|
|
|
function onMapClick(e) {
|
|
marker= new L.marker(e.latlng.wrap(),{draggable: true, icon: dotIcon});
|
|
map.addLayer(marker);
|
|
document.getElementsByName('latitude')[0].value=e.latlng.wrap().lat.toFixed(6).toString();
|
|
document.getElementsByName('longitude')[0].value=e.latlng.wrap().lng.toFixed(6).toString();
|
|
map.off('click', onMapClick);
|
|
marker.on('drag', onMarkerDrag);
|
|
}
|
|
EOF
|
|
|
|
if($lat and $lon)
|
|
{
|
|
print "marker= new L.marker([$lat,$lon],{draggable: true, icon: dotIcon});";
|
|
print "map.addLayer(marker);";
|
|
print "map.setView([$lat,$lon],13);";
|
|
print "marker.on('drag', onMarkerDrag);";
|
|
} else {
|
|
print "map.on('click', onMapClick);";
|
|
}
|
|
|
|
print <<EOF;
|
|
function onMarkerDrag(e) {
|
|
var m = e.target;
|
|
var p = m.getLatLng().wrap();
|
|
document.getElementsByName('latitude')[0].value=p.lat.toFixed(6).toString();
|
|
document.getElementsByName('longitude')[0].value=p.lng.toFixed(6).toString();
|
|
}
|
|
</script>
|
|
EOF
|
|
#}
|
|
print "</body>\n";
|
|
print "</html>\n";
|