diff options
-rw-r--r-- | docs/reference/libmbim-glib/meson.build | 2 | ||||
-rw-r--r-- | src/libmbim-glib/mbim-device.c | 4 | ||||
-rw-r--r-- | src/libmbim-glib/mbim-helpers.c | 10 | ||||
-rw-r--r-- | src/libmbim-glib/mbim-helpers.h | 10 | ||||
-rw-r--r-- | src/libmbim-glib/mbim-net-port-manager-wdm.c | 262 | ||||
-rw-r--r-- | src/libmbim-glib/mbim-net-port-manager-wdm.h | 44 | ||||
-rw-r--r-- | src/libmbim-glib/mbim-net-port-manager.c | 423 | ||||
-rw-r--r-- | src/libmbim-glib/mbim-net-port-manager.h | 68 | ||||
-rw-r--r-- | src/libmbim-glib/meson.build | 1 |
9 files changed, 545 insertions, 279 deletions
diff --git a/docs/reference/libmbim-glib/meson.build b/docs/reference/libmbim-glib/meson.build index 29c6adc..803b939 100644 --- a/docs/reference/libmbim-glib/meson.build +++ b/docs/reference/libmbim-glib/meson.build @@ -15,6 +15,8 @@ private_headers = [ 'mbim-helpers-netlink.h', 'mbim-message-private.h', 'mbim-net-port-manager.h', + 'mbim-net-port-manager-wdm.h', + 'wwan.h', ] scan_args = [ diff --git a/src/libmbim-glib/mbim-device.c b/src/libmbim-glib/mbim-device.c index cc623e7..bfc4084 100644 --- a/src/libmbim-glib/mbim-device.c +++ b/src/libmbim-glib/mbim-device.c @@ -39,6 +39,7 @@ #include "mbim-proxy.h" #include "mbim-proxy-control.h" #include "mbim-net-port-manager.h" +#include "mbim-net-port-manager-wdm.h" #include "mbim-basic-connect.h" #include "mbim-ms-basic-connect-extensions.h" @@ -593,7 +594,8 @@ setup_net_port_manager (MbimDevice *self, return FALSE; } - self->priv->net_port_manager = mbim_net_port_manager_new (self->priv->wwan_iface, error); + self->priv->net_port_manager = MBIM_NET_PORT_MANAGER (mbim_net_port_manager_wdm_new (self->priv->wwan_iface, error)); + return !!self->priv->net_port_manager; } diff --git a/src/libmbim-glib/mbim-helpers.c b/src/libmbim-glib/mbim-helpers.c index 9667981..3a37556 100644 --- a/src/libmbim-glib/mbim-helpers.c +++ b/src/libmbim-glib/mbim-helpers.c @@ -102,11 +102,11 @@ mbim_helpers_get_devname (const gchar *cdc_wdm_path, /*****************************************************************************/ gboolean -mbim_helpers_list_links (GFile *sysfs_file, - GCancellable *cancellable, - GPtrArray *previous_links, - GPtrArray **out_links, - GError **error) +mbim_helpers_list_links_wdm (GFile *sysfs_file, + GCancellable *cancellable, + GPtrArray *previous_links, + GPtrArray **out_links, + GError **error) { g_autofree gchar *sysfs_path = NULL; g_autoptr(GFileEnumerator) direnum = NULL; diff --git a/src/libmbim-glib/mbim-helpers.h b/src/libmbim-glib/mbim-helpers.h index 1f26fc3..b314e0e 100644 --- a/src/libmbim-glib/mbim-helpers.h +++ b/src/libmbim-glib/mbim-helpers.h @@ -31,11 +31,11 @@ gchar *mbim_helpers_get_devname (const gchar *cdc_wdm_path, GError **error); G_GNUC_INTERNAL -gboolean mbim_helpers_list_links (GFile *sysfs_file, - GCancellable *cancellable, - GPtrArray *previous_links, - GPtrArray **out_links, - GError **error); +gboolean mbim_helpers_list_links_wdm (GFile *sysfs_file, + GCancellable *cancellable, + GPtrArray *previous_links, + GPtrArray **out_links, + GError **error); #if !GLIB_CHECK_VERSION(2,54,0) diff --git a/src/libmbim-glib/mbim-net-port-manager-wdm.c b/src/libmbim-glib/mbim-net-port-manager-wdm.c new file mode 100644 index 0000000..2d0aa9a --- /dev/null +++ b/src/libmbim-glib/mbim-net-port-manager-wdm.c @@ -0,0 +1,262 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * libmbim-glib -- GLib/GIO based library to control MBIM devices + * + * Copyright (C) 2022 Daniele Palmas <dnlplm@gmail.com> + * + * Based on previous work: + * Copyright (C) 2020-2021 Eric Caruso <ejcaruso@chromium.org> + * Copyright (C) 2020-2021 Andrew Lassalle <andrewlassalle@chromium.org> + * Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es> + */ + +#include <linux/if_link.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <string.h> + +#include "mbim-device.h" +#include "mbim-helpers.h" +#include "mbim-error-types.h" +#include "mbim-net-port-manager.h" +#include "mbim-net-port-manager-wdm.h" +#include "mbim-helpers-netlink.h" + +G_DEFINE_TYPE (MbimNetPortManagerWdm, mbim_net_port_manager_wdm, MBIM_TYPE_NET_PORT_MANAGER) + +/* alternative VLAN for IP session 0 if not untagged */ +#define MBIM_IPS0_VID 4094 + +#define VLAN_DATA_TYPE "vlan" + +/*****************************************************************************/ + +static guint +session_id_to_vlan_id (guint session_id) +{ + /* VLAN ID 4094 is an alternative mapping of MBIM session 0. If you create + * a subinterface with this ID then it will take over the session 0 traffic + * and no packets go untagged anymore. */ + return (session_id == 0 ? MBIM_IPS0_VID : session_id); +} + +/*****************************************************************************/ + +static NetlinkMessage * +netlink_message_new_link (guint vlan_id, + gchar *ifname, + guint base_if_index) +{ + NetlinkMessage *msg; + guint linkinfo_pos, datainfo_pos; + struct rtattr info; + + msg = mbim_helpers_netlink_message_new (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL); + mbim_helpers_netlink_append_attribute_uint32 (msg, IFLA_LINK, base_if_index); + mbim_helpers_netlink_append_attribute_string (msg, IFLA_IFNAME, ifname); + + /* Store the position of the next attribute to adjust its length later. */ + linkinfo_pos = mbim_helpers_netlink_get_pos_of_next_attr (msg); + mbim_helpers_netlink_append_attribute_nested (msg, IFLA_LINKINFO); + mbim_helpers_netlink_append_attribute_string (msg, IFLA_INFO_KIND, VLAN_DATA_TYPE); + + /* Store the position of the next attribute to adjust its length later. */ + datainfo_pos = mbim_helpers_netlink_get_pos_of_next_attr (msg); + mbim_helpers_netlink_append_attribute_nested (msg, IFLA_INFO_DATA); + mbim_helpers_netlink_append_attribute_uint16 (msg, IFLA_VLAN_ID, vlan_id); + + /* Use memcpy to preserve byte alignment */ + memcpy (&info, (char *) msg->data + datainfo_pos, sizeof (struct rtattr)); + info.rta_len = msg->len - datainfo_pos; + memcpy ((char *) msg->data + datainfo_pos, &info, sizeof (struct rtattr)); + + memcpy (&info, (char *) msg->data + linkinfo_pos, sizeof (struct rtattr)); + info.rta_len = msg->len - linkinfo_pos; + memcpy ((char *) msg->data + linkinfo_pos, &info, sizeof (struct rtattr)); + + return msg; +} + +/*****************************************************************************/ + +static gboolean +mbim_net_port_manager_wdm_list_links (MbimNetPortManager *self, + const gchar *base_ifname, + GPtrArray **out_links, + GError **error) +{ + g_autoptr(GFile) sysfs_file = NULL; + g_autofree gchar *sysfs_path = NULL; + + sysfs_path = g_strdup_printf ("/sys/class/net/%s", base_ifname); + sysfs_file = g_file_new_for_path (sysfs_path); + + return mbim_helpers_list_links_wdm (sysfs_file, NULL, NULL, out_links, error); +} + +/*****************************************************************************/ + +typedef struct { + guint session_id; + guint vlan_id; + gchar *ifname; +} AddLinkContext; + +static void +add_link_context_free (AddLinkContext *ctx) +{ + g_free (ctx->ifname); + g_free (ctx); +} + +static gchar * +mbim_net_port_manager_wdm_add_link_finish (MbimNetPortManager *self, + guint *session_id, + GAsyncResult *res, + GError **error) +{ + AddLinkContext *ctx; + + ctx = g_task_get_task_data (G_TASK (res)); + + if (!g_task_propagate_boolean (G_TASK (res), error)) { + g_prefix_error (error, "Failed to add link with session id %d: ", + ctx->session_id); + return NULL; + } + + *session_id = ctx->session_id; + return g_steal_pointer (&ctx->ifname); +} + +static void +mbim_net_port_manager_wdm_add_link (MbimNetPortManager *self, + guint session_id, + const gchar *base_ifname, + const gchar *ifname_prefix, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + NetlinkMessage *msg; + NetlinkTransaction *tr; + GTask *task; + GError *error = NULL; + gssize bytes_sent; + guint base_if_index; + AddLinkContext *ctx; + + task = g_task_new (self, cancellable, callback, user_data); + + ctx = g_new0 (AddLinkContext, 1); + ctx->session_id = session_id; + g_task_set_task_data (task, ctx, (GDestroyNotify) add_link_context_free); + + if (ctx->session_id == MBIM_DEVICE_SESSION_ID_AUTOMATIC) { + if (!mbim_net_port_manager_util_get_first_free_session_id (ifname_prefix, &ctx->session_id)) { + g_task_return_new_error (task, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, + "Failed to find an available session ID"); + g_object_unref (task); + return; + } + g_debug ("Using dynamic session ID %u", ctx->session_id); + } else + g_debug ("Using static session ID %u", ctx->session_id); + + /* validate interface to use */ + if (g_strcmp0 (mbim_net_port_manager_peek_iface (self), + base_ifname) != 0) { + g_task_return_new_error (task, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, + "Invalid network interface %s: expected %s", + base_ifname, mbim_net_port_manager_peek_iface (self)); + g_object_unref (task); + return; + } + + base_if_index = if_nametoindex (base_ifname); + if (!base_if_index) { + g_task_return_new_error (task, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, + "%s interface is not available", + base_ifname); + g_object_unref (task); + return; + } + + ctx->ifname = mbim_net_port_manager_util_session_id_to_ifname (ifname_prefix, ctx->session_id); + ctx->vlan_id = session_id_to_vlan_id (ctx->session_id); + g_debug ("Using ifname '%s' and vlan id %u", ctx->ifname, ctx->vlan_id); + + msg = netlink_message_new_link (ctx->vlan_id, ctx->ifname, base_if_index); + + /* The task ownership is transferred to the transaction. */ + tr = mbim_helpers_netlink_transaction_new (mbim_net_port_manager_peek_current_sequence_id (MBIM_NET_PORT_MANAGER (self)), + mbim_net_port_manager_peek_transactions (MBIM_NET_PORT_MANAGER (self)), + msg, timeout, task); + + bytes_sent = g_socket_send (mbim_net_port_manager_peek_socket (MBIM_NET_PORT_MANAGER (self)), + (const gchar *) msg->data, + msg->len, + cancellable, + &error); + mbim_helpers_netlink_message_free (msg); + + if (bytes_sent < 0) + mbim_helpers_netlink_transaction_complete_with_error (tr, + mbim_net_port_manager_peek_transactions (MBIM_NET_PORT_MANAGER (self)), + error); + + g_object_unref (task); +} + +/*****************************************************************************/ + +MbimNetPortManagerWdm * +mbim_net_port_manager_wdm_new (const gchar *iface, + GError **error) +{ + MbimNetPortManagerWdm *self; + gint socket_fd; + GSocket *gsocket; + GError *inner_error = NULL; + + socket_fd = socket (AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (socket_fd < 0) { + g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, + "Failed to create netlink socket"); + return NULL; + } + + gsocket = g_socket_new_from_fd (socket_fd, &inner_error); + if (inner_error) { + g_debug ("Could not create socket: %s", inner_error->message); + close (socket_fd); + g_propagate_error (error, inner_error); + return NULL; + } + + self = g_object_new (MBIM_TYPE_NET_PORT_MANAGER_WDM, NULL); + mbim_net_port_manager_common_setup (MBIM_NET_PORT_MANAGER (self), iface, gsocket); + + return self; +} + +static void +mbim_net_port_manager_wdm_init (MbimNetPortManagerWdm *self) +{ +} + +static void +mbim_net_port_manager_wdm_class_init (MbimNetPortManagerWdmClass *klass) +{ + MbimNetPortManagerClass *net_port_manager_class = MBIM_NET_PORT_MANAGER_CLASS (klass); + + net_port_manager_class->list_links = mbim_net_port_manager_wdm_list_links; + net_port_manager_class->add_link = mbim_net_port_manager_wdm_add_link; + net_port_manager_class->add_link_finish = mbim_net_port_manager_wdm_add_link_finish; +} diff --git a/src/libmbim-glib/mbim-net-port-manager-wdm.h b/src/libmbim-glib/mbim-net-port-manager-wdm.h new file mode 100644 index 0000000..42aeaae --- /dev/null +++ b/src/libmbim-glib/mbim-net-port-manager-wdm.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * libmbim-glib -- GLib/GIO based library to control MBIM devices + * + * Copyright (C) 2022 Daniele Palmas <dnlplm@gmail.com> + * + * Based on previous work: + * Copyright (C) 2020-2021 Eric Caruso <ejcaruso@chromium.org> + * Copyright (C) 2020-2021 Andrew Lassalle <andrewlassalle@chromium.org> + * Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es> + */ + +#ifndef _LIBMBIM_GLIB_MBIM_NET_PORT_MANAGER_WDM_H_ +#define _LIBMBIM_GLIB_MBIM_NET_PORT_MANAGER_WDM_H_ + +#include <gio/gio.h> +#include <glib-object.h> + +#define MBIM_TYPE_NET_PORT_MANAGER_WDM (mbim_net_port_manager_wdm_get_type ()) +#define MBIM_NET_PORT_MANAGER_WDM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MBIM_TYPE_NET_PORT_MANAGER_WDM, MbimNetPortManagerWdm)) +#define MBIM_NET_PORT_MANAGER_WDM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MBIM_TYPE_NET_PORT_MANAGER_WDM, MbimNetPortManagerWdmClass)) +#define MBIM_IS_NET_PORT_MANAGER_WDM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MBIM_TYPE_NET_PORT_MANAGER_WDM)) +#define MBIM_IS_NET_PORT_MANAGER_WDM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MBIM_TYPE_NET_PORT_MANAGER_WDM)) +#define MBIM_NET_PORT_MANAGER_WDM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MBIM_TYPE_NET_PORT_MANAGER_WDM, MbimNetPortManagerWdmClass)) + +typedef struct _MbimNetPortManagerWdm MbimNetPortManagerWdm; +typedef struct _MbimNetPortManagerWdmClass MbimNetPortManagerWdmClass; + +struct _MbimNetPortManagerWdm { + MbimNetPortManager parent; +}; + +struct _MbimNetPortManagerWdmClass { + MbimNetPortManagerClass parent; +}; + +GType mbim_net_port_manager_wdm_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MbimNetPortManagerWdm, g_object_unref) + +MbimNetPortManagerWdm *mbim_net_port_manager_wdm_new (const gchar *iface, + GError **error); + +#endif /* _LIBMBIM_GLIB_MBIM_NET_PORT_MANAGER_WDM_H_ */ diff --git a/src/libmbim-glib/mbim-net-port-manager.c b/src/libmbim-glib/mbim-net-port-manager.c index 5958660..ef4a38a 100644 --- a/src/libmbim-glib/mbim-net-port-manager.c +++ b/src/libmbim-glib/mbim-net-port-manager.c @@ -14,10 +14,6 @@ #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <net/if.h> -#include <net/if_arp.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <string.h> #include "mbim-device.h" #include "mbim-helpers.h" @@ -25,7 +21,7 @@ #include "mbim-net-port-manager.h" #include "mbim-helpers-netlink.h" -G_DEFINE_TYPE (MbimNetPortManager, mbim_net_port_manager, G_TYPE_OBJECT) +G_DEFINE_ABSTRACT_TYPE (MbimNetPortManager, mbim_net_port_manager, G_TYPE_OBJECT) struct _MbimNetPortManagerPrivate { gchar *iface; @@ -39,237 +35,123 @@ struct _MbimNetPortManagerPrivate { GHashTable *transactions; }; -/* alternative VLAN for IP session 0 if not untagged */ -#define MBIM_IPS0_VID 4094 - -#define VLAN_DATA_TYPE "vlan" - /*****************************************************************************/ -static gchar * -session_id_to_ifname (const gchar *ifname_prefix, - guint session_id) +void +mbim_net_port_manager_add_link (MbimNetPortManager *self, + guint session_id, + const gchar *base_ifname, + const gchar *ifname_prefix, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - /* - * Link names are in the form <PREFIX>.<SESSION ID> */ - return g_strdup_printf ("%s%u", ifname_prefix, session_id); + MBIM_NET_PORT_MANAGER_GET_CLASS (self)->add_link (self, + session_id, + base_ifname, + ifname_prefix, + timeout, + cancellable, + callback, + user_data); } -/*****************************************************************************/ - -static guint -session_id_to_vlan_id (guint session_id) +gchar * +mbim_net_port_manager_add_link_finish (MbimNetPortManager *self, + guint *session_id, + GAsyncResult *res, + GError **error) { - /* VLAN ID 4094 is an alternative mapping of MBIM session 0. If you create - * a subinterface with this ID then it will take over the session 0 traffic - * and no packets go untagged anymore. */ - return (session_id == 0 ? MBIM_IPS0_VID : session_id); + return MBIM_NET_PORT_MANAGER_GET_CLASS (self)->add_link_finish (self, session_id, res, error); } -/*****************************************************************************/ - -static NetlinkMessage * -netlink_message_new_link (guint vlan_id, - gchar *ifname, - guint base_if_index) +void +mbim_net_port_manager_del_link (MbimNetPortManager *self, + const gchar *ifname, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - NetlinkMessage *msg; - guint linkinfo_pos, datainfo_pos; - struct rtattr info; - - msg = mbim_helpers_netlink_message_new (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL); - mbim_helpers_netlink_append_attribute_uint32 (msg, IFLA_LINK, base_if_index); - mbim_helpers_netlink_append_attribute_string (msg, IFLA_IFNAME, ifname); - - /* Store the position of the next attribute to adjust its length later. */ - linkinfo_pos = mbim_helpers_netlink_get_pos_of_next_attr (msg); - mbim_helpers_netlink_append_attribute_nested (msg, IFLA_LINKINFO); - mbim_helpers_netlink_append_attribute_string (msg, IFLA_INFO_KIND, VLAN_DATA_TYPE); - - /* Store the position of the next attribute to adjust its length later. */ - datainfo_pos = mbim_helpers_netlink_get_pos_of_next_attr (msg); - mbim_helpers_netlink_append_attribute_nested (msg, IFLA_INFO_DATA); - mbim_helpers_netlink_append_attribute_uint16 (msg, IFLA_VLAN_ID, vlan_id); - - /* Use memcpy to preserve byte alignment */ - memcpy (&info, (char *) msg->data + datainfo_pos, sizeof (struct rtattr)); - info.rta_len = msg->len - datainfo_pos; - memcpy ((char *) msg->data + datainfo_pos, &info, sizeof (struct rtattr)); - - memcpy (&info, (char *) msg->data + linkinfo_pos, sizeof (struct rtattr)); - info.rta_len = msg->len - linkinfo_pos; - memcpy ((char *) msg->data + linkinfo_pos, &info, sizeof (struct rtattr)); - - return msg; + MBIM_NET_PORT_MANAGER_GET_CLASS (self)->del_link (self, + ifname, + timeout, + cancellable, + callback, + user_data); } -static NetlinkMessage * -netlink_message_del_link (guint ifindex) +gboolean +mbim_net_port_manager_del_link_finish (MbimNetPortManager *self, + GAsyncResult *res, + GError **error) { - NetlinkMessage *msg; - - g_assert (ifindex != 0); - - msg = mbim_helpers_netlink_message_new (RTM_DELLINK, 0); - mbim_helpers_netlink_get_message_header (msg)->ifreq.ifi_index = ifindex; - - return msg; + return MBIM_NET_PORT_MANAGER_GET_CLASS (self)->del_link_finish (self, res, error); } -/*****************************************************************************/ - -static gboolean -get_first_free_session_id (MbimNetPortManager *self, - const gchar *ifname_prefix, - guint *session_id) +void +mbim_net_port_manager_del_all_links (MbimNetPortManager *self, + const gchar *base_ifname, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - guint i; - - /* The minimum session id is really 0 (MBIM_DEVICE_SESSION_ID_MIN), but - * when we have to automatically allocate a new session id we'll start at - * 1, because 0 is also used by the non-muxed setup. */ - for (i = 1; i <= MBIM_DEVICE_SESSION_ID_MAX; i++) { - g_autofree gchar *ifname = NULL; - - ifname = session_id_to_ifname (ifname_prefix, i); - if (!if_nametoindex (ifname)) { - *session_id = i; - return TRUE; - } - } - - return FALSE; + MBIM_NET_PORT_MANAGER_GET_CLASS (self)->del_all_links (self, + base_ifname, + cancellable, + callback, + user_data); } -/*****************************************************************************/ - -typedef struct { - guint session_id; - guint vlan_id; - gchar *ifname; -} AddLinkContext; - -static void -add_link_context_free (AddLinkContext *ctx) +gboolean +mbim_net_port_manager_del_all_links_finish (MbimNetPortManager *self, + GAsyncResult *res, + GError **error) { - g_free (ctx->ifname); - g_free (ctx); + return MBIM_NET_PORT_MANAGER_GET_CLASS (self)->del_all_links_finish (self, res, error); } -gchar * -mbim_net_port_manager_add_link_finish (MbimNetPortManager *self, - guint *session_id, - GAsyncResult *res, - GError **error) +gboolean +mbim_net_port_manager_list_links (MbimNetPortManager *self, + const gchar *base_ifname, + GPtrArray **out_links, + GError **error) { - AddLinkContext *ctx; - - ctx = g_task_get_task_data (G_TASK (res)); + return MBIM_NET_PORT_MANAGER_GET_CLASS (self)->list_links (self, base_ifname, out_links, error); +} - if (!g_task_propagate_boolean (G_TASK (res), error)) { - g_prefix_error (error, "Failed to add link with session id %d: ", - ctx->session_id); - return NULL; - } +/*****************************************************************************/ +/* Default implementations */ - *session_id = ctx->session_id; - return g_steal_pointer (&ctx->ifname); +static gboolean +net_port_manager_del_link_finish (MbimNetPortManager *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); } -void -mbim_net_port_manager_add_link (MbimNetPortManager *self, - guint session_id, - const gchar *base_ifname, - const gchar *ifname_prefix, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +static NetlinkMessage * +netlink_message_del_link (guint ifindex) { - NetlinkMessage *msg; - NetlinkTransaction *tr; - GTask *task; - GError *error = NULL; - gssize bytes_sent; - guint base_if_index; - AddLinkContext *ctx; - - task = g_task_new (self, cancellable, callback, user_data); - - ctx = g_new0 (AddLinkContext, 1); - ctx->session_id = session_id; - g_task_set_task_data (task, ctx, (GDestroyNotify) add_link_context_free); - - if (ctx->session_id == MBIM_DEVICE_SESSION_ID_AUTOMATIC) { - if (!get_first_free_session_id (self, ifname_prefix, &ctx->session_id)) { - g_task_return_new_error (task, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, - "Failed to find an available session ID"); - g_object_unref (task); - return; - } - g_debug ("Using dynamic session ID %u", ctx->session_id); - } else - g_debug ("Using static session ID %u", ctx->session_id); - - /* validate interface to use */ - if (g_strcmp0 (self->priv->iface, base_ifname) != 0) { - g_task_return_new_error (task, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, - "Invalid network interface %s: expected %s", - base_ifname, self->priv->iface); - g_object_unref (task); - return; - } - - base_if_index = if_nametoindex (base_ifname); - if (!base_if_index) { - g_task_return_new_error (task, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, - "%s interface is not available", - base_ifname); - g_object_unref (task); - return; - } - - ctx->ifname = session_id_to_ifname (ifname_prefix, ctx->session_id); - ctx->vlan_id = session_id_to_vlan_id (ctx->session_id); - g_debug ("Using ifname '%s' and vlan id %u", ctx->ifname, ctx->vlan_id); - - msg = netlink_message_new_link (ctx->vlan_id, ctx->ifname, base_if_index); - - /* The task ownership is transferred to the transaction. */ - tr = mbim_helpers_netlink_transaction_new (&self->priv->current_sequence_id, - self->priv->transactions, - msg, - timeout, - task); - - bytes_sent = g_socket_send (self->priv->socket, - (const gchar *) msg->data, - msg->len, - cancellable, - &error); - mbim_helpers_netlink_message_free (msg); + NetlinkMessage *msg; - if (bytes_sent < 0) - mbim_helpers_netlink_transaction_complete_with_error (tr, self->priv->transactions, error); + g_assert (ifindex != 0); - g_object_unref (task); -} + msg = mbim_helpers_netlink_message_new (RTM_DELLINK, 0); + mbim_helpers_netlink_get_message_header (msg)->ifreq.ifi_index = ifindex; -gboolean -mbim_net_port_manager_del_link_finish (MbimNetPortManager *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); + return msg; } -void -mbim_net_port_manager_del_link (MbimNetPortManager *self, - const gchar *ifname, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +static void +net_port_manager_del_link (MbimNetPortManager *self, + const gchar *ifname, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { guint ifindex; NetlinkMessage *msg; @@ -310,25 +192,6 @@ mbim_net_port_manager_del_link (MbimNetPortManager *self, g_object_unref (task); } -/*****************************************************************************/ - -gboolean -mbim_net_port_manager_list_links (MbimNetPortManager *self, - const gchar *base_ifname, - GPtrArray **out_links, - GError **error) -{ - g_autoptr(GFile) sysfs_file = NULL; - g_autofree gchar *sysfs_path = NULL; - - sysfs_path = g_strdup_printf ("/sys/class/net/%s", base_ifname); - sysfs_file = g_file_new_for_path (sysfs_path); - - return mbim_helpers_list_links (sysfs_file, NULL, NULL, out_links, error); -} - -/*****************************************************************************/ - typedef struct { GPtrArray *links; guint link_i; @@ -341,10 +204,10 @@ del_all_links_context_free (DelAllLinksContext *ctx) g_slice_free (DelAllLinksContext, ctx); } -gboolean -mbim_net_port_manager_del_all_links_finish (MbimNetPortManager *self, - GAsyncResult *res, - GError **error) +static gboolean +net_port_manager_del_all_links_finish (MbimNetPortManager *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } @@ -353,8 +216,8 @@ static void delete_next_link (GTask *task); static void port_manager_del_link_ready (MbimNetPortManager *self, - GAsyncResult *res, - GTask *task) + GAsyncResult *res, + GTask *task) { DelAllLinksContext *ctx; GError *error = NULL; @@ -390,16 +253,16 @@ delete_next_link (GTask *task) g_ptr_array_index (ctx->links, 0), 5, g_task_get_cancellable (task), - (GAsyncReadyCallback)port_manager_del_link_ready, + (GAsyncReadyCallback) port_manager_del_link_ready, task); } -void -mbim_net_port_manager_del_all_links (MbimNetPortManager *self, - const gchar *base_ifname, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +static void +net_port_manager_del_all_links (MbimNetPortManager *self, + const gchar *base_ifname, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { GTask *task; DelAllLinksContext *ctx; @@ -420,31 +283,35 @@ mbim_net_port_manager_del_all_links (MbimNetPortManager *self, /*****************************************************************************/ -MbimNetPortManager * -mbim_net_port_manager_new (const gchar *iface, - GError **error) +GHashTable * +mbim_net_port_manager_peek_transactions (MbimNetPortManager *self) { - MbimNetPortManager *self; - gint socket_fd; - GSocket *gsocket; - GError *inner_error = NULL; - - socket_fd = socket (AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); - if (socket_fd < 0) { - g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, - "Failed to create netlink socket"); - return NULL; - } + return self->priv->transactions; +} - gsocket = g_socket_new_from_fd (socket_fd, &inner_error); - if (inner_error) { - g_debug ("Could not create socket: %s", inner_error->message); - close (socket_fd); - g_propagate_error (error, inner_error); - return NULL; - } +gchar * +mbim_net_port_manager_peek_iface (MbimNetPortManager *self) +{ + return self->priv->iface; +} - self = g_object_new (MBIM_TYPE_NET_PORT_MANAGER, NULL); +guint * +mbim_net_port_manager_peek_current_sequence_id (MbimNetPortManager *self) +{ + return &self->priv->current_sequence_id; +} + +GSocket * +mbim_net_port_manager_peek_socket (MbimNetPortManager *self) +{ + return self->priv->socket; +} + +void +mbim_net_port_manager_common_setup (MbimNetPortManager *self, + const gchar *iface, + GSocket *gsocket) +{ self->priv->iface = g_strdup (iface); self->priv->socket = gsocket; self->priv->current_sequence_id = 0; @@ -456,13 +323,44 @@ mbim_net_port_manager_new (const gchar *iface, mbim_helpers_netlink_set_callback (&self->priv->source, self->priv->socket, self->priv->transactions); +} + +gchar * +mbim_net_port_manager_util_session_id_to_ifname (const gchar *ifname_prefix, + guint session_id) +{ + /* Link names are in the form <PREFIX>.<SESSION ID> */ + return g_strdup_printf ("%s%u", ifname_prefix, session_id); +} + +gboolean +mbim_net_port_manager_util_get_first_free_session_id (const gchar *ifname_prefix, + guint *session_id) +{ + guint i; + + /* The minimum session id is really 0 (MBIM_DEVICE_SESSION_ID_MIN), but + * when we have to automatically allocate a new session id we'll start at + * 1, because 0 is also used by the non-muxed setup. */ + for (i = 1; i <= MBIM_DEVICE_SESSION_ID_MAX; i++) { + g_autofree gchar *ifname = NULL; - return self; + ifname = mbim_net_port_manager_util_session_id_to_ifname (ifname_prefix, i); + if (!if_nametoindex (ifname)) { + *session_id = i; + return TRUE; + } + } + + return FALSE; } +/*****************************************************************************/ + static void mbim_net_port_manager_init (MbimNetPortManager *self) { + /* Initialize private data */ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MBIM_TYPE_NET_PORT_MANAGER, MbimNetPortManagerPrivate); } @@ -486,4 +384,9 @@ mbim_net_port_manager_class_init (MbimNetPortManagerClass *klass) g_type_class_add_private (object_class, sizeof (MbimNetPortManagerPrivate)); object_class->finalize = finalize; + + klass->del_link = net_port_manager_del_link; + klass->del_link_finish = net_port_manager_del_link_finish; + klass->del_all_links = net_port_manager_del_all_links; + klass->del_all_links_finish = net_port_manager_del_all_links_finish; } diff --git a/src/libmbim-glib/mbim-net-port-manager.h b/src/libmbim-glib/mbim-net-port-manager.h index 45027b8..095e637 100644 --- a/src/libmbim-glib/mbim-net-port-manager.h +++ b/src/libmbim-glib/mbim-net-port-manager.h @@ -28,24 +28,58 @@ typedef struct _MbimNetPortManagerClass MbimNetPortManagerClass; typedef struct _MbimNetPortManagerPrivate MbimNetPortManagerPrivate; struct _MbimNetPortManager { - GObject parent; + GObject parent; MbimNetPortManagerPrivate *priv; }; struct _MbimNetPortManagerClass { GObjectClass parent; + + gboolean (* list_links) (MbimNetPortManager *self, + const gchar *base_ifname, + GPtrArray **out_links, + GError **error); + + void (* add_link) (MbimNetPortManager *self, + guint session_id, + const gchar *base_ifname, + const gchar *ifname_prefix, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gchar * (* add_link_finish) (MbimNetPortManager *self, + guint *session_id, + GAsyncResult *res, + GError **error); + + void (* del_link) (MbimNetPortManager *self, + const gchar *ifname, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* del_link_finish) (MbimNetPortManager *self, + GAsyncResult *res, + GError **error); + + void (* del_all_links) (MbimNetPortManager *self, + const gchar *base_ifname, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* del_all_links_finish) (MbimNetPortManager *self, + GAsyncResult *res, + GError **error); }; GType mbim_net_port_manager_get_type (void); G_DEFINE_AUTOPTR_CLEANUP_FUNC (MbimNetPortManager, g_object_unref) -MbimNetPortManager *mbim_net_port_manager_new (const gchar *iface, - GError **error); - -gboolean mbim_net_port_manager_list_links (MbimNetPortManager *self, - const gchar *base_ifname, - GPtrArray **out_links, - GError **error); +gboolean mbim_net_port_manager_list_links (MbimNetPortManager *self, + const gchar *base_ifname, + GPtrArray **out_links, + GError **error); void mbim_net_port_manager_add_link (MbimNetPortManager *self, guint session_id, @@ -79,4 +113,22 @@ gboolean mbim_net_port_manager_del_all_links_finish (MbimNetPortManager *self GAsyncResult *res, GError **error); +GHashTable *mbim_net_port_manager_peek_transactions (MbimNetPortManager *self); + +gchar *mbim_net_port_manager_peek_iface (MbimNetPortManager *self); + +guint *mbim_net_port_manager_peek_current_sequence_id (MbimNetPortManager *self); + +GSocket *mbim_net_port_manager_peek_socket (MbimNetPortManager *self); + +void mbim_net_port_manager_common_setup (MbimNetPortManager *self, + const gchar *iface, + GSocket *gsocket); + +gchar *mbim_net_port_manager_util_session_id_to_ifname (const gchar *ifname_prefix, + guint session_id); + +gboolean mbim_net_port_manager_util_get_first_free_session_id (const gchar *ifname_prefix, + guint *session_id); + #endif /* _LIBMBIM_GLIB_MBIM_NET_PORT_MANAGER_H_ */ diff --git a/src/libmbim-glib/meson.build b/src/libmbim-glib/meson.build index a182866..6c3774e 100644 --- a/src/libmbim-glib/meson.build +++ b/src/libmbim-glib/meson.build @@ -42,6 +42,7 @@ sources = files( 'mbim-helpers-netlink.c', 'mbim-message.c', 'mbim-net-port-manager.c', + 'mbim-net-port-manager-wdm.c', 'mbim-proxy.c', 'mbim-proxy-helpers.c', 'mbim-utils.c', |