platform/ethtool: split functions for ETHTOOL_GSTRINGS

ethtool_get_stringset() will be used later, independently.

Also, don't trust and ensure that the block of strings
returned by ETHTOOL_GSTRINGS are NUL terminated.
This commit is contained in:
Thomas Haller
2018-07-16 10:43:28 +02:00
parent b7c8e3dbfa
commit 29266e0086

View File

@@ -39,9 +39,9 @@
#include "nm-core-utils.h"
/******************************************************************
/******************************************************************************
* utils
******************************************************************/
*****************************************************************************/
extern char *if_indextoname (unsigned __ifindex, char *__ifname);
unsigned if_nametoindex (const char *__ifname);
@@ -63,9 +63,9 @@ nmp_utils_if_nametoindex (const char *ifname)
return if_nametoindex (ifname);
}
/******************************************************************
/******************************************************************************
* ethtool
******************************************************************/
*****************************************************************************/
NM_UTILS_ENUM2STR_DEFINE_STATIC (_ethtool_cmd_to_string, guint32,
NM_UTILS_ENUM2STR (ETHTOOL_GDRVINFO, "ETHTOOL_GDRVINFO"),
@@ -157,39 +157,75 @@ ethtool_get (int ifindex, gpointer edata)
}
}
static int
ethtool_get_stringset_index (int ifindex, int stringset_id, const char *string)
/*****************************************************************************/
static struct ethtool_gstrings *
ethtool_get_stringset (int ifindex, int stringset_id)
{
gs_free struct ethtool_sset_info *info = NULL;
gs_free struct ethtool_gstrings *strings = NULL;
guint32 len, i;
struct {
struct ethtool_sset_info info;
guint32 sentinel;
} sset_info = { };
gs_free struct ethtool_gstrings *gstrings = NULL;
guint32 i, len;
g_return_val_if_fail (ifindex > 0, -1);
g_return_val_if_fail (ifindex > 0, NULL);
info = g_malloc0 (sizeof (*info) + sizeof (guint32));
info->cmd = ETHTOOL_GSSET_INFO;
info->reserved = 0;
info->sset_mask = 1ULL << stringset_id;
sset_info.info.cmd = ETHTOOL_GSSET_INFO;
sset_info.info.reserved = 0;
sset_info.info.sset_mask = (1ULL << stringset_id);
if (!ethtool_get (ifindex, info))
return -1;
if (!info->sset_mask)
return -1;
if (!ethtool_get (ifindex, &sset_info))
return NULL;
if (!sset_info.info.sset_mask)
return NULL;
len = info->data[0];
len = sset_info.info.data[0];
strings = g_malloc0 (sizeof (*strings) + len * ETH_GSTRING_LEN);
strings->cmd = ETHTOOL_GSTRINGS;
strings->string_set = stringset_id;
strings->len = len;
if (!ethtool_get (ifindex, strings))
return -1;
for (i = 0; i < len; i++) {
if (!strcmp ((char *) &strings->data[i * ETH_GSTRING_LEN], string))
return i;
gstrings = g_malloc0 (sizeof (*gstrings) + (len * ETH_GSTRING_LEN));
gstrings->cmd = ETHTOOL_GSTRINGS;
gstrings->string_set = stringset_id;
gstrings->len = len;
if (gstrings->len > 0) {
if (!ethtool_get (ifindex, gstrings))
return NULL;
for (i = 0; i < gstrings->len; i++) {
/* ensure NUL terminated */
gstrings->data[i * ETH_GSTRING_LEN + (ETH_GSTRING_LEN - 1)] = '\0';
}
}
return g_steal_pointer (&gstrings);
}
static int
ethtool_gstrings_find (const struct ethtool_gstrings *gstrings, const char *needle)
{
guint32 i;
/* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN.
* that means, we cannot possibly request longer names. */
nm_assert (needle && strlen (needle) < ETH_GSTRING_LEN);
for (i = 0; i < gstrings->len; i++) {
if (nm_streq ((char *) &gstrings->data[i * ETH_GSTRING_LEN], needle))
return i;
}
return -1;
}
static int
ethtool_get_stringset_index (int ifindex, int stringset_id, const char *needle)
{
gs_free struct ethtool_gstrings *gstrings = NULL;
/* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN.
* that means, we cannot possibly request longer names. */
nm_assert (needle && strlen (needle) < ETH_GSTRING_LEN);
gstrings = ethtool_get_stringset (ifindex, stringset_id);
if (gstrings)
return ethtool_gstrings_find (gstrings, needle);
return -1;
}
@@ -282,7 +318,7 @@ nmp_utils_ethtool_supports_vlans (int ifindex)
g_return_val_if_fail (ifindex > 0, FALSE);
idx = ethtool_get_stringset_index (ifindex, ETH_SS_FEATURES, "vlan-challenged");
if (idx == -1) {
if (idx < 0) {
nm_log_dbg (LOGD_PLATFORM, "ethtool: vlan-challenged ethtool feature does not exist for %d?", ifindex);
return FALSE;
}
@@ -310,7 +346,7 @@ nmp_utils_ethtool_get_peer_ifindex (int ifindex)
g_return_val_if_fail (ifindex > 0, 0);
peer_ifindex_stat = ethtool_get_stringset_index (ifindex, ETH_SS_STATS, "peer_ifindex");
if (peer_ifindex_stat == -1) {
if (peer_ifindex_stat < 0) {
nm_log_dbg (LOGD_PLATFORM, "ethtool: peer_ifindex stat for %d does not exist?", ifindex);
return FALSE;
}
@@ -530,9 +566,9 @@ nmp_utils_ethtool_set_wake_on_lan (int ifindex,
return ethtool_get (ifindex, &wol_info);
}
/******************************************************************
/******************************************************************************
* mii
******************************************************************/
*****************************************************************************/
gboolean
nmp_utils_mii_supports_carrier_detect (int ifindex)
@@ -576,9 +612,9 @@ nmp_utils_mii_supports_carrier_detect (int ifindex)
return TRUE;
}
/******************************************************************
/******************************************************************************
* udev
******************************************************************/
*****************************************************************************/
const char *
nmp_utils_udev_get_driver (struct udev_device *udevice)