/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "device-private.h"
#include "netlink-util.h"
+#include "strv.h"
#include "udev-netlink.h"
void link_info_clear(LinkInfo *info) {
info = LINK_INFO_NULL;
return 0;
}
+
+static int cache_unsigned(sd_device *device, const char *attr, uint64_t val) {
+ _cleanup_free_ char *str = NULL;
+ int r;
+
+ assert(device);
+ assert(attr);
+
+ if (device_get_cached_sysattr_value(device, attr, NULL) != -ESTALE)
+ return 0;
+
+ if (asprintf(&str, "%"PRIu64, val) < 0)
+ return -ENOMEM;
+
+ r = device_cache_sysattr_value(device, attr, str);
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(str);
+ return 0;
+}
+
+static int cache_hw_addr(sd_device *device, const char *attr, const struct hw_addr_data *hw_addr) {
+ _cleanup_free_ char *str = NULL;
+ int r;
+
+ assert(device);
+ assert(attr);
+ assert(hw_addr);
+
+ if (device_get_cached_sysattr_value(device, attr, NULL) != -ESTALE)
+ return 0;
+
+ str = new(char, HW_ADDR_TO_STRING_MAX);
+ if (!str)
+ return -ENOMEM;
+
+ r = device_cache_sysattr_value(device, attr, hw_addr_to_string(hw_addr, str));
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(str);
+ return 0;
+}
+
+static int cache_string(sd_device *device, const char *attr, const char *val) {
+ _cleanup_free_ char *str = NULL;
+ int r;
+
+ assert(device);
+ assert(attr);
+
+ if (device_get_cached_sysattr_value(device, attr, NULL) != -ESTALE)
+ return 0;
+
+ if (val) {
+ str = strdup(val);
+ if (!str)
+ return -ENOMEM;
+ }
+
+ r = device_cache_sysattr_value(device, attr, str);
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(str);
+ return 0;
+}
+
+int device_cache_sysattr_from_link_info(sd_device *device, LinkInfo *info) {
+ int ifindex, r;
+
+ assert(device);
+ assert(info);
+
+ r = sd_device_get_ifindex(device, &ifindex);
+ if (r < 0)
+ return r;
+
+ if (ifindex != info->ifindex)
+ return -EINVAL;
+
+ r = cache_unsigned(device, "type", info->iftype);
+ if (r < 0)
+ return r;
+
+ r = cache_hw_addr(device, "address", &info->hw_addr);
+ if (r < 0)
+ return r;
+
+ r = cache_unsigned(device, "iflink", info->iflink);
+ if (r < 0)
+ return r;
+
+ if (info->support_phys_port_name) {
+ r = cache_string(device, "phys_port_name", info->phys_port_name);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int device_get_sysattr_value_maybe_from_netlink(
+ sd_device *device,
+ sd_netlink **rtnl,
+ const char *sysattr,
+ const char **ret_value) {
+
+ _cleanup_(link_info_clear) LinkInfo info = LINK_INFO_NULL;
+ int ifindex, r;
+
+ assert(device);
+ assert(rtnl);
+ assert(sysattr);
+
+ if (sd_device_get_ifindex(device, &ifindex) < 0)
+ return sd_device_get_sysattr_value(device, sysattr, ret_value);
+
+ if (!STR_IN_SET(sysattr, "type", "address", "iflink", "phys_port_name"))
+ return sd_device_get_sysattr_value(device, sysattr, ret_value);
+
+ r = device_get_cached_sysattr_value(device, sysattr, ret_value);
+ if (r != -ESTALE)
+ return r;
+
+ r = link_info_get(rtnl, ifindex, &info);
+ if (r < 0)
+ return r;
+
+ r = device_cache_sysattr_from_link_info(device, &info);
+ if (r < 0)
+ return r;
+
+ /* Do not use device_get_cached_sysattr_value() here, as kernel may not support
+ * IFLA_PHYS_PORT_NAME, and in that case we need to read the value from sysfs. */
+ return sd_device_get_sysattr_value(device, sysattr, ret_value);
+}