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