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