bearer-mbim: implement bearer connection
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
#define _LIBMM_INSIDE_MM
|
#define _LIBMM_INSIDE_MM
|
||||||
#include <libmm-glib.h>
|
#include <libmm-glib.h>
|
||||||
|
|
||||||
|
#include "mm-modem-helpers-mbim.h"
|
||||||
#include "mm-serial-enums-types.h"
|
#include "mm-serial-enums-types.h"
|
||||||
#include "mm-bearer-mbim.h"
|
#include "mm-bearer-mbim.h"
|
||||||
#include "mm-log.h"
|
#include "mm-log.h"
|
||||||
@@ -33,7 +34,8 @@
|
|||||||
G_DEFINE_TYPE (MMBearerMbim, mm_bearer_mbim, MM_TYPE_BEARER);
|
G_DEFINE_TYPE (MMBearerMbim, mm_bearer_mbim, MM_TYPE_BEARER);
|
||||||
|
|
||||||
struct _MMBearerMbimPrivate {
|
struct _MMBearerMbimPrivate {
|
||||||
gpointer dummy;
|
guint32 session_id;
|
||||||
|
MMPort *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -99,6 +101,7 @@ peek_ports (gpointer self,
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
CONNECT_STEP_FIRST,
|
CONNECT_STEP_FIRST,
|
||||||
CONNECT_STEP_PROVISIONED_CONTEXTS,
|
CONNECT_STEP_PROVISIONED_CONTEXTS,
|
||||||
|
CONNECT_STEP_CONNECT,
|
||||||
CONNECT_STEP_LAST
|
CONNECT_STEP_LAST
|
||||||
} ConnectStep;
|
} ConnectStep;
|
||||||
|
|
||||||
@@ -110,6 +113,7 @@ typedef struct {
|
|||||||
MMBearerProperties *properties;
|
MMBearerProperties *properties;
|
||||||
ConnectStep step;
|
ConnectStep step;
|
||||||
MMPort *data;
|
MMPort *data;
|
||||||
|
MMBearerConnectResult *connect_result;
|
||||||
} ConnectContext;
|
} ConnectContext;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -117,6 +121,8 @@ connect_context_complete_and_free (ConnectContext *ctx)
|
|||||||
{
|
{
|
||||||
g_simple_async_result_complete_in_idle (ctx->result);
|
g_simple_async_result_complete_in_idle (ctx->result);
|
||||||
g_object_unref (ctx->result);
|
g_object_unref (ctx->result);
|
||||||
|
if (ctx->connect_result)
|
||||||
|
mm_bearer_connect_result_unref (ctx->connect_result);
|
||||||
g_object_unref (ctx->data);
|
g_object_unref (ctx->data);
|
||||||
g_object_unref (ctx->cancellable);
|
g_object_unref (ctx->cancellable);
|
||||||
g_object_unref (ctx->device);
|
g_object_unref (ctx->device);
|
||||||
@@ -138,7 +144,77 @@ connect_finish (MMBearer *self,
|
|||||||
static void connect_context_step (ConnectContext *ctx);
|
static void connect_context_step (ConnectContext *ctx);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
provisioned_contexts_query (MbimDevice *device,
|
connect_set_ready (MbimDevice *device,
|
||||||
|
GAsyncResult *res,
|
||||||
|
ConnectContext *ctx)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
MbimMessage *response;
|
||||||
|
guint32 session_id;
|
||||||
|
MbimActivationState activation_state;
|
||||||
|
MbimContextIpType ip_type;
|
||||||
|
guint32 nw_error;
|
||||||
|
|
||||||
|
response = mbim_device_command_finish (device, res, &error);
|
||||||
|
if (response &&
|
||||||
|
mbim_message_command_done_get_result (response, &error) &&
|
||||||
|
mbim_message_connect_response_parse (
|
||||||
|
response,
|
||||||
|
&session_id,
|
||||||
|
&activation_state,
|
||||||
|
NULL, /* voice_call_state */
|
||||||
|
&ip_type,
|
||||||
|
NULL, /* context_type */
|
||||||
|
&nw_error,
|
||||||
|
&error)) {
|
||||||
|
if (nw_error)
|
||||||
|
error = mm_mobile_equipment_error_from_mbim_nw_error (nw_error);
|
||||||
|
else {
|
||||||
|
MMBearerIpConfig *ipv4_config = NULL;
|
||||||
|
MMBearerIpConfig *ipv6_config = NULL;
|
||||||
|
|
||||||
|
mm_dbg ("Session ID '%u': %s (IP type: %s)",
|
||||||
|
session_id,
|
||||||
|
mbim_activation_state_get_string (activation_state),
|
||||||
|
mbim_context_ip_type_get_string (ip_type));
|
||||||
|
|
||||||
|
/* Build IPv4 config; always DHCP based */
|
||||||
|
if (ip_type == MBIM_CONTEXT_IP_TYPE_IPV4 ||
|
||||||
|
ip_type == MBIM_CONTEXT_IP_TYPE_IPV4V6 ||
|
||||||
|
ip_type == MBIM_CONTEXT_IP_TYPE_IPV4_AND_IPV6) {
|
||||||
|
ipv4_config = mm_bearer_ip_config_new ();
|
||||||
|
mm_bearer_ip_config_set_method (ipv4_config, MM_BEARER_IP_METHOD_DHCP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build IPv6 config; always DHCP based */
|
||||||
|
if (ip_type == MBIM_CONTEXT_IP_TYPE_IPV6 ||
|
||||||
|
ip_type == MBIM_CONTEXT_IP_TYPE_IPV4V6 ||
|
||||||
|
ip_type == MBIM_CONTEXT_IP_TYPE_IPV4_AND_IPV6) {
|
||||||
|
ipv6_config = mm_bearer_ip_config_new ();
|
||||||
|
mm_bearer_ip_config_set_method (ipv6_config, MM_BEARER_IP_METHOD_DHCP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store result */
|
||||||
|
ctx->connect_result = (mm_bearer_connect_result_new (
|
||||||
|
ctx->data,
|
||||||
|
ipv4_config,
|
||||||
|
ipv6_config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
g_simple_async_result_take_error (ctx->result, error);
|
||||||
|
connect_context_complete_and_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep on */
|
||||||
|
ctx->step++;
|
||||||
|
connect_context_step (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
provisioned_contexts_query_ready (MbimDevice *device,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
ConnectContext *ctx)
|
ConnectContext *ctx)
|
||||||
{
|
{
|
||||||
@@ -187,6 +263,8 @@ provisioned_contexts_query (MbimDevice *device,
|
|||||||
static void
|
static void
|
||||||
connect_context_step (ConnectContext *ctx)
|
connect_context_step (ConnectContext *ctx)
|
||||||
{
|
{
|
||||||
|
MbimMessage *message;
|
||||||
|
|
||||||
/* If cancelled, complete */
|
/* If cancelled, complete */
|
||||||
if (g_cancellable_is_cancelled (ctx->cancellable)) {
|
if (g_cancellable_is_cancelled (ctx->cancellable)) {
|
||||||
g_simple_async_result_set_error (ctx->result,
|
g_simple_async_result_set_error (ctx->result,
|
||||||
@@ -202,78 +280,128 @@ connect_context_step (ConnectContext *ctx)
|
|||||||
/* Fall down */
|
/* Fall down */
|
||||||
ctx->step++;
|
ctx->step++;
|
||||||
|
|
||||||
case CONNECT_STEP_PROVISIONED_CONTEXTS: {
|
case CONNECT_STEP_PROVISIONED_CONTEXTS:
|
||||||
MbimMessage *message;
|
mm_dbg ("Listing provisioned contexts...");
|
||||||
|
|
||||||
message = mbim_message_provisioned_contexts_query_new (NULL);
|
message = mbim_message_provisioned_contexts_query_new (NULL);
|
||||||
mbim_device_command (ctx->device,
|
mbim_device_command (ctx->device,
|
||||||
message,
|
message,
|
||||||
10,
|
10,
|
||||||
NULL,
|
NULL,
|
||||||
(GAsyncReadyCallback)provisioned_contexts_query,
|
(GAsyncReadyCallback)provisioned_contexts_query_ready,
|
||||||
|
ctx);
|
||||||
|
mbim_message_unref (message);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case CONNECT_STEP_CONNECT: {
|
||||||
|
const gchar *apn;
|
||||||
|
const gchar *user;
|
||||||
|
const gchar *password;
|
||||||
|
MbimAuthProtocol auth;
|
||||||
|
MMBearerAllowedAuth bearer_auth;
|
||||||
|
MbimContextIpType ip_type;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
/* Setup parameters to use */
|
||||||
|
|
||||||
|
apn = mm_bearer_properties_get_apn (ctx->properties);
|
||||||
|
user = mm_bearer_properties_get_user (ctx->properties);
|
||||||
|
password = mm_bearer_properties_get_password (ctx->properties);
|
||||||
|
|
||||||
|
bearer_auth = mm_bearer_properties_get_allowed_auth (ctx->properties);
|
||||||
|
if (bearer_auth == MM_BEARER_ALLOWED_AUTH_UNKNOWN) {
|
||||||
|
mm_dbg ("Using default (PAP) authentication method");
|
||||||
|
auth = MBIM_AUTH_PROTOCOL_PAP;
|
||||||
|
} else if (bearer_auth & MM_BEARER_ALLOWED_AUTH_PAP) {
|
||||||
|
auth = MBIM_AUTH_PROTOCOL_PAP;
|
||||||
|
} else if (bearer_auth & MM_BEARER_ALLOWED_AUTH_CHAP) {
|
||||||
|
auth = MBIM_AUTH_PROTOCOL_CHAP;
|
||||||
|
} else if (bearer_auth & MM_BEARER_ALLOWED_AUTH_MSCHAPV2) {
|
||||||
|
auth = MBIM_AUTH_PROTOCOL_MSCHAPV2;
|
||||||
|
} else if (bearer_auth & MM_BEARER_ALLOWED_AUTH_NONE) {
|
||||||
|
auth = MBIM_AUTH_PROTOCOL_NONE;
|
||||||
|
} else {
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
str = mm_bearer_allowed_auth_build_string_from_mask (bearer_auth);
|
||||||
|
g_simple_async_result_set_error (
|
||||||
|
ctx->result,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_UNSUPPORTED,
|
||||||
|
"Cannot use any of the specified authentication methods (%s)",
|
||||||
|
str);
|
||||||
|
g_free (str);
|
||||||
|
connect_context_complete_and_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mm_bearer_properties_get_ip_type (ctx->properties)) {
|
||||||
|
case MM_BEARER_IP_FAMILY_IPV4:
|
||||||
|
ip_type = MBIM_CONTEXT_IP_TYPE_IPV4;
|
||||||
|
break;
|
||||||
|
case MM_BEARER_IP_FAMILY_IPV6:
|
||||||
|
ip_type = MBIM_CONTEXT_IP_TYPE_IPV6;
|
||||||
|
break;
|
||||||
|
case MM_BEARER_IP_FAMILY_IPV4V6:
|
||||||
|
ip_type = MBIM_CONTEXT_IP_TYPE_IPV4V6;
|
||||||
|
break;
|
||||||
|
case MM_BEARER_IP_FAMILY_UNKNOWN:
|
||||||
|
default:
|
||||||
|
mm_dbg ("No specific IP family requested, defaulting to IPv4");
|
||||||
|
ip_type = MBIM_CONTEXT_IP_TYPE_IPV4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_dbg ("Launching connection with APN '%s'...", apn);
|
||||||
|
message = (mbim_message_connect_set_new (
|
||||||
|
/* use bearer ptr value as session ID */
|
||||||
|
(guint32)GPOINTER_TO_UINT (ctx->self),
|
||||||
|
MBIM_ACTIVATION_COMMAND_ACTIVATE,
|
||||||
|
apn ? apn : "",
|
||||||
|
user ? user : "",
|
||||||
|
password ? password : "",
|
||||||
|
MBIM_COMPRESSION_NONE,
|
||||||
|
auth,
|
||||||
|
ip_type,
|
||||||
|
mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_INTERNET),
|
||||||
|
&error));
|
||||||
|
if (!message) {
|
||||||
|
g_simple_async_result_take_error (ctx->result, error);
|
||||||
|
connect_context_complete_and_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbim_device_command (ctx->device,
|
||||||
|
message,
|
||||||
|
10,
|
||||||
|
NULL,
|
||||||
|
(GAsyncReadyCallback)connect_set_ready,
|
||||||
ctx);
|
ctx);
|
||||||
mbim_message_unref (message);
|
mbim_message_unref (message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case CONNECT_STEP_LAST:
|
case CONNECT_STEP_LAST:
|
||||||
/* /\* If one of IPv4 or IPv6 succeeds, we're connected *\/ */
|
/* Port is connected; update the state */
|
||||||
/* if (ctx->packet_data_handle_ipv4 || ctx->packet_data_handle_ipv6) { */
|
mm_port_set_connected (MM_PORT (ctx->data), TRUE);
|
||||||
/* MMBearerIpConfig *config; */
|
|
||||||
|
|
||||||
/* /\* Port is connected; update the state *\/ */
|
/* Keep the data port */
|
||||||
/* mm_port_set_connected (MM_PORT (ctx->data), TRUE); */
|
g_assert (ctx->self->priv->data == NULL);
|
||||||
|
ctx->self->priv->data = g_object_ref (ctx->data);
|
||||||
|
|
||||||
/* /\* Keep connection related data *\/ */
|
/* Keep the session id */
|
||||||
/* g_assert (ctx->self->priv->data == NULL); */
|
g_assert (ctx->self->priv->session_id == 0);
|
||||||
/* ctx->self->priv->data = g_object_ref (ctx->data); */
|
ctx->self->priv->session_id = (guint32)GPOINTER_TO_UINT (ctx->self);
|
||||||
|
|
||||||
/* g_assert (ctx->self->priv->packet_data_handle_ipv4 == 0); */
|
/* Set operation result */
|
||||||
/* g_assert (ctx->self->priv->client_ipv4 == NULL); */
|
g_simple_async_result_set_op_res_gpointer (
|
||||||
/* if (ctx->packet_data_handle_ipv4) { */
|
ctx->result,
|
||||||
/* ctx->self->priv->packet_data_handle_ipv4 = ctx->packet_data_handle_ipv4; */
|
mm_bearer_connect_result_ref (ctx->connect_result),
|
||||||
/* ctx->self->priv->client_ipv4 = g_object_ref (ctx->client_ipv4); */
|
(GDestroyNotify)mm_bearer_connect_result_unref);
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* g_assert (ctx->self->priv->packet_data_handle_ipv6 == 0); */
|
|
||||||
/* g_assert (ctx->self->priv->client_ipv6 == NULL); */
|
|
||||||
/* if (ctx->packet_data_handle_ipv6) { */
|
|
||||||
/* ctx->self->priv->packet_data_handle_ipv6 = ctx->packet_data_handle_ipv6; */
|
|
||||||
/* ctx->self->priv->client_ipv6 = g_object_ref (ctx->client_ipv6); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* /\* Build IP config; always DHCP based *\/ */
|
|
||||||
/* config = mm_bearer_ip_config_new (); */
|
|
||||||
/* mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP); */
|
|
||||||
|
|
||||||
/* /\* Set operation result *\/ */
|
|
||||||
/* g_simple_async_result_set_op_res_gpointer ( */
|
|
||||||
/* ctx->result, */
|
|
||||||
/* mm_bearer_connect_result_new ( */
|
|
||||||
/* ctx->data, */
|
|
||||||
/* ctx->packet_data_handle_ipv4 ? config : NULL, */
|
|
||||||
/* ctx->packet_data_handle_ipv6 ? config : NULL), */
|
|
||||||
/* (GDestroyNotify)mm_bearer_connect_result_unref); */
|
|
||||||
/* g_object_unref (config); */
|
|
||||||
/* } else { */
|
|
||||||
/* GError *error; */
|
|
||||||
|
|
||||||
/* /\* No connection, set error. If both set, IPv4 error preferred *\/ */
|
|
||||||
/* if (ctx->error_ipv4) { */
|
|
||||||
/* error = ctx->error_ipv4; */
|
|
||||||
/* ctx->error_ipv4 = NULL; */
|
|
||||||
/* } else { */
|
|
||||||
/* error = ctx->error_ipv6; */
|
|
||||||
/* ctx->error_ipv6 = NULL; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* g_simple_async_result_take_error (ctx->result, error); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
g_simple_async_result_set_error (ctx->result, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Oops");
|
|
||||||
connect_context_complete_and_free (ctx);
|
connect_context_complete_and_free (ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -346,6 +474,10 @@ mm_bearer_mbim_init (MMBearerMbim *self)
|
|||||||
static void
|
static void
|
||||||
dispose (GObject *object)
|
dispose (GObject *object)
|
||||||
{
|
{
|
||||||
|
MMBearerMbim *self = MM_BEARER_MBIM (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->priv->data);
|
||||||
|
|
||||||
G_OBJECT_CLASS (mm_bearer_mbim_parent_class)->dispose (object);
|
G_OBJECT_CLASS (mm_bearer_mbim_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user