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