aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-01-12 14:07:58 +0100
committerAleksander Morgado <aleksander@lanedo.com>2012-03-15 14:14:49 +0100
commitf07101943cdd3d74fe3f2600953d6085bc670e24 (patch)
tree925953df36ba22f20cd2dd8fe606cc7e1efb562d /src
parentd19cf55f8f35bd82408ecfce012cdebe0ed2183f (diff)
iface-modem-simple: new connection logic when more than one bearer around
For mixed 3GPP+CDMA modems, we first try to connect the 3GPP bearers, and then the CDMA ones.
Diffstat (limited to 'src')
-rw-r--r--src/mm-iface-modem-simple.c400
-rw-r--r--src/mm-iface-modem.c47
-rw-r--r--src/mm-iface-modem.h1
3 files changed, 385 insertions, 63 deletions
diff --git a/src/mm-iface-modem-simple.c b/src/mm-iface-modem-simple.c
index 179b51a1..dfcc176f 100644
--- a/src/mm-iface-modem-simple.c
+++ b/src/mm-iface-modem-simple.c
@@ -26,6 +26,8 @@
#include "mm-iface-modem-3gpp.h"
#include "mm-iface-modem-cdma.h"
#include "mm-iface-modem-simple.h"
+#include "mm-bearer-3gpp.h"
+#include "mm-bearer-cdma.h"
#include "mm-log.h"
/*****************************************************************************/
@@ -168,6 +170,314 @@ register_in_3gpp_or_cdma_network (MMIfaceModemSimple *self,
/*****************************************************************************/
+typedef struct {
+ GSimpleAsyncResult *result;
+ MMIfaceModemSimple *self;
+ MMCommonBearerProperties *bearer_properties;
+ gboolean create_cdma_bearer;
+ gboolean create_3gpp_bearer;
+ GList *list;
+} CreateBearersContext;
+
+static void
+create_bearers_context_complete_and_free (CreateBearersContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ g_list_free_full (ctx->list, (GDestroyNotify)g_object_unref);
+ g_object_unref (ctx->bearer_properties);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->self);
+ g_free (ctx);
+}
+
+static GList *
+create_3gpp_and_cdma_bearers_finish (MMIfaceModemSimple *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return NULL;
+
+ /* We return the list itself. Note that there was no GDestroyNotify given when
+ * the result was set, as we know that this finish() is always executed */
+ return (GList *) g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+}
+
+static void create_next_bearer (CreateBearersContext *ctx);
+
+static void
+create_bearer_ready (MMIfaceModem *self,
+ GAsyncResult *res,
+ CreateBearersContext *ctx)
+{
+ GError *error = NULL;
+ MMBearer *bearer;
+
+ bearer = mm_iface_modem_create_bearer_finish (self, res, &error);
+ if (!bearer) {
+ g_simple_async_result_take_error (ctx->result, error);
+ create_bearers_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Keep the new bearer */
+ ctx->list = g_list_prepend (ctx->list, bearer);
+
+ /* And see if we need to create a new one */
+ create_next_bearer (ctx);
+}
+
+static void
+create_next_bearer (CreateBearersContext *ctx)
+{
+ /* Create 3GPP bearer if needed */
+ if (ctx->create_3gpp_bearer) {
+ ctx->create_3gpp_bearer = FALSE;
+ mm_iface_modem_create_bearer (MM_IFACE_MODEM (ctx->self),
+ ctx->bearer_properties,
+ (GAsyncReadyCallback)create_bearer_ready,
+ ctx);
+ return;
+ }
+
+ /* Create CDMA bearer if needed */
+ if (ctx->create_cdma_bearer) {
+ MMCommonBearerProperties *cdma_properties = NULL;
+
+ ctx->create_cdma_bearer = FALSE;
+
+ /* If the bearer properties has 'apn', we need to remove that before
+ * trying to create the bearer. */
+ if (mm_common_bearer_properties_get_apn (ctx->bearer_properties)) {
+ cdma_properties = mm_common_bearer_properties_dup (ctx->bearer_properties);
+ mm_common_bearer_properties_set_apn (cdma_properties, NULL);
+ }
+
+ mm_iface_modem_create_bearer (
+ MM_IFACE_MODEM (ctx->self),
+ (cdma_properties ? cdma_properties : ctx->bearer_properties),
+ (GAsyncReadyCallback)create_bearer_ready,
+ ctx);
+
+ if (cdma_properties)
+ g_object_unref (cdma_properties);
+ return;
+ }
+
+ /* If no more bearers to create, we're done.
+ * NOTE: we won't provide a GDestroyNotify to clear the gpointer passed as
+ * result, as we know that finish() will ALWAYS be executed. */
+ g_assert (ctx->list != NULL);
+ g_simple_async_result_set_op_res_gpointer (ctx->result, ctx->list, NULL);
+ ctx->list = NULL;
+ create_bearers_context_complete_and_free (ctx);
+}
+
+static void
+create_3gpp_and_cdma_bearers (MMIfaceModemSimple *self,
+ MMCommonBearerProperties *bearer_properties,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ guint n_bearers_needed;
+ MMBearerList *list = NULL;
+ CreateBearersContext *ctx;
+
+ /* The implementation of this async method requires a valid callback, so
+ * that we ensure that finish() will always be called. */
+ g_assert (callback != NULL);
+
+ ctx = g_new0 (CreateBearersContext, 1);
+ ctx->self = g_object_ref (self);
+ ctx->bearer_properties = g_object_ref (bearer_properties);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ create_3gpp_and_cdma_bearers);
+
+ /* 3GPP-only modems... */
+ if (mm_iface_modem_is_3gpp_only (MM_IFACE_MODEM (ctx->self)))
+ ctx->create_3gpp_bearer = TRUE;
+ /* CDMA-only modems... */
+ else if (mm_iface_modem_is_cdma_only (MM_IFACE_MODEM (ctx->self)))
+ ctx->create_cdma_bearer = TRUE;
+ /* Mixed CDMA+3GPP(LTE) modems */
+ else {
+ /* If we have APN, we'll create both 3GPP and CDMA bearers.
+ * Otherwise we'll only create a CDMA bearer. */
+ if (mm_common_bearer_properties_get_apn (ctx->bearer_properties)) {
+ ctx->create_3gpp_bearer = TRUE;
+ }
+ ctx->create_cdma_bearer = TRUE;
+ }
+
+ n_bearers_needed = ctx->create_3gpp_bearer + ctx->create_cdma_bearer;
+ if (n_bearers_needed == 0)
+ g_assert_not_reached ();
+
+ g_object_get (self,
+ MM_IFACE_MODEM_BEARER_LIST, &list,
+ NULL);
+
+ /* TODO: check if the bearers we want to create are already in the list */
+
+ /* If we don't have enough space to create all needed bearers, try to remove
+ * all existing ones first BUT only if that will give us enough space. */
+ if (mm_bearer_list_get_max (list) < (mm_bearer_list_get_count (list) +
+ n_bearers_needed)) {
+ if (mm_bearer_list_get_max (list) < n_bearers_needed) {
+ g_simple_async_result_set_error (
+ ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_TOO_MANY,
+ "Cannot create bearers: need %u but only %u allowed",
+ n_bearers_needed,
+ mm_bearer_list_get_max (list));
+ create_bearers_context_complete_and_free (ctx);
+ g_object_unref (list);
+ return;
+ }
+
+ /* We are told to force the creation of the new bearer.
+ * We'll remove all existing bearers, and then go on creating the new one */
+ mm_bearer_list_delete_all_bearers (list);
+ }
+
+ create_next_bearer (ctx);
+ g_object_unref (list);
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ MMIfaceModemSimple *self;
+ GSimpleAsyncResult *result;
+ GList *bearers;
+ MMBearer *current;
+} ConnectBearerContext;
+
+static void
+connect_bearer_context_complete_and_free (ConnectBearerContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ if (ctx->current)
+ g_object_unref (ctx->current);
+ g_list_free_full (ctx->bearers, (GDestroyNotify)g_object_unref);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->self);
+ g_free (ctx);
+}
+
+static MMBearer *
+connect_3gpp_or_cdma_bearer_finish (MMIfaceModemSimple *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return NULL;
+
+ return MM_BEARER (g_object_ref (g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (res))));
+}
+
+static void connect_next_bearer (ConnectBearerContext *ctx);
+
+static void
+connect_bearer_ready (MMBearer *bearer,
+ GAsyncResult *res,
+ ConnectBearerContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!mm_bearer_connect_finish (bearer, res, &error)) {
+ mm_dbg ("Couldn't connect bearer: '%s'", error->message);
+ g_error_free (error);
+ /* We'll try with the next one */
+ connect_next_bearer (ctx);
+ return;
+ }
+
+ /* We got connected! */
+ g_simple_async_result_set_op_res_gpointer (ctx->result,
+ g_object_ref (ctx->current),
+ (GDestroyNotify)g_object_unref);
+ connect_bearer_context_complete_and_free (ctx);
+}
+
+static void
+connect_next_bearer (ConnectBearerContext *ctx)
+{
+ GList *l;
+
+ g_clear_object (&ctx->current);
+
+ /* First, look for 3GPP bearers */
+ for (l = ctx->bearers; l; l = g_list_next (l)) {
+ if (MM_IS_BEARER_3GPP (l->data)) {
+ /* Try to connect the current bearer. If the modem is not yet
+ * registered in the 3GPP network, connection won't succeed.
+ * Steal the reference from the list. */
+ ctx->current = MM_BEARER (l->data);
+ ctx->bearers = g_list_delete_link (ctx->bearers, l);
+ mm_bearer_connect (MM_BEARER (ctx->current),
+ NULL, /* no number given */
+ (GAsyncReadyCallback)connect_bearer_ready,
+ ctx);
+ return;
+ }
+ }
+
+ /* Then, we look for CDMA bearers */
+ for (l = ctx->bearers; l; l = g_list_next (l)) {
+ if (MM_IS_BEARER_CDMA (l->data)) {
+ /* Try to connect the current bearer. If the modem is not yet
+ * registered in the 3GPP network, connection won't succeed.
+ * Steal the reference from the list. */
+ ctx->current = MM_BEARER (l->data);
+ ctx->bearers = g_list_delete_link (ctx->bearers, l);
+ mm_bearer_connect (MM_BEARER (ctx->current),
+ NULL, /* no number given */
+ (GAsyncReadyCallback)connect_bearer_ready,
+ ctx);
+ return;
+ }
+ }
+
+ /* Here we shouldn't have any remaining bearer.
+ * POTS modem not yet supported */
+
+ /* If we got here, we didn't get connected :-/ */
+ g_simple_async_result_set_error (ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNAUTHORIZED,
+ "Cannot connect any bearer");
+ connect_bearer_context_complete_and_free (ctx);
+}
+
+static void
+connect_3gpp_or_cdma_bearer (MMIfaceModemSimple *self,
+ GList *bearers,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ConnectBearerContext *ctx;
+
+ g_assert (bearers != NULL);
+
+ ctx = g_new0 (ConnectBearerContext, 1);
+ ctx->self = g_object_ref (self);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ connect_3gpp_or_cdma_bearer);
+ ctx->bearers = g_list_copy (bearers);
+ g_list_foreach (ctx->bearers, (GFunc)g_object_ref, NULL);
+
+ connect_next_bearer (ctx);
+}
+
+/*****************************************************************************/
+
typedef enum {
CONNECTION_STEP_FIRST,
CONNECTION_STEP_UNLOCK_CHECK,
@@ -190,31 +500,34 @@ typedef struct {
MMCommonConnectProperties *properties;
/* Results to set */
- MMBearer *bearer;
+ GList *bearers;
+ MMBearer *connected_bearer;
} ConnectionContext;
static void
connection_context_free (ConnectionContext *ctx)
{
+ g_list_free_full (ctx->bearers, (GDestroyNotify)g_object_unref);
+ if (ctx->connected_bearer)
+ g_object_unref (ctx->connected_bearer);
g_object_unref (ctx->properties);
g_object_unref (ctx->skeleton);
g_object_unref (ctx->invocation);
g_object_unref (ctx->self);
- if (ctx->bearer)
- g_object_unref (ctx->bearer);
g_free (ctx);
}
static void connection_step (ConnectionContext *ctx);
static void
-connect_bearer_ready (MMBearer *bearer,
- GAsyncResult *res,
- ConnectionContext *ctx)
+connect_3gpp_or_cdma_bearer_ready (MMIfaceModemSimple *self,
+ GAsyncResult *res,
+ ConnectionContext *ctx)
{
GError *error = NULL;
- if (!mm_bearer_connect_finish (bearer, res, &error)) {
+ ctx->connected_bearer = connect_3gpp_or_cdma_bearer_finish (self, res, &error);
+ if (!ctx->connected_bearer) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
connection_context_free (ctx);
return;
@@ -226,20 +539,21 @@ connect_bearer_ready (MMBearer *bearer,
}
static void
-create_bearer_ready (MMIfaceModem *self,
- GAsyncResult *res,
- ConnectionContext *ctx)
+create_3gpp_and_cdma_bearers_ready (MMIfaceModemSimple *self,
+ GAsyncResult *res,
+ ConnectionContext *ctx)
{
GError *error = NULL;
- ctx->bearer = mm_iface_modem_create_bearer_finish (self, res, &error);
- if (!ctx->bearer) {
+ /* List ownership for the caller */
+ ctx->bearers = create_3gpp_and_cdma_bearers_finish (self, res, &error);
+ if (!ctx->bearers) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
connection_context_free (ctx);
return;
}
- /* Bearer available! */
+ /* Bearers available! */
ctx->step++;
connection_step (ctx);
}
@@ -497,40 +811,60 @@ connection_step (ConnectionContext *ctx)
* So, fall down to next step */
ctx->step++;
- case CONNECTION_STEP_BEARER: {
- MMCommonBearerProperties *bearer_properties;
-
+ case CONNECTION_STEP_BEARER:
mm_info ("Simple connect state (%d/%d): Bearer",
ctx->step, CONNECTION_STEP_LAST);
- bearer_properties = (mm_common_connect_properties_get_bearer_properties (
- ctx->properties));
- mm_iface_modem_create_bearer (
- MM_IFACE_MODEM (ctx->self),
- TRUE, /* Try to force bearer creation */
- bearer_properties,
- (GAsyncReadyCallback)create_bearer_ready,
- ctx);
- g_object_unref (bearer_properties);
+ if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (ctx->self)) ||
+ mm_iface_modem_is_cdma (MM_IFACE_MODEM (ctx->self))) {
+ MMCommonBearerProperties *bearer_properties;
+
+ bearer_properties = (mm_common_connect_properties_get_bearer_properties (
+ ctx->properties));
+ /* 3GPP and/or CDMA bearer creation */
+ create_3gpp_and_cdma_bearers (
+ ctx->self,
+ bearer_properties,
+ (GAsyncReadyCallback)create_3gpp_and_cdma_bearers_ready,
+ ctx);
+
+ g_object_unref (bearer_properties);
+ return;
+ }
+
+ /* If not 3GPP and not CDMA, this will possibly be a POTS modem,
+ * currently unsupported. So, just abort. */
+ g_assert_not_reached ();
return;
- }
case CONNECTION_STEP_CONNECT:
mm_info ("Simple connect state (%d/%d): Connect",
ctx->step, CONNECTION_STEP_LAST);
- mm_bearer_connect (ctx->bearer,
- NULL, /* no number given */
- (GAsyncReadyCallback)connect_bearer_ready,
- ctx);
+
+ if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (ctx->self)) ||
+ mm_iface_modem_is_cdma (MM_IFACE_MODEM (ctx->self))) {
+ /* 3GPP or CDMA bearer connection */
+ connect_3gpp_or_cdma_bearer (
+ ctx->self,
+ ctx->bearers,
+ (GAsyncReadyCallback)connect_3gpp_or_cdma_bearer_ready,
+ ctx);
+ return;
+ }
+
+ /* If not 3GPP and not CDMA, this will possibly be a POTS modem,
+ * currently unsupported. So, just abort. */
+ g_assert_not_reached ();
return;
case CONNECTION_STEP_LAST:
mm_info ("Simple connect state (%d/%d): All done",
ctx->step, CONNECTION_STEP_LAST);
/* All done, yey! */
- mm_gdbus_modem_simple_complete_connect (ctx->skeleton,
- ctx->invocation,
- mm_bearer_get_path (ctx->bearer));
+ mm_gdbus_modem_simple_complete_connect (
+ ctx->skeleton,
+ ctx->invocation,
+ mm_bearer_get_path (ctx->connected_bearer));
connection_context_free (ctx);
return;
}
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index 855931a3..0c9912e9 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -220,7 +220,6 @@ create_bearer_ready (MMIfaceModem *self,
void
mm_iface_modem_create_bearer (MMIfaceModem *self,
- gboolean force,
MMCommonBearerProperties *properties,
GAsyncReadyCallback callback,
gpointer user_data)
@@ -231,33 +230,24 @@ mm_iface_modem_create_bearer (MMIfaceModem *self,
MM_IFACE_MODEM_BEARER_LIST, &list,
NULL);
- if (mm_bearer_list_get_count (list) == mm_bearer_list_get_max (list)) {
- if (!force) {
- g_simple_async_report_error_in_idle (
- G_OBJECT (self),
- callback,
- user_data,
- MM_CORE_ERROR,
- MM_CORE_ERROR_TOO_MANY,
- "Cannot add new bearer: already reached maximum (%u)",
- mm_bearer_list_get_count (list));
- g_object_unref (list);
- return;
- }
-
- /* We are told to force the creation of the new bearer.
- * We'll remove all existing bearers, and then go on creating the new one */
- mm_bearer_list_delete_all_bearers (list);
- }
-
- MM_IFACE_MODEM_GET_INTERFACE (self)->create_bearer (
- self,
- properties,
- (GAsyncReadyCallback)create_bearer_ready,
- g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- mm_iface_modem_create_bearer));
+ if (mm_bearer_list_get_count (list) == mm_bearer_list_get_max (list))
+ g_simple_async_report_error_in_idle (
+ G_OBJECT (self),
+ callback,
+ user_data,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_TOO_MANY,
+ "Cannot add new bearer: already reached maximum (%u)",
+ mm_bearer_list_get_count (list));
+ else
+ MM_IFACE_MODEM_GET_INTERFACE (self)->create_bearer (
+ self,
+ properties,
+ (GAsyncReadyCallback)create_bearer_ready,
+ g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ mm_iface_modem_create_bearer));
g_object_unref (list);
}
@@ -296,7 +286,6 @@ handle_create_bearer (MmGdbusModem *skeleton,
} else {
mm_iface_modem_create_bearer (
self,
- FALSE, /* don't force when request comes from DBus */
properties,
(GAsyncReadyCallback)handle_create_bearer_ready,
dbus_call_context_new (skeleton,
diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h
index 141a975a..b7ab6102 100644
--- a/src/mm-iface-modem.h
+++ b/src/mm-iface-modem.h
@@ -348,7 +348,6 @@ gboolean mm_iface_modem_set_allowed_bands_finish (MMIfaceModem *self,
/* Allow creating bearers */
void mm_iface_modem_create_bearer (MMIfaceModem *self,
- gboolean force,
MMCommonBearerProperties *properties,
GAsyncReadyCallback callback,
gpointer user_data);