#! /usr/bin/lua --[[ Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks Copyright (C) 2021 Tim Wilkinson Orignal Perl Copyright (C) 2015 Conrad Lara See Contributors file for additional contributors 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 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 --]] require("nixio") require("aredn.utils") local aredn_info = require('aredn.info') require("aredn.hardware") require("iwinfo") -- helpers start function is_null(v) if not v or v == "" or v == 0 or v == "0" then return true else return false end end local function h2s(hex) local s = "" if hex then for i = 1,#hex,2 do local p = hex:sub(i, i+1) if p:match("[0-9a-f][0-9a-f]") then s = s .. string.char(tonumber(p, 16)) else s = s .. p end end end return s end -- helpers end local c = uci.cursor() -- validate args local auto = false local do_basic = true local config = nil for i, a in ipairs(arg) do if a == "-a" then auto = true elseif a == "-p" then do_basic = false elseif a[1] == '-' then break else config = a break end end if not config then print "usage: node-setup [-a] [-p] " print "-a: automatic mode - don't ask any questions" print "-p: only process port forwarding and dhcp settings" return -1 end if not (config == "mesh" and nixio.fs.access("/etc/config.mesh/_setup", "r")) then print (string.format("'%s' is not a valid configuration", config)) return -1 end local ieee80211 = "/sys/class/ieee80211/" local lanintf = aredn.hardware.get_board_network_ifname("lan") local node = aredn_info.get_nvram("node") local tactical = aredn_info.get_nvram("tactical") local mac2 = aredn_info.get_nvram("mac2") local dtdmac = aredn_info.get_nvram("dtdmac") local deleteme = {} local cfg = { lan_intf = lanintf, wan_intf = aredn.hardware.get_board_network_ifname("wan"), bridge_network_config = "", lan_network_config = "", wan_network_config = "", dtdlink_network_config = "", wifi_network_config = "" } function expand_vars(lines) local nlines = {} for line in lines:gmatch("([^\n]*\n?)") do local inc = line:match("^include%s+(%S+)%s*") if inc then if nixio.fs.stat(inc) then line = expand_vars(read_all(inc)) else line = nil end elseif line:match("^[^#]") then for parm in line:gmatch("<([^%s]*)>") do if deleteme[parm] then line = nil elseif parm == "NODE" then line = line:gsub("", node) elseif parm == "MAC2" then line = line:gsub("", mac2) elseif parm == "DTDMAC" then line = line:gsub("", dtdmac) elseif cfg[parm] then line = line:gsub("<" .. parm .. ">", cfg[parm]) else line = nil end end end if line then nlines[#nlines + 1] = line end end return table.concat(nlines, "") end if not auto then -- Is this used now? print "Non-auto mode no longer supported." return -1 end -- load the verify the selected configuration for line in io.lines("/etc/config.mesh/_setup") do if not (line:match("^%s*#") or line:match("^%s*$")) then line = line:gsub("", node):gsub("", mac2):gsub("", dtdmac) local k, v = line:match("^([^%s]*)%s*=%s*(.*)%s*$") cfg[k] = v end end if cfg.wifi_enable == "1" then if not cfg.wifi_intf or cfg.wifi_intf == "" then cfg.wifi_intf = aredn.hardware.get_board_network_ifname("wifi"):match("^(%S+)") end local mtu = c:get("aredn", "@lqm[0]", "mtu") mtu = tonumber(mtu) if mtu and mtu >= 256 and mtu <= 1500 then cfg.wifi_mtu = mtu end else cfg.wifi_intf = "br-nomesh" end -- delete some config lines if necessary if cfg.wan_proto == "dhcp" then deleteme.wan_ip = true deleteme.wan_gw = true deleteme.wan_mask = true end if not is_null(cfg.dmz_mode) or cfg.wan_proto ~= "disabled" then deleteme.lan_gw = true end -- lan_dhcp sense is inverted in the dhcp config file -- and it is a checkbox so it may not be defined - this fixes that if cfg.lan_dhcp == "1" then cfg.lan_dhcp = 0 else cfg.lan_dhcp = 1 end -- verify that we have all the variables we need for file in nixio.fs.glob("/etc/config.mesh/*") do for line in io.lines(file) do if line:match("^[^#]") then for parm in line:gmatch("<([^%s]*)>") do if parm:upper() == parm then -- nvram variable if aredn_info.get_nvram(parm:lower()) == "" then print ("nv parameter '" .. parm .. "' in file '" .. file .. "' does not exist") return -1 end else if not cfg[parm] and not deleteme[parm] then print ("parameter '" .. parm .. "' in file '" .. file .. "' does not exist") return -1 end end end end end end -- sensible dmz_mode default if is_null(cfg.dmz_mode) then cfg.dmz_mode = "0" end -- switch to dmz values if needed if not is_null(cfg.dmz_mode) then cfg.lan_ip = cfg.dmz_lan_ip cfg.lan_mask = cfg.dmz_lan_mask cfg.dhcp_start = cfg.dmz_dhcp_start cfg.dhcp_end = cfg.dmz_dhcp_end cfg.dhcp_limit = cfg.dmz_dhcp_limit end -- select ports and dhcp files based on mode local portfile = "/etc/config.mesh/_setup.ports" local dhcpfile = "/etc/config.mesh/_setup.dhcp" local aliasfile = "/etc/config.mesh/aliases" local servfile = "/etc/config.mesh/_setup.services" if is_null(cfg.dmz_mode) then portfile = portfile .. ".nat" dhcpfile = dhcpfile .. ".nat" aliasfile = aliasfile .. ".nat" servfile = servfile .. ".nat" else portfile = portfile .. ".dmz" dhcpfile = dhcpfile .. ".dmz" aliasfile = aliasfile .. ".dmz" servfile = servfile .. ".dmz" end -- check for old aliases file, copy it to .dmz and create symlink -- just in case anyone is already using the file for some script or something if not nixio.fs.readlink("/etc/config.mesh/aliases") then if nixio.fs.stat("/etc/config.mesh/aliases") then filecopy("/etc/config.mesh/aliases", "/etc/config.mesh/aliases.dmz") os.remove("/etc/config.mesh/aliases") else io.open("/etc/config.mesh/aliases.dmz", "a"):close() end nixio.fs.symlink("aliases.dmz", "/etc/config.mesh/aliases") end -- basic configuration if do_basic then -- generate the new school bridge configuration if nixio.fs.stat("/etc/aredn_include/bridge.network.user") then cfg.bridge_network_config = expand_vars(read_all("/etc/aredn_include/bridge.network.user")) else local list = {} for _, net in ipairs({ "lan", "wan", "dtdlink" }) do local ports = aredn.hardware.get_board_network_ifname(net):split(" ") for _, port in ipairs(ports) do list[port:gsub("%..*$", "")] = true end end local config = "config device\n option name 'br0'\n option type 'bridge'\n" for port, _ in pairs(list) do config = config .. " list ports '" .. port .. "'\n" end cfg.bridge_network_config = config end -- generate the network configurations for _, net in ipairs({ "lan", "wan", "dtdlink", "wifi" }) do local wireless = false local config = "" -- user override if nixio.fs.stat("/etc/aredn_include/" .. net .. ".network.user") then if nixio.fs.stat("/etc/aredn_include/fixedmac." .. net) then for line in io.lines("/etc/aredn_include/fixedmac." .. net) do local m = line:match("option%s+macaddr%s+(%S+)") if m then cfg[net .. "_mac"] = m end end end config = expand_vars(read_all("/etc/aredn_include/" .. net .. ".network.user")) else -- generate a complete config local vlan = nil local ports = aredn.hardware.get_board_network_ifname(net):split(" ") if net == "lan" then -- If the LAN has be given a vlan to use (usually by a switch) we use that here, -- otherwise we just use '3' local lvlan = ports[1]:match("%.(%d+)$") if lvlan then vlan = lvlan .. ":t" else vlan = "3:u" end elseif net == "wan" then -- wifi can be used for the WAN (we become a wifi client) if cfg.wifi3_enable == "1" then -- WAN uses wifi wireless = true ports = { "wlan0" } for devname in nixio.fs.dir(ieee80211) do local hwmode = "11g" if iwinfo.nl80211.freqlist(devname)[1].mhz > 5000 then hwmode="11a" end if hwmode == cfg.wifi3_hwmode then ports = { "wlan" .. devname:match("^phy(%d+)$") } break end end else -- If the WAN has been given a vlan to use (usually 1) we use that here. local wvlan = ports[1]:match("%.(%d+)$") if wvlan then vlan = wvlan .. ":t" else vlan = "4:u" end -- handle wan vlan override for line in io.lines("/etc/config.mesh/_setup") do local wport, wvlan = line:match("^wan_intf = (%w+%.)(%d+)") if wvlan then vlan = wvlan .. ":t" ports = { wport .. wvlan } break end end end elseif net == "dtdlink" then -- Always vlan 2 vlan = "2:t" cfg.dtdlink_proto = "static" cfg.dtdlink_mask = "255.0.0.0" elseif net == "wifi" then wireless = true ports = { cfg.wifi_intf } end if vlan then -- new school vlan configuration local v, t = vlan:match("(.*):(.*)") config = config .. "\nconfig bridge-vlan\n option device 'br0'\n option vlan '" .. v .. "'\n" for _, port in ipairs(ports) do config = config .. " list ports '" .. port:gsub("%..*$", "") .. ":" .. t .. "'\n" end config = config .. "\n" ports = { "br0." .. v } end local proto = cfg[net .. "_proto"] or "" local ipaddr = cfg[net .. "_ip"] or "" local netmask = cfg[net .. "_mask"] or "" local mtu = cfg[net .. "_mtu"] or "" local dns1 = "" local dns2 = "" if net == "lan" then dns1 = cfg.wan_dns1 or "" dns2 = cfg.wan_dns2 or "" end local gateway = cfg[net .. "_gw"] or "" config = config .. "config device\n" if not wireless then config = config .. " option name 'br-" .. net .. "'\n option type 'bridge'\n" elseif cfg.wifi_enable ~= "1" then netmask = "255.255.255.255" end if nixio.fs.stat("/etc/aredn_include/fixedmac." .. net) then config = config .. read_all("/etc/aredn_include/fixedmac." .. net) end if not wireless then for _, port in ipairs(ports) do config = config .. " list ports '" .. port .. "'\n" end else config = config .. " option name '" .. ports[1] .. "'\n" if not ports[1]:match("^wlan") then config = config .. " option type 'bridge'\n option bridge_empty '1'\n" end end config = config .. "\nconfig interface " .. net .. "\n" if wireless then config = config .. " option device '" .. ports[1] .. "'\n" else config = config .. " option device 'br-" .. net .. "'\n" end if proto ~= "" then config = config .. " option proto '" .. proto .. "'\n" end if mtu ~= "" then config = config .. " option mtu '" .. mtu .. "'\n" end if ipaddr ~= "" then config = config .. " option ipaddr '" .. ipaddr .. "'\n" end if netmask ~= "" then config = config .. " option netmask '" .. netmask .. "'\n" end if dns1 ~= "" or dns2 ~= "" then config = config .. " option dns '" .. (dns1 or "") .. (dns1 and dns2 and " " or "") .. (dns2 or "") .. "'\n" end if gateway ~= "" then config = config .. " option gateway '" .. gateway .. "'\n" end end cfg[net .. "_network_config"] = config end remove_all("/tmp/new_config") nixio.fs.mkdir("/tmp/new_config") for file in nixio.fs.glob("/etc/config.mesh/*") do local bfile = nixio.fs.basename(file) if not (bfile:match("^_setup") or bfile:match("^firewall.user") or bfile:match("^olsrd")) then local f = io.open("/tmp/new_config/" .. bfile, "w") if f then f:write(expand_vars(read_all(file))) f:close() end end end -- make it official for file in nixio.fs.glob("/etc/config/*") do nixio.fs.remove(file) end for file in nixio.fs.glob("/tmp/new_config/*") do filecopy(file, "/etc/config/" .. nixio.fs.basename(file)) nixio.fs.remove(file) end nixio.fs.rmdir("/etc/new_config") filecopy("/etc/config.mesh/firewall.user", "/etc/firewall.user") aredn_info.set_nvram("config", "mesh") aredn_info.set_nvram("node", node) aredn_info.set_nvram("tactical", tactical) end -- generate the system files local h = io.open("/etc/hosts", "w") local e = io.open("/etc/ethers", "w") if h and e then h:write("# automatically generated file - do not edit\n") h:write("# use /etc/hosts.user for custom entries\n") h:write("127.0.0.1\tlocalhost\n") if not is_null(cfg.wifi_ip) then h:write(cfg.lan_ip .. "\tlocalnode\n") h:write(cfg.wifi_ip .. "\t" .. node .. " " .. tactical .. "\n") else h:write(cfg.lan_ip .. "\tlocalnode " .. node .. " " .. tactical .. "\n") end if not is_null(cfg.dtdlink_ip) then h:write(cfg.dtdlink_ip .. "\tdtdlink." .. node .. ".local.mesh dtdlink." .. node .."\n") end if is_null(cfg.dmz_mode) then h:write(decimal_to_ip(ip_to_decimal(cfg.lan_ip) + 1) .. "\tlocalap\n") end e:write("# automatically generated file - do not edit\n") e:write("# use /etc/ethers.user for custom entries\n") local netaddr = nixio.bit.band(ip_to_decimal(cfg.lan_ip), ip_to_decimal(cfg.lan_mask)) if nixio.fs.access(dhcpfile) then for line in io.lines(dhcpfile) do if not (line:match("^%s*#") or line:match("^%s*$")) then local mac, ip, host, noprop = line:match("(%S+)%s+(%S+)%s+(%S+)%s*(%S*)") if mac and ip and host and noprop then ip = decimal_to_ip(netaddr + ip) if validate_same_subnet(ip, cfg.lan_ip, cfg.lan_mask) and validate_ip_netmask(ip, cfg.lan_mask) then h:write(ip .. "\t" .. host .. " " .. noprop .. "\n") e:write(mac .. "\t" .. ip .. "\n") end end end end end -- aliases need to ba added to /etc/hosts or they will now show up on the localnode -- nor will the services thehy offer -- also add a comment to the hosts file so we can display the aliases differently if needed local f = io.open(aliasfile, "r") if f then for line in f:lines() do if not (line:match("^%s*#") or line:match("^%s*$")) then local ip, host = line:match("(%S+)%s+(%S+)") if ip then if host:match("%.") and not host:match("%.local%.mesh$") then host = host .. ".local.mesh" end h:write(ip .. "\t" .. host .. " #ALIAS\n") end end end f:close() end h:write("\n") if nixio.fs.access("/etc/hosts.user", "r") then for line in io.lines("/etc/hosts.user") do h:write(line .. "\n") end end if nixio.fs.access("/etc/ethers.user", "r") then for line in io.lines("/etc/ethers.user") do e:write(line .. "\n") end end h:close() e:close() end if not do_basic then filecopy("/etc/config.mesh/firewall", "/etc/config/firewall") filecopy("/etc/config.mesh/firewall.user", "/etc/firewall.user") end -- append to firewall local add_masq = false local fw = io.open("/etc/config/firewall", "a") if fw then if not is_null(cfg.dmz_mode) then fw:write("\nconfig forwarding\n option src wifi\n option dest lan\n") fw:write("\nconfig forwarding\n option src dtdlink\n option dest lan\n") add_masq = true else fw:write("\nconfig 'include'\n option 'path' '/etc/firewall.natmode'\n option 'reload' '1'\n") end if c:get("aredn", "@wan[0]", "olsrd_gw") == "1" then fw:write("\nconfig forwarding\n option src wifi\n option dest wan\n") fw:write("\nconfig forwarding\n option src dtdlink\n option dest wan\n") end if nixio.fs.access(portfile) then for line in io.lines(portfile) do if not (line:match("^%s*#") or line:match("^%s*$")) then local dip = line:match("dmz_ip = (%w+)") if dip and cfg.dmz_mode ~= 0 then fw:write("\nconfig redirect\n option src wifi\n option proto tcp\n option src_dip " .. cfg.wifi_ip .. "\n option dest_ip " .. dip .. "\n") fw:write("\nconfig redirect\n option src wifi\n option proto udp\n option src_dip " .. cfg.wifi_ip .. "\n option dest_ip " .. dip .. "\n") else local intf, type, oport, host, iport, enable = line:match("(.*):(.*):(.*):(.*):(.*):(.*)") if enable == "1" then local match = " option src_dport " .. oport .. "\n" if type == "tcp" then match = match .. " option proto tcp\n" elseif type == "udp" then match = match .. " option proto udp\n" end -- uci the host and then -- set the inside port unless the rule uses an outside port range host = "option dest_ip " .. host .. "\n" if not oport:match("-") then host = host .. " option dest_port " .. iport .. "\n" end if not is_null(cfg.dmz_mode) and intf == "both" then intf = "wan" end if intf == "both" then fw:write("\nconfig redirect\n option src wifi\n " .. match .. " option src_dip " .. cfg.wifi_ip .. "\n " .. host .. "\n") fw:write("\nconfig redirect\n option src dtdlink\n " .. match .. " option src_dip " .. cfg.wifi_ip .. "\n " .. host .. "\n") fw:write("config redirect\n option src wan\n " .. match .. " " .. host .. "\n") elseif intf == "wifi" and is_null(cfg.dmz_mode) then fw:write("\nconfig redirect\n option src dtdlink\n " .. match .. " option src_dip " .. cfg.wifi_ip .. "\n " .. host .. "\n") fw:write("\nconfig redirect\n option src wifi\n " .. match .. " option src_dip " .. cfg.wifi_ip .. "\n " .. host .. "\n") elseif intf == "wan" then fw:write("\nconfig redirect\n option src dtdlink\n " .. match .. " option src_dip " .. cfg.wifi_ip .. "\n " .. host .. "\n") fw:write("config redirect\n option src wan\n " .. match .. " " .. host .. "\n") end end end end end end fw:close(); end if add_masq then c:set("firewall", "@zone[2]", "masq", "0") c:commit("firewall") end -- generate the services file local sf = io.open("/etc/config/services", "w") if sf then if nixio.fs.access(servfile) then for line in io.lines(servfile) do if not (line:match("^%s*#") or line:match("^%s*$")) then local name, link, proto, host, port, sffx = line:match("(.*)|(.*)|(.*)|(.*)|(.*)|(.*)") if name and name ~= "" and host ~= "" then if proto == "" then proto = "http" end if link == "0" then port = "0" end sf:write(string.format("%s://%s:%s/%s|tcp|%s\n", proto, host, port, sffx, name)) end end end end sf:close() end local sf = io.open("/etc/local/services", "w") if sf then sf:write("#!/bin/sh\n") if cfg.wifi_proto ~= "disabled" then local wifi_channel = tonumber(cfg.wifi_channel) if is_null(cfg.wifi_txpower) or tonumber(cfg.wifi_txpower) > aredn.hardware.wifi_maxpower(cfg.wifi_intf, wifi_channel) then cfg.wifi_txpower = aredn.hardware.wifi_maxpower(cfg.wifi_intf, wifi_channel) elseif tonumber(cfg.wifi_txpower) < 1 then cfg.wifi_txpower = 1 end if cfg.wifi_enable == "1" then sf:write("/usr/sbin/iw dev " .. cfg.wifi_intf .. " set txpower fixed " .. cfg.wifi_txpower .. "00\n") end if not is_null(cfg.aprs_lat) and not is_null(cfg.aprs_lon) then c:set("aredn", "@location[0]", "lat", cfg.aprs_lat) c:set("aredn", "@location[0]", "lon", cfg.aprs_lon) c:commit("aredn") end end sf:close() nixio.fs.chmod("/etc/local/services", "777") end -- generate olsrd.conf if nixio.fs.access("/etc/config.mesh/olsrd", "r") then local of = io.open("/etc/config/olsrd", "w") if of then if nixio.fs.access("/etc/config.mesh/olsrd") then for line in io.lines("/etc/config.mesh/olsrd") do if line:match("") then if is_null(cfg.olsrd_bridge) then line = line:gsub("", '"wifi" "lan"') else line = line:gsub("", '"lan"') end elseif line:match("^[^#]") then for parm in line:gmatch("<([^%s]*)>") do line = line:gsub("<" .. parm .. ">", cfg[parm]) end end of:write(line .. "\n") end if not is_null(cfg.dmz_mode) then local a, b, c, d = cfg.dmz_lan_ip:match("(.*)%.(.*)%.(.*)%.(.*)") of:write(string.format("\nconfig Hna4\n\toption netaddr %s.%s.%s.%d\n\toption netmask 255.255.255.%d\n\n", a, b, c, d - 1, nixio.bit.band(255 * 2 ^ cfg.dmz_mode, 255))) end if cfg.wifi_enable ~= "1" and not is_null(cfg.wifi_ip) then local cwan = aredn.hardware.get_iface_name("wan"):match("^([^%.%s]+)") local cdtd = aredn.hardware.get_iface_name("dtdlink"):match("^([^%.%s]+)") if cwan ~= cdtd then of:write(string.format("config Hna4\n\toption netaddr %s\n\toption netmask 255.255.255.255\n\n", cfg.wifi_ip)) end end if c:get("aredn", "@wan[0]", "olsrd_gw") == "1" then of:write("config LoadPlugin\n\toption library 'olsrd_dyn_gw.so.0.5'\n\toption Interval '60'\n\tlist Ping '8.8.8.8'\n\tlist Ping '8.8.4.4'\n\n\n") end end of:close() end end -- indicate whether lan is running in dmz mode c:set("aredn", "@dmz[0]", "mode", cfg.dmz_mode) c:commit("aredn") -- setup node lan dhcp if c:get("aredn", "@wan[0]", "lan_dhcp_route") == "1" or c:get("aredn", "@wan[0]", "lan_dhcp_defaultroute") == "1" then -- Provide stateless routes and default route c:set("dhcp", "@dhcp[0]", "dhcp_option", { "121,10.0.0.0/8," .. cfg.lan_ip .. ",0.0.0.0/0," .. cfg.lan_ip, "249,10.0.0.0/8," .. cfg.lan_ip .. ",0.0.0.0/0," .. cfg.lan_ip }) else -- Provide stateless routes to the mesh, and a blank default route (option 3 has no values) to -- surpress default route being sent c:set("dhcp", "@dhcp[0]", "dhcp_option", { "121,10.0.0.0/8," .. cfg.lan_ip, "249,10.0.0.0/8," .. cfg.lan_ip, "3" }) end c:commit("dhcp") -- generate the wireless config file local config = "" local ifacenum = 0 local ifacecount = 0 if nixio.fs.stat(ieee80211) then for devname in nixio.fs.dir(ieee80211) do ifacecount = ifacecount + 1 end for devname in nixio.fs.dir(ieee80211) do local dev = devname:match("^phy(%d+)$") local radio = "radio" .. dev local wlan = "wlan" .. dev local devpath = nixio.fs.realpath(ieee80211 .. nixio.fs.readlink(ieee80211 .. devname)):match("^/sys/devices/(.*)/ieee802.*$") if devpath:match("^platform.*/pci.*") then devpath = devpath:match("^platform/(.*)") end local is_mesh_rf = false local htmode = "HT20" local disabled = "0" local chanbw = nil local country = nil local channel = nil local distance = nil local hwmode = "11g" if iwinfo.nl80211.freqlist(devname)[1].mhz > 5000 then hwmode="11a" end local network = nil local mode = nil local ssid = nil local encryption = nil local key = nil if wlan == cfg.wifi_intf then -- mesh RF adhoc configuration is_mesh_rf = true channel = cfg.wifi_channel chanbw = cfg.wifi_chanbw country = "HX" distance = cfg.wifi_distance ssid = cfg.wifi_ssid .. "-" .. chanbw .. "-v3" mode = "adhoc" encryption = "none" network = "wifi" elseif cfg.wifi2_enable == "1" and (ifacecount == 1 or (ifacecount > 1 and hwmode == cfg.wifi2_hwmode)) then -- lan AP interface channel = cfg.wifi2_channel ssid = h2s(cfg.wifi2_ssid) mode = "ap" encryption = cfg.wifi2_encryption key = h2s(cfg.wifi2_key) network = "lan" elseif cfg.wifi3_enable == "1" and (ifacecount == 1 or (ifacecount > 1 and hwmode == cfg.wifi3_hwmode)) then -- wan client ssid = h2s(cfg.wifi3_ssid) mode = "sta" if cfg.wifi3_key and cfg.wifi3_key ~= "" then encryption = "psk2" key = h2s(cfg.wifi3_key) else enable = "none" end network = "wan" htmode = nil else disabled = "1" end config = config .. "config wifi-device '" .. radio .. "'\n option type 'mac80211'\n" config = config .. " option disabled '" .. disabled .. "'\n" if channel then config = config .. " option channel '" .. channel .. "'\n" end if chanbw then config = config .. " option chanbw '" .. chanbw .. "'\n" end if country then config = config .. " option country '" .. country .. "'\n" end if distance then config = config .. " option distance '" .. distance .. "'\n" end config = config .. " option hwmode '" .. hwmode .. "'\n" if htmode then config = config .. " option htmode '" .. htmode .. "'\n" end config = config .. " option path '" .. devpath .. "'\n\n" config = config .. "config wifi-iface\n" config = config .. " option ifname '" .. wlan .. "'\n" config = config .. " option device '" .. radio .. "'\n" if network then config = config .. " option network '" .. network .. "'\n" end if mode then config = config .. " option mode '" .. mode .. "'\n" end if ssid then config = config .. " option ssid '" .. ssid .. "'\n" end if encryption then config = config .. " option encryption '" .. encryption .. "'\n" end if key then config = config .. " option key '" .. key .. "'\n" end config = config .. "\n" if is_mesh_rf then config = config .. "config wifi-iface\n" config = config .. " option ifname '" .. wlan .. "-1'\n" config = config .. " option device '" .. radio .. "'\n" config = config .. " option network 'wifi_mon'\n option mode 'monitor'\n\n" end ifacenum = ifacenum + 1 end end write_all("/etc/config/wireless", config) if not auto then print "configuration complete."; print "you should now reboot the router."; end return 0