#!/usr/bin/perl =for commnet 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 . 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 conained 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; # # load the config parms # read_postdata(); ($config = $parms{config}) or ($config = nvram_get("config") and -d "/etc/config.$config") or ($config = "mesh"); # convert the %parms into scalars for convenience if($parms{button_default}) { load_cfg("/etc/config.$config/_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 $config ne $oldconfig) { load_cfg("/etc/config.$config/_setup"); foreach(keys %cfg) { eval (sprintf "\$$_ = \"%s\"", quotemeta $cfg{$_}); } } } 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 wifi_hidden)) { $parms{$_} = 0 unless $parms{$_}; } # lan is always static $lan_proto = "static"; # enforce direct mode settings # (formerly known as dmz mode) $dmz_mode = 0 unless $config eq "mesh"; $dmz_mode = 2 if $dmz_mode != 0 and $dmz_mode < 2; $dmz_mode = 4 if $dmz_mode > 4; 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_limit = $dhcp_end - $dhcp_start + 1; $parms{dmz_dhcp_limit} = $dmz_dhcp_limit = $dmz_dhcp_end - $dmz_dhcp_start + 1; # # get the active wifi settings on a fresh page load # unless($parms{reload}) { my $wifiintf = get_interface("wifi"); ($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; } if (wifi_useschains()){ $wifi_txant = `cat /sys/kernel/debug/ieee80211/phy0/ath9k/tx_chainmask`; $wifi_rxant = `cat /sys/kernel/debug/ieee80211/phy0/ath9k/rx_chainmask`; $wifi_txant = hex($wifi_txant); $wifi_rxant = hex($wifi_rxant); } else { foreach ( `iw phy phy0 info` ) { next unless /Configured Antennas: TX 0x([\d]+) RX 0x([\d]+)/; $wifi_txant = $1; $wifi_rxant = $2; } } $slottime = ""; } # sanitize the active settings $valid_ant = wifi_validant(); $wifi_txpower = wifi_maxpower() if not defined $wifi_txpower or $wifi_txpower > wifi_maxpower(); $wifi_txpower = 1 if $wifi_txpower < 1; $wifi_rxant = wifi_defaultant() if not defined $wifi_rxant or not exists $valid_ant->{$wifi_rxant}; $wifi_txant = wifi_defaultant() if not defined $wifi_txant or not exists $valid_ant->{$wifi_txant}; $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; $parms{wifi_txant} = $wifi_txant; $parms{wifi_rxant} = $wifi_rxant; # # apply the wifi settings # if($parms{button_apply} or $parms{button_save}) { my $wifiintf = get_interface("wifi"); $cmd = ""; if(wifi_useschains()){ $cmd .= "echo $wifi_rxant > /sys/kernel/debug/ieee80211/phy0/ath9k/rx_chainmask;"; $cmd .= "echo $wifi_txant > /sys/kernel/debug/ieee80211/phy0/ath9k/tx_chainmask;"; } else { $cmd .= "ifdown wifi >/dev/null 2>&1;"; $cmd .= "ifdown wifi_mon >/dev/null 2>&1;"; $cmd .= "iw phy phy0 set antenna $wifi_txantenna $wifi_rxantenna >/dev/null 2>&1;"; $cmd .= "ifup wifi >/dev/null 2>&1;"; $cmd .= "ifup wifi_mon >/dev/null 2>&1;"; } $cmd .= "iw phy phy0 set distance $wifi_distance >/dev/null 2>&1;"; $cmd .= "iw dev $wifiintf set txpower fixed ${wifi_txpower}00 >/dev/null 2>&1;"; system $cmd; } # validate and save configuration @errors = (); if($parms{button_save}) { if($wifi_proto eq "static") { if(not validate_netmask($wifi_mask)) { push @errors, "invalid WiFi netmask"; } elsif(not validate_ip_netmask($wifi_ip, $wifi_mask)) { push @errors, "invalid WiFi IP address"; } } if ($config eq "mesh"){ push (@errors, "invalid WiFi SSID") unless length $wifi_ssid <= 27; } else { push (@errors, "invalid WiFi SSID") unless length $wifi_ssid <= 32; } if ( is_channel_valid($wifi_channel) != 1 ) { push (@errors, "invalid WiFi channel") } if ( !is_wifi_chanbw_valid($wifi_chanbw,$wifi_ssid) ) { push (@errors, "Invalid WiFi channel width"); $wifi_chanbw = 20; } push (@errors, "invalid WiFi distance") if $wifi_distance < 0 or $wifi_distance =~ /\D/; $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; break; } } 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($aprs_lat or $aprs_lon) { push (@errors, "invalid latitude") unless validate_latitude($aprs_lat); push (@errors, "invalid longitude") unless validate_longitude($aprs_lon); } 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($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"; $rc = save_setup("/etc/config.$config/_setup"); 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}; # # generate the page # http_header() unless $debug == 2; html_header(nvram_get("node") . " setup", 1); print "
\n"; alert_banner(); print "
\n" unless $debug == 2; print "\n" if $debug == 2; print "\n"; print "\n"; # # control buttons # print "\n"; # messages if(@errors) { print "\n"; print "\n"; } elsif($parms{button_save}) { print "\n"; } if(not @errors and -f "/tmp/reboot-required") { print ""; } # # node name and type, password # print ""; if($config ne "mesh") { print ""; } print " \n"; print "
\n"; navbar("setup"); print "
Help          
 
