session: Do not access stale entry pointers
[platform/upstream/connman.git] / src / session.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  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 <errno.h>
28
29 #include <gdbus.h>
30
31 #include <connman/session.h>
32
33 #include "connman.h"
34
35 static DBusConnection *connection;
36 static GHashTable *session_hash;
37 static connman_bool_t sessionmode;
38 static struct connman_session *ecall_session;
39 static GSList *policy_list;
40
41 enum connman_session_trigger {
42         CONNMAN_SESSION_TRIGGER_UNKNOWN         = 0,
43         CONNMAN_SESSION_TRIGGER_SETTING         = 1,
44         CONNMAN_SESSION_TRIGGER_CONNECT         = 2,
45         CONNMAN_SESSION_TRIGGER_DISCONNECT      = 3,
46         CONNMAN_SESSION_TRIGGER_SERVICE         = 4,
47         CONNMAN_SESSION_TRIGGER_ECALL           = 5,
48 };
49
50 enum connman_session_reason {
51         CONNMAN_SESSION_REASON_UNKNOWN          = 0,
52         CONNMAN_SESSION_REASON_CONNECT          = 1,
53         CONNMAN_SESSION_REASON_FREE_RIDE        = 2,
54 };
55
56 enum connman_session_state {
57         CONNMAN_SESSION_STATE_DISCONNECTED   = 0,
58         CONNMAN_SESSION_STATE_CONNECTED      = 1,
59         CONNMAN_SESSION_STATE_ONLINE         = 2,
60 };
61
62 struct service_entry {
63         struct connman_session *session;
64         /* track why this service was selected */
65         enum connman_session_reason reason;
66         enum connman_service_state state;
67         const char *name;
68         struct connman_service *service;
69         char *ifname;
70         const char *bearer;
71         GSList *pending_timeouts;
72 };
73
74 struct session_info {
75         struct connman_session_config config;
76         enum connman_session_state state;
77         struct service_entry *entry;
78         enum connman_session_reason reason;
79 };
80
81 struct connman_session {
82         char *owner;
83         char *session_path;
84         char *notify_path;
85         guint notify_watch;
86
87         struct connman_session_policy *policy;
88
89         connman_bool_t append_all;
90         struct session_info *info;
91         struct session_info *info_last;
92         struct connman_session_config *policy_config;
93         GSList *user_allowed_bearers;
94
95         connman_bool_t ecall;
96
97         GSequence *service_list;
98         GHashTable *service_hash;
99 };
100
101 static const char *trigger2string(enum connman_session_trigger trigger)
102 {
103         switch (trigger) {
104         case CONNMAN_SESSION_TRIGGER_UNKNOWN:
105                 break;
106         case CONNMAN_SESSION_TRIGGER_SETTING:
107                 return "setting";
108         case CONNMAN_SESSION_TRIGGER_CONNECT:
109                 return "connect";
110         case CONNMAN_SESSION_TRIGGER_DISCONNECT:
111                 return "disconnect";
112         case CONNMAN_SESSION_TRIGGER_SERVICE:
113                 return "service";
114         case CONNMAN_SESSION_TRIGGER_ECALL:
115                 return "ecall";
116         }
117
118         return NULL;
119 }
120
121 static const char *reason2string(enum connman_session_reason reason)
122 {
123         switch (reason) {
124         case CONNMAN_SESSION_REASON_UNKNOWN:
125                 return "unknown";
126         case CONNMAN_SESSION_REASON_CONNECT:
127                 return "connect";
128         case CONNMAN_SESSION_REASON_FREE_RIDE:
129                 return "free-ride";
130         }
131
132         return NULL;
133 }
134
135 static const char *state2string(enum connman_session_state state)
136 {
137         switch (state) {
138         case CONNMAN_SESSION_STATE_DISCONNECTED:
139                 return "disconnected";
140         case CONNMAN_SESSION_STATE_CONNECTED:
141                 return "connected";
142         case CONNMAN_SESSION_STATE_ONLINE:
143                 return "online";
144         }
145
146         return NULL;
147 }
148
149 static const char *type2string(enum connman_session_type type)
150 {
151         switch (type) {
152         case CONNMAN_SESSION_TYPE_UNKNOWN:
153                 return "";
154         case CONNMAN_SESSION_TYPE_ANY:
155                 return "any";
156         case CONNMAN_SESSION_TYPE_LOCAL:
157                 return "local";
158         case CONNMAN_SESSION_TYPE_INTERNET:
159                 return "internet";
160         }
161
162         return NULL;
163 }
164
165 enum connman_session_roaming_policy connman_session_parse_roaming_policy(const char *policy)
166 {
167         if (g_strcmp0(policy, "default") == 0)
168                 return CONNMAN_SESSION_ROAMING_POLICY_DEFAULT;
169         else if (g_strcmp0(policy, "always") == 0)
170                 return CONNMAN_SESSION_ROAMING_POLICY_ALWAYS;
171         else if (g_strcmp0(policy, "forbidden") == 0)
172                 return CONNMAN_SESSION_ROAMING_POLICY_FORBIDDEN;
173         else if (g_strcmp0(policy, "national") == 0)
174                 return CONNMAN_SESSION_ROAMING_POLICY_NATIONAL;
175         else if (g_strcmp0(policy, "international") == 0)
176                 return CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL;
177         else
178                 return CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN;
179 }
180
181 enum connman_session_type connman_session_parse_connection_type(const char *type)
182 {
183         if (g_strcmp0(type, "any") == 0)
184                 return CONNMAN_SESSION_TYPE_ANY;
185         if (g_strcmp0(type, "local") == 0)
186                 return CONNMAN_SESSION_TYPE_LOCAL;
187         else if (g_strcmp0(type, "internet") == 0)
188                 return CONNMAN_SESSION_TYPE_INTERNET;
189
190         return CONNMAN_SESSION_TYPE_UNKNOWN;
191 }
192
193 static int bearer2service(const char *bearer, enum connman_service_type *type)
194 {
195         if (g_strcmp0(bearer, "ethernet") == 0)
196                 *type = CONNMAN_SERVICE_TYPE_ETHERNET;
197         else if (g_strcmp0(bearer, "wifi") == 0)
198                 *type = CONNMAN_SERVICE_TYPE_WIFI;
199         else if (g_strcmp0(bearer, "bluetooth") == 0)
200                 *type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
201         else if (g_strcmp0(bearer, "cellular") == 0)
202                 *type = CONNMAN_SERVICE_TYPE_CELLULAR;
203         else if (g_strcmp0(bearer, "vpn") == 0)
204                 *type = CONNMAN_SERVICE_TYPE_VPN;
205         else if (g_strcmp0(bearer, "*") == 0)
206                 *type = CONNMAN_SERVICE_TYPE_UNKNOWN;
207         else
208                 return -EINVAL;
209
210         return 0;
211 }
212
213 static char *service2bearer(enum connman_service_type type)
214 {
215         switch (type) {
216         case CONNMAN_SERVICE_TYPE_ETHERNET:
217                 return "ethernet";
218         case CONNMAN_SERVICE_TYPE_WIFI:
219                 return "wifi";
220         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
221                 return "bluetooth";
222         case CONNMAN_SERVICE_TYPE_CELLULAR:
223                 return "cellular";
224         case CONNMAN_SERVICE_TYPE_VPN:
225                 return "vpn";
226         case CONNMAN_SERVICE_TYPE_UNKNOWN:
227                 return "*";
228         case CONNMAN_SERVICE_TYPE_SYSTEM:
229         case CONNMAN_SERVICE_TYPE_GPS:
230         case CONNMAN_SERVICE_TYPE_GADGET:
231                 return "";
232         }
233
234         return "";
235 }
236
237 static void destroy_policy_config(struct connman_session *session)
238 {
239         if (session->policy == NULL) {
240                 g_free(session->policy_config);
241                 return;
242         }
243
244         (*session->policy->destroy)(session);
245 }
246
247 static void free_session(struct connman_session *session)
248 {
249         if (session == NULL)
250                 return;
251
252         if (session->notify_watch > 0)
253                 g_dbus_remove_watch(connection, session->notify_watch);
254
255         destroy_policy_config(session);
256         g_slist_free(session->info->config.allowed_bearers);
257         g_free(session->owner);
258         g_free(session->session_path);
259         g_free(session->notify_path);
260         g_free(session->info);
261         g_free(session->info_last);
262
263         g_free(session);
264 }
265
266 static void cleanup_session(gpointer user_data)
267 {
268         struct connman_session *session = user_data;
269         struct session_info *info = session->info;
270
271         DBG("remove %s", session->session_path);
272
273         g_slist_free(session->user_allowed_bearers);
274         g_hash_table_destroy(session->service_hash);
275         g_sequence_free(session->service_list);
276
277         if (info->entry != NULL &&
278                         info->entry->reason == CONNMAN_SESSION_REASON_CONNECT) {
279                 __connman_service_disconnect(info->entry->service);
280         }
281
282         free_session(session);
283 }
284
285 static int assign_policy_plugin(struct connman_session *session)
286 {
287         if (session->policy != NULL)
288                 return -EALREADY;
289
290         if (policy_list == NULL)
291                 return 0;
292
293         session->policy = policy_list->data;
294
295         return 0;
296 }
297
298 struct user_config {
299         DBusMessage *pending;
300
301         enum connman_session_type type;
302         GSList *allowed_bearers;
303 };
304
305 static void cleanup_user_config(struct user_config *user_config)
306 {
307         if (user_config == NULL)
308                 return;
309
310         if (user_config->pending != NULL)
311                 dbus_message_unref(user_config->pending);
312
313         g_slist_free(user_config->allowed_bearers);
314         g_free(user_config);
315 }
316
317 static int create_policy_config(struct connman_session *session,
318                                 connman_session_config_func_t cb,
319                                 struct user_config *user_config)
320 {
321         struct connman_session_config *config;
322
323         if (session->policy == NULL) {
324                 config = connman_session_create_default_config();
325                 if (config == NULL) {
326                         free_session(session);
327                         cleanup_user_config(user_config);
328                         return -ENOMEM;
329                 }
330
331                 return cb(session, config, user_config, 0);
332         }
333
334         return (*session->policy->create)(session, cb, user_config);
335 }
336
337 static void probe_policy(struct connman_session_policy *policy)
338 {
339
340         GHashTableIter iter;
341         gpointer key, value;
342         struct connman_session *session;
343
344         DBG("policy %p name %s", policy, policy->name);
345
346         g_hash_table_iter_init(&iter, session_hash);
347
348         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
349                 session = value;
350
351                 if (session->policy != NULL)
352                         continue;
353
354                 assign_policy_plugin(session);
355         }
356 }
357
358 static void remove_policy(struct connman_session_policy *policy)
359 {
360         GHashTableIter iter;
361         gpointer key, value;
362         struct connman_session *session;
363
364         if (session_hash == NULL)
365                 return;
366
367         DBG("policy %p name %s", policy, policy->name);
368
369         g_hash_table_iter_init(&iter, session_hash);
370
371         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
372                 session = value;
373
374                 if (session->policy != policy)
375                         continue;
376
377                 session->policy = NULL;
378                 assign_policy_plugin(session);
379         }
380 }
381
382 static gint compare_priority(gconstpointer a, gconstpointer b)
383 {
384         const struct connman_session_policy *policy1 = a;
385         const struct connman_session_policy *policy2 = b;
386
387         return policy2->priority - policy1->priority;
388 }
389
390
391 int connman_session_policy_register(struct connman_session_policy *policy)
392 {
393         DBG("name %s", policy->name);
394
395         if (policy->create == NULL || policy->destroy == NULL)
396                 return -EINVAL;
397
398         policy_list = g_slist_insert_sorted(policy_list, policy,
399                                                 compare_priority);
400
401         probe_policy(policy);
402
403         return 0;
404 }
405
406 void connman_session_policy_unregister(struct connman_session_policy *policy)
407 {
408         DBG("name %s", policy->name);
409
410         policy_list = g_slist_remove(policy_list, policy);
411
412         remove_policy(policy);
413 }
414
415 void connman_session_set_default_config(struct connman_session_config *config)
416 {
417         config->priority = FALSE;
418         config->roaming_policy = CONNMAN_SESSION_ROAMING_POLICY_DEFAULT;
419         config->type = CONNMAN_SESSION_TYPE_ANY;
420         config->ecall = FALSE;
421
422         g_slist_free(config->allowed_bearers);
423         config->allowed_bearers = g_slist_prepend(NULL,
424                                 GINT_TO_POINTER(CONNMAN_SERVICE_TYPE_UNKNOWN));
425 }
426
427 struct connman_session_config *connman_session_create_default_config(void)
428 {
429         struct connman_session_config *config;
430
431         config = g_new0(struct connman_session_config, 1);
432         connman_session_set_default_config(config);
433
434         return config;
435 }
436
437 static enum connman_session_type apply_policy_on_type(
438                         enum connman_session_type policy,
439                         enum connman_session_type type)
440 {
441         if (type == CONNMAN_SESSION_TYPE_UNKNOWN)
442                 return CONNMAN_SESSION_TYPE_UNKNOWN;
443
444         if (policy == CONNMAN_SESSION_TYPE_ANY)
445                 return type;
446
447         if (policy == CONNMAN_SESSION_TYPE_LOCAL)
448                 return CONNMAN_SESSION_TYPE_LOCAL;
449
450         return CONNMAN_SESSION_TYPE_INTERNET;
451 }
452
453 int connman_session_parse_bearers(const char *token, GSList **list)
454 {
455         enum connman_service_type bearer;
456         int err;
457
458         if (g_strcmp0(token, "") == 0)
459                 return 0;
460
461         err = bearer2service(token, &bearer);
462         if (err < 0)
463                 return err;
464
465         *list = g_slist_append(*list, GINT_TO_POINTER(bearer));
466
467         return 0;
468 }
469
470 static int parse_bearers(DBusMessageIter *iter, GSList **list)
471 {
472         DBusMessageIter array;
473         int type, err;
474
475         dbus_message_iter_recurse(iter, &array);
476
477         *list = NULL;
478
479         while ((type = dbus_message_iter_get_arg_type(&array)) !=
480                         DBUS_TYPE_INVALID) {
481                 char *bearer_name = NULL;
482
483                 if (type != DBUS_TYPE_STRING) {
484                         g_slist_free(*list);
485                         *list = NULL;
486                         return -EINVAL;
487                 }
488
489                 dbus_message_iter_get_basic(&array, &bearer_name);
490
491                 err = connman_session_parse_bearers(bearer_name, list);
492                 if (err < 0) {
493                         g_slist_free(*list);
494                         *list = NULL;
495                         return err;
496                 }
497
498                 dbus_message_iter_next(&array);
499         }
500
501         return 0;
502 }
503
504 static int filter_bearer(GSList *policy_bearers,
505                                 enum connman_service_type bearer,
506                                 GSList **list)
507 {
508         enum connman_service_type policy;
509         GSList *it;
510
511         if (policy_bearers == NULL)
512                 return 0;
513
514         for (it = policy_bearers; it != NULL; it = it->next) {
515                 policy = GPOINTER_TO_INT(it->data);
516
517                 if (bearer == CONNMAN_SERVICE_TYPE_UNKNOWN) {
518                         bearer = policy;
519                         goto clone;
520                 }
521
522                 if (policy != CONNMAN_SERVICE_TYPE_UNKNOWN && policy != bearer)
523                         continue;
524
525                 goto clone;
526         }
527
528         *list = NULL;
529
530         return 0;
531
532 clone:
533         *list = g_slist_append(*list, GINT_TO_POINTER(bearer));
534
535         return 0;
536 }
537
538 static int apply_policy_on_bearers(GSList *policy_bearers, GSList *bearers,
539                                 GSList **list)
540 {
541         enum connman_service_type bearer;
542         GSList *it;
543         int err;
544
545         *list = NULL;
546
547         for (it = bearers; it != NULL; it = it->next) {
548                 bearer = GPOINTER_TO_INT(it->data);
549
550                 err = filter_bearer(policy_bearers, bearer, list);
551                 if (err < 0)
552                         return err;
553         }
554
555         return 0;
556 }
557
558 const char *connman_session_get_owner(struct connman_session *session)
559 {
560         return session->owner;
561 }
562
563 static void append_allowed_bearers(DBusMessageIter *iter, void *user_data)
564 {
565         struct session_info *info = user_data;
566         GSList *list;
567
568         for (list = info->config.allowed_bearers;
569                         list != NULL; list = list->next) {
570                 enum connman_service_type bearer = GPOINTER_TO_INT(list->data);
571                 const char *name = __connman_service_type2string(bearer);
572
573                 if (name == NULL)
574                         name = "*";
575
576                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
577                                                 &name);
578         }
579 }
580
581 static void append_ipconfig_ipv4(DBusMessageIter *iter, void *user_data)
582 {
583         struct connman_service *service = user_data;
584         struct connman_ipconfig *ipconfig_ipv4;
585
586         if (service == NULL)
587                 return;
588
589         if (__connman_service_is_connected_state(service,
590                                 CONNMAN_IPCONFIG_TYPE_IPV4) == FALSE) {
591                 return;
592         }
593
594         ipconfig_ipv4 = __connman_service_get_ip4config(service);
595         if (ipconfig_ipv4 == NULL)
596                 return;
597
598         __connman_ipconfig_append_ipv4(ipconfig_ipv4, iter);
599 }
600
601 static void append_ipconfig_ipv6(DBusMessageIter *iter, void *user_data)
602 {
603         struct connman_service *service = user_data;
604         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
605
606         if (service == NULL)
607                 return;
608
609         if (__connman_service_is_connected_state(service,
610                                 CONNMAN_IPCONFIG_TYPE_IPV6) == FALSE) {
611                 return;
612         }
613
614         ipconfig_ipv4 = __connman_service_get_ip4config(service);
615         ipconfig_ipv6 = __connman_service_get_ip6config(service);
616         if (ipconfig_ipv6 == NULL)
617                 return;
618
619         __connman_ipconfig_append_ipv6(ipconfig_ipv6, iter, ipconfig_ipv4);
620 }
621
622 static void append_notify(DBusMessageIter *dict,
623                                         struct connman_session *session)
624 {
625         struct session_info *info = session->info;
626         struct session_info *info_last = session->info_last;
627         struct connman_service *service;
628         const char *name, *ifname, *bearer;
629
630         if (session->append_all == TRUE ||
631                         info->state != info_last->state) {
632                 const char *state = state2string(info->state);
633
634                 connman_dbus_dict_append_basic(dict, "State",
635                                                 DBUS_TYPE_STRING,
636                                                 &state);
637                 info_last->state = info->state;
638         }
639
640         if (session->append_all == TRUE ||
641                         info->entry != info_last->entry) {
642                 if (info->entry == NULL) {
643                         name = "";
644                         ifname = "";
645                         service = NULL;
646                         bearer = "";
647                 } else {
648                         name = info->entry->name;
649                         ifname = info->entry->ifname;
650                         service = info->entry->service;
651                         bearer = info->entry->bearer;
652                 }
653
654                 connman_dbus_dict_append_basic(dict, "Name",
655                                                 DBUS_TYPE_STRING,
656                                                 &name);
657
658                 connman_dbus_dict_append_dict(dict, "IPv4",
659                                                 append_ipconfig_ipv4,
660                                                 service);
661
662                 connman_dbus_dict_append_dict(dict, "IPv6",
663                                                 append_ipconfig_ipv6,
664                                                 service);
665
666                 connman_dbus_dict_append_basic(dict, "Interface",
667                                                 DBUS_TYPE_STRING,
668                                                 &ifname);
669
670                 connman_dbus_dict_append_basic(dict, "Bearer",
671                                                 DBUS_TYPE_STRING,
672                                                 &bearer);
673
674                 info_last->entry = info->entry;
675         }
676
677         if (session->append_all == TRUE ||
678                         info->config.type != info_last->config.type) {
679                 const char *type = type2string(info->config.type);
680
681                 connman_dbus_dict_append_basic(dict, "ConnectionType",
682                                                 DBUS_TYPE_STRING,
683                                                 &type);
684                 info_last->config.type = info->config.type;
685         }
686
687         if (session->append_all == TRUE ||
688                         info->config.allowed_bearers != info_last->config.allowed_bearers) {
689                 connman_dbus_dict_append_array(dict, "AllowedBearers",
690                                                 DBUS_TYPE_STRING,
691                                                 append_allowed_bearers,
692                                                 info);
693                 info_last->config.allowed_bearers = info->config.allowed_bearers;
694         }
695
696         session->append_all = FALSE;
697 }
698
699 static connman_bool_t is_type_matching_state(enum connman_session_state *state,
700                                                 enum connman_session_type type)
701 {
702         switch (type) {
703         case CONNMAN_SESSION_TYPE_UNKNOWN:
704                 return FALSE;
705         case CONNMAN_SESSION_TYPE_ANY:
706                 return TRUE;
707         case CONNMAN_SESSION_TYPE_LOCAL:
708                 if (*state >= CONNMAN_SESSION_STATE_CONNECTED) {
709                         *state = CONNMAN_SESSION_STATE_CONNECTED;
710                         return TRUE;
711                 }
712
713                 break;
714         case CONNMAN_SESSION_TYPE_INTERNET:
715                 if (*state == CONNMAN_SESSION_STATE_ONLINE)
716                         return TRUE;
717                 break;
718         }
719
720         return FALSE;
721 }
722
723 static connman_bool_t compute_notifiable_changes(struct connman_session *session)
724 {
725         struct session_info *info_last = session->info_last;
726         struct session_info *info = session->info;
727
728         if (session->append_all == TRUE)
729                 return TRUE;
730
731         if (info->state != info_last->state)
732                 return TRUE;
733
734         if (info->entry != info_last->entry &&
735                         info->state >= CONNMAN_SESSION_STATE_CONNECTED)
736                 return TRUE;
737
738         if (info->config.allowed_bearers != info_last->config.allowed_bearers ||
739                         info->config.type != info_last->config.type)
740                 return TRUE;
741
742         return FALSE;
743 }
744
745 static gboolean session_notify(gpointer user_data)
746 {
747         struct connman_session *session = user_data;
748         DBusMessage *msg;
749         DBusMessageIter array, dict;
750
751         if (compute_notifiable_changes(session) == FALSE)
752                 return FALSE;
753
754         DBG("session %p owner %s notify_path %s", session,
755                 session->owner, session->notify_path);
756
757         msg = dbus_message_new_method_call(session->owner, session->notify_path,
758                                                 CONNMAN_NOTIFICATION_INTERFACE,
759                                                 "Update");
760         if (msg == NULL)
761                 return FALSE;
762
763         dbus_message_iter_init_append(msg, &array);
764         connman_dbus_dict_open(&array, &dict);
765
766         append_notify(&dict, session);
767
768         connman_dbus_dict_close(&array, &dict);
769
770         g_dbus_send_message(connection, msg);
771
772         return FALSE;
773 }
774
775 static void ipconfig_ipv4_changed(struct connman_session *session)
776 {
777         struct session_info *info = session->info;
778
779         connman_dbus_setting_changed_dict(session->owner, session->notify_path,
780                                                 "IPv4", append_ipconfig_ipv4,
781                                                 info->entry->service);
782 }
783
784 static void ipconfig_ipv6_changed(struct connman_session *session)
785 {
786         struct session_info *info = session->info;
787
788         connman_dbus_setting_changed_dict(session->owner, session->notify_path,
789                                                 "IPv6", append_ipconfig_ipv6,
790                                                 info->entry->service);
791 }
792
793 static connman_bool_t service_type_match(struct connman_session *session,
794                                         struct connman_service *service)
795 {
796         struct session_info *info = session->info;
797         GSList *list;
798
799         for (list = info->config.allowed_bearers;
800                         list != NULL; list = list->next) {
801                 enum connman_service_type bearer = GPOINTER_TO_INT(list->data);
802                 enum connman_service_type service_type;
803
804                 if (bearer == CONNMAN_SERVICE_TYPE_UNKNOWN)
805                         return TRUE;
806
807                 service_type = connman_service_get_type(service);
808                 if (bearer == service_type)
809                         return TRUE;
810         }
811
812         return FALSE;
813 }
814
815 static connman_bool_t service_match(struct connman_session *session,
816                                         struct connman_service *service)
817 {
818         if (service_type_match(session, service) == FALSE)
819                 return FALSE;
820
821         return TRUE;
822 }
823
824 static int service_type_weight(enum connman_service_type type)
825 {
826         /*
827          * The session doesn't care which service
828          * to use. Nevertheless we have to sort them
829          * according their type. The ordering is
830          *
831          * 1. Ethernet
832          * 2. Bluetooth
833          * 3. WiFi
834          * 4. Cellular
835          */
836
837         switch (type) {
838         case CONNMAN_SERVICE_TYPE_ETHERNET:
839                 return 4;
840         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
841                 return 3;
842         case CONNMAN_SERVICE_TYPE_WIFI:
843                 return 2;
844         case CONNMAN_SERVICE_TYPE_CELLULAR:
845                 return 1;
846         case CONNMAN_SERVICE_TYPE_UNKNOWN:
847         case CONNMAN_SERVICE_TYPE_SYSTEM:
848         case CONNMAN_SERVICE_TYPE_GPS:
849         case CONNMAN_SERVICE_TYPE_VPN:
850         case CONNMAN_SERVICE_TYPE_GADGET:
851                 break;
852         }
853
854         return 0;
855 }
856
857 static gint sort_allowed_bearers(struct connman_service *service_a,
858                                         struct connman_service *service_b,
859                                         struct connman_session *session)
860 {
861         struct session_info *info = session->info;
862         GSList *list;
863         enum connman_service_type type_a, type_b;
864         int weight_a, weight_b;
865
866         type_a = connman_service_get_type(service_a);
867         type_b = connman_service_get_type(service_b);
868
869         for (list = info->config.allowed_bearers;
870                         list != NULL; list = list->next) {
871                 enum connman_service_type bearer = GPOINTER_TO_INT(list->data);
872
873                 if (bearer == CONNMAN_SERVICE_TYPE_UNKNOWN) {
874                         if (type_a != type_b) {
875                                 weight_a = service_type_weight(type_a);
876                                 weight_b = service_type_weight(type_b);
877
878                                 if (weight_a > weight_b)
879                                         return -1;
880
881                                 if (weight_a < weight_b)
882                                         return 1;
883
884                                 return 0;
885                         }
886                 }
887
888                 if (type_a == bearer && type_b == bearer)
889                         return 0;
890
891                 if (type_a == bearer && type_b != bearer)
892                         return -1;
893
894                 if (type_a != bearer && type_b == bearer)
895                         return 1;
896         }
897
898         return 0;
899 }
900
901 static gint sort_services(gconstpointer a, gconstpointer b, gpointer user_data)
902 {
903         struct service_entry *entry_a = (void *)a;
904         struct service_entry *entry_b = (void *)b;
905         struct connman_session *session = user_data;
906
907         return sort_allowed_bearers(entry_a->service, entry_b->service,
908                                 session);
909 }
910
911 static enum connman_session_state service_to_session_state(enum connman_service_state state)
912 {
913         switch (state) {
914         case CONNMAN_SERVICE_STATE_UNKNOWN:
915         case CONNMAN_SERVICE_STATE_IDLE:
916         case CONNMAN_SERVICE_STATE_ASSOCIATION:
917         case CONNMAN_SERVICE_STATE_CONFIGURATION:
918         case CONNMAN_SERVICE_STATE_DISCONNECT:
919         case CONNMAN_SERVICE_STATE_FAILURE:
920                 break;
921         case CONNMAN_SERVICE_STATE_READY:
922                 return CONNMAN_SESSION_STATE_CONNECTED;
923         case CONNMAN_SERVICE_STATE_ONLINE:
924                 return CONNMAN_SESSION_STATE_ONLINE;
925         }
926
927         return CONNMAN_SESSION_STATE_DISCONNECTED;
928 }
929
930 static connman_bool_t is_connected(enum connman_service_state state)
931 {
932         switch (state) {
933         case CONNMAN_SERVICE_STATE_UNKNOWN:
934         case CONNMAN_SERVICE_STATE_IDLE:
935         case CONNMAN_SERVICE_STATE_ASSOCIATION:
936         case CONNMAN_SERVICE_STATE_CONFIGURATION:
937         case CONNMAN_SERVICE_STATE_DISCONNECT:
938         case CONNMAN_SERVICE_STATE_FAILURE:
939                 break;
940         case CONNMAN_SERVICE_STATE_READY:
941         case CONNMAN_SERVICE_STATE_ONLINE:
942                 return TRUE;
943         }
944
945         return FALSE;
946 }
947
948 static connman_bool_t is_connecting(enum connman_service_state state)
949 {
950         switch (state) {
951         case CONNMAN_SERVICE_STATE_UNKNOWN:
952         case CONNMAN_SERVICE_STATE_IDLE:
953                 break;
954         case CONNMAN_SERVICE_STATE_ASSOCIATION:
955         case CONNMAN_SERVICE_STATE_CONFIGURATION:
956                 return TRUE;
957         case CONNMAN_SERVICE_STATE_DISCONNECT:
958         case CONNMAN_SERVICE_STATE_FAILURE:
959         case CONNMAN_SERVICE_STATE_READY:
960         case CONNMAN_SERVICE_STATE_ONLINE:
961                 break;
962         }
963
964         return FALSE;
965 }
966
967 static connman_bool_t explicit_connect(enum connman_session_reason reason)
968 {
969         switch (reason) {
970         case CONNMAN_SESSION_REASON_UNKNOWN:
971         case CONNMAN_SESSION_REASON_FREE_RIDE:
972                 break;
973         case CONNMAN_SESSION_REASON_CONNECT:
974                 return TRUE;
975         }
976
977         return FALSE;
978 }
979
980 static connman_bool_t explicit_disconnect(struct session_info *info)
981 {
982         if (info->entry == NULL)
983                 return FALSE;
984
985         DBG("reason %s service %p state %d",
986                 reason2string(info->entry->reason),
987                 info->entry->service, info->entry->state);
988
989         if (info->entry->reason == CONNMAN_SESSION_REASON_UNKNOWN)
990                 return FALSE;
991
992         if (explicit_connect(info->entry->reason) == FALSE)
993                 return FALSE;
994
995         if (__connman_service_session_dec(info->entry->service) == FALSE)
996                 return FALSE;
997
998         return TRUE;
999 }
1000
1001 struct pending_data {
1002         unsigned int timeout;
1003         struct service_entry *entry;
1004         gboolean (*cb)(gpointer);
1005 };
1006
1007 static void pending_timeout_free(gpointer data, gpointer user_data)
1008 {
1009         struct pending_data *pending = data;
1010
1011         DBG("pending %p timeout %d", pending, pending->timeout);
1012         g_source_remove(pending->timeout);
1013         g_free(pending);
1014 }
1015
1016 static void pending_timeout_remove_all(struct service_entry *entry)
1017 {
1018         DBG("");
1019
1020         g_slist_foreach(entry->pending_timeouts, pending_timeout_free, NULL);
1021         g_slist_free(entry->pending_timeouts);
1022         entry->pending_timeouts = NULL;
1023 }
1024
1025 static gboolean pending_timeout_cb(gpointer data)
1026 {
1027         struct pending_data *pending = data;
1028         struct service_entry *entry = pending->entry;
1029         gboolean ret;
1030
1031         DBG("pending %p timeout %d", pending, pending->timeout);
1032
1033         ret = pending->cb(pending->entry);
1034         if (ret == FALSE) {
1035                 entry->pending_timeouts =
1036                         g_slist_remove(entry->pending_timeouts,
1037                                         pending);
1038                 g_free(pending);
1039         }
1040         return ret;
1041 }
1042
1043 static connman_bool_t pending_timeout_add(unsigned int seconds,
1044                                         gboolean (*cb)(gpointer),
1045                                         struct service_entry *entry)
1046 {
1047         struct pending_data *pending = g_try_new0(struct pending_data, 1);
1048
1049         if (pending == NULL || cb == NULL || entry == NULL) {
1050                 g_free(pending);
1051                 return FALSE;
1052         }
1053
1054         pending->cb = cb;
1055         pending->entry = entry;
1056         pending->timeout = g_timeout_add_seconds(seconds, pending_timeout_cb,
1057                                                 pending);
1058         entry->pending_timeouts = g_slist_prepend(entry->pending_timeouts,
1059                                                 pending);
1060
1061         DBG("pending %p entry %p timeout id %d", pending, entry,
1062                 pending->timeout);
1063
1064         return TRUE;
1065 }
1066
1067 static gboolean call_disconnect(gpointer user_data)
1068 {
1069         struct service_entry *entry = user_data;
1070         struct connman_service *service = entry->service;
1071
1072         /*
1073          * TODO: We should mark this entry as pending work. In case
1074          * disconnect fails we just unassign this session from the
1075          * service and can't do anything later on it
1076          */
1077         DBG("disconnect service %p", service);
1078         __connman_service_disconnect(service);
1079
1080         return FALSE;
1081 }
1082
1083 static gboolean call_connect(gpointer user_data)
1084 {
1085         struct service_entry *entry = user_data;
1086         struct connman_service *service = entry->service;
1087
1088         DBG("connect service %p", service);
1089         __connman_service_connect(service);
1090
1091         return FALSE;
1092 }
1093
1094 static void deselect_service(struct session_info *info)
1095 {
1096         struct service_entry *entry;
1097         connman_bool_t disconnect, connected;
1098
1099         DBG("");
1100
1101         if (info->entry == NULL)
1102                 return;
1103
1104         disconnect = explicit_disconnect(info);
1105
1106         connected = is_connecting(info->entry->state) == TRUE ||
1107                         is_connected(info->entry->state) == TRUE;
1108
1109         info->state = CONNMAN_SESSION_STATE_DISCONNECTED;
1110         info->entry->reason = CONNMAN_SESSION_REASON_UNKNOWN;
1111
1112         entry = info->entry;
1113         info->entry = NULL;
1114
1115         DBG("disconnect %d connected %d", disconnect, connected);
1116
1117         if (disconnect == TRUE && connected == TRUE)
1118                 pending_timeout_add(0, call_disconnect, entry);
1119 }
1120
1121 static void deselect_and_disconnect(struct connman_session *session)
1122 {
1123         struct session_info *info = session->info;
1124
1125         deselect_service(info);
1126
1127         info->reason = CONNMAN_SESSION_REASON_FREE_RIDE;
1128 }
1129
1130 static void select_connected_service(struct session_info *info,
1131                                         struct service_entry *entry)
1132 {
1133         enum connman_session_state state;
1134
1135         state = service_to_session_state(entry->state);
1136         if (is_type_matching_state(&state, info->config.type) == FALSE)
1137                 return;
1138
1139         info->state = state;
1140
1141         info->entry = entry;
1142         info->entry->reason = info->reason;
1143
1144         if (explicit_connect(info->reason) == FALSE)
1145                 return;
1146
1147         __connman_service_session_inc(info->entry->service);
1148 }
1149
1150 static void select_offline_service(struct session_info *info,
1151                                         struct service_entry *entry)
1152 {
1153         if (explicit_connect(info->reason) == FALSE)
1154                 return;
1155
1156         info->state = service_to_session_state(entry->state);
1157
1158         info->entry = entry;
1159         info->entry->reason = info->reason;
1160
1161         __connman_service_session_inc(info->entry->service);
1162         pending_timeout_add(0, call_connect, entry);
1163 }
1164
1165 static void select_service(struct session_info *info,
1166                                 struct service_entry *entry)
1167 {
1168         DBG("service %p", entry->service);
1169
1170         if (is_connected(entry->state) == TRUE)
1171                 select_connected_service(info, entry);
1172         else
1173                 select_offline_service(info, entry);
1174 }
1175
1176 static void select_and_connect(struct connman_session *session,
1177                                 enum connman_session_reason reason)
1178 {
1179         struct session_info *info = session->info;
1180         struct service_entry *entry = NULL;
1181         GSequenceIter *iter;
1182
1183         DBG("session %p reason %s", session, reason2string(reason));
1184
1185         info->reason = reason;
1186
1187         iter = g_sequence_get_begin_iter(session->service_list);
1188
1189         while (g_sequence_iter_is_end(iter) == FALSE) {
1190                 entry = g_sequence_get(iter);
1191
1192                 switch (entry->state) {
1193                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
1194                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
1195                 case CONNMAN_SERVICE_STATE_READY:
1196                 case CONNMAN_SERVICE_STATE_ONLINE:
1197                 case CONNMAN_SERVICE_STATE_IDLE:
1198                 case CONNMAN_SERVICE_STATE_DISCONNECT:
1199                         select_service(info, entry);
1200                         return;
1201                 case CONNMAN_SERVICE_STATE_UNKNOWN:
1202                 case CONNMAN_SERVICE_STATE_FAILURE:
1203                         break;
1204                 }
1205
1206                 iter = g_sequence_iter_next(iter);
1207         }
1208 }
1209
1210 static struct service_entry *create_service_entry(struct connman_session * session,
1211                                         struct connman_service *service,
1212                                         const char *name,
1213                                         enum connman_service_state state)
1214 {
1215         struct service_entry *entry;
1216         enum connman_service_type type;
1217         int idx;
1218
1219         entry = g_try_new0(struct service_entry, 1);
1220         if (entry == NULL)
1221                 return entry;
1222
1223         entry->reason = CONNMAN_SESSION_REASON_UNKNOWN;
1224         entry->state = state;
1225         if (name != NULL)
1226                 entry->name = name;
1227         else
1228                 entry->name = "";
1229         entry->service = service;
1230
1231         idx = __connman_service_get_index(entry->service);
1232         entry->ifname = connman_inet_ifname(idx);
1233         if (entry->ifname == NULL)
1234                 entry->ifname = g_strdup("");
1235
1236         type = connman_service_get_type(entry->service);
1237         entry->bearer = service2bearer(type);
1238
1239         entry->session = session;
1240
1241         return entry;
1242 }
1243
1244 static void destroy_service_entry(gpointer data)
1245 {
1246         struct service_entry *entry = data;
1247         struct session_info *info = entry->session->info;
1248         struct connman_session *session;
1249
1250         if (info != NULL && info->entry == entry) {
1251                 session = entry->session;
1252                 deselect_and_disconnect(session);
1253         }
1254
1255         pending_timeout_remove_all(entry);
1256         g_free(entry->ifname);
1257
1258         g_free(entry);
1259 }
1260
1261 static void populate_service_list(struct connman_session *session)
1262 {
1263         struct service_entry *entry;
1264         GSequenceIter *iter;
1265
1266         session->service_hash =
1267                 g_hash_table_new_full(g_direct_hash, g_direct_equal,
1268                                         NULL, NULL);
1269         session->service_list = __connman_service_get_list(session,
1270                                                         service_match,
1271                                                         create_service_entry,
1272                                                         destroy_service_entry);
1273
1274         g_sequence_sort(session->service_list, sort_services, session);
1275
1276         iter = g_sequence_get_begin_iter(session->service_list);
1277
1278         while (g_sequence_iter_is_end(iter) == FALSE) {
1279                 entry = g_sequence_get(iter);
1280
1281                 DBG("service %p type %s name %s", entry->service,
1282                         service2bearer(connman_service_get_type(entry->service)),
1283                         entry->name);
1284
1285                 g_hash_table_replace(session->service_hash,
1286                                         entry->service, iter);
1287
1288                 iter = g_sequence_iter_next(iter);
1289         }
1290 }
1291
1292 static void session_changed(struct connman_session *session,
1293                                 enum connman_session_trigger trigger)
1294 {
1295         struct session_info *info = session->info;
1296         struct session_info *info_last = session->info_last;
1297         struct connman_service *service;
1298         GSequenceIter *service_iter = NULL, *service_iter_last = NULL;
1299         GSequence *service_list_last;
1300         GHashTable *service_hash_last;
1301
1302         /*
1303          * TODO: This only a placeholder for the 'real' algorithm to
1304          * play a bit around. So we are going to improve it step by step.
1305          */
1306
1307         DBG("session %p trigger %s reason %s", session, trigger2string(trigger),
1308                                                 reason2string(info->reason));
1309
1310         if (info->entry != NULL) {
1311                 enum connman_session_state state;
1312
1313                 state = service_to_session_state(info->entry->state);
1314
1315                 if (is_type_matching_state(&state, info->config.type) == TRUE)
1316                         info->state = state;
1317         }
1318
1319         switch (trigger) {
1320         case CONNMAN_SESSION_TRIGGER_UNKNOWN:
1321                 DBG("ignore session changed event");
1322                 return;
1323         case CONNMAN_SESSION_TRIGGER_SETTING:
1324                 if (info->config.allowed_bearers != info_last->config.allowed_bearers) {
1325
1326                         service_hash_last = session->service_hash;
1327                         service_list_last = session->service_list;
1328
1329                         if (info->entry != NULL)
1330                                 service = info->entry->service;
1331                         else
1332                                 service = NULL;
1333
1334                         populate_service_list(session);
1335
1336                         if (service != NULL) {
1337                                 service_iter_last = g_hash_table_lookup(
1338                                                         service_hash_last,
1339                                                         service);
1340                                 service_iter = g_hash_table_lookup(
1341                                                         session->service_hash,
1342                                                         service);
1343                         }
1344
1345                         if (service_iter == NULL && service_iter_last != NULL) {
1346                                 /*
1347                                  * The currently selected service is
1348                                  * not part of this session anymore.
1349                                  */
1350                                 deselect_and_disconnect(session);
1351                         }
1352
1353                         g_hash_table_remove_all(service_hash_last);
1354                         g_sequence_free(service_list_last);
1355                 }
1356
1357                 if (info->config.type != info_last->config.type) {
1358                         if (info->state >= CONNMAN_SESSION_STATE_CONNECTED &&
1359                                         is_type_matching_state(&info->state,
1360                                                         info->config.type) == FALSE)
1361                                 deselect_and_disconnect(session);
1362                 }
1363
1364                 if (info->state == CONNMAN_SESSION_STATE_DISCONNECTED) {
1365                         select_and_connect(session,
1366                                         CONNMAN_SESSION_REASON_FREE_RIDE);
1367                 }
1368
1369                 break;
1370         case CONNMAN_SESSION_TRIGGER_ECALL:
1371                 /*
1372                  * For the time beeing we fallback to normal connect
1373                  * strategy.
1374                  */
1375         case CONNMAN_SESSION_TRIGGER_CONNECT:
1376                 if (info->state >= CONNMAN_SESSION_STATE_CONNECTED) {
1377                         if (info->entry->reason == CONNMAN_SESSION_REASON_CONNECT)
1378                                 break;
1379                         info->entry->reason = CONNMAN_SESSION_REASON_CONNECT;
1380                         __connman_service_session_inc(info->entry->service);
1381                         break;
1382                 }
1383
1384                 if (info->entry != NULL &&
1385                                 is_connecting(info->entry->state) == TRUE) {
1386                         break;
1387                 }
1388
1389                 select_and_connect(session,
1390                                 CONNMAN_SESSION_REASON_CONNECT);
1391
1392                 break;
1393         case CONNMAN_SESSION_TRIGGER_DISCONNECT:
1394                 deselect_and_disconnect(session);
1395
1396                 break;
1397         case CONNMAN_SESSION_TRIGGER_SERVICE:
1398                 if (info->entry != NULL &&
1399                         (is_connecting(info->entry->state) == TRUE ||
1400                                 is_connected(info->entry->state) == TRUE)) {
1401                         break;
1402                 }
1403
1404                 deselect_and_disconnect(session);
1405
1406                 if (info->reason == CONNMAN_SESSION_REASON_FREE_RIDE) {
1407                         select_and_connect(session, info->reason);
1408                 }
1409
1410                 break;
1411         }
1412
1413         session_notify(session);
1414 }
1415
1416 int connman_session_config_update(struct connman_session *session)
1417 {
1418         struct session_info *info = session->info;
1419         GSList *allowed_bearers;
1420         int err;
1421
1422         DBG("session %p", session);
1423
1424         /*
1425          * We update all configuration even though only one entry
1426          * might have changed. We can still optimize this later.
1427          */
1428
1429         err = apply_policy_on_bearers(
1430                 session->policy_config->allowed_bearers,
1431                 session->user_allowed_bearers,
1432                 &allowed_bearers);
1433         if (err < 0)
1434                 return err;
1435
1436         g_slist_free(info->config.allowed_bearers);
1437         info->config.allowed_bearers = allowed_bearers;
1438
1439         info->config.type = apply_policy_on_type(
1440                                 session->policy_config->type,
1441                                 info->config.type);
1442
1443         info->config.roaming_policy = session->policy_config->roaming_policy;
1444
1445         info->config.ecall = session->policy_config->ecall;
1446         if (info->config.ecall == TRUE)
1447                 ecall_session = session;
1448
1449         info->config.priority = session->policy_config->priority;
1450
1451         session_changed(session, CONNMAN_SESSION_TRIGGER_SETTING);
1452
1453         return 0;
1454 }
1455
1456 static DBusMessage *connect_session(DBusConnection *conn,
1457                                         DBusMessage *msg, void *user_data)
1458 {
1459         struct connman_session *session = user_data;
1460
1461         DBG("session %p", session);
1462
1463         if (ecall_session != NULL) {
1464                 if (ecall_session->ecall == TRUE && ecall_session != session)
1465                         return __connman_error_failed(msg, EBUSY);
1466
1467                 session->ecall = TRUE;
1468                 session_changed(session, CONNMAN_SESSION_TRIGGER_ECALL);
1469         } else
1470                 session_changed(session, CONNMAN_SESSION_TRIGGER_CONNECT);
1471
1472         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1473 }
1474
1475 static DBusMessage *disconnect_session(DBusConnection *conn,
1476                                         DBusMessage *msg, void *user_data)
1477 {
1478         struct connman_session *session = user_data;
1479
1480         DBG("session %p", session);
1481
1482         if (ecall_session != NULL) {
1483                 if (ecall_session->ecall == TRUE && ecall_session != session)
1484                         return __connman_error_failed(msg, EBUSY);
1485
1486                 session->ecall = FALSE;
1487         }
1488
1489         session_changed(session, CONNMAN_SESSION_TRIGGER_DISCONNECT);
1490
1491         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1492 }
1493
1494 static DBusMessage *change_session(DBusConnection *conn,
1495                                         DBusMessage *msg, void *user_data)
1496 {
1497         struct connman_session *session = user_data;
1498         struct session_info *info = session->info;
1499         DBusMessageIter iter, value;
1500         const char *name;
1501         const char *val;
1502         GSList *allowed_bearers;
1503         int err;
1504
1505         DBG("session %p", session);
1506         if (dbus_message_iter_init(msg, &iter) == FALSE)
1507                 return __connman_error_invalid_arguments(msg);
1508
1509         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1510                 return __connman_error_invalid_arguments(msg);
1511
1512         dbus_message_iter_get_basic(&iter, &name);
1513         dbus_message_iter_next(&iter);
1514
1515         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1516                 return __connman_error_invalid_arguments(msg);
1517
1518         dbus_message_iter_recurse(&iter, &value);
1519
1520         switch (dbus_message_iter_get_arg_type(&value)) {
1521         case DBUS_TYPE_ARRAY:
1522                 if (g_str_equal(name, "AllowedBearers") == TRUE) {
1523                         err = parse_bearers(&value, &allowed_bearers);
1524                         if (err < 0)
1525                                 return __connman_error_failed(msg, err);
1526
1527                         g_slist_free(info->config.allowed_bearers);
1528                         session->user_allowed_bearers = allowed_bearers;
1529
1530                         err = apply_policy_on_bearers(
1531                                         session->policy_config->allowed_bearers,
1532                                         session->user_allowed_bearers,
1533                                         &info->config.allowed_bearers);
1534
1535                         if (err < 0)
1536                                 return __connman_error_failed(msg, err);
1537                 } else {
1538                         goto err;
1539                 }
1540                 break;
1541         case DBUS_TYPE_STRING:
1542                 if (g_str_equal(name, "ConnectionType") == TRUE) {
1543                         dbus_message_iter_get_basic(&value, &val);
1544                         info->config.type = apply_policy_on_type(
1545                                 session->policy_config->type,
1546                                 connman_session_parse_connection_type(val));
1547                 } else {
1548                         goto err;
1549                 }
1550                 break;
1551         default:
1552                 goto err;
1553         }
1554
1555         session_changed(session, CONNMAN_SESSION_TRIGGER_SETTING);
1556
1557         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1558
1559 err:
1560         return __connman_error_invalid_arguments(msg);
1561 }
1562
1563 static void release_session(gpointer key, gpointer value, gpointer user_data)
1564 {
1565         struct connman_session *session = value;
1566         DBusMessage *message;
1567
1568         DBG("owner %s path %s", session->owner, session->notify_path);
1569
1570         if (session->notify_watch > 0)
1571                 g_dbus_remove_watch(connection, session->notify_watch);
1572
1573         g_dbus_unregister_interface(connection, session->session_path,
1574                                                 CONNMAN_SESSION_INTERFACE);
1575
1576         message = dbus_message_new_method_call(session->owner,
1577                                                 session->notify_path,
1578                                                 CONNMAN_NOTIFICATION_INTERFACE,
1579                                                 "Release");
1580         if (message == NULL)
1581                 return;
1582
1583         dbus_message_set_no_reply(message, TRUE);
1584
1585         g_dbus_send_message(connection, message);
1586 }
1587
1588 static int session_disconnect(struct connman_session *session)
1589 {
1590         DBG("session %p, %s", session, session->owner);
1591
1592         if (session->notify_watch > 0)
1593                 g_dbus_remove_watch(connection, session->notify_watch);
1594
1595         g_dbus_unregister_interface(connection, session->session_path,
1596                                                 CONNMAN_SESSION_INTERFACE);
1597
1598         deselect_and_disconnect(session);
1599
1600         g_hash_table_remove(session_hash, session->session_path);
1601
1602         return 0;
1603 }
1604
1605 static void owner_disconnect(DBusConnection *conn, void *user_data)
1606 {
1607         struct connman_session *session = user_data;
1608
1609         DBG("session %p, %s died", session, session->owner);
1610
1611         session_disconnect(session);
1612 }
1613
1614 static DBusMessage *destroy_session(DBusConnection *conn,
1615                                         DBusMessage *msg, void *user_data)
1616 {
1617         struct connman_session *session = user_data;
1618
1619         DBG("session %p", session);
1620
1621         if (ecall_session != NULL && ecall_session != session)
1622                 return __connman_error_failed(msg, EBUSY);
1623
1624         session_disconnect(session);
1625
1626         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1627 }
1628
1629 static const GDBusMethodTable session_methods[] = {
1630         { GDBUS_METHOD("Destroy", NULL, NULL, destroy_session) },
1631         { GDBUS_METHOD("Connect", NULL, NULL, connect_session) },
1632         { GDBUS_METHOD("Disconnect", NULL, NULL,
1633                         disconnect_session ) },
1634         { GDBUS_METHOD("Change",
1635                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
1636                         NULL, change_session) },
1637         { },
1638 };
1639
1640 static int session_create_cb(struct connman_session *session,
1641                                 struct connman_session_config *config,
1642                                 void *user_data, int err)
1643 {
1644         DBusMessage *reply;
1645         struct user_config *user_config = user_data;
1646         struct session_info *info, *info_last;
1647
1648         DBG("session %p config %p", session, config);
1649
1650         if (err != 0)
1651                 goto out;
1652
1653         session->policy_config = config;
1654
1655         info = session->info;
1656         info_last = session->info_last;
1657
1658         if (session->policy_config->ecall == TRUE)
1659                 ecall_session = session;
1660
1661         info->state = CONNMAN_SESSION_STATE_DISCONNECTED;
1662         info->config.type = apply_policy_on_type(
1663                                 session->policy_config->type,
1664                                 user_config->type);
1665         info->config.priority = session->policy_config->priority;
1666         info->config.roaming_policy = session->policy_config->roaming_policy;
1667         info->entry = NULL;
1668
1669         session->user_allowed_bearers = user_config->allowed_bearers;
1670         user_config->allowed_bearers = NULL;
1671
1672         err = apply_policy_on_bearers(
1673                         session->policy_config->allowed_bearers,
1674                         session->user_allowed_bearers,
1675                         &info->config.allowed_bearers);
1676         if (err < 0)
1677                 goto out;
1678
1679         g_hash_table_replace(session_hash, session->session_path, session);
1680
1681         DBG("add %s", session->session_path);
1682
1683         if (g_dbus_register_interface(connection, session->session_path,
1684                                         CONNMAN_SESSION_INTERFACE,
1685                                         session_methods, NULL,
1686                                         NULL, session, NULL) == FALSE) {
1687                 connman_error("Failed to register %s", session->session_path);
1688                 g_hash_table_remove(session_hash, session->session_path);
1689                 err = -EINVAL;
1690                 goto out;
1691         }
1692
1693         reply = g_dbus_create_reply(user_config->pending,
1694                                 DBUS_TYPE_OBJECT_PATH, &session->session_path,
1695                                 DBUS_TYPE_INVALID);
1696         g_dbus_send_message(connection, reply);
1697         user_config->pending = NULL;
1698
1699         populate_service_list(session);
1700
1701         info_last->state = info->state;
1702         info_last->config.priority = info->config.priority;
1703         info_last->config.roaming_policy = info->config.roaming_policy;
1704         info_last->entry = info->entry;
1705         info_last->config.allowed_bearers = info->config.allowed_bearers;
1706
1707         session->append_all = TRUE;
1708
1709         session_changed(session, CONNMAN_SESSION_TRIGGER_SETTING);
1710
1711 out:
1712         if (err < 0) {
1713                 reply = __connman_error_failed(user_config->pending, -err);
1714                 g_dbus_send_message(connection, reply);
1715
1716                 free_session(session);
1717         }
1718
1719         cleanup_user_config(user_config);
1720
1721         return err;
1722 }
1723
1724 int __connman_session_create(DBusMessage *msg)
1725 {
1726         const char *owner, *notify_path;
1727         char *session_path = NULL;
1728         DBusMessageIter iter, array;
1729         struct connman_session *session = NULL;
1730         struct user_config *user_config = NULL;
1731         connman_bool_t user_allowed_bearers = FALSE;
1732         connman_bool_t user_connection_type = FALSE;
1733         int err;
1734
1735         owner = dbus_message_get_sender(msg);
1736
1737         DBG("owner %s", owner);
1738
1739         if (ecall_session != NULL && ecall_session->ecall == TRUE) {
1740                 /*
1741                  * If there is an emergency call already going on,
1742                  * ignore session creation attempt
1743                  */
1744                 err = -EBUSY;
1745                 goto err;
1746         }
1747
1748         user_config = g_try_new0(struct user_config, 1);
1749         if (user_config == NULL) {
1750                 err = -ENOMEM;
1751                 goto err;
1752         }
1753
1754         user_config->pending = dbus_message_ref(msg);
1755
1756         dbus_message_iter_init(msg, &iter);
1757         dbus_message_iter_recurse(&iter, &array);
1758
1759         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1760                 DBusMessageIter entry, value;
1761                 const char *key, *val;
1762
1763                 dbus_message_iter_recurse(&array, &entry);
1764                 dbus_message_iter_get_basic(&entry, &key);
1765
1766                 dbus_message_iter_next(&entry);
1767                 dbus_message_iter_recurse(&entry, &value);
1768
1769                 switch (dbus_message_iter_get_arg_type(&value)) {
1770                 case DBUS_TYPE_ARRAY:
1771                         if (g_str_equal(key, "AllowedBearers") == TRUE) {
1772                                 err = parse_bearers(&value,
1773                                                 &user_config->allowed_bearers);
1774                                 if (err < 0)
1775                                         goto err;
1776
1777                                 user_allowed_bearers = TRUE;
1778                         } else {
1779                                 err = -EINVAL;
1780                                 goto err;
1781                         }
1782                         break;
1783                 case DBUS_TYPE_STRING:
1784                         if (g_str_equal(key, "ConnectionType") == TRUE) {
1785                                 dbus_message_iter_get_basic(&value, &val);
1786                                 user_config->type =
1787                                         connman_session_parse_connection_type(val);
1788
1789                                 user_connection_type = TRUE;
1790                         } else {
1791                                 err = -EINVAL;
1792                                 goto err;
1793                         }
1794                 }
1795                 dbus_message_iter_next(&array);
1796         }
1797
1798         /*
1799          * If the user hasn't provided a configuration, we set
1800          * the default configuration.
1801          *
1802          * For AllowedBearers this is '*', ...
1803          */
1804         if (user_allowed_bearers == FALSE) {
1805                 user_config->allowed_bearers =
1806                         g_slist_append(NULL,
1807                                 GINT_TO_POINTER(CONNMAN_SERVICE_TYPE_UNKNOWN));
1808                 if (user_config->allowed_bearers == NULL) {
1809                         err = -ENOMEM;
1810                         goto err;
1811                 }
1812         }
1813
1814         /* ... and for ConnectionType it is 'any'. */
1815         if (user_connection_type == FALSE)
1816                 user_config->type = CONNMAN_SESSION_TYPE_ANY;
1817
1818         dbus_message_iter_next(&iter);
1819         dbus_message_iter_get_basic(&iter, &notify_path);
1820
1821         if (notify_path == NULL) {
1822                 err = -EINVAL;
1823                 goto err;
1824         }
1825
1826         session_path = g_strdup_printf("/sessions%s", notify_path);
1827         if (session_path == NULL) {
1828                 err = -ENOMEM;
1829                 goto err;
1830         }
1831
1832         session = g_hash_table_lookup(session_hash, session_path);
1833         if (session != NULL) {
1834                 g_free(session_path);
1835                 session = NULL;
1836                 err = -EEXIST;
1837                 goto err;
1838         }
1839
1840         session = g_try_new0(struct connman_session, 1);
1841         if (session == NULL) {
1842                 g_free(session_path);
1843                 err = -ENOMEM;
1844                 goto err;
1845         }
1846
1847         session->session_path = session_path;
1848
1849         session->info = g_try_new0(struct session_info, 1);
1850         if (session->info == NULL) {
1851                 err = -ENOMEM;
1852                 goto err;
1853         }
1854
1855         session->info_last = g_try_new0(struct session_info, 1);
1856         if (session->info_last == NULL) {
1857                 err = -ENOMEM;
1858                 goto err;
1859         }
1860
1861         session->owner = g_strdup(owner);
1862         session->notify_path = g_strdup(notify_path);
1863         session->notify_watch =
1864                 g_dbus_add_disconnect_watch(connection, session->owner,
1865                                         owner_disconnect, session, NULL);
1866
1867         err = assign_policy_plugin(session);
1868         if (err < 0)
1869                 goto err;
1870
1871         err = create_policy_config(session, session_create_cb, user_config);
1872         if (err < 0 && err != -EINPROGRESS)
1873                 return err;
1874
1875         return -EINPROGRESS;
1876
1877 err:
1878         connman_error("Failed to create session");
1879
1880         free_session(session);
1881
1882         cleanup_user_config(user_config);
1883         return err;
1884 }
1885
1886 void connman_session_destroy(struct connman_session *session)
1887 {
1888         DBG("session %p", session);
1889
1890         session_disconnect(session);
1891 }
1892
1893 int __connman_session_destroy(DBusMessage *msg)
1894 {
1895         const char *owner, *session_path;
1896         struct connman_session *session;
1897
1898         owner = dbus_message_get_sender(msg);
1899
1900         DBG("owner %s", owner);
1901
1902         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &session_path,
1903                                                         DBUS_TYPE_INVALID);
1904         if (session_path == NULL)
1905                 return -EINVAL;
1906
1907         session = g_hash_table_lookup(session_hash, session_path);
1908         if (session == NULL)
1909                 return -EINVAL;
1910
1911         if (g_strcmp0(owner, session->owner) != 0)
1912                 return -EACCES;
1913
1914         connman_session_destroy(session);
1915
1916         return 0;
1917 }
1918
1919 connman_bool_t __connman_session_mode()
1920 {
1921         return sessionmode;
1922 }
1923
1924 void __connman_session_set_mode(connman_bool_t enable)
1925 {
1926         DBG("enable %d", enable);
1927
1928         if (sessionmode != enable) {
1929                 sessionmode = enable;
1930
1931                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
1932                                 CONNMAN_MANAGER_INTERFACE, "SessionMode",
1933                                 DBUS_TYPE_BOOLEAN, &sessionmode);
1934         }
1935
1936         if (sessionmode == TRUE)
1937                 __connman_service_disconnect_all();
1938 }
1939
1940 static void service_add(struct connman_service *service,
1941                         const char *name)
1942 {
1943         GHashTableIter iter;
1944         GSequenceIter *iter_service_list;
1945         gpointer key, value;
1946         struct connman_session *session;
1947         struct service_entry *entry;
1948
1949         DBG("service %p", service);
1950
1951         g_hash_table_iter_init(&iter, session_hash);
1952
1953         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1954                 session = value;
1955
1956                 if (service_match(session, service) == FALSE)
1957                         continue;
1958
1959                 entry = create_service_entry(session, service, name,
1960                                                 CONNMAN_SERVICE_STATE_IDLE);
1961                 if (entry == NULL)
1962                         continue;
1963
1964                 iter_service_list =
1965                         g_sequence_insert_sorted(session->service_list,
1966                                                         entry, sort_services,
1967                                                         session);
1968
1969                 g_hash_table_replace(session->service_hash, service,
1970                                         iter_service_list);
1971
1972                 session_changed(session, CONNMAN_SESSION_TRIGGER_SERVICE);
1973         }
1974 }
1975
1976 static void service_remove(struct connman_service *service)
1977 {
1978
1979         GHashTableIter iter;
1980         gpointer key, value;
1981         struct connman_session *session;
1982         struct session_info *info;
1983
1984         DBG("service %p", service);
1985
1986         g_hash_table_iter_init(&iter, session_hash);
1987
1988         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1989                 GSequenceIter *seq_iter;
1990                 session = value;
1991                 info = session->info;
1992
1993                 seq_iter = g_hash_table_lookup(session->service_hash, service);
1994                 if (seq_iter == NULL)
1995                         continue;
1996
1997                 g_sequence_remove(seq_iter);
1998
1999                 if (info->entry != NULL && info->entry->service == service)
2000                         info->entry = NULL;
2001                 session_changed(session, CONNMAN_SESSION_TRIGGER_SERVICE);
2002         }
2003 }
2004
2005 static void service_state_changed(struct connman_service *service,
2006                                         enum connman_service_state state)
2007 {
2008         GHashTableIter iter;
2009         gpointer key, value;
2010
2011         DBG("service %p state %d", service, state);
2012
2013         g_hash_table_iter_init(&iter, session_hash);
2014
2015         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
2016                 struct connman_session *session = value;
2017                 GSequenceIter *service_iter;
2018
2019                 service_iter = g_hash_table_lookup(session->service_hash, service);
2020                 if (service_iter != NULL) {
2021                         struct service_entry *entry;
2022
2023                         entry = g_sequence_get(service_iter);
2024                         entry->state = state;
2025                 }
2026
2027                 session_changed(session,
2028                                 CONNMAN_SESSION_TRIGGER_SERVICE);
2029         }
2030 }
2031
2032 static void ipconfig_changed(struct connman_service *service,
2033                                 struct connman_ipconfig *ipconfig)
2034 {
2035         GHashTableIter iter;
2036         gpointer key, value;
2037         struct connman_session *session;
2038         struct session_info *info;
2039         enum connman_ipconfig_type type;
2040
2041         DBG("service %p ipconfig %p", service, ipconfig);
2042
2043         type = __connman_ipconfig_get_config_type(ipconfig);
2044
2045         g_hash_table_iter_init(&iter, session_hash);
2046
2047         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
2048                 session = value;
2049                 info = session->info;
2050
2051                 if (info->state == CONNMAN_SESSION_STATE_DISCONNECTED)
2052                         continue;
2053
2054                 if (info->entry != NULL && info->entry->service == service) {
2055                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
2056                                 ipconfig_ipv4_changed(session);
2057                         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
2058                                 ipconfig_ipv6_changed(session);
2059                 }
2060         }
2061 }
2062
2063 static struct connman_notifier session_notifier = {
2064         .name                   = "session",
2065         .service_add            = service_add,
2066         .service_remove         = service_remove,
2067         .service_state_changed  = service_state_changed,
2068         .ipconfig_changed       = ipconfig_changed,
2069 };
2070
2071 int __connman_session_init(void)
2072 {
2073         int err;
2074
2075         DBG("");
2076
2077         connection = connman_dbus_get_connection();
2078         if (connection == NULL)
2079                 return -1;
2080
2081         err = connman_notifier_register(&session_notifier);
2082         if (err < 0) {
2083                 dbus_connection_unref(connection);
2084                 return err;
2085         }
2086
2087         session_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2088                                                 NULL, cleanup_session);
2089
2090         sessionmode = FALSE;
2091         return 0;
2092 }
2093
2094 void __connman_session_cleanup(void)
2095 {
2096         DBG("");
2097
2098         if (connection == NULL)
2099                 return;
2100
2101         connman_notifier_unregister(&session_notifier);
2102
2103         g_hash_table_foreach(session_hash, release_session, NULL);
2104         g_hash_table_destroy(session_hash);
2105         session_hash = NULL;
2106
2107         dbus_connection_unref(connection);
2108 }