File: util.lua

package info (click to toggle)
lua-ljsyscall 0.12-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,732 kB
  • sloc: ansic: 434; sh: 59; makefile: 3
file content (138 lines) | stat: -rw-r--r-- 4,508 bytes parent folder | download | duplicates (3)
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}