session: Rename the Realtime flag to Priority
[platform/upstream/connman.git] / src / session.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2011  BWM CarIT GmbH. All rights reserved.
7  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <gdbus.h>
28
29 #include "connman.h"
30
31 static DBusConnection *connection;
32 static GHashTable *session_hash;
33 static connman_bool_t sessionmode;
34
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,
42 };
43
44 struct connman_session {
45         char *owner;
46         char *session_path;
47         char *notify_path;
48         guint notify_watch;
49
50         char *bearer;
51         const char *name;
52         char *ifname;
53         connman_bool_t online;
54         connman_bool_t priority;
55         GSList *allowed_bearers;
56         connman_bool_t avoid_handover;
57         connman_bool_t stay_connected;
58         unsigned int periodic_connect;
59         unsigned int idle_timeout;
60         connman_bool_t ecall;
61         enum connman_session_roaming_policy roaming_policy;
62         unsigned int marker;
63
64         GSequence *service_list;
65         struct connman_service *service;
66 };
67
68 struct bearer_info {
69         char *name;
70         connman_bool_t match_all;
71         enum connman_service_type service_type;
72 };
73
74 static const char *roamingpolicy2string(enum connman_session_roaming_policy policy)
75 {
76         switch (policy) {
77         case CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN:
78                 break;
79         case CONNMAN_SESSION_ROAMING_POLICY_DEFAULT:
80                 return "default";
81         case CONNMAN_SESSION_ROAMING_POLICY_ALWAYS:
82                 return "always";
83         case CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN:
84                 return "forbidden";
85         case CONNMAN_SESSION_ROAMING_POLICY_NATIONAL:
86                 return "national";
87         case CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL:
88                 return "international";
89         }
90
91         return NULL;
92 }
93
94 static enum connman_session_roaming_policy string2roamingpolicy(const char *policy)
95 {
96         if (g_strcmp0(policy, "default") == 0)
97                 return CONNMAN_SESSION_ROAMING_POLICY_DEFAULT;
98         else if (g_strcmp0(policy, "always") == 0)
99                 return CONNMAN_SESSION_ROAMING_POLICY_ALWAYS;
100         else if (g_strcmp0(policy, "forbidden") == 0)
101                 return CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN;
102         else if (g_strcmp0(policy, "national") == 0)
103                 return CONNMAN_SESSION_ROAMING_POLICY_NATIONAL;
104         else if (g_strcmp0(policy, "international") == 0)
105                 return CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL;
106         else
107                 return CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN;
108 }
109
110 static enum connman_service_type bearer2service(const char *bearer)
111 {
112         if (bearer == NULL)
113                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
114
115         if (g_strcmp0(bearer, "ethernet") == 0)
116                 return CONNMAN_SERVICE_TYPE_ETHERNET;
117         else if (g_strcmp0(bearer, "wifi") == 0)
118                 return CONNMAN_SERVICE_TYPE_WIFI;
119         else if (g_strcmp0(bearer, "wimax") == 0)
120                 return CONNMAN_SERVICE_TYPE_WIMAX;
121         else if (g_strcmp0(bearer, "bluetooth") == 0)
122                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
123         else if (g_strcmp0(bearer, "3g") == 0)
124                 return CONNMAN_SERVICE_TYPE_CELLULAR;
125         else
126                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
127 }
128
129 static char *service2bearer(enum connman_service_type type)
130 {
131         switch (type) {
132         case CONNMAN_SERVICE_TYPE_ETHERNET:
133                 return "ethernet";
134         case CONNMAN_SERVICE_TYPE_WIFI:
135                 return "wifi";
136         case CONNMAN_SERVICE_TYPE_WIMAX:
137                 return "wimax";
138         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
139                 return "bluetooth";
140         case CONNMAN_SERVICE_TYPE_CELLULAR:
141                 return "3g";
142         case CONNMAN_SERVICE_TYPE_UNKNOWN:
143         case CONNMAN_SERVICE_TYPE_SYSTEM:
144         case CONNMAN_SERVICE_TYPE_GPS:
145         case CONNMAN_SERVICE_TYPE_VPN:
146         case CONNMAN_SERVICE_TYPE_GADGET:
147                 return NULL;
148         }
149
150         return NULL;
151 }
152
153 static char *session2bearer(struct connman_session *session)
154 {
155         GSList *list;
156         struct bearer_info *info;
157         enum connman_service_type type;
158
159         if (session->service == NULL)
160                 return NULL;
161
162         type = connman_service_get_type(session->service);
163
164         for (list = session->allowed_bearers; list != NULL; list = list->next) {
165                 info = list->data;
166
167                 if (info->match_all)
168                         return service2bearer(type);
169
170                 if (info->service_type == CONNMAN_SERVICE_TYPE_UNKNOWN)
171                         return info->name;
172
173                 if (info->service_type == type)
174                         return service2bearer(type);
175         }
176
177         return NULL;
178
179 }
180
181 static void cleanup_bearer_info(gpointer data, gpointer user_data)
182 {
183         struct bearer_info *info = data;
184
185         g_free(info->name);
186         g_free(info);
187 }
188
189 static GSList *session_parse_allowed_bearers(DBusMessageIter *iter)
190 {
191         struct bearer_info *info;
192         DBusMessageIter array;
193         GSList *list = NULL;
194
195         dbus_message_iter_recurse(iter, &array);
196
197         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
198                 char *bearer = NULL;
199
200                 dbus_message_iter_get_basic(&array, &bearer);
201
202                 info = g_try_new0(struct bearer_info, 1);
203                 if (info == NULL) {
204                         g_slist_foreach(list, cleanup_bearer_info, NULL);
205                         g_slist_free(list);
206
207                         return NULL;
208                 }
209
210                 info->name = g_strdup(bearer);
211                 info->service_type = bearer2service(info->name);
212
213                 if (info->service_type == CONNMAN_SERVICE_TYPE_UNKNOWN &&
214                                 g_strcmp0(info->name, "*") == 0) {
215                         info->match_all = TRUE;
216                 } else {
217                         info->match_all = FALSE;
218                 }
219
220                 list = g_slist_append(list, info);
221
222                 dbus_message_iter_next(&array);
223         }
224
225         return list;
226 }
227
228 static GSList *session_allowed_bearers_any(void)
229 {
230         struct bearer_info *info;
231         GSList *list = NULL;
232
233         info = g_try_new0(struct bearer_info, 1);
234         if (info == NULL) {
235                 g_slist_free(list);
236
237                 return NULL;
238         }
239
240         info->name = g_strdup("");
241         info->match_all = TRUE;
242         info->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
243
244         list = g_slist_append(list, info);
245
246         return list;
247 }
248
249 static void append_allowed_bearers(DBusMessageIter *iter, void *user_data)
250 {
251         struct connman_session *session = user_data;
252         GSList *list;
253
254         for (list = session->allowed_bearers; list != NULL; list = list->next) {
255                 struct bearer_info *info = list->data;
256
257                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
258                                                 &info->name);
259         }
260 }
261
262 static void append_ipconfig_ipv4(DBusMessageIter *iter, void *user_data)
263 {
264         struct connman_service *service = user_data;
265         struct connman_ipconfig *ipconfig_ipv4;
266
267         if (service == NULL)
268                 return;
269
270         ipconfig_ipv4 = __connman_service_get_ip4config(service);
271         if (ipconfig_ipv4 == NULL)
272                 return;
273
274         __connman_ipconfig_append_ipv4(ipconfig_ipv4, iter);
275 }
276
277 static void append_ipconfig_ipv6(DBusMessageIter *iter, void *user_data)
278 {
279         struct connman_service *service = user_data;
280         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
281
282         if (service == NULL)
283                 return;
284
285         ipconfig_ipv4 = __connman_service_get_ip4config(service);
286         ipconfig_ipv6 = __connman_service_get_ip6config(service);
287         if (ipconfig_ipv6 == NULL)
288                 return;
289
290         __connman_ipconfig_append_ipv6(ipconfig_ipv6, iter, ipconfig_ipv4);
291 }
292
293 static void append_service(DBusMessageIter *dict,
294                                         struct connman_session *session)
295 {
296         connman_dbus_dict_append_basic(dict, "Bearer",
297                                         DBUS_TYPE_STRING, &session->bearer);
298
299         connman_dbus_dict_append_basic(dict, "Online",
300                                         DBUS_TYPE_BOOLEAN, &session->online);
301
302         connman_dbus_dict_append_basic(dict, "Name",
303                                         DBUS_TYPE_STRING, &session->name);
304
305         connman_dbus_dict_append_dict(dict, "IPv4",
306                                         append_ipconfig_ipv4, session->service);
307
308         connman_dbus_dict_append_dict(dict, "IPv6",
309                                         append_ipconfig_ipv6, session->service);
310
311         connman_dbus_dict_append_basic(dict, "Interface",
312                                         DBUS_TYPE_STRING, &session->ifname);
313
314 }
315
316 static void append_notify_all(DBusMessageIter *dict,
317                                         struct connman_session *session)
318 {
319         const char *policy;
320
321         append_service(dict, session);
322
323         connman_dbus_dict_append_basic(dict, "Priority",
324                                         DBUS_TYPE_BOOLEAN, &session->priority);
325
326         connman_dbus_dict_append_array(dict, "AllowedBearers",
327                                         DBUS_TYPE_STRING,
328                                         append_allowed_bearers,
329                                         session);
330
331         connman_dbus_dict_append_basic(dict, "AvoidHandover",
332                                         DBUS_TYPE_BOOLEAN,
333                                         &session->avoid_handover);
334
335         connman_dbus_dict_append_basic(dict, "StayConnected",
336                                         DBUS_TYPE_BOOLEAN,
337                                         &session->stay_connected);
338
339         connman_dbus_dict_append_basic(dict, "PeriodicConnect",
340                                         DBUS_TYPE_UINT32,
341                                         &session->periodic_connect);
342
343         connman_dbus_dict_append_basic(dict, "IdleTimeout",
344                                         DBUS_TYPE_UINT32,
345                                         &session->idle_timeout);
346
347         connman_dbus_dict_append_basic(dict, "EmergencyCall",
348                                         DBUS_TYPE_BOOLEAN, &session->ecall);
349
350         policy = roamingpolicy2string(session->roaming_policy);
351         connman_dbus_dict_append_basic(dict, "RoamingPolicy",
352                                         DBUS_TYPE_STRING,
353                                         &policy);
354
355         connman_dbus_dict_append_basic(dict, "SessionMarker",
356                                         DBUS_TYPE_UINT32, &session->marker);
357 }
358
359 static gboolean session_notify_all(gpointer user_data)
360 {
361         struct connman_session *session = user_data;
362         DBusMessage *msg;
363         DBusMessageIter array, dict;
364
365         DBG("session %p owner %s notify_path %s", session,
366                 session->owner, session->notify_path);
367
368         msg = dbus_message_new_method_call(session->owner, session->notify_path,
369                                                 CONNMAN_NOTIFICATION_INTERFACE,
370                                                 "Update");
371         if (msg == NULL) {
372                 connman_error("Could not create notification message");
373                 return FALSE;
374         }
375
376         dbus_message_iter_init_append(msg, &array);
377         connman_dbus_dict_open(&array, &dict);
378
379         append_notify_all(&dict, session);
380
381         connman_dbus_dict_close(&array, &dict);
382
383         g_dbus_send_message(connection, msg);
384
385         return FALSE;
386 }
387
388 static gboolean service_changed(gpointer user_data)
389 {
390         struct connman_session *session = user_data;
391
392
393         DBusMessage *msg;
394         DBusMessageIter array, dict;
395
396         DBG("session %p owner %s notify_path %s", session,
397                 session->owner, session->notify_path);
398
399         msg = dbus_message_new_method_call(session->owner, session->notify_path,
400                                                 CONNMAN_NOTIFICATION_INTERFACE,
401                                                 "Update");
402         if (msg == NULL) {
403                 connman_error("Could not create notification message");
404                 return FALSE;
405         }
406
407         dbus_message_iter_init_append(msg, &array);
408         connman_dbus_dict_open(&array, &dict);
409
410         append_service(&dict, session);
411
412         connman_dbus_dict_close(&array, &dict);
413
414         g_dbus_send_message(connection, msg);
415
416         return FALSE;
417 }
418
419 static void online_changed(struct connman_session *session)
420 {
421         connman_dbus_setting_changed_basic(session->owner, session->notify_path,
422                                                 "Online", DBUS_TYPE_BOOLEAN,
423                                                 &session->online);
424 }
425
426 static void ipconfig_ipv4_changed(struct connman_session *session)
427 {
428         connman_dbus_setting_changed_dict(session->owner, session->notify_path,
429                                         "IPv4", append_ipconfig_ipv4, session->service);
430 }
431
432 static void ipconfig_ipv6_changed(struct connman_session *session)
433 {
434         connman_dbus_setting_changed_dict(session->owner, session->notify_path,
435                                         "IPv6", append_ipconfig_ipv6, session->service);
436 }
437
438 static void update_service(struct connman_session *session)
439 {
440         int idx;
441
442         if (session->service != NULL) {
443                 session->bearer = session2bearer(session);
444                 session->online =
445                         __connman_service_is_connected(session->service);
446                 session->name = __connman_service_get_name(session->service);
447                 idx = __connman_service_get_index(session->service);
448                 session->ifname = connman_inet_ifname(idx);
449
450         } else {
451                 session->bearer = "";
452                 session->online = FALSE;
453                 session->name = "";
454                 session->ifname = "";
455         }
456 }
457
458 static connman_bool_t service_match(struct connman_session *session,
459                                         struct connman_service *service)
460 {
461         GSList *list;
462
463         DBG("session %p service %p", session, service);
464
465         for (list = session->allowed_bearers; list != NULL; list = list->next) {
466                 struct bearer_info *info = list->data;
467                 enum connman_service_type service_type;
468
469                 if (info->match_all == TRUE)
470                         return TRUE;
471
472                 service_type = connman_service_get_type(service);
473                 if (info->service_type == service_type)
474                         return TRUE;
475         }
476
477         return FALSE;
478 }
479
480 static connman_bool_t session_select_service(struct connman_session *session)
481 {
482         struct connman_service *service;
483         GSequenceIter *iter;
484
485         session->service_list =
486                 __connman_service_get_list(session, service_match);
487
488         if (session->service_list == NULL)
489                 return FALSE;
490
491         iter = g_sequence_get_begin_iter(session->service_list);
492
493         while (g_sequence_iter_is_end(iter) == FALSE) {
494                 service = g_sequence_get(iter);
495
496                 if (__connman_service_is_connected(service) == TRUE) {
497                         session->service = service;
498                         return TRUE;
499                 }
500                 iter = g_sequence_iter_next(iter);
501         }
502
503         return FALSE;
504 }
505
506 static void print_name(gpointer data, gpointer user_data)
507 {
508         struct connman_service *service = data;
509
510         DBG("service %p name %s", service,
511                 __connman_service_get_name(service));
512 }
513
514 static void cleanup_session(gpointer user_data)
515 {
516         struct connman_session *session = user_data;
517
518         DBG("remove %s", session->session_path);
519
520         g_sequence_free(session->service_list);
521
522         g_slist_foreach(session->allowed_bearers, cleanup_bearer_info, NULL);
523         g_slist_free(session->allowed_bearers);
524
525         g_free(session->owner);
526         g_free(session->session_path);
527         g_free(session->notify_path);
528
529         g_free(session);
530 }
531
532 static void release_session(gpointer key, gpointer value, gpointer user_data)
533 {
534         struct connman_session *session = value;
535         DBusMessage *message;
536
537         DBG("owner %s path %s", session->owner, session->notify_path);
538
539         if (session->notify_watch > 0)
540                 g_dbus_remove_watch(connection, session->notify_watch);
541
542         g_dbus_unregister_interface(connection, session->session_path,
543                                                 CONNMAN_SESSION_INTERFACE);
544
545         message = dbus_message_new_method_call(session->owner,
546                                                 session->notify_path,
547                                                 CONNMAN_NOTIFICATION_INTERFACE,
548                                                 "Release");
549         if (message == NULL)
550                 return;
551
552         dbus_message_set_no_reply(message, TRUE);
553
554         g_dbus_send_message(connection, message);
555 }
556
557 static int session_disconnect(struct connman_session *session)
558 {
559         DBG("session %p, %s", session, session->owner);
560
561         if (session->notify_watch > 0)
562                 g_dbus_remove_watch(connection, session->notify_watch);
563
564         g_dbus_unregister_interface(connection, session->session_path,
565                                                 CONNMAN_SESSION_INTERFACE);
566
567         g_hash_table_remove(session_hash, session->session_path);
568
569         return 0;
570 }
571
572 static void owner_disconnect(DBusConnection *conn, void *user_data)
573 {
574         struct connman_session *session = user_data;
575
576         DBG("session %p, %s died", session, session->owner);
577
578         session_disconnect(session);
579 }
580
581 static DBusMessage *destroy_session(DBusConnection *conn,
582                                         DBusMessage *msg, void *user_data)
583 {
584         struct connman_session *session = user_data;
585
586         DBG("session %p", session);
587
588         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
589 }
590
591 static DBusMessage *connect_session(DBusConnection *conn,
592                                         DBusMessage *msg, void *user_data)
593 {
594         struct connman_session *session = user_data;
595         int err;
596
597         DBG("session %p", session);
598
599         if (session->service_list != NULL)
600                 g_sequence_free(session->service_list);
601
602         session->service_list = __connman_service_get_list(session,
603                                                                 service_match);
604
605         g_sequence_foreach(session->service_list, print_name, NULL);
606
607         err = __connman_service_session_connect(session->service_list,
608                                                 &session->service);
609         if (err < 0)
610                 return __connman_error_failed(msg, -err);
611
612         update_service(session);
613         g_timeout_add_seconds(0, service_changed, session);
614
615         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
616 }
617
618 static DBusMessage *disconnect_session(DBusConnection *conn,
619                                         DBusMessage *msg, void *user_data)
620 {
621         struct connman_session *session = user_data;
622         int err;
623
624         DBG("session %p", session);
625
626         if (session->service == NULL)
627                 return __connman_error_already_disabled(msg);
628
629         err = __connman_service_disconnect(session->service);
630         if (err < 0)
631                 return __connman_error_failed(msg, -err);
632
633         session->service = NULL;
634         update_service(session);
635         g_timeout_add_seconds(0, service_changed, session);
636
637         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
638 }
639
640 static DBusMessage *change_session(DBusConnection *conn,
641                                         DBusMessage *msg, void *user_data)
642 {
643         struct connman_session *session = user_data;
644         DBusMessageIter iter, value;
645         DBusMessage *reply;
646         DBusMessageIter reply_array, reply_dict;
647         const char *name;
648         GSList *allowed_bearers;
649
650         DBG("session %p", session);
651         if (dbus_message_iter_init(msg, &iter) == FALSE)
652                 return __connman_error_invalid_arguments(msg);
653
654         reply = dbus_message_new_method_call(session->owner,
655                                                 session->notify_path,
656                                                 CONNMAN_NOTIFICATION_INTERFACE,
657                                                 "Update");
658         if (reply == NULL)
659                 return __connman_error_failed(msg, ENOMEM);
660
661         dbus_message_iter_init_append(reply, &reply_array);
662         connman_dbus_dict_open(&reply_array, &reply_dict);
663
664         dbus_message_iter_get_basic(&iter, &name);
665         dbus_message_iter_next(&iter);
666         dbus_message_iter_recurse(&iter, &value);
667
668         switch (dbus_message_iter_get_arg_type(&value)) {
669         case DBUS_TYPE_ARRAY:
670                 if (g_str_equal(name, "AllowedBearers") == TRUE) {
671                         allowed_bearers = session_parse_allowed_bearers(&value);
672
673                         g_slist_foreach(session->allowed_bearers,
674                                         cleanup_bearer_info, NULL);
675                         g_slist_free(session->allowed_bearers);
676
677                         if (allowed_bearers == NULL) {
678                                 allowed_bearers = session_allowed_bearers_any();
679
680                                 if (allowed_bearers == NULL) {
681                                         dbus_message_unref(reply);
682                                         return __connman_error_failed(msg, ENOMEM);
683                                 }
684                         }
685
686                         session->allowed_bearers = allowed_bearers;
687
688                         /* update_allowed_bearers(); */
689
690                         connman_dbus_dict_append_array(&reply_dict,
691                                                         "AllowedBearers",
692                                                         DBUS_TYPE_STRING,
693                                                         append_allowed_bearers,
694                                                         session);
695                 }
696                 break;
697         case DBUS_TYPE_BOOLEAN:
698                 if (g_str_equal(name, "Priority") == TRUE) {
699                         dbus_message_iter_get_basic(&value, &session->priority);
700
701                         /* update_priority(); */
702
703                         connman_dbus_dict_append_basic(&reply_dict, "Priority",
704                                                         DBUS_TYPE_BOOLEAN,
705                                                         &session->priority);
706
707                 } else if (g_str_equal(name, "AvoidHandover") == TRUE) {
708                         dbus_message_iter_get_basic(&value,
709                                                 &session->avoid_handover);
710
711                         /* update_avoid_handover(); */
712
713                         connman_dbus_dict_append_basic(&reply_dict,
714                                                 "AvoidHandover",
715                                                 DBUS_TYPE_BOOLEAN,
716                                                 &session->avoid_handover);
717
718                 } else if (g_str_equal(name, "StayConnected") == TRUE) {
719                         dbus_message_iter_get_basic(&value,
720                                                 &session->stay_connected);
721
722                         /* update_stay_connected(); */
723
724                         connman_dbus_dict_append_basic(&reply_dict,
725                                                 "StayConnected",
726                                                 DBUS_TYPE_BOOLEAN,
727                                                 &session->stay_connected);
728
729                 } else if (g_str_equal(name, "EmergencyCall") == TRUE) {
730                         dbus_message_iter_get_basic(&value, &session->ecall);
731
732                         /* update_ecall(); */
733
734                         connman_dbus_dict_append_basic(&reply_dict,
735                                                 "EmergencyCall",
736                                                 DBUS_TYPE_BOOLEAN,
737                                                 &session->ecall);
738
739                 }
740                 break;
741         case DBUS_TYPE_UINT32:
742                 if (g_str_equal(name, "PeriodicConnect") == TRUE) {
743                         dbus_message_iter_get_basic(&value,
744                                                 &session->periodic_connect);
745
746                         /* update_periodic_update(); */
747
748                         connman_dbus_dict_append_basic(&reply_dict,
749                                                 "PeriodicConnect",
750                                                 DBUS_TYPE_UINT32,
751                                                 &session->periodic_connect);
752                 } else if (g_str_equal(name, "IdleTimeout") == TRUE) {
753                         dbus_message_iter_get_basic(&value,
754                                                 &session->idle_timeout);
755
756                         /* update_idle_timeout(); */
757
758                         connman_dbus_dict_append_basic(&reply_dict,
759                                                 "IdleTimeout",
760                                                 DBUS_TYPE_UINT32,
761                                                 &session->idle_timeout);
762                 }
763                 break;
764         case DBUS_TYPE_STRING:
765                 if (g_str_equal(name, "RoamingPolicy") == TRUE) {
766                         const char *val;
767                         dbus_message_iter_get_basic(&value, &val);
768                         session->roaming_policy = string2roamingpolicy(val);
769
770                         /* update_roaming_allowed(); */
771
772                         val = roamingpolicy2string(session->roaming_policy);
773                         connman_dbus_dict_append_basic(&reply_dict,
774                                                 "RoamingPolicy",
775                                                 DBUS_TYPE_STRING,
776                                                 &val);
777                 }
778                 break;
779         }
780
781         connman_dbus_dict_close(&reply_array, &reply_dict);
782
783         g_dbus_send_message(connection, reply);
784
785         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
786 }
787
788 static GDBusMethodTable session_methods[] = {
789         { "Destroy",    "",   "", destroy_session    },
790         { "Connect",    "",   "", connect_session    },
791         { "Disconnect", "",   "", disconnect_session },
792         { "Change",     "sv", "", change_session     },
793         { },
794 };
795
796 int __connman_session_create(DBusMessage *msg)
797 {
798         const char *owner, *notify_path;
799         char *session_path;
800         DBusMessageIter iter, array;
801         struct connman_session *session;
802
803         connman_bool_t priority = FALSE, avoid_handover = FALSE;
804         connman_bool_t stay_connected = FALSE, ecall = FALSE;
805         enum connman_session_roaming_policy roaming_policy =
806                                 CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN;
807         GSList *allowed_bearers = NULL;
808         unsigned int periodic_connect = 0;
809         unsigned int idle_timeout = 0;
810
811         int err;
812
813         owner = dbus_message_get_sender(msg);
814
815         DBG("owner %s", owner);
816
817         dbus_message_iter_init(msg, &iter);
818         dbus_message_iter_recurse(&iter, &array);
819
820         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
821                 DBusMessageIter entry, value;
822                 const char *key, *val;
823
824                 dbus_message_iter_recurse(&array, &entry);
825                 dbus_message_iter_get_basic(&entry, &key);
826
827                 dbus_message_iter_next(&entry);
828                 dbus_message_iter_recurse(&entry, &value);
829
830                 switch (dbus_message_iter_get_arg_type(&value)) {
831                 case DBUS_TYPE_ARRAY:
832                         if (g_str_equal(key, "AllowedBearers") == TRUE) {
833                                 allowed_bearers =
834                                         session_parse_allowed_bearers(&value);
835                         }
836                         break;
837                 case DBUS_TYPE_BOOLEAN:
838                         if (g_str_equal(key, "Priority") == TRUE) {
839                                 dbus_message_iter_get_basic(&value,
840                                                         &priority);
841                         } else if (g_str_equal(key, "AvoidHandover") == TRUE) {
842                                 dbus_message_iter_get_basic(&value,
843                                                         &avoid_handover);
844                         } else if (g_str_equal(key, "StayConnected") == TRUE) {
845                                 dbus_message_iter_get_basic(&value,
846                                                         &stay_connected);
847                         } else if (g_str_equal(key, "EmergencyCall") == TRUE) {
848                                 dbus_message_iter_get_basic(&value,
849                                                         &ecall);
850                         }
851                         break;
852                 case DBUS_TYPE_UINT32:
853                         if (g_str_equal(key, "PeriodicConnect") == TRUE) {
854                                 dbus_message_iter_get_basic(&value,
855                                                         &periodic_connect);
856                         } else if (g_str_equal(key, "IdleTimeout") == TRUE) {
857                                 dbus_message_iter_get_basic(&value,
858                                                         &idle_timeout);
859                         }
860                         break;
861                 case DBUS_TYPE_STRING:
862
863                         if (g_str_equal(key, "RoamingPolicy") == TRUE) {
864                                 dbus_message_iter_get_basic(&value, &val);
865                                 roaming_policy = string2roamingpolicy(val);
866                         }
867                 }
868                 dbus_message_iter_next(&array);
869         }
870
871         dbus_message_iter_next(&iter);
872         dbus_message_iter_get_basic(&iter, &notify_path);
873
874         if (notify_path == NULL) {
875                 session_path = NULL;
876                 err = -EINVAL;
877                 goto err;
878         }
879
880         session_path = g_strdup_printf("/sessions%s", notify_path);
881         if (session_path == NULL) {
882                 err = -ENOMEM;
883                 goto err;
884         }
885
886         session = g_hash_table_lookup(session_hash, session_path);
887         if (session != NULL) {
888                 err = -EEXIST;
889                 goto err;
890         }
891
892         session = g_try_new0(struct connman_session, 1);
893         if (session == NULL) {
894                 err = -ENOMEM;
895                 goto err;
896         }
897
898         session->owner = g_strdup(owner);
899         session->session_path = session_path;
900         session->notify_path = g_strdup(notify_path);
901         session->notify_watch =
902                 g_dbus_add_disconnect_watch(connection, session->owner,
903                                         owner_disconnect, session, NULL);
904
905         session->bearer = "";
906         session->online = FALSE;
907         session->priority = priority;
908         session->avoid_handover = avoid_handover;
909         session->stay_connected = stay_connected;
910         session->periodic_connect = periodic_connect;
911         session->idle_timeout = idle_timeout;
912         session->ecall = ecall;
913         session->roaming_policy = roaming_policy;
914
915         if (session->allowed_bearers == NULL) {
916                 session->allowed_bearers = session_allowed_bearers_any();
917
918                 if (session->allowed_bearers == NULL) {
919                         err = -ENOMEM;
920                         goto err;
921                 }
922         }
923
924         session->service_list = NULL;
925
926         update_service(session);
927
928         g_hash_table_replace(session_hash, session->session_path, session);
929
930         DBG("add %s", session->session_path);
931
932         if (g_dbus_register_interface(connection, session->session_path,
933                                         CONNMAN_SESSION_INTERFACE,
934                                         session_methods, NULL,
935                                         NULL, session, NULL) == FALSE) {
936                 connman_error("Failed to register %s", session->session_path);
937                 g_hash_table_remove(session_hash, session->session_path);
938                 session = NULL;
939
940                 err = -EINVAL;
941                 goto err;
942         }
943
944         g_dbus_send_reply(connection, msg,
945                                 DBUS_TYPE_OBJECT_PATH, &session->session_path,
946                                 DBUS_TYPE_INVALID);
947
948
949         /*
950          * Check if the session settings matches to a service which is
951          * a already connected
952          */
953         if (session_select_service(session) == TRUE)
954                 update_service(session);
955
956         g_timeout_add_seconds(0, session_notify_all, session);
957
958         return 0;
959
960 err:
961         connman_error("Failed to create session");
962         g_free(session_path);
963
964         g_slist_foreach(allowed_bearers, cleanup_bearer_info, NULL);
965         g_slist_free(allowed_bearers);
966
967         return err;
968 }
969
970 int __connman_session_destroy(DBusMessage *msg)
971 {
972         const char *owner, *session_path;
973         struct connman_session *session;
974
975         owner = dbus_message_get_sender(msg);
976
977         DBG("owner %s", owner);
978
979         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &session_path,
980                                                         DBUS_TYPE_INVALID);
981         if (session_path == NULL)
982                 return -EINVAL;
983
984         session = g_hash_table_lookup(session_hash, session_path);
985         if (session == NULL)
986                 return -EINVAL;
987
988         if (g_strcmp0(owner, session->owner) != 0)
989                 return -EACCES;
990
991         session_disconnect(session);
992
993         return 0;
994 }
995
996 connman_bool_t __connman_session_mode()
997 {
998         return sessionmode;
999 }
1000
1001 void __connman_session_set_mode(connman_bool_t enable)
1002 {
1003         DBG("enable %d", enable);
1004
1005         if (sessionmode == enable)
1006                 return;
1007
1008         sessionmode = enable;
1009
1010         if (sessionmode == TRUE)
1011                 __connman_service_disconnect_all();
1012 }
1013
1014 static void service_state_changed(struct connman_service *service,
1015                                         enum connman_service_state state)
1016 {
1017         GHashTableIter iter;
1018         gpointer key, value;
1019         struct connman_session *session;
1020         connman_bool_t online;
1021
1022         DBG("service %p state %d", service, state);
1023
1024         g_hash_table_iter_init(&iter, session_hash);
1025
1026         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1027                 session = value;
1028
1029                 if (session->service == service) {
1030                         online = __connman_service_is_connected(service);
1031                         if (session->online != online)
1032                                 continue;
1033
1034                         session->online = online;
1035                         online_changed(session);
1036                 }
1037         }
1038 }
1039
1040 static void ipconfig_changed(struct connman_service *service,
1041                                 struct connman_ipconfig *ipconfig)
1042 {
1043         GHashTableIter iter;
1044         gpointer key, value;
1045         struct connman_session *session;
1046         enum connman_ipconfig_type type;
1047
1048         DBG("service %p ipconfig %p", service, ipconfig);
1049
1050         type = __connman_ipconfig_get_config_type(ipconfig);
1051
1052         g_hash_table_iter_init(&iter, session_hash);
1053
1054         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1055                 session = value;
1056
1057                 if (session->service == service) {
1058                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1059                                 ipconfig_ipv4_changed(session);
1060                         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1061                                 ipconfig_ipv6_changed(session);
1062                 }
1063         }
1064 }
1065
1066 static struct connman_notifier session_notifier = {
1067         .name                   = "session",
1068         .service_state_changed  = service_state_changed,
1069         .ipconfig_changed       = ipconfig_changed,
1070 };
1071
1072 int __connman_session_init(void)
1073 {
1074         int err;
1075
1076         DBG("");
1077
1078         connection = connman_dbus_get_connection();
1079         if (connection == NULL)
1080                 return -1;
1081
1082         err = connman_notifier_register(&session_notifier);
1083         if (err < 0) {
1084                 dbus_connection_unref(connection);
1085                 return err;
1086         }
1087
1088         session_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1089                                                 NULL, cleanup_session);
1090
1091         sessionmode = FALSE;
1092         return 0;
1093 }
1094
1095 void __connman_session_cleanup(void)
1096 {
1097         DBG("");
1098
1099         if (connection == NULL)
1100                 return;
1101
1102         connman_notifier_unregister(&session_notifier);
1103
1104         g_hash_table_foreach(session_hash, release_session, NULL);
1105         g_hash_table_destroy(session_hash);
1106
1107         dbus_connection_unref(connection);
1108 }