libs/core: merge luci.model.wireless into luci.model.network
[project/luci.git] / libs / core / luasrc / model / network.lua
1 --[[
2 LuCI - Network model
3
4 Copyright 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10         http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 ]]--
19
20 local type, pairs, ipairs, loadfile, table, tonumber, math, i18n
21         = type, pairs, ipairs, loadfile, table, tonumber, math, luci.i18n
22
23 local nxo = require "nixio"
24 local ipc = require "luci.ip"
25 local sys = require "luci.sys"
26 local utl = require "luci.util"
27 local dsp = require "luci.dispatcher"
28 local uci = require "luci.model.uci"
29
30 module "luci.model.network"
31
32
33 local ifs, brs, sws, uci_r, uci_s
34
35 function _list_del(c, s, o, r)
36         local val = uci_r:get(c, s, o)
37         if val then
38                 local l = { }
39                 if type(val) == "string" then
40                         for val in val:gmatch("%S+") do
41                                 if val ~= r then
42                                         l[#l+1] = val
43                                 end
44                         end
45                         if #l > 0 then
46                                 uci_r:set(c, s, o, table.concat(l, " "))
47                         else
48                                 uci_r:delete(c, s, o)
49                         end
50                 elseif type(val) == "table" then
51                         for _, val in ipairs(val) do
52                                 if val ~= r then
53                                         l[#l+1] = val
54                                 end
55                         end
56                         if #l > 0 then
57                                 uci_r:set(c, s, o, l)
58                         else
59                                 uci_r:delete(c, s, o)
60                         end
61                 end
62         end
63 end
64
65 function _list_add(c, s, o, a)
66         local val = uci_r:get(c, s, o) or ""
67         if type(val) == "string" then
68                 local l = { }
69                 for val in val:gmatch("%S+") do
70                         if val ~= a then
71                                 l[#l+1] = val
72                         end
73                 end
74                 l[#l+1] = a
75                 uci_r:set(c, s, o, table.concat(l, " "))
76         elseif type(val) == "table" then
77                 local l = { }
78                 for _, val in ipairs(val) do
79                         if val ~= a then
80                                 l[#l+1] = val
81                         end
82                 end
83                 l[#l+1] = a
84                 uci_r:set(c, s, o, l)
85         end
86 end
87
88 function _stror(s1, s2)
89         if not s1 or #s1 == 0 then
90                 return s2 and #s2 > 0 and s2
91         else
92                 return s1
93         end
94 end
95
96 function _get(c, s, o)
97         return uci_r:get(c, s, o)
98 end
99
100 function _set(c, s, o, v)
101         if v ~= nil then
102                 if type(v) == "boolean" then v = v and "1" or "0" end
103                 return uci_r:set(c, s, o, v)
104         else
105                 return uci_r:del(c, s, o, v)
106         end
107 end
108
109 function _wifi_iface(x)
110         return (
111                 x:match("^wlan%d") or x:match("^wl%d") or x:match("^ath%d") or
112                 x:match("^%w+%.network%d")
113         )
114 end
115
116 function _wifi_lookup(ifn)
117         -- got a radio#.network# pseudo iface, locate the corresponding section
118         local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$")
119         if radio and ifnidx then
120                 local sid = nil
121                 local num = 0
122
123                 ifnidx = tonumber(ifnidx)
124                 uci_r:foreach("wireless", "wifi-iface",
125                         function(s)
126                                 if s.device == radio then
127                                         num = num + 1
128                                         if num == ifnidx then
129                                                 sid = s['.name']
130                                                 return false
131                                         end
132                                 end
133                         end)
134
135                 return sid
136
137         -- looks like wifi, try to locate the section via state vars
138         elseif _wifi_iface(ifn) then
139                 local sid = nil
140
141                 uci_s:foreach("wireless", "wifi-iface",
142                         function(s)
143                                 if s.ifname == ifn then
144                                         sid = s['.name']
145                                         return false
146                                 end
147                         end)
148
149                 return sid
150         end
151 end
152
153 function _iface_ignore(x)
154         return (
155                 x:match("^wmaster%d") or x:match("^wifi%d") or x:match("^hwsim%d") or
156                 x:match("^imq%d") or x:match("^mon.wlan%d") or x:match("^6in4-%w") or
157                 x:match("^3g-%w") or x:match("^ppp-%w") or x:match("^pppoe-%w") or
158                 x:match("^pppoa-%w") or x == "lo"
159         )
160 end
161
162
163 function init(cursor)
164         uci_r = cursor or luci.model.uci.cursor()
165         uci_s = cursor:substate()
166
167         ifs = { }
168         brs = { }
169         sws = { }
170
171         -- read interface information
172         local n, i
173         for n, i in ipairs(nxo.getifaddrs()) do
174                 local name = i.name:match("[^:]+")
175                 local prnt = name:match("^([^%.]+)%.")
176
177                 if not _iface_ignore(name) then
178                         ifs[name] = ifs[name] or {
179                                 idx      = i.ifindex or n,
180                                 name     = name,
181                                 rawname  = i.name,
182                                 flags    = { },
183                                 ipaddrs  = { },
184                                 ip6addrs = { }
185                         }
186
187                         if prnt then
188                                 sws[name] = true
189                                 sws[prnt] = true
190                         end
191
192                         if i.family == "packet" then
193                                 ifs[name].flags   = i.flags
194                                 ifs[name].stats   = i.data
195                                 ifs[name].macaddr = i.addr
196                         elseif i.family == "inet" then
197                                 ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
198                         elseif i.family == "inet6" then
199                                 ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
200                         end
201                 end
202         end
203
204         -- read bridge informaton
205         local b, l
206         for l in utl.execi("brctl show") do
207                 if not l:match("STP") then
208                         local r = utl.split(l, "%s+", nil, true)
209                         if #r == 4 then
210                                 b = {
211                                         name    = r[1],
212                                         id      = r[2],
213                                         stp     = r[3] == "yes",
214                                         ifnames = { ifs[r[4]] }
215                                 }
216                                 if b.ifnames[1] then
217                                         b.ifnames[1].bridge = b
218                                 end
219                                 brs[r[1]] = b
220                         elseif b then
221                                 b.ifnames[#b.ifnames+1] = ifs[r[2]]
222                                 b.ifnames[#b.ifnames].bridge = b
223                         end
224                 end
225         end
226
227         return _M
228 end
229
230 function save(self, ...)
231         uci_r:save(...)
232         uci_r:load(...)
233 end
234
235 function commit(self, ...)
236         uci_r:commit(...)
237         uci_r:load(...)
238 end
239
240 function has_ipv6(self)
241         return nfs.access("/proc/net/ipv6_route")
242 end
243
244 function add_network(self, n, options)
245         if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
246                 if uci_r:section("network", "interface", n, options) then
247                         return network(n)
248                 end
249         end
250 end
251
252 function get_network(self, n)
253         if n and uci_r:get("network", n) == "interface" then
254                 return network(n)
255         end
256 end
257
258 function get_networks(self)
259         local nets = { }
260         local nls = { }
261
262         uci_r:foreach("network", "interface",
263                 function(s)
264                         nls[s['.name']] = network(s['.name'])
265                 end)
266
267         local n
268         for n in utl.kspairs(nls) do
269                 nets[#nets+1] = nls[n]
270         end
271
272         return nets
273 end
274
275 function del_network(self, n)
276         local r = uci_r:delete("network", n)
277         if r then
278                 uci_r:foreach("network", "alias",
279                         function(s)
280                                 if s.interface == n then
281                                         uci_r:delete("network", s['.name'])
282                                 end
283                         end)
284
285                 uci_r:foreach("network", "route",
286                         function(s)
287                                 if s.interface == n then
288                                         uci_r:delete("network", s['.name'])
289                                 end
290                         end)
291
292                 uci_r:foreach("network", "route6",
293                         function(s)
294                                 if s.interface == n then
295                                         uci_r:delete("network", s['.name'])
296                                 end
297                         end)
298
299                 uci_r:foreach("wireless", "wifi-iface",
300                         function(s)
301                                 if s.network == n then
302                                         uci_r:delete("wireless", s['.name'], "network")
303                                 end
304                         end)
305
306                 uci_r:delete("network", n)
307         end
308         return r
309 end
310
311 function rename_network(self, old, new)
312         local r
313         if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
314                 r = uci_r:section("network", "interface", new, uci_r:get_all("network", old))
315
316                 if r then
317                         uci_r:foreach("network", "alias",
318                                 function(s)
319                                         if s.interface == old then
320                                                 uci_r:set("network", s['.name'], "interface", new)
321                                         end
322                                 end)
323
324                         uci_r:foreach("network", "route",
325                                 function(s)
326                                         if s.interface == old then
327                                                 uci_r:set("network", s['.name'], "interface", new)
328                                         end
329                                 end)
330
331                         uci_r:foreach("network", "route6",
332                                 function(s)
333                                         if s.interface == old then
334                                                 uci_r:set("network", s['.name'], "interface", new)
335                                         end
336                                 end)
337
338                         uci_r:foreach("wireless", "wifi-iface",
339                                 function(s)
340                                         if s.network == old then
341                                                 uci_r:set("wireless", s['.name'], "network", new)
342                                         end
343                                 end)
344
345                         uci_r:delete("network", old)
346                 end
347         end
348         return r or false
349 end
350
351 function get_interface(self, i)
352         if ifs[i] or _wifi_iface(i) then
353                 return interface(i)
354         else
355                 local ifc
356                 local num = { }
357                 uci_r:foreach("wireless", "wifi-iface",
358                         function(s)
359                                 if s.device then
360                                         num[s.device] = num[s.device] and num[s.device] + 1 or 1
361                                         if s['.name'] == i then
362                                                 ifc = interface(
363                                                         "%s.network%d" %{s.device, num[s.device] })
364                                                 return false
365                                         end
366                                 end
367                         end)
368                 return ifc
369         end
370 end
371
372 function get_interfaces(self)
373         local iface
374         local ifaces = { }
375
376         -- find normal interfaces
377         for iface in utl.kspairs(ifs) do
378                 if not _iface_ignore(iface) and not _wifi_iface(iface) then
379                         ifaces[#ifaces+1] = interface(iface)
380                 end
381         end
382
383         -- find wifi interfaces
384         local num = { }
385         local wfs = { }
386         uci_r:foreach("wireless", "wifi-iface",
387                 function(s)
388                         if s.device then
389                                 num[s.device] = num[s.device] and num[s.device] + 1 or 1
390                                 local i = "%s.network%d" %{ s.device, num[s.device] }
391                                 wfs[i] = interface(i)
392                         end
393                 end)
394
395         for iface in utl.kspairs(wfs) do
396                 ifaces[#ifaces+1] = wfs[iface]
397         end
398
399         return ifaces
400 end
401
402 function ignore_interface(self, x)
403         return _iface_ignore(x)
404 end
405
406 function get_wifidev(self, dev)
407         if uci_r:get("wireless", dev) == "wifi-device" then
408                 return wifidev(dev)
409         end
410 end
411
412 function get_wifidevs(self)
413         local devs = { }
414         local wfd  = { }
415
416         uci_r:foreach("wireless", "wifi-device",
417                 function(s) wfd[#wfd+1] = s['.name'] end)
418
419         local dev
420         for _, dev in utl.vspairs(wfd) do
421                 devs[#devs+1] = wifidev(dev)
422         end
423
424         return devs
425 end
426
427 function get_wifinet(self, net)
428         local wnet = _wifi_lookup(net)
429         if wnet then
430                 return wifinet(wnet)
431         end
432 end
433
434 function add_wifinet(self, net, options)
435         if type(options) == "table" and options.device and
436                 uci_r:get("wireless", options.device) == "wifi-device"
437         then
438                 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
439                 return wifinet(wnet)
440         end
441 end
442
443 function del_wifinet(self, net)
444         local wnet = _wifi_lookup(net)
445         if wnet then
446                 uci_r:delete("wireless", wnet)
447                 return true
448         end
449         return false
450 end
451
452
453 network = utl.class()
454
455 function network.__init__(self, name)
456         self.sid = name
457 end
458
459 function network._get(self, opt)
460         local v = uci_r:get("network", self.sid, opt)
461         if type(v) == "table" then
462                 return table.concat(v, " ")
463         end
464         return v or ""
465 end
466
467 function network.get(self, opt)
468         return _get("network", self.sid, opt)
469 end
470
471 function network.set(self, opt, val)
472         return _set("network", self.sid, opt, val)
473 end
474
475 function network.ifname(self)
476         local p = self:proto()
477         if self:is_bridge() then
478                 return "br-" .. self.sid
479         elseif self:is_virtual() then
480                 return p .. "-" .. self.sid
481         else
482                 local dev = self:_get("ifname") or
483                         uci_r:get("network", self.sid, "ifname")
484
485                 dev = dev and dev:match("%S+")
486
487                 if not dev then
488                         uci_r:foreach("wireless", "wifi-iface",
489                                 function(s)
490                                         if s.device then
491                                                 num[s.device] = num[s.device]
492                                                         and num[s.device] + 1 or 1
493
494                                                 if s.network == self.sid then
495                                                         dev = "%s.network%d" %{ s.device, num[s.device] }
496                                                         return false
497                                                 end
498                                         end
499                                 end)
500                 end
501
502                 return dev
503         end
504 end
505
506 function network.device(self)
507         local dev = self:_get("device")
508         if not dev or dev:match("[^%w%-%.%s]") then
509                 dev = uci_r:get("network", self.sid, "ifname")
510         end
511         return dev
512 end
513
514 function network.proto(self)
515         return self:_get("proto") or "none"
516 end
517
518 function network.type(self)
519         return self:_get("type")
520 end
521
522 function network.name(self)
523         return self.sid
524 end
525
526 function network.is_bridge(self)
527         return (self:type() == "bridge")
528 end
529
530 function network.is_virtual(self)
531         local p = self:proto()
532         return (
533                 p == "3g" or p == "6in4" or p == "ppp" or
534                 p == "pppoe" or p == "pppoa"
535         )
536 end
537
538 function network.is_empty(self)
539         if self:is_virtual() then
540                 return false
541         else
542                 local rv = true
543
544                 if (self:_get("ifname") or ""):match("%S+") then
545                         rv = false
546                 end
547
548                 uci_r:foreach("wireless", "wifi-iface",
549                         function(s)
550                                 if s.network == self.sid then
551                                         rv = false
552                                         return false
553                                 end
554                         end)
555
556                 return rv
557         end
558 end
559
560 function network.add_interface(self, ifname)
561         if not self:is_virtual() then
562                 if type(ifname) ~= "string" then
563                         ifname = ifname:name()
564                 else
565                         ifname = ifname:match("[^%s:]+")
566                 end
567
568                 -- remove the interface from all ifaces
569                 uci_r:foreach("network", "interface",
570                         function(s)
571                                 _list_del("network", s['.name'], "ifname", ifname)
572                         end)
573
574                 -- if its a wifi interface, change its network option
575                 local wif = _wifi_lookup(ifname)
576                 if wif then
577                         uci_r:set("wireless", wif, "network", self.sid)
578
579                 -- add iface to our iface list
580                 else
581                         _list_add("network", self.sid, "ifname", ifname)
582                 end
583         end
584 end
585
586 function network.del_interface(self, ifname)
587         if not self:is_virtual() then
588                 if utl.instanceof(ifname, interface) then
589                         ifname = ifname:name()
590                 else
591                         ifname = ifname:match("[^%s:]+")
592                 end
593
594                 -- if its a wireless interface, clear its network option
595                 local wif = _wifi_lookup(ifname)
596                 if wif then     uci_r:delete("wireless", wif, "network") end
597
598                 -- remove the interface
599                 _list_del("network", self.sid, "ifname", ifname)
600         end
601 end
602
603 function network.get_interfaces(self)
604         local ifaces = { }
605
606         local ifn
607         if self:is_virtual() then
608                 ifn = self:proto() .. "-" .. self.sid
609                 ifaces = { interface(ifn) }
610         else
611                 local nfs = { }
612                 for ifn in self:_get("ifname"):gmatch("%S+") do
613                         ifn = ifn:match("[^:]+")
614                         nfs[ifn] = interface(ifn)
615                 end
616
617                 for ifn in utl.kspairs(nfs) do
618                         ifaces[#ifaces+1] = nfs[ifn]
619                 end
620
621                 local num = { }
622                 local wfs = { }
623                 uci_r:foreach("wireless", "wifi-iface",
624                         function(s)
625                                 if s.device then
626                                         num[s.device] = num[s.device] and num[s.device] + 1 or 1
627                                         if s.network == self.sid then
628                                                 ifn = "%s.network%d" %{ s.device, num[s.device] }
629                                                 wfs[ifn] = interface(ifn)
630                                         end
631                                 end
632                         end)
633
634                 for ifn in utl.kspairs(wfs) do
635                         ifaces[#ifaces+1] = wfs[ifn]
636                 end
637         end
638
639         return ifaces
640 end
641
642 function network.contains_interface(self, ifname)
643         if type(ifname) ~= "string" then
644                 ifname = ifname:name()
645         else
646                 ifname = ifname:match("[^%s:]+")
647         end
648
649         local ifn
650         if self:is_virtual() then
651                 ifn = self:proto() .. "-" .. self.sid
652                 return ifname == ifn
653         else
654                 for ifn in self:_get("ifname"):gmatch("%S+") do
655                         ifn = ifn:match("[^:]+")
656                         if ifn == ifname then
657                                 return true
658                         end
659                 end
660
661                 local wif = _wifi_lookup(ifname)
662                 if wif then
663                         return (uci_r:get("wireless", wif, "network") == self.sid)
664                 end
665         end
666
667         return false
668 end
669
670 function network.adminlink(self)
671         return dsp.build_url("admin", "network", "network", self.sid)
672 end
673
674
675 interface = utl.class()
676 function interface.__init__(self, ifname)
677         local wif = _wifi_lookup(ifname)
678         if wif then self.wif = wifinet(wif) end
679
680         self.ifname = self.ifname or ifname
681         self.dev    = ifs[self.ifname]
682 end
683
684 function interface.name(self)
685         return self.wif and self.wif:ifname() or self.ifname
686 end
687
688 function interface.mac(self)
689         return self.dev and self.dev or "00:00:00:00:00:00"
690 end
691
692 function interface.ipaddrs(self)
693         return self.dev and self.dev.ipaddrs or { }
694 end
695
696 function interface.ip6addrs(self)
697         return self.dev and self.dev.ip6addrs or { }
698 end
699
700 function interface.type(self)
701         if self.wif or _wifi_iface(self.ifname) then
702                 return "wifi"
703         elseif brs[self.ifname] then
704                 return "bridge"
705         elseif sws[self.ifname] or self.ifname:match("%.") then
706                 return "switch"
707         else
708                 return "ethernet"
709         end
710 end
711
712 function interface.shortname(self)
713         if self.wif then
714                 return "%s %q" %{
715                         self.wif:active_mode(),
716                         self.wif:active_ssid() or self.wif:active_bssid()
717                 }
718         else
719                 return self.ifname
720         end
721 end
722
723 function interface.get_i18n(self)
724         if self.wif then
725                 return "%s: %s %q" %{
726                         i18n.translate("Wireless Network"),
727                         self.wif:active_mode(),
728                         self.wif:active_ssid() or self.wif:active_bssid()
729                 }
730         else
731                 return "%s: %q" %{ self:get_type_i18n(), self:name() }
732         end
733 end
734
735 function interface.get_type_i18n(self)
736         local x = self:type()
737         if x == "wifi" then
738                 return i18n.translate("Wireless Adapter")
739         elseif x == "bridge" then
740                 return i18n.translate("Bridge")
741         elseif x == "switch" then
742                 return i18n.translate("Ethernet Switch")
743         else
744                 return i18n.translate("Ethernet Adapter")
745         end
746 end
747
748 function interface.adminlink(self)
749         if self.wif then
750                 return self.wif:adminlink()
751         end
752 end
753
754 function interface.ports(self)
755         if self.br then
756                 local iface
757                 local ifaces = { }
758                 for _, iface in ipairs(self.br.ifnames) do
759                         ifaces[#ifaces+1] = interface(iface.name)
760                 end
761                 return ifaces
762         end
763 end
764
765 function interface.bridge_id(self)
766         if self.br then
767                 return self.br.id
768         else
769                 return nil
770         end
771 end
772
773 function interface.bridge_stp(self)
774         if self.br then
775                 return self.br.stp
776         else
777                 return false
778         end
779 end
780
781 function interface.is_up(self)
782         if self.wif then
783                 return self.wif:is_up()
784         else
785                 return self.dev and self.dev.flags and self.dev.flags.up or false
786         end
787 end
788
789 function interface.is_bridge(self)
790         return (self:type() == "bridge")
791 end
792
793 function interface.is_bridgeport(self)
794         return self.dev and self.dev.bridge and true or false
795 end
796
797 function interface.tx_bytes(self)
798         return self.dev and self.dev.stats
799                 and self.dev.stats.tx_bytes or 0
800 end
801
802 function interface.rx_bytes(self)
803         return self.dev and self.dev.stats
804                 and self.dev.stats.rx_bytes or 0
805 end
806
807 function interface.tx_packets(self)
808         return self.dev and self.dev.stats
809                 and self.dev.stats.tx_packets or 0
810 end
811
812 function interface.rx_packets(self)
813         return self.dev and self.dev.stats
814                 and self.dev.stats.rx_packets or 0
815 end
816
817 function interface.get_network(self)
818         if self.dev and self.dev.network then
819                 self.network = _M:get_network(self.dev.network)
820         end
821
822         if not self.network then
823                 local net
824                 for _, net in ipairs(_M:get_networks()) do
825                         if net:contains_interface(self.ifname) then
826                                 self.network = net
827                                 return net
828                         end
829                 end
830         else
831                 return self.network
832         end
833 end
834
835 function interface.get_wifinet(self)
836         return self.wif
837 end
838
839
840 wifidev = utl.class()
841 function wifidev.__init__(self, dev)
842         self.sid = dev
843 end
844
845 function wifidev.get(self, opt)
846         return _get("wireless", self.sid, opt)
847 end
848
849 function wifidev.set(self, opt, val)
850         return _set("wireless", self.sid, opt, val)
851 end
852
853 function wifidev.name(self)
854         return self.sid
855 end
856
857 function wifidev.is_up(self)
858         local up = false
859
860         uci_s:foreach("wireless", "wifi-iface",
861                 function(s)
862                         if s.device == self.sid then
863                                 if s.up == "1" then
864                                         up = true
865                                         return false
866                                 end
867                         end
868                 end)
869
870         return up
871 end
872
873 function wifidev.get_wifinet(self, net)
874         if uci_r:get("wireless", net) == "wifi-iface" then
875                 return wifinet(net)
876         else
877                 local wnet = _wifi_lookup(net)
878                 if wnet then
879                         return wifinet(wnet)
880                 end
881         end
882 end
883
884 function wifidev.get_wifinets(self)
885         local nets = { }
886
887         uci_r:foreach("wireless", "wifi-iface",
888                 function(s)
889                         if s.device == self.sid then
890                                 nets[#nets+1] = wifinet(s['.name'])
891                         end
892                 end)
893
894         return nets
895 end
896
897 function wifidev.add_wifinet(self, options)
898         options = options or { }
899         options.device = self.sid
900
901         local wnet = uci_r:section("wifidev", "wifi-iface", nil, options)
902         if wnet then
903                 return wifinet(wnet)
904         end
905 end
906
907 function wifidev.del_wifinet(self, net)
908         if utl.instanceof(net, wifinet) then
909                 net = net.sid
910         elseif uci_r:get("wireless", net) ~= "wifi-iface" then
911                 net = _wifi_lookup(net)
912         end
913
914         if net and uci_r:get("wireless", net, "device") == self.sid then
915                 uci_r:delete("wireless", net)
916                 return true
917         end
918
919         return false
920 end
921
922
923 wifinet = utl.class()
924 function wifinet.__init__(self, net)
925         self.sid = net
926
927         local dev = uci_s:get("wireless", self.sid, "ifname")
928         if not dev then
929                 local num = { }
930                 uci_r:foreach("wireless", "wifi-iface",
931                         function(s)
932                                 if s.device then
933                                         num[s.device] = num[s.device] and num[s.device] + 1 or 1
934                                         if s['.name'] == self.sid then
935                                                 dev = "%s.network%d" %{ s.device, num[s.device] }
936                                                 return false
937                                         end
938                                 end
939                         end)
940         end
941
942         self.wdev   = dev
943         self.iwdata = uci_s:get_all("wireless", self.sid) or { }
944         self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
945 end
946
947 function wifinet.get(self, opt)
948         return _get("wireless", self.sid, opt)
949 end
950
951 function wifinet.set(self, opt, val)
952         return _set("wireless", self.sid, opt, val)
953 end
954
955 function wifinet.mode(self)
956         return uci_s:get("wireless", self.sid, "mode") or "ap"
957 end
958
959 function wifinet.ssid(self)
960         return uci_s:get("wireless", self.sid, "ssid")
961 end
962
963 function wifinet.bssid(self)
964         return uci_s:get("wireless", self.sid, "bssid")
965 end
966
967 function wifinet.network(self)
968         return uci_s:get("wifinet", self.sid, "network")
969 end
970
971 function wifinet.name(self)
972         return self.sid
973 end
974
975 function wifinet.ifname(self)
976         return self.iwinfo.ifname or self.wdev
977 end
978
979 function wifinet.get_device(self)
980         if self.iwdata.device then
981                 return wifidev(self.iwdata.device)
982         end
983 end
984
985 function wifinet.is_up(self)
986         return (self.iwdata.up == "1")
987 end
988
989 function wifinet.active_mode(self)
990         local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
991
992         if     m == "ap"      then m = "AP"
993         elseif m == "sta"     then m = "Client"
994         elseif m == "adhoc"   then m = "Ad-Hoc"
995         elseif m == "mesh"    then m = "Mesh"
996         elseif m == "monitor" then m = "Monitor"
997         end
998
999         return m
1000 end
1001
1002 function wifinet.active_mode_i18n(self)
1003         return i18n.translate(self:active_mode())
1004 end
1005
1006 function wifinet.active_ssid(self)
1007         return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1008 end
1009
1010 function wifinet.active_bssid(self)
1011         return _stror(self.iwinfo.bssid, self.iwinfo.bssid) or "00:00:00:00:00:00"
1012 end
1013
1014 function wifinet.active_encryption(self)
1015         local enc = self.iwinfo and self.iwinfo.encryption
1016         return enc and enc.description or "-"
1017 end
1018
1019 function wifinet.assoclist(self)
1020         return self.iwinfo.assoclist or { }
1021 end
1022
1023 function wifinet.frequency(self)
1024         local freq = self.iwinfo.frequency
1025         if freq and freq > 0 then
1026                 return "%.03f" % (freq / 1000)
1027         end
1028 end
1029
1030 function wifinet.bitrate(self)
1031         local rate = self.iwinfo.bitrate
1032         if rate and rate > 0 then
1033                 return (rate / 1000)
1034         end
1035 end
1036
1037 function wifinet.channel(self)
1038         return self.iwinfo.channel or
1039                 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1040 end
1041
1042 function wifinet.signal(self)
1043         return self.iwinfo.signal or 0
1044 end
1045
1046 function wifinet.noise(self)
1047         return self.iwinfo.noise or 0
1048 end
1049
1050 function wifinet.signal_level(self, s, n)
1051         if self:active_bssid() ~= "00:00:00:00:00:00" then
1052                 local signal = s or self:signal()
1053                 local noise  = n or self:noise()
1054
1055                 if signal < 0 and noise < 0 then
1056                         local snr = -1 * (noise - signal)
1057                         return math.floor(snr / 5)
1058                 else
1059                         return 0
1060                 end
1061         else
1062                 return -1
1063         end
1064 end
1065
1066 function wifinet.signal_percent(self)
1067         local qc = self.iwinfo.quality or 0
1068         local qm = self.iwinfo.quality_max or 0
1069
1070         if qc > 0 and qm > 0 then
1071                 return math.floor((100 / qm) * qc)
1072         else
1073                 return 0
1074         end
1075 end
1076
1077 function wifinet.shortname(self)
1078         return "%s %q" %{
1079                 i18n.translate(self:active_mode()),
1080                 self:active_ssid() or self:active_bssid()
1081         }
1082 end
1083
1084 function wifinet.get_i18n(self)
1085         return "%s: %s %q (%s)" %{
1086                 i18n.translate("Wireless Network"),
1087                 i18n.translate(self:active_mode()),
1088                 self:active_ssid() or self:active_bssid(),
1089                 self:ifname()
1090         }
1091 end
1092
1093 function wifinet.adminlink(self)
1094         return dsp.build_url("admin", "network", "wireless",
1095                 self.iwdata.device, self.wdev)
1096 end
1097
1098 function wifinet.get_network(self)
1099         if uci_r:get("network", self.iwdata.network) == "interface" then
1100                 return network(self.iwdata.network)
1101         end
1102 end
1103
1104 function wifinet.get_interface(self)
1105         return interface(self:ifname())
1106 end