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