Configuration NOT saved!
\n"; print "
    \n"; foreach(@errors) { print "
  • $_
  • \n" } print "
\n"; print "
"; print "Configuration saved.

\n"; print "

Reboot is required for changes to take effect

\n"; print ""; if(0)#$config eq "mesh") { print ""; print ""; print "\n"; } print " "; if(0)#$config eq "mesh") { print ""; print ""; print "\n"; } print "
Node Name Password  Latitude
Node Type Verify Password  Longitude
"; print "This node type will be removed in a future release -- See release notes"; print "

\n"; # # LAN settings # print "\n"; # # WAN settings # print "
\n"; # # WiFi settings # print "\n\n"; if($wifi_proto eq "static") { print "\n"; print "\n"; print "\n"; print "\n"; } else { push @hidden, ""; push @hidden, ""; } if($wifi_proto ne "disabled") { # 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 "\n"; print "\n"; } else { print "\n"; } if($wifi_mode eq "ap") { print ""; print "\n"; } print "\n"; if($config ne "user") { push @hidden, ""; print "\n"; if($wifi_mode ne "sta") { print "\n"; print "\n"; } else { push @hidden, ""; } { print "\n"; print "\n"; } if ($config ne "mesh") { print "\n"; print "\n"; } else { push (@hidden, ""); } print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; } else { push @hidden, ""; push @hidden, ""; push @hidden, ""; push @hidden, ""; push @hidden, ""; } print "
WiFi
Protocol "; #if($config ne "user" and $config ne "client") if($config ne "user") { push @hidden, ""; print "\n"; } $dis = ""; $dis = "disabled" if $config eq "client"; selopt("Static", "static", $wifi_proto); selopt("DHCP", "dhcp", $wifi_proto); selopt("Bridged", "bridged", $wifi_proto, $dis); selopt("disabled", "disabled", $wifi_proto, $dis); print "
IP Address
Netmask
SSID"; if ($config eq "mesh") { print "-$wifi_chanbw-v3
Hidden
Mode
Channel
Channel Width
Country

Active Settings
Rx Antenna
Tx Antenna
Tx Power
Distance
\n\n"; push @hidden, ""; if($dmz_mode) { print ""; #print "\n"; print "\n"; push @hidden, ""; print ""; #print "\n"; print "\n"; push @hidden, ""; print ""; print "\n"; print ""; #print "\n"; print "\n"; push @hidden, ""; print ""; #print "\n"; print "\n"; print ""; print ""; print ""; print "\n"; push @hidden, ""; push @hidden, ""; push @hidden, ""; push @hidden, ""; push @hidden, ""; push @hidden, ""; } else { print ""; print "\n"; print ""; print "\n"; if($wan_proto eq "disabled" and $wifi_proto ne "dhcp") { print ""; print "\n"; } print ""; print "\n"; print ""; print "\n"; print ""; print "\n"; push @hidden, ""; push @hidden, ""; push @hidden, ""; push @hidden, ""; push @hidden, ""; } if($config eq "mesh" and 0) # disable for now { print "\n"; print "\n"; print "\n"; } print "
LAN
LAN Mode
IP Address
$dmz_lan_ip
Netmask
$dmz_lan_mask
DHCP Server
DHCP Start
$dmz_dhcp_start
DHCP End
$dmz_dhcp_end

Advanced
Disable
Default Route
IP Address
Netmask
Gateway
DHCP Server"; } print " checked" if $lan_dhcp; print ">
DHCP Start"; } print ">
DHCP End"; } print ">

Mesh Bridge
\n"; if($config ne "client" and $config ne "mesh_ap") { print "\n\n"; if($wan_proto eq "static") { print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; } else { push @hidden, ""; push @hidden, ""; push @hidden, ""; } print "\n"; print "\n"; print "\n"; print "\n"; if($config eq "mesh") { print "\n"; print ""; print "\n"; print "\n"; } print "
WAN
Protocol"; print "
IP Address
Netmask
Gateway
DNS 1
DNS 2

Advanced
Mesh Gateway

\n"; push @hidden, ""; push @hidden, ""; push @hidden, ""; foreach(@hidden) { print "$_\n" } print "
\n"; show_debug_info(); if($debug) { print "
config
\n"; foreach(sort keys %cfg) { $tmp = $cfg{$_}; $tmp =~ s/ /\(space\)/g; if($cfg{$_} eq "") { print "$_ = (null)
\n" } else { print "$_ = $tmp
\n" } } } show_parse_errors(); page_footer(); print "\n"; print "\n";