--- src/gprs.c | 916 ++++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 679 insertions(+), 237 deletions(-)
diff --git a/src/gprs.c b/src/gprs.c index 37e7aee..6edeef6 100644 --- a/src/gprs.c +++ b/src/gprs.c @@ -54,6 +54,7 @@ #define MAX_MESSAGE_CENTER_LENGTH 255 #define MAX_CONTEXTS 256 #define SUSPEND_TIMEOUT 8 +#define ACTIVATE_FAIL_DELAY 2 static GSList *g_drivers = NULL; static GSList *g_context_drivers = NULL; @@ -97,19 +98,11 @@ struct ofono_gprs { struct ofono_atom *atom; }; -struct ofono_gprs_context { - struct ofono_gprs *gprs; - enum ofono_gprs_context_type type; - ofono_bool_t inuse; - const struct ofono_gprs_context_driver *driver; - void *driver_data; - struct ofono_atom *atom; -}; +struct pri_context; -struct context_settings { - enum ofono_gprs_context_type type; +struct context_settings_ip { char *interface; - gboolean static_ip; + enum ofono_gprs_addrconf_method method; char *ip; char *netmask; char *gateway; @@ -117,21 +110,43 @@ struct context_settings { char *proxy; }; +struct context_settings_ipv6 { + char *interface; + char *address; + char **dns; +}; + +struct ofono_gprs_context { + struct ofono_gprs *gprs; + struct pri_context *pri; + enum ofono_gprs_context_type type; + enum ofono_gprs_proto proto; + struct context_settings_ip *settings_ip; + struct context_settings_ipv6 *settings_ipv6; + guint timer; + unsigned int cid; + const struct ofono_gprs_context_driver *driver; + void *driver_data; + struct ofono_atom *atom; +}; + struct pri_context { ofono_bool_t active; enum ofono_gprs_context_type type; char name[MAX_CONTEXT_NAME_LENGTH + 1]; char message_proxy[MAX_MESSAGE_PROXY_LENGTH + 1]; char message_center[MAX_MESSAGE_CENTER_LENGTH + 1]; + char apn[OFONO_GPRS_MAX_APN_LENGTH + 1]; + char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1]; + char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1]; + enum ofono_gprs_proto proto; unsigned int id; char *path; char *key; - struct context_settings *settings; char *proxy_host; uint16_t proxy_port; DBusMessage *pending; - struct ofono_gprs_primary_context context; - struct ofono_gprs_context *context_driver; + GSList *bearers; struct ofono_gprs *gprs; }; @@ -240,11 +255,26 @@ static gboolean gprs_proto_from_string(const char *str, } else if (g_str_equal(str, "ipv6")) { *proto = OFONO_GPRS_PROTO_IPV6; return TRUE; + } else if (g_str_equal(str, "ipv4v6")) { + *proto = OFONO_GPRS_PROTO_IPV4V6; + return TRUE; } return FALSE; } +static const char *gprs_addrconf_to_string(enum ofono_gprs_proto method) +{ + switch (method) { + case OFONO_GPRS_ADDRCONF_STATIC: + return "static"; + case OFONO_GPRS_ADDRCONF_DHCP: + return "dhcp"; + } + + return NULL; +} + static unsigned int gprs_cid_alloc(struct ofono_gprs *gprs) { return idmap_alloc(gprs->cid_map); @@ -270,21 +300,37 @@ static struct pri_context *gprs_context_by_path(struct ofono_gprs *gprs, return NULL; } -static void context_settings_free(struct context_settings *settings) +static void context_settings_free(struct ofono_gprs_context *gc) +{ + if (gc->settings_ip == NULL) + return; + + g_free(gc->settings_ip->interface); + g_free(gc->settings_ip->ip); + g_free(gc->settings_ip->netmask); + g_free(gc->settings_ip->gateway); + g_strfreev(gc->settings_ip->dns); + g_free(gc->settings_ip->proxy); + g_free(gc->settings_ip); + gc->settings_ip = NULL; +} + +static void context_ipv6settings_free(struct ofono_gprs_context *gc) { - g_free(settings->interface); - g_free(settings->ip); - g_free(settings->netmask); - g_free(settings->gateway); - g_strfreev(settings->dns); - g_free(settings->proxy); + if (gc->settings_ipv6 == NULL) + return; - g_free(settings); + g_free(gc->settings_ipv6->interface); + g_free(gc->settings_ipv6->address); + g_strfreev(gc->settings_ipv6->dns); + g_free(gc->settings_ipv6); + gc->settings_ipv6 = NULL; } -static void context_settings_append_variant(struct context_settings *settings, +static void context_settings_append_variant(struct ofono_gprs_context *gc, DBusMessageIter *iter) { + struct context_settings_ip *settings = gc->settings_ip; DBusMessageIter variant; DBusMessageIter array; char typesig[5]; @@ -306,22 +352,21 @@ static void context_settings_append_variant(struct context_settings *settings, if (settings == NULL) goto done; - ofono_dbus_dict_append(&array, "Interface", - DBUS_TYPE_STRING, &settings->interface); + if (settings->interface != NULL) + ofono_dbus_dict_append(&array, "Interface", + DBUS_TYPE_STRING, &settings->interface); - if (settings->type == OFONO_GPRS_CONTEXT_TYPE_MMS) { + if (gc->pri->type == OFONO_GPRS_CONTEXT_TYPE_MMS) { if (settings->proxy) ofono_dbus_dict_append(&array, "Proxy", DBUS_TYPE_STRING, &settings->proxy); goto done; } - if (settings->static_ip == TRUE) - method = "static"; - else - method = "dhcp"; - - ofono_dbus_dict_append(&array, "Method", DBUS_TYPE_STRING, &method); + method = gprs_addrconf_to_string(settings->method); + if (method != NULL) + ofono_dbus_dict_append(&array, "Method", DBUS_TYPE_STRING, + &method); if (settings->ip) ofono_dbus_dict_append(&array, "Address", DBUS_TYPE_STRING, @@ -346,7 +391,7 @@ done: dbus_message_iter_close_container(iter, &variant); } -static void context_settings_append_dict(struct context_settings *settings, +static void context_settings_append_dict(struct ofono_gprs_context *gc, DBusMessageIter *dict) { DBusMessageIter entry; @@ -357,14 +402,15 @@ static void context_settings_append_dict(struct context_settings *settings, dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); - context_settings_append_variant(settings, &entry); + context_settings_append_variant(gc, &entry); dbus_message_iter_close_container(dict, &entry); } -static void pri_context_signal_settings(struct pri_context *ctx) +static void context_signal_settings(struct ofono_gprs_context *gc) { DBusConnection *conn = ofono_dbus_get_connection(); + struct pri_context *ctx = gc->pri; const char *path = ctx->path; DBusMessage *signal; DBusMessageIter iter; @@ -374,6 +420,98 @@ static void pri_context_signal_settings(struct pri_context *ctx) OFONO_CONNECTION_CONTEXT_INTERFACE, "PropertyChanged"); + DBG("signal = %p", signal); + + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &iter); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &prop); + + context_settings_append_variant(gc, &iter); + + g_dbus_send_message(conn, signal); +} + +static void context_ipv6settings_append_variant(struct ofono_gprs_context *gc, + DBusMessageIter *iter) +{ + struct context_settings_ipv6 *settings = gc->settings_ipv6; + DBusMessageIter variant; + DBusMessageIter array; + char typesig[5]; + char arraysig[6]; + + arraysig[0] = DBUS_TYPE_ARRAY; + arraysig[1] = typesig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR; + arraysig[2] = typesig[1] = DBUS_TYPE_STRING; + arraysig[3] = typesig[2] = DBUS_TYPE_VARIANT; + arraysig[4] = typesig[3] = DBUS_DICT_ENTRY_END_CHAR; + arraysig[5] = typesig[4] = '\0'; + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + arraysig, &variant); + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, + typesig, &array); + + if (settings == NULL) + goto done; + + if (settings->interface != NULL) + ofono_dbus_dict_append(&array, "Interface", + DBUS_TYPE_STRING, &settings->interface); + + if (settings->address != NULL) { + uint8_t addr[16]; + char *strll = alloca(INET6_ADDRSTRLEN); + + inet_pton(AF_INET6, settings->address, addr); + memset(addr, 0, 8); + addr[0] = 0xf0; + addr[1] = 0x80; + inet_ntop(AF_INET6, addr, strll, INET6_ADDRSTRLEN); + ofono_dbus_dict_append(&array, "LinkLocal", DBUS_TYPE_STRING, &strll); + } + + if (settings->dns != NULL) + ofono_dbus_dict_append_array(&array, "DomainNameServers", + DBUS_TYPE_STRING, &settings->dns); +done: + dbus_message_iter_close_container(&variant, &array); + + dbus_message_iter_close_container(iter, &variant); +} + +static void context_ipv6settings_append_dict(struct ofono_gprs_context *gc, + DBusMessageIter *dict) +{ + DBusMessageIter entry; + const char *key = "IPv6Settings"; + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + context_ipv6settings_append_variant(gc, &entry); + + dbus_message_iter_close_container(dict, &entry); +} + +static void context_signal_ipv6settings(struct ofono_gprs_context *gc) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + struct pri_context *ctx = gc->pri; + const char *path = ctx->path; + DBusMessage *signal; + DBusMessageIter iter; + const char *prop = "IPv6Settings"; + + signal = dbus_message_new_signal(path, + OFONO_CONNECTION_CONTEXT_INTERFACE, + "PropertyChanged"); + if (signal == NULL) return; @@ -381,11 +519,28 @@ static void pri_context_signal_settings(struct pri_context *ctx) dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &prop); - context_settings_append_variant(ctx->settings, &iter); + context_ipv6settings_append_variant(gc, &iter); g_dbus_send_message(conn, signal); } +static void pri_context_settings_append_dict(struct pri_context *ctx, + DBusMessageIter *dict) +{ + struct ofono_gprs_context *ip = NULL, *ipv6 = NULL; + GSList *l; + + for (l = ctx->bearers; l; l = l->next) { + struct ofono_gprs_context *gc = l->data; + + if (gc->settings_ip) + context_settings_append_dict(gc, dict); + + if (gc->settings_ipv6) + context_ipv6settings_append_dict(gc, dict); + } +} + static void pri_parse_proxy(struct pri_context *ctx, const char *proxy) { char *scheme, *host, *port, *path; @@ -552,78 +707,62 @@ static void pri_setproxy(const char *interface, const char *proxy) static void pri_reset_context_settings(struct pri_context *ctx) { - char *interface; - - if (ctx->settings == NULL) - return; - - interface = ctx->settings->interface; - ctx->settings->interface = NULL; - - context_settings_free(ctx->settings); - ctx->settings = NULL; - - pri_context_signal_settings(ctx); - if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS) { - pri_setaddr(interface, NULL); - g_free(ctx->proxy_host); ctx->proxy_host = NULL; ctx->proxy_port = 0; } - - pri_ifupdown(interface, FALSE); - - g_free(interface); } -static void pri_update_context_settings(struct pri_context *ctx, - const char *interface, - ofono_bool_t static_ip, - const char *ip, const char *netmask, - const char *gateway, const char **dns) +static void pri_update_context_settings(struct pri_context *ctx) { - if (ctx->settings) - context_settings_free(ctx->settings); + struct ofono_gprs_context *ip = NULL, *ipv6 = NULL; + GSList *l; - ctx->settings = g_try_new0(struct context_settings, 1); - if (ctx->settings == NULL) - return; + for (l = ctx->bearers; l; l = l->next) { + struct ofono_gprs_context *gc = l->data; - ctx->settings->type = ctx->type; + if (gc->settings_ip != NULL) + ip = gc; - ctx->settings->interface = g_strdup(interface); - ctx->settings->static_ip = static_ip; - ctx->settings->ip = g_strdup(ip); - ctx->settings->netmask = g_strdup(netmask); - ctx->settings->gateway = g_strdup(gateway); - ctx->settings->dns = g_strdupv((char **)dns); + if (gc->settings_ipv6 != NULL) + ipv6 = gc; + } - if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS && ctx->message_proxy) - ctx->settings->proxy = g_strdup(ctx->message_proxy); + if (ip != NULL) { + pri_ifupdown(ip->settings_ip->interface, TRUE); - pri_ifupdown(interface, TRUE); + if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS && + ctx->message_proxy != NULL) { + ip->settings_ip->proxy = g_strdup(ctx->message_proxy); + pri_parse_proxy(ctx, ctx->message_proxy); - if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS) { - pri_parse_proxy(ctx, ctx->message_proxy); + DBG("proxy %s port %u", ctx->proxy_host, + ctx->proxy_port); + + pri_setaddr(ip->settings_ip->interface, + ip->settings_ip->ip); - DBG("proxy %s port %u", ctx->proxy_host, ctx->proxy_port); + if (ctx->proxy_host) + pri_setproxy(ip->settings_ip->interface, + ctx->proxy_host); - pri_setaddr(interface, ip); + } - if (ctx->proxy_host) - pri_setproxy(interface, ctx->proxy_host); + context_signal_settings(ip); } - pri_context_signal_settings(ctx); + if (ipv6 != NULL) { + pri_ifupdown(ipv6->settings_ipv6->interface, TRUE); + context_signal_ipv6settings(ipv6); + } } static void append_context_properties(struct pri_context *ctx, DBusMessageIter *dict) { const char *type = gprs_context_type_to_string(ctx->type); - const char *proto = gprs_proto_to_string(ctx->context.proto); + const char *proto = gprs_proto_to_string(ctx->proto); const char *name = ctx->name; dbus_bool_t value; const char *strvalue; @@ -637,15 +776,15 @@ static void append_context_properties(struct pri_context *ctx, ofono_dbus_dict_append(dict, "Protocol", DBUS_TYPE_STRING, &proto); - strvalue = ctx->context.apn; + strvalue = ctx->apn; ofono_dbus_dict_append(dict, "AccessPointName", DBUS_TYPE_STRING, &strvalue); - strvalue = ctx->context.username; + strvalue = ctx->username; ofono_dbus_dict_append(dict, "Username", DBUS_TYPE_STRING, &strvalue); - strvalue = ctx->context.password; + strvalue = ctx->password; ofono_dbus_dict_append(dict, "Password", DBUS_TYPE_STRING, &strvalue); @@ -659,7 +798,7 @@ static void append_context_properties(struct pri_context *ctx, DBUS_TYPE_STRING, &strvalue); } - context_settings_append_dict(ctx->settings, dict); + pri_context_settings_append_dict(ctx, dict); } static DBusMessage *pri_get_properties(DBusConnection *conn, @@ -685,44 +824,243 @@ static DBusMessage *pri_get_properties(DBusConnection *conn, return reply; } -static void pri_activate_callback(const struct ofono_error *error, - const char *interface, - ofono_bool_t static_ip, - const char *ip, const char *netmask, - const char *gateway, const char **dns, - void *data) +static void pri_context_activated(struct pri_context *ctx) { - struct pri_context *ctx = data; DBusConnection *conn = ofono_dbus_get_connection(); dbus_bool_t value; - DBG("%p %s", ctx, interface); + ctx->active = TRUE; + __ofono_dbus_pending_reply(&ctx->pending, + dbus_message_new_method_return(ctx->pending)); + + pri_update_context_settings(ctx); + + value = ctx->active; + ofono_dbus_signal_property_changed(conn, ctx->path, + OFONO_CONNECTION_CONTEXT_INTERFACE, + "Active", DBUS_TYPE_BOOLEAN, &value); +} + +static struct ofono_gprs_context *assign_packet_bearer(struct pri_context *ctx) +{ + struct ofono_gprs *gprs = ctx->gprs; + struct idmap *cidmap = gprs->cid_map; + unsigned int cid_min, cid; + GSList *l; + + if (cidmap == NULL) + return NULL; + + cid_min = idmap_get_min(cidmap); + + cid = gprs_cid_alloc(gprs); + if (cid == 0) + return NULL; + + for (l = gprs->context_drivers; l; l = l->next) { + struct ofono_gprs_context *gc = l->data; + + if (gc->pri != NULL) + continue; + + if (gc->type == OFONO_GPRS_CONTEXT_TYPE_ANY || + gc->type == ctx->type) { + gc->cid = cid; + gc->pri = ctx; + ctx->bearers = g_slist_prepend(ctx->bearers, gc); + return gc; + } + } + + return NULL; +} + +static void release_packet_bearer(struct ofono_gprs_context *gc) +{ + struct pri_context *ctx; + ofono_bool_t ip, ipv6; + + if (gc == NULL) + return; + + ctx = gc->pri; + + if (gc->settings_ip != NULL) { + if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS) + pri_setaddr(gc->settings_ip->interface, NULL); + + pri_ifupdown(gc->settings_ip->interface, FALSE); + context_settings_free(gc); + + if (ctx->active == TRUE) + context_signal_settings(gc); + } + + if (gc->settings_ipv6 != NULL) { + pri_ifupdown(gc->settings_ipv6->interface, FALSE); + context_ipv6settings_free(gc); + + if (ctx->active == TRUE) + context_signal_ipv6settings(gc); + } + + if (gc->timer) { + g_source_remove(gc->timer); + gc->timer = 0; + } + + gprs_cid_release(ctx->gprs, gc->cid); + gc->cid = 0; + ctx->bearers = g_slist_remove(ctx->bearers, gc); + gc->pri = NULL; +} + +static void pri_activate_error(struct pri_context *ctx) +{ + __ofono_dbus_pending_reply(&ctx->pending, + __ofono_error_failed(ctx->pending)); + + while (ctx->bearers != NULL) + release_packet_bearer(ctx->bearers->data); +} + +static gboolean pri_activate_next(gpointer data); + +static void pri_activate_context_callback(const struct ofono_error *error, + ofono_bool_t single_bearers, + void *data) +{ + struct ofono_gprs_context *gc = data; + struct pri_context *ctx = gc->pri; + enum ofono_gprs_proto proto = gc->proto; + int bearers = g_slist_length(ctx->bearers); + + if (ctx == NULL) + return; if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { - DBG("Activating context failed with error: %s", + + if (bearers > 1) { + DBG("Activating second bearer failed with error: %s", telephony_error_to_str(error)); - __ofono_dbus_pending_reply(&ctx->pending, - __ofono_error_failed(ctx->pending)); + release_packet_bearer(gc); + pri_context_activated(ctx); + return; + } - gprs_cid_release(ctx->gprs, ctx->context.cid); - ctx->context.cid = 0; - ctx->context_driver->inuse = FALSE; - ctx->context_driver = NULL; + DBG("Activating bearer failed with error: %s", + telephony_error_to_str(error)); + + if (ctx->proto != OFONO_GPRS_PROTO_IPV4V6 || + proto == OFONO_GPRS_PROTO_IPV6) { + pri_activate_error(ctx); + return; + } + + /* Retry first bearer with different protocol */ + if (proto == OFONO_GPRS_PROTO_IPV4V6) + gc->proto = OFONO_GPRS_PROTO_IP; + else + gc->proto = OFONO_GPRS_PROTO_IPV6; + gc->timer = g_timeout_add_seconds(ACTIVATE_FAIL_DELAY, + pri_activate_next, gc); return; } - ctx->active = TRUE; + if (ctx->proto != OFONO_GPRS_PROTO_IPV4V6 || single_bearers == FALSE || + bearers > 1 || gc->proto == OFONO_GPRS_PROTO_IPV6) { + pri_context_activated(ctx); + return; + } + + /* Activate second bearer */ + if (gc->settings_ip == NULL) + proto = OFONO_GPRS_PROTO_IP; + else + proto = OFONO_GPRS_PROTO_IPV6; + + gc = assign_packet_bearer(ctx); + if (gc == NULL) { + /* No suitable driver. Go with a single bearer. */ + pri_context_activated(ctx); + return; + } + + gc->proto = proto; + gc->timer = g_timeout_add_seconds(0, pri_activate_next, gc); +} + +static gboolean pri_activate_next(gpointer data) +{ + struct ofono_gprs_context *gc = data; + struct pri_context *ctx = gc->pri; + + gc->timer = 0; + gc->driver->activate_primary_new(gc, gc->cid, ctx->apn, gc->proto, + ctx->username, ctx->password, + pri_activate_context_callback, + gc); + return FALSE; +} + +/* Backward compatibility hack (to be removed) ==> */ + +static void pri_activate_callback_shim(const struct ofono_error *error, + const char *interface, ofono_bool_t static_ip, + const char *address, const char *netmask, + const char *gw, const char **dns, void *data) +{ + struct ofono_gprs_context *gc = data; + + if (error->type == OFONO_ERROR_TYPE_NO_ERROR) { + ofono_gprs_context_set_ip_interface(gc, interface); + ofono_gprs_context_set_ip_addrconf(gc, static_ip ? + OFONO_GPRS_ADDRCONF_STATIC : + OFONO_GPRS_ADDRCONF_DHCP); + ofono_gprs_context_set_ip_address(gc, address); + ofono_gprs_context_set_ip_netmask(gc, netmask); + ofono_gprs_context_set_ip_gateway(gc, gw); + ofono_gprs_context_set_ip_dns_servers(gc, dns); + } + + pri_activate_context_callback(error, FALSE, data); +} + +static void activate_primary_shim(struct ofono_gprs_context *gc, + unsigned int id, + const char *apn, + enum ofono_gprs_proto proto, + const char *username, + const char *password, + void *data) +{ + struct ofono_gprs_primary_context context; + + memset(&context, 0, sizeof(context)); + context.cid = gc->cid; + strncpy(context.apn, apn, OFONO_GPRS_MAX_APN_LENGTH); + strncpy(context.username, username, OFONO_GPRS_MAX_USERNAME_LENGTH); + strncpy(context.password, password, OFONO_GPRS_MAX_PASSWORD_LENGTH); + context.proto = proto; + + gc->driver->activate_primary(gc, &context, pri_activate_callback_shim, + data); +} + +/* <== end of backward compatiblity hack */ + +static void pri_context_deactivated(struct pri_context *ctx) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + dbus_bool_t value; + + ctx->active = FALSE; + __ofono_dbus_pending_reply(&ctx->pending, dbus_message_new_method_return(ctx->pending)); - /* - * If we don't have the interface, don't bother emitting any settings, - * as nobody can make use of them - */ - if (interface != NULL) - pri_update_context_settings(ctx, interface, static_ip, - ip, netmask, gateway, dns); + pri_reset_context_settings(ctx); value = ctx->active; ofono_dbus_signal_property_changed(conn, ctx->path, @@ -730,11 +1068,11 @@ static void pri_activate_callback(const struct ofono_error *error, "Active", DBUS_TYPE_BOOLEAN, &value); } -static void pri_deactivate_callback(const struct ofono_error *error, void *data) +static void pri_deactivate_callback(const struct ofono_error *error, + void *data) { - struct pri_context *ctx = data; - DBusConnection *conn = ofono_dbus_get_connection(); - dbus_bool_t value; + struct ofono_gprs_context *gc = data; + struct pri_context *ctx = gc->pri; if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { DBG("Deactivating context failed with error: %s", @@ -744,21 +1082,16 @@ static void pri_deactivate_callback(const struct ofono_error *error, void *data) return; } - gprs_cid_release(ctx->gprs, ctx->context.cid); - ctx->context.cid = 0; - ctx->active = FALSE; - ctx->context_driver->inuse = FALSE; - ctx->context_driver = NULL; - - __ofono_dbus_pending_reply(&ctx->pending, - dbus_message_new_method_return(ctx->pending)); + release_packet_bearer(gc); - pri_reset_context_settings(ctx); + if (ctx->bearers != NULL) { + gc = ctx->bearers->data; + gc->driver->deactivate_primary(gc, gc->cid, + pri_deactivate_callback, gc); + return; + } - value = ctx->active; - ofono_dbus_signal_property_changed(conn, ctx->path, - OFONO_CONNECTION_CONTEXT_INTERFACE, - "Active", DBUS_TYPE_BOOLEAN, &value); + pri_context_deactivated(ctx); } static DBusMessage *pri_set_apn(struct pri_context *ctx, DBusConnection *conn, @@ -769,13 +1102,13 @@ static DBusMessage *pri_set_apn(struct pri_context *ctx, DBusConnection *conn, if (strlen(apn) > OFONO_GPRS_MAX_APN_LENGTH) return __ofono_error_invalid_format(msg); - if (g_str_equal(apn, ctx->context.apn)) + if (g_str_equal(apn, ctx->apn)) return dbus_message_new_method_return(msg); if (is_valid_apn(apn) == FALSE) return __ofono_error_invalid_format(msg); - strcpy(ctx->context.apn, apn); + strcpy(ctx->apn, apn); if (settings) { g_key_file_set_string(settings, ctx->key, @@ -802,10 +1135,10 @@ static DBusMessage *pri_set_username(struct pri_context *ctx, if (strlen(username) > OFONO_GPRS_MAX_USERNAME_LENGTH) return __ofono_error_invalid_format(msg); - if (g_str_equal(username, ctx->context.username)) + if (g_str_equal(username, ctx->username)) return dbus_message_new_method_return(msg); - strcpy(ctx->context.username, username); + strcpy(ctx->username, username); if (settings) { g_key_file_set_string(settings, ctx->key, @@ -832,10 +1165,10 @@ static DBusMessage *pri_set_password(struct pri_context *ctx, if (strlen(password) > OFONO_GPRS_MAX_PASSWORD_LENGTH) return __ofono_error_invalid_format(msg); - if (g_str_equal(password, ctx->context.password)) + if (g_str_equal(password, ctx->password)) return dbus_message_new_method_return(msg); - strcpy(ctx->context.password, password); + strcpy(ctx->password, password); if (settings) { g_key_file_set_string(settings, ctx->key, @@ -891,10 +1224,10 @@ static DBusMessage *pri_set_proto(struct pri_context *ctx, if (gprs_proto_from_string(str, &proto) == FALSE) return __ofono_error_invalid_format(msg); - if (ctx->context.proto == proto) + if (ctx->proto == proto) return dbus_message_new_method_return(msg); - ctx->context.proto = proto; + ctx->proto = proto; if (settings) { g_key_file_set_string(settings, ctx->key, "Protocol", str); @@ -995,42 +1328,11 @@ static DBusMessage *pri_set_message_center(struct pri_context *ctx, return NULL; } -static gboolean assign_context(struct pri_context *ctx) -{ - struct idmap *cidmap = ctx->gprs->cid_map; - unsigned int cid_min; - GSList *l; - - if (cidmap == NULL) - return FALSE; - - cid_min = idmap_get_min(cidmap); - - ctx->context.cid = gprs_cid_alloc(ctx->gprs); - if (ctx->context.cid == 0) - return FALSE; - - for (l = ctx->gprs->context_drivers; l; l = l->next) { - struct ofono_gprs_context *gc = l->data; - - if (gc->inuse == TRUE) - continue; - - if (gc->type == OFONO_GPRS_CONTEXT_TYPE_ANY || - gc->type == ctx->type) { - ctx->context_driver = gc; - ctx->context_driver->inuse = TRUE; - return TRUE; - } - } - - return FALSE; -} - static DBusMessage *pri_set_property(DBusConnection *conn, DBusMessage *msg, void *data) { struct pri_context *ctx = data; + struct ofono_gprs *gprs = ctx->gprs; DBusMessageIter iter; DBusMessageIter var; const char *property; @@ -1052,9 +1354,9 @@ static DBusMessage *pri_set_property(DBusConnection *conn, dbus_message_iter_recurse(&iter, &var); if (g_str_equal(property, "Active")) { - struct ofono_gprs_context *gc; + struct ofono_gprs_context *gc = NULL; - if (ctx->gprs->pending) + if (gprs->pending) return __ofono_error_busy(msg); if (ctx->pending) @@ -1068,31 +1370,49 @@ static DBusMessage *pri_set_property(DBusConnection *conn, if (ctx->active == (ofono_bool_t) value) return dbus_message_new_method_return(msg); - if (value && !ctx->gprs->attached) + if (value && !gprs->attached) return __ofono_error_not_attached(msg); - if (ctx->gprs->flags & GPRS_FLAG_ATTACHING) + if (gprs->flags & GPRS_FLAG_ATTACHING) return __ofono_error_attach_in_progress(msg); - if (value) { - if (assign_context(ctx) == FALSE) - return __ofono_error_not_implemented(msg); - } + if (value) + gc = assign_packet_bearer(ctx); + else if (ctx->bearers != NULL) + gc = ctx->bearers->data; - gc = ctx->context_driver; if (gc == NULL || gc->driver == NULL || - gc->driver->activate_primary == NULL || + (gc->driver->activate_primary == NULL && + gc->driver->activate_primary_new == NULL) || gc->driver->deactivate_primary == NULL) return __ofono_error_not_implemented(msg); ctx->pending = dbus_message_ref(msg); - if (value) - gc->driver->activate_primary(gc, &ctx->context, - pri_activate_callback, ctx); - else - gc->driver->deactivate_primary(gc, ctx->context.cid, - pri_deactivate_callback, ctx); + if (value) { + gc->proto = ctx->proto; + /* Backward compatiblity hack (to be removed) ==> */ + if (gc->driver->activate_primary_new == NULL) + activate_primary_shim(gc, + gc->cid, + ctx->apn, + gc->proto, + ctx->username, + ctx->password, + gc); + else + /* <== end of backward compatiblity hack */ + gc->driver->activate_primary_new(gc, + gc->cid, + ctx->apn, + gc->proto, + ctx->username, + ctx->password, + pri_activate_context_callback, + gc); + } else + gc->driver->deactivate_primary(gc, gc->cid, + pri_deactivate_callback, gc); return NULL; } @@ -1207,10 +1527,7 @@ static void pri_context_destroy(gpointer userdata) { struct pri_context *ctx = userdata; - if (ctx->settings) { - context_settings_free(ctx->settings); - ctx->settings = NULL; - } + pri_reset_context_settings(ctx); g_free(ctx->proxy_host); @@ -1344,13 +1661,10 @@ static void gprs_attached_update(struct ofono_gprs *gprs) if (ctx->active == FALSE) continue; - gprs_cid_release(gprs, ctx->context.cid); - ctx->context.cid = 0; ctx->active = FALSE; - ctx->context_driver->inuse = FALSE; - ctx->context_driver = NULL; - pri_reset_context_settings(ctx); + while (ctx->bearers != NULL) + release_packet_bearer(ctx->bearers->data); value = FALSE; ofono_dbus_signal_property_changed(conn, ctx->path, @@ -1597,15 +1911,15 @@ static void write_context_settings(struct ofono_gprs *gprs, g_key_file_set_string(gprs->settings, context->key, "Name", context->name); g_key_file_set_string(gprs->settings, context->key, - "AccessPointName", context->context.apn); + "AccessPointName", context->apn); g_key_file_set_string(gprs->settings, context->key, - "Username", context->context.username); + "Username", context->username); g_key_file_set_string(gprs->settings, context->key, - "Password", context->context.password); + "Password", context->password); g_key_file_set_string(gprs->settings, context->key, "Type", gprs_context_type_to_string(context->type)); g_key_file_set_string(gprs->settings, context->key, "Protocol", - gprs_proto_to_string(context->context.proto)); + gprs_proto_to_string(context->proto)); } static struct pri_context *add_context(struct ofono_gprs *gprs, @@ -1711,7 +2025,8 @@ static DBusMessage *gprs_add_context(DBusConnection *conn, static void gprs_deactivate_for_remove(const struct ofono_error *error, void *data) { - struct pri_context *ctx = data; + struct ofono_gprs_context *gc = data; + struct pri_context *ctx = gc->pri; struct ofono_gprs *gprs = ctx->gprs; DBusConnection *conn; char *path; @@ -1726,10 +2041,14 @@ static void gprs_deactivate_for_remove(const struct ofono_error *error, return; } - gprs_cid_release(gprs, ctx->context.cid); - ctx->context.cid = 0; - ctx->context_driver->inuse = FALSE; - ctx->context_driver = NULL; + release_packet_bearer(gc); + + if (ctx->bearers != NULL) { + gc = ctx->bearers->data; + gc->driver->deactivate_primary(gc, gc->cid, + gprs_deactivate_for_remove, gc); + return; + } if (gprs->settings) { g_key_file_remove_group(gprs->settings, ctx->key, NULL); @@ -1776,15 +2095,16 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn, return __ofono_error_not_found(msg); if (ctx->active) { - struct ofono_gprs_context *gc = ctx->context_driver; + struct ofono_gprs_context *gc; /* This context is already being messed with */ if (ctx->pending) return __ofono_error_busy(msg); gprs->pending = dbus_message_ref(msg); - gc->driver->deactivate_primary(gc, ctx->context.cid, - gprs_deactivate_for_remove, ctx); + gc = ctx->bearers->data; + gc->driver->deactivate_primary(gc, gc->cid, + gprs_deactivate_for_remove, gc); return NULL; } @@ -1810,7 +2130,8 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn, static void gprs_deactivate_for_all(const struct ofono_error *error, void *data) { - struct pri_context *ctx = data; + struct ofono_gprs_context *gc = data; + struct pri_context *ctx = gc->pri; struct ofono_gprs *gprs = ctx->gprs; DBusConnection *conn; dbus_bool_t value; @@ -1821,12 +2142,16 @@ static void gprs_deactivate_for_all(const struct ofono_error *error, return; } - gprs_cid_release(gprs, ctx->context.cid); - ctx->active = FALSE; - ctx->context.cid = 0; - ctx->context_driver->inuse = FALSE; - ctx->context_driver = NULL; + release_packet_bearer(gc); + + if (ctx->bearers != NULL) { + gc = ctx->bearers->data; + gc->driver->deactivate_primary(gc, gc->cid, + gprs_deactivate_for_all, gc); + return; + } + ctx->active = FALSE; pri_reset_context_settings(ctx); value = ctx->active; @@ -1850,9 +2175,9 @@ static void gprs_deactivate_next(struct ofono_gprs *gprs) if (ctx->active == FALSE) continue; - gc = ctx->context_driver; - gc->driver->deactivate_primary(gc, ctx->context.cid, - gprs_deactivate_for_all, ctx); + gc = ctx->bearers->data; + gc->driver->deactivate_primary(gc, gc->cid, + gprs_deactivate_for_all, gc); return; } @@ -2062,34 +2387,23 @@ void ofono_gprs_context_deactivated(struct ofono_gprs_context *gc, { DBusConnection *conn = ofono_dbus_get_connection(); GSList *l; - struct pri_context *ctx; + struct pri_context *ctx = gc->pri; dbus_bool_t value; - if (gc->gprs == NULL) + if (gc->gprs == NULL || ctx == NULL || ctx->active == FALSE) return; - for (l = gc->gprs->contexts; l; l = l->next) { - ctx = l->data; - - if (ctx->context.cid != cid) - continue; - - if (ctx->active == FALSE) - break; - - gprs_cid_release(ctx->gprs, ctx->context.cid); - ctx->context.cid = 0; - ctx->active = FALSE; - ctx->context_driver->inuse = FALSE; - ctx->context_driver = NULL; + release_packet_bearer(gc); - pri_reset_context_settings(ctx); + if (ctx->bearers != NULL) + return; - value = FALSE; - ofono_dbus_signal_property_changed(conn, ctx->path, + ctx->active = FALSE; + pri_reset_context_settings(ctx); + value = FALSE; + ofono_dbus_signal_property_changed(conn, ctx->path, OFONO_CONNECTION_CONTEXT_INTERFACE, "Active", DBUS_TYPE_BOOLEAN, &value); - } } int ofono_gprs_context_driver_register(const struct ofono_gprs_context_driver *d) @@ -2120,6 +2434,9 @@ static void gprs_context_remove(struct ofono_atom *atom) if (gc == NULL) return; + if (gc->pri != NULL) + release_packet_bearer(gc); + if (gc->driver && gc->driver->remove) gc->driver->remove(gc); @@ -2192,6 +2509,131 @@ void ofono_gprs_context_set_type(struct ofono_gprs_context *gc, gc->type = type; } +static struct context_settings_ip *get_ip_settings(struct ofono_gprs_context *gc) +{ + if (gc == NULL) + return NULL; + + if (gc->settings_ip == NULL) + gc->settings_ip = g_try_new0(struct context_settings_ip, 1); + + return gc->settings_ip; +} + +void ofono_gprs_context_set_ip_interface(struct ofono_gprs_context *gc, + const char *interface) +{ + struct context_settings_ip *settings = get_ip_settings(gc); + + if (settings == NULL || settings->interface != NULL) + return; + + settings->interface = g_strdup(interface); +} + +void ofono_gprs_context_set_ip_addrconf(struct ofono_gprs_context *gc, + enum ofono_gprs_addrconf_method method) +{ + struct context_settings_ip *settings = get_ip_settings(gc); + + if (settings == NULL || settings->method != OFONO_GPRS_ADDRCONF_NONE) + return; + + settings->method = method; +} + +void ofono_gprs_context_set_ip_address(struct ofono_gprs_context *gc, + const char *address) +{ + struct context_settings_ip *settings = get_ip_settings(gc); + + if (settings == NULL || settings->ip != NULL) + return; + + settings->ip = g_strdup(address); +} + +void ofono_gprs_context_set_ip_netmask(struct ofono_gprs_context *gc, + const char *netmask) +{ + struct context_settings_ip *settings = get_ip_settings(gc); + + if (settings == NULL || settings->netmask != NULL) + return; + + settings->netmask = g_strdup(netmask); +} + +void ofono_gprs_context_set_ip_gateway(struct ofono_gprs_context *gc, + const char *gateway) +{ + struct context_settings_ip *settings = get_ip_settings(gc); + + if (settings == NULL || settings->gateway != NULL) + return; + + settings->gateway = g_strdup(gateway); +} + +void ofono_gprs_context_set_ip_dns_servers(struct ofono_gprs_context *gc, + const char **dns) +{ + struct context_settings_ip *settings = get_ip_settings(gc); + + if (settings == NULL || settings->dns != NULL) + return; + + settings->dns = g_strdupv((char **)dns); +} + +static struct context_settings_ipv6 *get_ipv6_settings(struct ofono_gprs_context *gc) +{ + if (gc == NULL) + return NULL; + + if (gc->settings_ipv6 == NULL) { + gc->settings_ipv6 = g_try_new0(struct context_settings_ipv6, 1); + + if (gc->settings_ipv6 == NULL) + return NULL; + } + + return gc->settings_ipv6; +} + +void ofono_gprs_context_set_ipv6_interface(struct ofono_gprs_context *gc, + const char *interface) +{ + struct context_settings_ipv6 *settings = get_ipv6_settings(gc); + + if (settings == NULL || settings->interface != NULL) + return; + + settings->interface = g_strdup(interface); +} + +void ofono_gprs_context_set_ipv6_address(struct ofono_gprs_context *gc, + const char *address) +{ + struct context_settings_ipv6 *settings = get_ipv6_settings(gc); + + if (settings == NULL || settings->address != NULL) + return; + + settings->address = g_strdup(address); +} + +void ofono_gprs_context_set_ipv6_dns_servers(struct ofono_gprs_context *gc, + const char **dns) +{ + struct context_settings_ipv6 *settings = get_ipv6_settings(gc); + + if (settings == NULL || settings->dns != NULL) + return; + + settings->dns = g_strdupv((char **)dns); +} + int ofono_gprs_driver_register(const struct ofono_gprs_driver *d) { DBG("driver: %p, name: %s", d, d->name); @@ -2431,10 +2873,10 @@ static gboolean load_context(struct ofono_gprs *gprs, const char *group) idmap_take(gprs->pid_map, id); context->id = id; - strcpy(context->context.username, username); - strcpy(context->context.password, password); - strcpy(context->context.apn, apn); - context->context.proto = proto; + strcpy(context->username, username); + strcpy(context->password, password); + strcpy(context->apn, apn); + context->proto = proto; if (msgproxy != NULL) strcpy(context->message_proxy, msgproxy); -- 1.7.1 _______________________________________________ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono