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(); %>] QoS: Classification
</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>
18 <script type='text/javascript' src='protocols.js'
></script>
22 <style type='text/css'
>
90 padding: 2px 8px 0 8px;
100 padding: 2px 0 0 8px;
106 <script type='text/javascript' src='debug.js'
></script>
108 <script type='text/javascript'
>
110 // <% nvram("qos_classnames,qos_enable,qos_orules"); %>
113 var abc
= nvram
.qos_classnames
.split(' '); // Toastman - configurable class names
117 [0,'IPP2P (disabled)'],[0xFFF,'All IPP2P filters'],[1,'AppleJuice'],[2,'Ares'],[4,'BitTorrent'],[8,'Direct Connect'],
118 [16,'eDonkey'],[32,'Gnutella'],[64,'Kazaa'],[128,'Mute'],[256,'SoulSeek'],[512,'Waste'],[1024,'WinMX'],[2048,'XDCC']];
121 ['','DSCP (any)'],['0x00','BE'],
122 ['0x08','CS1'],['0x10','CS2'],['0x18','CS3'],['0x20','CS4'],['0x28','CS5'],['0x30','CS6'],['0x38','CS7'],
123 ['0x0a','AF11'],['0x0c','AF12'],['0x0e','AF13'],['0x12','AF21'],['0x14','AF22'],['0x16','AF23'],
124 ['0x1a','AF31'],['0x1c','AF32'],['0x1e','AF33'],['0x22','AF41'],['0x24','AF42'],['0x26','AF43'],
125 ['0x2e','EF'],['*','DSCP value']];
126 for (i
= 1; i
< dscp
.length
- 1; ++i
)
127 dscp
[i
][1] = 'DSCP Class ' + dscp
[i
][1];
131 for (i
= 0; i
< layer7
.length
; ++i
)
132 layer7
[i
] = [layer7
[i
],layer7
[i
]];
133 layer7
.unshift(['', 'Layer 7 (disabled)']);
135 var class1
= [[-1,'Disabled']];
136 for (i
= 0; i
< 10; ++i
) class1
.push([i
, abc
[i
]]);
137 var class2
= class1
.slice(1);
140 var qosg
= new TomatoGrid();
142 function dscpClass(v
)
148 for (i
= 1; i
< dscp
.length
- 1; ++i
) // skip 1st and last elements
149 if (dscp
[i
][0] * 1 == v
* 1) {
157 qosg
.dataToView = function(data
) {
162 b
.push(((data
[0] == 1) ? 'To ' : 'From ') + data
[1]);
165 if (data
[2] == -1) b
.push('TCP/UDP');
166 else if (data
[2] >= 0) b
.push(protocols
[data
[2]] || data
[2]);
167 if (data
[3] != 'a') {
168 if (data
[3] == 'd') s
= 'Dst ';
169 else if (data
[3] == 's') s
= 'Src ';
171 b
.push(s
+ 'Port: ' + data
[4].replace(/:/g
, '-'));
175 for (i
= 0; i
< ipp2p
.length
; ++i
)
176 if (ipp2p
[i
][0] == data
[5]) {
177 b
.push('IPP2P: ' + ipp2p
[i
][1]);
182 else if (data
[6] != '') {
183 b
.push('L7: ' + data
[6])
187 s
= dscpClass(data
[9]);
188 if (s
!= '') b
.push(s
);
189 else b
.push('DSCP Value: ' + data
[9]);
193 b
.push('Transferred: ' + data
[7] + ((data
[8] == '') ? '<small>KB+</small>' : (' - ' + data
[8] + '<small>KB</small>')));
196 return [b
.join('<br>'), class1
[(data
[10] * 1) + 1][1], escapeHTML(data
[11]), (ruleCounter
>= 0) ? ''+ ++ruleCounter
: ''];
199 qosg
.fieldValuesToData = function(row
) {
200 var f
= fields
.getAll(row
);
201 var proto
= f
[2].value
;
202 var dir
= f
[3].value
;
203 var vdscp
= (f
[7].value
== '*') ? f
[8].value
: f
[7].value
;
204 if ((proto
!= -1) && (proto
!= 6) && (proto
!= 17)) dir
= 'a';
205 return [f
[0].value
, f
[0].selectedIndex
? f
[1].value
: '',
206 proto
, dir
, (dir
!= 'a') ? f
[4].value
: '',
207 f
[5].value
, f
[6].value
, f
[9].value
, f
[10].value
,
208 vdscp
, f
[11].value
, f
[12].value
];
211 qosg
.dataToFieldValues = function(data
) {
215 if (dscpClass(data
[9]) == '') s
= '*';
216 else s
= data
[9].toLowerCase();
219 return [data
[0], data
[1], data
[2], data
[3], data
[4], data
[5], data
[6], s
, data
[9], data
[7], data
[8], data
[10], data
[11]];
222 qosg
.resetNewEditor = function() {
223 var f
= fields
.getAll(this.newEditor
);
224 f
[0].selectedIndex
= 0;
226 f
[2].selectedIndex
= 1;
227 f
[3].selectedIndex
= 0;
229 f
[5].selectedIndex
= 0;
230 f
[6].selectedIndex
= 0;
231 f
[7].selectedIndex
= 0;
235 f
[11].selectedIndex
= 5;
237 this.enDiFields(this.newEditor
);
238 ferror
.clearAll(fields
.getAll(this.newEditor
));
241 qosg
._disableNewEditor
= qosg
.disableNewEditor
;
242 qosg
.disableNewEditor = function(disable
) {
243 qosg
._disableNewEditor(disable
);
245 this.enDiFields(this.newEditor
);
249 qosg
.enDiFields = function(row
) {
250 var f
= fields
.getAll(row
);
253 f
[1].disabled
= (f
[0].selectedIndex
== 0);
255 x
= ((x
!= -1) && (x
!= 6) && (x
!= 17));
257 if (f
[3].selectedIndex
== 0) x
= 1;
260 f
[6].disabled
= (f
[5].selectedIndex
!= 0);
261 f
[5].disabled
= (f
[6].selectedIndex
!= 0);
263 f
[8].disabled
= (f
[7].value
!= '*');
266 function v_dscp(e
, quiet
)
268 if ((e
= E(e
)) == null) return 0;
270 if ((!v
.match(/^ *(0x)?[0-9A-Fa-f]+ *$/)) || (v
< 0) || (v
> 63)) {
271 ferror
.set(e
, 'Invalid DSCP value. Valid range: 0x00-0x3F', quiet
);
274 e
.value
= '0x' + (v
* 1).hex(2);
279 qosg
.verifyFields = function(row
, quiet
) {
280 var f
= fields
.getAll(row
);
283 this.enDiFields(row
);
287 if ((a
== 1) || (a
== 2)) {
288 if (!v_length(f
[1], quiet
, 1)) return 0;
289 if (!_v_iptaddr(f
[1], quiet
, 0, 1, 1)) return 0;
291 else if ((a
== 3) && (!v_mac(f
[1], quiet
))) return 0;
293 b
= f
[2].selectedIndex
;
294 if ((b
> 0) && (b
<= 3) && (f
[3].selectedIndex
!= 0) && (!v_iptport(f
[4], quiet
))) return 0;
296 var BMAX
= 1024 * 1024;
299 a
= e
.value
= e
.value
.trim();
301 if (!v_range(e
, quiet
, 0, BMAX
)) return 0;
306 b
= e
.value
= e
.value
.trim();
309 if (b
>= BMAX
) e
.value
= '';
310 else if (!v_range(e
, quiet
, 0, BMAX
)) return 0;
311 if (a
== '') f
[9].value
= a
= 0;
317 if ((b
!= '') && (a
>= b
)) {
318 ferror
.set(f
[9], 'Invalid range', quiet
);
322 if (f
[7].value
== '*') {
323 if (!v_dscp(f
[8], quiet
)) return 0;
325 else f
[8].value
= f
[7].value
;
327 if (!v_nodelim(f
[12], quiet
, 'Description', 1)) return 0;
328 return v_length(f
[12], quiet
);
331 qosg
.setup = function() {
333 a
= [[-2, 'Any Protocol'],[-1,'TCP/UDP'],[6,'TCP'],[17,'UDP']];
334 for (i
= 0; i
< 256; ++i
) {
335 if ((i
!= 6) && (i
!= 17)) a
.push([i
, protocols
[i
] || i
]);
339 this.init('qg', 'move', 80, [
341 { type
: 'select', options
: [[0,'Any Address'],[1,'Dst IP'],[2,'Src IP'],[3,'Src MAC']],
342 prefix
: '<div class="x1a">', suffix
: '</div>' },
343 { type
: 'text', prefix
: '<div class="x1b">', suffix
: '</div>' },
345 { type
: 'select', prefix
: '<div class="x2a">', suffix
: '</div>', options
: a
},
346 { type
: 'select', prefix
: '<div class="x2b">', suffix
: '</div>',
347 options
: [['a','Any Port'],['d','Dst Port'],['s','Src Port'],['x','Src or Dst']] },
348 { type
: 'text', prefix
: '<div class="x2c">', suffix
: '</div>' },
350 { type
: 'select', prefix
: '<div class="x3a">', suffix
: '</div>', options
: ipp2p
},
351 { type
: 'select', prefix
: '<div class="x3b">', suffix
: '</div>', options
: layer7
},
353 { type
: 'select', prefix
: '<div class="x4a">', suffix
: '</div>', options
: dscp
},
354 { type
: 'text', prefix
: '<div class="x4b">', suffix
: '</div>' },
356 { type
: 'text', prefix
: '<div class="x5a">', suffix
: '</div>' },
357 { type
: 'text', prefix
: '<div class="x5b"> - </div><div class="x5c">', suffix
: '</div><div class="x5d">KB Transferred</div>' }
359 { type
: 'select', options
: class1
, vtop
: 1 },
360 { type
: 'text', maxlen
: 32, vtop
: 1 }
363 this.headerSet(['Match Rule', 'Class', 'Description', '#']);
365 // addr_type < addr < proto < port_type < port < ipp2p < L7 < bcount < dscp < class < desc
367 a
= nvram
.qos_orules
.split('>');
368 for (i
= 0; i
< a
.length
; ++i
) {
372 // fixup < 0.08 !!! temp
373 b
.splice(7, 0, '', '', '');
375 else if (b
.length
== 10) {
380 if (b
.length
== 11) {
382 b
.splice(7, 1, c
[0], (c
.length
== 1) ? '' : c
[1]);
383 b
[11] = unescape(b
[11]);
386 b
[4] = b
[4].replace(/:/g
, '-');
387 qosg
.insertData(-1, b
);
391 this.showNewEditor();
392 this.resetNewEditor();
395 function verifyFields(focused
, quiet
)
402 if (qosg
.isEditing()) return;
407 c
= qosg
.getAllData();
409 for (i
= 0; i
< c
.length
; ++i
) {
411 b
[4] = b
[4].replace(/-/g
, ':');
412 b
.splice(7, 2, (b
[7] == '') ? '' : [b
[7],b
[8]].join(':'));
413 b
[10] = escapeD(b
[10]);
416 fom
.qos_orules
.value
= a
.join('>');
428 <body onload='init()'
>
429 <form id='_fom' method='post' action='tomato.cgi'
>
430 <table id='container' cellspacing=
0>
431 <tr><td colspan=
2 id='header'
>
432 <div class='title'
>Tomato
</div>
433 <div class='version'
>Version <%
version(); %></div>
435 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
437 <div id='ident'
><%
ident(); %></div>
441 <input type='hidden' name='_nextpage' value='qos-classify.asp'
>
442 <input type='hidden' name='_service' value='qos-restart'
>
443 <input type='hidden' name='qos_orules'
>
445 <div class='section-title'
>Outbound Direction
</div>
446 <div class='section'
>
447 <table class='tomato-grid' cellspacing=
1 id='qg'
></table>
451 <script type='text/javascript'
>
452 if (nvram
.qos_enable
!= '1') {
453 W('<div class="note-disabled"><b>QoS disabled.</b> <a href="qos-settings.asp">Enable »</a></div>');
456 show_notice1('<% notice("iptables"); %>');
463 <tr><td id='footer' colspan=
2>
464 <span id='footer-msg'
></span>
465 <input type='button' value='Save' id='save-button' onclick='save()'
>
466 <input type='button' value='Cancel' id='cancel-button' onclick='reloadPage();'
>
470 <script type='text/javascript'
>qosg
.setup();</script>