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