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