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