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