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 //Toastman Class Labels
114 var abc
= ['Service','VOIP/Game','Media','Remote','WWW', 'Mail', 'Messenger','Download','P2P/Bulk','Crawl'];
115 // var abc = ['1)', '2)', '3)', '4)', '5)', '6)','7)','8)','9)','10)'];
116 // var abc = ['Highest', 'High', 'Medium', 'Low', 'Lowest', 'A','B','C','D','E'];
119 [0,'IPP2P (disabled)'],[0xFFF,'All IPP2P filters'],[1,'AppleJuice'],[2,'Ares'],[4,'BitTorrent'],[8,'Direct Connect'],
120 [16,'eDonkey'],[32,'Gnutella'],[64,'Kazaa'],[128,'Mute'],[256,'SoulSeek'],[512,'Waste'],[1024,'WinMX'],[2048,'XDCC']];
123 ['','DSCP (any)'],['0x00','BE'],
124 ['0x08','CS1'],['0x10','CS2'],['0x18','CS3'],['0x20','CS4'],['0x28','CS5'],['0x30','CS6'],['0x38','CS7'],
125 ['0x0a','AF11'],['0x0c','AF12'],['0x0e','AF13'],['0x12','AF21'],['0x14','AF22'],['0x16','AF23'],
126 ['0x1a','AF31'],['0x1c','AF32'],['0x1e','AF33'],['0x22','AF41'],['0x24','AF42'],['0x26','AF43'],
127 ['0x2e','EF'],['*','DSCP value']];
128 for (i
= 1; i
< dscp
.length
- 1; ++i
)
129 dscp
[i
][1] = 'DSCP Class ' + dscp
[i
][1];
133 for (i
= 0; i
< layer7
.length
; ++i
)
134 layer7
[i
] = [layer7
[i
],layer7
[i
]];
135 layer7
.unshift(['', 'Layer 7 (disabled)']);
137 var class1
= [[-1,'Disabled']];
138 for (i
= 0; i
< 10; ++i
) class1
.push([i
, abc
[i
]]);
139 var class2
= class1
.slice(1);
142 var qosg
= new TomatoGrid();
144 function dscpClass(v
)
150 for (i
= 1; i
< dscp
.length
- 1; ++i
) // skip 1st and last elements
151 if (dscp
[i
][0] * 1 == v
* 1) {
159 qosg
.dataToView = function(data
) {
164 b
.push(((data
[0] == 1) ? 'To ' : 'From ') + data
[1]);
167 if (data
[2] == -1) b
.push('TCP/UDP');
168 else if (data
[2] >= 0) b
.push(protocols
[data
[2]] || data
[2]);
169 if (data
[3] != 'a') {
170 if (data
[3] == 'd') s
= 'Dst ';
171 else if (data
[3] == 's') s
= 'Src ';
173 b
.push(s
+ 'Port: ' + data
[4].replace(/:/g
, '-'));
177 for (i
= 0; i
< ipp2p
.length
; ++i
)
178 if (ipp2p
[i
][0] == data
[5]) {
179 b
.push('IPP2P: ' + ipp2p
[i
][1]);
184 else if (data
[6] != '') {
185 b
.push('L7: ' + data
[6])
189 s
= dscpClass(data
[9]);
190 if (s
!= '') b
.push(s
);
191 else b
.push('DSCP Value: ' + data
[9]);
195 b
.push('Transferred: ' + data
[7] + ((data
[8] == '') ? '<small>KB+</small>' : (' - ' + data
[8] + '<small>KB</small>')));
198 return [b
.join('<br>'), class1
[(data
[10] * 1) + 1][1], escapeHTML(data
[11]), (ruleCounter
>= 0) ? ''+ ++ruleCounter
: ''];
201 qosg
.fieldValuesToData = function(row
) {
202 var f
= fields
.getAll(row
);
203 var proto
= f
[2].value
;
204 var dir
= f
[3].value
;
205 var vdscp
= (f
[7].value
== '*') ? f
[8].value
: f
[7].value
;
206 if ((proto
!= -1) && (proto
!= 6) && (proto
!= 17)) dir
= 'a';
207 return [f
[0].value
, f
[0].selectedIndex
? f
[1].value
: '',
208 proto
, dir
, (dir
!= 'a') ? f
[4].value
: '',
209 f
[5].value
, f
[6].value
, f
[9].value
, f
[10].value
,
210 vdscp
, f
[11].value
, f
[12].value
];
213 qosg
.dataToFieldValues = function(data
) {
217 if (dscpClass(data
[9]) == '') s
= '*';
218 else s
= data
[9].toLowerCase();
221 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]];
224 qosg
.resetNewEditor = function() {
225 var f
= fields
.getAll(this.newEditor
);
226 f
[0].selectedIndex
= 0;
228 f
[2].selectedIndex
= 1;
229 f
[3].selectedIndex
= 0;
231 f
[5].selectedIndex
= 0;
232 f
[6].selectedIndex
= 0;
233 f
[7].selectedIndex
= 0;
237 f
[11].selectedIndex
= 5;
239 this.enDiFields(this.newEditor
);
240 ferror
.clearAll(fields
.getAll(this.newEditor
));
243 qosg
._disableNewEditor
= qosg
.disableNewEditor
;
244 qosg
.disableNewEditor = function(disable
) {
245 qosg
._disableNewEditor(disable
);
247 this.enDiFields(this.newEditor
);
251 qosg
.enDiFields = function(row
) {
252 var f
= fields
.getAll(row
);
255 f
[1].disabled
= (f
[0].selectedIndex
== 0);
257 x
= ((x
!= -1) && (x
!= 6) && (x
!= 17));
259 if (f
[3].selectedIndex
== 0) x
= 1;
262 f
[6].disabled
= (f
[5].selectedIndex
!= 0);
263 f
[5].disabled
= (f
[6].selectedIndex
!= 0);
265 f
[8].disabled
= (f
[7].value
!= '*');
268 function v_dscp(e
, quiet
)
270 if ((e
= E(e
)) == null) return 0;
272 if ((!v
.match(/^ *(0x)?[0-9A-Fa-f]+ *$/)) || (v
< 0) || (v
> 63)) {
273 ferror
.set(e
, 'Invalid DSCP value. Valid range: 0x00-0x3F', quiet
);
276 e
.value
= '0x' + (v
* 1).hex(2);
281 qosg
.verifyFields = function(row
, quiet
) {
282 var f
= fields
.getAll(row
);
285 this.enDiFields(row
);
289 if ((a
== 1) || (a
== 2)) {
290 if (!v_length(f
[1], quiet
, 1)) return 0;
291 if (!_v_iptaddr(f
[1], quiet
, 0, 1, 1)) return 0;
293 else if ((a
== 3) && (!v_mac(f
[1], quiet
))) return 0;
295 b
= f
[2].selectedIndex
;
296 if ((b
> 0) && (b
<= 3) && (f
[3].selectedIndex
!= 0) && (!v_iptport(f
[4], quiet
))) return 0;
298 var BMAX
= 1024 * 1024;
301 a
= e
.value
= e
.value
.trim();
303 if (!v_range(e
, quiet
, 0, BMAX
)) return 0;
308 b
= e
.value
= e
.value
.trim();
311 if (b
>= BMAX
) e
.value
= '';
312 else if (!v_range(e
, quiet
, 0, BMAX
)) return 0;
313 if (a
== '') f
[9].value
= a
= 0;
319 if ((b
!= '') && (a
>= b
)) {
320 ferror
.set(f
[9], 'Invalid range', quiet
);
324 if (f
[7].value
== '*') {
325 if (!v_dscp(f
[8], quiet
)) return 0;
327 else f
[8].value
= f
[7].value
;
329 if (!v_nodelim(f
[12], quiet
, 'Description', 1)) return 0;
330 return v_length(f
[12], quiet
);
333 qosg
.setup = function() {
335 a
= [[-2, 'Any Protocol'],[-1,'TCP/UDP'],[6,'TCP'],[17,'UDP']];
336 for (i
= 0; i
< 256; ++i
) {
337 if ((i
!= 6) && (i
!= 17)) a
.push([i
, protocols
[i
] || i
]);
341 this.init('qg', 'move', 50, [
343 { type
: 'select', options
: [[0,'Any Address'],[1,'Dst IP'],[2,'Src IP'],[3,'Src MAC']],
344 prefix
: '<div class="x1a">', suffix
: '</div>' },
345 { type
: 'text', prefix
: '<div class="x1b">', suffix
: '</div>' },
347 { type
: 'select', prefix
: '<div class="x2a">', suffix
: '</div>', options
: a
},
348 { type
: 'select', prefix
: '<div class="x2b">', suffix
: '</div>',
349 options
: [['a','Any Port'],['d','Dst Port'],['s','Src Port'],['x','Src or Dst']] },
350 { type
: 'text', prefix
: '<div class="x2c">', suffix
: '</div>' },
352 { type
: 'select', prefix
: '<div class="x3a">', suffix
: '</div>', options
: ipp2p
},
353 { type
: 'select', prefix
: '<div class="x3b">', suffix
: '</div>', options
: layer7
},
355 { type
: 'select', prefix
: '<div class="x4a">', suffix
: '</div>', options
: dscp
},
356 { type
: 'text', prefix
: '<div class="x4b">', suffix
: '</div>' },
358 { type
: 'text', prefix
: '<div class="x5a">', suffix
: '</div>' },
359 { type
: 'text', prefix
: '<div class="x5b"> - </div><div class="x5c">', suffix
: '</div><div class="x5d">KB Transferred</div>' }
361 { type
: 'select', options
: class1
, vtop
: 1 },
362 { type
: 'text', maxlen
: 32, vtop
: 1 }
365 this.headerSet(['Match Rule', 'Class', 'Description', '#']);
367 // addr_type < addr < proto < port_type < port < ipp2p < L7 < bcount < dscp < class < desc
369 a
= nvram
.qos_orules
.split('>');
370 for (i
= 0; i
< a
.length
; ++i
) {
374 // fixup < 0.08 !!! temp
375 b
.splice(7, 0, '', '', '');
377 else if (b
.length
== 10) {
382 if (b
.length
== 11) {
384 b
.splice(7, 1, c
[0], (c
.length
== 1) ? '' : c
[1]);
385 b
[11] = unescape(b
[11]);
388 b
[4] = b
[4].replace(/:/g
, '-');
389 qosg
.insertData(-1, b
);
393 this.showNewEditor();
394 this.resetNewEditor();
397 function verifyFields(focused
, quiet
)
404 if (qosg
.isEditing()) return;
409 c
= qosg
.getAllData();
411 for (i
= 0; i
< c
.length
; ++i
) {
413 b
[4] = b
[4].replace(/-/g
, ':');
414 b
.splice(7, 2, (b
[7] == '') ? '' : [b
[7],b
[8]].join(':'));
415 b
[10] = escapeD(b
[10]);
418 fom
.qos_orules
.value
= a
.join('>');
430 <body onload='init()'
>
431 <form id='_fom' method='post' action='tomato.cgi'
>
432 <table id='container' cellspacing=
0>
433 <tr><td colspan=
2 id='header'
>
434 <div class='title'
>Tomato
</div>
435 <div class='version'
>Version <%
version(); %></div>
437 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
439 <div id='ident'
><%
ident(); %></div>
443 <input type='hidden' name='_nextpage' value='qos-classify.asp'
>
444 <input type='hidden' name='_service' value='qos-restart'
>
445 <input type='hidden' name='qos_orules'
>
447 <div class='section-title'
>Outbound Direction
</div>
448 <div class='section'
>
449 <table class='tomato-grid' cellspacing=
1 id='qg'
></table>
453 <script type='text/javascript'
>
454 if (nvram
.qos_enable
!= '1') {
455 W('<div class="note-disabled"><b>QoS disabled.</b> <a href="qos-settings.asp">Enable »</a></div>');
458 show_notice1('<% notice("iptables"); %>');
465 <tr><td id='footer' colspan=
2>
466 <span id='footer-msg'
></span>
467 <input type='button' value='Save' id='save-button' onclick='save()'
>
468 <input type='button' value='Cancel' id='cancel-button' onclick='reloadPage();'
>
472 <script type='text/javascript'
>qosg
.setup();</script>