Remove WPA2 and WPA3 service together
[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 signal.
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 signal.
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(AF_INET);
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(AF_INET6);
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         list = modem->context_list;
1305         while (list) {
1306                 struct network_context *context = list->data;
1307
1308                 remove_cm_context(modem, context);
1309
1310                 list = modem->context_list;
1311         }
1312         g_slist_free(modem->context_list);
1313         modem->context_list = NULL;
1314 }
1315
1316 static void remove_all_networks(struct modem_data *modem)
1317 {
1318         GSList *list;
1319
1320         for (list = modem->context_list; list; list = list->next) {
1321                 struct network_context *context = list->data;
1322
1323                 remove_network(modem, context);
1324         }
1325 }
1326
1327 static gboolean context_changed(DBusConnection *conn,
1328                                 DBusMessage *message,
1329                                 void *user_data)
1330 {
1331         struct network_context *context = NULL;
1332         const char *context_path = dbus_message_get_path(message);
1333         struct modem_data *modem = NULL;
1334         DBusMessageIter iter, value;
1335         const char *key;
1336
1337         DBG("context_path %s", context_path);
1338
1339         modem = g_hash_table_lookup(context_hash, context_path);
1340         if (!modem)
1341                 return TRUE;
1342
1343         context = get_context_with_path(modem->context_list, context_path);
1344         if (!context)
1345                 return TRUE;
1346
1347         if (!dbus_message_iter_init(message, &iter))
1348                 return TRUE;
1349
1350         dbus_message_iter_get_basic(&iter, &key);
1351
1352         dbus_message_iter_next(&iter);
1353         dbus_message_iter_recurse(&iter, &value);
1354
1355         /*
1356          * oFono guarantees the ordering of Settings and
1357          * Active. Settings will always be send before Active = True.
1358          * That means we don't have to order here.
1359          */
1360         if (g_str_equal(key, "Settings")) {
1361                 DBG("%s Settings", modem->path);
1362
1363                 extract_ipv4_settings(&value, context);
1364         } else if (g_str_equal(key, "IPv6.Settings")) {
1365                 DBG("%s IPv6.Settings", modem->path);
1366
1367                 extract_ipv6_settings(&value, context);
1368         } else if (g_str_equal(key, "Active")) {
1369                 dbus_bool_t active;
1370
1371                 dbus_message_iter_get_basic(&value, &active);
1372                 context->active = active;
1373
1374                 DBG("%s Active %d", modem->path, context->active);
1375
1376                 if (context->active)
1377                         set_connected(modem, context);
1378                 else
1379                         set_disconnected(context);
1380         } else if (g_str_equal(key, "AccessPointName")) {
1381                 const char *apn;
1382
1383                 dbus_message_iter_get_basic(&value, &apn);
1384
1385                 DBG("%s AccessPointName %s", modem->path, apn);
1386
1387                 if (apn && strlen(apn) > 0) {
1388                         context->valid_apn = true;
1389
1390                         if (context->network)
1391                                 return TRUE;
1392
1393                         if (!modem->attached)
1394                                 return TRUE;
1395
1396                         if (!has_interface(modem->interfaces,
1397                                                 OFONO_API_NETREG))
1398                                 return TRUE;
1399
1400                         add_network(modem, context);
1401
1402                         if (context->active)
1403                                 set_connected(modem, context);
1404                 } else {
1405                         context->valid_apn = false;
1406
1407                         if (!context->network)
1408                                 return TRUE;
1409
1410                         remove_network(modem, context);
1411                 }
1412
1413         } else if (g_str_equal(key, "Protocol") &&
1414                 dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING ) {
1415                 const char *ip_protocol;
1416
1417                 dbus_message_iter_get_basic(&value, &ip_protocol);
1418
1419                 set_context_ipconfig(context, ip_protocol);
1420         }
1421
1422         return TRUE;
1423 }
1424
1425 static void cm_get_contexts_reply(DBusPendingCall *call, void *user_data)
1426 {
1427         struct modem_data *modem = user_data;
1428         DBusMessageIter array, dict, entry, value;
1429         DBusMessage *reply;
1430         DBusError error;
1431
1432         DBG("%s", modem->path);
1433
1434         modem->call_get_contexts = NULL;
1435
1436         reply = dbus_pending_call_steal_reply(call);
1437
1438         dbus_error_init(&error);
1439
1440         if (dbus_set_error_from_message(&error, reply)) {
1441                 connman_error("%s", error.message);
1442                 dbus_error_free(&error);
1443                 goto done;
1444         }
1445
1446         if (!dbus_message_iter_init(reply, &array))
1447                 goto done;
1448
1449         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1450                 goto done;
1451
1452         dbus_message_iter_recurse(&array, &dict);
1453
1454         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
1455                 const char *context_path;
1456
1457                 dbus_message_iter_recurse(&dict, &entry);
1458                 dbus_message_iter_get_basic(&entry, &context_path);
1459
1460                 dbus_message_iter_next(&entry);
1461                 dbus_message_iter_recurse(&entry, &value);
1462
1463                 if (add_cm_context(modem, context_path, &value))
1464                         break;
1465
1466                 dbus_message_iter_next(&dict);
1467         }
1468
1469 done:
1470         dbus_message_unref(reply);
1471
1472         dbus_pending_call_unref(call);
1473 }
1474
1475 static int cm_get_contexts(struct modem_data *modem)
1476 {
1477         DBusMessage *message;
1478
1479         DBG("%s", modem->path);
1480
1481         if (modem->call_get_contexts)
1482                 return -EBUSY;
1483
1484         message = dbus_message_new_method_call(OFONO_SERVICE, modem->path,
1485                                         OFONO_CM_INTERFACE, GET_CONTEXTS);
1486         if (!message)
1487                 return -ENOMEM;
1488
1489         if (!dbus_connection_send_with_reply(connection, message,
1490                                         &modem->call_get_contexts, TIMEOUT)) {
1491                 connman_error("Failed to call GetContexts()");
1492                 dbus_message_unref(message);
1493                 return -EINVAL;
1494         }
1495
1496         if (!modem->call_get_contexts) {
1497                 connman_error("D-Bus connection not available");
1498                 dbus_message_unref(message);
1499                 return -EINVAL;
1500         }
1501
1502         dbus_pending_call_set_notify(modem->call_get_contexts,
1503                                         cm_get_contexts_reply,
1504                                         modem, NULL);
1505
1506         dbus_message_unref(message);
1507
1508         return -EINPROGRESS;
1509 }
1510
1511 static gboolean cm_context_added(DBusConnection *conn,
1512                                         DBusMessage *message,
1513                                         void *user_data)
1514 {
1515         const char *path = dbus_message_get_path(message);
1516         char *context_path;
1517         struct modem_data *modem;
1518         DBusMessageIter iter, properties, dict;
1519
1520         DBG("%s", path);
1521
1522         modem = g_hash_table_lookup(modem_hash, path);
1523         if (!modem)
1524                 return TRUE;
1525
1526         if (!dbus_message_iter_init(message, &iter))
1527                 return TRUE;
1528
1529         dbus_message_iter_get_basic(&iter, &context_path);
1530
1531         dbus_message_iter_next(&iter);
1532         dbus_message_iter_recurse(&iter, &properties);
1533
1534         /* Sometimes, we get an array instead of dict */
1535         if (dbus_message_iter_get_arg_type(&properties) == DBUS_TYPE_ARRAY) {
1536                 /* Must recurse again */
1537                 dbus_message_iter_recurse(&properties, &dict);
1538                 if (add_cm_context(modem, context_path, &dict) != 0)
1539                         return TRUE;
1540         }
1541         if (add_cm_context(modem, context_path, &properties) != 0)
1542                 return TRUE;
1543
1544         return TRUE;
1545 }
1546
1547 static gboolean cm_context_removed(DBusConnection *conn,
1548                                         DBusMessage *message,
1549                                         void *user_data)
1550 {
1551         const char *path = dbus_message_get_path(message);
1552         const char *context_path;
1553         struct modem_data *modem;
1554         struct network_context *context;
1555         DBusMessageIter iter;
1556
1557         DBG("context path %s", path);
1558
1559         if (!dbus_message_iter_init(message, &iter))
1560                 return TRUE;
1561
1562         dbus_message_iter_get_basic(&iter, &context_path);
1563
1564         modem = g_hash_table_lookup(context_hash, context_path);
1565         if (!modem)
1566                 return TRUE;
1567
1568         context = get_context_with_path(modem->context_list, context_path);
1569         remove_cm_context(modem, context);
1570
1571         return TRUE;
1572 }
1573
1574 static void netreg_update_name(struct modem_data *modem,
1575                                 DBusMessageIter* value)
1576 {
1577         char *name;
1578         GSList *list;
1579
1580         dbus_message_iter_get_basic(value, &name);
1581
1582         DBG("%s Name %s", modem->path, name);
1583
1584         g_free(modem->name);
1585         modem->name = g_strdup(name);
1586
1587         if (!modem->context_list)
1588                 return;
1589
1590         /* For all the context */
1591         for (list = modem->context_list; list; list = list->next) {
1592                 struct network_context *context = list->data;
1593
1594                 if (context->network) {
1595                         connman_network_set_name(context->network, modem->name);
1596                         connman_network_update(context->network);
1597                 }
1598         }
1599 }
1600
1601 static void netreg_update_strength(struct modem_data *modem,
1602                                         DBusMessageIter *value)
1603 {
1604         GSList *list;
1605
1606         dbus_message_iter_get_basic(value, &modem->strength);
1607
1608         DBG("%s Strength %d", modem->path, modem->strength);
1609
1610         if (!modem->context_list)
1611                 return;
1612
1613         /*
1614          * GSM:
1615          * We don't have 2 signal notifications we always report the strength
1616          * signal. data_strength is always equal to 0.
1617          *
1618          * CDMA:
1619          * In the case we have a data_strength signal (from 1xEVDO network)
1620          * we don't need to update the value with strength signal (from 1xCDMA)
1621          * because the modem is registered to 1xEVDO network for data call.
1622          * In case we have no data_strength signal (not registered to 1xEVDO
1623          * network), we must report the strength signal (registered to 1xCDMA
1624          * network e.g slow mode).
1625          */
1626         if (modem->data_strength != 0)
1627                 return;
1628
1629         /* For all the context */
1630         for (list = modem->context_list; list; list = list->next) {
1631                 struct network_context *context = list->data;
1632
1633                 if (context->network) {
1634                         connman_network_set_strength(context->network,
1635                                                         modem->strength);
1636                         connman_network_update(context->network);
1637                 }
1638         }
1639 }
1640
1641 /* Retrieve 1xEVDO Data Strength signal */
1642 static void netreg_update_datastrength(struct modem_data *modem,
1643                                         DBusMessageIter *value)
1644 {
1645         GSList *list;
1646
1647         dbus_message_iter_get_basic(value, &modem->data_strength);
1648
1649         DBG("%s Data Strength %d", modem->path, modem->data_strength);
1650
1651         if (!modem->context_list)
1652                 return;
1653
1654         /*
1655          * CDMA modem is not registered to 1xEVDO network, let
1656          * update_signal_strength() reporting the value on the Strength signal
1657          * notification.
1658          */
1659         if (modem->data_strength == 0)
1660                 return;
1661
1662         /* For all the context */
1663         for (list = modem->context_list; list; list = list->next) {
1664                 struct network_context *context = list->data;
1665
1666                 if (context->network) {
1667                         connman_network_set_strength(context->network,
1668                                                         modem->data_strength);
1669                         connman_network_update(context->network);
1670                 }
1671         }
1672 }
1673
1674 static void netreg_update_status(struct modem_data *modem,
1675                                         DBusMessageIter *value)
1676 {
1677         char *status;
1678         bool roaming;
1679         GSList *list;
1680
1681         dbus_message_iter_get_basic(value, &status);
1682
1683         roaming = g_str_equal(status, "roaming");
1684         modem->registered = roaming || g_str_equal(status, "registered");
1685
1686         if (roaming == modem->roaming)
1687                 return;
1688
1689         modem->roaming = roaming;
1690
1691         if (!modem->context_list)
1692                 return;
1693
1694         /* For all the context */
1695         for (list = modem->context_list; list; list = list->next) {
1696                 struct network_context *context = list->data;
1697
1698                 if (context->network) {
1699                         connman_network_set_bool(context->network,
1700                                 "Roaming", modem->roaming);
1701                         connman_network_update(context->network);
1702                 }
1703         }
1704 }
1705
1706 static void netreg_update_regdom(struct modem_data *modem,
1707                                 DBusMessageIter *value)
1708 {
1709         char *mobile_country_code;
1710         char *alpha2;
1711         int mcc;
1712
1713         dbus_message_iter_get_basic(value, &mobile_country_code);
1714
1715         DBG("%s MobileContryCode %s", modem->path, mobile_country_code);
1716
1717
1718         mcc = atoi(mobile_country_code);
1719         if (mcc > 799 || mcc < 200)
1720                 return;
1721
1722         alpha2 = mcc_country_codes[mcc - 200];
1723         if (alpha2)
1724                 connman_technology_set_regdom(alpha2);
1725 }
1726
1727 static gboolean netreg_changed(DBusConnection *conn, DBusMessage *message,
1728                                 void *user_data)
1729 {
1730         const char *path = dbus_message_get_path(message);
1731         struct modem_data *modem;
1732         DBusMessageIter iter, value;
1733         const char *key;
1734
1735         modem = g_hash_table_lookup(modem_hash, path);
1736         if (!modem)
1737                 return TRUE;
1738
1739         if (modem->ignore)
1740                 return TRUE;
1741
1742         if (!dbus_message_iter_init(message, &iter))
1743                 return TRUE;
1744
1745         dbus_message_iter_get_basic(&iter, &key);
1746
1747         dbus_message_iter_next(&iter);
1748         dbus_message_iter_recurse(&iter, &value);
1749
1750         if (g_str_equal(key, "Name"))
1751                 netreg_update_name(modem, &value);
1752         else if (g_str_equal(key, "Strength"))
1753                 netreg_update_strength(modem, &value);
1754         else if (g_str_equal(key, "Status"))
1755                 netreg_update_status(modem, &value);
1756         else if (g_str_equal(key, "MobileCountryCode"))
1757                 netreg_update_regdom(modem, &value);
1758
1759         return TRUE;
1760 }
1761
1762 static void netreg_properties_reply(struct modem_data *modem,
1763                                         DBusMessageIter *dict)
1764 {
1765         GSList *list = NULL;
1766
1767         DBG("%s", modem->path);
1768
1769         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1770                 DBusMessageIter entry, value;
1771                 const char *key;
1772
1773                 dbus_message_iter_recurse(dict, &entry);
1774                 dbus_message_iter_get_basic(&entry, &key);
1775
1776                 dbus_message_iter_next(&entry);
1777                 dbus_message_iter_recurse(&entry, &value);
1778
1779                 if (g_str_equal(key, "Name"))
1780                         netreg_update_name(modem, &value);
1781                 else if (g_str_equal(key, "Strength"))
1782                         netreg_update_strength(modem, &value);
1783                 else if (g_str_equal(key, "Status"))
1784                         netreg_update_status(modem, &value);
1785                 else if (g_str_equal(key, "MobileCountryCode"))
1786                         netreg_update_regdom(modem, &value);
1787
1788                 dbus_message_iter_next(dict);
1789         }
1790
1791         if (!modem->context_list) {
1792                 /*
1793                  * netgreg_get_properties() was issued after we got
1794                  * cm_get_contexts_reply() where we create the
1795                  * context. Though before we got the
1796                  * netreg_properties_reply the context was removed
1797                  * again. Therefore we have to skip the network
1798                  * creation.
1799                  */
1800                 return;
1801         }
1802         /* Check for all contexts if they are valids and/or actives */
1803         for (list = modem->context_list; list; list = list->next) {
1804                 struct network_context *context = list->data;
1805
1806                 if (context->valid_apn)
1807                         add_network(modem, context);
1808                 if (context->active)
1809                         set_connected(modem, context);
1810         }
1811 }
1812
1813 static int netreg_get_properties(struct modem_data *modem)
1814 {
1815         return get_properties(modem->path, OFONO_NETREG_INTERFACE,
1816                         netreg_properties_reply, modem);
1817 }
1818
1819 static void add_cdma_network(struct modem_data *modem)
1820 {
1821         struct network_context *context = NULL;
1822         /* Be sure that device is created before adding CDMA network */
1823         if (!modem->device)
1824                 return;
1825
1826         /*
1827          * CDMA modems don't need contexts for data call, however the current
1828          * add_network() logic needs one, so we create one to proceed.
1829          */
1830         if (!modem->context_list) {
1831                 context = network_context_alloc(modem->path);
1832                 modem->context_list = g_slist_prepend(modem->context_list,
1833                                                         context);
1834         } else
1835                 context = modem->context_list->data;
1836
1837         if (!modem->name)
1838                 modem->name = g_strdup("CDMA Network");
1839
1840         add_network(modem, context);
1841
1842         if (modem->cdma_cm_powered)
1843                 set_connected(modem, context);
1844 }
1845
1846 static gboolean cdma_netreg_changed(DBusConnection *conn,
1847                                         DBusMessage *message,
1848                                         void *user_data)
1849 {
1850         const char *path = dbus_message_get_path(message);
1851         struct modem_data *modem;
1852         DBusMessageIter iter, value;
1853         const char *key;
1854
1855         DBG("");
1856
1857         modem = g_hash_table_lookup(modem_hash, path);
1858         if (!modem)
1859                 return TRUE;
1860
1861         if (modem->ignore)
1862                 return TRUE;
1863
1864         if (!dbus_message_iter_init(message, &iter))
1865                 return TRUE;
1866
1867         dbus_message_iter_get_basic(&iter, &key);
1868
1869         dbus_message_iter_next(&iter);
1870         dbus_message_iter_recurse(&iter, &value);
1871
1872         if (g_str_equal(key, "Name"))
1873                 netreg_update_name(modem, &value);
1874         else if (g_str_equal(key, "Strength"))
1875                 netreg_update_strength(modem, &value);
1876         else if (g_str_equal(key, "DataStrength"))
1877                 netreg_update_datastrength(modem, &value);
1878         else if (g_str_equal(key, "Status"))
1879                 netreg_update_status(modem, &value);
1880
1881         if (modem->registered)
1882                 add_cdma_network(modem);
1883         else
1884                 remove_all_networks(modem);
1885
1886         return TRUE;
1887 }
1888
1889 static void cdma_netreg_properties_reply(struct modem_data *modem,
1890                                         DBusMessageIter *dict)
1891 {
1892         DBG("%s", modem->path);
1893
1894         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1895                 DBusMessageIter entry, value;
1896                 const char *key;
1897
1898                 dbus_message_iter_recurse(dict, &entry);
1899                 dbus_message_iter_get_basic(&entry, &key);
1900
1901                 dbus_message_iter_next(&entry);
1902                 dbus_message_iter_recurse(&entry, &value);
1903
1904                 if (g_str_equal(key, "Name"))
1905                         netreg_update_name(modem, &value);
1906                 else if (g_str_equal(key, "Strength"))
1907                         netreg_update_strength(modem, &value);
1908                 else if (g_str_equal(key, "DataStrength"))
1909                         netreg_update_datastrength(modem, &value);
1910                 else if (g_str_equal(key, "Status"))
1911                         netreg_update_status(modem, &value);
1912
1913                 dbus_message_iter_next(dict);
1914         }
1915
1916         if (modem->registered)
1917                 add_cdma_network(modem);
1918         else
1919                 remove_all_networks(modem);
1920 }
1921
1922 static int cdma_netreg_get_properties(struct modem_data *modem)
1923 {
1924         return get_properties(modem->path, OFONO_CDMA_NETREG_INTERFACE,
1925                         cdma_netreg_properties_reply, modem);
1926 }
1927
1928 static void cm_update_attached(struct modem_data *modem,
1929                                 DBusMessageIter *value)
1930 {
1931         dbus_bool_t attached;
1932
1933         dbus_message_iter_get_basic(value, &attached);
1934         modem->attached = attached;
1935
1936         DBG("%s Attached %d", modem->path, modem->attached);
1937
1938         if (!modem->attached) {
1939                 remove_all_networks(modem);
1940                 return;
1941         }
1942
1943         if (!has_interface(modem->interfaces, OFONO_API_NETREG))
1944                 return;
1945
1946         netreg_get_properties(modem);
1947 }
1948
1949 static void cm_update_powered(struct modem_data *modem,
1950                                 DBusMessageIter *value)
1951 {
1952         dbus_bool_t cm_powered;
1953
1954         dbus_message_iter_get_basic(value, &cm_powered);
1955         modem->cm_powered = cm_powered;
1956
1957         DBG("%s ConnnectionManager Powered %d", modem->path,
1958                 modem->cm_powered);
1959
1960         if (modem->cm_powered)
1961                 return;
1962
1963         cm_set_powered(modem, TRUE);
1964 }
1965
1966 static gboolean cm_changed(DBusConnection *conn, DBusMessage *message,
1967                                 void *user_data)
1968 {
1969         const char *path = dbus_message_get_path(message);
1970         struct modem_data *modem;
1971         DBusMessageIter iter, value;
1972         const char *key;
1973
1974         modem = g_hash_table_lookup(modem_hash, path);
1975         if (!modem)
1976                 return TRUE;
1977
1978         if (modem->ignore)
1979                 return TRUE;
1980
1981         if (!dbus_message_iter_init(message, &iter))
1982                 return TRUE;
1983
1984         dbus_message_iter_get_basic(&iter, &key);
1985
1986         dbus_message_iter_next(&iter);
1987         dbus_message_iter_recurse(&iter, &value);
1988
1989         if (g_str_equal(key, "Attached"))
1990                 cm_update_attached(modem, &value);
1991         else if (g_str_equal(key, "Powered"))
1992                 cm_update_powered(modem, &value);
1993
1994         return TRUE;
1995 }
1996
1997 static void cdma_cm_update_powered(struct modem_data *modem,
1998                                         DBusMessageIter *value)
1999 {
2000         struct network_context *context =  NULL;
2001         dbus_bool_t cdma_cm_powered;
2002
2003         dbus_message_iter_get_basic(value, &cdma_cm_powered);
2004         modem->cdma_cm_powered = cdma_cm_powered;
2005
2006         DBG("%s CDMA cm Powered %d", modem->path, modem->cdma_cm_powered);
2007
2008         if (!modem->context_list)
2009                 return;
2010
2011         /* In case of CDMA, there is only one context */
2012         context = modem->context_list->data;
2013         if (modem->cdma_cm_powered)
2014                 set_connected(modem, context);
2015         else
2016                 set_disconnected(context);
2017 }
2018
2019 static void cdma_cm_update_settings(struct modem_data *modem,
2020                                         DBusMessageIter *value)
2021 {
2022         DBG("%s Settings", modem->path);
2023
2024         extract_ipv4_settings(value, modem->context_list->data);
2025 }
2026
2027 static gboolean cdma_cm_changed(DBusConnection *conn,
2028                                 DBusMessage *message, void *user_data)
2029 {
2030         const char *path = dbus_message_get_path(message);
2031         struct modem_data *modem;
2032         DBusMessageIter iter, value;
2033         const char *key;
2034
2035         modem = g_hash_table_lookup(modem_hash, path);
2036         if (!modem)
2037                 return TRUE;
2038
2039         if (modem->online && !modem->context_list)
2040                 cdma_netreg_get_properties(modem);
2041
2042         if (!dbus_message_iter_init(message, &iter))
2043                 return TRUE;
2044
2045         dbus_message_iter_get_basic(&iter, &key);
2046
2047         dbus_message_iter_next(&iter);
2048         dbus_message_iter_recurse(&iter, &value);
2049
2050         if (g_str_equal(key, "Powered"))
2051                 cdma_cm_update_powered(modem, &value);
2052         if (g_str_equal(key, "Settings"))
2053                 cdma_cm_update_settings(modem, &value);
2054
2055         return TRUE;
2056 }
2057
2058 static void cm_properties_reply(struct modem_data *modem, DBusMessageIter *dict)
2059 {
2060         DBG("%s", modem->path);
2061
2062         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
2063                 DBusMessageIter entry, value;
2064                 const char *key;
2065
2066                 dbus_message_iter_recurse(dict, &entry);
2067                 dbus_message_iter_get_basic(&entry, &key);
2068
2069                 dbus_message_iter_next(&entry);
2070                 dbus_message_iter_recurse(&entry, &value);
2071
2072                 if (g_str_equal(key, "Attached"))
2073                         cm_update_attached(modem, &value);
2074                 else if (g_str_equal(key, "Powered"))
2075                         cm_update_powered(modem, &value);
2076
2077                 dbus_message_iter_next(dict);
2078         }
2079 }
2080
2081 static int cm_get_properties(struct modem_data *modem)
2082 {
2083         return get_properties(modem->path, OFONO_CM_INTERFACE,
2084                                 cm_properties_reply, modem);
2085 }
2086
2087 static void cdma_cm_properties_reply(struct modem_data *modem,
2088                                         DBusMessageIter *dict)
2089 {
2090         DBG("%s", modem->path);
2091
2092         if (modem->online)
2093                 cdma_netreg_get_properties(modem);
2094
2095         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
2096                 DBusMessageIter entry, value;
2097                 const char *key;
2098
2099                 dbus_message_iter_recurse(dict, &entry);
2100                 dbus_message_iter_get_basic(&entry, &key);
2101
2102                 dbus_message_iter_next(&entry);
2103                 dbus_message_iter_recurse(&entry, &value);
2104
2105                 if (g_str_equal(key, "Powered"))
2106                         cdma_cm_update_powered(modem, &value);
2107                 if (g_str_equal(key, "Settings"))
2108                         cdma_cm_update_settings(modem, &value);
2109
2110                 dbus_message_iter_next(dict);
2111         }
2112 }
2113
2114 static int cdma_cm_get_properties(struct modem_data *modem)
2115 {
2116         return get_properties(modem->path, OFONO_CDMA_CM_INTERFACE,
2117                                 cdma_cm_properties_reply, modem);
2118 }
2119
2120 static void sim_update_imsi(struct modem_data *modem,
2121                                 DBusMessageIter *value)
2122 {
2123         char *imsi;
2124
2125         dbus_message_iter_get_basic(value, &imsi);
2126
2127         DBG("%s imsi %s", modem->path, imsi);
2128
2129         g_free(modem->imsi);
2130         modem->imsi = g_strdup(imsi);
2131 }
2132
2133 static gboolean sim_changed(DBusConnection *conn, DBusMessage *message,
2134                                 void *user_data)
2135 {
2136         const char *path = dbus_message_get_path(message);
2137         struct modem_data *modem;
2138         DBusMessageIter iter, value;
2139         const char *key;
2140
2141         modem = g_hash_table_lookup(modem_hash, path);
2142         if (!modem)
2143                 return TRUE;
2144
2145         if (modem->ignore)
2146                 return TRUE;
2147
2148         if (!dbus_message_iter_init(message, &iter))
2149                 return TRUE;
2150
2151         dbus_message_iter_get_basic(&iter, &key);
2152
2153         dbus_message_iter_next(&iter);
2154         dbus_message_iter_recurse(&iter, &value);
2155
2156         if (g_str_equal(key, "SubscriberIdentity")) {
2157                 sim_update_imsi(modem, &value);
2158
2159                 if (!ready_to_create_device(modem))
2160                         return TRUE;
2161
2162                 /*
2163                  * This is a GSM modem. Create the device and
2164                  * register it at the core. Enabling (setting
2165                  * it online is done through the
2166                  * modem_enable() callback.
2167                  */
2168                 create_device(modem);
2169         }
2170
2171         return TRUE;
2172 }
2173
2174 static void sim_properties_reply(struct modem_data *modem,
2175                                         DBusMessageIter *dict)
2176 {
2177         DBG("%s", modem->path);
2178
2179         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
2180                 DBusMessageIter entry, value;
2181                 const char *key;
2182
2183                 dbus_message_iter_recurse(dict, &entry);
2184                 dbus_message_iter_get_basic(&entry, &key);
2185
2186                 dbus_message_iter_next(&entry);
2187                 dbus_message_iter_recurse(&entry, &value);
2188
2189                 if (g_str_equal(key, "SubscriberIdentity")) {
2190                         sim_update_imsi(modem, &value);
2191
2192                         if (!ready_to_create_device(modem))
2193                                 return;
2194
2195                         /*
2196                          * This is a GSM modem. Create the device and
2197                          * register it at the core. Enabling (setting
2198                          * it online is done through the
2199                          * modem_enable() callback.
2200                          */
2201                         create_device(modem);
2202
2203                         if (!modem->online)
2204                                 return;
2205
2206                         /*
2207                          * The modem is already online and we have the CM interface.
2208                          * There will be no interface update and therefore our
2209                          * state machine will not go to next step. We have to
2210                          * trigger it from here.
2211                          */
2212                         if (has_interface(modem->interfaces, OFONO_API_CM)) {
2213                                 cm_get_properties(modem);
2214                                 cm_get_contexts(modem);
2215                         }
2216                         return;
2217                 }
2218
2219                 dbus_message_iter_next(dict);
2220         }
2221 }
2222
2223 static int sim_get_properties(struct modem_data *modem)
2224 {
2225         return get_properties(modem->path, OFONO_SIM_INTERFACE,
2226                                 sim_properties_reply, modem);
2227 }
2228
2229 static bool api_added(uint8_t old_iface, uint8_t new_iface,
2230                                 enum ofono_api api)
2231 {
2232         if (!has_interface(old_iface, api) &&
2233                         has_interface(new_iface, api)) {
2234                 DBG("%s added", api2string(api));
2235                 return true;
2236         }
2237
2238         return false;
2239 }
2240
2241 static bool api_removed(uint8_t old_iface, uint8_t new_iface,
2242                                 enum ofono_api api)
2243 {
2244         if (has_interface(old_iface, api) &&
2245                         !has_interface(new_iface, api)) {
2246                 DBG("%s removed", api2string(api));
2247                 return true;
2248         }
2249
2250         return false;
2251 }
2252
2253 static void modem_update_interfaces(struct modem_data *modem,
2254                                 uint8_t old_ifaces,
2255                                 uint8_t new_ifaces)
2256 {
2257         DBG("%s", modem->path);
2258
2259         if (api_added(old_ifaces, new_ifaces, OFONO_API_SIM)) {
2260                 if (!modem->imsi &&
2261                                 !modem->set_powered) {
2262                         /*
2263                          * Only use do GetProperties() when
2264                          * device has not been powered up.
2265                          */
2266                         sim_get_properties(modem);
2267                 }
2268         }
2269
2270         if (api_added(old_ifaces, new_ifaces, OFONO_API_CM)) {
2271                 if (modem->device) {
2272                         cm_get_properties(modem);
2273                         cm_get_contexts(modem);
2274                 }
2275         }
2276
2277         if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_CM)) {
2278                 if (ready_to_create_device(modem)) {
2279                         create_device(modem);
2280                         if (modem->registered)
2281                                 add_cdma_network(modem);
2282                 }
2283
2284                 if (modem->device)
2285                         cdma_cm_get_properties(modem);
2286         }
2287
2288         if (api_added(old_ifaces, new_ifaces, OFONO_API_NETREG)) {
2289                 if (modem->attached)
2290                         netreg_get_properties(modem);
2291         }
2292
2293         if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG))
2294                 cdma_netreg_get_properties(modem);
2295
2296         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CM)) {
2297                 if (modem->call_get_contexts) {
2298                         DBG("cancelling pending GetContexts call");
2299                         dbus_pending_call_cancel(modem->call_get_contexts);
2300                         dbus_pending_call_unref(modem->call_get_contexts);
2301                         modem->call_get_contexts = NULL;
2302                 }
2303                 remove_all_contexts(modem);
2304         }
2305
2306         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_CM))
2307                 remove_all_contexts(modem);
2308
2309         if (api_removed(old_ifaces, new_ifaces, OFONO_API_NETREG))
2310                 remove_all_networks(modem);
2311
2312         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG))
2313                 remove_all_networks(modem);
2314 }
2315
2316 static gboolean modem_changed(DBusConnection *conn, DBusMessage *message,
2317                                 void *user_data)
2318 {
2319         const char *path = dbus_message_get_path(message);
2320         struct modem_data *modem;
2321         DBusMessageIter iter, value;
2322         const char *key;
2323
2324         modem = g_hash_table_lookup(modem_hash, path);
2325         if (!modem)
2326                 return TRUE;
2327
2328         if (modem->ignore)
2329                 return TRUE;
2330
2331         if (!dbus_message_iter_init(message, &iter))
2332                 return TRUE;
2333
2334         dbus_message_iter_get_basic(&iter, &key);
2335
2336         dbus_message_iter_next(&iter);
2337         dbus_message_iter_recurse(&iter, &value);
2338
2339         if (g_str_equal(key, "Powered")) {
2340                 dbus_bool_t powered;
2341
2342                 dbus_message_iter_get_basic(&value, &powered);
2343                 modem->powered = powered;
2344
2345                 DBG("%s Powered %d", modem->path, modem->powered);
2346
2347                 /* Set the powered according to the value */
2348                 modem_set_powered(modem, powered);
2349         } else if (g_str_equal(key, "Online")) {
2350                 dbus_bool_t online;
2351
2352                 dbus_message_iter_get_basic(&value, &online);
2353                 modem->online = online;
2354
2355                 DBG("%s Online %d", modem->path, modem->online);
2356
2357                 if (!modem->device)
2358                         return TRUE;
2359
2360                 connman_device_set_powered(modem->device, modem->online);
2361         } else if (g_str_equal(key, "Interfaces")) {
2362                 uint8_t interfaces;
2363
2364                 interfaces = extract_interfaces(&value);
2365
2366                 if (interfaces == modem->interfaces)
2367                         return TRUE;
2368
2369                 DBG("%s Interfaces 0x%02x", modem->path, interfaces);
2370
2371                 modem_update_interfaces(modem, modem->interfaces, interfaces);
2372
2373                 modem->interfaces = interfaces;
2374         } else if (g_str_equal(key, "Serial")) {
2375                 char *serial;
2376
2377                 dbus_message_iter_get_basic(&value, &serial);
2378
2379                 g_free(modem->serial);
2380                 modem->serial = g_strdup(serial);
2381
2382                 DBG("%s Serial %s", modem->path, modem->serial);
2383
2384                 if (has_interface(modem->interfaces,
2385                                          OFONO_API_CDMA_CM)) {
2386                         if (ready_to_create_device(modem)) {
2387                                 create_device(modem);
2388                                 if (modem->registered)
2389                                         add_cdma_network(modem);
2390                         }
2391                 }
2392         }
2393
2394         return TRUE;
2395 }
2396
2397 static void add_modem(const char *path, DBusMessageIter *prop)
2398 {
2399         struct modem_data *modem;
2400
2401         DBG("%s", path);
2402
2403         modem = g_hash_table_lookup(modem_hash, path);
2404         if (modem) {
2405                 /*
2406                  * When oFono powers up we ask for the modems and oFono is
2407                  * reporting with modem_added signal the modems. Only
2408                  * handle them once.
2409                  */
2410                 return;
2411         }
2412
2413         modem = g_try_new0(struct modem_data, 1);
2414         if (!modem)
2415                 return;
2416
2417         modem->path = g_strdup(path);
2418
2419         g_hash_table_insert(modem_hash, g_strdup(path), modem);
2420
2421         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
2422                 DBusMessageIter entry, value;
2423                 const char *key;
2424
2425                 dbus_message_iter_recurse(prop, &entry);
2426                 dbus_message_iter_get_basic(&entry, &key);
2427
2428                 dbus_message_iter_next(&entry);
2429                 dbus_message_iter_recurse(&entry, &value);
2430
2431                 if (g_str_equal(key, "Powered")) {
2432                         dbus_bool_t powered;
2433
2434                         dbus_message_iter_get_basic(&value, &powered);
2435                         modem->powered = powered;
2436
2437                         DBG("%s Powered %d", modem->path, modem->powered);
2438                 } else if (g_str_equal(key, "Online")) {
2439                         dbus_bool_t online;
2440
2441                         dbus_message_iter_get_basic(&value, &online);
2442                         modem->online = online;
2443
2444                         DBG("%s Online %d", modem->path, modem->online);
2445                 } else if (g_str_equal(key, "Interfaces")) {
2446                         modem->interfaces = extract_interfaces(&value);
2447
2448                         DBG("%s Interfaces 0x%02x", modem->path,
2449                                 modem->interfaces);
2450                 } else if (g_str_equal(key, "Serial")) {
2451                         char *serial;
2452
2453                         dbus_message_iter_get_basic(&value, &serial);
2454                         modem->serial = g_strdup(serial);
2455
2456                         DBG("%s Serial %s", modem->path, modem->serial);
2457                 } else if (g_str_equal(key, "Type")) {
2458                         char *type;
2459
2460                         dbus_message_iter_get_basic(&value, &type);
2461
2462                         DBG("%s Type %s", modem->path, type);
2463                         if (g_strcmp0(type, "hardware") != 0) {
2464                                 DBG("%s Ignore this modem", modem->path);
2465                                 modem->ignore = true;
2466                         }
2467                 }
2468
2469                 dbus_message_iter_next(prop);
2470         }
2471
2472         if (modem->ignore)
2473                 return;
2474
2475         if (!modem->powered) {
2476                 modem_set_powered(modem, TRUE);
2477                 return;
2478         }
2479
2480         modem_update_interfaces(modem, 0, modem->interfaces);
2481 }
2482
2483 static void modem_power_down(gpointer key, gpointer value, gpointer user_data)
2484 {
2485         struct modem_data *modem = value;
2486
2487         DBG("%s", modem->path);
2488
2489         if (modem->ignore)
2490                 return;
2491
2492         modem_set_powered(modem, FALSE);
2493 }
2494
2495 static void remove_modem(gpointer data)
2496 {
2497         struct modem_data *modem = data;
2498
2499         DBG("%s", modem->path);
2500
2501         if (modem->call_set_property) {
2502                 dbus_pending_call_cancel(modem->call_set_property);
2503                 dbus_pending_call_unref(modem->call_set_property);
2504                 modem->call_set_property = NULL;
2505         }
2506
2507         if (modem->call_get_properties) {
2508                 dbus_pending_call_cancel(modem->call_get_properties);
2509                 dbus_pending_call_unref(modem->call_get_properties);
2510                 modem->call_get_properties = NULL;
2511         }
2512
2513         if (modem->call_get_contexts) {
2514                 dbus_pending_call_cancel(modem->call_get_contexts);
2515                 dbus_pending_call_unref(modem->call_get_contexts);
2516                 modem->call_get_contexts = NULL;
2517         }
2518
2519         /* Must remove the contexts before the device */
2520         if (modem->context_list)
2521                 remove_all_contexts(modem);
2522
2523         if (modem->device)
2524                 destroy_device(modem);
2525
2526         g_free(modem->serial);
2527         g_free(modem->name);
2528         g_free(modem->imsi);
2529         g_free(modem->path);
2530
2531         g_free(modem);
2532 }
2533
2534 static gboolean modem_added(DBusConnection *conn,
2535                                 DBusMessage *message, void *user_data)
2536 {
2537         DBusMessageIter iter, properties;
2538         const char *path;
2539
2540         DBG("");
2541
2542         if (!dbus_message_iter_init(message, &iter))
2543                 return TRUE;
2544
2545         dbus_message_iter_get_basic(&iter, &path);
2546
2547         dbus_message_iter_next(&iter);
2548         dbus_message_iter_recurse(&iter, &properties);
2549
2550         add_modem(path, &properties);
2551
2552         return TRUE;
2553 }
2554
2555 static gboolean modem_removed(DBusConnection *conn,
2556                                 DBusMessage *message, void *user_data)
2557 {
2558         DBusMessageIter iter;
2559         const char *path;
2560
2561         DBG("");
2562
2563         if (!dbus_message_iter_init(message, &iter))
2564                 return TRUE;
2565
2566         dbus_message_iter_get_basic(&iter, &path);
2567
2568         g_hash_table_remove(modem_hash, path);
2569
2570         return TRUE;
2571 }
2572
2573 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
2574 {
2575         DBusMessage *reply;
2576         DBusError error;
2577         DBusMessageIter array, dict;
2578
2579         DBG("");
2580
2581         reply = dbus_pending_call_steal_reply(call);
2582
2583         dbus_error_init(&error);
2584
2585         if (dbus_set_error_from_message(&error, reply)) {
2586                 connman_error("%s", error.message);
2587                 dbus_error_free(&error);
2588                 goto done;
2589         }
2590
2591         if (!dbus_message_iter_init(reply, &array))
2592                 goto done;
2593
2594         dbus_message_iter_recurse(&array, &dict);
2595
2596         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
2597                 DBusMessageIter value, properties;
2598                 const char *path;
2599
2600                 dbus_message_iter_recurse(&dict, &value);
2601                 dbus_message_iter_get_basic(&value, &path);
2602
2603                 dbus_message_iter_next(&value);
2604                 dbus_message_iter_recurse(&value, &properties);
2605
2606                 add_modem(path, &properties);
2607
2608                 dbus_message_iter_next(&dict);
2609         }
2610
2611 done:
2612         dbus_message_unref(reply);
2613
2614         dbus_pending_call_unref(call);
2615 }
2616
2617 static int manager_get_modems(void)
2618 {
2619         DBusMessage *message;
2620         DBusPendingCall *call;
2621
2622         DBG("");
2623
2624         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
2625                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
2626         if (!message)
2627                 return -ENOMEM;
2628
2629         if (!dbus_connection_send_with_reply(connection, message,
2630                                                 &call, TIMEOUT)) {
2631                 connman_error("Failed to call GetModems()");
2632                 dbus_message_unref(message);
2633                 return -EINVAL;
2634         }
2635
2636         if (!call) {
2637                 connman_error("D-Bus connection not available");
2638                 dbus_message_unref(message);
2639                 return -EINVAL;
2640         }
2641
2642         dbus_pending_call_set_notify(call, manager_get_modems_reply,
2643                                         NULL, NULL);
2644
2645         dbus_message_unref(message);
2646
2647         return -EINPROGRESS;
2648 }
2649
2650 static void ofono_connect(DBusConnection *conn, void *user_data)
2651 {
2652         DBG("");
2653
2654         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2655                                                 g_free, remove_modem);
2656         if (!modem_hash)
2657                 return;
2658
2659         context_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2660                                                 g_free, NULL);
2661         if (!context_hash) {
2662                 g_hash_table_destroy(modem_hash);
2663                 return;
2664         }
2665
2666         manager_get_modems();
2667 }
2668
2669 static void ofono_disconnect(DBusConnection *conn, void *user_data)
2670 {
2671         DBG("");
2672
2673         if (!modem_hash || !context_hash)
2674                 return;
2675
2676         g_hash_table_destroy(modem_hash);
2677         modem_hash = NULL;
2678
2679         g_hash_table_destroy(context_hash);
2680         context_hash = NULL;
2681 }
2682
2683 static int network_probe(struct connman_network *network)
2684 {
2685         struct modem_data *modem = connman_network_get_data(network);
2686
2687         DBG("%s network %p", modem->path, network);
2688
2689         return 0;
2690 }
2691
2692 static void network_remove(struct connman_network *network)
2693 {
2694         struct modem_data *modem = connman_network_get_data(network);
2695
2696         DBG("%s network %p", modem->path, network);
2697 }
2698
2699 static int network_connect(struct connman_network *network)
2700 {
2701         struct network_context *context;
2702         struct modem_data *modem = connman_network_get_data(network);
2703
2704         DBG("%s network %p", modem->path, network);
2705
2706         if (!g_hash_table_lookup(modem_hash, modem->path))
2707                 return -ENODEV;
2708
2709         context = get_context_with_network(modem->context_list, network);
2710         if (!context)
2711                 return -ENODEV;
2712
2713         if (has_interface(modem->interfaces, OFONO_API_CM))
2714                 return context_set_active(modem, context, TRUE);
2715         else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM))
2716                 return cdma_cm_set_powered(modem, TRUE);
2717
2718         connman_error("Connection manager interface not available");
2719
2720         return -ENOSYS;
2721 }
2722
2723 static int network_disconnect(struct connman_network *network)
2724 {
2725         struct network_context *context;
2726         struct modem_data *modem = connman_network_get_data(network);
2727
2728         DBG("%s network %p", modem->path, network);
2729
2730         if (!g_hash_table_lookup(modem_hash, modem->path))
2731                 return -ENODEV;
2732
2733         context = get_context_with_network(modem->context_list, network);
2734         if (!context)
2735                 return -ENODEV;
2736
2737         if (has_interface(modem->interfaces, OFONO_API_CM))
2738                 return context_set_active(modem, context, FALSE);
2739         else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM))
2740                 return cdma_cm_set_powered(modem, FALSE);
2741
2742         connman_error("Connection manager interface not available");
2743
2744         return -ENOSYS;
2745 }
2746
2747 static struct connman_network_driver network_driver = {
2748         .name           = "cellular",
2749         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
2750         .probe          = network_probe,
2751         .remove         = network_remove,
2752         .connect        = network_connect,
2753         .disconnect     = network_disconnect,
2754 };
2755
2756 static int modem_probe(struct connman_device *device)
2757 {
2758         struct modem_data *modem = connman_device_get_data(device);
2759
2760         DBG("%s device %p", modem->path, device);
2761
2762         return 0;
2763 }
2764
2765 static void modem_remove(struct connman_device *device)
2766 {
2767         struct modem_data *modem = connman_device_get_data(device);
2768
2769         DBG("%s device %p", modem->path, device);
2770 }
2771
2772 static int modem_enable(struct connman_device *device)
2773 {
2774         struct modem_data *modem = connman_device_get_data(device);
2775
2776         DBG("%s device %p", modem->path, device);
2777
2778         if (modem->online)
2779                 return 0;
2780
2781         return modem_set_online(modem, TRUE);
2782 }
2783
2784 static int modem_disable(struct connman_device *device)
2785 {
2786         struct modem_data *modem = connman_device_get_data(device);
2787
2788         DBG("%s device %p", modem->path, device);
2789
2790         if (!modem->online)
2791                 return 0;
2792
2793         return modem_set_online(modem, FALSE);
2794 }
2795
2796 static struct connman_device_driver modem_driver = {
2797         .name           = "modem",
2798         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
2799         .probe          = modem_probe,
2800         .remove         = modem_remove,
2801         .enable         = modem_enable,
2802         .disable        = modem_disable,
2803 };
2804
2805 static int tech_probe(struct connman_technology *technology)
2806 {
2807         return 0;
2808 }
2809
2810 static void tech_remove(struct connman_technology *technology)
2811 {
2812 }
2813
2814 static struct connman_technology_driver tech_driver = {
2815         .name           = "cellular",
2816         .type           = CONNMAN_SERVICE_TYPE_CELLULAR,
2817         .probe          = tech_probe,
2818         .remove         = tech_remove,
2819 };
2820
2821 static guint watch;
2822 static guint modem_added_watch;
2823 static guint modem_removed_watch;
2824 static guint modem_watch;
2825 static guint cm_watch;
2826 static guint sim_watch;
2827 static guint context_added_watch;
2828 static guint context_removed_watch;
2829 static guint netreg_watch;
2830 static guint context_watch;
2831 static guint cdma_cm_watch;
2832 static guint cdma_netreg_watch;
2833
2834 static int ofono_init(void)
2835 {
2836         int err;
2837
2838         DBG("");
2839
2840         connection = connman_dbus_get_connection();
2841         if (!connection)
2842                 return -EIO;
2843
2844         watch = g_dbus_add_service_watch(connection,
2845                                         OFONO_SERVICE, ofono_connect,
2846                                         ofono_disconnect, NULL, NULL);
2847
2848         modem_added_watch = g_dbus_add_signal_watch(connection, OFONO_SERVICE,
2849                                                 NULL, OFONO_MANAGER_INTERFACE,
2850                                                 MODEM_ADDED,
2851                                                 modem_added,
2852                                                 NULL, NULL);
2853
2854         modem_removed_watch = g_dbus_add_signal_watch(connection,
2855                                                 OFONO_SERVICE, NULL,
2856                                                 OFONO_MANAGER_INTERFACE,
2857                                                 MODEM_REMOVED,
2858                                                 modem_removed,
2859                                                 NULL, NULL);
2860
2861         modem_watch = g_dbus_add_signal_watch(connection, OFONO_SERVICE, NULL,
2862                                                 OFONO_MODEM_INTERFACE,
2863                                                 PROPERTY_CHANGED,
2864                                                 modem_changed,
2865                                                 NULL, NULL);
2866
2867         cm_watch = g_dbus_add_signal_watch(connection, OFONO_SERVICE, NULL,
2868                                                 OFONO_CM_INTERFACE,
2869                                                 PROPERTY_CHANGED,
2870                                                 cm_changed,
2871                                                 NULL, NULL);
2872
2873         sim_watch = g_dbus_add_signal_watch(connection, OFONO_SERVICE, NULL,
2874                                                 OFONO_SIM_INTERFACE,
2875                                                 PROPERTY_CHANGED,
2876                                                 sim_changed,
2877                                                 NULL, NULL);
2878
2879         context_added_watch = g_dbus_add_signal_watch(connection,
2880                                                 OFONO_SERVICE, NULL,
2881                                                 OFONO_CM_INTERFACE,
2882                                                 CONTEXT_ADDED,
2883                                                 cm_context_added,
2884                                                 NULL, NULL);
2885
2886         context_removed_watch = g_dbus_add_signal_watch(connection,
2887                                                 OFONO_SERVICE, NULL,
2888                                                 OFONO_CM_INTERFACE,
2889                                                 CONTEXT_REMOVED,
2890                                                 cm_context_removed,
2891                                                 NULL, NULL);
2892
2893         context_watch = g_dbus_add_signal_watch(connection, OFONO_SERVICE,
2894                                                 NULL, OFONO_CONTEXT_INTERFACE,
2895                                                 PROPERTY_CHANGED,
2896                                                 context_changed,
2897                                                 NULL, NULL);
2898
2899         netreg_watch = g_dbus_add_signal_watch(connection, OFONO_SERVICE, NULL,
2900                                                 OFONO_NETREG_INTERFACE,
2901                                                 PROPERTY_CHANGED,
2902                                                 netreg_changed,
2903                                                 NULL, NULL);
2904
2905         cdma_cm_watch = g_dbus_add_signal_watch(connection, OFONO_SERVICE,
2906                                                 NULL, OFONO_CDMA_CM_INTERFACE,
2907                                                 PROPERTY_CHANGED,
2908                                                 cdma_cm_changed,
2909                                                 NULL, NULL);
2910
2911         cdma_netreg_watch = g_dbus_add_signal_watch(connection, OFONO_SERVICE,
2912                                                 NULL, OFONO_CDMA_NETREG_INTERFACE,
2913                                                 PROPERTY_CHANGED,
2914                                                 cdma_netreg_changed,
2915                                                 NULL, NULL);
2916
2917
2918         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
2919                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
2920                         context_added_watch == 0 ||
2921                         context_removed_watch == 0 ||
2922                         context_watch == 0 || netreg_watch == 0 ||
2923                         cdma_cm_watch == 0 || cdma_netreg_watch == 0) {
2924                 err = -EIO;
2925                 goto remove;
2926         }
2927
2928         err = connman_network_driver_register(&network_driver);
2929         if (err < 0)
2930                 goto remove;
2931
2932         err = connman_device_driver_register(&modem_driver);
2933         if (err < 0) {
2934                 connman_network_driver_unregister(&network_driver);
2935                 goto remove;
2936         }
2937
2938         err = connman_technology_driver_register(&tech_driver);
2939         if (err < 0) {
2940                 connman_device_driver_unregister(&modem_driver);
2941                 connman_network_driver_unregister(&network_driver);
2942                 goto remove;
2943         }
2944
2945         return 0;
2946
2947 remove:
2948         g_dbus_remove_watch(connection, cdma_netreg_watch);
2949         g_dbus_remove_watch(connection, cdma_cm_watch);
2950         g_dbus_remove_watch(connection, netreg_watch);
2951         g_dbus_remove_watch(connection, context_watch);
2952         g_dbus_remove_watch(connection, context_removed_watch);
2953         g_dbus_remove_watch(connection, context_added_watch);
2954         g_dbus_remove_watch(connection, sim_watch);
2955         g_dbus_remove_watch(connection, cm_watch);
2956         g_dbus_remove_watch(connection, modem_watch);
2957         g_dbus_remove_watch(connection, modem_removed_watch);
2958         g_dbus_remove_watch(connection, modem_added_watch);
2959         g_dbus_remove_watch(connection, watch);
2960         dbus_connection_unref(connection);
2961
2962         return err;
2963 }
2964
2965 static void ofono_exit(void)
2966 {
2967         DBG("");
2968
2969         if (modem_hash) {
2970                 /*
2971                  * We should probably wait for the SetProperty() reply
2972                  * message, because ...
2973                  */
2974                 g_hash_table_foreach(modem_hash, modem_power_down, NULL);
2975
2976                 /*
2977                  * ... here we will cancel the call.
2978                  */
2979                 g_hash_table_destroy(modem_hash);
2980                 modem_hash = NULL;
2981         }
2982
2983         if (context_hash) {
2984                 g_hash_table_destroy(context_hash);
2985                 context_hash = NULL;
2986         }
2987
2988         connman_technology_driver_unregister(&tech_driver);
2989         connman_device_driver_unregister(&modem_driver);
2990         connman_network_driver_unregister(&network_driver);
2991
2992         g_dbus_remove_watch(connection, cdma_netreg_watch);
2993         g_dbus_remove_watch(connection, cdma_cm_watch);
2994         g_dbus_remove_watch(connection, netreg_watch);
2995         g_dbus_remove_watch(connection, context_watch);
2996         g_dbus_remove_watch(connection, context_removed_watch);
2997         g_dbus_remove_watch(connection, context_added_watch);
2998         g_dbus_remove_watch(connection, sim_watch);
2999         g_dbus_remove_watch(connection, cm_watch);
3000         g_dbus_remove_watch(connection, modem_watch);
3001         g_dbus_remove_watch(connection, modem_added_watch);
3002         g_dbus_remove_watch(connection, modem_removed_watch);
3003         g_dbus_remove_watch(connection, watch);
3004
3005         dbus_connection_unref(connection);
3006 }
3007
3008 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
3009                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)