]>
Commit | Line | Data |
---|---|---|
1dcf513a FB |
1 | #!/usr/bin/perl |
2 | ############################################################################### | |
3 | # # | |
4 | # VLAN Management for IPFire # | |
5 | # Copyright (C) 2019 Florian Bührle <fbuehrle@ipfire.org> # | |
6 | # # | |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | use strict; | |
23 | use Scalar::Util qw(looks_like_number); | |
24 | ||
25 | require '/var/ipfire/general-functions.pl'; | |
26 | require "${General::swroot}/lang.pl"; | |
27 | require "${General::swroot}/header.pl"; | |
52628052 | 28 | require "${General::swroot}/network-functions.pl"; |
1dcf513a | 29 | |
63a1c81a | 30 | ###--- HTML HEAD ---### |
5c33a761 | 31 | my $extraHead = <<END |
1dcf513a | 32 | <style> |
fc31c28d | 33 | table#zoneconf { |
1dcf513a | 34 | width: 100%; |
23b26ce5 | 35 | border-collapse: collapse; |
5e6eba88 | 36 | border-style: hidden; |
23b26ce5 | 37 | table-layout: fixed; |
1dcf513a FB |
38 | } |
39 | ||
5e6eba88 | 40 | /* row height */ |
fc31c28d | 41 | #zoneconf tr { |
1dcf513a FB |
42 | height: 4em; |
43 | } | |
8de94a23 LAH |
44 | #zoneconf tr.half-height { |
45 | height: 2em; | |
46 | } | |
47 | #zoneconf tr.half-height > td { | |
48 | padding: 2px 10px; | |
49 | } | |
50 | ||
5e6eba88 LAH |
51 | /* section separators */ |
52 | #zoneconf tr.divider-top { | |
53 | border-top: 2px solid $Header::bordercolour; | |
54 | } | |
55 | #zoneconf tr.divider-bottom { | |
56 | border-bottom: 2px solid $Header::bordercolour; | |
57 | } | |
1dcf513a | 58 | |
5e6eba88 | 59 | /* table cells */ |
fc31c28d LAH |
60 | #zoneconf td { |
61 | padding: 5px 10px; | |
5e6eba88 | 62 | border-left: 0.5px solid $Header::bordercolour; |
fc31c28d | 63 | text-align: center; |
1dcf513a FB |
64 | } |
65 | ||
5e6eba88 | 66 | /* grey header cells */ |
fc31c28d | 67 | #zoneconf td.heading { |
5e6eba88 | 68 | background-color: lightgrey; |
fc31c28d LAH |
69 | color: white; |
70 | } | |
5e6eba88 | 71 | #zoneconf td.heading.bold::first-line { |
fc31c28d LAH |
72 | font-weight: bold; |
73 | line-height: 1.6; | |
1dcf513a FB |
74 | } |
75 | ||
5e6eba88 | 76 | /* narrow left column with background color */ |
fc31c28d LAH |
77 | #zoneconf tr > td:first-child { |
78 | width: 11em; | |
23b26ce5 | 79 | } |
5e6eba88 LAH |
80 | #zoneconf tr.nic-row > td:first-child { |
81 | background-color: darkgray; | |
82 | } | |
83 | #zoneconf tr.nic-row { | |
84 | border-bottom: 0.5px solid $Header::bordercolour; | |
85 | } | |
8de94a23 LAH |
86 | #zoneconf tr.option-row > td:first-child { |
87 | background-color: gray; | |
88 | } | |
7478903f | 89 | |
fc31c28d | 90 | /* alternating row background color */ |
5e6eba88 LAH |
91 | #zoneconf tr { |
92 | background-color: $Header::table2colour; | |
93 | } | |
fc31c28d | 94 | #zoneconf tr:nth-child(2n+3) { |
5e6eba88 | 95 | background-color: $Header::table1colour; |
1dcf513a FB |
96 | } |
97 | ||
5e6eba88 | 98 | /* special cell colors */ |
fc31c28d | 99 | #zoneconf td.green { |
1dcf513a FB |
100 | background-color: $Header::colourgreen; |
101 | } | |
102 | ||
fc31c28d | 103 | #zoneconf td.red { |
1dcf513a FB |
104 | background-color: $Header::colourred; |
105 | } | |
106 | ||
fc31c28d | 107 | #zoneconf td.blue { |
1dcf513a FB |
108 | background-color: $Header::colourblue; |
109 | } | |
110 | ||
fc31c28d | 111 | #zoneconf td.orange { |
1dcf513a FB |
112 | background-color: $Header::colourorange; |
113 | } | |
114 | ||
fc31c28d LAH |
115 | #zoneconf td.topleft { |
116 | background-color: $Header::pagecolour; | |
1dcf513a FB |
117 | } |
118 | ||
7f44ec04 AK |
119 | input.vlanid { |
120 | width: 4em; | |
121 | } | |
8de94a23 LAH |
122 | input.stp-priority { |
123 | width: 5em; | |
124 | } | |
7f44ec04 | 125 | |
1dcf513a | 126 | #submit-container { |
1dcf513a | 127 | width: 100%; |
23b26ce5 | 128 | padding-top: 20px; |
1d6bc7a0 | 129 | text-align: right; |
23b26ce5 | 130 | color: red; |
1dcf513a FB |
131 | } |
132 | ||
133 | #submit-container.input { | |
134 | margin-left: auto; | |
135 | } | |
1dcf513a | 136 | </style> |
5c33a761 LAH |
137 | |
138 | <script src="/include/zoneconf.js"></script> | |
1dcf513a FB |
139 | END |
140 | ; | |
63a1c81a | 141 | ###--- END HTML HEAD ---### |
1dcf513a | 142 | |
63a1c81a | 143 | ### Read configuration ### |
1dcf513a FB |
144 | my %ethsettings = (); |
145 | my %vlansettings = (); | |
146 | my %cgiparams = (); | |
147 | ||
7478903f FB |
148 | my $restart_notice = ""; |
149 | ||
1dcf513a FB |
150 | &General::readhash("${General::swroot}/ethernet/settings",\%ethsettings); |
151 | &General::readhash("${General::swroot}/ethernet/vlans",\%vlansettings); | |
152 | ||
153 | &Header::getcgihash(\%cgiparams); | |
154 | &Header::showhttpheaders(); | |
155 | ||
52628052 LAH |
156 | # Get all network zones that are currently enabled |
157 | my @zones = Network::get_available_network_zones(); | |
1dcf513a FB |
158 | |
159 | # Get all physical NICs present | |
160 | opendir(my $dh, "/sys/class/net/"); | |
161 | my @nics = (); | |
162 | ||
163 | while (my $nic = readdir($dh)) { | |
164 | if (-e "/sys/class/net/$nic/device") { # Indicates that the NIC is physical | |
165 | push(@nics, [&Network::get_nic_property($nic, "address"), $nic, 0]); | |
166 | } | |
167 | } | |
168 | ||
169 | closedir($dh); | |
170 | ||
171 | @nics = sort {$a->[0] cmp $b->[0]} @nics; # Sort nics by their MAC address | |
172 | ||
173 | # Name the physical NICs | |
174 | # Even though they may not be really named like this, we will name them ethX or wlanX | |
175 | my $ethcount = 0; | |
176 | my $wlancount = 0; | |
177 | ||
178 | foreach (@nics) { | |
179 | my $nic = $_->[1]; | |
180 | ||
181 | if (-e "/sys/class/net/$nic/wireless") { | |
182 | $_->[1] = "wlan$wlancount"; | |
183 | $_->[2] = 1; | |
184 | $wlancount++; | |
185 | } else { | |
186 | $_->[1] = "eth$ethcount"; | |
187 | $ethcount++; | |
188 | } | |
189 | } | |
190 | ||
63a1c81a | 191 | ### START PAGE ### |
5c33a761 | 192 | &Header::openpage($Lang::tr{"zoneconf title"}, 1, $extraHead); |
1dcf513a FB |
193 | &Header::openbigbox('100%', 'center'); |
194 | ||
195 | ### Evaluate POST parameters ### | |
196 | ||
197 | if ($cgiparams{"ACTION"} eq $Lang::tr{"save"}) { | |
198 | my %VALIDATE_nic_check = (); | |
199 | my $VALIDATE_error = ""; | |
200 | ||
52628052 LAH |
201 | # Loop trough all known zones to ensure a complete configuration file is created |
202 | foreach (@Network::known_network_zones) { | |
1dcf513a FB |
203 | my $uc = uc $_; |
204 | my $slave_string = ""; | |
205 | my $zone_mode = $cgiparams{"MODE $uc"}; | |
206 | my $VALIDATE_vlancount = 0; | |
f60b61e0 FB |
207 | my $VALIDATE_zoneslaves = 0; |
208 | ||
1dcf513a FB |
209 | $ethsettings{"${uc}_MACADDR"} = ""; |
210 | $ethsettings{"${uc}_MODE"} = ""; | |
211 | $ethsettings{"${uc}_SLAVES"} = ""; | |
212 | $vlansettings{"${uc}_PARENT_DEV"} = ""; | |
213 | $vlansettings{"${uc}_VLAN_ID"} = ""; | |
214 | $vlansettings{"${uc}_MAC_ADDRESS"} = ""; | |
215 | ||
216 | # If RED is not in DHCP or static mode, we only set its MACADDR property | |
217 | if ($uc eq "RED" && ! $cgiparams{"PPPACCESS"} eq "") { | |
218 | foreach (@nics) { | |
219 | my $mac = $_->[0]; | |
220 | ||
221 | if ($mac eq $cgiparams{"PPPACCESS"}) { | |
222 | $ethsettings{"${uc}_MACADDR"} = $mac; | |
223 | ||
224 | # Check if this interface is already accessed by any other zone | |
225 | # If this is the case, show an error message | |
226 | if ($VALIDATE_nic_check{"ACC $mac"}) { | |
227 | $VALIDATE_error = $Lang::tr{"zoneconf val ppp assignment error"}; | |
228 | } | |
229 | ||
230 | $VALIDATE_nic_check{"RESTRICT $mac"} = 1; | |
231 | last; | |
232 | } | |
233 | } | |
234 | ||
63a1c81a | 235 | # skip NIC/VLAN assignment and additional zone options for RED in PPP mode |
1dcf513a FB |
236 | next; |
237 | } | |
238 | ||
239 | foreach (@nics) { | |
240 | my $mac = $_->[0]; | |
241 | my $nic_access = $cgiparams{"ACCESS $uc $mac"}; | |
242 | ||
bb90622c MT |
243 | next unless ($nic_access); |
244 | ||
a6695868 | 245 | if ($nic_access ne "NONE") { |
1dcf513a FB |
246 | if ($VALIDATE_nic_check{"RESTRICT $mac"}) { # If this interface is already assigned to RED in PPP mode, throw an error |
247 | $VALIDATE_error = $Lang::tr{"zoneconf val ppp assignment error"}; | |
f60b61e0 FB |
248 | last; |
249 | } | |
250 | ||
a6695868 | 251 | if ($zone_mode ne "BRIDGE" && $VALIDATE_zoneslaves > 0 && $nic_access ne "") { |
f60b61e0 FB |
252 | $VALIDATE_error = $Lang::tr{"zoneconf val zoneslave amount error"}; |
253 | last; | |
1dcf513a FB |
254 | } |
255 | ||
256 | $VALIDATE_nic_check{"ACC $mac"} = 1; | |
f60b61e0 | 257 | $VALIDATE_zoneslaves++; |
1dcf513a FB |
258 | } |
259 | ||
260 | if ($nic_access eq "NATIVE") { | |
261 | if ($VALIDATE_nic_check{"NATIVE $mac"}) { | |
262 | $VALIDATE_error = $Lang::tr{"zoneconf val native assignment error"}; | |
f60b61e0 | 263 | last; |
1dcf513a FB |
264 | } |
265 | ||
266 | $VALIDATE_nic_check{"NATIVE $mac"} = 1; | |
267 | ||
268 | if ($zone_mode eq "BRIDGE") { | |
269 | $slave_string = "${slave_string}${mac} "; | |
270 | } else { | |
271 | $ethsettings{"${uc}_MACADDR"} = $mac; | |
272 | } | |
273 | } elsif ($nic_access eq "VLAN") { | |
274 | my $vlan_tag = $cgiparams{"TAG $uc $mac"}; | |
275 | ||
276 | if ($VALIDATE_nic_check{"VLAN $mac $vlan_tag"}) { | |
277 | $VALIDATE_error = $Lang::tr{"zoneconf val vlan tag assignment error"}; | |
f60b61e0 | 278 | last; |
1dcf513a FB |
279 | } |
280 | ||
281 | $VALIDATE_nic_check{"VLAN $mac $vlan_tag"} = 1; | |
715aa887 LAH |
282 | |
283 | # check VLAN tag range: 1..4094 (0, 4095 are reserved) | |
284 | unless (looks_like_number($vlan_tag) && ($vlan_tag >= 1) && ($vlan_tag <= 4094)) { | |
285 | $VALIDATE_error = $Lang::tr{"zoneconf val vlan tag range error"}; | |
f60b61e0 | 286 | last; |
1dcf513a FB |
287 | } |
288 | ||
289 | my $rnd_mac = &Network::random_mac(); | |
290 | ||
291 | $vlansettings{"${uc}_PARENT_DEV"} = $mac; | |
292 | $vlansettings{"${uc}_VLAN_ID"} = $vlan_tag; | |
293 | $vlansettings{"${uc}_MAC_ADDRESS"} = $rnd_mac; | |
294 | ||
295 | if ($zone_mode eq "BRIDGE") { | |
296 | $slave_string = "${slave_string}${rnd_mac} "; | |
297 | } | |
298 | ||
299 | $VALIDATE_vlancount++; # We can't allow more than one VLAN per zone | |
300 | } | |
301 | } | |
302 | ||
303 | if ($VALIDATE_vlancount > 1) { | |
304 | $VALIDATE_error = $Lang::tr{"zoneconf val vlan amount assignment error"}; | |
f60b61e0 | 305 | last; |
1dcf513a FB |
306 | } |
307 | ||
308 | chop($slave_string); | |
309 | ||
310 | if ($zone_mode eq "BRIDGE") { | |
311 | $ethsettings{"${uc}_MODE"} = "bridge"; | |
312 | $ethsettings{"${uc}_SLAVES"} = $slave_string; | |
313 | } elsif ($zone_mode eq "MACVTAP") { | |
314 | $ethsettings{"${uc}_MODE"} = "macvtap"; | |
315 | } | |
8de94a23 LAH |
316 | |
317 | # STP options | |
318 | # (this has already been skipped when RED is in PPP mode, so we don't need to check for PPP here) | |
319 | $ethsettings{"${uc}_STP"} = ""; | |
320 | my $stp_enabled = $cgiparams{"STP-$uc"} eq "on"; | |
321 | my $stp_priority = $cgiparams{"STP-PRIORITY-$uc"}; | |
322 | ||
323 | if($stp_enabled) { | |
324 | unless($ethsettings{"${uc}_MODE"} eq "bridge") { # STP is only available in bridge mode | |
325 | $VALIDATE_error = $Lang::tr{"zoneconf val stp zone mode error"}; | |
326 | last; | |
327 | } | |
328 | unless (looks_like_number($stp_priority) && ($stp_priority >= 1) && ($stp_priority <= 65535)) { # STP bridge priority range: 1..65535 | |
329 | $VALIDATE_error = $Lang::tr{"zoneconf val stp priority range error"}; | |
330 | last; | |
331 | } | |
332 | $ethsettings{"${uc}_STP"} = "on"; # network-hotplug-bridges expects "on" | |
333 | $ethsettings{"${uc}_STP_PRIORITY"} = $stp_priority; | |
334 | } | |
1dcf513a FB |
335 | } |
336 | ||
63a1c81a | 337 | # validation failed, show error message and exit |
1dcf513a FB |
338 | if ($VALIDATE_error) { |
339 | &Header::openbox('100%', 'left', $Lang::tr{"error"}); | |
340 | ||
8797526d | 341 | print "$VALIDATE_error<br><br><a href='$ENV{'SCRIPT_NAME'}'>$Lang::tr{'back'}</a>\n"; |
1dcf513a FB |
342 | |
343 | &Header::closebox(); | |
344 | &Header::closebigbox(); | |
345 | &Header::closepage(); | |
346 | ||
347 | exit 0; | |
348 | } | |
349 | ||
63a1c81a | 350 | # new settings are valid, write configuration files |
1dcf513a FB |
351 | &General::writehash("${General::swroot}/ethernet/settings",\%ethsettings); |
352 | &General::writehash("${General::swroot}/ethernet/vlans",\%vlansettings); | |
7478903f | 353 | |
23b26ce5 | 354 | $restart_notice = $Lang::tr{'zoneconf notice reboot'}; |
1dcf513a FB |
355 | } |
356 | ||
1dcf513a FB |
357 | ### START OF TABLE ### |
358 | ||
63a1c81a LAH |
359 | &Header::openbox('100%', 'left', $Lang::tr{"zoneconf nic assignment"}); |
360 | ||
1dcf513a | 361 | print <<END |
0ec8e31a | 362 | <form method='post' enctype='multipart/form-data'> |
fc31c28d | 363 | <table id="zoneconf"> |
5e6eba88 | 364 | <tr class="divider-bottom"> |
fc31c28d | 365 | <td class="topleft"></td> |
1dcf513a FB |
366 | END |
367 | ; | |
368 | ||
0ec8e31a | 369 | # Fill the table header with all activated zones |
1dcf513a | 370 | foreach (@zones) { |
1dcf513a | 371 | my $uc = uc $_; |
1dcf513a | 372 | |
63a1c81a | 373 | # If the red zone is in PPP mode, don't show a mode dropdown |
23b26ce5 | 374 | if ($uc eq "RED") { |
1dcf513a | 375 | my $red_type = $ethsettings{"RED_TYPE"}; |
1dcf513a | 376 | |
52628052 | 377 | unless (Network::is_red_mode_ip()) { |
63a1c81a | 378 | print "\t\t<td class='heading bold $_'>$uc ($red_type)</td>\n"; |
1dcf513a | 379 | |
1dcf513a FB |
380 | next; # We're done here |
381 | } | |
382 | } | |
383 | ||
384 | my %mode_selected = (); | |
385 | my $zone_mode = $ethsettings{"${uc}_MODE"}; | |
386 | ||
387 | if ($zone_mode eq "") { | |
388 | $mode_selected{"DEFAULT"} = "selected"; | |
389 | } elsif ($zone_mode eq "bridge") { | |
390 | $mode_selected{"BRIDGE"} = "selected"; | |
391 | } elsif ($zone_mode eq "macvtap") { | |
392 | $mode_selected{"MACVTAP"} = "selected"; | |
393 | } | |
394 | ||
395 | print <<END | |
5e6eba88 | 396 | <td class='heading bold $_'>$uc<br> |
b4434345 | 397 | <select name="MODE $uc" data-zone="$uc" onchange="changeZoneMode(this)"> |
1dcf513a FB |
398 | <option value="DEFAULT" $mode_selected{"DEFAULT"}>$Lang::tr{"zoneconf nicmode default"}</option> |
399 | <option value="BRIDGE" $mode_selected{"BRIDGE"}>$Lang::tr{"zoneconf nicmode bridge"}</option> | |
400 | <option value="MACVTAP" $mode_selected{"MACVTAP"}>$Lang::tr{"zoneconf nicmode macvtap"}</option> | |
401 | </select> | |
402 | </td> | |
403 | END | |
404 | ; | |
0ec8e31a FB |
405 | } |
406 | ||
96d0c761 | 407 | print "\t</tr>\n"; |
0ec8e31a | 408 | |
63a1c81a | 409 | # NIC assignment matrix |
0ec8e31a | 410 | foreach (@nics) { |
23b26ce5 | 411 | my $mac = $_->[0]; |
0ec8e31a | 412 | my $nic = $_->[1]; |
23b26ce5 | 413 | my $wlan = $_->[2]; |
0ec8e31a | 414 | |
5e6eba88 LAH |
415 | print "\t<tr class='nic-row'>\n"; |
416 | print "\t\t<td class='heading bold'>$nic<br>$mac</td>\n"; | |
0ec8e31a | 417 | |
23b26ce5 MT |
418 | # Iterate through all zones and check if the current NIC is assigned to it |
419 | foreach (@zones) { | |
420 | my $uc = uc $_; | |
5c33a761 | 421 | my $highlight = ""; |
0ec8e31a | 422 | |
23b26ce5 | 423 | if ($uc eq "RED") { |
23b26ce5 | 424 | # VLANs/Bridging is not possible if the RED interface is set to PPP, PPPoE, VDSL, ... |
52628052 | 425 | unless (Network::is_red_mode_ip()) { |
23b26ce5 | 426 | my $checked = ""; |
1dcf513a | 427 | |
0ec8e31a FB |
428 | if ($mac eq $ethsettings{"${uc}_MACADDR"}) { |
429 | $checked = "checked"; | |
5c33a761 | 430 | $highlight = $_; |
0ec8e31a FB |
431 | } |
432 | ||
96d0c761 | 433 | print <<END |
5c33a761 LAH |
434 | <td class="$highlight"> |
435 | <input type="radio" name="PPPACCESS" value="$mac" data-zone="RED" data-mac="$mac" onchange="highlightAccess(this)" $checked> | |
96d0c761 LAH |
436 | </td> |
437 | END | |
438 | ; | |
23b26ce5 MT |
439 | next; # We're done here |
440 | } | |
441 | } | |
442 | ||
443 | my %access_selected = (); | |
444 | my $zone_mode = $ethsettings{"${uc}_MODE"}; | |
445 | my $zone_parent_dev = $vlansettings{"${uc}_PARENT_DEV"}; # ZONE_PARENT_DEV is set if this zone accesses any interface via a VLAN | |
446 | my $field_disabled = "disabled"; # Only enable the VLAN ID input field if the current access mode is VLAN | |
1dcf513a FB |
447 | my $zone_vlan_id = ""; |
448 | ||
23b26ce5 MT |
449 | # If ZONE_PARENT_DEV is set to a NICs name (e.g. green0 or eth0) instead of a MAC address, we have to find out this NICs MAC address |
450 | $zone_parent_dev = &Network::get_mac_by_name($zone_parent_dev); | |
0ec8e31a | 451 | |
23b26ce5 MT |
452 | # If the current NIC is accessed by the current zone via a VLAN, the ZONE_PARENT_DEV option corresponds to the current NIC |
453 | if ($mac eq $zone_parent_dev) { | |
1dcf513a FB |
454 | $access_selected{"VLAN"} = "selected"; |
455 | $field_disabled = ""; | |
456 | $zone_vlan_id = $vlansettings{"${uc}_VLAN_ID"}; | |
0ec8e31a | 457 | } elsif ($zone_mode eq "bridge") { # If the current zone is in bridge mode, all corresponding NICs (Native as well as VLAN) are set via the ZONE_SLAVES option |
1dcf513a FB |
458 | my @slaves = split(/ /, $ethsettings{"${uc}_SLAVES"}); |
459 | ||
460 | foreach (@slaves) { | |
461 | # Slaves can be set to a NICs name so we have to find out its MAC address | |
462 | $_ = &Network::get_mac_by_name($_); | |
463 | ||
464 | if ($_ eq $mac) { | |
465 | $access_selected{"NATIVE"} = "selected"; | |
466 | last; | |
467 | } | |
468 | } | |
0ec8e31a FB |
469 | } elsif ($mac eq $ethsettings{"${uc}_MACADDR"}) { # Native access via ZONE_MACADDR is only set if the zone does not access a NIC via a VLAN and the zone is not in bridge mode |
470 | $access_selected{"NATIVE"} = "selected"; | |
1dcf513a FB |
471 | } |
472 | ||
23b26ce5 | 473 | $access_selected{"NONE"} = ($access_selected{"NATIVE"} eq "") && ($access_selected{"VLAN"} eq "") ? "selected" : ""; |
1dcf513a FB |
474 | my $vlan_disabled = ($wlan) ? "disabled" : ""; |
475 | ||
5c33a761 LAH |
476 | # If the interface is assigned, hightlight table cell |
477 | if ($access_selected{"NONE"} eq "") { | |
478 | $highlight = $_; | |
479 | } | |
01139abb | 480 | |
23b26ce5 | 481 | print <<END |
5c33a761 LAH |
482 | <td class="$highlight"> |
483 | <select name="ACCESS $uc $mac" data-zone="$uc" data-mac="$mac" onchange="highlightAccess(this)"> | |
96d0c761 LAH |
484 | <option value="NONE" $access_selected{"NONE"}>- $Lang::tr{"zoneconf access none"} -</option> |
485 | <option value="NATIVE" $access_selected{"NATIVE"}>$Lang::tr{"zoneconf access native"}</option> | |
486 | <option value="VLAN" $access_selected{"VLAN"} $vlan_disabled>$Lang::tr{"zoneconf access vlan"}</option> | |
487 | </select> | |
715aa887 | 488 | <input type="number" class="vlanid" id="TAG-$uc-$mac" name="TAG $uc $mac" min="1" max="4094" value="$zone_vlan_id" required $field_disabled> |
96d0c761 | 489 | </td> |
1dcf513a FB |
490 | END |
491 | ; | |
23b26ce5 | 492 | } |
1dcf513a | 493 | |
96d0c761 | 494 | print "\t</tr>\n"; |
1dcf513a FB |
495 | } |
496 | ||
8de94a23 LAH |
497 | # STP options |
498 | my @stp_html = (); # form fields buffer (two rows) | |
499 | ||
500 | foreach (@zones) { # load settings and prepare form elements for each zone | |
501 | my $uc = uc $_; | |
502 | ||
8de94a23 LAH |
503 | # STP is not available if the RED interface is set to PPP, PPPoE, VDSL, ... |
504 | if ($uc eq "RED") { | |
52628052 | 505 | unless (Network::is_red_mode_ip()) { |
8de94a23 LAH |
506 | push(@stp_html, ["\t\t<td></td>\n", "\t\t<td></td>\n"]); # print empty cell |
507 | next; | |
508 | } | |
509 | } | |
510 | ||
511 | # load configuration | |
512 | my $stp_available = $ethsettings{"${uc}_MODE"} eq "bridge"; # STP is only available in bridge mode | |
513 | my $stp_enabled = $ethsettings{"${uc}_STP"} eq "on"; | |
514 | my $stp_priority = $ethsettings{"${uc}_STP_PRIORITY"}; | |
01139abb LAH |
515 | |
516 | # set priority to default value if no numerical value is configured | |
517 | $stp_priority = 32768 unless looks_like_number($stp_priority); | |
8de94a23 LAH |
518 | |
519 | # form element modifiers | |
520 | my $checked = ""; | |
521 | my $disabled = ""; | |
522 | $checked = "checked" if ($stp_available && $stp_enabled); | |
523 | $disabled = "disabled" unless $stp_available; | |
524 | ||
525 | # enable checkbox HTML | |
526 | my $row_1 = <<END | |
527 | <td> | |
b4434345 | 528 | <input type="checkbox" id="STP-$uc" name="STP-$uc" data-zone="$uc" onchange="changeEnableSTP(this)" $disabled $checked> |
8de94a23 LAH |
529 | </td> |
530 | END | |
531 | ; | |
532 | $disabled = "disabled" unless $stp_enabled; # STP priority can't be entered if STP is disabled | |
533 | ||
534 | # priority input box HTML | |
535 | my $row_2 = <<END | |
536 | <td> | |
01139abb | 537 | <input type="number" class="stp-priority" id="STP-PRIORITY-$uc" name="STP-PRIORITY-$uc" min="1" max="65535" value="$stp_priority" required $disabled> |
8de94a23 LAH |
538 | </td> |
539 | END | |
540 | ; | |
541 | # add fields to buffer | |
542 | push(@stp_html, [$row_1, $row_2]); | |
543 | } | |
544 | ||
545 | # print two rows of prepared form elements | |
546 | print <<END | |
547 | <tr class="half-height divider-top option-row"> | |
548 | <td class="heading bold">$Lang::tr{"zoneconf stp enable"}</td> | |
549 | END | |
550 | ; | |
551 | foreach (@stp_html) { | |
552 | print $_->[0]; # row 1 | |
553 | } | |
554 | print <<END | |
555 | </tr> | |
556 | <tr class="half-height option-row"> | |
557 | <td class="heading">$Lang::tr{"zoneconf stp priority"}</td> | |
558 | END | |
559 | ; | |
560 | foreach (@stp_html) { | |
561 | print $_->[1]; # row 2 | |
562 | } | |
563 | print "\t</tr>\n"; | |
564 | ||
63a1c81a | 565 | # footer and submit button |
1dcf513a FB |
566 | print <<END |
567 | </table> | |
1d6bc7a0 MT |
568 | |
569 | <div id="submit-container"> | |
23b26ce5 | 570 | $restart_notice |
1d6bc7a0 MT |
571 | <input type="submit" name="ACTION" value="$Lang::tr{"save"}"> |
572 | </div> | |
573 | </form> | |
1dcf513a FB |
574 | END |
575 | ; | |
576 | ||
577 | ### END OF TABLE ### | |
578 | ||
579 | &Header::closebox(); | |
580 | &Header::closebigbox(); | |
581 | &Header::closepage(); |