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