From 3303268d0272cfe53e7ac13f51e56ff639424eb9 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Sat, 26 Dec 2020 23:56:41 +0300 Subject: [PATCH] gemalto: gprs: support automatic context activation Implement read_settings function to get configuration for automatic contexts. AT^SWWAN command activates PDP context unless it has been already activated automatically, and then starts DHCP server in the ME. So AT^SWWAN command should be run for automatic context as well in order to obtain IP settings from the ME. This commit also fixes the issue uncovered by the added support for automatic contexts: as per modem specs, AT+CGACT context should not be reused for AT^SWWAN. Though that worked for some reason when automatic context was reactivated without proper deactivation. Note that in both cases success code is reported to the core before AT^SWWAN response. This is because the ME waits until DHCP negotiation has finished before sending the "OK" or "ERROR" result code. --- drivers/gemaltomodem/gprs-context.c | 122 ++++++++++++++++------------ 1 file changed, 72 insertions(+), 50 deletions(-) diff --git a/drivers/gemaltomodem/gprs-context.c b/drivers/gemaltomodem/gprs-context.c index 13a858d4..99cb4114 100644 --- a/drivers/gemaltomodem/gprs-context.c +++ b/drivers/gemaltomodem/gprs-context.c @@ -51,30 +51,10 @@ struct gprs_context_data { void *cb_data; }; -static void cgact_enable_cb(gboolean ok, GAtResult *result, - gpointer user_data) +static void set_gprs_context_interface(struct ofono_gprs_context *gc) { - struct ofono_gprs_context *gc = user_data; - struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); struct ofono_modem *modem; const char *interface; - char buf[64]; - - DBG("ok %d", ok); - - if (!ok) { - struct ofono_error error; - - gcd->active_context = 0; - - decode_at_error(&error, g_at_result_final_response(result)); - gcd->cb(&error, gcd->cb_data); - - return; - } - - snprintf(buf, sizeof(buf), "AT^SWWAN=1,%u", gcd->active_context); - g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL); modem = ofono_gprs_context_get_modem(gc); interface = ofono_modem_get_string(modem, "NetworkInterface"); @@ -82,39 +62,52 @@ static void cgact_enable_cb(gboolean ok, GAtResult *result, /* Use DHCP */ ofono_gprs_context_set_ipv4_address(gc, NULL, 0); - - CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data); } -static void cgdcont_enable_cb(gboolean ok, GAtResult *result, - gpointer user_data) +static void swwan_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_gprs_context *gc = user_data; struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); + struct ofono_error error; + + DBG("ok %d", ok); + + if (!ok) { + ofono_error("Unable to activate context"); + ofono_gprs_context_deactivated(gc, gcd->active_context); + gcd->active_context = 0; + decode_at_error(&error, g_at_result_final_response(result)); + gcd->cb(&error, gcd->cb_data); + return; + } +} + +static void cgdcont_enable_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct ofono_gprs_context *gc = user_data; + struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); + struct ofono_error error; char buf[64]; DBG("ok %d", ok); if (!ok) { - struct ofono_error error; - gcd->active_context = 0; - decode_at_error(&error, g_at_result_final_response(result)); gcd->cb(&error, gcd->cb_data); - return; } - snprintf(buf, sizeof(buf), "AT+CGACT=1,%u", gcd->active_context); + snprintf(buf, sizeof(buf), "AT^SWWAN=1,%u", gcd->active_context); - if (g_at_chat_send(gcd->chat, buf, none_prefix, - cgact_enable_cb, gc, NULL) == 0) - goto error; + if (g_at_chat_send(gcd->chat, buf, none_prefix, swwan_cb, gc, NULL)) { + set_gprs_context_interface(gc); - return; + CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data); + return; + } -error: CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data); } @@ -152,31 +145,27 @@ static void gemalto_gprs_activate_primary(struct ofono_gprs_context *gc, snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"", ctx->apn); if (g_at_chat_send(gcd->chat, buf, none_prefix, - cgdcont_enable_cb, gc, NULL) > 0) + cgdcont_enable_cb, gc, NULL)) return; CALLBACK_WITH_FAILURE(cb, data); } -static void cgact_disable_cb(gboolean ok, GAtResult *result, - gpointer user_data) +static void deactivate_cb(gboolean ok, GAtResult *result, + gpointer user_data) { struct ofono_gprs_context *gc = user_data; struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); - char buf[64]; DBG("ok %d", ok); + gcd->active_context = 0; + if (!ok) { CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data); return; } - snprintf(buf, sizeof(buf), "AT^SWWAN=0,%u", gcd->active_context); - g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL); - - gcd->active_context = 0; - CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data); } @@ -193,17 +182,49 @@ static void gemalto_gprs_deactivate_primary(struct ofono_gprs_context *gc, gcd->cb = cb; gcd->cb_data = data; - snprintf(buf, sizeof(buf), "AT+CGACT=0,%u", cid); + snprintf(buf, sizeof(buf), "AT^SWWAN=0,%u", gcd->active_context); if (g_at_chat_send(gcd->chat, buf, none_prefix, - cgact_disable_cb, gc, NULL) == 0) - goto error; + deactivate_cb, gc, NULL)) + return; - return; - -error: CALLBACK_WITH_FAILURE(cb, data); +} +static void gemalto_gprs_read_settings(struct ofono_gprs_context *gc, + unsigned int cid, + ofono_gprs_context_cb_t cb, void *data) +{ + struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); + char buf[64]; + + DBG("cid %u", cid); + + gcd->active_context = cid; + gcd->cb = cb; + gcd->cb_data = data; + + /* + * AT^SWWAN command activates PDP context unless it has been already + * activated automatically, and then starts DHCP server in the ME. + * So AT^SWWAN command should be run in both cases: + * - when activate context and then obtain IP address from the ME + * - when obtain IP address from the automatically activated context + * + * Note that the ME waits until DHCP negotiation has finished before + * sending the "OK" or "ERROR" result code. So success is reported + * to the core before AT^SWWAN response. + */ + snprintf(buf, sizeof(buf), "AT^SWWAN=1,%u", gcd->active_context); + + if (g_at_chat_send(gcd->chat, buf, none_prefix, swwan_cb, gc, NULL)) { + set_gprs_context_interface(gc); + + CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data); + return; + } + + CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data); } static void cgev_notify(GAtResult *result, gpointer user_data) @@ -275,6 +296,7 @@ static const struct ofono_gprs_context_driver driver = { .remove = gemalto_gprs_context_remove, .activate_primary = gemalto_gprs_activate_primary, .deactivate_primary = gemalto_gprs_deactivate_primary, + .read_settings = gemalto_gprs_read_settings, }; void gemalto_gprs_context_init(void)