diff options
author | Aleksander Morgado <aleksandermj@chromium.org> | 2023-12-17 11:37:33 +0000 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2024-01-25 13:45:14 +0000 |
commit | 7ad85d2bff6cc6b4b5e5541f0871985bb570d1ac (patch) | |
tree | ee92ec3bc3c0c3354b1b5df03720e9b2f21738fe /src | |
parent | 910e450ea7189bcd726d94374458867bfb15576d (diff) |
port-qmi: allow preallocated links when using rmnet multiplexing
A new ID_MM_QMI_PREALLOCATED_LINKS udev tag, set in the NET port of
the device, allows configuring the amount of preallocated multiplexed
links that need to be created upon the first connection attempt,
regardless of the multiplexing setup method used.
If not specified by the user, 4 preallocated links are created when
using the qmi_wwan multiplexing procedure, and none for rmnet.
Previously, using preallocated links was exclusive used with the
qmi_wwan multiplexing procedure. Using preallocated links may be
useful if you want to maintain the same links across multiple
connection and disconnection loops, e.g. if running a tcpdump on a
given link interface capturing all traffic (not using preallocated
links in this case would be problematic as tcpdump cannot be requested
to run on net interfaces that don't exist yet).
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-port-qmi.c | 188 |
1 files changed, 120 insertions, 68 deletions
diff --git a/src/mm-port-qmi.c b/src/mm-port-qmi.c index 2c608e96..f3c64464 100644 --- a/src/mm-port-qmi.c +++ b/src/mm-port-qmi.c @@ -29,8 +29,6 @@ #include "mm-modem-helpers-qmi.h" #include "mm-log-object.h" -#define DEFAULT_LINK_PREALLOCATED_AMOUNT 4 - /* as internally defined in the kernel */ #define RMNET_MAX_PACKET_SIZE 16384 #define MHI_NET_MTU_DEFAULT 16384 @@ -61,6 +59,7 @@ struct _MMPortQmiPrivate { GList *services; gchar *net_driver; gchar *net_sysfs_path; + guint net_preallocated_links_requested; #if defined WITH_QRTR QrtrNode *node; #endif @@ -79,6 +78,7 @@ struct _MMPortQmiPrivate { QmiWdaDataAggregationProtocol dap; guint max_multiplexed_links; /* preallocated links */ + guint preallocated_links_needed; MMPort *preallocated_links_main; GArray *preallocated_links; GList *preallocated_links_setup_pending; @@ -485,9 +485,11 @@ acquire_preallocated_link (MMPortQmi *self, /*****************************************************************************/ typedef struct { - QmiDevice *qmi_device; - MMPort *data; - GArray *preallocated_links; + QmiDevice *qmi_device; + gchar *link_prefix_hint; + QmiDeviceAddLinkFlags flags; + MMPort *data; + GArray *preallocated_links; } InitializePreallocatedLinksContext; static void @@ -497,6 +499,7 @@ initialize_preallocated_links_context_free (InitializePreallocatedLinksContext * delete_preallocated_links (ctx->qmi_device, ctx->preallocated_links); g_array_unref (ctx->preallocated_links); } + g_clear_pointer (&ctx->link_prefix_hint, g_free); g_object_unref (ctx->qmi_device); g_object_unref (ctx->data); g_slice_free (InitializePreallocatedLinksContext, ctx); @@ -517,16 +520,18 @@ device_add_link_preallocated_ready (QmiDevice *device, GAsyncResult *res, GTask *task) { + MMPortQmi *self; InitializePreallocatedLinksContext *ctx; GError *error = NULL; PreallocatedLinkInfo info = { NULL, 0, FALSE }; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); - info.link_name = qmi_device_add_link_finish (device, res, &info.mux_id, &error); + info.link_name = qmi_device_add_link_with_flags_finish (device, res, &info.mux_id, &error); if (!info.link_name) { g_prefix_error (&error, "failed to add preallocated link (%u/%u) for device: ", - ctx->preallocated_links->len + 1, DEFAULT_LINK_PREALLOCATED_AMOUNT); + ctx->preallocated_links->len + 1, self->priv->preallocated_links_needed); g_task_return_error (task, error); return; } @@ -551,25 +556,29 @@ initialize_preallocated_links_next (GTask *task) return; } - if (ctx->preallocated_links->len == DEFAULT_LINK_PREALLOCATED_AMOUNT) { + g_assert (self->priv->preallocated_links_needed > 0); + if (ctx->preallocated_links->len == (guint) self->priv->preallocated_links_needed) { g_task_return_pointer (task, g_steal_pointer (&ctx->preallocated_links), (GDestroyNotify)g_array_unref); g_object_unref (task); return; } - qmi_device_add_link (self->priv->qmi_device, - ctx->preallocated_links->len + 1, - mm_kernel_device_get_name (mm_port_peek_kernel_device (ctx->data)), - "ignored", /* n/a in qmi_wwan add_mux */ - NULL, - (GAsyncReadyCallback) device_add_link_preallocated_ready, - task); + qmi_device_add_link_with_flags (self->priv->qmi_device, + ctx->preallocated_links->len + 1, + mm_kernel_device_get_name (mm_port_peek_kernel_device (ctx->data)), + ctx->link_prefix_hint, + ctx->flags, + NULL, + (GAsyncReadyCallback) device_add_link_preallocated_ready, + task); } static void -initialize_preallocated_links (MMPortQmi *self, - GAsyncReadyCallback callback, - gpointer user_data) +initialize_preallocated_links (MMPortQmi *self, + const gchar *link_prefix_hint, + QmiDeviceAddLinkFlags flags, + GAsyncReadyCallback callback, + gpointer user_data) { InitializePreallocatedLinksContext *ctx; GTask *task; @@ -578,8 +587,10 @@ initialize_preallocated_links (MMPortQmi *self, ctx = g_slice_new0 (InitializePreallocatedLinksContext); ctx->qmi_device = g_object_ref (self->priv->qmi_device); + ctx->link_prefix_hint = g_strdup (link_prefix_hint); + ctx->flags = flags; ctx->data = g_object_ref (self->priv->preallocated_links_main); - ctx->preallocated_links = g_array_sized_new (FALSE, FALSE, sizeof (PreallocatedLinkInfo), DEFAULT_LINK_PREALLOCATED_AMOUNT); + ctx->preallocated_links = g_array_sized_new (FALSE, FALSE, sizeof (PreallocatedLinkInfo), self->priv->preallocated_links_needed); g_array_set_clear_func (ctx->preallocated_links, (GDestroyNotify)preallocated_link_info_clear); g_task_set_task_data (task, ctx, (GDestroyNotify)initialize_preallocated_links_context_free); @@ -771,21 +782,8 @@ mm_port_qmi_setup_link (MMPortQmi *self, ctx->mux_id = QMI_DEVICE_MUX_ID_UNBOUND; g_task_set_task_data (task, ctx, (GDestroyNotify) setup_link_context_free); - /* When using rmnet, just try to add link in the QmiDevice */ - if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) { - qmi_device_add_link_with_flags (self->priv->qmi_device, - QMI_DEVICE_MUX_ID_AUTOMATIC, - mm_kernel_device_get_name (mm_port_peek_kernel_device (data)), - link_prefix_hint, - get_rmnet_device_add_link_flags (self), - NULL, - (GAsyncReadyCallback) device_add_link_ready, - task); - return; - } - - /* For qmi_wwan, use preallocated links */ - if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_QMIWWAN) { + /* If we're requested to use preallocated links, do it right away */ + if (self->priv->preallocated_links_needed > 0) { if (self->priv->preallocated_links) { setup_preallocated_link (task); return; @@ -803,11 +801,26 @@ mm_port_qmi_setup_link (MMPortQmi *self, /* Store main to flag that we're initializing preallocated links */ self->priv->preallocated_links_main = g_object_ref (data); initialize_preallocated_links (self, + link_prefix_hint, + get_rmnet_device_add_link_flags (self), (GAsyncReadyCallback) initialize_preallocated_links_ready, task); return; } + /* No preallocated links required and using rmnet, just try to add link in the QmiDevice */ + if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) { + qmi_device_add_link_with_flags (self->priv->qmi_device, + QMI_DEVICE_MUX_ID_AUTOMATIC, + mm_kernel_device_get_name (mm_port_peek_kernel_device (data)), + link_prefix_hint, + get_rmnet_device_add_link_flags (self), + NULL, + (GAsyncReadyCallback) device_add_link_ready, + task); + return; + } + g_assert_not_reached (); } @@ -865,7 +878,17 @@ mm_port_qmi_cleanup_link (MMPortQmi *self, return; } - /* When using rmnet, just try to add link in the QmiDevice */ + /* If using preallocated links, just release one */ + if (self->priv->preallocated_links_needed > 0) { + if (!release_preallocated_link (self, link_name, mux_id, &error)) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + /* When using rmnet, just try to delete the link from the QmiDevice */ if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) { qmi_device_delete_link (self->priv->qmi_device, link_name, @@ -876,16 +899,6 @@ mm_port_qmi_cleanup_link (MMPortQmi *self, return; } - /* For qmi_wwan, use preallocated links */ - if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_QMIWWAN) { - if (!release_preallocated_link (self, link_name, mux_id, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - g_assert_not_reached (); } @@ -1213,6 +1226,7 @@ load_supported_kernel_data_modes (MMPortQmi *self, /*****************************************************************************/ +#define DEFAULT_QMI_WWAN_PREALLOCATED_LINKS 4 #define DEFAULT_DOWNLINK_DATA_AGGREGATION_MAX_SIZE 32768 #define DEFAULT_DOWNLINK_DATA_AGGREGATION_MAX_SIZE_QMI_WWAN_RMNET 16384 #define DEFAULT_DOWNLINK_DATA_AGGREGATION_MAX_DATAGRAMS 32 @@ -1300,6 +1314,57 @@ internal_setup_data_format_context_free (InternalSetupDataFormatContext *ctx) g_slice_free (InternalSetupDataFormatContext, ctx); } +static void +internal_setup_data_format_propagate_link_setup (GTask *task, + guint *out_max_multiplexed_links, + guint *out_preallocated_links) +{ + MMPortQmi *self; + InternalSetupDataFormatContext *ctx; + guint max_multiplexed_links; + guint preallocated_links; + + if (!out_max_multiplexed_links && !out_preallocated_links) + return; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + if (!ctx->wda_dap_supported) { + max_multiplexed_links = 0; + preallocated_links = 0; + mm_obj_dbg (self, "wda data aggregation protocol unsupported: no multiplexed bearers allowed"); + } else { + /* if multiplex backend may be rmnet, MAX-MIN */ + if (ctx->kernel_data_modes_supported & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) { + max_multiplexed_links = 1 + (QMI_DEVICE_MUX_ID_MAX - QMI_DEVICE_MUX_ID_MIN); + preallocated_links = (self->priv->net_preallocated_links_requested > max_multiplexed_links) ? + max_multiplexed_links : + self->priv->net_preallocated_links_requested; + mm_obj_dbg (self, "rmnet link management supported: %u multiplexed bearers allowed, %u links preallocated", + max_multiplexed_links, preallocated_links); + } + /* if multiplex backend may be qmi_wwan, the max preallocated amount :/ */ + else if (ctx->kernel_data_modes_supported & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_QMIWWAN) { + preallocated_links = (self->priv->net_preallocated_links_requested > 0) ? + self->priv->net_preallocated_links_requested : + DEFAULT_QMI_WWAN_PREALLOCATED_LINKS; + max_multiplexed_links = preallocated_links; + mm_obj_dbg (self, "qmi_wwan link management supported: %u multiplexed bearers allowed, %u links preallocated", + max_multiplexed_links, preallocated_links); + } else { + max_multiplexed_links = 0; + preallocated_links = 0; + mm_obj_dbg (self, "link management unsupported: no multiplexed bearers allowed"); + } + } + + if (out_max_multiplexed_links) + *out_max_multiplexed_links = max_multiplexed_links; + if (out_preallocated_links) + *out_preallocated_links = preallocated_links; +} + static gboolean internal_setup_data_format_finish (MMPortQmi *self, GAsyncResult *res, @@ -1307,6 +1372,7 @@ internal_setup_data_format_finish (MMPortQmi *self, QmiWdaLinkLayerProtocol *out_llp, QmiWdaDataAggregationProtocol *out_dap, guint *out_max_multiplexed_links, + guint *out_preallocated_links, GError **error) { InternalSetupDataFormatContext *ctx; @@ -1320,28 +1386,9 @@ internal_setup_data_format_finish (MMPortQmi *self, g_assert (ctx->wda_dl_dap_current == ctx->wda_ul_dap_current); *out_dap = ctx->wda_dl_dap_current; - if (out_max_multiplexed_links) { - if (!ctx->wda_dap_supported) { - *out_max_multiplexed_links = 0; - mm_obj_dbg (self, "wda data aggregation protocol unsupported: no multiplexed bearers allowed"); - } else { - /* if multiplex backend may be rmnet, MAX-MIN */ - if (ctx->kernel_data_modes_supported & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) { - *out_max_multiplexed_links = 1 + (QMI_DEVICE_MUX_ID_MAX - QMI_DEVICE_MUX_ID_MIN); - mm_obj_dbg (self, "rmnet link management supported: %u multiplexed bearers allowed", - *out_max_multiplexed_links); - } - /* if multiplex backend may be qmi_wwan, the max preallocated amount :/ */ - else if (ctx->kernel_data_modes_supported & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_QMIWWAN) { - *out_max_multiplexed_links = DEFAULT_LINK_PREALLOCATED_AMOUNT; - mm_obj_dbg (self, "qmi_wwan link management supported: %u multiplexed bearers allowed", - *out_max_multiplexed_links); - } else { - *out_max_multiplexed_links = 0; - mm_obj_dbg (self, "link management unsupported: no multiplexed bearers allowed"); - } - } - } + internal_setup_data_format_propagate_link_setup (G_TASK (res), + out_max_multiplexed_links, + out_preallocated_links); return TRUE; } @@ -2076,6 +2123,7 @@ internal_setup_data_format_ready (MMPortQmi *self, &self->priv->llp, &self->priv->dap, NULL, /* not expected to update */ + NULL, /* not expected to update */ &error)) g_task_return_error (task, error); else { @@ -2375,6 +2423,7 @@ open_internal_setup_data_format_ready (MMPortQmi *self, &self->priv->llp, &self->priv->dap, &self->priv->max_multiplexed_links, + &self->priv->preallocated_links_needed, &error)) { /* Continue with fallback to LLP requested via CTL */ mm_obj_warn (self, "Couldn't setup data format: %s", error->message); @@ -2671,6 +2720,9 @@ mm_port_qmi_set_net_details (MMPortQmi *self, g_assert (!self->priv->net_sysfs_path); self->priv->net_sysfs_path = g_strdup (mm_kernel_device_get_sysfs_path (first_net_dev)); + g_assert (!self->priv->net_preallocated_links_requested); + self->priv->net_preallocated_links_requested = mm_kernel_device_get_global_property_as_int (first_net_dev, "ID_MM_QMI_PREALLOCATED_LINKS"); + initialize_endpoint_info (self); } |