#!/usr/bin/env lua local posix = require "Posix" local json = require "json" local ubus = require "ubus" --[[ pppoe exit code #define EXIT_OK 0 #define EXIT_FATAL_ERROR 1 #define EXIT_OPTION_ERROR 2 #define EXIT_NOT_ROOT 3 #define EXIT_NO_KERNEL_SUPPORT 4 #define EXIT_USER_REQUEST 5 #define EXIT_LOCK_FAILED 6 #define EXIT_OPEN_FAILED 7 #define EXIT_CONNECT_FAILED 8 #define EXIT_PTYCMD_FAILED 9 #define EXIT_NEGOTIATION_FAILED 10 #define EXIT_PEER_AUTH_FAILED 11 #define EXIT_IDLE_TIMEOUT 12 #define EXIT_CONNECT_TIME 13 #define EXIT_CALLBACK 14 #define EXIT_PEER_DEAD 15 #define EXIT_HANGUP 16 #define EXIT_LOOPBACK 17 #define EXIT_INIT_FAILED 18 #define EXIT_AUTH_TOPEER_FAILED 19 #define EXIT_TRAFFIC_LIMIT 20 #define EXIT_CNID_AUTH_FAILED 21 --]] -- result begin -- peer no response local PPPOE_RESULT = { ['PEER_NO_RESP'] = { code = 531, vcode = 678, ppp_exit = '10', }, ['NO_MORE_SESSION'] = { code = 530, vcode = 633, ppp_exit = '20' }, ['AUTH_FAILD'] = { code = 507, vcode = 691, ppp_exit = { ['11'] = true, ['19'] = true} } } local PPPOE_OTHER_ERROR = { [678] = 532, [691] = 508 } -- result end local config = { last_error = '/tmp/state/pppoe_last_error', debug = nil, check_interval = 2 } LOG = { debug = posix.LOG_DEBUG, info = posix.LOG_INFO, warning = posix.LOG_WARNING, error = posix.LOG_ERR } function log(level, fmt, ...) logstr = string.format(fmt, unpack(arg)) posix.syslog(level, logstr) if config.debug then print(logstr) end end function uconn_read_status(uconn) return uconn:call("network.interface", "status", {interface="wan"}) end function get_if_status(uconn) ifst = uconn_read_status(uconn) if not ifst then uconn:call("network", "reload", {}) log(LOG.debug, "ubus call network reload") posix.sleep(1) -- wait reload ifst = uconn_read_status(uconn) end return ifst end function print_usage(proc) proc = proc or "pppoe.lua" print(string.format("usage: %s ", proc)) os.exit(1) end function action_up(ifst, uconn) if ifst.autostart then log(LOG.warning, "already start, skip ifup") os.exit(1) end log(LOG.debug, "ifup wan") os.execute("ifup wan") os.exit(0) end function action_down(ifst) if ifst.autostart then os.execute("ifdown wan") log(LOG.info, "put ifdown wan") os.exit(0) else log(LOG.warning, "already down, skip ifdown") os.exit(1) end end function match_pattern(exit_code) for key, pattern in pairs(PPPOE_RESULT) do local p = pattern.ppp_exit if type(p) == 'table' then if p[exit_code] then return pattern end else if p == exit_code then return pattern end end end return nil end function get_last_error() local logfd = io.open(config.last_error) if not logfd then return nil end local exit_code = logfd:read("*all") logfd:close() local res = match_pattern(exit_code:gsub('\n*','')) if res then return { code = res.code, msg = res.vcode } else return { code = 0, msg = ""} end end function get_profile_record() local uci = require("luci.model.uci").cursor() local crypto = require("xiaoqiang.util.XQCryptoUtil") local name = uci:get("network", "wan", "username") local password = uci:get("network", "wan", "password") if not name or not password then return 0 end local key = crypto.md5Str(name..password) local value = uci:get_all("xiaoqiang", key) if value and value.status then local num_status = tonumber(value.status) return num_status or 0 end return 0 end function action_status(ifst) local status = get_last_error() if not status then status = {} end if ifst.up then status.process = "up" elseif ifst.pending then status.process = "connecting" else status.process = "down" end local last_status = get_profile_record() if last_status == 1 then local other_error = PPPOE_OTHER_ERROR[status['msg']] if other_error then status['code'] = other_error end end print(json.encode(status)) os.exit(0) end local status, err = pcall( function () local proc = arg[0] local action = arg[1] if not action then print_usage(proc) end if action == "up" and action == "down" then posix.daemonize() end posix.openlog(proc, "cp", posix.LOG_LOCAL7) local uconn = ubus.connect() local cursor = require("luci.model.uci").cursor() local ifst = get_if_status(uconn) local proto = cursor:get("network", "wan", "proto") if proto ~= "pppoe" then log(LOG.error, "wan proto is not pppoe but %s", proto) os.exit(1) end if action == "up" then action_up(ifst, uconn) elseif action == "down" then action_down(ifst) elseif action == "status" then action_status(ifst) else print_usage(proc) os.exit(1) end end ) if not status then log(LOG.error, err) end