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