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