fwupd/plugins/redfish/fu-redfish-network.c
Richard Hughes 6b238b2daa redfish: Automatically connect the BMC network interface at startup
Some distributions like RHEL change the default to not autoconnect
ethernet devices. This breaks connecting to the SMBIOS-defined BMC
adapter which means all the reads fail after a 60s timemout.

Autoconnect the internal USB ethernet adapter so we can use Redfish
without user action.
2021-07-22 12:48:22 +01:00

199 lines
5.5 KiB
C

/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <fwupdplugin.h>
#include "fu-redfish-network.h"
typedef struct {
FuRedfishNetworkDevice *device;
const gchar *mac_addr;
guint16 vid;
guint16 pid;
} FuRedfishNetworkMatchHelper;
static gboolean
fu_redfish_network_device_match_device (FuRedfishNetworkMatchHelper *helper,
const gchar *object_path,
GError **error)
{
g_autoptr(GDBusProxy) proxy = NULL;
/* connect to device */
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
NETWORK_MANAGER_SERVICE_NAME,
object_path,
NETWORK_MANAGER_INTERFACE_DEVICE,
NULL,
error);
if (proxy == NULL) {
g_prefix_error (error, "failed to connect to interface %s: ", object_path);
return FALSE;
}
/* compare MAC address different */
if (helper->mac_addr != NULL) {
const gchar *mac_addr = NULL;
g_autoptr(GVariant) hw_address = NULL;
hw_address = g_dbus_proxy_get_cached_property (proxy, "HwAddress");
if (hw_address == NULL)
return TRUE;
mac_addr = g_variant_get_string (hw_address, NULL);
/* verify */
if (g_getenv ("FWUPD_REDFISH_VERBOSE") != NULL)
g_debug ("mac_addr=%s", mac_addr);
if (g_strcmp0 (mac_addr, helper->mac_addr) == 0)
helper->device = fu_redfish_network_device_new (object_path);
}
/* compare VID:PID */
if (helper->vid != 0x0 && helper->pid != 0x0) {
#ifdef HAVE_GUDEV
const gchar *sysfs_path = NULL;
const gchar *tmp;
guint16 pid = 0;
guint16 vid = 0;
g_autoptr(GVariant) udi = NULL;
g_autoptr(GUdevClient) udev_client = NULL;
g_autoptr(GUdevDevice) udev_device = NULL;
udi = g_dbus_proxy_get_cached_property (proxy, "Udi");
if (udi == NULL)
return TRUE;
sysfs_path = g_variant_get_string (udi, NULL);
/* get the VID and PID */
udev_client = g_udev_client_new (NULL);
udev_device = g_udev_client_query_by_sysfs_path (udev_client, sysfs_path);
if (udev_device == NULL)
return TRUE;
tmp = g_udev_device_get_property (udev_device, "ID_VENDOR_ID");
if (tmp != NULL)
vid = g_ascii_strtoull (tmp, NULL, 16);
tmp = g_udev_device_get_property (udev_device, "ID_MODEL_ID");
if (tmp != NULL)
pid = g_ascii_strtoull (tmp, NULL, 16);
/* verify */
if (g_getenv ("FWUPD_REDFISH_VERBOSE") != NULL)
g_debug ("%s: 0x%04x, 0x%04x", sysfs_path, vid, pid);
if (vid == helper->vid && pid == helper->pid)
helper->device = fu_redfish_network_device_new (object_path);
#else
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"no UDev support");
return FALSE;
#endif
}
/* assume success */
return TRUE;
}
static gboolean
fu_redfish_network_device_match (FuRedfishNetworkMatchHelper *helper, GError **error)
{
g_autoptr(GDBusProxy) proxy = NULL;
g_autoptr(GError) error_local = NULL;
g_autoptr(GVariant) devices = NULL;
g_auto(GStrv) paths = NULL;
/* get devices */
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL,
NETWORK_MANAGER_SERVICE_NAME,
NETWORK_MANAGER_PATH,
NETWORK_MANAGER_INTERFACE,
NULL,
&error_local);
if (proxy == NULL) {
if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR) ||
g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"D-Bus is not running");
return FALSE;
}
g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
"failed to construct proxy for %s: ",
NETWORK_MANAGER_SERVICE_NAME);
return FALSE;
}
devices = g_dbus_proxy_call_sync (proxy, "GetDevices",
NULL, G_DBUS_CALL_FLAGS_NONE, -1,
NULL, &error_local);
if (devices == NULL) {
if (g_error_matches (error_local, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"NetworkManager is not running");
return FALSE;
}
g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
"failed to call GetDevices() on %s: ",
g_dbus_proxy_get_name (proxy));
return FALSE;
}
/* look at each device */
g_variant_get (devices, "(^ao)", &paths);
for (guint i = 0; paths[i] != NULL; i++) {
if (g_getenv ("FWUPD_REDFISH_VERBOSE") != NULL)
g_debug ("device %u: %s", i, paths[i]);
if (!fu_redfish_network_device_match_device (helper, paths[i], error))
return FALSE;
if (helper->device != NULL)
break;
}
if (helper->device == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"could not find device");
return FALSE;
}
return TRUE;
}
FuRedfishNetworkDevice *
fu_redfish_network_device_for_mac_addr (const gchar *mac_addr, GError **error)
{
FuRedfishNetworkMatchHelper helper = {
.mac_addr = mac_addr,
};
if (!fu_redfish_network_device_match (&helper, error)) {
g_prefix_error (error, "missing %s: ", mac_addr);
return NULL;
}
return helper.device;
}
FuRedfishNetworkDevice *
fu_redfish_network_device_for_vid_pid (guint16 vid, guint16 pid, GError **error)
{
FuRedfishNetworkMatchHelper helper = {
.vid = vid,
.pid = pid,
};
if (!fu_redfish_network_device_match (&helper, error)) {
g_prefix_error (error, "missing 0x%04x:0x%04x: ", vid, pid);
return NULL;
}
return helper.device;
}