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