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