modules/admin-full: add "auto" option to interface settings (#235)
[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-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 local fs = require "nixio.fs"
17 local ut = require "luci.util"
18 local nw = require "luci.model.network"
19 local fw = require "luci.model.firewall"
20
21 arg[1] = arg[1] or ""
22
23 local has_dnsmasq  = fs.access("/etc/config/dhcp")
24 local has_firewall = fs.access("/etc/config/firewall")
25 local has_radvd    = fs.access("/etc/config/radvd")
26
27 local has_3g     = fs.access("/usr/bin/gcom")
28 local has_pptp   = fs.access("/usr/sbin/pptp")
29 local has_pppd   = fs.access("/usr/sbin/pppd")
30 local has_pppoe  = fs.glob("/usr/lib/pppd/*/rp-pppoe.so")()
31 local has_pppoa  = fs.glob("/usr/lib/pppd/*/pppoatm.so")()
32 local has_ipv6   = fs.access("/proc/net/ipv6_route")
33 local has_6in4   = fs.access("/lib/network/6in4.sh")
34 local has_6to4   = fs.access("/lib/network/6to4.sh")
35 local has_relay  = fs.access("/lib/network/relay.sh")
36 local has_ahcp   = fs.access("/lib/network/ahcp.sh")
37
38 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>)."))
39 m:chain("wireless")
40
41 if has_firewall then
42         m:chain("firewall")
43 end
44
45 if has_radvd then
46         m:chain("radvd")
47 end
48
49 nw.init(m.uci)
50 fw.init(m.uci)
51
52
53 local net = nw:get_network(arg[1])
54
55 -- redirect to overview page if network does not exist anymore (e.g. after a revert)
56 if not net then
57         luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
58         return
59 end
60
61 local ifc = net:get_interfaces()[1]
62
63 s = m:section(NamedSection, arg[1], "interface", translate("Common Configuration"))
64 s.addremove = false
65
66 s:tab("general", translate("General Setup"))
67 if has_ipv6  then s:tab("ipv6", translate("IPv6 Setup")) end
68 if has_pppd  then s:tab("ppp", translate("PPP Settings")) end
69 if has_pppoa then s:tab("atm", translate("ATM Settings")) end
70 if has_6in4 or has_6to4 then s:tab("tunnel", translate("Tunnel Settings")) end
71 if has_relay then s:tab("relay", translate("Relay Settings")) end
72 if has_ahcp then s:tab("ahcp", translate("AHCP Settings")) end
73 s:tab("physical", translate("Physical Settings"))
74 if has_firewall then s:tab("firewall", translate("Firewall Settings")) end
75
76 st = s:taboption("general", DummyValue, "__status", translate("Status"))
77 st.template = "admin_network/iface_status"
78 st.network  = arg[1]
79
80 --[[
81 back = s:taboption("general", DummyValue, "_overview", translate("Overview"))
82 back.value = ""
83 back.titleref = luci.dispatcher.build_url("admin", "network", "network")
84 ]]
85
86 p = s:taboption("general", ListValue, "proto", translate("Protocol"))
87 p.override_scheme = true
88 p.default = "static"
89 p:value("static", translate("static"))
90 p:value("dhcp", "DHCP")
91 if has_pppd  then p:value("ppp",   "PPP")     end
92 if has_pppoe then p:value("pppoe", "PPPoE")   end
93 if has_pppoa then p:value("pppoa", "PPPoA")   end
94 if has_3g    then p:value("3g",    "UMTS/3G") end
95 if has_pptp  then p:value("pptp",  "PPTP")    end
96 if has_6in4  then p:value("6in4",  "6in4")    end
97 if has_6to4  then p:value("6to4",  "6to4")    end
98 if has_relay then p:value("relay", "Relay")   end
99 if has_ahcp  then p:value("ahcp",  "AHCP")    end
100 p:value("none", translate("none"))
101
102 if not ( has_pppd and has_pppoe and has_pppoa and has_3g and has_pptp ) then
103         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")
104 end
105
106 auto = s:taboption("physical", Flag, "auto", translate("Bring up on boot"))                                                                                            
107 auto.default = (m.uci:get("network", arg[1], "proto") == "none") and auto.disabled or auto.enabled
108
109 br = s:taboption("physical", Flag, "type", translate("Bridge interfaces"), translate("creates a bridge over specified interface(s)"))
110 br.enabled = "bridge"
111 br.rmempty = true
112 br:depends("proto", "static")
113 br:depends("proto", "dhcp")
114 br:depends("proto", "none")
115
116 stp = s:taboption("physical", Flag, "stp", translate("Enable <abbr title=\"Spanning Tree Protocol\">STP</abbr>"),
117         translate("Enables the Spanning Tree Protocol on this bridge"))
118 stp:depends("type", "bridge")
119 stp.rmempty = true
120
121 ifname_single = s:taboption("physical", Value, "ifname_single", translate("Interface"))
122 ifname_single.template = "cbi/network_ifacelist"
123 ifname_single.widget = "radio"
124 ifname_single.nobridges = true
125 ifname_single.network = arg[1]
126 ifname_single.rmempty = true
127 ifname_single:depends({ type = "", proto = "static" })
128 ifname_single:depends({ type = "", proto = "dhcp"   })
129 ifname_single:depends({ type = "", proto = "pppoe"  })
130 ifname_single:depends({ type = "", proto = "pppoa"  })
131 ifname_single:depends({ type = "", proto = "ahcp"   })
132 ifname_single:depends({ type = "", proto = "none"   })
133
134 function ifname_single.cfgvalue(self, s)
135         return self.map.uci:get("network", s, "ifname")
136 end
137
138 function ifname_single.write(self, s, val)
139         local n = nw:get_network(s)
140         if n then
141                 local i
142                 for _, i in ipairs(n:get_interfaces()) do
143                         n:del_interface(i)
144                 end
145
146                 for i in ut.imatch(val) do
147                         n:add_interface(i)
148
149                         -- if this is not a bridge, only assign first interface
150                         if self.option == "ifname_single" then
151                                 break
152                         end
153                 end
154         end
155 end
156
157 ifname_multi = s:taboption("physical", Value, "ifname_multi", translate("Interface"))
158 ifname_multi.template = "cbi/network_ifacelist"
159 ifname_multi.nobridges = true
160 ifname_multi.network = arg[1]
161 ifname_multi.widget = "checkbox"
162 ifname_multi:depends("type", "bridge")
163 ifname_multi.cfgvalue = ifname_single.cfgvalue
164 ifname_multi.write = ifname_single.write
165
166
167 if has_firewall then
168         fwzone = s:taboption("firewall", Value, "_fwzone",
169                 translate("Create / Assign firewall-zone"),
170                 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."))
171
172         fwzone.template = "cbi/firewall_zonelist"
173         fwzone.network = arg[1]
174         fwzone.rmempty = false
175
176         function fwzone.cfgvalue(self, section)
177                 self.iface = section
178                 local z = fw:get_zone_by_network(section)
179                 return z and z:name()
180         end
181
182         function fwzone.write(self, section, value)
183                 local zone = fw:get_zone(value)
184
185                 if not zone and value == '-' then
186                         value = m:formvalue(self:cbid(section) .. ".newzone")
187                         if value and #value > 0 then
188                                 zone = fw:add_zone(value)
189                         else
190                                 fw:del_network(section)
191                         end
192                 end
193
194                 if zone then
195                         fw:del_network(section)
196                         zone:add_network(section)
197                 end
198         end
199 end
200
201 ipaddr = s:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
202 ipaddr.optional = true
203 ipaddr.datatype = "ip4addr"
204 ipaddr:depends("proto", "static")
205
206 nm = s:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
207 nm.optional = true
208 nm.datatype = "ip4addr"
209 nm:depends("proto", "static")
210 nm:value("255.255.255.0")
211 nm:value("255.255.0.0")
212 nm:value("255.0.0.0")
213
214 gw = s:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
215 gw.optional = true
216 gw.datatype = "ip4addr"
217 gw:depends("proto", "static")
218
219 bcast = s:taboption("general", Value, "broadcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
220 bcast.optional = true
221 bcast.datatype = "ip4addr"
222 bcast:depends("proto", "static")
223
224 if has_ipv6 then
225         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"))
226         ip6addr.optional = true
227         ip6addr.datatype = "ip6addr"
228         ip6addr:depends("proto", "static")
229         ip6addr:depends("proto", "6in4")
230
231         ip6gw = s:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
232         ip6gw.optional = true
233         ip6gw.datatype = "ip6addr"
234         ip6gw:depends("proto", "static")
235
236
237         ra = s:taboption("ipv6", Flag, "accept_ra", translate("Accept Router Advertisements"))
238         ra.default = m.uci:get("network", arg[1], "proto") == "dhcp" and ra.enabled or ra.disabled
239         ra:depends("proto", "static")
240         ra:depends("proto", "dhcp")
241         ra:depends("proto", "none")
242
243         rs = s:taboption("ipv6", Flag, "send_rs", translate("Send Router Solicitiations"))
244         rs.default = m.uci:get("network", arg[1], "proto") ~= "dhcp" and rs.enabled or rs.disabled
245         rs:depends("proto", "static")
246         rs:depends("proto", "dhcp")
247         rs:depends("proto", "none")
248 end
249
250 dns = s:taboption("general", DynamicList, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"),
251         translate("You can specify multiple DNS servers here, press enter to add a new entry. Servers entered here will override " ..
252                 "automatically assigned ones."))
253
254 dns.optional = true
255 dns.cast = "string"
256 dns.datatype = "ipaddr"
257 dns:depends({ peerdns = "", proto = "static" })
258 dns:depends({ peerdns = "", proto = "dhcp"   })
259 dns:depends({ peerdns = "", proto = "pppoe"  })
260 dns:depends({ peerdns = "", proto = "pppoa"  })
261 dns:depends({ peerdns = "", proto = "none"   })
262
263 mtu = s:taboption("physical", Value, "mtu", "MTU")
264 mtu.optional = true
265 mtu.datatype = "uinteger"
266 mtu.placeholder = 1500
267 mtu:depends("proto", "static")
268 mtu:depends("proto", "dhcp")
269 mtu:depends("proto", "pppoe")
270 mtu:depends("proto", "pppoa")
271 mtu:depends("proto", "6in4")
272 mtu:depends("proto", "6to4")
273 mtu:depends("proto", "none")
274
275 srv = s:taboption("general", Value, "server", translate("<abbr title=\"Point-to-Point Tunneling Protocol\">PPTP</abbr>-Server"))
276 srv:depends("proto", "pptp")
277 srv.optional = false
278 srv.datatype = "host"
279
280 if has_6in4 then
281         peer = s:taboption("general", Value, "peeraddr", translate("Server IPv4-Address"))
282         peer.optional = false
283         peer.datatype = "ip4addr"
284         peer:depends("proto", "6in4")
285 end
286
287 if has_6in4 or has_6to4 then
288         ttl = s:taboption("physical", Value, "ttl", translate("TTL"))
289         ttl.default = "64"
290         ttl.optional = true
291         ttl.datatype = "uinteger"
292         ttl:depends("proto", "6in4")
293         ttl:depends("proto", "6to4")
294 end
295
296 if has_6to4 then
297         advi = s:taboption("general", Value, "adv_interface", translate("Advertise IPv6 on network"))
298         advi.widget = "checkbox"
299         advi.exclude = arg[1]
300         advi.default = "lan"
301         advi.template = "cbi/network_netlist"
302         advi.nocreate = true
303         advi.nobridges = true
304         advi:depends("proto", "6to4")
305
306         advn = s:taboption("general", Value, "adv_subnet", translate("Advertised network ID"), translate("Allowed range is 1 to FFFF"))
307         advn.default = "1"
308         advn:depends("proto", "6to4")
309
310         function advn.write(self, section, value)
311                 value = tonumber(value, 16) or 1
312
313                 if value > 65535 then value = 65535
314                 elseif value < 1 then value = 1 end
315
316                 Value.write(self, section, "%X" % value)
317         end
318 end
319
320 if has_relay then
321         rnet = s:taboption("general", Value, "network", translate("Relay between networks"))
322         rnet.widget = "checkbox"
323         rnet.exclude = arg[1]
324         rnet.template = "cbi/network_netlist"
325         rnet.nocreate = true
326         rnet.nobridges = true
327         rnet:depends("proto", "relay")
328 end
329
330 mac = s:taboption("physical", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
331 mac:depends("proto", "none")
332 mac:depends("proto", "static")
333 mac:depends("proto", "dhcp")
334 mac.placeholder = ifc and ifc:mac():upper()
335
336 if has_3g then
337         service = s:taboption("general", ListValue, "service", translate("Service type"))
338         service:value("", translate("-- Please choose --"))
339         service:value("umts", "UMTS/GPRS")
340         service:value("cdma", "CDMA")
341         service:value("evdo", "EV-DO")
342         service:depends("proto", "3g")
343         service.rmempty = true
344
345         apn = s:taboption("general", Value, "apn", translate("Access point (APN)"))
346         apn:depends("proto", "3g")
347
348         pincode = s:taboption("general", Value, "pincode",
349          translate("PIN code"),
350          translate("Make sure that you provide the correct pin code here or you might lock your sim card!")
351         )
352         pincode:depends("proto", "3g")
353 end
354
355 if has_6in4 then
356         tunid = s:taboption("general", Value, "tunnelid", translate("HE.net Tunnel ID"))
357         tunid.optional = true
358         tunid.datatype = "uinteger"
359         tunid:depends("proto", "6in4")
360 end
361
362 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp or has_6in4 then
363         user = s:taboption("general", Value, "username", translate("Username"))
364         user.rmempty = true
365         user:depends("proto", "pptp")
366         user:depends("proto", "pppoe")
367         user:depends("proto", "pppoa")
368         user:depends("proto", "ppp")
369         user:depends("proto", "3g")
370         user:depends("proto", "6in4")
371
372         pass = s:taboption("general", Value, "password", translate("Password"))
373         pass.rmempty = true
374         pass.password = true
375         pass:depends("proto", "pptp")
376         pass:depends("proto", "pppoe")
377         pass:depends("proto", "pppoa")
378         pass:depends("proto", "ppp")
379         pass:depends("proto", "3g")
380         pass:depends("proto", "6in4")
381 end
382
383 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp then
384         ka = s:taboption("ppp", Value, "keepalive",
385          translate("Keep-Alive"),
386          translate("Number of failed connection tests to initiate automatic reconnect")
387         )
388         ka:depends("proto", "pptp")
389         ka:depends("proto", "pppoe")
390         ka:depends("proto", "pppoa")
391         ka:depends("proto", "ppp")
392         ka:depends("proto", "3g")
393
394         demand = s:taboption("ppp", Value, "demand",
395          translate("Automatic Disconnect"),
396          translate("Time (in seconds) after which an unused connection will be closed")
397         )
398         demand.optional = true
399         demand.datatype = "uinteger"
400         demand:depends("proto", "pptp")
401         demand:depends("proto", "pppoe")
402         demand:depends("proto", "pppoa")
403         demand:depends("proto", "ppp")
404         demand:depends("proto", "3g")
405 end
406
407 if has_pppoa then
408         encaps = s:taboption("atm", ListValue, "encaps", translate("PPPoA Encapsulation"))
409         encaps:depends("proto", "pppoa")
410         encaps:value("vc", "VC-Mux")
411         encaps:value("llc", "LLC")
412
413         atmdev = s:taboption("atm", Value, "atmdev", translate("ATM device number"))
414         atmdev:depends("proto", "pppoa")
415         atmdev.default = "0"
416         atmdev.datatype = "uinteger"
417
418         vci = s:taboption("atm", Value, "vci", translate("ATM Virtual Channel Identifier (VCI)"))
419         vci:depends("proto", "pppoa")
420         vci.default = "35"
421         vci.datatype = "uinteger"
422
423         vpi = s:taboption("atm", Value, "vpi", translate("ATM Virtual Path Identifier (VPI)"))
424         vpi:depends("proto", "pppoa")
425         vpi.default = "8"
426         vpi.datatype = "uinteger"
427 end
428
429 if has_pptp or has_pppd or has_pppoe or has_pppoa or has_3g then
430         device = s:taboption("general", Value, "device",
431          translate("Modem device"),
432          translate("The device node of your modem, e.g. /dev/ttyUSB0")
433         )
434         device:depends("proto", "ppp")
435         device:depends("proto", "3g")
436
437         defaultroute = s:taboption("ppp", Flag, "defaultroute",
438          translate("Replace default route"),
439          translate("Let pppd replace the current default route to use the PPP interface after successful connect")
440         )
441         defaultroute:depends("proto", "ppp")
442         defaultroute:depends("proto", "pppoa")
443         defaultroute:depends("proto", "pppoe")
444         defaultroute:depends("proto", "pptp")
445         defaultroute:depends("proto", "3g")
446         defaultroute.default = defaultroute.enabled
447
448         peerdns = s:taboption("ppp", Flag, "peerdns",
449          translate("Use peer DNS"),
450          translate("Configure the local DNS server to use the name servers adverticed by the PPP peer")
451         )
452         peerdns:depends("proto", "ppp")
453         peerdns:depends("proto", "pppoa")
454         peerdns:depends("proto", "pppoe")
455         peerdns:depends("proto", "pptp")
456         peerdns:depends("proto", "3g")
457         peerdns.default = peerdns.enabled
458
459         if has_ipv6 then
460                 ipv6 = s:taboption("ppp", Flag, "ipv6", translate("Enable IPv6 on PPP link") )
461                 ipv6:depends("proto", "ppp")
462                 ipv6:depends("proto", "pppoa")
463                 ipv6:depends("proto", "pppoe")
464                 ipv6:depends("proto", "pptp")
465                 ipv6:depends("proto", "3g")
466         end
467
468         connect = s:taboption("ppp", Value, "connect",
469          translate("Connect script"),
470          translate("Let pppd run this script after establishing the PPP link")
471         )
472         connect:depends("proto", "ppp")
473         connect:depends("proto", "pppoe")
474         connect:depends("proto", "pppoa")
475         connect:depends("proto", "pptp")
476         connect:depends("proto", "3g")
477
478         disconnect = s:taboption("ppp", Value, "disconnect",
479          translate("Disconnect script"),
480          translate("Let pppd run this script before tearing down the PPP link")
481         )
482         disconnect:depends("proto", "ppp")
483         disconnect:depends("proto", "pppoe")
484         disconnect:depends("proto", "pppoa")
485         disconnect:depends("proto", "pptp")
486         disconnect:depends("proto", "3g")
487
488         pppd_options = s:taboption("ppp", Value, "pppd_options",
489          translate("Additional pppd options"),
490          translate("Specify additional command line arguments for pppd here")
491         )
492         pppd_options:depends("proto", "ppp")
493         pppd_options:depends("proto", "pppoa")
494         pppd_options:depends("proto", "pppoe")
495         pppd_options:depends("proto", "pptp")
496         pppd_options:depends("proto", "3g")
497
498         maxwait = s:taboption("ppp", Value, "maxwait",
499          translate("Setup wait time"),
500          translate("Seconds to wait for the modem to become ready before attempting to connect")
501         )
502         maxwait:depends("proto", "3g")
503         maxwait.default  = "0"
504         maxwait.optional = true
505         maxwait.datatype = "uinteger"
506 end
507
508 if has_relay then
509         fb = s:taboption("relay", Flag, "forward_bcast", translate("Forward broadcasts"))
510         fb.default = fb.enabled
511         fb:depends("proto", "relay")
512
513         fd = s:taboption("relay", Flag, "forward_dhcp", translate("Forward DHCP"))
514         fd.default = fd.enabled
515         fd:depends("proto", "relay")
516
517         gw = s:taboption("relay", Value, "relay_gateway", translate("Override Gateway"))
518         gw.optional    = true
519         gw.placeholder = "0.0.0.0"
520         gw.datatype    = "ip4addr"
521         gw:depends("proto", "relay")
522         function gw.cfgvalue(self, section)
523                 return m.uci:get("network", section, "gateway")
524         end
525         function gw.write(self, section, value)
526                 return m.uci:set("network", section, "gateway", value)
527         end
528         function gw.delete(self, section)
529                 return m.uci:delete("network", section, "gateway")
530         end
531
532         expiry = s:taboption("relay", Value, "expiry", translate("Host expiry timeout"))
533         expiry.optional    = true
534         expiry.placeholder = 30
535         expiry.datatype    = "uinteger"
536         expiry:depends("proto", "relay")
537
538         retry = s:taboption("relay", Value, "retry", translate("ARP ping retries"))
539         retry.optional     = true
540         retry.placeholder  = 5
541         retry.datatype     = "uinteger"
542         retry:depends("proto", "relay")
543
544         table = s:taboption("relay", Value, "table", translate("Routing table ID"))
545         table.optional     = true
546         table.placeholder  = 16800
547         table.datatype     = "uinteger"
548         table:depends("proto", "relay")
549 end
550
551 if has_ahcp then
552         mca = s:taboption("ahcp", Value, "multicast_address", translate("Multicast address"))
553         mca.optional    = true
554         mca.placeholder = "ff02::cca6:c0f9:e182:5359"
555         mca.datatype    = "ip6addr"
556         mca:depends("proto", "ahcp")
557
558         port = s:taboption("ahcp", Value, "port", translate("Port"))
559         port.optional    = true
560         port.placeholder = 5359
561         port.datatype    = "port"
562         port:depends("proto", "ahcp")
563
564         fam = s:taboption("ahcp", ListValue, "_family", translate("Protocol family"))
565         fam:value("", translate("IPv4 and IPv6"))
566         fam:value("ipv4", translate("IPv4 only"))
567         fam:value("ipv6", translate("IPv6 only"))
568         fam:depends("proto", "ahcp")
569
570         function fam.cfgvalue(self, section)
571                 local v4 = m.uci:get_bool("network", section, "ipv4_only")
572                 local v6 = m.uci:get_bool("network", section, "ipv6_only")
573                 if v4 then
574                         return "ipv4"
575                 elseif v6 then
576                         return "ipv6"
577                 end
578                 return ""
579         end
580
581         function fam.write(self, section, value)
582                 if value == "ipv4" then
583                         m.uci:set("network", section, "ipv4_only", "true")
584                         m.uci:delete("network", section, "ipv6_only")
585                 elseif value == "ipv6" then
586                         m.uci:set("network", section, "ipv6_only", "true")
587                         m.uci:delete("network", section, "ipv4_only")
588                 end
589         end
590
591         function fam.remove(self, section)
592                 m.uci:delete("network", section, "ipv4_only")
593                 m.uci:delete("network", section, "ipv6_only")
594         end
595
596         nodns = s:taboption("ahcp", Flag, "no_dns", translate("Disable DNS setup"))
597         nodns.optional = true
598         nodns.enabled  = "true"
599         nodns.disabled = "false"
600         nodns.default  = nodns.disabled
601         nodns:depends("proto", "ahcp")
602
603         ltime = s:taboption("ahcp", Value, "lease_time", translate("Lease validity time"))
604         ltime.optional    = true
605         ltime.placeholder = 3666
606         ltime.datatype    = "uinteger"
607         ltime:depends("proto", "ahcp")
608 end
609
610 if net:proto() ~= "relay" then
611         s2 = m:section(TypedSection, "alias", translate("IP-Aliases"))
612         s2.addremove = true
613
614         s2:depends("interface", arg[1])
615         s2.defaults.interface = arg[1]
616
617         s2:tab("general", translate("General Setup"))
618         s2.defaults.proto = "static"
619
620         ip = s2:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
621         ip.optional = true
622         ip.datatype = "ip4addr"
623
624         nm = s2:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
625         nm.optional = true
626         nm.datatype = "ip4addr"
627         nm:value("255.255.255.0")
628         nm:value("255.255.0.0")
629         nm:value("255.0.0.0")
630
631         gw = s2:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
632         gw.optional = true
633         gw.datatype = "ip4addr"
634
635         if has_ipv6 then
636                 s2:tab("ipv6", translate("IPv6 Setup"))
637
638                 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"))
639                 ip6.optional = true
640                 ip6.datatype = "ip6addr"
641
642                 gw6 = s2:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
643                 gw6.optional = true
644                 gw6.datatype = "ip6addr"
645         end
646
647         s2:tab("advanced", translate("Advanced Settings"))
648
649         bcast = s2:taboption("advanced", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
650         bcast.optional = true
651         bcast.datatype = "ip4addr"
652
653         dns = s2:taboption("advanced", Value, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"))
654         dns.optional = true
655         dns.datatype = "ip4addr"
656 end
657
658
659 --
660 -- Display DNS settings if dnsmasq is available
661 --
662
663 if has_dnsmasq and net:proto() == "static" then
664         m2 = Map("dhcp", "", "")
665         
666         local section_id = "-"
667
668         function m2.on_parse()
669                 m2.uci:foreach("dhcp", "dhcp", function(s)
670                         if s.interface == arg[1] then
671                                 section_id = s['.name']
672                                 return false
673                         end
674                 end)
675         end
676
677         s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
678         s.addremove = false
679         s.anonymous = true
680         s:tab("general",  translate("General Setup"))
681         s:tab("advanced", translate("Advanced Settings"))
682
683         function s.cfgsections(self)
684                 return { section_id }
685         end
686
687         local ignore = s:taboption("general", Flag, "ignore",
688                 translate("Ignore interface"),
689                 translate("Disable <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr> for " ..
690                         "this interface."))
691
692         ignore.rmempty = false
693
694         function ignore.cfgvalue(self, section)
695                 return (section == "-") and self.enabled or Flag.cfgvalue(self, section)
696         end
697
698         function ignore.write(self, section, value)
699                 section_id = m2.uci:section("dhcp", "dhcp", nil, {
700                         ignore    = value,
701                         interface = arg[1]
702                 })
703         end 
704
705
706         local start = s:taboption("general", Value, "start", translate("Start"),
707                 translate("Lowest leased address as offset from the network address."))
708         start.optional = true
709         start.datatype = "uinteger"
710         start.default = "100"
711
712         local limit = s:taboption("general", Value, "limit", translate("Limit"),
713                 translate("Maximum number of leased addresses."))
714         limit.optional = true
715         limit.datatype = "uinteger"
716         limit.default = "150"
717
718         local ltime = s:taboption("general", Value, "leasetime", translate("Leasetime"),
719                 translate("Expiry time of leased addresses, minimum is 2 Minutes (<code>2m</code>)."))
720         ltime.rmempty = true
721         ltime.default = "12h"
722
723         local dd = s:taboption("advanced", Flag, "dynamicdhcp",
724                 translate("Dynamic <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr>"),
725                 translate("Dynamically allocate DHCP addresses for clients. If disabled, only " ..
726                         "clients having static leases will be served."))
727         dd.default = dd.enabled
728
729         s:taboption("advanced", Flag, "force", translate("Force"),
730                 translate("Force DHCP on this network even if another server is detected."))
731
732         -- XXX: is this actually useful?
733         --s:taboption("advanced", Value, "name", translate("Name"),
734         --      translate("Define a name for this network."))
735
736         mask = s:taboption("advanced", Value, "netmask",
737                 translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"),
738                 translate("Override the netmask sent to clients. Normally it is calculated " ..
739                         "from the subnet that is served."))
740
741         mask.optional = true
742         mask.datatype = "ip4addr"
743
744         s:taboption("advanced", DynamicList, "dhcp_option", translate("DHCP-Options"),
745                 translate("Define additional DHCP options, for example \"<code>6,192.168.2.1," ..
746                         "192.168.2.2</code>\" which advertises different DNS servers to clients."))
747
748
749         local function write_opt(self, section, value)
750                 return getmetatable(self).__index.write(self, section_id, value)
751         end
752
753         local function remove_opt(self, section, value)
754                 return getmetatable(self).__index.remove(self, section_id, value)
755         end
756
757         for i, n in ipairs(s.children) do
758                 if n ~= ignore then
759                         n:depends("ignore", "")
760                         n.write  = write_opt
761                         n.remove = remove_opt
762                 end
763         end
764 end
765
766 return m, m2