Fix Memory Leak: Incorrect deallocator used.
[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         retv_if(NULL == address, NULL);
75
76         for (l = paired_list; NULL != l; l = g_slist_next(l)) {
77                 bt_remote_dev_info_t *rem_info = l->data;
78
79                 if (!rem_info)
80                         continue;
81
82                 if (!strncasecmp(rem_info->address, address, BT_ADDRESS_STRING_SIZE))
83                         return rem_info;
84                 }
85
86         return NULL;
87 }
88
89 static void __bt_handle_pending_request(int result, int service_function)
90 {
91         GSList *l;
92         GArray *out_param;
93         invocation_info_t *req_info = NULL;
94
95         BT_DBG("+");
96
97         /* Get method invocation context */
98         for (l = _bt_get_invocation_list(); l != NULL; ) {
99                 req_info = l->data;
100                 l = g_slist_next(l);
101                 if (req_info == NULL || req_info->service_function != service_function)
102                         continue;
103
104                 switch (service_function) {
105                 case BT_GET_BONDED_DEVICE: {
106                         char *address;
107                         bt_remote_dev_info_t *rem_info;
108                         bluetooth_device_info_t dev_info;
109
110                         address = (char *)req_info->user_data;
111                         if (!address) {
112                                 BT_ERR_C("Unexpected: address is NULL");
113                                 continue;
114                         }
115
116                         BT_DBG("BT_GET_BONDED_DEVICE for [%s] found", address);
117                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
118                         rem_info = _bt_service_get_remote_dev_info(address);
119                         if (rem_info) {
120                                 result = BLUETOOTH_ERROR_NONE;
121                                 _bt_copy_remote_device(rem_info, &dev_info);
122                                 g_array_append_vals(out_param, &dev_info,
123                                                 sizeof(bluetooth_device_info_t));
124                         } else {
125                                 BT_DBG("Device not found in paired list");
126                                 result = BLUETOOTH_ERROR_NOT_PAIRED;
127                         }
128
129                         _bt_service_method_return(req_info->context, out_param, result);
130                         _bt_free_info_from_invocation_list(req_info);
131                         g_array_free(out_param, TRUE);
132                         break;
133                 }
134                 case BT_GET_BONDED_DEVICES: {
135                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
136                         _bt_service_get_bonded_dev_list(&out_param);
137                         _bt_service_method_return(req_info->context, out_param, result);
138                         _bt_free_info_from_invocation_list(req_info);
139                         g_array_free(out_param, TRUE);
140                         break;
141                 }
142                 case BT_GET_IS_ALIAS_SET: {
143                         char *address;
144                         bt_remote_dev_info_t *rem_info;
145
146                         address = (char *)req_info->user_data;
147                         if (!address) {
148                                 BT_ERR_C("Unexpected: address is NULL");
149                                 continue;
150                         }
151
152                         BT_DBG("BT_GET_IS_ALIAS_SET for [%s] found", address);
153                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
154                         rem_info = _bt_service_get_remote_dev_info(address);
155                         if (rem_info) {
156                                 result = BLUETOOTH_ERROR_NONE;
157                                 g_array_append_vals(out_param, &(rem_info->is_alias_set),
158                                                 sizeof(gboolean));
159                         } else {
160                                 BT_DBG("Device not found in paired list");
161                                 result = BLUETOOTH_ERROR_NOT_PAIRED;
162                         }
163
164                         _bt_service_method_return(req_info->context, out_param, result);
165                         _bt_free_info_from_invocation_list(req_info);
166                         g_array_free(out_param, TRUE);
167                         break;
168                 }
169                 case BT_GET_CONNECTED_LINK_TYPE: {
170                         char *address;
171                         bt_remote_dev_info_t *rem_info;
172
173                         address = (char *)req_info->user_data;
174                         if (!address) {
175                                 BT_ERR_C("Unexpected: address is NULL");
176                                 continue;
177                         }
178
179                         BT_DBG("BT_GET_CONNECTED_LINK_TYPE for [%s] found", address);
180                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
181                         rem_info = _bt_service_get_remote_dev_info(address);
182                         if (rem_info) {
183                                 result = BLUETOOTH_ERROR_NONE;
184                                 g_array_append_vals(out_param, &(rem_info->connected),
185                                                 sizeof(bluetooth_connected_link_t));
186                         }
187                         else if (_bt_find_remote_gatt_client_info(address) || _bt_find_remote_gatt_server_info(address)) {
188                                 bluetooth_connected_link_t value = BLUETOOTH_CONNECTED_LINK_LE;
189                                 result = BLUETOOTH_ERROR_NONE;
190                                 g_array_append_vals(out_param, &(value),
191                                                 sizeof(bluetooth_connected_link_t));
192                         }
193                         else {
194                                 BT_DBG("Device not found in paired list \n Device not found in the LE devices list");
195                                 result = BLUETOOTH_ERROR_NOT_FOUND;
196                         }
197
198                         _bt_service_method_return(req_info->context, out_param, result);
199                         _bt_free_info_from_invocation_list(req_info);
200                         g_array_free(out_param, TRUE);
201                         break;
202                 }
203                 default:
204                         BT_ERR_C("Unknown service function %d", service_function);
205                 }
206         }
207 }
208
209 static void __bt_service_fetch_dev_info_for_bonded_addr_list(void)
210 {
211         unsigned int count = g_slist_length(bonded_addr_list);
212
213         BT_DBG("+");
214
215         BT_INFO("bonded_list_index: %d", bonded_list_index);
216         for (; bonded_list_index < count; bonded_list_index++) {
217                 GSList *l = g_slist_nth(bonded_addr_list, bonded_list_index);
218                 bluetooth_device_address_t *dev_addr = l->data;
219
220                 if (!dev_addr)
221                         continue;
222
223                 if (BLUETOOTH_ERROR_NONE != _bt_device_get_bonded_device_info(dev_addr)) {
224                         char address[BT_ADDRESS_STRING_SIZE];
225                         _bt_convert_addr_type_to_string(address, dev_addr->addr);
226                         BT_ERR("_bt_device_get_bonded_device_info Failed for [%s]", address);
227                         continue;
228                 }
229                 return;
230         }
231
232         /* Retrieval of bonded device list completed */
233         bonded_list_index = 0;
234         bonded_list_retrieved = TRUE;
235         g_slist_free_full(bonded_addr_list, g_free);
236         bonded_addr_list = NULL;
237
238         /* Send reply if request for BT_GET_BONDED_DEVICES is pending */
239         __bt_handle_pending_request(
240                         BLUETOOTH_ERROR_NONE, BT_GET_BONDED_DEVICES);
241
242         /* Send reply if request for BT_GET_BONDED_DEVICE is pending */
243         __bt_handle_pending_request(
244                         BLUETOOTH_ERROR_NONE, BT_GET_BONDED_DEVICE);
245
246         __bt_handle_pending_request(
247                         BLUETOOTH_ERROR_NONE, BT_GET_IS_ALIAS_SET);
248         __bt_handle_pending_request(
249                         BLUETOOTH_ERROR_NONE, BT_GET_CONNECTED_LINK_TYPE);
250         BT_DBG("-");
251 }
252
253 static void __bt_update_connected_status(bt_remote_dev_info_t *rem_info, gboolean connected, unsigned char type)
254 {
255         BT_DBG("+");
256
257         if (connected) {
258                 if (0 == type) {
259                         switch (rem_info->connected) {
260                         case BLUETOOTH_CONNECTED_LINK_NONE:
261                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_BREDR;
262                                 break;
263                         case BLUETOOTH_CONNECTED_LINK_LE:
264                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_BREDR_LE;
265                                 break;
266                         default:
267                                 BT_ERR_C("rem_info->connected is already set to desired value: %d",
268                                                 rem_info->connected);
269                         }
270                 } else {
271                         switch (rem_info->connected) {
272                         case BLUETOOTH_CONNECTED_LINK_NONE:
273                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_LE;
274                                 break;
275                         case BLUETOOTH_CONNECTED_LINK_BREDR:
276                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_BREDR_LE;
277                                 break;
278                         default:
279                                 BT_ERR_C("rem_info->connected is already set to desired value: %d",
280                                                 rem_info->connected);
281                         }
282                 }
283         } else {
284                 if (0 == type) {
285                         switch (rem_info->connected) {
286                         case BLUETOOTH_CONNECTED_LINK_BREDR:
287                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_NONE;
288                                 break;
289                         case BLUETOOTH_CONNECTED_LINK_BREDR_LE:
290                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_LE;
291                                 break;
292                         default:
293                                 BT_ERR_C("rem_info->connected is already set to desired value: %d",
294                                                 rem_info->connected);
295                         }
296                 } else {
297                         switch (rem_info->connected) {
298                         case BLUETOOTH_CONNECTED_LINK_LE:
299                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_NONE;
300                                 break;
301                         case BLUETOOTH_CONNECTED_LINK_BREDR_LE:
302                                 rem_info->connected = BLUETOOTH_CONNECTED_LINK_BREDR;
303                                 break;
304                         default:
305                                 BT_ERR_C("rem_info->connected is already set to desired value: %d",
306                                                 rem_info->connected);
307                         }
308                 }
309         }
310
311         BT_DBG("-");
312 }
313
314 void _bt_update_remote_dev_property(
315                 const char *address, bt_device_prop_type_e type, void *value)
316 {
317         bt_remote_dev_info_t *rem_info;
318
319         BT_DBG("Property type: %d", type);
320         rem_info = _bt_service_get_remote_dev_info(address);
321         ret_if(NULL == rem_info);
322
323         switch (type) {
324         case DEV_PROP_CONNECTED: {
325                 bt_device_conn_info_t *conn_info = value;
326
327                 __bt_update_connected_status(
328                         rem_info, conn_info->connected, conn_info->type);
329                 break;
330         }
331         case DEV_PROP_NAME: {
332                 char *name = value;
333
334                 if (name && strlen(name) > 0) {
335                         g_free(rem_info->name);
336                         rem_info->name = g_strdup(name);
337                 }
338                 break;
339         }
340         case DEV_PROP_ALIAS: {
341                 char *alias = value;
342
343                 g_free(rem_info->alias);
344                 rem_info->alias = NULL;
345                 rem_info->is_alias_set = FALSE;
346
347                 if (alias && strlen(alias) > 0) {
348                         rem_info->alias = g_strdup(alias);
349                         rem_info->is_alias_set = TRUE;
350                 }
351                 break;
352         }
353         case DEV_PROP_TRUST: {
354                 gboolean *trusted = value;
355                 rem_info->trust = *trusted;
356                 break;
357         }
358         case DEV_PROP_SERVICES: {
359                 bt_remote_dev_info_t *src = value;
360
361                 if (src->uuid_count > 0 && src->uuids) {
362                         int i;
363
364                         /* Release previously allocated UUIDs */
365                         if (rem_info->uuid_count > 0 && rem_info->uuids)
366                                 for (i = 0; i < rem_info->uuid_count; i++)
367                                         g_free(rem_info->uuids[i]);
368                         g_free(rem_info->uuids);
369
370                         /* Copy new UUID list */
371                         rem_info->uuids = g_malloc0(src->uuid_count * sizeof(char *));
372                         for (i = 0; i < src->uuid_count; i++)
373                                 rem_info->uuids[i] = g_strdup(src->uuids[i]);
374
375                         rem_info->uuid_count = src->uuid_count;
376                         BT_DBG("UUID count: %d", rem_info->uuid_count);
377                 }
378                 break;
379         }
380         default:
381                 BT_DBG("Unknown property");
382                 return;
383         }
384
385 }
386
387 void _bt_service_add_device_to_bonded_list(bt_remote_dev_info_t *rem_info)
388 {
389         bt_remote_dev_info_t *dev_info;
390
391         ret_if(NULL == rem_info);
392
393         dev_info = _bt_service_get_remote_dev_info(rem_info->address);
394         if (!dev_info) {
395                 BT_DBG("Device info not present, allocate memory");
396                 dev_info = g_malloc0(sizeof(bt_remote_dev_info_t));
397                 paired_list = g_slist_append(paired_list, dev_info);
398         }
399
400         _bt_copy_remote_dev_info(dev_info, rem_info);
401
402         if (!bonded_list_retrieved) {
403                 char addr_str[BT_ADDRESS_STRING_SIZE];
404                 bluetooth_device_address_t *dev_addr;
405                 GSList *l;
406
407                 l = g_slist_nth(bonded_addr_list, bonded_list_index);
408                 if (!l) {
409                         BT_ERR_C("l is NULL unexpectedly, need to check");
410                         return;
411                 }
412
413                 dev_addr = l->data;
414                 if (!dev_addr) {
415                         BT_ERR_C("dev_addr is NULL unexpectedly, need to check");
416                         return;
417                 }
418
419                 _bt_convert_addr_type_to_string(addr_str, dev_addr->addr);
420                 if (!strncasecmp(addr_str, rem_info->address, BT_ADDRESS_STRING_SIZE)) {
421                         bonded_list_index++;
422                         __bt_service_fetch_dev_info_for_bonded_addr_list();
423                 }
424         }
425
426 }
427
428 void _bt_service_remove_device_from_bonded_list(const char *address)
429 {
430         bt_remote_dev_info_t *rem_info;
431
432         BT_DBG("+");
433         ret_if(NULL == address);
434
435         rem_info = _bt_service_get_remote_dev_info(address);
436         if (!rem_info) {
437                 BT_DBG("Device not found in list");
438                 return;
439         }
440
441         paired_list = g_slist_remove(paired_list, rem_info);
442         _bt_free_remote_dev(rem_info);
443         BT_DBG("-");
444 }
445
446 void _bt_device_handle_paired_address_list(bluetooth_device_address_t *addr_list, int count)
447 {
448         int indx;
449
450         BT_DBG("+");
451
452         if (bonded_list_retrieved) {
453                 BT_ERR_C("Unexpected bonded address list received");
454                 return;
455         }
456
457         if (0 == count) {
458                 BT_DBG("No paired device found");
459                 bonded_list_index = 0;
460                 bonded_list_retrieved = TRUE;
461                 return;
462         }
463
464         ret_if(NULL == addr_list);
465
466         for (indx = 0; indx < count; indx++) {
467                 bluetooth_device_address_t *dev_addr;
468
469                 dev_addr = g_memdup(&(addr_list[indx]), sizeof(bluetooth_device_address_t));
470                 bonded_addr_list = g_slist_append(bonded_addr_list, dev_addr);
471         }
472
473         __bt_service_fetch_dev_info_for_bonded_addr_list();
474         BT_DBG("-");
475 }
476
477 static gboolean __check_bonded_devices(gpointer data)
478 {
479         BT_DBG("+");
480
481         retv_if(bonded_list_retrieved, FALSE);
482
483         /* Bonded devices are not yet retrived, retry */
484         if (BLUETOOTH_ERROR_NONE != _bt_adapter_get_bonded_devices())
485                 BT_ERR_C("_bt_adapter_get_bonded_devices failed");
486
487         BT_DBG("-");
488         return TRUE;
489 }
490
491 void _bt_device_handle_adapter_state(gboolean enabled)
492 {
493         BT_DBG("+");
494
495         if (!enabled) {
496                 BT_DBG("Adapter disabled");
497                 g_slist_free_full(paired_list, _bt_free_paired_dev);
498                 paired_list = NULL;
499                 bonded_list_retrieved = FALSE;
500                 return;
501         }
502
503         if (BLUETOOTH_ERROR_NONE != _bt_adapter_get_bonded_devices())
504                 BT_ERR_C("_bt_adapter_get_bonded_devices failed");
505
506         g_timeout_add_seconds(5, __check_bonded_devices, NULL);
507         BT_DBG("-");
508 }
509
510 static gboolean __reply_pending_request(gpointer data)
511 {
512         int *request = data;
513
514         BT_INFO("Request: %d", *request);
515         __bt_handle_pending_request(BLUETOOTH_ERROR_NONE, *request);
516         g_free(request);
517         return FALSE;
518 }
519
520 int _bt_get_bonded_device_info(bluetooth_device_address_t *dev_addr)
521 {
522         char address[BT_ADDRESS_STRING_SIZE];
523         bt_remote_dev_info_t *rem_info;
524         int request = BT_GET_BONDED_DEVICE;
525
526         BT_DBG("+");
527
528         retv_if(!dev_addr, BLUETOOTH_ERROR_INVALID_PARAM);
529
530         if (!bonded_list_retrieved) {
531                 /*
532                  * Blonded list retrival is in progress, return BLUETOOTH_ERROR_NONE here.
533                  * reply will be sent once bonded list is retrieved completely.
534                  */
535                 return BLUETOOTH_ERROR_NONE;
536         }
537
538         _bt_convert_addr_type_to_string(address, dev_addr->addr);
539
540         rem_info = _bt_service_get_remote_dev_info(address);
541         if (!rem_info) {
542                 BT_ERR("Bonded device not found in the list, return error");
543                 return BLUETOOTH_ERROR_NOT_PAIRED;
544         }
545
546         g_idle_add(__reply_pending_request, g_memdup(&request, sizeof(int)));
547         BT_DBG("-");
548         return BLUETOOTH_ERROR_NONE;
549 }
550
551 int _bt_get_bonded_devices(void)
552 {
553         int request = BT_GET_BONDED_DEVICES;
554
555         BT_DBG("+");
556         if (!bonded_list_retrieved) {
557                 /*
558                  * Blonded list retrival is in progress, return BLUETOOTH_ERROR_NONE here.
559                  * reply will be sent once bonded list is retrieved completely.
560                  */
561                 return BLUETOOTH_ERROR_NONE;
562         }
563
564         g_idle_add(__reply_pending_request, g_memdup(&request, sizeof(int)));
565         BT_DBG("-");
566         return BLUETOOTH_ERROR_NONE;
567 }
568
569 int _bt_is_alias_set(bluetooth_device_address_t *device_address)
570 {
571         char address[BT_ADDRESS_STRING_SIZE];
572         bt_remote_dev_info_t *rem_info;
573         int request = BT_GET_IS_ALIAS_SET;
574
575         BT_DBG("+");
576         if (!bonded_list_retrieved) {
577                 /*
578                  * Blonded list retrival is in progress, return BLUETOOTH_ERROR_NONE here.
579                  * reply will be sent once bonded list is retrieved completely.
580                  */
581                 return BLUETOOTH_ERROR_NONE;
582         }
583
584         _bt_convert_addr_type_to_string(address, device_address->addr);
585         rem_info = _bt_service_get_remote_dev_info(address);
586         if (!rem_info) {
587                 BT_ERR("Bonded device not found in the list, return error");
588                 return BLUETOOTH_ERROR_NOT_PAIRED;
589         }
590
591         g_idle_add(__reply_pending_request, g_memdup(&request, sizeof(int)));
592         BT_DBG("-");
593         return BLUETOOTH_ERROR_NONE;
594 }
595
596 int _bt_get_connected_link(bluetooth_device_address_t *device_address)
597 {
598         int request = BT_GET_CONNECTED_LINK_TYPE;
599
600         BT_DBG("+");
601         if (!bonded_list_retrieved) {
602                 /*
603                  * Blonded list retrival is in progress, return BLUETOOTH_ERROR_NONE here.
604                  * reply will be sent once bonded list is retrieved completely.
605                  */
606                 return BLUETOOTH_ERROR_NONE;
607         }
608
609         g_idle_add(__reply_pending_request, g_memdup(&request, sizeof(int)));
610         BT_DBG("-");
611         return BLUETOOTH_ERROR_NONE;
612 }
613
614 gboolean _bt_is_bonded_devices_retrived(void)
615 {
616         return bonded_list_retrieved;
617 }