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