From 389eb70dc809eb74e6704e2a4675f224cf9b3dfb Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 31 Mar 2010 18:49:39 -0500 Subject: [PATCH] Initial implementation of the PPP gprs context --- drivers/atmodem/gprs-context.c | 203 +++++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 88 deletions(-) diff --git a/drivers/atmodem/gprs-context.c b/drivers/atmodem/gprs-context.c index a89dcf7..848616a 100644 --- a/drivers/atmodem/gprs-context.c +++ b/drivers/atmodem/gprs-context.c @@ -36,15 +36,33 @@ #include "gatchat.h" #include "gatresult.h" +#include "gatppp.h" #include "atmodem.h" -static const char *cgact_prefix[] = { "+CGACT:", NULL }; +#define STATIC_IP_NETMASK "255.255.255.248" + static const char *none_prefix[] = { NULL }; +enum state { + STATE_IDLE, + STATE_ENABLING, + STATE_DISABLING, + STATE_ACTIVE, +}; + struct gprs_context_data { GAtChat *chat; unsigned int active_context; + char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1]; + char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1]; + GAtPPP *ppp; + enum state 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 */ }; static void at_cgact_down_cb(gboolean ok, GAtResult *result, gpointer user_data) @@ -63,50 +81,120 @@ static void at_cgact_down_cb(gboolean ok, GAtResult *result, gpointer user_data) cb(&error, cbd->data); } -static void at_cgact_up_cb(gboolean ok, GAtResult *result, gpointer user_data) +static void ppp_connect(GAtPPPConnectStatus success, + const char *interface, const char *ip, + const char *dns1, const char *dns2, + gpointer user_data) { - struct cb_data *cbd = user_data; - ofono_gprs_context_up_cb_t cb = cbd->cb; - struct ofono_error error; + struct ofono_gprs_context *gc = user_data; + struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); + const char *dns[3]; - decode_at_error(&error, g_at_result_final_response(result)); + if (success != G_AT_PPP_CONNECT_SUCCESS) { + gcd->active_context = 0; + gcd->state = STATE_IDLE; + + CALLBACK_WITH_FAILURE(gcd->up_cb, NULL, 0, NULL, NULL, NULL, + NULL, gcd->cb_data); + return; + } - cb(&error, NULL, 0, NULL, NULL, NULL, NULL, cbd->data); + dns[0] = dns1; + dns[1] = dns2; + dns[2] = 0; + + gcd->state = STATE_ACTIVE; + CALLBACK_WITH_SUCCESS(gcd->up_cb, interface, TRUE, ip, + STATIC_IP_NETMASK, NULL, + dns, gcd->cb_data); } -static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data) +static void ppp_disconnect(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; + struct ofono_gprs_context *gc = user_data; + struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); + + ofono_gprs_context_deactivated(gc, gcd->active_context); + gcd->active_context = 0; + gcd->state = STATE_IDLE; +} + +static gboolean setup_ppp(struct ofono_gprs_context *gc) +{ + struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); + GIOChannel *channel; + + channel = g_at_chat_get_channel(gcd->chat); + g_at_chat_shutdown(gcd->chat); + + /* open ppp */ + gcd->ppp = g_at_ppp_new(channel); + + if (gcd->ppp == NULL) + return FALSE; + + g_at_ppp_set_credentials(gcd->ppp, gcd->username, gcd->password); + + /* set connect and disconnect callbacks */ + g_at_ppp_set_connect_function(gcd->ppp, ppp_connect, gc); + g_at_ppp_set_disconnect_function(gcd->ppp, ppp_disconnect, gc); + + /* open the ppp connection */ + g_at_ppp_open(gcd->ppp); + + return TRUE; +} + +static void at_cgdata_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 cb_data *ncbd; - char buf[64]; if (!ok) { struct ofono_error error; + ofono_info("Unable to enter data state"); + gcd->active_context = 0; + gcd->state = STATE_IDLE; decode_at_error(&error, g_at_result_final_response(result)); - cb(&error, NULL, 0, NULL, NULL, NULL, NULL, cbd->data); + gcd->up_cb(&error, NULL, 0, NULL, NULL, NULL, NULL, + gcd->cb_data); return; } - ncbd = g_memdup(cbd, sizeof(struct cb_data)); + setup_ppp(gc); +} - snprintf(buf, sizeof(buf), "AT+CGACT=1,%u", gcd->active_context); +static void at_cgdcont_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]; - if (g_at_chat_send(gcd->chat, buf, none_prefix, - at_cgact_up_cb, ncbd, g_free) > 0) + if (!ok) { + struct ofono_error error; + + gcd->active_context = 0; + gcd->state = STATE_IDLE; + + decode_at_error(&error, g_at_result_final_response(result)); + gcd->up_cb(&error, NULL, 0, NULL, NULL, NULL, NULL, + gcd->cb_data); return; + } - if (ncbd) - g_free(ncbd); + sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context); + if (g_at_chat_send(gcd->chat, buf, none_prefix, + at_cgdata_cb, gc, NULL) > 0) + return; gcd->active_context = 0; + gcd->state = STATE_IDLE; - CALLBACK_WITH_FAILURE(cb, NULL, 0, NULL, NULL, NULL, NULL, cbd->data); + CALLBACK_WITH_FAILURE(gcd->up_cb, NULL, 0, NULL, NULL, NULL, NULL, + gcd->cb_data); } static void at_gprs_activate_primary(struct ofono_gprs_context *gc, @@ -114,18 +202,17 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc, ofono_gprs_context_up_cb_t cb, void *data) { struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); - struct cb_data *cbd = cb_data_new(cb, data); char buf[OFONO_GPRS_MAX_APN_LENGTH + 128]; int len; - if (!cbd) - goto error; - gcd->active_context = ctx->cid; + gcd->up_cb = cb; + gcd->cb_data = data; + memcpy(gcd->username, ctx->username, sizeof(ctx->username)); + memcpy(gcd->password, ctx->password, sizeof(ctx->password)); - cbd->user = gc; + gcd->state = STATE_ENABLING; - /* TODO: Handle username / password fields */ len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"", ctx->cid); if (ctx->apn) @@ -133,11 +220,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc, ctx->apn); if (g_at_chat_send(gcd->chat, buf, none_prefix, - at_cgdcont_cb, cbd, g_free) > 0) + at_cgdcont_cb, gc, NULL) > 0) return; -error: - if (cbd) - g_free(cbd); CALLBACK_WITH_FAILURE(cb, NULL, 0, NULL, NULL, NULL, NULL, data); } @@ -168,61 +252,6 @@ error: CALLBACK_WITH_FAILURE(cb, data); } -static void at_cgact_read_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); - gint cid, state; - GAtResultIter iter; - - if (!ok) - return; - - while (g_at_result_iter_next(&iter, "+CGACT:")) { - if (!g_at_result_iter_next_number(&iter, &cid)) - continue; - - if ((unsigned int) cid != gcd->active_context) - continue; - - if (!g_at_result_iter_next_number(&iter, &state)) - continue; - - if (state == 1) - continue; - - ofono_gprs_context_deactivated(gc, gcd->active_context); - gcd->active_context = 0; - - break; - } -} - -static void cgev_notify(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; - const char *event; - - if (!g_at_result_iter_next(&iter, "+CGEV:")) - return; - - if (!g_at_result_iter_next_unquoted_string(&iter, &event)) - return; - - if (g_str_has_prefix(event, "NW REACT ") || - g_str_has_prefix(event, "NW DEACT ") || - g_str_has_prefix(event, "ME DEACT ")) { - /* Ask what primary contexts are active now */ - g_at_chat_send(gcd->chat, "AT+CGACT?", cgact_prefix, - at_cgact_read_cb, gc, NULL); - - return; - } -} - static int at_gprs_context_probe(struct ofono_gprs_context *gc, unsigned int vendor, void *data) { @@ -232,8 +261,6 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc, gcd = g_new0(struct gprs_context_data, 1); gcd->chat = chat; - g_at_chat_register(gcd->chat, "+CGEV:", cgev_notify, FALSE, gc, NULL); - ofono_gprs_context_set_data(gc, gcd); return 0; -- 2.7.4