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