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