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