mod-admin-full: Add IPv6 Prefix Delegation information to Status Pages
[project/luci.git] / modules / luci-mod-admin-full / luasrc / view / admin_status / index.htm
1 <%#
2  Copyright 2008 Steven Barth <steven@midlink.org>
3  Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
4  Licensed to the public under the Apache License 2.0.
5 -%>
6
7 <%
8         local fs = require "nixio.fs"
9         local util = require "luci.util"
10         local stat = require "luci.tools.status"
11         local ver = require "luci.version"
12
13         local has_ipv6 = fs.access("/proc/net/ipv6_route")
14         local has_dhcp = fs.access("/etc/config/dhcp")
15         local has_wifi = ((fs.stat("/etc/config/wireless", "size") or 0) > 0)
16
17         local sysinfo = luci.util.ubus("system", "info") or { }
18         local boardinfo = luci.util.ubus("system", "board") or { }
19         local unameinfo = nixio.uname() or { }
20
21         local meminfo = sysinfo.memory or {
22                 total = 0,
23                 free = 0,
24                 buffered = 0,
25                 shared = 0
26         }
27
28         local swapinfo = sysinfo.swap or {
29                 total = 0,
30                 free = 0
31         }
32
33         local has_dsl = fs.access("/etc/init.d/dsl_control")
34
35         if luci.http.formvalue("status") == "1" then
36                 local ntm = require "luci.model.network".init()
37                 local wan = ntm:get_wannet()
38                 local wan6 = ntm:get_wan6net()
39
40                 local conn_count = tonumber((
41                         luci.sys.exec("wc -l /proc/net/nf_conntrack") or
42                         luci.sys.exec("wc -l /proc/net/ip_conntrack") or
43                         ""):match("%d+")) or 0
44
45                 local conn_max = tonumber((
46                         luci.sys.exec("sysctl net.nf_conntrack_max") or
47                         luci.sys.exec("sysctl net.ipv4.netfilter.ip_conntrack_max") or
48                         ""):match("%d+")) or 4096
49
50                 local rv = {
51                         uptime     = sysinfo.uptime or 0,
52                         localtime  = os.date(),
53                         loadavg    = sysinfo.load or { 0, 0, 0 },
54                         memory     = meminfo,
55                         swap       = swapinfo,
56                         connmax    = conn_max,
57                         conncount  = conn_count,
58                         leases     = stat.dhcp_leases(),
59                         leases6    = stat.dhcp6_leases(),
60                         wifinets   = stat.wifi_networks()
61                 }
62
63                 if wan then
64                         rv.wan = {
65                                 ipaddr  = wan:ipaddr(),
66                                 gwaddr  = wan:gwaddr(),
67                                 netmask = wan:netmask(),
68                                 dns     = wan:dnsaddrs(),
69                                 expires = wan:expires(),
70                                 uptime  = wan:uptime(),
71                                 proto   = wan:proto(),
72                                 ifname  = wan:ifname(),
73                                 link    = wan:adminlink()
74                         }
75                 end
76
77                 if wan6 then
78                         rv.wan6 = {
79                                 ip6addr   = wan6:ip6addr(),
80                                 gw6addr   = wan6:gw6addr(),
81                                 dns       = wan6:dns6addrs(),
82                                 ip6prefix = wan6:ip6prefix(),
83                                 uptime    = wan6:uptime(),
84                                 proto     = wan6:proto(),
85                                 ifname    = wan6:ifname(),
86                                 link      = wan6:adminlink()
87                         }
88                 end
89
90                 if has_dsl then
91                         local dsl_stat = luci.sys.exec("/etc/init.d/dsl_control lucistat")
92                         local dsl_func = loadstring(dsl_stat)
93                         if dsl_func then
94                                 rv.dsl = dsl_func()
95                         end
96                 end
97
98                 luci.http.prepare_content("application/json")
99                 luci.http.write_json(rv)
100
101                 return
102         elseif luci.http.formvalue("hosts") == "1" then
103                 luci.http.prepare_content("application/json")
104                 luci.http.write_json(luci.sys.net.host_hints())
105
106                 return
107         end
108 -%>
109
110 <%+header%>
111
112 <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
113 <script type="text/javascript">//<![CDATA[
114         function progressbar(v, m)
115         {
116                 var vn = parseInt(v) || 0;
117                 var mn = parseInt(m) || 100;
118                 var pc = Math.floor((100 / mn) * vn);
119
120                 return String.format(
121                         '<div style="width:200px; position:relative; border:1px solid #999999">' +
122                                 '<div style="background-color:#CCCCCC; width:%d%%; height:15px">' +
123                                         '<div style="position:absolute; left:0; top:0; text-align:center; width:100%%; color:#000000">' +
124                                                 '<small>%s / %s (%d%%)</small>' +
125                                         '</div>' +
126                                 '</div>' +
127                         '</div>', pc, v, m, pc
128                 );
129         }
130
131         function wifirate(bss, rx) {
132                 var p = rx ? 'rx_' : 'tx_',
133                     s = '%.1f <%:Mbit/s%>, %d<%:MHz%>'
134                                         .format(bss[p+'rate'] / 1000, bss[p+'mhz']),
135                     ht = bss[p+'ht'], vht = bss[p+'vht'],
136                         mhz = bss[p+'mhz'], nss = bss[p+'nss'],
137                         mcs = bss[p+'mcs'], sgi = bss[p+'short_gi'];
138
139                 if (ht || vht) {
140                         if (vht) s += ', VHT-MCS %d'.format(mcs);
141                         if (nss) s += ', VHT-NSS %d'.format(nss);
142                         if (ht)  s += ', MCS %s'.format(mcs);
143                         if (sgi) s += ', <%:Short GI%>';
144                 }
145
146                 return s;
147         }
148
149         function duid2mac(duid) {
150                 // DUID-LLT / Ethernet
151                 if (duid.length === 28 && duid.substr(0, 8) === '00010001')
152                         return duid.substr(16).replace(/(..)(?=..)/g, '$1:').toUpperCase();
153
154                 // DUID-LL / Ethernet
155                 if (duid.length === 24 && duid.substr(0, 8) === '00030001')
156                         return duid.substr(8).replace(/(..)(?=..)/g, '$1:').toUpperCase();
157
158                 return null;
159         }
160
161         var npoll = 1;
162         var hosts = <%=luci.http.write_json(luci.sys.net.host_hints())%>;
163
164         function updateHosts() {
165                 XHR.get('<%=REQUEST_URI%>', { hosts: 1 }, function(x, data) {
166                         hosts = data;
167                 });
168         }
169
170         XHR.poll(5, '<%=REQUEST_URI%>', { status: 1 },
171                 function(x, info)
172                 {
173                         if (!(npoll++ % 5))
174                                 updateHosts();
175
176                         var si = document.getElementById('wan4_i');
177                         var ss = document.getElementById('wan4_s');
178                         var ifc = info.wan;
179
180                         if (ifc && ifc.ifname && ifc.proto != 'none')
181                         {
182                                 var s = String.format(
183                                         '<strong><%:Type%>: </strong>%s<br />' +
184                                         '<strong><%:Address%>: </strong>%s<br />' +
185                                         '<strong><%:Netmask%>: </strong>%s<br />' +
186                                         '<strong><%:Gateway%>: </strong>%s<br />',
187                                                 ifc.proto,
188                                                 (ifc.ipaddr) ? ifc.ipaddr : '0.0.0.0',
189                                                 (ifc.netmask && ifc.netmask != ifc.ipaddr) ? ifc.netmask : '255.255.255.255',
190                                                 (ifc.gwaddr) ? ifc.gwaddr : '0.0.0.0'
191                                 );
192
193                                 for (var i = 0; i < ifc.dns.length; i++)
194                                 {
195                                         s += String.format(
196                                                 '<strong><%:DNS%> %d: </strong>%s<br />',
197                                                 i + 1, ifc.dns[i]
198                                         );
199                                 }
200
201                                 if (ifc.expires > -1)
202                                 {
203                                         s += String.format(
204                                                 '<strong><%:Expires%>: </strong>%t<br />',
205                                                 ifc.expires
206                                         );
207                                 }
208
209                                 if (ifc.uptime > 0)
210                                 {
211                                         s += String.format(
212                                                 '<strong><%:Connected%>: </strong>%t<br />',
213                                                 ifc.uptime
214                                         );
215                                 }
216
217                                 ss.innerHTML = String.format('<small>%s</small>', s);
218                                 si.innerHTML = String.format(
219                                         '<img src="<%=resource%>/icons/ethernet.png" />' +
220                                         '<br /><small><a href="%s">%s</a></small>',
221                                                 ifc.link, ifc.ifname
222                                 );
223                         }
224                         else
225                         {
226                                 si.innerHTML = '<img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small>';
227                                 ss.innerHTML = '<em><%:Not connected%></em>';
228                         }
229
230                         <% if has_ipv6 then %>
231                         var si6 = document.getElementById('wan6_i');
232                         var ss6 = document.getElementById('wan6_s');
233                         var ifc6 = info.wan6;
234
235                         if (ifc6 && ifc6.ifname && ifc6.proto != 'none')
236                         {
237                                 var s = String.format(
238                                         '<strong><%:Type%>: </strong>%s%s<br />',
239                                                 ifc6.proto, (ifc6.ip6prefix) ? '-pd' : ''
240                                 );
241                                 
242                                 if (!ifc6.ip6prefix)
243                                 {
244                                         s += String.format(
245                                                 '<strong><%:Address%>: </strong>%s<br />',
246                                                 (ifc6.ip6addr) ? ifc6.ip6addr : '::'
247                                         );
248                                 }
249                                 else
250                                 {
251                                         s += String.format(
252                                                 '<strong><%:Prefix Delegated%>: </strong>%s<br />',
253                                                 ifc6.ip6prefix
254                                         );
255                                         if (ifc6.ip6addr)
256                                         {
257                                                 s += String.format(
258                                                         '<strong><%:Address%>: </strong>%s<br />',
259                                                         ifc6.ip6addr
260                                                 );
261                                         }
262                                 }
263
264                                 s += String.format(
265                                         '<strong><%:Gateway%>: </strong>%s<br />',
266                                                 (ifc6.gw6addr) ? ifc6.gw6addr : '::'
267                                 );
268
269                                 for (var i = 0; i < ifc6.dns.length; i++)
270                                 {
271                                         s += String.format(
272                                                 '<strong><%:DNS%> %d: </strong>%s<br />',
273                                                 i + 1, ifc6.dns[i]
274                                         );
275                                 }
276
277                                 if (ifc6.uptime > 0)
278                                 {
279                                         s += String.format(
280                                                 '<strong><%:Connected%>: </strong>%t<br />',
281                                                 ifc6.uptime
282                                         );
283                                 }
284
285                                 ss6.innerHTML = String.format('<small>%s</small>', s);
286                                 si6.innerHTML = String.format(
287                                         '<img src="<%=resource%>/icons/ethernet.png" />' +
288                                         '<br /><small><a href="%s">%s</a></small>',
289                                                 ifc6.link, ifc6.ifname
290                                 );
291                         }
292                         else
293                         {
294                                 si6.innerHTML = '<img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small>';
295                                 ss6.innerHTML = '<em><%:Not connected%></em>';
296                         }
297                         <% end %>
298
299                         <% if has_dsl then %>
300                                 var dsl_i = document.getElementById('dsl_i');
301                                 var dsl_s = document.getElementById('dsl_s');
302
303                                 var s = String.format(
304                                         '<strong><%:Status%>: </strong>%s<br />' +
305                                         '<strong><%:Line State%>: </strong>%s [0x%x]<br />' +
306                                         '<strong><%:Line Mode%>: </strong>%s<br />' +
307                                         '<strong><%:Annex%>: </strong>%s<br />' +
308                                         '<strong><%:Profile%>: </strong>%s<br />' +
309                                         '<strong><%:Data Rate%>: </strong>%s/s / %s/s<br />' +
310                                         '<strong><%:Max. Attainable Data Rate (ATTNDR)%>: </strong>%s/s / %s/s<br />' +
311                                         '<strong><%:Latency%>: </strong>%s / %s<br />' +
312                                         '<strong><%:Line Attenuation (LATN)%>: </strong>%s dB / %s dB<br />' +
313                                         '<strong><%:Signal Attenuation (SATN)%>: </strong>%s dB / %s dB<br />' +
314                                         '<strong><%:Noise Margin (SNR)%>: </strong>%s dB / %s dB<br />' +
315                                         '<strong><%:Aggregate Transmit Power(ACTATP)%>: </strong>%s dB / %s dB<br />' +
316                                         '<strong><%:Forward Error Correction Seconds (FECS)%>: </strong>%s / %s<br />' +
317                                         '<strong><%:Errored seconds (ES)%>: </strong>%s / %s<br />' +
318                                         '<strong><%:Severely Errored Seconds (SES)%>: </strong>%s / %s<br />' +
319                                         '<strong><%:Loss of Signal Seconds (LOSS)%>: </strong>%s / %s<br />' +
320                                         '<strong><%:Unavailable Seconds (UAS)%>: </strong>%s / %s<br />' +
321                                         '<strong><%:Header Error Code Errors (HEC)%>: </strong>%s / %s<br />' +
322                                         '<strong><%:Non Pre-emtive CRC errors (CRC_P)%>: </strong>%s / %s<br />' +
323                                         '<strong><%:Pre-emtive CRC errors (CRCP_P)%>: </strong>%s / %s<br />' +
324                                         '<strong><%:Line Uptime%>: </strong>%s<br />' +
325                                         '<strong><%:ATU-C System Vendor ID%>: </strong>%s<br />' +
326                                         '<strong><%:Power Management Mode%>: </strong>%s<br />',
327                                                 info.dsl.line_state, info.dsl.line_state_detail,
328                                                 info.dsl.line_state_num,
329                                                 info.dsl.line_mode_s,
330                                                 info.dsl.annex_s,
331                                                 info.dsl.profile_s,
332                                                 info.dsl.data_rate_down_s, info.dsl.data_rate_up_s,
333                                                 info.dsl.max_data_rate_down_s, info.dsl.max_data_rate_up_s,
334                                                 info.dsl.latency_num_down, info.dsl.latency_num_up,
335                                                 info.dsl.line_attenuation_down, info.dsl.line_attenuation_up,
336                                                 info.dsl.signal_attenuation_down, info.dsl.signal_attenuation_up,
337                                                 info.dsl.noise_margin_down, info.dsl.noise_margin_up,
338                                                 info.dsl.actatp_down, info.dsl.actatp_up,
339                                                 info.dsl.errors_fec_near, info.dsl.errors_fec_far,
340                                                 info.dsl.errors_es_near, info.dsl.errors_es_far,
341                                                 info.dsl.errors_ses_near, info.dsl.errors_ses_far,
342                                                 info.dsl.errors_loss_near, info.dsl.errors_loss_far,
343                                                 info.dsl.errors_uas_near, info.dsl.errors_uas_far,
344                                                 info.dsl.errors_hec_near, info.dsl.errors_hec_far,
345                                                 info.dsl.errors_crc_p_near, info.dsl.errors_crc_p_far,
346                                                 info.dsl.errors_crcp_p_near, info.dsl.errors_crcp_p_far,
347                                                 info.dsl.line_uptime_s,
348                                                 info.dsl.atuc_vendor_id,
349                                                 info.dsl.power_mode_s
350                                 );
351
352                                 dsl_s.innerHTML = String.format('<small>%s</small>', s);
353                                 dsl_i.innerHTML = String.format(
354                                         '<img src="<%=resource%>/icons/ethernet.png" />' +
355                                         '<br /><small>DSL</small>'
356                                 );
357                         <% end %>
358
359                         <% if has_dhcp then %>
360                         var ls = document.getElementById('lease_status_table');
361                         if (ls)
362                         {
363                                 /* clear all rows */
364                                 while( ls.rows.length > 1 )
365                                         ls.rows[0].parentNode.deleteRow(1);
366
367                                 for( var i = 0; i < info.leases.length; i++ )
368                                 {
369                                         var timestr;
370
371                                         if (info.leases[i].expires === false)
372                                                 timestr = '<em><%:unlimited%></em>';
373                                         else if (info.leases[i].expires <= 0)
374                                                 timestr = '<em><%:expired%></em>';
375                                         else
376                                                 timestr = String.format('%t', info.leases[i].expires);
377
378                                         var tr = ls.rows[0].parentNode.insertRow(-1);
379                                                 tr.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
380
381                                         tr.insertCell(-1).innerHTML = info.leases[i].hostname ? info.leases[i].hostname : '?';
382                                         tr.insertCell(-1).innerHTML = info.leases[i].ipaddr;
383                                         tr.insertCell(-1).innerHTML = info.leases[i].macaddr;
384                                         tr.insertCell(-1).innerHTML = timestr;
385                                 }
386
387                                 if( ls.rows.length == 1 )
388                                 {
389                                         var tr = ls.rows[0].parentNode.insertRow(-1);
390                                                 tr.className = 'cbi-section-table-row';
391
392                                         var td = tr.insertCell(-1);
393                                                 td.colSpan = 4;
394                                                 td.innerHTML = '<em><br /><%:There are no active leases.%></em>';
395                                 }
396                         }
397
398                         var ls6 = document.getElementById('lease6_status_table');
399                         if (ls6 && info.leases6)
400                         {
401                                 ls6.parentNode.style.display = 'block';
402
403                                 /* clear all rows */
404                                 while( ls6.rows.length > 1 )
405                                         ls6.rows[0].parentNode.deleteRow(1);
406
407                                 for( var i = 0; i < info.leases6.length; i++ )
408                                 {
409                                         var timestr;
410
411                                         if (info.leases6[i].expires === false)
412                                                 timestr = '<em><%:unlimited%></em>';
413                                         else if (info.leases6[i].expires <= 0)
414                                                 timestr = '<em><%:expired%></em>';
415                                         else
416                                                 timestr = String.format('%t', info.leases6[i].expires);
417
418                                         var tr = ls6.rows[0].parentNode.insertRow(-1);
419                                                 tr.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
420
421                                         var host = hosts[duid2mac(info.leases6[i].duid)];
422                                         if (host)
423                                                 tr.insertCell(-1).innerHTML = String.format(
424                                                         '<div style="max-width:200px;overflow:hidden;text-overflow:ellipsis">%s</div>',
425                                                         ((host.name && (host.ipv4 || host.ipv6))
426                                                                 ? '%h (%s)'.format(host.name, host.ipv4 || host.ipv6)
427                                                                 : '%h'.format(host.name || host.ipv4 || host.ipv6)).nobr()
428                                                 );
429                                         else
430                                                 tr.insertCell(-1).innerHTML = info.leases6[i].hostname ? info.leases6[i].hostname : '?';
431
432                                         tr.insertCell(-1).innerHTML = info.leases6[i].ip6addr;
433                                         tr.insertCell(-1).innerHTML = info.leases6[i].duid;
434                                         tr.insertCell(-1).innerHTML = timestr;
435                                 }
436
437                                 if( ls6.rows.length == 1 )
438                                 {
439                                         var tr = ls6.rows[0].parentNode.insertRow(-1);
440                                                 tr.className = 'cbi-section-table-row';
441
442                                         var td = tr.insertCell(-1);
443                                                 td.colSpan = 4;
444                                                 td.innerHTML = '<em><br /><%:There are no active leases.%></em>';
445                                 }
446                         }
447                         <% end %>
448
449                         <% if has_wifi then %>
450                         var assoclist = [ ];
451
452                         var ws = document.getElementById('wifi_status_table');
453                         if (ws)
454                         {
455                                 var wsbody = ws.rows[0].parentNode;
456                                 while (ws.rows.length > 0)
457                                         wsbody.deleteRow(0);
458
459                                 for (var didx = 0; didx < info.wifinets.length; didx++)
460                                 {
461                                         var dev = info.wifinets[didx];
462
463                                         var tr = wsbody.insertRow(-1);
464                                         var td;
465
466                                         td = tr.insertCell(-1);
467                                         td.width     = "33%";
468                                         td.innerHTML = dev.name;
469                                         td.style.verticalAlign = "top";
470
471                                         td = tr.insertCell(-1);
472
473                                         var s = '';
474
475                                         for (var nidx = 0; nidx < dev.networks.length; nidx++)
476                                         {
477                                                 var net = dev.networks[nidx];
478                                                 var is_assoc = (net.bssid != '00:00:00:00:00:00' && net.channel && !net.disabled);
479
480                                                 var icon;
481                                                 if (!is_assoc)
482                                                         icon = "<%=resource%>/icons/signal-none.png";
483                                                 else if (net.quality == 0)
484                                                         icon = "<%=resource%>/icons/signal-0.png";
485                                                 else if (net.quality < 25)
486                                                         icon = "<%=resource%>/icons/signal-0-25.png";
487                                                 else if (net.quality < 50)
488                                                         icon = "<%=resource%>/icons/signal-25-50.png";
489                                                 else if (net.quality < 75)
490                                                         icon = "<%=resource%>/icons/signal-50-75.png";
491                                                 else
492                                                         icon = "<%=resource%>/icons/signal-75-100.png";
493
494                                                 s += String.format(
495                                                         '<table><tr><td style="text-align:center; width:32px; padding:3px">' +
496                                                                 '<img src="%s" title="<%:Signal%>: %d dBm / <%:Noise%>: %d dBm" />' +
497                                                                 '<br /><small>%d%%</small>' +
498                                                         '</td><td style="text-align:left; padding:3px"><small>' +
499                                                                 '<strong><%:SSID%>:</strong> <a href="%s">%h</a><br />' +
500                                                                 '<strong><%:Mode%>:</strong> %s<br />' +
501                                                                 '<strong><%:Channel%>:</strong> %d (%.3f <%:GHz%>)<br />' +
502                                                                 '<strong><%:Bitrate%>:</strong> %s <%:Mbit/s%><br />',
503                                                                 icon, net.signal, net.noise,
504                                                                 net.quality,
505                                                                 net.link, net.ssid || '?',
506                                                                 net.mode,
507                                                                 net.channel, net.frequency,
508                                                                 net.bitrate || '?'
509                                                 );
510
511                                                 if (is_assoc)
512                                                 {
513                                                         s += String.format(
514                                                                 '<strong><%:BSSID%>:</strong> %s<br />' +
515                                                                 '<strong><%:Encryption%>:</strong> %s',
516                                                                         net.bssid || '?',
517                                                                         net.encryption
518                                                         );
519                                                 }
520                                                 else
521                                                 {
522                                                         s += '<em><%:Wireless is disabled or not associated%></em>';
523                                                 }
524
525                                                 s += '</small></td></tr></table>';
526
527                                                 for (var bssid in net.assoclist)
528                                                 {
529                                                         var bss = net.assoclist[bssid];
530
531                                                         bss.bssid  = bssid;
532                                                         bss.link   = net.link;
533                                                         bss.name   = net.name;
534                                                         bss.ifname = net.ifname;
535                                                         bss.radio  = dev.name;
536
537                                                         assoclist.push(bss);
538                                                 }
539                                         }
540
541                                         if (!s)
542                                                 s = '<em><%:No information available%></em>';
543
544                                         td.innerHTML = s;
545                                 }
546                         }
547
548                         var ac = document.getElementById('wifi_assoc_table');
549                         if (ac)
550                         {
551                                 /* clear all rows */
552                                 while( ac.rows.length > 1 )
553                                         ac.rows[0].parentNode.deleteRow(1);
554
555                                 assoclist.sort(function(a, b) {
556                                         return (a.name == b.name)
557                                                 ? (a.bssid < b.bssid)
558                                                 : (a.name  > b.name )
559                                         ;
560                                 });
561
562                                 for( var i = 0; i < assoclist.length; i++ )
563                                 {
564                                         var tr = ac.rows[0].parentNode.insertRow(-1);
565                                                 tr.className = 'cbi-section-table-row cbi-rowstyle-' + (1 + (i % 2));
566
567                                         var icon;
568                                         var q = (-1 * (assoclist[i].noise - assoclist[i].signal)) / 5;
569                                         if (q < 1)
570                                                 icon = "<%=resource%>/icons/signal-0.png";
571                                         else if (q < 2)
572                                                 icon = "<%=resource%>/icons/signal-0-25.png";
573                                         else if (q < 3)
574                                                 icon = "<%=resource%>/icons/signal-25-50.png";
575                                         else if (q < 4)
576                                                 icon = "<%=resource%>/icons/signal-50-75.png";
577                                         else
578                                                 icon = "<%=resource%>/icons/signal-75-100.png";
579
580                                         tr.insertCell(-1).innerHTML = String.format(
581                                                 '<span class="ifacebadge" title="%q"><img src="<%=resource%>/icons/wifi.png" /> %h</span>',
582                                                 assoclist[i].radio, assoclist[i].ifname
583                                         );
584
585                                         tr.insertCell(-1).innerHTML = String.format(
586                                                 '<a href="%s">%s</a>',
587                                                         assoclist[i].link,
588                                                         '%h'.format(assoclist[i].name).nobr()
589                                         );
590
591                                         tr.insertCell(-1).innerHTML = assoclist[i].bssid;
592
593                                         var host = hosts[assoclist[i].bssid];
594                                         if (host)
595                                                 tr.insertCell(-1).innerHTML = String.format(
596                                                         '<div style="max-width:200px;overflow:hidden;text-overflow:ellipsis">%s</div>',
597                                                         ((host.name && (host.ipv4 || host.ipv6))
598                                                                 ? '%h (%s)'.format(host.name, host.ipv4 || host.ipv6)
599                                                                 : '%h'.format(host.name || host.ipv4 || host.ipv6)).nobr()
600                                                 );
601                                         else
602                                                 tr.insertCell(-1).innerHTML = '?';
603
604                                         tr.insertCell(-1).innerHTML = String.format(
605                                                 '<span class="ifacebadge" title="<%:Signal%>: %d <%:dBm%> / <%:Noise%>: %d <%:dBm%> / <%:SNR%>: %d"><img src="%s" /> %d / %d <%:dBm%></span>',
606                                                 assoclist[i].signal, assoclist[i].noise, assoclist[i].signal - assoclist[i].noise,
607                                                 icon,
608                                                 assoclist[i].signal, assoclist[i].noise
609                                         );
610
611                                         tr.insertCell(-1).innerHTML = wifirate(assoclist[i], true).nobr() + '<br />' + wifirate(assoclist[i], false).nobr();
612                                 }
613
614                                 if (ac.rows.length == 1)
615                                 {
616                                         var tr = ac.rows[0].parentNode.insertRow(-1);
617                                                 tr.className = 'cbi-section-table-row';
618
619                                         var td = tr.insertCell(-1);
620                                                 td.colSpan = 7;
621                                                 td.innerHTML = '<br /><em><%:No information available%></em>';
622                                 }
623                         }
624                         <% end %>
625
626                         var e;
627
628                         if (e = document.getElementById('localtime'))
629                                 e.innerHTML = info.localtime;
630
631                         if (e = document.getElementById('uptime'))
632                                 e.innerHTML = String.format('%t', info.uptime);
633
634                         if (e = document.getElementById('loadavg'))
635                                 e.innerHTML = String.format(
636                                         '%.02f, %.02f, %.02f',
637                                         info.loadavg[0] / 65535.0,
638                                         info.loadavg[1] / 65535.0,
639                                         info.loadavg[2] / 65535.0
640                                 );
641
642                         if (e = document.getElementById('memtotal'))
643                                 e.innerHTML = progressbar(
644                                         ((info.memory.free + info.memory.buffered) / 1024) + " <%:kB%>",
645                                         (info.memory.total / 1024) + " <%:kB%>"
646                                 );
647
648                         if (e = document.getElementById('memfree'))
649                                 e.innerHTML = progressbar(
650                                         (info.memory.free / 1024) + " <%:kB%>",
651                                         (info.memory.total / 1024) + " <%:kB%>"
652                                 );
653
654                         if (e = document.getElementById('membuff'))
655                                 e.innerHTML = progressbar(
656                                         (info.memory.buffered / 1024) + " <%:kB%>",
657                                         (info.memory.total / 1024) + " <%:kB%>"
658                                 );
659
660                         if (e = document.getElementById('swaptotal'))
661                                 e.innerHTML = progressbar(
662                                         (info.swap.free / 1024) + " <%:kB%>",
663                                         (info.swap.total / 1024) + " <%:kB%>"
664                                 );
665
666                         if (e = document.getElementById('swapfree'))
667                                 e.innerHTML = progressbar(
668                                         (info.swap.free / 1024) + " <%:kB%>",
669                                         (info.swap.total / 1024) + " <%:kB%>"
670                                 );
671
672                         if (e = document.getElementById('conns'))
673                                 e.innerHTML = progressbar(info.conncount, info.connmax);
674
675                 }
676         );
677 //]]></script>
678
679 <h2 name="content"><%:Status%></h2>
680
681 <fieldset class="cbi-section">
682         <legend><%:System%></legend>
683
684         <table width="100%" cellspacing="10">
685                 <tr><td width="33%"><%:Hostname%></td><td><%=luci.sys.hostname() or "?"%></td></tr>
686                 <tr><td width="33%"><%:Model%></td><td><%=pcdata(boardinfo.model or boardinfo.system or "?")%></td></tr>
687                 <tr><td width="33%"><%:Firmware Version%></td><td>
688                         <%=pcdata(ver.distname)%> <%=pcdata(ver.distversion)%> /
689                         <%=pcdata(ver.luciname)%> (<%=pcdata(ver.luciversion)%>)
690                 </td></tr>
691                 <tr><td width="33%"><%:Kernel Version%></td><td><%=unameinfo.release or "?"%></td></tr>
692                 <tr><td width="33%"><%:Local Time%></td><td id="localtime">-</td></tr>
693                 <tr><td width="33%"><%:Uptime%></td><td id="uptime">-</td></tr>
694                 <tr><td width="33%"><%:Load Average%></td><td id="loadavg">-</td></tr>
695         </table>
696 </fieldset>
697
698 <fieldset class="cbi-section">
699         <legend><%:Memory%></legend>
700
701         <table width="100%" cellspacing="10">
702                 <tr><td width="33%"><%:Total Available%></td><td id="memtotal">-</td></tr>
703                 <tr><td width="33%"><%:Free%></td><td id="memfree">-</td></tr>
704                 <tr><td width="33%"><%:Buffered%></td><td id="membuff">-</td></tr>
705         </table>
706 </fieldset>
707
708 <% if swapinfo.total > 0 then %>
709 <fieldset class="cbi-section">
710         <legend><%:Swap%></legend>
711
712         <table width="100%" cellspacing="10">
713                 <tr><td width="33%"><%:Total Available%></td><td id="swaptotal">-</td></tr>
714                 <tr><td width="33%"><%:Free%></td><td id="swapfree">-</td></tr>
715         </table>
716 </fieldset>
717 <% end %>
718
719 <fieldset class="cbi-section">
720         <legend><%:Network%></legend>
721
722         <table width="100%" cellspacing="10">
723                 <tr><td width="33%" style="vertical-align:top"><%:IPv4 WAN Status%></td><td>
724                         <table><tr>
725                                 <td id="wan4_i" style="width:16px; text-align:center; padding:3px"><img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small></td>
726                                 <td id="wan4_s" style="vertical-align:middle; padding: 3px"><em><%:Collecting data...%></em></td>
727                         </tr></table>
728                 </td></tr>
729                 <% if has_ipv6 then %>
730                 <tr><td width="33%" style="vertical-align:top"><%:IPv6 WAN Status%></td><td>
731                         <table><tr>
732                                 <td id="wan6_i" style="width:16px; text-align:center; padding:3px"><img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small></td>
733                                 <td id="wan6_s" style="vertical-align:middle; padding: 3px"><em><%:Collecting data...%></em></td>
734                         </tr></table>
735                 </td></tr>
736                 <% end %>
737                 <tr><td width="33%"><%:Active Connections%></td><td id="conns">-</td></tr>
738         </table>
739 </fieldset>
740
741 <% if has_dhcp then %>
742 <fieldset class="cbi-section">
743         <legend><%:DHCP Leases%></legend>
744
745         <table class="cbi-section-table" id="lease_status_table">
746                 <tr class="cbi-section-table-titles">
747                         <th class="cbi-section-table-cell"><%:Hostname%></th>
748                         <th class="cbi-section-table-cell"><%:IPv4-Address%></th>
749                         <th class="cbi-section-table-cell"><%:MAC-Address%></th>
750                         <th class="cbi-section-table-cell"><%:Leasetime remaining%></th>
751                 </tr>
752                 <tr class="cbi-section-table-row">
753                         <td colspan="4"><em><br /><%:Collecting data...%></em></td>
754                 </tr>
755         </table>
756 </fieldset>
757
758 <fieldset class="cbi-section" style="display:none">
759         <legend><%:DHCPv6 Leases%></legend>
760
761         <table class="cbi-section-table" id="lease6_status_table">
762                 <tr class="cbi-section-table-titles">
763                         <th class="cbi-section-table-cell"><%:Host%></th>
764                         <th class="cbi-section-table-cell"><%:IPv6-Address%></th>
765                         <th class="cbi-section-table-cell"><%:DUID%></th>
766                         <th class="cbi-section-table-cell"><%:Leasetime remaining%></th>
767                 </tr>
768                 <tr class="cbi-section-table-row">
769                         <td colspan="4"><em><br /><%:Collecting data...%></em></td>
770                 </tr>
771         </table>
772 </fieldset>
773 <% end %>
774
775 <% if has_dsl then %>
776 <fieldset class="cbi-section">
777        <legend><%:DSL%></legend>
778        <table width="100%" cellspacing="10">
779                <tr><td width="33%" style="vertical-align:top"><%:DSL Status%></td><td>
780                        <table><tr>
781                                <td id="dsl_i" style="width:16px; text-align:center; padding:3px"><img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small></td>
782                                <td id="dsl_s" style="vertical-align:middle; padding: 3px"><em><%:Collecting data...%></em></td>
783                        </tr></table>
784                </td></tr>
785        </table>
786 </fieldset>
787 <% end %>
788
789 <% if has_wifi then %>
790 <fieldset class="cbi-section">
791         <legend><%:Wireless%></legend>
792
793         <table id="wifi_status_table" width="100%" cellspacing="10">
794                 <tr><td><em><%:Collecting data...%></em></td></tr>
795         </table>
796 </fieldset>
797
798 <fieldset class="cbi-section">
799         <legend><%:Associated Stations%></legend>
800
801         <table class="cbi-section-table valign-middle" id="wifi_assoc_table">
802                 <tr class="cbi-section-table-titles">
803                         <th class="cbi-section-table-cell">&#160;</th>
804                         <th class="cbi-section-table-cell"><%:Network%></th>
805                         <th class="cbi-section-table-cell"><%:MAC-Address%></th>
806                         <th class="cbi-section-table-cell"><%:Host%></th>
807                         <th class="cbi-section-table-cell"><%:Signal%> / <%:Noise%></th>
808                         <th class="cbi-section-table-cell"><%:RX Rate%> / <%:TX Rate%></th>
809                 </tr>
810                 <tr class="cbi-section-table-row">
811                         <td colspan="6"><em><br /><%:Collecting data...%></em></td>
812                 </tr>
813         </table>
814 </fieldset>
815 <% end %>
816
817 <%-
818         local incdir = util.libpath() .. "/view/admin_status/index/"
819         if fs.access(incdir) then
820                 local inc
821                 for inc in fs.dir(incdir) do
822                         if inc:match("%.htm$") then
823                                 include("admin_status/index/" .. inc:gsub("%.htm$", ""))
824                         end
825                 end
826         end
827 -%>
828
829 <%+footer%>