ofono: Add support for CDMA modems
[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  *  Copyright (C) 2011  BWM Car IT GmbH. All rights reserved.
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License version 2 as
11  *  published by the Free Software Foundation.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <errno.h>
29 #include <stdlib.h>
30
31 #include <gdbus.h>
32 #include <string.h>
33 #include <stdint.h>
34
35 #define CONNMAN_API_SUBJECT_TO_CHANGE
36 #include <connman/plugin.h>
37 #include <connman/device.h>
38 #include <connman/network.h>
39 #include <connman/inet.h>
40 #include <connman/dbus.h>
41 #include <connman/log.h>
42
43 #define uninitialized_var(x) x = x
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_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
50 #define OFONO_NETREG_INTERFACE          OFONO_SERVICE ".NetworkRegistration"
51 #define OFONO_CM_INTERFACE              OFONO_SERVICE ".ConnectionManager"
52 #define OFONO_CONTEXT_INTERFACE         OFONO_SERVICE ".ConnectionContext"
53 #define OFONO_CDMA_CM_INTERFACE         OFONO_SERVICE ".cdma.ConnectionManager"
54 #define OFONO_CDMA_NETREG_INTERFACE     OFONO_SERVICE ".cdma.NetworkRegistration"
55
56 #define MODEM_ADDED                     "ModemAdded"
57 #define MODEM_REMOVED                   "ModemRemoved"
58 #define PROPERTY_CHANGED                "PropertyChanged"
59 #define CONTEXT_ADDED                   "ContextAdded"
60 #define CONTEXT_REMOVED                 "ContextRemoved"
61
62 #define GET_PROPERTIES                  "GetProperties"
63 #define SET_PROPERTY                    "SetProperty"
64 #define GET_MODEMS                      "GetModems"
65 #define GET_CONTEXTS                    "GetContexts"
66
67 #define TIMEOUT 40000
68
69 enum ofono_api {
70         OFONO_API_SIM =         0x1,
71         OFONO_API_NETREG =      0x2,
72         OFONO_API_CM =          0x4,
73         OFONO_API_CDMA_NETREG = 0x8,
74         OFONO_API_CDMA_CM =     0x10,
75 };
76
77 /*
78  * The way this plugin works is following:
79  *
80  *   powered -> SubscriberIdentity or Online = True -> gprs, context ->
81  *     attached -> netreg -> ready
82  *
83  * Enabling and disabling modems are steered through the rfkill
84  * interface. That means when ConnMan toggles the rfkill bit oFono
85  * will add or remove the modems.
86  *
87  * ConnMan will always power up (set Powered and Online) the
88  * modems. No need to power them down because this will be done
89  * through the rfkill inteface.
90  */
91
92 static DBusConnection *connection;
93
94 static GHashTable *modem_hash;
95 static GHashTable *context_hash;
96
97 struct network_context {
98         char *path;
99         int index;
100
101         enum connman_ipconfig_method ipv4_method;
102         struct connman_ipaddress *ipv4_address;
103         char *ipv4_nameservers;
104
105         enum connman_ipconfig_method ipv6_method;
106         struct connman_ipaddress *ipv6_address;
107         char *ipv6_nameservers;
108 };
109
110 struct modem_data {
111         char *path;
112
113         struct connman_device *device;
114         struct connman_network *network;
115
116         struct network_context *context;
117
118         /* Modem Interface */
119         char *serial;
120         connman_bool_t powered;
121         connman_bool_t online;
122         uint8_t interfaces;
123         connman_bool_t ignore;
124
125         connman_bool_t set_powered;
126         connman_bool_t set_online;
127
128         /* ConnectionManager Interface */
129         connman_bool_t attached;
130         connman_bool_t cm_powered;
131
132         connman_bool_t set_cm_powered;
133
134         /* ConnectionContext Interface */
135         connman_bool_t active;
136         connman_bool_t set_active;
137
138         /* SimManager Interface */
139         char *imsi;
140
141         /* Netreg Interface */
142         char *name;
143         uint8_t strength;
144         connman_bool_t roaming;
145
146         /* pending calls */
147         DBusPendingCall *call_set_property;
148         DBusPendingCall *call_get_properties;
149         DBusPendingCall *call_get_contexts;
150 };
151
152 static char *get_ident(const char *path)
153 {
154         char *pos;
155
156         if (*path != '/')
157                 return NULL;
158
159         pos = strrchr(path, '/');
160         if (pos == NULL)
161                 return NULL;
162
163         return pos + 1;
164 }
165
166 static struct network_context *network_context_alloc(const char *path)
167 {
168         struct network_context *context;
169
170         context = g_try_new0(struct network_context, 1);
171         if (context == NULL)
172                 return NULL;
173
174         context->path = g_strdup(path);
175         context->index = -1;
176
177         context->ipv4_method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
178         context->ipv4_address = NULL;
179         context->ipv4_nameservers = NULL;
180
181         context->ipv6_method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
182         context->ipv6_address = NULL;
183         context->ipv6_nameservers = NULL;
184
185         return context;
186 }
187
188 static void network_context_free(struct network_context *context)
189 {
190         g_free(context->path);
191
192         connman_ipaddress_free(context->ipv4_address);
193         g_free(context->ipv4_nameservers);
194
195         connman_ipaddress_free(context->ipv6_address);
196         g_free(context->ipv6_nameservers);
197
198         free(context);
199 }
200
201 static void set_connected(struct modem_data *modem)
202 {
203         connman_bool_t setip = FALSE;
204
205         DBG("%s", modem->path);
206
207         connman_network_set_index(modem->network, modem->context->index);
208
209         switch (modem->context->ipv4_method) {
210         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
211         case CONNMAN_IPCONFIG_METHOD_OFF:
212         case CONNMAN_IPCONFIG_METHOD_MANUAL:
213         case CONNMAN_IPCONFIG_METHOD_AUTO:
214                 break;
215
216         case CONNMAN_IPCONFIG_METHOD_FIXED:
217                 connman_network_set_ipv4_method(modem->network,
218                                                 modem->context->ipv4_method);
219                 connman_network_set_ipaddress(modem->network,
220                                                 modem->context->ipv4_address);
221                 connman_network_set_nameservers(modem->network,
222                                         modem->context->ipv4_nameservers);
223                 setip = TRUE;
224                 break;
225
226         case CONNMAN_IPCONFIG_METHOD_DHCP:
227                 connman_network_set_ipv4_method(modem->network,
228                                                 modem->context->ipv4_method);
229                 setip = TRUE;
230                 break;
231         }
232
233         switch (modem->context->ipv6_method) {
234         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
235         case CONNMAN_IPCONFIG_METHOD_OFF:
236         case CONNMAN_IPCONFIG_METHOD_MANUAL:
237         case CONNMAN_IPCONFIG_METHOD_DHCP:
238         case CONNMAN_IPCONFIG_METHOD_AUTO:
239                 break;
240
241         case CONNMAN_IPCONFIG_METHOD_FIXED:
242                 connman_network_set_ipv6_method(modem->network,
243                                                         modem->context->ipv6_method);
244                 connman_network_set_ipaddress(modem->network,
245                                                         modem->context->ipv6_address);
246                 setip = TRUE;
247                 break;
248         }
249
250         if (setip == TRUE)
251                 connman_network_set_connected(modem->network, TRUE);
252 }
253
254 static void set_disconnected(struct modem_data *modem)
255 {
256         DBG("%s", modem->path);
257
258         connman_network_set_connected(modem->network, FALSE);
259 }
260
261 typedef void (*set_property_cb)(struct modem_data *data,
262                                 connman_bool_t success);
263 typedef void (*get_properties_cb)(struct modem_data *data,
264                                 DBusMessageIter *dict);
265
266 struct property_info {
267         struct modem_data *modem;
268         const char *path;
269         const char *interface;
270         const char *property;
271         set_property_cb set_property_cb;
272         get_properties_cb get_properties_cb;
273 };
274
275 static void set_property_reply(DBusPendingCall *call, void *user_data)
276 {
277         struct property_info *info = user_data;
278         DBusMessage *reply;
279         DBusError error;
280         connman_bool_t success = TRUE;
281
282         DBG("%s path %s %s.%s", info->modem->path,
283                 info->path, info->interface, info->property);
284
285         info->modem->call_set_property = NULL;
286
287         dbus_error_init(&error);
288
289         reply = dbus_pending_call_steal_reply(call);
290
291         if (dbus_set_error_from_message(&error, reply)) {
292                 connman_error("Failed to change property: %s %s.%s: %s %s",
293                                 info->path, info->interface, info->property,
294                                 error.name, error.message);
295                 dbus_error_free(&error);
296                 success = FALSE;
297         }
298
299         if (info->set_property_cb != NULL)
300                 (*info->set_property_cb)(info->modem, success);
301
302         dbus_message_unref(reply);
303
304         dbus_pending_call_unref(call);
305 }
306
307 static int set_property(struct modem_data *modem,
308                         const char *path, const char *interface,
309                         const char *property, int type, void *value,
310                         set_property_cb notify)
311 {
312         DBusMessage *message;
313         DBusMessageIter iter;
314         struct property_info *info;
315
316         DBG("%s path %s %s.%s", modem->path, path, interface, property);
317
318         if (modem->call_set_property != NULL) {
319                 connman_error("Pending SetProperty");
320                 return -EBUSY;
321         }
322
323         message = dbus_message_new_method_call(OFONO_SERVICE, path,
324                                         interface, SET_PROPERTY);
325         if (message == NULL)
326                 return -ENOMEM;
327
328         dbus_message_iter_init_append(message, &iter);
329         connman_dbus_property_append_basic(&iter, property, type, value);
330
331         if (dbus_connection_send_with_reply(connection, message,
332                         &modem->call_set_property, TIMEOUT) == FALSE) {
333                 connman_error("Failed to change property: %s %s.%s",
334                                 path, interface, property);
335                 dbus_message_unref(message);
336                 return -EINVAL;
337         }
338
339         if (modem->call_set_property == NULL) {
340                 connman_error("D-Bus connection not available");
341                 dbus_message_unref(message);
342                 return -EINVAL;
343         }
344
345         info = g_try_new0(struct property_info, 1);
346         if (info == NULL) {
347                 dbus_message_unref(message);
348                 return -ENOMEM;
349         }
350
351         info->modem = modem;
352         info->path = path;
353         info->interface = interface;
354         info->property = property;
355         info->set_property_cb = notify;
356
357         dbus_pending_call_set_notify(modem->call_set_property,
358                                         set_property_reply, info, g_free);
359
360         dbus_message_unref(message);
361
362         return -EINPROGRESS;
363 }
364
365 static void get_properties_reply(DBusPendingCall *call, void *user_data)
366 {
367         struct property_info *info = user_data;
368         DBusMessageIter array, dict;
369         DBusMessage *reply;
370         DBusError error;
371
372         DBG("%s path %s %s", info->modem->path, info->path, info->interface);
373
374         info->modem->call_get_properties = NULL;
375
376         dbus_error_init(&error);
377
378         reply = dbus_pending_call_steal_reply(call);
379
380         if (dbus_set_error_from_message(&error, reply)) {
381                 connman_error("Failed to get properties: %s %s: %s %s",
382                                 info->path, info->interface,
383                                 error.name, error.message);
384                 dbus_error_free(&error);
385
386                 goto done;
387         }
388
389         if (dbus_message_iter_init(reply, &array) == FALSE)
390                 goto done;
391
392         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
393                 goto done;
394
395         dbus_message_iter_recurse(&array, &dict);
396
397         if (info->get_properties_cb != NULL)
398                 (*info->get_properties_cb)(info->modem, &dict);
399
400 done:
401
402         dbus_message_unref(reply);
403
404         dbus_pending_call_unref(call);
405 }
406
407 static int get_properties(const char *path, const char *interface,
408                                 get_properties_cb notify,
409                                 struct modem_data *modem)
410 {
411         DBusMessage *message;
412         struct property_info *info;
413
414         DBG("%s path %s %s", modem->path, path, interface);
415
416         if (modem->call_get_properties != NULL) {
417                 connman_error("Pending GetProperties");
418                 return -EBUSY;
419         }
420
421         message = dbus_message_new_method_call(OFONO_SERVICE, path,
422                                         interface, GET_PROPERTIES);
423         if (message == NULL)
424                 return -ENOMEM;
425
426         if (dbus_connection_send_with_reply(connection, message,
427                         &modem->call_get_properties, TIMEOUT) == FALSE) {
428                 connman_error("Failed to call %s.GetProperties()", interface);
429                 dbus_message_unref(message);
430                 return -EINVAL;
431         }
432
433         if (modem->call_get_properties == NULL) {
434                 connman_error("D-Bus connection not available");
435                 dbus_message_unref(message);
436                 return -EINVAL;
437         }
438
439         info = g_try_new0(struct property_info, 1);
440         if (info == NULL) {
441                 dbus_message_unref(message);
442                 return -ENOMEM;
443         }
444
445         info->modem = modem;
446         info->path = path;
447         info->interface = interface;
448         info->get_properties_cb = notify;
449
450         dbus_pending_call_set_notify(modem->call_get_properties,
451                                         get_properties_reply, info, g_free);
452
453         dbus_message_unref(message);
454
455         return -EINPROGRESS;
456 }
457
458 static void context_set_active_reply(struct modem_data *modem,
459                                         connman_bool_t success)
460 {
461         DBG("%s", modem->path);
462
463         if (success == TRUE) {
464                 /*
465                  * Don't handle do anything on success here. oFono will send
466                  * the change via PropertyChanged singal.
467                  */
468                 return;
469         }
470
471         /*
472          * Active = True might fail due a timeout. That means oFono
473          * still tries to go online. If we retry to set Active = True,
474          * we just get a InProgress error message. Should we power
475          * cycle the modem in such cases?
476          */
477
478         connman_network_set_error(modem->network,
479                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
480 }
481
482 static int context_set_active(struct modem_data *modem)
483 {
484         dbus_bool_t active = TRUE;
485
486         DBG("%s", modem->path);
487
488         return set_property(modem, modem->context->path,
489                                 OFONO_CONTEXT_INTERFACE,
490                                 "Active", DBUS_TYPE_BOOLEAN,
491                                 &active,
492                                 context_set_active_reply);
493 }
494
495 static int context_set_inactive(struct modem_data *modem)
496 {
497         dbus_bool_t active = FALSE;
498         int err;
499
500         DBG("%s", modem->path);
501
502         err = set_property(modem, modem->context->path,
503                                 OFONO_CONTEXT_INTERFACE,
504                                 "Active", DBUS_TYPE_BOOLEAN,
505                                 &active,
506                                 NULL);
507         if (err == -EINPROGRESS)
508                 return 0;
509
510         return err;
511 }
512
513 static void cdma_cm_set_powered_reply(struct modem_data *modem,
514                                         connman_bool_t success)
515 {
516         DBG("%s", modem->path);
517
518         if (success == TRUE) {
519                 /*
520                  * Don't handle do anything on success here. oFono will send
521                  * the change via PropertyChanged singal.
522                  */
523                 return;
524         }
525
526         /*
527          * Powered = True might fail due a timeout. That means oFono
528          * still tries to go online. If we retry to set Powered = True,
529          * we just get a InProgress error message. Should we power
530          * cycle the modem in such cases?
531          */
532
533         connman_network_set_error(modem->network,
534                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
535 }
536
537 static int cdma_cm_set_powered(struct modem_data *modem)
538 {
539         dbus_bool_t powered = TRUE;
540
541         DBG("%s", modem->path);
542
543         return set_property(modem, modem->path, OFONO_CDMA_CM_INTERFACE,
544                                 "Powered", DBUS_TYPE_BOOLEAN, &powered,
545                                 cdma_cm_set_powered_reply);
546 }
547
548 static int cdma_cm_shutdown(struct modem_data *modem)
549 {
550         dbus_bool_t powered = FALSE;
551         int err;
552
553         DBG("%s", modem->path);
554
555         err = set_property(modem, modem->path, OFONO_CDMA_CM_INTERFACE,
556                                 "Powered", DBUS_TYPE_BOOLEAN, &powered, NULL);
557         if (err == -EINPROGRESS)
558                 return 0;
559
560         return err;
561 }
562
563 static void modem_set_online_reply(struct modem_data *modem,
564                                         connman_bool_t success)
565 {
566         DBG("%s", modem->path);
567
568         if (success == TRUE) {
569                 /*
570                  * Don't handle do anything on success here. oFono will send
571                  * the change via PropertyChanged singal.
572                  */
573                 return;
574         }
575
576         modem->set_online = FALSE;
577 }
578
579 static int modem_set_online(struct modem_data *modem)
580 {
581         DBG("%s", modem->path);
582
583         modem->set_online = TRUE;
584
585         return set_property(modem, modem->path,
586                                 OFONO_MODEM_INTERFACE,
587                                 "Online", DBUS_TYPE_BOOLEAN,
588                                 &modem->set_online,
589                                 modem_set_online_reply);
590 }
591
592 static void cm_set_powered_reply(struct modem_data *modem,
593                                         connman_bool_t success)
594 {
595         DBG("%s", modem->path);
596
597         if (success == TRUE) {
598                 /*
599                  * Don't handle do anything on success here. oFono will send
600                  * the change via PropertyChanged singal.
601                  */
602                 return;
603         }
604
605         modem->set_cm_powered = FALSE;
606 }
607
608 static int cm_set_powered(struct modem_data *modem)
609 {
610         DBG("%s", modem->path);
611
612         modem->set_cm_powered = TRUE;
613
614         return set_property(modem, modem->path,
615                                 OFONO_CM_INTERFACE,
616                                 "Powered", DBUS_TYPE_BOOLEAN,
617                                 &modem->set_cm_powered,
618                                 cm_set_powered_reply);
619 }
620
621 static int modem_set_powered(struct modem_data *modem)
622 {
623         DBG("%s", modem->path);
624
625         modem->set_powered = TRUE;
626
627         return set_property(modem, modem->path,
628                                 OFONO_MODEM_INTERFACE,
629                                 "Powered", DBUS_TYPE_BOOLEAN,
630                                 &modem->set_powered,
631                                 NULL);
632 }
633
634 static int modem_set_unpowered(struct modem_data *modem)
635 {
636         DBG("%s", modem->path);
637
638         modem->set_powered = FALSE;
639
640         return set_property(modem, modem->path,
641                                 OFONO_MODEM_INTERFACE,
642                                 "Powered", DBUS_TYPE_BOOLEAN,
643                                 &modem->set_powered,
644                                 NULL);
645 }
646
647 static connman_bool_t has_interface(uint8_t interfaces,
648                                         enum ofono_api api)
649 {
650         if ((interfaces & api) == api)
651                 return TRUE;
652
653         return FALSE;
654 }
655
656 static uint8_t extract_interfaces(DBusMessageIter *array)
657 {
658         DBusMessageIter entry;
659         uint8_t interfaces = 0;
660
661         dbus_message_iter_recurse(array, &entry);
662
663         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
664                 const char *name;
665
666                 dbus_message_iter_get_basic(&entry, &name);
667
668                 if (g_str_equal(name, OFONO_SIM_INTERFACE) == TRUE)
669                         interfaces |= OFONO_API_SIM;
670                 else if (g_str_equal(name, OFONO_NETREG_INTERFACE) == TRUE)
671                         interfaces |= OFONO_API_NETREG;
672                 else if (g_str_equal(name, OFONO_CM_INTERFACE) == TRUE)
673                         interfaces |= OFONO_API_CM;
674                 else if (g_str_equal(name, OFONO_CDMA_CM_INTERFACE) == TRUE)
675                         interfaces |= OFONO_API_CDMA_CM;
676                 else if (g_str_equal(name, OFONO_CDMA_NETREG_INTERFACE) == TRUE)
677                         interfaces |= OFONO_API_CDMA_NETREG;
678
679                 dbus_message_iter_next(&entry);
680         }
681
682         return interfaces;
683 }
684
685 static char *extract_nameservers(DBusMessageIter *array)
686 {
687         DBusMessageIter entry;
688         char *nameservers = NULL;
689         char *tmp;
690
691         dbus_message_iter_recurse(array, &entry);
692
693         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
694                 const char *nameserver;
695
696                 dbus_message_iter_get_basic(&entry, &nameserver);
697
698                 if (nameservers == NULL) {
699                         nameservers = g_strdup(nameserver);
700                 } else {
701                         tmp = nameservers;
702                         nameservers = g_strdup_printf("%s %s", tmp, nameserver);
703                         g_free(tmp);
704                 }
705
706                 dbus_message_iter_next(&entry);
707         }
708
709         return nameservers;
710 }
711
712 static void extract_ipv4_settings(DBusMessageIter *array,
713                                 struct network_context *context)
714 {
715         DBusMessageIter dict;
716         char *address = NULL, *netmask = NULL, *gateway = NULL;
717         char *nameservers = NULL;
718         const char *interface = NULL;
719         int index = -1;
720
721         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
722                 return;
723
724         dbus_message_iter_recurse(array, &dict);
725
726         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
727                 DBusMessageIter entry, value;
728                 const char *key, *val;
729
730                 dbus_message_iter_recurse(&dict, &entry);
731                 dbus_message_iter_get_basic(&entry, &key);
732
733                 dbus_message_iter_next(&entry);
734                 dbus_message_iter_recurse(&entry, &value);
735
736                 if (g_str_equal(key, "Interface") == TRUE) {
737                         dbus_message_iter_get_basic(&value, &interface);
738
739                         DBG("Interface %s", interface);
740
741                         index = connman_inet_ifindex(interface);
742
743                         DBG("index %d", index);
744                 } else if (g_str_equal(key, "Method") == TRUE) {
745                         dbus_message_iter_get_basic(&value, &val);
746
747                         DBG("Method %s", val);
748
749                         if (g_strcmp0(val, "static") == 0) {
750                                 context->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED;
751                         } else if (g_strcmp0(val, "dhcp") == 0) {
752                                 context->ipv4_method = CONNMAN_IPCONFIG_METHOD_DHCP;
753                                 break;
754                         }
755                 } else if (g_str_equal(key, "Address") == TRUE) {
756                         dbus_message_iter_get_basic(&value, &val);
757
758                         address = g_strdup(val);
759
760                         DBG("Address %s", address);
761                 } else if (g_str_equal(key, "Netmask") == TRUE) {
762                         dbus_message_iter_get_basic(&value, &val);
763
764                         netmask = g_strdup(val);
765
766                         DBG("Netmask %s", netmask);
767                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
768                         nameservers = extract_nameservers(&value);
769
770                         DBG("Nameservers %s", nameservers);
771                 } else if (g_str_equal(key, "Gateway") == TRUE) {
772                         dbus_message_iter_get_basic(&value, &val);
773
774                         gateway = g_strdup(val);
775
776                         DBG("Gateway %s", gateway);
777                 }
778
779                 dbus_message_iter_next(&dict);
780         }
781
782         if (index < 0)
783                 goto out;
784
785         if (context->ipv4_method != CONNMAN_IPCONFIG_METHOD_FIXED)
786                 goto out;
787
788         context->ipv4_address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
789         if (context->ipv4_address == NULL)
790                 goto out;
791
792         context->index = index;
793         connman_ipaddress_set_ipv4(context->ipv4_address, address,
794                                 netmask, gateway);
795
796         context->ipv4_nameservers = nameservers;
797
798 out:
799         if (context->ipv4_nameservers != nameservers)
800                 g_free(nameservers);
801
802         g_free(address);
803         g_free(netmask);
804         g_free(gateway);
805 }
806
807 static void extract_ipv6_settings(DBusMessageIter *array,
808                                 struct network_context *context)
809 {
810         DBusMessageIter dict;
811         char *address = NULL, *gateway = NULL;
812         unsigned char prefix_length;
813         char *nameservers = NULL;
814         const char *interface = NULL;
815         int index = -1;
816
817         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
818                 return;
819
820         dbus_message_iter_recurse(array, &dict);
821
822         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
823                 DBusMessageIter entry, value;
824                 const char *key, *val;
825
826                 dbus_message_iter_recurse(&dict, &entry);
827                 dbus_message_iter_get_basic(&entry, &key);
828
829                 dbus_message_iter_next(&entry);
830                 dbus_message_iter_recurse(&entry, &value);
831
832                 if (g_str_equal(key, "Interface") == TRUE) {
833                         dbus_message_iter_get_basic(&value, &interface);
834
835                         DBG("Interface %s", interface);
836
837                         index = connman_inet_ifindex(interface);
838
839                         DBG("index %d", index);
840                 } else if (g_str_equal(key, "Address") == TRUE) {
841                         dbus_message_iter_get_basic(&value, &val);
842
843                         address = g_strdup(val);
844
845                         DBG("Address %s", address);
846                 } else if (g_str_equal(key, "PrefixLength") == TRUE) {
847                         dbus_message_iter_get_basic(&value, &prefix_length);
848
849                         DBG("prefix length %d", prefix_length);
850                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
851                         nameservers = extract_nameservers(&value);
852
853                         DBG("Nameservers %s", nameservers);
854                 } else if (g_str_equal(key, "Gateway") == TRUE) {
855                         dbus_message_iter_get_basic(&value, &val);
856
857                         gateway = g_strdup(val);
858
859                         DBG("Gateway %s", gateway);
860                 }
861
862                 dbus_message_iter_next(&dict);
863         }
864
865         if (index < 0)
866                 goto out;
867
868         context->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED;
869
870         context->ipv6_address =
871                 connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6);
872         if (context->ipv6_address == NULL)
873                 goto out;
874
875         context->index = index;
876         connman_ipaddress_set_ipv6(context->ipv6_address, address,
877                                 prefix_length, gateway);
878
879         context->ipv6_nameservers = nameservers;
880
881 out:
882         if (context->ipv6_nameservers != nameservers)
883                 g_free(nameservers);
884
885         g_free(address);
886         g_free(gateway);
887 }
888
889 static connman_bool_t ready_to_create_device(struct modem_data *modem)
890 {
891         /*
892          * There are three different modem types which behave slightly
893          * different:
894          * - GSM modems will expose the SIM interface then the
895          *   CM interface.
896          * - DUN modems will expose first a unique serial number (BDADDR)
897          *   and then the CM interface.
898          * - CDMA modems will expose CM first and sometime later
899          *   a unique serial number.
900          *
901          * This functions tests if we have the necessary information gathered
902          * before we are able to create a device.
903          */
904
905         if (modem->device != NULL)
906                 return FALSE;
907
908         if (modem->imsi != NULL || modem->serial != NULL)
909                 return TRUE;
910
911         return FALSE;
912 }
913
914 static void create_device(struct modem_data *modem)
915 {
916         struct connman_device *device;
917         char *uninitialized_var(ident);
918
919         DBG("%s", modem->path);
920
921         if (modem->imsi != NULL)
922                 ident = modem->imsi;
923         else if (modem->serial != NULL)
924                 ident = modem->serial;
925
926         if (connman_dbus_validate_ident(ident) == FALSE)
927                 ident = connman_dbus_encode_string(ident);
928         else
929                 ident = g_strdup(ident);
930
931         device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_CELLULAR);
932         if (device == NULL)
933                 goto out;
934
935         DBG("device %p", device);
936
937         connman_device_set_ident(device, ident);
938
939         connman_device_set_string(device, "Path", modem->path);
940
941         connman_device_set_data(device, modem);
942
943         if (connman_device_register(device) < 0) {
944                 connman_error("Failed to register cellular device");
945                 connman_device_unref(device);
946                 goto out;
947         }
948
949         modem->device = device;
950
951 out:
952         g_free(ident);
953 }
954
955 static void destroy_device(struct modem_data *modem)
956 {
957         DBG("%s", modem->path);
958
959         connman_device_set_powered(modem->device, FALSE);
960
961         if (modem->network != NULL) {
962                 connman_device_remove_network(modem->device, modem->network);
963                 connman_network_unref(modem->network);
964                 modem->network = NULL;
965         }
966
967         connman_device_unregister(modem->device);
968         connman_device_unref(modem->device);
969
970         modem->device = NULL;
971 }
972
973 static void add_network(struct modem_data *modem)
974 {
975         const char *group;
976
977         DBG("%s", modem->path);
978
979         if (modem->network != NULL)
980                 return;
981
982         modem->network = connman_network_create(modem->context->path,
983                                                 CONNMAN_NETWORK_TYPE_CELLULAR);
984         if (modem->network == NULL)
985                 return;
986
987         DBG("network %p", modem->network);
988
989         connman_network_set_data(modem->network, modem);
990
991         connman_network_set_string(modem->network, "Path",
992                                         modem->context->path);
993
994         connman_network_set_index(modem->network, modem->context->index);
995
996         if (modem->name != NULL)
997                 connman_network_set_name(modem->network, modem->name);
998         else
999                 connman_network_set_name(modem->network, "");
1000
1001         connman_network_set_strength(modem->network, modem->strength);
1002
1003         group = get_ident(modem->context->path);
1004         connman_network_set_group(modem->network, group);
1005
1006         connman_network_set_available(modem->network, TRUE);
1007
1008         connman_network_set_bool(modem->network, "Roaming",
1009                                         modem->roaming);
1010
1011         if (connman_device_add_network(modem->device, modem->network) < 0) {
1012                 connman_network_unref(modem->network);
1013                 modem->network = NULL;
1014                 return;
1015         }
1016 }
1017
1018 static int add_cm_context(struct modem_data *modem, const char *context_path,
1019                                 DBusMessageIter *dict)
1020 {
1021         const char *context_type;
1022         struct network_context *context = NULL;
1023         connman_bool_t active = FALSE;
1024
1025         DBG("%s context path %s", modem->path, context_path);
1026
1027         if (modem->context != NULL) {
1028                 /*
1029                  * We have already assigned a context to this modem
1030                  * and we do only support one Internet context.
1031                  */
1032                 return -EALREADY;
1033         }
1034
1035         context = network_context_alloc(context_path);
1036         if (context == NULL)
1037                 return -ENOMEM;
1038
1039         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1040                 DBusMessageIter entry, value;
1041                 const char *key;
1042
1043                 dbus_message_iter_recurse(dict, &entry);
1044                 dbus_message_iter_get_basic(&entry, &key);
1045
1046                 dbus_message_iter_next(&entry);
1047                 dbus_message_iter_recurse(&entry, &value);
1048
1049                 if (g_str_equal(key, "Type") == TRUE) {
1050                         dbus_message_iter_get_basic(&value, &context_type);
1051
1052                         DBG("%s context %s type %s", modem->path,
1053                                 context_path, context_type);
1054                 } else if (g_str_equal(key, "Settings") == TRUE) {
1055                         DBG("%s Settings", modem->path);
1056
1057                         extract_ipv4_settings(&value, context);
1058                 } else if (g_str_equal(key, "IPv6.Settings") == TRUE) {
1059                         DBG("%s IPv6.Settings", modem->path);
1060
1061                         extract_ipv6_settings(&value, context);
1062                 } else if (g_str_equal(key, "Active") == TRUE) {
1063                         dbus_message_iter_get_basic(&value, &active);
1064
1065                         DBG("%s Active %d", modem->path, active);
1066                 }
1067
1068                 dbus_message_iter_next(dict);
1069         }
1070
1071         if (g_strcmp0(context_type, "internet") != 0) {
1072                 network_context_free(context);
1073                 return -EINVAL;
1074         }
1075
1076         modem->context = context;
1077         modem->active = active;
1078
1079         g_hash_table_replace(context_hash, g_strdup(context_path), modem);
1080
1081         return 0;
1082 }
1083
1084 static void remove_cm_context(struct modem_data *modem,
1085                                 const char *context_path)
1086 {
1087         if (modem->context == NULL)
1088                 return;
1089
1090         g_hash_table_remove(context_hash, context_path);
1091
1092         network_context_free(modem->context);
1093         modem->context = NULL;
1094 }
1095
1096 static gboolean context_changed(DBusConnection *connection,
1097                                 DBusMessage *message,
1098                                 void *user_data)
1099 {
1100         const char *context_path = dbus_message_get_path(message);
1101         struct modem_data *modem = NULL;
1102         DBusMessageIter iter, value;
1103         const char *key;
1104
1105         DBG("context_path %s", context_path);
1106
1107         modem = g_hash_table_lookup(context_hash, context_path);
1108         if (modem == NULL)
1109                 return TRUE;
1110
1111         if (dbus_message_iter_init(message, &iter) == FALSE)
1112                 return TRUE;
1113
1114         dbus_message_iter_get_basic(&iter, &key);
1115
1116         dbus_message_iter_next(&iter);
1117         dbus_message_iter_recurse(&iter, &value);
1118
1119         /*
1120          * oFono guarantees the ordering of Settings and
1121          * Active. Settings will always be send before Active = True.
1122          * That means we don't have to order here.
1123          */
1124         if (g_str_equal(key, "Settings") == TRUE) {
1125                 DBG("%s Settings", modem->path);
1126
1127                 extract_ipv4_settings(&value, modem->context);
1128         } else if (g_str_equal(key, "IPv6.Settings") == TRUE) {
1129                 DBG("%s IPv6.Settings", modem->path);
1130
1131                 extract_ipv6_settings(&value, modem->context);
1132         } else if (g_str_equal(key, "Active") == TRUE) {
1133                 dbus_message_iter_get_basic(&value, &modem->active);
1134
1135                 DBG("%s Active %d", modem->path, modem->active);
1136
1137                 if (modem->active == TRUE)
1138                         set_connected(modem);
1139                 else
1140                         set_disconnected(modem);
1141         }
1142
1143         return TRUE;
1144 }
1145
1146 static void cm_get_contexts_reply(DBusPendingCall *call, void *user_data)
1147 {
1148         struct modem_data *modem = user_data;
1149         DBusMessageIter array, dict, entry, value;
1150         DBusMessage *reply;
1151         DBusError error;
1152
1153         DBG("%s", modem->path);
1154
1155         modem->call_get_contexts = NULL;
1156
1157         reply = dbus_pending_call_steal_reply(call);
1158
1159         dbus_error_init(&error);
1160
1161         if (dbus_set_error_from_message(&error, reply) == TRUE) {
1162                 connman_error("%s", error.message);
1163                 dbus_error_free(&error);
1164                 goto done;
1165         }
1166
1167         if (dbus_message_iter_init(reply, &array) == FALSE)
1168                 goto done;
1169
1170         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1171                 goto done;
1172
1173         dbus_message_iter_recurse(&array, &dict);
1174
1175         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
1176                 const char *context_path;
1177
1178                 dbus_message_iter_recurse(&dict, &entry);
1179                 dbus_message_iter_get_basic(&entry, &context_path);
1180
1181                 dbus_message_iter_next(&entry);
1182                 dbus_message_iter_recurse(&entry, &value);
1183
1184                 if (add_cm_context(modem, context_path, &value) == 0)
1185                         break;
1186
1187                 dbus_message_iter_next(&dict);
1188         }
1189
1190 done:
1191         dbus_message_unref(reply);
1192
1193         dbus_pending_call_unref(call);
1194 }
1195
1196 static int cm_get_contexts(struct modem_data *modem)
1197 {
1198         DBusMessage *message;
1199
1200         DBG("%s", modem->path);
1201
1202         if (modem->call_get_contexts != NULL)
1203                 return -EBUSY;
1204
1205         message = dbus_message_new_method_call(OFONO_SERVICE, modem->path,
1206                                         OFONO_CM_INTERFACE, GET_CONTEXTS);
1207         if (message == NULL)
1208                 return -ENOMEM;
1209
1210         if (dbus_connection_send_with_reply(connection, message,
1211                         &modem->call_get_contexts, TIMEOUT) == FALSE) {
1212                 connman_error("Failed to call GetContexts()");
1213                 dbus_message_unref(message);
1214                 return -EINVAL;
1215         }
1216
1217         if (modem->call_get_contexts == NULL) {
1218                 connman_error("D-Bus connection not available");
1219                 dbus_message_unref(message);
1220                 return -EINVAL;
1221         }
1222
1223         dbus_pending_call_set_notify(modem->call_get_contexts,
1224                                         cm_get_contexts_reply,
1225                                         modem, NULL);
1226
1227         dbus_message_unref(message);
1228
1229         return -EINPROGRESS;
1230 }
1231
1232 static gboolean cm_context_added(DBusConnection *connection,
1233                                         DBusMessage *message,
1234                                         void *user_data)
1235 {
1236         const char *path = dbus_message_get_path(message);
1237         char *context_path;
1238         struct modem_data *modem;
1239         DBusMessageIter iter, properties;
1240
1241         DBG("%s", path);
1242
1243         modem = g_hash_table_lookup(modem_hash, context_path);
1244         if (modem == NULL)
1245                 return TRUE;
1246
1247         if (dbus_message_iter_init(message, &iter) == FALSE)
1248                 return TRUE;
1249
1250         dbus_message_iter_get_basic(&iter, &context_path);
1251
1252         dbus_message_iter_next(&iter);
1253         dbus_message_iter_recurse(&iter, &properties);
1254
1255         if (add_cm_context(modem, context_path, &properties) != 0)
1256                 return TRUE;
1257
1258         return TRUE;
1259 }
1260
1261 static gboolean cm_context_removed(DBusConnection *connection,
1262                                         DBusMessage *message,
1263                                         void *user_data)
1264 {
1265         const char *path = dbus_message_get_path(message);
1266         const char *context_path;
1267         struct modem_data *modem;
1268         DBusMessageIter iter;
1269
1270         DBG("context path %s", path);
1271
1272         if (dbus_message_iter_init(message, &iter) == FALSE)
1273                 return TRUE;
1274
1275         dbus_message_iter_get_basic(&iter, &context_path);
1276
1277         modem = g_hash_table_lookup(context_hash, context_path);
1278         if (modem == NULL)
1279                 return TRUE;
1280
1281         remove_cm_context(modem, context_path);
1282
1283         return TRUE;
1284 }
1285
1286 static void netreg_update_name(struct modem_data *modem,
1287                                 DBusMessageIter* value)
1288 {
1289         char *name;
1290
1291         dbus_message_iter_get_basic(value, &name);
1292
1293         DBG("%s Name %s", modem->path, name);
1294
1295         g_free(modem->name);
1296         modem->name = g_strdup(name);
1297
1298         if (modem->network == NULL)
1299                 return;
1300
1301         connman_network_set_name(modem->network, modem->name);
1302         connman_network_update(modem->network);
1303 }
1304
1305 static void netreg_update_strength(struct modem_data *modem,
1306                                         DBusMessageIter *value)
1307 {
1308         dbus_message_iter_get_basic(value, &modem->strength);
1309
1310         DBG("%s Strength %d", modem->path, modem->strength);
1311
1312         if (modem->network == NULL)
1313                 return;
1314
1315         connman_network_set_strength(modem->network, modem->strength);
1316         connman_network_update(modem->network);
1317 }
1318
1319 static void netreg_update_roaming(struct modem_data *modem,
1320                                         DBusMessageIter *value)
1321 {
1322         char *status;
1323         connman_bool_t roaming;
1324
1325         dbus_message_iter_get_basic(value, &status);
1326
1327         if (g_str_equal(status, "roaming") == TRUE)
1328                 roaming = TRUE;
1329         else
1330                 roaming = FALSE;
1331
1332         if (roaming == modem->roaming)
1333                 return;
1334
1335         modem->roaming = roaming;
1336
1337         if (modem->network == NULL)
1338                 return;
1339
1340         connman_network_set_bool(modem->network,
1341                                 "Roaming", modem->roaming);
1342         connman_network_update(modem->network);
1343 }
1344
1345 static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
1346                                 void *user_data)
1347 {
1348         const char *path = dbus_message_get_path(message);
1349         struct modem_data *modem;
1350         DBusMessageIter iter, value;
1351         const char *key;
1352
1353         modem = g_hash_table_lookup(modem_hash, path);
1354         if (modem == NULL)
1355                 return TRUE;
1356
1357         if (modem->ignore == TRUE)
1358                 return TRUE;
1359
1360         if (dbus_message_iter_init(message, &iter) == FALSE)
1361                 return TRUE;
1362
1363         dbus_message_iter_get_basic(&iter, &key);
1364
1365         dbus_message_iter_next(&iter);
1366         dbus_message_iter_recurse(&iter, &value);
1367
1368         if (g_str_equal(key, "Name") == TRUE)
1369                 netreg_update_name(modem, &value);
1370         else if (g_str_equal(key, "Strength") == TRUE)
1371                 netreg_update_strength(modem, &value);
1372         else if (g_str_equal(key, "Status") == TRUE)
1373                 netreg_update_roaming(modem, &value);
1374
1375         return TRUE;
1376 }
1377
1378 static void netreg_properties_reply(struct modem_data *modem,
1379                                         DBusMessageIter *dict)
1380 {
1381         DBG("%s", modem->path);
1382
1383         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1384                 DBusMessageIter entry, value;
1385                 const char *key;
1386
1387                 dbus_message_iter_recurse(dict, &entry);
1388                 dbus_message_iter_get_basic(&entry, &key);
1389
1390                 dbus_message_iter_next(&entry);
1391                 dbus_message_iter_recurse(&entry, &value);
1392
1393                 if (g_str_equal(key, "Name") == TRUE)
1394                         netreg_update_name(modem, &value);
1395                 else if (g_str_equal(key, "Strength") == TRUE)
1396                         netreg_update_strength(modem, &value);
1397                 else if (g_str_equal(key, "Status") == TRUE)
1398                         netreg_update_roaming(modem, &value);
1399
1400                 dbus_message_iter_next(dict);
1401         }
1402
1403         if (modem->context == NULL) {
1404                 /*
1405                  * netgreg_get_properties() was issued after we got
1406                  * cm_get_contexts_reply() where we create the
1407                  * context. Though before we got the
1408                  * netreg_properties_reply the context was removed
1409                  * again. Therefore we have to skip the network
1410                  * creation.
1411                  */
1412                 return;
1413         }
1414
1415         add_network(modem);
1416
1417         if (modem->active == TRUE)
1418                 set_connected(modem);
1419 }
1420
1421 static int netreg_get_properties(struct modem_data *modem)
1422 {
1423         return get_properties(modem->path, OFONO_NETREG_INTERFACE,
1424                         netreg_properties_reply, modem);
1425 }
1426
1427 static int cdma_netreg_get_properties(struct modem_data *modem)
1428 {
1429         return -EINVAL;
1430 }
1431
1432 static void cm_update_attached(struct modem_data *modem,
1433                                 DBusMessageIter *value)
1434 {
1435         dbus_message_iter_get_basic(value, &modem->attached);
1436
1437         DBG("%s Attached %d", modem->path, modem->attached);
1438
1439         if (modem->attached == FALSE)
1440                 return;
1441
1442         if (has_interface(modem->interfaces,
1443                                 OFONO_API_NETREG) == FALSE) {
1444                 return;
1445         }
1446
1447         netreg_get_properties(modem);
1448 }
1449
1450 static void cm_update_powered(struct modem_data *modem,
1451                                 DBusMessageIter *value)
1452 {
1453         dbus_message_iter_get_basic(value, &modem->cm_powered);
1454
1455         DBG("%s ConnnectionManager Powered %d", modem->path,
1456                 modem->cm_powered);
1457
1458         if (modem->cm_powered == TRUE)
1459                 return;
1460
1461         cm_set_powered(modem);
1462 }
1463
1464 static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
1465                                 void *user_data)
1466 {
1467         const char *path = dbus_message_get_path(message);
1468         struct modem_data *modem;
1469         DBusMessageIter iter, value;
1470         const char *key;
1471
1472         modem = g_hash_table_lookup(modem_hash, path);
1473         if (modem == NULL)
1474                 return TRUE;
1475
1476         if (modem->ignore == TRUE)
1477                 return TRUE;
1478
1479         if (dbus_message_iter_init(message, &iter) == FALSE)
1480                 return TRUE;
1481
1482         dbus_message_iter_get_basic(&iter, &key);
1483
1484         dbus_message_iter_next(&iter);
1485         dbus_message_iter_recurse(&iter, &value);
1486
1487         if (g_str_equal(key, "Attached") == TRUE)
1488                 cm_update_attached(modem, &value);
1489         else if (g_str_equal(key, "Powered") == TRUE)
1490                 cm_update_powered(modem, &value);
1491
1492         return TRUE;
1493 }
1494
1495 static void cm_properties_reply(struct modem_data *modem, DBusMessageIter *dict)
1496 {
1497         DBG("%s", modem->path);
1498
1499         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1500                 DBusMessageIter entry, value;
1501                 const char *key;
1502
1503                 dbus_message_iter_recurse(dict, &entry);
1504                 dbus_message_iter_get_basic(&entry, &key);
1505
1506                 dbus_message_iter_next(&entry);
1507                 dbus_message_iter_recurse(&entry, &value);
1508
1509                 if (g_str_equal(key, "Attached") == TRUE)
1510                         cm_update_attached(modem, &value);
1511                 else if (g_str_equal(key, "Powered") == TRUE)
1512                         cm_update_powered(modem, &value);
1513
1514                 dbus_message_iter_next(dict);
1515         }
1516 }
1517
1518 static int cm_get_properties(struct modem_data *modem)
1519 {
1520         return get_properties(modem->path, OFONO_CM_INTERFACE,
1521                                 cm_properties_reply, modem);
1522 }
1523
1524 static int cdma_cm_get_properties(struct modem_data *modem)
1525 {
1526         return -EINVAL;
1527 }
1528
1529 static void update_sim_imsi(struct modem_data *modem,
1530                                 const char *imsi)
1531 {
1532         DBG("%s imsi %s", modem->path, imsi);
1533
1534         if (g_strcmp0(modem->imsi, imsi) == 0)
1535                 return;
1536
1537         g_free(modem->imsi);
1538         modem->imsi = g_strdup(imsi);
1539 }
1540
1541 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
1542                                 void *user_data)
1543 {
1544         const char *path = dbus_message_get_path(message);
1545         struct modem_data *modem;
1546         DBusMessageIter iter, value;
1547         const char *key;
1548
1549         modem = g_hash_table_lookup(modem_hash, path);
1550         if (modem == NULL)
1551                 return TRUE;
1552
1553         if (modem->ignore == TRUE)
1554                 return TRUE;
1555
1556         if (dbus_message_iter_init(message, &iter) == FALSE)
1557                 return TRUE;
1558
1559         dbus_message_iter_get_basic(&iter, &key);
1560
1561         dbus_message_iter_next(&iter);
1562         dbus_message_iter_recurse(&iter, &value);
1563
1564         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1565                 char *imsi;
1566
1567                 dbus_message_iter_get_basic(&value, &imsi);
1568
1569                 update_sim_imsi(modem, imsi);
1570
1571                 if (modem->online == FALSE) {
1572                         modem_set_online(modem);
1573                 } else if (has_interface(modem->interfaces,
1574                                                 OFONO_API_CM) == TRUE) {
1575                         if (ready_to_create_device(modem) == TRUE)
1576                                 create_device(modem);
1577                 } else if (has_interface(modem->interfaces,
1578                                                 OFONO_API_CDMA_CM) == TRUE) {
1579                         if (ready_to_create_device(modem) == TRUE)
1580                                 create_device(modem);
1581                 }
1582         }
1583
1584         return TRUE;
1585 }
1586
1587 static void sim_properties_reply(struct modem_data *modem,
1588                                         DBusMessageIter *dict)
1589 {
1590         DBG("%s", modem->path);
1591
1592         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1593                 DBusMessageIter entry, value;
1594                 const char *key;
1595
1596                 dbus_message_iter_recurse(dict, &entry);
1597                 dbus_message_iter_get_basic(&entry, &key);
1598
1599                 dbus_message_iter_next(&entry);
1600                 dbus_message_iter_recurse(&entry, &value);
1601
1602                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1603                         char *imsi;
1604
1605                         dbus_message_iter_get_basic(&value, &imsi);
1606
1607                         update_sim_imsi(modem, imsi);
1608
1609                         if (modem->online == FALSE) {
1610                                 modem_set_online(modem);
1611                                 break;
1612                         }
1613
1614                         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1615                                 if (ready_to_create_device(modem) == TRUE)
1616                                         create_device(modem);
1617                                 if (modem->device != NULL) {
1618                                         cm_get_properties(modem);
1619                                         cm_get_contexts(modem);
1620                                 }
1621                         } else if (has_interface(modem->interfaces,
1622                                         OFONO_API_CDMA_CM) == TRUE) {
1623                                 if (ready_to_create_device(modem) == TRUE)
1624                                         create_device(modem);
1625                                 if (modem->device != NULL)
1626                                         cdma_cm_get_properties(modem);
1627                         }
1628                         return;
1629                 }
1630
1631                 dbus_message_iter_next(dict);
1632         }
1633 }
1634
1635 static int sim_get_properties(struct modem_data *modem)
1636 {
1637         return get_properties(modem->path, OFONO_SIM_INTERFACE,
1638                         sim_properties_reply, modem);
1639 }
1640
1641 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
1642                                 void *user_data)
1643 {
1644         const char *path = dbus_message_get_path(message);
1645         struct modem_data *modem;
1646         DBusMessageIter iter, value;
1647         const char *key;
1648
1649         modem = g_hash_table_lookup(modem_hash, path);
1650         if (modem == NULL)
1651                 return TRUE;
1652
1653         if (modem->ignore == TRUE)
1654                 return TRUE;
1655
1656         if (dbus_message_iter_init(message, &iter) == FALSE)
1657                 return TRUE;
1658
1659         dbus_message_iter_get_basic(&iter, &key);
1660
1661         dbus_message_iter_next(&iter);
1662         dbus_message_iter_recurse(&iter, &value);
1663
1664         if (g_str_equal(key, "Powered") == TRUE) {
1665                 dbus_message_iter_get_basic(&value, &modem->powered);
1666
1667                 DBG("%s Powered %d", modem->path, modem->powered);
1668
1669                 if (modem->powered == FALSE)
1670                         modem_set_powered(modem);
1671         } else if (g_str_equal(key, "Online") == TRUE) {
1672                 dbus_message_iter_get_basic(&value, &modem->online);
1673
1674                 DBG("%s Online %d", modem->path, modem->online);
1675
1676                 if (modem->online == FALSE)
1677                         return TRUE;
1678
1679                 if (has_interface(modem->interfaces, OFONO_API_CM) == FALSE) {
1680                         if (ready_to_create_device(modem) == TRUE)
1681                                 create_device(modem);
1682                         if (modem->device != NULL) {
1683                                 cm_get_properties(modem);
1684                                 cm_get_contexts(modem);
1685                         }
1686                 } else if (has_interface(modem->interfaces,
1687                                                 OFONO_API_CDMA_CM) == TRUE) {
1688                         if (ready_to_create_device(modem) == TRUE)
1689                                 create_device(modem);
1690                         if (modem->device != NULL) {
1691                                 cdma_cm_get_properties(modem);
1692                                 cdma_netreg_get_properties(modem);
1693                         }
1694                 }
1695         } else if (g_str_equal(key, "Interfaces") == TRUE) {
1696                 modem->interfaces = extract_interfaces(&value);
1697
1698                 DBG("%s Interfaces 0x%02x", modem->path,
1699                         modem->interfaces);
1700
1701                 if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
1702                         if (modem->imsi == NULL &&
1703                                         modem->set_powered == FALSE) {
1704                                 /*
1705                                  * Only use do GetProperties() when
1706                                  * device has not been powered up.
1707                                  */
1708                                 sim_get_properties(modem);
1709                                 return TRUE;
1710                         }
1711                 }
1712
1713                 if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1714                         if (ready_to_create_device(modem) == TRUE)
1715                                 create_device(modem);
1716                         if (modem->device != NULL) {
1717                                 cm_get_properties(modem);
1718                                 cm_get_contexts(modem);
1719                                 return TRUE;
1720                         }
1721                 } else if (has_interface(modem->interfaces,
1722                                         OFONO_API_CDMA_CM) == TRUE) {
1723                                 if (ready_to_create_device(modem) == TRUE)
1724                                         create_device(modem);
1725                                 if (modem->device != NULL)
1726                                         cdma_cm_get_properties(modem);
1727                 } else {
1728                         if (modem->context != NULL) {
1729                                 remove_cm_context(modem,
1730                                                 modem->context->path);
1731                         }
1732
1733                         if (modem->device != NULL)
1734                                 destroy_device(modem);
1735
1736                         return TRUE;
1737                 }
1738
1739                 if (has_interface(modem->interfaces, OFONO_API_NETREG) == TRUE) {
1740                         if (modem->attached == TRUE)
1741                                 netreg_get_properties(modem);
1742                 } else if (has_interface(modem->interfaces,
1743                                 OFONO_API_CDMA_NETREG) == TRUE)
1744                         cdma_netreg_get_properties(modem);
1745         } else if (g_str_equal(key, "Serial") == TRUE) {
1746                 char *serial;
1747
1748                 dbus_message_iter_get_basic(&value, &serial);
1749
1750                 g_free(modem->serial);
1751                 modem->serial = g_strdup(serial);
1752
1753                 DBG("%s Serial %s", modem->path, modem->serial);
1754
1755                 if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1756                         if (ready_to_create_device(modem) == TRUE)
1757                                 create_device(modem);
1758                         if (modem->device != NULL) {
1759                                 cm_get_properties(modem);
1760                                 cm_get_contexts(modem);
1761                         }
1762                 } else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM)
1763                                 == TRUE) {
1764                         if (ready_to_create_device(modem) == TRUE)
1765                                 create_device(modem);
1766                         if (modem->device != NULL)
1767                                 cdma_cm_get_properties(modem);
1768                 }
1769         }
1770
1771         return TRUE;
1772 }
1773
1774 static void add_modem(const char *path, DBusMessageIter *prop)
1775 {
1776         struct modem_data *modem;
1777
1778         DBG("%s", path);
1779
1780         modem = g_hash_table_lookup(modem_hash, path);
1781         if (modem != NULL) {
1782                 /*
1783                  * When oFono powers up we ask for the modems and oFono is
1784                  * reporting with modem_added signal the modems. Only
1785                  * handle them once.
1786                  */
1787                 return;
1788         }
1789
1790         modem = g_try_new0(struct modem_data, 1);
1791         if (modem == NULL)
1792                 return;
1793
1794         modem->path = g_strdup(path);
1795
1796         g_hash_table_insert(modem_hash, g_strdup(path), modem);
1797
1798         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
1799                 DBusMessageIter entry, value;
1800                 const char *key;
1801
1802                 dbus_message_iter_recurse(prop, &entry);
1803                 dbus_message_iter_get_basic(&entry, &key);
1804
1805                 dbus_message_iter_next(&entry);
1806                 dbus_message_iter_recurse(&entry, &value);
1807
1808                 if (g_str_equal(key, "Powered") == TRUE) {
1809                         dbus_message_iter_get_basic(&value, &modem->powered);
1810
1811                         DBG("%s Powered %d", modem->path, modem->powered);
1812                 } else if (g_str_equal(key, "Online") == TRUE) {
1813                         dbus_message_iter_get_basic(&value, &modem->online);
1814
1815                         DBG("%s Online %d", modem->path, modem->online);
1816                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
1817                         modem->interfaces = extract_interfaces(&value);
1818
1819                         DBG("%s Interfaces 0x%02x", modem->path,
1820                                 modem->interfaces);
1821                 } else if (g_str_equal(key, "Serial") == TRUE) {
1822                         char *serial;
1823
1824                         dbus_message_iter_get_basic(&value, &serial);
1825                         modem->serial = g_strdup(serial);
1826
1827                         DBG("%s Serial %s", modem->path, modem->serial);
1828                 } else if (g_str_equal(key, "Type") == TRUE) {
1829                         char *type;
1830
1831                         dbus_message_iter_get_basic(&value, &type);
1832
1833                         DBG("%s Type %s", modem->path, type);
1834                         if (g_strcmp0(type, "hardware") != 0) {
1835                                 DBG("%s Ignore this modem", modem->path);
1836                                 modem->ignore = TRUE;
1837                         }
1838                 }
1839
1840                 dbus_message_iter_next(prop);
1841         }
1842
1843         if (modem->ignore == TRUE)
1844                 return;
1845
1846         if (modem->powered == FALSE) {
1847                 modem_set_powered(modem);
1848         } else if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
1849                 sim_get_properties(modem);
1850         } else if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1851                 if (ready_to_create_device(modem) == TRUE)
1852                         create_device(modem);
1853                 if (modem->device != NULL) {
1854                         cm_get_properties(modem);
1855                         cm_get_contexts(modem);
1856                 }
1857         } else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM)
1858                         == TRUE) {
1859                 if (ready_to_create_device(modem) == TRUE)
1860                         create_device(modem);
1861                 if (modem->device != NULL)
1862                         cdma_cm_get_properties(modem);
1863         }
1864 }
1865
1866 static void modem_power_down(gpointer key, gpointer value, gpointer user_data)
1867 {
1868         struct modem_data *modem = value;
1869
1870         DBG("%s", modem->path);
1871
1872         if (modem->ignore ==  TRUE)
1873                 return;
1874
1875         modem_set_unpowered(modem);
1876 }
1877
1878 static void remove_modem(gpointer data)
1879 {
1880         struct modem_data *modem = data;
1881
1882         DBG("%s", modem->path);
1883
1884         if (modem->call_set_property != NULL)
1885                 dbus_pending_call_cancel(modem->call_set_property);
1886
1887         if (modem->call_get_properties != NULL)
1888                 dbus_pending_call_cancel(modem->call_get_properties);
1889
1890         if (modem->call_get_contexts != NULL)
1891                 dbus_pending_call_cancel(modem->call_get_contexts);
1892
1893         if (modem->device != NULL)
1894                 destroy_device(modem);
1895
1896         if (modem->context != NULL)
1897                 remove_cm_context(modem, modem->context->path);
1898
1899         g_free(modem->serial);
1900         g_free(modem->name);
1901         g_free(modem->imsi);
1902         g_free(modem->path);
1903
1904         g_free(modem);
1905 }
1906
1907 static gboolean modem_added(DBusConnection *connection,
1908                                 DBusMessage *message, void *user_data)
1909 {
1910         DBusMessageIter iter, properties;
1911         const char *path;
1912
1913         DBG("");
1914
1915         if (dbus_message_iter_init(message, &iter) == FALSE)
1916                 return TRUE;
1917
1918         dbus_message_iter_get_basic(&iter, &path);
1919
1920         dbus_message_iter_next(&iter);
1921         dbus_message_iter_recurse(&iter, &properties);
1922
1923         add_modem(path, &properties);
1924
1925         return TRUE;
1926 }
1927
1928 static gboolean modem_removed(DBusConnection *connection,
1929                                 DBusMessage *message, void *user_data)
1930 {
1931         DBusMessageIter iter;
1932         const char *path;
1933
1934         DBG("");
1935
1936         if (dbus_message_iter_init(message, &iter) == FALSE)
1937                 return TRUE;
1938
1939         dbus_message_iter_get_basic(&iter, &path);
1940
1941         g_hash_table_remove(modem_hash, path);
1942
1943         return TRUE;
1944 }
1945
1946 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
1947 {
1948         DBusMessage *reply;
1949         DBusError error;
1950         DBusMessageIter array, dict;
1951
1952         DBG("");
1953
1954         reply = dbus_pending_call_steal_reply(call);
1955
1956         dbus_error_init(&error);
1957
1958         if (dbus_set_error_from_message(&error, reply) == TRUE) {
1959                 connman_error("%s", error.message);
1960                 dbus_error_free(&error);
1961                 goto done;
1962         }
1963
1964         if (dbus_message_iter_init(reply, &array) == FALSE)
1965                 goto done;
1966
1967         dbus_message_iter_recurse(&array, &dict);
1968
1969         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
1970                 DBusMessageIter value, properties;
1971                 const char *path;
1972
1973                 dbus_message_iter_recurse(&dict, &value);
1974                 dbus_message_iter_get_basic(&value, &path);
1975
1976                 dbus_message_iter_next(&value);
1977                 dbus_message_iter_recurse(&value, &properties);
1978
1979                 add_modem(path, &properties);
1980
1981                 dbus_message_iter_next(&dict);
1982         }
1983
1984 done:
1985         dbus_message_unref(reply);
1986
1987         dbus_pending_call_unref(call);
1988 }
1989
1990 static int manager_get_modems(void)
1991 {
1992         DBusMessage *message;
1993         DBusPendingCall *call;
1994
1995         DBG("");
1996
1997         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
1998                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
1999         if (message == NULL)
2000                 return -ENOMEM;
2001
2002         if (dbus_connection_send_with_reply(connection, message,
2003                                                &call, TIMEOUT) == FALSE) {
2004                 connman_error("Failed to call GetModems()");
2005                 dbus_message_unref(message);
2006                 return -EINVAL;
2007         }
2008
2009         if (call == NULL) {
2010                 connman_error("D-Bus connection not available");
2011                 dbus_message_unref(message);
2012                 return -EINVAL;
2013         }
2014
2015         dbus_pending_call_set_notify(call, manager_get_modems_reply,
2016                                         NULL, NULL);
2017
2018         dbus_message_unref(message);
2019
2020         return -EINPROGRESS;
2021 }
2022
2023 static void ofono_connect(DBusConnection *conn, void *user_data)
2024 {
2025         DBG("");
2026
2027         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2028                                                 g_free, remove_modem);
2029         if (modem_hash == NULL)
2030                 return;
2031
2032         context_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2033                                                 g_free, NULL);
2034         if (context_hash == NULL) {
2035                 g_hash_table_destroy(modem_hash);
2036                 return;
2037         }
2038
2039         manager_get_modems();
2040 }
2041
2042 static void ofono_disconnect(DBusConnection *conn, void *user_data)
2043 {
2044         DBG("");
2045
2046         if (modem_hash == NULL || context_hash == NULL)
2047                 return;
2048
2049         g_hash_table_destroy(modem_hash);
2050         modem_hash = NULL;
2051
2052         g_hash_table_destroy(context_hash);
2053         context_hash = NULL;
2054 }
2055
2056 static int network_probe(struct connman_network *network)
2057 {
2058         struct modem_data *modem = connman_network_get_data(network);
2059
2060         DBG("%s network %p", modem->path, network);
2061
2062         return 0;
2063 }
2064
2065 static void network_remove(struct connman_network *network)
2066 {
2067         struct modem_data *modem = connman_network_get_data(network);
2068
2069         DBG("%s network %p", modem->path, network);
2070 }
2071
2072 static int network_connect(struct connman_network *network)
2073 {
2074         struct modem_data *modem = connman_network_get_data(network);
2075
2076         DBG("%s network %p", modem->path, network);
2077
2078         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE)
2079                 return context_set_active(modem);
2080         else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM) == TRUE)
2081                 return cdma_cm_set_powered(modem);
2082
2083         connman_error("Connection manager interface not available");
2084
2085         return -ENOSYS;
2086 }
2087
2088 static int network_disconnect(struct connman_network *network)
2089 {
2090         struct modem_data *modem = connman_network_get_data(network);
2091
2092         DBG("%s network %p", modem->path, network);
2093
2094         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE)
2095                 return context_set_inactive(modem);
2096         else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM) == TRUE)
2097                 return cdma_cm_shutdown(modem);
2098
2099         connman_error("Connection manager interface not available");
2100
2101         return -ENOSYS;
2102 }
2103
2104 static struct connman_network_driver network_driver = {
2105         .name           = "network",
2106         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
2107         .probe          = network_probe,
2108         .remove         = network_remove,
2109         .connect        = network_connect,
2110         .disconnect     = network_disconnect,
2111 };
2112
2113 static int modem_probe(struct connman_device *device)
2114 {
2115         struct modem_data *modem = connman_device_get_data(device);
2116
2117         DBG("%s device %p", modem->path, device);
2118
2119         return 0;
2120 }
2121
2122 static void modem_remove(struct connman_device *device)
2123 {
2124         struct modem_data *modem = connman_device_get_data(device);
2125
2126         DBG("%s device %p", modem->path, device);
2127 }
2128
2129 static int modem_enable(struct connman_device *device)
2130 {
2131         struct modem_data *modem = connman_device_get_data(device);
2132
2133         DBG("%s device %p", modem->path, device);
2134
2135         return 0;
2136 }
2137
2138 static int modem_disable(struct connman_device *device)
2139 {
2140         struct modem_data *modem = connman_device_get_data(device);
2141
2142         DBG("%s device %p", modem->path, device);
2143
2144         return 0;
2145 }
2146
2147 static struct connman_device_driver modem_driver = {
2148         .name           = "modem",
2149         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
2150         .probe          = modem_probe,
2151         .remove         = modem_remove,
2152         .enable         = modem_enable,
2153         .disable        = modem_disable,
2154 };
2155
2156 static guint watch;
2157 static guint modem_added_watch;
2158 static guint modem_removed_watch;
2159 static guint modem_watch;
2160 static guint cm_watch;
2161 static guint sim_watch;
2162 static guint context_added_watch;
2163 static guint context_removed_watch;
2164 static guint netreg_watch;
2165 static guint context_watch;
2166
2167 static int ofono_init(void)
2168 {
2169         int err;
2170
2171         DBG("");
2172
2173         connection = connman_dbus_get_connection();
2174         if (connection == NULL)
2175                 return -EIO;
2176
2177         watch = g_dbus_add_service_watch(connection,
2178                                         OFONO_SERVICE, ofono_connect,
2179                                         ofono_disconnect, NULL, NULL);
2180
2181         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2182                                                 OFONO_MANAGER_INTERFACE,
2183                                                 MODEM_ADDED,
2184                                                 modem_added,
2185                                                 NULL, NULL);
2186
2187         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2188                                                 OFONO_MANAGER_INTERFACE,
2189                                                 MODEM_REMOVED,
2190                                                 modem_removed,
2191                                                 NULL, NULL);
2192
2193         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2194                                                 OFONO_MODEM_INTERFACE,
2195                                                 PROPERTY_CHANGED,
2196                                                 modem_changed,
2197                                                 NULL, NULL);
2198
2199         cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2200                                                 OFONO_CM_INTERFACE,
2201                                                 PROPERTY_CHANGED,
2202                                                 cm_changed,
2203                                                 NULL, NULL);
2204
2205         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2206                                                 OFONO_SIM_INTERFACE,
2207                                                 PROPERTY_CHANGED,
2208                                                 sim_changed,
2209                                                 NULL, NULL);
2210
2211         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2212                                                 OFONO_CM_INTERFACE,
2213                                                 CONTEXT_ADDED,
2214                                                 cm_context_added,
2215                                                 NULL, NULL);
2216
2217         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2218                                                 OFONO_CM_INTERFACE,
2219                                                 CONTEXT_REMOVED,
2220                                                 cm_context_removed,
2221                                                 NULL, NULL);
2222
2223         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2224                                                 OFONO_CONTEXT_INTERFACE,
2225                                                 PROPERTY_CHANGED,
2226                                                 context_changed,
2227                                                 NULL, NULL);
2228
2229         netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2230                                                 OFONO_NETREG_INTERFACE,
2231                                                 PROPERTY_CHANGED,
2232                                                 netreg_changed,
2233                                                 NULL, NULL);
2234
2235
2236         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
2237                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
2238                         context_added_watch == 0 ||
2239                         context_removed_watch == 0 ||
2240                         context_watch == 0 || netreg_watch == 0) {
2241                 err = -EIO;
2242                 goto remove;
2243         }
2244
2245         err = connman_network_driver_register(&network_driver);
2246         if (err < 0)
2247                 goto remove;
2248
2249         err = connman_device_driver_register(&modem_driver);
2250         if (err < 0) {
2251                 connman_network_driver_unregister(&network_driver);
2252                 goto remove;
2253         }
2254
2255         return 0;
2256
2257 remove:
2258         g_dbus_remove_watch(connection, netreg_watch);
2259         g_dbus_remove_watch(connection, context_watch);
2260         g_dbus_remove_watch(connection, context_removed_watch);
2261         g_dbus_remove_watch(connection, context_added_watch);
2262         g_dbus_remove_watch(connection, sim_watch);
2263         g_dbus_remove_watch(connection, cm_watch);
2264         g_dbus_remove_watch(connection, modem_watch);
2265         g_dbus_remove_watch(connection, modem_removed_watch);
2266         g_dbus_remove_watch(connection, modem_added_watch);
2267         g_dbus_remove_watch(connection, watch);
2268         dbus_connection_unref(connection);
2269
2270         return err;
2271 }
2272
2273 static void ofono_exit(void)
2274 {
2275         DBG("");
2276
2277         if (modem_hash != NULL) {
2278                 /*
2279                  * We should propably wait for the SetProperty() reply
2280                  * message, because ...
2281                  */
2282                 g_hash_table_foreach(modem_hash, modem_power_down, NULL);
2283
2284                 /*
2285                  * ... here we will cancel the call.
2286                  */
2287                 g_hash_table_destroy(modem_hash);
2288                 modem_hash = NULL;
2289         }
2290
2291         if (context_hash != NULL) {
2292                 g_hash_table_destroy(context_hash);
2293                 context_hash = NULL;
2294         }
2295
2296         connman_device_driver_unregister(&modem_driver);
2297         connman_network_driver_unregister(&network_driver);
2298
2299         g_dbus_remove_watch(connection, netreg_watch);
2300         g_dbus_remove_watch(connection, context_watch);
2301         g_dbus_remove_watch(connection, context_removed_watch);
2302         g_dbus_remove_watch(connection, context_added_watch);
2303         g_dbus_remove_watch(connection, sim_watch);
2304         g_dbus_remove_watch(connection, cm_watch);
2305         g_dbus_remove_watch(connection, modem_watch);
2306         g_dbus_remove_watch(connection, modem_added_watch);
2307         g_dbus_remove_watch(connection, modem_removed_watch);
2308         g_dbus_remove_watch(connection, watch);
2309
2310         dbus_connection_unref(connection);
2311 }
2312
2313 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
2314                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)