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