diff options
author | Thomas Vogt <acc-github@tovotu.de> | 2024-06-28 15:07:51 +0200 |
---|---|---|
committer | Thomas Vogt <acc-github@tovotu.de> | 2025-05-09 07:31:31 +0200 |
commit | 4cae0406452ef4621aa7cc73f9d7a54db2ca0fb1 (patch) | |
tree | e7331cd0736ab0d005717e76bfb0f3351e6f9b74 /src/plugins/intel/mm-bearer-xmm7360.c | |
parent | d165d61a9515061837ac12054d15dbeaeb134adf (diff) |
intel: implement support for RPC-powered xmm7360
Signed-off-by: Thomas Vogt <acc-github@tovotu.de>
Diffstat (limited to 'src/plugins/intel/mm-bearer-xmm7360.c')
-rw-r--r-- | src/plugins/intel/mm-bearer-xmm7360.c | 766 |
1 files changed, 766 insertions, 0 deletions
diff --git a/src/plugins/intel/mm-bearer-xmm7360.c b/src/plugins/intel/mm-bearer-xmm7360.c new file mode 100644 index 00000000..10dd2c26 --- /dev/null +++ b/src/plugins/intel/mm-bearer-xmm7360.c @@ -0,0 +1,766 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2019 James Wah + * Copyright (C) 2020 Marinus Enzinger <marinus@enzingerm.de> + * Copyright (C) 2023 Shane Parslow + * Copyright (C) 2024 Thomas Vogt + */ + +#include <ModemManager.h> +#define _LIBMM_INSIDE_MM +#include <libmm-glib.h> + +#include "mm-log-object.h" + +#include "mm-bearer-xmm7360.h" +#include "mm-broadband-modem-xmm7360.h" +#include "mm-broadband-modem-xmm7360-rpc.h" +#include "mm-port-serial-xmmrpc-xmm7360.h" + +G_DEFINE_TYPE (MMBearerXmm7360, mm_bearer_xmm7360, MM_TYPE_BASE_BEARER) + +struct _MMBearerXmm7360Private { + gboolean is_connected; +}; + +/*****************************************************************************/ +/* Connect */ + +typedef struct { + MMPort *data; + MMPortSerialXmmrpcXmm7360 *port; + guint unsol_handler_id; + gboolean is_attach_allowed; + gboolean is_attached; + guint attach_attempts; + guint attach_allowed_timeout_id; + Xmm7360RpcResponse *ps_connect_response; + GInetAddress *ip; + GPtrArray *dns; +} ConnectContext; + +static void +connect_context_free (ConnectContext *ctx) +{ + if (ctx->ps_connect_response) + xmm7360_rpc_response_free (ctx->ps_connect_response); + if (ctx->attach_allowed_timeout_id) + g_source_remove (ctx->attach_allowed_timeout_id); + if (ctx->unsol_handler_id) { + mm_port_serial_xmmrpc_xmm7360_enable_unsolicited_msg_handler ( + ctx->port, + ctx->unsol_handler_id, + FALSE); + } + g_clear_object (&ctx->ip); + if (ctx->dns) + g_ptr_array_free (ctx->dns, TRUE); + mm_port_serial_close (MM_PORT_SERIAL (ctx->port)); + g_clear_object (&ctx->port); + g_clear_object (&ctx->data); + g_slice_free (ConnectContext, ctx); +} + +static MMBearerConnectResult * +connect_finish (MMBaseBearer *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +xmm7360_connect_apn_ready (MMBroadbandModemXmm7360 *modem, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + MMBearerXmm7360 *self; + MMBearerConnectResult *connect_result; + + self = g_task_get_source_object (task); + + connect_result = g_task_propagate_pointer (G_TASK (res), &error); + if (error) { + g_task_return_error (task, error); + } else { + self->priv->is_connected = TRUE; + g_task_return_pointer (task, + connect_result, + (GDestroyNotify)mm_bearer_connect_result_unref); + } + g_object_unref (task); +} + +static void +ps_connect_setup_ready (MMBroadbandModemXmm7360 *modem, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + ConnectContext *ctx; + g_autoptr(Xmm7360RpcResponse) response = NULL; + g_autoptr(MMBearerIpConfig) ip_config = NULL; + g_autofree gchar *ipaddr = NULL; + g_auto(GStrv) dnsaddrs = NULL; + GInetAddress *dns; + guint i; + guint n; + + ctx = g_task_get_task_data (task); + + response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error); + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + /* we get static IPs to set */ + ip_config = mm_bearer_ip_config_new (); + ipaddr = g_inet_address_to_string (ctx->ip); + dnsaddrs = g_new0 (gchar *, ctx->dns->len + 1); + for (i = 0, n = 0; i < ctx->dns->len; i++) { + dns = g_ptr_array_index (ctx->dns, i); + if (g_inet_address_get_family (dns) == G_SOCKET_FAMILY_IPV4 + && !g_inet_address_get_is_any (dns)) { + dnsaddrs[n++] = g_inet_address_to_string (dns); + } + } + mm_bearer_ip_config_set_method (ip_config, MM_BEARER_IP_METHOD_STATIC); + mm_bearer_ip_config_set_address (ip_config, ipaddr); + mm_bearer_ip_config_set_dns (ip_config, (const gchar **)dnsaddrs); + + g_task_return_pointer (task, + mm_bearer_connect_result_new (ctx->data, ip_config, NULL), + (GDestroyNotify)mm_bearer_connect_result_unref); + g_object_unref (task); +} + +static void +ps_connect_to_datachannel_ready (MMBroadbandModemXmm7360 *modem, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + ConnectContext *ctx; + g_autoptr(Xmm7360RpcResponse) response = NULL; + g_autoptr(GByteArray) connect_setup_body = NULL; + + ctx = g_task_get_task_data (task); + + response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error); + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + connect_setup_body = g_byte_array_new (); + g_byte_array_append (connect_setup_body, + ctx->ps_connect_response->body->data, + ctx->ps_connect_response->body->len - 6); + g_byte_array_append (connect_setup_body, + response->body->data, + response->body->len); + xmm7360_byte_array_append_asn_int4 (connect_setup_body, 0); + + mm_broadband_modem_xmm7360_rpc_command_full (modem, + ctx->port, + XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_SETUP_REQ, + FALSE, + connect_setup_body, + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)ps_connect_setup_ready, + task); +} + +static GByteArray * +pack_uta_rpc_ps_connect_to_datachannel_req (void) +{ + static const Xmm7360RpcMsgArg args[] = { + /* size is length of string + null byte */ + { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = "/sioscc/PCIE/IOSM/IPS/0" }, 24 }, + { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN }, + }; + return xmm7360_rpc_args_to_byte_array (args); +} + +static void +ps_connect_ready (MMBroadbandModemXmm7360 *modem, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + ConnectContext *ctx; + Xmm7360RpcResponse *response = NULL; + g_autoptr(GByteArray) body = NULL; + + ctx = g_task_get_task_data (task); + + response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error); + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + xmm7360_rpc_response_free (response); + return; + } + + ctx->ps_connect_response = response; + + body = pack_uta_rpc_ps_connect_to_datachannel_req (); + + mm_broadband_modem_xmm7360_rpc_command_full (modem, + ctx->port, + XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_TO_DATACHANNEL_REQ, + FALSE, + body, + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)ps_connect_to_datachannel_ready, + task); +} + +static GByteArray * +pack_uta_ms_call_ps_connect_req (void) +{ + static const Xmm7360RpcMsgArg args[] = { + { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 6 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN }, + }; + return xmm7360_rpc_args_to_byte_array (args); +} + +static void +get_dns_ready (MMBroadbandModemXmm7360 *modem, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + ConnectContext *ctx; + g_autoptr(Xmm7360RpcResponse) response = NULL; + Xmm7360RpcMsgArg *arg; + guint i; + g_autoptr(GByteArray) body = NULL; + + ctx = g_task_get_task_data (task); + + response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error); + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + for (i = 1; i < 17; i += 2) { + /* iterate over pairs of args: IP [i] and IP format (v4(1) or v6(2) or MISSING(0)) [i+1] */ + arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, i + 1); + if (XMM7360_RPC_MSG_ARG_GET_INT (arg) == 1) { + arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, i); + g_assert (arg->size >= 4); + g_ptr_array_add (ctx->dns, g_inet_address_new_from_bytes ((const guint8 *)arg->value.string, + G_SOCKET_FAMILY_IPV4)); + } else if (XMM7360_RPC_MSG_ARG_GET_INT (arg) == 2) { + arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, i); + g_assert (arg->size >= 16); + g_ptr_array_add (ctx->dns, g_inet_address_new_from_bytes ((const guint8 *)arg->value.string, + G_SOCKET_FAMILY_IPV6)); + } + } + + body = pack_uta_ms_call_ps_connect_req (); + + mm_broadband_modem_xmm7360_rpc_command_full (modem, + ctx->port, + XMM7360_RPC_CALL_UTA_MS_CALL_PS_CONNECT_REQ, + TRUE, + body, + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)ps_connect_ready, + task); +} + +static GByteArray * +pack_uta_ms_call_ps_get_negotiated_dns_req (void) +{ + static const Xmm7360RpcMsgArg args[] = { + { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN }, + }; + return xmm7360_rpc_args_to_byte_array (args); +} + +static void +get_ip_addr_ready (MMBroadbandModemXmm7360 *modem, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + ConnectContext *ctx; + g_autoptr(Xmm7360RpcResponse) response = NULL; + Xmm7360RpcMsgArg *arg; + gint i; + guint32 *ip_bytes; + g_autoptr(GByteArray) body = NULL; + + ctx = g_task_get_task_data (task); + + response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error); + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 1); + if (arg->size < 12) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "The IP address field is invalid (too short)"); + g_object_unref (task); + return; + } + + /* the STRING arg contains three IP addresses, we only use the last non-zero address */ + ip_bytes = (guint32 *)arg->value.string; + for (i = 2; i >= 0; i--) { + if (ip_bytes[i] != 0) { + ctx->ip = g_inet_address_new_from_bytes ((const guint8 *)&ip_bytes[i], + G_SOCKET_FAMILY_IPV4); + break; + } + } + + if (ctx->ip == NULL) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "The IP address field is invalid (all zeros)"); + g_object_unref (task); + return; + } + + body = pack_uta_ms_call_ps_get_negotiated_dns_req (); + + mm_broadband_modem_xmm7360_rpc_command_full (modem, + ctx->port, + XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_NEGOTIATED_DNS_REQ, + TRUE, + body, + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)get_dns_ready, + task); +} + +static GByteArray * +pack_uta_ms_call_ps_get_neg_ip_addr_req (void) +{ + static const Xmm7360RpcMsgArg args[] = { + { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN }, + }; + return xmm7360_rpc_args_to_byte_array (args); +} + +static gboolean +get_ip_config (GTask *task) +{ + ConnectContext *ctx; + MMBroadbandModemXmm7360 *modem; + g_autoptr(GByteArray) body = NULL; + + if (g_cancellable_is_cancelled (g_task_get_cancellable (task))) { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "operation has been cancelled"); + g_object_unref (task); + return G_SOURCE_REMOVE; + } + + ctx = g_task_get_task_data (task); + + modem = g_task_get_source_object (task); + + body = pack_uta_ms_call_ps_get_neg_ip_addr_req (); + + mm_broadband_modem_xmm7360_rpc_command_full (modem, + ctx->port, + XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_NEG_IP_ADDR_REQ, + TRUE, + body, + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)get_ip_addr_ready, + task); + + return G_SOURCE_REMOVE; +} + +static gboolean +attach_allowed_timeout_cb (GTask *task) +{ + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Connecting timed out (waiting for attach-allowed)"); + g_object_unref (task); + return G_SOURCE_REMOVE; +} + +static void net_attach_command (GTask *task); + +static void +net_attach_command_ready (MMBroadbandModemXmm7360 *modem, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + ConnectContext *ctx; + g_autoptr(Xmm7360RpcResponse) response = NULL; + Xmm7360RpcMsgArg *arg; + gint status; + + ctx = g_task_get_task_data (task); + + response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error); + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (response->content->len < 2) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "The response for net-attach is invalid (too short)"); + g_object_unref (task); + return; + } + + /* status code */ + arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 1); + g_assert (arg->type == XMM7360_RPC_MSG_ARG_TYPE_LONG); + status = XMM7360_RPC_MSG_ARG_GET_INT (arg); + + if (status != (gint32)0xffffffff) { + ctx->is_attached = TRUE; + /* give the modem a second before requesting the IP */ + g_timeout_add_seconds (1, (GSourceFunc)get_ip_config, task); + } else if (ctx->is_attach_allowed && ctx->attach_attempts < 2) { + /* immediately try a second time if it should have been allowed */ + ctx->is_attach_allowed = FALSE; + net_attach_command (task); + } else if (ctx->attach_attempts < 3) { + /* give up if we do not receive an attach-allowed unsolicited message within 5 seconds */ + ctx->attach_allowed_timeout_id = g_timeout_add_seconds (5, (GSourceFunc)attach_allowed_timeout_cb, task); + } else { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Giving up on attach-net operation after three failed attempts"); + g_object_unref (task); + } +} + +static GByteArray * +pack_uta_ms_net_attach_req (void) +{ + static const Xmm7360RpcMsgArg args[] = { + { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_SHORT, { .s = 0xffff } }, + { XMM7360_RPC_MSG_ARG_TYPE_SHORT, { .s = 0xffff } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN }, + }; + return xmm7360_rpc_args_to_byte_array (args); +} + +static void +net_attach_command (GTask *task) +{ + ConnectContext *ctx; + MMBroadbandModemXmm7360 *modem; + g_autoptr(GByteArray) body = NULL; + + ctx = g_task_get_task_data (task); + ctx->attach_attempts++; + + modem = g_task_get_source_object (task); + + body = pack_uta_ms_net_attach_req (); + + mm_broadband_modem_xmm7360_rpc_command_full (modem, + ctx->port, + XMM7360_RPC_CALL_UTA_MS_NET_ATTACH_REQ, + TRUE, + body, + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)net_attach_command_ready, + task); +} + +static gboolean +connect_unsol_handler (MMPortSerialXmmrpcXmm7360 *port, + Xmm7360RpcResponse *response, + GTask *task) +{ + Xmm7360RpcMsgArg *arg; + ConnectContext *ctx; + + if (response->unsol_id != XMM7360_RPC_UNSOL_UTA_MS_NET_IS_ATTACH_ALLOWED_IND_CB) { + return FALSE; + } + + if (response->content->len <= 2) { + mm_obj_dbg (port, "Ignoring invalid is-attach-allowed message (too short)"); + return TRUE; + } + + ctx = g_task_get_task_data (task); + + if (ctx->is_attached) { + /* already attached, ignore the attach-allowed status message */ + return TRUE; + } + + arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 2); + if (XMM7360_RPC_MSG_ARG_GET_INT (arg)) { + ctx->is_attach_allowed = TRUE; + if (ctx->attach_allowed_timeout_id) { + g_source_remove (ctx->attach_allowed_timeout_id); + ctx->attach_allowed_timeout_id = 0; + /* attach-net is allowed now, retry */ + net_attach_command (task); + } + } + + return TRUE; +} + +static void +xmm7360_connect (MMBroadbandModemXmm7360 *modem, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GError *error = NULL; + GTask *task; + ConnectContext *ctx; + + task = g_task_new (modem, cancellable, callback, user_data); + + ctx = g_slice_new0 (ConnectContext); + ctx->port = mm_broadband_modem_xmm7360_get_port_xmmrpc (modem); + ctx->dns = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + g_task_set_task_data (task, ctx, (GDestroyNotify)connect_context_free); + + /* Grab a data port */ + ctx->data = mm_base_modem_get_best_data_port (MM_BASE_MODEM (modem), MM_PORT_TYPE_NET); + if (!ctx->data) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND, + "No valid data port found to launch connection"); + g_object_unref (task); + return; + } + + /* Open XMMRPC port for initialization */ + if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->port), &error)) { + g_prefix_error (&error, "Couldn't open XMMRPC port for connection setup: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + ctx->unsol_handler_id = mm_port_serial_xmmrpc_xmm7360_add_unsolicited_msg_handler ( + ctx->port, + (MMPortSerialXmmrpcXmm7360UnsolicitedMsgFn)connect_unsol_handler, + task, + NULL); + + net_attach_command (task); +} + +static void +connect (MMBaseBearer *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + g_autoptr(MMBaseModem) modem = NULL; + + /* Get the owner modem object */ + g_object_get (self, + MM_BASE_BEARER_MODEM, &modem, + NULL); + g_assert (modem != NULL); + + task = g_task_new (self, cancellable, callback, user_data); + + /* the connect routine is independent of the bearer object */ + xmm7360_connect (MM_BROADBAND_MODEM_XMM7360 (modem), + cancellable, + (GAsyncReadyCallback)xmm7360_connect_apn_ready, + task); +} + +/*****************************************************************************/ +/* Disconnect */ + +static gboolean +disconnect_finish (MMBaseBearer *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +disconnect_sequence_ready (MMBroadbandModem *modem, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + g_autoptr(Xmm7360RpcResponse) response = NULL; + + response = mm_broadband_modem_xmm7360_rpc_sequence_finish (MM_BROADBAND_MODEM_XMM7360 (modem), + res, + &error); + + if (error) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Failed to complete disconnect sequence: %s", error->message); + g_object_unref (task); + return; + } + + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static const MMBroadbandModemXmm7360RpcCommand disconnect_sequence[] = { + { + XMM7360_RPC_CALL_UTA_MS_CALL_PS_DEACTIVATE_REQ, + TRUE, + (Xmm7360RpcMsgArg[]) { + { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } }, + { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN }, + }, + 3, + FALSE, + mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success + /* response will be: L(0x0) L(0x0) L(0x5dffffff) L(0x0) (meaning unknown) */ + }, + { + XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_RELEASE_REQ, + FALSE, + (Xmm7360RpcMsgArg[]) { + /* the meaning of this value is unknown, but it is used by the Windows driver */ + { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0x20017 } }, + { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN }, + }, + 3, + FALSE, + mm_broadband_modem_xmm7360_rpc_response_processor_final + /* response will be: L(0x0) (meaning unknown) */ + }, + { 0 } +}; + +static void +disconnect (MMBaseBearer *bearer, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + g_autoptr(MMBaseModem) modem = NULL; + g_autoptr(MMPortSerialXmmrpcXmm7360) port = NULL; + + task = g_task_new (bearer, NULL, callback, user_data); + + /* Get the owner modem object */ + g_object_get (bearer, MM_BASE_BEARER_MODEM, &modem, NULL); + g_assert (modem != NULL); + + port = mm_broadband_modem_xmm7360_get_port_xmmrpc (MM_BROADBAND_MODEM_XMM7360 (modem)); + + mm_broadband_modem_xmm7360_rpc_sequence_full (MM_BROADBAND_MODEM_XMM7360 (modem), + port, + disconnect_sequence, + NULL, /* cancellable */ + (GAsyncReadyCallback)disconnect_sequence_ready, + task); +} + +/*****************************************************************************/ + +MMBaseBearer * +mm_bearer_xmm7360_new (MMBroadbandModemXmm7360 *modem, + MMBearerProperties *config) +{ + MMBaseBearer *base_bearer; + MMBearerXmm7360 *bearer; + + /* The Xmm7360 bearer inherits from MMBaseBearer (so it's not a MMBroadbandBearer) + * and that means that the object is not async-initable, so we just use + * g_object_new here */ + bearer = g_object_new (MM_TYPE_BEARER_XMM7360, + MM_BASE_BEARER_MODEM, modem, + MM_BASE_BEARER_CONFIG, config, + NULL); + + base_bearer = MM_BASE_BEARER (bearer); + /* Only export valid bearers */ + mm_base_bearer_export (base_bearer); + + return base_bearer; +} + +static void +mm_bearer_xmm7360_init (MMBearerXmm7360 *self) +{ + /* Initialize private data */ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + MM_TYPE_BEARER_XMM7360, + MMBearerXmm7360Private); +} + +static void +mm_bearer_xmm7360_class_init (MMBearerXmm7360Class *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMBearerXmm7360Private)); + + base_bearer_class->connect = connect; + base_bearer_class->connect_finish = connect_finish; + + base_bearer_class->disconnect = disconnect; + base_bearer_class->disconnect_finish = disconnect_finish; +} |