#!/opt/lnxall_app/bin/lua

local bit = require "bit"
local uci = require "uci"
local invoker = require "invoker"
local posix = require "posix"

local giface, gmac, gval = arg[1], arg[2], arg[3]
local gmac_val = nil

local function usage()
	local iou = io.stderr
	iou:write("Usage: uci_set_mac wan1 MAC-ADDRESS [1]\n")
	iou:flush()
	os.exit(1)
end

local function validate_args()
	if type(giface) ~= "string" or #giface == 0 then
		usage()
	end

	if type(gmac) ~= "string" or #gmac ~= 17 then
		io.stderr:write("Error, invalid MAC address\n")
		usage()
	end

	local mval = {}
	for byte in string.gmatch(gmac, "[^:]+") do
		local num = tonumber("0x" .. byte)
		if not num or num < 0 or num > 255 then
			io.stderr:write(string.format("Error, invalid MAC address: %s\n", gmac))
			usage()
		end
		mval[#mval + 1] = num
	end
	if #mval ~= 6 then
		io.stderr:write(string.format("Error, invalid MAC address: %s\n", gmac))
		usage()
	end
	gmac_val = mval

	if type(gval) == "string" and #gval > 0 then
		local val = tonumber(gval)
		if type(val) ~= "number" or val ~= math.floor(val) or val < -255 or val > 255 then
			io.stderr:write(string.format("Error, invalid substruct/addition argument: %s\n", gval))
			usage()
		end
		gval = val
	else
		gval = 0
	end
	return true
end

local function modify_macaddr()
	local newmac = gmac
	if gval ~= 0 then
		local nval = gmac_val
		for idx = 6, 1, -1 do
			nval[idx] = nval[idx] + gval
			if nval[idx] < 0 then
				gval = -1
				nval[idx] = bit.band(nval[idx], 0xff)
			elseif nval[idx] > 255 then
				gval = 1
				nval[idx] = bit.band(nval[idx], 0xff)
			else
				break
			end
		end

		newmac = string.format("%02x:%02x:%02x:%02x:%02x:%02x",
			nval[1], nval[2], nval[3], nval[4], nval[5], nval[6])
		io.stdout:write(string.format("Computed modified MAC address: %s\n", newmac))
		io.stdout:flush()
	end

	local okay, nminfo = invoker.invoke(invoker.OUTPUT + invoker.NOSTDIO + 0x70000,
		"nmcli", "con", "show", giface)
	if okay ~= 0 or type(nminfo) ~= "string" then nminfo = "" end

	local nuci = uci.cursor("/etc/config")
	if nuci:get("network", giface) == nil then
		nuci:close(); nuci = nil
		os.exit(2)
	end
	local oldmac = nuci:get("network", giface, "macaddr")
	if oldmac == newmac and string.find(nminfo, newmac, 1, true) then
		nuci:close(); nuci = nil
		os.exit(3)
	end

	io.stdout:write(string.format("Updating interface %s with MAC address: %s\n",
		giface, newmac))
	io.stdout:flush()
	nuci:set("network", giface, "macaddr", newmac)
	nuci:commit("network")
	nuci:close(); nuci = nil

	-- invoker.invoke(0, "nothup", "/bin/sh", "-c", "sleep 3 ; netuci")
	return true
end

posix.setenv("PATH",
	"/opt/lnxall_app/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin", true)
validate_args()
modify_macaddr()
os.exit(0)
