--[[ @object-name: tethering @object-desc: this is the API related to tethering internet access --]] local utils = require "oui.utils" local fs = require "oui.fs" local ubus = require "ubus" local uci = require "uci" local hardware = require "hardware" local ERR_TETHERING_UNSUPPORT = -1 local ERR_TETHERING_NO_DEVICE = -2 local ERR_TETHERING_PARAM_MISSING = -3 local M = {} --[[ @method-name: get_status @method-desc: get tethering info @out array devices device list @out string devices.device device name @out number devices.type device type [0: Android; 1:Apple; 2:unknow] @out bool devices.use working status [ture: enable; false: disable] @out number status device status [0: disconnected; 1: connected; 2: connecting] @out object ?ipv6 IPv6 info @out string ?ipv6.ip IPv6 address @out string ?ipv6.gateway IPv6 gateway @out array ?ipv6.dns IPv6 DNS @out object ?ipv4 IPv4 info @out string ?ipv4.ip IPv4 address @out string ?ipv4.gateway IPv4 gateway @out array ?ipv4.dns IPv4 DNS @out number ?err_code error code [-1: This feature is not supported; -2: The device is not plugged in] @out string ?err_msg error message @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[\"\",\"tethering\",\"get_status\",{}],\"id\":1} @out-example: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"devices\":[{\"name\":\"usb0\",\"tyep\":0,\"use\":true},{\"device\":\"usb1\",\"tyep\":0,\"use\":false}],\"status\":1,\"ipv4\":{\"ip\":\"192.168.42.38/24\",\"gateway\":\"192.168.42.129\",\"dns\":[\"192.168.42.129\"]}}} --]] M.get_status = function() if not fs.access("/proc/gl-hw-info/usb-port") then return { err_code = ERR_TETHERING_UNSUPPORT, err_msg = "Unsupported features" } end local devices = {} for ifname in fs.dir("/sys/class/net") do local s = hardware.platform_telething_whether_removing_usb0() if s ~= ifname then if not ifname:match("^wwan") then local link = fs.readlink("/sys/class/net/" .. ifname) if link and link:match("usb") then local typ = 2 if ifname:match("^eth%d") then if utils.readfile("/sys/kernel/debug/usb/devices"):match("ipheth") then typ = 1 end elseif ifname:match("^usb%d") then typ = 0 end devices[#devices + 1] = { device = ifname, type = typ, use = false } end end end end if #devices == 0 then return { err_code = ERR_TETHERING_NO_DEVICE, err_msg = "No device found. Please insert" } end local res = { devices = devices, status = 0 } local conn = ubus.connect() local s = conn:call("network.interface.tethering", "status", {}) or {} if s.up == nil then return res end if s["ipv4-address"] and #s["ipv4-address"] > 0 then res.ipv4 = {} res.status = 1 res.ipv4.ip = s["ipv4-address"][1].address .. "/" .. s["ipv4-address"][1].mask else res.status = 2 return res end for _, r in ipairs(s.route) do if r.target == "0.0.0.0" then res.ipv4.gateway = r.nexthop end end if s.device then for _, dev in ipairs(res.devices) do if s.device == dev.device then dev.use = true end end end local c = uci.cursor() local manual_dns = c:get("glconfig", "general", "manual_dns") if manual_dns == "1" then local server = c:get("dhcp", "@dnsmasq[0]", "server") or "" for dns in server:gmatch("%S+") do res.ipv4.dns[#res.ipv4.dns + 1] = dns end else res.ipv4.dns = s["dns-server"] end s = conn:call("network.interface.tethering6", "status", {}) or {} if not s.up then return res end res.ipv6 = {} if #s["ipv6-address"] > 0 then res.ipv6.ip = s["ipv6-address"][1].address .. "/" .. s["ipv6-address"][1].mask end for _, r in ipairs(s.route) do if r.target == "::" then res.ipv6.gateway = r.nexthop end end res.ipv6.dns = s["dns-server"] return res end --[[ @method-name: set_connect @method-desc: connect or disconnect tethering @in string device device name @out number ?err_code error code [-3: missing parameters] @out string ?err_msg error message @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[\"\",\"tethering\",\"set_connect\",{\"device\":\"usb0\"}],\"id\":1} @out-example: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{}} --]] M.set_connect = function(params) local device = params.device local c = uci.cursor() if not device or device == "" then return { err_code = ERR_TETHERING_PARAM_MISSING, err_msg = "No parameter (device)" } end c:delete("network", "tethering") c:set("network", "tethering", "interface") c:set("network", "tethering", "proto", "dhcp") c:set("network", "tethering", "ifname", device) c:set("network", "tethering", "metric", "30") c:commit("network") fs.sync() c:foreach("firewall", "zone", function(s) if s.name == "wan" then local nets = s.network or {} if type(nets) == "string" then local iterator = nets:gmatch("%S+") nets = {} for net in iterator do nets[#nets + 1] = net end end for _, net in ipairs(nets) do if net == "tethering" then return false end end nets[#nets + 1] = "tethering" c:set("firewall", s[".name"], "network", nets) return false end end) c:commit("firewall") fs.sync() local conn = ubus.connect() conn:call("network", "reload", {}) conn:close() ngx.pipe.spawn({"/etc/init.d/firewall", "reload"}) end --[[ @method-name: disconnect @method-desc: disconnect tethering @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[\"\",\"tethering\",\"disconnect\"],\"id\":1} @out-example: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{}} --]] M.disconnect = function() local c = uci.cursor() c:set("network", "tethering", "disabled", 1) c:commit("network") fs.sync() local conn = ubus.connect() conn:call("network", "reload", {}) conn:close() ngx.pipe.spawn("kill $(pgrep -f \"mwan3track tethering\")") end return M