From 29266e0086fa1b0faa76da266cbce9fa6467e965 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 16 Jul 2018 10:43:28 +0200 Subject: [PATCH] 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. --- src/platform/nm-platform-utils.c | 106 +++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 35 deletions(-) diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 0d224443fa..2bcaa4d94e 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -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)