]>
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; | |
348 | } elsif ($zone_mode eq "MACVTAP") { | |
349 | $ethsettings{"${uc}_MODE"} = "macvtap"; | |
350 | } | |
8de94a23 LAH |
351 | |
352 | # STP options | |
353 | # (this has already been skipped when RED is in PPP mode, so we don't need to check for PPP here) | |
354 | $ethsettings{"${uc}_STP"} = ""; | |
355 | my $stp_enabled = $cgiparams{"STP-$uc"} eq "on"; | |
356 | my $stp_priority = $cgiparams{"STP-PRIORITY-$uc"}; | |
357 | ||
358 | if($stp_enabled) { | |
359 | unless($ethsettings{"${uc}_MODE"} eq "bridge") { # STP is only available in bridge mode | |
360 | $VALIDATE_error = $Lang::tr{"zoneconf val stp zone mode error"}; | |
361 | last; | |
362 | } | |
363 | unless (looks_like_number($stp_priority) && ($stp_priority >= 1) && ($stp_priority <= 65535)) { # STP bridge priority range: 1..65535 | |
364 | $VALIDATE_error = $Lang::tr{"zoneconf val stp priority range error"}; | |
365 | last; | |
366 | } | |
367 | $ethsettings{"${uc}_STP"} = "on"; # network-hotplug-bridges expects "on" | |
368 | $ethsettings{"${uc}_STP_PRIORITY"} = $stp_priority; | |
369 | } | |
1dcf513a FB |
370 | } |
371 | ||
63a1c81a | 372 | # validation failed, show error message and exit |
1dcf513a FB |
373 | if ($VALIDATE_error) { |
374 | &Header::openbox('100%', 'left', $Lang::tr{"error"}); | |
375 | ||
8797526d | 376 | print "$VALIDATE_error<br><br><a href='$ENV{'SCRIPT_NAME'}'>$Lang::tr{'back'}</a>\n"; |
1dcf513a FB |
377 | |
378 | &Header::closebox(); | |
379 | &Header::closebigbox(); | |
380 | &Header::closepage(); | |
381 | ||
382 | exit 0; | |
383 | } | |
384 | ||
63a1c81a | 385 | # new settings are valid, write configuration files |
1dcf513a FB |
386 | &General::writehash("${General::swroot}/ethernet/settings",\%ethsettings); |
387 | &General::writehash("${General::swroot}/ethernet/vlans",\%vlansettings); | |
7478903f | 388 | |
23b26ce5 | 389 | $restart_notice = $Lang::tr{'zoneconf notice reboot'}; |
1dcf513a FB |
390 | } |
391 | ||
1dcf513a FB |
392 | ### START OF TABLE ### |
393 | ||
63a1c81a LAH |
394 | &Header::openbox('100%', 'left', $Lang::tr{"zoneconf nic assignment"}); |
395 | ||
1dcf513a | 396 | print <<END |
0ec8e31a | 397 | <form method='post' enctype='multipart/form-data'> |
fc31c28d | 398 | <table id="zoneconf"> |
5e6eba88 | 399 | <tr class="divider-bottom"> |
fc31c28d | 400 | <td class="topleft"></td> |
1dcf513a FB |
401 | END |
402 | ; | |
403 | ||
0ec8e31a | 404 | # Fill the table header with all activated zones |
1dcf513a | 405 | foreach (@zones) { |
1dcf513a | 406 | my $uc = uc $_; |
1dcf513a | 407 | |
63a1c81a | 408 | # If the red zone is in PPP mode, don't show a mode dropdown |
23b26ce5 | 409 | if ($uc eq "RED") { |
1dcf513a | 410 | my $red_type = $ethsettings{"RED_TYPE"}; |
1dcf513a | 411 | |
52628052 | 412 | unless (Network::is_red_mode_ip()) { |
63a1c81a | 413 | print "\t\t<td class='heading bold $_'>$uc ($red_type)</td>\n"; |
1dcf513a | 414 | |
1dcf513a FB |
415 | next; # We're done here |
416 | } | |
417 | } | |
418 | ||
419 | my %mode_selected = (); | |
420 | my $zone_mode = $ethsettings{"${uc}_MODE"}; | |
421 | ||
422 | if ($zone_mode eq "") { | |
423 | $mode_selected{"DEFAULT"} = "selected"; | |
424 | } elsif ($zone_mode eq "bridge") { | |
425 | $mode_selected{"BRIDGE"} = "selected"; | |
426 | } elsif ($zone_mode eq "macvtap") { | |
427 | $mode_selected{"MACVTAP"} = "selected"; | |
428 | } | |
429 | ||
430 | print <<END | |
5e6eba88 | 431 | <td class='heading bold $_'>$uc<br> |
b4434345 | 432 | <select name="MODE $uc" data-zone="$uc" onchange="changeZoneMode(this)"> |
1dcf513a FB |
433 | <option value="DEFAULT" $mode_selected{"DEFAULT"}>$Lang::tr{"zoneconf nicmode default"}</option> |
434 | <option value="BRIDGE" $mode_selected{"BRIDGE"}>$Lang::tr{"zoneconf nicmode bridge"}</option> | |
435 | <option value="MACVTAP" $mode_selected{"MACVTAP"}>$Lang::tr{"zoneconf nicmode macvtap"}</option> | |
436 | </select> | |
437 | </td> | |
438 | END | |
439 | ; | |
0ec8e31a FB |
440 | } |
441 | ||
96d0c761 | 442 | print "\t</tr>\n"; |
0ec8e31a | 443 | |
63a1c81a | 444 | # NIC assignment matrix |
0ec8e31a | 445 | foreach (@nics) { |
23b26ce5 | 446 | my $mac = $_->[0]; |
0ec8e31a | 447 | my $nic = $_->[1]; |
23b26ce5 | 448 | my $wlan = $_->[2]; |
0ec8e31a | 449 | |
5e6eba88 LAH |
450 | print "\t<tr class='nic-row'>\n"; |
451 | print "\t\t<td class='heading bold'>$nic<br>$mac</td>\n"; | |
0ec8e31a | 452 | |
23b26ce5 MT |
453 | # Iterate through all zones and check if the current NIC is assigned to it |
454 | foreach (@zones) { | |
455 | my $uc = uc $_; | |
5c33a761 | 456 | my $highlight = ""; |
0ec8e31a | 457 | |
23b26ce5 | 458 | if ($uc eq "RED") { |
23b26ce5 | 459 | # VLANs/Bridging is not possible if the RED interface is set to PPP, PPPoE, VDSL, ... |
52628052 | 460 | unless (Network::is_red_mode_ip()) { |
23b26ce5 | 461 | my $checked = ""; |
1dcf513a | 462 | |
0ec8e31a FB |
463 | if ($mac eq $ethsettings{"${uc}_MACADDR"}) { |
464 | $checked = "checked"; | |
5c33a761 | 465 | $highlight = $_; |
0ec8e31a FB |
466 | } |
467 | ||
96d0c761 | 468 | print <<END |
5c33a761 LAH |
469 | <td class="$highlight"> |
470 | <input type="radio" name="PPPACCESS" value="$mac" data-zone="RED" data-mac="$mac" onchange="highlightAccess(this)" $checked> | |
96d0c761 LAH |
471 | </td> |
472 | END | |
473 | ; | |
23b26ce5 MT |
474 | next; # We're done here |
475 | } | |
476 | } | |
477 | ||
478 | my %access_selected = (); | |
479 | my $zone_mode = $ethsettings{"${uc}_MODE"}; | |
480 | my $zone_parent_dev = $vlansettings{"${uc}_PARENT_DEV"}; # ZONE_PARENT_DEV is set if this zone accesses any interface via a VLAN | |
481 | my $field_disabled = "disabled"; # Only enable the VLAN ID input field if the current access mode is VLAN | |
1dcf513a FB |
482 | my $zone_vlan_id = ""; |
483 | ||
23b26ce5 MT |
484 | # 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 |
485 | $zone_parent_dev = &Network::get_mac_by_name($zone_parent_dev); | |
0ec8e31a | 486 | |
23b26ce5 MT |
487 | # If the current NIC is accessed by the current zone via a VLAN, the ZONE_PARENT_DEV option corresponds to the current NIC |
488 | if ($mac eq $zone_parent_dev) { | |
1dcf513a FB |
489 | $access_selected{"VLAN"} = "selected"; |
490 | $field_disabled = ""; | |
491 | $zone_vlan_id = $vlansettings{"${uc}_VLAN_ID"}; | |
0ec8e31a | 492 | } 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 |
493 | my @slaves = split(/ /, $ethsettings{"${uc}_SLAVES"}); |
494 | ||
495 | foreach (@slaves) { | |
496 | # Slaves can be set to a NICs name so we have to find out its MAC address | |
497 | $_ = &Network::get_mac_by_name($_); | |
498 | ||
499 | if ($_ eq $mac) { | |
500 | $access_selected{"NATIVE"} = "selected"; | |
501 | last; | |
502 | } | |
503 | } | |
0ec8e31a FB |
504 | } 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 |
505 | $access_selected{"NATIVE"} = "selected"; | |
1dcf513a FB |
506 | } |
507 | ||
23b26ce5 | 508 | $access_selected{"NONE"} = ($access_selected{"NATIVE"} eq "") && ($access_selected{"VLAN"} eq "") ? "selected" : ""; |
1dcf513a FB |
509 | my $vlan_disabled = ($wlan) ? "disabled" : ""; |
510 | ||
5c33a761 LAH |
511 | # If the interface is assigned, hightlight table cell |
512 | if ($access_selected{"NONE"} eq "") { | |
513 | $highlight = $_; | |
514 | } | |
01139abb | 515 | |
23b26ce5 | 516 | print <<END |
5c33a761 LAH |
517 | <td class="$highlight"> |
518 | <select name="ACCESS $uc $mac" data-zone="$uc" data-mac="$mac" onchange="highlightAccess(this)"> | |
96d0c761 LAH |
519 | <option value="NONE" $access_selected{"NONE"}>- $Lang::tr{"zoneconf access none"} -</option> |
520 | <option value="NATIVE" $access_selected{"NATIVE"}>$Lang::tr{"zoneconf access native"}</option> | |
521 | <option value="VLAN" $access_selected{"VLAN"} $vlan_disabled>$Lang::tr{"zoneconf access vlan"}</option> | |
522 | </select> | |
715aa887 | 523 | <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 | 524 | </td> |
1dcf513a FB |
525 | END |
526 | ; | |
23b26ce5 | 527 | } |
1dcf513a | 528 | |
96d0c761 | 529 | print "\t</tr>\n"; |
1dcf513a FB |
530 | } |
531 | ||
8de94a23 LAH |
532 | # STP options |
533 | my @stp_html = (); # form fields buffer (two rows) | |
534 | ||
535 | foreach (@zones) { # load settings and prepare form elements for each zone | |
536 | my $uc = uc $_; | |
537 | ||
8de94a23 LAH |
538 | # STP is not available if the RED interface is set to PPP, PPPoE, VDSL, ... |
539 | if ($uc eq "RED") { | |
52628052 | 540 | unless (Network::is_red_mode_ip()) { |
8de94a23 LAH |
541 | push(@stp_html, ["\t\t<td></td>\n", "\t\t<td></td>\n"]); # print empty cell |
542 | next; | |
543 | } | |
544 | } | |
545 | ||
546 | # load configuration | |
547 | my $stp_available = $ethsettings{"${uc}_MODE"} eq "bridge"; # STP is only available in bridge mode | |
548 | my $stp_enabled = $ethsettings{"${uc}_STP"} eq "on"; | |
549 | my $stp_priority = $ethsettings{"${uc}_STP_PRIORITY"}; | |
01139abb LAH |
550 | |
551 | # set priority to default value if no numerical value is configured | |
552 | $stp_priority = 32768 unless looks_like_number($stp_priority); | |
8de94a23 LAH |
553 | |
554 | # form element modifiers | |
555 | my $checked = ""; | |
556 | my $disabled = ""; | |
557 | $checked = "checked" if ($stp_available && $stp_enabled); | |
558 | $disabled = "disabled" unless $stp_available; | |
559 | ||
560 | # enable checkbox HTML | |
561 | my $row_1 = <<END | |
562 | <td> | |
b4434345 | 563 | <input type="checkbox" id="STP-$uc" name="STP-$uc" data-zone="$uc" onchange="changeEnableSTP(this)" $disabled $checked> |
8de94a23 LAH |
564 | </td> |
565 | END | |
566 | ; | |
567 | $disabled = "disabled" unless $stp_enabled; # STP priority can't be entered if STP is disabled | |
568 | ||
569 | # priority input box HTML | |
570 | my $row_2 = <<END | |
571 | <td> | |
01139abb | 572 | <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 |
573 | </td> |
574 | END | |
575 | ; | |
576 | # add fields to buffer | |
577 | push(@stp_html, [$row_1, $row_2]); | |
578 | } | |
579 | ||
580 | # print two rows of prepared form elements | |
581 | print <<END | |
582 | <tr class="half-height divider-top option-row"> | |
583 | <td class="heading bold">$Lang::tr{"zoneconf stp enable"}</td> | |
584 | END | |
585 | ; | |
586 | foreach (@stp_html) { | |
587 | print $_->[0]; # row 1 | |
588 | } | |
589 | print <<END | |
590 | </tr> | |
591 | <tr class="half-height option-row"> | |
592 | <td class="heading">$Lang::tr{"zoneconf stp priority"}</td> | |
593 | END | |
594 | ; | |
595 | foreach (@stp_html) { | |
596 | print $_->[1]; # row 2 | |
597 | } | |
598 | print "\t</tr>\n"; | |
599 | ||
63a1c81a | 600 | # footer and submit button |
1dcf513a FB |
601 | print <<END |
602 | </table> | |
1d6bc7a0 MT |
603 | |
604 | <div id="submit-container"> | |
23b26ce5 | 605 | $restart_notice |
1d6bc7a0 MT |
606 | <input type="submit" name="ACTION" value="$Lang::tr{"save"}"> |
607 | </div> | |
608 | </form> | |
1dcf513a FB |
609 | END |
610 | ; | |
611 | ||
612 | ### END OF TABLE ### | |
613 | ||
614 | &Header::closebox(); | |
615 | &Header::closebigbox(); | |
616 | &Header::closepage(); |