1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML
4.0//EN'
>
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.
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'
>
17 <script type='text/javascript' src='tomato.js'
></script>
18 <style type='text/css'
>
34 #vlan-grid .centered
{
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;
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
83 case '0x04ef': // WRT320N/E2000
84 case '0x04cf': // WRT610Nv2/E3000, RT-N16, WNR3500L
91 // should work on WRT54G v2/v3, WRT54GS v1/v2 and others
112 var COL_VID_DEF
= 11;
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');
126 // var wlan = E('_f_bridge_wlan_to');
127 // if (wl_ifaces.length < 1) {
128 // wlan.disabled=true;
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;
143 if (vlg
.isEditing()) return;
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
= '';
159 var d
= vlg
.getAllData();
161 for (var i
= 0; i
< d
.length
; ++i
) {
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?)
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] : '';
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);
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');
210 // var wlan = E('_f_bridge_wlan_to');
211 // alert(wlan.selectedIndex);
213 switch(parseInt(wlan
.selectedIndex
)) {
215 fom
['lan_ifnames'].value
+= ' ' + wl_ifaces
[uidx
][0];
218 fom
['lan1_ifnames'].value
+= ' ' + wl_ifaces
[uidx
][0];
221 fom
['lan2_ifnames'].value
+= ' ' + wl_ifaces
[uidx
][0];
224 fom
['lan3_ifnames'].value
+= ' ' + wl_ifaces
[uidx
][0];
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);
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);
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';
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';
258 e
.style
.visibility
= 'hidden';
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';
269 e
.style
.visibility
= 'hidden';
275 e
.innerHTML
= 'Cannot proceed without setting a default VID';
276 e
.style
.visibility
= 'visible';
280 e
.style
.visibility
= 'hidden';
285 if (confirm("Router must be rebooted to proceed. Commit changes to NVRAM and reboot now?"))
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
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(' ');
321 // alert('lan' + j + '_ifnames=' + l);
323 for (var k
= 0 ; k
< l
.length
; k
++) {
325 // alert("bridge br" + i + "=vlan" + parseInt(l[k].replace('vlan','')));
327 if(l
[k
].indexOf('vlan') != -1) {
329 // alert('lan' + j + '_ifname=br' + nvram['lan' + j + '_ifname'].replace('br',''));
331 if (nvram
['lan' + j
+ '_ifname'] != '')
332 bridged
[parseInt(l
[k
].replace('vlan',''))] = (3 + parseInt(nvram
['lan' + j
+ '_ifname'].replace('br',''))).toString();
334 bridged
[parseInt(l
[k
].replace('vlan',''))] = '1';
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
;
341 // E('_f_bridge_wlan_to').selectedIndex=i;
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
++) {
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
++) {
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;
386 vlg
.resetNewEditor();
389 vlg
.countElem = function(f
, v
)
391 var data
= this.getAllData();
393 for (var i
= 0; i
< data
.length
; ++i
) {
394 total
+= (data
[i
][f
] == v
) ? 1 : 0;
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
) {
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;
435 // if((f[COL_P0T].checked==0) || (this.countElem(COL_P0,1)>0) )
436 // if(this.countElem(COL_P0,1)>0) {
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;
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;
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;
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;
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
540 ferror
.clear(f
[COL_BRI
]);
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' : '',
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,
596 vlg
.onCancel = function() {
599 this.disableNewEditor(false);
601 this.resetNewEditor();
604 vlg
.onAdd = function() {
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();
621 vlg
.onOK = function() {
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
];
636 this.disableNewEditor(false);
638 this.resetNewEditor();
642 vlg
.onDelete = function() {
644 elem
.remove(this.source
);
646 this.disableNewEditor(false);
648 this.resetNewEditor();
651 vlg
.sortCompare = function(a
, b
) {
653 var col
= obj
.sortColumn
;
654 if (this.sortColumn
== 0) {
655 var r
= cmpInt(parseInt(a
.cells
[col
].innerHTML
), parseInt(b
.cells
[col
].innerHTML
));
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;
672 while((this.countVID(f
[COL_VID
].selectedIndex
) > 0) && (t
> 0)) {
673 f
[COL_VID
].selectedIndex
= (f
[COL_VID
].selectedIndex
%(MAX_VLAN_ID
))+1;
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
706 if(port_vlan_supported
) {
708 vlg
.resetNewEditor();
714 if(!port_vlan_supported
) {
715 E('save-button').disabled
= 1;
718 PORT_VLAN_SUPPORT_OVERRIDE
= ((nvram
['trunk_vlan_so'] == '1') ? 1 : 0);
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>
730 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
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>
783 <div class='section-title'
>Wireless
</div>
784 <div class='section'
>
785 <script type='text/javascript'
>
787 for (var uidx
= 0; uidx
< wl_ifaces
.length
; ++uidx
) {
788 var u
= wl_fface(uidx
);
791 // { title: ('Bridge WLAN' + uidx + ' (' + wl_ifaces[uidx][0] + ') to'), name: ('f_bridge_wlan'+u+'_to'), type: 'select',
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
);
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']] }
803 if(port_vlan_supported
) vlg
.setup();
807 <div class='section-title'
>Notes
</div>
808 <div class='section'
>
810 <li><b>VID
</b> - Unique identifier of a VLAN.
</li>
811 <li><b>Ports
1-
4 & 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>');
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>
823 <li><b>Other relevant notes/hints:
</b>
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>');
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' },
847 <script type='text/javascript'
>
848 if(!port_vlan_supported
)
849 W('<i>This feature is not supported on this router.</i>');
851 E('sesdiv').style
.display
= '';
852 if(!trunk_vlan_supported
)
853 E('trunk_vlan_override').style
.display
= '';
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();'
>
864 <script type='text/javascript'
>earlyInit(); verifyFields(null,1);</script>