libs/core: fixes luci.model.wireless
[project/luci.git] / libs / core / luasrc / model / wireless.lua
1 --[[
2 LuCI - Wireless model
3
4 Copyright 2009 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 pairs, i18n, uci, math = pairs, luci.i18n, luci.model.uci, math
21
22 local iwi = require "iwinfo"
23 local utl = require "luci.util"
24 local uct = require "luci.model.uci.bind"
25
26 module "luci.model.wireless"
27
28 local ub = uct.bind("wireless")
29 local st, ifs
30
31 function init(cursor)
32         cursor:unload("wireless")
33         cursor:load("wireless")
34         ub:init(cursor)
35
36         st = uci.cursor_state()
37         ifs = { }
38
39         local count = 0
40
41         ub.uci:foreach("wireless", "wifi-iface",
42                 function(s)
43                         count = count + 1
44
45                         local id = "%s.network%d" %{ s.device, count }
46
47                         ifs[id] = {
48                                 id    = id,
49                                 sid   = s['.name'],
50                                 count = count
51                         }
52
53                         local dev = st:get("wireless", s['.name'], "ifname")
54                                 or st:get("wireless", s['.name'], "device")
55
56                         local wtype = dev and iwi.type(dev)
57
58                         if dev and wtype then
59                                 ifs[id].winfo = iwi[wtype]
60                                 ifs[id].wdev  = dev
61                         end
62                 end)
63 end
64
65 function get_device(self, dev)
66         return device(dev)
67 end
68
69 function get_network(self, id)
70         if ifs[id] then
71                 return network(ifs[id].sid)
72         else
73                 local n
74                 for n, _ in pairs(ifs) do
75                         if ifs[n].sid == id then
76                                 return network(id)
77                         end
78                 end
79         end
80 end
81
82 function shortname(self, iface)
83         if iface.wdev and iface.winfo then
84                 return "%s %q" %{
85                         i18n.translate("a_s_if_iwmode_" .. iface:active_mode(), iface.winfo.mode(iface.wdev)), 
86                         iface:active_ssid() or "(hidden)"
87                 }
88         else
89                 return iface:name()
90         end
91 end
92
93 function get_i18n(self, iface)
94         if iface.wdev and iface.winfo then
95                 return "%s: %s %q (%s)" %{
96                         i18n.translate("a_s_if_wifinet", "Wireless Network"),
97                         i18n.translate("a_s_if_iwmode_" .. iface:active_mode(), iface.winfo.mode(iface.wdev)),
98                         iface:active_ssid() or "(hidden)", iface.wdev
99                 }
100         else
101                 return "%s: %q" %{ i18n.translate("a_s_if_wifinet", "Wireless Network"), iface:name() }
102         end
103 end
104
105 function rename_network(self, old, new)
106         local i
107         for i, _ in pairs(ifs) do
108                 if ifs[i].network == old then
109                         ifs[i].network = new
110                 end
111         end
112
113         ub.uci:foreach("wireless", "wifi-iface",
114                 function(s)
115                         if s.network == old then
116                                 if new then 
117                                         ub.uci:set("wireless", s['.name'], "network", new)
118                                 else
119                                         ub.uci:delete("wireless", s['.name'], "network")
120                                 end
121                         end
122                 end)
123 end
124
125 function del_network(self, old)
126         return self:rename_network(old, nil)
127 end
128
129 function find_interfaces(self, iflist, brlist)
130         local iface
131         for iface, _ in pairs(ifs) do
132                 iflist[iface] = ifs[iface]
133         end
134 end
135
136 function ignore_interface(self, iface)
137         if ifs and ifs[iface] then
138                 return false
139         else
140                 return iwi.type(iface) and true or false
141         end
142 end
143
144 function add_interface(self, net, iface)
145         if ifs and ifs[iface] and ifs[iface].sid then
146                 ub.uci:set("wireless", ifs[iface].sid, "network", net:name())
147                 ifs[iface].network = net:name()
148                 return true
149         end
150
151         return false
152 end
153
154 function del_interface(self, net, iface)
155         if ifs and ifs[iface] and ifs[iface].sid then
156                 ub.uci:delete("wireless", ifs[iface].sid, "network")
157                 --return true
158         end
159
160         return false
161 end
162
163
164 device = ub:section("wifi-device")
165 device:property("type")
166 device:property("channel")
167 device:property("disabled")
168
169 function device.name(self)
170         return self.sid
171 end
172
173 function device.get_networks(self)
174         local nets = { }
175
176         ub.uci:foreach("wireless", "wifi-iface",
177                 function(s)
178                         if s.device == self:name() then
179                                 nets[#nets+1] = network(s['.name'])
180                         end
181                 end)
182
183         return nets
184 end
185
186
187 network = ub:section("wifi-iface")
188 network:property("mode")
189 network:property("ssid")
190 network:property("bssid")
191 network:property("network")
192
193 function network._init(self, sid)
194         local count = 0
195
196         ub.uci:foreach("wireless", "wifi-iface",
197                 function(s)
198                         count = count + 1
199                         return s['.name'] ~= sid
200                 end)
201         
202         local dev = st:get("wireless", sid, "ifname")
203                 or st:get("wireless", sid, "device")
204
205         if dev then
206                 self.id = "%s.network%d" %{ dev, count }
207
208                 local wtype = iwi.type(dev)
209                 if dev and wtype then
210                         self.winfo = iwi[wtype]
211                         self.wdev  = dev
212                 end
213         end
214 end
215
216 function network.name(self)
217         return self.id
218 end
219
220 function network.ifname(self)
221         return self.wdev
222 end
223
224 function network.get_device(self)
225         if self.device then
226                 return device(self.device)
227         end
228 end
229
230 function network.active_mode(self)
231         local m = self.winfo and self.winfo.mode(self.wdev)
232         if m == "Master" or m == "Auto" then
233                 m = "ap"
234         elseif m == "Ad-Hoc" then
235                 m = "adhoc"
236         elseif m == "Client" then
237                 m = "sta"
238         elseif m then
239                 m = m:lower()
240         else
241                 m = self:mode()
242         end
243         return m or "ap"
244 end
245
246 function network.active_mode_i18n(self)
247         return i18n.translate("a_s_if_iwmode_" .. self:active_mode())
248 end
249
250 function network.active_ssid(self)
251         return self.winfo and self.winfo.ssid(self.wdev) or
252                 self:ssid()
253 end
254
255 function network.active_bssid(self)
256         return self.winfo and self.winfo.bssid(self.wdev) or
257                 self:bssid() or "00:00:00:00:00:00"
258 end
259
260 function network.signal(self)
261         return self.winfo and self.winfo.signal(self.wdev) or 0
262 end
263
264 function network.noise(self)
265         return self.winfo and self.winfo.noise(self.wdev) or 0
266 end
267
268 function network.signal_level(self)
269         if self:active_bssid() ~= "00:00:00:00:00:00" then
270                 local signal = self:signal()
271                 local noise  = self:noise()
272
273                 if signal > 0 and noise > 0 then
274                         local snr = -1 * (noise - signal)
275                         return math.floor(snr / 5)
276                 else
277                         return 0
278                 end
279         else
280                 return -1
281         end
282 end
283
284 function network.signal_percent(self)
285         local qc = self.winfo and
286                 self.winfo.quality(self.wdev) or 0
287
288         local qm = self.winfo and
289                 self.winfo.quality_max(self.wdev) or 0
290
291         if qc > 0 and qm > 0 then
292                 return math.floor((100 / qm) * qc)
293         else
294                 return 0
295         end
296 end
297