fabc75f7636fbdb2ca829ffb06a59a42fc560302
[platform/upstream/connman.git] / plugins / bluetooth.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <netinet/ether.h>
31
32 #include <gdbus.h>
33
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/plugin.h>
36 #include <connman/device.h>
37 #include <connman/inet.h>
38 #include <connman/dbus.h>
39 #include <connman/log.h>
40
41 #define BLUEZ_SERVICE                   "org.bluez"
42 #define BLUEZ_MANAGER_INTERFACE         BLUEZ_SERVICE ".Manager"
43 #define BLUEZ_ADAPTER_INTERFACE         BLUEZ_SERVICE ".Adapter"
44 #define BLUEZ_DEVICE_INTERFACE          BLUEZ_SERVICE ".Device"
45 #define BLUEZ_NETWORK_INTERFACE         BLUEZ_SERVICE ".Network"
46
47 #define LIST_ADAPTERS                   "ListAdapters"
48 #define ADAPTER_ADDED                   "AdapterAdded"
49 #define ADAPTER_REMOVED                 "AdapterRemoved"
50
51 #define PROPERTY_CHANGED                "PropertyChanged"
52 #define GET_PROPERTIES                  "GetProperties"
53 #define SET_PROPERTY                    "SetProperty"
54
55 #define CONNECT                         "Connect"
56 #define DISCONNECT                      "Disconnect"
57
58 #define UUID_NAP        "00001116-0000-1000-8000-00805f9b34fb"
59
60 #define TIMEOUT 5000
61
62 static DBusConnection *connection;
63
64 static GHashTable *bluetooth_devices = NULL;
65
66 static int pan_probe(struct connman_network *network)
67 {
68         DBG("network %p", network);
69
70         return 0;
71 }
72
73 static void pan_remove(struct connman_network *network)
74 {
75         DBG("network %p", network);
76 }
77
78 static void connect_reply(DBusPendingCall *call, void *user_data)
79 {
80         struct connman_network *network = user_data;
81         DBusMessage *reply;
82         DBusError error;
83         const char *interface = NULL;
84         int index;
85
86         DBG("network %p", network);
87
88         reply = dbus_pending_call_steal_reply(call);
89
90         dbus_error_init(&error);
91
92         if (dbus_set_error_from_message(&error, reply) == TRUE) {
93                 connman_error("%s", error.message);
94                 dbus_error_free(&error);
95                 goto done;
96         }
97
98         if (dbus_message_get_args(reply, &error,
99                                         DBUS_TYPE_STRING, &interface,
100                                                 DBUS_TYPE_INVALID) == FALSE) {
101                 if (dbus_error_is_set(&error) == TRUE) {
102                         connman_error("%s", error.message);
103                         dbus_error_free(&error);
104                 } else
105                         connman_error("Wrong arguments for connect");
106                 goto done;
107         }
108
109         if (interface == NULL)
110                 goto done;
111
112         DBG("interface %s", interface);
113
114         index = connman_inet_ifindex(interface);
115
116         connman_network_set_index(network, index);
117
118         connman_network_set_connected(network, TRUE);
119
120 done:
121         dbus_message_unref(reply);
122
123         dbus_pending_call_unref(call);
124 }
125
126 static int pan_connect(struct connman_network *network)
127 {
128         const char *path = connman_network_get_string(network, "Path");
129         const char *uuid = "nap";
130         DBusMessage *message;
131         DBusPendingCall *call;
132
133         DBG("network %p", network);
134
135         if (path == NULL)
136                 return -EINVAL;
137
138         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
139                                         BLUEZ_NETWORK_INTERFACE, CONNECT);
140         if (message == NULL)
141                 return -ENOMEM;
142
143         dbus_message_set_auto_start(message, FALSE);
144
145         dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
146                                                         DBUS_TYPE_INVALID);
147
148         if (dbus_connection_send_with_reply(connection, message,
149                                         &call, TIMEOUT * 10) == FALSE) {
150                 connman_error("Failed to connect service");
151                 dbus_message_unref(message);
152                 return -EINVAL;
153         }
154
155         if (call == NULL) {
156                 connman_error("D-Bus connection not available");
157                 dbus_message_unref(message);
158                 return -EINVAL;
159         }
160
161         dbus_pending_call_set_notify(call, connect_reply, network, NULL);
162
163         dbus_message_unref(message);
164
165         return -EINPROGRESS;
166 }
167
168 static void disconnect_reply(DBusPendingCall *call, void *user_data)
169 {
170         struct connman_network *network = user_data;
171         DBusMessage *reply;
172         DBusError error;
173
174         DBG("network %p", network);
175
176         reply = dbus_pending_call_steal_reply(call);
177
178         dbus_error_init(&error);
179
180         if (dbus_set_error_from_message(&error, reply) == TRUE) {
181                 connman_error("%s", error.message);
182                 dbus_error_free(&error);
183                 goto done;
184         }
185
186         if (dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) == FALSE) {
187                 if (dbus_error_is_set(&error) == TRUE) {
188                         connman_error("%s", error.message);
189                         dbus_error_free(&error);
190                 } else
191                         connman_error("Wrong arguments for disconnect");
192                 goto done;
193         }
194
195         connman_network_set_connected(network, FALSE);
196
197 done:
198         dbus_message_unref(reply);
199
200         dbus_pending_call_unref(call);
201
202         connman_network_unref(network);
203 }
204
205 static int pan_disconnect(struct connman_network *network)
206 {
207         const char *path = connman_network_get_string(network, "Path");
208         DBusMessage *message;
209         DBusPendingCall *call;
210
211         DBG("network %p", network);
212
213         if (path == NULL)
214                 return -EINVAL;
215
216         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
217                                         BLUEZ_NETWORK_INTERFACE, DISCONNECT);
218         if (message == NULL)
219                 return -ENOMEM;
220
221         dbus_message_set_auto_start(message, FALSE);
222
223         dbus_message_append_args(message, DBUS_TYPE_INVALID);
224
225         if (dbus_connection_send_with_reply(connection, message,
226                                                 &call, TIMEOUT) == FALSE) {
227                 connman_error("Failed to disconnect service");
228                 dbus_message_unref(message);
229                 return -EINVAL;
230         }
231
232         if (call == NULL) {
233                 connman_error("D-Bus connection not available");
234                 dbus_message_unref(message);
235                 return -EINVAL;
236         }
237
238         connman_network_ref(network);
239
240         dbus_pending_call_set_notify(call, disconnect_reply, network, NULL);
241
242         dbus_message_unref(message);
243
244         return 0;
245 }
246
247 static struct connman_network_driver pan_driver = {
248         .name           = "bluetooth-pan",
249         .type           = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
250         .probe          = pan_probe,
251         .remove         = pan_remove,
252         .connect        = pan_connect,
253         .disconnect     = pan_disconnect,
254 };
255
256 static void extract_properties(DBusMessage *reply, const char **parent,
257                                                 const char **address,
258                                                 const char **name,
259                                                 const char **alias,
260                                                 dbus_bool_t *powered,
261                                                 dbus_bool_t *scanning,
262                                                 DBusMessageIter *uuids,
263                                                 DBusMessageIter *networks)
264 {
265         DBusMessageIter array, dict;
266
267         if (dbus_message_iter_init(reply, &array) == FALSE)
268                 return;
269
270         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
271                 return;
272
273         dbus_message_iter_recurse(&array, &dict);
274
275         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
276                 DBusMessageIter entry, value;
277                 const char *key;
278
279                 dbus_message_iter_recurse(&dict, &entry);
280                 dbus_message_iter_get_basic(&entry, &key);
281
282                 dbus_message_iter_next(&entry);
283                 dbus_message_iter_recurse(&entry, &value);
284
285                 if (g_str_equal(key, "Adapter") == TRUE) {
286                         if (parent != NULL)
287                                 dbus_message_iter_get_basic(&value, parent);
288                 } else if (g_str_equal(key, "Address") == TRUE) {
289                         if (address != NULL)
290                                 dbus_message_iter_get_basic(&value, address);
291                 } else if (g_str_equal(key, "Name") == TRUE) {
292                         if (name != NULL)
293                                 dbus_message_iter_get_basic(&value, name);
294                 } else if (g_str_equal(key, "Alias") == TRUE) {
295                         if (alias != NULL)
296                                 dbus_message_iter_get_basic(&value, alias);
297                 } else if (g_str_equal(key, "Powered") == TRUE) {
298                         if (powered != NULL)
299                                 dbus_message_iter_get_basic(&value, powered);
300                 } else if (g_str_equal(key, "Discovering") == TRUE) {
301                         if (scanning != NULL)
302                                 dbus_message_iter_get_basic(&value, scanning);
303                 } else if (g_str_equal(key, "Devices") == TRUE) {
304                         if (networks != NULL)
305                                 memcpy(networks, &value, sizeof(value));
306                 } else if (g_str_equal(key, "UUIDs") == TRUE) {
307                         if (uuids != NULL)
308                                 memcpy(uuids, &value, sizeof(value));
309                 }
310
311                 dbus_message_iter_next(&dict);
312         }
313 }
314
315 static dbus_bool_t has_pan(DBusMessageIter *array)
316 {
317         DBusMessageIter value;
318
319         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
320                 return FALSE;
321
322         dbus_message_iter_recurse(array, &value);
323
324         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
325                 const char *uuid;
326
327                 dbus_message_iter_get_basic(&value, &uuid);
328
329                 if (g_strcmp0(uuid, UUID_NAP) == 0)
330                         return TRUE;
331
332                 dbus_message_iter_next(&value);
333         }
334
335         return FALSE;
336 }
337
338 static void network_properties_reply(DBusPendingCall *call, void *user_data)
339 {
340         char *path = user_data;
341         struct connman_device *device;
342         struct connman_network *network;
343         DBusMessage *reply;
344         DBusMessageIter uuids;
345         const char *parent = NULL, *address = NULL, *name = NULL;
346         struct ether_addr addr;
347         char ident[13];
348
349         reply = dbus_pending_call_steal_reply(call);
350
351         extract_properties(reply, &parent, &address, NULL, &name,
352                                                 NULL, NULL, &uuids, NULL);
353
354         if (parent == NULL)
355                 goto done;
356
357         device = g_hash_table_lookup(bluetooth_devices, parent);
358         if (device == NULL)
359                 goto done;
360
361         if (address == NULL)
362                 goto done;
363
364         ether_aton_r(address, &addr);
365
366         snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
367                                                 addr.ether_addr_octet[0],
368                                                 addr.ether_addr_octet[1],
369                                                 addr.ether_addr_octet[2],
370                                                 addr.ether_addr_octet[3],
371                                                 addr.ether_addr_octet[4],
372                                                 addr.ether_addr_octet[5]);
373
374         if (has_pan(&uuids) == FALSE)
375                 goto done;
376
377         network = connman_device_get_network(device, ident);
378         if (network != NULL)
379                 goto done;
380
381         network = connman_network_create(ident,
382                                         CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
383         if (network == NULL)
384                 goto done;
385
386         connman_network_set_string(network, "Path", path);
387
388         connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
389
390         connman_network_set_name(network, name);
391
392         connman_device_add_network(device, network);
393
394         connman_network_set_group(network, ident);
395
396 done:
397         dbus_message_unref(reply);
398
399         dbus_pending_call_unref(call);
400 }
401
402 static void add_network(struct connman_device *device, const char *path)
403 {
404         DBusMessage *message;
405         DBusPendingCall *call;
406
407         DBG("path %s", path);
408
409         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
410                                 BLUEZ_DEVICE_INTERFACE, GET_PROPERTIES);
411         if (message == NULL)
412                 return;
413
414         dbus_message_set_auto_start(message, FALSE);
415
416         if (dbus_connection_send_with_reply(connection, message,
417                                                 &call, TIMEOUT) == FALSE) {
418                 connman_error("Failed to get network properties for %s", path);
419                 goto done;
420         }
421
422         if (call == NULL) {
423                 connman_error("D-Bus connection not available");
424                 goto done;
425         }
426
427         dbus_pending_call_set_notify(call, network_properties_reply,
428                                                 g_strdup(path), g_free);
429
430 done:
431         dbus_message_unref(message);
432 }
433
434 static void check_networks(struct connman_device *device,
435                                                 DBusMessageIter *array)
436 {
437         DBusMessageIter value;
438
439         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
440                 return;
441
442         dbus_message_iter_recurse(array, &value);
443
444         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
445                 const char *path;
446
447                 dbus_message_iter_get_basic(&value, &path);
448
449                 add_network(device, path);
450
451                 dbus_message_iter_next(&value);
452         }
453 }
454
455 static gboolean adapter_changed(DBusConnection *connection,
456                                 DBusMessage *message, void *user_data)
457 {
458         const char *path = dbus_message_get_path(message);
459         struct connman_device *device;
460         DBusMessageIter iter, value;
461         const char *key;
462
463         DBG("path %s", path);
464
465         device = g_hash_table_lookup(bluetooth_devices, path);
466         if (device == NULL)
467                 return TRUE;
468
469         if (dbus_message_iter_init(message, &iter) == FALSE)
470                 return TRUE;
471
472         dbus_message_iter_get_basic(&iter, &key);
473
474         dbus_message_iter_next(&iter);
475         dbus_message_iter_recurse(&iter, &value);
476
477         if (g_str_equal(key, "Powered") == TRUE) {
478                 dbus_bool_t val;
479
480                 dbus_message_iter_get_basic(&value, &val);
481                 connman_device_set_powered(device, val);
482         } else if (g_str_equal(key, "Discovering") == TRUE) {
483                 dbus_bool_t val;
484
485                 dbus_message_iter_get_basic(&value, &val);
486                 connman_device_set_scanning(device, val);
487         } else if (g_str_equal(key, "Devices") == TRUE) {
488                 check_networks(device, &value);
489         }
490
491         return TRUE;
492 }
493
494 static void adapter_properties_reply(DBusPendingCall *call, void *user_data)
495 {
496         char *path = user_data;
497         struct connman_device *device;
498         DBusMessage *reply;
499         DBusMessageIter networks;
500         const char *address = NULL, *name = NULL;
501         dbus_bool_t powered = FALSE, scanning = FALSE;
502         struct ether_addr addr;
503         char ident[13];
504
505         DBG("path %s", path);
506
507         reply = dbus_pending_call_steal_reply(call);
508
509         if (path == NULL)
510                 goto done;
511
512         extract_properties(reply, NULL, &address, &name, NULL,
513                                         &powered, &scanning, NULL, &networks);
514
515         if (address == NULL)
516                 goto done;
517
518         device = g_hash_table_lookup(bluetooth_devices, path);
519         if (device != NULL)
520                 goto update;
521
522         ether_aton_r(address, &addr);
523
524         snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
525                                                 addr.ether_addr_octet[0],
526                                                 addr.ether_addr_octet[1],
527                                                 addr.ether_addr_octet[2],
528                                                 addr.ether_addr_octet[3],
529                                                 addr.ether_addr_octet[4],
530                                                 addr.ether_addr_octet[5]);
531
532         device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_BLUETOOTH);
533         if (device == NULL)
534                 goto done;
535
536         connman_device_set_ident(device, ident);
537
538         connman_device_set_mode(device, CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE);
539
540         connman_device_set_string(device, "Path", path);
541
542         if (connman_device_register(device) < 0) {
543                 connman_device_unref(device);
544                 goto done;
545         }
546
547         g_hash_table_insert(bluetooth_devices, g_strdup(path), device);
548
549 update:
550         connman_device_set_string(device, "Address", address);
551         connman_device_set_string(device, "Name", name);
552         connman_device_set_string(device, "Path", path);
553
554         connman_device_set_powered(device, powered);
555         connman_device_set_scanning(device, scanning);
556
557         if (powered == TRUE)
558                 check_networks(device, &networks);
559
560 done:
561         dbus_message_unref(reply);
562
563         dbus_pending_call_unref(call);
564 }
565
566 static void add_adapter(DBusConnection *connection, const char *path)
567 {
568         DBusMessage *message;
569         DBusPendingCall *call;
570
571         DBG("path %s", path);
572
573         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
574                                 BLUEZ_ADAPTER_INTERFACE, GET_PROPERTIES);
575         if (message == NULL)
576                 return;
577
578         dbus_message_set_auto_start(message, FALSE);
579
580         if (dbus_connection_send_with_reply(connection, message,
581                                                 &call, TIMEOUT) == FALSE) {
582                 connman_error("Failed to get adapter properties for %s", path);
583                 goto done;
584         }
585
586         if (call == NULL) {
587                 connman_error("D-Bus connection not available");
588                 goto done;
589         }
590
591         dbus_pending_call_set_notify(call, adapter_properties_reply,
592                                                 g_strdup(path), g_free);
593
594 done:
595         dbus_message_unref(message);
596 }
597
598 static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
599                                 void *user_data)
600 {
601         const char *path;
602
603         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
604                                 DBUS_TYPE_INVALID);
605         add_adapter(connection, path);
606         return TRUE;
607 }
608
609 static void remove_adapter(DBusConnection *connection, const char *path)
610 {
611         DBG("path %s", path);
612
613         g_hash_table_remove(bluetooth_devices, path);
614 }
615
616 static gboolean adapter_removed(DBusConnection *connection, DBusMessage *message,
617                                 void *user_data)
618 {
619         const char *path;
620
621         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
622                                 DBUS_TYPE_INVALID);
623         remove_adapter(connection, path);
624         return TRUE;
625 }
626
627 static void list_adapters_reply(DBusPendingCall *call, void *user_data)
628 {
629         DBusMessage *reply;
630         DBusError error;
631         char **adapters;
632         int i, num_adapters;
633
634         DBG("");
635
636         reply = dbus_pending_call_steal_reply(call);
637
638         dbus_error_init(&error);
639
640         if (dbus_set_error_from_message(&error, reply) == TRUE) {
641                 connman_error("%s", error.message);
642                 dbus_error_free(&error);
643                 goto done;
644         }
645
646         if (dbus_message_get_args(reply, &error,
647                                 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
648                                                 &adapters, &num_adapters,
649                                                 DBUS_TYPE_INVALID) == FALSE) {
650                 if (dbus_error_is_set(&error) == TRUE) {
651                         connman_error("%s", error.message);
652                         dbus_error_free(&error);
653                 } else
654                         connman_error("Wrong arguments for adapter list");
655                 goto done;
656         }
657
658         for (i = 0; i < num_adapters; i++)
659                 add_adapter(connection, adapters[i]);
660
661         g_strfreev(adapters);
662
663 done:
664         dbus_message_unref(reply);
665
666         dbus_pending_call_unref(call);
667 }
668
669 static void unregister_device(gpointer data)
670 {
671         struct connman_device *device = data;
672
673         DBG("");
674
675         connman_device_unregister(device);
676         connman_device_unref(device);
677 }
678
679 static void bluetooth_connect(DBusConnection *connection, void *user_data)
680 {
681         DBusMessage *message;
682         DBusPendingCall *call;
683
684         DBG("connection %p", connection);
685
686         bluetooth_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
687                                                 g_free, unregister_device);
688
689         message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
690                                 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
691         if (message == NULL)
692                 return;
693
694         dbus_message_set_auto_start(message, FALSE);
695
696         if (dbus_connection_send_with_reply(connection, message,
697                                                 &call, TIMEOUT) == FALSE) {
698                 connman_error("Failed to get Bluetooth adapters");
699                 goto done;
700         }
701
702         if (call == NULL) {
703                 connman_error("D-Bus connection not available");
704                 goto done;
705         }
706
707         dbus_pending_call_set_notify(call, list_adapters_reply, NULL, NULL);
708
709 done:
710         dbus_message_unref(message);
711 }
712
713 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
714 {
715         DBG("connection %p", connection);
716
717         if (bluetooth_devices == NULL)
718                 return;
719
720         g_hash_table_destroy(bluetooth_devices);
721         bluetooth_devices = NULL;
722 }
723
724 static int bluetooth_probe(struct connman_device *device)
725 {
726         DBG("device %p", device);
727
728         return 0;
729 }
730
731 static void bluetooth_remove(struct connman_device *device)
732 {
733         DBG("device %p", device);
734 }
735
736 static void powered_reply(DBusPendingCall *call, void *user_data)
737 {
738         DBusError error;
739         DBusMessage *reply;
740
741         DBG("");
742
743         reply = dbus_pending_call_steal_reply(call);
744
745         dbus_error_init(&error);
746
747         if (dbus_set_error_from_message(&error, reply) == TRUE) {
748                 connman_error("%s", error.message);
749                 dbus_error_free(&error);
750                 dbus_message_unref(reply);
751                 dbus_pending_call_unref(call);
752                 return;
753         }
754
755         dbus_message_unref(reply);
756         dbus_pending_call_unref(call);
757
758         add_adapter(connection, user_data);
759 }
760
761 static int change_powered(DBusConnection *connection, const char *path,
762                                                         dbus_bool_t powered)
763 {
764         DBusMessage *message;
765         DBusMessageIter iter;
766         DBusPendingCall *call;
767
768         DBG("");
769
770         if (path == NULL)
771                 return -EINVAL;
772
773         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
774                                         BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
775         if (message == NULL)
776                 return -ENOMEM;
777
778         dbus_message_set_auto_start(message, FALSE);
779
780         dbus_message_iter_init_append(message, &iter);
781         connman_dbus_property_append_basic(&iter, "Powered",
782                                                 DBUS_TYPE_BOOLEAN, &powered);
783
784         if (dbus_connection_send_with_reply(connection, message,
785                                                 &call, TIMEOUT) == FALSE) {
786                 connman_error("Failed to change Powered property");
787                 dbus_message_unref(message);
788                 return -EINVAL;
789         }
790
791         if (call == NULL) {
792                 connman_error("D-Bus connection not available");
793                 dbus_message_unref(message);
794                 return -EINVAL;
795         }
796
797         dbus_pending_call_set_notify(call, powered_reply,
798                                         g_strdup(path), g_free);
799
800         dbus_message_unref(message);
801
802         return -EINPROGRESS;
803 }
804
805 static int bluetooth_enable(struct connman_device *device)
806 {
807         const char *path = connman_device_get_string(device, "Path");
808
809         DBG("device %p", device);
810
811         return change_powered(connection, path, TRUE);
812 }
813
814 static int bluetooth_disable(struct connman_device *device)
815 {
816         const char *path = connman_device_get_string(device, "Path");
817
818         DBG("device %p", device);
819
820         return change_powered(connection, path, FALSE);
821 }
822
823 static struct connman_device_driver bluetooth_driver = {
824         .name           = "bluetooth",
825         .type           = CONNMAN_DEVICE_TYPE_BLUETOOTH,
826         .probe          = bluetooth_probe,
827         .remove         = bluetooth_remove,
828         .enable         = bluetooth_enable,
829         .disable        = bluetooth_disable,
830 };
831
832 static guint watch;
833 static guint added_watch;
834 static guint removed_watch;
835 static guint adapter_watch;
836
837 static int bluetooth_init(void)
838 {
839         int err;
840
841         connection = connman_dbus_get_connection();
842         if (connection == NULL)
843                 return -EIO;
844
845         watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
846                         bluetooth_connect, bluetooth_disconnect, NULL, NULL);
847
848         added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
849                                                 BLUEZ_MANAGER_INTERFACE,
850                                                 ADAPTER_ADDED, adapter_added,
851                                                 NULL, NULL);
852
853         removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
854                                                 BLUEZ_MANAGER_INTERFACE,
855                                                 ADAPTER_REMOVED, adapter_removed,
856                                                 NULL, NULL);
857
858         adapter_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
859                                                 BLUEZ_MANAGER_INTERFACE,
860                                                 PROPERTY_CHANGED, adapter_changed,
861                                                 NULL, NULL);
862
863         if (watch == 0 || added_watch == 0 || removed_watch == 0
864                         || adapter_watch == 0) {
865                 err = -EIO;
866                 goto remove;
867         }
868
869         err = connman_network_driver_register(&pan_driver);
870         if (err < 0)
871                 goto remove;
872
873         err = connman_device_driver_register(&bluetooth_driver);
874         if (err < 0) {
875                 connman_network_driver_unregister(&pan_driver);
876                 goto remove;
877         }
878
879         return 0;
880
881 remove:
882         g_dbus_remove_watch(connection, watch);
883         g_dbus_remove_watch(connection, added_watch);
884         g_dbus_remove_watch(connection, removed_watch);
885         g_dbus_remove_watch(connection, adapter_watch);
886
887         dbus_connection_unref(connection);
888
889         return err;
890 }
891
892 static void bluetooth_exit(void)
893 {
894         g_dbus_remove_watch(connection, watch);
895         g_dbus_remove_watch(connection, added_watch);
896         g_dbus_remove_watch(connection, removed_watch);
897         g_dbus_remove_watch(connection, adapter_watch);
898
899         bluetooth_disconnect(connection, NULL);
900
901         connman_device_driver_unregister(&bluetooth_driver);
902         connman_network_driver_unregister(&pan_driver);
903
904         dbus_connection_unref(connection);
905 }
906
907 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
908                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)