2 * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <gio/gunixfdlist.h>
20 #include <sys/socket.h>
22 #include "bluetooth-api.h"
23 #include "bt-internal-types.h"
25 #include "bt-common.h"
26 #include "bt-request-sender.h"
27 #include "bt-event-handler.h"
29 /* Variable for privilege, only for write API,
30 before we should reduce time to bt-service dbus calling
31 -1 : Don't have a permission to access API
32 0 : Initial value, not yet check
33 1 : Have a permission to access API
35 static int privilege_token;
37 GSList *l2cap_le_clients;
44 } l2cap_le_client_conn_info_t;
46 static gboolean __is_error_by_disconnect(GError *err)
48 return !g_strcmp0(err->message, "Connection reset by peer") ||
49 !g_strcmp0(err->message, "Connection timed out") ||
50 !g_strcmp0(err->message, "Software caused connection abort");
53 static l2cap_le_client_conn_info_t *__find_l2cap_le_conn_info_with_fd(int fd)
59 for (l = l2cap_le_clients; l != NULL; l = l->next) {
60 l2cap_le_client_conn_info_t *info = l->data;
62 if (info && info->sock_fd == fd) {
63 BT_INFO("Match found");
72 static void __l2cap_le_remove_client_conn_info_t(
73 l2cap_le_client_conn_info_t *info)
77 l2cap_le_clients = g_slist_remove(l2cap_le_clients, info);
78 g_free(info->remote_addr);
80 if (info->sock_fd > 0) {
81 shutdown(info->sock_fd, SHUT_RDWR);
85 if (info->watch_id > 0)
86 g_source_remove(info->watch_id);
90 static void __bt_l2cap_le_client_disconnected(
91 l2cap_le_client_conn_info_t *conn_info)
93 bluetooth_l2cap_le_disconnection_t disconn_info;
94 bt_event_info_t *event_info = NULL;
98 ret_if(conn_info == NULL);
100 event_info = _bt_event_get_cb_data(BT_L2CAP_LE_CLIENT_EVENT);
101 ret_if(event_info == NULL);
103 memset(&disconn_info, 0x00, sizeof(bluetooth_l2cap_le_disconnection_t));
104 disconn_info.device_role = L2CAP_LE_ROLE_CLIENT;
105 disconn_info.socket_fd = conn_info->sock_fd;
106 disconn_info.psm = conn_info->psm;
107 _bt_convert_addr_string_to_type(disconn_info.device_addr.addr,
108 conn_info->remote_addr);
110 BT_INFO("Disconnection Result[%d] BT_ADDRESS[%s] FD[%d] PSM[%d]",
111 BLUETOOTH_ERROR_NONE, conn_info->remote_addr,
112 conn_info->sock_fd, conn_info->psm);
113 _bt_common_event_cb(BLUETOOTH_EVENT_L2CAP_LE_DISCONNECTED,
114 BLUETOOTH_ERROR_NONE, &disconn_info,
115 event_info->cb, event_info->user_data);
120 static gboolean __client_data_received_cb(GIOChannel *chan, GIOCondition cond,
123 bt_event_info_t *event_info;
124 bluetooth_l2cap_le_received_data_t data_r;
125 l2cap_le_client_conn_info_t *conn_info;
130 GIOStatus status = G_IO_STATUS_NORMAL;
131 static int resource_unavailable_cnt = 0;
135 fd = g_io_channel_unix_get_fd(chan);
136 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
137 BT_ERR_C("L2cap_le Client disconnected: %d", fd);
141 buffer = g_malloc0(BT_L2CAP_LE_BUFFER_LEN + 1);
142 g_io_channel_set_buffer_size(chan, BT_L2CAP_LE_BUFFER_LEN);
143 status = g_io_channel_read_chars(chan, buffer, BT_L2CAP_LE_BUFFER_LEN,
145 if (status != G_IO_STATUS_NORMAL) {
146 BT_ERR("IO Channel read is failed with %d", status);
149 BT_ERR("IO Channel read error [%s]", err->message);
150 if (status == G_IO_STATUS_ERROR &&
151 __is_error_by_disconnect(err)) {
152 BT_ERR("cond : %d", cond);
159 if (status == G_IO_STATUS_ERROR ||
160 status == G_IO_STATUS_EOF) {
162 } else if (status == G_IO_STATUS_AGAIN) {
163 resource_unavailable_cnt++;
164 if (resource_unavailable_cnt > 10)
170 resource_unavailable_cnt = 0;
173 BT_ERR("Length is zero, remote end hang up");
178 BT_DBG("fd: %d, len: %zd, buffer: %s", fd, len, buffer);
180 event_info = _bt_event_get_cb_data(BT_L2CAP_LE_CLIENT_EVENT);
181 if (event_info == NULL) {
182 BT_INFO("event_info == NULL");
187 data_r.socket_fd = fd;
188 data_r.buffer_size = len;
189 data_r.buffer = buffer;
191 _bt_common_event_cb(BLUETOOTH_EVENT_L2CAP_LE_DATA_RECEIVED,
192 BLUETOOTH_ERROR_NONE, &data_r,
193 event_info->cb, event_info->user_data);
199 conn_info = __find_l2cap_le_conn_info_with_fd(fd);
201 BT_INFO("Disconnecting client, fd %d", fd);
202 __bt_l2cap_le_client_disconnected(conn_info);
203 __l2cap_le_remove_client_conn_info_t(conn_info);
205 BT_ERR("l2cap_le client conn_info not found");
212 static void __l2cap_le_client_connection_create_watch(
213 l2cap_le_client_conn_info_t *conn_info)
219 ret_if(NULL == conn_info);
221 data_io = g_io_channel_unix_new(conn_info->sock_fd);
222 g_io_channel_set_encoding(data_io, NULL, NULL);
223 g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
224 conn_info->watch_id = g_io_add_watch(data_io,
225 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
226 __client_data_received_cb, NULL);
227 g_io_channel_unref(data_io);
232 static void __bt_l2cap_le_handle_new_client_connection(
233 bluetooth_l2cap_le_connection_t *info)
235 l2cap_le_client_conn_info_t *conn_info;
239 ret_if(NULL == info);
241 conn_info = g_malloc0(sizeof(l2cap_le_client_conn_info_t));
242 conn_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
243 _bt_convert_addr_type_to_string(
244 conn_info->remote_addr, info->device_addr.addr);
245 conn_info->sock_fd = info->socket_fd;
246 conn_info->psm = info->psm;
248 BT_INFO("Address:%s, Socket: %d, psm: %d",
249 conn_info->remote_addr, conn_info->sock_fd, conn_info->psm);
251 l2cap_le_clients = g_slist_append(l2cap_le_clients, conn_info);
252 __l2cap_le_client_connection_create_watch(conn_info);
257 static void __async_req_cb_with_unix_fd_list(GDBusProxy *proxy,
258 GAsyncResult *res, gpointer user_data)
260 int result = BLUETOOTH_ERROR_NONE;
261 int event_type = BT_LE_ADAPTER_EVENT;
262 gboolean fail = false;
264 bt_req_info_t *cb_data = user_data;
265 bluetooth_event_param_t bt_event;
266 GArray *out_param1 = NULL;
267 GUnixFDList *out_fd_list = NULL;
268 bt_l2cap_user_info_t *l2cap_user_info = NULL;
273 l2cap_user_info = (bt_l2cap_user_info_t *)cb_data->user_data;
276 cb_data->user_data = (void *)l2cap_user_info->user_data;
278 _bt_get_fd_list_info(proxy, res, user_data, &bt_event, &out_param1,
279 &event_type, &out_fd_list, &result, &fail);
282 BT_INFO("Connection failed due to error: %d", result);
283 bluetooth_l2cap_le_connection_t *conn_info;
285 conn_info = g_malloc0(sizeof(bluetooth_l2cap_le_connection_t));
286 memset(conn_info, 0x00, sizeof(bluetooth_l2cap_le_connection_t));
288 if (l2cap_user_info) {
289 conn_info->psm = l2cap_user_info->psm;
290 memcpy(&conn_info->device_addr, &l2cap_user_info->device_addr,
291 sizeof(bluetooth_device_address_t));
294 bt_event.param_data = (void *)conn_info;
301 if (result == BLUETOOTH_ERROR_NONE && out_param1) {
302 if (BT_L2CAP_LE_CLIENT_CONNECT == cb_data->service_function) {
305 bluetooth_l2cap_le_connection_t *conn_info;
307 conn_info = (bluetooth_l2cap_le_connection_t *)bt_event.param_data;
309 BT_ERR("out_fd_list is NULL");
313 fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len);
314 BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]);
315 conn_info->socket_fd = fd_list_array[0];
317 BT_INFO("conn_info->socket_fd: %d", conn_info->socket_fd);
318 __bt_l2cap_le_handle_new_client_connection(conn_info);
320 if (cb_data->cb != NULL) {
321 /* Send client connected event */
322 bt_event.result = result;
323 BT_INFO("send client connected event event_type[%d], result=[%d]", event_type, result);
324 ((bluetooth_cb_func_ptr)cb_data->cb)(
325 bt_event.event, &bt_event, cb_data->user_data);
328 g_free(fd_list_array);
329 g_object_unref(out_fd_list);
335 if (cb_data->cb == NULL)
338 /* Only if fail case, call the callback function*/
339 bt_event.result = result;
341 BT_INFO("send fail event event_type[%d], result=[%d]", event_type, result);
342 if (event_type == BT_L2CAP_LE_CLIENT_EVENT) {
343 BT_INFO("l2cap_le client event");
344 ((bluetooth_cb_func_ptr)cb_data->cb)(bt_event.event,
345 &bt_event, cb_data->user_data);
347 BT_INFO("Not handled event type : %d", event_type);
351 g_array_free(out_param1, TRUE);
353 g_free(l2cap_user_info);
358 BT_EXPORT_API int bluetooth_l2cap_le_connect(
359 const bluetooth_device_address_t *remote_bt_address, int psm)
362 bt_user_info_t *user_info;
364 bt_l2cap_user_info_t *l2cap_user_info;
366 BT_CHECK_PARAMETER(remote_bt_address, return);
367 BT_CHECK_ENABLED_LE(return);
369 BT_INFO_C("connect l2cap_le psm %d", psm);
370 user_info = _bt_get_user_data(BT_COMMON);
371 retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
374 if (_bt_check_privilege_le(BT_CHECK_PRIVILEGE, BT_L2CAP_LE_CLIENT_CONNECT)
375 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
376 BT_ERR("Don't have a privilege to use this API");
379 l2cap_user_info = g_malloc0(sizeof(bt_l2cap_user_info_t));
380 l2cap_user_info->psm = psm;
381 l2cap_user_info->user_data = user_info->user_data;
382 memcpy(&l2cap_user_info->device_addr, remote_bt_address,
383 sizeof(bluetooth_device_address_t));
386 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
388 g_array_append_vals(in_param1, remote_bt_address,
389 sizeof(bluetooth_device_address_t));
392 g_array_append_vals(in_param2, &t_psm, sizeof(int));
394 result = _bt_send_request_async_with_unix_fd_list(BT_BLUEZ_SERVICE,
395 BT_L2CAP_LE_CLIENT_CONNECT,
396 in_param1, in_param2,
397 in_param3, in_param4,
398 user_info->cb, (void *)l2cap_user_info,
399 NULL, (GAsyncReadyCallback)__async_req_cb_with_unix_fd_list);
401 BT_INFO("result: %x", result);
403 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
408 BT_EXPORT_API int bluetooth_l2cap_le_client_is_connected(
409 const bluetooth_device_address_t *device_address, gboolean *connected)
412 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
414 BT_CHECK_PARAMETER(device_address, return);
415 BT_CHECK_PARAMETER(connected, return);
420 _bt_convert_addr_type_to_string(address, (unsigned char *)device_address->addr);
421 BT_INFO("Client address: [%s]", address);
423 for (l = l2cap_le_clients; l != NULL; l = l->next) {
424 l2cap_le_client_conn_info_t *info = l->data;
426 if (info && !strncasecmp(info->remote_addr, address, BT_ADDRESS_STRING_SIZE)) {
427 BT_INFO("Match found");
429 return BLUETOOTH_ERROR_NONE;
434 return BLUETOOTH_ERROR_NONE;
437 BT_EXPORT_API int bluetooth_l2cap_le_disconnect(int socket_fd)
439 l2cap_le_client_conn_info_t *conn_info;
441 BT_INFO_C("<<<<<<<<< L2CAP_LE Disconnect request from app >>>>>>>>");
443 BT_CHECK_ENABLED_ANY(return);
444 retv_if(socket_fd < 0, BLUETOOTH_ERROR_INVALID_PARAM);
446 if (_bt_check_privilege_le(BT_CHECK_PRIVILEGE, BT_L2CAP_LE_SOCKET_DISCONNECT)
447 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
448 BT_ERR("Don't have a privilege to use this API");
451 BT_INFO("FD %d", socket_fd);
453 conn_info = __find_l2cap_le_conn_info_with_fd(socket_fd);
454 if (conn_info == NULL) {
455 BT_INFO("Could not find in client, so check in server");
456 /* Check for fd in server list and perform the disconnection if present */
457 return bluetooth_l2cap_le_server_disconnect(socket_fd);
460 if (conn_info->watch_id <= 0) {
461 BT_ERR("Invalid state");
462 return BLUETOOTH_ERROR_NOT_CONNECTED;
465 __bt_l2cap_le_client_disconnected(conn_info);
466 __l2cap_le_remove_client_conn_info_t(conn_info);
468 return BLUETOOTH_ERROR_NONE;
471 static int __write_all(int fd, const char *buf, int len)
473 int sent = 0, try = 0;
479 written = write(fd, buf, len);
480 BT_DBG("written: %d, len %d", written, len);
482 if (errno == EINTR || errno == EAGAIN) {
503 BT_EXPORT_API int bluetooth_l2cap_le_write(int fd, const char *buf, int length)
507 BT_CHECK_ENABLED_LE(return);
508 BT_CHECK_PARAMETER(buf, return);
511 BT_ERR("Invalid FD");
512 return BLUETOOTH_ERROR_INVALID_PARAM;
515 retv_if(length <= 0, BLUETOOTH_ERROR_INVALID_PARAM);
517 switch (privilege_token) {
519 result = _bt_check_privilege_le(BT_CHECK_PRIVILEGE, BT_L2CAP_LE_SOCKET_WRITE);
521 if (result == BLUETOOTH_ERROR_NONE) {
522 privilege_token = 1; /* Have a permission */
523 } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
524 BT_ERR("Don't have a privilege to use this API");
525 privilege_token = -1; /* Don't have a permission */
526 return BLUETOOTH_ERROR_PERMISSION_DEINED;
528 BT_ERR("Some error occurred");
529 /* Just break - It is not related with permission error */
533 /* Already have a privilege */
536 return BLUETOOTH_ERROR_PERMISSION_DEINED;
538 /* Invalid privilge token value */
539 return BLUETOOTH_ERROR_INTERNAL;
542 result = __write_all(fd, buf, length);
547 BT_EXPORT_API int bluetooth_l2cap_le_get_max_buffer_size(int *size)
549 BT_CHECK_ENABLED_LE(return);
550 BT_CHECK_PARAMETER(size, return);
552 *size = BT_L2CAP_LE_BUFFER_LEN;
554 return BLUETOOTH_ERROR_NONE;