libs/core: Fix wireless network ids
[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, type, i18n, uci, math = pairs, type, 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_devices(self)
70         local devs = { }
71         ub.uci:foreach("wireless", "wifi-device",
72                 function(s) devs[#devs+1] = device(s['.name']) end)
73         return devs
74 end
75
76 function get_network(self, id)
77         if ifs[id] then
78                 return network(ifs[id].sid)
79         else
80                 local n
81                 for n, _ in pairs(ifs) do
82                         if ifs[n].sid == id then
83                                 return network(id)
84                         end
85                 end
86         end
87 end
88
89 function add_network(self, options)
90         if type(options) == "table" and options.device and
91                 ub.uci:get("wireless", options.device) == "wifi-device"
92         then
93                 local s = ub.uci:section("wireless", "wifi-iface", nil, options)
94                 local c = 1
95                 ub.uci:foreach("wireless", "wifi-iface", function(s) c = c + 1 end)
96
97                 local id = "%s.network%d" %{ options.device, c }
98                 ifs[id] = {
99                         id    = id,
100                         sid   = s,
101                         count = c
102                 }
103
104                 local wtype = iwi.type(options.device)
105                 if wtype then
106                         ifs[id].winfo = iwi[wtype]
107                         ifs[id].wdev  = options.device
108                 end
109
110                 return network(s)
111         end
112 end
113
114 function del_network(self, id)
115         if ifs[id] then
116                 ub.uci:delete("wireless", ifs[id].sid)
117                 ifs[id] = nil
118         else
119                 local n
120                 for n, _ in pairs(ifs) do
121                         if ifs[n].sid == id then
122                                 ub.uci:delete("wireless", id)
123                                 ifs[n] = nil
124                         end
125                 end
126         end
127 end
128
129 function shortname(self, iface)
130         if iface.wdev and iface.winfo then
131                 return "%s %q" %{
132                         i18n.translate(iface:active_mode()), 
133                         iface:active_ssid() or i18n.translate("(hidden)")
134                 }
135         else
136                 return iface:name()
137         end
138 end
139
140 function get_i18n(self, iface)
141         if iface.wdev and iface.winfo then
142                 return "%s: %s %q (%s)" %{
143                         i18n.translate("Wireless Network"),
144                         i18n.translate(iface:active_mode()),
145                         iface:active_ssid() or i18n.translate("(hidden)"), iface.wdev
146                 }
147         else
148                 return "%s: %q" %{ i18n.translate("Wireless Network"), iface:name() }
149         end
150 end
151
152 function find_interfaces(self, iflist, brlist)
153         local iface
154         for iface, _ in pairs(ifs) do
155                 iflist[iface] = ifs[iface]
156         end
157 end
158
159 function ignore_interface(self, iface)
160         if ifs and ifs[iface] then
161                 return false
162         else
163                 return iwi.type(iface) and true or false
164         end
165 end
166
167 function add_interface(self, net, iface)
168         if ifs and ifs[iface] and ifs[iface].sid then
169                 ub.uci:set("wireless", ifs[iface].sid, "network", net:name())
170                 ifs[iface].network = net:name()
171                 return true
172         end
173
174         return false
175 end
176
177 function del_interface(self, net, iface)
178         if ifs and ifs[iface] and ifs[iface].sid then
179                 ub.uci:delete("wireless", ifs[iface].sid, "network")
180                 --return true
181         end
182
183         return false
184 end
185
186
187 device = ub:section("wifi-device")
188 device:property("type")
189 device:property("channel")
190 device:property_bool("disabled")
191
192 function device.name(self)
193         return self.sid
194 end
195
196 function device.is_up(self)
197         local rv = false
198
199         if not self:disabled() then
200                 st:foreach("wireless", "wifi-iface",
201                         function(s)
202                                 if s.device == self:name() and s.up == "1" then
203                                         rv = true
204                                         return false
205                                 end
206                         end)
207         end
208
209         return rv
210 end
211
212 function device.get_networks(self)
213         local nets = { }
214
215         ub.uci:foreach("wireless", "wifi-iface",
216                 function(s)
217                         if s.device == self:name() then
218                                 nets[#nets+1] = network(s['.name'])
219                         end
220                 end)
221
222         return nets
223 end
224
225
226 network = ub:section("wifi-iface")
227 network:property("mode")
228 network:property("ssid")
229 network:property("bssid")
230 network:property("network")
231
232 function network._init(self, sid)
233         local count = 0
234
235         local parent_dev = st:get("wireless", sid, "device")
236                 or ub.uci:get("wireless", sid, "device")
237
238         local dev = st:get("wireless", sid, "ifname")
239                 or parent_dev
240
241         if dev then
242                 ub.uci:foreach("wireless", "wifi-iface",
243                         function(s)
244                                 count = count + 1
245                                 if s['.name'] == sid then
246                                         self.id = "%s.network%d" %{ parent_dev, count }
247
248                                         local wtype = iwi.type(dev)
249                                         if dev and wtype then
250                                                 self.winfo = iwi[wtype]
251                                                 self.wdev  = dev
252                                         end
253                                 end
254                         end)
255         end
256 end
257
258 function network.name(self)
259         return self.id
260 end
261
262 function network.ifname(self)
263         return self.wdev
264 end
265
266 function network.get_device(self)
267         if self.device then
268                 return device(self.device)
269         end
270 end
271
272 function network.is_up(self)
273         return (st:get("wireless", self.sid, "up") == "1")
274 end
275
276 function network.active_mode(self)
277         local m = self.winfo and self.winfo.mode(self.wdev)
278         if not m then
279                 m = self:mode()
280                 if     m == "ap"      then m = "AP"
281                 elseif m == "sta"     then m = "Client"
282                 elseif m == "adhoc"   then m = "Ad-Hoc"
283                 elseif m == "mesh"    then m = "Mesh"
284                 elseif m == "monitor" then m = "Monitor"
285                 end
286         end
287         return m or "Client"
288 end
289
290 function network.active_mode_i18n(self)
291         return i18n.translate(self:active_mode())
292 end
293
294 function network.active_ssid(self)
295         return self.winfo and self.winfo.ssid(self.wdev) or
296                 self:ssid()
297 end
298
299 function network.active_bssid(self)
300         return self.winfo and self.winfo.bssid(self.wdev) or
301                 self:bssid() or "00:00:00:00:00:00"
302 end
303
304 function network.active_encryption(self)
305         return self.winfo and self.winfo.enctype(self.wdev) or "-"
306 end
307
308 function network.assoclist(self)
309         return self.winfo and self.winfo.assoclist(self.wdev) or { }
310 end
311
312 function network.frequency(self)
313         local freq = self.winfo and self.winfo.frequency(self.wdev)
314         return freq and freq > 0 and "%.03f" % (freq / 1000)
315 end
316
317 function network.bitrate(self)
318         local rate = self.winfo and self.winfo.bitrate(self.wdev)
319         return rate and rate > 0 and (rate / 1000)
320 end
321
322 function network.channel(self)
323         return self.winfo and self.winfo.channel(self.wdev)
324 end
325
326 function network.signal(self)
327         return self.winfo and self.winfo.signal(self.wdev) or 0
328 end
329
330 function network.noise(self)
331         return self.winfo and self.winfo.noise(self.wdev) or 0
332 end
333
334 function network.signal_level(self, s, n)
335         if self:active_bssid() ~= "00:00:00:00:00:00" then
336                 local signal = s or self:signal()
337                 local noise  = n or self:noise()
338
339                 if signal < 0 and noise < 0 then
340                         local snr = -1 * (noise - signal)
341                         return math.floor(snr / 5)
342                 else
343                         return 0
344                 end
345         else
346                 return -1
347         end
348 end
349
350 function network.signal_percent(self)
351         local qc = self.winfo and
352                 self.winfo.quality(self.wdev) or 0
353
354         local qm = self.winfo and
355                 self.winfo.quality_max(self.wdev) or 0
356
357         if qc > 0 and qm > 0 then
358                 return math.floor((100 / qm) * qc)
359         else
360                 return 0
361         end
362 end
363