CONNMAN_SESSION_STATE_ONLINE = 2,
};
-enum connman_session_type {
- CONNMAN_SESSION_TYPE_ANY = 0,
- CONNMAN_SESSION_TYPE_LOCAL = 1,
- CONNMAN_SESSION_TYPE_INTERNET = 2,
-};
-
-enum connman_session_roaming_policy {
- CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN = 0,
- CONNMAN_SESSION_ROAMING_POLICY_DEFAULT = 1,
- CONNMAN_SESSION_ROAMING_POLICY_ALWAYS = 2,
- CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN = 3,
- CONNMAN_SESSION_ROAMING_POLICY_NATIONAL = 4,
- CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL = 5,
-};
-
struct service_entry {
/* track why this service was selected */
enum connman_session_reason reason;
};
struct session_info {
+ struct connman_session_config config;
enum connman_session_state state;
- enum connman_session_type type;
- connman_bool_t priority;
- GSList *allowed_bearers;
- enum connman_session_roaming_policy roaming_policy;
-
struct service_entry *entry;
enum connman_session_reason reason;
};
connman_bool_t append_all;
struct session_info *info;
struct session_info *info_last;
+ struct connman_session_config *policy_config;
connman_bool_t ecall;
GHashTable *service_hash;
};
-struct bearer_info {
- char *name;
- connman_bool_t match_all;
- enum connman_service_type service_type;
-};
-
static const char *trigger2string(enum connman_session_trigger trigger)
{
switch (trigger) {
static const char *type2string(enum connman_session_type type)
{
switch (type) {
- case CONNMAN_SESSION_TYPE_ANY:
+ case CONNMAN_SESSION_TYPE_UNKNOWN:
return "";
+ case CONNMAN_SESSION_TYPE_ANY:
+ return "any";
case CONNMAN_SESSION_TYPE_LOCAL:
return "local";
case CONNMAN_SESSION_TYPE_INTERNET:
static enum connman_session_type string2type(const char *type)
{
+ if (g_strcmp0(type, "any") == 0)
+ return CONNMAN_SESSION_TYPE_ANY;
if (g_strcmp0(type, "local") == 0)
return CONNMAN_SESSION_TYPE_LOCAL;
else if (g_strcmp0(type, "internet") == 0)
return CONNMAN_SESSION_TYPE_INTERNET;
- return CONNMAN_SESSION_TYPE_ANY;
-}
-
-static enum connman_session_roaming_policy string2roamingpolicy(const char *policy)
-{
- if (g_strcmp0(policy, "default") == 0)
- return CONNMAN_SESSION_ROAMING_POLICY_DEFAULT;
- else if (g_strcmp0(policy, "always") == 0)
- return CONNMAN_SESSION_ROAMING_POLICY_ALWAYS;
- else if (g_strcmp0(policy, "forbidden") == 0)
- return CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN;
- else if (g_strcmp0(policy, "national") == 0)
- return CONNMAN_SESSION_ROAMING_POLICY_NATIONAL;
- else if (g_strcmp0(policy, "international") == 0)
- return CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL;
- else
- return CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN;
+ return CONNMAN_SESSION_TYPE_UNKNOWN;
}
static enum connman_service_type bearer2service(const char *bearer)
return "";
}
-static int policy_get_bool(struct connman_session *session, const char *id,
- const char *key, connman_bool_t *val)
-{
- if (session->policy == NULL) {
- *val = FALSE;
- return -EINVAL;
- }
-
- return (*session->policy->get_bool)(id, key, val);
-}
-
-static int policy_get_string(struct connman_session *session, const char *id,
- const char *key, char **val)
-{
- if (session->policy == NULL) {
- *val = NULL;
- return -EINVAL;
- }
-
- return (*session->policy->get_string)(id, key, val);
-}
-
static int assign_policy_plugin(struct connman_session *session)
{
GSList *list;
return 0;
}
+static int create_policy_config(struct connman_session *session)
+{
+ struct connman_session_config *config;
+
+ if (session->policy == NULL)
+ config = connman_session_create_default_config();
+ else
+ config = (*session->policy->create)(session);
+
+ if (config == NULL)
+ return -ENOMEM;
+
+ session->policy_config = config;
+
+ return 0;
+}
+
+static void destroy_policy_config(struct connman_session *session)
+{
+ if (session->policy == NULL) {
+ connman_session_free_bearers(
+ session->policy_config->allowed_bearers);
+ g_free(session->policy_config);
+ } else {
+ (*session->policy->destroy)(session);
+ }
+}
+
static void probe_policy(struct connman_session_policy *policy)
{
return policy2->priority - policy1->priority;
}
-static struct connman_session *session_lookup_by_id(const char *id)
-{
- struct connman_session *session;
- GHashTableIter iter;
- gpointer key, value;
-
- DBG("id %s", id);
-
- g_hash_table_iter_init(&iter, session_hash);
-
- while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
- session = value;
- if (g_strcmp0(session->owner, id) == FALSE)
- continue;
+int connman_session_policy_register(struct connman_session_policy *policy)
+{
+ DBG("name %s", policy->name);
- return session;
- }
+ policy_list = g_slist_insert_sorted(policy_list, policy,
+ compare_priority);
- DBG("No session found by id %s", id);
+ probe_policy(policy);
- return NULL;
+ return 0;
}
-int connman_session_update_bool(const char *id, const char *key,
- connman_bool_t val)
+void connman_session_policy_unregister(struct connman_session_policy *policy)
{
- struct connman_session *session;
- struct session_info *info;
-
- session = session_lookup_by_id(id);
- if (session == NULL)
- return -EINVAL;
-
- info = session->info;
- if (info == NULL)
- return 0;
+ DBG("name %s", policy->name);
- DBG("%s %d", key, val);
+ policy_list = g_slist_remove(policy_list, policy);
- return -EINVAL;
+ remove_policy(policy);
}
-int connman_session_update_string(const char *id, const char *key,
- const char *val)
+struct connman_session_config *connman_session_create_default_config(void)
{
- struct connman_session *session;
- struct session_info *info;
+ struct connman_session_config *config;
- session = session_lookup_by_id(id);
- if (session == NULL)
- return -EINVAL;
-
- info = session->info;
- if (info == NULL)
- return 0;
+ config = g_try_new0(struct connman_session_config, 1);
+ if (config == NULL)
+ return NULL;
- DBG("%s %s", key, val);
+ config->priority = FALSE;
+ config->roaming_policy = CONNMAN_SESSION_ROAMING_POLICY_DEFAULT;
+ config->type = CONNMAN_SESSION_TYPE_ANY;
+ config->ecall = FALSE;
+ config->allowed_bearers = connman_session_allowed_bearers_any();
+ if (config->allowed_bearers == NULL) {
+ g_free(config);
+ return NULL;
+ }
- return -EINVAL;
+ return config;
}
-int connman_session_policy_register(struct connman_session_policy *policy)
+static enum connman_session_type apply_policy_on_type(
+ enum connman_session_type policy,
+ enum connman_session_type type)
{
- DBG("name %s", policy->name);
+ if (type == CONNMAN_SESSION_TYPE_UNKNOWN)
+ return CONNMAN_SESSION_TYPE_UNKNOWN;
- policy_list = g_slist_insert_sorted(policy_list, policy,
- compare_priority);
+ if (policy == CONNMAN_SESSION_TYPE_ANY)
+ return type;
- probe_policy(policy);
+ if (policy == CONNMAN_SESSION_TYPE_LOCAL)
+ return CONNMAN_SESSION_TYPE_LOCAL;
- return 0;
+ return CONNMAN_SESSION_TYPE_INTERNET;
}
-void connman_session_policy_unregister(struct connman_session_policy *policy)
+static void cleanup_bearer(gpointer data)
{
- DBG("name %s", policy->name);
+ struct connman_session_bearer *bearer = data;
- policy_list = g_slist_remove(policy_list, policy);
-
- remove_policy(policy);
+ g_free(bearer->name);
+ g_free(bearer);
}
-static void cleanup_bearer_info(gpointer data, gpointer user_data)
+void connman_session_free_bearers(GSList *bearers)
{
- struct bearer_info *info = data;
-
- g_free(info->name);
- g_free(info);
+ g_slist_free_full(bearers, cleanup_bearer);
}
-static GSList *session_parse_allowed_bearers(DBusMessageIter *iter)
+static int session_parse_allowed_bearers(DBusMessageIter *iter, GSList **list)
{
- struct bearer_info *info;
+ struct connman_session_bearer *bearer;
DBusMessageIter array;
- GSList *list = NULL;
dbus_message_iter_recurse(iter, &array);
- while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
- char *bearer = NULL;
+ *list = NULL;
- dbus_message_iter_get_basic(&array, &bearer);
+ while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+ char *bearer_name = NULL;
- info = g_try_new0(struct bearer_info, 1);
- if (info == NULL) {
- g_slist_foreach(list, cleanup_bearer_info, NULL);
- g_slist_free(list);
+ dbus_message_iter_get_basic(&array, &bearer_name);
- return NULL;
+ bearer = g_try_new0(struct connman_session_bearer, 1);
+ if (bearer == NULL) {
+ connman_session_free_bearers(*list);
+ *list = NULL;
+ return -ENOMEM;
}
- info->name = g_strdup(bearer);
- info->service_type = bearer2service(info->name);
+ bearer->name = g_strdup(bearer_name);
+ bearer->service_type = bearer2service(bearer->name);
- if (info->service_type == CONNMAN_SERVICE_TYPE_UNKNOWN &&
- g_strcmp0(info->name, "*") == 0) {
- info->match_all = TRUE;
+ if (bearer->service_type == CONNMAN_SERVICE_TYPE_UNKNOWN &&
+ g_strcmp0(bearer->name, "*") == 0) {
+ bearer->match_all = TRUE;
} else {
- info->match_all = FALSE;
+ bearer->match_all = FALSE;
}
- list = g_slist_append(list, info);
+ *list = g_slist_append(*list, bearer);
dbus_message_iter_next(&array);
}
- return list;
+ return 0;
}
-static GSList *session_allowed_bearers_any(void)
+static struct connman_session_bearer *clone_bearer(
+ struct connman_session_bearer *orig)
{
- struct bearer_info *info;
+ struct connman_session_bearer *bearer;
+
+ bearer = g_try_new0(struct connman_session_bearer, 1);
+ if (bearer == NULL)
+ return NULL;
+
+ bearer->name = g_strdup(orig->name);
+ bearer->match_all = orig->match_all;
+ bearer->service_type = orig->service_type;
+
+ return bearer;
+}
+
+static int filter_bearer(GSList *policy_bearers,
+ struct connman_session_bearer *bearer,
+ GSList **list)
+{
+ struct connman_session_bearer *policy, *tmp;
+ GSList *it;
+
+ if (policy_bearers == NULL)
+ goto clone;
+
+ for (it = policy_bearers; it != NULL; it = it->next) {
+ policy = it->data;
+
+ if (policy->match_all == FALSE &&
+ bearer->service_type != policy->service_type)
+ continue;
+
+ goto clone;
+ }
+
+ *list = NULL;
+
+ return 0;
+
+clone:
+ tmp = clone_bearer(bearer);
+ if (tmp == NULL) {
+ connman_session_free_bearers(*list);
+ *list = NULL;
+ return -ENOMEM;
+ }
+ *list = g_slist_append(*list, tmp);
+
+ return 0;
+}
+
+static connman_bool_t is_bearer_valid(struct connman_session_bearer *bearer)
+{
+ if (bearer->match_all == FALSE &&
+ bearer->service_type == CONNMAN_SERVICE_TYPE_UNKNOWN)
+ return FALSE;
+
+ return TRUE;
+}
+
+static int apply_policy_on_bearers(GSList *policy_bearers, GSList *bearers,
+ GSList **list)
+{
+ struct connman_session_bearer *bearer;
+ GSList *it;
+ int err;
+
+ *list = NULL;
+
+ for (it = bearers; it != NULL; it = it->next) {
+ bearer = it->data;
+
+ if (is_bearer_valid(bearer) == FALSE)
+ continue;
+
+ err = filter_bearer(policy_bearers, bearer, list);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+GSList *connman_session_allowed_bearers_any(void)
+{
+ struct connman_session_bearer *bearer;
GSList *list = NULL;
- info = g_try_new0(struct bearer_info, 1);
- if (info == NULL)
+ bearer = g_try_new0(struct connman_session_bearer, 1);
+ if (bearer == NULL)
return NULL;
- info->name = g_strdup("");
- info->match_all = TRUE;
- info->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
+ bearer->name = g_strdup("");
+ bearer->match_all = TRUE;
+ bearer->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
- list = g_slist_append(list, info);
+ list = g_slist_append(list, bearer);
return list;
}
struct session_info *info = user_data;
GSList *list;
- for (list = info->allowed_bearers;
+ for (list = info->config.allowed_bearers;
list != NULL; list = list->next) {
- struct bearer_info *bearer_info = list->data;
+ struct connman_session_bearer *bearer = list->data;
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
- &bearer_info->name);
+ &bearer->name);
}
}
info_last->entry = info->entry;
}
- if (session->append_all == TRUE || info->type != info_last->type) {
- const char *type = type2string(info->type);
+ if (session->append_all == TRUE ||
+ info->config.type != info_last->config.type) {
+ const char *type = type2string(info->config.type);
connman_dbus_dict_append_basic(dict, "ConnectionType",
DBUS_TYPE_STRING,
&type);
- info_last->type = info->type;
+ info_last->config.type = info->config.type;
}
if (session->append_all == TRUE ||
- info->allowed_bearers != info_last->allowed_bearers) {
+ info->config.allowed_bearers != info_last->config.allowed_bearers) {
connman_dbus_dict_append_array(dict, "AllowedBearers",
DBUS_TYPE_STRING,
append_allowed_bearers,
info);
- info_last->allowed_bearers = info->allowed_bearers;
+ info_last->config.allowed_bearers = info->config.allowed_bearers;
}
session->append_all = FALSE;
enum connman_session_type type)
{
switch (type) {
+ case CONNMAN_SESSION_TYPE_UNKNOWN:
+ return FALSE;
case CONNMAN_SESSION_TYPE_ANY:
return TRUE;
case CONNMAN_SESSION_TYPE_LOCAL:
info->state >= CONNMAN_SESSION_STATE_CONNECTED)
return TRUE;
- if (info->allowed_bearers != info_last->allowed_bearers ||
- info->type != info_last->type)
+ if (info->config.allowed_bearers != info_last->config.allowed_bearers ||
+ info->config.type != info_last->config.type)
return TRUE;
return FALSE;
struct session_info *info = session->info;
GSList *list;
- for (list = info->allowed_bearers;
+ for (list = info->config.allowed_bearers;
list != NULL; list = list->next) {
- struct bearer_info *bearer_info = list->data;
+ struct connman_session_bearer *bearer = list->data;
enum connman_service_type service_type;
- if (bearer_info->match_all == TRUE)
+ if (bearer->match_all == TRUE)
return TRUE;
service_type = connman_service_get_type(service);
- if (bearer_info->service_type == service_type)
+ if (bearer->service_type == service_type)
return TRUE;
}
type_a = connman_service_get_type(service_a);
type_b = connman_service_get_type(service_b);
- for (list = info->allowed_bearers;
+ for (list = info->config.allowed_bearers;
list != NULL; list = list->next) {
- struct bearer_info *bearer_info = list->data;
+ struct connman_session_bearer *bearer = list->data;
- if (bearer_info->match_all == TRUE) {
+ if (bearer->match_all == TRUE) {
if (type_a != type_b) {
weight_a = service_type_weight(type_a);
weight_b = service_type_weight(type_b);
}
}
- if (type_a == bearer_info->service_type &&
- type_b == bearer_info->service_type) {
+ if (type_a == bearer->service_type &&
+ type_b == bearer->service_type) {
return 0;
}
- if (type_a == bearer_info->service_type &&
- type_b != bearer_info->service_type) {
+ if (type_a == bearer->service_type &&
+ type_b != bearer->service_type) {
return -1;
}
- if (type_a != bearer_info->service_type &&
- type_b == bearer_info->service_type) {
+ if (type_a != bearer->service_type &&
+ type_b == bearer->service_type) {
return 1;
}
}
__connman_service_disconnect(info->entry->service);
}
- g_slist_foreach(info->allowed_bearers, cleanup_bearer_info, NULL);
- g_slist_free(info->allowed_bearers);
-
+ destroy_policy_config(session);
+ connman_session_free_bearers(session->info->config.allowed_bearers);
g_free(session->owner);
g_free(session->session_path);
g_free(session->notify_path);
enum connman_session_state state;
state = service_to_session_state(entry->state);
- if (is_type_matching_state(&state, info->type) == FALSE)
+ if (is_type_matching_state(&state, info->config.type) == FALSE)
return;
info->state = state;
state = service_to_session_state(info->entry->state);
- if (is_type_matching_state(&state, info->type) == TRUE)
+ if (is_type_matching_state(&state, info->config.type) == TRUE)
info->state = state;
}
DBG("ignore session changed event");
return;
case CONNMAN_SESSION_TRIGGER_SETTING:
- if (info->allowed_bearers != info_last->allowed_bearers) {
+ if (info->config.allowed_bearers != info_last->config.allowed_bearers) {
service_hash_last = session->service_hash;
service_list_last = session->service_list;
g_sequence_free(service_list_last);
}
- if (info->type != info_last->type) {
+ if (info->config.type != info_last->config.type) {
if (info->state >= CONNMAN_SESSION_STATE_CONNECTED &&
is_type_matching_state(&info->state,
- info->type) == FALSE)
+ info->config.type) == FALSE)
deselect_and_disconnect(session);
}
const char *name;
const char *val;
GSList *allowed_bearers;
+ int err;
DBG("session %p", session);
if (dbus_message_iter_init(msg, &iter) == FALSE)
switch (dbus_message_iter_get_arg_type(&value)) {
case DBUS_TYPE_ARRAY:
if (g_str_equal(name, "AllowedBearers") == TRUE) {
- allowed_bearers = session_parse_allowed_bearers(&value);
-
- g_slist_foreach(info->allowed_bearers,
- cleanup_bearer_info, NULL);
- g_slist_free(info->allowed_bearers);
-
- if (allowed_bearers == NULL) {
- allowed_bearers = session_allowed_bearers_any();
-
- if (allowed_bearers == NULL)
- return __connman_error_failed(msg, ENOMEM);
- }
-
- info->allowed_bearers = allowed_bearers;
+ err = session_parse_allowed_bearers(&value,
+ &allowed_bearers);
+ if (err < 0)
+ return __connman_error_failed(msg, err);
+
+ connman_session_free_bearers(info->config.allowed_bearers);
+ err = apply_policy_on_bearers(
+ session->policy_config->allowed_bearers,
+ allowed_bearers,
+ &info->config.allowed_bearers);
+
+ connman_session_free_bearers(allowed_bearers);
+ if (err < 0)
+ return __connman_error_failed(msg, err);
} else {
goto err;
}
case DBUS_TYPE_STRING:
if (g_str_equal(name, "ConnectionType") == TRUE) {
dbus_message_iter_get_basic(&value, &val);
- info->type = string2type(val);
+ info->config.type = apply_policy_on_type(
+ session->policy_config->type,
+ string2type(val));
} else {
goto err;
}
DBusMessageIter iter, array;
struct connman_session *session = NULL;
struct session_info *info, *info_last;
-
enum connman_session_type type = CONNMAN_SESSION_TYPE_ANY;
- connman_bool_t priority;
- connman_bool_t ecall_app;
- enum connman_session_roaming_policy roaming_policy;
- char *roaming_policy_str;
GSList *allowed_bearers = NULL;
+ connman_bool_t allowed_bearers_valid = FALSE;
+ connman_bool_t type_valid = FALSE;
int err;
owner = dbus_message_get_sender(msg);
switch (dbus_message_iter_get_arg_type(&value)) {
case DBUS_TYPE_ARRAY:
if (g_str_equal(key, "AllowedBearers") == TRUE) {
- allowed_bearers =
- session_parse_allowed_bearers(&value);
+ err = session_parse_allowed_bearers(&value,
+ &allowed_bearers);
+ if (err < 0)
+ goto err;
+
+ allowed_bearers_valid = TRUE;
} else {
return -EINVAL;
}
if (g_str_equal(key, "ConnectionType") == TRUE) {
dbus_message_iter_get_basic(&value, &val);
type = string2type(val);
+ type_valid = TRUE;
} else {
return -EINVAL;
}
g_dbus_add_disconnect_watch(connection, session->owner,
owner_disconnect, session, NULL);
- assign_policy_plugin(session);
-
- policy_get_bool(session, owner, "Priority", &priority);
- policy_get_bool(session, owner, "EmergencyCall", &ecall_app);
- policy_get_string(session, owner, "RoamingPolicy", &roaming_policy_str);
- roaming_policy = string2roamingpolicy(roaming_policy_str);
+ err = assign_policy_plugin(session);
+ if (err < 0)
+ goto err;
+ err = create_policy_config(session);
+ if (err < 0)
+ goto err;
- if (ecall_app == TRUE)
+ if (session->policy_config->ecall == TRUE)
ecall_session = session;
info->state = CONNMAN_SESSION_STATE_DISCONNECTED;
- info->type = type;
- info->priority = priority;
- info->roaming_policy = roaming_policy;
+ if (type_valid == FALSE)
+ type = CONNMAN_SESSION_TYPE_ANY;
+ info->config.type = apply_policy_on_type(
+ session->policy_config->type,
+ type);
+ info->config.priority = session->policy_config->priority;
+ info->config.roaming_policy = session->policy_config->roaming_policy;
info->entry = NULL;
- if (allowed_bearers == NULL) {
- info->allowed_bearers =
- session_allowed_bearers_any();
-
- if (info->allowed_bearers == NULL) {
+ if (allowed_bearers_valid == FALSE) {
+ allowed_bearers = connman_session_allowed_bearers_any();
+ if (allowed_bearers == NULL) {
err = -ENOMEM;
goto err;
}
- } else {
- info->allowed_bearers = allowed_bearers;
}
+ err = apply_policy_on_bearers(
+ session->policy_config->allowed_bearers,
+ allowed_bearers,
+ &info->config.allowed_bearers);
+ if (err < 0)
+ goto err;
+
g_hash_table_replace(session_hash, session->session_path, session);
DBG("add %s", session->session_path);
populate_service_list(session);
info_last->state = info->state;
- info_last->priority = info->priority;
- info_last->roaming_policy = info->roaming_policy;
+ info_last->config.priority = info->config.priority;
+ info_last->config.roaming_policy = info->config.roaming_policy;
info_last->entry = info->entry;
- info_last->allowed_bearers = info->allowed_bearers;
+ info_last->config.allowed_bearers = info->config.allowed_bearers;
session->append_all = TRUE;
g_free(session_path);
- g_slist_foreach(allowed_bearers, cleanup_bearer_info, NULL);
- g_slist_free(allowed_bearers);
+ connman_session_free_bearers(allowed_bearers);
return err;
}