luci-mod-admin-full: show realtime wlan graph only if iw command is installed
[project/luci.git] / applications / luci-app-olsr / luasrc / controller / olsr.lua
1 module("luci.controller.olsr", package.seeall)
2
3 local neigh_table = nil
4 local ifaddr_table = nil
5
6 function index()
7         local ipv4,ipv6
8         if nixio.fs.access("/etc/config/olsrd") then
9                 ipv4 = 1
10         end
11         if nixio.fs.access("/etc/config/olsrd6") then
12                 ipv6 = 1
13         end
14         if not ipv4 and not ipv6 then
15                 return
16         end
17
18         require("luci.model.uci")
19         local uci = luci.model.uci.cursor_state()
20
21         uci:foreach("olsrd", "olsrd", function(s)
22                 if s.SmartGateway and s.SmartGateway == "yes" then has_smartgw  = true end
23         end)
24
25         local page  = node("admin", "status", "olsr")
26         page.target = template("status-olsr/overview")
27         page.title  = _("OLSR")
28         page.subindex = true
29
30         local page  = node("admin", "status", "olsr", "json")
31         page.target = call("action_json")
32         page.title = nil
33         page.leaf = true
34
35         local page  = node("admin", "status", "olsr", "neighbors")
36         page.target = call("action_neigh")
37         page.title  = _("Neighbours")
38         page.subindex = true
39         page.order  = 5
40
41         local page  = node("admin", "status", "olsr", "routes")
42         page.target = call("action_routes")
43         page.title  = _("Routes")
44         page.order  = 10
45
46         local page  = node("admin", "status", "olsr", "topology")
47         page.target = call("action_topology")
48         page.title  = _("Topology")
49         page.order  = 20
50
51         local page  = node("admin", "status", "olsr", "hna")
52         page.target = call("action_hna")
53         page.title  = _("HNA")
54         page.order  = 30
55
56         local page  = node("admin", "status", "olsr", "mid")
57         page.target = call("action_mid")
58         page.title  = _("MID")
59         page.order  = 50
60
61         if has_smartgw then
62                 local page  = node("admin", "status", "olsr", "smartgw")
63                 page.target = call("action_smartgw")
64                 page.title  = _("SmartGW")
65                 page.order  = 60
66         end
67
68         local page  = node("admin", "status", "olsr", "interfaces")
69         page.target = call("action_interfaces")
70         page.title  = _("Interfaces")
71         page.order  = 70
72
73         odsp = entry(
74                 {"admin", "services", "olsrd", "display"},
75                 cbi("olsr/olsrddisplay"), _("Display")
76         )
77
78 end
79
80 function action_json()
81         local http = require "luci.http"
82         local utl = require "luci.util"
83         local uci = require "luci.model.uci".cursor()
84         local jsonreq4
85         local jsonreq6
86
87         local v4_port = uci:get("olsrd", "olsrd_jsoninfo", "port") or 9090
88         local v6_port = uci:get("olsrd6", "olsrd_jsoninfo", "port") or 9090
89
90         jsonreq4 = utl.exec("(echo /status | nc 127.0.0.1 " .. v4_port .. ") 2>/dev/null" )
91         jsonreq6 = utl.exec("(echo /status | nc ::1 " .. v6_port .. ") 2>/dev/null")
92         http.prepare_content("application/json")
93         if not jsonreq4 or jsonreq4 == "" then
94                 jsonreq4 = "{}"
95         end
96         if not jsonreq6 or jsonreq6 == "" then
97                 jsonreq6 = "{}"
98         end
99         http.write('{"v4":' .. jsonreq4 .. ', "v6":' .. jsonreq6 .. '}')
100 end
101
102
103 local function local_mac_lookup(ipaddr)
104         local _, ifa, dev
105
106         ipaddr = tostring(ipaddr)
107
108         if not ifaddr_table then
109                 ifaddr_table = nixio.getifaddrs()
110         end
111
112         -- ipaddr -> ifname
113         for _, ifa in ipairs(ifaddr_table) do
114                 if ifa.addr == ipaddr then
115                         dev = ifa.name
116                         break
117                 end
118         end
119
120         -- ifname -> macaddr
121         for _, ifa in ipairs(ifaddr_table) do
122                 if ifa.name == dev and ifa.family == "packet" then
123                         return ifa.addr
124                 end
125         end
126 end
127
128 local function remote_mac_lookup(ipaddr)
129         local _, n
130
131         if not neigh_table then
132                 neigh_table = luci.ip.neighbors()
133         end
134
135         for _, n in ipairs(neigh_table) do
136                 if n.mac and n.dest and n.dest:equal(ipaddr) then
137                         return n.mac
138                 end
139         end
140 end
141
142 function action_neigh(json)
143         local data, has_v4, has_v6, error = fetch_jsoninfo('links')
144
145         if error then
146                 return
147         end
148
149         local uci = require "luci.model.uci".cursor_state()
150         local resolve = uci:get("luci_olsr", "general", "resolve")
151         local ntm = require "luci.model.network".init()
152         local devices  = ntm:get_wifidevs()
153         local sys = require "luci.sys"
154         local assoclist = {}
155         --local neightbl = require "neightbl"
156         local ntm = require "luci.model.network"
157         local ipc = require "luci.ip"
158         local nxo = require "nixio"
159         local defaultgw
160
161         ipc.routes({ family = 4, type = 1, dest_exact = "0.0.0.0/0" },
162                 function(rt) defaultgw = rt.gw end)
163
164         local function compare(a,b)
165                 if a.proto == b.proto then
166                         return a.linkCost < b.linkCost
167                 else
168                         return a.proto < b.proto
169                 end
170         end
171
172         for _, dev in ipairs(devices) do
173                 for _, net in ipairs(dev:get_wifinets()) do
174                         local radio = net:get_device()
175                         assoclist[#assoclist+1] = {} 
176                         assoclist[#assoclist]['ifname'] = net:ifname()
177                         assoclist[#assoclist]['network'] = net:network()[1]
178                         assoclist[#assoclist]['device'] = radio and radio:name() or nil
179                         assoclist[#assoclist]['list'] = net:assoclist()
180                 end
181         end
182
183         for k, v in ipairs(data) do
184                 local snr = 0
185                 local signal = 0
186                 local noise = 0
187                 local mac = ""
188                 local ip
189                 local neihgt = {}
190                 
191                 if resolve == "1" then
192                         hostname = nixio.getnameinfo(v.remoteIP, nil, 100)
193                         if hostname then
194                                 v.hostname = hostname
195                         end
196                 end
197
198                 local interface = ntm:get_status_by_address(v.localIP)
199                 local lmac = local_mac_lookup(v.localIP)
200                 local rmac = remote_mac_lookup(v.remoteIP)
201
202                 for _, val in ipairs(assoclist) do
203                         if val.network == interface and val.list then
204                                 for assocmac, assot in pairs(val.list) do
205                                         assocmac = string.lower(assocmac or "")
206                                         if rmac == assocmac then
207                                                 signal = tonumber(assot.signal)
208                                                 noise = tonumber(assot.noise)
209                                                 snr = (noise*-1) - (signal*-1)
210                                         end
211                                 end
212                         end
213                 end
214                 if interface then
215                         v.interface = interface
216                 end
217                 v.snr = snr
218                 v.signal = signal
219                 v.noise = noise
220                 if rmac then
221                         v.remoteMAC = rmac
222                 end
223                 if lmac then
224                         v.localMAC = lmac
225                 end
226
227                 if defaultgw == v.remoteIP then
228                         v.defaultgw = 1
229                 end
230         end
231
232         table.sort(data, compare)
233         luci.template.render("status-olsr/neighbors", {links=data, has_v4=has_v4, has_v6=has_v6})
234 end
235
236 function action_routes()
237         local data, has_v4, has_v6, error = fetch_jsoninfo('routes')
238         if error then
239                 return
240         end
241
242         local uci = require "luci.model.uci".cursor_state()
243         local resolve = uci:get("luci_olsr", "general", "resolve")
244
245         for k, v in ipairs(data) do
246                 if resolve == "1" then
247                         local hostname = nixio.getnameinfo(v.gateway, nil, 100)
248                         if hostname then
249                                 v.hostname = hostname
250                         end
251                 end
252         end
253
254         local function compare(a,b)
255                 if a.proto == b.proto then
256                         return a.rtpMetricCost < b.rtpMetricCost
257                 else
258                         return a.proto < b.proto
259                 end
260         end
261
262         table.sort(data, compare)
263         luci.template.render("status-olsr/routes", {routes=data, has_v4=has_v4, has_v6=has_v6})
264 end
265
266 function action_topology()
267         local data, has_v4, has_v6, error = fetch_jsoninfo('topology')
268         if error then
269                 return
270         end
271
272         local function compare(a,b)
273                 if a.proto == b.proto then
274                         return a.tcEdgeCost < b.tcEdgeCost
275                 else
276                         return a.proto < b.proto
277                 end
278         end
279
280         table.sort(data, compare)
281         luci.template.render("status-olsr/topology", {routes=data, has_v4=has_v4, has_v6=has_v6})
282 end
283
284 function action_hna()
285         local data, has_v4, has_v6, error = fetch_jsoninfo('hna')
286         if error then
287                 return
288         end
289
290         local uci = require "luci.model.uci".cursor_state()
291         local resolve = uci:get("luci_olsr", "general", "resolve")
292
293         local function compare(a,b)
294                 if a.proto == b.proto then
295                         return a.genmask < b.genmask
296                 else
297                         return a.proto < b.proto
298                 end
299         end
300
301         for k, v in ipairs(data) do
302                 if resolve == "1" then
303                         hostname = nixio.getnameinfo(v.gateway, nil, 100)
304                         if hostname then
305                                 v.hostname = hostname
306                         end
307                 end
308                 if v.validityTime then
309                         v.validityTime = tonumber(string.format("%.0f", v.validityTime / 1000))
310                 end
311         end
312
313         table.sort(data, compare)
314         luci.template.render("status-olsr/hna", {hna=data, has_v4=has_v4, has_v6=has_v6})
315 end
316
317 function action_mid()
318         local data, has_v4, has_v6, error = fetch_jsoninfo('mid')
319         if error then
320                 return
321         end
322
323         local function compare(a,b)
324                 if a.proto == b.proto then
325                         return a.ipAddress < b.ipAddress
326                 else
327                         return a.proto < b.proto
328                 end
329         end
330
331         table.sort(data, compare)
332         luci.template.render("status-olsr/mid", {mids=data, has_v4=has_v4, has_v6=has_v6})
333 end
334
335 function action_smartgw()
336         local data, has_v4, has_v6, error = fetch_jsoninfo('gateways')
337         if error then
338                 return
339         end
340
341         local function compare(a,b)
342                 if a.proto == b.proto then
343                         return a.tcPathCost < b.tcPathCost
344                 else
345                         return a.proto < b.proto
346                 end
347         end
348
349         table.sort(data, compare)
350         luci.template.render("status-olsr/smartgw", {gws=data, has_v4=has_v4, has_v6=has_v6})
351 end
352
353 function action_interfaces()
354         local data, has_v4, has_v6, error = fetch_jsoninfo('interfaces')
355         if error then
356                 return
357         end
358
359         local function compare(a,b)
360                 return a.proto < b.proto
361         end
362
363         table.sort(data, compare)
364         luci.template.render("status-olsr/interfaces", {iface=data, has_v4=has_v4, has_v6=has_v6})
365 end
366
367 -- Internal
368 function fetch_jsoninfo(otable)
369         local uci = require "luci.model.uci".cursor_state()
370         local utl = require "luci.util"
371         local json = require "luci.json"
372         local IpVersion = uci:get_first("olsrd", "olsrd","IpVersion")
373         local jsonreq4 = ""
374         local jsonreq6 = ""
375         local v4_port = uci:get("olsrd", "olsrd_jsoninfo", "port") or 9090
376         local v6_port = uci:get("olsrd6", "olsrd_jsoninfo", "port") or 9090
377
378         jsonreq4 = utl.exec("(echo /" .. otable .. " | nc 127.0.0.1 " .. v4_port .. ") 2>/dev/null")
379         jsonreq6 = utl.exec("(echo /" .. otable .. " | nc ::1 " .. v6_port .. ") 2>/dev/null")
380         local jsondata4 = {}
381         local jsondata6 = {}
382         local data4 = {}
383         local data6 = {}
384         local has_v4 = False
385         local has_v6 = False
386
387         if jsonreq4 == '' and jsonreq6 == '' then
388                 luci.template.render("status-olsr/error_olsr")
389                 return nil, 0, 0, true
390         end
391
392         if jsonreq4 ~= "" then
393                 has_v4 = 1
394                 jsondata4 = json.decode(jsonreq4)
395                 if otable == 'status' then
396                         data4 = jsondata4 or {}
397                 else
398                         data4 = jsondata4[otable] or {}
399                 end
400
401                 for k, v in ipairs(data4) do
402                         data4[k]['proto'] = '4'
403                 end
404
405         end
406         if jsonreq6 ~= "" then
407                 has_v6 = 1
408                 jsondata6 = json.decode(jsonreq6)
409                 if otable == 'status' then
410                         data6 = jsondata6 or {}
411                 else
412                         data6 = jsondata6[otable] or {}
413                 end
414                 for k, v in ipairs(data6) do
415                         data6[k]['proto'] = '6'
416                 end
417         end
418
419         for k, v in ipairs(data6) do
420                 table.insert(data4, v)
421         end
422
423         return data4, has_v4, has_v6, false
424 end
425