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