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