ofono: Create device for CDMA modem
[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         if (modem->context != NULL)
1675                 return;
1676
1677         extract_ipv4_settings(value, modem->context);
1678 }
1679
1680 static gboolean cdma_cm_changed(DBusConnection *connection,
1681                                 DBusMessage *message, void *user_data)
1682 {
1683         const char *path = dbus_message_get_path(message);
1684         struct modem_data *modem;
1685         DBusMessageIter iter, value;
1686         const char *key;
1687
1688         modem = g_hash_table_lookup(modem_hash, path);
1689         if (modem == NULL)
1690                 return TRUE;
1691
1692         if (modem->online == TRUE && modem->network == NULL)
1693                 cdma_netreg_get_properties(modem);
1694
1695         if (dbus_message_iter_init(message, &iter) == FALSE)
1696                 return TRUE;
1697
1698         dbus_message_iter_get_basic(&iter, &key);
1699
1700         dbus_message_iter_next(&iter);
1701         dbus_message_iter_recurse(&iter, &value);
1702
1703         if (g_str_equal(key, "Powered") == TRUE)
1704                 cdma_cm_update_powered(modem, &value);
1705         if (g_str_equal(key, "Settings") == TRUE)
1706                 cdma_cm_update_settings(modem, &value);
1707
1708         return TRUE;
1709 }
1710
1711 static void cm_properties_reply(struct modem_data *modem, DBusMessageIter *dict)
1712 {
1713         DBG("%s", modem->path);
1714
1715         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1716                 DBusMessageIter entry, value;
1717                 const char *key;
1718
1719                 dbus_message_iter_recurse(dict, &entry);
1720                 dbus_message_iter_get_basic(&entry, &key);
1721
1722                 dbus_message_iter_next(&entry);
1723                 dbus_message_iter_recurse(&entry, &value);
1724
1725                 if (g_str_equal(key, "Attached") == TRUE)
1726                         cm_update_attached(modem, &value);
1727                 else if (g_str_equal(key, "Powered") == TRUE)
1728                         cm_update_powered(modem, &value);
1729
1730                 dbus_message_iter_next(dict);
1731         }
1732 }
1733
1734 static int cm_get_properties(struct modem_data *modem)
1735 {
1736         return get_properties(modem->path, OFONO_CM_INTERFACE,
1737                                 cm_properties_reply, modem);
1738 }
1739
1740 static void cdma_cm_properties_reply(struct modem_data *modem,
1741                                         DBusMessageIter *dict)
1742 {
1743         DBG("%s", modem->path);
1744
1745         if (modem->online == TRUE)
1746                 cdma_netreg_get_properties(modem);
1747
1748         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1749                 DBusMessageIter entry, value;
1750                 const char *key;
1751
1752                 dbus_message_iter_recurse(dict, &entry);
1753                 dbus_message_iter_get_basic(&entry, &key);
1754
1755                 dbus_message_iter_next(&entry);
1756                 dbus_message_iter_recurse(&entry, &value);
1757
1758                 if (g_str_equal(key, "Powered") == TRUE)
1759                         cdma_cm_update_powered(modem, &value);
1760                 if (g_str_equal(key, "Settings") == TRUE)
1761                         cdma_cm_update_settings(modem, &value);
1762
1763                 dbus_message_iter_next(dict);
1764         }
1765 }
1766
1767 static int cdma_cm_get_properties(struct modem_data *modem)
1768 {
1769         return get_properties(modem->path, OFONO_CDMA_CM_INTERFACE,
1770                                 cdma_cm_properties_reply, modem);
1771 }
1772
1773 static void sim_update_imsi(struct modem_data *modem,
1774                                 DBusMessageIter* value)
1775 {
1776         char *imsi;
1777
1778         dbus_message_iter_get_basic(value, &imsi);
1779
1780         DBG("%s imsi %s", modem->path, imsi);
1781
1782         g_free(modem->imsi);
1783         modem->imsi = g_strdup(imsi);
1784 }
1785
1786 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
1787                                 void *user_data)
1788 {
1789         const char *path = dbus_message_get_path(message);
1790         struct modem_data *modem;
1791         DBusMessageIter iter, value;
1792         const char *key;
1793
1794         modem = g_hash_table_lookup(modem_hash, path);
1795         if (modem == NULL)
1796                 return TRUE;
1797
1798         if (modem->ignore == TRUE)
1799                 return TRUE;
1800
1801         if (dbus_message_iter_init(message, &iter) == FALSE)
1802                 return TRUE;
1803
1804         dbus_message_iter_get_basic(&iter, &key);
1805
1806         dbus_message_iter_next(&iter);
1807         dbus_message_iter_recurse(&iter, &value);
1808
1809         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1810                 sim_update_imsi(modem, &value);
1811
1812                 if (ready_to_create_device(modem) == FALSE)
1813                         return TRUE;
1814
1815                 /*
1816                  * This is a GSM modem. Create the device and
1817                  * register it at the core. Enabling (setting
1818                  * it online is done through the
1819                  * modem_enable() callback.
1820                  */
1821                 create_device(modem);
1822         }
1823
1824         return TRUE;
1825 }
1826
1827 static void sim_properties_reply(struct modem_data *modem,
1828                                         DBusMessageIter *dict)
1829 {
1830         DBG("%s", modem->path);
1831
1832         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1833                 DBusMessageIter entry, value;
1834                 const char *key;
1835
1836                 dbus_message_iter_recurse(dict, &entry);
1837                 dbus_message_iter_get_basic(&entry, &key);
1838
1839                 dbus_message_iter_next(&entry);
1840                 dbus_message_iter_recurse(&entry, &value);
1841
1842                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1843                         sim_update_imsi(modem, &value);
1844
1845                         if (ready_to_create_device(modem) == FALSE)
1846                                 return;
1847
1848                         /*
1849                          * This is a GSM modem. Create the device and
1850                          * register it at the core. Enabling (setting
1851                          * it online is done through the
1852                          * modem_enable() callback.
1853                          */
1854                         create_device(modem);
1855
1856                         if (modem->online == FALSE)
1857                                 return;
1858
1859                         /*
1860                          * The modem is already online and we have the CM interface.
1861                          * There will be no interface update and therefore our
1862                          * state machine will not go to next step. We have to
1863                          * trigger it from here.
1864                          */
1865                         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1866                                 cm_get_properties(modem);
1867                                 cm_get_contexts(modem);
1868                         }
1869                         return;
1870                 }
1871
1872                 dbus_message_iter_next(dict);
1873         }
1874 }
1875
1876 static int sim_get_properties(struct modem_data *modem)
1877 {
1878         return get_properties(modem->path, OFONO_SIM_INTERFACE,
1879                                 sim_properties_reply, modem);
1880 }
1881
1882 static connman_bool_t api_added(uint8_t old_iface, uint8_t new_iface,
1883                                 enum ofono_api api)
1884 {
1885         if (has_interface(old_iface, api) == FALSE &&
1886                         has_interface(new_iface, api) == TRUE) {
1887                 DBG("%s added", api2string(api));
1888                 return TRUE;
1889         }
1890
1891         return FALSE;
1892 }
1893
1894 static connman_bool_t api_removed(uint8_t old_iface, uint8_t new_iface,
1895                                 enum ofono_api api)
1896 {
1897         if (has_interface(old_iface, api) == TRUE &&
1898                         has_interface(new_iface, api) == FALSE) {
1899                 DBG("%s removed", api2string(api));
1900                 return TRUE;
1901         }
1902
1903         return FALSE;
1904 }
1905
1906 static void modem_update_interfaces(struct modem_data *modem,
1907                                 uint8_t old_ifaces,
1908                                 uint8_t new_ifaces)
1909 {
1910         DBG("%s", modem->path);
1911
1912         if (api_added(old_ifaces, new_ifaces, OFONO_API_SIM) == TRUE) {
1913                 if (modem->imsi == NULL &&
1914                                 modem->set_powered == FALSE) {
1915                         /*
1916                          * Only use do GetProperties() when
1917                          * device has not been powered up.
1918                          */
1919                         sim_get_properties(modem);
1920                 }
1921         }
1922
1923         if (api_added(old_ifaces, new_ifaces, OFONO_API_CM) == TRUE) {
1924                 if (modem->device != NULL) {
1925                         cm_get_properties(modem);
1926                         cm_get_contexts(modem);
1927                 }
1928         }
1929
1930         if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_CM) == TRUE) {
1931                 if (ready_to_create_device(modem) == TRUE)
1932                         create_device(modem);
1933
1934                 if (modem->device != NULL)
1935                         cdma_cm_get_properties(modem);
1936         }
1937
1938         if (api_added(old_ifaces, new_ifaces, OFONO_API_NETREG) == TRUE) {
1939                 if (modem->attached == TRUE)
1940                         netreg_get_properties(modem);
1941         }
1942
1943         if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG) == TRUE) {
1944                 cdma_netreg_get_properties(modem);
1945         }
1946
1947         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CM) == TRUE) {
1948                 remove_cm_context(modem, modem->context->path);
1949         }
1950
1951         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_CM) == TRUE) {
1952                 remove_cm_context(modem, modem->context->path);
1953         }
1954
1955         if (api_removed(old_ifaces, new_ifaces, OFONO_API_NETREG) == TRUE) {
1956                 remove_network(modem);
1957         }
1958
1959         if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG == TRUE)) {
1960                 remove_network(modem);
1961         }
1962 }
1963
1964 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
1965                                 void *user_data)
1966 {
1967         const char *path = dbus_message_get_path(message);
1968         struct modem_data *modem;
1969         DBusMessageIter iter, value;
1970         const char *key;
1971
1972         modem = g_hash_table_lookup(modem_hash, path);
1973         if (modem == NULL)
1974                 return TRUE;
1975
1976         if (modem->ignore == TRUE)
1977                 return TRUE;
1978
1979         if (dbus_message_iter_init(message, &iter) == FALSE)
1980                 return TRUE;
1981
1982         dbus_message_iter_get_basic(&iter, &key);
1983
1984         dbus_message_iter_next(&iter);
1985         dbus_message_iter_recurse(&iter, &value);
1986
1987         if (g_str_equal(key, "Powered") == TRUE) {
1988                 dbus_message_iter_get_basic(&value, &modem->powered);
1989
1990                 DBG("%s Powered %d", modem->path, modem->powered);
1991
1992                 if (modem->powered == FALSE)
1993                         modem_set_powered(modem, TRUE);
1994         } else if (g_str_equal(key, "Online") == TRUE) {
1995                 dbus_message_iter_get_basic(&value, &modem->online);
1996
1997                 DBG("%s Online %d", modem->path, modem->online);
1998
1999                 if (modem->device == NULL)
2000                         return TRUE;
2001
2002                 connman_device_set_powered(modem->device, modem->online);
2003         } else if (g_str_equal(key, "Interfaces") == TRUE) {
2004                 uint8_t interfaces;
2005
2006                 interfaces = extract_interfaces(&value);
2007
2008                 if (interfaces == modem->interfaces)
2009                         return TRUE;
2010
2011                 DBG("%s Interfaces 0x%02x", modem->path, interfaces);
2012
2013                 modem_update_interfaces(modem, modem->interfaces, interfaces);
2014
2015                 modem->interfaces = interfaces;
2016         } else if (g_str_equal(key, "Serial") == TRUE) {
2017                 char *serial;
2018
2019                 dbus_message_iter_get_basic(&value, &serial);
2020
2021                 g_free(modem->serial);
2022                 modem->serial = g_strdup(serial);
2023
2024                 DBG("%s Serial %s", modem->path, modem->serial);
2025
2026                 if (has_interface(modem->interfaces,
2027                                          OFONO_API_CDMA_CM) == TRUE) {
2028                         if (ready_to_create_device(modem) == TRUE)
2029                                 create_device(modem);
2030                 }
2031         }
2032
2033         return TRUE;
2034 }
2035
2036 static void add_modem(const char *path, DBusMessageIter *prop)
2037 {
2038         struct modem_data *modem;
2039
2040         DBG("%s", path);
2041
2042         modem = g_hash_table_lookup(modem_hash, path);
2043         if (modem != NULL) {
2044                 /*
2045                  * When oFono powers up we ask for the modems and oFono is
2046                  * reporting with modem_added signal the modems. Only
2047                  * handle them once.
2048                  */
2049                 return;
2050         }
2051
2052         modem = g_try_new0(struct modem_data, 1);
2053         if (modem == NULL)
2054                 return;
2055
2056         modem->path = g_strdup(path);
2057
2058         g_hash_table_insert(modem_hash, g_strdup(path), modem);
2059
2060         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
2061                 DBusMessageIter entry, value;
2062                 const char *key;
2063
2064                 dbus_message_iter_recurse(prop, &entry);
2065                 dbus_message_iter_get_basic(&entry, &key);
2066
2067                 dbus_message_iter_next(&entry);
2068                 dbus_message_iter_recurse(&entry, &value);
2069
2070                 if (g_str_equal(key, "Powered") == TRUE) {
2071                         dbus_message_iter_get_basic(&value, &modem->powered);
2072
2073                         DBG("%s Powered %d", modem->path, modem->powered);
2074                 } else if (g_str_equal(key, "Online") == TRUE) {
2075                         dbus_message_iter_get_basic(&value, &modem->online);
2076
2077                         DBG("%s Online %d", modem->path, modem->online);
2078                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
2079                         modem->interfaces = extract_interfaces(&value);
2080
2081                         DBG("%s Interfaces 0x%02x", modem->path,
2082                                 modem->interfaces);
2083                 } else if (g_str_equal(key, "Serial") == TRUE) {
2084                         char *serial;
2085
2086                         dbus_message_iter_get_basic(&value, &serial);
2087                         modem->serial = g_strdup(serial);
2088
2089                         DBG("%s Serial %s", modem->path, modem->serial);
2090                 } else if (g_str_equal(key, "Type") == TRUE) {
2091                         char *type;
2092
2093                         dbus_message_iter_get_basic(&value, &type);
2094
2095                         DBG("%s Type %s", modem->path, type);
2096                         if (g_strcmp0(type, "hardware") != 0) {
2097                                 DBG("%s Ignore this modem", modem->path);
2098                                 modem->ignore = TRUE;
2099                         }
2100                 }
2101
2102                 dbus_message_iter_next(prop);
2103         }
2104
2105         if (modem->ignore == TRUE)
2106                 return;
2107
2108         if (modem->powered == FALSE) {
2109                 modem_set_powered(modem, TRUE);
2110                 return;
2111         }
2112
2113         modem_update_interfaces(modem, 0, modem->interfaces);
2114 }
2115
2116 static void modem_power_down(gpointer key, gpointer value, gpointer user_data)
2117 {
2118         struct modem_data *modem = value;
2119
2120         DBG("%s", modem->path);
2121
2122         if (modem->ignore ==  TRUE)
2123                 return;
2124
2125         modem_set_powered(modem, FALSE);
2126 }
2127
2128 static void remove_modem(gpointer data)
2129 {
2130         struct modem_data *modem = data;
2131
2132         DBG("%s", modem->path);
2133
2134         if (modem->call_set_property != NULL)
2135                 dbus_pending_call_cancel(modem->call_set_property);
2136
2137         if (modem->call_get_properties != NULL)
2138                 dbus_pending_call_cancel(modem->call_get_properties);
2139
2140         if (modem->call_get_contexts != NULL)
2141                 dbus_pending_call_cancel(modem->call_get_contexts);
2142
2143         if (modem->device != NULL)
2144                 destroy_device(modem);
2145
2146         if (modem->context != NULL)
2147                 remove_cm_context(modem, modem->context->path);
2148
2149         g_free(modem->serial);
2150         g_free(modem->name);
2151         g_free(modem->imsi);
2152         g_free(modem->path);
2153
2154         g_free(modem);
2155 }
2156
2157 static gboolean modem_added(DBusConnection *connection,
2158                                 DBusMessage *message, void *user_data)
2159 {
2160         DBusMessageIter iter, properties;
2161         const char *path;
2162
2163         DBG("");
2164
2165         if (dbus_message_iter_init(message, &iter) == FALSE)
2166                 return TRUE;
2167
2168         dbus_message_iter_get_basic(&iter, &path);
2169
2170         dbus_message_iter_next(&iter);
2171         dbus_message_iter_recurse(&iter, &properties);
2172
2173         add_modem(path, &properties);
2174
2175         return TRUE;
2176 }
2177
2178 static gboolean modem_removed(DBusConnection *connection,
2179                                 DBusMessage *message, void *user_data)
2180 {
2181         DBusMessageIter iter;
2182         const char *path;
2183
2184         DBG("");
2185
2186         if (dbus_message_iter_init(message, &iter) == FALSE)
2187                 return TRUE;
2188
2189         dbus_message_iter_get_basic(&iter, &path);
2190
2191         g_hash_table_remove(modem_hash, path);
2192
2193         return TRUE;
2194 }
2195
2196 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
2197 {
2198         DBusMessage *reply;
2199         DBusError error;
2200         DBusMessageIter array, dict;
2201
2202         DBG("");
2203
2204         reply = dbus_pending_call_steal_reply(call);
2205
2206         dbus_error_init(&error);
2207
2208         if (dbus_set_error_from_message(&error, reply) == TRUE) {
2209                 connman_error("%s", error.message);
2210                 dbus_error_free(&error);
2211                 goto done;
2212         }
2213
2214         if (dbus_message_iter_init(reply, &array) == FALSE)
2215                 goto done;
2216
2217         dbus_message_iter_recurse(&array, &dict);
2218
2219         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
2220                 DBusMessageIter value, properties;
2221                 const char *path;
2222
2223                 dbus_message_iter_recurse(&dict, &value);
2224                 dbus_message_iter_get_basic(&value, &path);
2225
2226                 dbus_message_iter_next(&value);
2227                 dbus_message_iter_recurse(&value, &properties);
2228
2229                 add_modem(path, &properties);
2230
2231                 dbus_message_iter_next(&dict);
2232         }
2233
2234 done:
2235         dbus_message_unref(reply);
2236
2237         dbus_pending_call_unref(call);
2238 }
2239
2240 static int manager_get_modems(void)
2241 {
2242         DBusMessage *message;
2243         DBusPendingCall *call;
2244
2245         DBG("");
2246
2247         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
2248                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
2249         if (message == NULL)
2250                 return -ENOMEM;
2251
2252         if (dbus_connection_send_with_reply(connection, message,
2253                                                &call, TIMEOUT) == FALSE) {
2254                 connman_error("Failed to call GetModems()");
2255                 dbus_message_unref(message);
2256                 return -EINVAL;
2257         }
2258
2259         if (call == NULL) {
2260                 connman_error("D-Bus connection not available");
2261                 dbus_message_unref(message);
2262                 return -EINVAL;
2263         }
2264
2265         dbus_pending_call_set_notify(call, manager_get_modems_reply,
2266                                         NULL, NULL);
2267
2268         dbus_message_unref(message);
2269
2270         return -EINPROGRESS;
2271 }
2272
2273 static void ofono_connect(DBusConnection *conn, void *user_data)
2274 {
2275         DBG("");
2276
2277         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2278                                                 g_free, remove_modem);
2279         if (modem_hash == NULL)
2280                 return;
2281
2282         context_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2283                                                 g_free, NULL);
2284         if (context_hash == NULL) {
2285                 g_hash_table_destroy(modem_hash);
2286                 return;
2287         }
2288
2289         manager_get_modems();
2290 }
2291
2292 static void ofono_disconnect(DBusConnection *conn, void *user_data)
2293 {
2294         DBG("");
2295
2296         if (modem_hash == NULL || context_hash == NULL)
2297                 return;
2298
2299         g_hash_table_destroy(modem_hash);
2300         modem_hash = NULL;
2301
2302         g_hash_table_destroy(context_hash);
2303         context_hash = NULL;
2304 }
2305
2306 static int network_probe(struct connman_network *network)
2307 {
2308         struct modem_data *modem = connman_network_get_data(network);
2309
2310         DBG("%s network %p", modem->path, network);
2311
2312         return 0;
2313 }
2314
2315 static void network_remove(struct connman_network *network)
2316 {
2317         struct modem_data *modem = connman_network_get_data(network);
2318
2319         DBG("%s network %p", modem->path, network);
2320 }
2321
2322 static int network_connect(struct connman_network *network)
2323 {
2324         struct modem_data *modem = connman_network_get_data(network);
2325
2326         DBG("%s network %p", modem->path, network);
2327
2328         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE)
2329                 return context_set_active(modem, TRUE);
2330         else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM) == TRUE)
2331                 return cdma_cm_set_powered(modem, TRUE);
2332
2333         connman_error("Connection manager interface not available");
2334
2335         return -ENOSYS;
2336 }
2337
2338 static int network_disconnect(struct connman_network *network)
2339 {
2340         struct modem_data *modem = connman_network_get_data(network);
2341
2342         DBG("%s network %p", modem->path, network);
2343
2344         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE)
2345                 return context_set_active(modem, FALSE);
2346         else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM) == TRUE)
2347                 return cdma_cm_set_powered(modem, FALSE);
2348
2349         connman_error("Connection manager interface not available");
2350
2351         return -ENOSYS;
2352 }
2353
2354 static struct connman_network_driver network_driver = {
2355         .name           = "network",
2356         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
2357         .probe          = network_probe,
2358         .remove         = network_remove,
2359         .connect        = network_connect,
2360         .disconnect     = network_disconnect,
2361 };
2362
2363 static int modem_probe(struct connman_device *device)
2364 {
2365         struct modem_data *modem = connman_device_get_data(device);
2366
2367         DBG("%s device %p", modem->path, device);
2368
2369         return 0;
2370 }
2371
2372 static void modem_remove(struct connman_device *device)
2373 {
2374         struct modem_data *modem = connman_device_get_data(device);
2375
2376         DBG("%s device %p", modem->path, device);
2377 }
2378
2379 static int modem_enable(struct connman_device *device)
2380 {
2381         struct modem_data *modem = connman_device_get_data(device);
2382
2383         DBG("%s device %p", modem->path, device);
2384
2385         if (modem->online == TRUE)
2386                 return 0;
2387
2388         return modem_set_online(modem, TRUE);
2389 }
2390
2391 static int modem_disable(struct connman_device *device)
2392 {
2393         struct modem_data *modem = connman_device_get_data(device);
2394
2395         DBG("%s device %p", modem->path, device);
2396
2397         if (modem->online == FALSE)
2398                 return 0;
2399
2400         return modem_set_online(modem, FALSE);
2401 }
2402
2403 static struct connman_device_driver modem_driver = {
2404         .name           = "modem",
2405         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
2406         .probe          = modem_probe,
2407         .remove         = modem_remove,
2408         .enable         = modem_enable,
2409         .disable        = modem_disable,
2410 };
2411
2412 static guint watch;
2413 static guint modem_added_watch;
2414 static guint modem_removed_watch;
2415 static guint modem_watch;
2416 static guint cm_watch;
2417 static guint sim_watch;
2418 static guint context_added_watch;
2419 static guint context_removed_watch;
2420 static guint netreg_watch;
2421 static guint context_watch;
2422 static guint cdma_cm_watch;
2423 static guint cdma_netreg_watch;
2424
2425 static int ofono_init(void)
2426 {
2427         int err;
2428
2429         DBG("");
2430
2431         connection = connman_dbus_get_connection();
2432         if (connection == NULL)
2433                 return -EIO;
2434
2435         watch = g_dbus_add_service_watch(connection,
2436                                         OFONO_SERVICE, ofono_connect,
2437                                         ofono_disconnect, NULL, NULL);
2438
2439         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2440                                                 OFONO_MANAGER_INTERFACE,
2441                                                 MODEM_ADDED,
2442                                                 modem_added,
2443                                                 NULL, NULL);
2444
2445         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2446                                                 OFONO_MANAGER_INTERFACE,
2447                                                 MODEM_REMOVED,
2448                                                 modem_removed,
2449                                                 NULL, NULL);
2450
2451         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2452                                                 OFONO_MODEM_INTERFACE,
2453                                                 PROPERTY_CHANGED,
2454                                                 modem_changed,
2455                                                 NULL, NULL);
2456
2457         cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2458                                                 OFONO_CM_INTERFACE,
2459                                                 PROPERTY_CHANGED,
2460                                                 cm_changed,
2461                                                 NULL, NULL);
2462
2463         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2464                                                 OFONO_SIM_INTERFACE,
2465                                                 PROPERTY_CHANGED,
2466                                                 sim_changed,
2467                                                 NULL, NULL);
2468
2469         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2470                                                 OFONO_CM_INTERFACE,
2471                                                 CONTEXT_ADDED,
2472                                                 cm_context_added,
2473                                                 NULL, NULL);
2474
2475         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2476                                                 OFONO_CM_INTERFACE,
2477                                                 CONTEXT_REMOVED,
2478                                                 cm_context_removed,
2479                                                 NULL, NULL);
2480
2481         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2482                                                 OFONO_CONTEXT_INTERFACE,
2483                                                 PROPERTY_CHANGED,
2484                                                 context_changed,
2485                                                 NULL, NULL);
2486
2487         netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2488                                                 OFONO_NETREG_INTERFACE,
2489                                                 PROPERTY_CHANGED,
2490                                                 netreg_changed,
2491                                                 NULL, NULL);
2492
2493         cdma_cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2494                                                 OFONO_CDMA_CM_INTERFACE,
2495                                                 PROPERTY_CHANGED,
2496                                                 cdma_cm_changed,
2497                                                 NULL, NULL);
2498
2499         cdma_netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2500                                                 OFONO_CDMA_NETREG_INTERFACE,
2501                                                 PROPERTY_CHANGED,
2502                                                 cdma_netreg_changed,
2503                                                 NULL, NULL);
2504
2505
2506         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
2507                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
2508                         context_added_watch == 0 ||
2509                         context_removed_watch == 0 ||
2510                         context_watch == 0 || netreg_watch == 0 ||
2511                         cdma_cm_watch == 0 || cdma_netreg_watch == 0) {
2512                 err = -EIO;
2513                 goto remove;
2514         }
2515
2516         err = connman_network_driver_register(&network_driver);
2517         if (err < 0)
2518                 goto remove;
2519
2520         err = connman_device_driver_register(&modem_driver);
2521         if (err < 0) {
2522                 connman_network_driver_unregister(&network_driver);
2523                 goto remove;
2524         }
2525
2526         return 0;
2527
2528 remove:
2529         g_dbus_remove_watch(connection, cdma_netreg_watch);
2530         g_dbus_remove_watch(connection, cdma_cm_watch);
2531         g_dbus_remove_watch(connection, netreg_watch);
2532         g_dbus_remove_watch(connection, context_watch);
2533         g_dbus_remove_watch(connection, context_removed_watch);
2534         g_dbus_remove_watch(connection, context_added_watch);
2535         g_dbus_remove_watch(connection, sim_watch);
2536         g_dbus_remove_watch(connection, cm_watch);
2537         g_dbus_remove_watch(connection, modem_watch);
2538         g_dbus_remove_watch(connection, modem_removed_watch);
2539         g_dbus_remove_watch(connection, modem_added_watch);
2540         g_dbus_remove_watch(connection, watch);
2541         dbus_connection_unref(connection);
2542
2543         return err;
2544 }
2545
2546 static void ofono_exit(void)
2547 {
2548         DBG("");
2549
2550         if (modem_hash != NULL) {
2551                 /*
2552                  * We should propably wait for the SetProperty() reply
2553                  * message, because ...
2554                  */
2555                 g_hash_table_foreach(modem_hash, modem_power_down, NULL);
2556
2557                 /*
2558                  * ... here we will cancel the call.
2559                  */
2560                 g_hash_table_destroy(modem_hash);
2561                 modem_hash = NULL;
2562         }
2563
2564         if (context_hash != NULL) {
2565                 g_hash_table_destroy(context_hash);
2566                 context_hash = NULL;
2567         }
2568
2569         connman_device_driver_unregister(&modem_driver);
2570         connman_network_driver_unregister(&network_driver);
2571
2572         g_dbus_remove_watch(connection, cdma_netreg_watch);
2573         g_dbus_remove_watch(connection, cdma_cm_watch);
2574         g_dbus_remove_watch(connection, netreg_watch);
2575         g_dbus_remove_watch(connection, context_watch);
2576         g_dbus_remove_watch(connection, context_removed_watch);
2577         g_dbus_remove_watch(connection, context_added_watch);
2578         g_dbus_remove_watch(connection, sim_watch);
2579         g_dbus_remove_watch(connection, cm_watch);
2580         g_dbus_remove_watch(connection, modem_watch);
2581         g_dbus_remove_watch(connection, modem_added_watch);
2582         g_dbus_remove_watch(connection, modem_removed_watch);
2583         g_dbus_remove_watch(connection, watch);
2584
2585         dbus_connection_unref(connection);
2586 }
2587
2588 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
2589                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)