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