5 * Copyright (C) 2007-2014 Intel Corporation. All rights reserved.
6 * Copyright (C) 2011-2014 BMW Car IT GmbH.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include <connman/session.h>
35 static DBusConnection *connection;
36 static GHashTable *session_hash;
37 static GHashTable *service_hash;
38 static struct connman_session *ecall_session;
39 static uint32_t session_mark = 256;
40 static struct firewall_context *global_firewall = NULL;
42 enum connman_session_state {
43 CONNMAN_SESSION_STATE_DISCONNECTED = 0,
44 CONNMAN_SESSION_STATE_CONNECTED = 1,
45 CONNMAN_SESSION_STATE_ONLINE = 2,
49 struct connman_session_config config;
50 enum connman_session_state state;
53 struct connman_session {
61 struct session_info *info;
62 struct session_info *info_last;
63 struct connman_service *service;
64 struct connman_service *service_last;
65 struct connman_session_config *policy_config;
66 GSList *user_allowed_bearers;
70 enum connman_session_id_type id_type;
71 struct firewall_context *fw;
78 struct connman_service_info {
79 struct connman_service *service;
83 static struct connman_session_policy *policy;
84 static void session_activate(struct connman_session *session);
85 static void session_deactivate(struct connman_session *session);
86 static void update_session_state(struct connman_session *session);
88 static void cleanup_service(gpointer data)
90 struct connman_service_info *info = data;
92 g_slist_free(info->sessions);
96 static const char *state2string(enum connman_session_state state)
99 case CONNMAN_SESSION_STATE_DISCONNECTED:
100 return "disconnected";
101 case CONNMAN_SESSION_STATE_CONNECTED:
103 case CONNMAN_SESSION_STATE_ONLINE:
110 static const char *type2string(enum connman_session_type type)
113 case CONNMAN_SESSION_TYPE_UNKNOWN:
115 case CONNMAN_SESSION_TYPE_ANY:
117 case CONNMAN_SESSION_TYPE_LOCAL:
119 case CONNMAN_SESSION_TYPE_INTERNET:
126 enum connman_session_roaming_policy connman_session_parse_roaming_policy(const char *policy)
128 if (g_strcmp0(policy, "default") == 0)
129 return CONNMAN_SESSION_ROAMING_POLICY_DEFAULT;
130 else if (g_strcmp0(policy, "always") == 0)
131 return CONNMAN_SESSION_ROAMING_POLICY_ALWAYS;
132 else if (g_strcmp0(policy, "forbidden") == 0)
133 return CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN;
134 else if (g_strcmp0(policy, "national") == 0)
135 return CONNMAN_SESSION_ROAMING_POLICY_NATIONAL;
136 else if (g_strcmp0(policy, "international") == 0)
137 return CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL;
139 return CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN;
142 enum connman_session_type connman_session_parse_connection_type(const char *type)
144 if (g_strcmp0(type, "any") == 0)
145 return CONNMAN_SESSION_TYPE_ANY;
146 if (g_strcmp0(type, "local") == 0)
147 return CONNMAN_SESSION_TYPE_LOCAL;
148 else if (g_strcmp0(type, "internet") == 0)
149 return CONNMAN_SESSION_TYPE_INTERNET;
151 return CONNMAN_SESSION_TYPE_UNKNOWN;
154 static int bearer2service(const char *bearer, enum connman_service_type *type)
156 if (g_strcmp0(bearer, "ethernet") == 0)
157 *type = CONNMAN_SERVICE_TYPE_ETHERNET;
158 else if (g_strcmp0(bearer, "wifi") == 0)
159 *type = CONNMAN_SERVICE_TYPE_WIFI;
160 else if (g_strcmp0(bearer, "gadget") == 0)
161 *type = CONNMAN_SERVICE_TYPE_GADGET;
162 else if (g_strcmp0(bearer, "bluetooth") == 0)
163 *type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
164 else if (g_strcmp0(bearer, "cellular") == 0)
165 *type = CONNMAN_SERVICE_TYPE_CELLULAR;
166 else if (g_strcmp0(bearer, "vpn") == 0)
167 *type = CONNMAN_SERVICE_TYPE_VPN;
174 static char *service2bearer(enum connman_service_type type)
177 case CONNMAN_SERVICE_TYPE_ETHERNET:
179 case CONNMAN_SERVICE_TYPE_GADGET:
181 case CONNMAN_SERVICE_TYPE_WIFI:
183 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
185 case CONNMAN_SERVICE_TYPE_CELLULAR:
187 case CONNMAN_SERVICE_TYPE_VPN:
189 case CONNMAN_SERVICE_TYPE_SYSTEM:
190 case CONNMAN_SERVICE_TYPE_GPS:
191 case CONNMAN_SERVICE_TYPE_P2P:
192 case CONNMAN_SERVICE_TYPE_UNKNOWN:
199 static int init_firewall(void)
201 struct firewall_context *fw;
207 fw = __connman_firewall_create();
209 err = __connman_firewall_add_rule(fw, "mangle", "INPUT",
210 "-j CONNMARK --restore-mark");
214 err = __connman_firewall_add_rule(fw, "mangle", "POSTROUTING",
215 "-j CONNMARK --save-mark");
219 err = __connman_firewall_enable(fw);
223 global_firewall = fw;
228 __connman_firewall_destroy(fw);
233 static void cleanup_firewall(void)
235 if (!global_firewall)
238 __connman_firewall_disable(global_firewall);
239 __connman_firewall_destroy(global_firewall);
242 static int init_firewall_session(struct connman_session *session)
244 struct firewall_context *fw;
247 if (session->policy_config->id_type == CONNMAN_SESSION_ID_TYPE_UNKNOWN)
252 err = init_firewall();
256 fw = __connman_firewall_create();
260 switch (session->policy_config->id_type) {
261 case CONNMAN_SESSION_ID_TYPE_UID:
262 err = __connman_firewall_add_rule(fw, "mangle", "OUTPUT",
263 "-m owner --uid-owner %s -j MARK --set-mark %d",
264 session->policy_config->id,
267 case CONNMAN_SESSION_ID_TYPE_GID:
268 err = __connman_firewall_add_rule(fw, "mangle", "OUTPUT",
269 "-m owner --gid-owner %s -j MARK --set-mark %d",
270 session->policy_config->id,
273 case CONNMAN_SESSION_ID_TYPE_LSM:
281 session->id_type = session->policy_config->id_type;
283 err = __connman_firewall_enable(fw);
292 __connman_firewall_destroy(fw);
297 static void cleanup_firewall_session(struct connman_session *session)
302 __connman_firewall_disable(session->fw);
303 __connman_firewall_destroy(session->fw);
308 static int init_routing_table(struct connman_session *session)
312 if (session->policy_config->id_type == CONNMAN_SESSION_ID_TYPE_UNKNOWN)
317 err = __connman_inet_add_fwmark_rule(session->mark,
318 AF_INET, session->mark);
322 err = __connman_inet_add_fwmark_rule(session->mark,
323 AF_INET6, session->mark);
325 __connman_inet_del_fwmark_rule(session->mark,
326 AF_INET, session->mark);
327 session->policy_routing = true;
332 static void del_default_route(struct connman_session *session)
334 if (!session->gateway)
337 DBG("index %d routing table %d default gateway %s",
338 session->index, session->mark, session->gateway);
340 __connman_inet_del_default_from_table(session->mark,
341 session->index, session->gateway);
342 g_free(session->gateway);
343 session->gateway = NULL;
347 static void add_default_route(struct connman_session *session)
349 struct connman_ipconfig *ipconfig;
352 if (!session->service)
355 ipconfig = __connman_service_get_ip4config(session->service);
356 session->index = __connman_ipconfig_get_index(ipconfig);
357 session->gateway = g_strdup(__connman_ipconfig_get_gateway(ipconfig));
359 DBG("index %d routing table %d default gateway %s",
360 session->index, session->mark, session->gateway);
362 err = __connman_inet_add_default_to_table(session->mark,
363 session->index, session->gateway);
365 DBG("session %p %s", session, strerror(-err));
368 static void cleanup_routing_table(struct connman_session *session)
372 if (session->policy_routing) {
373 __connman_inet_del_fwmark_rule(session->mark,
374 AF_INET6, session->mark);
376 __connman_inet_del_fwmark_rule(session->mark,
377 AF_INET, session->mark);
378 session->policy_routing = false;
381 del_default_route(session);
384 static void update_routing_table(struct connman_session *session)
386 del_default_route(session);
387 add_default_route(session);
390 static void destroy_policy_config(struct connman_session *session)
393 g_free(session->policy_config);
397 policy->destroy(session);
400 static void free_session(struct connman_session *session)
405 if (session->notify_watch > 0)
406 g_dbus_remove_watch(connection, session->notify_watch);
408 destroy_policy_config(session);
409 g_slist_free(session->info->config.allowed_bearers);
410 g_free(session->owner);
411 g_free(session->session_path);
412 g_free(session->notify_path);
413 g_free(session->info);
414 g_free(session->info_last);
415 g_free(session->gateway);
420 static void set_active_session(struct connman_session *session, bool enable)
423 if (policy && policy->session_changed)
424 policy->session_changed(session, enable,
425 session->info->config.allowed_bearers);
427 __connman_service_set_active_session(enable,
428 session->info->config.allowed_bearers);
431 static void cleanup_session(gpointer user_data)
433 struct connman_session *session = user_data;
435 DBG("remove %s", session->session_path);
437 cleanup_routing_table(session);
438 cleanup_firewall_session(session);
441 set_active_session(session, false);
443 session_deactivate(session);
444 update_session_state(session);
446 g_slist_free(session->user_allowed_bearers);
448 free_session(session);
451 struct creation_data {
452 DBusMessage *pending;
453 struct connman_session *session;
456 enum connman_session_type type;
457 GSList *allowed_bearers;
460 static void cleanup_creation_data(struct creation_data *creation_data)
465 if (creation_data->pending)
466 dbus_message_unref(creation_data->pending);
468 g_slist_free(creation_data->allowed_bearers);
469 g_free(creation_data);
472 static int create_policy_config(struct connman_session *session,
473 connman_session_config_func_t cb,
474 struct creation_data *creation_data)
476 struct connman_session_config *config;
479 config = connman_session_create_default_config();
481 free_session(session);
482 cleanup_creation_data(creation_data);
486 return cb(session, config, creation_data, 0);
489 return policy->create(session, cb, creation_data);
492 int connman_session_policy_register(struct connman_session_policy *plugin)
497 if (!plugin->create || !plugin->destroy)
500 DBG("name %s", plugin->name);
507 void connman_session_policy_unregister(struct connman_session_policy *plugin)
509 if (plugin != policy)
512 DBG("name %s", policy->name);
517 static int default_bearers[] = {
518 CONNMAN_SERVICE_TYPE_ETHERNET,
519 CONNMAN_SERVICE_TYPE_WIFI,
520 CONNMAN_SERVICE_TYPE_BLUETOOTH,
521 CONNMAN_SERVICE_TYPE_CELLULAR,
522 CONNMAN_SERVICE_TYPE_GADGET,
525 static void add_default_bearer_types(GSList **list)
529 for (i = 0; i < G_N_ELEMENTS(default_bearers); i++)
530 *list = g_slist_append(*list,
531 GINT_TO_POINTER(default_bearers[i]));
534 void connman_session_set_default_config(struct connman_session_config *config)
536 config->id_type = CONNMAN_SESSION_ID_TYPE_UNKNOWN;
540 config->priority = FALSE;
541 config->roaming_policy = CONNMAN_SESSION_ROAMING_POLICY_DEFAULT;
542 config->type = CONNMAN_SESSION_TYPE_ANY;
543 config->ecall = FALSE;
545 g_slist_free(config->allowed_bearers);
546 add_default_bearer_types(&config->allowed_bearers);
549 struct connman_session_config *connman_session_create_default_config(void)
551 struct connman_session_config *config;
553 config = g_new0(struct connman_session_config, 1);
554 connman_session_set_default_config(config);
559 static enum connman_session_type apply_policy_on_type(
560 enum connman_session_type policy,
561 enum connman_session_type type)
563 if (type == CONNMAN_SESSION_TYPE_UNKNOWN)
564 return CONNMAN_SESSION_TYPE_UNKNOWN;
566 if (policy == CONNMAN_SESSION_TYPE_ANY)
569 if (policy == CONNMAN_SESSION_TYPE_LOCAL)
570 return CONNMAN_SESSION_TYPE_LOCAL;
572 return CONNMAN_SESSION_TYPE_INTERNET;
575 int connman_session_parse_bearers(const char *token, GSList **list)
577 enum connman_service_type bearer;
580 if (g_strcmp0(token, "") == 0)
583 if (g_strcmp0(token, "*") == 0) {
584 add_default_bearer_types(list);
588 err = bearer2service(token, &bearer);
592 *list = g_slist_append(*list, GINT_TO_POINTER(bearer));
597 static int parse_bearers(DBusMessageIter *iter, GSList **list)
599 DBusMessageIter array;
602 dbus_message_iter_recurse(iter, &array);
606 while ((type = dbus_message_iter_get_arg_type(&array)) !=
608 char *bearer_name = NULL;
610 if (type != DBUS_TYPE_STRING) {
616 dbus_message_iter_get_basic(&array, &bearer_name);
618 err = connman_session_parse_bearers(bearer_name, list);
625 dbus_message_iter_next(&array);
631 static void filter_bearer(GSList *policy_bearers,
632 enum connman_service_type bearer,
635 enum connman_service_type policy;
641 for (it = policy_bearers; it; it = it->next) {
642 policy = GPOINTER_TO_INT(it->data);
644 if (policy != bearer)
647 *list = g_slist_append(*list, GINT_TO_POINTER(bearer));
652 static void apply_policy_on_bearers(GSList *policy_bearers, GSList *bearers,
655 enum connman_service_type bearer;
660 for (it = bearers; it; it = it->next) {
661 bearer = GPOINTER_TO_INT(it->data);
663 filter_bearer(policy_bearers, bearer, list);
667 const char *connman_session_get_owner(struct connman_session *session)
669 return session->owner;
672 static void append_allowed_bearers(DBusMessageIter *iter, void *user_data)
674 struct session_info *info = user_data;
677 for (list = info->config.allowed_bearers;
678 list; list = list->next) {
679 enum connman_service_type bearer = GPOINTER_TO_INT(list->data);
680 const char *name = __connman_service_type2string(bearer);
685 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
690 static void append_ipconfig_ipv4(DBusMessageIter *iter, void *user_data)
692 struct connman_service *service = user_data;
693 struct connman_ipconfig *ipconfig_ipv4;
698 if (!__connman_service_is_connected_state(service,
699 CONNMAN_IPCONFIG_TYPE_IPV4))
702 ipconfig_ipv4 = __connman_service_get_ip4config(service);
706 __connman_ipconfig_append_ipv4(ipconfig_ipv4, iter);
709 static void append_ipconfig_ipv6(DBusMessageIter *iter, void *user_data)
711 struct connman_service *service = user_data;
712 struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
717 if (!__connman_service_is_connected_state(service,
718 CONNMAN_IPCONFIG_TYPE_IPV6))
721 ipconfig_ipv4 = __connman_service_get_ip4config(service);
722 ipconfig_ipv6 = __connman_service_get_ip6config(service);
726 __connman_ipconfig_append_ipv6(ipconfig_ipv6, iter, ipconfig_ipv4);
729 static void append_notify(DBusMessageIter *dict,
730 struct connman_session *session)
732 struct session_info *info = session->info;
733 struct session_info *info_last = session->info_last;
734 struct connman_service *service;
735 enum connman_service_type type;
736 const char *name, *bearer;
740 if (session->append_all || info->state != info_last->state) {
741 const char *state = state2string(info->state);
743 connman_dbus_dict_append_basic(dict, "State",
746 info_last->state = info->state;
749 if (session->append_all || session->service != session->service_last) {
750 if (session->service) {
751 service = session->service;
752 name = __connman_service_get_name(service);
753 idx = __connman_service_get_index(service);
755 ifname = connman_inet_ifname(idx);
757 ifname = g_strdup("");
759 type = connman_service_get_type(service);
760 bearer = service2bearer(type);
764 ifname = g_strdup("");
768 connman_dbus_dict_append_basic(dict, "Name",
772 connman_dbus_dict_append_dict(dict, "IPv4",
773 append_ipconfig_ipv4,
776 connman_dbus_dict_append_dict(dict, "IPv6",
777 append_ipconfig_ipv6,
780 connman_dbus_dict_append_basic(dict, "Interface",
784 connman_dbus_dict_append_basic(dict, "Bearer",
790 session->service_last = session->service;
793 if (session->append_all ||
794 info->config.type != info_last->config.type) {
795 const char *type = type2string(info->config.type);
797 connman_dbus_dict_append_basic(dict, "ConnectionType",
800 info_last->config.type = info->config.type;
803 if (session->append_all ||
804 info->config.allowed_bearers != info_last->config.allowed_bearers) {
805 connman_dbus_dict_append_array(dict, "AllowedBearers",
807 append_allowed_bearers,
809 info_last->config.allowed_bearers = info->config.allowed_bearers;
812 session->append_all = false;
815 static bool compute_notifiable_changes(struct connman_session *session)
817 struct session_info *info_last = session->info_last;
818 struct session_info *info = session->info;
820 if (session->append_all)
823 if (info->state != info_last->state)
826 if (session->service != session->service_last &&
827 info->state >= CONNMAN_SESSION_STATE_CONNECTED)
830 if (info->config.allowed_bearers != info_last->config.allowed_bearers ||
831 info->config.type != info_last->config.type)
837 static gboolean session_notify(gpointer user_data)
839 struct connman_session *session = user_data;
841 DBusMessageIter array, dict;
843 if (!compute_notifiable_changes(session))
846 DBG("session %p owner %s notify_path %s", session,
847 session->owner, session->notify_path);
849 msg = dbus_message_new_method_call(session->owner, session->notify_path,
850 CONNMAN_NOTIFICATION_INTERFACE,
855 dbus_message_iter_init_append(msg, &array);
856 connman_dbus_dict_open(&array, &dict);
858 append_notify(&dict, session);
860 connman_dbus_dict_close(&array, &dict);
862 g_dbus_send_message(connection, msg);
867 static void ipconfig_ipv4_changed(struct connman_session *session)
869 connman_dbus_setting_changed_dict(session->owner, session->notify_path,
870 "IPv4", append_ipconfig_ipv4,
874 static void ipconfig_ipv6_changed(struct connman_session *session)
876 connman_dbus_setting_changed_dict(session->owner, session->notify_path,
877 "IPv6", append_ipconfig_ipv6,
881 int connman_session_config_update(struct connman_session *session)
883 struct session_info *info = session->info;
884 GSList *allowed_bearers;
887 DBG("session %p", session);
890 * We update all configuration even though only one entry
891 * might have changed. We can still optimize this later.
894 if (session->id_type != session->policy_config->id_type) {
895 cleanup_firewall_session(session);
896 err = init_firewall_session(session);
898 connman_session_destroy(session);
902 session->id_type = session->policy_config->id_type;
905 apply_policy_on_bearers(
906 session->policy_config->allowed_bearers,
907 session->user_allowed_bearers,
911 set_active_session(session, false);
913 session->active = false;
914 session_deactivate(session);
916 g_slist_free(info->config.allowed_bearers);
917 info->config.allowed_bearers = allowed_bearers;
919 session_activate(session);
921 info->config.type = apply_policy_on_type(
922 session->policy_config->type,
925 info->config.roaming_policy = session->policy_config->roaming_policy;
927 info->config.ecall = session->policy_config->ecall;
928 if (info->config.ecall)
929 ecall_session = session;
931 info->config.priority = session->policy_config->priority;
933 session_notify(session);
938 static DBusMessage *connect_session(DBusConnection *conn,
939 DBusMessage *msg, void *user_data)
941 struct connman_session *session = user_data;
943 DBG("session %p", session);
946 if (ecall_session->ecall && ecall_session != session)
947 return __connman_error_failed(msg, EBUSY);
949 session->ecall = true;
952 if (!session->active) {
953 session->active = true;
954 set_active_session(session, true);
957 session_activate(session);
959 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_SESSION);
961 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
964 static DBusMessage *disconnect_session(DBusConnection *conn,
965 DBusMessage *msg, void *user_data)
967 struct connman_session *session = user_data;
969 DBG("session %p", session);
972 if (ecall_session->ecall && ecall_session != session)
973 return __connman_error_failed(msg, EBUSY);
975 session->ecall = false;
978 if (session->active) {
979 session->active = false;
980 set_active_session(session, false);
983 session_deactivate(session);
984 update_session_state(session);
986 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
989 static DBusMessage *change_session(DBusConnection *conn,
990 DBusMessage *msg, void *user_data)
992 struct connman_session *session = user_data;
993 struct session_info *info = session->info;
994 DBusMessageIter iter, value;
997 GSList *allowed_bearers;
1000 DBG("session %p", session);
1001 if (!dbus_message_iter_init(msg, &iter))
1002 return __connman_error_invalid_arguments(msg);
1004 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1005 return __connman_error_invalid_arguments(msg);
1007 dbus_message_iter_get_basic(&iter, &name);
1008 dbus_message_iter_next(&iter);
1010 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1011 return __connman_error_invalid_arguments(msg);
1013 dbus_message_iter_recurse(&iter, &value);
1015 switch (dbus_message_iter_get_arg_type(&value)) {
1016 case DBUS_TYPE_ARRAY:
1017 if (g_str_equal(name, "AllowedBearers")) {
1018 err = parse_bearers(&value, &allowed_bearers);
1020 return __connman_error_failed(msg, -err);
1022 if (session->active)
1023 set_active_session(session, false);
1025 session->active = false;
1026 session_deactivate(session);
1028 g_slist_free(info->config.allowed_bearers);
1029 session->user_allowed_bearers = allowed_bearers;
1031 apply_policy_on_bearers(
1032 session->policy_config->allowed_bearers,
1033 session->user_allowed_bearers,
1034 &info->config.allowed_bearers);
1036 session_activate(session);
1041 case DBUS_TYPE_STRING:
1042 if (g_str_equal(name, "ConnectionType")) {
1043 dbus_message_iter_get_basic(&value, &val);
1044 info->config.type = apply_policy_on_type(
1045 session->policy_config->type,
1046 connman_session_parse_connection_type(val));
1055 session_notify(session);
1057 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1060 return __connman_error_invalid_arguments(msg);
1063 static void release_session(gpointer key, gpointer value, gpointer user_data)
1065 struct connman_session *session = value;
1066 DBusMessage *message;
1068 DBG("owner %s path %s", session->owner, session->notify_path);
1070 if (session->notify_watch > 0)
1071 g_dbus_remove_watch(connection, session->notify_watch);
1073 g_dbus_unregister_interface(connection, session->session_path,
1074 CONNMAN_SESSION_INTERFACE);
1076 message = dbus_message_new_method_call(session->owner,
1077 session->notify_path,
1078 CONNMAN_NOTIFICATION_INTERFACE,
1083 dbus_message_set_no_reply(message, TRUE);
1085 g_dbus_send_message(connection, message);
1088 static int session_disconnect(struct connman_session *session)
1090 DBG("session %p, %s", session, session->owner);
1092 if (session->notify_watch > 0)
1093 g_dbus_remove_watch(connection, session->notify_watch);
1095 g_dbus_unregister_interface(connection, session->session_path,
1096 CONNMAN_SESSION_INTERFACE);
1098 g_hash_table_remove(session_hash, session->session_path);
1103 static void owner_disconnect(DBusConnection *conn, void *user_data)
1105 struct connman_session *session = user_data;
1107 DBG("session %p, %s died", session, session->owner);
1109 session_disconnect(session);
1112 static DBusMessage *destroy_session(DBusConnection *conn,
1113 DBusMessage *msg, void *user_data)
1115 struct connman_session *session = user_data;
1117 DBG("session %p", session);
1119 if (ecall_session && ecall_session != session)
1120 return __connman_error_failed(msg, EBUSY);
1122 session_disconnect(session);
1124 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1127 static const GDBusMethodTable session_methods[] = {
1128 { GDBUS_METHOD("Destroy", NULL, NULL, destroy_session) },
1129 { GDBUS_METHOD("Connect", NULL, NULL, connect_session) },
1130 { GDBUS_METHOD("Disconnect", NULL, NULL,
1131 disconnect_session ) },
1132 { GDBUS_METHOD("Change",
1133 GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
1134 NULL, change_session) },
1138 static int session_policy_config_cb(struct connman_session *session,
1139 struct connman_session_config *config,
1140 void *user_data, int err)
1142 struct creation_data *creation_data = user_data;
1143 struct session_info *info, *info_last;
1146 DBG("session %p config %p", session, config);
1151 session->policy_config = config;
1153 session->mark = session_mark++;
1154 session->index = -1;
1156 err = init_firewall_session(session);
1160 err = init_routing_table(session);
1164 info = session->info;
1165 info_last = session->info_last;
1167 if (session->policy_config->ecall)
1168 ecall_session = session;
1170 info->state = CONNMAN_SESSION_STATE_DISCONNECTED;
1171 info->config.type = apply_policy_on_type(
1172 session->policy_config->type,
1173 creation_data->type);
1174 info->config.priority = session->policy_config->priority;
1175 info->config.roaming_policy = session->policy_config->roaming_policy;
1177 session->user_allowed_bearers = creation_data->allowed_bearers;
1178 creation_data->allowed_bearers = NULL;
1180 apply_policy_on_bearers(
1181 session->policy_config->allowed_bearers,
1182 session->user_allowed_bearers,
1183 &info->config.allowed_bearers);
1185 g_hash_table_replace(session_hash, session->session_path, session);
1187 DBG("add %s", session->session_path);
1189 if (!g_dbus_register_interface(connection, session->session_path,
1190 CONNMAN_SESSION_INTERFACE,
1191 session_methods, NULL, NULL,
1193 connman_error("Failed to register %s", session->session_path);
1194 g_hash_table_remove(session_hash, session->session_path);
1199 reply = g_dbus_create_reply(creation_data->pending,
1200 DBUS_TYPE_OBJECT_PATH, &session->session_path,
1202 g_dbus_send_message(connection, reply);
1203 creation_data->pending = NULL;
1205 info_last->state = info->state;
1206 info_last->config.priority = info->config.priority;
1207 info_last->config.roaming_policy = info->config.roaming_policy;
1208 info_last->config.allowed_bearers = info->config.allowed_bearers;
1210 session->append_all = true;
1212 cleanup_creation_data(creation_data);
1214 session_activate(session);
1219 reply = __connman_error_failed(creation_data->pending, -err);
1220 g_dbus_send_message(connection, reply);
1221 creation_data->pending = NULL;
1223 cleanup_session(session);
1224 cleanup_creation_data(creation_data);
1229 int __connman_session_create(DBusMessage *msg)
1231 const char *owner, *notify_path;
1232 char *session_path = NULL;
1233 DBusMessageIter iter, array;
1234 struct connman_session *session = NULL;
1235 struct creation_data *creation_data = NULL;
1236 bool user_allowed_bearers = false;
1237 bool user_connection_type = false;
1241 owner = dbus_message_get_sender(msg);
1243 DBG("owner %s", owner);
1245 if (ecall_session && ecall_session->ecall) {
1247 * If there is an emergency call already going on,
1248 * ignore session creation attempt
1254 creation_data = g_try_new0(struct creation_data, 1);
1255 if (!creation_data) {
1260 creation_data->pending = dbus_message_ref(msg);
1262 dbus_message_iter_init(msg, &iter);
1263 dbus_message_iter_recurse(&iter, &array);
1265 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1266 DBusMessageIter entry, value;
1267 const char *key, *val;
1269 dbus_message_iter_recurse(&array, &entry);
1270 dbus_message_iter_get_basic(&entry, &key);
1272 dbus_message_iter_next(&entry);
1273 dbus_message_iter_recurse(&entry, &value);
1275 switch (dbus_message_iter_get_arg_type(&value)) {
1276 case DBUS_TYPE_ARRAY:
1277 if (g_str_equal(key, "AllowedBearers")) {
1278 err = parse_bearers(&value,
1279 &creation_data->allowed_bearers);
1283 user_allowed_bearers = true;
1289 case DBUS_TYPE_STRING:
1290 if (g_str_equal(key, "ConnectionType")) {
1291 dbus_message_iter_get_basic(&value, &val);
1292 creation_data->type =
1293 connman_session_parse_connection_type(val);
1295 user_connection_type = true;
1301 dbus_message_iter_next(&array);
1305 * If the user hasn't provided a configuration, we set
1306 * the default configuration.
1308 * For AllowedBearers this is '*', ...
1310 if (!user_allowed_bearers) {
1311 add_default_bearer_types(&creation_data->allowed_bearers);
1312 if (!creation_data->allowed_bearers) {
1318 /* ... and for ConnectionType it is 'any'. */
1319 if (!user_connection_type)
1320 creation_data->type = CONNMAN_SESSION_TYPE_ANY;
1322 dbus_message_iter_next(&iter);
1323 dbus_message_iter_get_basic(&iter, ¬ify_path);
1330 str = g_strdup(owner);
1331 for (i = 0; str[i] != '\0'; i++)
1332 if (str[i] == ':' || str[i] == '.')
1334 session_path = g_strdup_printf("/sessions/%s%s", str, notify_path);
1337 if (!session_path) {
1342 session = g_hash_table_lookup(session_hash, session_path);
1344 g_free(session_path);
1350 session = g_try_new0(struct connman_session, 1);
1352 g_free(session_path);
1357 creation_data->session = session;
1358 session->session_path = session_path;
1360 session->info = g_try_new0(struct session_info, 1);
1361 if (!session->info) {
1366 session->info_last = g_try_new0(struct session_info, 1);
1367 if (!session->info_last) {
1372 session->owner = g_strdup(owner);
1373 session->notify_path = g_strdup(notify_path);
1374 session->notify_watch =
1375 g_dbus_add_disconnect_watch(connection, session->owner,
1376 owner_disconnect, session, NULL);
1378 err = create_policy_config(session, session_policy_config_cb,
1380 if (err < 0 && err != -EINPROGRESS)
1383 return -EINPROGRESS;
1386 connman_error("Failed to create session");
1388 free_session(session);
1390 cleanup_creation_data(creation_data);
1394 bool __connman_session_policy_autoconnect(enum connman_service_connect_reason reason)
1396 if (!policy || !policy->autoconnect)
1399 return policy->autoconnect(reason);
1402 void connman_session_destroy(struct connman_session *session)
1404 DBG("session %p", session);
1406 session_disconnect(session);
1409 int __connman_session_destroy(DBusMessage *msg)
1411 const char *owner, *session_path;
1412 struct connman_session *session;
1414 owner = dbus_message_get_sender(msg);
1416 DBG("owner %s", owner);
1418 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &session_path,
1423 session = g_hash_table_lookup(session_hash, session_path);
1427 if (g_strcmp0(owner, session->owner) != 0)
1430 connman_session_destroy(session);
1435 int connman_session_connect(struct connman_service *service)
1437 DBG("service %p name %s", service, __connman_service_get_name(service));
1439 return __connman_service_connect(service,
1440 CONNMAN_SERVICE_CONNECT_REASON_SESSION);
1443 int connman_session_disconnect(struct connman_service *service)
1445 DBG("service %p", service);
1447 return __connman_service_disconnect(service);
1450 static enum connman_session_state service_to_session_state(
1451 enum connman_service_state state)
1454 case CONNMAN_SERVICE_STATE_UNKNOWN:
1455 case CONNMAN_SERVICE_STATE_IDLE:
1456 case CONNMAN_SERVICE_STATE_ASSOCIATION:
1457 case CONNMAN_SERVICE_STATE_CONFIGURATION:
1458 case CONNMAN_SERVICE_STATE_DISCONNECT:
1459 case CONNMAN_SERVICE_STATE_FAILURE:
1461 case CONNMAN_SERVICE_STATE_READY:
1462 return CONNMAN_SESSION_STATE_CONNECTED;
1463 case CONNMAN_SERVICE_STATE_ONLINE:
1464 return CONNMAN_SESSION_STATE_ONLINE;
1467 return CONNMAN_SESSION_STATE_DISCONNECTED;
1470 static void update_session_state(struct connman_session *session)
1472 enum connman_service_state service_state;
1473 enum connman_session_state state = CONNMAN_SESSION_STATE_DISCONNECTED;
1475 if (session->service) {
1476 service_state = __connman_service_get_state(session->service);
1477 state = service_to_session_state(service_state);
1478 session->info->state = state;
1480 session->info->state = state;
1482 DBG("session %p state %s", session, state2string(state));
1484 update_routing_table(session);
1485 session_notify(session);
1488 static bool session_match_service(struct connman_session *session,
1489 struct connman_service *service)
1491 enum connman_service_type bearer_type;
1492 enum connman_service_type service_type;
1495 if (policy && policy->allowed)
1496 return policy->allowed(session, service);
1498 for (list = session->info->config.allowed_bearers; list; list = list->next) {
1499 bearer_type = GPOINTER_TO_INT(list->data);
1500 service_type = connman_service_get_type(service);
1502 if (bearer_type == service_type)
1509 static bool is_session_connected(struct connman_session *session,
1510 enum connman_service_state state)
1514 case CONNMAN_SERVICE_STATE_UNKNOWN:
1515 case CONNMAN_SERVICE_STATE_IDLE:
1516 case CONNMAN_SERVICE_STATE_ASSOCIATION:
1517 case CONNMAN_SERVICE_STATE_CONFIGURATION:
1518 case CONNMAN_SERVICE_STATE_DISCONNECT:
1519 case CONNMAN_SERVICE_STATE_FAILURE:
1521 case CONNMAN_SERVICE_STATE_READY:
1522 if (session->info->config.type == CONNMAN_SESSION_TYPE_INTERNET)
1524 case CONNMAN_SERVICE_STATE_ONLINE:
1531 static void session_activate(struct connman_session *session)
1533 GHashTableIter iter;
1534 gpointer key, value;
1539 g_hash_table_iter_init(&iter, service_hash);
1540 while (g_hash_table_iter_next(&iter, &key, &value)) {
1541 struct connman_service_info *info = value;
1542 enum connman_service_state state;
1544 state = __connman_service_get_state(info->service);
1546 if (is_session_connected(session, state) &&
1547 session_match_service(session, info->service)) {
1548 DBG("session %p add service %p", session, info->service);
1550 info->sessions = g_slist_prepend(info->sessions,
1552 session->service = info->service;
1553 update_session_state(session);
1559 session_notify(session);
1562 static void session_deactivate(struct connman_session *session)
1564 struct connman_service_info *info;
1569 if (!session->service)
1572 info = g_hash_table_lookup(service_hash, session->service);
1576 info->sessions = g_slist_remove(info->sessions, session);
1577 session->service = NULL;
1579 session->info->state = CONNMAN_SESSION_STATE_DISCONNECTED;
1582 static void handle_service_state_online(struct connman_service *service,
1583 enum connman_service_state state,
1584 struct connman_service_info *info)
1586 GHashTableIter iter;
1587 gpointer key, value;
1589 g_hash_table_iter_init(&iter, session_hash);
1590 while (g_hash_table_iter_next(&iter, &key, &value)) {
1591 struct connman_session *session = value;
1594 connected = is_session_connected(session, state);
1596 if (session->service == service) {
1598 DBG("session %p remove service %p", session, service);
1599 info->sessions = g_slist_remove(info->sessions,
1601 session->service = NULL;
1602 update_session_state(session);
1604 } else if (connected && session_match_service(session, service)) {
1605 DBG("session %p add service %p", session, service);
1607 info->sessions = g_slist_prepend(info->sessions,
1609 session->service = service;
1610 update_session_state(session);
1615 static void handle_service_state_offline(struct connman_service *service,
1616 struct connman_service_info *info)
1620 for (list = info->sessions; list; list = list->next) {
1621 struct connman_session *session = list->data;
1623 if (session->service != service) {
1624 connman_warn("session %p should have session %p assigned",
1629 DBG("session %p remove service %p", session, service);
1631 session->service = NULL;
1632 update_session_state(session);
1637 static void service_state_changed(struct connman_service *service,
1638 enum connman_service_state state)
1640 struct connman_service_info *info;
1642 DBG("service %p state %d", service, state);
1644 info = g_hash_table_lookup(service_hash, service);
1647 case CONNMAN_SERVICE_STATE_UNKNOWN:
1648 case CONNMAN_SERVICE_STATE_IDLE:
1649 case CONNMAN_SERVICE_STATE_ASSOCIATION:
1650 case CONNMAN_SERVICE_STATE_CONFIGURATION:
1651 case CONNMAN_SERVICE_STATE_FAILURE:
1652 case CONNMAN_SERVICE_STATE_DISCONNECT:
1656 handle_service_state_offline(service, info);
1658 g_hash_table_remove(service_hash, service);
1661 case CONNMAN_SERVICE_STATE_READY:
1662 case CONNMAN_SERVICE_STATE_ONLINE:
1664 info = g_new0(struct connman_service_info, 1);
1665 g_hash_table_replace(service_hash, service, info);
1668 info->service = service;
1669 handle_service_state_online(service, state, info);
1673 static void ipconfig_changed(struct connman_service *service,
1674 struct connman_ipconfig *ipconfig)
1676 GHashTableIter iter;
1677 gpointer key, value;
1678 struct connman_session *session;
1679 struct session_info *info;
1680 enum connman_ipconfig_type type;
1682 DBG("service %p ipconfig %p", service, ipconfig);
1684 type = __connman_ipconfig_get_config_type(ipconfig);
1686 g_hash_table_iter_init(&iter, session_hash);
1688 while (g_hash_table_iter_next(&iter, &key, &value)) {
1690 info = session->info;
1692 if (info->state == CONNMAN_SESSION_STATE_DISCONNECTED)
1695 if (session->service && session->service == service) {
1696 update_routing_table(session);
1698 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1699 ipconfig_ipv4_changed(session);
1700 else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1701 ipconfig_ipv6_changed(session);
1706 static struct connman_notifier session_notifier = {
1708 .service_state_changed = service_state_changed,
1709 .ipconfig_changed = ipconfig_changed,
1712 int __connman_session_init(void)
1718 connection = connman_dbus_get_connection();
1722 err = connman_notifier_register(&session_notifier);
1724 dbus_connection_unref(connection);
1728 session_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1729 NULL, cleanup_session);
1731 service_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1732 NULL, cleanup_service);
1733 if (__connman_firewall_is_up()) {
1734 err = init_firewall();
1742 void __connman_session_cleanup(void)
1751 connman_notifier_unregister(&session_notifier);
1753 g_hash_table_foreach(session_hash, release_session, NULL);
1754 g_hash_table_destroy(session_hash);
1755 session_hash = NULL;
1756 g_hash_table_destroy(service_hash);
1757 service_hash = NULL;
1759 dbus_connection_unref(connection);