diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc index 5de9f40b7..360e66635 100644 --- a/src/etc/inc/interfaces.inc +++ b/src/etc/inc/interfaces.inc @@ -1,7 +1,7 @@ + * Copyright (C) 2015-2024 Franco Fichtner * Copyright (C) 2004-2008 Scott Ullrich * Copyright (C) 2008-2009 Ermal Luçi * Copyright (C) 2005 Espen Johansen @@ -2270,13 +2270,40 @@ function interface_configure($verbose = false, $interface = 'wan', $reload = fal } /* - * Don't try to reapply the spoofed MAC if it's already applied. + * Do not try to reapply the spoofed MAC if it's already applied. * When ifconfig link is used, it cycles the interface down/up, * which triggers the interface config again, which attempts to - * spoof the MAC again which cycles the link again... + * spoof the MAC again which cycles the link again. */ - if (!empty($wancfg['spoofmac']) && strcasecmp($wancfg['spoofmac'], get_interface_mac($realhwif, $ifconfig_details))) { - mwexecf('/sbin/ifconfig %s link %s', [$realhwif, $wancfg['spoofmac']]); + $mac_prev = $ifconfig_details[$realhwif]['macaddr'] ?? ''; + $mac_next = !empty($wancfg['spoofmac']) ? $wancfg['spoofmac'] : ($ifconfig_details[$realhwif]['macaddr_hw'] ?? ''); + if (!empty($mac_prev) && !empty($mac_next) && strcasecmp($mac_prev, $mac_next)) { + /* + * When the hardware interface matches the IPv6 interface where we set + * the MAC address we can assist in providing the accompanying link-local + * address (EUI-64 embedded MAC address) by nudging the kernel to reapply + * this address due to the auto_linklocal field which we do not operate + * unless for bridges, but that one is a reversed use case. + * + * Delete all link-local addresses and send the "down" event to bring + * the kernel into the transition where it will auto-add the right + * address on the following "up" event. + */ + $mac_cmd[] = exec_safe('/sbin/ifconfig %s link %s', [$realhwif, $mac_next]); + if ($realhwif == $realifv6) { + $ll_found = false; + foreach (array_keys(interfaces_addresses($realifv6, true, $ifconfig_details)) as $tmpiface) { + if (is_linklocal($tmpiface)) { + $tmpip = explode('%', $tmpiface)[0]; + legacy_interface_deladdress($realifv6, $tmpip, 6); + $ll_found = true; + } + } + if ($ll_found) { + $mac_cmd[] = 'down'; + } + } + mwexec(join(' ', $mac_cmd)); } /* only try to set media properties when requested */ diff --git a/src/etc/inc/interfaces.lib.inc b/src/etc/inc/interfaces.lib.inc index fda67e9f9..8245b7ce2 100644 --- a/src/etc/inc/interfaces.lib.inc +++ b/src/etc/inc/interfaces.lib.inc @@ -1,7 +1,7 @@ + * Copyright (c) 2015-2024 Franco Fichtner * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -304,8 +304,15 @@ function legacy_interfaces_details($intf = null) $result[$current_interface]["options"][] = strtolower(trim($option)); } } elseif (strpos($line, "\tether ") !== false) { - // mac address + // current mac address $result[$current_interface]["macaddr"] = $line_parts[1]; + // fill original as well if not found + if (!isset($result[$current_interface]['macaddr_hw'])) { + $result[$current_interface]['macaddr_hw'] = $line_parts[1]; + } + } elseif (strpos($line, "\thwaddr ") !== false) { + // original mac address + $result[$current_interface]['macaddr_hw'] = $line_parts[1]; } elseif (strpos($line, "\tinet ") !== false) { // IPv4 information unset($mask);