WNR3500Lv2: advanced-vlan patch.
[tomato.git] / release / src / router / www / advanced-vlan.asp
blob07075ba8ebeb8c5e41ddbcaaddabee082c8219fe
1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN'>
2 <!--
3 Tomato VLAN GUI
4 Copyright (C) 2011-2012 Augusto Bott
5 http://code.google.com/p/tomato-sdhc-vlan/
7 Tomato GUI
8 Copyright (C) 2006-2007 Jonathan Zarate
9 http://www.polarcloud.com/tomato/
11 Tomato VLAN update and bug correction
12 Copyright (C) 2011-2012 Vicente Soriano
13 http://tomatoraf.com
15 For use with Tomato Firmware only.
16 No part of this file may be used without permission.
17 -->
18 <html>
19 <head>
20 <meta http-equiv='content-type' content='text/html;charset=utf-8'>
21 <meta name='robots' content='noindex,nofollow'>
22 <title>[<% ident(); %>] Advanced: VLAN</title>
23 <link rel='stylesheet' type='text/css' href='tomato.css'>
24 <% css(); %>
25 <script type='text/javascript' src='tomato.js'></script>
26 <style type='text/css'>
27 #vlan-grid .co1,
28 #vlan-grid .co2,
29 #vlan-grid .co3,
30 #vlan-grid .co4,
31 #vlan-grid .co5,
32 #vlan-grid .co6,
33 #vlan-grid .co7,
34 #vlan-grid .co8,
35 #vlan-grid .co9,
36 #vlan-grid .co10,
37 #vlan-grid .co11,
38 #vlan-grid .co12,
39 #vlan-grid .co13,
40 #vlan-grid .co14 {
41 text-align: center;
43 #vlan-grid .co2 {
44 width: 60px;
46 #vlan-grid .centered {
47 text-align: center;
49 </style>
50 <script type='text/javascript' src='wireless.jsx?_http_id=<% nv(http_id); %>'></script>
51 <script type='text/javascript' src='interfaces.js'></script>
52 <script type='text/javascript'>
53 <% nvram ("vlan0ports,vlan1ports,vlan2ports,vlan3ports,vlan4ports,vlan5ports,vlan6ports,vlan7ports,vlan8ports,vlan9ports,vlan10ports,vlan11ports,vlan12ports,vlan13ports,vlan14ports,vlan15ports,vlan0hwname,vlan1hwname,vlan2hwname,vlan3hwname,vlan4hwname,vlan5hwname,vlan6hwname,vlan7hwname,vlan8hwname,vlan9hwname,vlan10hwname,vlan11hwname,vlan12hwname,vlan13hwname,vlan14hwname,vlan15hwname,wan_ifnameX,manual_boot_nv,boardtype,boardflags,trunk_vlan_so,lan_ifname,lan_ifnames,lan1_ifname,lan1_ifnames,lan2_ifname,lan2_ifnames,lan3_ifname,lan3_ifnames,boardrev,vlan0tag,vlan0vid,vlan1vid,vlan2vid,vlan3vid,vlan4vid,vlan5vid,vlan6vid,vlan7vid,vlan8vid,vlan9vid,vlan10vid,vlan11vid,vlan12vid,vlan13vid,vlan14vid,vlan15vid");%>
55 var port_vlan_supported = 0;
56 var trunk_vlan_supported = 0;
58 // does not seem to be strictly necessary for boardflags as it's supposed to be a bitmap
59 nvram['boardflags'] = ((nvram['boardflags'].toLowerCase().indexOf('0x') != -1) ? '0x' : '') + String('0000' + ((nvram['boardflags'].toLowerCase()).replace('0x',''))).slice(-4);
60 // but the contents of router/shared/id.c seem to indicate string formatting/padding might be required for some models as we check if strings match
61 nvram['boardtype'] = ((nvram['boardtype'].toLowerCase().indexOf('0x') != -1) ? '0x' : '') + String('0000' + ((nvram['boardtype'].toLowerCase()).replace('0x',''))).slice(-4);
63 // see http://www.dd-wrt.com/wiki/index.php/Hardware#Boardflags and router/shared/id.c
64 if(nvram['boardflags'] & 0x0100) { // BFL_ENETVLAN = this board has vlan capability
65 port_vlan_supported = 1;
68 // TESTED ONLY ON WRT54G v2 (boardtype 0x0101) and WRT54GL v1.1 (boardtype 0x0467)
69 // attempt of cross-referencing boardtypes/routers mentioned on id.c and the wiki page above
70 switch(nvram['boardtype']) {
71 case '0x0467': // WRT54GL 1.x, WRT54GS 3.x/4.x
72 case '0x048e': // WL-520GU, WL-500G Premium v2
73 case '0x04ef': // WRT320N/E2000
74 case '0x04cf': // WRT610Nv2/E3000, RT-N16
75 case '0xf52c': // E4200v1
76 case '0xf52a': // E3200v1
77 case '0xf5b2': // RT-N66
78 trunk_vlan_supported = 1;
79 break;
80 default:
81 break;
84 // TESTED ONLY ON WRT54G v2 (boardtype 0x0101),WRT54GL v1.1 (boardtype 0x0467) and WNR3500L (boardtype 0x04cf)
85 // info on some of these boardtypes/routers obtained from
86 // http://wiki.openwrt.org/toh/asus/start
87 // http://wiki.openwrt.org/toh/linksys/start
88 // http://wiki.openwrt.org/toh/start
89 switch(nvram['boardtype']) {
90 case '0x0467': // WRT54GL 1.x, WRT54GS 3.x/4.x
91 if (nvram['boardrev'] == '0x13') { // WHR-G54S
92 COL_P0N = '1';
93 COL_P1N = '2';
94 COL_P2N = '3';
95 COL_P3N = '4';
96 COL_P4N = '0';
97 break;
99 case '0xa4cf': // Belkin F7D3301
100 if (nvram['boardrev'] == '0x1100') { //Belkin F5D8235-4 v3
101 COL_P0N = '1';
102 COL_P1N = '2';
103 COL_P2N = '3';
104 COL_P3N = '4';
105 COL_P4N = '0';
106 break;
108 case '0xd4cf': // Belkin F7D4301
109 case '0x048e': // WL-520GU, WL-500G Premium v2
110 case '0x0550': // RT-N53 (boardrev = 0x1442), RT-N10U ( boardrev = 0x1102)
111 if (((nvram['boardrev'] == '0x1102') || (nvram['boardrev'] == '0x1100')) || (nvram['boardrev'] == '0x1400')) { //RT-N10U, CW-5358U, L600N
112 COL_P0N = '1';
113 COL_P1N = '2';
114 COL_P2N = '3';
115 COL_P3N = '4';
116 COL_P4N = '0';
117 break;
119 if (nvram['boardrev'] == '0x1100') { //CW-5358U
120 COL_P0N = '1';
121 COL_P1N = '2';
122 COL_P2N = '3';
123 COL_P3N = '4';
124 COL_P4N = '0';
125 break;
127 COL_P0N = '3';
128 COL_P1N = '2';
129 COL_P2N = '1';
130 COL_P3N = '0';
131 COL_P4N = '4';
132 break;
133 case '0x04ef': // WRT320N/E2000
134 case '0x04cf': // WRT610Nv2/E3000, RT-N16, WNR3500L
135 case '0xf5b2': // RT-N66
136 case '0x052b': // WNR3500Lv2
137 COL_P0N = '4';
138 COL_P1N = '3';
139 COL_P2N = '2';
140 COL_P3N = '1';
141 COL_P4N = '0';
142 break;
143 case '0xf53a': // E1000v2.1/E1200v1
144 case '0xf53b': // E1000v2/E1500
145 if (((nvram['boot_hw_model'] == 'E1200') && (nvram['boot_hw_ver'] == '1.0')) || (nvram['boot_hw_model'] == 'E1500')) {
146 COL_P0N = '0';
147 COL_P1N = '1';
148 COL_P2N = '2';
149 COL_P3N = '3';
150 COL_P4N = '4';
151 break;
153 COL_P0N = '1';
154 COL_P1N = '2';
155 COL_P2N = '3';
156 COL_P3N = '4';
157 COL_P4N = '0';
158 break;
159 case '0xc550': // E1550
160 case '0xf550': // E2500
161 case '0x058e': // E900
162 case '0xf52a': // E3200
163 case '0xf52c': // E4200v1
164 case '0x1202': // HG320 - not sure, need test
165 if (nvram['boardrev'] == '0x1153') { //RG200E-CA type 0x058e same as E900
166 COL_P0N = '4';
167 COL_P1N = '3';
168 COL_P2N = '2';
169 COL_P3N = '1';
170 COL_P4N = '0';
171 break;
173 COL_P0N = '0';
174 COL_P1N = '1';
175 COL_P2N = '2';
176 COL_P3N = '3';
177 COL_P4N = '4';
178 break;
179 if (nvram['boardrev'] == '0x1204') { //rt-n15u
180 COL_P0N = '3';
181 COL_P1N = '2';
182 COL_P2N = '1';
183 COL_P3N = '0';
184 COL_P4N = '4';
185 break;
187 // should work on WRT54G v2/v3, WRT54GS v1/v2 and others
188 default:
189 COL_P0N = '1';
190 COL_P1N = '2';
191 COL_P2N = '3';
192 COL_P3N = '4';
193 COL_P4N = '0';
194 break;
197 var COL_VID = 0;
198 var COL_MAP = 1;
199 var COL_P0 = 2;
200 var COL_P0T = 3;
201 var COL_P1 = 4;
202 var COL_P1T = 5;
203 var COL_P2 = 6;
204 var COL_P2T = 7;
205 var COL_P3 = 8;
206 var COL_P3T = 9;
207 var COL_P4 = 10;
208 var COL_P4T = 11;
209 var COL_VID_DEF = 12;
210 var COL_BRI = 13;
212 var vlt = nvram.vlan0tag | '0';
214 // set to either 5 or 8 when nvram settings are read (FastE or GigE routers)
215 var SWITCH_INTERNAL_PORT=0;
216 // option made available for experimental purposes on routers known to support port-based VLANs, but not confirmed to support 801.11q trunks
217 var PORT_VLAN_SUPPORT_OVERRIDE = ((nvram['trunk_vlan_so'] == '1') ? 1 : 0);
219 function verifyFields(focused, quiet){
220 PORT_VLAN_SUPPORT_OVERRIDE=(E('_f_trunk_vlan_so').checked ? 1 : 0);
221 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
222 var u = wl_fface(uidx);
223 var wlan = E('_f_bridge_wlan'+u+'_to');
224 if(nvram.lan_ifname.length < 1)
225 wlan.options[0].disabled=true;
226 if(nvram.lan1_ifname.length < 1)
227 wlan.options[1].disabled=true;
228 if(nvram.lan2_ifname.length < 1)
229 wlan.options[2].disabled=true;
230 if(nvram.lan3_ifname.length < 1)
231 wlan.options[3].disabled=true;
233 var e = E('_vlan0tag');
234 if (!v_range('_vlan0tag', quiet, 0, 4080)) return 0;
235 var v = parseInt(e.value);
236 e.value = v - (v % 16);
237 if ((e.value != vlt) && (typeof(vlg) != 'undefined')) {
238 vlg.populate();
239 vlt = e.value;
241 return 1;
244 function save() {
245 if (vlg.isEditing()) return;
247 var fom = E('_fom');
248 fom.trunk_vlan_so.value = (E('_f_trunk_vlan_so').checked ? 1 : 0);
249 // wipe out relevant fields just in case this is not the first time we try to submit
250 for (var i = 0 ; i <= MAX_VLAN_ID ; i++) {
251 fom['vlan' + i + 'ports'].value = '';
252 fom['vlan' + i + 'hwname'].value = '';
253 fom['vlan' + i + 'vid'].value = '';
255 fom['wan_ifnameX'].value = '';
256 fom['lan_ifnames'].value = '';
257 fom['lan1_ifnames'].value = '';
258 fom['lan2_ifnames'].value = '';
259 fom['lan3_ifnames'].value = '';
261 var v = '';
262 var d = vlg.getAllData();
264 for (var i = 0; i < d.length; ++i) {
265 var p = '';
266 p += (d[i][COL_P0].toString() != '0') ? COL_P0N : '';
267 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P0T].toString() != '0')) ? 't' : '';
268 p += trailingSpace(p);
270 p += (d[i][COL_P1].toString() != '0') ? COL_P1N : '';
271 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P1T].toString() != '0')) ? 't' : '';
272 p += trailingSpace(p);
274 p += (d[i][COL_P2].toString() != '0') ? COL_P2N : '';
275 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P2T].toString() != '0')) ? 't' : '';
276 p += trailingSpace(p);
278 p += (d[i][COL_P3].toString() != '0') ? COL_P3N : '';
279 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P3T].toString() != '0')) ? 't' : '';
280 p += trailingSpace(p);
282 p += (d[i][COL_P4].toString() != '0') ? COL_P4N : '';
283 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P4T].toString() != '0')) ? 't' : '';
284 p += trailingSpace(p);
286 p += (d[i][COL_VID_DEF].toString() != '0') ? (SWITCH_INTERNAL_PORT + '*') : SWITCH_INTERNAL_PORT;
288 // arrange port numbers in ascending order just to be safe (not sure if this is really needed... mostly, cosmetics?)
289 p = p.split(" ");
290 p = p.sort(cmpInt);
291 p = p.join(" ");
293 v += (d[i][COL_VID_DEF].toString() != '0') ? d[i][0] : '';
295 fom['vlan'+d[i][COL_VID]+'ports'].value = p;
296 fom['vlan'+d[i][COL_VID]+'hwname'].value = 'et0';
297 fom['vlan'+d[i][COL_VID]+'vid'].value = ((d[i][COL_MAP].toString() != '') && (d[i][COL_MAP].toString() != '0')) ? d[i][COL_MAP] : '';
299 fom['wan_ifnameX'].value += (d[i][COL_BRI] == '2') ? 'vlan'+d[i][0] : '';
300 fom['lan_ifnames'].value += (d[i][COL_BRI] == '3') ? 'vlan'+d[i][0] : '';
301 /* REMOVE-BEGIN
302 // fom['lan_ifnames'].value += trailingSpace(fom['lan_ifnames'].value);
303 // alert('vlan'+d[i][0]+'ports='+fom['vlan'+d[i][0]+'ports'].value+'\nvlan'+d[i][0]+'hwname='+fom['vlan'+d[i][0]+'hwname'].value);
304 REMOVE-END */
305 fom['lan1_ifnames'].value += (d[i][COL_BRI] == '4') ? 'vlan'+d[i][0] : '';
306 fom['lan2_ifnames'].value += (d[i][COL_BRI] == '5') ? 'vlan'+d[i][0] : '';
307 fom['lan3_ifnames'].value += (d[i][COL_BRI] == '6') ? 'vlan'+d[i][0] : '';
310 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
311 var u = wl_fface(uidx);
312 var wlan = E('_f_bridge_wlan'+u+'_to');
313 /* REMOVE-BEGIN
314 // var wlan = E('_f_bridge_wlan_to');
315 // alert(wlan.selectedIndex);
316 REMOVE-END */
317 switch(parseInt(wlan.selectedIndex)) {
318 case 0:
319 fom['lan_ifnames'].value += ' ' + wl_ifaces[uidx][0];
320 break;
321 case 1:
322 fom['lan1_ifnames'].value += ' ' + wl_ifaces[uidx][0];
323 break;
324 case 2:
325 fom['lan2_ifnames'].value += ' ' + wl_ifaces[uidx][0];
326 break;
327 case 3:
328 fom['lan3_ifnames'].value += ' ' + wl_ifaces[uidx][0];
329 break;
332 /* REMOVE-BEGIN
333 // var lif = nvram['lan_ifnames'].split(' ');
334 // for (var j = 0; j < lif.length; j++) {
335 // fom['lan_ifnames'].value += (lif[j].indexOf('vlan') != -1) ? '' : lif[j];
336 // fom['lan_ifnames'].value += trailingSpace(fom['lan_ifnames'].value);
337 // }
338 // alert('lan_ifnames=' + fom['lan_ifnames'].value + '\n' +
339 // 'lan1_ifnames=' + fom['lan1_ifnames'].value + '\n' +
340 // 'lan2_ifnames=' + fom['lan2_ifnames'].value + '\n' +
341 // 'lan3_ifnames=' + fom['lan3_ifnames'].value);
342 REMOVE-END */
344 // for some models, Tomato checks for a few vital/crucial nvram settings at init time
345 // in some cases, if some/any of them are not found, a full nvram reset/clean could be triggered
346 // so, to (try to) play it safe, we check for the 1st needed/available/required
347 // VLAN for FastE (vlan0 is usually LAN) and GigE routers (vlan1 is usually LAN)
348 if((fom['vlan0ports'].value.length < 1) || (fom['vlan0hwname'].value.length < 1) ||
349 (fom['vlan1ports'].value.length < 1) || (fom['vlan1hwname'].value.length < 1))
350 fom['manual_boot_nv'].value = '1';
351 else
352 fom['manual_boot_nv'].value = nvram['manual_boot_nv'];
354 var e = E('footer-msg');
356 if(vlg.countWan() != 1) {
357 e.innerHTML = 'Cannot proceed: one VID must be assigned to WAN.';
358 e.style.visibility = 'visible';
359 setTimeout(
360 function() {
361 e.innerHTML = '';
362 e.style.visibility = 'hidden';
363 }, 5000);
364 return;
367 if(vlg.countLan(0) != 1) {
368 e.innerHTML = 'Cannot proceed: one and only one VID must be assigned to the primary LAN (br0).';
369 e.style.visibility = 'visible';
370 setTimeout(
371 function() {
372 e.innerHTML = '';
373 e.style.visibility = 'hidden';
374 }, 5000);
375 return;
378 if (v.length < 1) {
379 e.innerHTML = 'Cannot proceed without setting a default VID';
380 e.style.visibility = 'visible';
381 setTimeout(
382 function() {
383 e.innerHTML = '';
384 e.style.visibility = 'hidden';
385 }, 5000);
386 return;
389 if (confirm("Router must be rebooted to proceed. Commit changes to NVRAM and reboot now?"))
390 form.submit(fom, 0);
393 function trailingSpace(s)
395 return ((s.length>0)&&(s.charAt(s.length-1) != ' ')) ? ' ' : '';
398 if(port_vlan_supported) { // aka if(supported_hardware) block
399 var vlg = new TomatoGrid();
400 vlg.setup = function() {
401 this.init('vlan-grid', '', (MAX_VLAN_ID + 1), [
402 { type: 'select', options: [[0, '0'],[1, '1'],[2, '2'],[3, '3'],[4, '4'],[5, '5'],[6, '6'],[7, '7'],[8, '8'],[9, '9'],[10, '10'],[11, '11'],[12, '12'],[13, '13'],[14, '14'],[15, '15']], prefix: '<div class="centered">', suffix: '</div>' },
403 { type: 'text', maxlen: 4, prefix: '<div class="centered">', suffix: '</div>' },
404 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
405 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
406 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
407 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
408 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
409 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
410 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
411 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
412 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
413 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
414 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
415 { type: 'select', options: [[1, 'none'],[2, 'WAN'],[3, 'LAN (br0)'],[4, 'LAN1 (br1)'],[5, 'LAN2 (br2)'],[6, 'LAN3 (br3)']], prefix: '<div class="centered">', suffix: '</div>' }]);
417 this.headerSet(['VLAN', 'VID', 'Port 1', 'Tagged', 'Port 2', 'Tagged', 'Port 3', 'Tagged', 'Port 4', 'Tagged', 'WAN Port', 'Tagged', 'Default', 'Bridge']);
419 vlg.populate();
420 vlg.canDelete = false;
421 vlg.sort(0);
422 vlg.showNewEditor();
423 vlg.resetNewEditor();
426 vlg.populate = function() {
427 vlg.removeAllData();
429 // find out which vlans are supposed to be bridged to each LAN
430 var bridged = [];
432 for (var i = 0 ; i <= MAX_BRIDGE_ID ; i++) {
433 var j = (i == 0) ? '' : i.toString();
434 var l = nvram['lan' + j + '_ifnames'].split(' ');
435 /* REMOVE-BEGIN
436 // alert('lan' + j + '_ifnames=' + l);
437 REMOVE-END */
438 for (var k = 0 ; k < l.length; k++) {
439 /* REMOVE-BEGIN
440 // alert("bridge br" + i + "=vlan" + parseInt(l[k].replace('vlan','')));
441 REMOVE-END */
442 if(l[k].indexOf('vlan') != -1) {
443 /* REMOVE-BEGIN
444 // alert('lan' + j + '_ifname=br' + nvram['lan' + j + '_ifname'].replace('br',''));
445 REMOVE-END */
446 if (nvram['lan' + j + '_ifname'] != '')
447 bridged[parseInt(l[k].replace('vlan',''))] = (3 + parseInt(nvram['lan' + j + '_ifname'].replace('br',''))).toString();
448 else
449 bridged[parseInt(l[k].replace('vlan',''))] = '1';
451 // WLAN
452 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
453 if(l[k].indexOf(wl_ifaces[uidx][0]) != -1) {
454 E('_f_bridge_wlan'+wl_fface(uidx)+'_to').selectedIndex=i;
460 // WAN port
461 bridged[parseInt(nvram['wan_ifnameX'].replace('vlan',''))] = '2';
463 // go thru all possible VLANs
464 for (var i = 0 ; i <= MAX_VLAN_ID ; i++) {
465 var port = [];
466 var tagged = [];
467 if ((nvram['vlan' + i + 'hwname'].length > 0) || (nvram['vlan' + i + 'ports'].length > 0)) {
468 // (re)initialize our bitmap for this particular iteration
469 for (var j=0; j <= MAX_PORT_ID ; j++) {
470 port[j] = '0';
471 tagged[j] = '0';
473 // which ports are members of this VLAN?
474 var m=nvram['vlan' + i + 'ports'].split(' ');
475 for (var j = 0; j < (m.length) ; j++) {
476 port[parseInt(m[j].charAt(0))] = '1';
477 tagged[parseInt(m[j].charAt(0))] = (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (m[j].indexOf('t') != -1)) ? '1' : '0';
480 if (port_vlan_supported) {
481 if((nvram['vlan' + i + 'ports']).indexOf('*') != -1)
482 SWITCH_INTERNAL_PORT=(nvram['vlan' + i + 'ports']).charAt((nvram['vlan' + i + 'ports']).indexOf('*')-1);
484 vlg.insertData(-1, [ i.toString(),
485 ((nvram['vlan' + i + 'vid'] != '') && (nvram['vlan' + i + 'vid'] > 0)) ? (nvram['vlan' + i + 'vid']).toString() : '0',
486 port[COL_P0N], tagged[COL_P0N],
487 port[COL_P1N], tagged[COL_P1N],
488 port[COL_P2N], tagged[COL_P2N],
489 port[COL_P3N], tagged[COL_P3N],
490 port[COL_P4N], tagged[COL_P4N],
491 (((nvram['vlan' + i + 'ports']).indexOf('*') != -1) ? '1' : '0' ),
492 (bridged[i] != null) ? bridged[i] : '1' ]);
498 vlg.countElem = function(f, v)
500 var data = this.getAllData();
501 var total = 0;
502 for (var i = 0; i < data.length; ++i) {
503 total += (data[i][f] == v) ? 1 : 0;
505 return total;
508 vlg.countDefaultVID = function()
510 return this.countElem(COL_VID_DEF,1);
513 vlg.countVID = function (v)
515 return this.countElem(COL_VID,v);
518 vlg.countWan = function()
520 return this.countElem(COL_BRI,2);
523 vlg.countLan = function(l)
525 return this.countElem(COL_BRI,l+3);
528 vlg.verifyFields = function(row, quiet) {
529 var valid = 1;
530 var f = fields.getAll(row);
532 for(var i=0; i<= MAX_VLAN_ID ; i++) {
533 f[COL_VID].options[i].disabled = (this.countVID(i) > 0);
536 for (var i=0; i <= MAX_BRIDGE_ID; i++) {
537 var j = (i==0) ? '' : i.toString();
538 f[COL_BRI].options[i+2].disabled = (nvram['lan' + j + '_ifname'].length < 1);
541 if (!v_range(f[COL_MAP], quiet, 0, 4094)) valid = 0;
543 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P0].checked == 1)) {
544 f[COL_P0T].disabled=0;
545 /* REMOVE-BEGIN
546 // if((f[COL_P0T].checked==0) || (this.countElem(COL_P0,1)>0) )
547 // if(this.countElem(COL_P0,1)>0) {
548 // }
549 REMOVE-END */
550 } else {
551 f[COL_P0T].disabled=1;
552 f[COL_P0T].checked=0;
554 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P1].checked == 1)) {
555 f[COL_P1T].disabled=0;
556 } else {
557 f[COL_P1T].disabled=1;
558 f[COL_P1T].checked=0;
560 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P2].checked == 1)) {
561 f[COL_P2T].disabled=0;
562 } else {
563 f[COL_P2T].disabled=1;
564 f[COL_P2T].checked=0;
566 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P3].checked == 1)) {
567 f[COL_P3T].disabled=0;
568 } else {
569 f[COL_P3T].disabled=1;
570 f[COL_P3T].checked=0;
572 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P4].checked == 1)) {
573 f[COL_P4T].disabled=0;
574 } else {
575 f[COL_P4T].disabled=1;
576 f[COL_P4T].checked=0;
579 if ((f[COL_P0].checked == 1) && (this.countElem(COL_P0,1)>0)) {
580 if (((this.countElem(COL_P0,1) != this.countElem(COL_P0T,1)) || (f[COL_P0T].checked==0))) {
581 ferror.set(f[COL_P0T], 'Port 1 cannot be assigned to more than one VLAN unless frames are tagged on all VLANs Port 1 is member', quiet);
582 valid=0;
583 } else {
584 ferror.clear(f[COL_P0T]);
587 if ((f[COL_P1].checked == 1) && (this.countElem(COL_P1,1)>0)) {
588 if (((this.countElem(COL_P1,1) != this.countElem(COL_P1T,1)) || (f[COL_P1T].checked==0))) {
589 ferror.set(f[COL_P1T], 'Port 2 cannot be assigned to more than one VLAN unless frames are tagged on all VLANs Port 2 is member', quiet);
590 valid=0;
591 } else {
592 ferror.clear(f[COL_P1T]);
595 if ((f[COL_P2].checked == 1) && (this.countElem(COL_P2,1)>0)) {
596 if (((this.countElem(COL_P2,1) != this.countElem(COL_P2T,1)) || (f[COL_P2T].checked==0))) {
597 ferror.set(f[COL_P2T], 'Port 3 cannot be assigned to more than one VLAN unless frames are tagged on all VLANs Port 3 is member', quiet);
598 valid=0;
599 } else {
600 ferror.clear(f[COL_P2T]);
603 if ((f[COL_P3].checked == 1) && (this.countElem(COL_P3,1)>0)) {
604 if (((this.countElem(COL_P3,1) != this.countElem(COL_P3T,1)) || (f[COL_P3T].checked==0))) {
605 ferror.set(f[COL_P3T], 'Port 4 cannot be assigned to more than one VLAN unless frames are tagged on all VLANs Port 4 is member', quiet);
606 valid=0;
607 } else {
608 ferror.clear(f[COL_P3T]);
611 if ((f[COL_P4].checked == 1) && (this.countElem(COL_P4,1)>0)) {
612 if (((this.countElem(COL_P4,1) != this.countElem(COL_P4T,1)) || (f[COL_P4T].checked==0))) {
613 ferror.set(f[COL_P4T], 'WAN port cannot be assigned to more than one VLAN unless frames are tagged on all VLANs WAN port is member', quiet);
614 valid=0;
615 } else {
616 ferror.clear(f[COL_P4T]);
620 if(this.countDefaultVID() > 0) {
621 f[COL_VID_DEF].disabled=1;
622 f[COL_VID_DEF].checked=0;
625 if((this.countDefaultVID() > 0) && (f[COL_VID_DEF].checked ==1)) {
626 ferror.set(f[COL_VID_DEF], 'Only one VID can be selected as the default VID', quiet);
627 valid = 0;
628 } else {
629 ferror.clear(f[COL_VID_DEF]);
632 if(this.countVID(f[COL_VID].selectedIndex) > 0) {
633 ferror.set(f[COL_VID], 'Cannot add more than one entry with VID ' + f[0].selectedIndex, quiet);
634 valid = 0;
635 } else {
636 ferror.clear(f[COL_VID]);
639 if ((this.countWan() > 0) && (f[COL_BRI].selectedIndex == 1)) {
640 ferror.set(f[COL_BRI],'Only one VID can be used as WAN at any time', quiet);
641 valid = 0;
642 } else {
643 ferror.clear(f[COL_BRI]);
646 for(var i=0; i<4; i++) {
647 if ((this.countLan(i) > 0) && (f[COL_BRI].selectedIndex == (i+2))) {
648 ferror.set(f[COL_BRI],'One and only one VID can be used for LAN' + ((i==0) ? '' : i ) + ' (br'+i+') at any time', quiet);
649 valid = 0;
650 } else {
651 ferror.clear(f[COL_BRI]);
655 return valid;
658 vlg.dataToView = function(data) {
659 return [data[COL_VID],
660 ((data[COL_MAP].toString() == '') || (data[COL_MAP].toString() == '0')) ? (parseInt(E('_vlan0tag').value) * 1 + data[COL_VID] *1 ).toString() : data[COL_MAP].toString(),
661 (data[COL_P0].toString() != '0') ? 'Yes' : '',
662 (data[COL_P0T].toString() != '0') ? 'On' : '',
663 (data[COL_P1].toString() != '0') ? 'Yes' : '',
664 (data[COL_P1T].toString() != '0') ? 'On' : '',
665 (data[COL_P2].toString() != '0') ? 'Yes' : '',
666 (data[COL_P2T].toString() != '0') ? 'On' : '',
667 (data[COL_P3].toString() != '0') ? 'Yes' : '',
668 (data[COL_P3T].toString() != '0') ? 'On' : '',
669 (data[COL_P4].toString() != '0') ? 'Yes' : '',
670 (data[COL_P4T].toString() != '0') ? 'On' : '',
671 (data[COL_VID_DEF].toString() != '0') ? '*' : '',
672 ['', 'WAN', 'LAN (br0)', 'LAN1 (br1)', 'LAN2 (br2)', 'LAN3 (br3)' ][data[COL_BRI] - 1]];
675 vlg.dataToFieldValues = function (data) {
676 return [data[COL_VID],
677 data[COL_MAP],
678 (data[COL_P0] != 0) ? 'checked' : '',
679 (data[COL_P0T] != 0) ? 'checked' : '',
680 (data[COL_P1] != 0) ? 'checked' : '',
681 (data[COL_P1T] != 0) ? 'checked' : '',
682 (data[COL_P2] != 0) ? 'checked' : '',
683 (data[COL_P2T] != 0) ? 'checked' : '',
684 (data[COL_P3] != 0) ? 'checked' : '',
685 (data[COL_P3T] != 0) ? 'checked' : '',
686 (data[COL_P4] != 0) ? 'checked' : '',
687 (data[COL_P4T] != 0) ? 'checked' : '',
688 (data[COL_VID_DEF] != 0) ? 'checked' : '',
689 data[COL_BRI]];
692 vlg.fieldValuesToData = function(row) {
693 var f = fields.getAll(row);
694 return [f[COL_VID].value,
695 f[COL_MAP].value,
696 f[COL_P0].checked ? 1 : 0,
697 f[COL_P0T].checked ? 1 : 0,
698 f[COL_P1].checked ? 1 : 0,
699 f[COL_P1T].checked ? 1 : 0,
700 f[COL_P2].checked ? 1 : 0,
701 f[COL_P2T].checked ? 1 : 0,
702 f[COL_P3].checked ? 1 : 0,
703 f[COL_P3T].checked ? 1 : 0,
704 f[COL_P4].checked ? 1 : 0,
705 f[COL_P4T].checked ? 1 : 0,
706 f[COL_VID_DEF].checked ? 1 : 0,
707 f[COL_BRI].value];
710 vlg.onCancel = function() {
711 this.removeEditor();
712 this.showSource();
713 this.disableNewEditor(false);
715 this.resetNewEditor();
718 vlg.onAdd = function() {
719 var data;
721 this.moving = null;
722 this.rpHide();
724 if (!this.verifyFields(this.newEditor, false)) return;
726 data = this.fieldValuesToData(this.newEditor);
727 this.insertData(-1, data);
729 this.disableNewEditor(false);
730 this.resetNewEditor();
732 this.resort();
735 vlg.onOK = function() {
736 var i, data, view;
738 if (!this.verifyFields(this.editor, false)) return;
740 data = this.fieldValuesToData(this.editor);
741 view = this.dataToView(data);
743 this.source.setRowData(data);
744 for (i = 0; i < this.source.cells.length; ++i) {
745 this.source.cells[i].innerHTML = view[i];
748 this.removeEditor();
749 this.showSource();
750 this.disableNewEditor(false);
752 this.resetNewEditor();
753 this.resort();
756 vlg.onDelete = function() {
757 this.removeEditor();
758 elem.remove(this.source);
759 this.source = null;
760 this.disableNewEditor(false);
762 this.resetNewEditor();
765 vlg.sortCompare = function(a, b) {
766 var obj = TGO(a);
767 var col = obj.sortColumn;
768 if (this.sortColumn == 0) {
769 var r = cmpInt(parseInt(a.cells[col].innerHTML), parseInt(b.cells[col].innerHTML));
770 } else {
771 var r = cmpText(a.cells[col].innerHTML, b.cells[col].innerHTML);
773 return obj.sortAscending ? r : -r;
776 vlg.resetNewEditor = function() {
777 var f = fields.getAll(this.newEditor);
779 for (var i=0; i <= MAX_BRIDGE_ID; i++) {
780 var j = (i==0) ? '' : i.toString();
781 f[COL_BRI].options[i+2].disabled = (nvram['lan' + j + '_ifname'].length < 1);
784 f[COL_MAP].value = '0';
786 f[COL_VID].selectedIndex=0;
787 var t = MAX_VLAN_ID;
788 while((this.countVID(f[COL_VID].selectedIndex) > 0) && (t > 0)) {
789 f[COL_VID].selectedIndex = (f[COL_VID].selectedIndex%(MAX_VLAN_ID))+1;
790 t--;
793 for(var i=0; i<= MAX_VLAN_ID ; i++) {
794 f[COL_VID].options[i].disabled = (this.countVID(i) > 0);
797 f[COL_P0].checked = 0;
798 f[COL_P0T].checked = 0;
799 f[COL_P0T].disabled = 1;
800 f[COL_P1].checked = 0;
801 f[COL_P1T].checked = 0;
802 f[COL_P1T].disabled = 1;
803 f[COL_P2].checked = 0;
804 f[COL_P2T].checked = 0;
805 f[COL_P2T].disabled = 1;
806 f[COL_P3].checked = 0;
807 f[COL_P3T].checked = 0;
808 f[COL_P3T].disabled = 1;
809 f[COL_P4].checked = 0;
810 f[COL_P4T].checked = 0;
811 f[COL_P4T].disabled = 1;
812 f[COL_VID_DEF].checked = 0;
813 if (this.countDefaultVID()>0)
814 f[COL_VID_DEF].disabled = 1;
815 f[COL_BRI].selectedIndex = 0;
816 ferror.clearAll(fields.getAll(this.newEditor));
818 } // end of the so-called if(supported_device) block
820 function init() {
821 if(port_vlan_supported) {
822 vlg.recolor();
823 vlg.resetNewEditor();
824 var c;
825 if (((c = cookie.get('advanced_vlan_notes_vis')) != null) && (c == '1')) toggleVisibility("notes");
826 if (((c = cookie.get('advanced_vlan_wireless_vis')) != null) && (c == '1')) toggleVisibility("wireless");
827 if (((c = cookie.get('advanced_vlan_vidmap_vis')) != null) && (c == '1')) toggleVisibility("vidmap");
831 function toggleVisibility(whichone) {
832 if (E('sesdiv_' + whichone).style.display == '') {
833 E('sesdiv_' + whichone).style.display = 'none';
834 E('sesdiv_' + whichone + '_showhide').innerHTML = '(Click here to show)';
835 cookie.set('advanced_vlan_' + whichone + '_vis', 0);
836 } else {
837 E('sesdiv_' + whichone).style.display='';
838 E('sesdiv_' + whichone + '_showhide').innerHTML = '(Click here to hide)';
839 cookie.set('advanced_vlan_' + whichone + '_vis', 1);
843 function earlyInit() {
844 if(!port_vlan_supported) {
845 E('save-button').disabled = 1;
846 return;
848 PORT_VLAN_SUPPORT_OVERRIDE = ((nvram['trunk_vlan_so'] == '1') ? 1 : 0);
851 </script>
852 </head>
853 <body onload='init()'>
854 <form id='_fom' method='post' action='tomato.cgi'>
855 <table id='container' cellspacing=0>
856 <tr><td colspan=2 id='header'>
857 <div class='title'>Tomato</div>
858 <div class='version'>Version <% version(); %></div>
859 </td></tr>
860 <tr id='body'><td id='navi'><script type='text/javascript'>navi()</script></td>
861 <td id='content'>
862 <div id='ident'><% ident(); %></div>
863 <input type='hidden' name='_nextpage' value='advanced-vlan.asp'>
864 <input type='hidden' name='_nextwait' value='30'>
865 <input type='hidden' name='_reboot' value='1'>
866 <input type='hidden' name='_nvset' value='1'>
867 <input type='hidden' name='_commit' value='1'>
868 <input type='hidden' name='vlan0ports'>
869 <input type='hidden' name='vlan1ports'>
870 <input type='hidden' name='vlan2ports'>
871 <input type='hidden' name='vlan3ports'>
872 <input type='hidden' name='vlan4ports'>
873 <input type='hidden' name='vlan5ports'>
874 <input type='hidden' name='vlan6ports'>
875 <input type='hidden' name='vlan7ports'>
876 <input type='hidden' name='vlan8ports'>
877 <input type='hidden' name='vlan9ports'>
878 <input type='hidden' name='vlan10ports'>
879 <input type='hidden' name='vlan11ports'>
880 <input type='hidden' name='vlan12ports'>
881 <input type='hidden' name='vlan13ports'>
882 <input type='hidden' name='vlan14ports'>
883 <input type='hidden' name='vlan15ports'>
884 <input type='hidden' name='vlan0hwname'>
885 <input type='hidden' name='vlan1hwname'>
886 <input type='hidden' name='vlan2hwname'>
887 <input type='hidden' name='vlan3hwname'>
888 <input type='hidden' name='vlan4hwname'>
889 <input type='hidden' name='vlan5hwname'>
890 <input type='hidden' name='vlan6hwname'>
891 <input type='hidden' name='vlan7hwname'>
892 <input type='hidden' name='vlan8hwname'>
893 <input type='hidden' name='vlan9hwname'>
894 <input type='hidden' name='vlan10hwname'>
895 <input type='hidden' name='vlan11hwname'>
896 <input type='hidden' name='vlan12hwname'>
897 <input type='hidden' name='vlan13hwname'>
898 <input type='hidden' name='vlan14hwname'>
899 <input type='hidden' name='vlan15hwname'>
900 <input type='hidden' name='wan_ifnameX'>
901 <input type='hidden' name='manual_boot_nv'>
902 <input type='hidden' name='lan_ifnames'>
903 <input type='hidden' name='lan1_ifnames'>
904 <input type='hidden' name='lan2_ifnames'>
905 <input type='hidden' name='lan3_ifnames'>
906 <input type='hidden' name='trunk_vlan_so'>
907 <input type='hidden' name='vlan0vid'>
908 <input type='hidden' name='vlan1vid'>
909 <input type='hidden' name='vlan2vid'>
910 <input type='hidden' name='vlan3vid'>
911 <input type='hidden' name='vlan4vid'>
912 <input type='hidden' name='vlan5vid'>
913 <input type='hidden' name='vlan6vid'>
914 <input type='hidden' name='vlan7vid'>
915 <input type='hidden' name='vlan8vid'>
916 <input type='hidden' name='vlan9vid'>
917 <input type='hidden' name='vlan10vid'>
918 <input type='hidden' name='vlan11vid'>
919 <input type='hidden' name='vlan12vid'>
920 <input type='hidden' name='vlan13vid'>
921 <input type='hidden' name='vlan14vid'>
922 <input type='hidden' name='vlan15vid'>
924 <div id='sesdiv' style='display:none'>
925 <div class='section-title'>VLAN</div>
926 <div class='section'>
927 <table class='tomato-grid' cellspacing=1 id='vlan-grid'></table>
928 </div>
930 <!-- / / / -->
932 <div class='section-title'>VID Offset <small><i><a href='javascript:toggleVisibility("vidmap");'><span id='sesdiv_vidmap_showhide'>(Click here to show)</span></a></i></small></div>
933 <div class='section' id='sesdiv_vidmap' style='display:none'>
934 <script type='text/javascript'>
935 createFieldTable('', [
936 { title: 'First 802.1Q VLAN tag', name: 'vlan0tag', type: 'text', maxlen:4, size:6,
937 value: fixInt(nvram.vlan0tag, 0, 4080, 0),
938 suffix: ' <small><i>(range: 0 - 4080; must be a multiple of 16; set to 0 to disable)</i></small>' }
940 </script>
941 </div>
943 <!-- / / / -->
945 <div class='section-title'>Wireless <small><i><a href='javascript:toggleVisibility("wireless");'><span id='sesdiv_wireless_showhide'>(Click here to show)</span></a></i></small></div>
946 <div class='section' id='sesdiv_wireless' style='display:none'>
947 <script type='text/javascript'>
948 var f = [];
949 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
950 var u = wl_fface(uidx);
951 f.push(
952 { title: ('Bridge ' + wl_ifaces[uidx][0] + ' to'), name: ('f_bridge_wlan'+u+'_to'), type: 'select',
953 options: [[0,'LAN (br0)'],[1,'LAN1 (br1)'],[2,'LAN2 (br2)'],[3,'LAN3 (br3)'],[4,'none']], value: 4 } );
955 createFieldTable('',f);
956 if(port_vlan_supported) vlg.setup();
957 </script>
958 </div>
960 <!-- / / / -->
962 <div class='section-title'>Notes <small><i><a href='javascript:toggleVisibility("notes");'><span id='sesdiv_notes_showhide'>(Click here to show)</span></a></i></small></div>
963 <div class='section' id='sesdiv_notes' style='display:none'>
964 <ul>
965 <li><b>VLAN</b> - Unique identifier of a VLAN.</li>
966 <li><b>VID</b> - <i>EXPERIMENTAL</i> - Allows overriding 'traditional' VLAN/VID mapping with arbitrary VIDs for each VLAN (set to '0' to use 'regular' VLAN/VID mappings instead). Warning: this hasn't been verified/tested on anything but a Cisco/Linksys E3000 and may not be supported by your particular device/model (<small><b><i>see notes on "VID Offset" below</i></b></small>).</li>
967 <li><b>Ports 1-4 &amp; WAN</b> - Which ethernet ports on the router should be members of this VLAN.</li>
968 <li><b>Tagged</b> - Enable 802.1Q tagging of ethernet frames on a particular port/VLAN
969 <script type='text/javascript'>
970 if(!trunk_vlan_supported)
971 W(' <i><b>(unknown support for this model...contact the developper (Victek))</i></b>');
972 </script>
973 </li>
974 <li><b>Default</b> - VLAN ID assigned to untagged frames received by the router.</li>
975 <li><b>Bridge</b> - Determines if this VLAN ID should be treated as WAN, part of a LAN bridge or just left alone (i.e. member of a 802.1Q trunk, being managed manually via scripts, etc...).</li>
976 </ul>
978 <ul>
979 <li><b>VID Offset</b> - <i>EXPERIMENTAL</i> - First 802.1Q VLAN tag to be used as <i>base/initial tag/VID</i> for VLAN and VID assignments. This allows using VIDs larger than 15 on (older) devices such as the Linksys WRT54GL v1.1 (in contiguous blocks/ranges with up to 16 VLANs/VIDs). Set to '0' (zero) to disable this feature and VLANs will have the very same/identical value for its VID, as usual (from 0 to 15).</li>
980 </ul>
982 <ul>
983 <li><b>Wireless</b> - Assignments of wireless interfaces to different LAN briges. You should probably be using and/or check things on <a href=advanced-wlanvifs.asp>Advanced/Virtual Wireless</a> and <a href=basic-network.asp>Basic/Network</a>.</li>
984 </ul>
986 <small>
987 <ul>
988 <li><b>Other relevant notes/hints:</b>
989 <ul>
990 <li>One VID <i>must</i> be assigned to WAN.</li>
991 <li>One VID <i>must</i> be selected as the default.</li>
992 <script type='text/javascript'>
993 if((trunk_vlan_supported) || (nvram.trunk_vlan_so == '1')) {
994 W('<li>To prevent 802.1Q compatibility issues, avoid using VID "0" as 802.1Q specifies that frames with a tag of "0" do not belong to any VLAN (the tag contains only user priority information).</li>');
995 W('<li>It may be also recommended to avoid using VID "1" as some vendors consider it special/reserved (for management purposes).</li>');
997 </script>
998 </ul>
999 <br>
1000 <ul>
1001 <li>This is an <b>experimental</b> feature and hasn't been tested in anything but a Linksys WRT54GL v1.1 running a Teaman-ND K24 build and a Cisco/Linksys E3000 running a Teaman-RT K26 build.</li>
1002 <li>There's lots of things that could go wrong, please do think about what you're doing and take a backup before hitting the 'Save' button on this page!</li>
1003 </ul>
1004 </ul>
1005 <div id='trunk_vlan_override' style='display:none'>
1006 <div class='section-title'>Trunk VLAN support override (experimental)</div>
1007 <div class='section'>
1008 <script type='text/javascript'>
1009 createFieldTable('', [
1010 { title: 'Enable', name: 'f_trunk_vlan_so', type: 'checkbox', value: nvram.trunk_vlan_so == '1' },
1012 </script>
1013 </div>
1014 </div>
1015 </div>
1016 </small>
1017 </div>
1018 </div>
1019 <script type='text/javascript'>
1020 if(!port_vlan_supported)
1021 W('<i>This feature is not supported on this router.</i>');
1022 else {
1023 E('sesdiv').style.display = '';
1024 if(!trunk_vlan_supported)
1025 E('trunk_vlan_override').style.display = '';
1027 </script>
1028 </td></tr>
1029 <tr><td id='footer' colspan=2>
1030 <span id='footer-msg'></span>
1031 <input type='button' value='Save' id='save-button' onclick='save()'>
1032 <input type='button' value='Cancel' id='cancel-button' onclick='javascript:reloadPage();'>
1033 </td></tr>
1034 </table>
1035 </form>
1036 <script type='text/javascript'>earlyInit(); verifyFields(null,1);</script>
1037 </body>
1038 </html>