#!/opt/lnxall_app/bin/lua -- Created by jiaqiang.ye@lnxall.com -- New 4G service for Non-openwrt -- 2025/04/17 -- Load external modules local uci = require "uci" local invoker = require "invoker" local cjson = require "cjson" local plat4g = require "plat4g" local newmodems = require "newmodems" local comm4gnet = require "comm4gnet" local gfmt = string.format local g_tty4g_file = "/tmp/4g_modem_tty" local g_iccid_file = "/tmp/simcard_iccid" local g_signal_file = "/etc/signal_4g.txt" local g_cardinfo_file = "/tmp/.modem_4ginfo.json" local g_status_file = "/tmp/status_info.json" local g_modem_file = "/app/config/modefor4g.json" local g_lang_file = "/etc/default/locale" local g_modem_md5sum = nil local g_SIMCARD_EXTERNAL = 0 local g_SIMCARD_INTERNAL = 1 -- global variables definition local g_modem4g = nil -- 4G modem object local g_platform = nil -- underlying hardware object local g_netdev = nil local g_cardno = g_SIMCARD_EXTERNAL local g_resolved = {} local g_4gmode = { ["simno"] = g_SIMCARD_INTERNAL, ["ips"] = { [1] = "mqtt.lnxall.com", [2] = "emsmqtt.lnxall.com", [3] = "smc.lnxall.com", [4] = "emsiot.lnxall.com" }, ["operator_map"] = { ["zh_CN"] = {}, ["en_US"] = {} }, ["apn"] = "internet" } -- if file `g_force4g_reconnect exists, it works as an indicator that, `new4gnet.lua should force 4G modem to connect 4G network local function force4g_reconnect(keepfile) local tmpv = invoker.statfile(g_force4g_reconnect) if not keepfile then invoker.unlink(g_force4g_reconnect) end if tmpv then return true end return false end local function update_ttypath_file(stty) local ttypath = g_modem4g:f_ttypath() if not ttypath then io.stderr:write("Error, failed to determine 4G modem tty path.\n") io.stderr:flush() return false end if stty then local ttyrw = g_modem4g:f_opentty(115200) if ttyrw then ttyrw:close(); ttyrw = nil end end local oldpath = invoker.readfile(g_tty4g_file, invoker.TRIMEND) if oldpath == ttypath then return true end local th = io.open(g_tty4g_file, "wb") if th then th:write(gfmt("%s\n", ttypath)) th:close(); th = nil return true end io.stderr:write(gfmt("Error, failed to open file for writing: %s\n", g_tty4g_file)) io.stderr:flush() return false end local function update_signal_file(signal) local oldsignal = invoker.readfile(g_signal_file, invoker.TRIMEND) if signal and signal ~= oldsignal then local idh = io.open(g_signal_file, "wb") if idh then idh:write(gfmt("%s\n", signal)) idh:close(); idh = nil return true end end return false end local function update_simcard_info(g_cardno) local cardinfo = g_modem4g:f_cardinfo(g_cardno) local oldinfo = invoker.readfile(g_cardinfo_file, invoker.TRIMEND) if not cardinfo then return false end local _,data = pcall(cjson.decode, cardinfo) if (data.ICCID1 and data.ICCID0 and data.ICCID0 == data.ICCID1) or (data.hassim1 and not data.ICCID1) or (data.hassim0 and not data.ICCID0) then cardinfo = g_modem4g:f_cardinfo(g_cardno) end if cardinfo and cardinfo ~= oldinfo then local idh = io.open(g_cardinfo_file, "wb") if idh then idh:write(gfmt("%s\n", cardinfo)) idh:close(); idh = nil return true end end return false end local function update_using_simcard_info(str) if not str or type(str) ~= "table" then io.stderr:write("Warning, cannot get 4g status.\n") io.stderr:flush() return false end local okay = nil local data, itab = invoker.readfile(g_cardinfo_file), {} if type(data) == "string" then okay, data = pcall(cjson.decode, data) else io.stderr:write(gfmt("Error, failed to read file: %s\n", g_cardinfo_file)) io.stderr:flush() end if okay and type(data) == "table" then itab["ICCID1"] = data.ICCID1 itab["ICCID0"] = data.ICCID0 itab["hassim1"] = data.hassim1 itab["hassim0"] = data.hassim0 end local hassim, simno, iccid = nil, str[2], str[3] if str[1] then hassim = string.find(str[1], "READY", 1, true) and true or false end if simno and #iccid > 1 then itab["ICCID" .. simno] = iccid end if simno and type(hassim) ~= 'nil' then itab["hassim" .. simno] = hassim end local cardinfo = cjson.encode({ ["ICCID1"] = itab["ICCID1"], ["ICCID0"] = itab["ICCID0"], ["hassim1"] = itab["hassim1"], ["hassim0"] = itab["hassim0"] }) local oldinfo = invoker.readfile(g_cardinfo_file, invoker.TRIMEND) if cardinfo and cardinfo ~= oldinfo then local idh = io.open(g_cardinfo_file, "wb") if idh then idh:write(gfmt("%s\n", cardinfo)) idh:close(); idh = nil return true end end return false end local function update_simcard_iccid() local iccid = g_modem4g:f_iccid() if iccid then iccid = "ICCID: " .. iccid else iccid = "ICCID: " end local oldiccid = invoker.readfile(g_iccid_file, invoker.TRIMEND) if iccid and iccid ~= oldiccid then local idh = io.open(g_iccid_file, "wb") if idh then idh:write(gfmt("%s\n", iccid)) idh:close(); idh = nil return true end end return false end local function update_status_info(str, passcnt, failcnt) if not str or type(str) ~= "table" then io.stderr:write("Warning, cannot get 4g status.\n") io.stderr:flush() return false end local simno, operator = str[2], str[4] local LANG = invoker.readfile(g_lang_file, invoker.TRIMEND) if LANG and #LANG > 0 then local last_match = nil for line in string.gmatch(LANG, "[^\r\n]+") do local match = string.match(line, "=([^%.]+)") if match then last_match = match end end LANG = last_match end if not LANG or (not string.match(LANG,"en_US") and not string.match(LANG,"zh_CN")) then LANG = os.getenv('LANG') end if LANG and #LANG > 0 then LANG = string.match(LANG, "^([^%.]+)") end if not LANG or #LANG == 0 then LANG = "en_US" end local lantab = g_4gmode["operator_map"][LANG] if type(lantab) ~= "table" then lantab = {} end if lantab[operator] then operator = lantab[operator] end if LANG == "zh_CN" then simno = simno == "0" and "外置卡" or "内置卡" else simno = simno == "0" and "External simcard" or "Internal simcard" end local newinfo = cjson.encode({ ["hassim"] = str[1], ["simno"] = simno, ["iccid"] = str[3], ["operator"] = operator, ["area"] = str[5], ["registerd"] = str[6], ["signal"] = str[7], ["passcnt"] = passcnt, ["failcnt"] = failcnt }) local oldinfo = invoker.readfile(g_status_file, invoker.TRIMEND) if newinfo and newinfo ~= oldinfo then local idh = io.open(g_status_file, "wb") if idh then idh:write(gfmt("%s\n", newinfo)) idh:close(); idh = nil return true end end return false end local function modem4g_repower(delay0, delay1) g_platform:poweron(false); invoker.waitsec(delay0) g_platform:poweron(true); invoker.waitsec(delay1) end -- check whether 4G network is enabled or not local function network4g_enabled() local netuci = uci.cursor('/etc/config') if not netuci then return true end local disabled = netuci:get("network", "wwan", "disabled") netuci:close(); netuci = nil if disabled == "1" then return false end return true end local function wwan_cannot_up() local st4g = g_modem4g:f_status() if not st4g['HAS_REGISTERD'] or not st4g['HAS_SIMCARD'] then return false end local result = invoker.invoke(0,'nmcli', '-w', '6', 'con', 'up' ,'wwan') if result == 0 then return false end return true end local function netdev_exists(iface) if type(iface) ~= "string" or #iface == 0 then io.stderr:write("Error, cannot determine 4G network device.\n") io.stderr:flush() return false end local rval = invoker.invoke(invoker.NOSTDIO,"ip", "link", "show", "dev", iface) return rval end local function ping_list_swap1(ptab) if type(ptab) ~= "table" then return {} end -- remove duplicated host names local dtab, idx = {}, 0 while true do idx = idx + 1 local h = ptab[idx] if type(h) == "string" and #h > 0 then dtab[h] = true end if idx >= 128 then break end end local ipnum = 0 ptab = {} -- clear existing table for h, _ in pairs(dtab) do ipnum = ipnum + 1 ptab[#ptab + 1] = h end -- check the number of entries in the table: if ipnum <= 1 or type(ptab[1]) ~= "string" then -- return original ping-table return ptab end local mi = invoker.random(ipnum) + 1 if mi >= 0x2 and mi <= ipnum and type(ptab[mi]) == "string" then io.stdout:write(gfmt("Switch ping host %s with %s\n", ptab[1], ptab[mi])) io.stdout:flush() ptab[1], ptab[mi] = ptab[mi], ptab[1] end return ptab end local function endswith(str, suffix) if type(str) ~= "string" then return false end local l0, l1 = string.len(str), string.len(suffix) if l0 < l1 then return false end return str:sub(l0 - l1 + 1) == suffix end local function ipw_filter_lnxall(ptab) if type(ptab) ~= "table" then return {} end local ntab, idx = {}, 0 while true do idx = idx + 1 local h = ptab[idx] -- if type(h) ~= "string" then break end if endswith(h, ".lnxall.com") or endswith(h, ".lnxall.cn") then io.stderr:write(gfmt("Warning, skip lnxall hostname: %s\n", h)) io.stderr:flush() elseif h == "ntp.aliyun.com" or endswith(h, ".aliyuncs.com") then io.stderr:write(gfmt("Warning, skip ntp/aliyuncs hostname: %s\n", h)) io.stderr:flush() elseif type(h) == "string" and #h > 0 then ntab[#ntab + 1] = h io.stdout:write(gfmt("Adding client IP whitelist: %s\n", h)) io.stdout:flush() end if idx >= 128 then break end end return ntab end local function load_json_config(onlyip) local mret, md5val = invoker.invoke(invoker.OUTPUT, "md5sum", g_modem_file) if mret ~= 0 or type(md5val) ~= "string" then md5val = nil else md5val = string.match(md5val, "^([%x]+)") end if md5val and g_modem_md5sum == md5val then -- configuration file already loaded return true end g_modem_md5sum = md5val local jsonc = invoker.readfile(g_modem_file, nil, 0x40000) if type(jsonc) ~= "string" or #jsonc == 0 then io.stderr:write(gfmt("Error, failed to read: %s\n", g_modem_file)) io.stderr:flush() return false end local okay, data = pcall(cjson.decode, jsonc) if not okay or type(data) ~= "table" then io.stderr:write(gfmt("Error, failed to decode as JSON: %s\n", g_modem_file)) io.stderr:flush() return false end -- host/iparray for WhiteList g_4gmode["ipw"] = ping_list_swap1(ipw_filter_lnxall(data.ipw)) g_4gmode["ips"] = ping_list_swap1(data.ips) if not onlyip then if data.apn then g_4gmode["apn"] = data.apn end if data.simno then g_4gmode["simno"] = data.simno end if data.operator_map then g_4gmode["operator_map"] = data.operator_map end end return true end local function nslookup(hostn) local pid, pfd = invoker.invoke(invoker.NOWAIT + invoker.NOSTDIO + invoker.OUTPUT, "nslookup", hostn) if not pid then return nil end local swait = invoker.uptimsec() local nwait, exited = swait, false swait = swait + 4000 while nwait < swait do if invoker.waitpid(pid, true) then exited = true break end invoker.msleep(250) nwait = invoker.uptimsec() end if not exited then invoker.kill(pid, 9) invoker.waitpid(pid, false) end local output = invoker.readfd(pfd, 8192) if type(pfd) == "number" then invoker.closefd(pfd); pfd = nil end if type(output) ~= "string" then return nil end local iptab, ipn, ans = {}, 0, false for line in string.gmatch(output, "[^\r\n]+") do if not ans then if string.find(line, "answer:", 1, true) then ans = true end else local ipv4 = string.match(line, "Address:%s+([%d%.]+)") if ipv4 and invoker.isipv4(ipv4) then ipn = ipn + 1 iptab[ipn] = ipv4 end end end if ipn == 0 then return nil end return iptab end local function ping_with_netdev(ndev, phost) if type(phost) ~= "string" or #phost == 0 then io.stderr:write("Error, invalid host given for `ping\n") io.stderr:flush() return nil end local cmds = { "ping", "-c3", "-w12" } if type(ndev) == "string" and #ndev > 0 then cmds[#cmds + 1] = "-I" cmds[#cmds + 1] = ndev end local hipv4 = nil if not invoker.isipv4(phost) then hipv4 = g_resolved[phost] if not hipv4 then local ip = nslookup(phost) if ip then hipv4 = ip[1] io.stdout:write(gfmt("DNS resolved: %s => %s\n", phost, hipv4)) io.stdout:flush() g_resolved[phost] = hipv4 else io.stderr:write(gfmt("Error, DNS resolved failed for %s\n", phost)) io.stderr:flush() end end end cmds[#cmds + 1] = hipv4 or phost local _, output = invoker.invoke(invoker.OUTPUT, cmds) if type(output) ~= "string" then output = "" end -- process output from `ping if not string.find(output, "packet loss", 1, true) or string.find(output, "100% packet loss", 1, true) then io.stderr:write(gfmt("Error, ping host has failed: %s\n", phost)) io.stderr:flush() return false end io.stdout:write(gfmt("INFO, ping host okay: %s\n", phost)) io.stdout:flush() return true end local function network_okay(iface) load_json_config(true) local ipt = g_4gmode["ipw"] if type(ipt) ~= "table" then ipt = {} end local idx, numping = 0, 0 while true do idx = idx + 1 local hostn = ipt[idx] if type(hostn) ~= "string" then break end if ping_with_netdev(iface, hostn) then return hostn end io.stderr:write(gfmt("Error, ping whitelist host failed: %s\n", hostn)) io.stderr:flush() numping = numping + 1 end if numping >= 1 then io.stderr:write("Error, hostnames in whitelist has all failed.\n") io.stderr:flush() return false end ipt, idx, numping = g_4gmode["ips"], 0, 0 while true do idx = idx + 1 local hostn = ipt[idx] if type(hostn) ~= "string" then break end if ping_with_netdev(iface, hostn) then return hostn end numping = numping + 1 end return numping <= 0 end local function switch_simcard() if g_cardno == 1 then g_cardno = 0 else g_cardno = 1 end io.stdout:write(gfmt("Error, 4G Network cannot work, switching SIMCARD: %d ...\n", g_cardno)) io.stdout:flush() while g_cardno ~= g_modem4g:f_get_cursim() do g_modem4g:f_switch_sim(g_cardno) invoker.waitsec(5) end return true end local function check_apn() local target_apn = g_4gmode["apn"] local current_apn = g_modem4g:f_getapn() or " " if current_apn == newmodems.APN_ALREADY then g_modem4g:f_connect() return true end if current_apn ~= target_apn then g_modem4g:f_setapn(target_apn) invoker.msleep(1000) io.stdout:write(gfmt("set apn '%s' -> '%s'\n", current_apn, target_apn)) end if g_modem4g:f_getapn() == target_apn then io.stdout:write(gfmt("already set apn '%s'\n", target_apn)) io.stdout:flush() g_modem4g:f_connect() return true end return false end local function new4gnet_init() invoker.setname("NEW4GNET") invoker.setenv("PATH", "/opt/lnxall_app/bin:/opt/lnxall_app/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin") invoker.unlink(g_tty4g_file) invoker.unlink(g_iccid_file) invoker.unlink(g_signal_file) invoker.unlink(g_cardinfo_file) invoker.unlink(g_status_file) load_json_config(false) -- detect hardware platform local platdev = nil while not platdev do platdev = plat4g.detect() if platdev then break end invoker.waitsec(invoker.uptime() < 120 and 5 or 60) end g_platform = platdev io.stdout:write(gfmt("Found hardware device: %s\n", platdev.name)) io.stdout:flush() -- power on 4G modem unconditionally local tmpval = 3 if not platdev:ison() then tmpval = 15 end if platdev:poweron(true) then io.stdout:write("4G modem has been powered up\n") io.stdout:flush() invoker.waitsec(tmpval) else io.stderr:write("Error, failed to power on 4G modem\n") io.stderr:flush() end -- wait for 4G modem to show up local modem4g = nil while true do modem4g = newmodems.detect() if modem4g and modem4g:f_preinit() == newmodems.PREINIT_AGAIN then local name = modem4g.name or "WTH SAID THAT, 4G NOT WORKING..." io.stdout:write(gfmt("Restarting 4G modem checking for '%s'\n", name)) io.stdout:flush() modem4g:close(); modem4g = nil end if modem4g then break end invoker.waitsec(invoker.uptime() < 120 and 15 or 60) end g_modem4g = modem4g io.stdout:write(gfmt("Found 4G modem device: %s\n", modem4g.name)) io.stdout:flush() -- set apn local renum = 1 while not check_apn() do if renum > 2 then io.stderr:write("Failed to set apn\n") io.stderr:flush() break end renum = renum + 1 invoker.waitsec(5) end -- wait for netdev g_netdev = g_platform:netdev() if not g_netdev or modem4g.name == "L610" then io.stderr:write("4G netdev not found\n") io.stderr:flush() modem4g_repower(5, 20) io.stdout:write("Warning, trying to reconnect 4G modem to find netdev...\n") io.stdout:flush() g_modem4g:f_connect() invoker.waitsec(15) else io.stdout:write(gfmt("Found netdev: %s\n", g_netdev)) io.stdout:flush() end update_ttypath_file(true) -- read simcard no if g_modem4g.dualsim then g_cardno = tonumber(g_4gmode["simno"]) if g_cardno ~= g_SIMCARD_EXTERNAL and g_cardno ~= g_SIMCARD_INTERNAL then g_cardno = g_SIMCARD_INTERNAL io.stderr:write("Error, invalid SIMCard choice from config file.\n") io.stderr:flush() end end io.stdout:write(gfmt("Firstly use card %d\n", g_cardno)) io.stdout:flush() -- update ttydev/iccid files if g_modem4g.dualsim then update_simcard_info(g_cardno) end while g_cardno ~= g_modem4g:f_get_cursim() do g_modem4g:f_switch_sim(g_cardno) invoker.waitsec(5) end return true end local function mainfunc() local tmpval, itercnt, failcnt, passcnt = 0, 0, 0, 0 local at_okay, at_recon, at_time = false, 3, 0 local sim_okay, sim_recon, sim_time = false , 3, 0 local ping_recon = 3 local nowtime, changenum = 0, 2 while true do tmpval = 120 -- whether 4g network is enabled if network4g_enabled() then local phost, recon, change_disable = false, false, false local st4g, stinfo = {}, {} itercnt = itercnt + 1 if not invoker.statfile(g_iccid_file) or (itercnt % 6) == 1 then update_simcard_iccid() end -- check AT-command replay local ttyrw = g_modem4g:f_opentty(115200) if not ttyrw then at_okay = true io.stderr:write("Error, not find tty dev") io.stderr:flush() else if at_recon >= 0 then at_okay = ttyrw:hasreply() end if at_okay then at_recon, at_time = 3, 0 elseif at_recon > 0 then if at_time == 0 or invoker.uptime() - at_time >= 180 then at_time, recon = -1, true at_recon = at_recon - 1 end io.stderr:write(gfmt("%d:Error, AT-commond not replay.\n", at_recon+1)) io.stderr:flush() else at_time, change_disable = 0, true --ulog.log(ulog.LOG_ERR, gfmt("ERROR, AT-command not have replay %d.", itercnt)) end ttyrw:close(); ttyrw = nil end -- check hassim if sim_recon >= 0 and at_okay then sim_okay = g_modem4g:f_hassim() end if sim_okay then sim_recon, sim_time = 3, 0 elseif sim_recon > 0 and at_okay then if sim_time == 0 or invoker.uptime() - sim_time >= 300 then sim_time, recon = -1, true sim_recon = sim_recon - 1 end io.stderr:write(gfmt("%d:Error, not found simcard.\n", sim_recon+1)) io.stderr:flush() else sim_time, change_disable = 0, true end -- check status if at_okay then st4g, stinfo = g_modem4g:f_status() end if type(st4g) == "table" then if not st4g['HAS_REGISTERD'] then io.stdout:write(gfmt("Error, 4G modem not registerd: \n%s\n,%s\n", st4g["AT+CREG"] or "WTH SAIED THAT...", st4g["AT+CGREG"] or "WTH SAIED THAT...")) else io.stdout:write(gfmt("INFO, 4G modem has registered: \n%s\n,%s\n", st4g["AT+CREG"] or "WTH SAIED THAT...", st4g["AT+CGREG"] or "WTH SAIED THAT...")) end io.stdout:flush() end -- ping test if at_okay and sim_okay and ping_recon >= 0 then phost = network_okay(nil) elseif not at_okay or not sim_okay then passcnt = 0 failcnt = failcnt + 1 end if at_okay and sim_okay and ping_recon >= 0 and not phost then io.stdout:write(gfmt("%s: Network ping failed\n", os.date())) if ping_recon == 3 then io.stdout:write(gfmt("Warning, trying to reset 4G modem %s ...\n", g_modem4g.name)) io.stdout:flush() g_modem4g:f_reset() invoker.msleep(7000) update_ttypath_file(true) io.stdout:write(gfmt("Warning, trying to reconnect 4G modem %s ...\n", g_modem4g.name)) io.stdout:flush() check_apn() elseif wwan_cannot_up() then io.stdout:write(gfmt("%d: Warning, trying to restart Network Daemon...\n", ping_recon)) io.stdout:flush() invoker.invoke(invoker.NOSTDIO, "netdaemon-restart", "restart") invoker.msleep(3000) if g_modem4g.name == "MC661" or g_platform.name == "MA35D1" then g_modem4g:f_connect() end invoker.msleep(3000) phost = true else io.stdout:write(gfmt("%d: Warning, trying to reconnect 4G modem %s ...\n", ping_recon, g_modem4g.name)) io.stdout:flush() g_modem4g:f_connect() end tmpval, passcnt = 60, 0 failcnt = failcnt + 1 ping_recon = ping_recon - 1 elseif phost then io.stdout:write(gfmt("%s: Network ping okay: %s\n", os.date(), phost)) io.stdout:flush() passcnt = passcnt + 1 failcnt, ping_recon = 0, 3 nowtime, changenum = 0, 2 end -- no AT-command replay or not hassim if recon then io.stdout:write(gfmt("4G SIMCard found: %s, re-power 4G modem...\n", sim_okay and "true" or "false")) io.stdout:flush() modem4g_repower(5, 20) update_ttypath_file(true) io.stdout:write(gfmt("Warning, trying to reconnect 4G modem %s ...\n", g_modem4g.name)) io.stdout:flush() g_modem4g:f_connect() if at_time == -1 then at_time = invoker.uptime() end if sim_time == -1 then sim_time = invoker.uptime() end tmpval = 60 end -- reset more than 3 local flag = ((sim_recon == 0) or (at_recon == 0)) and change_disable or (ping_recon < 0) if flag and g_modem4g.dualsim then if changenum > 0 then switch_simcard() tmpval = 30 changenum = changenum - 1 at_recon, sim_recon, ping_recon = 3, 3, 3 elseif nowtime == 0 then invoker.invoke(invoker.NOSTDIO, "ip", "addr", "flush", g_netdev) nowtime = invoker.uptime() io.stdout:write("Waiting 2 hours for switching simcard......\n") io.stdout:flush() elseif (invoker.uptime() - nowtime) > 7200 then nowtime, changenum = 0, 2 at_recon, sim_recon = 3, 3 tmpval, ping_recon = 30, 3 end elseif flag and not g_modem4g.dualsim then if nowtime == 0 then invoker.invoke(invoker.NOSTDIO, "ip", "addr", "flush", g_netdev) nowtime = invoker.uptime() io.stdout:write("Waiting 2 hours for restarting modem......\n") io.stdout:flush() elseif (invoker.uptime() - nowtime) > 7200 then tmpval = 30 nowtime, at_recon = 0, 3 sim_recon, ping_recon = 3, 3 end end local signal = 99 if stinfo and (type(stinfo[4]) ~= 'string' or string.len(stinfo[4]) < 2) then stinfo[7] = 99 end if stinfo then signal = stinfo[7] end update_signal_file(signal) update_using_simcard_info(stinfo) update_status_info(stinfo,passcnt,failcnt) else io.stdout:write("Warning, network4g is disabled!!!\n") io.stdout:flush() -- TODO: bring down 4G network if g_netdev then invoker.invoke(0, "ip", "addr", "flush", "dev", g_netdev) invoker.invoke(0, "ip", "link", "set", "dev", g_netdev, "down") end end invoker.waitsec(tmpval) end end new4gnet_init() mainfunc() os.exit(1)