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,dhcpd_static_only,cstats_include,arpbind_listed"); %>
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(5, name
);
75 sg
.inStatic = function(n
) {
76 return this.exist(3, 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
);
85 v
.push((data
[2].toString() != '0') ? '<small><i>Enabled</i></small>' : '');
86 v
.push(escapeHTML('' + data
[3]));
87 v
.push((data
[4].toString() != '0') ? '<small><i>Enabled</i></small>' : '');
88 v
.push(escapeHTML('' + data
[5]));
92 sg
.dataToFieldValues = function (data
) {
95 (data
[2].toString() != '0') ? 'checked' : '',
97 (data
[4].toString() != '0') ? 'checked' : '',
101 sg
.fieldValuesToData = function(row
) {
102 var f
= fields
.getAll(row
);
105 f
[2].checked
? '1' : '0',
107 f
[4].checked
? '1' : '0',
111 sg
.sortCompare = function(a
, b
) {
112 var da
= a
.getRowData();
113 var db
= b
.getRowData();
115 switch (this.sortColumn
) {
117 r
= cmpText(da
[0], db
[0]);
120 r
= cmpInt(da
[2], db
[2]);
123 r
= cmpIP(da
[3], db
[3]);
126 r
= cmpInt(da
[4], db
[4]);
129 if (r
== 0) r
= cmpText(da
[5], db
[5]);
130 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
;
153 f
[1].disabled
= f
[2].checked
;
155 for (i
= 0; i
< 2; ++i
) {
156 if (this.existMAC(f
[i
].value
)) {
157 ferror
.set(f
[i
], 'Duplicate MAC address', quiet
);
162 if (f
[3].value
.indexOf('.') == -1) {
163 s
= parseInt(f
[3].value
, 10)
164 if (isNaN(s
) || (s
<= 0) || (s
>= 255)) {
165 ferror
.set(f
[3], 'Invalid IP address', quiet
);
168 f
[3].value
= ipp
+ s
;
171 if ((!isMAC0(f
[0].value
)) && (this.inStatic(f
[3].value
))) {
172 ferror
.set(f
[3], 'Duplicate IP address', quiet
);
177 // if (!v_hostname(f[5], quiet, 5)) return 0;
178 // if (!v_nodelim(f[5], quiet, 'Hostname', 1)) return 0;
180 s
= f
[5].value
.trim().replace(/\s+/g, ' ');
183 if (s
.search(/^[.a-zA-Z0-9_\- ]+$/) == -1) {
184 ferror
.set(f
[5], 'Invalid hostname. Only characters "A-Z 0-9 . - _" are allowed.', quiet
);
187 if (this.existName(s
)) {
188 ferror
.set(f
[5], 'Duplicate hostname.', quiet
);
194 if (isMAC0(f
[0].value
)) {
196 s
= 'Both MAC address and name fields must not be empty.';
197 ferror
.set(f
[0], s
, 1);
198 ferror
.set(f
[5], s
, quiet
);
206 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
)) {
216 sg
.resetNewEditor = function() {
219 f
= fields
.getAll(this.newEditor
);
222 if ((c
= cookie
.get('addstatic')) != null) {
223 cookie
.set('addstatic', '', 0);
227 f
[1].value
= '00:00:00:00:00:00';
234 f
[0].value
= '00:00:00:00:00:00';
235 f
[1].value
= '00:00:00:00:00:00';
248 } while (((c
= fixIP(ntoa(autonum
), 1)) == null) || (c
== nvram
.lan_ipaddr
) || (this.inStatic(c
)));
253 sg
.setup = function() {
254 this.init('bs-grid', 'sort', 250, [
255 { multi
: [ { type
: 'text', maxlen
: 17 }, { type
: 'text', maxlen
: 17 } ] },
256 { type
: 'checkbox', prefix
: '<div class="centered">', suffix
: '</div>' },
257 { type
: 'text', maxlen
: 15 },
258 { type
: 'checkbox', prefix
: '<div class="centered">', suffix
: '</div>' },
259 { type
: 'text', maxlen
: 50 } ] );
261 this.headerSet(['MAC Address', 'Bound to', 'IP Address', 'IPTraffic', 'Hostname']);
263 var ipt
= nvram
.cstats_include
.split(',');
264 var s
= nvram
.dhcpd_static
.split('>');
265 for (var i
= 0; i
< s
.length
; ++i
) {
267 var t
= s
[i
].split('<');
268 if ((t
.length
== 3) || (t
.length
== 4)) {
269 var d
= t
[0].split(',');
270 var ip
= (t
[1].indexOf('.') == -1) ? (ipp
+ t
[1]) : t
[1];
271 for (var j
= 0; j
< ipt
.length
; ++j
) {
280 this.insertData(-1, [d
[0], (d
.length
>= 2) ? d
[1] : '00:00:00:00:00:00', t
[3],
281 (t
[1].indexOf('.') == -1) ? (ipp
+ t
[1]) : t
[1], h
, t
[2]]);
285 this.showNewEditor();
286 this.resetNewEditor();
290 if (sg
.isEditing()) return;
292 var data
= sg
.getAllData();
297 for (i
= 0; i
< data
.length
; ++i
) {
300 if (!isMAC0(d
[1])) sdhcp
+= ',' + d
[1];
301 sdhcp
+= '<' + d
[3] + '<' + d
[5] + '<' + d
[2] + '>';
302 if (d
[4] == '1') ipt
+= ((ipt
.length
> 0) ? ',' : '') + d
[3];
306 fom
.dhcpd_static
.value
= sdhcp
;
307 fom
.arpbind_listed
.value
= E('_f_arpbind_listed').checked
? '1' : '0';
308 fom
.dhcpd_static_only
.value
= E('_f_dhcpd_static_only').checked
? '1' : '0';
309 fom
.cstats_include
.value
= ipt
;
315 if (((c
= cookie
.get('basic_static_notes_vis')) != null) && (c
== '1')) {
316 toggleVisibility("notes");
319 if (((c
= cookie
.get('basic_static_options_vis')) != null) && (c
== '1')) {
320 toggleVisibility("options");
326 function toggleVisibility(whichone
) {
327 if(E('sesdiv' + whichone
).style
.display
=='') {
328 E('sesdiv' + whichone
).style
.display
='none';
329 E('sesdiv' + whichone
+ 'showhide').innerHTML
='(Click here to show)';
330 cookie
.set('basic_static_' + whichone
+ '_vis', 0);
332 E('sesdiv' + whichone
).style
.display
='';
333 E('sesdiv' + whichone
+ 'showhide').innerHTML
='(Click here to hide)';
334 cookie
.set('basic_static_' + whichone
+ '_vis', 1);
338 function verifyFields(focused
, quiet
) {
344 <body onload='init()'
>
345 <form id='_fom' method='post' action='tomato.cgi'
>
346 <table id='container' cellspacing=
0>
347 <tr><td colspan=
2 id='header'
>
348 <div class='title'
>Tomato
</div>
349 <div class='version'
>Version <%
version(); %></div>
351 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
353 <div id='ident'
><%
ident(); %></div>
357 <input type='hidden' name='_nextpage' value='basic-static.asp'
>
358 <input type='hidden' name='_service' value='dhcpd-restart,arpbind-restart,cstats-restart'
>
360 <input type='hidden' name='dhcpd_static'
>
361 <input type='hidden' name='dhcpd_static_only'
>
362 <input type='hidden' name='cstats_include'
>
363 <input type='hidden' name='arpbind_listed'
>
365 <div class='section-title'
>Static DHCP/ARP
& Bandwidth Monitoring of LAN Clients
</div>
366 <div class='section'
>
367 <table class='tomato-grid' id='bs-grid'
></table>
372 <div class='section-title'
>Options
<small><i><a href='javascript:toggleVisibility(
"options");'
><span id='sesdivoptionsshowhide'
>(Click here to show)
</span></a></i></small></div>
373 <div class='section' id='sesdivoptions' style='display:none'
>
374 <script type='text/javascript'
>
375 createFieldTable('', [
376 { title
: 'Enable static ARP for all devices on list ', name
: 'f_arpbind_listed', type
: 'checkbox', value
: nvram
.arpbind_listed
== '1' },
377 { title
: 'Ignore DHCP requests from unknown devices', name
: 'f_dhcpd_static_only', type
: 'checkbox', value
: nvram
.dhcpd_static_only
== '1' }
384 <div class='section-title'
>Notes
<small><i><a href='javascript:toggleVisibility(
"notes");'
><span id='sesdivnotesshowhide'
>(Click here to show)
</span></a></i></small></div>
385 <div class='section' id='sesdivnotes' style='display:none'
>
387 <li><b>MAC Address
</b> - Unique identifier associated to a network interface on this particular device.
</li>
388 <li><b>Bound to
</b> - Enforce static ARP binding of this particular IP/MAC address pair.
</li>
389 <li><b>IP Address
</b> - Network address assigned to this device on the local network.
</li>
390 <li><b>IPTraffic
</b> - Keep track of bandwidth usage for this IP address.
</li>
391 <li><b>Hostname
</b> - Human-readable nickname/label assigned to this device on the network.
</li>
395 <li><b>Enable static ARP for (...)
</b> - Enforce static ARP binding for all IP/MAC address pairs listed above.
</li>
396 <li><b>Ignore DHCP requests (...)
</b> - Unlisted MAC addresses won't be able to obtain an IP address through DHCP.
</li>
401 <li><b>Other relevant notes/hints:
</b>
403 <li>To specify multiple hostnames for a device, separate them with spaces.
</li>
404 <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>
405 <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>
406 <li>See also the
<a href='advanced-dhcpdns.asp'
>Advanced DHCP/DNS
</a> settings page for more DHCP-related configuration options.
</li>
416 <tr><td id='footer' colspan=
2>
417 <span id='footer-msg'
></span>
418 <input type='button' value='Save' id='save-button' onclick='save()'
>
419 <input type='button' value='Cancel' id='cancel-button' onclick='javascript:reloadPage();'
>
423 <script type='text/javascript'
>sg
.setup();</script>