cfadd9b7c72c197cc7a426b13a7d791ff6949465
[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                         assoclist[#assoclist+1] = {} 
175                         assoclist[#assoclist]['ifname'] = net.iwdata.ifname
176                         assoclist[#assoclist]['network'] = net.iwdata.network
177                         assoclist[#assoclist]['device'] = net.iwdata.device
178                         assoclist[#assoclist]['list'] = net.iwinfo.assoclist
179                 end
180         end
181
182         for k, v in ipairs(data) do
183                 local snr = 0
184                 local signal = 0
185                 local noise = 0
186                 local mac = ""
187                 local ip
188                 local neihgt = {}
189                 
190                 if resolve == "1" then
191                         hostname = nixio.getnameinfo(v.remoteIP, nil, 100)
192                         if hostname then
193                                 v.hostname = hostname
194                         end
195                 end
196
197                 local interface = ntm:get_status_by_address(v.localIP)
198                 local lmac = local_mac_lookup(v.localIP)
199                 local rmac = remote_mac_lookup(v.remoteIP)
200
201                 for _, val in ipairs(assoclist) do
202                         if val.network == interface and val.list then
203                                 for assocmac, assot in pairs(val.list) do
204                                         assocmac = string.lower(assocmac or "")
205                                         if rmac == assocmac then
206                                                 signal = tonumber(assot.signal)
207                                                 noise = tonumber(assot.noise)
208                                                 snr = (noise*-1) - (signal*-1)
209                                         end
210                                 end
211                         end
212                 end
213                 if interface then
214                         v.interface = interface
215                 end
216                 v.snr = snr
217                 v.signal = signal
218                 v.noise = noise
219                 if rmac then
220                         v.remoteMAC = rmac
221                 end
222                 if lmac then
223                         v.localMAC = lmac
224                 end
225
226                 if defaultgw == v.remoteIP then
227                         v.defaultgw = 1
228                 end
229         end
230
231         table.sort(data, compare)
232         luci.template.render("status-olsr/neighbors", {links=data, has_v4=has_v4, has_v6=has_v6})
233 end
234
235 function action_routes()
236         local data, has_v4, has_v6, error = fetch_jsoninfo('routes')
237         if error then
238                 return
239         end
240
241         local uci = require "luci.model.uci".cursor_state()
242         local resolve = uci:get("luci_olsr", "general", "resolve")
243
244         for k, v in ipairs(data) do
245                 if resolve == "1" then
246                         local hostname = nixio.getnameinfo(v.gateway, nil, 100)
247                         if hostname then
248                                 v.hostname = hostname
249                         end
250                 end
251         end
252
253         local function compare(a,b)
254                 if a.proto == b.proto then
255                         return a.rtpMetricCost < b.rtpMetricCost
256                 else
257                         return a.proto < b.proto
258                 end
259         end
260
261         table.sort(data, compare)
262         luci.template.render("status-olsr/routes", {routes=data, has_v4=has_v4, has_v6=has_v6})
263 end
264
265 function action_topology()
266         local data, has_v4, has_v6, error = fetch_jsoninfo('topology')
267         if error then
268                 return
269         end
270
271         local function compare(a,b)
272                 if a.proto == b.proto then
273                         return a.tcEdgeCost < b.tcEdgeCost
274                 else
275                         return a.proto < b.proto
276                 end
277         end
278
279         table.sort(data, compare)
280         luci.template.render("status-olsr/topology", {routes=data, has_v4=has_v4, has_v6=has_v6})
281 end
282
283 function action_hna()
284         local data, has_v4, has_v6, error = fetch_jsoninfo('hna')
285         if error then
286                 return
287         end
288
289         local uci = require "luci.model.uci".cursor_state()
290         local resolve = uci:get("luci_olsr", "general", "resolve")
291
292         local function compare(a,b)
293                 if a.proto == b.proto then
294                         return a.genmask < b.genmask
295                 else
296                         return a.proto < b.proto
297                 end
298         end
299
300         for k, v in ipairs(data) do
301                 if resolve == "1" then
302                         hostname = nixio.getnameinfo(v.gateway, nil, 100)
303                         if hostname then
304                                 v.hostname = hostname
305                         end
306                 end
307                 if v.validityTime then
308                         v.validityTime = tonumber(string.format("%.0f", v.validityTime / 1000))
309                 end
310         end
311
312         table.sort(data, compare)
313         luci.template.render("status-olsr/hna", {hna=data, has_v4=has_v4, has_v6=has_v6})
314 end
315
316 function action_mid()
317         local data, has_v4, has_v6, error = fetch_jsoninfo('mid')
318         if error then
319                 return
320         end
321
322         local function compare(a,b)
323                 if a.proto == b.proto then
324                         return a.ipAddress < b.ipAddress
325                 else
326                         return a.proto < b.proto
327                 end
328         end
329
330         table.sort(data, compare)
331         luci.template.render("status-olsr/mid", {mids=data, has_v4=has_v4, has_v6=has_v6})
332 end
333
334 function action_smartgw()
335         local data, has_v4, has_v6, error = fetch_jsoninfo('gateways')
336         if error then
337                 return
338         end
339
340         local function compare(a,b)
341                 if a.proto == b.proto then
342                         return a.tcPathCost < b.tcPathCost
343                 else
344                         return a.proto < b.proto
345                 end
346         end
347
348         table.sort(data, compare)
349         luci.template.render("status-olsr/smartgw", {gws=data, has_v4=has_v4, has_v6=has_v6})
350 end
351
352 function action_interfaces()
353         local data, has_v4, has_v6, error = fetch_jsoninfo('interfaces')
354         if error then
355                 return
356         end
357
358         local function compare(a,b)
359                 return a.proto < b.proto
360         end
361
362         table.sort(data, compare)
363         luci.template.render("status-olsr/interfaces", {iface=data, has_v4=has_v4, has_v6=has_v6})
364 end
365
366 -- Internal
367 function fetch_jsoninfo(otable)
368         local uci = require "luci.model.uci".cursor_state()
369         local utl = require "luci.util"
370         local json = require "luci.json"
371         local IpVersion = uci:get_first("olsrd", "olsrd","IpVersion")
372         local jsonreq4 = ""
373         local jsonreq6 = ""
374         local v4_port = uci:get("olsrd", "olsrd_jsoninfo", "port") or 9090
375         local v6_port = uci:get("olsrd6", "olsrd_jsoninfo", "port") or 9090
376
377         jsonreq4 = utl.exec("(echo /" .. otable .. " | nc 127.0.0.1 " .. v4_port .. ") 2>/dev/null")
378         jsonreq6 = utl.exec("(echo /" .. otable .. " | nc ::1 " .. v6_port .. ") 2>/dev/null")
379         local jsondata4 = {}
380         local jsondata6 = {}
381         local data4 = {}
382         local data6 = {}
383         local has_v4 = False
384         local has_v6 = False
385
386         if jsonreq4 == '' and jsonreq6 == '' then
387                 luci.template.render("status-olsr/error_olsr")
388                 return nil, 0, 0, true
389         end
390
391         if jsonreq4 ~= "" then
392                 has_v4 = 1
393                 jsondata4 = json.decode(jsonreq4)
394                 if otable == 'status' then
395                         data4 = jsondata4 or {}
396                 else
397                         data4 = jsondata4[otable] or {}
398                 end
399
400                 for k, v in ipairs(data4) do
401                         data4[k]['proto'] = '4'
402                 end
403
404         end
405         if jsonreq6 ~= "" then
406                 has_v6 = 1
407                 jsondata6 = json.decode(jsonreq6)
408                 if otable == 'status' then
409                         data6 = jsondata6 or {}
410                 else
411                         data6 = jsondata6[otable] or {}
412                 end
413                 for k, v in ipairs(data6) do
414                         data6[k]['proto'] = '6'
415                 end
416         end
417
418         for k, v in ipairs(data6) do
419                 table.insert(data4, v)
420         end
421
422         return data4, has_v4, has_v6, false
423 end
424