From ab9e02bb3093963449e0305755036453ba2ae41d Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Tue, 1 Dec 2009 17:25:20 -0600 Subject: [PATCH] Add experimental support for E2IPCFG --- drivers/mbmmodem/gprs-context.c | 183 ++++++++++++++++++++++++++++---- 1 file changed, 163 insertions(+), 20 deletions(-) diff --git a/drivers/mbmmodem/gprs-context.c b/drivers/mbmmodem/gprs-context.c index 8cf8f854..76c76a16 100644 --- a/drivers/mbmmodem/gprs-context.c +++ b/drivers/mbmmodem/gprs-context.c @@ -47,10 +47,26 @@ OFONO_GPRS_MAX_PASSWORD_LENGTH + 128 static const char *none_prefix[] = { NULL }; +static const char *e2ipcfg_prefix[] = { "*E2IPCFG:", NULL }; + +enum mbm_state { + MBM_NONE = 0, + MBM_ENABLING = 1, + MBM_DISABLING = 2, +}; struct gprs_context_data { GAtChat *chat; unsigned int active_context; + gboolean have_e2nap; + gboolean have_e2ipcfg; + enum mbm_state mbm_state; + union { + ofono_gprs_context_cb_t down_cb; /* Down callback */ + ofono_gprs_context_up_cb_t up_cb; /* Up callback */ + }; + void *cb_data; /* Callback data */ + int enap; /* State of the call */ }; static void at_enap_down_cb(gboolean ok, GAtResult *result, gpointer user_data) @@ -60,13 +76,16 @@ static void at_enap_down_cb(gboolean ok, GAtResult *result, gpointer user_data) struct ofono_gprs_context *gc = cbd->user; struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); struct ofono_error error; + + /* Now we have to wait for the unsolicited notification to arrive */ + if (ok && gcd->enap != 0) { + gcd->mbm_state = MBM_DISABLING; + gcd->down_cb = cb; + gcd->cb_data = cbd->data; + return; + } - if (ok) - gcd->active_context = 0; - - dump_response("enap_down_cb", ok, result); decode_at_error(&error, g_at_result_final_response(result)); - cb(&error, cbd->data); } @@ -75,21 +94,20 @@ static void mbm_enap_up_cb(gboolean ok, GAtResult *result, gpointer user_data) struct cb_data *cbd = user_data; ofono_gprs_context_up_cb_t cb = cbd->cb; struct ofono_gprs_context *gc = cbd->user; - const char *interface = NULL; + struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); struct ofono_error error; - dump_response("enap_up_cb", ok, result); - decode_at_error(&error, g_at_result_final_response(result)); - if (ok) { - struct ofono_modem *modem = ofono_gprs_context_get_modem(gc); - interface = ofono_modem_get_string(modem, "NetworkInterface"); - } else { - struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); - gcd->active_context = 0; + gcd->mbm_state = MBM_ENABLING; + gcd->up_cb = cb; + gcd->cb_data = cbd->data; + return; } - cb(&error, interface, FALSE, NULL, NULL, NULL, NULL, cbd->data); + gcd->active_context = 0; + + decode_at_error(&error, g_at_result_final_response(result)); + cb(&error, NULL, FALSE, NULL, NULL, NULL, NULL, cbd->data); } static void mbm_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data) @@ -191,6 +209,89 @@ error: CALLBACK_WITH_FAILURE(cb, data); } +static void mbm_e2ipcfg_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); + GAtResultIter iter; + int numdns = 0; + int type; + const char *str; + const char *ip = NULL; + const char *gateway = NULL; + const char *dns[5]; + struct ofono_modem *modem; + const char *interface; + gboolean success = FALSE; + + if (!ok) + goto out; + + g_at_result_iter_init(&iter, result); + + if (g_at_result_iter_next(&iter, "*E2IPCFG:") == FALSE) + return; + + while (g_at_result_iter_open_list(&iter)) { + if (g_at_result_iter_next_number(&iter, &type) == FALSE) + break; + + if (g_at_result_iter_next_string(&iter, &str) == FALSE) + break; + + switch (type) { + case 1: + ip = str; + break; + case 2: + gateway = str; + break; + case 3: + dns[numdns++] = str; + break; + default: + break; + } + } + + dns[numdns] = NULL; + + if (ip && gateway && numdns) + success = TRUE; + +out: + modem = ofono_gprs_context_get_modem(gc); + interface = ofono_modem_get_string(modem, "NetworkInterface"); + + CALLBACK_WITH_SUCCESS(gcd->up_cb, interface, success, ip, NULL, + gateway, success ? dns : NULL, gcd->cb_data); + gcd->mbm_state = MBM_NONE; + gcd->up_cb = NULL; + gcd->cb_data = NULL; +} + +static void mbm_get_ip_details(struct ofono_gprs_context *gc) +{ + struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); + struct ofono_modem *modem; + const char *interface; + + if (gcd->have_e2ipcfg) { + g_at_chat_send(gcd->chat, "AT*E2IPCFG?", e2ipcfg_prefix, + mbm_e2ipcfg_cb, gc, NULL); + return; + } + + modem = ofono_gprs_context_get_modem(gc); + interface = ofono_modem_get_string(modem, "NetworkInterface"); + CALLBACK_WITH_SUCCESS(gcd->up_cb, interface, FALSE, NULL, NULL, + NULL, NULL, gcd->cb_data); + + gcd->mbm_state = MBM_NONE; + gcd->up_cb = NULL; + gcd->cb_data = NULL; +} + static void e2nap_notifier(GAtResult *result, gpointer user_data) { struct ofono_gprs_context *gc = user_data; @@ -210,18 +311,60 @@ static void e2nap_notifier(GAtResult *result, gpointer user_data) switch (state) { case MBM_E2NAP_DISCONNECTED: - ofono_gprs_context_deactivated(gc, gcd->active_context); + if (gcd->mbm_state == MBM_DISABLING) { + CALLBACK_WITH_SUCCESS(gcd->down_cb, gcd->cb_data); + gcd->down_cb = NULL; + } else if (gcd->mbm_state == MBM_ENABLING) { + CALLBACK_WITH_FAILURE(gcd->up_cb, NULL, 0, NULL, NULL, + NULL, NULL, gcd->cb_data); + gcd->up_cb = NULL; + } else + ofono_gprs_context_deactivated(gc, gcd->active_context); + + gcd->mbm_state = MBM_NONE; + gcd->cb_data = NULL; gcd->active_context = 0; + break; + case MBM_E2NAP_CONNECTED: ofono_debug("MBM Context: connected"); + + if (gcd->mbm_state == MBM_ENABLING) + mbm_get_ip_details(gc); + break; + case MBM_E2NAP_CONNECTING: ofono_debug("MBM Context: connecting"); break; + default: break; }; + + gcd->enap = state; +} + +static void mbm_e2nap_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); + + gcd->have_e2nap = ok; + + if (ok) + g_at_chat_register(gcd->chat, "*E2NAP:", e2nap_notifier, + FALSE, gc, NULL); +} + +static void mbm_e2ipcfg_query_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); + + gcd->have_e2ipcfg = ok; } static int mbm_gprs_context_probe(struct ofono_gprs_context *gc, @@ -233,12 +376,12 @@ static int mbm_gprs_context_probe(struct ofono_gprs_context *gc, gcd = g_new0(struct gprs_context_data, 1); gcd->chat = chat; - g_at_chat_register(chat, "*E2NAP:", e2nap_notifier, FALSE, gc, NULL); - - g_at_chat_send(chat, "AT*E2NAP=1", NULL, NULL, NULL, NULL); - ofono_gprs_context_set_data(gc, gcd); + g_at_chat_send(chat, "AT*E2NAP=1", none_prefix, mbm_e2nap_cb, gc, NULL); + g_at_chat_send(chat, "AT*E2IPCFG=?", e2ipcfg_prefix, + mbm_e2ipcfg_query_cb, gc, NULL); + return 0; }