cinterion: setup per-interface configuration settings
Define the relationship between PDP context, SWWAN index and USB interface number in one single place.
This commit is contained in:
@@ -32,10 +32,62 @@
|
|||||||
G_DEFINE_TYPE (MMBroadbandBearerCinterion, mm_broadband_bearer_cinterion, MM_TYPE_BROADBAND_BEARER)
|
G_DEFINE_TYPE (MMBroadbandBearerCinterion, mm_broadband_bearer_cinterion, MM_TYPE_BROADBAND_BEARER)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Common enums and structs */
|
/* WWAN interface mapping */
|
||||||
|
|
||||||
#define FIRST_USB_INTERFACE 1
|
typedef struct {
|
||||||
#define SECOND_USB_INTERFACE 2
|
guint swwan_index;
|
||||||
|
guint usb_iface_num;
|
||||||
|
guint pdp_context;
|
||||||
|
} UsbInterfaceConfig;
|
||||||
|
|
||||||
|
/* Map SWWAN index, USB interface number and preferred PDP context.
|
||||||
|
*
|
||||||
|
* The expected USB interface mapping is:
|
||||||
|
* INTERFACE=usb0 -> ID_USB_INTERFACE_NUM=0a
|
||||||
|
* INTERFACE=usb1 -> ID_USB_INTERFACE_NUM=0c
|
||||||
|
*
|
||||||
|
* The preferred PDP context CIDs are:
|
||||||
|
* INTERFACE=usb0 -> PDP CID #3
|
||||||
|
* INTERFACE=usb1 -> PDP CID #1
|
||||||
|
*
|
||||||
|
* The PDP context mapping is as suggested by Cinterion, although it looks like
|
||||||
|
* this isn't strictly enforced by the modem; i.e. SWWAN could work fine with
|
||||||
|
* any PDP context vs SWWAN interface mapping.
|
||||||
|
*/
|
||||||
|
static const UsbInterfaceConfig usb_interface_configs[] = {
|
||||||
|
{
|
||||||
|
.swwan_index = 1,
|
||||||
|
.usb_iface_num = 0x0a,
|
||||||
|
.pdp_context = 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.swwan_index = 2,
|
||||||
|
.usb_iface_num = 0x0c,
|
||||||
|
.pdp_context = 1
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static gint
|
||||||
|
get_usb_interface_config_index (MMPort *data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
guint usb_iface_num;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
usb_iface_num = mm_kernel_device_get_property_as_int_hex (mm_port_peek_kernel_device (data), "ID_USB_INTERFACE_NUM");
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (usb_interface_configs); i++) {
|
||||||
|
if (usb_interface_configs[i].usb_iface_num == usb_iface_num)
|
||||||
|
return (gint) i;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||||
|
"Unsupported WWAN interface: unexpected interface number: 0x%02x", usb_iface_num);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Common enums and structs */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BEARER_CINTERION_AUTH_UNKNOWN = -1,
|
BEARER_CINTERION_AUTH_UNKNOWN = -1,
|
||||||
@@ -66,6 +118,7 @@ typedef struct {
|
|||||||
MMBaseModem *modem;
|
MMBaseModem *modem;
|
||||||
MMPortSerialAt *primary;
|
MMPortSerialAt *primary;
|
||||||
MMPort *data;
|
MMPort *data;
|
||||||
|
gint usb_interface_config_index;
|
||||||
Connect3gppContextStep connect;
|
Connect3gppContextStep connect;
|
||||||
MMBearerIpConfig *ipv4_config;
|
MMBearerIpConfig *ipv4_config;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
@@ -77,13 +130,14 @@ typedef struct {
|
|||||||
MMBaseModem *modem;
|
MMBaseModem *modem;
|
||||||
MMPortSerialAt *primary;
|
MMPortSerialAt *primary;
|
||||||
MMPort *data;
|
MMPort *data;
|
||||||
|
gint usb_interface_config_index;
|
||||||
Disconnect3gppContextStep disconnect;
|
Disconnect3gppContextStep disconnect;
|
||||||
GSimpleAsyncResult *result;
|
GSimpleAsyncResult *result;
|
||||||
} Disconnect3gppContext;
|
} Disconnect3gppContext;
|
||||||
|
|
||||||
struct _MMBroadbandBearerCinterionPrivate {
|
struct _MMBroadbandBearerCinterionPrivate {
|
||||||
guint network_disconnect_pending_id;/* Flag for network-initiated disconnect */
|
/* Flag for network-initiated disconnect */
|
||||||
guint pdp_cid;/* Mapping for PDP Context to network (SWWAN) interface */
|
guint network_disconnect_pending_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -96,23 +150,6 @@ static void disconnect_3gpp_context_complete_and_free (Disconnect3gppContext *ct
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Common - Helper Functions*/
|
/* Common - Helper Functions*/
|
||||||
|
|
||||||
static void
|
|
||||||
pdp_cid_map (MMBroadbandBearerCinterion *self, const gchar *bearer_interface)
|
|
||||||
{
|
|
||||||
/* Map PDP context from the current Bearer. USB0 -> 3rd context, USB1 -> 1st context.
|
|
||||||
* Note - Cinterion told me specifically to map the contexts to the interfaces this way, though
|
|
||||||
* I've seen that SWWAN appear's to work fine with any PDP to any interface */
|
|
||||||
|
|
||||||
if (g_strcmp0 (bearer_interface, "0a") == 0)
|
|
||||||
self->priv->pdp_cid = 3;
|
|
||||||
else if (g_strcmp0 (bearer_interface, "0c") == 0)
|
|
||||||
self->priv->pdp_cid = 1;
|
|
||||||
else
|
|
||||||
/* Shouldn't be able to create a bearer for SWWAN and not be able to
|
|
||||||
* find the net interface. Otherwise connects/disconnects will get wrecked */
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
verify_connection_state_from_swwan_response (GList *result, GError **error)
|
verify_connection_state_from_swwan_response (GList *result, GError **error)
|
||||||
{
|
{
|
||||||
@@ -199,25 +236,6 @@ connect_3gpp_finish (MMBroadbandBearer *self,
|
|||||||
return mm_bearer_connect_result_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
|
return mm_bearer_connect_result_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
pdp_cid_connect (Connect3gppContext *ctx)
|
|
||||||
{
|
|
||||||
const gchar *bearer_interface;
|
|
||||||
|
|
||||||
/* For E: INTERFACE=usb0 -> E: ID_USB_INTERFACE_NUM=0a
|
|
||||||
* For E: INTERFACE=usb1 -> E: ID_USB_INTERFACE_NUM=0c */
|
|
||||||
|
|
||||||
/* Look up the net port to associate with this bearer */
|
|
||||||
bearer_interface = mm_kernel_device_get_property (mm_port_peek_kernel_device (ctx->data),
|
|
||||||
"ID_USB_INTERFACE_NUM");
|
|
||||||
|
|
||||||
pdp_cid_map (ctx->self, bearer_interface);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_cmd_write_response_ctx_connect (MMBaseModem *modem,
|
get_cmd_write_response_ctx_connect (MMBaseModem *modem,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
@@ -333,9 +351,8 @@ build_cinterion_auth_string (Connect3gppContext *ctx)
|
|||||||
* ERROR
|
* ERROR
|
||||||
* +CME ERROR: <err>
|
* +CME ERROR: <err>
|
||||||
*/
|
*/
|
||||||
|
command = g_strdup_printf ("^SGAUTH=%u,%i,%s,%s",
|
||||||
command = g_strdup_printf ("^SGAUTH=%i,%i,%s,%s",
|
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
|
||||||
ctx->self->priv->pdp_cid,
|
|
||||||
encoded_auth,
|
encoded_auth,
|
||||||
passwd,
|
passwd,
|
||||||
user);
|
user);
|
||||||
@@ -353,9 +370,9 @@ build_cinterion_pdp_context_string (Connect3gppContext *ctx)
|
|||||||
|
|
||||||
/* TODO: Get IP type if protocol was specified. Hardcoded to IPV4 for now */
|
/* TODO: Get IP type if protocol was specified. Hardcoded to IPV4 for now */
|
||||||
|
|
||||||
command = g_strdup_printf ("+CGDCONT=%i,\"IP\",\"%s\"",
|
command = g_strdup_printf ("+CGDCONT=%u,\"IP\",\"%s\"",
|
||||||
ctx->self->priv->pdp_cid,
|
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
|
||||||
apn == NULL ? "" : apn);
|
apn ? apn : "");
|
||||||
|
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
@@ -366,10 +383,9 @@ handle_cancel_connect (Connect3gppContext *ctx)
|
|||||||
gchar *command;
|
gchar *command;
|
||||||
|
|
||||||
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
|
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
|
||||||
command = g_strdup_printf ("^SWWAN=%s,%i,%i",
|
command = g_strdup_printf ("^SWWAN=0,%u,%u",
|
||||||
"0",
|
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
|
||||||
ctx->self->priv->pdp_cid,
|
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||||
ctx->self->priv->pdp_cid == 3 ? FIRST_USB_INTERFACE : SECOND_USB_INTERFACE);
|
|
||||||
|
|
||||||
/* Disconnect, may not succeed. Will not check response on cancel */
|
/* Disconnect, may not succeed. Will not check response on cancel */
|
||||||
mm_base_modem_at_command_full (ctx->modem,
|
mm_base_modem_at_command_full (ctx->modem,
|
||||||
@@ -445,10 +461,9 @@ send_swwan_connect_command_ctx_connect (Connect3gppContext *ctx)
|
|||||||
{
|
{
|
||||||
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
|
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
|
||||||
gchar *command;
|
gchar *command;
|
||||||
command = g_strdup_printf ("^SWWAN=%s,%i,%i",
|
command = g_strdup_printf ("^SWWAN=1,%u,%u",
|
||||||
"1",
|
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
|
||||||
ctx->self->priv->pdp_cid,
|
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||||
ctx->self->priv->pdp_cid == 3 ? FIRST_USB_INTERFACE : SECOND_USB_INTERFACE);
|
|
||||||
|
|
||||||
send_write_command_ctx_connect(ctx, &command);
|
send_write_command_ctx_connect(ctx, &command);
|
||||||
|
|
||||||
@@ -460,10 +475,9 @@ send_swwan_disconnect_command_ctx_connect (Connect3gppContext *ctx)
|
|||||||
{
|
{
|
||||||
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
|
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
|
||||||
gchar *command;
|
gchar *command;
|
||||||
command = g_strdup_printf ("^SWWAN=%s,%i,%i",
|
command = g_strdup_printf ("^SWWAN=0,%u,%u",
|
||||||
"0",
|
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
|
||||||
ctx->self->priv->pdp_cid,
|
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||||
ctx->self->priv->pdp_cid == 3 ? FIRST_USB_INTERFACE : SECOND_USB_INTERFACE);
|
|
||||||
|
|
||||||
send_write_command_ctx_connect(ctx, &command);
|
send_write_command_ctx_connect(ctx, &command);
|
||||||
|
|
||||||
@@ -548,9 +562,6 @@ connect_3gpp_context_step (Connect3gppContext *ctx)
|
|||||||
/* Setup bearer */
|
/* Setup bearer */
|
||||||
create_cinterion_bearer (ctx);
|
create_cinterion_bearer (ctx);
|
||||||
|
|
||||||
/* Clear context */
|
|
||||||
ctx->self->priv->pdp_cid = 0;
|
|
||||||
|
|
||||||
connect_3gpp_context_complete_and_free (ctx);
|
connect_3gpp_context_complete_and_free (ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -567,6 +578,8 @@ connect_3gpp (MMBroadbandBearer *self,
|
|||||||
{
|
{
|
||||||
Connect3gppContext *ctx;
|
Connect3gppContext *ctx;
|
||||||
MMPort *port;
|
MMPort *port;
|
||||||
|
gint usb_interface_config_index;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
g_assert (primary != NULL);
|
g_assert (primary != NULL);
|
||||||
|
|
||||||
@@ -582,11 +595,22 @@ connect_3gpp (MMBroadbandBearer *self,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Validate configuration */
|
||||||
|
usb_interface_config_index = get_usb_interface_config_index (port, &error);
|
||||||
|
if (usb_interface_config_index < 0) {
|
||||||
|
g_simple_async_report_take_gerror_in_idle (G_OBJECT (self),
|
||||||
|
callback,
|
||||||
|
user_data,
|
||||||
|
error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup connection context */
|
/* Setup connection context */
|
||||||
ctx = g_slice_new0 (Connect3gppContext);
|
ctx = g_slice_new0 (Connect3gppContext);
|
||||||
ctx->self = g_object_ref (self);
|
ctx->self = g_object_ref (self);
|
||||||
ctx->modem = g_object_ref (modem);
|
ctx->modem = g_object_ref (modem);
|
||||||
ctx->data = g_object_ref (port);
|
ctx->data = g_object_ref (port);
|
||||||
|
ctx->usb_interface_config_index = usb_interface_config_index;
|
||||||
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||||
callback,
|
callback,
|
||||||
user_data,
|
user_data,
|
||||||
@@ -594,9 +618,6 @@ connect_3gpp (MMBroadbandBearer *self,
|
|||||||
ctx->cancellable = g_object_ref (cancellable);
|
ctx->cancellable = g_object_ref (cancellable);
|
||||||
ctx->primary = g_object_ref (primary);
|
ctx->primary = g_object_ref (primary);
|
||||||
|
|
||||||
/* Maps Bearer-> Net Interface-> PDP Context */
|
|
||||||
pdp_cid_connect (ctx);
|
|
||||||
|
|
||||||
/* Initialize */
|
/* Initialize */
|
||||||
ctx->connect = CONNECT_3GPP_CONTEXT_STEP_INIT;
|
ctx->connect = CONNECT_3GPP_CONTEXT_STEP_INIT;
|
||||||
|
|
||||||
@@ -608,23 +629,6 @@ connect_3gpp (MMBroadbandBearer *self,
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Disconnect - Helper Functions*/
|
/* Disconnect - Helper Functions*/
|
||||||
|
|
||||||
static void
|
|
||||||
pdp_cid_disconnect(Disconnect3gppContext *ctx)
|
|
||||||
{
|
|
||||||
const gchar *bearer_interface;
|
|
||||||
|
|
||||||
/* For E: INTERFACE=usb0 -> E: ID_USB_INTERFACE_NUM=0a
|
|
||||||
* For E: INTERFACE=usb1 -> E: ID_USB_INTERFACE_NUM=0c */
|
|
||||||
|
|
||||||
/* Look up the net port to associate with this bearer */
|
|
||||||
bearer_interface = mm_kernel_device_get_property (mm_port_peek_kernel_device (ctx->data),
|
|
||||||
"ID_USB_INTERFACE_NUM");
|
|
||||||
|
|
||||||
pdp_cid_map (ctx->self, bearer_interface);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_cmd_write_response_ctx_disconnect (MMBaseModem *modem,
|
get_cmd_write_response_ctx_disconnect (MMBaseModem *modem,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
@@ -685,10 +689,9 @@ send_swwan_disconnect_command_ctx_disconnect (Disconnect3gppContext *ctx)
|
|||||||
{
|
{
|
||||||
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
|
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
|
||||||
gchar *command;
|
gchar *command;
|
||||||
command = g_strdup_printf ("^SWWAN=%s,%i,%i",
|
command = g_strdup_printf ("^SWWAN=0,%u,%u",
|
||||||
"0",
|
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
|
||||||
ctx->self->priv->pdp_cid,
|
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||||
ctx->self->priv->pdp_cid == 3 ? FIRST_USB_INTERFACE : SECOND_USB_INTERFACE);
|
|
||||||
|
|
||||||
mm_base_modem_at_command_full (ctx->modem,
|
mm_base_modem_at_command_full (ctx->modem,
|
||||||
ctx->primary,
|
ctx->primary,
|
||||||
@@ -761,8 +764,6 @@ disconnect_3gpp_context_step (Disconnect3gppContext *ctx)
|
|||||||
|
|
||||||
case DISCONNECT_3GPP_CONTEXT_STEP_FINISH:
|
case DISCONNECT_3GPP_CONTEXT_STEP_FINISH:
|
||||||
|
|
||||||
ctx->self->priv->pdp_cid = 0;
|
|
||||||
|
|
||||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||||
disconnect_3gpp_context_complete_and_free (ctx);
|
disconnect_3gpp_context_complete_and_free (ctx);
|
||||||
|
|
||||||
@@ -781,10 +782,22 @@ disconnect_3gpp (MMBroadbandBearer *self,
|
|||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
Disconnect3gppContext *ctx;
|
Disconnect3gppContext *ctx;
|
||||||
|
gint usb_interface_config_index;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
g_assert (primary != NULL);
|
g_assert (primary != NULL);
|
||||||
g_assert (data != NULL);
|
g_assert (data != NULL);
|
||||||
|
|
||||||
|
/* Validate configuration */
|
||||||
|
usb_interface_config_index = get_usb_interface_config_index (data, &error);
|
||||||
|
if (usb_interface_config_index < 0) {
|
||||||
|
g_simple_async_report_take_gerror_in_idle (G_OBJECT (self),
|
||||||
|
callback,
|
||||||
|
user_data,
|
||||||
|
error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup connection context */
|
/* Setup connection context */
|
||||||
ctx = g_slice_new0 (Disconnect3gppContext);
|
ctx = g_slice_new0 (Disconnect3gppContext);
|
||||||
ctx->self = g_object_ref (self);
|
ctx->self = g_object_ref (self);
|
||||||
@@ -793,12 +806,9 @@ disconnect_3gpp (MMBroadbandBearer *self,
|
|||||||
callback,
|
callback,
|
||||||
user_data,
|
user_data,
|
||||||
disconnect_3gpp);
|
disconnect_3gpp);
|
||||||
ctx->data = g_object_ref (data);
|
|
||||||
ctx->primary = g_object_ref (primary);
|
ctx->primary = g_object_ref (primary);
|
||||||
|
ctx->data = g_object_ref (data);
|
||||||
/* Maps Bearer->Net Interface-> PDP Context
|
ctx->usb_interface_config_index = usb_interface_config_index;
|
||||||
* We can't disconnect if we don't know which context to disconnect from. */
|
|
||||||
pdp_cid_disconnect (ctx);
|
|
||||||
|
|
||||||
/* Initialize */
|
/* Initialize */
|
||||||
ctx->disconnect = DISCONNECT_3GPP_CONTEXT_STEP_STOP_SWWAN;
|
ctx->disconnect = DISCONNECT_3GPP_CONTEXT_STEP_STOP_SWWAN;
|
||||||
|
Reference in New Issue
Block a user