]>
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"}) { | |
a2f77069 LAH |
198 | my %VALIDATE_nic_check = (); # array of flags (assigned, restricted/pppoe, vlan, ...) per NIC |
199 | my $VALIDATE_error = ""; # contains an error message if the config validation failed | |
1dcf513a | 200 | |
52628052 LAH |
201 | # Loop trough all known zones to ensure a complete configuration file is created |
202 | foreach (@Network::known_network_zones) { | |
1dcf513a | 203 | my $uc = uc $_; |
a2f77069 | 204 | my $slave_string = ""; # list of interfaces attached to the bridge |
1dcf513a FB |
205 | my $zone_mode = $cgiparams{"MODE $uc"}; |
206 | my $VALIDATE_vlancount = 0; | |
f60b61e0 FB |
207 | my $VALIDATE_zoneslaves = 0; |
208 | ||
a2f77069 LAH |
209 | # Each zone can contain up to one bridge and up to one VLAN, |
210 | # cache their mac addresses to prevent unnecessary changes | |
211 | my $bridge_mac = $ethsettings{"${uc}_MACADDR"}; | |
212 | my $vlan_mac = $vlansettings{"${uc}_MAC_ADDRESS"}; | |
213 | ||
214 | # Clear old configuration | |
1dcf513a FB |
215 | $ethsettings{"${uc}_MACADDR"} = ""; |
216 | $ethsettings{"${uc}_MODE"} = ""; | |
217 | $ethsettings{"${uc}_SLAVES"} = ""; | |
218 | $vlansettings{"${uc}_PARENT_DEV"} = ""; | |
219 | $vlansettings{"${uc}_VLAN_ID"} = ""; | |
220 | $vlansettings{"${uc}_MAC_ADDRESS"} = ""; | |
221 | ||
222 | # If RED is not in DHCP or static mode, we only set its MACADDR property | |
223 | if ($uc eq "RED" && ! $cgiparams{"PPPACCESS"} eq "") { | |
224 | foreach (@nics) { | |
225 | my $mac = $_->[0]; | |
226 | ||
227 | if ($mac eq $cgiparams{"PPPACCESS"}) { | |
228 | $ethsettings{"${uc}_MACADDR"} = $mac; | |
229 | ||
230 | # Check if this interface is already accessed by any other zone | |
231 | # If this is the case, show an error message | |
232 | if ($VALIDATE_nic_check{"ACC $mac"}) { | |
233 | $VALIDATE_error = $Lang::tr{"zoneconf val ppp assignment error"}; | |
234 | } | |
235 | ||
236 | $VALIDATE_nic_check{"RESTRICT $mac"} = 1; | |
237 | last; | |
238 | } | |
239 | } | |
240 | ||
63a1c81a | 241 | # skip NIC/VLAN assignment and additional zone options for RED in PPP mode |
1dcf513a FB |
242 | next; |
243 | } | |
244 | ||
a2f77069 LAH |
245 | # Zone in bridge mode: Always assign a MAC to the bridge |
246 | if($zone_mode eq "BRIDGE") { | |
247 | # Ensure that the bridge's cached MAC does not come from a real NIC | |
248 | # (this could happen if the zone was in default mode before) | |
249 | foreach (@nics) { | |
250 | my $nic_mac = $_->[0]; | |
251 | if(Network::is_mac_equal($bridge_mac, $nic_mac)) { | |
252 | $bridge_mac = ""; | |
253 | last; | |
254 | } | |
255 | } | |
256 | ||
257 | # Generate random MAC if none was configured | |
258 | if(! Network::valid_mac($bridge_mac)) { | |
259 | $bridge_mac = Network::random_mac(); | |
260 | } | |
261 | ||
262 | # Assign the address to the bridge | |
263 | $ethsettings{"${uc}_MACADDR"} = $bridge_mac; | |
264 | } | |
265 | ||
1dcf513a FB |
266 | foreach (@nics) { |
267 | my $mac = $_->[0]; | |
268 | my $nic_access = $cgiparams{"ACCESS $uc $mac"}; | |
269 | ||
bb90622c MT |
270 | next unless ($nic_access); |
271 | ||
a2f77069 | 272 | # This NIC is to be assigned: check preconditions |
a6695868 | 273 | if ($nic_access ne "NONE") { |
1dcf513a FB |
274 | if ($VALIDATE_nic_check{"RESTRICT $mac"}) { # If this interface is already assigned to RED in PPP mode, throw an error |
275 | $VALIDATE_error = $Lang::tr{"zoneconf val ppp assignment error"}; | |
f60b61e0 FB |
276 | last; |
277 | } | |
278 | ||
a2f77069 | 279 | # Enforce bridge mode when you try to assign multiple NICs to a zone |
a6695868 | 280 | if ($zone_mode ne "BRIDGE" && $VALIDATE_zoneslaves > 0 && $nic_access ne "") { |
f60b61e0 FB |
281 | $VALIDATE_error = $Lang::tr{"zoneconf val zoneslave amount error"}; |
282 | last; | |
1dcf513a FB |
283 | } |
284 | ||
a2f77069 | 285 | # Mark this NIC as "accessed by zone" |
1dcf513a | 286 | $VALIDATE_nic_check{"ACC $mac"} = 1; |
f60b61e0 | 287 | $VALIDATE_zoneslaves++; |
1dcf513a FB |
288 | } |
289 | ||
290 | if ($nic_access eq "NATIVE") { | |
291 | if ($VALIDATE_nic_check{"NATIVE $mac"}) { | |
292 | $VALIDATE_error = $Lang::tr{"zoneconf val native assignment error"}; | |
f60b61e0 | 293 | last; |
1dcf513a FB |
294 | } |
295 | ||
296 | $VALIDATE_nic_check{"NATIVE $mac"} = 1; | |
297 | ||
a2f77069 | 298 | # Zone in bridge mode: Add NIC to slave list. Otherwise access NIC directly |
1dcf513a FB |
299 | if ($zone_mode eq "BRIDGE") { |
300 | $slave_string = "${slave_string}${mac} "; | |
301 | } else { | |
302 | $ethsettings{"${uc}_MACADDR"} = $mac; | |
303 | } | |
304 | } elsif ($nic_access eq "VLAN") { | |
305 | my $vlan_tag = $cgiparams{"TAG $uc $mac"}; | |
306 | ||
307 | if ($VALIDATE_nic_check{"VLAN $mac $vlan_tag"}) { | |
308 | $VALIDATE_error = $Lang::tr{"zoneconf val vlan tag assignment error"}; | |
f60b61e0 | 309 | last; |
1dcf513a FB |
310 | } |
311 | ||
312 | $VALIDATE_nic_check{"VLAN $mac $vlan_tag"} = 1; | |
715aa887 LAH |
313 | |
314 | # check VLAN tag range: 1..4094 (0, 4095 are reserved) | |
315 | unless (looks_like_number($vlan_tag) && ($vlan_tag >= 1) && ($vlan_tag <= 4094)) { | |
316 | $VALIDATE_error = $Lang::tr{"zoneconf val vlan tag range error"}; | |
f60b61e0 | 317 | last; |
1dcf513a FB |
318 | } |
319 | ||
a2f77069 LAH |
320 | # Generate random MAC if none was configured |
321 | if(! Network::valid_mac($vlan_mac)) { | |
322 | $vlan_mac = Network::random_mac(); | |
323 | } | |
1dcf513a FB |
324 | |
325 | $vlansettings{"${uc}_PARENT_DEV"} = $mac; | |
326 | $vlansettings{"${uc}_VLAN_ID"} = $vlan_tag; | |
a2f77069 | 327 | $vlansettings{"${uc}_MAC_ADDRESS"} = $vlan_mac; # Generated MAC |
1dcf513a | 328 | |
a2f77069 | 329 | # Zone in bridge mode: Add VLAN to slave list |
1dcf513a | 330 | if ($zone_mode eq "BRIDGE") { |
a2f77069 | 331 | $slave_string = "${slave_string}${vlan_mac} "; |
1dcf513a FB |
332 | } |
333 | ||
334 | $VALIDATE_vlancount++; # We can't allow more than one VLAN per zone | |
335 | } | |
336 | } | |
337 | ||
338 | if ($VALIDATE_vlancount > 1) { | |
339 | $VALIDATE_error = $Lang::tr{"zoneconf val vlan amount assignment error"}; | |
f60b61e0 | 340 | last; |
1dcf513a FB |
341 | } |
342 | ||
343 | chop($slave_string); | |
344 | ||
345 | if ($zone_mode eq "BRIDGE") { | |
346 | $ethsettings{"${uc}_MODE"} = "bridge"; | |
347 | $ethsettings{"${uc}_SLAVES"} = $slave_string; | |
1dcf513a | 348 | } |
8de94a23 LAH |
349 | |
350 | # STP options | |
351 | # (this has already been skipped when RED is in PPP mode, so we don't need to check for PPP here) | |
352 | $ethsettings{"${uc}_STP"} = ""; | |
353 | my $stp_enabled = $cgiparams{"STP-$uc"} eq "on"; | |
354 | my $stp_priority = $cgiparams{"STP-PRIORITY-$uc"}; | |
355 | ||
356 | if($stp_enabled) { | |
357 | unless($ethsettings{"${uc}_MODE"} eq "bridge") { # STP is only available in bridge mode | |
358 | $VALIDATE_error = $Lang::tr{"zoneconf val stp zone mode error"}; | |
359 | last; | |
360 | } | |
361 | unless (looks_like_number($stp_priority) && ($stp_priority >= 1) && ($stp_priority <= 65535)) { # STP bridge priority range: 1..65535 | |
362 | $VALIDATE_error = $Lang::tr{"zoneconf val stp priority range error"}; | |
363 | last; | |
364 | } | |
365 | $ethsettings{"${uc}_STP"} = "on"; # network-hotplug-bridges expects "on" | |
366 | $ethsettings{"${uc}_STP_PRIORITY"} = $stp_priority; | |
367 | } | |
1dcf513a FB |
368 | } |
369 | ||
63a1c81a | 370 | # validation failed, show error message and exit |
1dcf513a FB |
371 | if ($VALIDATE_error) { |
372 | &Header::openbox('100%', 'left', $Lang::tr{"error"}); | |
373 | ||
8797526d | 374 | print "$VALIDATE_error<br><br><a href='$ENV{'SCRIPT_NAME'}'>$Lang::tr{'back'}</a>\n"; |
1dcf513a FB |
375 | |
376 | &Header::closebox(); | |
377 | &Header::closebigbox(); | |
378 | &Header::closepage(); | |
379 | ||
380 | exit 0; | |
381 | } | |
382 | ||
63a1c81a | 383 | # new settings are valid, write configuration files |
1dcf513a FB |
384 | &General::writehash("${General::swroot}/ethernet/settings",\%ethsettings); |
385 | &General::writehash("${General::swroot}/ethernet/vlans",\%vlansettings); | |
7478903f | 386 | |
23b26ce5 | 387 | $restart_notice = $Lang::tr{'zoneconf notice reboot'}; |
1dcf513a FB |
388 | } |
389 | ||
1dcf513a FB |
390 | ### START OF TABLE ### |
391 | ||
63a1c81a LAH |
392 | &Header::openbox('100%', 'left', $Lang::tr{"zoneconf nic assignment"}); |
393 | ||
1dcf513a | 394 | print <<END |
0ec8e31a | 395 | <form method='post' enctype='multipart/form-data'> |
fc31c28d | 396 | <table id="zoneconf"> |
5e6eba88 | 397 | <tr class="divider-bottom"> |
fc31c28d | 398 | <td class="topleft"></td> |
1dcf513a FB |
399 | END |
400 | ; | |
401 | ||
0ec8e31a | 402 | # Fill the table header with all activated zones |
1dcf513a | 403 | foreach (@zones) { |
1dcf513a | 404 | my $uc = uc $_; |
1dcf513a | 405 | |
63a1c81a | 406 | # If the red zone is in PPP mode, don't show a mode dropdown |
23b26ce5 | 407 | if ($uc eq "RED") { |
1dcf513a | 408 | my $red_type = $ethsettings{"RED_TYPE"}; |
1dcf513a | 409 | |
52628052 | 410 | unless (Network::is_red_mode_ip()) { |
63a1c81a | 411 | print "\t\t<td class='heading bold $_'>$uc ($red_type)</td>\n"; |
1dcf513a | 412 | |
1dcf513a FB |
413 | next; # We're done here |
414 | } | |
415 | } | |
416 | ||
417 | my %mode_selected = (); | |
418 | my $zone_mode = $ethsettings{"${uc}_MODE"}; | |
419 | ||
420 | if ($zone_mode eq "") { | |
421 | $mode_selected{"DEFAULT"} = "selected"; | |
422 | } elsif ($zone_mode eq "bridge") { | |
423 | $mode_selected{"BRIDGE"} = "selected"; | |
1dcf513a FB |
424 | } |
425 | ||
426 | print <<END | |
5e6eba88 | 427 | <td class='heading bold $_'>$uc<br> |
b4434345 | 428 | <select name="MODE $uc" data-zone="$uc" onchange="changeZoneMode(this)"> |
1dcf513a FB |
429 | <option value="DEFAULT" $mode_selected{"DEFAULT"}>$Lang::tr{"zoneconf nicmode default"}</option> |
430 | <option value="BRIDGE" $mode_selected{"BRIDGE"}>$Lang::tr{"zoneconf nicmode bridge"}</option> | |
1dcf513a FB |
431 | </select> |
432 | </td> | |
433 | END | |
434 | ; | |
0ec8e31a FB |
435 | } |
436 | ||
96d0c761 | 437 | print "\t</tr>\n"; |
0ec8e31a | 438 | |
63a1c81a | 439 | # NIC assignment matrix |
0ec8e31a | 440 | foreach (@nics) { |
23b26ce5 | 441 | my $mac = $_->[0]; |
0ec8e31a | 442 | my $nic = $_->[1]; |
23b26ce5 | 443 | my $wlan = $_->[2]; |
0ec8e31a | 444 | |
5e6eba88 LAH |
445 | print "\t<tr class='nic-row'>\n"; |
446 | print "\t\t<td class='heading bold'>$nic<br>$mac</td>\n"; | |
0ec8e31a | 447 | |
23b26ce5 MT |
448 | # Iterate through all zones and check if the current NIC is assigned to it |
449 | foreach (@zones) { | |
450 | my $uc = uc $_; | |
5c33a761 | 451 | my $highlight = ""; |
0ec8e31a | 452 | |
23b26ce5 | 453 | if ($uc eq "RED") { |
23b26ce5 | 454 | # VLANs/Bridging is not possible if the RED interface is set to PPP, PPPoE, VDSL, ... |
52628052 | 455 | unless (Network::is_red_mode_ip()) { |
23b26ce5 | 456 | my $checked = ""; |
1dcf513a | 457 | |
0ec8e31a FB |
458 | if ($mac eq $ethsettings{"${uc}_MACADDR"}) { |
459 | $checked = "checked"; | |
5c33a761 | 460 | $highlight = $_; |
0ec8e31a FB |
461 | } |
462 | ||
96d0c761 | 463 | print <<END |
5c33a761 LAH |
464 | <td class="$highlight"> |
465 | <input type="radio" name="PPPACCESS" value="$mac" data-zone="RED" data-mac="$mac" onchange="highlightAccess(this)" $checked> | |
96d0c761 LAH |
466 | </td> |
467 | END | |
468 | ; | |
23b26ce5 MT |
469 | next; # We're done here |
470 | } | |
471 | } | |
472 | ||
473 | my %access_selected = (); | |
474 | my $zone_mode = $ethsettings{"${uc}_MODE"}; | |
475 | my $zone_parent_dev = $vlansettings{"${uc}_PARENT_DEV"}; # ZONE_PARENT_DEV is set if this zone accesses any interface via a VLAN | |
476 | my $field_disabled = "disabled"; # Only enable the VLAN ID input field if the current access mode is VLAN | |
1dcf513a FB |
477 | my $zone_vlan_id = ""; |
478 | ||
23b26ce5 MT |
479 | # 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 |
480 | $zone_parent_dev = &Network::get_mac_by_name($zone_parent_dev); | |
0ec8e31a | 481 | |
23b26ce5 MT |
482 | # If the current NIC is accessed by the current zone via a VLAN, the ZONE_PARENT_DEV option corresponds to the current NIC |
483 | if ($mac eq $zone_parent_dev) { | |
1dcf513a FB |
484 | $access_selected{"VLAN"} = "selected"; |
485 | $field_disabled = ""; | |
486 | $zone_vlan_id = $vlansettings{"${uc}_VLAN_ID"}; | |
0ec8e31a | 487 | } 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 |
488 | my @slaves = split(/ /, $ethsettings{"${uc}_SLAVES"}); |
489 | ||
490 | foreach (@slaves) { | |
491 | # Slaves can be set to a NICs name so we have to find out its MAC address | |
492 | $_ = &Network::get_mac_by_name($_); | |
493 | ||
494 | if ($_ eq $mac) { | |
495 | $access_selected{"NATIVE"} = "selected"; | |
496 | last; | |
497 | } | |
498 | } | |
0ec8e31a FB |
499 | } 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 |
500 | $access_selected{"NATIVE"} = "selected"; | |
1dcf513a FB |
501 | } |
502 | ||
23b26ce5 | 503 | $access_selected{"NONE"} = ($access_selected{"NATIVE"} eq "") && ($access_selected{"VLAN"} eq "") ? "selected" : ""; |
1dcf513a FB |
504 | my $vlan_disabled = ($wlan) ? "disabled" : ""; |
505 | ||
5c33a761 LAH |
506 | # If the interface is assigned, hightlight table cell |
507 | if ($access_selected{"NONE"} eq "") { | |
508 | $highlight = $_; | |
509 | } | |
01139abb | 510 | |
23b26ce5 | 511 | print <<END |
5c33a761 LAH |
512 | <td class="$highlight"> |
513 | <select name="ACCESS $uc $mac" data-zone="$uc" data-mac="$mac" onchange="highlightAccess(this)"> | |
96d0c761 LAH |
514 | <option value="NONE" $access_selected{"NONE"}>- $Lang::tr{"zoneconf access none"} -</option> |
515 | <option value="NATIVE" $access_selected{"NATIVE"}>$Lang::tr{"zoneconf access native"}</option> | |
516 | <option value="VLAN" $access_selected{"VLAN"} $vlan_disabled>$Lang::tr{"zoneconf access vlan"}</option> | |
517 | </select> | |
715aa887 | 518 | <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 | 519 | </td> |
1dcf513a FB |
520 | END |
521 | ; | |
23b26ce5 | 522 | } |
1dcf513a | 523 | |
96d0c761 | 524 | print "\t</tr>\n"; |
1dcf513a FB |
525 | } |
526 | ||
8de94a23 LAH |
527 | # STP options |
528 | my @stp_html = (); # form fields buffer (two rows) | |
529 | ||
530 | foreach (@zones) { # load settings and prepare form elements for each zone | |
531 | my $uc = uc $_; | |
532 | ||
8de94a23 LAH |
533 | # STP is not available if the RED interface is set to PPP, PPPoE, VDSL, ... |
534 | if ($uc eq "RED") { | |
52628052 | 535 | unless (Network::is_red_mode_ip()) { |
8de94a23 LAH |
536 | push(@stp_html, ["\t\t<td></td>\n", "\t\t<td></td>\n"]); # print empty cell |
537 | next; | |
538 | } | |
539 | } | |
540 | ||
541 | # load configuration | |
542 | my $stp_available = $ethsettings{"${uc}_MODE"} eq "bridge"; # STP is only available in bridge mode | |
543 | my $stp_enabled = $ethsettings{"${uc}_STP"} eq "on"; | |
544 | my $stp_priority = $ethsettings{"${uc}_STP_PRIORITY"}; | |
01139abb LAH |
545 | |
546 | # set priority to default value if no numerical value is configured | |
547 | $stp_priority = 32768 unless looks_like_number($stp_priority); | |
8de94a23 LAH |
548 | |
549 | # form element modifiers | |
550 | my $checked = ""; | |
551 | my $disabled = ""; | |
552 | $checked = "checked" if ($stp_available && $stp_enabled); | |
553 | $disabled = "disabled" unless $stp_available; | |
554 | ||
555 | # enable checkbox HTML | |
556 | my $row_1 = <<END | |
557 | <td> | |
b4434345 | 558 | <input type="checkbox" id="STP-$uc" name="STP-$uc" data-zone="$uc" onchange="changeEnableSTP(this)" $disabled $checked> |
8de94a23 LAH |
559 | </td> |
560 | END | |
561 | ; | |
562 | $disabled = "disabled" unless $stp_enabled; # STP priority can't be entered if STP is disabled | |
563 | ||
564 | # priority input box HTML | |
565 | my $row_2 = <<END | |
566 | <td> | |
01139abb | 567 | <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 |
568 | </td> |
569 | END | |
570 | ; | |
571 | # add fields to buffer | |
572 | push(@stp_html, [$row_1, $row_2]); | |
573 | } | |
574 | ||
575 | # print two rows of prepared form elements | |
576 | print <<END | |
577 | <tr class="half-height divider-top option-row"> | |
578 | <td class="heading bold">$Lang::tr{"zoneconf stp enable"}</td> | |
579 | END | |
580 | ; | |
581 | foreach (@stp_html) { | |
582 | print $_->[0]; # row 1 | |
583 | } | |
584 | print <<END | |
585 | </tr> | |
586 | <tr class="half-height option-row"> | |
587 | <td class="heading">$Lang::tr{"zoneconf stp priority"}</td> | |
588 | END | |
589 | ; | |
590 | foreach (@stp_html) { | |
591 | print $_->[1]; # row 2 | |
592 | } | |
593 | print "\t</tr>\n"; | |
594 | ||
63a1c81a | 595 | # footer and submit button |
1dcf513a FB |
596 | print <<END |
597 | </table> | |
1d6bc7a0 MT |
598 | |
599 | <div id="submit-container"> | |
23b26ce5 | 600 | $restart_notice |
1d6bc7a0 MT |
601 | <input type="submit" name="ACTION" value="$Lang::tr{"save"}"> |
602 | </div> | |
603 | </form> | |
1dcf513a FB |
604 | END |
605 | ; | |
606 | ||
607 | ### END OF TABLE ### | |
608 | ||
609 | &Header::closebox(); | |
610 | &Header::closebigbox(); | |
611 | &Header::closepage(); |