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