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