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