MIPSR2 - Router Model name is used to setup the Vlan Port order
[tomato.git] / release / src / router / www / advanced-vlan-r1.asp
blob55c83ad4d8c59783c31b17fc560720813374123d
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 For use with Tomato Firmware only.
12 No part of this file may be used without permission.
13 -->
14 <html>
15 <head>
16 <meta http-equiv='content-type' content='text/html;charset=utf-8'>
17 <meta name='robots' content='noindex,nofollow'>
18 <title>[<% ident(); %>] Advanced: VLAN</title>
19 <link rel='stylesheet' type='text/css' href='tomato.css'>
20 <% css(); %>
21 <script type='text/javascript' src='tomato.js'></script>
22 <style type='text/css'>
23 #vlan-grid .co1,
24 #vlan-grid .co2,
25 #vlan-grid .co3,
26 #vlan-grid .co4,
27 #vlan-grid .co5,
28 #vlan-grid .co6,
29 #vlan-grid .co7,
30 #vlan-grid .co8,
31 #vlan-grid .co9,
32 #vlan-grid .co10,
33 #vlan-grid .co11,
34 #vlan-grid .co12,
35 #vlan-grid .co13,
36 #vlan-grid .co14 {
37 text-align: center;
39 #vlan-grid .co2 {
40 width: 60px;
42 #vlan-grid .centered {
43 text-align: center;
45 </style>
46 <script type='text/javascript' src='wireless.jsx?_http_id=<% nv(http_id); %>'></script>
47 <script type='text/javascript' src='interfaces.js'></script>
48 <script type='text/javascript'>
49 <% 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,wan2_ifnameX,wan3_ifnameX,wan4_ifnameX,manual_boot_nv,boardtype,boardflags,boardnum,boardrev,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,model,mwan_num");%>
51 var port_vlan_supported = 0;
52 var trunk_vlan_supported = 0;
54 // does not seem to be strictly necessary for boardflags as it's supposed to be a bitmap
55 nvram['boardflags'] = ((nvram['boardflags'].toLowerCase().indexOf('0x') != -1) ? '0x' : '') + String('0000' + ((nvram['boardflags'].toLowerCase()).replace('0x',''))).slice(-4);
56 // 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
57 nvram['boardtype'] = ((nvram['boardtype'].toLowerCase().indexOf('0x') != -1) ? '0x' : '') + String('0000' + ((nvram['boardtype'].toLowerCase()).replace('0x',''))).slice(-4);
59 // see http://www.dd-wrt.com/wiki/index.php/Hardware#Boardflags and router/shared/id.c
60 if(nvram['boardflags'] & 0x0100) { // BFL_ENETVLAN = this board has vlan capability
61 port_vlan_supported = 1;
64 // TESTED ONLY ON WRT54G v2 (boardtype 0x0101) and WRT54GL v1.1 (boardtype 0x0467)
65 // attempt of cross-referencing boardtypes/routers mentioned on id.c and the wiki page above
66 switch(nvram['boardtype']) {
67 case '0x0467': // WRT54GL 1.x, WRT54GS 3.x/4.x
68 case '0x048e': // WL-520GU, WL-500G Premium v2
69 case '0x04ef': // WRT320N/E2000
70 case '0x04cf': // WRT610Nv2/E3000, RT-N16
71 case '0xf52c': // E4200v1
72 trunk_vlan_supported = 1;
73 break;
74 default:
75 break;
78 // TESTED ONLY ON WRT54G v2 (boardtype 0x0101),WRT54GL v1.1 (boardtype 0x0467) and WNR3500L (boardtype 0x04cf)
79 // info on some of these boardtypes/routers obtained from
80 // http://wiki.openwrt.org/toh/asus/start
81 // http://wiki.openwrt.org/toh/linksys/start
82 // http://wiki.openwrt.org/toh/start
83 switch(nvram['boardtype']) {
84 case '0x0467': // WRT54GL 1.x, WRT54GS 3.x/4.x
85 if (nvram['boardrev'] == '0x13') { // WHR-G54S
86 COL_P0N = '1';
87 COL_P1N = '2';
88 COL_P2N = '3';
89 COL_P3N = '4';
90 COL_P4N = '0';
91 break;
93 case '0xa4cf': // Belkin F7D3301
94 if (nvram['boardrev'] == '0x1100'){ //Belkin F5D8235-4 v3
95 COL_P0N = '1';
96 COL_P1N = '2';
97 COL_P2N = '3';
98 COL_P3N = '4';
99 COL_P4N = '0';
100 break;
102 case '0xd4cf': // Belkin F7D4301
103 case '0x048e': // WL-520GU, WL-500G Premium v2
104 COL_P0N = '3';
105 COL_P1N = '2';
106 COL_P2N = '1';
107 COL_P3N = '0';
108 COL_P4N = '4';
109 break;
110 case '0x04ef': // WRT320N/E2000
111 case '0x04cf': // WRT610Nv2/E3000, RT-N16, WNR3500L
112 COL_P0N = '4';
113 COL_P1N = '3';
114 COL_P2N = '2';
115 COL_P3N = '1';
116 COL_P4N = '0';
117 break;
118 case '0xf52c': // E4200v1
119 COL_P0N = '0';
120 COL_P1N = '1';
121 COL_P2N = '2';
122 COL_P3N = '3';
123 COL_P4N = '4';
124 break;
125 // should work on WRT54G v2/v3, WRT54GS v1/v2 and others
126 default:
127 COL_P0N = '1';
128 COL_P1N = '2';
129 COL_P2N = '3';
130 COL_P3N = '4';
131 COL_P4N = '0';
132 break;
135 var COL_VID = 0;
136 var COL_MAP = 1;
137 var COL_P0 = 2;
138 var COL_P0T = 3;
139 var COL_P1 = 4;
140 var COL_P1T = 5;
141 var COL_P2 = 6;
142 var COL_P2T = 7;
143 var COL_P3 = 8;
144 var COL_P3T = 9;
145 var COL_P4 = 10;
146 var COL_P4T = 11;
147 var COL_VID_DEF = 12;
148 var COL_BRI = 13;
150 var vlt = nvram.vlan0tag | '0';
152 // set to either 5 or 8 when nvram settings are read (FastE or GigE routers)
153 var SWITCH_INTERNAL_PORT=0;
154 // option made available for experimental purposes on routers known to support port-based VLANs, but not confirmed to support 801.11q trunks
155 var PORT_VLAN_SUPPORT_OVERRIDE = ((nvram['trunk_vlan_so'] == '1') ? 1 : 0);
157 function verifyFields(focused, quiet){
158 PORT_VLAN_SUPPORT_OVERRIDE=(E('_f_trunk_vlan_so').checked ? 1 : 0);
159 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
160 var u = wl_fface(uidx);
161 var wlan = E('_f_bridge_wlan'+u+'_to');
162 if(nvram.lan_ifname.length < 1)
163 wlan.options[0].disabled=true;
164 if(nvram.lan1_ifname.length < 1)
165 wlan.options[1].disabled=true;
166 if(nvram.lan2_ifname.length < 1)
167 wlan.options[2].disabled=true;
168 if(nvram.lan3_ifname.length < 1)
169 wlan.options[3].disabled=true;
171 var e = E('_vlan0tag');
172 if (!v_range('_vlan0tag', quiet, 0, 4080)) return 0;
173 var v = parseInt(e.value);
174 e.value = v - (v % 16);
175 if ((e.value != vlt) && (typeof(vlg) != 'undefined')) {
176 vlg.populate();
177 vlt = e.value;
179 return 1;
182 function save() {
183 if (vlg.isEditing()) return;
185 var fom = E('_fom');
186 fom.trunk_vlan_so.value = (E('_f_trunk_vlan_so').checked ? 1 : 0);
187 // wipe out relevant fields just in case this is not the first time we try to submit
188 for (var i = 0 ; i <= MAX_VLAN_ID ; i++) {
189 fom['vlan' + i + 'ports'].value = '';
190 fom['vlan' + i + 'hwname'].value = '';
191 fom['vlan' + i + 'vid'].value = '';
193 fom['wan_ifnameX'].value = '';
194 fom['lan_ifnames'].value = '';
195 fom['lan1_ifnames'].value = '';
196 fom['lan2_ifnames'].value = '';
197 fom['lan3_ifnames'].value = '';
198 fom['wan2_ifnameX'].value = '';
200 var v = '';
201 var d = vlg.getAllData();
203 for (var i = 0; i < d.length; ++i) {
204 var p = '';
205 p += (d[i][COL_P0].toString() != '0') ? COL_P0N : '';
206 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P0T].toString() != '0')) ? 't' : '';
207 p += trailingSpace(p);
209 p += (d[i][COL_P1].toString() != '0') ? COL_P1N : '';
210 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P1T].toString() != '0')) ? 't' : '';
211 p += trailingSpace(p);
213 p += (d[i][COL_P2].toString() != '0') ? COL_P2N : '';
214 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P2T].toString() != '0')) ? 't' : '';
215 p += trailingSpace(p);
217 p += (d[i][COL_P3].toString() != '0') ? COL_P3N : '';
218 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P3T].toString() != '0')) ? 't' : '';
219 p += trailingSpace(p);
221 p += (d[i][COL_P4].toString() != '0') ? COL_P4N : '';
222 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P4T].toString() != '0')) ? 't' : '';
223 p += trailingSpace(p);
225 p += (d[i][COL_VID_DEF].toString() != '0') ? (SWITCH_INTERNAL_PORT + '*') : SWITCH_INTERNAL_PORT;
227 // arrange port numbers in ascending order just to be safe (not sure if this is really needed... mostly, cosmetics?)
228 p = p.split(" ");
229 p = p.sort(cmpInt);
230 p = p.join(" ");
232 v += (d[i][COL_VID_DEF].toString() != '0') ? d[i][0] : '';
234 fom['vlan'+d[i][COL_VID]+'ports'].value = p;
235 fom['vlan'+d[i][COL_VID]+'hwname'].value = 'et0';
236 fom['vlan'+d[i][COL_VID]+'vid'].value = ((d[i][COL_MAP].toString() != '') && (d[i][COL_MAP].toString() != '0')) ? d[i][COL_MAP] : '';
238 fom['wan_ifnameX'].value += (d[i][COL_BRI] == '2') ? 'vlan'+d[i][0] : '';
239 fom['lan_ifnames'].value += (d[i][COL_BRI] == '3') ? 'vlan'+d[i][0] : '';
240 /* REMOVE-BEGIN
241 // fom['lan_ifnames'].value += trailingSpace(fom['lan_ifnames'].value);
242 // 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);
243 REMOVE-END */
244 fom['lan1_ifnames'].value += (d[i][COL_BRI] == '4') ? 'vlan'+d[i][0] : '';
245 fom['lan2_ifnames'].value += (d[i][COL_BRI] == '5') ? 'vlan'+d[i][0] : '';
246 fom['lan3_ifnames'].value += (d[i][COL_BRI] == '6') ? 'vlan'+d[i][0] : '';
247 fom['wan2_ifnameX'].value += (d[i][COL_BRI] == '7') ? 'vlan'+d[i][0] : '';
250 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
251 var u = wl_fface(uidx);
252 var wlan = E('_f_bridge_wlan'+u+'_to');
253 /* REMOVE-BEGIN
254 // var wlan = E('_f_bridge_wlan_to');
255 // alert(wlan.selectedIndex);
256 REMOVE-END */
257 switch(parseInt(wlan.selectedIndex)) {
258 case 0:
259 fom['lan_ifnames'].value += ' ' + wl_ifaces[uidx][0];
260 break;
261 case 1:
262 fom['lan1_ifnames'].value += ' ' + wl_ifaces[uidx][0];
263 break;
264 case 2:
265 fom['lan2_ifnames'].value += ' ' + wl_ifaces[uidx][0];
266 break;
267 case 3:
268 fom['lan3_ifnames'].value += ' ' + wl_ifaces[uidx][0];
269 break;
272 /* REMOVE-BEGIN
273 // var lif = nvram['lan_ifnames'].split(' ');
274 // for (var j = 0; j < lif.length; j++) {
275 // fom['lan_ifnames'].value += (lif[j].indexOf('vlan') != -1) ? '' : lif[j];
276 // fom['lan_ifnames'].value += trailingSpace(fom['lan_ifnames'].value);
277 // }
278 // alert('lan_ifnames=' + fom['lan_ifnames'].value + '\n' +
279 // 'lan1_ifnames=' + fom['lan1_ifnames'].value + '\n' +
280 // 'lan2_ifnames=' + fom['lan2_ifnames'].value + '\n' +
281 // 'lan3_ifnames=' + fom['lan3_ifnames'].value);
282 REMOVE-END */
284 // fom['manual_boot_nv'].value = nvram['manual_boot_nv']; //Prevent vlan reset to default
285 fom['manual_boot_nv'].value = 1 //Prevent vlan reset to default
287 var e = E('footer-msg');
289 if(vlg.countWan() != 1) {
290 e.innerHTML = 'Cannot proceed: one VID must be assigned to WAN.';
291 e.style.visibility = 'visible';
292 setTimeout(
293 function() {
294 e.innerHTML = '';
295 e.style.visibility = 'hidden';
296 }, 5000);
297 return;
300 if(vlg.countLan(0) != 1) {
301 e.innerHTML = 'Cannot proceed: one and only one VID must be assigned to the primary LAN (br0).';
302 e.style.visibility = 'visible';
303 setTimeout(
304 function() {
305 e.innerHTML = '';
306 e.style.visibility = 'hidden';
307 }, 5000);
308 return;
311 if (v.length < 1) {
312 e.innerHTML = 'Cannot proceed without setting a default VID';
313 e.style.visibility = 'visible';
314 setTimeout(
315 function() {
316 e.innerHTML = '';
317 e.style.visibility = 'hidden';
318 }, 5000);
319 return;
322 if (confirm("Router must be rebooted to proceed. Commit changes to NVRAM and reboot now?"))
323 form.submit(fom, 0);
326 function trailingSpace(s)
328 return ((s.length>0)&&(s.charAt(s.length-1) != ' ')) ? ' ' : '';
331 if(port_vlan_supported) { // aka if(supported_hardware) block
332 var vlg = new TomatoGrid();
333 vlg.setup = function() {
334 this.init('vlan-grid', '', (MAX_VLAN_ID + 1), [
335 { 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>' },
336 { type: 'text', maxlen: 4, prefix: '<div class="centered">', suffix: '</div>' },
337 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
338 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
339 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
340 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
341 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
342 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
343 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
344 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
345 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
346 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
347 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
348 { type: 'select', options: [[1, 'none'],[2, 'WAN'],[3, 'LAN (br0)'],[4, 'LAN1 (br1)'],[5, 'LAN2 (br2)'],[6, 'LAN3 (br3)'],[7, 'WAN2'],
349 ], prefix: '<div class="centered">', suffix: '</div>' }]);
351 this.headerSet(['VLAN', 'VID', 'Port 1', 'Tagged', 'Port 2', 'Tagged', 'Port 3', 'Tagged', 'Port 4', 'Tagged', 'WAN Port', 'Tagged', 'Default', 'Bridge']);
353 vlg.populate();
354 vlg.canDelete = false;
355 vlg.sort(0);
356 vlg.showNewEditor();
357 vlg.resetNewEditor();
360 vlg.populate = function() {
361 vlg.removeAllData();
363 // find out which vlans are supposed to be bridged to each LAN
364 var bridged = [];
366 for (var i = 0 ; i <= MAX_BRIDGE_ID ; i++) {
367 var j = (i == 0) ? '' : i.toString();
368 var l = nvram['lan' + j + '_ifnames'].split(' ');
369 /* REMOVE-BEGIN
370 // alert('lan' + j + '_ifnames=' + l);
371 REMOVE-END */
372 for (var k = 0 ; k < l.length; k++) {
373 /* REMOVE-BEGIN
374 // alert("bridge br" + i + "=vlan" + parseInt(l[k].replace('vlan','')));
375 REMOVE-END */
376 if(l[k].indexOf('vlan') != -1) {
377 /* REMOVE-BEGIN
378 // alert('lan' + j + '_ifname=br' + nvram['lan' + j + '_ifname'].replace('br',''));
379 REMOVE-END */
380 if (nvram['lan' + j + '_ifname'] != '')
381 bridged[parseInt(l[k].replace('vlan',''))] = (3 + parseInt(nvram['lan' + j + '_ifname'].replace('br',''))).toString();
382 else
383 bridged[parseInt(l[k].replace('vlan',''))] = '1';
385 // WLAN
386 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
387 if(l[k].indexOf(wl_ifaces[uidx][0]) != -1) {
388 E('_f_bridge_wlan'+wl_fface(uidx)+'_to').selectedIndex=i;
394 // WAN port
395 bridged[parseInt(nvram['wan_ifnameX'].replace('vlan',''))] = '2';
396 bridged[parseInt(nvram['wan2_ifnameX'].replace('vlan',''))] = '7';
398 // go thru all possible VLANs
399 for (var i = 0 ; i <= MAX_VLAN_ID ; i++) {
400 var port = [];
401 var tagged = [];
402 if ((nvram['vlan' + i + 'hwname'].length > 0) || (nvram['vlan' + i + 'ports'].length > 0)) {
403 // (re)initialize our bitmap for this particular iteration
404 for (var j=0; j <= MAX_PORT_ID ; j++) {
405 port[j] = '0';
406 tagged[j] = '0';
408 // which ports are members of this VLAN?
409 var m=nvram['vlan' + i + 'ports'].split(' ');
410 for (var j = 0; j < (m.length) ; j++) {
411 port[parseInt(m[j].charAt(0))] = '1';
412 tagged[parseInt(m[j].charAt(0))] = (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (m[j].indexOf('t') != -1)) ? '1' : '0';
415 if (port_vlan_supported) {
416 if((nvram['vlan' + i + 'ports']).indexOf('*') != -1)
417 SWITCH_INTERNAL_PORT=(nvram['vlan' + i + 'ports']).charAt((nvram['vlan' + i + 'ports']).indexOf('*')-1);
419 vlg.insertData(-1, [ i.toString(),
420 ((nvram['vlan' + i + 'vid'] != '') && (nvram['vlan' + i + 'vid'] > 0)) ? (nvram['vlan' + i + 'vid']).toString() : '0',
421 port[COL_P0N], tagged[COL_P0N],
422 port[COL_P1N], tagged[COL_P1N],
423 port[COL_P2N], tagged[COL_P2N],
424 port[COL_P3N], tagged[COL_P3N],
425 port[COL_P4N], tagged[COL_P4N],
426 (((nvram['vlan' + i + 'ports']).indexOf('*') != -1) ? '1' : '0' ),
427 (bridged[i] != null) ? bridged[i] : '1' ]);
433 vlg.countElem = function(f, v)
435 var data = this.getAllData();
436 var total = 0;
437 for (var i = 0; i < data.length; ++i) {
438 total += (data[i][f] == v) ? 1 : 0;
440 return total;
443 vlg.countDefaultVID = function()
445 return this.countElem(COL_VID_DEF,1);
448 vlg.countVID = function (v)
450 return this.countElem(COL_VID,v);
453 vlg.countWan = function()
455 return this.countElem(COL_BRI,2);
458 vlg.countWan2 = function()
460 return this.countElem(COL_BRI,7);
464 vlg.countLan = function(l)
466 return this.countElem(COL_BRI,l+3);
469 vlg.verifyFields = function(row, quiet) {
470 var valid = 1;
471 var f = fields.getAll(row);
473 for(var i=0; i<= MAX_VLAN_ID ; i++) {
474 f[COL_VID].options[i].disabled = (this.countVID(i) > 0);
477 for (var i=0; i <= MAX_BRIDGE_ID; i++) {
478 var j = (i==0) ? '' : i.toString();
479 f[COL_BRI].options[i+2].disabled = (nvram['lan' + j + '_ifname'].length < 1);
482 if (!v_range(f[COL_MAP], quiet, 0, 4094)) valid = 0;
484 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P0].checked == 1)) {
485 f[COL_P0T].disabled=0;
486 /* REMOVE-BEGIN
487 // if((f[COL_P0T].checked==0) || (this.countElem(COL_P0,1)>0) )
488 // if(this.countElem(COL_P0,1)>0) {
489 // }
490 REMOVE-END */
491 } else {
492 f[COL_P0T].disabled=1;
493 f[COL_P0T].checked=0;
495 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P1].checked == 1)) {
496 f[COL_P1T].disabled=0;
497 } else {
498 f[COL_P1T].disabled=1;
499 f[COL_P1T].checked=0;
501 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P2].checked == 1)) {
502 f[COL_P2T].disabled=0;
503 } else {
504 f[COL_P2T].disabled=1;
505 f[COL_P2T].checked=0;
507 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P3].checked == 1)) {
508 f[COL_P3T].disabled=0;
509 } else {
510 f[COL_P3T].disabled=1;
511 f[COL_P3T].checked=0;
513 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P4].checked == 1)) {
514 f[COL_P4T].disabled=0;
515 } else {
516 f[COL_P4T].disabled=1;
517 f[COL_P4T].checked=0;
520 if ((f[COL_P0].checked == 1) && (this.countElem(COL_P0,1)>0)) {
521 if (((this.countElem(COL_P0,1) != this.countElem(COL_P0T,1)) || (f[COL_P0T].checked==0))) {
522 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);
523 valid=0;
524 } else {
525 ferror.clear(f[COL_P0T]);
528 if ((f[COL_P1].checked == 1) && (this.countElem(COL_P1,1)>0)) {
529 if (((this.countElem(COL_P1,1) != this.countElem(COL_P1T,1)) || (f[COL_P1T].checked==0))) {
530 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);
531 valid=0;
532 } else {
533 ferror.clear(f[COL_P1T]);
536 if ((f[COL_P2].checked == 1) && (this.countElem(COL_P2,1)>0)) {
537 if (((this.countElem(COL_P2,1) != this.countElem(COL_P2T,1)) || (f[COL_P2T].checked==0))) {
538 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);
539 valid=0;
540 } else {
541 ferror.clear(f[COL_P2T]);
544 if ((f[COL_P3].checked == 1) && (this.countElem(COL_P3,1)>0)) {
545 if (((this.countElem(COL_P3,1) != this.countElem(COL_P3T,1)) || (f[COL_P3T].checked==0))) {
546 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);
547 valid=0;
548 } else {
549 ferror.clear(f[COL_P3T]);
552 if ((f[COL_P4].checked == 1) && (this.countElem(COL_P4,1)>0)) {
553 if (((this.countElem(COL_P4,1) != this.countElem(COL_P4T,1)) || (f[COL_P4T].checked==0))) {
554 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);
555 valid=0;
556 } else {
557 ferror.clear(f[COL_P4T]);
561 if(this.countDefaultVID() > 0) {
562 f[COL_VID_DEF].disabled=1;
563 f[COL_VID_DEF].checked=0;
566 if((this.countDefaultVID() > 0) && (f[COL_VID_DEF].checked ==1)) {
567 ferror.set(f[COL_VID_DEF], 'Only one VID can be selected as the default VID', quiet);
568 valid = 0;
569 } else {
570 ferror.clear(f[COL_VID_DEF]);
573 if(this.countVID(f[COL_VID].selectedIndex) > 0) {
574 ferror.set(f[COL_VID], 'Cannot add more than one entry with VID ' + f[0].selectedIndex, quiet);
575 valid = 0;
576 } else {
577 ferror.clear(f[COL_VID]);
580 if ((this.countWan() > 0) && (f[COL_BRI].selectedIndex == 1)) {
581 ferror.set(f[COL_BRI],'Only one VID can be used as WAN at any time', quiet);
582 valid = 0;
583 } else {
584 ferror.clear(f[COL_BRI]);
587 if ((this.countWan2() > 0) && (f[COL_BRI].selectedIndex == 6)) {
588 ferror.set(f[COL_BRI],'Only one VID can be used as WAN2 at any time', quiet);
589 valid = 0;
590 } else {
591 ferror.clear(f[COL_BRI]);
594 for(var i=0; i<4; i++) {
595 if ((this.countLan(i) > 0) && (f[COL_BRI].selectedIndex == (i+2))) {
596 ferror.set(f[COL_BRI],'One and only one VID can be used for LAN' + ((i==0) ? '' : i ) + ' (br'+i+') at any time', quiet);
597 valid = 0;
598 } else {
599 ferror.clear(f[COL_BRI]);
603 return valid;
606 vlg.dataToView = function(data) {
607 return [data[COL_VID],
608 ((data[COL_MAP].toString() == '') || (data[COL_MAP].toString() == '0')) ? (parseInt(E('_vlan0tag').value) * 1 + data[COL_VID] *1 ).toString() : data[COL_MAP].toString(),
609 (data[COL_P0].toString() != '0') ? 'Yes' : '',
610 (data[COL_P0T].toString() != '0') ? 'On' : '',
611 (data[COL_P1].toString() != '0') ? 'Yes' : '',
612 (data[COL_P1T].toString() != '0') ? 'On' : '',
613 (data[COL_P2].toString() != '0') ? 'Yes' : '',
614 (data[COL_P2T].toString() != '0') ? 'On' : '',
615 (data[COL_P3].toString() != '0') ? 'Yes' : '',
616 (data[COL_P3T].toString() != '0') ? 'On' : '',
617 (data[COL_P4].toString() != '0') ? 'Yes' : '',
618 (data[COL_P4T].toString() != '0') ? 'On' : '',
619 (data[COL_VID_DEF].toString() != '0') ? '*' : '',
620 ['', 'WAN', 'LAN (br0)', 'LAN1 (br1)', 'LAN2 (br2)', 'LAN3 (br3)', 'WAN2'
621 ][data[COL_BRI] - 1]];
624 vlg.dataToFieldValues = function (data) {
625 return [data[COL_VID],
626 data[COL_MAP],
627 (data[COL_P0] != 0) ? 'checked' : '',
628 (data[COL_P0T] != 0) ? 'checked' : '',
629 (data[COL_P1] != 0) ? 'checked' : '',
630 (data[COL_P1T] != 0) ? 'checked' : '',
631 (data[COL_P2] != 0) ? 'checked' : '',
632 (data[COL_P2T] != 0) ? 'checked' : '',
633 (data[COL_P3] != 0) ? 'checked' : '',
634 (data[COL_P3T] != 0) ? 'checked' : '',
635 (data[COL_P4] != 0) ? 'checked' : '',
636 (data[COL_P4T] != 0) ? 'checked' : '',
637 (data[COL_VID_DEF] != 0) ? 'checked' : '',
638 data[COL_BRI]];
641 vlg.fieldValuesToData = function(row) {
642 var f = fields.getAll(row);
643 return [f[COL_VID].value,
644 f[COL_MAP].value,
645 f[COL_P0].checked ? 1 : 0,
646 f[COL_P0T].checked ? 1 : 0,
647 f[COL_P1].checked ? 1 : 0,
648 f[COL_P1T].checked ? 1 : 0,
649 f[COL_P2].checked ? 1 : 0,
650 f[COL_P2T].checked ? 1 : 0,
651 f[COL_P3].checked ? 1 : 0,
652 f[COL_P3T].checked ? 1 : 0,
653 f[COL_P4].checked ? 1 : 0,
654 f[COL_P4T].checked ? 1 : 0,
655 f[COL_VID_DEF].checked ? 1 : 0,
656 f[COL_BRI].value];
659 vlg.onCancel = function() {
660 this.removeEditor();
661 this.showSource();
662 this.disableNewEditor(false);
664 this.resetNewEditor();
667 vlg.onAdd = function() {
668 var data;
670 this.moving = null;
671 this.rpHide();
673 if (!this.verifyFields(this.newEditor, false)) return;
675 data = this.fieldValuesToData(this.newEditor);
676 this.insertData(-1, data);
678 this.disableNewEditor(false);
679 this.resetNewEditor();
681 this.resort();
684 vlg.onOK = function() {
685 var i, data, view;
687 if (!this.verifyFields(this.editor, false)) return;
689 data = this.fieldValuesToData(this.editor);
690 view = this.dataToView(data);
692 this.source.setRowData(data);
693 for (i = 0; i < this.source.cells.length; ++i) {
694 this.source.cells[i].innerHTML = view[i];
697 this.removeEditor();
698 this.showSource();
699 this.disableNewEditor(false);
701 this.resetNewEditor();
702 this.resort();
705 vlg.onDelete = function() {
706 this.removeEditor();
707 elem.remove(this.source);
708 this.source = null;
709 this.disableNewEditor(false);
711 this.resetNewEditor();
714 vlg.sortCompare = function(a, b) {
715 var obj = TGO(a);
716 var col = obj.sortColumn;
717 if (this.sortColumn == 0) {
718 var r = cmpInt(parseInt(a.cells[col].innerHTML), parseInt(b.cells[col].innerHTML));
719 } else {
720 var r = cmpText(a.cells[col].innerHTML, b.cells[col].innerHTML);
722 return obj.sortAscending ? r : -r;
725 vlg.resetNewEditor = function() {
726 var f = fields.getAll(this.newEditor);
728 for (var i=0; i <= MAX_BRIDGE_ID; i++) {
729 var j = (i==0) ? '' : i.toString();
730 f[COL_BRI].options[i+2].disabled = (nvram['lan' + j + '_ifname'].length < 1);
733 f[COL_MAP].value = '0';
735 f[COL_VID].selectedIndex=0;
736 var t = MAX_VLAN_ID;
737 while((this.countVID(f[COL_VID].selectedIndex) > 0) && (t > 0)) {
738 f[COL_VID].selectedIndex = (f[COL_VID].selectedIndex%(MAX_VLAN_ID))+1;
739 t--;
742 for(var i=0; i<= MAX_VLAN_ID ; i++) {
743 f[COL_VID].options[i].disabled = (this.countVID(i) > 0);
746 f[COL_P0].checked = 0;
747 f[COL_P0T].checked = 0;
748 f[COL_P0T].disabled = 1;
749 f[COL_P1].checked = 0;
750 f[COL_P1T].checked = 0;
751 f[COL_P1T].disabled = 1;
752 f[COL_P2].checked = 0;
753 f[COL_P2T].checked = 0;
754 f[COL_P2T].disabled = 1;
755 f[COL_P3].checked = 0;
756 f[COL_P3T].checked = 0;
757 f[COL_P3T].disabled = 1;
758 f[COL_P4].checked = 0;
759 f[COL_P4T].checked = 0;
760 f[COL_P4T].disabled = 1;
761 f[COL_VID_DEF].checked = 0;
762 if (this.countDefaultVID()>0)
763 f[COL_VID_DEF].disabled = 1;
764 f[COL_BRI].selectedIndex = 0;
765 ferror.clearAll(fields.getAll(this.newEditor));
767 } // end of the so-called if(supported_device) block
769 function init() {
770 if(port_vlan_supported) {
771 vlg.recolor();
772 vlg.resetNewEditor();
773 var c;
774 if (((c = cookie.get('advanced_vlan_notes_vis')) != null) && (c == '1')) toggleVisibility("notes");
778 function toggleVisibility(whichone) {
779 if (E('sesdiv_' + whichone).style.display == '') {
780 E('sesdiv_' + whichone).style.display = 'none';
781 E('sesdiv_' + whichone + '_showhide').innerHTML = '(Click here to show)';
782 cookie.set('advanced_vlan_' + whichone + '_vis', 0);
783 } else {
784 E('sesdiv_' + whichone).style.display='';
785 E('sesdiv_' + whichone + '_showhide').innerHTML = '(Click here to hide)';
786 cookie.set('advanced_vlan_' + whichone + '_vis', 1);
790 function earlyInit() {
791 if(!port_vlan_supported) {
792 E('save-button').disabled = 1;
793 return;
795 PORT_VLAN_SUPPORT_OVERRIDE = ((nvram['trunk_vlan_so'] == '1') ? 1 : 0);
798 </script>
799 </head>
800 <body onload='init()'>
801 <form id='_fom' method='post' action='tomato.cgi'>
802 <table id='container' cellspacing=0>
803 <tr><td colspan=2 id='header'>
804 <div class='title'>Tomato</div>
805 <div class='version'>Version <% version(); %></div>
806 </td></tr>
807 <tr id='body'><td id='navi'><script type='text/javascript'>navi()</script></td>
808 <td id='content'>
809 <div id='ident'><% ident(); %></div>
810 <input type='hidden' name='_nextpage' value='advanced-vlan.asp'>
811 <input type='hidden' name='_nextwait' value='30'>
812 <input type='hidden' name='_reboot' value='1'>
813 <input type='hidden' name='_nvset' value='1'>
814 <input type='hidden' name='_commit' value='1'>
815 <input type='hidden' name='vlan0ports'>
816 <input type='hidden' name='vlan1ports'>
817 <input type='hidden' name='vlan2ports'>
818 <input type='hidden' name='vlan3ports'>
819 <input type='hidden' name='vlan4ports'>
820 <input type='hidden' name='vlan5ports'>
821 <input type='hidden' name='vlan6ports'>
822 <input type='hidden' name='vlan7ports'>
823 <input type='hidden' name='vlan8ports'>
824 <input type='hidden' name='vlan9ports'>
825 <input type='hidden' name='vlan10ports'>
826 <input type='hidden' name='vlan11ports'>
827 <input type='hidden' name='vlan12ports'>
828 <input type='hidden' name='vlan13ports'>
829 <input type='hidden' name='vlan14ports'>
830 <input type='hidden' name='vlan15ports'>
831 <input type='hidden' name='vlan0hwname'>
832 <input type='hidden' name='vlan1hwname'>
833 <input type='hidden' name='vlan2hwname'>
834 <input type='hidden' name='vlan3hwname'>
835 <input type='hidden' name='vlan4hwname'>
836 <input type='hidden' name='vlan5hwname'>
837 <input type='hidden' name='vlan6hwname'>
838 <input type='hidden' name='vlan7hwname'>
839 <input type='hidden' name='vlan8hwname'>
840 <input type='hidden' name='vlan9hwname'>
841 <input type='hidden' name='vlan10hwname'>
842 <input type='hidden' name='vlan11hwname'>
843 <input type='hidden' name='vlan12hwname'>
844 <input type='hidden' name='vlan13hwname'>
845 <input type='hidden' name='vlan14hwname'>
846 <input type='hidden' name='vlan15hwname'>
847 <input type='hidden' name='wan_ifnameX'>
848 <input type='hidden' name='wan2_ifnameX'>
849 <input type='hidden' name='manual_boot_nv'>
850 <input type='hidden' name='lan_ifnames'>
851 <input type='hidden' name='lan1_ifnames'>
852 <input type='hidden' name='lan2_ifnames'>
853 <input type='hidden' name='lan3_ifnames'>
854 <input type='hidden' name='trunk_vlan_so'>
855 <input type='hidden' name='vlan0vid'>
856 <input type='hidden' name='vlan1vid'>
857 <input type='hidden' name='vlan2vid'>
858 <input type='hidden' name='vlan3vid'>
859 <input type='hidden' name='vlan4vid'>
860 <input type='hidden' name='vlan5vid'>
861 <input type='hidden' name='vlan6vid'>
862 <input type='hidden' name='vlan7vid'>
863 <input type='hidden' name='vlan8vid'>
864 <input type='hidden' name='vlan9vid'>
865 <input type='hidden' name='vlan10vid'>
866 <input type='hidden' name='vlan11vid'>
867 <input type='hidden' name='vlan12vid'>
868 <input type='hidden' name='vlan13vid'>
869 <input type='hidden' name='vlan14vid'>
870 <input type='hidden' name='vlan15vid'>
872 <div id='sesdiv' style='display:none'>
873 <div class='section-title'>VLAN</div>
874 <div class='section'>
875 <table class='tomato-grid' cellspacing=1 id='vlan-grid'></table>
876 </div>
878 <!-- / / / -->
880 <div class='section-title'>VID Offset</div>
881 <div class='section'>
882 <script type='text/javascript'>
883 createFieldTable('', [
884 { title: 'First 802.1Q VLAN tag', name: 'vlan0tag', type: 'text', maxlen:4, size:6,
885 value: fixInt(nvram.vlan0tag, 0, 4080, 0),
886 suffix: ' <small><i>(range: 0 - 4080; must be a multiple of 16; set to 0 to disable)</i></small>' }
888 </script>
889 </div>
891 <!-- / / / -->
893 <div class='section-title'>Wireless</div>
894 <div class='section'>
895 <script type='text/javascript'>
896 var f = [];
897 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
898 var u = wl_fface(uidx);
899 f.push(
900 { title: ('Bridge ' + wl_ifaces[uidx][0] + ' to'), name: ('f_bridge_wlan'+u+'_to'), type: 'select',
901 options: [[0,'LAN (br0)'],[1,'LAN1 (br1)'],[2,'LAN2 (br2)'],[3,'LAN3 (br3)'],[4,'none']], value: 4 } );
903 createFieldTable('',f);
904 if(port_vlan_supported) vlg.setup();
905 </script>
906 </div>
908 <!-- / / / -->
909 <div class='section-title'>Trunk VLAN support override (experimental)</div>
910 <div class='section'>
911 <script type='text/javascript'>
912 createFieldTable('', [
913 { title: 'Enable', name: 'f_trunk_vlan_so', type: 'checkbox', value: nvram.trunk_vlan_so == '1' },
915 </script>
916 </div>
918 <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>
919 <div class='section' id='sesdiv_notes' style='display:none'>
920 <ul>
921 <li><b>VLAN</b> - Unique identifier of a VLAN.</li>
922 <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>
923 <li><b>Ports 1-4 &amp; WAN</b> - Which ethernet ports on the router should be members of this VLAN.</li>
924 <li><b>Tagged</b> - Enable 802.1Q tagging of ethernet frames on a particular port/VLAN
925 <script type='text/javascript'>
926 if(!trunk_vlan_supported)
927 W(' <i>(not known to be supported on this model)</i>');
928 </script>
929 </li>
930 <li><b>Default</b> - VLAN ID assigned to untagged frames received by the router.</li>
931 <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>
932 </ul>
934 <ul>
935 <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>
936 </ul>
938 <ul>
939 <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>
940 </ul>
942 <small>
943 <ul>
944 <li><b>Other relevant notes/hints:</b>
945 <ul>
946 <li>One VID <i>must</i> be assigned to WAN.</li>
947 <li>One VID <i>must</i> be selected as the default.</li>
948 <script type='text/javascript'>
949 if((trunk_vlan_supported) || (nvram.trunk_vlan_so == '1')) {
950 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>');
951 W('<li>It may be also recommended to avoid using VID "1" as some vendors consider it special/reserved (for management purposes).</li>');
953 </script>
954 </ul>
955 <br>
956 <ul>
957 <li>This is highly <b>experimental</b> 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>
958 <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>
959 <li>You've been warned!</li>
960 </ul>
961 </ul>
962 </div>
963 </div>
964 </small>
965 </div>
966 </div>
967 <script type='text/javascript'>
968 if(!port_vlan_supported)
969 W('<i>This feature is not supported on this router.</i>');
970 else {
971 E('sesdiv').style.display = '';
972 if(!trunk_vlan_supported)
973 E('trunk_vlan_override').style.display = '';
975 </script>
976 </td></tr>
977 <tr><td id='footer' colspan=2>
978 <span id='footer-msg'></span>
979 <input type='button' value='Save' id='save-button' onclick='save()'>
980 <input type='button' value='Cancel' id='cancel-button' onclick='javascript:reloadPage();'>
981 </td></tr>
982 </table>
983 </form>
984 <script type='text/javascript'>earlyInit(); verifyFields(null,1);</script>
985 </body>
986 </html>