ofono: Do not call set_connected() from the activation reply
[platform/upstream/connman.git] / plugins / ofono.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
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 #include <stdlib.h>
29
30 #include <gdbus.h>
31 #include <string.h>
32
33 #define CONNMAN_API_SUBJECT_TO_CHANGE
34 #include <connman/plugin.h>
35 #include <connman/device.h>
36 #include <connman/network.h>
37 #include <connman/ipconfig.h>
38 #include <connman/dbus.h>
39 #include <connman/inet.h>
40 #include <connman/technology.h>
41 #include <connman/log.h>
42
43 #include "mcc.h"
44
45 #define OFONO_SERVICE                   "org.ofono"
46
47 #define OFONO_MANAGER_INTERFACE         OFONO_SERVICE ".Manager"
48 #define OFONO_MODEM_INTERFACE           OFONO_SERVICE ".Modem"
49 #define OFONO_GPRS_INTERFACE            OFONO_SERVICE ".ConnectionManager"
50 #define OFONO_CONTEXT_INTERFACE         OFONO_SERVICE ".ConnectionContext"
51 #define OFONO_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
52 #define OFONO_REGISTRATION_INTERFACE    OFONO_SERVICE ".NetworkRegistration"
53
54 #define PROPERTY_CHANGED                "PropertyChanged"
55 #define GET_PROPERTIES                  "GetProperties"
56 #define SET_PROPERTY                    "SetProperty"
57 #define CONTEXT_ADDED                   "ContextAdded"
58 #define CONTEXT_REMOVED                 "ContextRemoved"
59 #define ADD_CONTEXT                     "AddContext"
60 #define GET_MODEMS                      "GetModems"
61 #define MODEM_ADDED                     "ModemAdded"
62 #define MODEM_REMOVED                   "ModemRemoved"
63
64
65 #define TIMEOUT 40000
66
67 static DBusConnection *connection;
68
69 static GHashTable *modem_hash = NULL;
70
71 static GHashTable *network_hash;
72
73 struct modem_data {
74         char *path;
75         struct connman_device *device;
76         gboolean has_sim;
77         gboolean has_reg;
78         gboolean has_gprs;
79         gboolean available;
80         gboolean pending_online;
81         dbus_bool_t requested_online;
82         dbus_bool_t online;
83
84         /* org.ofono.ConnectionManager properties */
85         dbus_bool_t powered;
86         dbus_bool_t attached;
87         dbus_bool_t roaming_allowed;
88
89         connman_bool_t registered;
90         connman_bool_t roaming;
91         uint8_t strength, has_strength;
92         char *operator;
93 };
94
95 struct network_info {
96         struct connman_network *network;
97
98         enum connman_ipconfig_method ipv4_method;
99         struct connman_ipaddress ipv4_address;
100
101         enum connman_ipconfig_method ipv6_method;
102         struct connman_ipaddress ipv6_address;
103 };
104
105 static int modem_probe(struct connman_device *device)
106 {
107         DBG("device %p", device);
108
109         return 0;
110 }
111
112 static void modem_remove(struct connman_device *device)
113 {
114         DBG("device %p", device);
115 }
116
117 static int call_ofono(const char *path,
118                         const char *interface, const char *method,
119                         DBusPendingCallNotifyFunction notify, void *user_data,
120                         DBusFreeFunction free_function,
121                         int type, ...)
122 {
123         DBusMessage *message;
124         DBusPendingCall *call;
125         dbus_bool_t ok;
126         va_list va;
127
128         DBG("path %s %s.%s", path, interface, method);
129
130         if (path == NULL)
131                 return -EINVAL;
132
133         message = dbus_message_new_method_call(OFONO_SERVICE, path,
134                                         interface, method);
135         if (message == NULL)
136                 return -ENOMEM;
137
138         dbus_message_set_auto_start(message, FALSE);
139
140         va_start(va, type);
141         ok = dbus_message_append_args_valist(message, type, va);
142         va_end(va);
143
144         if (!ok)
145                 return -ENOMEM;
146
147         if (dbus_connection_send_with_reply(connection, message,
148                                                 &call, TIMEOUT) == FALSE) {
149                 connman_error("Failed to call %s.%s", interface, method);
150                 dbus_message_unref(message);
151                 return -EINVAL;
152         }
153
154         if (call == NULL) {
155                 connman_error("D-Bus connection not available");
156                 dbus_message_unref(message);
157                 return -EINVAL;
158         }
159
160         dbus_pending_call_set_notify(call, notify, user_data, free_function);
161
162         dbus_message_unref(message);
163
164         return -EINPROGRESS;
165 }
166
167 static void set_property_reply(DBusPendingCall *call, void *user_data)
168 {
169         DBusMessage *reply;
170         DBusError error;
171         char const *name = user_data;
172
173         DBG("");
174
175         dbus_error_init(&error);
176
177         reply = dbus_pending_call_steal_reply(call);
178
179         if (dbus_set_error_from_message(&error, reply)) {
180                 connman_error("SetProperty(%s) %s %s", name,
181                                 error.name, error.message);
182                 dbus_error_free(&error);
183         }
184
185         dbus_message_unref(reply);
186
187         dbus_pending_call_unref(call);
188 }
189
190 static int set_property(const char *path, const char *interface,
191                         const char *property, int type, void *value,
192                         DBusPendingCallNotifyFunction notify, void *user_data,
193                         DBusFreeFunction free_function)
194 {
195         DBusMessage *message;
196         DBusMessageIter iter;
197         DBusPendingCall *call;
198
199         DBG("path %s %s.%s", path, interface, property);
200
201         g_assert(notify == NULL ? free_function == NULL : 1);
202
203         if (path == NULL)
204                 return -EINVAL;
205
206         message = dbus_message_new_method_call(OFONO_SERVICE, path,
207                                         interface, SET_PROPERTY);
208         if (message == NULL)
209                 return -ENOMEM;
210
211         dbus_message_set_auto_start(message, FALSE);
212
213         dbus_message_iter_init_append(message, &iter);
214         connman_dbus_property_append_basic(&iter, property, type, value);
215
216         if (dbus_connection_send_with_reply(connection, message,
217                                                 &call, TIMEOUT) == FALSE) {
218                 connman_error("Failed to change \"%s\" property on %s",
219                                 property, interface);
220                 dbus_message_unref(message);
221                 return -EINVAL;
222         }
223
224         if (call == NULL) {
225                 connman_error("D-Bus connection not available");
226                 dbus_message_unref(message);
227                 return -EINVAL;
228         }
229
230         if (notify == NULL) {
231                 notify = set_property_reply;
232                 user_data = (void *)property;
233                 free_function = NULL;
234         }
235
236         dbus_pending_call_set_notify(call, notify, user_data, free_function);
237
238         dbus_message_unref(message);
239
240         return -EINPROGRESS;
241 }
242
243 static void update_modem_online(struct modem_data *modem,
244                                 connman_bool_t online)
245 {
246         DBG("modem %p path %s online %d", modem, modem->path, online);
247
248         modem->online = online;
249         modem->requested_online = online;
250         modem->pending_online = FALSE;
251
252         if (modem->device)
253                 connman_device_set_powered(modem->device, online);
254 }
255
256 static void remove_device_networks(struct connman_device *device)
257 {
258         GHashTableIter iter;
259         gpointer key, value;
260         GSList *info_list = NULL;
261         GSList *list;
262
263         if (network_hash == NULL)
264                 return;
265
266         g_hash_table_iter_init(&iter, network_hash);
267
268         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
269                 struct network_info *info = value;
270
271                 if (connman_network_get_device(info->network) != device)
272                         continue;
273
274                 info_list = g_slist_append(info_list, info);
275         }
276
277         for (list = info_list; list != NULL; list = list->next) {
278                 struct network_info *info = list->data;
279
280                 connman_device_remove_network(device, info->network);
281         }
282
283         g_slist_free(info_list);
284 }
285
286 static void set_online_reply(DBusPendingCall *call, void *user_data)
287 {
288         struct modem_data *modem;
289         DBusMessage *reply;
290         DBusError error;
291         gboolean result;
292
293         DBG("path %s", (char *)user_data);
294
295         if (modem_hash == NULL)
296                 return;
297
298         modem = g_hash_table_lookup(modem_hash, user_data);
299         if (modem == NULL)
300                 return;
301
302         reply = dbus_pending_call_steal_reply(call);
303
304         dbus_error_init(&error);
305
306         if (dbus_set_error_from_message(&error, reply)) {
307                 connman_error("SetProperty(Online) %s %s",
308                                 error.name, error.message);
309                 dbus_error_free(&error);
310
311                 result = modem->online;
312         } else
313                 result = modem->requested_online;
314
315         if (modem->pending_online)
316                 update_modem_online(modem, result);
317
318         if (result == FALSE)
319                 remove_device_networks(modem->device);
320
321         dbus_message_unref(reply);
322
323         dbus_pending_call_unref(call);
324 }
325
326 static int modem_change_online(char const *path, dbus_bool_t online)
327 {
328         struct modem_data *modem = g_hash_table_lookup(modem_hash, path);
329
330         if (modem == NULL)
331                 return -ENODEV;
332
333         if (modem->online == online)
334                 return -EALREADY;
335
336         modem->requested_online = online;
337
338         return set_property(path, OFONO_MODEM_INTERFACE, "Online",
339                                 DBUS_TYPE_BOOLEAN, &online,
340                                 set_online_reply,
341                                 (void *)g_strdup(path), g_free);
342 }
343
344 static int modem_enable(struct connman_device *device)
345 {
346         const char *path = connman_device_get_string(device, "Path");
347
348         DBG("device %p, path, %s", device, path);
349
350         return modem_change_online(path, TRUE);
351 }
352
353 static int modem_disable(struct connman_device *device)
354 {
355         const char *path = connman_device_get_string(device, "Path");
356
357         DBG("device %p path %s", device, path);
358
359         return modem_change_online(path, FALSE);
360 }
361
362 static struct connman_device_driver modem_driver = {
363         .name           = "modem",
364         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
365         .probe          = modem_probe,
366         .remove         = modem_remove,
367         .enable         = modem_enable,
368         .disable        = modem_disable,
369 };
370
371 static void modem_remove_device(struct modem_data *modem)
372 {
373         DBG("modem %p path %s device %p", modem, modem->path, modem->device);
374
375         if (modem->device == NULL)
376                 return;
377
378         remove_device_networks(modem->device);
379
380         connman_device_unregister(modem->device);
381         connman_device_unref(modem->device);
382
383         modem->device = NULL;
384 }
385
386 static void remove_modem(gpointer data)
387 {
388         struct modem_data *modem = data;
389
390         modem_remove_device(modem);
391
392         g_free(modem->path);
393         g_free(modem->operator);
394
395         g_free(modem);
396 }
397
398 static void remove_network(gpointer data)
399 {
400         struct network_info *info = data;
401         struct connman_device *device;
402
403         device = connman_network_get_device(info->network);
404         if (device != NULL)
405                 connman_device_remove_network(device, info->network);
406
407         connman_network_unref(info->network);
408
409         g_free(info);
410 }
411
412 static char *get_ident(const char *path)
413 {
414         char *pos;
415
416         if (*path != '/')
417                 return NULL;
418
419         pos = strrchr(path, '/');
420         if (pos == NULL)
421                 return NULL;
422
423         return pos + 1;
424 }
425
426 static void create_service(struct connman_network *network)
427 {
428         const char *path;
429         char *group;
430
431         DBG("");
432
433         path = connman_network_get_string(network, "Path");
434
435         group = get_ident(path);
436
437         connman_network_set_group(network, group);
438 }
439
440 static int network_probe(struct connman_network *network)
441 {
442         return 0;
443 }
444
445 static gboolean pending_network_is_available(struct connman_network *network)
446 {
447         /* Modem or network may be removed */
448         if (network == NULL || connman_network_get_device(network) == NULL) {
449                 DBG("Modem or network was removed");
450                 return FALSE;
451         }
452
453         return TRUE;
454 }
455
456 static void set_connected(struct network_info *info,
457                                 connman_bool_t connected)
458 {
459         gboolean setip = FALSE;
460
461         DBG("network %p connected %d", info->network, connected);
462
463         switch (info->ipv4_method) {
464         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
465         case CONNMAN_IPCONFIG_METHOD_OFF:
466         case CONNMAN_IPCONFIG_METHOD_MANUAL:
467         case CONNMAN_IPCONFIG_METHOD_AUTO:
468                 break;
469
470         case CONNMAN_IPCONFIG_METHOD_FIXED:
471                 connman_network_set_ipv4_method(info->network,
472                                                         info->ipv4_method);
473                 connman_network_set_ipaddress(info->network,
474                                                         &info->ipv4_address);
475                 setip = TRUE;
476                 break;
477
478         case CONNMAN_IPCONFIG_METHOD_DHCP:
479                 connman_network_set_ipv4_method(info->network,
480                                                         info->ipv4_method);
481                 setip = TRUE;
482                 break;
483         }
484
485         switch (info->ipv6_method) {
486         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
487         case CONNMAN_IPCONFIG_METHOD_OFF:
488         case CONNMAN_IPCONFIG_METHOD_MANUAL:
489         case CONNMAN_IPCONFIG_METHOD_DHCP:
490         case CONNMAN_IPCONFIG_METHOD_AUTO:
491                 break;
492
493         case CONNMAN_IPCONFIG_METHOD_FIXED:
494                 connman_network_set_ipv6_method(info->network,
495                                                         info->ipv6_method);
496                 connman_network_set_ipaddress(info->network,
497                                                         &info->ipv6_address);
498                 setip = TRUE;
499                 break;
500         }
501
502         if (setip == TRUE)
503                 connman_network_set_connected(info->network, connected);
504 }
505
506 static void set_active_reply(DBusPendingCall *call, void *user_data)
507 {
508         char const *path = user_data;
509         DBusMessage *reply;
510         DBusError error;
511         struct network_info *info;
512
513         info = g_hash_table_lookup(network_hash, path);
514
515         reply = dbus_pending_call_steal_reply(call);
516
517         if (info == NULL)
518                 goto done;
519
520         DBG("path %s network %p", path, info->network);
521
522         if (!pending_network_is_available(info->network))
523                 goto done;
524
525         dbus_error_init(&error);
526
527         if (dbus_set_error_from_message(&error, reply)) {
528                 connman_error("SetProperty(Active) %s %s",
529                                 error.name, error.message);
530
531                 connman_network_set_error(info->network,
532                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
533
534                 dbus_error_free(&error);
535         }
536
537 done:
538         dbus_message_unref(reply);
539
540         dbus_pending_call_unref(call);
541 }
542
543 static int set_network_active(struct connman_network *network)
544 {
545         dbus_bool_t value = TRUE;
546         const char *path = connman_network_get_string(network, "Path");
547
548         DBG("network %p, path %s", network, path);
549
550         return set_property(path, OFONO_CONTEXT_INTERFACE,
551                                 "Active", DBUS_TYPE_BOOLEAN, &value,
552                                 set_active_reply, g_strdup(path), g_free);
553 }
554
555 static int set_network_inactive(struct connman_network *network)
556 {
557         int err;
558         dbus_bool_t value = FALSE;
559         const char *path = connman_network_get_string(network, "Path");
560
561         DBG("network %p, path %s", network, path);
562
563         err = set_property(path, OFONO_CONTEXT_INTERFACE,
564                                 "Active", DBUS_TYPE_BOOLEAN, &value,
565                                 NULL, NULL, NULL);
566
567         if (err == -EINPROGRESS)
568                 err = 0;
569
570         return err;
571 }
572
573 static int network_connect(struct connman_network *network)
574 {
575         struct connman_device *device;
576         struct modem_data *modem;
577
578         DBG("network %p", network);
579
580         device = connman_network_get_device(network);
581         if (device == NULL)
582                 return -ENODEV;
583
584         modem = connman_device_get_data(device);
585         if (modem == NULL)
586                 return -ENODEV;
587
588         if (modem->registered == FALSE)
589                 return -ENOLINK;
590
591         if (modem->powered == FALSE)
592                 return -ENOLINK;
593
594         if (modem->roaming_allowed == FALSE && modem->roaming == TRUE)
595                 return -ENOLINK;
596
597         return set_network_active(network);
598 }
599
600 static int network_disconnect(struct connman_network *network)
601 {
602         DBG("network %p", network);
603
604         if (connman_network_get_index(network) < 0)
605                 return -ENOTCONN;
606
607         connman_network_set_associating(network, FALSE);
608
609         return set_network_inactive(network);
610 }
611
612 static void network_remove(struct connman_network *network)
613 {
614         char const *path = connman_network_get_string(network, "Path");
615
616         DBG("network %p path %s", network, path);
617
618         g_hash_table_remove(network_hash, path);
619 }
620
621 static struct connman_network_driver network_driver = {
622         .name           = "network",
623         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
624         .probe          = network_probe,
625         .remove         = network_remove,
626         .connect        = network_connect,
627         .disconnect     = network_disconnect,
628 };
629
630 static void get_dns(DBusMessageIter *array, struct network_info *info)
631 {
632         DBusMessageIter entry;
633         gchar *nameservers = NULL, *nameservers_old = NULL;
634
635         DBG("");
636
637
638         dbus_message_iter_recurse(array, &entry);
639
640         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
641                 const char *dns;
642
643                 dbus_message_iter_get_basic(&entry, &dns);
644
645                 DBG("dns %s", dns);
646
647                 if (nameservers == NULL) {
648
649                         nameservers = g_strdup(dns);
650                 } else {
651
652                         nameservers_old = nameservers;
653                         nameservers = g_strdup_printf("%s %s",
654                                                 nameservers_old, dns);
655                         g_free(nameservers_old);
656                 }
657
658                 dbus_message_iter_next(&entry);
659         }
660
661         connman_network_set_nameservers(info->network, nameservers);
662
663         g_free(nameservers);
664 }
665
666 static void update_ipv4_settings(DBusMessageIter *array,
667                                 struct network_info *info)
668 {
669         DBusMessageIter dict;
670         char *address = NULL, *netmask = NULL, *gateway = NULL;
671         const char *interface = NULL;
672
673         DBG("network %p", info->network);
674
675         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
676                 return;
677
678         dbus_message_iter_recurse(array, &dict);
679
680         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
681                 DBusMessageIter entry, value;
682                 const char *key, *val;
683
684                 dbus_message_iter_recurse(&dict, &entry);
685                 dbus_message_iter_get_basic(&entry, &key);
686
687                 DBG("key %s", key);
688
689                 dbus_message_iter_next(&entry);
690                 dbus_message_iter_recurse(&entry, &value);
691
692                 if (g_str_equal(key, "Interface") == TRUE) {
693                         int index;
694
695                         dbus_message_iter_get_basic(&value, &interface);
696
697                         DBG("interface %s", interface);
698
699                         index = connman_inet_ifindex(interface);
700                         if (index >= 0) {
701                                 connman_network_set_index(info->network, index);
702                         } else {
703                                 connman_error("Can not find interface %s",
704                                                                 interface);
705                                 break;
706                         }
707                 } else if (g_str_equal(key, "Method") == TRUE) {
708                         const char *method;
709
710                         dbus_message_iter_get_basic(&value, &method);
711
712                         if (g_strcmp0(method, "static") == 0) {
713
714                                 info->ipv4_method =
715                                         CONNMAN_IPCONFIG_METHOD_FIXED;
716                         } else if (g_strcmp0(method, "dhcp") == 0) {
717
718                                 info->ipv4_method =
719                                         CONNMAN_IPCONFIG_METHOD_DHCP;
720                                 break;
721                         }
722                 } else if (g_str_equal(key, "Address") == TRUE) {
723                         dbus_message_iter_get_basic(&value, &val);
724
725                         address = g_strdup(val);
726
727                         DBG("address %s", address);
728                 } else if (g_str_equal(key, "Netmask") == TRUE) {
729                         dbus_message_iter_get_basic(&value, &val);
730
731                         netmask = g_strdup(val);
732
733                         DBG("netmask %s", netmask);
734                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
735
736                         get_dns(&value, info);
737                 } else if (g_str_equal(key, "Gateway") == TRUE) {
738                         dbus_message_iter_get_basic(&value, &val);
739
740                         gateway = g_strdup(val);
741
742                         DBG("gateway %s", gateway);
743                 }
744
745                 dbus_message_iter_next(&dict);
746         }
747
748
749         if (info->ipv4_method == CONNMAN_IPCONFIG_METHOD_FIXED) {
750                 connman_ipaddress_set_ipv4(&info->ipv4_address, address,
751                                                 netmask, gateway);
752         }
753
754         g_free(address);
755         g_free(netmask);
756         g_free(gateway);
757 }
758
759 static void update_ipv6_settings(DBusMessageIter *array,
760                                 struct network_info *info)
761 {
762         DBusMessageIter dict;
763         char *address = NULL, *gateway = NULL;
764         unsigned char prefix_length;
765         const char *interface = NULL;
766
767         DBG("network %p", info->network);
768
769         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
770                 return;
771
772         dbus_message_iter_recurse(array, &dict);
773
774         info->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED;
775
776         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
777                 DBusMessageIter entry, value;
778                 const char *key, *val;
779
780                 dbus_message_iter_recurse(&dict, &entry);
781                 dbus_message_iter_get_basic(&entry, &key);
782
783                 DBG("key %s", key);
784
785                 dbus_message_iter_next(&entry);
786                 dbus_message_iter_recurse(&entry, &value);
787
788                 if (g_str_equal(key, "Interface") == TRUE) {
789                         int index;
790
791                         dbus_message_iter_get_basic(&value, &interface);
792
793                         DBG("interface %s", interface);
794
795                         index = connman_inet_ifindex(interface);
796                         if (index >= 0) {
797                                 connman_network_set_index(info->network, index);
798                         } else {
799                                 connman_error("Can not find interface %s",
800                                                                 interface);
801                                 break;
802                         }
803                 } else if (g_str_equal(key, "Address") == TRUE) {
804                         dbus_message_iter_get_basic(&value, &val);
805
806                         address = g_strdup(val);
807
808                         DBG("address %s", address);
809                 } else if (g_str_equal(key, "PrefixLength") == TRUE) {
810                         dbus_message_iter_get_basic(&value, &prefix_length);
811
812                         DBG("prefix length %d", prefix_length);
813                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
814
815                         get_dns(&value, info);
816                 } else if (g_str_equal(key, "Gateway") == TRUE) {
817                         dbus_message_iter_get_basic(&value, &val);
818
819                         gateway = g_strdup(val);
820
821                         DBG("gateway %s", gateway);
822                 }
823
824                 dbus_message_iter_next(&dict);
825         }
826
827         connman_ipaddress_set_ipv6(&info->ipv6_address, address,
828                                                 prefix_length, gateway);
829
830         g_free(address);
831         g_free(gateway);
832 }
833
834 static int add_network(struct connman_device *device,
835                         const char *path, DBusMessageIter *dict)
836 {
837         struct modem_data *modem = connman_device_get_data(device);
838         struct connman_network *network;
839         struct network_info *info;
840         char *ident;
841         dbus_bool_t active = FALSE;
842
843         DBG("modem %p device %p path %s", modem, device, path);
844
845         ident = get_ident(path);
846
847         network = connman_device_get_network(device, ident);
848         if (network != NULL)
849                 return -EALREADY;
850
851         info = g_hash_table_lookup(network_hash, path);
852         if (info != NULL) {
853                 DBG("path %p already exists with device %p", path,
854                         connman_network_get_device(info->network));
855                 if (connman_network_get_device(info->network))
856                         return -EALREADY;
857                 g_hash_table_remove(network_hash, path);
858         }
859
860         network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR);
861         if (network == NULL)
862                 return -ENOMEM;
863
864         info = g_try_new0(struct network_info, 1);
865         if (info == NULL) {
866                 connman_network_unref(network);
867                 return -ENOMEM;
868         }
869
870         connman_ipaddress_clear(&info->ipv4_address);
871         connman_ipaddress_clear(&info->ipv6_address);
872         info->network = network;
873
874         connman_network_set_string(network, "Path", path);
875
876         create_service(network);
877
878         g_hash_table_insert(network_hash, g_strdup(path), info);
879
880         connman_network_set_available(network, TRUE);
881         connman_network_set_index(network, -1);
882
883         if (modem->operator)
884                 connman_network_set_name(network, modem->operator);
885         else
886                 connman_network_set_name(network, "");
887
888         if (modem->has_strength)
889                 connman_network_set_strength(network, modem->strength);
890
891         connman_network_set_roaming(network, modem->roaming);
892
893         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
894                 DBusMessageIter entry, value;
895                 const char *key;
896
897                 dbus_message_iter_recurse(dict, &entry);
898                 dbus_message_iter_get_basic(&entry, &key);
899
900                 dbus_message_iter_next(&entry);
901                 dbus_message_iter_recurse(&entry, &value);
902
903                 if (g_str_equal(key, "Type")) {
904                         const char *type;
905
906                         dbus_message_iter_get_basic(&value, &type);
907                         if (g_strcmp0(type, "internet") != 0) {
908                                 DBG("path %p type %s", path, type);
909                                 g_hash_table_remove(network_hash, path);
910                                 return -EIO;
911                         }
912                 } else if (g_str_equal(key, "Settings"))
913                         update_ipv4_settings(&value, info);
914                 else if (g_str_equal(key, "IPv6.Settings"))
915                         update_ipv6_settings(&value, info);
916                 else if (g_str_equal(key, "Active") == TRUE)
917                         dbus_message_iter_get_basic(&value, &active);
918
919                 dbus_message_iter_next(dict);
920         }
921
922         if (connman_device_add_network(device, network) != 0) {
923                 g_hash_table_remove(network_hash, path);
924                 return -EIO;
925         }
926
927         /* Connect only if requested to do so */
928         if (active && connman_network_get_connecting(network) == TRUE)
929                 set_connected(info, active);
930
931         return 0;
932 }
933
934 static void check_networks_reply(DBusPendingCall *call, void *user_data)
935 {
936         char *path = user_data;
937         struct modem_data *modem;
938         DBusMessage *reply;
939         DBusMessageIter array, entry, value, properties;
940
941         DBG("path %s", path);
942
943         modem = g_hash_table_lookup(modem_hash, path);
944         if (modem == NULL)
945                 return;
946         if (modem->device == NULL)
947                 return;
948
949         reply = dbus_pending_call_steal_reply(call);
950
951         if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
952                 goto done;
953
954         dbus_message_iter_init(reply, &array);
955
956         dbus_message_iter_recurse(&array, &entry);
957
958         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
959                 char const *network_path;
960
961                 dbus_message_iter_recurse(&entry, &value);
962                 dbus_message_iter_get_basic(&value, &network_path);
963
964                 dbus_message_iter_next(&value);
965                 dbus_message_iter_recurse(&value, &properties);
966
967                 add_network(modem->device, network_path, &properties);
968
969                 dbus_message_iter_next(&entry);
970         }
971
972 done:
973         dbus_message_unref(reply);
974
975         dbus_pending_call_unref(call);
976 }
977
978 static void check_networks(struct modem_data *modem)
979 {
980         char const *path = modem->path;
981
982         DBG("modem %p path %s", modem, path);
983
984         call_ofono(path, OFONO_GPRS_INTERFACE, "GetContexts",
985                         check_networks_reply, g_strdup(path), g_free,
986                         DBUS_TYPE_INVALID);
987 }
988
989 static void modem_clear_network_errors(struct modem_data *modem)
990 {
991         struct connman_device *device = modem->device;
992         GHashTableIter i;
993         gpointer value;
994
995         if (device == NULL)
996                 return;
997
998         g_hash_table_iter_init(&i, network_hash);
999
1000         while (g_hash_table_iter_next(&i, NULL, &value)) {
1001                 struct network_info *info = value;
1002
1003                 if (connman_network_get_device(info->network) == device)
1004                         connman_network_clear_error(info->network);
1005         }
1006 }
1007
1008 static void modem_operator_name_changed(struct modem_data *modem,
1009                                         char const *name)
1010 {
1011         struct connman_device *device = modem->device;
1012         GHashTableIter i;
1013         gpointer value;
1014
1015         if (device == NULL)
1016                 return;
1017
1018         if (modem->operator != NULL)
1019                 g_free(modem->operator);
1020         modem->operator = g_strdup(name);
1021
1022         for (g_hash_table_iter_init(&i, network_hash);
1023              g_hash_table_iter_next(&i, NULL, &value);) {
1024                 struct network_info *info = value;
1025
1026                 if (connman_network_get_device(info->network) == device) {
1027                         connman_network_set_name(info->network, name);
1028                         connman_network_update(info->network);
1029                 }
1030         }
1031 }
1032
1033 static void modem_strength_changed(struct modem_data *modem, uint8_t strength)
1034 {
1035         struct connman_device *device = modem->device;
1036         GHashTableIter i;
1037         gpointer value;
1038
1039         modem->strength = strength;
1040         modem->has_strength = TRUE;
1041
1042         if (device == NULL)
1043                 return;
1044
1045         for (g_hash_table_iter_init(&i, network_hash);
1046              g_hash_table_iter_next(&i, NULL, &value);) {
1047                 struct network_info *info = value;
1048
1049                 if (connman_network_get_device(info->network) == device) {
1050                         connman_network_set_strength(info->network, strength);
1051                         connman_network_update(info->network);
1052                 }
1053         }
1054 }
1055
1056 static void modem_roaming_changed(struct modem_data *modem,
1057                                         char const *status)
1058 {
1059         struct connman_device *device = modem->device;
1060         connman_bool_t roaming = FALSE;
1061         connman_bool_t registered = FALSE;
1062         connman_bool_t was_roaming = modem->roaming;
1063         GHashTableIter i;
1064         gpointer value;
1065
1066         if (g_str_equal(status, "roaming"))
1067                 roaming = TRUE;
1068         else if (g_str_equal(status, "registered"))
1069                 registered = TRUE;
1070
1071         registered = registered || roaming;
1072
1073         if (modem->roaming == roaming && modem->registered == registered)
1074                 return;
1075
1076         modem->registered = registered;
1077         modem->roaming = roaming;
1078
1079         if (roaming == was_roaming)
1080                 return;
1081
1082         if (device == NULL)
1083                 return;
1084
1085         g_hash_table_iter_init(&i, network_hash);
1086
1087         while (g_hash_table_iter_next(&i, NULL, &value)) {
1088                 struct network_info *info = value;
1089
1090                 if (connman_network_get_device(info->network) == device) {
1091                         connman_network_set_roaming(info->network, roaming);
1092                         connman_network_update(info->network);
1093                 }
1094         }
1095 }
1096
1097 static void modem_registration_removed(struct modem_data *modem)
1098 {
1099         modem->registered = FALSE;
1100         modem->roaming = FALSE;
1101 }
1102
1103 static void modem_registration_changed(struct modem_data *modem,
1104                                         DBusMessageIter *entry)
1105 {
1106         DBusMessageIter iter;
1107         const char *key;
1108         int type;
1109         connman_uint8_t strength;
1110         char const *name, *status, *mcc_s;
1111
1112         dbus_message_iter_get_basic(entry, &key);
1113
1114         DBG("key %s", key);
1115
1116         dbus_message_iter_next(entry);
1117
1118         dbus_message_iter_recurse(entry, &iter);
1119
1120         type = dbus_message_iter_get_arg_type(&iter);
1121         if (type != DBUS_TYPE_BYTE && type != DBUS_TYPE_STRING)
1122                 return;
1123
1124         if (g_str_equal(key, "Name") && type == DBUS_TYPE_STRING) {
1125                 dbus_message_iter_get_basic(&iter, &name);
1126                 modem_operator_name_changed(modem, name);
1127         } else if (g_str_equal(key, "Strength") && type == DBUS_TYPE_BYTE) {
1128                 dbus_message_iter_get_basic(&iter, &strength);
1129                 modem_strength_changed(modem, strength);
1130         } else if (g_str_equal(key, "Status") && type == DBUS_TYPE_STRING) {
1131                 dbus_message_iter_get_basic(&iter, &status);
1132                 modem_roaming_changed(modem, status);
1133         } else if (g_str_equal(key, "MobileCountryCode") &&
1134                                         type == DBUS_TYPE_STRING) {
1135                 int mcc;
1136                 char *alpha2;
1137
1138                 dbus_message_iter_get_basic(&iter, &mcc_s);
1139
1140                 mcc = atoi(mcc_s);
1141                 if (mcc > 799)
1142                         return;
1143
1144                 alpha2 = mcc_country_codes[mcc - 200];
1145                 connman_technology_set_regdom(alpha2);
1146         }
1147
1148 }
1149
1150 static gboolean reg_changed(DBusConnection *connection,
1151                                 DBusMessage *message, void *user_data)
1152 {
1153         const char *path = dbus_message_get_path(message);
1154         struct modem_data *modem;
1155         DBusMessageIter iter;
1156
1157         DBG("path %s", path);
1158
1159         modem = g_hash_table_lookup(modem_hash, path);
1160         if (modem == NULL)
1161                 return TRUE;
1162
1163         if (dbus_message_iter_init(message, &iter))
1164                 modem_registration_changed(modem, &iter);
1165
1166         return TRUE;
1167 }
1168
1169 static void check_registration_reply(DBusPendingCall *call, void *user_data)
1170 {
1171         char const *path = user_data;
1172         struct modem_data *modem;
1173         DBusMessage *reply;
1174         DBusMessageIter array, dict, entry;
1175
1176         DBG("path %s", path);
1177
1178         modem = g_hash_table_lookup(modem_hash, path);
1179         if (modem == NULL)
1180                 return;
1181
1182         reply = dbus_pending_call_steal_reply(call);
1183
1184         if (dbus_message_iter_init(reply, &array) == FALSE)
1185                 goto done;
1186
1187         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1188                 goto done;
1189
1190         dbus_message_iter_recurse(&array, &dict);
1191         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1192                 dbus_message_iter_recurse(&dict, &entry);
1193                 modem_registration_changed(modem, &entry);
1194                 dbus_message_iter_next(&dict);
1195         }
1196
1197 done:
1198         dbus_message_unref(reply);
1199
1200         dbus_pending_call_unref(call);
1201 }
1202
1203 static void check_registration(struct modem_data *modem)
1204 {
1205         char const *path = modem->path;
1206
1207         DBG("modem %p path %s", modem, path);
1208
1209         call_ofono(path, OFONO_REGISTRATION_INTERFACE, GET_PROPERTIES,
1210                         check_registration_reply, g_strdup(path), g_free,
1211                         DBUS_TYPE_INVALID);
1212 }
1213
1214 static void modem_gprs_changed(struct modem_data *modem,
1215                                         DBusMessageIter *entry)
1216 {
1217         DBusMessageIter iter;
1218         const char *key;
1219         int type;
1220         dbus_bool_t value;
1221
1222         dbus_message_iter_get_basic(entry, &key);
1223
1224         DBG("key %s", key);
1225
1226         dbus_message_iter_next(entry);
1227
1228         dbus_message_iter_recurse(entry, &iter);
1229
1230         type = dbus_message_iter_get_arg_type(&iter);
1231
1232         if (type != DBUS_TYPE_BOOLEAN)
1233                 return;
1234
1235         dbus_message_iter_get_basic(&iter, &value);
1236
1237         if (g_str_equal(key, "Attached") == TRUE) {
1238                 DBG("Attached %d", value);
1239
1240                 if (modem->attached == value)
1241                         return;
1242
1243                 modem->attached = value;
1244
1245                 if (value == TRUE) {
1246                         modem_clear_network_errors(modem);
1247                         check_networks(modem);
1248                 }
1249         } else if (g_str_equal(key, "Powered") == TRUE) {
1250                 DBG("Powered %d", value);
1251
1252                 modem->powered = value;
1253         } else if (g_str_equal(key, "RoamingAllowed") == TRUE) {
1254                 DBG("RoamingAllowed %d", value);
1255
1256                 modem->roaming_allowed = value;
1257         }
1258 }
1259
1260 static void check_gprs_reply(DBusPendingCall *call, void *user_data)
1261 {
1262         char const *path = user_data;
1263         struct modem_data *modem;
1264         DBusMessage *reply;
1265         DBusMessageIter array, dict, entry;
1266
1267         DBG("path %s", path);
1268
1269         modem = g_hash_table_lookup(modem_hash, path);
1270         if (modem == NULL)
1271                 return;
1272
1273         reply = dbus_pending_call_steal_reply(call);
1274
1275         if (dbus_message_iter_init(reply, &array) == FALSE)
1276                 goto done;
1277
1278         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1279                 goto done;
1280
1281         dbus_message_iter_recurse(&array, &dict);
1282         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1283                 dbus_message_iter_recurse(&dict, &entry);
1284                 modem_gprs_changed(modem, &entry);
1285                 dbus_message_iter_next(&dict);
1286         }
1287
1288 done:
1289         dbus_message_unref(reply);
1290
1291         dbus_pending_call_unref(call);
1292
1293 }
1294
1295 static void check_gprs(struct modem_data *modem)
1296 {
1297         char const *path = modem->path;
1298
1299         DBG("modem %p path %s", modem, path);
1300
1301         call_ofono(path, OFONO_GPRS_INTERFACE, GET_PROPERTIES,
1302                         check_gprs_reply, g_strdup(path), g_free,
1303                         DBUS_TYPE_INVALID);
1304 }
1305
1306 static void add_device(const char *path, const char *imsi)
1307 {
1308         struct modem_data *modem;
1309         struct connman_device *device;
1310
1311         DBG("path %s imsi %s", path, imsi);
1312
1313         if (path == NULL)
1314                 return;
1315
1316         if (imsi == NULL)
1317                 return;
1318
1319         modem = g_hash_table_lookup(modem_hash, path);
1320         if (modem == NULL)
1321                 return;
1322
1323         if (modem->device) {
1324                 if (!g_strcmp0(imsi, connman_device_get_ident(modem->device)))
1325                         return;
1326
1327                 modem_remove_device(modem);
1328         }
1329
1330         if (strlen(imsi) == 0)
1331                 return;
1332
1333         device = connman_device_create(imsi, CONNMAN_DEVICE_TYPE_CELLULAR);
1334         if (device == NULL)
1335                 return;
1336
1337         connman_device_set_ident(device, imsi);
1338
1339         connman_device_set_string(device, "Path", path);
1340
1341         connman_device_set_data(device, modem);
1342
1343         if (connman_device_register(device) < 0) {
1344                 connman_device_unref(device);
1345                 return;
1346         }
1347
1348         modem->device = device;
1349
1350         if (modem->has_reg)
1351                 check_registration(modem);
1352
1353         if (modem->has_gprs)
1354                 check_gprs(modem);
1355 }
1356
1357 static void sim_properties_reply(DBusPendingCall *call, void *user_data)
1358 {
1359         const char *path = user_data;
1360         const char *imsi = NULL;
1361         DBusMessage *reply;
1362         DBusMessageIter array, dict;
1363
1364         DBG("path %s", path);
1365
1366         reply = dbus_pending_call_steal_reply(call);
1367
1368         if (dbus_message_iter_init(reply, &array) == FALSE)
1369                 goto done;
1370
1371         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1372                 goto done;
1373
1374         dbus_message_iter_recurse(&array, &dict);
1375
1376         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1377                 DBusMessageIter entry, value;
1378                 const char *key;
1379
1380                 dbus_message_iter_recurse(&dict, &entry);
1381                 dbus_message_iter_get_basic(&entry, &key);
1382
1383                 dbus_message_iter_next(&entry);
1384                 dbus_message_iter_recurse(&entry, &value);
1385
1386                 if (g_str_equal(key, "SubscriberIdentity")) {
1387                         dbus_message_iter_get_basic(&value, &imsi);
1388                         add_device(path, imsi);
1389                 }
1390
1391                 dbus_message_iter_next(&dict);
1392         }
1393
1394 done:
1395         dbus_message_unref(reply);
1396
1397         dbus_pending_call_unref(call);
1398 }
1399
1400 static void get_imsi(const char *path)
1401 {
1402         DBG("path %s", path);
1403
1404         call_ofono(path, OFONO_SIM_INTERFACE, GET_PROPERTIES,
1405                         sim_properties_reply, g_strdup(path), g_free,
1406                         DBUS_TYPE_INVALID);
1407 }
1408
1409 static int gprs_change_powered(const char *path, dbus_bool_t powered)
1410 {
1411         DBG("path %s powered %d", path, powered);
1412
1413         return set_property(path, OFONO_GPRS_INTERFACE, "Powered",
1414                                 DBUS_TYPE_BOOLEAN, &powered,
1415                                 NULL, NULL, NULL);
1416 }
1417
1418 static int modem_change_powered(const char *path, dbus_bool_t powered)
1419 {
1420         DBG("path %s powered %d", path, powered);
1421
1422         return set_property(path, OFONO_MODEM_INTERFACE, "Powered",
1423                                 DBUS_TYPE_BOOLEAN, &powered,
1424                                 NULL, NULL, NULL);
1425 }
1426
1427
1428 static gboolean modem_has_interface(DBusMessageIter *array,
1429                                         char const *interface)
1430 {
1431         DBusMessageIter entry;
1432
1433         dbus_message_iter_recurse(array, &entry);
1434
1435         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1436                 const char *element;
1437
1438                 dbus_message_iter_get_basic(&entry, &element);
1439
1440                 if (g_strcmp0(interface, element) == 0)
1441                         return TRUE;
1442
1443                 dbus_message_iter_next(&entry);
1444         }
1445
1446         return FALSE;
1447 }
1448
1449 static gboolean modem_has_sim(DBusMessageIter *array)
1450 {
1451         return modem_has_interface(array, OFONO_SIM_INTERFACE);
1452 }
1453
1454 static gboolean modem_has_reg(DBusMessageIter *array)
1455 {
1456         return modem_has_interface(array, OFONO_REGISTRATION_INTERFACE);
1457 }
1458
1459 static gboolean modem_has_gprs(DBusMessageIter *array)
1460 {
1461         return modem_has_interface(array, OFONO_GPRS_INTERFACE);
1462 }
1463
1464 static void add_modem(const char *path, DBusMessageIter *prop)
1465 {
1466         struct modem_data *modem;
1467         dbus_bool_t powered = FALSE;
1468         dbus_bool_t online = FALSE;
1469         dbus_bool_t locked = FALSE;
1470         gboolean has_sim = FALSE;
1471         gboolean has_reg = FALSE;
1472         gboolean has_gprs = FALSE;
1473
1474         modem = g_hash_table_lookup(modem_hash, path);
1475
1476         if (modem != NULL)
1477                 return;
1478
1479         modem = g_try_new0(struct modem_data, 1);
1480         if (modem == NULL)
1481                 return;
1482
1483         modem->path = g_strdup(path);
1484         modem->device = NULL;
1485         modem->available = TRUE;
1486
1487         g_hash_table_insert(modem_hash, g_strdup(path), modem);
1488
1489         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
1490                 DBusMessageIter entry, value;
1491                 const char *key;
1492
1493                 dbus_message_iter_recurse(prop, &entry);
1494                 dbus_message_iter_get_basic(&entry, &key);
1495
1496                 dbus_message_iter_next(&entry);
1497                 dbus_message_iter_recurse(&entry, &value);
1498
1499                 if (g_str_equal(key, "Powered") == TRUE)
1500                         dbus_message_iter_get_basic(&value, &powered);
1501                 else if (g_str_equal(key, "Lockdown") == TRUE)
1502                         dbus_message_iter_get_basic(&value, &locked);
1503                 else if (g_str_equal(key, "Interfaces") == TRUE) {
1504                         has_sim = modem_has_sim(&value);
1505                         has_reg = modem_has_reg(&value);
1506                         has_gprs = modem_has_gprs(&value);
1507                 }
1508
1509                 dbus_message_iter_next(prop);
1510         }
1511
1512         if (locked)
1513                 return;
1514
1515         if (!powered)
1516                 modem_change_powered(path, TRUE);
1517
1518         modem->has_sim = has_sim;
1519         modem->has_reg = has_reg;
1520         modem->has_gprs = has_gprs;
1521
1522         update_modem_online(modem, online);
1523
1524         if (has_sim)
1525                 get_imsi(path);
1526 }
1527
1528 static void manager_modems_reply(DBusPendingCall *call, void *user_data)
1529 {
1530         DBusMessage *reply;
1531         DBusError error;
1532         DBusMessageIter array, dict;
1533
1534         DBG("");
1535
1536         reply = dbus_pending_call_steal_reply(call);
1537
1538         if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
1539                 goto done;
1540
1541         dbus_error_init(&error);
1542
1543         if (dbus_set_error_from_message(&error, reply)) {
1544                 connman_error("ModemManager.GetModems() %s %s",
1545                                 error.name, error.message);
1546                 dbus_error_free(&error);
1547                 goto done;
1548         }
1549
1550         if (dbus_message_iter_init(reply, &array) == FALSE)
1551                 goto done;
1552
1553         dbus_message_iter_recurse(&array, &dict);
1554
1555         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
1556                 DBusMessageIter value, properties;
1557                 const char *modem_path;
1558
1559                 dbus_message_iter_recurse(&dict, &value);
1560                 dbus_message_iter_get_basic(&value, &modem_path);
1561
1562                 dbus_message_iter_next(&value);
1563                 dbus_message_iter_recurse(&value, &properties);
1564
1565                 /* Add modem */
1566                 add_modem(modem_path, &properties);
1567
1568                 dbus_message_iter_next(&dict);
1569         }
1570
1571 done:
1572         dbus_message_unref(reply);
1573
1574         dbus_pending_call_unref(call);
1575 }
1576
1577 static void ofono_connect(DBusConnection *connection, void *user_data)
1578 {
1579         DBG("connection %p", connection);
1580
1581         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1582                                                 g_free, remove_modem);
1583
1584         network_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1585                                                 g_free, remove_network);
1586
1587         call_ofono("/", OFONO_MANAGER_INTERFACE, GET_MODEMS,
1588                         manager_modems_reply, NULL, NULL,
1589                         DBUS_TYPE_INVALID);
1590 }
1591
1592 static void ofono_disconnect(DBusConnection *connection, void *user_data)
1593 {
1594         DBG("connection %p", connection);
1595
1596         if (modem_hash != NULL) {
1597                 g_hash_table_destroy(modem_hash);
1598                 modem_hash = NULL;
1599         }
1600
1601         if (network_hash != NULL) {
1602                 g_hash_table_destroy(network_hash);
1603                 network_hash = NULL;
1604         }
1605 }
1606
1607 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
1608                                 void *user_data)
1609 {
1610         const char *path = dbus_message_get_path(message);
1611         struct modem_data *modem;
1612         DBusMessageIter iter, value;
1613         const char *key;
1614
1615         DBG("path %s", path);
1616
1617         modem = g_hash_table_lookup(modem_hash, path);
1618         if (modem == NULL)
1619                 return TRUE;
1620
1621         if (dbus_message_iter_init(message, &iter) == FALSE)
1622                 return TRUE;
1623
1624         dbus_message_iter_get_basic(&iter, &key);
1625
1626         dbus_message_iter_next(&iter);
1627         dbus_message_iter_recurse(&iter, &value);
1628
1629         if (g_str_equal(key, "Powered") == TRUE) {
1630                 dbus_bool_t powered;
1631
1632                 dbus_message_iter_get_basic(&value, &powered);
1633                 if (powered == TRUE)
1634                         return TRUE;
1635
1636                 modem->has_sim = FALSE;
1637                 modem->has_reg = FALSE;
1638                 modem->has_gprs = FALSE;
1639
1640                 modem_remove_device(modem);
1641         } else if (g_str_equal(key, "Online") == TRUE) {
1642                 dbus_bool_t online;
1643
1644                 dbus_message_iter_get_basic(&value, &online);
1645
1646                 update_modem_online(modem, online);
1647         } else if (g_str_equal(key, "Lockdown") == TRUE) {
1648                 dbus_bool_t locked;
1649
1650                 dbus_message_iter_get_basic(&value, &locked);
1651
1652                 if (!locked)
1653                         modem_change_powered(path, TRUE);
1654
1655         } else if (g_str_equal(key, "Interfaces") == TRUE) {
1656                 gboolean has_sim = modem_has_sim(&value);
1657                 gboolean has_reg = modem_has_reg(&value);
1658                 gboolean had_reg = modem->has_reg;
1659                 gboolean has_gprs = modem_has_gprs(&value);
1660                 gboolean had_gprs = modem->has_gprs;
1661
1662                 modem->has_sim = has_sim;
1663                 modem->has_reg = has_reg;
1664                 modem->has_gprs = has_gprs;
1665
1666                 if (modem->device == NULL) {
1667                         if (has_sim)
1668                                 get_imsi(modem->path);
1669                 } else if (!has_sim) {
1670                         modem_remove_device(modem);
1671                 } else {
1672                         if (has_reg && !had_reg)
1673                                 check_registration(modem);
1674                         else if (had_reg && !has_reg)
1675                                 modem_registration_removed(modem);
1676
1677                         if (has_gprs && !had_gprs) {
1678                                 gprs_change_powered(modem->path, TRUE);
1679                                 check_gprs(modem);
1680                         }
1681                 }
1682         }
1683
1684         return TRUE;
1685 }
1686
1687 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
1688                                 void *user_data)
1689 {
1690         const char *path = dbus_message_get_path(message);
1691         struct modem_data *modem;
1692         DBusMessageIter iter, value;
1693         const char *key;
1694
1695         DBG("path %s", path);
1696
1697         modem = g_hash_table_lookup(modem_hash, path);
1698         if (modem == NULL)
1699                 return TRUE;
1700
1701         if (dbus_message_iter_init(message, &iter) == FALSE)
1702                 return TRUE;
1703
1704         dbus_message_iter_get_basic(&iter, &key);
1705
1706         dbus_message_iter_next(&iter);
1707         dbus_message_iter_recurse(&iter, &value);
1708
1709         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1710                 char *imsi;
1711
1712                 dbus_message_iter_get_basic(&value, &imsi);
1713
1714                 add_device(path, imsi);
1715         } else if (g_str_equal(key, "Present") == TRUE) {
1716                 dbus_bool_t present;
1717
1718                 dbus_message_iter_get_basic(&value, &present);
1719
1720                 if (present)
1721                         return TRUE;
1722
1723                 if (modem->device != NULL)
1724                         modem_remove_device(modem);
1725
1726                 modem->has_gprs = FALSE;
1727                 modem->has_reg = FALSE;
1728         }
1729
1730         return TRUE;
1731 }
1732
1733 static gboolean gprs_changed(DBusConnection *connection, DBusMessage *message,
1734                                 void *user_data)
1735 {
1736         const char *path = dbus_message_get_path(message);
1737         struct modem_data *modem;
1738         DBusMessageIter iter;
1739
1740         DBG("path %s", path);
1741
1742         modem = g_hash_table_lookup(modem_hash, path);
1743         if (modem == NULL)
1744                 return TRUE;
1745
1746         if (dbus_message_iter_init(message, &iter))
1747                 modem_gprs_changed(modem, &iter);
1748
1749         return TRUE;
1750 }
1751
1752 static gboolean context_added(DBusConnection *connection,
1753                                 DBusMessage *message, void *user_data)
1754 {
1755         const char *path = dbus_message_get_path(message);
1756         const char *network_path;
1757         struct modem_data *modem;
1758         DBusMessageIter iter, properties;
1759
1760         DBG("path %s", path);
1761
1762         modem = g_hash_table_lookup(modem_hash, path);
1763         if (modem == NULL || modem->device == NULL)
1764                 return TRUE;
1765
1766         /* Create the related network only when we are attached */
1767         if (modem->attached == FALSE)
1768                 return TRUE;
1769
1770         if (dbus_message_iter_init(message, &iter) == FALSE)
1771                 return TRUE;
1772
1773         dbus_message_iter_get_basic(&iter, &network_path);
1774
1775         dbus_message_iter_next(&iter);
1776         dbus_message_iter_recurse(&iter, &properties);
1777
1778         add_network(modem->device, network_path, &properties);
1779
1780         return TRUE;
1781 }
1782
1783 static gboolean context_removed(DBusConnection *connection,
1784                                 DBusMessage *message, void *user_data)
1785 {
1786         const char *path = dbus_message_get_path(message);
1787         const char *network_path;
1788         struct modem_data *modem;
1789         DBusMessageIter iter;
1790
1791         DBG("path %s", path);
1792
1793         modem = g_hash_table_lookup(modem_hash, path);
1794         if (modem == NULL || modem->device == NULL)
1795                 return TRUE;
1796
1797         if (dbus_message_iter_init(message, &iter) == FALSE)
1798                 return TRUE;
1799
1800         dbus_message_iter_get_basic(&iter, &network_path);
1801
1802         g_hash_table_remove(network_hash, network_path);
1803         return TRUE;
1804 }
1805
1806 static gboolean modem_added(DBusConnection *connection,
1807                                 DBusMessage *message, void *user_data)
1808 {
1809         DBusMessageIter iter, properties;
1810         const char *modem_path;
1811
1812         DBG("");
1813
1814         if (dbus_message_iter_init(message, &iter) == FALSE)
1815                 return TRUE;
1816
1817         dbus_message_iter_get_basic(&iter, &modem_path);
1818
1819         dbus_message_iter_next(&iter);
1820         dbus_message_iter_recurse(&iter, &properties);
1821
1822         add_modem(modem_path, &properties);
1823
1824         return TRUE;
1825 }
1826
1827 static gboolean modem_removed(DBusConnection *connection,
1828                                 DBusMessage *message, void *user_data)
1829 {
1830         DBusMessageIter iter;
1831         const char *modem_path;
1832
1833         DBG("");
1834
1835         if (dbus_message_iter_init(message, &iter) == FALSE)
1836                 return TRUE;
1837
1838         dbus_message_iter_get_basic(&iter, &modem_path);
1839
1840         g_hash_table_remove(modem_hash, modem_path);
1841
1842         return TRUE;
1843 }
1844
1845 static gboolean context_changed(DBusConnection *connection,
1846                                         DBusMessage *message, void *user_data)
1847 {
1848         const char *path = dbus_message_get_path(message);
1849         struct network_info *info;
1850         DBusMessageIter iter, value;
1851         const char *key;
1852
1853         DBG("path %s", path);
1854
1855         info = g_hash_table_lookup(network_hash, path);
1856         if (info == NULL)
1857                 return TRUE;
1858
1859         if (!pending_network_is_available(info->network)) {
1860                 g_hash_table_remove(network_hash, path);
1861                 return TRUE;
1862         }
1863
1864         if (dbus_message_iter_init(message, &iter) == FALSE)
1865                 return TRUE;
1866
1867         dbus_message_iter_get_basic(&iter, &key);
1868
1869         dbus_message_iter_next(&iter);
1870         dbus_message_iter_recurse(&iter, &value);
1871
1872         DBG("key %s", key);
1873
1874         if (g_str_equal(key, "Settings") == TRUE)
1875                 update_ipv4_settings(&value, info);
1876         else if (g_str_equal(key, "IPv6.Settings"))
1877                         update_ipv6_settings(&value, info);
1878         else if (g_str_equal(key, "Active") == TRUE) {
1879                 dbus_bool_t active;
1880
1881                 dbus_message_iter_get_basic(&value, &active);
1882
1883                 if (active == FALSE)
1884                         set_connected(info, active);
1885                 else if (connman_network_get_connecting(info->network) == TRUE)
1886                         /* Connect only if requested to do so */
1887                         set_connected(info, active);
1888         }
1889
1890         return TRUE;
1891 }
1892
1893 static guint watch;
1894 static guint reg_watch;
1895 static guint sim_watch;
1896 static guint gprs_watch;
1897 static guint context_added_watch;
1898 static guint context_removed_watch;
1899 static guint modem_watch;
1900 static guint modem_added_watch;
1901 static guint modem_removed_watch;
1902 static guint context_watch;
1903
1904 static int ofono_init(void)
1905 {
1906         int err;
1907
1908         connection = connman_dbus_get_connection();
1909         if (connection == NULL)
1910                 return -EIO;
1911
1912         watch = g_dbus_add_service_watch(connection, OFONO_SERVICE,
1913                         ofono_connect, ofono_disconnect, NULL, NULL);
1914
1915         reg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1916                                                 OFONO_REGISTRATION_INTERFACE,
1917                                                 PROPERTY_CHANGED,
1918                                                 reg_changed,
1919                                                 NULL, NULL);
1920
1921         gprs_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1922                                                 OFONO_GPRS_INTERFACE,
1923                                                 PROPERTY_CHANGED,
1924                                                 gprs_changed,
1925                                                 NULL, NULL);
1926
1927         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1928                                                 OFONO_GPRS_INTERFACE,
1929                                                 CONTEXT_ADDED,
1930                                                 context_added,
1931                                                 NULL, NULL);
1932
1933         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1934                                                 OFONO_GPRS_INTERFACE,
1935                                                 CONTEXT_REMOVED,
1936                                                 context_removed,
1937                                                 NULL, NULL);
1938
1939         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1940                                                 OFONO_MODEM_INTERFACE,
1941                                                 PROPERTY_CHANGED,
1942                                                 modem_changed,
1943                                                 NULL, NULL);
1944
1945         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1946                                                 OFONO_SIM_INTERFACE,
1947                                                 PROPERTY_CHANGED,
1948                                                 sim_changed,
1949                                                 NULL, NULL);
1950
1951         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1952                                                 OFONO_MANAGER_INTERFACE,
1953                                                 MODEM_ADDED,
1954                                                 modem_added,
1955                                                 NULL, NULL);
1956
1957         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1958                                                 OFONO_MANAGER_INTERFACE,
1959                                                 MODEM_REMOVED,
1960                                                 modem_removed,
1961                                                 NULL, NULL);
1962
1963         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1964                                                 OFONO_CONTEXT_INTERFACE,
1965                                                 PROPERTY_CHANGED,
1966                                                 context_changed,
1967                                                 NULL, NULL);
1968
1969         if (watch == 0 || gprs_watch == 0 || context_added_watch == 0 ||
1970                         context_removed_watch == 0 || modem_watch == 0 ||
1971                         reg_watch == 0 || sim_watch == 0 ||
1972                         modem_added_watch == 0 || modem_removed_watch == 0 ||
1973                                 context_watch == 0) {
1974                 err = -EIO;
1975                 goto remove;
1976         }
1977
1978         err = connman_network_driver_register(&network_driver);
1979         if (err < 0)
1980                 goto remove;
1981
1982         err = connman_device_driver_register(&modem_driver);
1983         if (err < 0) {
1984                 connman_network_driver_unregister(&network_driver);
1985                 goto remove;
1986         }
1987
1988         return 0;
1989
1990 remove:
1991         g_dbus_remove_watch(connection, watch);
1992         g_dbus_remove_watch(connection, sim_watch);
1993         g_dbus_remove_watch(connection, reg_watch);
1994         g_dbus_remove_watch(connection, gprs_watch);
1995         g_dbus_remove_watch(connection, context_added_watch);
1996         g_dbus_remove_watch(connection, context_removed_watch);
1997         g_dbus_remove_watch(connection, modem_watch);
1998         g_dbus_remove_watch(connection, modem_added_watch);
1999         g_dbus_remove_watch(connection, modem_removed_watch);
2000         g_dbus_remove_watch(connection, context_watch);
2001
2002         dbus_connection_unref(connection);
2003
2004         return err;
2005 }
2006
2007 static void ofono_exit(void)
2008 {
2009         g_dbus_remove_watch(connection, watch);
2010         g_dbus_remove_watch(connection, sim_watch);
2011         g_dbus_remove_watch(connection, reg_watch);
2012         g_dbus_remove_watch(connection, gprs_watch);
2013         g_dbus_remove_watch(connection, context_added_watch);
2014         g_dbus_remove_watch(connection, context_removed_watch);
2015         g_dbus_remove_watch(connection, modem_watch);
2016         g_dbus_remove_watch(connection, modem_added_watch);
2017         g_dbus_remove_watch(connection, modem_removed_watch);
2018         g_dbus_remove_watch(connection, context_watch);
2019
2020         ofono_disconnect(connection, NULL);
2021
2022         connman_device_driver_unregister(&modem_driver);
2023         connman_network_driver_unregister(&network_driver);
2024
2025         dbus_connection_unref(connection);
2026 }
2027
2028 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
2029                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)