Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / plugins / policy.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2013  Intel Corporation.
6  *
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 as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <time.h>
32
33 #include <glib.h>
34
35 #include "lib/bluetooth.h"
36 #include "lib/sdp.h"
37 #include "lib/uuid.h"
38 #include "lib/mgmt.h"
39
40 #include "src/log.h"
41 #include "src/plugin.h"
42 #include "src/adapter.h"
43 #include "src/device.h"
44 #include "src/service.h"
45 #include "src/profile.h"
46 #include "src/hcid.h"
47
48 #ifdef __TIZEN_PATCH__
49 #define CONTROL_CONNECT_TIMEOUT 4
50 #define TARGET_CONNECT_TIMEOUT 1
51 #else
52 #define CONTROL_CONNECT_TIMEOUT 2
53 #endif
54 #define SOURCE_RETRY_TIMEOUT 2
55 #define SINK_RETRY_TIMEOUT SOURCE_RETRY_TIMEOUT
56 #define CT_RETRY_TIMEOUT 1
57 #define TG_RETRY_TIMEOUT CT_RETRY_TIMEOUT
58 #ifdef __TIZEN_PATCH__
59 #define SOURCE_RETRIES 0
60 #else
61 #define SOURCE_RETRIES 1
62 #endif
63 #define SINK_RETRIES SOURCE_RETRIES
64 #define CT_RETRIES 1
65 #define TG_RETRIES CT_RETRIES
66
67 struct reconnect_data {
68         struct btd_device *dev;
69         bool reconnect;
70         GSList *services;
71         guint timer;
72         bool active;
73         unsigned int attempt;
74 };
75
76 static const char *default_reconnect[] = {
77                         HSP_AG_UUID, HFP_AG_UUID, A2DP_SOURCE_UUID, NULL };
78 static char **reconnect_uuids = NULL;
79
80 static const size_t default_attempts = 7;
81 static size_t reconnect_attempts = 0;
82
83 static const int default_intervals[] = { 1, 2, 4, 8, 16, 32, 64 };
84 static int *reconnect_intervals = NULL;
85 static size_t reconnect_intervals_len = 0;
86
87 static GSList *reconnects = NULL;
88
89 static unsigned int service_id = 0;
90 static GSList *devices = NULL;
91
92 static bool auto_enable = false;
93
94 struct policy_data {
95         struct btd_device *dev;
96
97         guint source_timer;
98         uint8_t source_retries;
99         guint sink_timer;
100         uint8_t sink_retries;
101         guint ct_timer;
102         uint8_t ct_retries;
103         guint tg_timer;
104         uint8_t tg_retries;
105 };
106
107 static void policy_connect(struct policy_data *data,
108                                                 struct btd_service *service)
109 {
110         struct btd_profile *profile = btd_service_get_profile(service);
111
112         DBG("%s profile %s", device_get_path(data->dev), profile->name);
113
114         btd_service_connect(service);
115 }
116
117 static void policy_disconnect(struct policy_data *data,
118                                                 struct btd_service *service)
119 {
120         struct btd_profile *profile = btd_service_get_profile(service);
121
122         DBG("%s profile %s", device_get_path(data->dev), profile->name);
123
124         btd_service_disconnect(service);
125 }
126
127 static gboolean policy_connect_ct(gpointer user_data)
128 {
129         struct policy_data *data = user_data;
130         struct btd_service *service;
131
132         data->ct_timer = 0;
133         data->ct_retries++;
134
135         service = btd_device_get_service(data->dev, AVRCP_REMOTE_UUID);
136         if (service != NULL)
137                 policy_connect(data, service);
138
139         return FALSE;
140 }
141
142 static void policy_set_ct_timer(struct policy_data *data, int timeout)
143 {
144         if (data->ct_timer > 0)
145                 g_source_remove(data->ct_timer);
146
147         data->ct_timer = g_timeout_add_seconds(timeout, policy_connect_ct,
148                                                                         data);
149 }
150
151 static struct policy_data *find_data(struct btd_device *dev)
152 {
153         GSList *l;
154
155         for (l = devices; l; l = l->next) {
156                 struct policy_data *data = l->data;
157
158                 if (data->dev == dev)
159                         return data;
160         }
161
162         return NULL;
163 }
164
165 static void policy_remove(void *user_data)
166 {
167         struct policy_data *data = user_data;
168
169         if (data->source_timer > 0)
170                 g_source_remove(data->source_timer);
171
172         if (data->sink_timer > 0)
173                 g_source_remove(data->sink_timer);
174
175         if (data->ct_timer > 0)
176                 g_source_remove(data->ct_timer);
177
178         if (data->tg_timer > 0)
179                 g_source_remove(data->tg_timer);
180
181         g_free(data);
182 }
183
184 static struct policy_data *policy_get_data(struct btd_device *dev)
185 {
186         struct policy_data *data;
187
188         data = find_data(dev);
189         if (data != NULL)
190                 return data;
191
192         data = g_new0(struct policy_data, 1);
193         data->dev = dev;
194
195         devices = g_slist_prepend(devices, data);
196
197         return data;
198 }
199
200 static gboolean policy_connect_sink(gpointer user_data)
201 {
202         struct policy_data *data = user_data;
203         struct btd_service *service;
204
205         data->source_timer = 0;
206         data->sink_retries++;
207
208         service = btd_device_get_service(data->dev, A2DP_SINK_UUID);
209         if (service != NULL)
210                 policy_connect(data, service);
211
212         return FALSE;
213 }
214
215 static void policy_set_sink_timer(struct policy_data *data)
216 {
217         if (data->sink_timer > 0)
218                 g_source_remove(data->sink_timer);
219
220         data->sink_timer = g_timeout_add_seconds(SINK_RETRY_TIMEOUT,
221                                                         policy_connect_sink,
222                                                         data);
223 }
224
225 static void sink_cb(struct btd_service *service, btd_service_state_t old_state,
226                                                 btd_service_state_t new_state)
227 {
228         struct btd_device *dev = btd_service_get_device(service);
229         struct policy_data *data;
230         struct btd_service *controller;
231
232         controller = btd_device_get_service(dev, AVRCP_REMOTE_UUID);
233         if (controller == NULL)
234                 return;
235
236         data = policy_get_data(dev);
237
238         switch (new_state) {
239         case BTD_SERVICE_STATE_UNAVAILABLE:
240                 if (data->sink_timer > 0) {
241                         g_source_remove(data->sink_timer);
242                         data->sink_timer = 0;
243                 }
244                 break;
245         case BTD_SERVICE_STATE_DISCONNECTED:
246                 if (old_state == BTD_SERVICE_STATE_CONNECTING) {
247                         int err = btd_service_get_error(service);
248
249                         if (err == -EAGAIN) {
250                                 if (data->sink_retries < SINK_RETRIES)
251                                         policy_set_sink_timer(data);
252                                 else
253                                         data->sink_retries = 0;
254                                 break;
255                         } else if (data->sink_timer > 0) {
256                                 g_source_remove(data->sink_timer);
257                                 data->sink_timer = 0;
258                         }
259                 }
260
261                 if (data->ct_timer > 0) {
262                         g_source_remove(data->ct_timer);
263                         data->ct_timer = 0;
264                 } else if (btd_service_get_state(controller) !=
265                                                 BTD_SERVICE_STATE_DISCONNECTED)
266                         policy_disconnect(data, controller);
267                 break;
268         case BTD_SERVICE_STATE_CONNECTING:
269                 break;
270         case BTD_SERVICE_STATE_CONNECTED:
271                 if (data->sink_timer > 0) {
272                         g_source_remove(data->sink_timer);
273                         data->sink_timer = 0;
274                 }
275
276                 /* Check if service initiate the connection then proceed
277                  * immediatelly otherwise set timer
278                  */
279                 if (old_state == BTD_SERVICE_STATE_CONNECTING)
280 #ifdef __TIZEN_PATCH__
281                         /* Set timer as most of the devices initiate
282                          * avrcp connection immediately; irrespective of local
283                          * or remote initiated a2dp connection
284                          */
285                         policy_set_ct_timer(data, CONTROL_CONNECT_TIMEOUT);
286 #else
287                         policy_connect(data, controller);
288 #endif
289                 else if (btd_service_get_state(controller) !=
290                                                 BTD_SERVICE_STATE_CONNECTED)
291                         policy_set_ct_timer(data, CONTROL_CONNECT_TIMEOUT);
292                 break;
293         case BTD_SERVICE_STATE_DISCONNECTING:
294                 break;
295         }
296 }
297
298 static gboolean policy_connect_tg(gpointer user_data)
299 {
300         struct policy_data *data = user_data;
301         struct btd_service *service;
302
303         data->tg_timer = 0;
304         data->tg_retries++;
305
306         service = btd_device_get_service(data->dev, AVRCP_TARGET_UUID);
307         if (service != NULL)
308                 policy_connect(data, service);
309
310         return FALSE;
311 }
312
313 static void policy_set_tg_timer(struct policy_data *data, int timeout)
314 {
315         if (data->tg_timer > 0)
316                 g_source_remove(data->tg_timer);
317
318
319 #ifdef __TIZEN_PATCH__
320         data->tg_timer = g_timeout_add_seconds(TARGET_CONNECT_TIMEOUT,
321                                                         policy_connect_tg,
322                                                         data);
323 #else
324         data->tg_timer = g_timeout_add_seconds(timeout, policy_connect_tg,
325                                                         data);
326 #endif
327 }
328
329 static gboolean policy_connect_source(gpointer user_data)
330 {
331         struct policy_data *data = user_data;
332         struct btd_service *service;
333
334         data->source_timer = 0;
335         data->source_retries++;
336
337         service = btd_device_get_service(data->dev, A2DP_SOURCE_UUID);
338         if (service != NULL)
339                 policy_connect(data, service);
340
341         return FALSE;
342 }
343
344 static void policy_set_source_timer(struct policy_data *data)
345 {
346         if (data->source_timer > 0)
347                 g_source_remove(data->source_timer);
348
349         data->source_timer = g_timeout_add_seconds(SOURCE_RETRY_TIMEOUT,
350                                                         policy_connect_source,
351                                                         data);
352 }
353
354 static void source_cb(struct btd_service *service,
355                                                 btd_service_state_t old_state,
356                                                 btd_service_state_t new_state)
357 {
358         struct btd_device *dev = btd_service_get_device(service);
359         struct policy_data *data;
360         struct btd_service *target;
361
362         target = btd_device_get_service(dev, AVRCP_TARGET_UUID);
363         if (target == NULL)
364                 return;
365
366         data = policy_get_data(dev);
367
368         switch (new_state) {
369         case BTD_SERVICE_STATE_UNAVAILABLE:
370                 if (data->source_timer > 0) {
371                         g_source_remove(data->source_timer);
372                         data->source_timer = 0;
373                 }
374                 break;
375         case BTD_SERVICE_STATE_DISCONNECTED:
376                 if (old_state == BTD_SERVICE_STATE_CONNECTING) {
377                         int err = btd_service_get_error(service);
378
379                         if (err == -EAGAIN) {
380                                 if (data->source_retries < SOURCE_RETRIES)
381                                         policy_set_source_timer(data);
382                                 else
383                                         data->source_retries = 0;
384                                 break;
385                         } else if (data->source_timer > 0) {
386                                 g_source_remove(data->source_timer);
387                                 data->source_timer = 0;
388                         }
389                 }
390
391                 if (data->tg_timer > 0) {
392                         g_source_remove(data->tg_timer);
393                         data->tg_timer = 0;
394 #if defined __TIZEN_PATCH__ && defined BT_QUALIFICATION
395                 }
396 #else
397                 } else if (btd_service_get_state(target) !=
398                                                 BTD_SERVICE_STATE_DISCONNECTED)
399                         policy_disconnect(data, target);
400 #endif
401                 break;
402         case BTD_SERVICE_STATE_CONNECTING:
403                 break;
404         case BTD_SERVICE_STATE_CONNECTED:
405                 if (data->source_timer > 0) {
406                         g_source_remove(data->source_timer);
407                         data->source_timer = 0;
408                 }
409
410                 /* Check if service initiate the connection then proceed
411                  * immediatelly otherwise set timer
412                  */
413                 if (old_state == BTD_SERVICE_STATE_CONNECTING)
414                         policy_connect(data, target);
415                 else if (btd_service_get_state(target) !=
416                                                 BTD_SERVICE_STATE_CONNECTED)
417                         policy_set_tg_timer(data, CONTROL_CONNECT_TIMEOUT);
418                 break;
419         case BTD_SERVICE_STATE_DISCONNECTING:
420                 break;
421         }
422 }
423
424 static void controller_cb(struct btd_service *service,
425                                                 btd_service_state_t old_state,
426                                                 btd_service_state_t new_state)
427 {
428         struct btd_device *dev = btd_service_get_device(service);
429         struct policy_data *data;
430
431         data = find_data(dev);
432         if (data == NULL)
433                 return;
434
435         switch (new_state) {
436         case BTD_SERVICE_STATE_UNAVAILABLE:
437                 if (data->ct_timer > 0) {
438                         g_source_remove(data->ct_timer);
439                         data->ct_timer = 0;
440                 }
441                 break;
442         case BTD_SERVICE_STATE_DISCONNECTED:
443                 if (old_state == BTD_SERVICE_STATE_CONNECTING) {
444                         int err = btd_service_get_error(service);
445
446                         if (err == -EAGAIN) {
447                                 if (data->ct_retries < CT_RETRIES)
448                                         policy_set_ct_timer(data,
449                                                         CT_RETRY_TIMEOUT);
450                                 else
451                                         data->ct_retries = 0;
452                                 break;
453                         } else if (data->ct_timer > 0) {
454                                 g_source_remove(data->ct_timer);
455                                 data->ct_timer = 0;
456                         }
457                 } else if (old_state == BTD_SERVICE_STATE_CONNECTED) {
458                         data->ct_retries = 0;
459                 }
460                 break;
461         case BTD_SERVICE_STATE_CONNECTING:
462                 break;
463         case BTD_SERVICE_STATE_CONNECTED:
464                 if (data->ct_timer > 0) {
465                         g_source_remove(data->ct_timer);
466                         data->ct_timer = 0;
467                 }
468                 break;
469         case BTD_SERVICE_STATE_DISCONNECTING:
470                 break;
471         }
472 }
473
474 static void target_cb(struct btd_service *service,
475                                                 btd_service_state_t old_state,
476                                                 btd_service_state_t new_state)
477 {
478         struct btd_device *dev = btd_service_get_device(service);
479         struct policy_data *data;
480
481         data = find_data(dev);
482         if (data == NULL)
483                 return;
484
485         switch (new_state) {
486         case BTD_SERVICE_STATE_UNAVAILABLE:
487                 if (data->tg_timer > 0) {
488                         g_source_remove(data->tg_timer);
489                         data->tg_timer = 0;
490                 }
491                 break;
492         case BTD_SERVICE_STATE_DISCONNECTED:
493                 if (old_state == BTD_SERVICE_STATE_CONNECTING) {
494                         int err = btd_service_get_error(service);
495
496                         if (err == -EAGAIN) {
497                                 if (data->tg_retries < TG_RETRIES)
498                                         policy_set_tg_timer(data,
499                                                         TG_RETRY_TIMEOUT);
500                                 else
501                                         data->tg_retries = 0;
502                                 break;
503                         } else if (data->tg_timer > 0) {
504                                 g_source_remove(data->tg_timer);
505                                 data->tg_timer = 0;
506                         }
507                 } else if (old_state == BTD_SERVICE_STATE_CONNECTED) {
508                         data->tg_retries = 0;
509                 }
510                 break;
511         case BTD_SERVICE_STATE_CONNECTING:
512                 break;
513         case BTD_SERVICE_STATE_CONNECTED:
514                 if (data->tg_timer > 0) {
515                         g_source_remove(data->tg_timer);
516                         data->tg_timer = 0;
517                 }
518                 break;
519         case BTD_SERVICE_STATE_DISCONNECTING:
520                 break;
521         }
522 }
523
524 static void reconnect_reset(struct reconnect_data *reconnect)
525 {
526         reconnect->attempt = 0;
527
528         if (reconnect->timer > 0) {
529                 g_source_remove(reconnect->timer);
530                 reconnect->timer = 0;
531         }
532 }
533
534 static bool reconnect_match(const char *uuid)
535 {
536         char **str;
537
538         if (!reconnect_uuids)
539                 return false;
540
541         for (str = reconnect_uuids; *str; str++) {
542                 if (!bt_uuid_strcmp(uuid, *str))
543                         return true;
544         }
545
546         return false;
547 }
548
549 static struct reconnect_data *reconnect_find(struct btd_device *dev)
550 {
551         GSList *l;
552
553         for (l = reconnects; l; l = g_slist_next(l)) {
554                 struct reconnect_data *reconnect = l->data;
555
556                 if (reconnect->dev == dev)
557                         return reconnect;
558         }
559
560         return NULL;
561 }
562
563 static struct reconnect_data *reconnect_add(struct btd_service *service)
564 {
565         struct btd_device *dev = btd_service_get_device(service);
566         struct reconnect_data *reconnect;
567
568         reconnect = reconnect_find(dev);
569         if (!reconnect) {
570                 reconnect = g_new0(struct reconnect_data, 1);
571                 reconnect->dev = dev;
572                 reconnects = g_slist_append(reconnects, reconnect);
573         }
574
575         if (g_slist_find(reconnect->services, service))
576                 return reconnect;
577
578         reconnect->services = g_slist_append(reconnect->services,
579                                                 btd_service_ref(service));
580
581         return reconnect;
582 }
583
584 static void reconnect_destroy(gpointer data)
585 {
586         struct reconnect_data *reconnect = data;
587
588         if (reconnect->timer > 0)
589                 g_source_remove(reconnect->timer);
590
591         g_slist_free_full(reconnect->services,
592                                         (GDestroyNotify) btd_service_unref);
593         g_free(reconnect);
594 }
595
596 static void reconnect_remove(struct btd_service *service)
597 {
598         struct btd_device *dev = btd_service_get_device(service);
599         struct reconnect_data *reconnect;
600         GSList *l;
601
602         reconnect = reconnect_find(dev);
603         if (!reconnect)
604                 return;
605
606         l = g_slist_find(reconnect->services, service);
607         if (!l)
608                 return;
609
610         reconnect->services = g_slist_delete_link(reconnect->services, l);
611         btd_service_unref(service);
612
613         if (reconnect->services)
614                 return;
615
616         reconnects = g_slist_remove(reconnects, reconnect);
617
618         if (reconnect->timer > 0)
619                 g_source_remove(reconnect->timer);
620
621         g_free(reconnect);
622 }
623
624 static void service_cb(struct btd_service *service,
625                                                 btd_service_state_t old_state,
626                                                 btd_service_state_t new_state,
627                                                 void *user_data)
628 {
629         struct btd_profile *profile = btd_service_get_profile(service);
630         struct reconnect_data *reconnect;
631
632         if (g_str_equal(profile->remote_uuid, A2DP_SINK_UUID))
633                 sink_cb(service, old_state, new_state);
634         else if (g_str_equal(profile->remote_uuid, A2DP_SOURCE_UUID))
635                 source_cb(service, old_state, new_state);
636         else if (g_str_equal(profile->remote_uuid, AVRCP_REMOTE_UUID))
637                 controller_cb(service, old_state, new_state);
638         else if (g_str_equal(profile->remote_uuid, AVRCP_TARGET_UUID))
639                 target_cb(service, old_state, new_state);
640
641         /*
642          * Return if the reconnection feature is not enabled (all
643          * subsequent code in this function is about that).
644          */
645         if (!reconnect_uuids || !reconnect_uuids[0])
646                 return;
647
648         /*
649          * We're only interested in reconnecting profiles which have set
650          * auto_connect to true.
651          */
652         if (!profile->auto_connect)
653                 return;
654
655         /*
656          * If the service went away remove it from the reconnection
657          * tracking. The function will remove the entire tracking data
658          * if this was the last service for the device.
659          */
660         if (new_state == BTD_SERVICE_STATE_UNAVAILABLE) {
661                 reconnect_remove(service);
662                 return;
663         }
664
665         if (new_state != BTD_SERVICE_STATE_CONNECTED)
666                 return;
667
668         /*
669          * Add an entry to track reconnections. The function will return
670          * an existing entry if there is one.
671          */
672         reconnect = reconnect_add(service);
673
674         reconnect->active = false;
675         reconnect_reset(reconnect);
676
677         /*
678          * Should this device be reconnected? A matching UUID might not
679          * be the first profile that's connected so we might have an
680          * entry but with the reconnect flag set to false.
681          */
682         if (!reconnect->reconnect)
683                 reconnect->reconnect = reconnect_match(profile->remote_uuid);
684
685         DBG("Added %s reconnect %u", profile->name, reconnect->reconnect);
686 }
687
688 static gboolean reconnect_timeout(gpointer data)
689 {
690         struct reconnect_data *reconnect = data;
691         int err;
692
693         DBG("Reconnecting profiles");
694
695         /* Mark the GSource as invalid */
696         reconnect->timer = 0;
697
698         err = btd_device_connect_services(reconnect->dev, reconnect->services);
699         if (err < 0) {
700                 error("Reconnecting services failed: %s (%d)",
701                                                         strerror(-err), -err);
702                 reconnect_reset(reconnect);
703                 return FALSE;
704         }
705
706         reconnect->active = true;
707         reconnect->attempt++;
708
709         return FALSE;
710 }
711
712 static void reconnect_set_timer(struct reconnect_data *reconnect)
713 {
714         static int timeout = 0;
715
716         reconnect->attempt++;
717
718         if (reconnect->attempt < reconnect_intervals_len)
719                 timeout = reconnect_intervals[reconnect->attempt];
720
721         DBG("%d seconds", timeout);
722
723         reconnect->timer = g_timeout_add_seconds(timeout, reconnect_timeout,
724                                                                 reconnect);
725 }
726
727 static void disconnect_cb(struct btd_device *dev, uint8_t reason)
728 {
729         struct reconnect_data *reconnect;
730
731         DBG("reason %u", reason);
732
733         if (reason != MGMT_DEV_DISCONN_TIMEOUT)
734                 return;
735
736         reconnect = reconnect_find(dev);
737         if (!reconnect || !reconnect->reconnect)
738                 return;
739
740         DBG("Device %s identified for auto-reconnection",
741                                                         device_get_path(dev));
742
743         reconnect_set_timer(reconnect);
744 }
745
746 static void conn_fail_cb(struct btd_device *dev, uint8_t status)
747 {
748         struct reconnect_data *reconnect;
749
750         DBG("status %u", status);
751
752         reconnect = reconnect_find(dev);
753         if (!reconnect || !reconnect->reconnect)
754                 return;
755
756         if (!reconnect->active)
757                 return;
758
759         reconnect->active = false;
760
761         /* Give up if we were powered off */
762         if (status == MGMT_STATUS_NOT_POWERED) {
763                 reconnect_reset(reconnect);
764                 return;
765         }
766
767         /* Reset if ReconnectAttempts was reached */
768         if (reconnect->attempt == reconnect_attempts) {
769                 reconnect_reset(reconnect);
770                 return;
771         }
772
773         reconnect_set_timer(reconnect);
774 }
775
776 static int policy_adapter_probe(struct btd_adapter *adapter)
777 {
778         DBG("");
779
780         btd_adapter_restore_powered(adapter);
781
782         return 0;
783 }
784
785 static struct btd_adapter_driver policy_driver = {
786         .name   = "policy",
787         .probe  = policy_adapter_probe,
788 };
789
790 static int policy_init(void)
791 {
792         GError *gerr = NULL;
793         GKeyFile *conf;
794
795         service_id = btd_service_add_state_cb(service_cb, NULL);
796
797         conf = btd_get_main_conf();
798         if (!conf) {
799                 reconnect_uuids = g_strdupv((char **) default_reconnect);
800                 reconnect_attempts = default_attempts;
801                 reconnect_intervals_len = sizeof(default_intervals) /
802                                                 sizeof(*reconnect_intervals);
803                 reconnect_intervals = g_memdup(default_intervals,
804                                                 reconnect_intervals_len);
805                 goto done;
806         }
807
808         reconnect_uuids = g_key_file_get_string_list(conf, "Policy",
809                                                         "ReconnectUUIDs",
810                                                         NULL, &gerr);
811         if (gerr) {
812                 g_clear_error(&gerr);
813                 reconnect_uuids = g_strdupv((char **) default_reconnect);
814         }
815
816         reconnect_attempts = g_key_file_get_integer(conf, "Policy",
817                                                         "ReconnectAttempts",
818                                                         &gerr);
819         if (gerr) {
820                 g_clear_error(&gerr);
821                 reconnect_attempts = default_attempts;
822         }
823
824         reconnect_intervals = g_key_file_get_integer_list(conf, "Policy",
825                                         "ReconnectIntervals",
826                                         (size_t *) &reconnect_intervals_len,
827                                         &gerr);
828         if (gerr) {
829                 g_clear_error(&gerr);
830                 reconnect_intervals_len = sizeof(default_intervals);
831                 reconnect_intervals = g_memdup(default_intervals,
832                                                 reconnect_intervals_len);
833         }
834
835         auto_enable = g_key_file_get_boolean(conf, "Policy", "AutoEnable",
836                                                                         NULL);
837
838 done:
839         if (reconnect_uuids && reconnect_uuids[0] && reconnect_attempts) {
840                 btd_add_disconnect_cb(disconnect_cb);
841                 btd_add_conn_fail_cb(conn_fail_cb);
842         }
843
844         if (auto_enable)
845                 btd_register_adapter_driver(&policy_driver);
846
847         return 0;
848 }
849
850 static void policy_exit(void)
851 {
852         btd_remove_disconnect_cb(disconnect_cb);
853         btd_remove_conn_fail_cb(conn_fail_cb);
854
855         if (reconnect_uuids)
856                 g_strfreev(reconnect_uuids);
857
858         g_free(reconnect_intervals);
859
860         g_slist_free_full(reconnects, reconnect_destroy);
861
862         g_slist_free_full(devices, policy_remove);
863
864         btd_service_remove_state_cb(service_id);
865
866         if (auto_enable)
867                 btd_unregister_adapter_driver(&policy_driver);
868 }
869
870 BLUETOOTH_PLUGIN_DEFINE(policy, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
871                                                 policy_init, policy_exit)