5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
6 * Copyright (C) 2011 BWM CarIT GmbH. All rights reserved.
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 static DBusConnection *connection;
32 static GHashTable *session_hash;
33 static connman_bool_t sessionmode;
35 enum connman_session_roaming_policy {
36 CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN = 0,
37 CONNMAN_SESSION_ROAMING_POLICY_DEFAULT = 1,
38 CONNMAN_SESSION_ROAMING_POLICY_ALWAYS = 2,
39 CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN = 3,
40 CONNMAN_SESSION_ROAMING_POLICY_NATIONAL = 4,
41 CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL = 5,
48 connman_bool_t connect;
49 connman_bool_t online;
50 connman_bool_t priority;
51 GSList *allowed_bearers;
52 connman_bool_t avoid_handover;
53 connman_bool_t stay_connected;
54 unsigned int periodic_connect;
55 unsigned int idle_timeout;
57 enum connman_session_roaming_policy roaming_policy;
60 struct connman_service *service;
63 struct connman_session {
69 struct session_info info;
70 struct session_info info_last;
72 GSequence *service_list;
77 connman_bool_t match_all;
78 enum connman_service_type service_type;
81 static const char *roamingpolicy2string(enum connman_session_roaming_policy policy)
84 case CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN:
86 case CONNMAN_SESSION_ROAMING_POLICY_DEFAULT:
88 case CONNMAN_SESSION_ROAMING_POLICY_ALWAYS:
90 case CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN:
92 case CONNMAN_SESSION_ROAMING_POLICY_NATIONAL:
94 case CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL:
95 return "international";
101 static enum connman_session_roaming_policy string2roamingpolicy(const char *policy)
103 if (g_strcmp0(policy, "default") == 0)
104 return CONNMAN_SESSION_ROAMING_POLICY_DEFAULT;
105 else if (g_strcmp0(policy, "always") == 0)
106 return CONNMAN_SESSION_ROAMING_POLICY_ALWAYS;
107 else if (g_strcmp0(policy, "forbidden") == 0)
108 return CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN;
109 else if (g_strcmp0(policy, "national") == 0)
110 return CONNMAN_SESSION_ROAMING_POLICY_NATIONAL;
111 else if (g_strcmp0(policy, "international") == 0)
112 return CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL;
114 return CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN;
117 static enum connman_service_type bearer2service(const char *bearer)
120 return CONNMAN_SERVICE_TYPE_UNKNOWN;
122 if (g_strcmp0(bearer, "ethernet") == 0)
123 return CONNMAN_SERVICE_TYPE_ETHERNET;
124 else if (g_strcmp0(bearer, "wifi") == 0)
125 return CONNMAN_SERVICE_TYPE_WIFI;
126 else if (g_strcmp0(bearer, "wimax") == 0)
127 return CONNMAN_SERVICE_TYPE_WIMAX;
128 else if (g_strcmp0(bearer, "bluetooth") == 0)
129 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
130 else if (g_strcmp0(bearer, "3g") == 0)
131 return CONNMAN_SERVICE_TYPE_CELLULAR;
133 return CONNMAN_SERVICE_TYPE_UNKNOWN;
136 static char *service2bearer(enum connman_service_type type)
139 case CONNMAN_SERVICE_TYPE_ETHERNET:
141 case CONNMAN_SERVICE_TYPE_WIFI:
143 case CONNMAN_SERVICE_TYPE_WIMAX:
145 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
147 case CONNMAN_SERVICE_TYPE_CELLULAR:
149 case CONNMAN_SERVICE_TYPE_UNKNOWN:
150 case CONNMAN_SERVICE_TYPE_SYSTEM:
151 case CONNMAN_SERVICE_TYPE_GPS:
152 case CONNMAN_SERVICE_TYPE_VPN:
153 case CONNMAN_SERVICE_TYPE_GADGET:
160 static char *session2bearer(struct connman_session *session)
162 struct session_info *info = &session->info;
164 struct bearer_info *bearer_info;
165 enum connman_service_type type;
167 if (info->service == NULL)
170 type = connman_service_get_type(info->service);
172 for (list = info->allowed_bearers;
173 list != NULL; list = list->next) {
174 bearer_info = list->data;
176 if (bearer_info->match_all)
177 return service2bearer(type);
179 if (bearer_info->service_type == CONNMAN_SERVICE_TYPE_UNKNOWN)
180 return bearer_info->name;
182 if (bearer_info->service_type == type)
183 return service2bearer(type);
190 static void cleanup_bearer_info(gpointer data, gpointer user_data)
192 struct bearer_info *info = data;
198 static GSList *session_parse_allowed_bearers(DBusMessageIter *iter)
200 struct bearer_info *info;
201 DBusMessageIter array;
204 dbus_message_iter_recurse(iter, &array);
206 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
209 dbus_message_iter_get_basic(&array, &bearer);
211 info = g_try_new0(struct bearer_info, 1);
213 g_slist_foreach(list, cleanup_bearer_info, NULL);
219 info->name = g_strdup(bearer);
220 info->service_type = bearer2service(info->name);
222 if (info->service_type == CONNMAN_SERVICE_TYPE_UNKNOWN &&
223 g_strcmp0(info->name, "*") == 0) {
224 info->match_all = TRUE;
226 info->match_all = FALSE;
229 list = g_slist_append(list, info);
231 dbus_message_iter_next(&array);
237 static GSList *session_allowed_bearers_any(void)
239 struct bearer_info *info;
242 info = g_try_new0(struct bearer_info, 1);
249 info->name = g_strdup("");
250 info->match_all = TRUE;
251 info->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
253 list = g_slist_append(list, info);
258 static void append_allowed_bearers(DBusMessageIter *iter, void *user_data)
260 struct session_info *info = user_data;
263 for (list = info->allowed_bearers;
264 list != NULL; list = list->next) {
265 struct bearer_info *info = list->data;
267 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
272 static void append_ipconfig_ipv4(DBusMessageIter *iter, void *user_data)
274 struct connman_service *service = user_data;
275 struct connman_ipconfig *ipconfig_ipv4;
280 ipconfig_ipv4 = __connman_service_get_ip4config(service);
281 if (ipconfig_ipv4 == NULL)
284 __connman_ipconfig_append_ipv4(ipconfig_ipv4, iter);
287 static void append_ipconfig_ipv6(DBusMessageIter *iter, void *user_data)
289 struct connman_service *service = user_data;
290 struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
295 ipconfig_ipv4 = __connman_service_get_ip4config(service);
296 ipconfig_ipv6 = __connman_service_get_ip6config(service);
297 if (ipconfig_ipv6 == NULL)
300 __connman_ipconfig_append_ipv6(ipconfig_ipv6, iter, ipconfig_ipv4);
303 static void append_notify_all(DBusMessageIter *dict,
304 struct connman_session *session)
306 struct session_info *info = &session->info;
307 struct session_info *info_last = &session->info_last;
310 if (info->bearer != info_last->bearer) {
311 connman_dbus_dict_append_basic(dict, "Bearer",
314 info_last->bearer = info->bearer;
317 if (info->online != info_last->online) {
318 connman_dbus_dict_append_basic(dict, "Online",
321 info_last->online = info->online;
324 if (info->name != info_last->name) {
325 connman_dbus_dict_append_basic(dict, "Name",
328 info_last->name = info->name;
331 if (info->service != info_last->service) {
332 connman_dbus_dict_append_dict(dict, "IPv4",
333 append_ipconfig_ipv4,
336 connman_dbus_dict_append_dict(dict, "IPv6",
337 append_ipconfig_ipv6,
340 connman_dbus_dict_append_basic(dict, "Interface",
344 info_last->service = info->service;
348 if (info->priority != info_last->priority) {
349 connman_dbus_dict_append_basic(dict, "Priority",
352 info_last->priority = info->priority;
355 if (info->allowed_bearers != info_last->allowed_bearers) {
356 connman_dbus_dict_append_array(dict, "AllowedBearers",
358 append_allowed_bearers,
360 info_last->allowed_bearers = info->allowed_bearers;
363 if (info->avoid_handover != info_last->avoid_handover) {
364 connman_dbus_dict_append_basic(dict, "AvoidHandover",
366 &info->avoid_handover);
367 info_last->avoid_handover = info->avoid_handover;
370 if (info->stay_connected != info_last->stay_connected) {
371 connman_dbus_dict_append_basic(dict, "StayConnected",
373 &info->stay_connected);
374 info_last->stay_connected = info->stay_connected;
377 if (info->periodic_connect != info_last->periodic_connect) {
378 connman_dbus_dict_append_basic(dict, "PeriodicConnect",
380 &info->periodic_connect);
381 info_last->periodic_connect = info->periodic_connect;
384 if (info->idle_timeout != info_last->idle_timeout) {
385 connman_dbus_dict_append_basic(dict, "IdleTimeout",
387 &info->idle_timeout);
388 info_last->idle_timeout = info->idle_timeout;
391 if (info->ecall != info_last->ecall) {
392 connman_dbus_dict_append_basic(dict, "EmergencyCall",
395 info_last->ecall = info->ecall;
398 if (info->roaming_policy != info_last->roaming_policy) {
399 policy = roamingpolicy2string(info->roaming_policy);
400 connman_dbus_dict_append_basic(dict, "RoamingPolicy",
403 info_last->roaming_policy = info->roaming_policy;
406 if (info->marker != info_last->marker) {
407 connman_dbus_dict_append_basic(dict, "SessionMarker",
410 info_last->marker = info->marker;
414 static gboolean session_notify_all(gpointer user_data)
416 struct connman_session *session = user_data;
418 DBusMessageIter array, dict;
420 DBG("session %p owner %s notify_path %s", session,
421 session->owner, session->notify_path);
423 msg = dbus_message_new_method_call(session->owner, session->notify_path,
424 CONNMAN_NOTIFICATION_INTERFACE,
427 connman_error("Could not create notification message");
431 dbus_message_iter_init_append(msg, &array);
432 connman_dbus_dict_open(&array, &dict);
434 append_notify_all(&dict, session);
436 connman_dbus_dict_close(&array, &dict);
438 g_dbus_send_message(connection, msg);
443 static gboolean service_changed(gpointer user_data)
445 struct connman_session *session = user_data;
449 DBusMessageIter array, dict;
451 DBG("session %p owner %s notify_path %s", session,
452 session->owner, session->notify_path);
454 msg = dbus_message_new_method_call(session->owner, session->notify_path,
455 CONNMAN_NOTIFICATION_INTERFACE,
458 connman_error("Could not create notification message");
462 dbus_message_iter_init_append(msg, &array);
463 connman_dbus_dict_open(&array, &dict);
465 append_notify_all(&dict, session);
467 connman_dbus_dict_close(&array, &dict);
469 g_dbus_send_message(connection, msg);
474 static void online_changed(struct connman_session *session)
476 struct session_info *info = &session->info;
478 connman_dbus_setting_changed_basic(session->owner, session->notify_path,
479 "Online", DBUS_TYPE_BOOLEAN,
483 static void ipconfig_ipv4_changed(struct connman_session *session)
485 struct session_info *info = &session->info;
487 connman_dbus_setting_changed_dict(session->owner, session->notify_path,
488 "IPv4", append_ipconfig_ipv4,
492 static void ipconfig_ipv6_changed(struct connman_session *session)
494 struct session_info *info = &session->info;
496 connman_dbus_setting_changed_dict(session->owner, session->notify_path,
497 "IPv6", append_ipconfig_ipv6,
501 static void update_service(struct connman_session *session)
503 struct session_info *info = &session->info;
506 if (info->service != NULL) {
507 info->bearer = session2bearer(session);
508 info->online = __connman_service_is_connected(info->service);
509 info->name = __connman_service_get_name(info->service);
510 idx = __connman_service_get_index(info->service);
511 info->ifname = connman_inet_ifname(idx);
515 info->online = FALSE;
521 static connman_bool_t service_type_match(struct connman_session *session,
522 struct connman_service *service)
524 struct session_info *info = &session->info;
527 for (list = info->allowed_bearers;
528 list != NULL; list = list->next) {
529 struct bearer_info *info = list->data;
530 enum connman_service_type service_type;
532 if (info->match_all == TRUE)
535 service_type = connman_service_get_type(service);
536 if (info->service_type == service_type)
543 static connman_bool_t service_match(struct connman_session *session,
544 struct connman_service *service)
546 if (service_type_match(session, service) == FALSE)
552 static int service_type_weight(enum connman_service_type type)
555 * The session doesn't care which service
556 * to use. Nevertheless we have to sort them
557 * according their type. The ordering is
566 case CONNMAN_SERVICE_TYPE_ETHERNET:
568 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
570 case CONNMAN_SERVICE_TYPE_WIFI:
571 case CONNMAN_SERVICE_TYPE_WIMAX:
573 case CONNMAN_SERVICE_TYPE_CELLULAR:
575 case CONNMAN_SERVICE_TYPE_UNKNOWN:
576 case CONNMAN_SERVICE_TYPE_SYSTEM:
577 case CONNMAN_SERVICE_TYPE_GPS:
578 case CONNMAN_SERVICE_TYPE_VPN:
579 case CONNMAN_SERVICE_TYPE_GADGET:
586 static gint sort_allowed_bearers(struct connman_service *service_a,
587 struct connman_service *service_b,
588 struct connman_session *session)
590 struct session_info *info = &session->info;
592 enum connman_service_type type_a, type_b;
593 int weight_a, weight_b;
595 type_a = connman_service_get_type(service_a);
596 type_b = connman_service_get_type(service_b);
598 for (list = info->allowed_bearers;
599 list != NULL; list = list->next) {
600 struct bearer_info *info = list->data;
602 if (info->match_all == TRUE) {
603 if (type_a != type_b) {
604 weight_a = service_type_weight(type_a);
605 weight_b = service_type_weight(type_b);
607 if (weight_a > weight_b)
610 if (weight_a < weight_b)
617 if (type_a == info->service_type &&
618 type_b == info->service_type) {
622 if (type_a == info->service_type &&
623 type_b != info->service_type) {
627 if (type_a != info->service_type &&
628 type_b == info->service_type) {
636 static gint sort_services(gconstpointer a, gconstpointer b, gpointer user_data)
638 struct connman_service *service_a = (void *)a;
639 struct connman_service *service_b = (void *)b;
640 struct connman_session *session = user_data;
642 return sort_allowed_bearers(service_a, service_b, session);
645 static void print_name(gpointer data, gpointer user_data)
647 struct connman_service *service = data;
649 DBG("service %p type %s name %s", service,
650 service2bearer(connman_service_get_type(service)),
651 __connman_service_get_name(service));
654 static connman_bool_t session_select_service(struct connman_session *session)
656 struct session_info *info = &session->info;
657 struct connman_service *service;
660 session->service_list =
661 __connman_service_get_list(session, service_match);
663 if (session->service_list == NULL)
666 g_sequence_sort(session->service_list, sort_services, session);
667 g_sequence_foreach(session->service_list, print_name, NULL);
669 iter = g_sequence_get_begin_iter(session->service_list);
671 while (g_sequence_iter_is_end(iter) == FALSE) {
672 service = g_sequence_get(iter);
674 if (__connman_service_is_connecting(service) == TRUE ||
675 __connman_service_is_connected(service) == TRUE) {
676 info->service = service;
680 iter = g_sequence_iter_next(iter);
686 static void cleanup_session(gpointer user_data)
688 struct connman_session *session = user_data;
689 struct session_info *info = &session->info;
691 DBG("remove %s", session->session_path);
693 g_sequence_free(session->service_list);
695 g_slist_foreach(info->allowed_bearers, cleanup_bearer_info, NULL);
696 g_slist_free(info->allowed_bearers);
698 g_free(session->owner);
699 g_free(session->session_path);
700 g_free(session->notify_path);
705 static void release_session(gpointer key, gpointer value, gpointer user_data)
707 struct connman_session *session = value;
708 DBusMessage *message;
710 DBG("owner %s path %s", session->owner, session->notify_path);
712 if (session->notify_watch > 0)
713 g_dbus_remove_watch(connection, session->notify_watch);
715 g_dbus_unregister_interface(connection, session->session_path,
716 CONNMAN_SESSION_INTERFACE);
718 message = dbus_message_new_method_call(session->owner,
719 session->notify_path,
720 CONNMAN_NOTIFICATION_INTERFACE,
725 dbus_message_set_no_reply(message, TRUE);
727 g_dbus_send_message(connection, message);
730 static int session_disconnect(struct connman_session *session)
732 DBG("session %p, %s", session, session->owner);
734 if (session->notify_watch > 0)
735 g_dbus_remove_watch(connection, session->notify_watch);
737 g_dbus_unregister_interface(connection, session->session_path,
738 CONNMAN_SESSION_INTERFACE);
740 g_hash_table_remove(session_hash, session->session_path);
745 static void owner_disconnect(DBusConnection *conn, void *user_data)
747 struct connman_session *session = user_data;
749 DBG("session %p, %s died", session, session->owner);
751 session_disconnect(session);
754 static DBusMessage *destroy_session(DBusConnection *conn,
755 DBusMessage *msg, void *user_data)
757 struct connman_session *session = user_data;
759 DBG("session %p", session);
761 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
764 static gboolean session_do_connect(gpointer user_data)
766 struct connman_session *session = user_data;
767 struct session_info *info = &session->info;
769 __connman_service_connect(info->service);
771 service_changed(session);
775 static DBusMessage *connect_session(DBusConnection *conn,
776 DBusMessage *msg, void *user_data)
778 struct connman_session *session = user_data;
779 struct session_info *info = &session->info;
780 struct connman_service *service = NULL;
781 GSourceFunc callback = NULL;
784 DBG("session %p", session);
786 info->connect = TRUE;
788 if (session->service_list != NULL)
789 g_sequence_free(session->service_list);
791 session->service_list = __connman_service_get_list(session,
794 g_sequence_sort(session->service_list, sort_services, session);
795 g_sequence_foreach(session->service_list, print_name, NULL);
797 iter = g_sequence_get_begin_iter(session->service_list);
799 while (g_sequence_iter_is_end(iter) == FALSE) {
800 service = g_sequence_get(iter);
802 if (__connman_service_is_connecting(service) == TRUE ||
803 __connman_service_is_connected(service) == TRUE) {
804 callback = service_changed;
808 if (__connman_service_is_idle(service) == TRUE) {
809 callback = session_do_connect;
815 iter = g_sequence_iter_next(iter);
818 if (service != NULL) {
819 info->service = service;
820 update_service(session);
821 g_timeout_add_seconds(0, callback, session);
824 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
827 static gboolean session_do_disconnect(gpointer user_data)
829 struct connman_session *session = user_data;
830 struct session_info *info = &session->info;
832 if (__connman_service_disconnect(info->service) < 0)
835 info->service = NULL;
836 update_service(session);
837 service_changed(session);
842 static DBusMessage *disconnect_session(DBusConnection *conn,
843 DBusMessage *msg, void *user_data)
845 struct connman_session *session = user_data;
846 struct session_info *info = &session->info;
848 DBG("session %p", session);
850 info->connect = FALSE;
852 if (info->service == NULL)
853 return __connman_error_already_disabled(msg);
855 g_timeout_add_seconds(0, session_do_disconnect, session);
857 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
860 static DBusMessage *change_session(DBusConnection *conn,
861 DBusMessage *msg, void *user_data)
863 struct connman_session *session = user_data;
864 struct session_info *info = &session->info;
865 DBusMessageIter iter, value;
867 DBusMessageIter reply_array, reply_dict;
869 GSList *allowed_bearers;
871 DBG("session %p", session);
872 if (dbus_message_iter_init(msg, &iter) == FALSE)
873 return __connman_error_invalid_arguments(msg);
875 reply = dbus_message_new_method_call(session->owner,
876 session->notify_path,
877 CONNMAN_NOTIFICATION_INTERFACE,
880 return __connman_error_failed(msg, ENOMEM);
882 dbus_message_iter_init_append(reply, &reply_array);
883 connman_dbus_dict_open(&reply_array, &reply_dict);
885 dbus_message_iter_get_basic(&iter, &name);
886 dbus_message_iter_next(&iter);
887 dbus_message_iter_recurse(&iter, &value);
889 switch (dbus_message_iter_get_arg_type(&value)) {
890 case DBUS_TYPE_ARRAY:
891 if (g_str_equal(name, "AllowedBearers") == TRUE) {
892 allowed_bearers = session_parse_allowed_bearers(&value);
894 g_slist_foreach(info->allowed_bearers,
895 cleanup_bearer_info, NULL);
896 g_slist_free(info->allowed_bearers);
898 if (allowed_bearers == NULL) {
899 allowed_bearers = session_allowed_bearers_any();
901 if (allowed_bearers == NULL) {
902 dbus_message_unref(reply);
903 return __connman_error_failed(msg, ENOMEM);
907 info->allowed_bearers = allowed_bearers;
909 /* update_allowed_bearers(); */
914 case DBUS_TYPE_BOOLEAN:
915 if (g_str_equal(name, "Priority") == TRUE) {
916 dbus_message_iter_get_basic(&value,
919 /* update_priority(); */
920 } else if (g_str_equal(name, "AvoidHandover") == TRUE) {
921 dbus_message_iter_get_basic(&value,
922 &info->avoid_handover);
924 /* update_avoid_handover(); */
925 } else if (g_str_equal(name, "StayConnected") == TRUE) {
926 dbus_message_iter_get_basic(&value,
927 &info->stay_connected);
929 /* update_stay_connected(); */
930 } else if (g_str_equal(name, "EmergencyCall") == TRUE) {
931 dbus_message_iter_get_basic(&value,
934 /* update_ecall(); */
939 case DBUS_TYPE_UINT32:
940 if (g_str_equal(name, "PeriodicConnect") == TRUE) {
941 dbus_message_iter_get_basic(&value,
942 &info->periodic_connect);
944 /* update_periodic_update(); */
945 } else if (g_str_equal(name, "IdleTimeout") == TRUE) {
946 dbus_message_iter_get_basic(&value,
947 &info->idle_timeout);
949 /* update_idle_timeout(); */
954 case DBUS_TYPE_STRING:
955 if (g_str_equal(name, "RoamingPolicy") == TRUE) {
957 dbus_message_iter_get_basic(&value, &val);
958 info->roaming_policy =
959 string2roamingpolicy(val);
961 /* update_roaming_allowed(); */
968 append_notify_all(&reply_dict, session);
970 connman_dbus_dict_close(&reply_array, &reply_dict);
972 g_dbus_send_message(connection, reply);
974 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
977 dbus_message_unref(reply);
978 return __connman_error_invalid_arguments(msg);
981 static GDBusMethodTable session_methods[] = {
982 { "Destroy", "", "", destroy_session },
983 { "Connect", "", "", connect_session },
984 { "Disconnect", "", "", disconnect_session },
985 { "Change", "sv", "", change_session },
989 int __connman_session_create(DBusMessage *msg)
991 const char *owner, *notify_path;
993 DBusMessageIter iter, array;
994 struct connman_session *session;
995 struct session_info *info, *info_last;
997 connman_bool_t priority = FALSE, avoid_handover = FALSE;
998 connman_bool_t stay_connected = FALSE, ecall = FALSE;
999 enum connman_session_roaming_policy roaming_policy =
1000 CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN;
1001 GSList *allowed_bearers = NULL;
1002 unsigned int periodic_connect = 0;
1003 unsigned int idle_timeout = 0;
1007 owner = dbus_message_get_sender(msg);
1009 DBG("owner %s", owner);
1011 dbus_message_iter_init(msg, &iter);
1012 dbus_message_iter_recurse(&iter, &array);
1014 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1015 DBusMessageIter entry, value;
1016 const char *key, *val;
1018 dbus_message_iter_recurse(&array, &entry);
1019 dbus_message_iter_get_basic(&entry, &key);
1021 dbus_message_iter_next(&entry);
1022 dbus_message_iter_recurse(&entry, &value);
1024 switch (dbus_message_iter_get_arg_type(&value)) {
1025 case DBUS_TYPE_ARRAY:
1026 if (g_str_equal(key, "AllowedBearers") == TRUE) {
1028 session_parse_allowed_bearers(&value);
1033 case DBUS_TYPE_BOOLEAN:
1034 if (g_str_equal(key, "Priority") == TRUE) {
1035 dbus_message_iter_get_basic(&value,
1037 } else if (g_str_equal(key, "AvoidHandover") == TRUE) {
1038 dbus_message_iter_get_basic(&value,
1040 } else if (g_str_equal(key, "StayConnected") == TRUE) {
1041 dbus_message_iter_get_basic(&value,
1043 } else if (g_str_equal(key, "EmergencyCall") == TRUE) {
1044 dbus_message_iter_get_basic(&value,
1050 case DBUS_TYPE_UINT32:
1051 if (g_str_equal(key, "PeriodicConnect") == TRUE) {
1052 dbus_message_iter_get_basic(&value,
1054 } else if (g_str_equal(key, "IdleTimeout") == TRUE) {
1055 dbus_message_iter_get_basic(&value,
1061 case DBUS_TYPE_STRING:
1062 if (g_str_equal(key, "RoamingPolicy") == TRUE) {
1063 dbus_message_iter_get_basic(&value, &val);
1064 roaming_policy = string2roamingpolicy(val);
1069 dbus_message_iter_next(&array);
1072 dbus_message_iter_next(&iter);
1073 dbus_message_iter_get_basic(&iter, ¬ify_path);
1075 if (notify_path == NULL) {
1076 session_path = NULL;
1081 session_path = g_strdup_printf("/sessions%s", notify_path);
1082 if (session_path == NULL) {
1087 session = g_hash_table_lookup(session_hash, session_path);
1088 if (session != NULL) {
1093 session = g_try_new0(struct connman_session, 1);
1094 if (session == NULL) {
1099 info = &session->info;
1100 info_last = &session->info_last;
1102 session->owner = g_strdup(owner);
1103 session->session_path = session_path;
1104 session->notify_path = g_strdup(notify_path);
1105 session->notify_watch =
1106 g_dbus_add_disconnect_watch(connection, session->owner,
1107 owner_disconnect, session, NULL);
1110 info->online = FALSE;
1111 info->priority = priority;
1112 info->avoid_handover = avoid_handover;
1113 info->stay_connected = stay_connected;
1114 info->periodic_connect = periodic_connect;
1115 info->idle_timeout = idle_timeout;
1116 info->ecall = ecall;
1117 info->roaming_policy = roaming_policy;
1119 if (allowed_bearers == NULL) {
1120 info->allowed_bearers =
1121 session_allowed_bearers_any();
1123 if (info->allowed_bearers == NULL) {
1128 info->allowed_bearers = allowed_bearers;
1131 info_last->bearer = NULL;
1132 info_last->online = !priority;
1133 info_last->avoid_handover = !avoid_handover;
1134 info_last->stay_connected = !stay_connected;
1135 info_last->periodic_connect = !periodic_connect;
1136 info_last->idle_timeout = !idle_timeout;
1137 info_last->ecall = !ecall;
1138 info_last->roaming_policy =
1139 CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN;
1140 info_last->allowed_bearers = NULL;
1141 info_last->service = NULL;
1142 info_last->marker = info->marker + 1;
1144 session->service_list = NULL;
1146 update_service(session);
1148 g_hash_table_replace(session_hash, session->session_path, session);
1150 DBG("add %s", session->session_path);
1152 if (g_dbus_register_interface(connection, session->session_path,
1153 CONNMAN_SESSION_INTERFACE,
1154 session_methods, NULL,
1155 NULL, session, NULL) == FALSE) {
1156 connman_error("Failed to register %s", session->session_path);
1157 g_hash_table_remove(session_hash, session->session_path);
1164 g_dbus_send_reply(connection, msg,
1165 DBUS_TYPE_OBJECT_PATH, &session->session_path,
1170 * Check if the session info matches to a service which is
1171 * a already connected
1173 if (session_select_service(session) == TRUE)
1174 update_service(session);
1176 info_last->service = (void *)1;
1178 g_timeout_add_seconds(0, session_notify_all, session);
1183 connman_error("Failed to create session");
1184 g_free(session_path);
1186 g_slist_foreach(allowed_bearers, cleanup_bearer_info, NULL);
1187 g_slist_free(allowed_bearers);
1192 int __connman_session_destroy(DBusMessage *msg)
1194 const char *owner, *session_path;
1195 struct connman_session *session;
1197 owner = dbus_message_get_sender(msg);
1199 DBG("owner %s", owner);
1201 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &session_path,
1203 if (session_path == NULL)
1206 session = g_hash_table_lookup(session_hash, session_path);
1207 if (session == NULL)
1210 if (g_strcmp0(owner, session->owner) != 0)
1213 session_disconnect(session);
1218 connman_bool_t __connman_session_mode()
1223 void __connman_session_set_mode(connman_bool_t enable)
1225 DBG("enable %d", enable);
1227 if (sessionmode == enable)
1230 sessionmode = enable;
1232 if (sessionmode == TRUE)
1233 __connman_service_disconnect_all();
1236 static void service_add(struct connman_service *service)
1238 GHashTableIter iter;
1239 gpointer key, value;
1240 struct connman_session *session;
1242 DBG("service %p", service);
1244 g_hash_table_iter_init(&iter, session_hash);
1246 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1249 if (service_match(session, service) == FALSE)
1252 g_sequence_insert_sorted(session->service_list, service,
1253 sort_services, session);
1257 static gint service_in_session(gconstpointer a, gconstpointer b,
1266 static void service_remove(struct connman_service *service)
1269 GHashTableIter iter;
1270 gpointer key, value;
1271 GSequenceIter *seq_iter;
1272 struct connman_session *session;
1273 struct session_info *info;
1274 struct connman_service *found_service;
1276 DBG("service %p", service);
1278 g_hash_table_iter_init(&iter, session_hash);
1280 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1282 info = &session->info;
1284 if (session->service_list == NULL)
1287 seq_iter = g_sequence_search(session->service_list, service,
1288 service_in_session, NULL);
1289 if (g_sequence_iter_is_end(seq_iter) == TRUE)
1292 g_sequence_remove(seq_iter);
1294 found_service = g_sequence_get(seq_iter);
1295 if (found_service != info->service)
1298 info->service = NULL;
1299 update_service(session);
1300 g_timeout_add_seconds(0, service_changed, session);
1304 static void service_state_changed(struct connman_service *service,
1305 enum connman_service_state state)
1307 GHashTableIter iter;
1308 gpointer key, value;
1309 struct connman_session *session;
1310 struct session_info *info;
1311 connman_bool_t online;
1313 DBG("service %p state %d", service, state);
1315 g_hash_table_iter_init(&iter, session_hash);
1317 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1319 info = &session->info;
1321 if (info->service == service) {
1322 online = __connman_service_is_connected(service);
1323 if (info->online == online)
1326 info->online = online;
1327 online_changed(session);
1332 static void ipconfig_changed(struct connman_service *service,
1333 struct connman_ipconfig *ipconfig)
1335 GHashTableIter iter;
1336 gpointer key, value;
1337 struct connman_session *session;
1338 struct session_info *info;
1339 enum connman_ipconfig_type type;
1341 DBG("service %p ipconfig %p", service, ipconfig);
1343 type = __connman_ipconfig_get_config_type(ipconfig);
1345 g_hash_table_iter_init(&iter, session_hash);
1347 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1349 info = &session->info;
1351 if (info->service == service) {
1352 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1353 ipconfig_ipv4_changed(session);
1354 else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1355 ipconfig_ipv6_changed(session);
1360 static struct connman_notifier session_notifier = {
1362 .service_add = service_add,
1363 .service_remove = service_remove,
1364 .service_state_changed = service_state_changed,
1365 .ipconfig_changed = ipconfig_changed,
1368 int __connman_session_init(void)
1374 connection = connman_dbus_get_connection();
1375 if (connection == NULL)
1378 err = connman_notifier_register(&session_notifier);
1380 dbus_connection_unref(connection);
1384 session_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1385 NULL, cleanup_session);
1387 sessionmode = FALSE;
1391 void __connman_session_cleanup(void)
1395 if (connection == NULL)
1398 connman_notifier_unregister(&session_notifier);
1400 g_hash_table_foreach(session_hash, release_session, NULL);
1401 g_hash_table_destroy(session_hash);
1403 dbus_connection_unref(connection);