d614337204f9e407f737f5e3e2aa9f313db002be
[project/luci.git] / modules / admin-full / luasrc / model / cbi / admin_network / ifaces.lua
1 --[[
2 LuCI - Lua Configuration Interface
3
4 Copyright 2008 Steven Barth <steven@midlink.org>
5 Copyright 2008 Jo-Philipp Wich <xm@subsignal.org>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11         http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14 ]]--
15
16 local fs = require "nixio.fs"
17 local nw = require "luci.model.network"
18 local fw = require "luci.model.firewall"
19
20 arg[1] = arg[1] or ""
21
22 local has_3g    = fs.access("/usr/bin/gcom")
23 local has_pptp  = fs.access("/usr/sbin/pptp")
24 local has_pppd  = fs.access("/usr/sbin/pppd")
25 local has_pppoe = fs.glob("/usr/lib/pppd/*/rp-pppoe.so")()
26 local has_pppoa = fs.glob("/usr/lib/pppd/*/pppoatm.so")()
27 local has_ipv6  = fs.access("/proc/net/ipv6_route")
28
29 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>)."))
30 m:chain("firewall")
31 m:chain("wireless")
32
33 nw.init(m.uci)
34 fw.init(m.uci)
35
36 s = m:section(NamedSection, arg[1], "interface", translate("Common Configuration"))
37 s.addremove = false
38
39 s:tab("general", translate("General Setup"))
40 if has_ipv6 then s:tab("ipv6", translate("IPv6 Setup")) end
41 if has_pppd then s:tab("ppp", translate("PPP Settings")) end
42 s:tab("physical", translate("Physical Settings"))
43 s:tab("firewall", translate("Firewall Settings"))
44
45 --[[
46 back = s:taboption("general", DummyValue, "_overview", translate("Overview"))
47 back.value = ""
48 back.titleref = luci.dispatcher.build_url("admin", "network", "network")
49 ]]
50
51 p = s:taboption("general", ListValue, "proto", translate("Protocol"))
52 p.override_scheme = true
53 p.default = "static"
54 p:value("static", translate("static"))
55 p:value("dhcp", "DHCP")
56 if has_pppd  then p:value("ppp",   "PPP")     end
57 if has_pppoe then p:value("pppoe", "PPPoE")   end
58 if has_pppoa then p:value("pppoa", "PPPoA")   end
59 if has_3g    then p:value("3g",    "UMTS/3G") end
60 if has_pptp  then p:value("pptp",  "PPTP")    end
61 p:value("none", translate("none"))
62
63 if not ( has_pppd and has_pppoe and has_pppoa and has_3g and has_pptp ) then
64         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")
65 end
66
67 br = s:taboption("physical", Flag, "type", translate("Bridge interfaces"), translate("creates a bridge over specified interface(s)"))
68 br.enabled = "bridge"
69 br.rmempty = true
70
71 stp = s:taboption("physical", Flag, "stp", translate("Enable <abbr title=\"Spanning Tree Protocol\">STP</abbr>"),
72         translate("Enables the Spanning Tree Protocol on this bridge"))
73 stp:depends("type", "1")
74 stp.rmempty = true
75
76 ifname_single = s:taboption("physical", Value, "ifname_single", translate("Interface"))
77 ifname_single.template = "cbi/network_ifacelist"
78 ifname_single.widget = "radio"
79 ifname_single.nobridges = true
80 ifname_single.network = arg[1]
81 ifname_single.rmempty = true
82 ifname_single:depends("type", "")
83
84 function ifname_single.cfgvalue(self, s)
85         return self.map.uci:get("network", s, "ifname")
86 end
87
88 function ifname_single.write(self, s, val)
89         local n = nw:get_network(s)
90         if n then
91                 local i
92                 for _, i in ipairs(n:get_interfaces()) do
93                         n:del_interface(i)
94                 end
95                 n:add_interface(val)
96         end
97 end
98
99
100 ifname_multi = s:taboption("physical", MultiValue, "ifname_multi", translate("Interface"))
101 ifname_multi.template = "cbi/network_ifacelist"
102 ifname_multi.nobridges = true
103 ifname_multi.network = arg[1]
104 ifname_multi.widget = "checkbox"
105 ifname_multi:depends("type", "1")
106 ifname_multi.cfgvalue = ifname_single.cfgvalue
107 ifname_multi.write = ifname_single.write
108
109
110 for _, d in ipairs(nw:get_interfaces()) do
111         if not d:is_bridge() then
112                 ifname_single:value(d:name())
113                 ifname_multi:value(d:name())
114         end
115 end
116
117
118 local fwd_to, fwd_from
119
120 fwzone = s:taboption("firewall", Value, "_fwzone",
121         translate("Create / Assign firewall-zone"),
122         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."))
123
124 fwzone.template = "cbi/firewall_zonelist"
125 fwzone.network = arg[1]
126 fwzone.rmempty = false
127
128 function fwzone.cfgvalue(self, section)
129         self.iface = section
130         local z = fw:get_zone_by_network(section)
131         return z and z:name()
132 end
133
134 function fwzone.write(self, section, value)
135         local zone = fw:get_zone(value)
136
137         if not zone and value == '-' then
138                 value = m:formvalue(self:cbid(section) .. ".newzone")
139                 if value and #value > 0 then
140                         zone = fw:add_zone(value)
141                 else
142                         fw:del_network(section)
143                 end
144         end
145
146         if zone then
147                 fw:del_network(section)
148                 zone:add_network(section)
149         end
150 end
151
152
153 ipaddr = s:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
154 ipaddr.rmempty = true
155 ipaddr:depends("proto", "static")
156
157 nm = s:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
158 nm.rmempty = true
159 nm:depends("proto", "static")
160 nm:value("255.255.255.0")
161 nm:value("255.255.0.0")
162 nm:value("255.0.0.0")
163
164 gw = s:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
165 gw:depends("proto", "static")
166 gw.rmempty = true
167
168 bcast = s:taboption("general", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
169 bcast:depends("proto", "static")
170
171 if has_ipv6 then
172         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"))
173         ip6addr:depends("proto", "static")
174
175         ip6gw = s:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
176         ip6gw:depends("proto", "static")
177 end
178
179 dns = s:taboption("general", Value, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"),
180         translate("You can specify multiple DNS servers separated by space here. Servers entered here will override " ..
181                 "automatically assigned ones."))
182
183 dns:depends("peerdns", "")
184
185 mtu = s:taboption("physical", Value, "mtu", "MTU")
186 mtu.isinteger = true
187
188 mac = s:taboption("physical", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
189
190
191 srv = s:taboption("general", Value, "server", translate("<abbr title=\"Point-to-Point Tunneling Protocol\">PPTP</abbr>-Server"))
192 srv:depends("proto", "pptp")
193 srv.rmempty = true
194
195 if has_3g then
196         service = s:taboption("general", ListValue, "service", translate("Service type"))
197         service:value("", translate("-- Please choose --"))
198         service:value("umts", "UMTS/GPRS")
199         service:value("cdma", "CDMA")
200         service:value("evdo", "EV-DO")
201         service:depends("proto", "3g")
202         service.rmempty = true
203
204         apn = s:taboption("general", Value, "apn", translate("Access point (APN)"))
205         apn:depends("proto", "3g")
206
207         pincode = s:taboption("general", Value, "pincode",
208          translate("PIN code"),
209          translate("Make sure that you provide the correct pin code here or you might lock your sim card!")
210         )
211         pincode:depends("proto", "3g")
212 end
213
214 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp then
215         user = s:taboption("general", Value, "username", translate("Username"))
216         user.rmempty = true
217         user:depends("proto", "pptp")
218         user:depends("proto", "pppoe")
219         user:depends("proto", "pppoa")
220         user:depends("proto", "ppp")
221         user:depends("proto", "3g")
222
223         pass = s:taboption("general", Value, "password", translate("Password"))
224         pass.rmempty = true
225         pass.password = true
226         pass:depends("proto", "pptp")
227         pass:depends("proto", "pppoe")
228         pass:depends("proto", "pppoa")
229         pass:depends("proto", "ppp")
230         pass:depends("proto", "3g")
231
232         ka = s:taboption("ppp", Value, "keepalive",
233          translate("Keep-Alive"),
234          translate("Number of failed connection tests to initiate automatic reconnect")
235         )
236         ka:depends("proto", "pptp")
237         ka:depends("proto", "pppoe")
238         ka:depends("proto", "pppoa")
239         ka:depends("proto", "ppp")
240         ka:depends("proto", "3g")
241
242         demand = s:taboption("ppp", Value, "demand",
243          translate("Automatic Disconnect"),
244          translate("Time (in seconds) after which an unused connection will be closed")
245         )
246         demand:depends("proto", "pptp")
247         demand:depends("proto", "pppoe")
248         demand:depends("proto", "pppoa")
249         demand:depends("proto", "ppp")
250         demand:depends("proto", "3g")
251 end
252
253 if has_pppoa then
254         encaps = s:taboption("ppp", ListValue, "encaps", translate("PPPoA Encapsulation"))
255         encaps:depends("proto", "pppoa")
256         encaps:value("", translate("-- Please choose --"))
257         encaps:value("vc", "VC")
258         encaps:value("llc", "LLC")
259
260         vpi = s:taboption("ppp", Value, "vpi", "VPI")
261         vpi:depends("proto", "pppoa")
262
263         vci = s:taboption("ppp", Value, "vci", "VCI")
264         vci:depends("proto", "pppoa")
265 end
266
267 if has_pptp or has_pppd or has_pppoe or has_pppoa or has_3g then
268         device = s:taboption("general", Value, "device",
269          translate("Modem device"),
270          translate("The device node of your modem, e.g. /dev/ttyUSB0")
271         )
272         device:depends("proto", "ppp")
273         device:depends("proto", "3g")
274
275         defaultroute = s:taboption("ppp", Flag, "defaultroute",
276          translate("Replace default route"),
277          translate("Let pppd replace the current default route to use the PPP interface after successful connect")
278         )
279         defaultroute:depends("proto", "ppp")
280         defaultroute:depends("proto", "pppoa")
281         defaultroute:depends("proto", "pppoe")
282         defaultroute:depends("proto", "pptp")
283         defaultroute:depends("proto", "3g")
284         defaultroute.rmempty = false
285         function defaultroute.cfgvalue(...)
286                 return ( AbstractValue.cfgvalue(...) or '1' )
287         end
288
289         peerdns = s:taboption("ppp", Flag, "peerdns",
290          translate("Use peer DNS"),
291          translate("Configure the local DNS server to use the name servers adverticed by the PPP peer")
292         )
293         peerdns:depends("proto", "ppp")
294         peerdns:depends("proto", "pppoa")
295         peerdns:depends("proto", "pppoe")
296         peerdns:depends("proto", "pptp")
297         peerdns:depends("proto", "3g")
298         peerdns.rmempty = false
299         function peerdns.cfgvalue(...)
300                 return ( AbstractValue.cfgvalue(...) or '1' )
301         end
302
303         if has_ipv6 then
304                 ipv6 = s:taboption("ppp", Flag, "ipv6", translate("Enable IPv6 on PPP link") )
305                 ipv6:depends("proto", "ppp")
306                 ipv6:depends("proto", "pppoa")
307                 ipv6:depends("proto", "pppoe")
308                 ipv6:depends("proto", "pptp")
309                 ipv6:depends("proto", "3g")
310         end
311
312         connect = s:taboption("ppp", Value, "connect",
313          translate("Connect script"),
314          translate("Let pppd run this script after establishing the PPP link")
315         )
316         connect:depends("proto", "ppp")
317         connect:depends("proto", "pppoe")
318         connect:depends("proto", "pppoa")
319         connect:depends("proto", "pptp")
320         connect:depends("proto", "3g")
321
322         disconnect = s:taboption("ppp", Value, "disconnect",
323          translate("Disconnect script"),
324          translate("Let pppd run this script before tearing down the PPP link")
325         )
326         disconnect:depends("proto", "ppp")
327         disconnect:depends("proto", "pppoe")
328         disconnect:depends("proto", "pppoa")
329         disconnect:depends("proto", "pptp")
330         disconnect:depends("proto", "3g")
331
332         pppd_options = s:taboption("ppp", Value, "pppd_options",
333          translate("Additional pppd options"),
334          translate("Specify additional command line arguments for pppd here")
335         )
336         pppd_options:depends("proto", "ppp")
337         pppd_options:depends("proto", "pppoa")
338         pppd_options:depends("proto", "pppoe")
339         pppd_options:depends("proto", "pptp")
340         pppd_options:depends("proto", "3g")
341
342         maxwait = s:taboption("ppp", Value, "maxwait",
343          translate("Setup wait time"),
344          translate("Seconds to wait for the modem to become ready before attempting to connect")
345         )
346         maxwait:depends("proto", "3g")
347 end
348
349 s2 = m:section(TypedSection, "alias", translate("IP-Aliases"))
350 s2.addremove = true
351
352 s2:depends("interface", arg[1])
353 s2.defaults.interface = arg[1]
354
355 s2:tab("general", translate("General Setup"))
356
357 s2.defaults.proto = "static"
358
359 s2:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address")).rmempty = true
360
361 nm = s2:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
362 nm.rmempty = true
363 nm:value("255.255.255.0")
364 nm:value("255.255.0.0")
365 nm:value("255.0.0.0")
366
367 s2:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway")).rmempty = true
368 s2:taboption("general", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
369 s2:taboption("general", Value, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"))
370
371 if has_ipv6 then
372         s2:tab("ipv6", translate("IPv6 Setup"))
373         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"))
374         s2:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
375 end
376
377
378 m2 = Map("dhcp", "", "")
379 function m2.on_parse()
380         local has_section = false
381
382         m2.uci:foreach("dhcp", "dhcp", function(s)
383                 if s.interface == arg[1] then
384                         has_section = true
385                         return false
386                 end
387         end)
388
389         if not has_section then
390                 m2.uci:section("dhcp", "dhcp", nil, { interface = arg[1], ignore = "1" })
391                 m2.uci:save("dhcp")
392         end
393 end
394
395 s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
396 s.addremove = false
397 s:tab("general",  translate("General Setup"))
398 s:tab("advanced", translate("Advanced Settings"))
399
400 function s.filter(self, section)
401         return m2.uci:get("dhcp", section, "interface") == arg[1]
402 end
403
404 local ignore = s:taboption("general", Flag, "ignore",
405         translate("Ignore interface"),
406         translate("Disable <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr> for " ..
407                 "this interface."))
408
409 ignore.rmempty = false
410
411 local start = s:taboption("general", Value, "start", translate("Start"),
412         translate("Lowest leased address as offset from the network address."))
413 start.rmempty = true
414 start.default = "100"
415
416 local limit = s:taboption("general", Value, "limit", translate("Limit"),
417         translate("Maximum number of leased addresses."))
418 limit.rmempty = true
419 limit.default = "150"
420
421 local ltime = s:taboption("general", Value, "leasetime", translate("Leasetime"),
422         translate("Expiry time of leased addresses, minimum is 2 Minutes (<code>2m</code>)."))
423 ltime.rmempty = true
424 ltime.default = "12h"
425
426 local dd = s:taboption("advanced", Flag, "dynamicdhcp",
427         translate("Dynamic <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr>"),
428         translate("Dynamically allocate DHCP addresses for clients. If disabled, only " ..
429                 "clients having static leases will be served."))
430
431 dd.rmempty = false
432 function dd.cfgvalue(self, section)
433         return Flag.cfgvalue(self, section) or "1"
434 end
435
436 s:taboption("advanced", Flag, "force", translate("Force"),
437         translate("Force DHCP on this network even if another server is detected."))
438
439 -- XXX: is this actually useful?
440 --s:taboption("advanced", Value, "name", translate("Name"),
441 --      translate("Define a name for this network."))
442
443 s:taboption("advanced", Value, "netmask",
444         translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"),
445         translate("Override the netmask sent to clients. Normally it is calculated " ..
446                 "from the subnet that is served."))
447
448 s:taboption("advanced", DynamicList, "dhcp_option", translate("DHCP-Options"),
449         translate("Define additional DHCP options, for example \"<code>6,192.168.2.1," ..
450                 "192.168.2.2</code>\" which advertises different DNS servers to clients."))
451
452 for i, n in ipairs(s.children) do
453         if n ~= ignore then
454                 n:depends("ignore", "")
455         end
456 end
457
458 return m, m2