1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML
4.0//EN'
>
4 Copyright (C) 2006-2010 Jonathan Zarate
5 http://www.polarcloud.com/tomato/
8 Copyright (C) 2011 Augusto Bott
9 http://code.google.com/p/tomato-sdhc-vlan/
11 For use with Tomato Firmware only.
12 No part of this file may be used without permission.
16 <meta http-equiv='content-type' content='text/html;charset=utf-
8'
>
17 <meta name='robots' content='noindex,nofollow'
>
18 <title>[<%
ident(); %>] Basic: Static DHCP/ARP
& Bandwidth Monitoring of LAN Clients
</title>
19 <link rel='stylesheet' type='text/css' href='tomato.css'
>
21 <script type='text/javascript' src='tomato.js'
></script>
24 <style type='text/css'
>
45 <script type='text/javascript' src='debug.js'
></script>
47 <script type='text/javascript'
>
49 // <% nvram("lan_ipaddr,lan_netmask,dhcpd_static,dhcpd_startip,bwm_client,dhcpd_static_only,arpbind_static"); %>
51 if (nvram
.lan_ipaddr
.match(/^(\d+\.\d+\.\d+)\.(\d+)$/)) ipp
= RegExp
.$1 + '.';
54 autonum
= aton(nvram
.lan_ipaddr
) & aton(nvram
.lan_netmask
);
56 var sg
= new TomatoGrid();
58 sg
.exist = function(f
, v
) {
59 var data
= this.getAllData();
60 for (var i
= 0; i
< data
.length
; ++i
) {
61 if (data
[i
][f
] == v
) return true;
66 sg
.existMAC = function(mac
) {
67 if (isMAC0(mac
)) return false;
68 return this.exist(0, mac
) || this.exist(1, mac
);
71 sg
.existName = function(name
) {
72 return this.exist(4, name
);
75 sg
.inStatic = function(n
) {
76 return this.exist(2, n
);
79 sg
.dataToView = function(data
) {
81 var s
= (data
[0] == '00:00:00:00:00:00') ? '' : data
[0];
82 if (!isMAC0(data
[1])) s
+= '<br>' + data
[1];
83 v
.push((s
== '') ? '<center><small><i>(unset)</i></small></center>' : s
);
84 v
.push((data
[2].toString() != '0') ? 'Enabled' : '');
85 v
.push(escapeHTML('' + data
[3]));
86 v
.push((data
[4].toString() != '0') ? 'Enabled' : '');
87 v
.push(escapeHTML('' + data
[5]));
91 sg
.dataToFieldValues = function (data
) {
94 (data
[2].toString() != '0') ? 'checked' : '',
96 (data
[4].toString() != '0') ? 'checked' : '',
100 sg
.fieldValuesToData = function(row
) {
101 var f
= fields
.getAll(row
);
104 f
[2].checked
? '1' : '0',
106 f
[4].checked
? '1' : '0',
110 sg
.sortCompare = function(a
, b
) {
111 var da
= a
.getRowData();
112 var db
= b
.getRowData();
114 switch (this.sortColumn
) {
116 r
= cmpText(da
[0], db
[0]);
119 r
= cmpInt(da
[2], db
[2]);
122 r
= cmpIP(da
[3], db
[3]);
125 r
= cmpInt(da
[4], db
[4]);
128 if (r
== 0) r
= cmpText(da
[5], db
[5]);
129 return this.sortAscending
? r
: -r
;
133 sg
.verifyFields = function(row
, quiet
) {
136 f
= fields
.getAll(row
);
138 if (!v_macz(f
[0], quiet
)) return 0;
139 if (!v_macz(f
[1], quiet
)) return 0;
140 if (isMAC0(f
[0].value
)) {
141 f
[0].value
= f
[1].value
;
142 f
[1].value
= '00:00:00:00:00:00';
144 else if (f
[0].value
== f
[1].value
) {
145 f
[1].value
= '00:00:00:00:00:00';
147 else if ((!isMAC0(f
[1].value
)) && (f
[0].value
> f
[1].value
)) {
149 f
[1].value
= f
[0].value
;
155 // f[1].value = '00:00:00:00:00:00';
156 f[1].disabled = true;
158 f[1].disabled = false;
161 f
[1].disabled
= f
[2].checked
;
163 for (i
= 0; i
< 2; ++i
) {
164 if (this.existMAC(f
[i
].value
)) {
165 ferror
.set(f
[i
], 'Duplicate MAC address', quiet
);
170 if (f
[2].value
.indexOf('.') == -1) {
171 s
= parseInt(f
[3].value
, 10)
172 if (isNaN(s
) || (s
<= 0) || (s
>= 255)) {
173 ferror
.set(f
[3], 'Invalid IP address', quiet
);
176 f
[2].value
= ipp
+ s
;
179 if ((!isMAC0(f
[0].value
)) && (this.inStatic(f
[3].value
))) {
180 ferror
.set(f
[3], 'Duplicate IP address', quiet
);
184 s
= f
[5].value
.trim().replace(/\s+/g, ' ');
186 if (s
.search(/^[.a-zA-Z0-9_\- ]+$/) == -1) {
187 ferror
.set(f
[5], 'Invalid hostname. Only characters "A-Z 0-9 . - _" are allowed.', quiet
);
190 if (this.existName(s
)) {
191 ferror
.set(f
[5], 'Duplicate hostname.', quiet
);
197 if (isMAC0(f
[0].value
)) {
199 s
= 'Both MAC address and name fields must not be empty.';
200 ferror
.set(f
[0], s
, 1);
201 ferror
.set(f
[5], s
, quiet
);
209 if (((f
[0].value
== '00:00:00:00:00:00') || (f
[1].value
== '00:00:00:00:00:00')) && (f
[0].value
== f
[1].value
)) {
219 sg
.resetNewEditor = function() {
222 f
= fields
.getAll(this.newEditor
);
225 if ((c
= cookie
.get('addstatic')) != null) {
226 cookie
.set('addstatic', '', 0);
230 f
[1].value
= '00:00:00:00:00:00';
237 f
[0].value
= '00:00:00:00:00:00';
238 f
[1].value
= '00:00:00:00:00:00';
249 } while (((c
= fixIP(ntoa(autonum
), 1)) == null) || (c
== nvram
.lan_ipaddr
) || (this.inStatic(c
)));
254 sg
.setup = function() {
255 this.init('bs-grid', 'sort', 250, [
256 { multi
: [ { type
: 'text', maxlen
: 17 }, { type
: 'text', maxlen
: 17 } ] },
257 { type
: 'checkbox', prefix
: '<div class="centered">', suffix
: '</div>' },
258 { type
: 'text', maxlen
: 15 },
259 { type
: 'checkbox', prefix
: '<div class="centered">', suffix
: '</div>' },
260 { type
: 'text', maxlen
: 50 } ] );
262 this.headerSet(['MAC Address', 'Bound to', 'IP Address', 'BW Mon', 'Hostname' ]);
264 var s
= nvram
.dhcpd_static
.split('>');
265 var asr
= nvram
.arpbind_static
.split('>');
268 if (nvram
.bwm_client
.indexOf('>') > 0) {
269 bwr
= nvram
.bwm_client
.split('>');
271 bwr
= nvram
.bwm_client
.split(',');
274 for (var i
= 0; i
< s
.length
; ++i
) {
277 var t
= s
[i
].split('<');
280 var ip
= (t
[1].indexOf('.') == -1) ? (ipp
+ t
[1]) : t
[1];
281 var d
= t
[0].split(',');
284 for (var j
= 0; j
< bwr
.length
; ++j
) {
285 var bwl
= bwr
[j
].split('<');
286 if ((bwl
.length
== 2) && (bwl
[0] == ip
))
289 for (var k
= 0; k
< asr
.length
; ++k
) {
290 var asl
= asr
[k
].split('<');
291 if ((asl
.length
== 2) && (asl
[1] == d
))
297 for (var j
= 0; j
< bwr
.length
; ++j
) {
303 ase
= t
[3].toString();
306 this.insertData(-1, [ d
[0], (d
.length
>= 2) ? d
[1] : '00:00:00:00:00:00', ase
, ip
, bwe
, t
[2] ]);
311 this.showNewEditor();
312 this.resetNewEditor();
316 if (sg
.isEditing()) return;
318 var data
= sg
.getAllData();
323 for (i
= 0; i
< data
.length
; ++i
) {
326 if (!isMAC0(d
[1])) sdhcp
+= ',' + d
[1];
327 sdhcp
+= '<' + d
[3] + '<' + d
[5] + '<' + d
[2] + '>';
329 if (d
[4] == '1') bwm
+= ((bwm
.length
> 0) ? ',' : '') + d
[3];
333 fom
.bwm_client
.value
= bwm
;
334 fom
.dhcpd_static
.value
= sdhcp
;
335 fom
.dhcpd_static_only
.value
= E('_f_dhcpd_static_only').checked
? '1' : '0';
342 if (((c
= cookie
.get('basic_static_notes_vis')) != null) && (c
== '1')) {
343 toggleVisibility("notes");
345 if (((c
= cookie
.get('basic_static_options_vis')) != null) && (c
== '1')) {
346 toggleVisibility("options");
351 function toggleVisibility(whichone
) {
352 if(E('sesdiv' + whichone
).style
.display
=='') {
353 E('sesdiv' + whichone
).style
.display
='none';
354 E('sesdiv' + whichone
+ 'showhide').innerHTML
='(Click here to show)';
355 cookie
.set('basic_static_' + whichone
+ '_vis', 0);
357 E('sesdiv' + whichone
).style
.display
='';
358 E('sesdiv' + whichone
+ 'showhide').innerHTML
='(Click here to hide)';
359 cookie
.set('basic_static_' + whichone
+ '_vis', 1);
363 function verifyFields(focused
, quiet
) {
369 <body onload='init()'
>
370 <form id='_fom' method='post' action='tomato.cgi'
>
371 <table id='container' cellspacing=
0>
372 <tr><td colspan=
2 id='header'
>
373 <div class='title'
>Tomato
</div>
374 <div class='version'
>Version <%
version(); %></div>
376 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
378 <div id='ident'
><%
ident(); %></div>
382 <input type='hidden' name='_nextpage' value='basic-static.asp'
>
383 <input type='hidden' name='_service' value='dhcpd-restart,bwclimon-restart,arpbind-restart'
>
385 <input type='hidden' name='bwm_client'
>
386 <input type='hidden' name='dhcpd_static'
>
387 <input type='hidden' name='dhcpd_static_only'
>
388 <input type='hidden' name='arpbind_static'
>
390 <div class='section-title'
>Static DHCP/ARP
& Bandwidth Monitoring of LAN Clients
</div>
391 <div class='section'
>
392 <table class='tomato-grid' id='bs-grid'
></table>
397 <div class='section-title'
>Options
<small><i><a href='javascript:toggleVisibility(
"options");'
><span id='sesdivoptionsshowhide'
>(Click here to show)
</span></a></i></small></div>
398 <div class='section' id='sesdivoptions' style='display:none'
>
399 <script type='text/javascript'
>
400 createFieldTable('', [
401 { title
: 'Ignore DHCP requests from unknown devices', name
: 'f_dhcpd_static_only', type
: 'checkbox', value
: nvram
.dhcpd_static_only
== '1' }
408 <div class='section-title'
>Notes
<small><i><a href='javascript:toggleVisibility(
"notes");'
><span id='sesdivnotesshowhide'
>(Click here to show)
</span></a></i></small></div>
409 <div class='section' id='sesdivnotes' style='display:none'
>
411 <li><b>MAC Address
</b> - Unique identifier associated to a network interface on this particular device.
</li>
412 <li><b>Bound to
</b> - Enforce static ARP binding of this particular IP/MAC address pair.
</li>
413 <li><b>IP Address
</b> - Network address assigned to this device on the local network.
</li>
414 <li><b>BW Mon
</b> - Monitor volume of network traffic from/to this IP address that goes through the router.
</li>
415 <li><b>Hostname
</b> - Human-readable nickname/label assigned to this device on the network.
</li>
418 <li><b>Ignore DHCP requests (...)
</b> - Unlisted MAC addresses won't be able to obtain an IP address through DHCP.
</li>
422 <li><b>Other relevant notes/hints:
</b>
424 <li>To specify multiple hostnames for a device, separate them with spaces.
</li>
425 <li>To enable/enforce static ARP binding for a particular device, it must have only one MAC associated with that particular IP address (i.e. you can't have two MAC addresses linked to the same hostname/device in the table above).
</li>
426 <li>When ARP binding is enabled for a particular MAC/IP address pair, that device will always be shown as
"active" in the
<a href=
"tools-wol.asp">Wake On LAN
</a> table.
</li>
435 <tr><td id='footer' colspan=
2>
436 <span id='footer-msg'
></span>
437 <input type='button' value='Save' id='save-button' onclick='save()'
>
438 <input type='button' value='Cancel' id='cancel-button' onclick='javascript:reloadPage();'
>
442 <script type='text/javascript'
>sg
.setup();</script>