Merge branch 'VLAN-GUI' into VLAN-MultiSSID
[tomato.git] / release / src / router / www / advanced-vlan.asp
blob93408d5652246c2930e5b8c2d666eaad81d85c7f
1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN'>
2 <!--
3 Tomato VLAN GUI
4 Copyright (C) 2011 Augusto Bott
5 http://code.google.com/p/tomato-sdhc-vlan/
7 For use with Tomato Firmware only.
8 No part of this file may be used without permission.
9 -->
10 <html>
11 <head>
12 <meta http-equiv='content-type' content='text/html;charset=utf-8'>
13 <meta name='robots' content='noindex,nofollow'>
14 <title>[<% ident(); %>] Advanced: VLAN</title>
15 <link rel='stylesheet' type='text/css' href='tomato.css'>
16 <% css(); %>
17 <script type='text/javascript' src='tomato.js'></script>
18 <style type='text/css'>
19 #vlan-grid .co1,
20 #vlan-grid .co2,
21 #vlan-grid .co3,
22 #vlan-grid .co4,
23 #vlan-grid .co5,
24 #vlan-grid .co6,
25 #vlan-grid .co7,
26 #vlan-grid .co8,
27 #vlan-grid .co9,
28 #vlan-grid .co10,
29 #vlan-grid .co11,
30 #vlan-grid .co12,
31 #vlan-grid .co13 {
32 text-align: center;
34 #vlan-grid .centered {
35 text-align: center;
37 </style>
38 <script type='text/javascript' src='wireless.jsx?_http_id=<% nv(http_id); %>'></script>
39 <script type='text/javascript' src='interfaces.js'></script>
40 <script type='text/javascript'>
41 <% 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");%>
43 var port_vlan_supported = 0;
44 var trunk_vlan_supported = 0;
46 // does not seem to be strictly necessary for boardflags as it's supposed to be a bitmap
47 nvram['boardflags'] = ((nvram['boardflags'].toLowerCase().indexOf('0x') != -1) ? '0x' : '') + String('0000' + ((nvram['boardflags'].toLowerCase()).replace('0x',''))).slice(-4);
48 // 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
49 nvram['boardtype'] = ((nvram['boardtype'].toLowerCase().indexOf('0x') != -1) ? '0x' : '') + String('0000' + ((nvram['boardtype'].toLowerCase()).replace('0x',''))).slice(-4);
51 // see http://www.dd-wrt.com/wiki/index.php/Hardware#Boardflags and router/shared/id.c
52 if(nvram['boardflags'] & 0x0100) { // BFL_ENETVLAN = this board has vlan capability
53 port_vlan_supported = 1;
56 // TESTED ONLY ON WRT54G v2 (boardtype 0x0101) and WRT54GL v1.1 (boardtype 0x0467)
57 // attempt of cross-referencing boardtypes/routers mentioned on id.c and the wiki page above
58 switch(nvram['boardtype']) {
59 case '0x0467': // WRT54GL 1.x, WRT54GS 3.x/4.x
60 case '0x048e': // WL-520GU, WL-500G Premium v2
61 case '0x04ef': // WRT320N/E2000
62 case '0x04cf': // WRT610Nv2/E3000, RT-N16
63 trunk_vlan_supported = 1;
64 break;
65 default:
66 break;
69 // TESTED ONLY ON WRT54G v2 (boardtype 0x0101),WRT54GL v1.1 (boardtype 0x0467) and WNR3500L (boardtype 0x04cf)
70 // info on some of these boardtypes/routers obtained from
71 // http://wiki.openwrt.org/toh/asus/start
72 // http://wiki.openwrt.org/toh/linksys/start
73 // http://wiki.openwrt.org/toh/start
74 switch(nvram['boardtype']) {
75 case '0x0467': // WRT54GL 1.x, WRT54GS 3.x/4.x
76 case '0x048e': // WL-520GU, WL-500G Premium v2
77 COL_P0N = '3';
78 COL_P1N = '2';
79 COL_P2N = '1';
80 COL_P3N = '0';
81 COL_P4N = '4';
82 break;
83 case '0x04ef': // WRT320N/E2000
84 case '0x04cf': // WRT610Nv2/E3000, RT-N16, WNR3500L
85 COL_P0N = '4';
86 COL_P1N = '3';
87 COL_P2N = '2';
88 COL_P3N = '1';
89 COL_P4N = '0';
90 break;
91 // should work on WRT54G v2/v3, WRT54GS v1/v2 and others
92 default:
93 COL_P0N = '1';
94 COL_P1N = '2';
95 COL_P2N = '3';
96 COL_P3N = '4';
97 COL_P4N = '0';
98 break;
101 var COL_VID = 0;
102 var COL_P0 = 1;
103 var COL_P0T = 2;
104 var COL_P1 = 3;
105 var COL_P1T = 4;
106 var COL_P2 = 5;
107 var COL_P2T = 6;
108 var COL_P3 = 7;
109 var COL_P3T = 8;
110 var COL_P4 = 9;
111 var COL_P4T = 10;
112 var COL_VID_DEF = 11;
113 var COL_BRI = 12;
115 // set to either 5 or 8 when nvram settings are read (FastE or GigE routers)
116 var SWITCH_INTERNAL_PORT=0;
117 // option made available for experimental purposes on routers known to support port-based VLANs, but not confirmed to support 801.11q trunks
118 var PORT_VLAN_SUPPORT_OVERRIDE=0;
120 function verifyFields(focused, quiet){
121 PORT_VLAN_SUPPORT_OVERRIDE=(E('_f_trunk_vlan_so').checked ? 1 : 0);
122 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
123 var u = wl_fface(uidx);
124 var wlan = E('_f_bridge_wlan'+u+'_to');
125 /* REMOVE-BEGIN
126 // var wlan = E('_f_bridge_wlan_to');
127 // if (wl_ifaces.length < 1) {
128 // wlan.disabled=true;
129 // } else {
130 REMOVE-END */
131 if(nvram.lan_ifname.length < 1)
132 wlan.options[0].disabled=true;
133 if(nvram.lan1_ifname.length < 1)
134 wlan.options[1].disabled=true;
135 if(nvram.lan2_ifname.length < 1)
136 wlan.options[2].disabled=true;
137 if(nvram.lan3_ifname.length < 1)
138 wlan.options[3].disabled=true;
142 function save() {
143 if (vlg.isEditing()) return;
145 var fom = E('_fom');
146 fom.trunk_vlan_so.value = (E('_f_trunk_vlan_so').checked ? 1 : 0);
147 // wipe out relevant fields just in case this is not the first time we try to submit
148 for (var i = 0 ; i <= MAX_VLAN_ID ; i++) {
149 fom['vlan' + i + 'ports'].value = '';
150 fom['vlan' + i + 'hwname'].value = '';
152 fom['wan_ifnameX'].value = '';
153 fom['lan_ifnames'].value = '';
154 fom['lan1_ifnames'].value = '';
155 fom['lan2_ifnames'].value = '';
156 fom['lan3_ifnames'].value = '';
158 var v = '';
159 var d = vlg.getAllData();
161 for (var i = 0; i < d.length; ++i) {
162 var p = '';
163 p += (d[i][COL_P0].toString() != '0') ? COL_P0N : '';
164 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P0T].toString() != '0')) ? 't' : '';
165 p += trailingSpace(p);
167 p += (d[i][COL_P1].toString() != '0') ? COL_P1N : '';
168 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P1T].toString() != '0')) ? 't' : '';
169 p += trailingSpace(p);
171 p += (d[i][COL_P2].toString() != '0') ? COL_P2N : '';
172 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P2T].toString() != '0')) ? 't' : '';
173 p += trailingSpace(p);
175 p += (d[i][COL_P3].toString() != '0') ? COL_P3N : '';
176 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P3T].toString() != '0')) ? 't' : '';
177 p += trailingSpace(p);
179 p += (d[i][COL_P4].toString() != '0') ? COL_P4N : '';
180 p += (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (d[i][COL_P4T].toString() != '0')) ? 't' : '';
181 p += trailingSpace(p);
183 p += (d[i][COL_VID_DEF].toString() != '0') ? (SWITCH_INTERNAL_PORT + '*') : SWITCH_INTERNAL_PORT;
185 // arrange port numbers in ascending order just to be safe (not sure if this is really needed... mostly, cosmetics?)
186 p = p.split(" ");
187 p = p.sort(cmpInt);
188 p = p.join(" ");
190 v += (d[i][COL_VID_DEF].toString() != '0') ? d[i][0] : '';
192 fom['vlan'+d[i][COL_VID]+'ports'].value = p;
193 fom['vlan'+d[i][COL_VID]+'hwname'].value = 'et0';
195 fom['wan_ifnameX'].value += (d[i][COL_BRI] == '2') ? 'vlan'+d[i][0] : '';
196 fom['lan_ifnames'].value += (d[i][COL_BRI] == '3') ? 'vlan'+d[i][0] : '';
197 /* REMOVE-BEGIN
198 // fom['lan_ifnames'].value += trailingSpace(fom['lan_ifnames'].value);
199 // 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);
200 REMOVE-END */
201 fom['lan1_ifnames'].value += (d[i][COL_BRI] == '4') ? 'vlan'+d[i][0] : '';
202 fom['lan2_ifnames'].value += (d[i][COL_BRI] == '5') ? 'vlan'+d[i][0] : '';
203 fom['lan3_ifnames'].value += (d[i][COL_BRI] == '6') ? 'vlan'+d[i][0] : '';
206 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
207 var u = wl_fface(uidx);
208 var wlan = E('_f_bridge_wlan'+u+'_to');
209 /* REMOVE-BEGIN
210 // var wlan = E('_f_bridge_wlan_to');
211 // alert(wlan.selectedIndex);
212 REMOVE-END */
213 switch(parseInt(wlan.selectedIndex)) {
214 case 0:
215 fom['lan_ifnames'].value += ' ' + wl_ifaces[uidx][0];
216 break;
217 case 1:
218 fom['lan1_ifnames'].value += ' ' + wl_ifaces[uidx][0];
219 break;
220 case 2:
221 fom['lan2_ifnames'].value += ' ' + wl_ifaces[uidx][0];
222 break;
223 case 3:
224 fom['lan3_ifnames'].value += ' ' + wl_ifaces[uidx][0];
225 break;
228 /* REMOVE-BEGIN
229 // var lif = nvram['lan_ifnames'].split(' ');
230 // for (var j = 0; j < lif.length; j++) {
231 // fom['lan_ifnames'].value += (lif[j].indexOf('vlan') != -1) ? '' : lif[j];
232 // fom['lan_ifnames'].value += trailingSpace(fom['lan_ifnames'].value);
233 // }
234 // alert('lan_ifnames=' + fom['lan_ifnames'].value + '\n' +
235 // 'lan1_ifnames=' + fom['lan1_ifnames'].value + '\n' +
236 // 'lan2_ifnames=' + fom['lan2_ifnames'].value + '\n' +
237 // 'lan3_ifnames=' + fom['lan3_ifnames'].value);
238 REMOVE-END */
240 // for some models, Tomato checks for a few vital/crucial nvram settings at init time
241 // in some cases, if some/any of them are not found, a full nvram reset/clean could be triggered
242 // so, to (try to) play it safe, we check for the 1st needed/available/required
243 // VLAN for FastE (vlan0 is usually LAN) and GigE routers (vlan1 is usually LAN)
244 if((fom['vlan0ports'].value.length < 1) || (fom['vlan0hwname'].value.length < 1) ||
245 (fom['vlan1ports'].value.length < 1) || (fom['vlan1hwname'].value.length < 1))
246 fom['manual_boot_nv'].value = '1';
247 else
248 fom['manual_boot_nv'].value = nvram['manual_boot_nv'];
250 var e = E('footer-msg');
252 if(vlg.countWan() != 1) {
253 e.innerHTML = 'Cannot proceed: one VID must be assigned to WAN.';
254 e.style.visibility = 'visible';
255 setTimeout(
256 function() {
257 e.innerHTML = '';
258 e.style.visibility = 'hidden';
259 }, 5000);
260 return;
263 if(vlg.countLan(0) != 1) {
264 e.innerHTML = 'Cannot proceed: one and only one VID must be assigned to the primary LAN (br0).';
265 e.style.visibility = 'visible';
266 setTimeout(
267 function() {
268 e.innerHTML = '';
269 e.style.visibility = 'hidden';
270 }, 5000);
271 return;
274 if (v.length < 1) {
275 e.innerHTML = 'Cannot proceed without setting a default VID';
276 e.style.visibility = 'visible';
277 setTimeout(
278 function() {
279 e.innerHTML = '';
280 e.style.visibility = 'hidden';
281 }, 5000);
282 return;
285 if (confirm("Router must be rebooted to proceed. Commit changes to NVRAM and reboot now?"))
286 form.submit(fom, 0);
289 function trailingSpace(s)
291 return ((s.length>0)&&(s.charAt(s.length-1) != ' ')) ? ' ' : '';
294 if(port_vlan_supported) { // aka if(supported_hardware) block
295 var vlg = new TomatoGrid();
296 vlg.setup = function() {
297 this.init('vlan-grid', '', (MAX_VLAN_ID + 1), [
298 { 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>' },
299 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
300 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
301 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
302 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
303 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
304 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
305 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
306 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
307 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
308 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
309 { type: 'checkbox', prefix: '<div class="centered">', suffix: '</div>' },
310 { 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>' }]);
312 this.headerSet(['VID', 'Port 1', 'Tagged', 'Port 2', 'Tagged', 'Port 3', 'Tagged', 'Port 4', 'Tagged', 'WAN Port', 'Tagged', 'Default', 'Bridge']);
314 // find out which vlans are supposed to be bridged to each LAN
315 var bridged = [];
317 for (var i = 0 ; i <= MAX_BRIDGE_ID ; i++) {
318 var j = (i == 0) ? '' : i.toString();
319 var l = nvram['lan' + j + '_ifnames'].split(' ');
320 /* REMOVE-BEGIN
321 // alert('lan' + j + '_ifnames=' + l);
322 REMOVE-END */
323 for (var k = 0 ; k < l.length; k++) {
324 /* REMOVE-BEGIN
325 // alert("bridge br" + i + "=vlan" + parseInt(l[k].replace('vlan','')));
326 REMOVE-END */
327 if(l[k].indexOf('vlan') != -1) {
328 /* REMOVE-BEGIN
329 // alert('lan' + j + '_ifname=br' + nvram['lan' + j + '_ifname'].replace('br',''));
330 REMOVE-END */
331 if (nvram['lan' + j + '_ifname'] != '')
332 bridged[parseInt(l[k].replace('vlan',''))] = (3 + parseInt(nvram['lan' + j + '_ifname'].replace('br',''))).toString();
333 else
334 bridged[parseInt(l[k].replace('vlan',''))] = '1';
336 // WLAN
337 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
338 if(l[k].indexOf(wl_ifaces[uidx][0]) != -1) {
339 E('_f_bridge_wlan'+wl_fface(uidx)+'_to').selectedIndex=i;
340 /* REMOVE-BEGIN
341 // E('_f_bridge_wlan_to').selectedIndex=i;
342 REMOVE-END */
348 // WAN port
349 bridged[parseInt(nvram['wan_ifnameX'].replace('vlan',''))] = '2';
351 // go thru all possible VLANs
352 for (var i = 0 ; i <= MAX_VLAN_ID ; i++) {
353 var port = [];
354 var tagged = [];
355 if ((nvram['vlan' + i + 'hwname'].length > 0) || (nvram['vlan' + i + 'ports'].length > 0)) {
356 // (re)initialize our bitmap for this particular iteration
357 for (var j=0; j <= MAX_PORT_ID ; j++) {
358 port[j] = '0';
359 tagged[j] = '0';
361 // which ports are members of this VLAN?
362 var m=nvram['vlan' + i + 'ports'].split(' ');
363 for (var j = 0; j < (m.length) ; j++) {
364 port[parseInt(m[j].charAt(0))] = '1';
365 tagged[parseInt(m[j].charAt(0))] = (((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (m[j].indexOf('t') != -1)) ? '1' : '0';
368 if (port_vlan_supported) {
369 if((nvram['vlan' + i + 'ports']).indexOf('*') != -1)
370 SWITCH_INTERNAL_PORT=(nvram['vlan' + i + 'ports']).charAt((nvram['vlan' + i + 'ports']).indexOf('*')-1);
372 vlg.insertData(-1, [ i.toString(),
373 port[COL_P0N], tagged[COL_P0N],
374 port[COL_P1N], tagged[COL_P1N],
375 port[COL_P2N], tagged[COL_P2N],
376 port[COL_P3N], tagged[COL_P3N],
377 port[COL_P4N], tagged[COL_P4N],
378 (((nvram['vlan' + i + 'ports']).indexOf('*') != -1) ? '1' : '0' ),
379 (bridged[i] != null) ? bridged[i] : '1' ]);
383 vlg.canDelete = false;
384 vlg.sort(0);
385 vlg.showNewEditor();
386 vlg.resetNewEditor();
389 vlg.countElem = function(f, v)
391 var data = this.getAllData();
392 var total = 0;
393 for (var i = 0; i < data.length; ++i) {
394 total += (data[i][f] == v) ? 1 : 0;
396 return total;
399 vlg.countDefaultVID = function()
401 return this.countElem(COL_VID_DEF,1);
404 vlg.countVID = function (v)
406 return this.countElem(COL_VID,v);
409 vlg.countWan = function()
411 return this.countElem(COL_BRI,2);
414 vlg.countLan = function(l)
416 return this.countElem(COL_BRI,l+3);
419 vlg.verifyFields = function(row, quiet) {
420 var valid = 1;
421 var f = fields.getAll(row);
423 for(var i=0; i<= MAX_VLAN_ID ; i++) {
424 f[COL_VID].options[i].disabled = (this.countVID(i) > 0);
427 for (var i=0; i <= MAX_BRIDGE_ID; i++) {
428 var j = (i==0) ? '' : i.toString();
429 f[COL_BRI].options[i+2].disabled = (nvram['lan' + j + '_ifname'].length < 1);
432 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P0].checked == 1)) {
433 f[COL_P0T].disabled=0;
434 /* REMOVE-BEGIN
435 // if((f[COL_P0T].checked==0) || (this.countElem(COL_P0,1)>0) )
436 // if(this.countElem(COL_P0,1)>0) {
437 // }
438 REMOVE-END */
439 } else {
440 f[COL_P0T].disabled=1;
441 f[COL_P0T].checked=0;
443 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P1].checked == 1)) {
444 f[COL_P1T].disabled=0;
445 } else {
446 f[COL_P1T].disabled=1;
447 f[COL_P1T].checked=0;
449 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P2].checked == 1)) {
450 f[COL_P2T].disabled=0;
451 } else {
452 f[COL_P2T].disabled=1;
453 f[COL_P2T].checked=0;
455 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P3].checked == 1)) {
456 f[COL_P3T].disabled=0;
457 } else {
458 f[COL_P3T].disabled=1;
459 f[COL_P3T].checked=0;
461 if(((trunk_vlan_supported) || (PORT_VLAN_SUPPORT_OVERRIDE)) && (f[COL_P4].checked == 1)) {
462 f[COL_P4T].disabled=0;
463 } else {
464 f[COL_P4T].disabled=1;
465 f[COL_P4T].checked=0;
468 if ((f[COL_P0].checked == 1) && (this.countElem(COL_P0,1)>0)) {
469 if (((this.countElem(COL_P0,1) != this.countElem(COL_P0T,1)) || (f[COL_P0T].checked==0))) {
470 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);
471 valid=0;
472 } else {
473 ferror.clear(f[COL_P0T]);
476 if ((f[COL_P1].checked == 1) && (this.countElem(COL_P1,1)>0)) {
477 if (((this.countElem(COL_P1,1) != this.countElem(COL_P1T,1)) || (f[COL_P1T].checked==0))) {
478 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);
479 valid=0;
480 } else {
481 ferror.clear(f[COL_P1T]);
484 if ((f[COL_P2].checked == 1) && (this.countElem(COL_P2,1)>0)) {
485 if (((this.countElem(COL_P2,1) != this.countElem(COL_P2T,1)) || (f[COL_P2T].checked==0))) {
486 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);
487 valid=0;
488 } else {
489 ferror.clear(f[COL_P2T]);
492 if ((f[COL_P3].checked == 1) && (this.countElem(COL_P3,1)>0)) {
493 if (((this.countElem(COL_P3,1) != this.countElem(COL_P3T,1)) || (f[COL_P3T].checked==0))) {
494 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);
495 valid=0;
496 } else {
497 ferror.clear(f[COL_P3T]);
500 if ((f[COL_P4].checked == 1) && (this.countElem(COL_P4,1)>0)) {
501 if (((this.countElem(COL_P4,1) != this.countElem(COL_P4T,1)) || (f[COL_P4T].checked==0))) {
502 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);
503 valid=0;
504 } else {
505 ferror.clear(f[COL_P4T]);
509 if(this.countDefaultVID() > 0) {
510 f[COL_VID_DEF].disabled=1;
511 f[COL_VID_DEF].checked=0;
514 if((this.countDefaultVID() > 0) && (f[COL_VID_DEF].checked ==1)) {
515 ferror.set(f[COL_VID_DEF], 'Only one VID can be selected as the default VID', quiet);
516 valid = 0;
517 } else {
518 ferror.clear(f[COL_VID_DEF]);
521 if(this.countVID(f[COL_VID].selectedIndex) > 0) {
522 ferror.set(f[COL_VID], 'Cannot add more than one entry with VID ' + f[0].selectedIndex, quiet);
523 valid = 0;
524 } else {
525 ferror.clear(f[COL_VID]);
528 if ((this.countWan() > 0) && (f[COL_BRI].selectedIndex == 1)) {
529 ferror.set(f[COL_BRI],'Only one VID can be used as WAN at any time', quiet);
530 valid = 0;
531 } else {
532 ferror.clear(f[COL_BRI]);
535 for(var i=0; i<4; i++) {
536 if ((this.countLan(i) > 0) && (f[COL_BRI].selectedIndex == (i+2))) {
537 ferror.set(f[COL_BRI],'One and only one VID can be used for LAN' + ((i==0) ? '' : i ) + ' (br'+i+') at any time', quiet);
538 valid = 0;
539 } else {
540 ferror.clear(f[COL_BRI]);
544 return valid;
547 vlg.dataToView = function(data) {
548 return [data[COL_VID],
549 (data[COL_P0].toString() != '0') ? 'Yes' : '',
550 (data[COL_P0T].toString() != '0') ? 'On' : '',
551 (data[COL_P1].toString() != '0') ? 'Yes' : '',
552 (data[COL_P1T].toString() != '0') ? 'On' : '',
553 (data[COL_P2].toString() != '0') ? 'Yes' : '',
554 (data[COL_P2T].toString() != '0') ? 'On' : '',
555 (data[COL_P3].toString() != '0') ? 'Yes' : '',
556 (data[COL_P3T].toString() != '0') ? 'On' : '',
557 (data[COL_P4].toString() != '0') ? 'Yes' : '',
558 (data[COL_P4T].toString() != '0') ? 'On' : '',
559 (data[COL_VID_DEF].toString() != '0') ? '*' : '',
560 ['', 'WAN', 'LAN (br0)', 'LAN1 (br1)', 'LAN2 (br2)', 'LAN3 (br3)' ][data[COL_BRI] - 1]];
563 vlg.dataToFieldValues = function (data) {
564 return [data[COL_VID],
565 (data[COL_P0] != 0) ? 'checked' : '',
566 (data[COL_P0T] != 0) ? 'checked' : '',
567 (data[COL_P1] != 0) ? 'checked' : '',
568 (data[COL_P1T] != 0) ? 'checked' : '',
569 (data[COL_P2] != 0) ? 'checked' : '',
570 (data[COL_P2T] != 0) ? 'checked' : '',
571 (data[COL_P3] != 0) ? 'checked' : '',
572 (data[COL_P3T] != 0) ? 'checked' : '',
573 (data[COL_P4] != 0) ? 'checked' : '',
574 (data[COL_P4T] != 0) ? 'checked' : '',
575 (data[COL_VID_DEF] != 0) ? 'checked' : '',
576 data[COL_BRI]];
579 vlg.fieldValuesToData = function(row) {
580 var f = fields.getAll(row);
581 return [f[COL_VID].value,
582 f[COL_P0].checked ? 1 : 0,
583 f[COL_P0T].checked ? 1 : 0,
584 f[COL_P1].checked ? 1 : 0,
585 f[COL_P1T].checked ? 1 : 0,
586 f[COL_P2].checked ? 1 : 0,
587 f[COL_P2T].checked ? 1 : 0,
588 f[COL_P3].checked ? 1 : 0,
589 f[COL_P3T].checked ? 1 : 0,
590 f[COL_P4].checked ? 1 : 0,
591 f[COL_P4T].checked ? 1 : 0,
592 f[COL_VID_DEF].checked ? 1 : 0,
593 f[COL_BRI].value];
596 vlg.onCancel = function() {
597 this.removeEditor();
598 this.showSource();
599 this.disableNewEditor(false);
601 this.resetNewEditor();
604 vlg.onAdd = function() {
605 var data;
607 this.moving = null;
608 this.rpHide();
610 if (!this.verifyFields(this.newEditor, false)) return;
612 data = this.fieldValuesToData(this.newEditor);
613 this.insertData(-1, data);
615 this.disableNewEditor(false);
616 this.resetNewEditor();
618 this.resort();
621 vlg.onOK = function() {
622 var i, data, view;
624 if (!this.verifyFields(this.editor, false)) return;
626 data = this.fieldValuesToData(this.editor);
627 view = this.dataToView(data);
629 this.source.setRowData(data);
630 for (i = 0; i < this.source.cells.length; ++i) {
631 this.source.cells[i].innerHTML = view[i];
634 this.removeEditor();
635 this.showSource();
636 this.disableNewEditor(false);
638 this.resetNewEditor();
639 this.resort();
642 vlg.onDelete = function() {
643 this.removeEditor();
644 elem.remove(this.source);
645 this.source = null;
646 this.disableNewEditor(false);
648 this.resetNewEditor();
651 vlg.sortCompare = function(a, b) {
652 var obj = TGO(a);
653 var col = obj.sortColumn;
654 if (this.sortColumn == 0) {
655 var r = cmpInt(parseInt(a.cells[col].innerHTML), parseInt(b.cells[col].innerHTML));
656 } else {
657 var r = cmpText(a.cells[col].innerHTML, b.cells[col].innerHTML);
659 return obj.sortAscending ? r : -r;
662 vlg.resetNewEditor = function() {
663 var f = fields.getAll(this.newEditor);
665 for (var i=0; i <= MAX_BRIDGE_ID; i++) {
666 var j = (i==0) ? '' : i.toString();
667 f[COL_BRI].options[i+2].disabled = (nvram['lan' + j + '_ifname'].length < 1);
670 f[COL_VID].selectedIndex=0;
671 var t = MAX_VLAN_ID;
672 while((this.countVID(f[COL_VID].selectedIndex) > 0) && (t > 0)) {
673 f[COL_VID].selectedIndex = (f[COL_VID].selectedIndex%(MAX_VLAN_ID))+1;
674 t--;
677 for(var i=0; i<= MAX_VLAN_ID ; i++) {
678 f[COL_VID].options[i].disabled = (this.countVID(i) > 0);
681 f[COL_P0].checked = 0;
682 f[COL_P0T].checked = 0;
683 f[COL_P0T].disabled = 1;
684 f[COL_P1].checked = 0;
685 f[COL_P1T].checked = 0;
686 f[COL_P1T].disabled = 1;
687 f[COL_P2].checked = 0;
688 f[COL_P2T].checked = 0;
689 f[COL_P2T].disabled = 1;
690 f[COL_P3].checked = 0;
691 f[COL_P3T].checked = 0;
692 f[COL_P3T].disabled = 1;
693 f[COL_P4].checked = 0;
694 f[COL_P4T].checked = 0;
695 f[COL_P4T].disabled = 1;
696 f[COL_VID_DEF].checked = 0;
697 if (this.countDefaultVID()>0)
698 f[COL_VID_DEF].disabled = 1;
699 f[COL_BRI].selectedIndex = 0;
700 ferror.clearAll(fields.getAll(this.newEditor));
702 } // end of the so-called if(supported_device) block
704 function init()
706 if(port_vlan_supported) {
707 vlg.recolor();
708 vlg.resetNewEditor();
712 function earlyInit()
714 if(!port_vlan_supported) {
715 E('save-button').disabled = 1;
716 return;
718 PORT_VLAN_SUPPORT_OVERRIDE = ((nvram['trunk_vlan_so'] == '1') ? 1 : 0);
721 </script>
722 </head>
723 <body onload='init()'>
724 <form id='_fom' method='post' action='tomato.cgi'>
725 <table id='container' cellspacing=0>
726 <tr><td colspan=2 id='header'>
727 <div class='title'>Tomato</div>
728 <div class='version'>Version <% version(); %></div>
729 </td></tr>
730 <tr id='body'><td id='navi'><script type='text/javascript'>navi()</script></td>
731 <td id='content'>
732 <div id='ident'><% ident(); %></div>
733 <input type='hidden' name='_nextpage' value='advanced-vlan.asp'>
734 <input type='hidden' name='_nextwait' value='30'>
735 <input type='hidden' name='_reboot' value='1'>
736 <input type='hidden' name='_nvset' value='1'>
737 <input type='hidden' name='_commit' value='1'>
738 <input type='hidden' name='vlan0ports'>
739 <input type='hidden' name='vlan1ports'>
740 <input type='hidden' name='vlan2ports'>
741 <input type='hidden' name='vlan3ports'>
742 <input type='hidden' name='vlan4ports'>
743 <input type='hidden' name='vlan5ports'>
744 <input type='hidden' name='vlan6ports'>
745 <input type='hidden' name='vlan7ports'>
746 <input type='hidden' name='vlan8ports'>
747 <input type='hidden' name='vlan9ports'>
748 <input type='hidden' name='vlan10ports'>
749 <input type='hidden' name='vlan11ports'>
750 <input type='hidden' name='vlan12ports'>
751 <input type='hidden' name='vlan13ports'>
752 <input type='hidden' name='vlan14ports'>
753 <input type='hidden' name='vlan15ports'>
754 <input type='hidden' name='vlan0hwname'>
755 <input type='hidden' name='vlan1hwname'>
756 <input type='hidden' name='vlan2hwname'>
757 <input type='hidden' name='vlan3hwname'>
758 <input type='hidden' name='vlan4hwname'>
759 <input type='hidden' name='vlan5hwname'>
760 <input type='hidden' name='vlan6hwname'>
761 <input type='hidden' name='vlan7hwname'>
762 <input type='hidden' name='vlan8hwname'>
763 <input type='hidden' name='vlan9hwname'>
764 <input type='hidden' name='vlan10hwname'>
765 <input type='hidden' name='vlan11hwname'>
766 <input type='hidden' name='vlan12hwname'>
767 <input type='hidden' name='vlan13hwname'>
768 <input type='hidden' name='vlan14hwname'>
769 <input type='hidden' name='vlan15hwname'>
770 <input type='hidden' name='wan_ifnameX'>
771 <input type='hidden' name='manual_boot_nv'>
772 <input type='hidden' name='lan_ifnames'>
773 <input type='hidden' name='lan1_ifnames'>
774 <input type='hidden' name='lan2_ifnames'>
775 <input type='hidden' name='lan3_ifnames'>
776 <input type='hidden' name='trunk_vlan_so'>
778 <div id='sesdiv' style='display:none'>
779 <div class='section-title'>VLAN</div>
780 <div class='section'>
781 <table class='tomato-grid' cellspacing=1 id='vlan-grid'></table>
782 </div>
783 <div class='section-title'>Wireless</div>
784 <div class='section'>
785 <script type='text/javascript'>
786 var f = [];
787 for (var uidx = 0; uidx < wl_ifaces.length; ++uidx) {
788 var u = wl_fface(uidx);
789 f.push(
790 /* REMOVE-BEGIN
791 // { title: ('Bridge WLAN' + uidx + ' (' + wl_ifaces[uidx][0] + ') to'), name: ('f_bridge_wlan'+u+'_to'), type: 'select',
792 REMOVE-END */
793 { title: ('Bridge ' + wl_ifaces[uidx][0] + ' to'), name: ('f_bridge_wlan'+u+'_to'), type: 'select',
794 options: [[0,'LAN (br0)'],[1,'LAN1 (br1)'],[2,'LAN2 (br2)'],[3,'LAN3 (br3)'],[4,'none']] } );
796 createFieldTable('',f);
797 /* REMOVE-BEGIN
798 //W('<hr>');
799 // createFieldTable('', [
800 // { title: 'Bridge WLAN to', name: 'f_bridge_wlan_to', type: 'select', options: [[0,'LAN (br0)'],[1,'LAN1 (br1)'],[2,'LAN2 (br2)'],[3,'LAN3 (br3)'],[4,'none']] }
801 // ]);
802 REMOVE-END */
803 if(port_vlan_supported) vlg.setup();
804 </script>
805 </div>
807 <div class='section-title'>Notes</div>
808 <div class='section'>
809 <ul>
810 <li><b>VID</b> - Unique identifier of a VLAN.</li>
811 <li><b>Ports 1-4 &amp; WAN</b> - Which ethernet ports on the router should be members of this VLAN.</li>
812 <li><b>Tagged</b> - Enable 802.1q tagging of ethernet frames on a particular port/VLAN
813 <script type='text/javascript'>
814 if(!trunk_vlan_supported)
815 W(' <i>(not known to be supported on this model)</i>');
816 </script>
817 </li>
818 <li><b>Default</b> - VLAN ID assigned to untagged frames received by the router.</li>
819 <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>
820 </ul>
821 <small>
822 <ul>
823 <li><b>Other relevant notes/hints:</b>
824 <ul>
825 <li>One VID <i>must</i> be assigned to WAN.</li>
826 <li>One VID <i>must</i> be selected as the default.</li>
827 <script type='text/javascript'>
828 if((trunk_vlan_supported) || (nvram.trunk_vlan_so == '1'))
829 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.</li>');
830 </script>
831 </ul>
832 </ul>
833 <div id='trunk_vlan_override' style='display:none'>
834 <div class='section-title'>Trunk VLAN support override (experimental)</div>
835 <div class='section'>
836 <script type='text/javascript'>
837 createFieldTable('', [
838 { title: 'Enable', name: 'f_trunk_vlan_so', type: 'checkbox', value: nvram.trunk_vlan_so == '1' },
840 </script>
841 </div>
842 </div>
843 </div>
844 </small>
845 </div>
846 </div>
847 <script type='text/javascript'>
848 if(!port_vlan_supported)
849 W('<i>This feature is not supported on this router.</i>');
850 else {
851 E('sesdiv').style.display = '';
852 if(!trunk_vlan_supported)
853 E('trunk_vlan_override').style.display = '';
855 </script>
856 </td></tr>
857 <tr><td id='footer' colspan=2>
858 <span id='footer-msg'></span>
859 <input type='button' value='Save' id='save-button' onclick='save()'>
860 <input type='button' value='Cancel' id='cancel-button' onclick='javascript:reloadPage();'>
861 </td></tr>
862 </table>
863 </form>
864 <script type='text/javascript'>earlyInit(); verifyFields(null,1);</script>
865 </body>
866 </html>