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