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