Merge "Fix iOS GM connection issue" into tizen
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / device / bt-service-bonded-device.c
1 /*
2  * Copyright (c) 2015 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Contact: Atul Rai <a.rai@samsung.com>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *              http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <gio/gio.h>
22 #include <glib.h>
23 #include <dlog.h>
24 #include <string.h>
25
26 /*bt-service headers */
27 #include "bt-internal-types.h"
28 #include "bt-service-common.h"
29 #include "bt-service-util.h"
30 #include "bt-service-event-receiver.h"
31 #include "bt-request-handler.h"
32 #include "bt-service-event.h"
33 #include "bt-service-core-adapter.h"
34 #include "bt-service-core-device.h"
35 #include "bt-service-device-internal.h"
36 #include "bt-service-gatt.h"
37
38 /* OAL headers */
39 #include <oal-event.h>
40 #include <oal-manager.h>
41
42 static GSList *paired_list;
43 static GSList *bonded_addr_list;
44 static unsigned int bonded_list_index = 0;
45 static gboolean bonded_list_retrieved = FALSE;
46
47 void _bt_service_get_bonded_dev_list(GArray **dev_list)
48 {
49         GSList *l;
50
51         BT_DBG("+");
52
53         ret_if(NULL == dev_list);
54
55         for (l = paired_list; NULL != l; l = g_slist_next(l)) {
56                 bt_remote_dev_info_t *rem_info = l->data;
57                 bluetooth_device_info_t dev_info;
58
59                 if (!rem_info)
60                         continue;
61
62                 _bt_copy_remote_device(rem_info, &dev_info);
63                 g_array_append_vals(*dev_list, &dev_info, sizeof(bluetooth_device_info_t));
64         }
65
66         BT_DBG("+");
67         return;
68 }
69
70 bt_remote_dev_info_t *_bt_service_get_remote_dev_info(const char *address)
71 {
72         GSList *l;
73
74         BT_DBG("+");
75         retv_if(NULL == address, NULL);
76
77         for (l = paired_list; NULL != l; l = g_slist_next(l)) {
78                 bt_remote_dev_info_t *rem_info = l->data;
79
80                 if (!rem_info)
81                         continue;
82
83                 if (!strncasecmp(rem_info->address, address, BT_ADDRESS_STRING_SIZE)) {
84                         BT_DBG("Device found");
85                         return rem_info;
86                 }
87         }
88
89         BT_DBG("-");
90         return NULL;
91 }
92
93 static void __bt_handle_pending_request(int result, int service_function)
94 {
95         GSList *l;
96         GArray *out_param;
97         invocation_info_t *req_info = NULL;
98
99         BT_DBG("+");
100
101         /* Get method invocation context */
102         for (l = _bt_get_invocation_list(); l != NULL; ) {
103                 req_info = l->data;
104                 l = g_slist_next(l);
105                 if (req_info == NULL || req_info->service_function != service_function)
106                         continue;
107
108                 switch (service_function) {
109                 case BT_GET_BONDED_DEVICE: {
110                         char *address;
111                         bt_remote_dev_info_t *rem_info;
112                         bluetooth_device_info_t dev_info;
113
114                         address = (char *)req_info->user_data;
115                         if (!address) {
116                                 BT_ERR_C("Unexpected: address is NULL");
117                                 continue;
118                         }
119
120                         BT_DBG("BT_GET_BONDED_DEVICE for [%s] found", address);
121                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
122                         rem_info = _bt_service_get_remote_dev_info(address);
123                         if (rem_info) {
124                                 result = BLUETOOTH_ERROR_NONE;
125                                 _bt_copy_remote_device(rem_info, &dev_info);
126                                 g_array_append_vals(out_param, &dev_info,
127                                                 sizeof(bluetooth_device_info_t));
128                         } else {
129                                 BT_DBG("Device not found in paired list");
130                                 result = BLUETOOTH_ERROR_NOT_PAIRED;
131                         }
132
133                         _bt_service_method_return(req_info->context, out_param, result);
134                         _bt_free_info_from_invocation_list(req_info);
135                         g_array_free(out_param, TRUE);
136                         break;
137                 }
138                 case BT_GET_BONDED_DEVICES: {
139                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
140                         _bt_service_get_bonded_dev_list(&out_param);
141                         _bt_service_method_return(req_info->context, out_param, result);
142                         _bt_free_info_from_invocation_list(req_info);
143                         g_array_free(out_param, TRUE);
144                         break;
145                 }
146                 case BT_GET_IS_ALIAS_SET: {
147                         char *address;
148                         bt_remote_dev_info_t *rem_info;
149
150                         address = (char *)req_info->user_data;
151                         if (!address) {
152                                 BT_ERR_C("Unexpected: address is NULL");
153                                 continue;
154                         }
155
156                         BT_DBG("BT_GET_IS_ALIAS_SET for [%s] found", address);
157                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
158                         rem_info = _bt_service_get_remote_dev_info(address);
159                         if (rem_info) {
160                                 result = BLUETOOTH_ERROR_NONE;
161                                 g_array_append_vals(out_param, &(rem_info->is_alias_set),
162                                                 sizeof(gboolean));
163                         } else {
164                                 BT_DBG("Device not found in paired list");
165                                 result = BLUETOOTH_ERROR_NOT_PAIRED;
166                         }
167
168                         _bt_service_method_return(req_info->context, out_param, result);
169                         _bt_free_info_from_invocation_list(req_info);
170                         g_array_free(out_param, TRUE);
171                         break;
172                 }
173                 case BT_GET_CONNECTED_LINK_TYPE: {
174                         char *address;
175                         bt_remote_dev_info_t *rem_info;
176
177                         address = (char *)req_info->user_data;
178                         if (!address) {
179                                 BT_ERR_C("Unexpected: address is NULL");
180                                 continue;
181                         }
182
183                         BT_DBG("BT_GET_CONNECTED_LINK_TYPE for [%s] found", address);
184                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
185                         rem_info = _bt_service_get_remote_dev_info(address);
186                         if (rem_info) {
187                                 result = BLUETOOTH_ERROR_NONE;
188                                 g_array_append_vals(out_param, &(rem_info->connected),
189                                                 sizeof(bluetooth_connected_link_t));
190                         }
191                         else if (_bt_find_remote_gatt_client_info(address) || _bt_find_remote_gatt_server_info(address)) {
192                                 bluetooth_connected_link_t value = BLUETOOTH_CONNECTED_LINK_LE;
193                                 result = BLUETOOTH_ERROR_NONE;
194                                 g_array_append_vals(out_param, &(value),
195                                                 sizeof(bluetooth_connected_link_t));
196                         }
197                         else {
198                                 BT_DBG("Device not found in paired list \n Device not found in the LE devices list");
199                                 result = BLUETOOTH_ERROR_NOT_FOUND;
200                         }
201
202                         _bt_service_method_return(req_info->context, out_param, result);
203                         _bt_free_info_from_invocation_list(req_info);
204                         g_array_free(out_param, TRUE);
205                         break;
206                 }
207                 default:
208                         BT_ERR_C("Unknown service function %d", service_function);
209                 }
210         }
211 }
212
213 static void __bt_service_fetch_dev_info_for_bonded_addr_list(void)
214 {
215         unsigned int count = g_slist_length(bonded_addr_list);
216
217         BT_DBG("+");
218
219         BT_INFO("bonded_list_index: %d", bonded_list_index);
220         for (; bonded_list_index < count; bonded_list_index++) {
221                 GSList *l = g_slist_nth(bonded_addr_list, bonded_list_index);
222                 bluetooth_device_address_t *dev_addr = l->data;
223
224                 if (!dev_addr)
225                         continue;
226
227                 if (BLUETOOTH_ERROR_NONE != _bt_device_get_bonded_device_info(dev_addr)) {
228                         char address[BT_ADDRESS_STRING_SIZE];
229                         _bt_convert_addr_type_to_string(address, dev_addr->addr);
230                         BT_ERR("_bt_device_get_bonded_device_info Failed for [%s]", address);
231                         continue;
232                 }
233                 return;
234         }
235
236         /* Retrieval of bonded device list completed */
237         bonded_list_index = 0;
238         bonded_list_retrieved = TRUE;
239         g_slist_free_full(bonded_addr_list, g_free);
240         bonded_addr_list = NULL;
241
242         /* Send reply if request for BT_GET_BONDED_DEVICES is pending */
243         __bt_handle_pending_request(
244                         BLUETOOTH_ERROR_NONE, BT_GET_BONDED_DEVICES);
245
246         /* Send reply if request for BT_GET_BONDED_DEVICE is pending */
247         __bt_handle_pending_request(
248                         BLUETOOTH_ERROR_NONE, BT_GET_BONDED_DEVICE);
249
250         __bt_handle_pending_request(
251                         BLUETOOTH_ERROR_NONE, BT_GET_IS_ALIAS_SET);
252         __bt_handle_pending_request(
253                         BLUETOOTH_ERROR_NONE, BT_GET_CONNECTED_LINK_TYPE);
254         BT_DBG("-");
255 }
256
257 static void __bt_update_connected_status(bt_remote_dev_info_t *rem_info, gboolean connected, unsigned char type)
258 {
259         BT_DBG("+");
260
261         if (connected) {
262                 if (0 == type) {
263                         switch (rem_info->connected) {
264                         case BLUETOOTH_CONNECTED_LINK_NONE:
265                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_BREDR;
266                                 break;
267                         case BLUETOOTH_CONNECTED_LINK_LE:
268                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_BREDR_LE;
269                                 break;
270                         default:
271                                 BT_ERR_C("rem_info->connected is already set to desired value: %d",
272                                                 rem_info->connected);
273                         }
274                 } else {
275                         switch (rem_info->connected) {
276                         case BLUETOOTH_CONNECTED_LINK_NONE:
277                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_LE;
278                                 break;
279                         case BLUETOOTH_CONNECTED_LINK_BREDR:
280                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_BREDR_LE;
281                                 break;
282                         default:
283                                 BT_ERR_C("rem_info->connected is already set to desired value: %d",
284                                                 rem_info->connected);
285                         }
286                 }
287         } else {
288                 if (0 == type) {
289                         switch (rem_info->connected) {
290                         case BLUETOOTH_CONNECTED_LINK_BREDR:
291                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_NONE;
292                                 break;
293                         case BLUETOOTH_CONNECTED_LINK_BREDR_LE:
294                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_LE;
295                                 break;
296                         default:
297                                 BT_ERR_C("rem_info->connected is already set to desired value: %d",
298                                                 rem_info->connected);
299                         }
300                 } else {
301                         switch (rem_info->connected) {
302                         case BLUETOOTH_CONNECTED_LINK_LE:
303                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_NONE;
304                                 break;
305                         case BLUETOOTH_CONNECTED_LINK_BREDR_LE:
306                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_BREDR;
307                                 break;
308                         default:
309                                 BT_ERR_C("rem_info->connected is already set to desired value: %d",
310                                                 rem_info->connected);
311                         }
312                 }
313         }
314
315         BT_DBG("-");
316 }
317
318 void _bt_update_remote_dev_property(
319                 const char *address, bt_device_prop_type_e type, void *value)
320 {
321         bt_remote_dev_info_t *rem_info;
322
323         BT_DBG("+");
324
325         BT_DBG("Property type: %d", type);
326         rem_info = _bt_service_get_remote_dev_info(address);
327         ret_if(NULL == rem_info);
328
329         switch (type) {
330         case DEV_PROP_CONNECTED: {
331                 bt_device_conn_info_t *conn_info = value;
332
333                 __bt_update_connected_status(
334                         rem_info, conn_info->connected, conn_info->type);
335                 break;
336         }
337         case DEV_PROP_NAME: {
338                 char *name = value;
339
340                 if (name && strlen(name) > 0) {
341                         g_free(rem_info->name);
342                         rem_info->name = g_strdup(name);
343                 }
344                 break;
345         }
346         case DEV_PROP_ALIAS: {
347                 char *alias = value;
348
349                 g_free(rem_info->alias);
350                 rem_info->alias = NULL;
351                 rem_info->is_alias_set = FALSE;
352
353                 if (alias && strlen(alias) > 0) {
354                         rem_info->alias = g_strdup(alias);
355                         rem_info->is_alias_set = TRUE;
356                 }
357                 break;
358         }
359         case DEV_PROP_TRUST: {
360                 gboolean *trusted = value;
361                 rem_info->trust = *trusted;
362                 break;
363         }
364         case DEV_PROP_SERVICES: {
365                 bt_remote_dev_info_t *src = value;
366
367                 if (src->uuid_count > 0 && src->uuids) {
368                         int i;
369
370                         /* Release previously allocated UUIDs */
371                         if (rem_info->uuid_count > 0 && rem_info->uuids)
372                                 for (i = 0; i < rem_info->uuid_count; i++)
373                                         g_free(rem_info->uuids[i]);
374                         g_free(rem_info->uuids);
375
376                         /* Copy new UUID list */
377                         rem_info->uuids = g_malloc0(src->uuid_count * sizeof(char *));
378                         for (i = 0; i < src->uuid_count; i++)
379                                 rem_info->uuids[i] = g_strdup(src->uuids[i]);
380
381                         rem_info->uuid_count = src->uuid_count;
382                         BT_DBG("UUID count: %d", rem_info->uuid_count);
383                 }
384                 break;
385         }
386         default:
387                 BT_DBG("Unknown property");
388                 return;
389         }
390
391         BT_DBG("-");
392 }
393
394 void _bt_service_add_device_to_bonded_list(bt_remote_dev_info_t *rem_info)
395 {
396         bt_remote_dev_info_t *dev_info;
397
398         BT_DBG("+");
399         ret_if(NULL == rem_info);
400
401         dev_info = _bt_service_get_remote_dev_info(rem_info->address);
402         if (!dev_info) {
403                 BT_DBG("Device info not present, allocate memory");
404                 dev_info = g_malloc0(sizeof(bt_remote_dev_info_t));
405                 paired_list = g_slist_append(paired_list, dev_info);
406         }
407
408         _bt_copy_remote_dev_info(dev_info, rem_info);
409
410         if (!bonded_list_retrieved) {
411                 char addr_str[BT_ADDRESS_STRING_SIZE];
412                 bluetooth_device_address_t *dev_addr;
413                 GSList *l;
414
415                 l = g_slist_nth(bonded_addr_list, bonded_list_index);
416                 if (!l) {
417                         BT_ERR_C("l is NULL unexpectedly, need to check");
418                         return;
419                 }
420
421                 dev_addr = l->data;
422                 if (!dev_addr) {
423                         BT_ERR_C("dev_addr is NULL unexpectedly, need to check");
424                         return;
425                 }
426
427                 _bt_convert_addr_type_to_string(addr_str, dev_addr->addr);
428                 if (!strncasecmp(addr_str, rem_info->address, BT_ADDRESS_STRING_SIZE)) {
429                         bonded_list_index++;
430                         __bt_service_fetch_dev_info_for_bonded_addr_list();
431                 }
432         }
433
434         BT_DBG("-");
435 }
436
437 void _bt_service_remove_device_from_bonded_list(const char *address)
438 {
439         bt_remote_dev_info_t *rem_info;
440
441         BT_DBG("+");
442         ret_if(NULL == address);
443
444         rem_info = _bt_service_get_remote_dev_info(address);
445         if (!rem_info) {
446                 BT_DBG("Device not found in list");
447                 return;
448         }
449
450         paired_list = g_slist_remove(paired_list, rem_info);
451         _bt_free_remote_dev(rem_info);
452         BT_DBG("-");
453 }
454
455 void _bt_device_handle_paired_address_list(bluetooth_device_address_t *addr_list, int count)
456 {
457         int indx;
458
459         BT_DBG("+");
460
461         if (bonded_list_retrieved) {
462                 BT_ERR_C("Unexpected bonded address list received");
463                 return;
464         }
465
466         if (0 == count) {
467                 BT_DBG("No paired device found");
468                 bonded_list_index = 0;
469                 bonded_list_retrieved = TRUE;
470                 return;
471         }
472
473         ret_if(NULL == addr_list);
474
475         for (indx = 0; indx < count; indx++) {
476                 bluetooth_device_address_t *dev_addr;
477
478                 dev_addr = g_memdup(&(addr_list[indx]), sizeof(bluetooth_device_address_t));
479                 bonded_addr_list = g_slist_append(bonded_addr_list, dev_addr);
480         }
481
482         __bt_service_fetch_dev_info_for_bonded_addr_list();
483         BT_DBG("-");
484 }
485
486 static gboolean __check_bonded_devices(gpointer data)
487 {
488         BT_DBG("+");
489
490         retv_if(bonded_list_retrieved, FALSE);
491
492         /* Bonded devices are not yet retrived, retry */
493         if (BLUETOOTH_ERROR_NONE != _bt_adapter_get_bonded_devices())
494                 BT_ERR_C("_bt_adapter_get_bonded_devices failed");
495
496         BT_DBG("-");
497         return TRUE;
498 }
499
500 void _bt_device_handle_adapter_state(gboolean enabled)
501 {
502         BT_DBG("+");
503
504         if (!enabled) {
505                 BT_DBG("Adapter disabled");
506                 g_slist_free_full(paired_list, g_free);
507                 paired_list = NULL;
508                 bonded_list_retrieved = FALSE;
509                 return;
510         }
511
512         if (BLUETOOTH_ERROR_NONE != _bt_adapter_get_bonded_devices())
513                 BT_ERR_C("_bt_adapter_get_bonded_devices failed");
514
515         g_timeout_add_seconds(5, __check_bonded_devices, NULL);
516         BT_DBG("-");
517 }
518
519 static gboolean __reply_pending_request(gpointer data)
520 {
521         int *request = data;
522
523         BT_INFO("Request: %d", *request);
524         __bt_handle_pending_request(BLUETOOTH_ERROR_NONE, *request);
525         g_free(request);
526         return FALSE;
527 }
528
529 int _bt_get_bonded_device_info(bluetooth_device_address_t *dev_addr)
530 {
531         char address[BT_ADDRESS_STRING_SIZE];
532         bt_remote_dev_info_t *rem_info;
533         int request = BT_GET_BONDED_DEVICE;
534
535         BT_DBG("+");
536
537         retv_if(!dev_addr, BLUETOOTH_ERROR_INVALID_PARAM);
538
539         if (!bonded_list_retrieved) {
540                 /*
541                  * Blonded list retrival is in progress, return BLUETOOTH_ERROR_NONE here.
542                  * reply will be sent once bonded list is retrieved completely.
543                  */
544                 return BLUETOOTH_ERROR_NONE;
545         }
546
547         _bt_convert_addr_type_to_string(address, dev_addr->addr);
548
549         rem_info = _bt_service_get_remote_dev_info(address);
550         if (!rem_info) {
551                 BT_ERR("Bonded device not found in the list, return error");
552                 return BLUETOOTH_ERROR_NOT_PAIRED;
553         }
554
555         g_idle_add(__reply_pending_request, g_memdup(&request, sizeof(int)));
556         BT_DBG("-");
557         return BLUETOOTH_ERROR_NONE;
558 }
559
560 int _bt_get_bonded_devices(void)
561 {
562         int request = BT_GET_BONDED_DEVICES;
563
564         BT_DBG("+");
565         if (!bonded_list_retrieved) {
566                 /*
567                  * Blonded list retrival is in progress, return BLUETOOTH_ERROR_NONE here.
568                  * reply will be sent once bonded list is retrieved completely.
569                  */
570                 return BLUETOOTH_ERROR_NONE;
571         }
572
573         g_idle_add(__reply_pending_request, g_memdup(&request, sizeof(int)));
574         BT_DBG("-");
575         return BLUETOOTH_ERROR_NONE;
576 }
577
578 int _bt_is_alias_set(bluetooth_device_address_t *device_address)
579 {
580         char address[BT_ADDRESS_STRING_SIZE];
581         bt_remote_dev_info_t *rem_info;
582         int request = BT_GET_IS_ALIAS_SET;
583
584         BT_DBG("+");
585         if (!bonded_list_retrieved) {
586                 /*
587                  * Blonded list retrival is in progress, return BLUETOOTH_ERROR_NONE here.
588                  * reply will be sent once bonded list is retrieved completely.
589                  */
590                 return BLUETOOTH_ERROR_NONE;
591         }
592
593         _bt_convert_addr_type_to_string(address, device_address->addr);
594         rem_info = _bt_service_get_remote_dev_info(address);
595         if (!rem_info) {
596                 BT_ERR("Bonded device not found in the list, return error");
597                 return BLUETOOTH_ERROR_NOT_PAIRED;
598         }
599
600         g_idle_add(__reply_pending_request, g_memdup(&request, sizeof(int)));
601         BT_DBG("-");
602         return BLUETOOTH_ERROR_NONE;
603 }
604
605 int _bt_get_connected_link(bluetooth_device_address_t *device_address)
606 {
607         int request = BT_GET_CONNECTED_LINK_TYPE;
608
609         BT_DBG("+");
610         if (!bonded_list_retrieved) {
611                 /*
612                  * Blonded list retrival is in progress, return BLUETOOTH_ERROR_NONE here.
613                  * reply will be sent once bonded list is retrieved completely.
614                  */
615                 return BLUETOOTH_ERROR_NONE;
616         }
617
618         g_idle_add(__reply_pending_request, g_memdup(&request, sizeof(int)));
619         BT_DBG("-");
620         return BLUETOOTH_ERROR_NONE;
621 }
622
623 gboolean _bt_is_bonded_devices_retrived(void)
624 {
625         return bonded_list_retrieved;
626 }