oFono: Update documentation
[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)
1419                 return;
1420
1421         alpha2 = mcc_country_codes[mcc - 200];
1422         connman_technology_set_regdom(alpha2);
1423 }
1424
1425 static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
1426                                 void *user_data)
1427 {
1428         const char *path = dbus_message_get_path(message);
1429         struct modem_data *modem;
1430         DBusMessageIter iter, value;
1431         const char *key;
1432
1433         modem = g_hash_table_lookup(modem_hash, path);
1434         if (modem == NULL)
1435                 return TRUE;
1436
1437         if (modem->ignore == TRUE)
1438                 return TRUE;
1439
1440         if (dbus_message_iter_init(message, &iter) == FALSE)
1441                 return TRUE;
1442
1443         dbus_message_iter_get_basic(&iter, &key);
1444
1445         dbus_message_iter_next(&iter);
1446         dbus_message_iter_recurse(&iter, &value);
1447
1448         if (g_str_equal(key, "Name") == TRUE)
1449                 netreg_update_name(modem, &value);
1450         else if (g_str_equal(key, "Strength") == TRUE)
1451                 netreg_update_strength(modem, &value);
1452         else if (g_str_equal(key, "Status") == TRUE)
1453                 netreg_update_roaming(modem, &value);
1454         else if (g_str_equal(key, "MobileCountryCode") == TRUE)
1455                 netreg_update_regdom(modem, &value);
1456
1457         return TRUE;
1458 }
1459
1460 static void netreg_properties_reply(struct modem_data *modem,
1461                                         DBusMessageIter *dict)
1462 {
1463         DBG("%s", modem->path);
1464
1465         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1466                 DBusMessageIter entry, value;
1467                 const char *key;
1468
1469                 dbus_message_iter_recurse(dict, &entry);
1470                 dbus_message_iter_get_basic(&entry, &key);
1471
1472                 dbus_message_iter_next(&entry);
1473                 dbus_message_iter_recurse(&entry, &value);
1474
1475                 if (g_str_equal(key, "Name") == TRUE)
1476                         netreg_update_name(modem, &value);
1477                 else if (g_str_equal(key, "Strength") == TRUE)
1478                         netreg_update_strength(modem, &value);
1479                 else if (g_str_equal(key, "Status") == TRUE)
1480                         netreg_update_roaming(modem, &value);
1481                 else if (g_str_equal(key, "MobileCountryCode") == TRUE)
1482                         netreg_update_regdom(modem, &value);
1483
1484                 dbus_message_iter_next(dict);
1485         }
1486
1487         if (modem->context == NULL) {
1488                 /*
1489                  * netgreg_get_properties() was issued after we got
1490                  * cm_get_contexts_reply() where we create the
1491                  * context. Though before we got the
1492                  * netreg_properties_reply the context was removed
1493                  * again. Therefore we have to skip the network
1494                  * creation.
1495                  */
1496                 return;
1497         }
1498
1499         add_network(modem);
1500
1501         if (modem->active == TRUE)
1502                 set_connected(modem);
1503 }
1504
1505 static int netreg_get_properties(struct modem_data *modem)
1506 {
1507         return get_properties(modem->path, OFONO_NETREG_INTERFACE,
1508                         netreg_properties_reply, modem);
1509 }
1510
1511 static void add_cdma_network(struct modem_data *modem)
1512 {
1513         /* Be sure that device is created before adding CDMA network */
1514         if (modem->device == NULL)
1515                 return;
1516
1517         /*
1518          * CDMA modems don't need contexts for data call, however the current
1519          * add_network() logic needs one, so we create one to proceed.
1520          */
1521         if (modem->context == NULL)
1522                 modem->context = network_context_alloc(modem->path);
1523
1524         if (modem->name == NULL)
1525                 modem->name = g_strdup("CDMA Network");
1526
1527         add_network(modem);
1528
1529         if (modem->cdma_cm_powered == TRUE)
1530                 set_connected(modem);
1531 }
1532
1533 static gboolean cdma_netreg_changed(DBusConnection *connection,
1534                                         DBusMessage *message,
1535                                         void *user_data)
1536 {
1537         const char *path = dbus_message_get_path(message);
1538         struct modem_data *modem;
1539         DBusMessageIter iter, value;
1540         const char *key;
1541
1542         DBG("");
1543
1544         modem = g_hash_table_lookup(modem_hash, path);
1545         if (modem == NULL)
1546                 return TRUE;
1547
1548         if (modem->ignore == TRUE)
1549                 return TRUE;
1550
1551         if (dbus_message_iter_init(message, &iter) == FALSE)
1552                 return TRUE;
1553
1554         dbus_message_iter_get_basic(&iter, &key);
1555
1556         dbus_message_iter_next(&iter);
1557         dbus_message_iter_recurse(&iter, &value);
1558
1559         if (g_str_equal(key, "Name") == TRUE)
1560                 netreg_update_name(modem, &value);
1561         else if (g_str_equal(key, "Strength") == TRUE)
1562                 netreg_update_strength(modem, &value);
1563         else if (g_str_equal(key, "DataStrength") == TRUE)
1564                 netreg_update_datastrength(modem, &value);
1565         else if (g_str_equal(key, "Status") == TRUE)
1566                 netreg_update_roaming(modem, &value);
1567
1568         add_cdma_network(modem);
1569
1570         return TRUE;
1571 }
1572
1573 static void cdma_netreg_properties_reply(struct modem_data *modem,
1574                                         DBusMessageIter *dict)
1575 {
1576         DBG("%s", modem->path);
1577
1578         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1579                 DBusMessageIter entry, value;
1580                 const char *key;
1581
1582                 dbus_message_iter_recurse(dict, &entry);
1583                 dbus_message_iter_get_basic(&entry, &key);
1584
1585                 dbus_message_iter_next(&entry);
1586                 dbus_message_iter_recurse(&entry, &value);
1587
1588                 if (g_str_equal(key, "Name") == TRUE)
1589                         netreg_update_name(modem, &value);
1590                 else if (g_str_equal(key, "Strength") == TRUE)
1591                         netreg_update_strength(modem, &value);
1592                 else if (g_str_equal(key, "DataStrength") == TRUE)
1593                         netreg_update_datastrength(modem, &value);
1594                 else if (g_str_equal(key, "Status") == TRUE)
1595                         netreg_update_roaming(modem, &value);
1596
1597                 dbus_message_iter_next(dict);
1598         }
1599
1600         add_cdma_network(modem);
1601 }
1602
1603 static int cdma_netreg_get_properties(struct modem_data *modem)
1604 {
1605         return get_properties(modem->path, OFONO_CDMA_NETREG_INTERFACE,
1606                         cdma_netreg_properties_reply, modem);
1607 }
1608
1609 static void cm_update_attached(struct modem_data *modem,
1610                                 DBusMessageIter *value)
1611 {
1612         dbus_message_iter_get_basic(value, &modem->attached);
1613
1614         DBG("%s Attached %d", modem->path, modem->attached);
1615
1616         if (modem->attached == FALSE)
1617                 return;
1618
1619         if (has_interface(modem->interfaces,
1620                                 OFONO_API_NETREG) == FALSE) {
1621                 return;
1622         }
1623
1624         netreg_get_properties(modem);
1625 }
1626
1627 static void cm_update_powered(struct modem_data *modem,
1628                                 DBusMessageIter *value)
1629 {
1630         dbus_message_iter_get_basic(value, &modem->cm_powered);
1631
1632         DBG("%s ConnnectionManager Powered %d", modem->path,
1633                 modem->cm_powered);
1634
1635         if (modem->cm_powered == TRUE)
1636                 return;
1637
1638         cm_set_powered(modem, TRUE);
1639 }
1640
1641 static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
1642                                 void *user_data)
1643 {
1644         const char *path = dbus_message_get_path(message);
1645         struct modem_data *modem;
1646         DBusMessageIter iter, value;
1647         const char *key;
1648
1649         modem = g_hash_table_lookup(modem_hash, path);
1650         if (modem == NULL)
1651                 return TRUE;
1652
1653         if (modem->ignore == TRUE)
1654                 return TRUE;
1655
1656         if (dbus_message_iter_init(message, &iter) == FALSE)
1657                 return TRUE;
1658
1659         dbus_message_iter_get_basic(&iter, &key);
1660
1661         dbus_message_iter_next(&iter);
1662         dbus_message_iter_recurse(&iter, &value);
1663
1664         if (g_str_equal(key, "Attached") == TRUE)
1665                 cm_update_attached(modem, &value);
1666         else if (g_str_equal(key, "Powered") == TRUE)
1667                 cm_update_powered(modem, &value);
1668
1669         return TRUE;
1670 }
1671
1672 static void cdma_cm_update_powered(struct modem_data *modem,
1673                                         DBusMessageIter *value)
1674 {
1675         dbus_message_iter_get_basic(value, &modem->cdma_cm_powered);
1676
1677         DBG("%s CDMA cm Powered %d", modem->path, modem->cdma_cm_powered);
1678
1679         if (modem->network == NULL)
1680                 return;
1681
1682         if (modem->cdma_cm_powered == TRUE)
1683                 set_connected(modem);
1684         else
1685                 set_disconnected(modem);
1686 }
1687
1688 static void cdma_cm_update_settings(struct modem_data *modem,
1689                                         DBusMessageIter *value)
1690 {
1691         DBG("%s Settings", modem->path);
1692
1693         extract_ipv4_settings(value, modem->context);
1694 }
1695
1696 static gboolean cdma_cm_changed(DBusConnection *connection,
1697                                 DBusMessage *message, void *user_data)
1698 {
1699         const char *path = dbus_message_get_path(message);
1700         struct modem_data *modem;
1701         DBusMessageIter iter, value;
1702         const char *key;
1703
1704         modem = g_hash_table_lookup(modem_hash, path);
1705         if (modem == NULL)
1706                 return TRUE;
1707
1708         if (modem->online == TRUE && modem->network == NULL)
1709                 cdma_netreg_get_properties(modem);
1710
1711         if (dbus_message_iter_init(message, &iter) == FALSE)
1712                 return TRUE;
1713
1714         dbus_message_iter_get_basic(&iter, &key);
1715
1716         dbus_message_iter_next(&iter);
1717         dbus_message_iter_recurse(&iter, &value);
1718
1719         if (g_str_equal(key, "Powered") == TRUE)
1720                 cdma_cm_update_powered(modem, &value);
1721         if (g_str_equal(key, "Settings") == TRUE)
1722                 cdma_cm_update_settings(modem, &value);
1723
1724         return TRUE;
1725 }
1726
1727 static void cm_properties_reply(struct modem_data *modem, DBusMessageIter *dict)
1728 {
1729         DBG("%s", modem->path);
1730
1731         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1732                 DBusMessageIter entry, value;
1733                 const char *key;
1734
1735                 dbus_message_iter_recurse(dict, &entry);
1736                 dbus_message_iter_get_basic(&entry, &key);
1737
1738                 dbus_message_iter_next(&entry);
1739                 dbus_message_iter_recurse(&entry, &value);
1740
1741                 if (g_str_equal(key, "Attached") == TRUE)
1742                         cm_update_attached(modem, &value);
1743                 else if (g_str_equal(key, "Powered") == TRUE)
1744                         cm_update_powered(modem, &value);
1745
1746                 dbus_message_iter_next(dict);
1747         }
1748 }
1749
1750 static int cm_get_properties(struct modem_data *modem)
1751 {
1752         return get_properties(modem->path, OFONO_CM_INTERFACE,
1753                                 cm_properties_reply, modem);
1754 }
1755
1756 static void cdma_cm_properties_reply(struct modem_data *modem,
1757                                         DBusMessageIter *dict)
1758 {
1759         DBG("%s", modem->path);
1760
1761         if (modem->online == TRUE)
1762                 cdma_netreg_get_properties(modem);
1763
1764         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1765                 DBusMessageIter entry, value;
1766                 const char *key;
1767
1768                 dbus_message_iter_recurse(dict, &entry);
1769                 dbus_message_iter_get_basic(&entry, &key);
1770
1771                 dbus_message_iter_next(&entry);
1772                 dbus_message_iter_recurse(&entry, &value);
1773
1774                 if (g_str_equal(key, "Powered") == TRUE)
1775                         cdma_cm_update_powered(modem, &value);
1776                 if (g_str_equal(key, "Settings") == TRUE)
1777                         cdma_cm_update_settings(modem, &value);
1778
1779                 dbus_message_iter_next(dict);
1780         }
1781 }
1782
1783 static int cdma_cm_get_properties(struct modem_data *modem)
1784 {
1785         return get_properties(modem->path, OFONO_CDMA_CM_INTERFACE,
1786                                 cdma_cm_properties_reply, modem);
1787 }
1788
1789 static void sim_update_imsi(struct modem_data *modem,
1790                                 DBusMessageIter* value)
1791 {
1792         char *imsi;
1793
1794         dbus_message_iter_get_basic(value, &imsi);
1795
1796         DBG("%s imsi %s", modem->path, imsi);
1797
1798         g_free(modem->imsi);
1799         modem->imsi = g_strdup(imsi);
1800 }
1801
1802 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
1803                                 void *user_data)
1804 {
1805         const char *path = dbus_message_get_path(message);
1806         struct modem_data *modem;
1807         DBusMessageIter iter, value;
1808         const char *key;
1809
1810         modem = g_hash_table_lookup(modem_hash, path);
1811         if (modem == NULL)
1812                 return TRUE;
1813
1814         if (modem->ignore == TRUE)
1815                 return TRUE;
1816
1817         if (dbus_message_iter_init(message, &iter) == FALSE)
1818                 return TRUE;
1819
1820         dbus_message_iter_get_basic(&iter, &key);
1821
1822         dbus_message_iter_next(&iter);
1823         dbus_message_iter_recurse(&iter, &value);
1824
1825         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1826                 sim_update_imsi(modem, &value);
1827
1828                 if (ready_to_create_device(modem) == FALSE)
1829                         return TRUE;
1830
1831                 /*
1832                  * This is a GSM modem. Create the device and
1833                  * register it at the core. Enabling (setting
1834                  * it online is done through the
1835                  * modem_enable() callback.
1836                  */
1837                 create_device(modem);
1838         }
1839
1840         return TRUE;
1841 }
1842
1843 static void sim_properties_reply(struct modem_data *modem,
1844                                         DBusMessageIter *dict)
1845 {
1846         DBG("%s", modem->path);
1847
1848         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1849                 DBusMessageIter entry, value;
1850                 const char *key;
1851
1852                 dbus_message_iter_recurse(dict, &entry);
1853                 dbus_message_iter_get_basic(&entry, &key);
1854
1855                 dbus_message_iter_next(&entry);
1856                 dbus_message_iter_recurse(&entry, &value);
1857
1858                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1859                         sim_update_imsi(modem, &value);
1860
1861                         if (ready_to_create_device(modem) == FALSE)
1862                                 return;
1863
1864                         /*
1865                          * This is a GSM modem. Create the device and
1866                          * register it at the core. Enabling (setting
1867                          * it online is done through the
1868                          * modem_enable() callback.
1869                          */
1870                         create_device(modem);
1871
1872                         if (modem->online == FALSE)
1873                                 return;
1874
1875                         /*
1876                          * The modem is already online and we have the CM interface.
1877                          * There will be no interface update and therefore our
1878                          * state machine will not go to next step. We have to
1879                          * trigger it from here.
1880                          */
1881                         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1882                                 cm_get_properties(modem);
1883                                 cm_get_contexts(modem);
1884                         }
1885                         return;
1886                 }
1887
1888                 dbus_message_iter_next(dict);
1889         }
1890 }
1891
1892 static int sim_get_properties(struct modem_data *modem)
1893 {
1894         return get_properties(modem->path, OFONO_SIM_INTERFACE,
1895                                 sim_properties_reply, modem);
1896 }
1897
1898 static connman_bool_t api_added(uint8_t old_iface, uint8_t new_iface,
1899                                 enum ofono_api api)
1900 {
1901         if (has_interface(old_iface, api) == FALSE &&
1902                         has_interface(new_iface, api) == TRUE) {
1903                 DBG("%s added", api2string(api));
1904                 return TRUE;
1905         }
1906
1907         return FALSE;
1908 }
1909
1910 static connman_bool_t api_removed(uint8_t old_iface, uint8_t new_iface,
1911                                 enum ofono_api api)
1912 {
1913         if (has_interface(old_iface, api) == TRUE &&
1914                         has_interface(new_iface, api) == FALSE) {
1915                 DBG("%s removed", api2string(api));
1916                 return TRUE;
1917         }
1918
1919         return FALSE;
1920 }
1921
1922 static void modem_update_interfaces(struct modem_data *modem,
1923                                 uint8_t old_ifaces,
1924                                 uint8_t new_ifaces)
1925 {
1926         DBG("%s", modem->path);
1927
1928         if (api_added(old_ifaces, new_ifaces, OFONO_API_SIM) == TRUE) {
1929                 if (modem->imsi == NULL &&
1930                                 modem->set_powered == FALSE) {
1931                         /*
1932                          * Only use do GetProperties() when
1933                          * device has not been powered up.
1934                          */
1935                         sim_get_properties(modem);
1936                 }
1937         }
1938
1939         if (api_added(old_ifaces, new_ifaces, OFONO_API_CM) == TRUE) {
1940                 if (modem->device != NULL) {
1941                         cm_get_properties(modem);
1942                         cm_get_contexts(modem);
1943                 }
1944         }
1945
1946         if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_CM) == TRUE) {
1947                 if (ready_to_create_device(modem) == TRUE)
1948                         create_device(modem);
1949
1950                 if (modem->device != NULL)
1951                         cdma_cm_get_properties(modem);
1952         }
1953
1954         if (api_added(old_ifaces, new_ifaces, OFONO_API_NETREG) == TRUE) {
1955                 if (modem->attached == TRUE)
1956                         netreg_get_properties(modem);
1957         }
1958
1959         if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG) == TRUE) {
1960                 cdma_netreg_get_properties(modem);
1961         }
1962
1963         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CM) == TRUE) {
1964                 remove_cm_context(modem, modem->context->path);
1965         }
1966
1967         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_CM) == TRUE) {
1968                 remove_cm_context(modem, modem->context->path);
1969         }
1970
1971         if (api_removed(old_ifaces, new_ifaces, OFONO_API_NETREG) == TRUE) {
1972                 remove_network(modem);
1973         }
1974
1975         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG == TRUE)) {
1976                 remove_network(modem);
1977         }
1978 }
1979
1980 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
1981                                 void *user_data)
1982 {
1983         const char *path = dbus_message_get_path(message);
1984         struct modem_data *modem;
1985         DBusMessageIter iter, value;
1986         const char *key;
1987
1988         modem = g_hash_table_lookup(modem_hash, path);
1989         if (modem == NULL)
1990                 return TRUE;
1991
1992         if (modem->ignore == TRUE)
1993                 return TRUE;
1994
1995         if (dbus_message_iter_init(message, &iter) == FALSE)
1996                 return TRUE;
1997
1998         dbus_message_iter_get_basic(&iter, &key);
1999
2000         dbus_message_iter_next(&iter);
2001         dbus_message_iter_recurse(&iter, &value);
2002
2003         if (g_str_equal(key, "Powered") == TRUE) {
2004                 dbus_message_iter_get_basic(&value, &modem->powered);
2005
2006                 DBG("%s Powered %d", modem->path, modem->powered);
2007
2008                 if (modem->powered == FALSE)
2009                         modem_set_powered(modem, TRUE);
2010         } else if (g_str_equal(key, "Online") == TRUE) {
2011                 dbus_message_iter_get_basic(&value, &modem->online);
2012
2013                 DBG("%s Online %d", modem->path, modem->online);
2014
2015                 if (modem->device == NULL)
2016                         return TRUE;
2017
2018                 connman_device_set_powered(modem->device, modem->online);
2019         } else if (g_str_equal(key, "Interfaces") == TRUE) {
2020                 uint8_t interfaces;
2021
2022                 interfaces = extract_interfaces(&value);
2023
2024                 if (interfaces == modem->interfaces)
2025                         return TRUE;
2026
2027                 DBG("%s Interfaces 0x%02x", modem->path, interfaces);
2028
2029                 modem_update_interfaces(modem, modem->interfaces, interfaces);
2030
2031                 modem->interfaces = interfaces;
2032         } else if (g_str_equal(key, "Serial") == TRUE) {
2033                 char *serial;
2034
2035                 dbus_message_iter_get_basic(&value, &serial);
2036
2037                 g_free(modem->serial);
2038                 modem->serial = g_strdup(serial);
2039
2040                 DBG("%s Serial %s", modem->path, modem->serial);
2041
2042                 if (has_interface(modem->interfaces,
2043                                          OFONO_API_CDMA_CM) == TRUE) {
2044                         if (ready_to_create_device(modem) == TRUE)
2045                                 create_device(modem);
2046                 }
2047         }
2048
2049         return TRUE;
2050 }
2051
2052 static void add_modem(const char *path, DBusMessageIter *prop)
2053 {
2054         struct modem_data *modem;
2055
2056         DBG("%s", path);
2057
2058         modem = g_hash_table_lookup(modem_hash, path);
2059         if (modem != NULL) {
2060                 /*
2061                  * When oFono powers up we ask for the modems and oFono is
2062                  * reporting with modem_added signal the modems. Only
2063                  * handle them once.
2064                  */
2065                 return;
2066         }
2067
2068         modem = g_try_new0(struct modem_data, 1);
2069         if (modem == NULL)
2070                 return;
2071
2072         modem->path = g_strdup(path);
2073
2074         g_hash_table_insert(modem_hash, g_strdup(path), modem);
2075
2076         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
2077                 DBusMessageIter entry, value;
2078                 const char *key;
2079
2080                 dbus_message_iter_recurse(prop, &entry);
2081                 dbus_message_iter_get_basic(&entry, &key);
2082
2083                 dbus_message_iter_next(&entry);
2084                 dbus_message_iter_recurse(&entry, &value);
2085
2086                 if (g_str_equal(key, "Powered") == TRUE) {
2087                         dbus_message_iter_get_basic(&value, &modem->powered);
2088
2089                         DBG("%s Powered %d", modem->path, modem->powered);
2090                 } else if (g_str_equal(key, "Online") == TRUE) {
2091                         dbus_message_iter_get_basic(&value, &modem->online);
2092
2093                         DBG("%s Online %d", modem->path, modem->online);
2094                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
2095                         modem->interfaces = extract_interfaces(&value);
2096
2097                         DBG("%s Interfaces 0x%02x", modem->path,
2098                                 modem->interfaces);
2099                 } else if (g_str_equal(key, "Serial") == TRUE) {
2100                         char *serial;
2101
2102                         dbus_message_iter_get_basic(&value, &serial);
2103                         modem->serial = g_strdup(serial);
2104
2105                         DBG("%s Serial %s", modem->path, modem->serial);
2106                 } else if (g_str_equal(key, "Type") == TRUE) {
2107                         char *type;
2108
2109                         dbus_message_iter_get_basic(&value, &type);
2110
2111                         DBG("%s Type %s", modem->path, type);
2112                         if (g_strcmp0(type, "hardware") != 0) {
2113                                 DBG("%s Ignore this modem", modem->path);
2114                                 modem->ignore = TRUE;
2115                         }
2116                 }
2117
2118                 dbus_message_iter_next(prop);
2119         }
2120
2121         if (modem->ignore == TRUE)
2122                 return;
2123
2124         if (modem->powered == FALSE) {
2125                 modem_set_powered(modem, TRUE);
2126                 return;
2127         }
2128
2129         modem_update_interfaces(modem, 0, modem->interfaces);
2130 }
2131
2132 static void modem_power_down(gpointer key, gpointer value, gpointer user_data)
2133 {
2134         struct modem_data *modem = value;
2135
2136         DBG("%s", modem->path);
2137
2138         if (modem->ignore ==  TRUE)
2139                 return;
2140
2141         modem_set_powered(modem, FALSE);
2142 }
2143
2144 static void remove_modem(gpointer data)
2145 {
2146         struct modem_data *modem = data;
2147
2148         DBG("%s", modem->path);
2149
2150         if (modem->call_set_property != NULL)
2151                 dbus_pending_call_cancel(modem->call_set_property);
2152
2153         if (modem->call_get_properties != NULL)
2154                 dbus_pending_call_cancel(modem->call_get_properties);
2155
2156         if (modem->call_get_contexts != NULL)
2157                 dbus_pending_call_cancel(modem->call_get_contexts);
2158
2159         if (modem->device != NULL)
2160                 destroy_device(modem);
2161
2162         if (modem->context != NULL)
2163                 remove_cm_context(modem, modem->context->path);
2164
2165         g_free(modem->serial);
2166         g_free(modem->name);
2167         g_free(modem->imsi);
2168         g_free(modem->path);
2169
2170         g_free(modem);
2171 }
2172
2173 static gboolean modem_added(DBusConnection *connection,
2174                                 DBusMessage *message, void *user_data)
2175 {
2176         DBusMessageIter iter, properties;
2177         const char *path;
2178
2179         DBG("");
2180
2181         if (dbus_message_iter_init(message, &iter) == FALSE)
2182                 return TRUE;
2183
2184         dbus_message_iter_get_basic(&iter, &path);
2185
2186         dbus_message_iter_next(&iter);
2187         dbus_message_iter_recurse(&iter, &properties);
2188
2189         add_modem(path, &properties);
2190
2191         return TRUE;
2192 }
2193
2194 static gboolean modem_removed(DBusConnection *connection,
2195                                 DBusMessage *message, void *user_data)
2196 {
2197         DBusMessageIter iter;
2198         const char *path;
2199
2200         DBG("");
2201
2202         if (dbus_message_iter_init(message, &iter) == FALSE)
2203                 return TRUE;
2204
2205         dbus_message_iter_get_basic(&iter, &path);
2206
2207         g_hash_table_remove(modem_hash, path);
2208
2209         return TRUE;
2210 }
2211
2212 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
2213 {
2214         DBusMessage *reply;
2215         DBusError error;
2216         DBusMessageIter array, dict;
2217
2218         DBG("");
2219
2220         reply = dbus_pending_call_steal_reply(call);
2221
2222         dbus_error_init(&error);
2223
2224         if (dbus_set_error_from_message(&error, reply) == TRUE) {
2225                 connman_error("%s", error.message);
2226                 dbus_error_free(&error);
2227                 goto done;
2228         }
2229
2230         if (dbus_message_iter_init(reply, &array) == FALSE)
2231                 goto done;
2232
2233         dbus_message_iter_recurse(&array, &dict);
2234
2235         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
2236                 DBusMessageIter value, properties;
2237                 const char *path;
2238
2239                 dbus_message_iter_recurse(&dict, &value);
2240                 dbus_message_iter_get_basic(&value, &path);
2241
2242                 dbus_message_iter_next(&value);
2243                 dbus_message_iter_recurse(&value, &properties);
2244
2245                 add_modem(path, &properties);
2246
2247                 dbus_message_iter_next(&dict);
2248         }
2249
2250 done:
2251         dbus_message_unref(reply);
2252
2253         dbus_pending_call_unref(call);
2254 }
2255
2256 static int manager_get_modems(void)
2257 {
2258         DBusMessage *message;
2259         DBusPendingCall *call;
2260
2261         DBG("");
2262
2263         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
2264                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
2265         if (message == NULL)
2266                 return -ENOMEM;
2267
2268         if (dbus_connection_send_with_reply(connection, message,
2269                                                &call, TIMEOUT) == FALSE) {
2270                 connman_error("Failed to call GetModems()");
2271                 dbus_message_unref(message);
2272                 return -EINVAL;
2273         }
2274
2275         if (call == NULL) {
2276                 connman_error("D-Bus connection not available");
2277                 dbus_message_unref(message);
2278                 return -EINVAL;
2279         }
2280
2281         dbus_pending_call_set_notify(call, manager_get_modems_reply,
2282                                         NULL, NULL);
2283
2284         dbus_message_unref(message);
2285
2286         return -EINPROGRESS;
2287 }
2288
2289 static void ofono_connect(DBusConnection *conn, void *user_data)
2290 {
2291         DBG("");
2292
2293         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2294                                                 g_free, remove_modem);
2295         if (modem_hash == NULL)
2296                 return;
2297
2298         context_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2299                                                 g_free, NULL);
2300         if (context_hash == NULL) {
2301                 g_hash_table_destroy(modem_hash);
2302                 return;
2303         }
2304
2305         manager_get_modems();
2306 }
2307
2308 static void ofono_disconnect(DBusConnection *conn, void *user_data)
2309 {
2310         DBG("");
2311
2312         if (modem_hash == NULL || context_hash == NULL)
2313                 return;
2314
2315         g_hash_table_destroy(modem_hash);
2316         modem_hash = NULL;
2317
2318         g_hash_table_destroy(context_hash);
2319         context_hash = NULL;
2320 }
2321
2322 static int network_probe(struct connman_network *network)
2323 {
2324         struct modem_data *modem = connman_network_get_data(network);
2325
2326         DBG("%s network %p", modem->path, network);
2327
2328         return 0;
2329 }
2330
2331 static void network_remove(struct connman_network *network)
2332 {
2333         struct modem_data *modem = connman_network_get_data(network);
2334
2335         DBG("%s network %p", modem->path, network);
2336 }
2337
2338 static int network_connect(struct connman_network *network)
2339 {
2340         struct modem_data *modem = connman_network_get_data(network);
2341
2342         DBG("%s network %p", modem->path, network);
2343
2344         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE)
2345                 return context_set_active(modem, TRUE);
2346         else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM) == TRUE)
2347                 return cdma_cm_set_powered(modem, TRUE);
2348
2349         connman_error("Connection manager interface not available");
2350
2351         return -ENOSYS;
2352 }
2353
2354 static int network_disconnect(struct connman_network *network)
2355 {
2356         struct modem_data *modem = connman_network_get_data(network);
2357
2358         DBG("%s network %p", modem->path, network);
2359
2360         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE)
2361                 return context_set_active(modem, FALSE);
2362         else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM) == TRUE)
2363                 return cdma_cm_set_powered(modem, FALSE);
2364
2365         connman_error("Connection manager interface not available");
2366
2367         return -ENOSYS;
2368 }
2369
2370 static struct connman_network_driver network_driver = {
2371         .name           = "network",
2372         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
2373         .probe          = network_probe,
2374         .remove         = network_remove,
2375         .connect        = network_connect,
2376         .disconnect     = network_disconnect,
2377 };
2378
2379 static int modem_probe(struct connman_device *device)
2380 {
2381         struct modem_data *modem = connman_device_get_data(device);
2382
2383         DBG("%s device %p", modem->path, device);
2384
2385         return 0;
2386 }
2387
2388 static void modem_remove(struct connman_device *device)
2389 {
2390         struct modem_data *modem = connman_device_get_data(device);
2391
2392         DBG("%s device %p", modem->path, device);
2393 }
2394
2395 static int modem_enable(struct connman_device *device)
2396 {
2397         struct modem_data *modem = connman_device_get_data(device);
2398
2399         DBG("%s device %p", modem->path, device);
2400
2401         if (modem->online == TRUE)
2402                 return 0;
2403
2404         return modem_set_online(modem, TRUE);
2405 }
2406
2407 static int modem_disable(struct connman_device *device)
2408 {
2409         struct modem_data *modem = connman_device_get_data(device);
2410
2411         DBG("%s device %p", modem->path, device);
2412
2413         if (modem->online == FALSE)
2414                 return 0;
2415
2416         return modem_set_online(modem, FALSE);
2417 }
2418
2419 static struct connman_device_driver modem_driver = {
2420         .name           = "modem",
2421         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
2422         .probe          = modem_probe,
2423         .remove         = modem_remove,
2424         .enable         = modem_enable,
2425         .disable        = modem_disable,
2426 };
2427
2428 static int tech_probe(struct connman_technology *technology)
2429 {
2430         return 0;
2431 }
2432
2433 static void tech_remove(struct connman_technology *technology)
2434 {
2435 }
2436
2437 static struct connman_technology_driver tech_driver = {
2438         .name           = "cellular",
2439         .type           = CONNMAN_SERVICE_TYPE_CELLULAR,
2440         .probe          = tech_probe,
2441         .remove         = tech_remove,
2442 };
2443
2444 static guint watch;
2445 static guint modem_added_watch;
2446 static guint modem_removed_watch;
2447 static guint modem_watch;
2448 static guint cm_watch;
2449 static guint sim_watch;
2450 static guint context_added_watch;
2451 static guint context_removed_watch;
2452 static guint netreg_watch;
2453 static guint context_watch;
2454 static guint cdma_cm_watch;
2455 static guint cdma_netreg_watch;
2456
2457 static int ofono_init(void)
2458 {
2459         int err;
2460
2461         DBG("");
2462
2463         connection = connman_dbus_get_connection();
2464         if (connection == NULL)
2465                 return -EIO;
2466
2467         watch = g_dbus_add_service_watch(connection,
2468                                         OFONO_SERVICE, ofono_connect,
2469                                         ofono_disconnect, NULL, NULL);
2470
2471         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2472                                                 OFONO_MANAGER_INTERFACE,
2473                                                 MODEM_ADDED,
2474                                                 modem_added,
2475                                                 NULL, NULL);
2476
2477         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2478                                                 OFONO_MANAGER_INTERFACE,
2479                                                 MODEM_REMOVED,
2480                                                 modem_removed,
2481                                                 NULL, NULL);
2482
2483         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2484                                                 OFONO_MODEM_INTERFACE,
2485                                                 PROPERTY_CHANGED,
2486                                                 modem_changed,
2487                                                 NULL, NULL);
2488
2489         cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2490                                                 OFONO_CM_INTERFACE,
2491                                                 PROPERTY_CHANGED,
2492                                                 cm_changed,
2493                                                 NULL, NULL);
2494
2495         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2496                                                 OFONO_SIM_INTERFACE,
2497                                                 PROPERTY_CHANGED,
2498                                                 sim_changed,
2499                                                 NULL, NULL);
2500
2501         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2502                                                 OFONO_CM_INTERFACE,
2503                                                 CONTEXT_ADDED,
2504                                                 cm_context_added,
2505                                                 NULL, NULL);
2506
2507         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2508                                                 OFONO_CM_INTERFACE,
2509                                                 CONTEXT_REMOVED,
2510                                                 cm_context_removed,
2511                                                 NULL, NULL);
2512
2513         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2514                                                 OFONO_CONTEXT_INTERFACE,
2515                                                 PROPERTY_CHANGED,
2516                                                 context_changed,
2517                                                 NULL, NULL);
2518
2519         netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2520                                                 OFONO_NETREG_INTERFACE,
2521                                                 PROPERTY_CHANGED,
2522                                                 netreg_changed,
2523                                                 NULL, NULL);
2524
2525         cdma_cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2526                                                 OFONO_CDMA_CM_INTERFACE,
2527                                                 PROPERTY_CHANGED,
2528                                                 cdma_cm_changed,
2529                                                 NULL, NULL);
2530
2531         cdma_netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2532                                                 OFONO_CDMA_NETREG_INTERFACE,
2533                                                 PROPERTY_CHANGED,
2534                                                 cdma_netreg_changed,
2535                                                 NULL, NULL);
2536
2537
2538         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
2539                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
2540                         context_added_watch == 0 ||
2541                         context_removed_watch == 0 ||
2542                         context_watch == 0 || netreg_watch == 0 ||
2543                         cdma_cm_watch == 0 || cdma_netreg_watch == 0) {
2544                 err = -EIO;
2545                 goto remove;
2546         }
2547
2548         err = connman_network_driver_register(&network_driver);
2549         if (err < 0)
2550                 goto remove;
2551
2552         err = connman_device_driver_register(&modem_driver);
2553         if (err < 0) {
2554                 connman_network_driver_unregister(&network_driver);
2555                 goto remove;
2556         }
2557
2558         err = connman_technology_driver_register(&tech_driver);
2559         if (err < 0) {
2560                 connman_device_driver_unregister(&modem_driver);
2561                 connman_network_driver_unregister(&network_driver);
2562                 goto remove;
2563         }
2564
2565         return 0;
2566
2567 remove:
2568         g_dbus_remove_watch(connection, cdma_netreg_watch);
2569         g_dbus_remove_watch(connection, cdma_cm_watch);
2570         g_dbus_remove_watch(connection, netreg_watch);
2571         g_dbus_remove_watch(connection, context_watch);
2572         g_dbus_remove_watch(connection, context_removed_watch);
2573         g_dbus_remove_watch(connection, context_added_watch);
2574         g_dbus_remove_watch(connection, sim_watch);
2575         g_dbus_remove_watch(connection, cm_watch);
2576         g_dbus_remove_watch(connection, modem_watch);
2577         g_dbus_remove_watch(connection, modem_removed_watch);
2578         g_dbus_remove_watch(connection, modem_added_watch);
2579         g_dbus_remove_watch(connection, watch);
2580         dbus_connection_unref(connection);
2581
2582         return err;
2583 }
2584
2585 static void ofono_exit(void)
2586 {
2587         DBG("");
2588
2589         if (modem_hash != NULL) {
2590                 /*
2591                  * We should propably wait for the SetProperty() reply
2592                  * message, because ...
2593                  */
2594                 g_hash_table_foreach(modem_hash, modem_power_down, NULL);
2595
2596                 /*
2597                  * ... here we will cancel the call.
2598                  */
2599                 g_hash_table_destroy(modem_hash);
2600                 modem_hash = NULL;
2601         }
2602
2603         if (context_hash != NULL) {
2604                 g_hash_table_destroy(context_hash);
2605                 context_hash = NULL;
2606         }
2607
2608         connman_technology_driver_unregister(&tech_driver);
2609         connman_device_driver_unregister(&modem_driver);
2610         connman_network_driver_unregister(&network_driver);
2611
2612         g_dbus_remove_watch(connection, cdma_netreg_watch);
2613         g_dbus_remove_watch(connection, cdma_cm_watch);
2614         g_dbus_remove_watch(connection, netreg_watch);
2615         g_dbus_remove_watch(connection, context_watch);
2616         g_dbus_remove_watch(connection, context_removed_watch);
2617         g_dbus_remove_watch(connection, context_added_watch);
2618         g_dbus_remove_watch(connection, sim_watch);
2619         g_dbus_remove_watch(connection, cm_watch);
2620         g_dbus_remove_watch(connection, modem_watch);
2621         g_dbus_remove_watch(connection, modem_added_watch);
2622         g_dbus_remove_watch(connection, modem_removed_watch);
2623         g_dbus_remove_watch(connection, watch);
2624
2625         dbus_connection_unref(connection);
2626 }
2627
2628 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
2629                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)