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