ethtool-util: fix setting advertising link modes

Fixes a regression caused by d307410327.

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.
This commit is contained in:
Yu Watanabe
2025-09-02 23:41:18 +09:00
committed by Daan De Meyer
parent b10619484d
commit d8af104fb0

View File

@@ -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));