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