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