modules/admin-full: fix frequency display on index status page
[project/luci.git] / modules / admin-full / luasrc / view / admin_status / index.htm
1 <%#
2 LuCI - Lua Configuration Interface
3 Copyright 2008 Steven Barth <steven@midlink.org>
4 Copyright 2008-2011 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 $Id$
13
14 -%>
15
16 <%
17         require "luci.fs"
18         require "luci.tools.status"
19
20         local has_ipv6 = luci.fs.access("/proc/net/ipv6_route")
21         local has_dhcp = luci.fs.access("/etc/config/dhcp")
22         local has_wifi = luci.fs.stat("/etc/config/wireless")
23               has_wifi = has_wifi and has_wifi.size > 0
24
25         if luci.http.formvalue("status") == "1" then
26                 local ntm = require "luci.model.network".init()
27                 local wan = ntm:get_wannet()
28                 local wan6 = ntm:get_wan6net()
29
30                 local _, _, memtotal, memcached, membuffers, memfree = luci.sys.sysinfo()
31
32                 local conn_count = tonumber((
33                         luci.sys.exec("wc -l /proc/net/nf_conntrack") or
34                         luci.sys.exec("wc -l /proc/net/ip_conntrack") or
35                         ""):match("%d+")) or 0
36
37                 local conn_max = tonumber((
38                         luci.sys.exec("sysctl net.nf_conntrack_max") or
39                         luci.sys.exec("sysctl net.ipv4.netfilter.ip_conntrack_max") or
40                         ""):match("%d+")) or 4096
41
42                 local rv = {
43                         uptime     = luci.sys.uptime(),
44                         localtime  = os.date(),
45                         loadavg    = { luci.sys.loadavg() },
46                         memtotal   = memtotal,
47                         memcached  = memcached,
48                         membuffers = membuffers,
49                         memfree    = memfree,
50                         connmax    = conn_max,
51                         conncount  = conn_count,
52                         leases     = luci.tools.status.dhcp_leases(),
53                         wifinets   = luci.tools.status.wifi_networks()
54                 }
55
56                 if wan then
57                         rv.wan = {
58                                 ipaddr  = wan:ipaddr(),
59                                 gwaddr  = wan:gwaddr(),
60                                 netmask = wan:netmask(),
61                                 dns     = wan:dnsaddrs(),
62                                 expires = wan:expires(),
63                                 uptime  = wan:uptime(),
64                                 proto   = wan:proto(),
65                                 ifname  = wan:ifname(),
66                                 link    = wan:adminlink()
67                         }
68                 end
69
70                 if wan6 then
71                         rv.wan6 = {
72                                 ip6addr = wan6:ip6addr(),
73                                 gw6addr = wan6:gw6addr(),
74                                 dns     = wan6:dns6addrs(),
75                                 uptime  = wan6:uptime(),
76                                 ifname  = wan6:ifname(),
77                                 link    = wan6:adminlink()
78                         }
79                 end
80
81                 luci.http.prepare_content("application/json")
82                 luci.http.write_json(rv)
83
84                 return
85         end
86
87         local system, model = luci.sys.sysinfo()
88 -%>
89
90 <%+header%>
91
92 <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
93 <script type="text/javascript">//<![CDATA[
94         function progressbar(v, m)
95         {
96                 var vn = parseInt(v) || 0;
97                 var mn = parseInt(m) || 100;
98                 var pc = Math.floor((100 / mn) * vn);
99
100                 return String.format(
101                         '<div style="width:200px; position:relative; border:1px solid #999999">' +
102                                 '<div style="background-color:#CCCCCC; width:%d%%; height:15px">' +
103                                         '<div style="position:absolute; left:0; top:0; text-align:center; width:100%%; color:#000000">' +
104                                                 '<small>%s / %s (%d%%)</small>' +
105                                         '</div>' +
106                                 '</div>' +
107                         '</div>', pc, v, m, pc
108                 );
109         }
110
111         var wifidevs = <%=luci.http.write_json(netdevs)%>;
112         var arptable = <%=luci.http.write_json(arpcache)%>;
113
114         XHR.poll(5, '<%=REQUEST_URI%>', { status: 1 },
115                 function(x, info)
116                 {
117                         var si = document.getElementById('wan4_i');
118                         var ss = document.getElementById('wan4_s');
119                         var ifc = info.wan;
120
121                         if (ifc && ifc.ifname && ifc.proto != 'none')
122                         {
123                                 var s = String.format(
124                                         '<strong><%:Type%>: </strong>%s<br />' +
125                                         '<strong><%:Address%>: </strong>%s<br />' +
126                                         '<strong><%:Netmask%>: </strong>%s<br />' +
127                                         '<strong><%:Gateway%>: </strong>%s<br />',
128                                                 ifc.proto,
129                                                 (ifc.ipaddr) ? ifc.ipaddr : '0.0.0.0',
130                                                 (ifc.netmask && ifc.netmask != ifc.ipaddr) ? ifc.netmask : '255.255.255.255',
131                                                 (ifc.gwaddr) ? ifc.gwaddr : '0.0.0.0'
132                                 );
133
134                                 for (var i = 0; i < ifc.dns.length; i++)
135                                 {
136                                         s += String.format(
137                                                 '<strong><%:DNS%> %d: </strong>%s<br />',
138                                                 i + 1, ifc.dns[i]
139                                         );
140                                 }
141
142                                 if (ifc.expires > -1)
143                                 {
144                                         s += String.format(
145                                                 '<strong><%:Expires%>: </strong>%t<br />',
146                                                 ifc.expires
147                                         );
148                                 }
149
150                                 if (ifc.uptime > 0)
151                                 {
152                                         s += String.format(
153                                                 '<strong><%:Connected%>: </strong>%t<br />',
154                                                 ifc.uptime
155                                         );
156                                 }
157
158                                 ss.innerHTML = String.format('<small>%s</small>', s);
159                                 si.innerHTML = String.format(
160                                         '<img src="<%=resource%>/icons/ethernet.png" />' +
161                                         '<br /><small><a href="%s">%s</a></small>',
162                                                 ifc.link, ifc.ifname
163                                 );
164                         }
165                         else
166                         {
167                                 si.innerHTML = '<img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small>';
168                                 ss.innerHTML = '<em><%:Not connected%></em>';
169                         }
170
171                         <% if has_ipv6 then %>
172                         var si6 = document.getElementById('wan6_i');
173                         var ss6 = document.getElementById('wan6_s');
174                         var ifc6 = info.wan6;
175
176                         if (ifc6 && ifc6.ifname && ifc6.proto != 'none')
177                         {
178                                 var s = String.format(
179                                         '<strong><%:Address%>: </strong>%s<br />' +
180                                         '<strong><%:Gateway%>: </strong>%s<br />',
181                                                 (ifc6.ip6addr) ? ifc6.ip6addr : '::',
182                                                 (ifc6.gw6addr) ? ifc6.gw6addr : '::'
183                                 );
184
185                                 for (var i = 0; i < ifc6.dns.length; i++)
186                                 {
187                                         s += String.format(
188                                                 '<strong><%:DNS%> %d: </strong>%s<br />',
189                                                 i + 1, ifc6.dns[i]
190                                         );
191                                 }
192
193                                 if (ifc6.uptime > 0)
194                                 {
195                                         s += String.format(
196                                                 '<strong><%:Connected%>: </strong>%t<br />',
197                                                 ifc6.uptime
198                                         );
199                                 }
200
201                                 ss6.innerHTML = String.format('<small>%s</small>', s);
202                                 si6.innerHTML = String.format(
203                                         '<img src="<%=resource%>/icons/ethernet.png" />' +
204                                         '<br /><small><a href="%s">%s</a></small>',
205                                                 ifc6.link, ifc6.ifname
206                                 );
207                         }
208                         else
209                         {
210                                 si6.innerHTML = '<img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small>';
211                                 ss6.innerHTML = '<em><%:Not connected%></em>';
212                         }
213                         <% end %>
214
215                         <% if has_dhcp then %>
216                         var ls = document.getElementById('lease_status_table');
217                         if (ls)
218                         {
219                                 /* clear all rows */
220                                 while( ls.rows.length > 1 )
221                                         ls.rows[0].parentNode.deleteRow(1);
222
223                                 for( var i = 0; i < info.leases.length; i++ )
224                                 {
225                                         var timestr;
226
227                                         if (info.leases[i].expires <= 0)
228                                                 timestr = '<em><%:expired%></em>';
229                                         else
230                                                 timestr = String.format('%t', info.leases[i].expires);
231
232                                         var tr = ls.rows[0].parentNode.insertRow(-1);
233                                                 tr.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
234
235                                         tr.insertCell(-1).innerHTML = info.leases[i].hostname ? info.leases[i].hostname : '?';
236                                         tr.insertCell(-1).innerHTML = info.leases[i].ipaddr;
237                                         tr.insertCell(-1).innerHTML = info.leases[i].macaddr;
238                                         tr.insertCell(-1).innerHTML = timestr;
239                                 }
240
241                                 if( ls.rows.length == 1 )
242                                 {
243                                         var tr = ls.rows[0].parentNode.insertRow(-1);
244                                                 tr.className = 'cbi-section-table-row';
245
246                                         var td = tr.insertCell(-1);
247                                                 td.colSpan = 4;
248                                                 td.innerHTML = '<em><br /><%:There are no active leases.%></em>';
249                                 }
250                         }
251                         <% end %>
252
253                         <% if has_wifi then %>
254                         var assoclist = [ ];
255
256                         var ws = document.getElementById('wifi_status_table');
257                         if (ws)
258                         {
259                                 var wsbody = ws.rows[0].parentNode;
260                                 while (ws.rows.length > 0)
261                                         wsbody.deleteRow(0);
262
263                                 for (var didx = 0; didx < info.wifinets.length; didx++)
264                                 {
265                                         var dev = info.wifinets[didx];
266
267                                         var tr = wsbody.insertRow(-1);
268                                         var td;
269
270                                         td = tr.insertCell(-1);
271                                         td.width     = "33%";
272                                         td.innerHTML = dev.name;
273                                         td.style.verticalAlign = "top";
274
275                                         td = tr.insertCell(-1);
276
277                                         var s = '';
278
279                                         for (var nidx = 0; nidx < dev.networks.length; nidx++)
280                                         {
281                                                 var net = dev.networks[nidx];
282                                                 var is_assoc = (net.bssid != '00:00:00:00:00:00' && net.channel);
283
284                                                 var icon;
285                                                 if (!is_assoc)
286                                                         icon = "<%=resource%>/icons/signal-none.png";
287                                                 else if (net.quality == 0)
288                                                         icon = "<%=resource%>/icons/signal-0.png";
289                                                 else if (net.quality < 25)
290                                                         icon = "<%=resource%>/icons/signal-0-25.png";
291                                                 else if (net.quality < 50)
292                                                         icon = "<%=resource%>/icons/signal-25-50.png";
293                                                 else if (net.quality < 75)
294                                                         icon = "<%=resource%>/icons/signal-50-75.png";
295                                                 else
296                                                         icon = "<%=resource%>/icons/signal-75-100.png";
297
298                                                 s += String.format(
299                                                         '<table><tr><td style="text-align:center; width:32px; padding:3px">' +
300                                                                 '<img src="%s" title="<%:Signal%>: %d dBm / <%:Noise%>: %d dBm" />' +
301                                                                 '<br /><small>%d%%</small>' +
302                                                         '</td><td style="text-align:left; padding:3px"><small>' +
303                                                                 '<strong><%:SSID%>:</strong> <a href="%s">%h</a><br />' +
304                                                                 '<strong><%:Mode%>:</strong> %s<br />' +
305                                                                 '<strong><%:Channel%>:</strong> %d (%.3f GHz)<br />' +
306                                                                 '<strong><%:Bitrate%>:</strong> %s Mb/s<br />',
307                                                                 icon, net.signal, net.noise,
308                                                                 net.quality,
309                                                                 net.link, net.ssid,
310                                                                 net.mode,
311                                                                 net.channel, net.frequency,
312                                                                 net.bitrate || '?'
313                                                 );
314
315                                                 if (is_assoc)
316                                                 {
317                                                         s += String.format(
318                                                                 '<strong><%:BSSID%>:</strong> %s<br />' +
319                                                                 '<strong><%:Encryption%>:</strong> %s',
320                                                                         net.bssid,
321                                                                         net.encryption
322                                                         );
323                                                 }
324                                                 else
325                                                 {
326                                                         s += '<em><%:Wireless is disabled or not associated%></em>';
327                                                 }
328
329                                                 s += '</small></td></tr></table>';
330
331                                                 for (var bssid in net.assoclist)
332                                                 {
333                                                         assoclist.push({
334                                                                 bssid:    bssid,
335                                                                 signal:   net.assoclist[bssid].signal,
336                                                                 noise:    net.assoclist[bssid].noise,
337                                                                 rx_rate:  net.assoclist[bssid].rx_rate,
338                                                                 rx_mcs:   net.assoclist[bssid].rx_mcs,
339                                                                 rx_40mhz: net.assoclist[bssid].rx_40mhz,
340                                                                 tx_rate:  net.assoclist[bssid].tx_rate,
341                                                                 tx_mcs:   net.assoclist[bssid].tx_mcs,
342                                                                 tx_40mhz: net.assoclist[bssid].tx_40mhz,
343                                                                 link:     net.link,
344                                                                 name:     net.name
345                                                         });
346                                                 }
347                                         }
348
349                                         if (!s)
350                                                 s = '<em><%:No information available%></em>';
351
352                                         td.innerHTML = s;
353                                 }
354                         }
355
356                         var ac = document.getElementById('wifi_assoc_table');
357                         if (ac)
358                         {
359                                 /* clear all rows */
360                                 while( ac.rows.length > 1 )
361                                         ac.rows[0].parentNode.deleteRow(1);
362
363                                 assoclist.sort(function(a, b) {
364                                         return (a.name == b.name)
365                                                 ? (a.bssid < b.bssid)
366                                                 : (a.name  > b.name )
367                                         ;
368                                 });
369
370                                 for( var i = 0; i < assoclist.length; i++ )
371                                 {
372                                         var tr = ac.rows[0].parentNode.insertRow(-1);
373                                                 tr.className = 'cbi-section-table-row cbi-rowstyle-' + (1 + (i % 2));
374
375                                         var icon;
376                                         var q = (-1 * (assoclist[i].noise - assoclist[i].signal)) / 5;
377                                         if (q < 1)
378                                                 icon = "<%=resource%>/icons/signal-0.png";
379                                         else if (q < 2)
380                                                 icon = "<%=resource%>/icons/signal-0-25.png";
381                                         else if (q < 3)
382                                                 icon = "<%=resource%>/icons/signal-25-50.png";
383                                         else if (q < 4)
384                                                 icon = "<%=resource%>/icons/signal-50-75.png";
385                                         else
386                                                 icon = "<%=resource%>/icons/signal-75-100.png";
387
388                                         tr.insertCell(-1).innerHTML = String.format(
389                                                 '<img src="%s" title="<%:Signal%>: %d dBm / <%:Noise%>: %d dBm" />',
390                                                 icon, assoclist[i].signal, assoclist[i].noise
391                                         );
392
393                                         tr.insertCell(-1).innerHTML = assoclist[i].bssid;
394
395                                         tr.insertCell(-1).innerHTML = String.format(
396                                                 '<a href="%s">%h</a>',
397                                                         assoclist[i].link,
398                                                         assoclist[i].name
399                                         );
400
401                                         tr.insertCell(-1).innerHTML = String.format('%d dBm', assoclist[i].signal);
402                                         tr.insertCell(-1).innerHTML = String.format('%d dBm', assoclist[i].noise);
403
404                                         tr.insertCell(-1).innerHTML = (assoclist[i].rx_mcs > -1)
405                                                 ? String.format('%.1f Mbit/s, MCS %d, %dMHz', assoclist[i].rx_rate / 1000, assoclist[i].rx_mcs, assoclist[i].rx_40mhz ? 40 : 20)
406                                                 : String.format('%.1f Mbit/s', assoclist[i].rx_rate / 1000)
407                                         ;
408
409                                         tr.insertCell(-1).innerHTML = (assoclist[i].tx_mcs > -1)
410                                                 ? String.format('%.1f Mbit/s, MCS %d, %dMHz', assoclist[i].tx_rate / 1000, assoclist[i].tx_mcs, assoclist[i].tx_40mhz ? 40 : 20)
411                                                 : String.format('%.1f Mbit/s', assoclist[i].tx_rate / 1000)
412                                         ;
413                                 }
414
415                                 if (ac.rows.length == 1)
416                                 {
417                                         var tr = ac.rows[0].parentNode.insertRow(-1);
418                                                 tr.className = 'cbi-section-table-row';
419
420                                         var td = tr.insertCell(-1);
421                                                 td.colSpan = 7;
422                                                 td.innerHTML = '<br /><em><%:No information available%></em>';
423                                 }
424                         }
425                         <% end %>
426
427                         var e;
428
429                         if (e = document.getElementById('localtime'))
430                                 e.innerHTML = info.localtime;
431
432                         if (e = document.getElementById('uptime'))
433                                 e.innerHTML = String.format('%t', info.uptime);
434
435                         if (e = document.getElementById('loadavg'))
436                                 e.innerHTML = String.format('%.02f, %.02f, %.02f',
437                                         info.loadavg[0], info.loadavg[1], info.loadavg[2]);
438
439                         if (e = document.getElementById('memtotal'))
440                                 e.innerHTML = progressbar(
441                                         (info.memfree + info.membuffers + info.memcached) + " kB",
442                                         info.memtotal + " kB"
443                                 );
444
445                         if (e = document.getElementById('memfree'))
446                                 e.innerHTML = progressbar(
447                                         info.memfree + " kB", info.memtotal + " kB"
448                                 );
449
450                         if (e = document.getElementById('memcache'))
451                                 e.innerHTML = progressbar(
452                                         info.memcached + " kB", info.memtotal + " kB"
453                                 );
454
455                         if (e = document.getElementById('membuff'))
456                                 e.innerHTML = progressbar(
457                                         info.membuffers + " kB", info.memtotal + " kB"
458                                 );
459
460                         if (e = document.getElementById('conns'))
461                                 e.innerHTML = progressbar(info.conncount, info.connmax);
462
463                 }
464         );
465 //]]></script>
466
467 <h2><a id="content" name="content"><%:Status%></a></h2>
468
469 <fieldset class="cbi-section">
470         <legend><%:System%></legend>
471
472         <table width="100%" cellspacing="10">
473                 <tr><td width="33%"><%:Router Name%></td><td><%=luci.sys.hostname() or "?"%></td></tr>
474                 <tr><td width="33%"><%:Router Model%></td><td><%=pcdata(model or "?")%></td></tr>
475                 <tr><td width="33%"><%:Firmware Version%></td><td>
476                         <%=pcdata(luci.version.distname)%> <%=pcdata(luci.version.distversion)%> /
477                         <%=pcdata(luci.version.luciname)%> (<%=pcdata(luci.version.luciversion)%>)
478                 </td></tr>
479                 <tr><td width="33%"><%:Kernel Version%></td><td><%=luci.sys.exec("uname -r")%></td></tr>
480                 <tr><td width="33%"><%:Local Time%></td><td id="localtime">-</td></tr>
481                 <tr><td width="33%"><%:Uptime%></td><td id="uptime">-</td></tr>
482                 <tr><td width="33%"><%:Load Average%></td><td id="loadavg">-</td></tr>
483         </table>
484 </fieldset>
485
486 <fieldset class="cbi-section">
487         <legend><%:Memory%></legend>
488
489         <table width="100%" cellspacing="10">
490                 <tr><td width="33%"><%:Total Available%></td><td id="memtotal">-</td></tr>
491                 <tr><td width="33%"><%:Free%></td><td id="memfree">-</td></tr>
492                 <tr><td width="33%"><%:Cached%></td><td id="memcache">-</td></tr>
493                 <tr><td width="33%"><%:Buffered%></td><td id="membuff">-</td></tr>
494         </table>
495 </fieldset>
496
497 <fieldset class="cbi-section">
498         <legend><%:Network%></legend>
499
500         <table width="100%" cellspacing="10">
501                 <tr><td width="33%" style="vertical-align:top"><%:IPv4 WAN Status%></td><td>
502                         <table><tr>
503                                 <td id="wan4_i" style="width:16px; text-align:center; padding:3px"><img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small></td>
504                                 <td id="wan4_s" style="vertical-align:middle; padding: 3px"><em><%:Collecting data...%></em></td>
505                         </tr></table>
506                 </td></tr>
507                 <% if has_ipv6 then %>
508                 <tr><td width="33%" style="vertical-align:top"><%:IPv6 WAN Status%></td><td>
509                         <table><tr>
510                                 <td id="wan6_i" style="width:16px; text-align:center; padding:3px"><img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small></td>
511                                 <td id="wan6_s" style="vertical-align:middle; padding: 3px"><em><%:Collecting data...%></em></td>
512                         </tr></table>
513                 </td></tr>
514                 <% end %>
515                 <tr><td width="33%"><%:Active Connections%></td><td id="conns">-</td></tr>
516         </table>
517 </fieldset>
518
519 <% if has_dhcp then %>
520 <fieldset class="cbi-section">
521         <legend><%:DHCP Leases%></legend>
522
523         <table class="cbi-section-table" id="lease_status_table">
524                 <tr class="cbi-section-table-titles">
525                         <th class="cbi-section-table-cell"><%:Hostname%></th>
526                         <th class="cbi-section-table-cell"><%:IPv4-Address%></th>
527                         <th class="cbi-section-table-cell"><%:MAC-Address%></th>
528                         <th class="cbi-section-table-cell"><%:Leasetime remaining%></th>
529                 </tr>
530                 <tr class="cbi-section-table-row">
531                         <td colspan="4"><em><br /><%:Collecting data...%></em></td>
532                 </tr>
533         </table>
534 </fieldset>
535 <% end %>
536
537 <% if has_wifi then %>
538 <fieldset class="cbi-section">
539         <legend><%:Wireless%></legend>
540
541         <table id="wifi_status_table" width="100%" cellspacing="10">
542                 <tr><td><em><%:Collecting data...%></em></td></tr>
543         </table>
544 </fieldset>
545
546 <fieldset class="cbi-section">
547         <legend><%:Associated Stations%></legend>
548
549         <table class="cbi-section-table" id="wifi_assoc_table">
550                 <tr class="cbi-section-table-titles">
551                         <th class="cbi-section-table-cell">&#160;</th>
552                         <th class="cbi-section-table-cell"><%:MAC-Address%></th>
553                         <th class="cbi-section-table-cell"><%:Network%></th>
554                         <th class="cbi-section-table-cell"><%:Signal%></th>
555                         <th class="cbi-section-table-cell"><%:Noise%></th>
556                         <th class="cbi-section-table-cell"><%:RX Rate%></th>
557                         <th class="cbi-section-table-cell"><%:TX Rate%></th>
558                 </tr>
559                 <tr class="cbi-section-table-row">
560                         <td colspan="7"><em><br /><%:Collecting data...%></em></td>
561                 </tr>
562         </table>
563 </fieldset>
564 <% end %>
565
566 <%-
567         require "luci.util"
568         require "nixio.fs"
569
570         local plugins = nixio.fs.dir(luci.util.libpath() .. "/view/admin_status/index")
571         if plugins then
572                 local inc
573                 for inc in plugins do
574                         if inc:match("%.htm$") then
575                                 include("admin_status/index/" .. inc:gsub("%.htm$", ""))
576                         end
577                 end
578         end
579 -%>
580
581 <%+footer%>