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