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