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:
Aleksander Morgado
2016-11-23 23:42:46 +01:00
parent 938a53e7c6
commit d50059ead4

View File

@@ -32,10 +32,62 @@
G_DEFINE_TYPE (MMBroadbandBearerCinterion, mm_broadband_bearer_cinterion, MM_TYPE_BROADBAND_BEARER)
/*****************************************************************************/
/* Common enums and structs */
/* WWAN interface mapping */
#define FIRST_USB_INTERFACE 1
#define SECOND_USB_INTERFACE 2
typedef struct {
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 {
BEARER_CINTERION_AUTH_UNKNOWN = -1,
@@ -66,6 +118,7 @@ typedef struct {
MMBaseModem *modem;
MMPortSerialAt *primary;
MMPort *data;
gint usb_interface_config_index;
Connect3gppContextStep connect;
MMBearerIpConfig *ipv4_config;
GCancellable *cancellable;
@@ -77,13 +130,14 @@ typedef struct {
MMBaseModem *modem;
MMPortSerialAt *primary;
MMPort *data;
gint usb_interface_config_index;
Disconnect3gppContextStep disconnect;
GSimpleAsyncResult *result;
} Disconnect3gppContext;
struct _MMBroadbandBearerCinterionPrivate {
guint network_disconnect_pending_id;/* Flag for network-initiated disconnect */
guint pdp_cid;/* Mapping for PDP Context to network (SWWAN) interface */
/* Flag for network-initiated disconnect */
guint network_disconnect_pending_id;
};
/*****************************************************************************/
@@ -96,23 +150,6 @@ static void disconnect_3gpp_context_complete_and_free (Disconnect3gppContext *ct
/*****************************************************************************/
/* 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
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)));
}
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
get_cmd_write_response_ctx_connect (MMBaseModem *modem,
GAsyncResult *res,
@@ -333,9 +351,8 @@ build_cinterion_auth_string (Connect3gppContext *ctx)
* ERROR
* +CME ERROR: <err>
*/
command = g_strdup_printf ("^SGAUTH=%i,%i,%s,%s",
ctx->self->priv->pdp_cid,
command = g_strdup_printf ("^SGAUTH=%u,%i,%s,%s",
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
encoded_auth,
passwd,
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 */
command = g_strdup_printf ("+CGDCONT=%i,\"IP\",\"%s\"",
ctx->self->priv->pdp_cid,
apn == NULL ? "" : apn);
command = g_strdup_printf ("+CGDCONT=%u,\"IP\",\"%s\"",
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
apn ? apn : "");
return command;
}
@@ -366,10 +383,9 @@ handle_cancel_connect (Connect3gppContext *ctx)
gchar *command;
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
command = g_strdup_printf ("^SWWAN=%s,%i,%i",
"0",
ctx->self->priv->pdp_cid,
ctx->self->priv->pdp_cid == 3 ? FIRST_USB_INTERFACE : SECOND_USB_INTERFACE);
command = g_strdup_printf ("^SWWAN=0,%u,%u",
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
/* Disconnect, may not succeed. Will not check response on cancel */
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 */
gchar *command;
command = g_strdup_printf ("^SWWAN=%s,%i,%i",
"1",
ctx->self->priv->pdp_cid,
ctx->self->priv->pdp_cid == 3 ? FIRST_USB_INTERFACE : SECOND_USB_INTERFACE);
command = g_strdup_printf ("^SWWAN=1,%u,%u",
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
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 */
gchar *command;
command = g_strdup_printf ("^SWWAN=%s,%i,%i",
"0",
ctx->self->priv->pdp_cid,
ctx->self->priv->pdp_cid == 3 ? FIRST_USB_INTERFACE : SECOND_USB_INTERFACE);
command = g_strdup_printf ("^SWWAN=0,%u,%u",
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
send_write_command_ctx_connect(ctx, &command);
@@ -548,9 +562,6 @@ connect_3gpp_context_step (Connect3gppContext *ctx)
/* Setup bearer */
create_cinterion_bearer (ctx);
/* Clear context */
ctx->self->priv->pdp_cid = 0;
connect_3gpp_context_complete_and_free (ctx);
return;
}
@@ -567,6 +578,8 @@ connect_3gpp (MMBroadbandBearer *self,
{
Connect3gppContext *ctx;
MMPort *port;
gint usb_interface_config_index;
GError *error = NULL;
g_assert (primary != NULL);
@@ -582,11 +595,22 @@ connect_3gpp (MMBroadbandBearer *self,
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 */
ctx = g_slice_new0 (Connect3gppContext);
ctx->self = g_object_ref (self);
ctx->modem = g_object_ref (modem);
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),
callback,
user_data,
@@ -594,9 +618,6 @@ connect_3gpp (MMBroadbandBearer *self,
ctx->cancellable = g_object_ref (cancellable);
ctx->primary = g_object_ref (primary);
/* Maps Bearer-> Net Interface-> PDP Context */
pdp_cid_connect (ctx);
/* Initialize */
ctx->connect = CONNECT_3GPP_CONTEXT_STEP_INIT;
@@ -608,23 +629,6 @@ connect_3gpp (MMBroadbandBearer *self,
/*****************************************************************************/
/* 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
get_cmd_write_response_ctx_disconnect (MMBaseModem *modem,
GAsyncResult *res,
@@ -685,10 +689,9 @@ send_swwan_disconnect_command_ctx_disconnect (Disconnect3gppContext *ctx)
{
/* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */
gchar *command;
command = g_strdup_printf ("^SWWAN=%s,%i,%i",
"0",
ctx->self->priv->pdp_cid,
ctx->self->priv->pdp_cid == 3 ? FIRST_USB_INTERFACE : SECOND_USB_INTERFACE);
command = g_strdup_printf ("^SWWAN=0,%u,%u",
usb_interface_configs[ctx->usb_interface_config_index].pdp_context,
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
mm_base_modem_at_command_full (ctx->modem,
ctx->primary,
@@ -761,8 +764,6 @@ disconnect_3gpp_context_step (Disconnect3gppContext *ctx)
case DISCONNECT_3GPP_CONTEXT_STEP_FINISH:
ctx->self->priv->pdp_cid = 0;
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
disconnect_3gpp_context_complete_and_free (ctx);
@@ -781,10 +782,22 @@ disconnect_3gpp (MMBroadbandBearer *self,
gpointer user_data)
{
Disconnect3gppContext *ctx;
gint usb_interface_config_index;
GError *error = NULL;
g_assert (primary != 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 */
ctx = g_slice_new0 (Disconnect3gppContext);
ctx->self = g_object_ref (self);
@@ -793,12 +806,9 @@ disconnect_3gpp (MMBroadbandBearer *self,
callback,
user_data,
disconnect_3gpp);
ctx->data = g_object_ref (data);
ctx->primary = g_object_ref (primary);
/* Maps Bearer->Net Interface-> PDP Context
* We can't disconnect if we don't know which context to disconnect from. */
pdp_cid_disconnect (ctx);
ctx->data = g_object_ref (data);
ctx->usb_interface_config_index = usb_interface_config_index;
/* Initialize */
ctx->disconnect = DISCONNECT_3GPP_CONTEXT_STEP_STOP_SWWAN;