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_enable,qos_orules"); %>
112 var abc
= ['Highest', 'High', 'Medium', 'Low', 'Lowest', 'A','B','C','D','E'];
115 [0,'IPP2P (disabled)'],[0xFFF,'All IPP2P filters'],[1,'AppleJuice'],[2,'Ares'],[4,'BitTorrent'],[8,'Direct Connect'],
116 [16,'eDonkey'],[32,'Gnutella'],[64,'Kazaa'],[128,'Mute'],[256,'SoulSeek'],[512,'Waste'],[1024,'WinMX'],[2048,'XDCC']];
119 ['','DSCP (any)'],['0x00','BE'],
120 ['0x08','CS1'],['0x10','CS2'],['0x18','CS3'],['0x20','CS4'],['0x28','CS5'],['0x30','CS6'],['0x38','CS7'],
121 ['0x0a','AF11'],['0x0c','AF12'],['0x0e','AF13'],['0x12','AF21'],['0x14','AF22'],['0x16','AF23'],
122 ['0x1a','AF31'],['0x1c','AF32'],['0x1e','AF33'],['0x22','AF41'],['0x24','AF42'],['0x26','AF43'],
123 ['0x2e','EF'],['*','DSCP value']];
124 for (i
= 1; i
< dscp
.length
- 1; ++i
)
125 dscp
[i
][1] = 'DSCP Class ' + dscp
[i
][1];
129 for (i
= 0; i
< layer7
.length
; ++i
)
130 layer7
[i
] = [layer7
[i
],layer7
[i
]];
131 layer7
.unshift(['', 'Layer 7 (disabled)']);
133 var class1
= [[-1,'Disabled']];
134 for (i
= 0; i
< 10; ++i
) class1
.push([i
, abc
[i
]]);
135 var class2
= class1
.slice(1);
138 var qosg
= new TomatoGrid();
140 function dscpClass(v
)
146 for (i
= 1; i
< dscp
.length
- 1; ++i
) // skip 1st and last elements
147 if (dscp
[i
][0] * 1 == v
* 1) {
155 qosg
.dataToView = function(data
) {
160 b
.push(((data
[0] == 1) ? 'To ' : 'From ') + data
[1]);
163 if (data
[2] == -1) b
.push('TCP/UDP');
164 else if (data
[2] >= 0) b
.push(protocols
[data
[2]] || data
[2]);
165 if (data
[3] != 'a') {
166 if (data
[3] == 'd') s
= 'Dst ';
167 else if (data
[3] == 's') s
= 'Src ';
169 b
.push(s
+ 'Port: ' + data
[4].replace(/:/g
, '-'));
173 for (i
= 0; i
< ipp2p
.length
; ++i
)
174 if (ipp2p
[i
][0] == data
[5]) {
175 b
.push('IPP2P: ' + ipp2p
[i
][1]);
180 else if (data
[6] != '') {
181 b
.push('L7: ' + data
[6])
185 s
= dscpClass(data
[9]);
186 if (s
!= '') b
.push(s
);
187 else b
.push('DSCP Value: ' + data
[9]);
191 b
.push('Transferred: ' + data
[7] + ((data
[8] == '') ? '<small>KB+</small>' : (' - ' + data
[8] + '<small>KB</small>')));
194 return [b
.join('<br>'), class1
[(data
[10] * 1) + 1][1], escapeHTML(data
[11]), (ruleCounter
>= 0) ? ''+ ++ruleCounter
: ''];
197 qosg
.fieldValuesToData = function(row
) {
198 var f
= fields
.getAll(row
);
199 var proto
= f
[2].value
;
200 var dir
= f
[3].value
;
201 var vdscp
= (f
[7].value
== '*') ? f
[8].value
: f
[7].value
;
202 if ((proto
!= -1) && (proto
!= 6) && (proto
!= 17)) dir
= 'a';
203 return [f
[0].value
, f
[0].selectedIndex
? f
[1].value
: '',
204 proto
, dir
, (dir
!= 'a') ? f
[4].value
: '',
205 f
[5].value
, f
[6].value
, f
[9].value
, f
[10].value
,
206 vdscp
, f
[11].value
, f
[12].value
];
209 qosg
.dataToFieldValues = function(data
) {
213 if (dscpClass(data
[9]) == '') s
= '*';
214 else s
= data
[9].toLowerCase();
217 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]];
220 qosg
.resetNewEditor = function() {
221 var f
= fields
.getAll(this.newEditor
);
222 f
[0].selectedIndex
= 0;
224 f
[2].selectedIndex
= 1;
225 f
[3].selectedIndex
= 0;
227 f
[5].selectedIndex
= 0;
228 f
[6].selectedIndex
= 0;
229 f
[7].selectedIndex
= 0;
233 f
[11].selectedIndex
= 5;
235 this.enDiFields(this.newEditor
);
236 ferror
.clearAll(fields
.getAll(this.newEditor
));
239 qosg
._disableNewEditor
= qosg
.disableNewEditor
;
240 qosg
.disableNewEditor = function(disable
) {
241 qosg
._disableNewEditor(disable
);
243 this.enDiFields(this.newEditor
);
247 qosg
.enDiFields = function(row
) {
248 var f
= fields
.getAll(row
);
251 f
[1].disabled
= (f
[0].selectedIndex
== 0);
253 x
= ((x
!= -1) && (x
!= 6) && (x
!= 17));
255 if (f
[3].selectedIndex
== 0) x
= 1;
258 f
[6].disabled
= (f
[5].selectedIndex
!= 0);
259 f
[5].disabled
= (f
[6].selectedIndex
!= 0);
261 f
[8].disabled
= (f
[7].value
!= '*');
264 function v_dscp(e
, quiet
)
266 if ((e
= E(e
)) == null) return 0;
268 if ((!v
.match(/^ *(0x)?[0-9A-Fa-f]+ *$/)) || (v
< 0) || (v
> 63)) {
269 ferror
.set(e
, 'Invalid DSCP value. Valid range: 0x00-0x3F', quiet
);
272 e
.value
= '0x' + (v
* 1).hex(2);
277 qosg
.verifyFields = function(row
, quiet
) {
278 var f
= fields
.getAll(row
);
281 this.enDiFields(row
);
285 if ((a
== 1) || (a
== 2)) {
286 if (!v_length(f
[1], quiet
, 1)) return 0;
287 if (!_v_iptaddr(f
[1], quiet
, 0, 1, 1)) return 0;
289 else if ((a
== 3) && (!v_mac(f
[1], quiet
))) return 0;
291 b
= f
[2].selectedIndex
;
292 if ((b
> 0) && (b
<= 3) && (f
[3].selectedIndex
!= 0) && (!v_iptport(f
[4], quiet
))) return 0;
294 var BMAX
= 1024 * 1024;
297 a
= e
.value
= e
.value
.trim();
299 if (!v_range(e
, quiet
, 0, BMAX
)) return 0;
304 b
= e
.value
= e
.value
.trim();
307 if (b
>= BMAX
) e
.value
= '';
308 else if (!v_range(e
, quiet
, 0, BMAX
)) return 0;
309 if (a
== '') f
[9].value
= a
= 0;
315 if ((b
!= '') && (a
>= b
)) {
316 ferror
.set(f
[9], 'Invalid range', quiet
);
320 if (f
[7].value
== '*') {
321 if (!v_dscp(f
[8], quiet
)) return 0;
323 else f
[8].value
= f
[7].value
;
325 if (!v_nodelim(f
[12], quiet
, 'Description', 1)) return 0;
326 return v_length(f
[12], quiet
);
329 qosg
.setup = function() {
331 a
= [[-2, 'Any Protocol'],[-1,'TCP/UDP'],[6,'TCP'],[17,'UDP']];
332 for (i
= 0; i
< 256; ++i
) {
333 if ((i
!= 6) && (i
!= 17)) a
.push([i
, protocols
[i
] || i
]);
337 this.init('qg', 'move', 50, [
339 { type
: 'select', options
: [[0,'Any Address'],[1,'Dst IP'],[2,'Src IP'],[3,'Src MAC']],
340 prefix
: '<div class="x1a">', suffix
: '</div>' },
341 { type
: 'text', prefix
: '<div class="x1b">', suffix
: '</div>' },
343 { type
: 'select', prefix
: '<div class="x2a">', suffix
: '</div>', options
: a
},
344 { type
: 'select', prefix
: '<div class="x2b">', suffix
: '</div>',
345 options
: [['a','Any Port'],['d','Dst Port'],['s','Src Port'],['x','Src or Dst']] },
346 { type
: 'text', prefix
: '<div class="x2c">', suffix
: '</div>' },
348 { type
: 'select', prefix
: '<div class="x3a">', suffix
: '</div>', options
: ipp2p
},
349 { type
: 'select', prefix
: '<div class="x3b">', suffix
: '</div>', options
: layer7
},
351 { type
: 'select', prefix
: '<div class="x4a">', suffix
: '</div>', options
: dscp
},
352 { type
: 'text', prefix
: '<div class="x4b">', suffix
: '</div>' },
354 { type
: 'text', prefix
: '<div class="x5a">', suffix
: '</div>' },
355 { type
: 'text', prefix
: '<div class="x5b"> - </div><div class="x5c">', suffix
: '</div><div class="x5d">KB Transferred</div>' }
357 { type
: 'select', options
: class1
, vtop
: 1 },
358 { type
: 'text', maxlen
: 32, vtop
: 1 }
361 this.headerSet(['Match Rule', 'Class', 'Description', '#']);
363 // addr_type < addr < proto < port_type < port < ipp2p < L7 < bcount < dscp < class < desc
365 a
= nvram
.qos_orules
.split('>');
366 for (i
= 0; i
< a
.length
; ++i
) {
370 // fixup < 0.08 !!! temp
371 b
.splice(7, 0, '', '', '');
373 else if (b
.length
== 10) {
378 if (b
.length
== 11) {
380 b
.splice(7, 1, c
[0], (c
.length
== 1) ? '' : c
[1]);
381 b
[11] = unescape(b
[11]);
384 b
[4] = b
[4].replace(/:/g
, '-');
385 qosg
.insertData(-1, b
);
389 this.showNewEditor();
390 this.resetNewEditor();
393 function verifyFields(focused
, quiet
)
400 if (qosg
.isEditing()) return;
405 c
= qosg
.getAllData();
407 for (i
= 0; i
< c
.length
; ++i
) {
409 b
[4] = b
[4].replace(/-/g
, ':');
410 b
.splice(7, 2, (b
[7] == '') ? '' : [b
[7],b
[8]].join(':'));
411 b
[10] = escapeD(b
[10]);
414 fom
.qos_orules
.value
= a
.join('>');
426 <body onload='init()'
>
427 <form id='_fom' method='post' action='tomato.cgi'
>
428 <table id='container' cellspacing=
0>
429 <tr><td colspan=
2 id='header'
>
430 <div class='title'
>Tomato
</div>
431 <div class='version'
>Version <%
version(); %></div>
433 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
435 <div id='ident'
><%
ident(); %></div>
439 <input type='hidden' name='_nextpage' value='qos-classify.asp'
>
440 <input type='hidden' name='_service' value='qos-restart'
>
441 <input type='hidden' name='qos_orules'
>
443 <div class='section-title'
>Outbound Direction
</div>
444 <div class='section'
>
445 <table class='tomato-grid' cellspacing=
1 id='qg'
></table>
449 <script type='text/javascript'
>
450 if (nvram
.qos_enable
!= '1') {
451 W('<div class="note-disabled"><b>QoS disabled.</b> <a href="qos-settings.asp">Enable »</a></div>');
454 show_notice1('<% notice("iptables"); %>');
461 <tr><td id='footer' colspan=
2>
462 <span id='footer-msg'
></span>
463 <input type='button' value='Save' id='save-button' onclick='save()'
>
464 <input type='button' value='Cancel' id='cancel-button' onclick='reloadPage();'
>
468 <script type='text/javascript'
>qosg
.setup();</script>