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