1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
-- NetBSD utility functions
local require, error, assert, tonumber, tostring,
setmetatable, pairs, ipairs, unpack, rawget, rawset,
pcall, type, table, string =
require, error, assert, tonumber, tostring,
setmetatable, pairs, ipairs, unpack, rawget, rawset,
pcall, type, table, string
local function init(S)
local abi, types, c = S.abi, S.types, S.c
local t, pt, s = types.t, types.pt, types.s
local h = require "syscall.helpers"
local divmod = h.divmod
local ffi = require "ffi"
local bit = require "syscall.bit"
local octal = h.octal
-- TODO move to helpers? see notes in syscall.lua about reworking though
local function istype(tp, x)
if ffi.istype(tp, x) then return x end
return false
end
local util = {}
local mt = {}
-- initial implementation of network ioctls, no real attempt to make it compatible with Linux...
-- initially just implement the ones from rump netconfig, make interface later
-- it is a bit messy creating new socket every time, better make a sequence of commands
local function sockioctl(domain, tp, io, data)
local sock, err = S.socket(domain, tp)
if not sock then return nil, err end
local io, err = sock:ioctl(io, data)
sock:close()
if not io then return nil, err end
return io
end
function util.ifcreate(name) return sockioctl("inet", "dgram", "SIOCIFCREATE", t.ifreq{name = name}) end
function util.ifdestroy(name) return sockioctl("inet", "dgram", "SIOCIFDESTROY", t.ifreq{name = name}) end
function util.ifgetflags(name)
local io, err = sockioctl("inet", "dgram", "SIOCGIFFLAGS", t.ifreq{name = name})
if not io then return nil, err end
return io.flags
end
function util.ifsetflags(name, flags)
return sockioctl("inet", "dgram", "SIOCSIFFLAGS", {name = name, flags = c.IFF[flags]})
end
function util.ifup(name)
local flags, err = util.ifgetflags(name)
if not flags then return nil, err end
return util.ifsetflags(name, c.IFF(flags, "up"))
end
function util.ifdown(name)
local flags, err = util.ifgetflags(name)
if not flags then return nil, err end
return util.ifsetflags(name, c.IFF(flags, "~up"))
end
function util.ifsetlinkstr(name, str) -- used to pass (optional) string to rump virtif (eg name of underlying tap device)
return sockioctl("inet", "dgram", "SIOCSLINKSTR", {name = name, cmd = 0, data = str})
end
-- TODO merge into one ifaddr function
function util.ifaddr_inet4(name, addr, mask)
-- TODO this function needs mask as an inaddr, so need to fix this if passed as / format or number
local addr, mask = util.inet_name(addr, mask)
local bn = addr:get_mask_bcast(mask)
local broadcast, netmask = bn.broadcast, bn.netmask
local ia = t.ifaliasreq{name = name, addr = addr, mask = netmask, broadaddr = broadcast}
return sockioctl("inet", "dgram", "SIOCAIFADDR", ia)
end
function util.ifaddr_inet6(name, addr, mask)
local addr, mask = util.inet_name(addr, mask)
assert(ffi.istype(t.in6_addr, addr), "not an ipv6 address") -- TODO remove once merged
local prefixmask = t.in6_addr()
local bb, b = divmod(mask, 8)
for i = 0, bb - 1 do prefixmask.s6_addr[i] = 0xff end
if bb < 16 then prefixmask.s6_addr[bb] = bit.lshift(0xff, 8 - b) end -- TODO needs test!
local ia = t.in6_aliasreq{name = name, addr = addr, prefixmask = prefixmask,
lifetime = {pltime = "infinite_lifetime", vltime = "infinite_lifetime"}}
return sockioctl("inet6", "dgram", "SIOCAIFADDR_IN6", ia)
end
-- table based mount, more cross OS compatible
function util.mount(tab)
local filesystemtype = tab.type
local dir = tab.target or tab.dir
local flags = tab.flags
local data = tab.data
local datalen = tab.datalen
if tab.fspec then data = tab.fspec end
return S.mount(filesystemtype, dir, flags, data, datalen)
end
local function kdumpfn(len)
return function(buf, pos)
if pos + s.ktr_header >= len then return nil end
local ktr = pt.ktr_header(buf + pos)
if pos + s.ktr_header + ktr.len >= len then return nil end
return pos + #ktr, ktr
end
end
function util.kdump(buf, len)
return kdumpfn(len), buf, 0
end
local function do_bridge_setcmd(name, op, arg)
return sockioctl("inet", "dgram", "SIOCSDRVSPEC", {name = name, cms = op, data = arg})
end
local function do_bridge_getcmd(name, op, arg) -- TODO should allocate correct arg type here based on arg
local data, err = sockioctl("inet", "dgram", "SIOCGDRVSPEC", {name = name, cms = op, data = arg})
if not data then return nil, err end
return arg
end
return util
end
return {init = init}
|