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