1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML
4.0//EN'
>
4 Copyright (C) 2006-2010 Jonathan Zarate
5 http://www.polarcloud.com/tomato/
7 For use with Tomato Firmware only.
8 No part of this file may be used without permission.
12 <meta http-equiv='content-type' content='text/html;charset=utf-
8'
>
13 <meta name='robots' content='noindex,nofollow'
>
14 <title>[<%
ident(); %>] Tools: Wireless Survey
</title>
15 <link rel='stylesheet' type='text/css' href='tomato.css'
>
16 <link rel='stylesheet' type='text/css' href='color.css'
>
17 <script type='text/javascript' src='tomato.js'
></script>
20 <style type='text/css'
>
36 border: 1px dashed
#f0f0f0;
50 <script type='text/javascript' src='debug.js'
></script>
52 <script type='text/javascript'
>
53 // <% nvram(''); %> // http_id
57 var dayOfWeek
= ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
59 Date
.prototype.toWHMS = function() {
60 return dayOfWeek
[this.getDay()] + ' ' + this.getHours() + ':' + this.getMinutes().pad(2)+ ':' + this.getSeconds().pad(2);
63 var sg
= new TomatoGrid();
65 sg
.sortCompare = function(a
, b
) {
66 var col
= this.sortColumn
;
67 var da
= a
.getRowData();
68 var db
= b
.getRowData();
73 r
= -cmpDate(da
.lastSeen
, db
.lastSeen
);
76 r
= cmpInt(da
.rssi
, db
.rssi
);
79 r
= cmpInt(da
.noise
, db
.noise
);
82 r
= cmpInt(da
.qual
, db
.qual
);
85 r
= cmpInt(da
.channel
, db
.channel
);
88 r
= cmpText(a
.cells
[col
].innerHTML
, b
.cells
[col
].innerHTML
);
90 if (r
== 0) r
= cmpText(da
.bssid
, db
.bssid
);
92 return this.sortAscending
? r
: -r
;
95 sg
.rateSorter = function(a
, b
)
102 sg
.populate = function()
104 var caps
= ['infra', 'adhoc', 'poll', 'pollreq', 'wep', 'shortpre', 'pbcc', 'agility', 'X', 'Y', 'shortslot'];
105 var ncap
= '802.11n';
108 var i
, j
, k
, t
, e
, s
;
110 if ((wlscandata
.length
== 1) && (!wlscandata
[0][0])) {
111 setMsg("error: " + wlscandata
[0][1]);
115 for (i
= 0; i
< wlscandata
.length
; ++i
) {
119 for (j
= 0; j
< entries
.length
; ++j
) {
120 if (entries
[j
].bssid
== s
[0]) {
128 e
.firstSeen
= new Date();
131 e
.lastSeen
= new Date();
141 for (j
= 0; j
< caps
.length
; ++j
) {
142 if ((s
[3] & (1 << j
)) && (caps
[j
])) {
154 t
+= ((k
> 12) ? '<br>' : ' ') + ncap
;
161 for (j
= 0; j
< s
[6].length
; ++j
) {
163 var r
= (x
& 0x7F) / 2;
164 if (x
& 0x80) rb
.push(r
);
167 rb
.sort(this.rateSorter
);
168 rg
.sort(this.rateSorter
);
171 if (rb
.length
) t
= '<span class="brate">' + rb
.join(',') + '</span>';
173 if (rb
.length
) t
+= '<br>';
174 t
+='<span class="grate">' + rg
.join(',') + '</span>';
179 t
= E('expire-time').value
;
181 var cut
= (new Date()).getTime() - (t
* 1000);
182 for (i
= 0; i
< entries
.length
; ) {
183 if (entries
[i
].lastSeen
.getTime() < cut
) {
184 entries
.splice(i
, 1);
191 for (i
= 0; i
< entries
.length
; ++i
) {
197 e
.rssi
= MAX(e
.rssi
- 5, -101);
198 e
.noise
= MAX(e
.noise
- 2, -101);
199 if ((e
.rssi
== -101) || (e
.noise
== -101))
200 e
.noise
= e
.rssi
= -999;
204 e
.qual
= MAX(e
.rssi
- e
.noise
, 0);
206 seen
= e
.lastSeen
.toWHMS();
208 m
= Math
.floor(((new Date()).getTime() - e
.firstSeen
.getTime()) / 60000);
209 if (m
<= 10) seen
+= '<br> <b><small>NEW (' + -m
+ 'm)</small></b>';
213 if (mac
.match(/^(..):(..):(..)/))
214 mac
= '<a href="http://standards.ieee.org/cgi-bin/ouisearch?' + RegExp
.$1 + '-' + RegExp
.$2 + '-' + RegExp
.$3 + '" target="_new" title="OUI search">' + mac
+ '</a>';
217 '<small>' + seen
+ '</small>',
220 (e
.rssi
== -999) ? '' : (e
.rssi
+ ' <small>dBm</small>'),
221 (e
.noise
== -999) ? '' : (e
.noise
+ ' <small>dBm</small>'),
222 '<small>' + e
.qual
+ '</small> <img src="bar' + MIN(MAX(Math
.floor(e
.qual
/ 10), 1), 6) + '.gif">',
225 '' + e
.rates
], false);
229 if (useAjax()) s
= added
+ ' added, ' + removed
+ ' removed, ';
230 s
+= entries
.length
+ ' total.';
232 s
+= '<br><br><small>Last updated: ' + (new Date()).toWHMS() + '</small>';
238 sg
.setup = function() {
239 this.init('survey-grid', 'sort');
240 this.headerSet(['Last Seen', 'SSID', 'BSSID', 'RSSI ', 'Noise ', 'Quality', 'Ch', 'Capabilities', 'Rates']);
248 E('survey-msg').innerHTML
= msg
;
252 var ref
= new TomatoRefresh('update.cgi', 'exec=wlscan', 0, 'tools_survey_refresh');
254 ref
.refresh = function(text
)
269 if (!useAjax()) E('expire-time').style
.visibility
= 'hidden';
280 <body onload='init()'
>
281 <form action='javascript:{}'
>
282 <table id='container' cellspacing=
0>
283 <tr><td colspan=
2 id='header'
>
284 <div class='title'
>Tomato
</div>
285 <div class='version'
>Version <%
version(); %></div>
287 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
289 <div id='ident'
><%
ident(); %></div>
293 <div class='section-title'
>Wireless Site Survey
</div>
294 <div class='section'
>
295 <table id='survey-grid' class='tomato-grid' cellspacing=
0></table>
296 <div id='survey-msg'
></div>
297 <div id='survey-controls'
>
298 <img src=
"spin.gif" id=
"refresh-spinner">
299 <script type='text/javascript'
>
300 genStdTimeList('expire-time', 'Auto Expire', 1);
301 genStdTimeList('refresh-time', 'Auto Refresh', 1);
303 <input type=
"button" value=
"Refresh" onclick=
"ref.toggle()" id=
"refresh-button">
307 <script type='text/javascript'
>
308 if ('<% wlclient(); %>' == '0') {
309 document
.write('<small>Warning: Wireless connections to this router may be disrupted while using this tool.</small>');
317 <tr><td id='footer' colspan=
2> </td></tr>
320 <script type='text/javascript'
>earlyInit();</script>