modules/admin-full: convert cbi maps to new network model
[project/luci.git] / modules / admin-full / luasrc / model / cbi / admin_network / ifaces.lua
1 --[[
2 LuCI - Lua Configuration Interface
3
4 Copyright 2008 Steven Barth <steven@midlink.org>
5 Copyright 2008 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 local fs = require "nixio.fs"
17 local nw = require "luci.model.network"
18 local fw = require "luci.model.firewall"
19
20 arg[1] = arg[1] or ""
21
22 local has_3g = fs.access("/usr/bin/gcom")
23 local has_pptp = fs.access("/usr/sbin/pptp")
24 local has_pppd = fs.access("/usr/sbin/pppd")
25 local has_pppoe = fs.glob("/usr/lib/pppd/*/rp-pppoe.so")()
26 local has_pppoa = fs.glob("/usr/lib/pppd/*/pppoatm.so")()
27 local has_ipv6 = fs.access("/proc/net/ipv6_route")
28 local has_6in4 = fs.access("/lib/network/6in4.sh")
29
30 m = Map("network", translate("Interfaces") .. " - " .. arg[1]:upper(), translate("On this page you can configure the network interfaces. You can bridge several interfaces by ticking the \"bridge interfaces\" field and enter the names of several network interfaces separated by spaces. You can also use <abbr title=\"Virtual Local Area Network\">VLAN</abbr> notation <samp>INTERFACE.VLANNR</samp> (<abbr title=\"for example\">e.g.</abbr>: <samp>eth0.1</samp>)."))
31 m:chain("firewall")
32 m:chain("wireless")
33
34 nw.init(m.uci)
35 fw.init(m.uci)
36
37 --function m.on_commit(map)
38 -- nw.init(map.uci)
39 -- fw.init(map.uci)
40 --end
41
42 s = m:section(NamedSection, arg[1], "interface", translate("Common Configuration"))
43 s.addremove = false
44
45 s:tab("general", translate("General Setup"))
46 if has_ipv6 then s:tab("ipv6", translate("IPv6 Setup")) end
47 if has_pppd then s:tab("ppp", translate("PPP Settings")) end
48 if has_pppoa then s:tab("atm", translate("ATM Settings")) end
49 if has_6in4 then s:tab("tunnel", translate("Tunnel Settings")) end
50 s:tab("physical", translate("Physical Settings"))
51 s:tab("firewall", translate("Firewall Settings"))
52
53 st = s:taboption("general", DummyValue, "__status", translate("Status"))
54 st.template = "admin_network/iface_status"
55 st.network = arg[1]
56
57 --[[
58 back = s:taboption("general", DummyValue, "_overview", translate("Overview"))
59 back.value = ""
60 back.titleref = luci.dispatcher.build_url("admin", "network", "network")
61 ]]
62
63 p = s:taboption("general", ListValue, "proto", translate("Protocol"))
64 p.override_scheme = true
65 p.default = "static"
66 p:value("static", translate("static"))
67 p:value("dhcp", "DHCP")
68 if has_pppd then p:value("ppp", "PPP") end
69 if has_pppoe then p:value("pppoe", "PPPoE") end
70 if has_pppoa then p:value("pppoa", "PPPoA") end
71 if has_3g then p:value("3g", "UMTS/3G") end
72 if has_pptp then p:value("pptp", "PPTP") end
73 if has_6in4 then p:value("6in4", "6in4") end
74 p:value("none", translate("none"))
75
76 if not ( has_pppd and has_pppoe and has_pppoa and has_3g and has_pptp ) then
77 p.description = translate("You need to install \"comgt\" for UMTS/GPRS, \"ppp-mod-pppoe\" for PPPoE, \"ppp-mod-pppoa\" for PPPoA or \"pptp\" for PPtP support")
78 end
79
80 br = s:taboption("physical", Flag, "type", translate("Bridge interfaces"), translate("creates a bridge over specified interface(s)"))
81 br.enabled = "bridge"
82 br.rmempty = true
83 br:depends("proto", "static")
84 br:depends("proto", "dhcp")
85 br:depends("proto", "none")
86
87 stp = s:taboption("physical", Flag, "stp", translate("Enable <abbr title=\"Spanning Tree Protocol\">STP</abbr>"),
88 translate("Enables the Spanning Tree Protocol on this bridge"))
89 stp:depends("type", "1")
90 stp.rmempty = true
91
92 ifname_single = s:taboption("physical", Value, "ifname_single", translate("Interface"))
93 ifname_single.template = "cbi/network_ifacelist"
94 ifname_single.widget = "radio"
95 ifname_single.nobridges = true
96 ifname_single.network = arg[1]
97 ifname_single.rmempty = true
98 ifname_single:depends({ type = "", proto = "static" })
99 ifname_single:depends({ type = "", proto = "dhcp" })
100 ifname_single:depends({ type = "", proto = "pppoe" })
101 ifname_single:depends({ type = "", proto = "pppoa" })
102 ifname_single:depends({ type = "", proto = "none" })
103
104 function ifname_single.cfgvalue(self, s)
105 return self.map.uci:get("network", s, "ifname")
106 end
107
108 function ifname_single.write(self, s, val)
109 local n = nw:get_network(s)
110 if n then
111 local i
112 for _, i in ipairs(n:get_interfaces()) do
113 n:del_interface(i)
114 end
115
116 for i in val:gmatch("%S+") do
117 n:add_interface(i)
118
119 -- if this is not a bridge, only assign first interface
120 if self.option == "ifname_single" then
121 break
122 end
123 end
124 end
125 end
126
127
128 ifname_multi = s:taboption("physical", MultiValue, "ifname_multi", translate("Interface"))
129 ifname_multi.template = "cbi/network_ifacelist"
130 ifname_multi.nobridges = true
131 ifname_multi.network = arg[1]
132 ifname_multi.widget = "checkbox"
133 ifname_multi:depends("type", "1")
134 ifname_multi.cfgvalue = ifname_single.cfgvalue
135 ifname_multi.write = ifname_single.write
136
137
138 for _, d in ipairs(nw:get_interfaces()) do
139 if not d:is_bridge() then
140 ifname_single:value(d:name())
141 ifname_multi:value(d:name())
142 end
143 end
144
145
146 local fwd_to, fwd_from
147
148 fwzone = s:taboption("firewall", Value, "_fwzone",
149 translate("Create / Assign firewall-zone"),
150 translate("Choose the firewall zone you want to assign to this interface. Select <em>unspecified</em> to remove the interface from the associated zone or fill out the <em>create</em> field to define a new zone and attach the interface to it."))
151
152 fwzone.template = "cbi/firewall_zonelist"
153 fwzone.network = arg[1]
154 fwzone.rmempty = false
155
156 function fwzone.cfgvalue(self, section)
157 self.iface = section
158 local z = fw:get_zone_by_network(section)
159 return z and z:name()
160 end
161
162 function fwzone.write(self, section, value)
163 local zone = fw:get_zone(value)
164
165 if not zone and value == '-' then
166 value = m:formvalue(self:cbid(section) .. ".newzone")
167 if value and #value > 0 then
168 zone = fw:add_zone(value)
169 else
170 fw:del_network(section)
171 end
172 end
173
174 if zone then
175 fw:del_network(section)
176 zone:add_network(section)
177 end
178 end
179
180 ipaddr = s:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
181 ipaddr.optional = true
182 ipaddr.datatype = "ip4addr"
183 ipaddr:depends("proto", "static")
184
185 nm = s:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
186 nm.optional = true
187 nm.datatype = "ip4addr"
188 nm:depends("proto", "static")
189 nm:value("255.255.255.0")
190 nm:value("255.255.0.0")
191 nm:value("255.0.0.0")
192
193 gw = s:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
194 gw.optional = true
195 gw.datatype = "ip4addr"
196 gw:depends("proto", "static")
197
198 bcast = s:taboption("general", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
199 bcast.optional = true
200 bcast.datatype = "ip4addr"
201 bcast:depends("proto", "static")
202
203 if has_ipv6 then
204 ip6addr = s:taboption("ipv6", Value, "ip6addr", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Address"), translate("<abbr title=\"Classless Inter-Domain Routing\">CIDR</abbr>-Notation: address/prefix"))
205 ip6addr.optional = true
206 ip6addr.datatype = "ip6addr"
207 ip6addr:depends("proto", "static")
208 ip6addr:depends("proto", "6in4")
209
210 ip6gw = s:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
211 ip6gw.optional = true
212 ip6gw.datatype = "ip6addr"
213 ip6gw:depends("proto", "static")
214 end
215
216 dns = s:taboption("general", DynamicList, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"),
217 translate("You can specify multiple DNS servers here, press enter to add a new entry. Servers entered here will override " ..
218 "automatically assigned ones."))
219
220 dns.optional = true
221 dns.cast = "string"
222 dns.datatype = "ipaddr"
223 dns:depends("peerdns", "")
224
225 mtu = s:taboption("physical", Value, "mtu", "MTU")
226 mtu.optional = true
227 mtu.datatype = "uinteger"
228
229 srv = s:taboption("general", Value, "server", translate("<abbr title=\"Point-to-Point Tunneling Protocol\">PPTP</abbr>-Server"))
230 srv:depends("proto", "pptp")
231 srv.optional = false
232 srv.datatype = "ip4addr"
233
234 if has_6in4 then
235 peer = s:taboption("general", Value, "peeraddr", translate("Server IPv4-Address"))
236 peer.optional = false
237 peer.datatype = "ip4addr"
238 peer:depends("proto", "6in4")
239
240 ttl = s:taboption("physical", Value, "ttl", translate("TTL"))
241 ttl.default = "64"
242 ttl.optional = true
243 ttl.datatype = "uinteger"
244 ttl:depends("proto", "6in4")
245 end
246
247 mac = s:taboption("physical", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
248 mac:depends("proto", "none")
249 mac:depends("proto", "static")
250 mac:depends("proto", "dhcp")
251
252 if has_3g then
253 service = s:taboption("general", ListValue, "service", translate("Service type"))
254 service:value("", translate("-- Please choose --"))
255 service:value("umts", "UMTS/GPRS")
256 service:value("cdma", "CDMA")
257 service:value("evdo", "EV-DO")
258 service:depends("proto", "3g")
259 service.rmempty = true
260
261 apn = s:taboption("general", Value, "apn", translate("Access point (APN)"))
262 apn:depends("proto", "3g")
263
264 pincode = s:taboption("general", Value, "pincode",
265 translate("PIN code"),
266 translate("Make sure that you provide the correct pin code here or you might lock your sim card!")
267 )
268 pincode:depends("proto", "3g")
269 end
270
271 if has_6in4 then
272 tunid = s:taboption("general", Value, "tunnelid", translate("HE.net Tunnel ID"))
273 tunid.optional = true
274 tunid.datatype = "uinteger"
275 tunid:depends("proto", "6in4")
276 end
277
278 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp or has_6in4 then
279 user = s:taboption("general", Value, "username", translate("Username"))
280 user.rmempty = true
281 user:depends("proto", "pptp")
282 user:depends("proto", "pppoe")
283 user:depends("proto", "pppoa")
284 user:depends("proto", "ppp")
285 user:depends("proto", "3g")
286 user:depends("proto", "6in4")
287
288 pass = s:taboption("general", Value, "password", translate("Password"))
289 pass.rmempty = true
290 pass.password = true
291 pass:depends("proto", "pptp")
292 pass:depends("proto", "pppoe")
293 pass:depends("proto", "pppoa")
294 pass:depends("proto", "ppp")
295 pass:depends("proto", "3g")
296 pass:depends("proto", "6in4")
297 end
298
299 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp then
300 ka = s:taboption("ppp", Value, "keepalive",
301 translate("Keep-Alive"),
302 translate("Number of failed connection tests to initiate automatic reconnect")
303 )
304 ka:depends("proto", "pptp")
305 ka:depends("proto", "pppoe")
306 ka:depends("proto", "pppoa")
307 ka:depends("proto", "ppp")
308 ka:depends("proto", "3g")
309
310 demand = s:taboption("ppp", Value, "demand",
311 translate("Automatic Disconnect"),
312 translate("Time (in seconds) after which an unused connection will be closed")
313 )
314 demand.optional = true
315 demand.datatype = "uinteger"
316 demand:depends("proto", "pptp")
317 demand:depends("proto", "pppoe")
318 demand:depends("proto", "pppoa")
319 demand:depends("proto", "ppp")
320 demand:depends("proto", "3g")
321 end
322
323 if has_pppoa then
324 encaps = s:taboption("atm", ListValue, "encaps", translate("PPPoA Encapsulation"))
325 encaps:depends("proto", "pppoa")
326 encaps:value("vc", "VC-Mux")
327 encaps:value("llc", "LLC")
328
329 atmdev = s:taboption("atm", Value, "atmdev", translate("ATM device number"))
330 atmdev:depends("proto", "pppoa")
331 atmdev.default = "0"
332 atmdev.datatype = "uinteger"
333
334 vci = s:taboption("atm", Value, "vci", translate("ATM Virtual Channel Identifier (VCI)"))
335 vci:depends("proto", "pppoa")
336 vci.default = "35"
337 vci.datatype = "uinteger"
338
339 vpi = s:taboption("atm", Value, "vpi", translate("ATM Virtual Path Identifier (VPI)"))
340 vpi:depends("proto", "pppoa")
341 vpi.default = "8"
342 vpi.datatype = "uinteger"
343 end
344
345 if has_pptp or has_pppd or has_pppoe or has_pppoa or has_3g then
346 device = s:taboption("general", Value, "device",
347 translate("Modem device"),
348 translate("The device node of your modem, e.g. /dev/ttyUSB0")
349 )
350 device:depends("proto", "ppp")
351 device:depends("proto", "3g")
352
353 defaultroute = s:taboption("ppp", Flag, "defaultroute",
354 translate("Replace default route"),
355 translate("Let pppd replace the current default route to use the PPP interface after successful connect")
356 )
357 defaultroute:depends("proto", "ppp")
358 defaultroute:depends("proto", "pppoa")
359 defaultroute:depends("proto", "pppoe")
360 defaultroute:depends("proto", "pptp")
361 defaultroute:depends("proto", "3g")
362 defaultroute.rmempty = false
363 function defaultroute.cfgvalue(...)
364 return ( AbstractValue.cfgvalue(...) or '1' )
365 end
366
367 peerdns = s:taboption("ppp", Flag, "peerdns",
368 translate("Use peer DNS"),
369 translate("Configure the local DNS server to use the name servers adverticed by the PPP peer")
370 )
371 peerdns:depends("proto", "ppp")
372 peerdns:depends("proto", "pppoa")
373 peerdns:depends("proto", "pppoe")
374 peerdns:depends("proto", "pptp")
375 peerdns:depends("proto", "3g")
376 peerdns.rmempty = false
377 function peerdns.cfgvalue(...)
378 return ( AbstractValue.cfgvalue(...) or '1' )
379 end
380
381 if has_ipv6 then
382 ipv6 = s:taboption("ppp", Flag, "ipv6", translate("Enable IPv6 on PPP link") )
383 ipv6:depends("proto", "ppp")
384 ipv6:depends("proto", "pppoa")
385 ipv6:depends("proto", "pppoe")
386 ipv6:depends("proto", "pptp")
387 ipv6:depends("proto", "3g")
388 end
389
390 connect = s:taboption("ppp", Value, "connect",
391 translate("Connect script"),
392 translate("Let pppd run this script after establishing the PPP link")
393 )
394 connect:depends("proto", "ppp")
395 connect:depends("proto", "pppoe")
396 connect:depends("proto", "pppoa")
397 connect:depends("proto", "pptp")
398 connect:depends("proto", "3g")
399
400 disconnect = s:taboption("ppp", Value, "disconnect",
401 translate("Disconnect script"),
402 translate("Let pppd run this script before tearing down the PPP link")
403 )
404 disconnect:depends("proto", "ppp")
405 disconnect:depends("proto", "pppoe")
406 disconnect:depends("proto", "pppoa")
407 disconnect:depends("proto", "pptp")
408 disconnect:depends("proto", "3g")
409
410 pppd_options = s:taboption("ppp", Value, "pppd_options",
411 translate("Additional pppd options"),
412 translate("Specify additional command line arguments for pppd here")
413 )
414 pppd_options:depends("proto", "ppp")
415 pppd_options:depends("proto", "pppoa")
416 pppd_options:depends("proto", "pppoe")
417 pppd_options:depends("proto", "pptp")
418 pppd_options:depends("proto", "3g")
419
420 maxwait = s:taboption("ppp", Value, "maxwait",
421 translate("Setup wait time"),
422 translate("Seconds to wait for the modem to become ready before attempting to connect")
423 )
424 maxwait:depends("proto", "3g")
425 maxwait.default = "0"
426 maxwait.optional = true
427 maxwait.datatype = "uinteger"
428 end
429
430 s2 = m:section(TypedSection, "alias", translate("IP-Aliases"))
431 s2.addremove = true
432
433 s2:depends("interface", arg[1])
434 s2.defaults.interface = arg[1]
435
436 s2:tab("general", translate("General Setup"))
437 s2.defaults.proto = "static"
438
439 ip = s2:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
440 ip.optional = true
441 ip.datatype = "ip4addr"
442
443 nm = s2:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
444 nm.optional = true
445 nm.datatype = "ip4addr"
446 nm:value("255.255.255.0")
447 nm:value("255.255.0.0")
448 nm:value("255.0.0.0")
449
450 gw = s2:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
451 gw.optional = true
452 gw.datatype = "ip4addr"
453
454 if has_ipv6 then
455 s2:tab("ipv6", translate("IPv6 Setup"))
456
457 ip6 = s2:taboption("ipv6", Value, "ip6addr", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Address"), translate("<abbr title=\"Classless Inter-Domain Routing\">CIDR</abbr>-Notation: address/prefix"))
458 ip6.optional = true
459 ip6.datatype = "ip6addr"
460
461 gw6 = s2:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
462 gw6.optional = true
463 gw6.datatype = "ip6addr"
464 end
465
466 s2:tab("advanced", translate("Advanced Settings"))
467
468 bcast = s2:taboption("advanced", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
469 bcast.optional = true
470 bcast.datatype = "ip4addr"
471
472 dns = s2:taboption("advanced", Value, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"))
473 dns.optional = true
474 dns.datatype = "ip4addr"
475
476
477 m2 = Map("dhcp", "", "")
478 function m2.on_parse()
479 local has_section = false
480
481 m2.uci:foreach("dhcp", "dhcp", function(s)
482 if s.interface == arg[1] then
483 has_section = true
484 return false
485 end
486 end)
487
488 if not has_section then
489 m2.uci:section("dhcp", "dhcp", nil, { interface = arg[1], ignore = "1" })
490 m2.uci:save("dhcp")
491 end
492 end
493
494 s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
495 s.addremove = false
496 s.anonymous = true
497 s:tab("general", translate("General Setup"))
498 s:tab("advanced", translate("Advanced Settings"))
499
500 function s.filter(self, section)
501 return m2.uci:get("dhcp", section, "interface") == arg[1]
502 end
503
504 local ignore = s:taboption("general", Flag, "ignore",
505 translate("Ignore interface"),
506 translate("Disable <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr> for " ..
507 "this interface."))
508
509 ignore.rmempty = false
510
511 local start = s:taboption("general", Value, "start", translate("Start"),
512 translate("Lowest leased address as offset from the network address."))
513 start.optional = true
514 start.datatype = "uinteger"
515 start.default = "100"
516
517 local limit = s:taboption("general", Value, "limit", translate("Limit"),
518 translate("Maximum number of leased addresses."))
519 limit.optional = true
520 limit.datatype = "uinteger"
521 limit.default = "150"
522
523 local ltime = s:taboption("general", Value, "leasetime", translate("Leasetime"),
524 translate("Expiry time of leased addresses, minimum is 2 Minutes (<code>2m</code>)."))
525 ltime.rmempty = true
526 ltime.default = "12h"
527
528 local dd = s:taboption("advanced", Flag, "dynamicdhcp",
529 translate("Dynamic <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr>"),
530 translate("Dynamically allocate DHCP addresses for clients. If disabled, only " ..
531 "clients having static leases will be served."))
532
533 dd.rmempty = false
534 function dd.cfgvalue(self, section)
535 return Flag.cfgvalue(self, section) or "1"
536 end
537
538 s:taboption("advanced", Flag, "force", translate("Force"),
539 translate("Force DHCP on this network even if another server is detected."))
540
541 -- XXX: is this actually useful?
542 --s:taboption("advanced", Value, "name", translate("Name"),
543 -- translate("Define a name for this network."))
544
545 mask = s:taboption("advanced", Value, "netmask",
546 translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"),
547 translate("Override the netmask sent to clients. Normally it is calculated " ..
548 "from the subnet that is served."))
549
550 mask.optional = true
551 mask.datatype = "ip4addr"
552
553 s:taboption("advanced", DynamicList, "dhcp_option", translate("DHCP-Options"),
554 translate("Define additional DHCP options, for example \"<code>6,192.168.2.1," ..
555 "192.168.2.2</code>\" which advertises different DNS servers to clients."))
556
557 for i, n in ipairs(s.children) do
558 if n ~= ignore then
559 n:depends("ignore", "")
560 end
561 end
562
563 return m, m2