ofono: Get ConnectionManager properties
[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/dbus.h>
39 #include <connman/log.h>
40
41 #define uninitialized_var(x) x = x
42
43 #define OFONO_SERVICE                   "org.ofono"
44
45 #define OFONO_MANAGER_INTERFACE         OFONO_SERVICE ".Manager"
46 #define OFONO_MODEM_INTERFACE           OFONO_SERVICE ".Modem"
47 #define OFONO_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
48 #define OFONO_NETREG_INTERFACE          OFONO_SERVICE ".NetworkRegistration"
49 #define OFONO_CM_INTERFACE              OFONO_SERVICE ".ConnectionManager"
50 #define OFONO_CONTEXT_INTERFACE         OFONO_SERVICE ".ConnectionContext"
51
52 #define MODEM_ADDED                     "ModemAdded"
53 #define MODEM_REMOVED                   "ModemRemoved"
54 #define PROPERTY_CHANGED                "PropertyChanged"
55 #define CONTEXT_ADDED                   "ContextAdded"
56 #define CONTEXT_REMOVED                 "ContextRemoved"
57
58 #define GET_PROPERTIES                  "GetProperties"
59 #define SET_PROPERTY                    "SetProperty"
60 #define GET_MODEMS                      "GetModems"
61
62 #define TIMEOUT 40000
63
64 enum ofono_api {
65         OFONO_API_SIM =         0x1,
66         OFONO_API_NETREG =      0x2,
67         OFONO_API_CM =          0x4,
68 };
69
70 static DBusConnection *connection;
71
72 static GHashTable *modem_hash;
73
74 struct modem_data {
75         char *path;
76
77         struct connman_device *device;
78
79         /* Modem Interface */
80         char *serial;
81         connman_bool_t powered;
82         connman_bool_t online;
83         uint8_t interfaces;
84
85         connman_bool_t set_powered;
86         connman_bool_t set_online;
87
88         /* ConnectionManager Interface */
89         connman_bool_t attached;
90
91         /* SimManager Interface */
92         char *imsi;
93
94         /* pending calls */
95         DBusPendingCall *call_set_property;
96         DBusPendingCall *call_get_properties;
97 };
98
99 typedef void (*set_property_cb)(struct modem_data *data,
100                                 connman_bool_t success);
101 typedef void (*get_properties_cb)(struct modem_data *data,
102                                 DBusMessageIter *dict);
103
104 struct property_info {
105         struct modem_data *modem;
106         const char *path;
107         const char *interface;
108         const char *property;
109         set_property_cb set_property_cb;
110         get_properties_cb get_properties_cb;
111 };
112
113 static void set_property_reply(DBusPendingCall *call, void *user_data)
114 {
115         struct property_info *info = user_data;
116         DBusMessage *reply;
117         DBusError error;
118         connman_bool_t success = TRUE;
119
120         DBG("%s path %s %s.%s", info->modem->path,
121                 info->path, info->interface, info->property);
122
123         info->modem->call_set_property = NULL;
124
125         dbus_error_init(&error);
126
127         reply = dbus_pending_call_steal_reply(call);
128
129         if (dbus_set_error_from_message(&error, reply)) {
130                 connman_error("Failed to change property: %s %s.%s: %s %s",
131                                 info->path, info->interface, info->property,
132                                 error.name, error.message);
133                 dbus_error_free(&error);
134                 success = FALSE;
135         }
136
137         if (info->set_property_cb != NULL)
138                 (*info->set_property_cb)(info->modem, success);
139
140         dbus_message_unref(reply);
141
142         dbus_pending_call_unref(call);
143 }
144
145 static int set_property(struct modem_data *modem,
146                         const char *path, const char *interface,
147                         const char *property, int type, void *value,
148                         set_property_cb notify)
149 {
150         DBusMessage *message;
151         DBusMessageIter iter;
152         struct property_info *info;
153
154         DBG("%s path %s %s.%s", modem->path, path, interface, property);
155
156         if (modem->call_set_property != NULL) {
157                 connman_error("Pending SetProperty");
158                 return -EBUSY;
159         }
160
161         message = dbus_message_new_method_call(OFONO_SERVICE, path,
162                                         interface, SET_PROPERTY);
163         if (message == NULL)
164                 return -ENOMEM;
165
166         dbus_message_iter_init_append(message, &iter);
167         connman_dbus_property_append_basic(&iter, property, type, value);
168
169         if (dbus_connection_send_with_reply(connection, message,
170                         &modem->call_set_property, TIMEOUT) == FALSE) {
171                 connman_error("Failed to change property: %s %s.%s",
172                                 path, interface, property);
173                 dbus_message_unref(message);
174                 return -EINVAL;
175         }
176
177         if (modem->call_set_property == NULL) {
178                 connman_error("D-Bus connection not available");
179                 dbus_message_unref(message);
180                 return -EINVAL;
181         }
182
183         info = g_try_new0(struct property_info, 1);
184         if (info == NULL) {
185                 dbus_message_unref(message);
186                 return -ENOMEM;
187         }
188
189         info->modem = modem;
190         info->path = path;
191         info->interface = interface;
192         info->property = property;
193         info->set_property_cb = notify;
194
195         dbus_pending_call_set_notify(modem->call_set_property,
196                                         set_property_reply, info, g_free);
197
198         dbus_message_unref(message);
199
200         return -EINPROGRESS;
201 }
202
203 static void get_properties_reply(DBusPendingCall *call, void *user_data)
204 {
205         struct property_info *info = user_data;
206         DBusMessageIter array, dict;
207         DBusMessage *reply;
208         DBusError error;
209
210         DBG("%s path %s %s", info->modem->path, info->path, info->interface);
211
212         info->modem->call_get_properties = NULL;
213
214         dbus_error_init(&error);
215
216         reply = dbus_pending_call_steal_reply(call);
217
218         if (dbus_set_error_from_message(&error, reply)) {
219                 connman_error("Failed to get properties: %s %s: %s %s",
220                                 info->path, info->interface,
221                                 error.name, error.message);
222                 dbus_error_free(&error);
223
224                 goto done;
225         }
226
227         if (dbus_message_iter_init(reply, &array) == FALSE)
228                 goto done;
229
230         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
231                 goto done;
232
233         dbus_message_iter_recurse(&array, &dict);
234
235         if (info->get_properties_cb != NULL)
236                 (*info->get_properties_cb)(info->modem, &dict);
237
238 done:
239
240         dbus_message_unref(reply);
241
242         dbus_pending_call_unref(call);
243 }
244
245 static int get_properties(const char *path, const char *interface,
246                                 get_properties_cb notify,
247                                 struct modem_data *modem)
248 {
249         DBusMessage *message;
250         struct property_info *info;
251
252         DBG("%s path %s %s", modem->path, path, interface);
253
254         if (modem->call_get_properties != NULL) {
255                 connman_error("Pending GetProperties");
256                 return -EBUSY;
257         }
258
259         message = dbus_message_new_method_call(OFONO_SERVICE, path,
260                                         interface, GET_PROPERTIES);
261         if (message == NULL)
262                 return -ENOMEM;
263
264         if (dbus_connection_send_with_reply(connection, message,
265                         &modem->call_get_properties, TIMEOUT) == FALSE) {
266                 connman_error("Failed to call %s.GetProperties()", interface);
267                 dbus_message_unref(message);
268                 return -EINVAL;
269         }
270
271         if (modem->call_get_properties == NULL) {
272                 connman_error("D-Bus connection not available");
273                 dbus_message_unref(message);
274                 return -EINVAL;
275         }
276
277         info = g_try_new0(struct property_info, 1);
278         if (info == NULL) {
279                 dbus_message_unref(message);
280                 return -ENOMEM;
281         }
282
283         info->modem = modem;
284         info->path = path;
285         info->interface = interface;
286         info->get_properties_cb = notify;
287
288         dbus_pending_call_set_notify(modem->call_get_properties,
289                                         get_properties_reply, info, g_free);
290
291         dbus_message_unref(message);
292
293         return -EINPROGRESS;
294 }
295
296 static void modem_set_online_reply(struct modem_data *modem,
297                                         connman_bool_t success)
298 {
299         DBG("%s", modem->path);
300
301         if (success == TRUE) {
302                 /*
303                  * Don't handle do anything on success here. oFono will send
304                  * the change via PropertyChanged singal.
305                  */
306                 return;
307         }
308
309         modem->set_online = FALSE;
310 }
311
312 static int modem_set_online(struct modem_data *modem)
313 {
314         DBG("%s", modem->path);
315
316         modem->set_online = TRUE;
317
318         return set_property(modem, modem->path,
319                                 OFONO_MODEM_INTERFACE,
320                                 "Online", DBUS_TYPE_BOOLEAN,
321                                 &modem->set_online,
322                                 modem_set_online_reply);
323 }
324
325 static int modem_set_powered(struct modem_data *modem)
326 {
327         DBG("%s", modem->path);
328
329         modem->set_powered = TRUE;
330
331         return set_property(modem, modem->path,
332                                 OFONO_MODEM_INTERFACE,
333                                 "Powered", DBUS_TYPE_BOOLEAN,
334                                 &modem->set_powered,
335                                 NULL);
336 }
337
338 static connman_bool_t has_interface(uint8_t interfaces,
339                                         enum ofono_api api)
340 {
341         if ((interfaces & api) == api)
342                 return TRUE;
343
344         return FALSE;
345 }
346
347 static uint8_t extract_interfaces(DBusMessageIter *array)
348 {
349         DBusMessageIter entry;
350         uint8_t interfaces = 0;
351
352         dbus_message_iter_recurse(array, &entry);
353
354         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
355                 const char *name;
356
357                 dbus_message_iter_get_basic(&entry, &name);
358
359                 if (g_str_equal(name, OFONO_SIM_INTERFACE) == TRUE)
360                         interfaces |= OFONO_API_SIM;
361                 else if (g_str_equal(name, OFONO_NETREG_INTERFACE) == TRUE)
362                         interfaces |= OFONO_API_NETREG;
363                 else if (g_str_equal(name, OFONO_CM_INTERFACE) == TRUE)
364                         interfaces |= OFONO_API_CM;
365
366                 dbus_message_iter_next(&entry);
367         }
368
369         return interfaces;
370 }
371
372 static connman_bool_t ready_to_create_device(struct modem_data *modem)
373 {
374         /*
375          * There are three different modem types which behave slightly
376          * different:
377          * - GSM modems will expose the SIM interface then the
378          *   CM interface.
379          * - DUN modems will expose first a unique serial number (BDADDR)
380          *   and then the CM interface.
381          * - CDMA modems will expose CM first and sometime later
382          *   a unique serial number.
383          *
384          * This functions tests if we have the necessary information gathered
385          * before we are able to create a device.
386          */
387
388         if (modem->device != NULL)
389                 return FALSE;
390
391         if (modem->imsi != NULL || modem->serial != NULL)
392                 return TRUE;
393
394         return FALSE;
395 }
396
397 static void create_device(struct modem_data *modem)
398 {
399         struct connman_device *device;
400         char *uninitialized_var(ident);
401
402         DBG("%s", modem->path);
403
404         if (modem->imsi != NULL)
405                 ident = modem->imsi;
406         else if (modem->serial != NULL)
407                 ident = modem->serial;
408
409         if (connman_dbus_validate_ident(ident) == FALSE)
410                 ident = connman_dbus_encode_string(ident);
411         else
412                 ident = g_strdup(ident);
413
414         device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_CELLULAR);
415         if (device == NULL)
416                 goto out;
417
418         DBG("device %p", device);
419
420         connman_device_set_ident(device, ident);
421
422         connman_device_set_string(device, "Path", modem->path);
423
424         connman_device_set_data(device, modem);
425
426         if (connman_device_register(device) < 0) {
427                 connman_error("Failed to register cellular device");
428                 connman_device_unref(device);
429                 goto out;
430         }
431
432         modem->device = device;
433
434 out:
435         g_free(ident);
436 }
437
438 static void destroy_device(struct modem_data *modem)
439 {
440         DBG("%s", modem->path);
441
442         connman_device_set_powered(modem->device, FALSE);
443
444         connman_device_unregister(modem->device);
445         connman_device_unref(modem->device);
446
447         modem->device = NULL;
448 }
449
450 static gboolean context_changed(DBusConnection *connection,
451                                 DBusMessage *message,
452                                 void *user_data)
453 {
454         return TRUE;
455 }
456
457 static gboolean cm_context_added(DBusConnection *connection,
458                                         DBusMessage *message,
459                                         void *user_data)
460 {
461         return TRUE;
462 }
463
464 static gboolean cm_context_removed(DBusConnection *connection,
465                                         DBusMessage *message,
466                                         void *user_data)
467 {
468         return TRUE;
469 }
470
471 static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
472                                 void *user_data)
473 {
474         return TRUE;
475 }
476
477 static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
478                                 void *user_data)
479 {
480         const char *path = dbus_message_get_path(message);
481         struct modem_data *modem;
482         DBusMessageIter iter, value;
483         const char *key;
484
485         modem = g_hash_table_lookup(modem_hash, path);
486         if (modem == NULL)
487                 return TRUE;
488
489         if (dbus_message_iter_init(message, &iter) == FALSE)
490                 return TRUE;
491
492         dbus_message_iter_get_basic(&iter, &key);
493
494         dbus_message_iter_next(&iter);
495         dbus_message_iter_recurse(&iter, &value);
496
497         if (g_str_equal(key, "Attached") == TRUE) {
498                 dbus_message_iter_get_basic(&value, &modem->attached);
499
500                 DBG("%s Attached %d", modem->path, modem->attached);
501         }
502
503         return TRUE;
504 }
505
506 static void cm_properties_reply(struct modem_data *modem, DBusMessageIter *dict)
507 {
508         DBG("%s", modem->path);
509
510         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
511                 DBusMessageIter entry, value;
512                 const char *key;
513
514                 dbus_message_iter_recurse(dict, &entry);
515                 dbus_message_iter_get_basic(&entry, &key);
516
517                 dbus_message_iter_next(&entry);
518                 dbus_message_iter_recurse(&entry, &value);
519
520                 if (g_str_equal(key, "Attached") == TRUE) {
521                         dbus_message_iter_get_basic(&value, &modem->attached);
522
523                         DBG("%s Attached %d", modem->path,
524                                 modem->attached);
525
526                         return;
527                 }
528
529                 dbus_message_iter_next(dict);
530         }
531 }
532
533 static int cm_get_properties(struct modem_data *modem)
534 {
535         return get_properties(modem->path, OFONO_CM_INTERFACE,
536                                 cm_properties_reply, modem);
537 }
538
539 static void update_sim_imsi(struct modem_data *modem,
540                                 const char *imsi)
541 {
542         DBG("%s imsi %s", modem->path, imsi);
543
544         if (g_strcmp0(modem->imsi, imsi) == 0)
545                 return;
546
547         g_free(modem->imsi);
548         modem->imsi = g_strdup(imsi);
549 }
550
551 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
552                                 void *user_data)
553 {
554         const char *path = dbus_message_get_path(message);
555         struct modem_data *modem;
556         DBusMessageIter iter, value;
557         const char *key;
558
559         modem = g_hash_table_lookup(modem_hash, path);
560         if (modem == NULL)
561                 return TRUE;
562
563         if (dbus_message_iter_init(message, &iter) == FALSE)
564                 return TRUE;
565
566         dbus_message_iter_get_basic(&iter, &key);
567
568         dbus_message_iter_next(&iter);
569         dbus_message_iter_recurse(&iter, &value);
570
571         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
572                 char *imsi;
573
574                 dbus_message_iter_get_basic(&value, &imsi);
575
576                 update_sim_imsi(modem, imsi);
577
578                 if (modem->online == FALSE) {
579                         modem_set_online(modem);
580                 } else if (has_interface(modem->interfaces,
581                                                 OFONO_API_CM) == TRUE) {
582                         if (ready_to_create_device(modem) == TRUE)
583                                 create_device(modem);
584                 }
585         }
586
587         return TRUE;
588 }
589
590 static void sim_properties_reply(struct modem_data *modem,
591                                         DBusMessageIter *dict)
592 {
593         DBG("%s", modem->path);
594
595         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
596                 DBusMessageIter entry, value;
597                 const char *key;
598
599                 dbus_message_iter_recurse(dict, &entry);
600                 dbus_message_iter_get_basic(&entry, &key);
601
602                 dbus_message_iter_next(&entry);
603                 dbus_message_iter_recurse(&entry, &value);
604
605                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
606                         char *imsi;
607
608                         dbus_message_iter_get_basic(&value, &imsi);
609
610                         update_sim_imsi(modem, imsi);
611
612                         if (modem->online == FALSE) {
613                                 modem_set_online(modem);
614                                 break;
615                         }
616
617                         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
618                                 if (ready_to_create_device(modem) == TRUE)
619                                         create_device(modem);
620                                 if (modem->device != NULL)
621                                         cm_get_properties(modem);
622                         }
623                         return;
624                 }
625
626                 dbus_message_iter_next(dict);
627         }
628 }
629
630 static int sim_get_properties(struct modem_data *modem)
631 {
632         return get_properties(modem->path, OFONO_SIM_INTERFACE,
633                         sim_properties_reply, modem);
634 }
635
636 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
637                                 void *user_data)
638 {
639         const char *path = dbus_message_get_path(message);
640         struct modem_data *modem;
641         DBusMessageIter iter, value;
642         const char *key;
643
644         modem = g_hash_table_lookup(modem_hash, path);
645         if (modem == NULL)
646                 return TRUE;
647
648         if (dbus_message_iter_init(message, &iter) == FALSE)
649                 return TRUE;
650
651         dbus_message_iter_get_basic(&iter, &key);
652
653         dbus_message_iter_next(&iter);
654         dbus_message_iter_recurse(&iter, &value);
655
656         if (g_str_equal(key, "Powered") == TRUE) {
657                 dbus_message_iter_get_basic(&value, &modem->powered);
658
659                 DBG("%s Powered %d", modem->path, modem->powered);
660
661                 if (modem->powered == FALSE)
662                         modem_set_powered(modem);
663         } else if (g_str_equal(key, "Online") == TRUE) {
664                 dbus_message_iter_get_basic(&value, &modem->online);
665
666                 DBG("%s Online %d", modem->path, modem->online);
667
668                 if (modem->online == FALSE)
669                         return TRUE;
670
671                 if (has_interface(modem->interfaces, OFONO_API_CM) == FALSE)
672                         return TRUE;
673                 if (ready_to_create_device(modem) == TRUE)
674                         create_device(modem);
675                 if (modem->device != NULL)
676                         cm_get_properties(modem);
677         } else if (g_str_equal(key, "Interfaces") == TRUE) {
678                 modem->interfaces = extract_interfaces(&value);
679
680                 DBG("%s Interfaces 0x%02x", modem->path,
681                         modem->interfaces);
682
683                 if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
684                         if (modem->imsi == NULL &&
685                                         modem->set_powered == FALSE) {
686                                 /*
687                                  * Only use do GetProperties() when
688                                  * device has not been powered up.
689                                  */
690                                 sim_get_properties(modem);
691                                 return TRUE;
692                         }
693                 }
694
695                 if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
696                         if (ready_to_create_device(modem) == TRUE)
697                                 create_device(modem);
698                         if (modem->device != NULL)
699                                 cm_get_properties(modem);
700                 } else {
701                         if (modem->device != NULL)
702                                 destroy_device(modem);
703                 }
704         } else if (g_str_equal(key, "Serial") == TRUE) {
705                 char *serial;
706
707                 dbus_message_iter_get_basic(&value, &serial);
708
709                 g_free(modem->serial);
710                 modem->serial = g_strdup(serial);
711
712                 DBG("%s Serial %s", modem->path, modem->serial);
713
714                 if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
715                         if (ready_to_create_device(modem) == TRUE)
716                                 create_device(modem);
717                         if (modem->device != NULL)
718                                 cm_get_properties(modem);
719                 }
720         }
721
722         return TRUE;
723 }
724
725 static void add_modem(const char *path, DBusMessageIter *prop)
726 {
727         struct modem_data *modem;
728
729         DBG("%s", path);
730
731         modem = g_hash_table_lookup(modem_hash, path);
732         if (modem != NULL) {
733                 /*
734                  * When oFono powers up we ask for the modems and oFono is
735                  * reporting with modem_added signal the modems. Only
736                  * handle them once.
737                  */
738                 return;
739         }
740
741         modem = g_try_new0(struct modem_data, 1);
742         if (modem == NULL)
743                 return;
744
745         modem->path = g_strdup(path);
746
747         g_hash_table_insert(modem_hash, g_strdup(path), modem);
748
749         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
750                 DBusMessageIter entry, value;
751                 const char *key;
752
753                 dbus_message_iter_recurse(prop, &entry);
754                 dbus_message_iter_get_basic(&entry, &key);
755
756                 dbus_message_iter_next(&entry);
757                 dbus_message_iter_recurse(&entry, &value);
758
759                 if (g_str_equal(key, "Powered") == TRUE) {
760                         dbus_message_iter_get_basic(&value, &modem->powered);
761
762                         DBG("%s Powered %d", modem->path, modem->powered);
763                 } else if (g_str_equal(key, "Online") == TRUE) {
764                         dbus_message_iter_get_basic(&value, &modem->online);
765
766                         DBG("%s Online %d", modem->path, modem->online);
767                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
768                         modem->interfaces = extract_interfaces(&value);
769
770                         DBG("%s Interfaces 0x%02x", modem->path,
771                                 modem->interfaces);
772                 } else if (g_str_equal(key, "Serial") == TRUE) {
773                         char *serial;
774
775                         dbus_message_iter_get_basic(&value, &serial);
776                         modem->serial = g_strdup(serial);
777
778                         DBG("%s Serial %s", modem->path, modem->serial);
779                 }
780
781                 dbus_message_iter_next(prop);
782         }
783
784         if (modem->powered == FALSE) {
785                 modem_set_powered(modem);
786         } else if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
787                 sim_get_properties(modem);
788         } else if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
789                 if (ready_to_create_device(modem) == TRUE)
790                         create_device(modem);
791                 if (modem->device != NULL)
792                         cm_get_properties(modem);
793         }
794 }
795
796 static void remove_modem(gpointer data)
797 {
798         struct modem_data *modem = data;
799
800         DBG("%s", modem->path);
801
802         if (modem->call_set_property != NULL)
803                 dbus_pending_call_cancel(modem->call_set_property);
804
805         if (modem->call_get_properties != NULL)
806                 dbus_pending_call_cancel(modem->call_get_properties);
807
808         if (modem->device != NULL)
809                 destroy_device(modem);
810
811         g_free(modem->serial);
812         g_free(modem->imsi);
813         g_free(modem->path);
814
815         g_free(modem);
816 }
817
818 static gboolean modem_added(DBusConnection *connection,
819                                 DBusMessage *message, void *user_data)
820 {
821         DBusMessageIter iter, properties;
822         const char *path;
823
824         DBG("");
825
826         if (dbus_message_iter_init(message, &iter) == FALSE)
827                 return TRUE;
828
829         dbus_message_iter_get_basic(&iter, &path);
830
831         dbus_message_iter_next(&iter);
832         dbus_message_iter_recurse(&iter, &properties);
833
834         add_modem(path, &properties);
835
836         return TRUE;
837 }
838
839 static gboolean modem_removed(DBusConnection *connection,
840                                 DBusMessage *message, void *user_data)
841 {
842         DBusMessageIter iter;
843         const char *path;
844
845         DBG("");
846
847         if (dbus_message_iter_init(message, &iter) == FALSE)
848                 return TRUE;
849
850         dbus_message_iter_get_basic(&iter, &path);
851
852         g_hash_table_remove(modem_hash, path);
853
854         return TRUE;
855 }
856
857 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
858 {
859         DBusMessage *reply;
860         DBusError error;
861         DBusMessageIter array, dict;
862
863         DBG("");
864
865         reply = dbus_pending_call_steal_reply(call);
866
867         dbus_error_init(&error);
868
869         if (dbus_set_error_from_message(&error, reply) == TRUE) {
870                 connman_error("%s", error.message);
871                 dbus_error_free(&error);
872                 goto done;
873         }
874
875         if (dbus_message_iter_init(reply, &array) == FALSE)
876                 goto done;
877
878         dbus_message_iter_recurse(&array, &dict);
879
880         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
881                 DBusMessageIter value, properties;
882                 const char *path;
883
884                 dbus_message_iter_recurse(&dict, &value);
885                 dbus_message_iter_get_basic(&value, &path);
886
887                 dbus_message_iter_next(&value);
888                 dbus_message_iter_recurse(&value, &properties);
889
890                 add_modem(path, &properties);
891
892                 dbus_message_iter_next(&dict);
893         }
894
895 done:
896         dbus_message_unref(reply);
897
898         dbus_pending_call_unref(call);
899 }
900
901 static int manager_get_modems(void)
902 {
903         DBusMessage *message;
904         DBusPendingCall *call;
905
906         DBG("");
907
908         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
909                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
910         if (message == NULL)
911                 return -ENOMEM;
912
913         if (dbus_connection_send_with_reply(connection, message,
914                                                &call, TIMEOUT) == FALSE) {
915                 connman_error("Failed to call GetModems()");
916                 dbus_message_unref(message);
917                 return -EINVAL;
918         }
919
920         if (call == NULL) {
921                 connman_error("D-Bus connection not available");
922                 dbus_message_unref(message);
923                 return -EINVAL;
924         }
925
926         dbus_pending_call_set_notify(call, manager_get_modems_reply,
927                                         NULL, NULL);
928
929         dbus_message_unref(message);
930
931         return -EINPROGRESS;
932 }
933
934 static void ofono_connect(DBusConnection *conn, void *user_data)
935 {
936         DBG("");
937
938         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
939                                                 g_free, remove_modem);
940         if (modem_hash == NULL)
941                 return;
942
943         manager_get_modems();
944 }
945
946 static void ofono_disconnect(DBusConnection *conn, void *user_data)
947 {
948         DBG("");
949
950         if (modem_hash == NULL)
951                 return;
952
953         g_hash_table_destroy(modem_hash);
954         modem_hash = NULL;
955 }
956
957 static int network_probe(struct connman_network *network)
958 {
959         DBG("network %p", network);
960
961         return 0;
962 }
963
964 static void network_remove(struct connman_network *network)
965 {
966         DBG("network %p", network);
967 }
968
969 static int network_connect(struct connman_network *network)
970 {
971         DBG("network %p", network);
972
973         return 0;
974 }
975
976 static int network_disconnect(struct connman_network *network)
977 {
978         DBG("network %p", network);
979
980         return 0;
981 }
982
983 static struct connman_network_driver network_driver = {
984         .name           = "network",
985         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
986         .probe          = network_probe,
987         .remove         = network_remove,
988         .connect        = network_connect,
989         .disconnect     = network_disconnect,
990 };
991
992 static int modem_probe(struct connman_device *device)
993 {
994         struct modem_data *modem = connman_device_get_data(device);
995
996         DBG("%s device %p", modem->path, device);
997
998         return 0;
999 }
1000
1001 static void modem_remove(struct connman_device *device)
1002 {
1003         struct modem_data *modem = connman_device_get_data(device);
1004
1005         DBG("%s device %p", modem->path, device);
1006 }
1007
1008 static int modem_enable(struct connman_device *device)
1009 {
1010         struct modem_data *modem = connman_device_get_data(device);
1011
1012         DBG("%s device %p", modem->path, device);
1013
1014         return 0;
1015 }
1016
1017 static int modem_disable(struct connman_device *device)
1018 {
1019         struct modem_data *modem = connman_device_get_data(device);
1020
1021         DBG("%s device %p", modem->path, device);
1022
1023         return 0;
1024 }
1025
1026 static struct connman_device_driver modem_driver = {
1027         .name           = "modem",
1028         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
1029         .probe          = modem_probe,
1030         .remove         = modem_remove,
1031         .enable         = modem_enable,
1032         .disable        = modem_disable,
1033 };
1034
1035 static guint watch;
1036 static guint modem_added_watch;
1037 static guint modem_removed_watch;
1038 static guint modem_watch;
1039 static guint cm_watch;
1040 static guint sim_watch;
1041 static guint context_added_watch;
1042 static guint context_removed_watch;
1043 static guint netreg_watch;
1044 static guint context_watch;
1045
1046 static int ofono_init(void)
1047 {
1048         int err;
1049
1050         DBG("");
1051
1052         connection = connman_dbus_get_connection();
1053         if (connection == NULL)
1054                 return -EIO;
1055
1056         watch = g_dbus_add_service_watch(connection,
1057                                         OFONO_SERVICE, ofono_connect,
1058                                         ofono_disconnect, NULL, NULL);
1059
1060         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1061                                                 OFONO_MANAGER_INTERFACE,
1062                                                 MODEM_ADDED,
1063                                                 modem_added,
1064                                                 NULL, NULL);
1065
1066         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1067                                                 OFONO_MANAGER_INTERFACE,
1068                                                 MODEM_REMOVED,
1069                                                 modem_removed,
1070                                                 NULL, NULL);
1071
1072         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1073                                                 OFONO_MODEM_INTERFACE,
1074                                                 PROPERTY_CHANGED,
1075                                                 modem_changed,
1076                                                 NULL, NULL);
1077
1078         cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1079                                                 OFONO_CM_INTERFACE,
1080                                                 PROPERTY_CHANGED,
1081                                                 cm_changed,
1082                                                 NULL, NULL);
1083
1084         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1085                                                 OFONO_SIM_INTERFACE,
1086                                                 PROPERTY_CHANGED,
1087                                                 sim_changed,
1088                                                 NULL, NULL);
1089
1090         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1091                                                 OFONO_CM_INTERFACE,
1092                                                 CONTEXT_ADDED,
1093                                                 cm_context_added,
1094                                                 NULL, NULL);
1095
1096         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1097                                                 OFONO_CM_INTERFACE,
1098                                                 CONTEXT_REMOVED,
1099                                                 cm_context_removed,
1100                                                 NULL, NULL);
1101
1102         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1103                                                 OFONO_CONTEXT_INTERFACE,
1104                                                 PROPERTY_CHANGED,
1105                                                 context_changed,
1106                                                 NULL, NULL);
1107
1108         netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1109                                                 OFONO_NETREG_INTERFACE,
1110                                                 PROPERTY_CHANGED,
1111                                                 netreg_changed,
1112                                                 NULL, NULL);
1113
1114
1115         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
1116                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
1117                         context_added_watch == 0 ||
1118                         context_removed_watch == 0 ||
1119                         context_watch == 0 || netreg_watch == 0) {
1120                 err = -EIO;
1121                 goto remove;
1122         }
1123
1124         err = connman_network_driver_register(&network_driver);
1125         if (err < 0)
1126                 goto remove;
1127
1128         err = connman_device_driver_register(&modem_driver);
1129         if (err < 0) {
1130                 connman_network_driver_unregister(&network_driver);
1131                 goto remove;
1132         }
1133
1134         return 0;
1135
1136 remove:
1137         g_dbus_remove_watch(connection, netreg_watch);
1138         g_dbus_remove_watch(connection, context_watch);
1139         g_dbus_remove_watch(connection, context_removed_watch);
1140         g_dbus_remove_watch(connection, context_added_watch);
1141         g_dbus_remove_watch(connection, sim_watch);
1142         g_dbus_remove_watch(connection, cm_watch);
1143         g_dbus_remove_watch(connection, modem_watch);
1144         g_dbus_remove_watch(connection, modem_removed_watch);
1145         g_dbus_remove_watch(connection, modem_added_watch);
1146         g_dbus_remove_watch(connection, watch);
1147         dbus_connection_unref(connection);
1148
1149         return err;
1150 }
1151
1152 static void ofono_exit(void)
1153 {
1154         DBG("");
1155
1156         if (modem_hash != NULL) {
1157                 g_hash_table_destroy(modem_hash);
1158                 modem_hash = NULL;
1159         }
1160
1161         connman_device_driver_unregister(&modem_driver);
1162         connman_network_driver_unregister(&network_driver);
1163
1164         g_dbus_remove_watch(connection, netreg_watch);
1165         g_dbus_remove_watch(connection, context_watch);
1166         g_dbus_remove_watch(connection, context_removed_watch);
1167         g_dbus_remove_watch(connection, context_added_watch);
1168         g_dbus_remove_watch(connection, sim_watch);
1169         g_dbus_remove_watch(connection, cm_watch);
1170         g_dbus_remove_watch(connection, modem_watch);
1171         g_dbus_remove_watch(connection, modem_added_watch);
1172         g_dbus_remove_watch(connection, modem_removed_watch);
1173         g_dbus_remove_watch(connection, watch);
1174
1175         dbus_connection_unref(connection);
1176 }
1177
1178 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
1179                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)