luci-mod-admin-full: fix missing wifi_assoclist
[oweals/luci.git] / modules / luci-mod-admin-full / luasrc / controller / admin / network.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Copyright 2011-2015 Jo-Philipp Wich <jow@openwrt.org>
3 -- Licensed to the public under the Apache License 2.0.
4
5 module("luci.controller.admin.network", package.seeall)
6
7 function index()
8         local uci = require("luci.model.uci").cursor()
9         local page
10
11         page = node("admin", "network")
12         page.target = firstchild()
13         page.title  = _("Network")
14         page.order  = 50
15         page.index  = true
16
17 --      if page.inreq then
18                 local has_switch = false
19
20                 uci:foreach("network", "switch",
21                         function(s)
22                                 has_switch = true
23                                 return false
24                         end)
25
26                 if has_switch then
27                         page  = node("admin", "network", "vlan")
28                         page.target = cbi("admin_network/vlan")
29                         page.title  = _("Switch")
30                         page.order  = 20
31
32                         page = entry({"admin", "network", "switch_status"}, call("switch_status"), nil)
33                         page.leaf = true
34                 end
35
36
37                 local has_wifi = false
38
39                 uci:foreach("wireless", "wifi-device",
40                         function(s)
41                                 has_wifi = true
42                                 return false
43                         end)
44
45                 if has_wifi then
46                         page = entry({"admin", "network", "wireless_assoclist"}, call("wifi_assoclist"), nil)
47                         page.leaf = true
48                 
49                         page = entry({"admin", "network", "wireless_join"}, post("wifi_join"), nil)
50                         page.leaf = true
51
52                         page = entry({"admin", "network", "wireless_add"}, post("wifi_add"), nil)
53                         page.leaf = true
54
55                         page = entry({"admin", "network", "wireless_delete"}, post("wifi_delete"), nil)
56                         page.leaf = true
57
58                         page = entry({"admin", "network", "wireless_status"}, call("wifi_status"), nil)
59                         page.leaf = true
60
61                         page = entry({"admin", "network", "wireless_reconnect"}, post("wifi_reconnect"), nil)
62                         page.leaf = true
63
64                         page = entry({"admin", "network", "wireless_shutdown"}, post("wifi_shutdown"), nil)
65                         page.leaf = true
66
67                         page = entry({"admin", "network", "wireless"}, arcombine(template("admin_network/wifi_overview"), cbi("admin_network/wifi")), _("Wireless"), 15)
68                         page.leaf = true
69                         page.subindex = true
70
71                         if page.inreq then
72                                 local wdev
73                                 local net = require "luci.model.network".init(uci)
74                                 for _, wdev in ipairs(net:get_wifidevs()) do
75                                         local wnet
76                                         for _, wnet in ipairs(wdev:get_wifinets()) do
77                                                 entry(
78                                                         {"admin", "network", "wireless", wnet:id()},
79                                                         alias("admin", "network", "wireless"),
80                                                         wdev:name() .. ": " .. wnet:shortname()
81                                                 )
82                                         end
83                                 end
84                         end
85                 end
86
87
88                 page = entry({"admin", "network", "iface_add"}, form("admin_network/iface_add"), nil)
89                 page.leaf = true
90
91                 page = entry({"admin", "network", "iface_delete"}, post("iface_delete"), nil)
92                 page.leaf = true
93
94                 page = entry({"admin", "network", "iface_status"}, call("iface_status"), nil)
95                 page.leaf = true
96
97                 page = entry({"admin", "network", "iface_reconnect"}, post("iface_reconnect"), nil)
98                 page.leaf = true
99
100                 page = entry({"admin", "network", "iface_shutdown"}, post("iface_shutdown"), nil)
101                 page.leaf = true
102
103                 page = entry({"admin", "network", "network"}, arcombine(cbi("admin_network/network"), cbi("admin_network/ifaces")), _("Interfaces"), 10)
104                 page.leaf   = true
105                 page.subindex = true
106
107                 if page.inreq then
108                         uci:foreach("network", "interface",
109                                 function (section)
110                                         local ifc = section[".name"]
111                                         if ifc ~= "loopback" then
112                                                 entry({"admin", "network", "network", ifc},
113                                                 true, ifc:upper())
114                                         end
115                                 end)
116                 end
117
118
119                 if nixio.fs.access("/etc/config/dhcp") then
120                         page = node("admin", "network", "dhcp")
121                         page.target = cbi("admin_network/dhcp")
122                         page.title  = _("DHCP and DNS")
123                         page.order  = 30
124
125                         page = entry({"admin", "network", "dhcplease_status"}, call("lease_status"), nil)
126                         page.leaf = true
127
128                         page = node("admin", "network", "hosts")
129                         page.target = cbi("admin_network/hosts")
130                         page.title  = _("Hostnames")
131                         page.order  = 40
132                 end
133
134                 page  = node("admin", "network", "routes")
135                 page.target = cbi("admin_network/routes")
136                 page.title  = _("Static Routes")
137                 page.order  = 50
138
139                 page = node("admin", "network", "diagnostics")
140                 page.target = template("admin_network/diagnostics")
141                 page.title  = _("Diagnostics")
142                 page.order  = 60
143
144                 page = entry({"admin", "network", "diag_ping"}, post("diag_ping"), nil)
145                 page.leaf = true
146
147                 page = entry({"admin", "network", "diag_nslookup"}, post("diag_nslookup"), nil)
148                 page.leaf = true
149
150                 page = entry({"admin", "network", "diag_traceroute"}, post("diag_traceroute"), nil)
151                 page.leaf = true
152
153                 page = entry({"admin", "network", "diag_ping6"}, post("diag_ping6"), nil)
154                 page.leaf = true
155
156                 page = entry({"admin", "network", "diag_traceroute6"}, post("diag_traceroute6"), nil)
157                 page.leaf = true
158 --      end
159 end
160
161 function wifi_join()
162         local tpl  = require "luci.template"
163         local http = require "luci.http"
164         local dev  = http.formvalue("device")
165         local ssid = http.formvalue("join")
166
167         if dev and ssid then
168                 local cancel = (http.formvalue("cancel") or http.formvalue("cbi.cancel"))
169                 if not cancel then
170                         local cbi = require "luci.cbi"
171                         local map = luci.cbi.load("admin_network/wifi_add")[1]
172
173                         if map:parse() ~= cbi.FORM_DONE then
174                                 tpl.render("header")
175                                 map:render()
176                                 tpl.render("footer")
177                         end
178
179                         return
180                 end
181         end
182
183         tpl.render("admin_network/wifi_join")
184 end
185
186 function wifi_add()
187         local dev = luci.http.formvalue("device")
188         local ntm = require "luci.model.network".init()
189
190         dev = dev and ntm:get_wifidev(dev)
191
192         if dev then
193                 local net = dev:add_wifinet({
194                         mode       = "ap",
195                         ssid       = "OpenWrt",
196                         encryption = "none"
197                 })
198
199                 ntm:save("wireless")
200                 luci.http.redirect(net:adminlink())
201         end
202 end
203
204 function wifi_delete(network)
205         local ntm = require "luci.model.network".init()
206         local wnet = ntm:get_wifinet(network)
207         if wnet then
208                 local dev = wnet:get_device()
209                 local nets = wnet:get_networks()
210                 if dev then
211                         ntm:del_wifinet(network)
212                         ntm:commit("wireless")
213                         local _, net
214                         for _, net in ipairs(nets) do
215                                 if net:is_empty() then
216                                         ntm:del_network(net:name())
217                                         ntm:commit("network")
218                                 end
219                         end
220                         luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>/dev/null")
221                 end
222         end
223
224         luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
225 end
226
227 function iface_status(ifaces)
228         local netm = require "luci.model.network".init()
229         local rv   = { }
230
231         local iface
232         for iface in ifaces:gmatch("[%w%.%-_]+") do
233                 local net = netm:get_network(iface)
234                 local device = net and net:get_interface()
235                 if device then
236                         local data = {
237                                 id         = iface,
238                                 proto      = net:proto(),
239                                 uptime     = net:uptime(),
240                                 gwaddr     = net:gwaddr(),
241                                 ipaddrs    = net:ipaddrs(),
242                                 ip6addrs   = net:ip6addrs(),
243                                 dnsaddrs   = net:dnsaddrs(),
244                                 ip6prefix  = net:ip6prefix(),
245                                 name       = device:shortname(),
246                                 type       = device:type(),
247                                 ifname     = device:name(),
248                                 macaddr    = device:mac(),
249                                 is_up      = device:is_up(),
250                                 rx_bytes   = device:rx_bytes(),
251                                 tx_bytes   = device:tx_bytes(),
252                                 rx_packets = device:rx_packets(),
253                                 tx_packets = device:tx_packets(),
254
255                                 subdevices = { }
256                         }
257
258                         for _, device in ipairs(net:get_interfaces() or {}) do
259                                 data.subdevices[#data.subdevices+1] = {
260                                         name       = device:shortname(),
261                                         type       = device:type(),
262                                         ifname     = device:name(),
263                                         macaddr    = device:mac(),
264                                         is_up      = device:is_up(),
265                                         rx_bytes   = device:rx_bytes(),
266                                         tx_bytes   = device:tx_bytes(),
267                                         rx_packets = device:rx_packets(),
268                                         tx_packets = device:tx_packets(),
269                                 }
270                         end
271
272                         rv[#rv+1] = data
273                 else
274                         rv[#rv+1] = {
275                                 id   = iface,
276                                 name = iface,
277                                 type = "ethernet"
278                         }
279                 end
280         end
281
282         if #rv > 0 then
283                 luci.http.prepare_content("application/json")
284                 luci.http.write_json(rv)
285                 return
286         end
287
288         luci.http.status(404, "No such device")
289 end
290
291 function iface_reconnect(iface)
292         local netmd = require "luci.model.network".init()
293         local net = netmd:get_network(iface)
294         if net then
295                 luci.sys.call("env -i /sbin/ifup %s >/dev/null 2>/dev/null"
296                         % luci.util.shellquote(iface))
297                 luci.http.status(200, "Reconnected")
298                 return
299         end
300
301         luci.http.status(404, "No such interface")
302 end
303
304 function iface_shutdown(iface)
305         local netmd = require "luci.model.network".init()
306         local net = netmd:get_network(iface)
307         if net then
308                 luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null"
309                         % luci.util.shellquote(iface))
310                 luci.http.status(200, "Shutdown")
311                 return
312         end
313
314         luci.http.status(404, "No such interface")
315 end
316
317 function iface_delete(iface)
318         local netmd = require "luci.model.network".init()
319         local net = netmd:del_network(iface)
320         if net then
321                 luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null"
322                         % luci.util.shellquote(iface))
323                 luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
324                 netmd:commit("network")
325                 netmd:commit("wireless")
326                 return
327         end
328
329         luci.http.status(404, "No such interface")
330 end
331
332 function wifi_status(devs)
333         local s    = require "luci.tools.status"
334         local rv   = { }
335
336         if type(devs) == "string" then
337                 local dev
338                 for dev in devs:gmatch("[%w%.%-]+") do
339                         rv[#rv+1] = s.wifi_network(dev)
340                 end
341         end
342
343         if #rv > 0 then
344                 luci.http.prepare_content("application/json")
345                 luci.http.write_json(rv)
346                 return
347         end
348
349         luci.http.status(404, "No such device")
350 end
351
352 local function wifi_reconnect_shutdown(shutdown, wnet)
353         local netmd = require "luci.model.network".init()
354         local net = netmd:get_wifinet(wnet)
355         local dev = net:get_device()
356         if dev and net then
357                 dev:set("disabled", nil)
358                 net:set("disabled", shutdown and 1 or nil)
359                 netmd:commit("wireless")
360
361                 luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>/dev/null")
362                 luci.http.status(200, shutdown and "Shutdown" or "Reconnected")
363
364                 return
365         end
366
367         luci.http.status(404, "No such radio")
368 end
369
370 function wifi_reconnect(wnet)
371         wifi_reconnect_shutdown(false, wnet)
372 end
373
374 function wifi_shutdown(wnet)
375         wifi_reconnect_shutdown(true, wnet)
376 end
377
378 function wifi_assoclist()
379         local s = require "luci.tools.status"
380         
381         luci.http.prepare_content("application/json")
382         luci.http.write_json(s.wifi_assoclist())
383 end
384
385 function lease_status()
386         local s = require "luci.tools.status"
387
388         luci.http.prepare_content("application/json")
389         luci.http.write('[')
390         luci.http.write_json(s.dhcp_leases())
391         luci.http.write(',')
392         luci.http.write_json(s.dhcp6_leases())
393         luci.http.write(']')
394 end
395
396 function switch_status(switches)
397         local s = require "luci.tools.status"
398
399         luci.http.prepare_content("application/json")
400         luci.http.write_json(s.switch_status(switches))
401 end
402
403 function diag_command(cmd, addr)
404         if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
405                 luci.http.prepare_content("text/plain")
406
407                 local util = io.popen(cmd % luci.util.shellquote(addr))
408                 if util then
409                         while true do
410                                 local ln = util:read("*l")
411                                 if not ln then break end
412                                 luci.http.write(ln)
413                                 luci.http.write("\n")
414                         end
415
416                         util:close()
417                 end
418
419                 return
420         end
421
422         luci.http.status(500, "Bad address")
423 end
424
425 function diag_ping(addr)
426         diag_command("ping -c 5 -W 1 %s 2>&1", addr)
427 end
428
429 function diag_traceroute(addr)
430         diag_command("traceroute -q 1 -w 1 -n %s 2>&1", addr)
431 end
432
433 function diag_nslookup(addr)
434         diag_command("nslookup %s 2>&1", addr)
435 end
436
437 function diag_ping6(addr)
438         diag_command("ping6 -c 5 %s 2>&1", addr)
439 end
440
441 function diag_traceroute6(addr)
442         diag_command("traceroute6 -q 1 -w 2 -n %s 2>&1", addr)
443 end