static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { u32 config = 0; u32 ret = 0; struct qlcnic_adapter *adapter = netdev_priv(dev); if (adapter->ahw->port_type != QLCNIC_GBE) return -EOPNOTSUPP; /* read which mode */ if (ecmd->duplex) config |= 0x1; if (ecmd->autoneg) config |= 0x2; switch (ethtool_cmd_speed(ecmd)) { case SPEED_10: config |= (0 << 8); break; case SPEED_100: config |= (1 << 8); break; case SPEED_1000: config |= (10 << 8); break; default: return -EIO; } ret = qlcnic_fw_cmd_set_port(adapter, config); if (ret == QLCNIC_RCODE_NOT_SUPPORTED) return -EOPNOTSUPP; else if (ret) return -EIO; adapter->link_speed = ethtool_cmd_speed(ecmd); adapter->link_duplex = ecmd->duplex; adapter->link_autoneg = ecmd->autoneg; if (!netif_running(dev)) return 0; dev->netdev_ops->ndo_stop(dev); return dev->netdev_ops->ndo_open(dev); }
static int qlcnic_set_port_config(struct qlcnic_adapter *adapter, struct ethtool_cmd *ecmd) { u32 ret = 0, config = 0; /* read which mode */ if (ecmd->duplex) config |= 0x1; if (ecmd->autoneg) config |= 0x2; switch (ethtool_cmd_speed(ecmd)) { case SPEED_10: config |= (0 << 8); break; case SPEED_100: config |= (1 << 8); break; case SPEED_1000: config |= (10 << 8); break; default: return -EIO; } ret = qlcnic_fw_cmd_set_port(adapter, config); if (ret == QLCNIC_RCODE_NOT_SUPPORTED) return -EOPNOTSUPP; else if (ret) return -EIO; return ret; }
static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { u32 ret = 0; struct qlcnic_adapter *adapter = netdev_priv(dev); if (adapter->ahw->port_type != QLCNIC_GBE) return -EOPNOTSUPP; if (qlcnic_83xx_check(adapter)) ret = qlcnic_83xx_set_settings(adapter, ecmd); else ret = qlcnic_set_port_config(adapter, ecmd); if (!ret) return ret; adapter->ahw->link_speed = ethtool_cmd_speed(ecmd); adapter->ahw->link_duplex = ecmd->duplex; adapter->ahw->link_autoneg = ecmd->autoneg; if (!netif_running(dev)) return 0; dev->netdev_ops->ndo_stop(dev); return dev->netdev_ops->ndo_open(dev); }
u32 ethtool_bitrate(const char *ifname) { int ret, sock, bitrate; struct ifreq ifr; struct ethtool_cmd ecmd; sock = af_socket(AF_INET); memset(&ecmd, 0, sizeof(ecmd)); memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); ecmd.cmd = ETHTOOL_GSET; ifr.ifr_data = (char *) &ecmd; ret = ioctl(sock, SIOCETHTOOL, &ifr); if (ret) { bitrate = 0; goto out; } bitrate = ethtool_cmd_speed(&ecmd); if (bitrate == SPEED_UNKNOWN) bitrate = 0; out: close(sock); return bitrate; }
static int xgbe_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { struct xgbe_prv_data *pdata = netdev_priv(netdev); struct phy_device *phydev = pdata->phydev; u32 speed; int ret; DBGPR("-->xgbe_set_settings\n"); if (!pdata->phydev) return -ENODEV; speed = ethtool_cmd_speed(cmd); if (cmd->phy_address != phydev->addr) return -EINVAL; if ((cmd->autoneg != AUTONEG_ENABLE) && (cmd->autoneg != AUTONEG_DISABLE)) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE) { switch (speed) { case SPEED_10000: case SPEED_2500: case SPEED_1000: break; default: return -EINVAL; } if (cmd->duplex != DUPLEX_FULL) return -EINVAL; } cmd->advertising &= phydev->supported; if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising) return -EINVAL; ret = 0; phydev->autoneg = cmd->autoneg; phydev->speed = speed; phydev->duplex = cmd->duplex; phydev->advertising = cmd->advertising; if (cmd->autoneg == AUTONEG_ENABLE) phydev->advertising |= ADVERTISED_Autoneg; else phydev->advertising &= ~ADVERTISED_Autoneg; if (netif_running(netdev)) ret = phy_start_aneg(phydev); DBGPR("<--xgbe_set_settings\n"); return ret; }
static int qede_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct qede_dev *edev = netdev_priv(dev); struct qed_link_output current_link; struct qed_link_params params; u32 speed; if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { DP_INFO(edev, "Link settings are not allowed to be changed\n"); return -EOPNOTSUPP; } memset(¤t_link, 0, sizeof(current_link)); memset(¶ms, 0, sizeof(params)); edev->ops->common->get_link(edev->cdev, ¤t_link); speed = ethtool_cmd_speed(cmd); params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS; params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG; if (cmd->autoneg == AUTONEG_ENABLE) { params.autoneg = true; params.forced_speed = 0; params.adv_speeds = cmd->advertising; } else { /* forced speed */ params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED; params.autoneg = false; params.forced_speed = speed; switch (speed) { case SPEED_10000: if (!(current_link.supported_caps & SUPPORTED_10000baseKR_Full)) { DP_INFO(edev, "10G speed not supported\n"); return -EINVAL; } params.adv_speeds = SUPPORTED_10000baseKR_Full; break; case SPEED_40000: if (!(current_link.supported_caps & SUPPORTED_40000baseLR4_Full)) { DP_INFO(edev, "40G speed not supported\n"); return -EINVAL; } params.adv_speeds = SUPPORTED_40000baseLR4_Full; break; default: DP_INFO(edev, "Unsupported speed %u\n", speed); return -EINVAL; } } params.link_up = true; edev->ops->common->set_link(edev->cdev, ¶ms); return 0; }
/** * vxge_ethtool_sset - Sets different link parameters. * @dev: device pointer. * @info: pointer to the structure with parameters given by ethtool to set * link information. * * The function sets different link parameters provided by the user onto * the NIC. * Return value: * 0 on success. */ static int vxge_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { /* We currently only support 10Gb/FULL */ if ((info->autoneg == AUTONEG_ENABLE) || (ethtool_cmd_speed(info) != SPEED_10000) || (info->duplex != DUPLEX_FULL)) return -EINVAL; return 0; }
static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; u32 caps; int rc; if (ecmd->autoneg) { caps = (ethtool_to_mcdi_cap(ecmd->advertising) | 1 << MC_CMD_PHY_CAP_AN_LBN); } else if (ecmd->duplex) { switch (ethtool_cmd_speed(ecmd)) { case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break; case 40000: caps = 1 << MC_CMD_PHY_CAP_40000FDX_LBN; break; default: return -EINVAL; } } else { switch (ethtool_cmd_speed(ecmd)) { case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; default: return -EINVAL; } } rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), efx->loopback_mode, 0); if (rc) return rc; if (ecmd->autoneg) { efx_link_set_advertising( efx, ecmd->advertising | ADVERTISED_Autoneg); phy_cfg->forced_cap = 0; } else { efx_link_set_advertising(efx, 0); phy_cfg->forced_cap = caps; } return 0; }
static int bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { /* 10G full duplex setting supported only */ if (cmd->autoneg == AUTONEG_ENABLE) return -EOPNOTSUPP; else { if ((ethtool_cmd_speed(cmd) == SPEED_10000) && (cmd->duplex == DUPLEX_FULL)) return 0; } return -EOPNOTSUPP; }
static int atl1c_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct atl1c_adapter *adapter = netdev_priv(netdev); struct atl1c_hw *hw = &adapter->hw; u16 autoneg_advertised; while (test_and_set_bit(__AT_RESETTING, &adapter->flags)) msleep(1); if (ecmd->autoneg == AUTONEG_ENABLE) { autoneg_advertised = ADVERTISED_Autoneg; } else { u32 speed = ethtool_cmd_speed(ecmd); if (speed == SPEED_1000) { if (ecmd->duplex != DUPLEX_FULL) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, "1000M half is invalid\n"); clear_bit(__AT_RESETTING, &adapter->flags); return -EINVAL; } autoneg_advertised = ADVERTISED_1000baseT_Full; } else if (speed == SPEED_100) { if (ecmd->duplex == DUPLEX_FULL) autoneg_advertised = ADVERTISED_100baseT_Full; else autoneg_advertised = ADVERTISED_100baseT_Half; } else { if (ecmd->duplex == DUPLEX_FULL) autoneg_advertised = ADVERTISED_10baseT_Full; else autoneg_advertised = ADVERTISED_10baseT_Half; } } if (hw->autoneg_advertised != autoneg_advertised) { hw->autoneg_advertised = autoneg_advertised; if (atl1c_restart_autoneg(hw) != 0) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, "ethtool speed/duplex setting failed\n"); clear_bit(__AT_RESETTING, &adapter->flags); return -EINVAL; } } clear_bit(__AT_RESETTING, &adapter->flags); return 0; }
static int netvsc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct net_device_context *ndc = netdev_priv(dev); u32 speed; speed = ethtool_cmd_speed(cmd); if (!ethtool_validate_speed(speed) || !ethtool_validate_duplex(cmd->duplex) || !netvsc_validate_ethtool_ss_cmd(cmd)) return -EINVAL; ndc->speed = speed; ndc->duplex = cmd->duplex; return 0; }
static int efx_ethtool_set_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd) #endif { struct efx_nic *efx = netdev_priv(net_dev); int rc; #ifdef EFX_NOT_UPSTREAM /* Older versions of ethtool have the following short-comings: * - They don't understand 10G. * - They have no "advertising" field to allow someone to * control the speeds supported by a non-autoneg PHY. * Support these versions by allowing the user to use "autoneg on" * to revert the advertised capabilities to the default set, even * on a PHY that doesn't support autoneg. * * The user can override this behaviour when using "ethtool advertise" * on ethtool-6 by including ADVERTISED_Autoneg = 0x40. */ if (ecmd->advertising != efx->link_advertising && ecmd->autoneg && !(ecmd->advertising & ADVERTISED_Autoneg)) { if (ecmd->advertising == (ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half | ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half)) ecmd->advertising = ecmd->supported; if (ecmd->autoneg && !(ecmd->supported & SUPPORTED_Autoneg)) ecmd->autoneg = 0; } #endif /* GMAC does not support 1000Mbps HD */ if ((ethtool_cmd_speed(ecmd) == SPEED_1000) && (ecmd->duplex != DUPLEX_FULL)) { netif_dbg(efx, drv, efx->net_dev, "rejecting unsupported 1000Mbps HD setting\n"); return -EINVAL; } mutex_lock(&efx->mac_lock); rc = efx->phy_op->set_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); return rc; }
/* * Obtain an appropriate bandwidth for the interface if_name. On Linux, we * get this via an ioctl(). Elsewhere or in the error case, we return the * speed as 0. */ unsigned int opal_ethtool_get_speed (const char *if_name) { unsigned int speed = 0; #if defined(HAVE_DECL_SIOCETHTOOL) && defined(HAVE_STRUCT_IFREQ) && defined(HAVE_STRUCT_ETHTOOL_CMD) int sockfd; struct ifreq ifr; struct ethtool_cmd edata = { .cmd = ETHTOOL_GSET, }; sockfd = socket(PF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { goto out; } memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifr.ifr_name, if_name, IF_NAMESIZE); /* strncpy does not null terminate when the string is truncated */ ifr.ifr_name[IF_NAMESIZE-1] = '\0'; ifr.ifr_data = (char *)&edata; if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) { goto out; } #if HAVE_DECL_ETHTOOL_CMD_SPEED speed = ethtool_cmd_speed(&edata); #elif defined(HAVE_STRUCT_ETHTOOL_CMD_SPEED_HI) speed = (edata.speed_hi << 16) | edata.speed; #else speed = edata.speed; #endif if (UINT_MAX == speed) { speed = 0; } out: close(sockfd); #endif return speed; }
static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { unsigned int cap; struct port_info *p = netdev_priv(dev); struct link_config *lc = &p->link_cfg; u32 speed = ethtool_cmd_speed(cmd); if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ return -EINVAL; if (!(lc->supported & FW_PORT_CAP_ANEG)) { /* PHY offers a single speed. See if that's what's * being requested. */ if (cmd->autoneg == AUTONEG_DISABLE && (lc->supported & speed_to_caps(speed))) return 0; return -EINVAL; } if (cmd->autoneg == AUTONEG_DISABLE) { cap = speed_to_caps(speed); if (!(lc->supported & cap) || (speed == 1000) || (speed == 10000) || (speed == 40000)) return -EINVAL; lc->requested_speed = cap; lc->advertising = 0; } else { cap = to_fw_linkcaps(cmd->advertising); if (!(lc->supported & cap)) return -EINVAL; lc->requested_speed = 0; lc->advertising = cap | FW_PORT_CAP_ANEG; } lc->autoneg = cmd->autoneg; if (netif_running(dev)) return t4_link_l1cfg(p->adapter, p->adapter->pf, p->tx_chan, lc); return 0; }
/* This must be called with rtnl_lock held. */ static int efx_ethtool_set_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd) { struct efx_nic *efx = netdev_priv(net_dev); int rc; /* GMAC does not support 1000Mbps HD */ if ((ethtool_cmd_speed(ecmd) == SPEED_1000) && (ecmd->duplex != DUPLEX_FULL)) { netif_dbg(efx, drv, efx->net_dev, "rejecting unsupported 1000Mbps HD setting\n"); return -EINVAL; } mutex_lock(&efx->mac_lock); rc = efx->phy_op->set_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); return rc; }
/** * DPDK callback to retrieve physical link information (unlocked version). * * @param dev * Pointer to Ethernet device structure. * @param wait_to_complete * Wait for request completion (ignored). */ static int mlx5_link_update_unlocked(struct rte_eth_dev *dev, int wait_to_complete) { struct priv *priv = mlx5_get_priv(dev); struct ethtool_cmd edata = { .cmd = ETHTOOL_GSET }; struct ifreq ifr; struct rte_eth_link dev_link; int link_speed = 0; (void)wait_to_complete; if (priv_ifreq(priv, SIOCGIFFLAGS, &ifr)) { WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(errno)); return -1; } memset(&dev_link, 0, sizeof(dev_link)); dev_link.link_status = ((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING)); ifr.ifr_data = &edata; if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) { WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s", strerror(errno)); return -1; } link_speed = ethtool_cmd_speed(&edata); if (link_speed == -1) dev_link.link_speed = 0; else dev_link.link_speed = link_speed; dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ? ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX); dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED); if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) { /* Link status changed. */ dev->data->dev_link = dev_link; return 0; } /* Link status is still the same. */ return -1; }
static int ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct ixgb_adapter *adapter = netdev_priv(netdev); u32 speed = ethtool_cmd_speed(ecmd); if (ecmd->autoneg == AUTONEG_ENABLE || (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) return -EINVAL; if (netif_running(adapter->netdev)) { ixgb_down(adapter, true); ixgb_reset(adapter); ixgb_up(adapter); ixgb_set_speed_duplex(netdev); } else ixgb_reset(adapter); return 0; }
/** * @brief Set Settings * @param[in] pointer to struct net_device. * @param[in] pointer to struct ethtool_cmd. */ static int32_t nss_gmac_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct nss_gmac_dev *gmacdev = NULL; struct phy_device *phydev = NULL; gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); BUG_ON(gmacdev == NULL); /* * If the speed for this GMAC is forced, and link polling * is disabled by platform, do not proceed with the * changes below. This would be true for GMACs connected * to switch and interfaces that do not use a PHY. */ if ((gmacdev->forced_speed != SPEED_UNKNOWN) && (!test_bit(__NSS_GMAC_LINKPOLL, &gmacdev->flags))) return -EPERM; phydev = gmacdev->phydev; mutex_lock(&gmacdev->link_mutex); nss_gmac_linkdown(gmacdev); mutex_unlock(&gmacdev->link_mutex); phydev->advertising = ecmd->advertising; phydev->autoneg = ecmd->autoneg; phydev->speed = ethtool_cmd_speed(ecmd); phydev->duplex = ecmd->duplex; if (ecmd->autoneg == AUTONEG_ENABLE) set_bit(__NSS_GMAC_AUTONEG, &gmacdev->flags); else clear_bit(__NSS_GMAC_AUTONEG, &gmacdev->flags); genphy_config_aneg(phydev); return 0; }
/* Returns speed in Mb/s */ static guint32 ethtool_get_speed (NMDeviceWired *self) { int fd; struct ifreq ifr; struct ethtool_cmd edata = { .cmd = ETHTOOL_GSET, }; guint32 speed = 0; g_return_val_if_fail (self != NULL, 0); fd = socket (PF_INET, SOCK_DGRAM, 0); if (fd < 0) { nm_log_warn (LOGD_HW, "couldn't open control socket."); return 0; } memset (&ifr, 0, sizeof (struct ifreq)); strncpy (ifr.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ); ifr.ifr_data = (char *) &edata; if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) goto out; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) speed = edata.speed; #else speed = ethtool_cmd_speed (&edata); #endif if (speed == G_MAXUINT16 || speed == G_MAXUINT32) speed = 0; out: close (fd); return speed; }
gboolean nmp_utils_ethtool_get_link_speed (const char *ifname, guint32 *out_speed) { struct ethtool_cmd edata = { .cmd = ETHTOOL_GSET, }; guint32 speed; if (!ethtool_get (ifname, &edata)) return FALSE; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) speed = edata.speed; #else speed = ethtool_cmd_speed (&edata); #endif if (speed == G_MAXUINT16 || speed == G_MAXUINT32) speed = 0; if (out_speed) *out_speed = speed; return TRUE; }
static int pch_gbe_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct pch_gbe_adapter *adapter = netdev_priv(netdev); struct pch_gbe_hw *hw = &adapter->hw; u32 speed = ethtool_cmd_speed(ecmd); int ret; pch_gbe_hal_write_phy_reg(hw, MII_BMCR, BMCR_RESET); /* */ if (speed == UINT_MAX) { speed = SPEED_1000; ecmd->duplex = DUPLEX_FULL; } ret = mii_ethtool_sset(&adapter->mii, ecmd); if (ret) { pr_err("Error: mii_ethtool_sset\n"); return ret; } hw->mac.link_speed = speed; hw->mac.link_duplex = ecmd->duplex; hw->phy.autoneg_advertised = ecmd->advertising; hw->mac.autoneg = ecmd->autoneg; pch_gbe_hal_phy_sw_reset(hw); /* */ if (netif_running(adapter->netdev)) { pch_gbe_down(adapter); ret = pch_gbe_up(adapter); } else { pch_gbe_reset(adapter); } return ret; }
int main(void) { int sockfd = socket(AF_INET, SOCK_DGRAM, 0); struct ifreq req; char name[PATH_MAX]; int index; struct ethtool_cmd etc; int err, ret; struct iwreq wreq; get_ifconfig(sockfd, &req); strcpy(name, req.ifr_name); req.ifr_ifindex = -1; strcpy(req.ifr_name, name); ret = ioctl(sockfd, SIOCGIFINDEX, &req); atomic_printf("SIOCGIFINDEX(ret:%d): %s index is %d\n", ret, req.ifr_name, req.ifr_ifindex); test_assert(0 == ret); index = req.ifr_ifindex; memset(&req.ifr_name, 0x5a, sizeof(req.ifr_name)); req.ifr_ifindex = index; ret = ioctl(sockfd, SIOCGIFNAME, &req); atomic_printf("SIOCGIFNAME(ret:%d): index %d(%s) name is %s\n", ret, index, name, req.ifr_name); test_assert(0 == ret); test_assert(!strcmp(name, req.ifr_name)); memset(&req.ifr_addr, 0x5a, sizeof(req.ifr_addr)); ret = ioctl(sockfd, SIOCGIFADDR, &req); atomic_printf("SIOCGIFADDR(ret:%d): %s addr is", ret, req.ifr_name); atomic_printf(" %s\n", sockaddr_name(&req.ifr_addr)); test_assert(0 == ret); memset(&req.ifr_addr, 0x5a, sizeof(req.ifr_addr)); ret = ioctl(sockfd, SIOCGIFHWADDR, &req); atomic_printf("SIOCGIFHWADDR(ret:%d): %s addr is", ret, req.ifr_name); atomic_printf(" %s\n", sockaddr_hw_name(&req.ifr_addr)); test_assert(0 == ret); memset(&req.ifr_flags, 0x5a, sizeof(req.ifr_flags)); ret = ioctl(sockfd, SIOCGIFFLAGS, &req); atomic_printf("SIOCGIFFLAGS(ret:%d): %s flags are", ret, req.ifr_name); test_assert(0 == ret); atomic_printf(" %#x\n", req.ifr_flags); memset(&req.ifr_flags, 0x5a, sizeof(req.ifr_mtu)); ret = ioctl(sockfd, SIOCGIFMTU, &req); atomic_printf("SIOCGIFMTU(ret:%d): %s MTU is", ret, req.ifr_name); test_assert(0 == ret); atomic_printf(" %d\n", req.ifr_mtu); memset(&etc, 0, sizeof(etc)); etc.cmd = ETHTOOL_GSET; req.ifr_data = (char*)&etc; ret = ioctl(sockfd, SIOCETHTOOL, &req); err = errno; atomic_printf("SIOCETHTOOL(ret:%d): %s ethtool data:\n", ret, req.ifr_name); atomic_printf(" speed:%#x duplex:%#x port:%#x physaddr:%#x, maxtxpkt:%u " "maxrxpkt:%u ...\n", ethtool_cmd_speed(&etc), etc.duplex, etc.port, etc.phy_address, etc.maxtxpkt, etc.maxrxpkt); if (-1 == ret) { atomic_printf("WARNING: %s doesn't appear to support SIOCETHTOOL; the test " "may have been meaningless (%s/%d)\n", name, strerror(err), err); test_assert(EOPNOTSUPP == err || EPERM == err); } memset(&wreq, 0x5a, sizeof(wreq)); strcpy(wreq.ifr_ifrn.ifrn_name, name); ret = ioctl(sockfd, SIOCGIWRATE, &wreq); err = errno; atomic_printf("SIOCGIWRATE(ret:%d): %s:\n", ret, wreq.ifr_name); atomic_printf(" bitrate:%d (fixed? %s; disabled? %s) flags:%#x\n", wreq.u.bitrate.value, wreq.u.bitrate.fixed ? "yes" : "no", wreq.u.bitrate.disabled ? "yes" : "no", wreq.u.bitrate.flags); if (-1 == ret) { atomic_printf("WARNING: %s doesn't appear to be a wireless iface; " "SIOCGIWRATE test may have been meaningless (%s/%d)\n", name, strerror(err), err); test_assert(EOPNOTSUPP == err || EPERM == err); } atomic_puts("EXIT-SUCCESS"); return 0; }
static int e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; /* * When SoL/IDER sessions are active, autoneg/speed/duplex * cannot be changed */ if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw)) { e_err("Cannot change link characteristics when SoL/IDER is active.\n"); return -EINVAL; } /* * MDI setting is only allowed when autoneg enabled because * some hardware doesn't allow MDI setting when speed or * duplex is forced. */ if (ecmd->eth_tp_mdix_ctrl) { if (hw->phy.media_type != e1000_media_type_copper) return -EOPNOTSUPP; if ((ecmd->eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO) && (ecmd->autoneg != AUTONEG_ENABLE)) { e_err("forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); return -EINVAL; } } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; if (hw->phy.media_type == e1000_media_type_fiber) hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg; else hw->phy.autoneg_advertised = ecmd->advertising | ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { u32 speed = ethtool_cmd_speed(ecmd); /* calling this overrides forced MDI setting */ if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } } /* MDI-X => 2; MDI => 1; Auto => 3 */ if (ecmd->eth_tp_mdix_ctrl) { /* * fix up the value for auto (3 => 0) as zero is mapped * internally to auto */ if (ecmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) hw->phy.mdix = AUTO_ALL_MODES; else hw->phy.mdix = ecmd->eth_tp_mdix_ctrl; } /* reset the link */ if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); } else e1000e_reset(adapter); clear_bit(__E1000_RESETTING, &adapter->state); return 0; }
/** * mdio45_ethtool_gset_npage - get settings for ETHTOOL_GSET * @mdio: MDIO interface * @ecmd: Ethtool request structure * @npage_adv: Modes currently advertised on next pages * @npage_lpa: Modes advertised by link partner on next pages * * The @ecmd parameter is expected to have been cleared before calling * mdio45_ethtool_gset_npage(). * * Since the CSRs for auto-negotiation using next pages are not fully * standardised, this function does not attempt to decode them. The * caller must pass them in. */ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, struct ethtool_cmd *ecmd, u32 npage_adv, u32 npage_lpa) { int reg; u32 speed; #if 0 BUILD_BUG_ON(MDIO_SUPPORTS_C22 != ETH_MDIO_SUPPORTS_C22); BUILD_BUG_ON(MDIO_SUPPORTS_C45 != ETH_MDIO_SUPPORTS_C45); #endif ecmd->transceiver = XCVR_INTERNAL; ecmd->phy_address = mdio->prtad; ecmd->mdio_support = mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22); reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_CTRL2); switch (reg & MDIO_PMA_CTRL2_TYPE) { case MDIO_PMA_CTRL2_10GBT: case MDIO_PMA_CTRL2_1000BT: case MDIO_PMA_CTRL2_100BTX: case MDIO_PMA_CTRL2_10BT: ecmd->port = PORT_TP; ecmd->supported = SUPPORTED_TP; reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_SPEED); if (reg & MDIO_SPEED_10G) ecmd->supported |= SUPPORTED_10000baseT_Full; if (reg & MDIO_PMA_SPEED_1000) ecmd->supported |= (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half); if (reg & MDIO_PMA_SPEED_100) ecmd->supported |= (SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half); if (reg & MDIO_PMA_SPEED_10) ecmd->supported |= (SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half); ecmd->advertising = ADVERTISED_TP; break; case MDIO_PMA_CTRL2_10GBCX4: ecmd->port = PORT_OTHER; ecmd->supported = 0; ecmd->advertising = 0; break; case MDIO_PMA_CTRL2_10GBKX4: case MDIO_PMA_CTRL2_10GBKR: case MDIO_PMA_CTRL2_1000BKX: ecmd->port = PORT_OTHER; ecmd->supported = SUPPORTED_Backplane; reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE); if (reg & MDIO_PMA_EXTABLE_10GBKX4) ecmd->supported |= SUPPORTED_10000baseKX4_Full; if (reg & MDIO_PMA_EXTABLE_10GBKR) ecmd->supported |= SUPPORTED_10000baseKR_Full; if (reg & MDIO_PMA_EXTABLE_1000BKX) ecmd->supported |= SUPPORTED_1000baseKX_Full; reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECABLE); if (reg & MDIO_PMA_10GBR_FECABLE_ABLE) ecmd->supported |= SUPPORTED_10000baseR_FEC; ecmd->advertising = ADVERTISED_Backplane; break; /* All the other defined modes are flavours of optical */ default: ecmd->port = PORT_FIBRE; ecmd->supported = SUPPORTED_FIBRE; ecmd->advertising = ADVERTISED_FIBRE; break; } if (mdio->mmds & MDIO_DEVS_AN) { ecmd->supported |= SUPPORTED_Autoneg; reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, MDIO_CTRL1); if (reg & MDIO_AN_CTRL1_ENABLE) { ecmd->autoneg = AUTONEG_ENABLE; ecmd->advertising |= ADVERTISED_Autoneg | mdio45_get_an(mdio, MDIO_AN_ADVERTISE) | npage_adv; } else { ecmd->autoneg = AUTONEG_DISABLE; } } else { ecmd->autoneg = AUTONEG_DISABLE; } if (ecmd->autoneg) { u32 modes = 0; int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, MDIO_STAT1); /* If AN is complete and successful, report best common * mode, otherwise report best advertised mode. */ if (an_stat & MDIO_AN_STAT1_COMPLETE) { ecmd->lp_advertising = mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa; if (an_stat & MDIO_AN_STAT1_LPABLE) ecmd->lp_advertising |= ADVERTISED_Autoneg; modes = ecmd->advertising & ecmd->lp_advertising; } if ((modes & ~ADVERTISED_Autoneg) == 0) modes = ecmd->advertising; if (modes & (ADVERTISED_10000baseT_Full | ADVERTISED_10000baseKX4_Full | ADVERTISED_10000baseKR_Full)) { speed = SPEED_10000; ecmd->duplex = DUPLEX_FULL; } else if (modes & (ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseKX_Full)) { speed = SPEED_1000; ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half); } else if (modes & (ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half)) { speed = SPEED_100; ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); } else { speed = SPEED_10; ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); } } else { /* Report forced settings */ reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_CTRL1); speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || speed == SPEED_10000); } ethtool_cmd_speed_set(ecmd, speed); /* 10GBASE-T MDI/MDI-X */ if (ecmd->port == PORT_TP && (ethtool_cmd_speed(ecmd) == SPEED_10000)) { switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_SWAPPOL)) { case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: ecmd->eth_tp_mdix = ETH_TP_MDI; break; case 0: ecmd->eth_tp_mdix = ETH_TP_MDI_X; break; default: /* It's complicated... */ ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; break; } } }
struct replay_list* load_interfaces() { struct replay_interface *iface; struct replay_list *new_item, *prev_item; struct ifreq *ifr; struct ifconf ifc; struct ethtool_cmd cmd; int s, rc, i; int numif; // find number of interfaces. memset(&ifc,0,sizeof(ifc)); ifc.ifc_ifcu.ifcu_req = NULL; ifc.ifc_len = 0; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { replay_error("find_interface: unable to open socket"); } if ((rc = ioctl(s, SIOCGIFCONF, &ifc)) < 0) { replay_error("find_interface: error on 1st ioctl"); } numif = ifc.ifc_len / sizeof(*ifr); if ((ifr = malloc(ifc.ifc_len)) == NULL) { replay_error("find_interface: error on malloc of ifreq"); } ifc.ifc_ifcu.ifcu_req = ifr; prev_item = NULL; for(i = 0; i < numif; i++) { if ((rc = ioctl(s, SIOCGIFCONF, &ifc)) < 0) { replay_error("find_interface: error on get IP ioctl"); } struct ifreq *r = &ifr[i]; iface = malloc(sizeof(*iface)); memset(iface,0,sizeof(*iface)); new_item = malloc(sizeof(*new_item)); memset(new_item,0,sizeof(*new_item)); iface->index = i; iface->ip.s_addr = ((struct sockaddr_in *)&r->ifr_addr)->sin_addr.s_addr; //iface->mtu = r->ifr_mtu; strcpy(iface->name,r->ifr_name); iface->ifr = malloc(sizeof(*iface->ifr)); memcpy(iface->ifr,r,sizeof(*iface->ifr)); new_item->next = prev_item; new_item->object = (void *) iface; // get interface speed / duplex settings r->ifr_data = (void *)&cmd; cmd.cmd = ETHTOOL_GSET; /* "Get settings" */ if (ioctl(s, SIOCETHTOOL, r) == -1) { /* Unknown */ iface->speed = -1L; iface->duplex = DUPLEX_UNKNOWN; } else { iface->speed = ethtool_cmd_speed(&cmd); iface->duplex = cmd.duplex; } // get interface flags if (ioctl(s, SIOCGIFFLAGS, r) == -1) { iface->flags = 0; } else { iface->flags = r->ifr_flags; } // get interface netmask if (ioctl(s, SIOCGIFNETMASK, r) == -1) { replay_error("load_interfaces: error getting interface netmask"); } else { iface->mask.s_addr = ((struct sockaddr_in *)&r->ifr_netmask)->sin_addr.s_addr; } // get interface MTU if (ioctl(s, SIOCGIFMTU, r) == -1) { replay_error("load_interfaces: error getting interface MTU"); } else { iface->mtu = r->ifr_mtu; } prev_item = new_item; } close(s); return prev_item; }
int main(void) { int sockfd = socket(AF_INET, SOCK_DGRAM, 0); struct ifreq* req; struct ifreq* eth_req; char name[PATH_MAX]; int index; struct ethtool_cmd* etc; int err, ret; struct iwreq* wreq; char buf[1024]; ALLOCATE_GUARD(req, 'a'); ALLOCATE_GUARD(eth_req, 'a'); get_ifconfig(sockfd, req, eth_req); strcpy(name, req->ifr_name); req->ifr_ifindex = -1; strcpy(req->ifr_name, name); ret = ioctl(sockfd, SIOCGIFINDEX, req); VERIFY_GUARD(req); atomic_printf("SIOCGIFINDEX(ret:%d): %s index is %d\n", ret, req->ifr_name, req->ifr_ifindex); test_assert(0 == ret); test_assert(req->ifr_ifindex != -1); index = req->ifr_ifindex; memset(&req->ifr_name, 0xff, sizeof(req->ifr_name)); req->ifr_ifindex = index; ret = ioctl(sockfd, SIOCGIFNAME, req); VERIFY_GUARD(req); atomic_printf("SIOCGIFNAME(ret:%d): index %d(%s) name is %s\n", ret, index, name, req->ifr_name); test_assert(0 == ret); test_assert(!strcmp(name, req->ifr_name)); GENERIC_REQUEST_BY_NAME(SIOCGIFFLAGS); atomic_printf("flags are %#x\n", req->ifr_flags); GENERIC_REQUEST_BY_NAME(SIOCGIFADDR); atomic_printf("addr is %s\n", sockaddr_name(&req->ifr_addr)); GENERIC_REQUEST_BY_NAME(SIOCGIFDSTADDR); atomic_printf("addr is %s\n", sockaddr_name(&req->ifr_addr)); GENERIC_REQUEST_BY_NAME(SIOCGIFBRDADDR); atomic_printf("addr is %s\n", sockaddr_name(&req->ifr_addr)); GENERIC_REQUEST_BY_NAME(SIOCGIFNETMASK); atomic_printf("netmask is %s\n", sockaddr_name(&req->ifr_addr)); GENERIC_REQUEST_BY_NAME(SIOCGIFMETRIC); atomic_printf("metric is %d\n", req->ifr_metric); memset(&req->ifr_metric, 0xff, sizeof(req->ifr_metric)); ret = ioctl(sockfd, SIOCGIFMEM, req); VERIFY_GUARD(req); test_assert(-1 == ret && errno == ENOTTY); GENERIC_REQUEST_BY_NAME(SIOCGIFMTU); atomic_printf("MTU is %d\n", req->ifr_mtu); GENERIC_REQUEST_BY_NAME(SIOCGIFHWADDR); atomic_printf("hwaddr %s\n", sockaddr_hw_name(&req->ifr_addr)); memset(&req->ifr_flags, 0xff, sizeof(req->ifr_flags)); ret = ioctl(sockfd, SIOCGIFPFLAGS, req); VERIFY_GUARD(req); if (ret != -1 || errno != EINVAL) { test_assert(0 == ret); atomic_printf("SIOCGIFPFLAGS(ret:%d): %s flags are", ret, req->ifr_name); atomic_printf(" %#x\n", req->ifr_flags); } GENERIC_REQUEST_BY_NAME(SIOCGIFTXQLEN); atomic_printf("qlen is %d\n", req->ifr_qlen); ALLOCATE_GUARD(etc, 'b'); etc->cmd = ETHTOOL_GSET; req->ifr_data = (char*)&etc; ret = ioctl(sockfd, SIOCETHTOOL, req); VERIFY_GUARD(req); VERIFY_GUARD(etc); err = errno; atomic_printf("SIOCETHTOOL(ret:%d): %s ethtool data: ", ret, req->ifr_name); if (-1 == ret) { atomic_printf("WARNING: %s doesn't appear to support SIOCETHTOOL\n", name); test_assert(EOPNOTSUPP == err || EPERM == err); } else { atomic_printf("speed:%#x duplex:%#x port:%#x physaddr:%#x, maxtxpkt:%u " "maxrxpkt:%u ...\n", ethtool_cmd_speed(etc), etc->duplex, etc->port, etc->phy_address, etc->maxtxpkt, etc->maxrxpkt); } GENERIC_WIRELESS_PARAM_REQUEST_BY_NAME(SIOCGIWRATE, bitrate); GENERIC_WIRELESS_REQUEST_BY_NAME(SIOCGIWNAME, ("wireless protocol name:%s", wreq->u.name)); GENERIC_WIRELESS_REQUEST_BY_NAME(SIOCGIWMODE, (" wireless mode:%d", wreq->u.mode)); ALLOCATE_GUARD(wreq, 'e'); strcpy(wreq->ifr_ifrn.ifrn_name, name); wreq->u.essid.length = sizeof(buf); wreq->u.essid.pointer = buf; wreq->u.essid.flags = 0; ret = ioctl(sockfd, SIOCGIWESSID, wreq); VERIFY_GUARD(wreq); err = errno; atomic_printf("SIOCGIWESSID(ret:%d): %s: ", ret, wreq->ifr_name); if (-1 == ret) { atomic_printf("WARNING: %s doesn't appear to be a wireless iface\n", name); test_assert(EOPNOTSUPP == err || EPERM == err || EINVAL == err); } else { atomic_printf("wireless ESSID:%s\n", buf); } GENERIC_WIRELESS_PARAM_REQUEST_BY_NAME(SIOCGIWSENS, sens); atomic_puts("EXIT-SUCCESS"); return 0; }
static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { int rc = 0; struct bnxt *bp = netdev_priv(dev); struct bnxt_link_info *link_info = &bp->link_info; u32 speed, fw_advertising = 0; bool set_pause = false; if (BNXT_VF(bp)) return rc; if (cmd->autoneg == AUTONEG_ENABLE) { if (link_info->media_type != PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { netdev_err(dev, "Media type doesn't support autoneg\n"); rc = -EINVAL; goto set_setting_exit; } if (cmd->advertising & ~(BNXT_ALL_COPPER_ETHTOOL_SPEED | ADVERTISED_Autoneg | ADVERTISED_TP | ADVERTISED_Pause | ADVERTISED_Asym_Pause)) { netdev_err(dev, "Unsupported advertising mask (adv: 0x%x)\n", cmd->advertising); rc = -EINVAL; goto set_setting_exit; } fw_advertising = bnxt_get_fw_auto_link_speeds(cmd->advertising); if (fw_advertising & ~link_info->support_speeds) { netdev_err(dev, "Advertising parameters are not supported! (adv: 0x%x)\n", cmd->advertising); rc = -EINVAL; goto set_setting_exit; } link_info->autoneg |= BNXT_AUTONEG_SPEED; if (!fw_advertising) link_info->advertising = link_info->support_speeds; else link_info->advertising = fw_advertising; /* any change to autoneg will cause link change, therefore the * driver should put back the original pause setting in autoneg */ set_pause = true; } else { /* TODO: currently don't support half duplex */ if (cmd->duplex == DUPLEX_HALF) { netdev_err(dev, "HALF DUPLEX is not supported!\n"); rc = -EINVAL; goto set_setting_exit; } /* If received a request for an unknown duplex, assume full*/ if (cmd->duplex == DUPLEX_UNKNOWN) cmd->duplex = DUPLEX_FULL; speed = ethtool_cmd_speed(cmd); link_info->req_link_speed = bnxt_get_fw_speed(dev, speed); link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; link_info->autoneg &= ~BNXT_AUTONEG_SPEED; link_info->advertising = 0; } if (netif_running(dev)) rc = bnxt_hwrm_set_link_setting(bp, set_pause); set_setting_exit: return rc; }
int ethtool_get_driver(int *fd, const char *ifname, char **ret) { struct ethtool_drvinfo ecmd = { .cmd = ETHTOOL_GDRVINFO }; struct ifreq ifr = { .ifr_data = (void*) &ecmd }; char *d; int r; if (*fd < 0) { r = ethtool_connect(fd); if (r < 0) { log_warning("link_config: could not connect to ethtool: %s", strerror(-r)); return r; } } strscpy(ifr.ifr_name, IFNAMSIZ, ifname); r = ioctl(*fd, SIOCETHTOOL, &ifr); if (r < 0) return -errno; d = strdup(ecmd.driver); if (!d) return -ENOMEM; *ret = d; return 0; } int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex) { struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; struct ifreq ifr = { .ifr_data = (void*) &ecmd }; bool need_update = false; int r; if (speed == 0 && duplex == _DUP_INVALID) return 0; if (*fd < 0) { r = ethtool_connect(fd); if (r < 0) { log_warning("link_config: could not connect to ethtool: %s", strerror(-r)); return r; } } strscpy(ifr.ifr_name, IFNAMSIZ, ifname); r = ioctl(*fd, SIOCETHTOOL, &ifr); if (r < 0) return -errno; if (ethtool_cmd_speed(&ecmd) != speed) { ethtool_cmd_speed_set(&ecmd, speed); need_update = true; } switch (duplex) { case DUP_HALF: if (ecmd.duplex != DUPLEX_HALF) { ecmd.duplex = DUPLEX_HALF; need_update = true; } break; case DUP_FULL: if (ecmd.duplex != DUPLEX_FULL) { ecmd.duplex = DUPLEX_FULL; need_update = true; } break; default: break; } if (need_update) { ecmd.cmd = ETHTOOL_SSET; r = ioctl(*fd, SIOCETHTOOL, &ifr); if (r < 0) return -errno; } return 0; } int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) { struct ethtool_wolinfo ecmd = { .cmd = ETHTOOL_GWOL }; struct ifreq ifr = { .ifr_data = (void*) &ecmd }; bool need_update = false; int r; if (wol == _WOL_INVALID) return 0; if (*fd < 0) { r = ethtool_connect(fd); if (r < 0) { log_warning("link_config: could not connect to ethtool: %s", strerror(-r)); return r; } } strscpy(ifr.ifr_name, IFNAMSIZ, ifname); r = ioctl(*fd, SIOCETHTOOL, &ifr); if (r < 0) return -errno; switch (wol) { case WOL_PHY: if (ecmd.wolopts != WAKE_PHY) { ecmd.wolopts = WAKE_PHY; need_update = true; } break; case WOL_MAGIC: if (ecmd.wolopts != WAKE_MAGIC) { ecmd.wolopts = WAKE_MAGIC; need_update = true; } break; case WOL_OFF: if (ecmd.wolopts != 0) { ecmd.wolopts = 0; need_update = true; } break; default: break; } if (need_update) { ecmd.cmd = ETHTOOL_SWOL; r = ioctl(*fd, SIOCETHTOOL, &ifr); if (r < 0) return -errno; } return 0; }
/** * mii_ethtool_sset - set settings that are specified in @ecmd * @mii: MII interface * @ecmd: requested ethtool_cmd * * Returns 0 for success, negative on error. */ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; u32 speed = ethtool_cmd_speed(ecmd); if (speed != SPEED_10 && speed != SPEED_100 && speed != SPEED_1000) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; if (ecmd->port != PORT_MII) return -EINVAL; if (ecmd->transceiver != XCVR_INTERNAL) return -EINVAL; if (ecmd->phy_address != mii->phy_id) return -EINVAL; if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) return -EINVAL; if ((speed == SPEED_1000) && (!mii->supports_gmii)) return -EINVAL; /* ignore supported, maxtxpkt, maxrxpkt */ if (ecmd->autoneg == AUTONEG_ENABLE) { u32 bmcr, advert, tmp; u32 advert2 = 0, tmp2 = 0; if ((ecmd->advertising & (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) == 0) return -EINVAL; /* advertise only what has been requested */ advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); if (mii->supports_gmii) { advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); } if (ecmd->advertising & ADVERTISED_10baseT_Half) tmp |= ADVERTISE_10HALF; if (ecmd->advertising & ADVERTISED_10baseT_Full) tmp |= ADVERTISE_10FULL; if (ecmd->advertising & ADVERTISED_100baseT_Half) tmp |= ADVERTISE_100HALF; if (ecmd->advertising & ADVERTISED_100baseT_Full) tmp |= ADVERTISE_100FULL; if (mii->supports_gmii) { if (ecmd->advertising & ADVERTISED_1000baseT_Half) tmp2 |= ADVERTISE_1000HALF; if (ecmd->advertising & ADVERTISED_1000baseT_Full) tmp2 |= ADVERTISE_1000FULL; } if (advert != tmp) { mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); mii->advertising = tmp; } if ((mii->supports_gmii) && (advert2 != tmp2)) mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2); /* turn on autonegotiation, and force a renegotiate */ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr); mii->force_media = 0; } else { u32 bmcr, tmp; /* turn off auto negotiation, set speed and duplexity */ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_FULLDPLX); if (speed == SPEED_1000) tmp |= BMCR_SPEED1000; else if (speed == SPEED_100) tmp |= BMCR_SPEED100; if (ecmd->duplex == DUPLEX_FULL) { tmp |= BMCR_FULLDPLX; mii->full_duplex = 1; } else mii->full_duplex = 0; if (bmcr != tmp) mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp); mii->force_media = 1; } return 0; }
bool update_device_status( ether_device *device ) { assert( device != NULL ); assert( strlen( device->name ) > 0 ); int fd = socket( PF_INET, SOCK_DGRAM, 0 ); if ( fd < 0 ) { char error_string[ ERROR_STRING_SIZE ]; error( "Failed to open a socket ( ret = %d, errno = %s [%d] ).", fd, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno ); return false; } struct ifreq ifr; memset( &ifr, 0, sizeof( ifr ) ); strncpy( ifr.ifr_name, device->name, IFNAMSIZ ); ifr.ifr_name[ IFNAMSIZ - 1 ] = '\0'; struct ethtool_value ev; memset( &ev, 0, sizeof( struct ethtool_value ) ); ev.cmd = ETHTOOL_GLINK; ifr.ifr_data = ( char * ) &ev; int ret = ioctl( fd, SIOCETHTOOL, &ifr ); if ( ret == -1 ) { char error_string[ ERROR_STRING_SIZE ]; error( "Failed to retrieve link status of %s ( ret = %d, error = %s [%d] ).", device->name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno ); warn( "Assuming link is up ( device = %s ).", device->name ); device->status.up = true; } else { if ( ev.data > 0 ) { device->status.up = true; } else { device->status.up = false; } } struct ethtool_cmd ec; memset( &ec, 0, sizeof( struct ethtool_cmd ) ); if ( device->status.can_retrieve_link_status ) { ec.cmd = ETHTOOL_GSET; ifr.ifr_data = ( char * ) &ec; ret = ioctl( fd, SIOCETHTOOL, &ifr ); if ( ret == -1 ) { char error_string[ ERROR_STRING_SIZE ]; warn( "Failed to retrieve statuses of %s ( ret = %d, error = %s [%d] ).", device->name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno ); warn( "Assuming 100Mbps/Full Duplex/Twisted Pair link ( device = %s ).", device->name ); device->status.can_retrieve_link_status = false; } } if ( !device->status.can_retrieve_link_status ) { ethtool_cmd_speed_set( &ec, SPEED_100 ); ec.duplex = DUPLEX_FULL; ec.port = PORT_TP; ec.advertising = ADVERTISED_100baseT_Full | ADVERTISED_TP; ec.supported = SUPPORTED_100baseT_Full | SUPPORTED_TP; } struct ethtool_pauseparam ep; memset( &ep, 0, sizeof( struct ethtool_pauseparam ) ); if ( device->status.can_retrieve_pause ) { ep.cmd = ETHTOOL_GPAUSEPARAM; ifr.ifr_data = ( char * ) &ep; ret = ioctl( fd, SIOCETHTOOL, &ifr ); if ( ret == -1 ) { char error_string[ ERROR_STRING_SIZE ]; warn( "Failed to retrieve pause parameters of %s ( ret = %d, error = %s [%d] ).", device->name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno ); warn( "Assuming pause is disabled ( device = %s ).", device->name ); device->status.can_retrieve_pause = false; } } close( fd ); device->status.curr = make_current_ofp_port_features( ethtool_cmd_speed( &ec ), ec.duplex, ec.port, ec.autoneg, ep.rx_pause, ep.tx_pause ); device->status.advertised = make_supported_ofp_port_features( ec.advertising ); device->status.supported = make_supported_ofp_port_features( ec.supported ); device->status.peer = device->status.curr; // FIMXE: how to know the correct value? device->status.curr_speed = 0; // Since we set curr flags, this field might be meaningless. device->status.max_speed = 0; // Since we set supported flags, this field might be meaningless. return true; }