From d8af104fb0eabd1f752ed80069a4cd9fd31446e0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 2 Sep 2025 23:41:18 +0900 Subject: [PATCH] ethtool-util: fix setting advertising link modes Fixes a regression caused by d307410327d14398cb60b72db9d0034b12950a72. The link_mode_masks flex array in struct ethtool_link_settings contains three packed arrays, and the length of each array is given by link_mode_masks_nwords field: ``` __u32 link_mode_masks[]; /* layout of link_mode_masks fields: * __u32 map_supported[link_mode_masks_nwords]; * __u32 map_advertising[link_mode_masks_nwords]; * __u32 map_lp_advertising[link_mode_masks_nwords]; */ ``` Hence, we cannot use the received data as is through the union, but need to shift the array to make each map accessible through the union. --- src/shared/ethtool-util.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index bf0095a5ff6..d961a81eca9 100644 --- a/src/shared/ethtool-util.c +++ b/src/shared/ethtool-util.c @@ -687,10 +687,19 @@ static int get_glinksettings(int fd, struct ifreq *ifr, union ethtool_link_usett if (ecmd.base.link_mode_masks_nwords <= 0 || ecmd.base.cmd != ETHTOOL_GLINKSETTINGS) return -EOPNOTSUPP; - union ethtool_link_usettings *u = newdup(union ethtool_link_usettings, &ecmd, 1); + union ethtool_link_usettings *u = new0(union ethtool_link_usettings, 1); if (!u) return -ENOMEM; + u->base = ecmd.base; + + uint32_t *p = ecmd.base.link_mode_masks; + memcpy(u->link_modes.supported, p, sizeof(uint32_t) * ecmd.base.link_mode_masks_nwords); + p += ecmd.base.link_mode_masks_nwords; + memcpy(u->link_modes.advertising, p, sizeof(uint32_t) * ecmd.base.link_mode_masks_nwords); + p += ecmd.base.link_mode_masks_nwords; + memcpy(u->link_modes.lp_advertising, p, sizeof(uint32_t) * ecmd.base.link_mode_masks_nwords); + *ret = u; return 0; } @@ -742,8 +751,14 @@ static int set_slinksettings(int fd, struct ifreq *ifr, const union ethtool_link if (u->base.cmd != ETHTOOL_GLINKSETTINGS || u->base.link_mode_masks_nwords <= 0) return -EINVAL; - union ethtool_link_usettings ecmd = *u; + union ethtool_link_usettings ecmd = { .base = u->base }; ecmd.base.cmd = ETHTOOL_SLINKSETTINGS; + + uint32_t *p = ecmd.base.link_mode_masks; + p = mempcpy(p, u->link_modes.supported, sizeof(uint32_t) * ecmd.base.link_mode_masks_nwords); + p = mempcpy(p, u->link_modes.advertising, sizeof(uint32_t) * ecmd.base.link_mode_masks_nwords); + memcpy(p, u->link_modes.lp_advertising, sizeof(uint32_t) * ecmd.base.link_mode_masks_nwords); + ifr->ifr_data = (void *) &ecmd; return RET_NERRNO(ioctl(fd, SIOCETHTOOL, ifr)); -- 2.47.3