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