Add experimental support for E2IPCFG
authorDenis Kenzior <denkenz@gmail.com>
Tue, 1 Dec 2009 23:25:20 +0000 (17:25 -0600)
committerDenis Kenzior <denkenz@gmail.com>
Tue, 1 Dec 2009 23:25:20 +0000 (17:25 -0600)
drivers/mbmmodem/gprs-context.c

index 8cf8f85..76c76a1 100644 (file)
                        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;
 }