diff -Nru bluez-5.63/acinclude.m4 bluez-5.64/acinclude.m4 --- bluez-5.63/acinclude.m4 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/acinclude.m4 2022-03-16 15:06:19.000000000 +0000 @@ -71,13 +71,13 @@ AC_DEFUN([MISC_FLAGS], [ misc_cflags="" misc_ldflags="" - AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], + AC_ARG_ENABLE(optimization, AS_HELP_STRING([--disable-optimization], [disable code optimization through compiler]), [ if (test "${enableval}" = "no"); then misc_cflags="$misc_cflags -O0" fi ]) - AC_ARG_ENABLE(asan, AC_HELP_STRING([--enable-asan], + AC_ARG_ENABLE(asan, AS_HELP_STRING([--enable-asan], [enable linking with address sanitizer]), [ save_LIBS=$LIBS AC_CHECK_LIB(asan, _init) @@ -90,7 +90,7 @@ AC_SUBST([ASAN_LIB], ${ac_cv_lib_asan__init}) fi ]) - AC_ARG_ENABLE(lsan, AC_HELP_STRING([--enable-lsan], + AC_ARG_ENABLE(lsan, AS_HELP_STRING([--enable-lsan], [enable linking with address sanitizer]), [ save_LIBS=$LIBS AC_CHECK_LIB(lsan, _init) @@ -103,7 +103,7 @@ AC_SUBST([ASAN_LIB], ${ac_cv_lib_lsan__init}) fi ]) - AC_ARG_ENABLE(ubsan, AC_HELP_STRING([--enable-ubsan], + AC_ARG_ENABLE(ubsan, AS_HELP_STRING([--enable-ubsan], [enable linking with address sanitizer]), [ save_LIBS=$LIBS AC_CHECK_LIB(ubsan, _init) @@ -115,14 +115,14 @@ misc_ldflags="$misc_ldflags -fsanitize=undefined"; fi ]) - AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], + AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [enable compiling with debugging information]), [ if (test "${enableval}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then misc_cflags="$misc_cflags -g" fi ]) - AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie], + AC_ARG_ENABLE(pie, AS_HELP_STRING([--enable-pie], [enable position independent executables flag]), [ if (test "${enableval}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then diff -Nru bluez-5.63/android/a2dp.c bluez-5.64/android/a2dp.c --- bluez-5.63/android/a2dp.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/android/a2dp.c 2022-03-16 15:06:19.000000000 +0000 @@ -26,6 +26,7 @@ #include "lib/sdp_lib.h" #include "profiles/audio/a2dp-codecs.h" #include "src/shared/queue.h" +#include "src/shared/util.h" #include "src/log.h" #include "hal-msg.h" #include "ipc-common.h" @@ -428,7 +429,7 @@ p = g_new0(struct a2dp_preset, 1); p->len = conf_len; - p->data = g_memdup(conf, p->len); + p->data = util_memdup(conf, p->len); return p; } @@ -448,7 +449,7 @@ p = g_new0(struct a2dp_preset, 1); p->len = conf_len; - p->data = g_memdup(conf, p->len); + p->data = util_memdup(conf, p->len); return p; } @@ -1036,7 +1037,7 @@ preset = g_new0(struct a2dp_preset, 1); preset->len = cap->length - sizeof(*codec); - preset->data = g_memdup(codec->data, preset->len); + preset->data = util_memdup(codec->data, preset->len); if (check_config(endpoint, preset) < 0) { preset_free(preset); @@ -1365,7 +1366,7 @@ preset = g_new0(struct a2dp_preset, 1); preset->len = p->len; - preset->data = g_memdup(p->data, preset->len); + preset->data = util_memdup(p->data, preset->len); l = g_slist_append(l, preset); len -= preset->len; diff -Nru bluez-5.63/android/avctp.c bluez-5.64/android/avctp.c --- bluez-5.63/android/avctp.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/android/avctp.c 2022-03-16 15:06:19.000000000 +0000 @@ -31,6 +31,7 @@ #include #include "lib/sdp.h" +#include "src/shared/util.h" #include "src/log.h" #include "avctp.h" @@ -1177,7 +1178,7 @@ for (i = 0; i < iov_cnt; i++) { pdu[i].iov_len = iov[i].iov_len; - pdu[i].iov_base = g_memdup(iov[i].iov_base, iov[i].iov_len); + pdu[i].iov_base = util_memdup(iov[i].iov_base, iov[i].iov_len); } req = g_new0(struct avctp_control_req, 1); @@ -1218,7 +1219,7 @@ for (i = 0; i < iov_cnt; i++) { pdu[i].iov_len = iov[i].iov_len; - pdu[i].iov_base = g_memdup(iov[i].iov_base, iov[i].iov_len); + pdu[i].iov_base = util_memdup(iov[i].iov_base, iov[i].iov_len); } req = g_new0(struct avctp_browsing_req, 1); diff -Nru bluez-5.63/android/avrcp-lib.c bluez-5.64/android/avrcp-lib.c --- bluez-5.63/android/avrcp-lib.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/android/avrcp-lib.c 2022-03-16 15:06:19.000000000 +0000 @@ -2620,7 +2620,7 @@ return NULL; } - folders[count] = g_memdup(¶ms[i], len); + folders[count] = util_memdup(¶ms[i], len); i += len; } diff -Nru bluez-5.63/android/gatt.c bluez-5.64/android/gatt.c --- bluez-5.63/android/gatt.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/android/gatt.c 2022-03-16 15:06:19.000000000 +0000 @@ -1338,7 +1338,8 @@ } bt_uuid_to_uuid128(&uuid, &u128); - new_uuid = g_memdup(&u128.value.u128, sizeof(u128.value.u128)); + new_uuid = util_memdup(&u128.value.u128, + sizeof(u128.value.u128)); uuids = g_slist_prepend(uuids, new_uuid); } @@ -6633,7 +6634,7 @@ queue_push_tail(dev->pending_requests, data); - data->value = g_memdup(value, vlen); + data->value = util_memdup(value, vlen); data->length = vlen; if (!gatt_db_attribute_write(attrib, offset, value, vlen, cmd[0], diff -Nru bluez-5.63/android/hidhost.c bluez-5.64/android/hidhost.c --- bluez-5.63/android/hidhost.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/android/hidhost.c 2022-03-16 15:06:19.000000000 +0000 @@ -689,7 +689,8 @@ goto fail; dev->rd_size = data->unitSize; - dev->rd_data = g_memdup(data->val.str, data->unitSize); + dev->rd_data = util_memdup(data->val.str, + data->unitSize); } } diff -Nru bluez-5.63/android/tester-main.c bluez-5.64/android/tester-main.c --- bluez-5.63/android/tester-main.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/android/tester-main.c 2022-03-16 15:06:20.000000000 +0000 @@ -1253,7 +1253,8 @@ for (i = 0; i < num_properties; i++) { props[i].type = properties[i].type; props[i].len = properties[i].len; - props[i].val = g_memdup(properties[i].val, properties[i].len); + props[i].val = util_memdup(properties[i].val, + properties[i].len); } return props; @@ -1268,7 +1269,8 @@ for (i = 0; i < num_properties; i++) { props[i].type = properties[i]->type; props[i].len = properties[i]->len; - props[i].val = g_memdup(properties[i]->val, properties[i]->len); + props[i].val = util_memdup(properties[i]->val, + properties[i]->len); } return props; @@ -1281,7 +1283,7 @@ prop->type = type; prop->len = len; - prop->val = g_memdup(val, len); + prop->val = util_memdup(val, len); return prop; } @@ -1615,7 +1617,7 @@ step->callback = CB_GATTC_SEARCH_RESULT; step->callback_result.conn_id = conn_id; - step->callback_result.service = g_memdup(srvc_id, sizeof(*srvc_id)); + step->callback_result.service = util_memdup(srvc_id, sizeof(*srvc_id)); schedule_callback_verification(step); } @@ -1639,8 +1641,8 @@ step->callback = CB_GATTC_GET_CHARACTERISTIC; step->callback_result.status = status; step->callback_result.conn_id = conn_id; - step->callback_result.service = g_memdup(srvc_id, sizeof(*srvc_id)); - step->callback_result.characteristic = g_memdup(char_id, + step->callback_result.service = util_memdup(srvc_id, sizeof(*srvc_id)); + step->callback_result.characteristic = util_memdup(char_id, sizeof(*char_id)); step->callback_result.char_prop = char_prop; @@ -1656,10 +1658,10 @@ step->callback = CB_GATTC_GET_DESCRIPTOR; step->callback_result.status = status; step->callback_result.conn_id = conn_id; - step->callback_result.service = g_memdup(srvc_id, sizeof(*srvc_id)); - step->callback_result.characteristic = g_memdup(char_id, + step->callback_result.service = util_memdup(srvc_id, sizeof(*srvc_id)); + step->callback_result.characteristic = util_memdup(char_id, sizeof(*char_id)); - step->callback_result.descriptor = g_memdup(descr_id, + step->callback_result.descriptor = util_memdup(descr_id, sizeof(*descr_id)); schedule_callback_verification(step); @@ -1673,8 +1675,8 @@ step->callback = CB_GATTC_GET_INCLUDED_SERVICE; step->callback_result.status = status; step->callback_result.conn_id = conn_id; - step->callback_result.service = g_memdup(srvc_id, sizeof(*srvc_id)); - step->callback_result.included = g_memdup(incl_srvc_id, + step->callback_result.service = util_memdup(srvc_id, sizeof(*srvc_id)); + step->callback_result.included = util_memdup(incl_srvc_id, sizeof(*srvc_id)); schedule_callback_verification(step); @@ -1688,7 +1690,8 @@ step->callback = CB_GATTC_READ_CHARACTERISTIC; step->callback_result.status = status; step->callback_result.conn_id = conn_id; - step->callback_result.read_params = g_memdup(p_data, sizeof(*p_data)); + step->callback_result.read_params = util_memdup(p_data, + sizeof(*p_data)); schedule_callback_verification(step); } @@ -1701,7 +1704,8 @@ step->callback = CB_GATTC_READ_DESCRIPTOR; step->callback_result.status = status; step->callback_result.conn_id = conn_id; - step->callback_result.read_params = g_memdup(p_data, sizeof(*p_data)); + step->callback_result.read_params = util_memdup(p_data, + sizeof(*p_data)); schedule_callback_verification(step); } @@ -1714,7 +1718,8 @@ step->callback = CB_GATTC_WRITE_CHARACTERISTIC; step->callback_result.status = status; step->callback_result.conn_id = conn_id; - step->callback_result.write_params = g_memdup(p_data, sizeof(*p_data)); + step->callback_result.write_params = util_memdup(p_data, + sizeof(*p_data)); schedule_callback_verification(step); } @@ -1727,7 +1732,8 @@ step->callback = CB_GATTC_WRITE_DESCRIPTOR; step->callback_result.status = status; step->callback_result.conn_id = conn_id; - step->callback_result.write_params = g_memdup(p_data, sizeof(*p_data)); + step->callback_result.write_params = util_memdup(p_data, + sizeof(*p_data)); schedule_callback_verification(step); } @@ -1742,8 +1748,8 @@ step->callback = CB_GATTC_REGISTER_FOR_NOTIFICATION; step->callback_result.status = status; step->callback_result.conn_id = conn_id; - step->callback_result.service = g_memdup(srvc_id, sizeof(*srvc_id)); - step->callback_result.characteristic = g_memdup(char_id, + step->callback_result.service = util_memdup(srvc_id, sizeof(*srvc_id)); + step->callback_result.characteristic = util_memdup(char_id, sizeof(*char_id)); step->callback_result.notification_registered = registered; @@ -1756,7 +1762,8 @@ step->callback = CB_GATTC_NOTIFY; step->callback_result.conn_id = conn_id; - step->callback_result.notify_params = g_memdup(p_data, sizeof(*p_data)); + step->callback_result.notify_params = util_memdup(p_data, + sizeof(*p_data)); schedule_callback_verification(step); } @@ -1827,8 +1834,8 @@ step->callback_result.status = status; step->callback_result.gatt_app_id = server_if; - step->callback_result.service = g_memdup(srvc_id, sizeof(*srvc_id)); - step->callback_result.srvc_handle = g_memdup(&srvc_handle, + step->callback_result.service = util_memdup(srvc_id, sizeof(*srvc_id)); + step->callback_result.srvc_handle = util_memdup(&srvc_handle, sizeof(srvc_handle)); schedule_callback_verification(step); @@ -1844,9 +1851,9 @@ step->callback_result.status = status; step->callback_result.gatt_app_id = server_if; - step->callback_result.srvc_handle = g_memdup(&srvc_handle, + step->callback_result.srvc_handle = util_memdup(&srvc_handle, sizeof(srvc_handle)); - step->callback_result.inc_srvc_handle = g_memdup(&inc_srvc_handle, + step->callback_result.inc_srvc_handle = util_memdup(&inc_srvc_handle, sizeof(inc_srvc_handle)); schedule_callback_verification(step); @@ -1863,10 +1870,10 @@ step->callback_result.status = status; step->callback_result.gatt_app_id = server_if; - step->callback_result.srvc_handle = g_memdup(&srvc_handle, + step->callback_result.srvc_handle = util_memdup(&srvc_handle, sizeof(srvc_handle)); - step->callback_result.uuid = g_memdup(uuid, sizeof(*uuid)); - step->callback_result.char_handle = g_memdup(&char_handle, + step->callback_result.uuid = util_memdup(uuid, sizeof(*uuid)); + step->callback_result.char_handle = util_memdup(&char_handle, sizeof(char_handle)); schedule_callback_verification(step); @@ -1883,10 +1890,10 @@ step->callback_result.status = status; step->callback_result.gatt_app_id = server_if; - step->callback_result.srvc_handle = g_memdup(&srvc_handle, + step->callback_result.srvc_handle = util_memdup(&srvc_handle, sizeof(srvc_handle)); - step->callback_result.uuid = g_memdup(uuid, sizeof(*uuid)); - step->callback_result.desc_handle = g_memdup(&desc_handle, + step->callback_result.uuid = util_memdup(uuid, sizeof(*uuid)); + step->callback_result.desc_handle = util_memdup(&desc_handle, sizeof(desc_handle)); schedule_callback_verification(step); @@ -1900,7 +1907,7 @@ step->callback_result.status = status; step->callback_result.gatt_app_id = server_if; - step->callback_result.srvc_handle = g_memdup(&srvc_handle, + step->callback_result.srvc_handle = util_memdup(&srvc_handle, sizeof(srvc_handle)); schedule_callback_verification(step); @@ -1914,7 +1921,7 @@ step->callback_result.status = status; step->callback_result.gatt_app_id = server_if; - step->callback_result.srvc_handle = g_memdup(&srvc_handle, + step->callback_result.srvc_handle = util_memdup(&srvc_handle, sizeof(srvc_handle)); schedule_callback_verification(step); @@ -1928,7 +1935,7 @@ step->callback_result.status = status; step->callback_result.gatt_app_id = server_if; - step->callback_result.srvc_handle = g_memdup(&srvc_handle, + step->callback_result.srvc_handle = util_memdup(&srvc_handle, sizeof(srvc_handle)); schedule_callback_verification(step); @@ -1945,7 +1952,7 @@ step->callback_result.conn_id = conn_id; step->callback_result.trans_id = trans_id; - step->callback_result.attr_handle = g_memdup(&attr_handle, + step->callback_result.attr_handle = util_memdup(&attr_handle, sizeof(attr_handle)); step->callback_result.offset = offset; step->callback_result.is_long = is_long; @@ -1974,13 +1981,13 @@ step->callback_result.conn_id = conn_id; step->callback_result.trans_id = trans_id; - step->callback_result.attr_handle = g_memdup(&attr_handle, + step->callback_result.attr_handle = util_memdup(&attr_handle, sizeof(attr_handle)); step->callback_result.offset = offset; step->callback_result.length = length; step->callback_result.need_rsp = need_rsp; step->callback_result.is_prep = is_prep; - step->callback_result.value = g_memdup(&value, length); + step->callback_result.value = util_memdup(&value, length); /* Utilize property verification mechanism for bdaddr */ props[0] = create_property(BT_PROPERTY_BDADDR, bda, sizeof(*bda)); @@ -2169,7 +2176,7 @@ inst[i].id = instances[i].id; inst[i].scn = instances[i].scn; inst[i].msg_types = instances[i].msg_types; - inst[i].p_name = g_memdup(instances[i].p_name, + inst[i].p_name = util_memdup(instances[i].p_name, strlen(instances[i].p_name)); } diff -Nru bluez-5.63/attrib/gatt.c bluez-5.64/attrib/gatt.c --- bluez-5.63/attrib/gatt.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/attrib/gatt.c 2022-03-16 15:06:20.000000000 +0000 @@ -135,7 +135,7 @@ g_slist_free_full(dc->characteristics, g_free); g_attrib_unref(dc->attrib); - g_free(dc->uuid); + free(dc->uuid); g_free(dc); } @@ -157,7 +157,7 @@ g_slist_free_full(dd->descriptors, g_free); g_attrib_unref(dd->attrib); - g_free(dd->uuid); + free(dd->uuid); g_free(dd); } @@ -696,7 +696,7 @@ dc->user_data = user_data; dc->end = end; dc->start = start; - dc->uuid = g_memdup(uuid, sizeof(bt_uuid_t)); + dc->uuid = util_memdup(uuid, sizeof(bt_uuid_t)); dc->id = g_attrib_send(attrib, 0, buf, plen, char_discovered_cb, discover_char_ref(dc), discover_char_unref); @@ -905,7 +905,7 @@ if (long_write->offset == long_write->vlen) { execute_write(long_write->attrib, ATT_WRITE_ALL_PREP_WRITES, long_write->func, long_write->user_data); - g_free(long_write->value); + free(long_write->value); g_free(long_write); return; @@ -964,7 +964,7 @@ long_write->func = func; long_write->user_data = user_data; long_write->handle = handle; - long_write->value = g_memdup(value, vlen); + long_write->value = util_memdup(value, vlen); long_write->vlen = vlen; return prepare_write(long_write); @@ -1130,7 +1130,7 @@ dd->user_data = user_data; dd->start = start; dd->end = end; - dd->uuid = g_memdup(uuid, sizeof(bt_uuid_t)); + dd->uuid = util_memdup(uuid, sizeof(bt_uuid_t)); dd->id = g_attrib_send(attrib, 0, buf, plen, desc_discovered_cb, discover_desc_ref(dd), discover_desc_unref); diff -Nru bluez-5.63/attrib/gatt-service.c bluez-5.64/attrib/gatt-service.c --- bluez-5.63/attrib/gatt-service.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/attrib/gatt-service.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,362 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2011 Nokia Corporation - * Copyright (C) 2011 Marcel Holtmann - * - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "lib/bluetooth.h" -#include "lib/sdp.h" -#include "lib/uuid.h" - -#include "src/adapter.h" -#include "src/shared/util.h" -#include "attrib/gattrib.h" -#include "attrib/att.h" -#include "attrib/gatt.h" -#include "attrib/att-database.h" -#include "src/attrib-server.h" -#include "attrib/gatt-service.h" -#include "src/log.h" - -struct gatt_info { - bt_uuid_t uuid; - uint8_t props; - int authentication; - int authorization; - GSList *callbacks; - unsigned int num_attrs; - uint16_t *value_handle; - uint16_t *ccc_handle; -}; - -struct attrib_cb { - attrib_event_t event; - void *fn; - void *user_data; -}; - -static inline void put_uuid_le(const bt_uuid_t *src, void *dst) -{ - if (src->type == BT_UUID16) - put_le16(src->value.u16, dst); - else - /* Convert from 128-bit BE to LE */ - bswap_128(&src->value.u128, dst); -} - -static GSList *parse_opts(gatt_option opt1, va_list args) -{ - gatt_option opt = opt1; - struct gatt_info *info; - struct attrib_cb *cb; - GSList *l = NULL; - - info = g_new0(struct gatt_info, 1); - l = g_slist_append(l, info); - - while (opt != GATT_OPT_INVALID) { - switch (opt) { - case GATT_OPT_CHR_UUID16: - bt_uuid16_create(&info->uuid, va_arg(args, int)); - /* characteristic declaration and value */ - info->num_attrs += 2; - break; - case GATT_OPT_CHR_UUID: - memcpy(&info->uuid, va_arg(args, bt_uuid_t *), - sizeof(bt_uuid_t)); - /* characteristic declaration and value */ - info->num_attrs += 2; - break; - case GATT_OPT_CHR_PROPS: - info->props = va_arg(args, int); - - if (info->props & (GATT_CHR_PROP_NOTIFY | - GATT_CHR_PROP_INDICATE)) - /* client characteristic configuration */ - info->num_attrs += 1; - - /* TODO: "Extended Properties" property requires a - * descriptor, but it is not supported yet. */ - break; - case GATT_OPT_CHR_VALUE_CB: - cb = g_new0(struct attrib_cb, 1); - cb->event = va_arg(args, attrib_event_t); - cb->fn = va_arg(args, void *); - cb->user_data = va_arg(args, void *); - info->callbacks = g_slist_append(info->callbacks, cb); - break; - case GATT_OPT_CHR_VALUE_GET_HANDLE: - info->value_handle = va_arg(args, void *); - break; - case GATT_OPT_CCC_GET_HANDLE: - info->ccc_handle = va_arg(args, void *); - break; - case GATT_OPT_CHR_AUTHENTICATION: - info->authentication = va_arg(args, gatt_option); - break; - case GATT_OPT_CHR_AUTHORIZATION: - info->authorization = va_arg(args, gatt_option); - break; - case GATT_CHR_VALUE_READ: - case GATT_CHR_VALUE_WRITE: - case GATT_CHR_VALUE_BOTH: - case GATT_OPT_INVALID: - default: - error("Invalid option: %d", opt); - } - - opt = va_arg(args, gatt_option); - if (opt == GATT_OPT_CHR_UUID16 || opt == GATT_OPT_CHR_UUID) { - info = g_new0(struct gatt_info, 1); - l = g_slist_append(l, info); - } - } - - return l; -} - -static struct attribute *add_service_declaration(struct btd_adapter *adapter, - uint16_t handle, uint16_t svc, bt_uuid_t *uuid) -{ - bt_uuid_t bt_uuid; - uint8_t atval[16]; - int len; - - put_uuid_le(uuid, &atval[0]); - len = bt_uuid_len(uuid); - - bt_uuid16_create(&bt_uuid, svc); - - return attrib_db_add(adapter, handle, &bt_uuid, ATT_NONE, - ATT_NOT_PERMITTED, atval, len); -} - -static int att_read_req(int authorization, int authentication, uint8_t props) -{ - if (authorization == GATT_CHR_VALUE_READ || - authorization == GATT_CHR_VALUE_BOTH) - return ATT_AUTHORIZATION; - else if (authentication == GATT_CHR_VALUE_READ || - authentication == GATT_CHR_VALUE_BOTH) - return ATT_AUTHENTICATION; - else if (!(props & GATT_CHR_PROP_READ)) - return ATT_NOT_PERMITTED; - - return ATT_NONE; -} - -static int att_write_req(int authorization, int authentication, uint8_t props) -{ - if (authorization == GATT_CHR_VALUE_WRITE || - authorization == GATT_CHR_VALUE_BOTH) - return ATT_AUTHORIZATION; - else if (authentication == GATT_CHR_VALUE_WRITE || - authentication == GATT_CHR_VALUE_BOTH) - return ATT_AUTHENTICATION; - else if (!(props & (GATT_CHR_PROP_WRITE | - GATT_CHR_PROP_WRITE_WITHOUT_RESP))) - return ATT_NOT_PERMITTED; - - return ATT_NONE; -} - -static int find_callback(gconstpointer a, gconstpointer b) -{ - const struct attrib_cb *cb = a; - unsigned int event = GPOINTER_TO_UINT(b); - - return cb->event - event; -} - -static gboolean add_characteristic(struct btd_adapter *adapter, - uint16_t *handle, struct gatt_info *info) -{ - int read_req, write_req; - uint16_t h = *handle; - struct attribute *a; - bt_uuid_t bt_uuid; - uint8_t atval[ATT_MAX_VALUE_LEN]; - GSList *l; - - if ((info->uuid.type != BT_UUID16 && info->uuid.type != BT_UUID128) || - !info->props) { - error("Characteristic UUID or properties are missing"); - return FALSE; - } - - read_req = att_read_req(info->authorization, info->authentication, - info->props); - write_req = att_write_req(info->authorization, info->authentication, - info->props); - - /* TODO: static characteristic values are not supported, therefore a - * callback must be always provided if a read/write property is set */ - if (read_req != ATT_NOT_PERMITTED) { - gpointer reqs = GUINT_TO_POINTER(ATTRIB_READ); - - if (!g_slist_find_custom(info->callbacks, reqs, - find_callback)) { - error("Callback for read required"); - return FALSE; - } - } - - if (write_req != ATT_NOT_PERMITTED) { - gpointer reqs = GUINT_TO_POINTER(ATTRIB_WRITE); - - if (!g_slist_find_custom(info->callbacks, reqs, - find_callback)) { - error("Callback for write required"); - return FALSE; - } - } - - /* characteristic declaration */ - bt_uuid16_create(&bt_uuid, GATT_CHARAC_UUID); - atval[0] = info->props; - put_le16(h + 1, &atval[1]); - put_uuid_le(&info->uuid, &atval[3]); - if (attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED, - atval, 3 + info->uuid.type / 8) == NULL) - return FALSE; - - /* characteristic value */ - a = attrib_db_add(adapter, h++, &info->uuid, read_req, write_req, - NULL, 0); - if (a == NULL) - return FALSE; - - for (l = info->callbacks; l != NULL; l = l->next) { - struct attrib_cb *cb = l->data; - - switch (cb->event) { - case ATTRIB_READ: - a->read_cb = cb->fn; - break; - case ATTRIB_WRITE: - a->write_cb = cb->fn; - break; - } - - a->cb_user_data = cb->user_data; - } - - if (info->value_handle != NULL) - *info->value_handle = a->handle; - - /* client characteristic configuration descriptor */ - if (info->props & (GATT_CHR_PROP_NOTIFY | GATT_CHR_PROP_INDICATE)) { - uint8_t cfg_val[2]; - - bt_uuid16_create(&bt_uuid, GATT_CLIENT_CHARAC_CFG_UUID); - cfg_val[0] = 0x00; - cfg_val[1] = 0x00; - a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, - ATT_AUTHENTICATION, cfg_val, sizeof(cfg_val)); - if (a == NULL) - return FALSE; - - if (info->ccc_handle != NULL) - *info->ccc_handle = a->handle; - } - - *handle = h; - - return TRUE; -} - -static void free_gatt_info(void *data) -{ - struct gatt_info *info = data; - - g_slist_free_full(info->callbacks, g_free); - g_free(info); -} - -static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle, - uint16_t end_handle) -{ - uint16_t handle; - - /* For a 128-bit category primary service below handle should be checked - * for both non-zero as well as >= 0xffff. As on last iteration the - * handle will turn to 0 from 0xffff and loop will be infinite. - */ - for (handle = start_handle; (handle != 0 && handle <= end_handle); - handle++) { - if (attrib_db_del(adapter, handle) < 0) - error("Can't delete handle 0x%04x", handle); - } -} - -gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid, - bt_uuid_t *svc_uuid, gatt_option opt1, ...) -{ - char uuidstr[MAX_LEN_UUID_STR]; - uint16_t start_handle, h; - unsigned int size; - va_list args; - GSList *chrs, *l; - - bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR); - - if (svc_uuid->type != BT_UUID16 && svc_uuid->type != BT_UUID128) { - error("Invalid service uuid: %s", uuidstr); - return FALSE; - } - - va_start(args, opt1); - chrs = parse_opts(opt1, args); - va_end(args); - - /* calculate how many attributes are necessary for this service */ - for (l = chrs, size = 1; l != NULL; l = l->next) { - struct gatt_info *info = l->data; - size += info->num_attrs; - } - - start_handle = attrib_db_find_avail(adapter, svc_uuid, size); - if (start_handle == 0) { - error("Not enough free handles to register service"); - goto fail; - } - - DBG("New service: handle 0x%04x, UUID %s, %d attributes", - start_handle, uuidstr, size); - - /* service declaration */ - h = start_handle; - if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL) - goto fail; - - for (l = chrs; l != NULL; l = l->next) { - struct gatt_info *info = l->data; - - DBG("New characteristic: handle 0x%04x", h); - if (!add_characteristic(adapter, &h, info)) { - service_attr_del(adapter, start_handle, h - 1); - goto fail; - } - } - - g_assert(size < USHRT_MAX); - g_assert(h == 0 || (h - start_handle == (uint16_t) size)); - g_slist_free_full(chrs, free_gatt_info); - - return TRUE; - -fail: - g_slist_free_full(chrs, free_gatt_info); - return FALSE; -} diff -Nru bluez-5.63/attrib/gatt-service.h bluez-5.64/attrib/gatt-service.h --- bluez-5.63/attrib/gatt-service.h 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/attrib/gatt-service.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2011 Nokia Corporation - * Copyright (C) 2011 Marcel Holtmann - * - * - */ - -typedef enum { - GATT_OPT_INVALID = 0, - - /* bt_uuid_t* value */ - GATT_OPT_CHR_UUID, - - /* a uint16 value */ - GATT_OPT_CHR_UUID16, - - GATT_OPT_CHR_PROPS, - GATT_OPT_CHR_VALUE_CB, - GATT_OPT_CHR_AUTHENTICATION, - GATT_OPT_CHR_AUTHORIZATION, - - /* Get attribute handle for characteristic value */ - GATT_OPT_CHR_VALUE_GET_HANDLE, - - /* Get handle for ccc attribute */ - GATT_OPT_CCC_GET_HANDLE, - - /* arguments for authentication/authorization */ - GATT_CHR_VALUE_READ, - GATT_CHR_VALUE_WRITE, - GATT_CHR_VALUE_BOTH, -} gatt_option; - -typedef enum { - ATTRIB_READ, - ATTRIB_WRITE, -} attrib_event_t; - -gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid, - bt_uuid_t *svc_uuid, gatt_option opt1, ...); diff -Nru bluez-5.63/ChangeLog bluez-5.64/ChangeLog --- bluez-5.63/ChangeLog 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/ChangeLog 2022-03-16 15:06:19.000000000 +0000 @@ -1,3 +1,11 @@ +ver 5.64: + Fix issue with handling A2DP discover procedure. + Fix issue with media endpoint replies and SetConfiguration. + Fix issue with HoG queuing events before report map is read. + Fix issue with HoG and read order of GATT attributes. + Fix issue with HoG and not using UHID_CREATE2 interface. + Fix issue with failed scanning for 5 minutes after reboot. + ver 5.63: Fix issue with storing IRK causing invalid read access. Fix issue with disconnecting due to GattCharacteristic1.MTU. diff -Nru bluez-5.63/client/gatt.c bluez-5.64/client/gatt.c --- bluez-5.63/client/gatt.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/client/gatt.c 2022-03-16 15:06:20.000000000 +0000 @@ -811,7 +811,7 @@ *val_len = i; - return g_memdup(value, i); + return util_memdup(value, i); } void gatt_write_attribute(GDBusProxy *proxy, int argc, char *argv[]) diff -Nru bluez-5.63/client/main.c bluez-5.64/client/main.c --- bluez-5.63/client/main.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/client/main.c 2022-03-16 15:06:20.000000000 +0000 @@ -1294,6 +1294,7 @@ dbus_bool_t discoverable; bool set; bool active; + unsigned int timeout; } filter = { .rssi = DISTANCE_VAL_INVALID, .pathloss = DISTANCE_VAL_INVALID, @@ -1415,18 +1416,33 @@ filter.set = true; } +static const char *scan_arguments[] = { + "on", + "off", + "bredr", + "le", + NULL +}; + static void cmd_scan(int argc, char *argv[]) { dbus_bool_t enable; const char *method; + const char *mode; - if (!parse_argument(argc, argv, NULL, NULL, &enable, NULL)) + if (!parse_argument(argc, argv, scan_arguments, "Mode", &enable, + &mode)) return bt_shell_noninteractive_quit(EXIT_FAILURE); if (check_default_ctrl() == FALSE) return bt_shell_noninteractive_quit(EXIT_FAILURE); if (enable == TRUE) { + if (strcmp(mode, "")) { + g_free(filter.transport); + filter.transport = g_strdup(mode); + } + set_discovery_filter(false); method = "StartDiscovery"; } else @@ -2514,6 +2530,11 @@ return argument_generator(text, state, agent_arguments); } +static char *scan_generator(const char *text, int state) +{ + return argument_generator(text, state, scan_arguments); +} + static void cmd_advertise(int argc, char *argv[]) { dbus_bool_t enable; @@ -3117,7 +3138,8 @@ "Enable/disable advertising with given type", ad_generator}, { "set-alias", "", cmd_set_alias, "Set device alias" }, - { "scan", "", cmd_scan, "Scan for devices", NULL }, + { "scan", "", cmd_scan, + "Scan for devices", scan_generator }, { "info", "[dev]", cmd_info, "Device information", dev_generator }, { "pair", "[dev]", cmd_pair, "Pair with device", diff -Nru bluez-5.63/config.h.in bluez-5.64/config.h.in --- bluez-5.63/config.h.in 2022-01-05 21:54:51.000000000 +0000 +++ bluez-5.64/config.h.in 2022-03-16 15:07:10.000000000 +0000 @@ -15,6 +15,9 @@ /* Define to 1 if you have the `explicit_bzero' function. */ #undef HAVE_EXPLICIT_BZERO +/* Define to 1 if you have the `getrandom' function. */ +#undef HAVE_GETRANDOM + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H @@ -60,6 +63,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RANDOM_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H diff -Nru bluez-5.63/configure bluez-5.64/configure --- bluez-5.63/configure 2022-01-05 21:55:03.000000000 +0000 +++ bluez-5.64/configure 2022-03-16 15:07:23.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for bluez 5.63. +# Generated by GNU Autoconf 2.69 for bluez 5.64. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ # Identity of this package. PACKAGE_NAME='bluez' PACKAGE_TARNAME='bluez' -PACKAGE_VERSION='5.63' -PACKAGE_STRING='bluez 5.63' +PACKAGE_VERSION='5.64' +PACKAGE_STRING='bluez 5.64' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1524,7 +1524,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures bluez 5.63 to adapt to many kinds of systems. +\`configure' configures bluez 5.64 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1595,7 +1595,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of bluez 5.63:";; + short | recursive ) echo "Configuration of bluez 5.64:";; esac cat <<\_ACEOF @@ -1798,7 +1798,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -bluez configure 5.63 +bluez configure 5.64 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2163,7 +2163,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by bluez $as_me 5.63, which was +It was created by bluez $as_me 5.64, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3022,7 +3022,7 @@ # Define the identity of the package. PACKAGE='bluez' - VERSION='5.63' + VERSION='5.64' cat >>confdefs.h <<_ACEOF @@ -13793,6 +13793,18 @@ done +for ac_func in getrandom +do : + ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom" +if test "x$ac_cv_func_getrandom" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETRANDOM 1 +_ACEOF + +fi +done + + for ac_func in rawmemchr do : ac_fn_c_check_func "$LINENO" "rawmemchr" "ac_cv_func_rawmemchr" @@ -13942,7 +13954,7 @@ fi -for ac_header in linux/types.h linux/if_alg.h linux/uinput.h linux/uhid.h +for ac_header in linux/types.h linux/if_alg.h linux/uinput.h linux/uhid.h sys/random.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -16346,7 +16358,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by bluez $as_me 5.63, which was +This file was extended by bluez $as_me 5.64, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -16412,7 +16424,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -bluez config.status 5.63 +bluez config.status 5.64 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -Nru bluez-5.63/configure.ac bluez-5.64/configure.ac --- bluez-5.63/configure.ac 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/configure.ac 2022-03-16 15:06:20.000000000 +0000 @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 AC_PREREQ(2.60) -AC_INIT(bluez, 5.63) +AC_INIT(bluez, 5.64) AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules tar-pax no-dist-gzip dist-xz]) @@ -16,7 +16,7 @@ COMPILER_FLAGS -AC_LANG_C +AC_LANG([C]) AC_C_RESTRICT @@ -49,11 +49,13 @@ AM_CONDITIONAL(VALGRIND, test "${enable_valgrind}" = "yes" && test "$ASAN_LIB" != "yes" && test "LSAN_LIB" != "yes") -AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], +AC_ARG_ENABLE(threads, AS_HELP_STRING([--enable-threads], [enable threading support]), [enable_threads=${enableval}]) AC_CHECK_FUNCS(explicit_bzero) +AC_CHECK_FUNCS(getrandom) + AC_CHECK_FUNCS(rawmemchr) AC_CHECK_FUNC(signalfd, dummy=yes, @@ -68,7 +70,7 @@ AC_CHECK_LIB(dl, dlopen, dummy=yes, AC_MSG_ERROR(dynamic linking loader is required)) -AC_CHECK_HEADERS(linux/types.h linux/if_alg.h linux/uinput.h linux/uhid.h) +AC_CHECK_HEADERS(linux/types.h linux/if_alg.h linux/uinput.h linux/uhid.h sys/random.h) PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes, AC_MSG_ERROR(GLib >= 2.28 is required)) @@ -88,7 +90,7 @@ AC_SUBST(DBUS_CFLAGS) AC_SUBST(DBUS_LIBS) -AC_ARG_WITH([dbusconfdir], AC_HELP_STRING([--with-dbusconfdir=DIR], +AC_ARG_WITH([dbusconfdir], AS_HELP_STRING([--with-dbusconfdir=DIR], [path to D-Bus configuration directory]), [path_dbusconfdir=${withval}]) if (test -z "${path_dbusconfdir}"); then @@ -101,7 +103,7 @@ fi AC_SUBST(DBUS_CONFDIR, [${path_dbusconfdir}]) -AC_ARG_WITH([dbussystembusdir], AC_HELP_STRING([--with-dbussystembusdir=DIR], +AC_ARG_WITH([dbussystembusdir], AS_HELP_STRING([--with-dbussystembusdir=DIR], [path to D-Bus system bus services directory]), [path_dbussystembusdir=${withval}]) if (test -z "${path_dbussystembusdir}"); then @@ -114,7 +116,7 @@ fi AC_SUBST(DBUS_SYSTEMBUSDIR, [${path_dbussystembusdir}]) -AC_ARG_WITH([dbussessionbusdir], AC_HELP_STRING([--with-dbussessionbusdir=DIR], +AC_ARG_WITH([dbussessionbusdir], AS_HELP_STRING([--with-dbussessionbusdir=DIR], [path to D-Bus session bus services directory]), [path_dbussessionbusdir=${withval}]) if (test -z "${path_dbussessionbusdir}"); then @@ -127,7 +129,7 @@ fi AC_SUBST(DBUS_SESSIONBUSDIR, [${path_dbussessionbusdir}]) -AC_ARG_WITH([zsh-completion-dir], AC_HELP_STRING([--with-zsh-completion-dir=DIR], +AC_ARG_WITH([zsh-completion-dir], AS_HELP_STRING([--with-zsh-completion-dir=DIR], [path to install zsh completions]), [path_zshcompletiondir=${withval}], [path_zshcompletiondir="yes"]) @@ -139,7 +141,7 @@ AC_SUBST(ZSH_COMPLETIONDIR, [${path_zshcompletiondir}]) AM_CONDITIONAL(ZSH_COMPLETIONS, test "${path_zshcompletiondir}" != "no") -AC_ARG_ENABLE(backtrace, AC_HELP_STRING([--enable-backtrace], +AC_ARG_ENABLE(backtrace, AS_HELP_STRING([--enable-backtrace], [compile backtrace support]), [enable_backtrace=${enableval}]) if (test "${enable_backtrace}" = "yes"); then @@ -153,55 +155,55 @@ AC_SUBST(BACKTRACE_LIBS) fi -AC_ARG_ENABLE(library, AC_HELP_STRING([--enable-library], +AC_ARG_ENABLE(library, AS_HELP_STRING([--enable-library], [install Bluetooth library]), [enable_library=${enableval}]) AM_CONDITIONAL(LIBRARY, test "${enable_library}" = "yes") -AC_ARG_ENABLE(test, AC_HELP_STRING([--enable-test], +AC_ARG_ENABLE(test, AS_HELP_STRING([--enable-test], [enable test/example scripts]), [enable_test=${enableval}]) AM_CONDITIONAL(TEST, test "${enable_test}" = "yes") -AC_ARG_ENABLE(nfc, AC_HELP_STRING([--enable-nfc], +AC_ARG_ENABLE(nfc, AS_HELP_STRING([--enable-nfc], [enable NFC paring]), [enable_nfc=${enableval}]) AM_CONDITIONAL(NFC, test "${enable_nfc}" = "yes") -AC_ARG_ENABLE(sap, AC_HELP_STRING([--enable-sap], +AC_ARG_ENABLE(sap, AS_HELP_STRING([--enable-sap], [enable SAP profile]), [enable_sap=${enableval}]) AM_CONDITIONAL(SAP, test "${enable_sap}" = "yes") -AC_ARG_ENABLE(a2dp, AC_HELP_STRING([--disable-a2dp], +AC_ARG_ENABLE(a2dp, AS_HELP_STRING([--disable-a2dp], [disable A2DP profile]), [enable_a2dp=${enableval}]) AM_CONDITIONAL(A2DP, test "${enable_a2dp}" != "no") -AC_ARG_ENABLE(avrcp, AC_HELP_STRING([--disable-avrcp], +AC_ARG_ENABLE(avrcp, AS_HELP_STRING([--disable-avrcp], [disable AVRCP profile]), [enable_avrcp=${enableval}]) AM_CONDITIONAL(AVRCP, test "${enable_avrcp}" != "no") -AC_ARG_ENABLE(network, AC_HELP_STRING([--disable-network], +AC_ARG_ENABLE(network, AS_HELP_STRING([--disable-network], [disable network profiles]), [enable_network=${enableval}]) AM_CONDITIONAL(NETWORK, test "${enable_network}" != "no") -AC_ARG_ENABLE(hid, AC_HELP_STRING([--disable-hid], +AC_ARG_ENABLE(hid, AS_HELP_STRING([--disable-hid], [disable HID profile]), [enable_hid=${enableval}]) AM_CONDITIONAL(HID, test "${enable_hid}" != "no") -AC_ARG_ENABLE(hog, AC_HELP_STRING([--disable-hog], +AC_ARG_ENABLE(hog, AS_HELP_STRING([--disable-hog], [disable HoG profile]), [enable_hog=${enableval}]) AM_CONDITIONAL(HOG, test "${enable_hog}" != "no") -AC_ARG_ENABLE(health, AC_HELP_STRING([--enable-health], +AC_ARG_ENABLE(health, AS_HELP_STRING([--enable-health], [enable health profiles]), [enable_health=${enableval}]) AM_CONDITIONAL(HEALTH, test "${enable_health}" = "yes") -AC_ARG_ENABLE(tools, AC_HELP_STRING([--disable-tools], +AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools], [disable Bluetooth tools]), [enable_tools=${enableval}]) AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no") -AC_ARG_ENABLE(monitor, AC_HELP_STRING([--disable-monitor], +AC_ARG_ENABLE(monitor, AS_HELP_STRING([--disable-monitor], [disable Bluetooth monitor]), [enable_monitor=${enableval}]) AM_CONDITIONAL(MONITOR, test "${enable_monitor}" != "no") -AC_ARG_ENABLE(udev, AC_HELP_STRING([--disable-udev], +AC_ARG_ENABLE(udev, AS_HELP_STRING([--disable-udev], [disable udev device support]), [enable_udev=${enableval}]) if (test "${enable_tools}" != "no" && test "${enable_udev}" != "no"); then PKG_CHECK_MODULES(UDEV, libudev >= 172, dummy=yes, @@ -214,7 +216,7 @@ fi AM_CONDITIONAL(UDEV, test "${enable_udev}" != "no") -AC_ARG_WITH([udevdir], AC_HELP_STRING([--with-udevdir=DIR], +AC_ARG_WITH([udevdir], AS_HELP_STRING([--with-udevdir=DIR], [path to udev directory]), [path_udevdir=${withval}]) if (test "${enable_udev}" != "no" && test -z "${path_udevdir}"); then AC_MSG_CHECKING([udev directory]) @@ -226,11 +228,11 @@ fi AC_SUBST(UDEV_DIR, [${path_udevdir}]) -AC_ARG_ENABLE(cups, AC_HELP_STRING([--disable-cups], +AC_ARG_ENABLE(cups, AS_HELP_STRING([--disable-cups], [disable CUPS printer support]), [enable_cups=${enableval}]) AM_CONDITIONAL(CUPS, test "${enable_cups}" != "no") -AC_ARG_ENABLE(mesh, AC_HELP_STRING([--enable-mesh], +AC_ARG_ENABLE(mesh, AS_HELP_STRING([--enable-mesh], [enable Mesh profile support]), [enable_mesh=${enableval}]) AM_CONDITIONAL(MESH, test "${enable_mesh}" = "yes") @@ -241,7 +243,7 @@ AC_SUBST(JSON_LIBS) fi -AC_ARG_ENABLE(midi, AC_HELP_STRING([--enable-midi], +AC_ARG_ENABLE(midi, AS_HELP_STRING([--enable-midi], [enable MIDI support]), [enable_midi=${enableval}]) AM_CONDITIONAL(MIDI, test "${enable_midi}" = "yes") @@ -252,7 +254,7 @@ AC_SUBST(ALSA_LIBS) fi -AC_ARG_ENABLE(obex, AC_HELP_STRING([--disable-obex], +AC_ARG_ENABLE(obex, AS_HELP_STRING([--disable-obex], [disable OBEX profile support]), [enable_obex=${enableval}]) if (test "${enable_obex}" != "no"); then PKG_CHECK_MODULES(ICAL, libical, dummy=yes, @@ -262,11 +264,11 @@ fi AM_CONDITIONAL(OBEX, test "${enable_obex}" != "no") -AC_ARG_ENABLE(btpclient, AC_HELP_STRING([--enable-btpclient], +AC_ARG_ENABLE(btpclient, AS_HELP_STRING([--enable-btpclient], [enable BTP client]), [enable_btpclient=${enableval}]) AM_CONDITIONAL(BTPCLIENT, test "${enable_btpclient}" = "yes") -AC_ARG_ENABLE([external_ell], AC_HELP_STRING([--enable-external-ell], +AC_ARG_ENABLE([external_ell], AS_HELP_STRING([--enable-external-ell], [enable external Embedded Linux library]), [enable_external_ell=${enableval}]) if (test "${enable_external_ell}" = "yes"); then @@ -281,7 +283,7 @@ AM_CONDITIONAL(LIBSHARED_ELL, test "${enable_btpclient}" = "yes" || test "${enable_mesh}" = "yes") -AC_ARG_ENABLE(client, AC_HELP_STRING([--disable-client], +AC_ARG_ENABLE(client, AS_HELP_STRING([--disable-client], [disable command line client]), [enable_client=${enableval}]) AM_CONDITIONAL(CLIENT, test "${enable_client}" != "no") @@ -291,12 +293,12 @@ fi AM_CONDITIONAL(READLINE, test "${enable_readline}" = "yes") -AC_ARG_ENABLE(systemd, AC_HELP_STRING([--disable-systemd], +AC_ARG_ENABLE(systemd, AS_HELP_STRING([--disable-systemd], [disable systemd integration]), [enable_systemd=${enableval}]) AM_CONDITIONAL(SYSTEMD, test "${enable_systemd}" != "no") AC_ARG_WITH([systemdsystemunitdir], - AC_HELP_STRING([--with-systemdsystemunitdir=DIR], + AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [path to systemd system unit directory]), [path_systemunitdir=${withval}]) if (test "${enable_systemd}" != "no" && test -z "${path_systemunitdir}"); then @@ -310,7 +312,7 @@ AC_SUBST(SYSTEMD_SYSTEMUNITDIR, [${path_systemunitdir}]) AC_ARG_WITH([systemduserunitdir], - AC_HELP_STRING([--with-systemduserunitdir=DIR], + AS_HELP_STRING([--with-systemduserunitdir=DIR], [path to systemd user unit directory]), [path_userunitdir=${withval}]) if (test "${enable_systemd}" != "no" && test -z "${path_userunitdir}"); then @@ -323,12 +325,12 @@ fi AC_SUBST(SYSTEMD_USERUNITDIR, [${path_userunitdir}]) -AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles], +AC_ARG_ENABLE(datafiles, AS_HELP_STRING([--disable-datafiles], [do not install configuration and data files]), [enable_datafiles=${enableval}]) AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no") -AC_ARG_ENABLE(manpages, AC_HELP_STRING([--disable-manpages], +AC_ARG_ENABLE(manpages, AS_HELP_STRING([--disable-manpages], [disable building of manual pages]), [enable_manpages=${enableval}]) if (test "${enable_manpages}" != "no"); then @@ -341,36 +343,36 @@ AM_CONDITIONAL(RUN_RST2MAN, test "${enable_manpages}" != "no" && test "${RST2MAN}" != "no") -AC_ARG_ENABLE(testing, AC_HELP_STRING([--enable-testing], +AC_ARG_ENABLE(testing, AS_HELP_STRING([--enable-testing], [enable testing tools]), [enable_testing=${enableval}]) AM_CONDITIONAL(TESTING, test "${enable_testing}" = "yes") -AC_ARG_ENABLE(experimental, AC_HELP_STRING([--enable-experimental], +AC_ARG_ENABLE(experimental, AS_HELP_STRING([--enable-experimental], [enable experimental tools]), [enable_experimental=${enableval}]) AM_CONDITIONAL(EXPERIMENTAL, test "${enable_experimental}" = "yes") -AC_ARG_ENABLE(deprecated, AC_HELP_STRING([--enable-deprecated], +AC_ARG_ENABLE(deprecated, AS_HELP_STRING([--enable-deprecated], [enable deprecated tools]), [enable_deprecated=${enableval}]) AM_CONDITIONAL(DEPRECATED, test "${enable_deprecated}" = "yes") -AC_ARG_ENABLE(sixaxis, AC_HELP_STRING([--enable-sixaxis], +AC_ARG_ENABLE(sixaxis, AS_HELP_STRING([--enable-sixaxis], [enable sixaxis plugin]), [enable_sixaxis=${enableval}]) AM_CONDITIONAL(SIXAXIS, test "${enable_sixaxis}" = "yes" && test "${enable_udev}" != "no") -AC_ARG_ENABLE(hid2hci, AC_HELP_STRING([--enable-hid2hci], +AC_ARG_ENABLE(hid2hci, AS_HELP_STRING([--enable-hid2hci], [enable hid2hci tool]), [enable_hid2hci=${enableval}]) AM_CONDITIONAL(HID2HCI, test "${enable_hid2hci}" = "yes" && test "${enable_udev}" != "no") -AC_ARG_ENABLE(logger, AC_HELP_STRING([--enable-logger], +AC_ARG_ENABLE(logger, AS_HELP_STRING([--enable-logger], [enable HCI logger service]), [enable_logger=${enableval}]) AM_CONDITIONAL(LOGGER, test "${enable_logger}" = "yes") -AC_ARG_ENABLE(admin, AC_HELP_STRING([--enable-admin], +AC_ARG_ENABLE(admin, AS_HELP_STRING([--enable-admin], [enable admin policy plugin]), [enable_admin=${enableval}]) AM_CONDITIONAL(ADMIN, test "${enable_admin}" = "yes") @@ -404,7 +406,7 @@ [Directory for the mesh daemon storage files]) AC_SUBST(MESH_STORAGEDIR, "${storagedir}/mesh") -AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android], +AC_ARG_ENABLE(android, AS_HELP_STRING([--enable-android], [enable BlueZ for Android]), [enable_android=${enableval}]) AM_CONDITIONAL(ANDROID, test "${enable_android}" = "yes") @@ -426,7 +428,7 @@ AC_DEFINE_UNQUOTED(ANDROID_STORAGEDIR, "${storagedir}/android", [Directory for the Android daemon storage files]) -AC_ARG_WITH([phonebook], AC_HELP_STRING([--with-phonebook=PLUGIN], +AC_ARG_WITH([phonebook], AS_HELP_STRING([--with-phonebook=PLUGIN], [obexd phonebook plugin (default=dummy)]), [plugin_phonebook=${withval}]) if (test -z "${plugin_phonebook}"); then @@ -446,4 +448,5 @@ fi AC_SUBST(PLUGIN_PHONEBOOK, [${plugin_phonebook}]) -AC_OUTPUT(Makefile src/bluetoothd.rst lib/bluez.pc mesh/bluetooth-meshd.rst) +AC_CONFIG_FILES(Makefile src/bluetoothd.rst lib/bluez.pc mesh/bluetooth-meshd.rst) +AC_OUTPUT diff -Nru bluez-5.63/debian/changelog bluez-5.64/debian/changelog --- bluez-5.63/debian/changelog 2022-03-02 09:26:23.000000000 +0000 +++ bluez-5.64/debian/changelog 2022-03-24 06:30:38.000000000 +0000 @@ -1,3 +1,21 @@ +bluez (5.64-0ubuntu1) jammy; urgency=medium + + * New upstream release 5.64 (LP: #1965740): + - Fix issue with handling A2DP discover procedure. + - Fix issue with media endpoint replies and SetConfiguration. + - Fix issue with HoG queuing events before report map is read. + - Fix issue with HoG and read order of GATT attributes. + - Fix issue with HoG and not using UHID_CREATE2 interface. + - Fix issue with failed scanning for 5 minutes after reboot. + * Drop upstreamed patches: + - hog-Fix-read-order-of-attributes.patch + - media-Fix-crash-when-endpoint-replies-with-an-error-to-Se.patch + - gdbus-Emit-InterfacesAdded-of-parents-objects-first.patch + * Refreshed patches: + - ubuntu_error_restart.patch + + -- Daniel van Vugt Thu, 24 Mar 2022 14:30:38 +0800 + bluez (5.63-0ubuntu2) jammy; urgency=medium * Cherry-pick 3 patches to fix some crash & reconnect issues diff -Nru bluez-5.63/debian/patches/gdbus-Emit-InterfacesAdded-of-parents-objects-first.patch bluez-5.64/debian/patches/gdbus-Emit-InterfacesAdded-of-parents-objects-first.patch --- bluez-5.63/debian/patches/gdbus-Emit-InterfacesAdded-of-parents-objects-first.patch 2022-03-02 09:26:23.000000000 +0000 +++ bluez-5.64/debian/patches/gdbus-Emit-InterfacesAdded-of-parents-objects-first.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -From: Luiz Augusto von Dentz -Date: Thu, 3 Feb 2022 17:29:25 -0800 -Subject: gdbus: Emit InterfacesAdded of parents objects first - -This makes InterfacesAdded respect the object hierarchy in case its -parent has pending interfaces to be added. - -Fixes: https://github.com/bluez/bluez/issues/272 -Fixes: https://github.com/bluez/bluez/issues/284 -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1534857 -Fixes: https://bugs.archlinux.org/task/57464 ---- - gdbus/object.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/gdbus/object.c b/gdbus/object.c -index 50a8b4f..f7c8c2b 100644 ---- a/gdbus/object.c -+++ b/gdbus/object.c -@@ -551,6 +551,12 @@ static void emit_interfaces_added(struct generic_data *data) - if (root == NULL || data == root) - return; - -+ /* Emit InterfacesAdded on the parent first so it appears first on the -+ * bus as child objects may point to it. -+ */ -+ if (data->parent && data->parent->added) -+ emit_interfaces_added(data->parent); -+ - signal = dbus_message_new_signal(root->path, - DBUS_INTERFACE_OBJECT_MANAGER, - "InterfacesAdded"); diff -Nru bluez-5.63/debian/patches/hog-Fix-read-order-of-attributes.patch bluez-5.64/debian/patches/hog-Fix-read-order-of-attributes.patch --- bluez-5.63/debian/patches/hog-Fix-read-order-of-attributes.patch 2022-03-02 09:26:23.000000000 +0000 +++ bluez-5.64/debian/patches/hog-Fix-read-order-of-attributes.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,538 +0,0 @@ -From: Luiz Augusto von Dentz -Date: Mon, 10 Jan 2022 17:35:15 -0800 -Subject: hog: Fix read order of attributes - -The Report Map must be read after all other attributes otherwise the -Kernel driver may start using UHID_SET_REPORT which requires the -report->id to be known in order to resolve the attribute to send to. - -Fixes: https://github.com/bluez/bluez/issues/220 ---- - profiles/input/hog-lib.c | 191 +++++++++++++++++++++++++++++------------------ - 1 file changed, 119 insertions(+), 72 deletions(-) - -diff --git a/profiles/input/hog-lib.c b/profiles/input/hog-lib.c -index 3bbe423..ed860f0 100644 ---- a/profiles/input/hog-lib.c -+++ b/profiles/input/hog-lib.c -@@ -90,6 +90,7 @@ struct bt_hog { - uint16_t getrep_id; - unsigned int setrep_att; - uint16_t setrep_id; -+ unsigned int report_map_id; - struct bt_scpp *scpp; - struct bt_dis *dis; - struct queue *bas; -@@ -146,13 +147,34 @@ static bool set_and_store_gatt_req(struct bt_hog *hog, - return queue_push_head(hog->gatt_op, req); - } - --static void destroy_gatt_req(struct gatt_request *req) -+static void destroy_gatt_req(void *data) - { -- queue_remove(req->hog->gatt_op, req); -+ struct gatt_request *req = data; -+ - bt_hog_unref(req->hog); - free(req); - } - -+static void read_report_map(struct bt_hog *hog); -+ -+static void remove_gatt_req(struct gatt_request *req, uint8_t status) -+{ -+ struct bt_hog *hog = req->hog; -+ -+ queue_remove(hog->gatt_op, req); -+ -+ if (!status && queue_isempty(hog->gatt_op)) { -+ /* Report Map must be read last since that can result -+ * in uhid being created and the driver may start to -+ * use UHID_SET_REPORT which requires the report->id to -+ * be known what attribute to send to. -+ */ -+ read_report_map(hog); -+ } -+ -+ destroy_gatt_req(req); -+} -+ - static void write_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle, - const uint8_t *value, size_t vlen, - GAttribResultFunc func, -@@ -178,27 +200,31 @@ static void write_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle, - } - } - --static void read_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle, -- GAttribResultFunc func, gpointer user_data) -+static unsigned int read_char(struct bt_hog *hog, GAttrib *attrib, -+ uint16_t handle, GAttribResultFunc func, -+ gpointer user_data) - { - struct gatt_request *req; - unsigned int id; - - req = create_request(hog, user_data); - if (!req) -- return; -+ return 0; - - id = gatt_read_char(attrib, handle, func, req); - if (!id) { - error("hog: Could not read char"); -- return; -+ return 0; - } - - if (!set_and_store_gatt_req(hog, req, id)) { - error("hog: Failed to queue read char req"); - g_attrib_cancel(attrib, id); - free(req); -+ return 0; - } -+ -+ return id; - } - - static void discover_desc(struct bt_hog *hog, GAttrib *attrib, -@@ -343,16 +369,14 @@ static void report_ccc_written_cb(guint8 status, const guint8 *pdu, - struct report *report = req->user_data; - struct bt_hog *hog = report->hog; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("Write report characteristic descriptor failed: %s", - att_ecode2str(status)); -- return; -+ goto remove; - } - - if (report->notifyid) -- return; -+ goto remove; - - report->notifyid = g_attrib_register(hog->attrib, - ATT_OP_HANDLE_NOTIFY, -@@ -360,6 +384,9 @@ static void report_ccc_written_cb(guint8 status, const guint8 *pdu, - report_value_cb, report, NULL); - - DBG("Report characteristic descriptor written: notifications enabled"); -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void write_ccc(struct bt_hog *hog, GAttrib *attrib, uint16_t handle, -@@ -379,14 +406,15 @@ static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len, - struct gatt_request *req = user_data; - struct report *report = req->user_data; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("Error reading CCC value: %s", att_ecode2str(status)); -- return; -+ goto remove; - } - - write_ccc(report->hog, report->hog->attrib, report->ccc_handle, report); -+ -+remove: -+ remove_gatt_req(req, status); - } - - static const char *type_to_string(uint8_t type) -@@ -409,17 +437,15 @@ static void report_reference_cb(guint8 status, const guint8 *pdu, - struct gatt_request *req = user_data; - struct report *report = req->user_data; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("Read Report Reference descriptor failed: %s", - att_ecode2str(status)); -- return; -+ goto remove; - } - - if (plen != 3) { - error("Malformed ATT read response"); -- return; -+ goto remove; - } - - report->id = pdu[1]; -@@ -432,6 +458,9 @@ static void report_reference_cb(guint8 status, const guint8 *pdu, - if (report->type == HOG_REPORT_TYPE_INPUT) - read_char(report->hog, report->hog->attrib, report->ccc_handle, - ccc_read_cb, report); -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void external_report_reference_cb(guint8 status, const guint8 *pdu, -@@ -442,12 +471,10 @@ static void discover_external_cb(uint8_t status, GSList *descs, void *user_data) - struct gatt_request *req = user_data; - struct bt_hog *hog = req->user_data; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("Discover external descriptors failed: %s", - att_ecode2str(status)); -- return; -+ goto remove; - } - - for ( ; descs; descs = descs->next) { -@@ -457,6 +484,9 @@ static void discover_external_cb(uint8_t status, GSList *descs, void *user_data) - external_report_reference_cb, - hog); - } -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void discover_external(struct bt_hog *hog, GAttrib *attrib, -@@ -480,12 +510,10 @@ static void discover_report_cb(uint8_t status, GSList *descs, void *user_data) - struct report *report = req->user_data; - struct bt_hog *hog = report->hog; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("Discover report descriptors failed: %s", - att_ecode2str(status)); -- return; -+ goto remove; - } - - for ( ; descs; descs = descs->next) { -@@ -501,6 +529,9 @@ static void discover_report_cb(uint8_t status, GSList *descs, void *user_data) - break; - } - } -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void discover_report(struct bt_hog *hog, GAttrib *attrib, -@@ -519,11 +550,9 @@ static void report_read_cb(guint8 status, const guint8 *pdu, guint16 len, - struct gatt_request *req = user_data; - struct report *report = req->user_data; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("Error reading Report value: %s", att_ecode2str(status)); -- return; -+ goto remove; - } - - if (report->value) -@@ -531,6 +560,9 @@ static void report_read_cb(guint8 status, const guint8 *pdu, guint16 len, - - report->value = g_memdup(pdu, len); - report->len = len; -+ -+remove: -+ remove_gatt_req(req, status); - } - - static int report_chrc_cmp(const void *data, const void *user_data) -@@ -572,12 +604,11 @@ static void external_service_char_cb(uint8_t status, GSList *chars, - struct report *report; - GSList *l; - -- destroy_gatt_req(req); -- - if (status != 0) { - const char *str = att_ecode2str(status); -+ - DBG("Discover external service characteristic failed: %s", str); -- return; -+ goto remove; - } - - for (l = chars; l; l = g_slist_next(l)) { -@@ -595,6 +626,9 @@ static void external_service_char_cb(uint8_t status, GSList *chars, - end = (next ? next->handle - 1 : primary->range.end); - discover_report(hog, hog->attrib, start, end, report); - } -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void external_report_reference_cb(guint8 status, const guint8 *pdu, -@@ -605,17 +639,15 @@ static void external_report_reference_cb(guint8 status, const guint8 *pdu, - uint16_t uuid16; - bt_uuid_t uuid; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("Read External Report Reference descriptor failed: %s", - att_ecode2str(status)); -- return; -+ goto remove; - } - - if (plen != 3) { - error("Malformed ATT read response"); -- return; -+ goto remove; - } - - uuid16 = get_le16(&pdu[1]); -@@ -624,11 +656,14 @@ static void external_report_reference_cb(guint8 status, const guint8 *pdu, - - /* Do not discover if is not a Report */ - if (uuid16 != HOG_REPORT_UUID) -- return; -+ goto remove; - - bt_uuid16_create(&uuid, uuid16); - discover_char(hog, hog->attrib, 0x0001, 0xffff, &uuid, - external_service_char_cb, hog); -+ -+remove: -+ remove_gatt_req(req, status); - } - - static int report_cmp(gconstpointer a, gconstpointer b) -@@ -687,12 +722,10 @@ static void output_written_cb(guint8 status, const guint8 *pdu, - { - struct gatt_request *req = user_data; - -- destroy_gatt_req(req); -- -- if (status != 0) { -+ if (status != 0) - error("Write output report failed: %s", att_ecode2str(status)); -- return; -- } -+ -+ remove_gatt_req(req, status); - } - - static void forward_report(struct uhid_event *ev, void *user_data) -@@ -1056,7 +1089,7 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen, - uint8_t value[HOG_REPORT_MAP_MAX_SIZE]; - ssize_t vlen; - -- destroy_gatt_req(req); -+ remove_gatt_req(req, status); - - DBG("HoG inspecting report map"); - -@@ -1081,6 +1114,19 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen, - } - } - -+static void read_report_map(struct bt_hog *hog) -+{ -+ uint16_t handle; -+ -+ if (!hog->report_map_attr || hog->uhid_created || hog->report_map_id) -+ return; -+ -+ handle = gatt_db_attribute_get_handle(hog->report_map_attr); -+ -+ hog->report_map_id = read_char(hog, hog->attrib, handle, -+ report_map_read_cb, hog); -+} -+ - static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen, - gpointer user_data) - { -@@ -1089,18 +1135,16 @@ static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen, - uint8_t value[HID_INFO_SIZE]; - ssize_t vlen; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("HID Information read failed: %s", - att_ecode2str(status)); -- return; -+ goto remove; - } - - vlen = dec_read_resp(pdu, plen, value, sizeof(value)); - if (vlen != 4) { - error("ATT protocol error"); -- return; -+ goto remove; - } - - hog->bcdhid = get_le16(&value[0]); -@@ -1109,6 +1153,9 @@ static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen, - - DBG("bcdHID: 0x%04X bCountryCode: 0x%02X Flags: 0x%02X", - hog->bcdhid, hog->bcountrycode, hog->flags); -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen, -@@ -1119,18 +1166,16 @@ static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen, - uint8_t value; - ssize_t vlen; - -- destroy_gatt_req(req); -- - if (status != 0) { - error("Protocol Mode characteristic read failed: %s", - att_ecode2str(status)); -- return; -+ goto remove; - } - - vlen = dec_read_resp(pdu, plen, &value, sizeof(value)); - if (vlen < 0) { - error("ATT protocol error"); -- return; -+ goto remove; - } - - if (value == HOG_PROTO_MODE_BOOT) { -@@ -1142,6 +1187,9 @@ static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen, - sizeof(nval), NULL, NULL); - } else if (value == HOG_PROTO_MODE_REPORT) - DBG("HoG is operating in Report Protocol Mode"); -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data) -@@ -1155,14 +1203,12 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data) - GSList *l; - uint16_t info_handle = 0, proto_mode_handle = 0; - -- destroy_gatt_req(req); -- - DBG("HoG inspecting characteristics"); - - if (status != 0) { -- const char *str = att_ecode2str(status); -- DBG("Discover all characteristics failed: %s", str); -- return; -+ DBG("Discover all characteristics failed: %s", -+ att_ecode2str(status)); -+ goto remove; - } - - bt_uuid16_create(&report_uuid, HOG_REPORT_UUID); -@@ -1211,6 +1257,9 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data) - - if (info_handle) - read_char(hog, hog->attrib, info_handle, info_read_cb, hog); -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void report_free(void *data) -@@ -1221,10 +1270,12 @@ static void report_free(void *data) - g_free(report); - } - --static void cancel_gatt_req(struct gatt_request *req) -+static bool cancel_gatt_req(const void *data, const void *user_data) - { -- if (g_attrib_cancel(req->hog->attrib, req->id)) -- destroy_gatt_req(req); -+ struct gatt_request *req = (void *) data; -+ const struct bt_hog *hog = user_data; -+ -+ return g_attrib_cancel(hog->attrib, req->id); - } - - static void hog_free(void *data) -@@ -1386,13 +1437,9 @@ static void foreach_hog_chrc(struct gatt_db_attribute *attr, void *user_data) - * UHID to optimize reconnection. - */ - uhid_create(hog, report_map.value, report_map.length); -- } else { -- read_char(hog, hog->attrib, value_handle, -- report_map_read_cb, hog); - } - - gatt_db_service_foreach_desc(attr, foreach_hog_external, hog); -- return; - } - - bt_uuid16_create(&info_uuid, HOG_INFO_UUID); -@@ -1552,12 +1599,9 @@ static void find_included_cb(uint8_t status, GSList *services, void *user_data) - - DBG(""); - -- destroy_gatt_req(req); -- - if (status) { -- const char *str = att_ecode2str(status); -- DBG("Find included failed: %s", str); -- return; -+ DBG("Find included failed: %s", att_ecode2str(status)); -+ goto remove; - } - - for (l = services; l; l = l->next) { -@@ -1566,6 +1610,9 @@ static void find_included_cb(uint8_t status, GSList *services, void *user_data) - DBG("included: handle %x, uuid %s", - include->handle, include->uuid); - } -+ -+remove: -+ remove_gatt_req(req, status); - } - - static void hog_attach_scpp(struct bt_hog *hog, struct gatt_primary *primary) -@@ -1640,17 +1687,14 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data) - - DBG(""); - -- destroy_gatt_req(req); -- - if (status) { -- const char *str = att_ecode2str(status); -- DBG("Discover primary failed: %s", str); -- return; -+ DBG("Discover primary failed: %s", att_ecode2str(status)); -+ goto remove; - } - - if (!services) { - DBG("No primary service found"); -- return; -+ goto remove; - } - - for (l = services; l; l = l->next) { -@@ -1674,6 +1718,9 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data) - if (strcmp(primary->uuid, HOG_UUID) == 0) - hog_attach_hog(hog, primary); - } -+ -+remove: -+ remove_gatt_req(req, status); - } - - bool bt_hog_attach(struct bt_hog *hog, void *gatt) -@@ -1790,7 +1837,7 @@ void bt_hog_detach(struct bt_hog *hog) - if (hog->dis) - bt_dis_detach(hog->dis); - -- queue_foreach(hog->gatt_op, (void *) cancel_gatt_req, NULL); -+ queue_remove_all(hog->gatt_op, cancel_gatt_req, hog, destroy_gatt_req); - g_attrib_unref(hog->attrib); - hog->attrib = NULL; - uhid_destroy(hog); diff -Nru bluez-5.63/debian/patches/media-Fix-crash-when-endpoint-replies-with-an-error-to-Se.patch bluez-5.64/debian/patches/media-Fix-crash-when-endpoint-replies-with-an-error-to-Se.patch --- bluez-5.63/debian/patches/media-Fix-crash-when-endpoint-replies-with-an-error-to-Se.patch 2022-03-02 09:26:23.000000000 +0000 +++ bluez-5.64/debian/patches/media-Fix-crash-when-endpoint-replies-with-an-error-to-Se.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -From: Luiz Augusto von Dentz -Date: Wed, 12 Jan 2022 07:22:22 -0800 -Subject: media: Fix crash when endpoint replies with an error to - SetConfiguration - -If endpoint responds to SetConfiguration the transport is being -destroyed without removing it from the list leading a crash. - -Fixes: https://github.com/bluez/bluez/issues/269 ---- - profiles/audio/media.c | 21 +++++++++++++-------- - 1 file changed, 13 insertions(+), 8 deletions(-) - -diff --git a/profiles/audio/media.c b/profiles/audio/media.c -index edefedc..8162417 100644 ---- a/profiles/audio/media.c -+++ b/profiles/audio/media.c -@@ -241,6 +241,16 @@ static struct media_adapter *find_adapter(struct btd_device *device) - return NULL; - } - -+static void endpoint_remove_transport(struct media_endpoint *endpoint, -+ struct media_transport *transport) -+{ -+ if (!endpoint || !transport) -+ return; -+ -+ endpoint->transports = g_slist_remove(endpoint->transports, transport); -+ media_transport_destroy(transport); -+} -+ - static void clear_configuration(struct media_endpoint *endpoint, - struct media_transport *transport) - { -@@ -260,8 +270,7 @@ static void clear_configuration(struct media_endpoint *endpoint, - DBUS_TYPE_INVALID); - g_dbus_send_message(btd_get_dbus_connection(), msg); - done: -- endpoint->transports = g_slist_remove(endpoint->transports, transport); -- media_transport_destroy(transport); -+ endpoint_remove_transport(endpoint, transport); - } - - static void clear_endpoint(struct media_endpoint *endpoint) -@@ -301,12 +310,8 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) - - if (dbus_message_is_method_call(request->msg, - MEDIA_ENDPOINT_INTERFACE, -- "SetConfiguration")) { -- if (request->transport == NULL) -- error("Expected to destroy transport"); -- else -- media_transport_destroy(request->transport); -- } -+ "SetConfiguration")) -+ endpoint_remove_transport(endpoint, request->transport); - - dbus_error_free(&err); - goto done; diff -Nru bluez-5.63/debian/patches/series bluez-5.64/debian/patches/series --- bluez-5.63/debian/patches/series 2022-03-02 09:26:23.000000000 +0000 +++ bluez-5.64/debian/patches/series 2022-03-24 06:30:38.000000000 +0000 @@ -13,7 +13,3 @@ raspi-bcm43xx-load-firmware.patch raspi-bcm43xx-3wire.patch raspi-cypress-305-bdaddr.patch - -hog-Fix-read-order-of-attributes.patch -media-Fix-crash-when-endpoint-replies-with-an-error-to-Se.patch -gdbus-Emit-InterfacesAdded-of-parents-objects-first.patch diff -Nru bluez-5.63/debian/patches/ubuntu_error_restart.patch bluez-5.64/debian/patches/ubuntu_error_restart.patch --- bluez-5.63/debian/patches/ubuntu_error_restart.patch 2022-03-02 09:26:23.000000000 +0000 +++ bluez-5.64/debian/patches/ubuntu_error_restart.patch 2022-03-24 06:30:38.000000000 +0000 @@ -1,10 +1,10 @@ # Description: restart the service on errors # Upstream: not-yet # -Index: bluez-5.53/src/bluetooth.service.in +Index: bluez/src/bluetooth.service.in =================================================================== ---- bluez-5.53.orig/src/bluetooth.service.in -+++ bluez-5.53/src/bluetooth.service.in +--- bluez.orig/src/bluetooth.service.in ++++ bluez/src/bluetooth.service.in @@ -9,7 +9,7 @@ BusName=org.bluez ExecStart=@pkglibexecdir@/bluetoothd NotifyAccess=main @@ -13,4 +13,4 @@ +Restart=on-failure CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE LimitNPROC=1 - ProtectHome=true + diff -Nru bluez-5.63/doc/adapter-api.txt bluez-5.64/doc/adapter-api.txt --- bluez-5.63/doc/adapter-api.txt 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/doc/adapter-api.txt 2022-03-16 15:06:20.000000000 +0000 @@ -21,6 +21,9 @@ During discovery RSSI delta-threshold is imposed. + Each client can request a single device discovery session + per adapter. + Possible errors: org.bluez.Error.NotReady org.bluez.Error.Failed org.bluez.Error.InProgress @@ -32,7 +35,8 @@ Note that a discovery procedure is shared between all discovery sessions thus calling StopDiscovery will only - release a single session. + release a single session and discovery will stop when + all sessions from all clients have finished. Possible errors: org.bluez.Error.NotReady org.bluez.Error.Failed diff -Nru bluez-5.63/ell/base64.c bluez-5.64/ell/base64.c --- bluez-5.63/ell/base64.c 2022-01-05 21:10:31.000000000 +0000 +++ bluez-5.64/ell/base64.c 2022-02-24 20:20:21.000000000 +0000 @@ -27,56 +27,59 @@ #include "utf8.h" #include "base64.h" #include "private.h" +#include "useful.h" + +#include LIB_EXPORT uint8_t *l_base64_decode(const char *in, size_t in_len, size_t *n_written) { const char *ptr, *in_end = in + in_len; + const char *base64_end = NULL; uint8_t *out_buf, *out; - int base64_len = 0, pad_len; + int base64_len = 0, pad_len = 0; uint16_t reg = 0; - for (ptr = in; ptr < in_end; ptr++) + for (ptr = in; ptr < in_end; ptr++) { if (l_ascii_isspace(*ptr)) /* Whitespace */ continue; - else if (*ptr == '=') + else if (*ptr == '=') { /* Final padding */ - break; - else if (l_ascii_isalnum(*ptr) || *ptr == '+' || *ptr == '/') + if (!pad_len) + base64_end = ptr; + + pad_len++; + } else if (!pad_len && (l_ascii_isalnum(*ptr) || *ptr == '+' || + *ptr == '/')) /* Base64 character */ base64_len++; else /* Bad character */ return NULL; + } - in_end = ptr; + if (ptr != in_end) + return NULL; if ((base64_len & 3) == 1) /* Invalid length */ return NULL; - pad_len = (4 - base64_len) & 3; - for (; ptr < in + in_len && pad_len; ptr++) - if (l_ascii_isspace(*ptr)) - /* Whitespace */ - continue; - else if (*ptr == '=') - /* Final padding */ - pad_len--; - else - /* Bad character */ - return NULL; - if (pad_len) + if (pad_len != align_len(base64_len, 4) - base64_len) return NULL; + /* No padding */ + if (!base64_end) + base64_end = ptr; + *n_written = base64_len * 3 / 4; out_buf = l_malloc(*n_written); out = out_buf; base64_len = 0; - for (ptr = in; ptr < in_end; ptr++) { + for (ptr = in; ptr < base64_end; ptr++) { if (l_ascii_isspace(*ptr)) /* Whitespace */ continue; diff -Nru bluez-5.63/ell/cert-crypto.c bluez-5.64/ell/cert-crypto.c --- bluez-5.63/ell/cert-crypto.c 2021-03-29 12:19:13.000000000 +0000 +++ bluez-5.64/ell/cert-crypto.c 2022-02-24 20:20:21.000000000 +0000 @@ -216,7 +216,7 @@ * characters used. Recalculate p_len after we know it. * Important: The password must be valid UTF-8 here. */ - if (password) { + if (p_len) { if (!(bmpstring = l_utf8_to_ucs2be(password, &passwd_len))) { l_checksum_free(h); return NULL; diff -Nru bluez-5.63/ell/dbus-util.c bluez-5.64/ell/dbus-util.c --- bluez-5.63/ell/dbus-util.c 2021-03-29 12:19:13.000000000 +0000 +++ bluez-5.64/ell/dbus-util.c 2022-01-24 20:40:13.000000000 +0000 @@ -39,6 +39,7 @@ #include "dbus-private.h" #include "string.h" #include "queue.h" +#include "utf8.h" #define DBUS_MAX_INTERFACE_LEN 255 #define DBUS_MAX_METHOD_LEN 255 @@ -341,9 +342,18 @@ if (!l_str_has_prefix(name, ":1.")) return false; + name += 3; + + /* + * Disallow '+' or '-' at the beginning of the string + * must have at least one digit + */ + if (!l_ascii_isdigit(*name)) + return false; + errno = 0; - r = strtoull(name + 3, &endp, 10); - if (!endp || endp == name || *endp || errno) + r = strtoull(name, &endp, 10); + if (!endp || *endp || errno) return false; if (out_id) diff -Nru bluez-5.63/ell/ecc.c bluez-5.64/ell/ecc.c --- bluez-5.63/ell/ecc.c 2021-08-01 19:49:37.000000000 +0000 +++ bluez-5.64/ell/ecc.c 2022-02-24 20:20:21.000000000 +0000 @@ -534,12 +534,17 @@ { struct l_ecc_point *p; size_t bytes = curve->ndigits * 8; + uint64_t tmp[L_ECC_MAX_DIGITS]; + bool sub; if (!data) return NULL; - /* In all cases there should be an X coordinate in data */ - if (len < bytes) + /* Verify the data length matches a full point or X coordinate */ + if (type == L_ECC_POINT_TYPE_FULL) { + if (len != bytes * 2) + return NULL; + } else if (len != bytes) return NULL; p = l_ecc_point_new(curve); @@ -553,26 +558,19 @@ break; case L_ECC_POINT_TYPE_COMPRESSED_BIT0: - if (!_ecc_compute_y(curve, p->y, p->x)) - goto failed; - - if (!(p->y[0] & 1)) - _vli_mod_sub(p->y, curve->p, p->y, curve->p, - curve->ndigits); - break; case L_ECC_POINT_TYPE_COMPRESSED_BIT1: if (!_ecc_compute_y(curve, p->y, p->x)) goto failed; - if (p->y[0] & 1) - _vli_mod_sub(p->y, curve->p, p->y, curve->p, - curve->ndigits); + sub = secure_select(type == L_ECC_POINT_TYPE_COMPRESSED_BIT0, + !(p->y[0] & 1), p->y[0] & 1); + + _vli_mod_sub(tmp, curve->p, p->y, curve->p, curve->ndigits); + + l_secure_select(sub, tmp, p->y, p->y, curve->ndigits * 8); break; case L_ECC_POINT_TYPE_FULL: - if (len < bytes * 2) - goto failed; - _ecc_be2native(p->y, (void *) data + bytes, curve->ndigits); if (!ecc_valid_point(p)) @@ -734,6 +732,11 @@ return p->curve->ndigits * 8; } +LIB_EXPORT bool l_ecc_point_y_isodd(const struct l_ecc_point *p) +{ + return p->y[0] & 1; +} + LIB_EXPORT ssize_t l_ecc_point_get_data(const struct l_ecc_point *p, void *buf, size_t len) { diff -Nru bluez-5.63/ell/ecc.h bluez-5.64/ell/ecc.h --- bluez-5.63/ell/ecc.h 2021-11-02 14:41:45.000000000 +0000 +++ bluez-5.64/ell/ecc.h 2022-01-24 20:40:13.000000000 +0000 @@ -69,6 +69,7 @@ const struct l_ecc_curve *l_ecc_point_get_curve(const struct l_ecc_point *p); ssize_t l_ecc_point_get_x(const struct l_ecc_point *p, void *x, size_t xlen); ssize_t l_ecc_point_get_y(const struct l_ecc_point *p, void *y, size_t ylen); +bool l_ecc_point_y_isodd(const struct l_ecc_point *p); ssize_t l_ecc_point_get_data(const struct l_ecc_point *p, void *buf, size_t len); void l_ecc_point_free(struct l_ecc_point *p); diff -Nru bluez-5.63/ell/settings.c bluez-5.64/ell/settings.c --- bluez-5.63/ell/settings.c 2021-05-02 11:06:43.000000000 +0000 +++ bluez-5.64/ell/settings.c 2022-02-24 20:20:21.000000000 +0000 @@ -116,6 +116,63 @@ return settings; } +static void copy_key_value_foreach(void *data, void *user_data) +{ + struct setting_data *s = data; + struct l_queue *settings = user_data; + struct setting_data *copy = l_new(struct setting_data, 1); + + copy->key = l_strdup(s->key); + copy->value = l_strdup(s->value); + + l_queue_push_head(settings, copy); +} + +static void copy_group_foreach(void *data, void *user_data) +{ + struct group_data *group = data; + struct l_queue *groups = user_data; + struct group_data *copy = l_new(struct group_data, 1); + + copy->name = l_strdup(group->name); + copy->settings = l_queue_new(); + + l_queue_push_head(groups, copy); + + l_queue_foreach(group->settings, copy_key_value_foreach, + copy->settings); +} + +static void copy_embedded_foreach(void *data, void *user_data) +{ + struct embedded_group_data *embedded = data; + struct l_queue *groups = user_data; + struct embedded_group_data *copy; + + copy = l_memdup(embedded, sizeof(struct embedded_group_data) + + embedded->len + 1); + copy->name = l_strdup(embedded->name); + + l_queue_push_tail(groups, copy); +} + +LIB_EXPORT struct l_settings *l_settings_clone( + const struct l_settings *settings) +{ + struct l_settings *copy; + + if (unlikely(!settings)) + return NULL; + + copy = l_settings_new(); + + l_queue_foreach(settings->groups, copy_group_foreach, copy->groups); + l_queue_foreach(settings->embedded_groups, copy_embedded_foreach, + copy->embedded_groups); + + return copy; +} + LIB_EXPORT void l_settings_free(struct l_settings *settings) { if (unlikely(!settings)) @@ -1061,7 +1118,8 @@ } LIB_EXPORT bool l_settings_get_uint(const struct l_settings *settings, - const char *group_name, const char *key, + const char *group_name, + const char *key, unsigned int *out) { const char *value = l_settings_get_value(settings, group_name, key); @@ -1072,7 +1130,8 @@ if (!value) return false; - if (*value == '\0') + /* Do not allow '+' or '-' or empty string */ + if (!l_ascii_isdigit(*value)) goto error; errno = 0; @@ -1154,7 +1213,8 @@ } LIB_EXPORT bool l_settings_get_uint64(const struct l_settings *settings, - const char *group_name, const char *key, + const char *group_name, + const char *key, uint64_t *out) { const char *value = l_settings_get_value(settings, group_name, key); @@ -1164,7 +1224,8 @@ if (!value) return false; - if (*value == '\0') + /* Do not allow '+' or '-' or empty string */ + if (!l_ascii_isdigit(*value)) goto error; errno = 0; @@ -1500,3 +1561,13 @@ return group->data; } + +LIB_EXPORT bool l_settings_remove_embedded_groups(struct l_settings *settings) +{ + if (unlikely(!settings)) + return false; + + l_queue_clear(settings->embedded_groups, embedded_group_destroy); + + return true; +} diff -Nru bluez-5.63/ell/settings.h bluez-5.64/ell/settings.h --- bluez-5.63/ell/settings.h 2021-11-02 14:41:45.000000000 +0000 +++ bluez-5.64/ell/settings.h 2022-02-24 20:20:21.000000000 +0000 @@ -37,6 +37,8 @@ typedef void (*l_settings_destroy_cb_t) (void *user_data); struct l_settings *l_settings_new(void); +struct l_settings *l_settings_clone(const struct l_settings *settings); + void l_settings_free(struct l_settings *settings); DEFINE_CLEANUP_FUNC(l_settings_free); @@ -135,6 +137,7 @@ bool l_settings_remove_group(struct l_settings *settings, const char *group_name); +bool l_settings_remove_embedded_groups(struct l_settings *settings); char **l_settings_get_embedded_groups(struct l_settings *settings); bool l_settings_has_embedded_group(struct l_settings *settings, const char *group); diff -Nru bluez-5.63/ell/tls-suites.c bluez-5.64/ell/tls-suites.c --- bluez-5.63/ell/tls-suites.c 2021-08-01 19:49:37.000000000 +0000 +++ bluez-5.64/ell/tls-suites.c 2022-01-24 20:40:13.000000000 +0000 @@ -534,7 +534,7 @@ params->curve = l_ecc_curve_from_tls_group(tls->negotiated_curve->id); params->public = l_ecc_point_from_data(params->curve, L_ECC_POINT_TYPE_FULL, - buf, len); + buf, point_bytes); tls->pending.key_xchg_params = params; buf += point_bytes; len -= point_bytes; diff -Nru bluez-5.63/ell/utf8.c bluez-5.64/ell/utf8.c --- bluez-5.63/ell/utf8.c 2021-03-29 12:19:13.000000000 +0000 +++ bluez-5.64/ell/utf8.c 2022-02-24 20:20:21.000000000 +0000 @@ -98,7 +98,7 @@ return 1; } - expect_bytes = __builtin_clz(~((unsigned char)str[0] << 24)); + expect_bytes = __builtin_clz(~((unsigned int)str[0] << 24)); if (expect_bytes < 2 || expect_bytes > 4) goto error; diff -Nru bluez-5.63/emulator/btdev.c bluez-5.64/emulator/btdev.c --- bluez-5.63/emulator/btdev.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/btdev.c 2022-03-16 15:06:20.000000000 +0000 @@ -34,11 +34,13 @@ #include "src/shared/queue.h" #include "monitor/bt.h" #include "monitor/msft.h" +#include "monitor/emulator.h" #include "btdev.h" #define AL_SIZE 16 #define RL_SIZE 16 #define CIS_SIZE 3 +#define BIS_SIZE 3 #define has_bredr(btdev) (!((btdev)->features[4] & 0x20)) #define has_le(btdev) (!!((btdev)->features[4] & 0x40)) @@ -46,6 +48,8 @@ #define ACL_HANDLE 42 #define ISO_HANDLE 257 #define SCO_HANDLE 257 +#define SYC_HANDLE 1 +#define INV_HANDLE 0xffff struct hook { btdev_hook_func handler; @@ -62,6 +66,7 @@ uint8_t type; struct btdev *dev; struct btdev_conn *link; + void *data; }; struct btdev_al { @@ -142,6 +147,8 @@ const struct btdev_cmd *cmds; uint16_t msft_opcode; const struct btdev_cmd *msft_cmds; + uint16_t emu_opcode; + const struct btdev_cmd *emu_cmds; bool aosp_capable; uint16_t default_link_policy; @@ -186,12 +193,15 @@ uint8_t le_scan_filter_policy; uint8_t le_filter_dup; uint8_t le_adv_enable; - uint8_t le_periodic_adv_enable; - uint16_t le_periodic_adv_properties; - uint16_t le_periodic_min_interval; - uint16_t le_periodic_max_interval; - uint8_t le_periodic_data_len; - uint8_t le_periodic_data[31]; + uint8_t le_pa_enable; + uint16_t le_pa_properties; + uint16_t le_pa_min_interval; + uint16_t le_pa_max_interval; + uint8_t le_pa_data_len; + uint8_t le_pa_data[31]; + struct bt_hci_cmd_le_pa_create_sync pa_sync_cmd; + uint16_t le_pa_sync_handle; + uint8_t big_handle; uint8_t le_ltk[16]; struct { struct bt_hci_cmd_le_set_cig_params params; @@ -683,6 +693,7 @@ queue_remove(conn->dev->conns, conn); + free(conn->data); free(conn); } @@ -1114,9 +1125,65 @@ return conn_link(acl->dev, acl->link->dev, handle, HCI_ISODATA_PKT); } -static struct btdev_conn *conn_add_bis(struct btdev *dev, uint16_t handle) +static struct btdev_conn *conn_add_bis(struct btdev *dev, uint16_t handle, + const struct bt_hci_bis *bis) { - return conn_new(dev, handle, HCI_ISODATA_PKT); + struct btdev_conn *conn; + + conn = conn_new(dev, handle, HCI_ISODATA_PKT); + if (!conn) + return conn; + + conn->data = util_memdup(bis, sizeof(*bis)); + + return conn; +} + +static struct btdev_conn *find_bis_index(struct btdev *remote, uint8_t index) +{ + struct btdev_conn *conn; + const struct queue_entry *entry; + + for (entry = queue_get_entries(remote->conns); entry; + entry = entry->next) { + conn = entry->data; + + /* Skip if not a broadcast */ + if (conn->type != HCI_ISODATA_PKT || conn->link) + continue; + + if (!index) + return conn; + + index--; + } + + return NULL; +} + +static struct btdev_conn *conn_link_bis(struct btdev *dev, struct btdev *remote, + uint8_t index) +{ + struct btdev_conn *conn; + struct btdev_conn *bis; + + bis = find_bis_index(remote, index); + if (!bis) + return NULL; + + conn = conn_add_bis(dev, ISO_HANDLE, bis->data); + if (!conn) + return NULL; + + bis->link = conn; + conn->link = bis; + + util_debug(dev->debug_callback, dev->debug_data, + "bis %p handle 0x%04x", bis, bis->handle); + util_debug(dev->debug_callback, dev->debug_data, + "conn %p handle 0x%04x", conn, conn->handle); + + return conn; } static void conn_complete(struct btdev *btdev, @@ -4604,7 +4671,8 @@ const struct bt_hci_cmd_le_set_ext_adv_params *cmd = data; struct bt_hci_rsp_le_set_ext_adv_params rsp; struct le_ext_adv *ext_adv; - uint8_t status; + + memset(&rsp, 0, sizeof(rsp)); /* Check if Ext Adv is already existed */ ext_adv = queue_find(dev->le_ext_adv, match_ext_adv_handle, @@ -4612,26 +4680,26 @@ if (!ext_adv) { /* No more than maximum number */ if (queue_length(dev->le_ext_adv) >= MAX_EXT_ADV_SETS) { - status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + rsp.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; cmd_complete(dev, BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS, - &status, sizeof(status)); + &rsp, sizeof(rsp)); return 0; } /* Create new set */ ext_adv = le_ext_adv_new(dev, cmd->handle); if (!ext_adv) { - status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + rsp.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; cmd_complete(dev, BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS, - &status, sizeof(status)); + &rsp, sizeof(rsp)); return 0; } } if (ext_adv->enable) { - status = BT_HCI_ERR_COMMAND_DISALLOWED; - cmd_complete(dev, BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS, &status, - sizeof(status)); + rsp.status = BT_HCI_ERR_COMMAND_DISALLOWED; + cmd_complete(dev, BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS, &rsp, + sizeof(rsp)); return 0; } @@ -5003,56 +5071,131 @@ return 0; } -static int cmd_set_per_adv_params(struct btdev *dev, const void *data, +static int cmd_set_pa_params(struct btdev *dev, const void *data, uint8_t len) { - const struct bt_hci_cmd_le_set_periodic_adv_params *cmd = data; + const struct bt_hci_cmd_le_set_pa_params *cmd = data; uint8_t status; - if (dev->le_periodic_adv_enable) { + if (dev->le_pa_enable) { status = BT_HCI_ERR_COMMAND_DISALLOWED; } else { status = BT_HCI_ERR_SUCCESS; - dev->le_periodic_adv_properties = le16_to_cpu(cmd->properties); - dev->le_periodic_min_interval = cmd->min_interval; - dev->le_periodic_max_interval = cmd->max_interval; + dev->le_pa_properties = le16_to_cpu(cmd->properties); + dev->le_pa_min_interval = cmd->min_interval; + dev->le_pa_max_interval = cmd->max_interval; } - cmd_complete(dev, BT_HCI_CMD_LE_SET_PERIODIC_ADV_PARAMS, &status, + cmd_complete(dev, BT_HCI_CMD_LE_SET_PA_PARAMS, &status, sizeof(status)); return 0; } -static int cmd_set_per_adv_data(struct btdev *dev, const void *data, +static int cmd_set_pa_data(struct btdev *dev, const void *data, uint8_t len) { - const struct bt_hci_cmd_le_set_periodic_adv_data *cmd = data; + const struct bt_hci_cmd_le_set_pa_data *cmd = data; uint8_t status = BT_HCI_ERR_SUCCESS; - dev->le_periodic_data_len = cmd->data_len; - memcpy(dev->le_periodic_data, cmd->data, 31); - cmd_complete(dev, BT_HCI_CMD_LE_SET_PERIODIC_ADV_DATA, &status, + dev->le_pa_data_len = cmd->data_len; + memcpy(dev->le_pa_data, cmd->data, 31); + cmd_complete(dev, BT_HCI_CMD_LE_SET_PA_DATA, &status, sizeof(status)); return 0; } -static int cmd_set_per_adv_enable(struct btdev *dev, const void *data, - uint8_t len) +static void send_pa(struct btdev *dev, const struct btdev *remote, + uint8_t offset) +{ + struct __packed { + struct bt_hci_le_pa_report ev; + uint8_t data[31]; + } pdu; + + memset(&pdu.ev, 0, sizeof(pdu.ev)); + pdu.ev.handle = cpu_to_le16(dev->le_pa_sync_handle); + pdu.ev.tx_power = 127; + pdu.ev.rssi = 127; + pdu.ev.cte_type = 0x0ff; + + if ((size_t) remote->le_pa_data_len - offset > sizeof(pdu.data)) { + pdu.ev.data_status = 0x01; + pdu.ev.data_len = sizeof(pdu.data); + } else { + pdu.ev.data_status = 0x00; + pdu.ev.data_len = remote->le_pa_data_len - offset; + } + + memcpy(pdu.data, remote->le_pa_data + offset, pdu.ev.data_len); + + le_meta_event(dev, BT_HCI_EVT_LE_PA_REPORT, &pdu, + sizeof(pdu.ev) + pdu.ev.data_len); + + if (pdu.ev.data_status == 0x01) { + offset += pdu.ev.data_len; + send_pa(dev, remote, offset); + } +} + +static void le_pa_sync_estabilished(struct btdev *dev, struct btdev *remote, + uint8_t status) +{ + struct bt_hci_evt_le_per_sync_established ev; + struct bt_hci_cmd_le_pa_create_sync *cmd = &dev->pa_sync_cmd; + + memset(&ev, 0, sizeof(ev)); + ev.status = status; + + if (status) { + memset(&dev->pa_sync_cmd, 0, sizeof(dev->pa_sync_cmd)); + dev->le_pa_sync_handle = 0x0000; + le_meta_event(dev, BT_HCI_EVT_LE_PA_SYNC_ESTABLISHED, &ev, + sizeof(ev)); + return; + } + + dev->le_pa_sync_handle = SYC_HANDLE; + + ev.handle = cpu_to_le16(dev->le_pa_sync_handle); + ev.addr_type = cmd->addr_type; + memcpy(ev.addr, cmd->addr, sizeof(ev.addr)); + ev.phy = 0x01; + ev.interval = remote->le_pa_min_interval; + ev.clock_accuracy = 0x07; + + le_meta_event(dev, BT_HCI_EVT_LE_PA_SYNC_ESTABLISHED, &ev, sizeof(ev)); + send_pa(dev, remote, 0); +} + +static int cmd_set_pa_enable(struct btdev *dev, const void *data, uint8_t len) { - const struct bt_hci_cmd_le_set_periodic_adv_enable *cmd = data; + const struct bt_hci_cmd_le_set_pa_enable *cmd = data; uint8_t status; + int i; - if (dev->le_periodic_adv_enable == cmd->enable) { + if (dev->le_pa_enable == cmd->enable) { status = BT_HCI_ERR_COMMAND_DISALLOWED; } else { - dev->le_periodic_adv_enable = cmd->enable; + dev->le_pa_enable = cmd->enable; status = BT_HCI_ERR_SUCCESS; } - cmd_complete(dev, BT_HCI_CMD_LE_SET_PERIODIC_ADV_ENABLE, &status, + cmd_complete(dev, BT_HCI_CMD_LE_SET_PA_ENABLE, &status, sizeof(status)); + for (i = 0; i < MAX_BTDEV_ENTRIES; i++) { + struct btdev *remote = btdev_list[i]; + + if (!remote || remote == dev) + continue; + + if (remote->le_scan_enable && + remote->le_pa_sync_handle == INV_HANDLE) + le_pa_sync_estabilished(remote, dev, + BT_HCI_ERR_SUCCESS); + } + return 0; } @@ -5154,6 +5297,18 @@ } } +static void scan_pa(struct btdev *dev, struct btdev *remote) +{ + if (dev->le_pa_sync_handle != INV_HANDLE || !remote->le_pa_enable) + return; + + if (remote != find_btdev_by_bdaddr_type(dev->pa_sync_cmd.addr, + dev->pa_sync_cmd.addr_type)) + return; + + le_pa_sync_estabilished(dev, remote, BT_HCI_ERR_SUCCESS); +} + static int cmd_set_ext_scan_enable_complete(struct btdev *dev, const void *data, uint8_t len) { @@ -5168,6 +5323,7 @@ continue; scan_ext_adv(dev, btdev_list[i]); + scan_pa(dev, btdev_list[i]); } return 0; @@ -5288,46 +5444,110 @@ return 0; } -static int cmd_per_adv_create_sync(struct btdev *dev, const void *data, - uint8_t len) +static int cmd_pa_create_sync(struct btdev *dev, const void *data, uint8_t len) { - /* TODO */ - return -ENOTSUP; + uint8_t status = BT_HCI_ERR_SUCCESS; + + if (dev->le_pa_sync_handle) + status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + else { + dev->le_pa_sync_handle = INV_HANDLE; + memcpy(&dev->pa_sync_cmd, data, len); + } + + cmd_status(dev, status, BT_HCI_CMD_LE_PA_CREATE_SYNC); + + return 0; } -static int cmd_per_adv_create_sync_cancel(struct btdev *dev, const void *data, +static int cmd_pa_create_sync_complete(struct btdev *dev, const void *data, uint8_t len) { - /* TODO */ - return -ENOTSUP; + const struct bt_hci_cmd_le_pa_create_sync *cmd = data; + struct btdev *remote; + + /* This command may be issued whether or not scanning is enabled and + * scanning may be enabled and disabled (see the LE Set Extended Scan + * Enable command) while this command is pending. However, + * synchronization can only occur when scanning is enabled. While + * scanning is disabled, no attempt to synchronize will take place. + */ + if (!dev->scan_enable) + return 0; + + remote = find_btdev_by_bdaddr_type(cmd->addr, cmd->addr_type); + if (!remote || !remote->le_pa_enable) + return 0; + + le_pa_sync_estabilished(dev, remote, BT_HCI_ERR_SUCCESS); + + return 0; } -static int cmd_per_adv_term_sync(struct btdev *dev, const void *data, +static int cmd_pa_create_sync_cancel(struct btdev *dev, const void *data, uint8_t len) { - /* TODO */ - return -ENOTSUP; + uint8_t status = BT_HCI_ERR_SUCCESS; + + /* If the Host issues this command while no + * HCI_LE_Periodic_Advertising_Create_Sync command is pending, the + * Controller shall return the error code Command Disallowed (0x0C). + */ + if (dev->le_pa_sync_handle != INV_HANDLE) + status = BT_HCI_ERR_COMMAND_DISALLOWED; + + cmd_complete(dev, BT_HCI_CMD_LE_PA_CREATE_SYNC_CANCEL, + &status, sizeof(status)); + + /* After the HCI_Command_Complete is sent and if the cancellation was + * successful, the Controller sends an + * HCI_LE_Periodic_Advertising_Sync_Established event to the Host with + * the error code Operation Cancelled by Host (0x44). + */ + if (!status) + le_pa_sync_estabilished(dev, NULL, BT_HCI_ERR_CANCELLED); + + return 0; } -static int cmd_per_adv_add(struct btdev *dev, const void *data, uint8_t len) +static int cmd_pa_term_sync(struct btdev *dev, const void *data, uint8_t len) +{ + uint8_t status = BT_HCI_ERR_SUCCESS; + + /* If the periodic advertising train corresponding to the Sync_Handle + * parameter does not exist, then the Controller shall return the error + * code Unknown Advertising Identifier (0x42). + */ + if (dev->le_pa_sync_handle != SYC_HANDLE) + status = BT_HCI_ERR_UNKNOWN_ADVERTISING_ID; + else + dev->le_pa_sync_handle = 0x0000; + + cmd_complete(dev, BT_HCI_CMD_LE_PA_TERM_SYNC, + &status, sizeof(status)); + + return 0; +} + +static int cmd_pa_add(struct btdev *dev, const void *data, uint8_t len) { /* TODO */ return -ENOTSUP; } -static int cmd_per_adv_remove(struct btdev *dev, const void *data, uint8_t len) +static int cmd_pa_remove(struct btdev *dev, const void *data, uint8_t len) { /* TODO */ return -ENOTSUP; } -static int cmd_per_adv_clear(struct btdev *dev, const void *data, uint8_t len) +static int cmd_pa_clear(struct btdev *dev, const void *data, uint8_t len) { /* TODO */ return -ENOTSUP; } -static int cmd_read_per_adv_list_size(struct btdev *dev, const void *data, +static int cmd_read_pa_list_size(struct btdev *dev, const void *data, uint8_t len) { /* TODO */ @@ -5406,28 +5626,24 @@ NULL), \ CMD(BT_HCI_CMD_LE_REMOVE_ADV_SET, cmd_remove_adv_set, NULL), \ CMD(BT_HCI_CMD_LE_CLEAR_ADV_SETS, cmd_clear_adv_sets, NULL), \ - CMD(BT_HCI_CMD_LE_SET_PERIODIC_ADV_PARAMS, cmd_set_per_adv_params, \ - NULL), \ - CMD(BT_HCI_CMD_LE_SET_PERIODIC_ADV_DATA, cmd_set_per_adv_data, NULL), \ - CMD(BT_HCI_CMD_LE_SET_PERIODIC_ADV_ENABLE, cmd_set_per_adv_enable, \ + CMD(BT_HCI_CMD_LE_SET_PA_PARAMS, cmd_set_pa_params, \ NULL), \ + CMD(BT_HCI_CMD_LE_SET_PA_DATA, cmd_set_pa_data, NULL), \ + CMD(BT_HCI_CMD_LE_SET_PA_ENABLE, cmd_set_pa_enable, NULL), \ CMD(BT_HCI_CMD_LE_SET_EXT_SCAN_PARAMS, cmd_set_ext_scan_params, NULL), \ CMD(BT_HCI_CMD_LE_SET_EXT_SCAN_ENABLE, cmd_set_ext_scan_enable, \ cmd_set_ext_scan_enable_complete), \ CMD(BT_HCI_CMD_LE_EXT_CREATE_CONN, cmd_ext_create_conn, \ cmd_ext_create_conn_complete), \ - CMD(BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC, cmd_per_adv_create_sync, \ - NULL), \ - CMD(BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC_CANCEL, \ - cmd_per_adv_create_sync_cancel, NULL), \ - CMD(BT_HCI_CMD_LE_PERIODIC_ADV_TERM_SYNC, cmd_per_adv_term_sync, \ + CMD(BT_HCI_CMD_LE_PA_CREATE_SYNC, cmd_pa_create_sync, \ + cmd_pa_create_sync_complete), \ + CMD(BT_HCI_CMD_LE_PA_CREATE_SYNC_CANCEL, cmd_pa_create_sync_cancel, \ NULL), \ - CMD(BT_HCI_CMD_LE_ADD_DEV_PERIODIC_ADV_LIST, cmd_per_adv_add, NULL), \ - CMD(BT_HCI_CMD_LE_REMOVE_DEV_PERIODIC_ADV_LIST, cmd_per_adv_remove, \ - NULL), \ - CMD(BT_HCI_CMD_LE_CLEAR_PERIODIC_ADV_LIST, cmd_per_adv_clear, NULL), \ - CMD(BT_HCI_CMD_LE_READ_PERIODIC_ADV_LIST_SIZE, \ - cmd_read_per_adv_list_size, NULL), \ + CMD(BT_HCI_CMD_LE_PA_TERM_SYNC, cmd_pa_term_sync, NULL), \ + CMD(BT_HCI_CMD_LE_ADD_DEV_PA_LIST, cmd_pa_add, NULL), \ + CMD(BT_HCI_CMD_LE_REMOVE_DEV_PA_LIST, cmd_pa_remove, NULL), \ + CMD(BT_HCI_CMD_LE_CLEAR_PA_LIST, cmd_pa_clear, NULL), \ + CMD(BT_HCI_CMD_LE_READ_PA_LIST_SIZE, cmd_read_pa_list_size, NULL), \ CMD(BT_HCI_CMD_LE_READ_TX_POWER, cmd_read_tx_power, NULL), \ CMD(BT_HCI_CMD_LE_SET_PRIV_MODE, cmd_set_privacy_mode, NULL) @@ -5627,13 +5843,14 @@ static int cmd_remove_cig(struct btdev *dev, const void *data, uint8_t len) { + const struct bt_hci_cmd_le_remove_cig *cmd = data; struct bt_hci_rsp_le_remove_cig rsp; memset(&dev->le_cig, 0, sizeof(dev->le_cig)); memset(&rsp, 0, sizeof(rsp)); rsp.status = BT_HCI_ERR_SUCCESS; - rsp.cig_id = 0x00; + rsp.cig_id = cmd->cig_id; cmd_complete(dev, BT_HCI_CMD_LE_REMOVE_CIG, &rsp, sizeof(rsp)); return 0; @@ -5688,10 +5905,10 @@ uint8_t len) { const struct bt_hci_cmd_le_create_big *cmd = data; + const struct bt_hci_bis *bis = &cmd->bis; int i; for (i = 0; i < cmd->num_bis; i++) { - const struct bt_hci_bis *bis = &cmd->bis[i]; struct btdev_conn *conn; struct { struct bt_hci_evt_le_big_complete evt; @@ -5700,14 +5917,14 @@ memset(&pdu, 0, sizeof(pdu)); - conn = conn_add_bis(dev, ISO_HANDLE); + conn = conn_add_bis(dev, ISO_HANDLE, bis); if (!conn) { pdu.evt.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; goto done; } pdu.evt.handle = cmd->handle; - pdu.evt.num_bis = 0x01; + pdu.evt.num_bis++; pdu.evt.phy = bis->phy; pdu.evt.max_pdu = bis->sdu; memcpy(pdu.evt.sync_delay, bis->sdu_interval, 3); @@ -5730,20 +5947,152 @@ static int cmd_term_big(struct btdev *dev, const void *data, uint8_t len) { - /* TODO */ - return -ENOTSUP; + cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_LE_TERM_BIG); + + return 0; +} + +static int cmd_term_big_complete(struct btdev *dev, const void *data, + uint8_t len) +{ + const struct bt_hci_cmd_le_term_big *cmd = data; + struct bt_hci_evt_le_big_terminate rsp; + + memset(&rsp, 0, sizeof(rsp)); + rsp.reason = cmd->reason; + rsp.handle = cmd->handle; + + le_meta_event(dev, BT_HCI_EVT_LE_BIG_TERMINATE, &rsp, sizeof(rsp)); + + return 0; } static int cmd_big_create_sync(struct btdev *dev, const void *data, uint8_t len) { - /* TODO */ - return -ENOTSUP; + const struct bt_hci_cmd_le_big_create_sync *cmd = data; + uint8_t status = BT_HCI_ERR_SUCCESS; + + /* If the Sync_Handle does not exist, the Controller shall return the + * error code Unknown Advertising Identifier (0x42). + */ + if (dev->le_pa_sync_handle != le16_to_cpu(cmd->sync_handle)) + status = BT_HCI_ERR_UNKNOWN_ADVERTISING_ID; + + /* If the Host sends this command with a BIG_Handle that is already + * allocated, the Controller shall return the error code Command + * Disallowed (0x0C). + */ + if (dev->big_handle == cmd->handle) + status = BT_HCI_ERR_COMMAND_DISALLOWED; + + /* If the Num_BIS parameter is greater than the total number of BISes + * in the BIG, the Controller shall return the error code Unsupported + * Feature or Parameter Value (0x11). + */ + if (cmd->num_bis != len - sizeof(*cmd)) + status = BT_HCI_ERR_UNSUPPORTED_FEATURE; + + if (status) + return status; + + cmd_status(dev, status, BT_HCI_CMD_LE_BIG_CREATE_SYNC); + + return status; +} + +static int cmd_big_create_sync_complete(struct btdev *dev, const void *data, + uint8_t len) +{ + const struct bt_hci_cmd_le_big_create_sync *cmd = data; + struct __packed { + struct bt_hci_evt_le_big_sync_estabilished ev; + uint16_t bis[BIS_SIZE]; + } pdu; + struct btdev *remote; + struct btdev_conn *conn = NULL; + struct bt_hci_bis *bis; + int i; + + remote = find_btdev_by_bdaddr_type(dev->pa_sync_cmd.addr, + dev->pa_sync_cmd.addr_type); + if (!remote) + return 0; + + memset(&pdu.ev, 0, sizeof(pdu.ev)); + + for (i = 0; i < cmd->num_bis; i++) { + conn = conn_link_bis(dev, remote, i); + if (!conn) + break; + + pdu.bis[i] = cpu_to_le16(conn->handle); + } + + if (i != cmd->num_bis || !conn) { + pdu.ev.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + le_meta_event(dev, BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED, &pdu, + sizeof(pdu.ev)); + return 0; + } + + dev->big_handle = cmd->handle; + bis = conn->data; + + pdu.ev.handle = cmd->handle; + memcpy(pdu.ev.latency, bis->sdu_interval, sizeof(pdu.ev.interval)); + pdu.ev.nse = 0x01; + pdu.ev.bn = 0x01; + pdu.ev.pto = 0x00; + pdu.ev.irc = 0x01; + pdu.ev.max_pdu = bis->sdu; + pdu.ev.interval = bis->latency; + pdu.ev.num_bis = cmd->num_bis; + + le_meta_event(dev, BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED, &pdu, + sizeof(pdu.ev) + (cmd->num_bis * sizeof(uint16_t))); + + return 0; } static int cmd_big_term_sync(struct btdev *dev, const void *data, uint8_t len) { - /* TODO */ - return -ENOTSUP; + const struct bt_hci_cmd_le_big_term_sync *cmd = data; + struct bt_hci_rsp_le_big_term_sync rsp; + const struct queue_entry *entry; + + memset(&rsp, 0, sizeof(rsp)); + + /* If the Host issues this command with a BIG_Handle that does not + * exist, the Controller shall return the error code Unknown + * Advertising Identifier (0x42). + */ + if (dev->big_handle != cmd->handle) { + rsp.status = BT_HCI_ERR_UNKNOWN_ADVERTISING_ID; + goto done; + } + + rsp.status = BT_HCI_ERR_COMMAND_DISALLOWED; + rsp.handle = cmd->handle; + + /* Cleanup existing connections */ + for (entry = queue_get_entries(dev->conns); entry; + entry = entry->next) { + struct btdev_conn *conn = entry->data; + + if (!conn->data) + continue; + + rsp.status = BT_HCI_ERR_SUCCESS; + disconnect_complete(dev, conn->handle, BT_HCI_ERR_SUCCESS, + 0x16); + + conn_remove(conn); + } + +done: + cmd_complete(dev, BT_HCI_CMD_LE_BIG_TERM_SYNC, &rsp, sizeof(rsp)); + + return 0; } static int cmd_req_peer_sca(struct btdev *dev, const void *data, uint8_t len) @@ -5950,8 +6299,9 @@ CMD(BT_HCI_CMD_LE_CREATE_BIG, cmd_create_big, \ cmd_create_big_complete), \ CMD(BT_HCI_CMD_LE_CREATE_BIG_TEST, cmd_create_big_test, NULL), \ - CMD(BT_HCI_CMD_LE_TERM_BIG, cmd_term_big, NULL), \ - CMD(BT_HCI_CMD_LE_BIG_CREATE_SYNC, cmd_big_create_sync, NULL), \ + CMD(BT_HCI_CMD_LE_TERM_BIG, cmd_term_big, cmd_term_big_complete), \ + CMD(BT_HCI_CMD_LE_BIG_CREATE_SYNC, cmd_big_create_sync, \ + cmd_big_create_sync_complete), \ CMD(BT_HCI_CMD_LE_BIG_TERM_SYNC, cmd_big_term_sync, NULL), \ CMD(BT_HCI_CMD_LE_REQ_PEER_SCA, cmd_req_peer_sca, NULL), \ CMD(BT_HCI_CMD_LE_SETUP_ISO_PATH, cmd_setup_iso_path, NULL), \ @@ -6586,12 +6936,11 @@ return NULL; } -static const struct btdev_cmd *msft_cmd(struct btdev *btdev, const void *data, - uint8_t len) +static const struct btdev_cmd *vnd_cmd(struct btdev *btdev, uint8_t op, + const struct btdev_cmd *cmd, + const void *data, uint8_t len) { - const struct btdev_cmd *cmd; - - for (cmd = btdev->msft_cmds; cmd->func; cmd++) { + for (; cmd && cmd->func; cmd++) { if (cmd->opcode != ((uint8_t *)data)[0]) continue; @@ -6599,10 +6948,10 @@ } util_debug(btdev->debug_callback, btdev->debug_data, - "Unsupported MSFT subcommand 0x%2.2x\n", + "Unsupported Vendor subcommand 0x%2.2x\n", ((uint8_t *)data)[0]); - cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, btdev->msft_opcode); + cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, op); return NULL; } @@ -6612,8 +6961,11 @@ { const struct btdev_cmd *cmd; + if (btdev->emu_opcode == opcode) + return vnd_cmd(btdev, opcode, btdev->emu_cmds, data, len); + if (btdev->msft_opcode == opcode) - return msft_cmd(btdev, data, len); + return vnd_cmd(btdev, opcode, btdev->msft_cmds, data, len); for (cmd = btdev->cmds; cmd->func; cmd++) { if (cmd->opcode != opcode) @@ -7049,3 +7401,50 @@ return 0; } + +static int cmd_emu_test_event(struct btdev *dev, const void *data, uint8_t len) +{ + const struct emu_cmd_test_event *cmd = data; + uint8_t status = BT_HCI_ERR_SUCCESS; + + if (len < sizeof(*cmd)) { + status = BT_HCI_ERR_INVALID_PARAMETERS; + goto done; + } + + send_event(dev, cmd->evt, cmd->data, len - sizeof(*cmd)); + +done: + cmd_complete(dev, dev->emu_opcode, &status, sizeof(status)); + + return 0; +} + +#define CMD_EMU \ + CMD(EMU_SUBCMD_TEST_EVENT, cmd_emu_test_event, NULL) + +static const struct btdev_cmd cmd_emu[] = { + CMD_EMU, + {} +}; + +int btdev_set_emu_opcode(struct btdev *btdev, uint16_t opcode) +{ + if (!btdev) + return -EINVAL; + + switch (btdev->type) { + case BTDEV_TYPE_BREDRLE: + case BTDEV_TYPE_BREDRLE50: + case BTDEV_TYPE_BREDRLE52: + btdev->emu_opcode = opcode; + btdev->emu_cmds = cmd_emu; + return 0; + case BTDEV_TYPE_BREDR: + case BTDEV_TYPE_LE: + case BTDEV_TYPE_AMP: + case BTDEV_TYPE_BREDR20: + default: + return -ENOTSUP; + } +} diff -Nru bluez-5.63/emulator/btdev.h bluez-5.64/emulator/btdev.h --- bluez-5.63/emulator/btdev.h 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/btdev.h 2022-03-16 15:06:20.000000000 +0000 @@ -102,3 +102,4 @@ int btdev_set_msft_opcode(struct btdev *btdev, uint16_t opcode); int btdev_set_aosp_capable(struct btdev *btdev, bool enable); +int btdev_set_emu_opcode(struct btdev *btdev, uint16_t opcode); diff -Nru bluez-5.63/emulator/bthost.c bluez-5.64/emulator/bthost.c --- bluez-5.63/emulator/bthost.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/bthost.c 2022-03-16 15:06:20.000000000 +0000 @@ -37,6 +37,9 @@ #define acl_handle(h) (h & 0x0fff) #define acl_flags(h) (h >> 12) +#define iso_flags_pb(f) (f & 0x0003) +#define iso_data_len_pack(h, f) ((uint16_t) ((h) | ((f) << 14))) + #define L2CAP_FEAT_FIXED_CHAN 0x00000080 #define L2CAP_FC_SIG_BREDR 0x02 #define L2CAP_FC_SMP_BREDR 0x80 @@ -131,6 +134,11 @@ struct rfcomm_chan_hook *next; }; +struct iso_hook { + bthost_cid_hook_func_t func; + void *user_data; +}; + struct btconn { uint16_t handle; uint8_t bdaddr[6]; @@ -142,8 +150,12 @@ struct rcconn *rcconns; struct cid_hook *cid_hooks; struct rfcomm_chan_hook *rfcomm_chan_hooks; + struct iso_hook *iso_hook; struct btconn *next; void *smp_data; + uint16_t recv_len; + uint16_t data_len; + void *recv_data; }; struct l2conn { @@ -211,6 +223,8 @@ void *cmd_complete_data; bthost_new_conn_cb new_conn_cb; void *new_conn_data; + bthost_new_conn_cb new_iso_cb; + void *new_iso_data; struct rfcomm_connection_data *rfcomm_conn_data; struct l2cap_conn_cb_data *new_l2cap_conn_data; struct rfcomm_conn_cb_data *new_rfcomm_conn_data; @@ -292,6 +306,8 @@ free(hook); } + free(conn->iso_hook); + free(conn->recv_data); free(conn); } @@ -659,6 +675,28 @@ conn->cid_hooks = hook; } +void bthost_add_iso_hook(struct bthost *bthost, uint16_t handle, + bthost_cid_hook_func_t func, void *user_data) +{ + struct iso_hook *hook; + struct btconn *conn; + + conn = bthost_find_conn(bthost, handle); + if (!conn || conn->iso_hook) + return; + + hook = malloc(sizeof(*hook)); + if (!hook) + return; + + memset(hook, 0, sizeof(*hook)); + + hook->func = func; + hook->user_data = user_data; + + conn->iso_hook = hook; +} + void bthost_send_cid(struct bthost *bthost, uint16_t handle, uint16_t cid, const void *data, uint16_t len) { @@ -683,6 +721,52 @@ send_iov(bthost, handle, cid, iov, iovcnt); } +static void send_iso(struct bthost *bthost, uint16_t handle, + const struct iovec *iov, int iovcnt) +{ + struct bt_hci_iso_hdr iso_hdr; + struct bt_hci_iso_data_start data_hdr; + uint8_t pkt = BT_H4_ISO_PKT; + struct iovec pdu[3 + iovcnt]; + int i, len = 0; + static uint16_t sn; + + for (i = 0; i < iovcnt; i++) { + pdu[3 + i].iov_base = iov[i].iov_base; + pdu[3 + i].iov_len = iov[i].iov_len; + len += iov[i].iov_len; + } + + pdu[0].iov_base = &pkt; + pdu[0].iov_len = sizeof(pkt); + + iso_hdr.handle = acl_handle_pack(handle, 0x02); + iso_hdr.dlen = cpu_to_le16(len + sizeof(data_hdr)); + + pdu[1].iov_base = &iso_hdr; + pdu[1].iov_len = sizeof(iso_hdr); + + data_hdr.sn = cpu_to_le16(sn++); + data_hdr.slen = cpu_to_le16(iso_data_len_pack(len, 0)); + + pdu[2].iov_base = &data_hdr; + pdu[2].iov_len = sizeof(data_hdr); + + send_packet(bthost, pdu, 3 + iovcnt); +} + +void bthost_send_iso(struct bthost *bthost, uint16_t handle, + const struct iovec *iov, int iovcnt) +{ + struct btconn *conn; + + conn = bthost_find_conn(bthost, handle); + if (!conn) + return; + + send_iso(bthost, handle, iov, iovcnt); +} + bool bthost_l2cap_req(struct bthost *bthost, uint16_t handle, uint8_t code, const void *data, uint16_t len, bthost_l2cap_rsp_cb cb, void *user_data) @@ -922,6 +1006,10 @@ break; case BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE: break; + case BT_HCI_CMD_LE_SET_PA_PARAMS: + break; + case BT_HCI_CMD_LE_SET_PA_ENABLE: + break; default: bthost_debug(bthost, "Unhandled cmd_complete opcode 0x%04x", opcode); @@ -1333,6 +1421,40 @@ sizeof(cp)); } +static void init_iso(struct bthost *bthost, uint16_t handle, + const uint8_t *bdaddr, uint8_t addr_type) +{ + struct btconn *conn; + + bthost_debug(bthost, "ISO handle 0x%4.4x", handle); + + conn = malloc(sizeof(*conn)); + if (!conn) + return; + + memset(conn, 0, sizeof(*conn)); + conn->handle = handle; + memcpy(conn->bdaddr, bdaddr, 6); + conn->addr_type = addr_type; + + conn->next = bthost->conns; + bthost->conns = conn; + + if (bthost->new_iso_cb) + bthost->new_iso_cb(handle, bthost->new_iso_data); +} + +static void evt_le_cis_established(struct bthost *bthost, const void *data, + uint8_t size) +{ + const struct bt_hci_evt_le_cis_established *ev = data; + + if (ev->status) + return; + + init_iso(bthost, ev->conn_handle, BDADDR_ANY->b, BDADDR_LE_PUBLIC); +} + static void evt_le_cis_req(struct bthost *bthost, const void *data, uint8_t len) { const struct bt_hci_evt_le_cis_req *ev = data; @@ -1380,6 +1502,38 @@ } } +static void evt_le_big_complete(struct bthost *bthost, const void *data, + uint8_t size) +{ + const struct bt_hci_evt_le_big_complete *ev = data; + int i; + + if (ev->status) + return; + + for (i = 0; i < ev->num_bis; i++) { + uint16_t handle = le16_to_cpu(ev->bis_handle[i]); + + init_iso(bthost, handle, BDADDR_ANY->b, BDADDR_LE_PUBLIC); + } +} + +static void evt_le_big_sync_established(struct bthost *bthost, + const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_big_sync_estabilished *ev = data; + int i; + + if (ev->status) + return; + + for (i = 0; i < ev->num_bis; i++) { + uint16_t handle = le16_to_cpu(ev->bis[i]); + + init_iso(bthost, handle, BDADDR_ANY->b, BDADDR_LE_PUBLIC); + } +} + static void evt_le_meta_event(struct bthost *bthost, const void *data, uint8_t len) { @@ -1389,7 +1543,7 @@ if (len < 1) return; - bthost_debug(bthost, "event 0x%02x", *event); + bthost_debug(bthost, "meta event 0x%02x", *event); switch (*event) { case BT_HCI_EVT_LE_CONN_COMPLETE: @@ -1410,9 +1564,18 @@ case BT_HCI_EVT_LE_EXT_ADV_REPORT: evt_le_ext_adv_report(bthost, evt_data, len - 1); break; + case BT_HCI_EVT_LE_CIS_ESTABLISHED: + evt_le_cis_established(bthost, evt_data, len - 1); + break; case BT_HCI_EVT_LE_CIS_REQ: evt_le_cis_req(bthost, evt_data, len - 1); break; + case BT_HCI_EVT_LE_BIG_COMPLETE: + evt_le_big_complete(bthost, evt_data, len - 1); + break; + case BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED: + evt_le_big_sync_established(bthost, evt_data, len - 1); + break; default: bthost_debug(bthost, "Unsupported LE Meta event 0x%2.2x", *event); @@ -2318,7 +2481,7 @@ pn_cmd.ack_timer = pn->ack_timer; pn_cmd.max_retrans = pn->max_retrans; pn_cmd.mtu = pn->mtu; - pn_cmd.credits = pn->credits; + pn_cmd.credits = 255; rfcomm_uih_send(bthost, conn, l2conn, RFCOMM_ADDR(1, 0), RFCOMM_MCC_TYPE(0, RFCOMM_PN), &pn_cmd, sizeof(pn_cmd)); @@ -2369,20 +2532,25 @@ uint16_t hdr_len, data_len; const void *p; - if (len < sizeof(*hdr)) + if (len < sizeof(*hdr)) { + bthost_debug(bthost, "RFCOMM UIH: too short"); return; + } if (RFCOMM_TEST_EA(hdr->length)) { data_len = (uint16_t) GET_LEN8(hdr->length); hdr_len = sizeof(*hdr); } else { uint8_t ex_len = *((uint8_t *)(data + sizeof(*hdr))); - data_len = ((uint16_t) hdr->length << 8) | ex_len; + data_len = GET_LEN16((((uint16_t) ex_len << 8) | hdr->length)); hdr_len = sizeof(*hdr) + sizeof(uint8_t); } - if (len < hdr_len + data_len) + if (len < hdr_len + data_len) { + bthost_debug(bthost, "RFCOMM UIH: %u != %u", len, + hdr_len + data_len); return; + } p = data + hdr_len; @@ -2404,6 +2572,8 @@ { const struct rfcomm_hdr *hdr = data; + bthost_debug(bthost, "RFCOMM data: %u bytes", len); + switch (RFCOMM_GET_TYPE(hdr->control)) { case RFCOMM_SABM: rfcomm_sabm_recv(bthost, conn, l2conn, data, len); @@ -2426,62 +2596,49 @@ } } -static void process_acl(struct bthost *bthost, const void *data, uint16_t len) +static void process_l2cap(struct bthost *bthost, struct btconn *conn, + const void *data, uint16_t len) { - const struct bt_hci_acl_hdr *acl_hdr = data; - const struct bt_l2cap_hdr *l2_hdr = data + sizeof(*acl_hdr); - uint16_t handle, cid, acl_len, l2_len; + const struct bt_l2cap_hdr *l2_hdr = data; struct cid_hook *hook; - struct btconn *conn; struct l2conn *l2conn; - const void *l2_data; - - if (len < sizeof(*acl_hdr) + sizeof(*l2_hdr)) - return; - - acl_len = le16_to_cpu(acl_hdr->dlen); - if (len != sizeof(*acl_hdr) + acl_len) - return; - - handle = acl_handle(acl_hdr->handle); - conn = bthost_find_conn(bthost, handle); - if (!conn) { - bthost_debug(bthost, "ACL data for unknown handle 0x%04x", - handle); - return; - } + uint16_t cid, l2_len; l2_len = le16_to_cpu(l2_hdr->len); - if (len - sizeof(*acl_hdr) != sizeof(*l2_hdr) + l2_len) + if (len != sizeof(*l2_hdr) + l2_len) { + bthost_debug(bthost, "L2CAP invalid length: %u != %zu", + len, sizeof(*l2_hdr) + l2_len); return; + } - l2_data = data + sizeof(*acl_hdr) + sizeof(*l2_hdr); + bthost_debug(bthost, "L2CAP data: %u bytes", l2_len); cid = le16_to_cpu(l2_hdr->cid); hook = find_cid_hook(conn, cid); if (hook) { - hook->func(l2_data, l2_len, hook->user_data); + hook->func(l2_hdr->data, l2_len, hook->user_data); return; } switch (cid) { case 0x0001: - l2cap_sig(bthost, conn, l2_data, l2_len); + l2cap_sig(bthost, conn, l2_hdr->data, l2_len); break; case 0x0005: - l2cap_le_sig(bthost, conn, l2_data, l2_len); + l2cap_le_sig(bthost, conn, l2_hdr->data, l2_len); break; case 0x0006: - smp_data(conn->smp_data, l2_data, l2_len); + smp_data(conn->smp_data, l2_hdr->data, l2_len); break; case 0x0007: - smp_bredr_data(conn->smp_data, l2_data, l2_len); + smp_bredr_data(conn->smp_data, l2_hdr->data, l2_len); break; default: l2conn = btconn_find_l2cap_conn_by_scid(conn, cid); if (l2conn && l2conn->psm == 0x0003) - process_rfcomm(bthost, conn, l2conn, l2_data, l2_len); + process_rfcomm(bthost, conn, l2conn, l2_hdr->data, + l2_len); else bthost_debug(bthost, "Packet for unknown CID 0x%04x (%u)", @@ -2490,6 +2647,201 @@ } } +static void append_recv_data(struct bthost *bthost, struct btconn *conn, + const char *type, uint8_t flags, + const void *data, uint16_t len) +{ + if (!conn->recv_data) { + bthost_debug(bthost, "Unexpected %s frame: handle 0x%4.4x " + "flags 0x%2.2x", type, conn->handle, flags); + return; + } + + if (conn->recv_len + len > conn->data_len) { + bthost_debug(bthost, "Unexpected %s frame: handle 0x%4.4x " + "flags 0x%2.2x", type, conn->handle, flags); + return; + } + + memcpy(conn->recv_data + conn->recv_len, data, len); + conn->recv_len += len; + + bthost_debug(bthost, "%s data: %u/%u bytes", type, conn->recv_len, + conn->data_len); +} + +static void free_recv_data(struct btconn *conn) +{ + free(conn->recv_data); + conn->recv_data = NULL; + conn->recv_len = 0; + conn->data_len = 0; +} + +static void append_acl_data(struct bthost *bthost, struct btconn *conn, + uint8_t flags, const void *data, uint16_t len) +{ + append_recv_data(bthost, conn, "ACL", flags, data, len); + + if (conn->recv_len < conn->data_len) + return; + + process_l2cap(bthost, conn, conn->recv_data, conn->recv_len); + + free_recv_data(conn); +} + +static void new_recv_data(struct btconn *conn, uint16_t len) +{ + conn->recv_data = malloc(len); + conn->recv_len = 0; + conn->data_len = len; +} + +static void process_acl(struct bthost *bthost, const void *data, uint16_t len) +{ + const struct bt_hci_acl_hdr *acl_hdr = data; + const struct bt_l2cap_hdr *l2_hdr = (void *) acl_hdr->data; + uint16_t handle, acl_len, l2_len; + uint8_t flags; + struct btconn *conn; + + acl_len = le16_to_cpu(acl_hdr->dlen); + if (len != sizeof(*acl_hdr) + acl_len) + return; + + handle = acl_handle(acl_hdr->handle); + flags = acl_flags(acl_hdr->handle); + + conn = bthost_find_conn(bthost, handle); + if (!conn) { + bthost_debug(bthost, "Unknown handle: 0x%4.4x", handle); + return; + } + + switch (flags) { + case 0x00: /* start of a non-automatically-flushable PDU */ + case 0x02: /* start of an automatically-flushable PDU */ + if (conn->recv_data) { + bthost_debug(bthost, "Unexpected ACL start frame"); + free_recv_data(conn); + } + + l2_len = le16_to_cpu(l2_hdr->len) + sizeof(*l2_hdr); + + bthost_debug(bthost, "acl_len %u l2_len %u", acl_len, l2_len); + + if (acl_len == l2_len) { + process_l2cap(bthost, conn, acl_hdr->data, acl_len); + break; + } + + new_recv_data(conn, l2_len); + /* fall through */ + case 0x01: /* continuing fragment */ + append_acl_data(bthost, conn, flags, acl_hdr->data, acl_len); + break; + case 0x03: /* complete automatically-flushable PDU */ + process_l2cap(bthost, conn, acl_hdr->data, acl_len); + break; + default: + bthost_debug(bthost, "Invalid ACL frame flags 0x%2.2x", flags); + } +} + +static void process_iso_data(struct bthost *bthost, struct btconn *conn, + const void *data, uint16_t len) +{ + const struct bt_hci_iso_data_start *data_hdr = data; + uint16_t data_len; + struct iso_hook *hook; + + data_len = le16_to_cpu(data_hdr->slen); + if (len != sizeof(*data_hdr) + data_len) { + bthost_debug(bthost, "ISO invalid length: %u != %zu", + len, sizeof(*data_hdr) + data_len); + return; + } + + bthost_debug(bthost, "ISO data: %u bytes (%u)", data_len, data_hdr->sn); + + hook = conn->iso_hook; + if (!hook) + return; + + hook->func(data_hdr->data, data_len, hook->user_data); +} + +static void append_iso_data(struct bthost *bthost, struct btconn *conn, + uint8_t flags, const void *data, uint16_t len) +{ + append_recv_data(bthost, conn, "ISO", flags, data, len); + + if (conn->recv_len < conn->data_len) { + if (flags == 0x03) { + bthost_debug(bthost, "Unexpected ISO end frame"); + free_recv_data(conn); + } + return; + } + + process_iso_data(bthost, conn, conn->recv_data, conn->recv_len); + + free_recv_data(conn); +} + +static void process_iso(struct bthost *bthost, const void *data, uint16_t len) +{ + const struct bt_hci_iso_hdr *iso_hdr = data; + const struct bt_hci_iso_data_start *data_hdr; + uint16_t handle, iso_len, data_len; + uint8_t flags; + struct btconn *conn; + + iso_len = le16_to_cpu(iso_hdr->dlen); + if (len != sizeof(*iso_hdr) + iso_len) + return; + + handle = acl_handle(iso_hdr->handle); + flags = iso_flags_pb(acl_flags(iso_hdr->handle)); + + conn = bthost_find_conn(bthost, handle); + if (!conn) { + bthost_debug(bthost, "Unknown handle: 0x%4.4x", handle); + return; + } + + data_hdr = (void *) data + sizeof(*iso_hdr); + + switch (flags) { + case 0x00: + case 0x02: + if (conn->recv_data) { + bthost_debug(bthost, "Unexpected ISO start frame"); + free_recv_data(conn); + } + + data_len = le16_to_cpu(data_hdr->slen) + sizeof(*data_hdr); + + bthost_debug(bthost, "iso_len %u data_len %u", iso_len, + data_len); + + if (iso_len == data_len) { + process_iso_data(bthost, conn, iso_hdr->data, iso_len); + break; + } + + new_recv_data(conn, data_len); + /* fall through */ + case 0x01: + case 0x03: + append_iso_data(bthost, conn, flags, iso_hdr->data, iso_len); + break; + default: + bthost_debug(bthost, "Invalid ISO frame flags 0x%2.2x", flags); + } +} + void bthost_receive_h4(struct bthost *bthost, const void *data, uint16_t len) { uint8_t pkt_type; @@ -2512,6 +2864,9 @@ case BT_H4_ACL_PKT: process_acl(bthost, data + 1, len - 1); break; + case BT_H4_ISO_PKT: + process_iso(bthost, data + 1, len - 1); + break; default: bthost_debug(bthost, "Unsupported packet 0x%2.2x", pkt_type); break; @@ -2532,6 +2887,13 @@ bthost->new_conn_data = user_data; } +void bthost_set_iso_cb(struct bthost *bthost, bthost_new_conn_cb cb, + void *user_data) +{ + bthost->new_iso_cb = cb; + bthost->new_iso_data = user_data; +} + void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr, uint8_t addr_type) { @@ -2715,6 +3077,38 @@ send_command(bthost, BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE, cp, 6); } +void bthost_set_pa_params(struct bthost *bthost) +{ + struct bt_hci_cmd_le_set_pa_params cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = 0x01; + send_command(bthost, BT_HCI_CMD_LE_SET_PA_PARAMS, &cp, sizeof(cp)); +} + +void bthost_set_pa_enable(struct bthost *bthost, uint8_t enable) +{ + struct bt_hci_cmd_le_set_pa_enable cp; + + memset(&cp, 0, sizeof(cp)); + cp.enable = enable; + cp.handle = 0x01; + send_command(bthost, BT_HCI_CMD_LE_SET_PA_ENABLE, &cp, sizeof(cp)); +} + +void bthost_create_big(struct bthost *bthost, uint8_t num_bis) +{ + struct bt_hci_cmd_le_create_big cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = 0x01; + cp.adv_handle = 0x01; + cp.num_bis = num_bis; + cp.bis.sdu = 40; + cp.bis.phy = 0x01; + send_command(bthost, BT_HCI_CMD_LE_CREATE_BIG, &cp, sizeof(cp)); +} + bool bthost_search_ext_adv_addr(struct bthost *bthost, const uint8_t *addr) { const struct queue_entry *entry; diff -Nru bluez-5.63/emulator/bthost.h bluez-5.64/emulator/bthost.h --- bluez-5.63/emulator/bthost.h 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/bthost.h 2022-03-16 15:06:20.000000000 +0000 @@ -47,6 +47,9 @@ void bthost_set_connect_cb(struct bthost *bthost, bthost_new_conn_cb cb, void *user_data); +void bthost_set_iso_cb(struct bthost *bthost, bthost_new_conn_cb cb, + void *user_data); + void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr, uint8_t addr_type); @@ -62,10 +65,18 @@ void bthost_add_cid_hook(struct bthost *bthost, uint16_t handle, uint16_t cid, bthost_cid_hook_func_t func, void *user_data); +typedef void (*bthost_iso_hook_func_t)(const void *data, uint16_t len, + void *user_data); + +void bthost_add_iso_hook(struct bthost *bthost, uint16_t handle, + bthost_iso_hook_func_t func, void *user_data); + void bthost_send_cid(struct bthost *bthost, uint16_t handle, uint16_t cid, const void *data, uint16_t len); void bthost_send_cid_v(struct bthost *bthost, uint16_t handle, uint16_t cid, const struct iovec *iov, int iovcnt); +void bthost_send_iso(struct bthost *bthost, uint16_t handle, + const struct iovec *iov, int iovcnt); typedef void (*bthost_l2cap_rsp_cb) (uint8_t code, const void *data, uint16_t len, void *user_data); @@ -84,6 +95,9 @@ uint8_t len); void bthost_set_ext_adv_params(struct bthost *bthost); void bthost_set_ext_adv_enable(struct bthost *bthost, uint8_t enable); +void bthost_set_pa_params(struct bthost *bthost); +void bthost_set_pa_enable(struct bthost *bthost, uint8_t enable); +void bthost_create_big(struct bthost *bthost, uint8_t num_bis); bool bthost_search_ext_adv_addr(struct bthost *bthost, const uint8_t *addr); void bthost_set_scan_params(struct bthost *bthost, uint8_t scan_type, diff -Nru bluez-5.63/emulator/hciemu.c bluez-5.64/emulator/hciemu.c --- bluez-5.63/emulator/hciemu.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/hciemu.c 2022-03-16 15:06:20.000000000 +0000 @@ -190,6 +190,7 @@ case BT_H4_CMD_PKT: case BT_H4_ACL_PKT: case BT_H4_SCO_PKT: + case BT_H4_ISO_PKT: btdev_receive_h4(btdev, buf, len); break; } diff -Nru bluez-5.63/emulator/le.c bluez-5.64/emulator/le.c --- bluez-5.63/emulator/le.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/le.c 2022-03-16 15:06:20.000000000 +0000 @@ -20,7 +20,6 @@ #include #include #include -#include #include #include "lib/bluetooth.h" @@ -509,7 +508,7 @@ /* The advertising delay is a pseudo-random value with a range * of 0 ms to 10 ms generated for each advertising event. */ - if (getrandom(&val, sizeof(val), 0) < 0) { + if (util_getrandom(&val, sizeof(val), 0) < 0) { /* If it fails to get the random number, use a static value */ val = 5; } diff -Nru bluez-5.63/emulator/main.c bluez-5.64/emulator/main.c --- bluez-5.63/emulator/main.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/main.c 2022-03-16 15:06:20.000000000 +0000 @@ -193,6 +193,7 @@ if (debug_enabled) vhci_set_debug(vhci, vhci_debug, UINT_TO_PTR(i), NULL); + vhci_set_emu_opcode(vhci, 0xfc10); vhci_set_msft_opcode(vhci, 0xfc1e); } diff -Nru bluez-5.63/emulator/phy.c bluez-5.64/emulator/phy.c --- bluez-5.63/emulator/phy.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/phy.c 2022-03-16 15:06:20.000000000 +0000 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -174,7 +173,7 @@ mainloop_add_fd(phy->rx_fd, EPOLLIN, phy_rx_callback, phy, NULL); if (!get_random_bytes(&phy->id, sizeof(phy->id))) { - if (getrandom(&phy->id, sizeof(phy->id), 0) < 0) { + if (util_getrandom(&phy->id, sizeof(phy->id), 0) < 0) { mainloop_remove_fd(phy->rx_fd); close(phy->tx_fd); close(phy->rx_fd); diff -Nru bluez-5.63/emulator/vhci.c bluez-5.64/emulator/vhci.c --- bluez-5.63/emulator/vhci.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/vhci.c 2022-03-16 15:06:20.000000000 +0000 @@ -252,3 +252,8 @@ return vhci_debugfs_write(vhci, "aosp_capable", &val, sizeof(val)); } + +int vhci_set_emu_opcode(struct vhci *vhci, uint16_t opcode) +{ + return btdev_set_emu_opcode(vhci->btdev, opcode); +} diff -Nru bluez-5.63/emulator/vhci.h bluez-5.64/emulator/vhci.h --- bluez-5.63/emulator/vhci.h 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/emulator/vhci.h 2022-03-16 15:06:20.000000000 +0000 @@ -27,3 +27,4 @@ int vhci_set_force_wakeup(struct vhci *vhci, bool enable); int vhci_set_msft_opcode(struct vhci *vhci, uint16_t opcode); int vhci_set_aosp_capable(struct vhci *vhci, bool enable); +int vhci_set_emu_opcode(struct vhci *vhci, uint16_t opcode); diff -Nru bluez-5.63/gdbus/object.c bluez-5.64/gdbus/object.c --- bluez-5.63/gdbus/object.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/gdbus/object.c 2022-03-16 15:06:20.000000000 +0000 @@ -551,6 +551,12 @@ if (root == NULL || data == root) return; + /* Emit InterfacesAdded on the parent first so it appears first on the + * bus as child objects may point to it. + */ + if (data->parent && data->parent->added) + emit_interfaces_added(data->parent); + signal = dbus_message_new_signal(root->path, DBUS_INTERFACE_OBJECT_MANAGER, "InterfacesAdded"); diff -Nru bluez-5.63/gobex/gobex.c bluez-5.64/gobex/gobex.c --- bluez-5.63/gobex/gobex.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/gobex/gobex.c 2022-03-16 15:06:20.000000000 +0000 @@ -419,6 +419,8 @@ gpointer user_data) { GObex *obex = user_data; + struct pending_pkt *p = NULL; + GError *err = NULL; if (cond & G_IO_NVAL) return FALSE; @@ -427,9 +429,9 @@ goto stop_tx; if (obex->tx_data == 0) { - struct pending_pkt *p = g_queue_pop_head(obex->tx_queue); ssize_t len; + p = g_queue_pop_head(obex->tx_queue); if (p == NULL) goto stop_tx; @@ -469,6 +471,8 @@ check_srm_final(obex, obex->tx_buf[0] & ~FINAL_BIT); pending_pkt_free(p); + /* g_free() doesn't set the pointer to NULL */ + p = NULL; } obex->tx_data = len; @@ -480,8 +484,19 @@ return FALSE; } - if (!obex->write(obex, NULL)) + if (!obex->write(obex, &err)) { + g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); + + if (p) { + if (p->rsp_func) + p->rsp_func(obex, err, NULL, p->rsp_data); + + pending_pkt_free(p); + } + + g_error_free(err); goto stop_tx; + } done: if (obex->tx_data > 0 || g_queue_get_length(obex->tx_queue) > 0) diff -Nru bluez-5.63/gobex/gobex-header.c bluez-5.64/gobex/gobex-header.c --- bluez-5.63/gobex/gobex-header.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/gobex/gobex-header.c 2022-03-16 15:06:20.000000000 +0000 @@ -15,6 +15,7 @@ #include "gobex-header.h" #include "gobex-debug.h" +#include "src/shared/util.h" /* Header types */ #define G_OBEX_HDR_ENC_UNICODE (0 << 6) @@ -222,7 +223,7 @@ switch (data_policy) { case G_OBEX_DATA_COPY: - header->v.data = g_memdup(ptr, header->vlen); + header->v.data = util_memdup(ptr, header->vlen); break; case G_OBEX_DATA_REF: header->extdata = TRUE; @@ -282,7 +283,7 @@ break; case G_OBEX_HDR_ENC_BYTES: if (!header->extdata) - g_free(header->v.data); + free(header->v.data); break; case G_OBEX_HDR_ENC_UINT8: case G_OBEX_HDR_ENC_UINT32: @@ -410,7 +411,7 @@ header->id = id; header->vlen = len; header->hlen = len + 3; - header->v.data = g_memdup(data, len); + header->v.data = util_memdup(data, len); return header; } diff -Nru bluez-5.63/gobex/gobex-packet.c bluez-5.64/gobex/gobex-packet.c --- bluez-5.63/gobex/gobex-packet.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/gobex/gobex-packet.c 2022-03-16 15:06:20.000000000 +0000 @@ -17,6 +17,7 @@ #include "gobex-defs.h" #include "gobex-packet.h" #include "gobex-debug.h" +#include "src/shared/util.h" #define FINAL_BIT 0x80 @@ -201,7 +202,7 @@ switch (data_policy) { case G_OBEX_DATA_COPY: - pkt->data.buf = g_memdup(data, len); + pkt->data.buf = util_memdup(data, len); break; case G_OBEX_DATA_REF: pkt->data.buf_ref = data; @@ -259,7 +260,7 @@ switch (pkt->data_policy) { case G_OBEX_DATA_INHERIT: case G_OBEX_DATA_COPY: - g_free(pkt->data.buf); + free(pkt->data.buf); break; case G_OBEX_DATA_REF: break; diff -Nru bluez-5.63/lib/hci.c bluez-5.64/lib/hci.c --- bluez-5.63/lib/hci.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/lib/hci.c 2022-03-16 15:06:20.000000000 +0000 @@ -323,7 +323,7 @@ int ret = hci_str2bit(link_mode_map, str, val); /* Deprecated name. Kept for compatibility. */ - if (strcasestr(str, "MASTER")) { + if (!!str && strcasestr(str, "MASTER")) { ret = 1; *val |= HCI_LM_MASTER; } diff -Nru bluez-5.63/lib/uuid.c bluez-5.64/lib/uuid.c --- bluez-5.63/lib/uuid.c 2021-06-13 19:56:36.000000000 +0000 +++ bluez-5.64/lib/uuid.c 2022-03-16 15:06:20.000000000 +0000 @@ -251,6 +251,9 @@ int bt_string_to_uuid(bt_uuid_t *uuid, const char *string) { + if (!string) + return -EINVAL; + if (is_base_uuid128(string)) return bt_string_to_uuid16(uuid, string + 4); else if (is_uuid128(string)) diff -Nru bluez-5.63/Makefile.am bluez-5.64/Makefile.am --- bluez-5.63/Makefile.am 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/Makefile.am 2022-03-16 15:06:19.000000000 +0000 @@ -28,14 +28,14 @@ $(LIBEDATASERVER_CFLAGS) $(ell_cflags) AM_LDFLAGS = $(MISC_LDFLAGS) +confdir = $(sysconfdir)/bluetooth +statedir = $(localstatedir)/lib/bluetooth + if DATAFILES dbusdir = $(DBUS_CONFDIR)/dbus-1/system.d dbus_DATA = src/bluetooth.conf -confdir = $(sysconfdir)/bluetooth conf_DATA = - -statedir = $(localstatedir)/lib/bluetooth state_DATA = endif @@ -267,8 +267,7 @@ attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \ attrib/gatt.h attrib/gatt.c \ - attrib/gattrib.h attrib/gattrib.c \ - attrib/gatt-service.h attrib/gatt-service.c + attrib/gattrib.h attrib/gattrib.c btio_sources = btio/btio.h btio/btio.c @@ -305,7 +304,6 @@ src/rfkill.c src/btd.h src/sdpd.h \ src/sdpd-server.c src/sdpd-request.c \ src/sdpd-service.c src/sdpd-database.c \ - src/attrib-server.h src/attrib-server.c \ src/gatt-database.h src/gatt-database.c \ src/sdp-xml.h src/sdp-xml.c \ src/sdp-client.h src/sdp-client.c \ @@ -508,23 +506,23 @@ unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ unit/test-gobex.c -unit_test_gobex_LDADD = $(GLIB_LIBS) +unit_test_gobex_LDADD = src/libshared-glib.la $(GLIB_LIBS) unit_test_gobex_packet_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ unit/test-gobex-packet.c -unit_test_gobex_packet_LDADD = $(GLIB_LIBS) +unit_test_gobex_packet_LDADD = src/libshared-glib.la $(GLIB_LIBS) unit_test_gobex_header_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ unit/test-gobex-header.c -unit_test_gobex_header_LDADD = $(GLIB_LIBS) +unit_test_gobex_header_LDADD = src/libshared-glib.la $(GLIB_LIBS) unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ unit/test-gobex-transfer.c -unit_test_gobex_transfer_LDADD = $(GLIB_LIBS) +unit_test_gobex_transfer_LDADD = src/libshared-glib.la $(GLIB_LIBS) unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ unit/test-gobex-apparam.c -unit_test_gobex_apparam_LDADD = $(GLIB_LIBS) +unit_test_gobex_apparam_LDADD = src/libshared-glib.la $(GLIB_LIBS) endif unit_tests += unit/test-lib @@ -624,6 +622,9 @@ SED_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ $(SED) -e 's,@pkglibexecdir\@,$(pkglibexecdir),g' \ + -e 's,@libexecdir\@,$(libexecdir),g' \ + -e 's,@statedir\@,$(statedir),g' \ + -e 's,@confdir\@,$(confdir),g' \ < $< > $@ if RUN_RST2MAN diff -Nru bluez-5.63/Makefile.in bluez-5.64/Makefile.in --- bluez-5.63/Makefile.in 2022-01-05 21:55:01.000000000 +0000 +++ bluez-5.64/Makefile.in 2022-03-16 15:07:21.000000000 +0000 @@ -1036,7 +1036,8 @@ monitor/keys.c monitor/analyze.h monitor/analyze.c \ monitor/intel.h monitor/intel.c monitor/broadcom.h \ monitor/broadcom.c monitor/msft.h monitor/msft.c \ - monitor/jlink.h monitor/jlink.c monitor/tty.h + monitor/jlink.h monitor/jlink.c monitor/tty.h \ + monitor/emulator.h @MONITOR_TRUE@am_monitor_btmon_OBJECTS = monitor/main.$(OBJEXT) \ @MONITOR_TRUE@ monitor/display.$(OBJEXT) \ @MONITOR_TRUE@ monitor/hcidump.$(OBJEXT) \ @@ -1138,9 +1139,9 @@ $(nodist_obexd_src_obexd_OBJECTS) @OBEX_TRUE@obexd_src_obexd_DEPENDENCIES = \ @OBEX_TRUE@ lib/libbluetooth-internal.la \ -@OBEX_TRUE@ gdbus/libgdbus-internal.la $(am__DEPENDENCIES_1) \ +@OBEX_TRUE@ gdbus/libgdbus-internal.la src/libshared-glib.la \ @OBEX_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ -@OBEX_TRUE@ $(am__DEPENDENCIES_1) +@OBEX_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) obexd_src_obexd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(obexd_src_obexd_CFLAGS) $(CFLAGS) $(obexd_src_obexd_LDFLAGS) \ @@ -1220,22 +1221,21 @@ profiles/midi/midi.c profiles/midi/libmidi.h \ profiles/midi/libmidi.c profiles/battery/battery.c \ attrib/att.h attrib/att-database.h attrib/att.c attrib/gatt.h \ - attrib/gatt.c attrib/gattrib.h attrib/gattrib.c \ - attrib/gatt-service.h attrib/gatt-service.c btio/btio.h \ + attrib/gatt.c attrib/gattrib.h attrib/gattrib.c btio/btio.h \ btio/btio.c src/bluetooth.ver src/main.c src/log.h src/log.c \ src/backtrace.h src/backtrace.c src/rfkill.c src/btd.h \ src/sdpd.h src/sdpd-server.c src/sdpd-request.c \ - src/sdpd-service.c src/sdpd-database.c src/attrib-server.h \ - src/attrib-server.c src/gatt-database.h src/gatt-database.c \ - src/sdp-xml.h src/sdp-xml.c src/sdp-client.h src/sdp-client.c \ - src/textfile.h src/textfile.c src/uuid-helper.h \ - src/uuid-helper.c src/plugin.h src/plugin.c src/storage.h \ - src/storage.c src/advertising.h src/advertising.c src/agent.h \ - src/agent.c src/error.h src/error.c src/adapter.h \ - src/adapter.c src/profile.h src/profile.c src/service.h \ - src/service.c src/gatt-client.h src/gatt-client.c src/device.h \ - src/device.c src/dbus-common.c src/dbus-common.h src/eir.h \ - src/eir.c src/adv_monitor.h src/adv_monitor.c src/battery.h \ + src/sdpd-service.c src/sdpd-database.c src/gatt-database.h \ + src/gatt-database.c src/sdp-xml.h src/sdp-xml.c \ + src/sdp-client.h src/sdp-client.c src/textfile.h \ + src/textfile.c src/uuid-helper.h src/uuid-helper.c \ + src/plugin.h src/plugin.c src/storage.h src/storage.c \ + src/advertising.h src/advertising.c src/agent.h src/agent.c \ + src/error.h src/error.c src/adapter.h src/adapter.c \ + src/profile.h src/profile.c src/service.h src/service.c \ + src/gatt-client.h src/gatt-client.c src/device.h src/device.c \ + src/dbus-common.c src/dbus-common.h src/eir.h src/eir.c \ + src/adv_monitor.h src/adv_monitor.c src/battery.h \ src/battery.c @ADMIN_TRUE@am__objects_17 = plugins/bluetoothd-admin.$(OBJEXT) @NFC_TRUE@am__objects_18 = plugins/bluetoothd-neard.$(OBJEXT) @@ -1292,8 +1292,7 @@ profiles/battery/bluetoothd-battery.$(OBJEXT) am__objects_28 = attrib/bluetoothd-att.$(OBJEXT) \ attrib/bluetoothd-gatt.$(OBJEXT) \ - attrib/bluetoothd-gattrib.$(OBJEXT) \ - attrib/bluetoothd-gatt-service.$(OBJEXT) + attrib/bluetoothd-gattrib.$(OBJEXT) am__objects_29 = btio/bluetoothd-btio.$(OBJEXT) am_src_bluetoothd_OBJECTS = $(am__objects_27) $(am__objects_28) \ $(am__objects_29) src/bluetoothd-main.$(OBJEXT) \ @@ -1304,7 +1303,6 @@ src/bluetoothd-sdpd-request.$(OBJEXT) \ src/bluetoothd-sdpd-service.$(OBJEXT) \ src/bluetoothd-sdpd-database.$(OBJEXT) \ - src/bluetoothd-attrib-server.$(OBJEXT) \ src/bluetoothd-gatt-database.$(OBJEXT) \ src/bluetoothd-sdp-xml.$(OBJEXT) \ src/bluetoothd-sdp-client.$(OBJEXT) \ @@ -1507,8 +1505,10 @@ @TOOLS_TRUE@am_tools_gatt_service_OBJECTS = \ @TOOLS_TRUE@ tools/gatt-service.$(OBJEXT) tools_gatt_service_OBJECTS = $(am_tools_gatt_service_OBJECTS) -@TOOLS_TRUE@tools_gatt_service_DEPENDENCIES = $(am__DEPENDENCIES_1) \ -@TOOLS_TRUE@ $(am__DEPENDENCIES_1) gdbus/libgdbus-internal.la +@TOOLS_TRUE@tools_gatt_service_DEPENDENCIES = \ +@TOOLS_TRUE@ gdbus/libgdbus-internal.la \ +@TOOLS_TRUE@ src/libshared-mainloop.la $(am__DEPENDENCIES_1) \ +@TOOLS_TRUE@ $(am__DEPENDENCIES_1) am__tools_hci_tester_SOURCES_DIST = tools/hci-tester.c monitor/bt.h @TESTING_TRUE@am_tools_hci_tester_OBJECTS = \ @TESTING_TRUE@ tools/hci-tester.$(OBJEXT) @@ -1739,7 +1739,7 @@ tools_obex_client_tool_OBJECTS = $(am_tools_obex_client_tool_OBJECTS) @READLINE_TRUE@tools_obex_client_tool_DEPENDENCIES = \ @READLINE_TRUE@ lib/libbluetooth-internal.la \ -@READLINE_TRUE@ $(am__DEPENDENCIES_1) +@READLINE_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) am__tools_obex_server_tool_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ @@ -1752,7 +1752,7 @@ tools_obex_server_tool_OBJECTS = $(am_tools_obex_server_tool_OBJECTS) @READLINE_TRUE@tools_obex_server_tool_DEPENDENCIES = \ @READLINE_TRUE@ lib/libbluetooth-internal.la \ -@READLINE_TRUE@ $(am__DEPENDENCIES_1) +@READLINE_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) am__tools_obexctl_SOURCES_DIST = tools/obexctl.c @READLINE_TRUE@am_tools_obexctl_OBJECTS = tools/obexctl.$(OBJEXT) tools_obexctl_OBJECTS = $(am_tools_obexctl_OBJECTS) @@ -1907,7 +1907,8 @@ @OBEX_TRUE@am_unit_test_gobex_OBJECTS = $(am__objects_30) \ @OBEX_TRUE@ unit/util.$(OBJEXT) unit/test-gobex.$(OBJEXT) unit_test_gobex_OBJECTS = $(am_unit_test_gobex_OBJECTS) -@OBEX_TRUE@unit_test_gobex_DEPENDENCIES = $(am__DEPENDENCIES_1) +@OBEX_TRUE@unit_test_gobex_DEPENDENCIES = src/libshared-glib.la \ +@OBEX_TRUE@ $(am__DEPENDENCIES_1) am__unit_test_gobex_apparam_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ @@ -1920,7 +1921,7 @@ unit_test_gobex_apparam_OBJECTS = \ $(am_unit_test_gobex_apparam_OBJECTS) @OBEX_TRUE@unit_test_gobex_apparam_DEPENDENCIES = \ -@OBEX_TRUE@ $(am__DEPENDENCIES_1) +@OBEX_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) am__unit_test_gobex_header_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ @@ -1932,7 +1933,7 @@ @OBEX_TRUE@ unit/test-gobex-header.$(OBJEXT) unit_test_gobex_header_OBJECTS = $(am_unit_test_gobex_header_OBJECTS) @OBEX_TRUE@unit_test_gobex_header_DEPENDENCIES = \ -@OBEX_TRUE@ $(am__DEPENDENCIES_1) +@OBEX_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) am__unit_test_gobex_packet_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ @@ -1944,7 +1945,7 @@ @OBEX_TRUE@ unit/test-gobex-packet.$(OBJEXT) unit_test_gobex_packet_OBJECTS = $(am_unit_test_gobex_packet_OBJECTS) @OBEX_TRUE@unit_test_gobex_packet_DEPENDENCIES = \ -@OBEX_TRUE@ $(am__DEPENDENCIES_1) +@OBEX_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) am__unit_test_gobex_transfer_SOURCES_DIST = gobex/gobex.h \ gobex/gobex.c gobex/gobex-defs.h gobex/gobex-defs.c \ gobex/gobex-packet.c gobex/gobex-packet.h gobex/gobex-header.c \ @@ -1958,7 +1959,7 @@ unit_test_gobex_transfer_OBJECTS = \ $(am_unit_test_gobex_transfer_OBJECTS) @OBEX_TRUE@unit_test_gobex_transfer_DEPENDENCIES = \ -@OBEX_TRUE@ $(am__DEPENDENCIES_1) +@OBEX_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) am_unit_test_hfp_OBJECTS = unit/test-hfp.$(OBJEXT) unit_test_hfp_OBJECTS = $(am_unit_test_hfp_OBJECTS) unit_test_hfp_DEPENDENCIES = src/libshared-glib.la \ @@ -2111,7 +2112,6 @@ android/hardware/$(DEPDIR)/android_tester-hardware.Po \ android/hardware/$(DEPDIR)/haltest-hardware.Po \ attrib/$(DEPDIR)/att.Po attrib/$(DEPDIR)/bluetoothd-att.Po \ - attrib/$(DEPDIR)/bluetoothd-gatt-service.Po \ attrib/$(DEPDIR)/bluetoothd-gatt.Po \ attrib/$(DEPDIR)/bluetoothd-gattrib.Po \ attrib/$(DEPDIR)/gatt.Po attrib/$(DEPDIR)/gattrib.Po \ @@ -2298,7 +2298,6 @@ src/$(DEPDIR)/bluetoothd-adv_monitor.Po \ src/$(DEPDIR)/bluetoothd-advertising.Po \ src/$(DEPDIR)/bluetoothd-agent.Po \ - src/$(DEPDIR)/bluetoothd-attrib-server.Po \ src/$(DEPDIR)/bluetoothd-backtrace.Po \ src/$(DEPDIR)/bluetoothd-battery.Po \ src/$(DEPDIR)/bluetoothd-dbus-common.Po \ @@ -3178,11 +3177,11 @@ $(LIBEDATASERVER_CFLAGS) $(ell_cflags) AM_LDFLAGS = $(MISC_LDFLAGS) +confdir = $(sysconfdir)/bluetooth +statedir = $(localstatedir)/lib/bluetooth @DATAFILES_TRUE@dbusdir = $(DBUS_CONFDIR)/dbus-1/system.d @DATAFILES_TRUE@dbus_DATA = src/bluetooth.conf $(am__append_56) -@DATAFILES_TRUE@confdir = $(sysconfdir)/bluetooth @DATAFILES_TRUE@conf_DATA = -@DATAFILES_TRUE@statedir = $(localstatedir)/lib/bluetooth @DATAFILES_TRUE@state_DATA = @SYSTEMD_TRUE@systemdsystemunitdir = $(SYSTEMD_SYSTEMUNITDIR) @SYSTEMD_TRUE@systemdsystemunit_DATA = src/bluetooth.service \ @@ -3364,8 +3363,7 @@ @LIBSHARED_ELL_TRUE@src_libshared_ell_la_CFLAGS = $(AM_CFLAGS) attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \ attrib/gatt.h attrib/gatt.c \ - attrib/gattrib.h attrib/gattrib.c \ - attrib/gatt-service.h attrib/gatt-service.c + attrib/gattrib.h attrib/gattrib.c btio_sources = btio/btio.h btio/btio.c gobex_sources = gobex/gobex.h gobex/gobex.c \ @@ -3409,7 +3407,6 @@ src/rfkill.c src/btd.h src/sdpd.h \ src/sdpd-server.c src/sdpd-request.c \ src/sdpd-service.c src/sdpd-database.c \ - src/attrib-server.h src/attrib-server.c \ src/gatt-database.h src/gatt-database.c \ src/sdp-xml.h src/sdp-xml.c \ src/sdp-client.h src/sdp-client.c \ @@ -3510,7 +3507,7 @@ @MONITOR_TRUE@ monitor/broadcom.h monitor/broadcom.c \ @MONITOR_TRUE@ monitor/msft.h monitor/msft.c \ @MONITOR_TRUE@ monitor/jlink.h monitor/jlink.c \ -@MONITOR_TRUE@ monitor/tty.h +@MONITOR_TRUE@ monitor/tty.h monitor/emulator.h @MONITOR_TRUE@monitor_btmon_LDADD = lib/libbluetooth-internal.la \ @MONITOR_TRUE@ src/libshared-mainloop.la $(UDEV_LIBS) -ldl @@ -3699,7 +3696,9 @@ @TOOLS_TRUE@tools_mpris_proxy_SOURCES = tools/mpris-proxy.c @TOOLS_TRUE@tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS) @TOOLS_TRUE@tools_gatt_service_SOURCES = tools/gatt-service.c -@TOOLS_TRUE@tools_gatt_service_LDADD = $(GLIB_LIBS) $(DBUS_LIBS) gdbus/libgdbus-internal.la +@TOOLS_TRUE@tools_gatt_service_LDADD = gdbus/libgdbus-internal.la \ +@TOOLS_TRUE@ src/libshared-mainloop.la $(GLIB_LIBS) $(DBUS_LIBS) + @TOOLS_TRUE@profiles_iap_iapd_SOURCES = profiles/iap/main.c @TOOLS_TRUE@profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS) @MESH_TRUE@@TOOLS_TRUE@tools_meshctl_SOURCES = tools/meshctl.c \ @@ -3794,12 +3793,14 @@ @READLINE_TRUE@ tools/obex-client-tool.c @READLINE_TRUE@tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \ -@READLINE_TRUE@ $(GLIB_LIBS) -lreadline +@READLINE_TRUE@ src/libshared-glib.la $(GLIB_LIBS) -lreadline @READLINE_TRUE@tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \ @READLINE_TRUE@ tools/obex-server-tool.c -@READLINE_TRUE@tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la $(GLIB_LIBS) +@READLINE_TRUE@tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la \ +@READLINE_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + @READLINE_TRUE@tools_bluetooth_player_SOURCES = tools/bluetooth-player.c @READLINE_TRUE@tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \ @READLINE_TRUE@ src/libshared-glib.la \ @@ -3807,7 +3808,7 @@ @READLINE_TRUE@tools_obexctl_SOURCES = tools/obexctl.c @READLINE_TRUE@tools_obexctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ -@READLINE_TRUE@ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline +@READLINE_TRUE@ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline @READLINE_TRUE@tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c @READLINE_TRUE@tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \ @@ -3891,6 +3892,7 @@ @OBEX_TRUE@obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \ @OBEX_TRUE@ gdbus/libgdbus-internal.la \ +@OBEX_TRUE@ src/libshared-glib.la \ @OBEX_TRUE@ $(ICAL_LIBS) $(DBUS_LIBS) $(LIBEBOOK_LIBS) \ @OBEX_TRUE@ $(LIBEDATASERVER_LIBS) $(GLIB_LIBS) -ldl @@ -4208,23 +4210,23 @@ @OBEX_TRUE@unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ @OBEX_TRUE@ unit/test-gobex.c -@OBEX_TRUE@unit_test_gobex_LDADD = $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_LDADD = src/libshared-glib.la $(GLIB_LIBS) @OBEX_TRUE@unit_test_gobex_packet_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ @OBEX_TRUE@ unit/test-gobex-packet.c -@OBEX_TRUE@unit_test_gobex_packet_LDADD = $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_packet_LDADD = src/libshared-glib.la $(GLIB_LIBS) @OBEX_TRUE@unit_test_gobex_header_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ @OBEX_TRUE@ unit/test-gobex-header.c -@OBEX_TRUE@unit_test_gobex_header_LDADD = $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_header_LDADD = src/libshared-glib.la $(GLIB_LIBS) @OBEX_TRUE@unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ @OBEX_TRUE@ unit/test-gobex-transfer.c -@OBEX_TRUE@unit_test_gobex_transfer_LDADD = $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_transfer_LDADD = src/libshared-glib.la $(GLIB_LIBS) @OBEX_TRUE@unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ @OBEX_TRUE@ unit/test-gobex-apparam.c -@OBEX_TRUE@unit_test_gobex_apparam_LDADD = $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_apparam_LDADD = src/libshared-glib.la $(GLIB_LIBS) unit_test_lib_SOURCES = unit/test-lib.c unit_test_lib_LDADD = src/libshared-glib.la \ lib/libbluetooth-internal.la $(GLIB_LIBS) @@ -4292,6 +4294,9 @@ SED_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ $(SED) -e 's,@pkglibexecdir\@,$(pkglibexecdir),g' \ + -e 's,@libexecdir\@,$(libexecdir),g' \ + -e 's,@statedir\@,$(statedir),g' \ + -e 's,@confdir\@,$(confdir),g' \ < $< > $@ @RUN_RST2MAN_FALSE@RST2MAN_PROCESS = $(AM_V_GEN)test -f $@ || \ @@ -5814,8 +5819,6 @@ attrib/$(DEPDIR)/$(am__dirstamp) attrib/bluetoothd-gattrib.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) -attrib/bluetoothd-gatt-service.$(OBJEXT): attrib/$(am__dirstamp) \ - attrib/$(DEPDIR)/$(am__dirstamp) btio/bluetoothd-btio.$(OBJEXT): btio/$(am__dirstamp) \ btio/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-main.$(OBJEXT): src/$(am__dirstamp) \ @@ -5834,8 +5837,6 @@ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-sdpd-database.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) -src/bluetoothd-attrib-server.$(OBJEXT): src/$(am__dirstamp) \ - src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-gatt-database.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-sdp-xml.$(OBJEXT): src/$(am__dirstamp) \ @@ -6756,7 +6757,6 @@ @AMDEP_TRUE@@am__include@ @am__quote@android/hardware/$(DEPDIR)/haltest-hardware.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/att.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-att.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt-service.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gattrib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/gatt.Po@am__quote@ # am--include-marker @@ -7009,7 +7009,6 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-adv_monitor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-advertising.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-agent.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-attrib-server.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-backtrace.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-battery.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-dbus-common.Po@am__quote@ # am--include-marker @@ -9920,20 +9919,6 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gattrib.obj `if test -f 'attrib/gattrib.c'; then $(CYGPATH_W) 'attrib/gattrib.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gattrib.c'; fi` -attrib/bluetoothd-gatt-service.o: attrib/gatt-service.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt-service.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo -c -o attrib/bluetoothd-gatt-service.o `test -f 'attrib/gatt-service.c' || echo '$(srcdir)/'`attrib/gatt-service.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo attrib/$(DEPDIR)/bluetoothd-gatt-service.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gatt-service.c' object='attrib/bluetoothd-gatt-service.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gatt-service.o `test -f 'attrib/gatt-service.c' || echo '$(srcdir)/'`attrib/gatt-service.c - -attrib/bluetoothd-gatt-service.obj: attrib/gatt-service.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt-service.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo -c -o attrib/bluetoothd-gatt-service.obj `if test -f 'attrib/gatt-service.c'; then $(CYGPATH_W) 'attrib/gatt-service.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gatt-service.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo attrib/$(DEPDIR)/bluetoothd-gatt-service.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gatt-service.c' object='attrib/bluetoothd-gatt-service.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gatt-service.obj `if test -f 'attrib/gatt-service.c'; then $(CYGPATH_W) 'attrib/gatt-service.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gatt-service.c'; fi` - btio/bluetoothd-btio.o: btio/btio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT btio/bluetoothd-btio.o -MD -MP -MF btio/$(DEPDIR)/bluetoothd-btio.Tpo -c -o btio/bluetoothd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/bluetoothd-btio.Tpo btio/$(DEPDIR)/bluetoothd-btio.Po @@ -10060,20 +10045,6 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-database.obj `if test -f 'src/sdpd-database.c'; then $(CYGPATH_W) 'src/sdpd-database.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-database.c'; fi` -src/bluetoothd-attrib-server.o: src/attrib-server.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-attrib-server.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-attrib-server.Tpo -c -o src/bluetoothd-attrib-server.o `test -f 'src/attrib-server.c' || echo '$(srcdir)/'`src/attrib-server.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-attrib-server.Tpo src/$(DEPDIR)/bluetoothd-attrib-server.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/attrib-server.c' object='src/bluetoothd-attrib-server.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-attrib-server.o `test -f 'src/attrib-server.c' || echo '$(srcdir)/'`src/attrib-server.c - -src/bluetoothd-attrib-server.obj: src/attrib-server.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-attrib-server.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-attrib-server.Tpo -c -o src/bluetoothd-attrib-server.obj `if test -f 'src/attrib-server.c'; then $(CYGPATH_W) 'src/attrib-server.c'; else $(CYGPATH_W) '$(srcdir)/src/attrib-server.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-attrib-server.Tpo src/$(DEPDIR)/bluetoothd-attrib-server.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/attrib-server.c' object='src/bluetoothd-attrib-server.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-attrib-server.obj `if test -f 'src/attrib-server.c'; then $(CYGPATH_W) 'src/attrib-server.c'; else $(CYGPATH_W) '$(srcdir)/src/attrib-server.c'; fi` - src/bluetoothd-gatt-database.o: src/gatt-database.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-gatt-database.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-gatt-database.Tpo -c -o src/bluetoothd-gatt-database.o `test -f 'src/gatt-database.c' || echo '$(srcdir)/'`src/gatt-database.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-gatt-database.Tpo src/$(DEPDIR)/bluetoothd-gatt-database.Po @@ -11526,7 +11497,6 @@ -rm -f android/hardware/$(DEPDIR)/haltest-hardware.Po -rm -f attrib/$(DEPDIR)/att.Po -rm -f attrib/$(DEPDIR)/bluetoothd-att.Po - -rm -f attrib/$(DEPDIR)/bluetoothd-gatt-service.Po -rm -f attrib/$(DEPDIR)/bluetoothd-gatt.Po -rm -f attrib/$(DEPDIR)/bluetoothd-gattrib.Po -rm -f attrib/$(DEPDIR)/gatt.Po @@ -11779,7 +11749,6 @@ -rm -f src/$(DEPDIR)/bluetoothd-adv_monitor.Po -rm -f src/$(DEPDIR)/bluetoothd-advertising.Po -rm -f src/$(DEPDIR)/bluetoothd-agent.Po - -rm -f src/$(DEPDIR)/bluetoothd-attrib-server.Po -rm -f src/$(DEPDIR)/bluetoothd-backtrace.Po -rm -f src/$(DEPDIR)/bluetoothd-battery.Po -rm -f src/$(DEPDIR)/bluetoothd-dbus-common.Po @@ -12168,7 +12137,6 @@ -rm -f android/hardware/$(DEPDIR)/haltest-hardware.Po -rm -f attrib/$(DEPDIR)/att.Po -rm -f attrib/$(DEPDIR)/bluetoothd-att.Po - -rm -f attrib/$(DEPDIR)/bluetoothd-gatt-service.Po -rm -f attrib/$(DEPDIR)/bluetoothd-gatt.Po -rm -f attrib/$(DEPDIR)/bluetoothd-gattrib.Po -rm -f attrib/$(DEPDIR)/gatt.Po @@ -12421,7 +12389,6 @@ -rm -f src/$(DEPDIR)/bluetoothd-adv_monitor.Po -rm -f src/$(DEPDIR)/bluetoothd-advertising.Po -rm -f src/$(DEPDIR)/bluetoothd-agent.Po - -rm -f src/$(DEPDIR)/bluetoothd-attrib-server.Po -rm -f src/$(DEPDIR)/bluetoothd-backtrace.Po -rm -f src/$(DEPDIR)/bluetoothd-battery.Po -rm -f src/$(DEPDIR)/bluetoothd-dbus-common.Po diff -Nru bluez-5.63/Makefile.obexd bluez-5.64/Makefile.obexd --- bluez-5.63/Makefile.obexd 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/Makefile.obexd 2022-03-16 15:06:19.000000000 +0000 @@ -82,6 +82,7 @@ obexd/src/map_ap.h obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \ gdbus/libgdbus-internal.la \ + src/libshared-glib.la \ $(ICAL_LIBS) $(DBUS_LIBS) $(LIBEBOOK_LIBS) \ $(LIBEDATASERVER_LIBS) $(GLIB_LIBS) -ldl diff -Nru bluez-5.63/Makefile.tools bluez-5.64/Makefile.tools --- bluez-5.63/Makefile.tools 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/Makefile.tools 2022-03-16 15:06:19.000000000 +0000 @@ -48,7 +48,7 @@ monitor/broadcom.h monitor/broadcom.c \ monitor/msft.h monitor/msft.c \ monitor/jlink.h monitor/jlink.c \ - monitor/tty.h + monitor/tty.h monitor/emulator.h monitor_btmon_LDADD = lib/libbluetooth-internal.la \ src/libshared-mainloop.la $(UDEV_LIBS) -ldl @@ -302,7 +302,8 @@ tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS) tools_gatt_service_SOURCES = tools/gatt-service.c -tools_gatt_service_LDADD = $(GLIB_LIBS) $(DBUS_LIBS) gdbus/libgdbus-internal.la +tools_gatt_service_LDADD = gdbus/libgdbus-internal.la \ + src/libshared-mainloop.la $(GLIB_LIBS) $(DBUS_LIBS) profiles_iap_iapd_SOURCES = profiles/iap/main.c profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS) @@ -448,11 +449,12 @@ tools_obex_client_tool_SOURCES = $(gobex_sources) $(btio_sources) \ tools/obex-client-tool.c tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \ - $(GLIB_LIBS) -lreadline + src/libshared-glib.la $(GLIB_LIBS) -lreadline tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \ tools/obex-server-tool.c -tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la $(GLIB_LIBS) +tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la \ + src/libshared-glib.la $(GLIB_LIBS) tools_bluetooth_player_SOURCES = tools/bluetooth-player.c tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \ @@ -461,7 +463,7 @@ tools_obexctl_SOURCES = tools/obexctl.c tools_obexctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ - $(GLIB_LIBS) $(DBUS_LIBS) -lreadline + $(GLIB_LIBS) $(DBUS_LIBS) -lreadline tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \ diff -Nru bluez-5.63/mesh/appkey.h bluez-5.64/mesh/appkey.h --- bluez-5.63/mesh/appkey.h 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/mesh/appkey.h 2022-03-16 15:06:20.000000000 +0000 @@ -18,7 +18,7 @@ void appkey_key_free(void *data); void appkey_finalize(struct mesh_net *net, uint16_t net_idx); const uint8_t *appkey_get_key(struct mesh_net *net, uint16_t app_idx, - uint8_t *key_id); + uint8_t *key_aid); int appkey_get_key_idx(struct mesh_app_key *app_key, const uint8_t **key, uint8_t *key_aid, const uint8_t **new_key, uint8_t *new_key_aid); diff -Nru bluez-5.63/mesh/friend.c bluez-5.64/mesh/friend.c --- bluez-5.63/mesh/friend.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/mesh/friend.c 2022-03-16 15:06:20.000000000 +0000 @@ -59,7 +59,7 @@ { struct mesh_friend *neg = user_data; uint16_t net_idx = neg->net_idx; - uint32_t key_id, seq; + uint32_t net_key_id, seq; uint8_t msg[8]; uint16_t n = 0; bool res; @@ -67,11 +67,11 @@ l_timeout_remove(timeout); /* Create key Set for this offer */ - res = mesh_net_get_key(neg->net, false, net_idx, &key_id); + res = mesh_net_get_key(neg->net, false, net_idx, &net_key_id); if (!res) goto cleanup; - neg->net_key_cur = net_key_frnd_add(key_id, neg->lp_addr, + neg->net_key_cur = net_key_frnd_add(net_key_id, neg->lp_addr, mesh_net_get_address(neg->net), neg->lp_cnt, counter); if (!neg->net_key_cur) @@ -88,7 +88,7 @@ n += 2; seq = mesh_net_next_seq_num(neg->net); print_packet("Tx-NET_OP_FRND_OFFER", msg, n); - mesh_net_transport_send(neg->net, key_id, 0, + mesh_net_transport_send(neg->net, net_key_id, 0, mesh_net_get_iv_index(neg->net), 0, seq, 0, neg->lp_addr, msg, n); diff -Nru bluez-5.63/mesh/keyring.c bluez-5.64/mesh/keyring.c --- bluez-5.63/mesh/keyring.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/mesh/keyring.c 2022-03-16 15:06:20.000000000 +0000 @@ -207,7 +207,7 @@ snprintf(key_file, PATH_MAX, "%s%s", node_path, dev_key_dir); - if (mkdir(key_file, 0755) != 0) + if (mkdir(key_file, 0755) != 0 && errno != EEXIST) l_error("Failed to create dir(%d): %s", errno, key_file); for (i = 0; i < count; i++) { diff -Nru bluez-5.63/mesh/net.c bluez-5.64/mesh/net.c --- bluez-5.63/mesh/net.c 2021-04-02 08:59:48.000000000 +0000 +++ bluez-5.64/mesh/net.c 2022-03-16 15:06:20.000000000 +0000 @@ -195,7 +195,7 @@ uint8_t *out; size_t out_size; enum _relay_advice relay_advice; - uint32_t key_id; + uint32_t net_key_id; uint32_t iv_index; uint16_t len; bool seen; @@ -210,7 +210,7 @@ }; struct net_beacon_data { - uint32_t key_id; + uint32_t net_key_id; uint32_t ivi; bool ivu; bool kr; @@ -238,19 +238,19 @@ static bool match_key_id(const void *a, const void *b) { const struct mesh_subnet *subnet = a; - uint32_t key_id = L_PTR_TO_UINT(b); + uint32_t net_key_id = L_PTR_TO_UINT(b); - return (key_id == subnet->net_key_cur) || - (key_id == subnet->net_key_upd); + return (net_key_id == subnet->net_key_cur) || + (net_key_id == subnet->net_key_upd); } static bool match_friend_key_id(const void *a, const void *b) { const struct mesh_friend *friend = a; - uint32_t key_id = L_PTR_TO_UINT(b); + uint32_t net_key_id = L_PTR_TO_UINT(b); - return (key_id == friend->net_key_cur) || - (key_id == friend->net_key_upd); + return (net_key_id == friend->net_key_cur) || + (net_key_id == friend->net_key_upd); } static void send_hb_publication(void *data) @@ -322,9 +322,9 @@ static void frnd_kr_phase1(void *a, void *b) { struct mesh_friend *frnd = a; - uint32_t key_id = L_PTR_TO_UINT(b); + uint32_t net_key_id = L_PTR_TO_UINT(b); - frnd->net_key_upd = net_key_frnd_add(key_id, frnd->lp_addr, + frnd->net_key_upd = net_key_frnd_add(net_key_id, frnd->lp_addr, frnd->net->src_addr, frnd->lp_cnt, frnd->fn_cnt); } @@ -918,7 +918,7 @@ } bool mesh_net_get_key(struct mesh_net *net, bool new_key, uint16_t idx, - uint32_t *key_id) + uint32_t *net_key_id) { struct mesh_subnet *subnet; @@ -931,14 +931,14 @@ return false; if (!new_key) { - *key_id = subnet->net_key_cur; + *net_key_id = subnet->net_key_cur; return true; } if (!subnet->net_key_upd) return false; - *key_id = subnet->net_key_upd; + *net_key_id = subnet->net_key_upd; return true; } @@ -1325,7 +1325,6 @@ hdr += (1 << SEGO_HDR_SHIFT); } - frnd_msg->u.s12[seg_max].seq = seq; frnd_msg->cnt_in = seg_max; frnd_msg->last_len = size % 12; if (!frnd_msg->last_len) @@ -1764,7 +1763,7 @@ return true; } -static uint16_t key_id_to_net_idx(struct mesh_net *net, uint32_t key_id) +static uint16_t key_id_to_net_idx(struct mesh_net *net, uint32_t net_key_id) { struct mesh_subnet *subnet; struct mesh_friend *friend; @@ -1773,19 +1772,19 @@ return NET_IDX_INVALID; subnet = l_queue_find(net->subnets, match_key_id, - L_UINT_TO_PTR(key_id)); + L_UINT_TO_PTR(net_key_id)); if (subnet) return subnet->idx; friend = l_queue_find(net->friends, match_friend_key_id, - L_UINT_TO_PTR(key_id)); + L_UINT_TO_PTR(net_key_id)); if (friend) return friend->net_idx; friend = l_queue_find(net->negotiations, match_friend_key_id, - L_UINT_TO_PTR(key_id)); + L_UINT_TO_PTR(net_key_id)); if (friend) return friend->net_idx; @@ -2029,7 +2028,7 @@ return false; } -static bool ctl_received(struct mesh_net *net, uint16_t key_id, +static bool ctl_received(struct mesh_net *net, uint16_t net_key_id, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, @@ -2079,7 +2078,7 @@ return false; print_packet("Rx-NET_OP_FRND_REQUEST", pkt, len); - net_idx = key_id_to_net_idx(net, key_id); + net_idx = key_id_to_net_idx(net, net_key_id); friend_request(net, net_idx, src, pkt[0], pkt[1], l_get_be32(pkt + 1) & 0xffffff, l_get_be16(pkt + 5), pkt[7], @@ -2270,13 +2269,13 @@ } static enum _relay_advice packet_received(void *user_data, - uint32_t key_id, uint32_t iv_index, + uint32_t net_key_id, uint32_t iv_index, const void *data, uint8_t size, int8_t rssi) { struct mesh_net *net = user_data; const uint8_t *msg = data; uint8_t app_msg_len; - uint8_t net_ttl, net_key_id, net_segO, net_segN, net_opcode; + uint8_t net_ttl, key_aid, net_segO, net_segN, net_opcode; uint32_t net_seq, cache_cookie; uint16_t net_src, net_dst, net_seqZero; uint16_t net_idx; @@ -2285,7 +2284,7 @@ memcpy(packet + 2, data, size); - net_idx = key_id_to_net_idx(net, key_id); + net_idx = key_id_to_net_idx(net, net_key_id); if (net_idx == NET_IDX_INVALID) return RELAY_NONE; @@ -2294,7 +2293,7 @@ if (!mesh_crypto_packet_parse(packet + 2, size, &net_ctl, &net_ttl, &net_seq, &net_src, &net_dst, &cache_cookie, &net_opcode, - &net_segmented, &net_key_id, &net_szmic, + &net_segmented, &key_aid, &net_szmic, &net_relay, &net_seqZero, &net_segO, &net_segN, &msg, &app_msg_len)) { l_error("Failed to parse packet content"); @@ -2348,7 +2347,7 @@ net_seqZero, l_get_be32(msg + 3)); } else { - ctl_received(net, key_id, iv_index, net_ttl, + ctl_received(net, key_aid, iv_index, net_ttl, net_seq, net_src, net_dst, net_opcode, rssi, msg, app_msg_len); @@ -2373,14 +2372,14 @@ } else { seg_rxed(net, NULL, iv_index, net_ttl, net_seq, net_idx, net_src, - net_dst, net_key_id, net_szmic, + net_dst, key_aid, net_szmic, net_seqZero, net_segO, net_segN, msg, app_msg_len); } } else { msg_rxed(net, NULL, iv_index, net_ttl, net_seq, net_idx, - net_src, net_dst, net_key_id, false, + net_src, net_dst, key_aid, false, false, net_seq & SEQ_ZERO_MASK, msg, app_msg_len); } @@ -2414,7 +2413,7 @@ enum _relay_advice relay_advice; uint8_t *out; size_t out_size; - uint32_t key_id; + uint32_t net_key_id; int8_t rssi = 0; bool ivi_net = !!(net->iv_index & 1); bool ivi_pkt = !!(data->data[0] & 0x80); @@ -2422,10 +2421,10 @@ /* if IVI flag differs, use previous IV Index */ uint32_t iv_index = net->iv_index - (ivi_pkt ^ ivi_net); - key_id = net_key_decrypt(iv_index, data->data, data->len, + net_key_id = net_key_decrypt(iv_index, data->data, data->len, &out, &out_size); - if (!key_id) + if (!net_key_id) return; if (!data->seen) { @@ -2439,12 +2438,12 @@ rssi = data->info->rssi; } - relay_advice = packet_received(net, key_id, iv_index, out, out_size, + relay_advice = packet_received(net, net_key_id, iv_index, out, out_size, rssi); if (relay_advice > data->relay_advice) { data->iv_index = iv_index; data->relay_advice = relay_advice; - data->key_id = key_id; + data->net_key_id = net_key_id; data->net = net; data->out = out; data->out_size = out_size; @@ -2482,7 +2481,7 @@ net_data.out[1] &= ~TTL_MASK; net_data.out[1] |= ttl - 1; - net_key_encrypt(net_data.key_id, net_data.iv_index, + net_key_encrypt(net_data.net_key_id, net_data.iv_index, net_data.out, net_data.out_size); send_relay_pkt(net_data.net, net_data.out, net_data.out_size); } @@ -2719,7 +2718,7 @@ /* Ignore beacons not in this universe */ subnet = l_queue_find(net->subnets, match_key_id, - L_UINT_TO_PTR(beacon_data->key_id)); + L_UINT_TO_PTR(beacon_data->net_key_id)); if (!subnet) return; @@ -2741,10 +2740,10 @@ updated |= update_iv_ivu_state(net, ivi, ivu); if (kr != local_kr) - updated |= update_kr_state(subnet, kr, beacon_data->key_id); + updated |= update_kr_state(subnet, kr, beacon_data->net_key_id); if (updated) - net_key_beacon_refresh(beacon_data->key_id, net->iv_index, + net_key_beacon_refresh(subnet->net_key_tx, net->iv_index, !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), net->iv_update); } @@ -2760,8 +2759,8 @@ return; /* Ignore Network IDs unknown to this daemon */ - beacon_data.key_id = net_key_network_id(data + 3); - if (!beacon_data.key_id) + beacon_data.net_key_id = net_key_network_id(data + 3); + if (!beacon_data.net_key_id) return; /* Get data bits from beacon */ @@ -2770,7 +2769,7 @@ beacon_data.ivi = l_get_be32(data + 11); /* Validate beacon before accepting */ - if (!net_key_snb_check(beacon_data.key_id, beacon_data.ivi, + if (!net_key_snb_check(beacon_data.net_key_id, beacon_data.ivi, beacon_data.kr, beacon_data.ivu, l_get_be64(data + 15))) { l_error("mesh_crypto_beacon verify failed"); @@ -2780,13 +2779,13 @@ l_queue_foreach(nets, process_beacon, &beacon_data); if (beacon_data.processed) - net_key_beacon_seen(beacon_data.key_id); + net_key_beacon_seen(beacon_data.net_key_id); } -void net_local_beacon(uint32_t key_id, uint8_t *beacon) +void net_local_beacon(uint32_t net_key_id, uint8_t *beacon) { struct net_beacon_data beacon_data = { - .key_id = key_id, + .net_key_id = net_key_id, .ivu = !!(beacon[2] & 0x02), .kr = !!(beacon[2] & 0x01), .ivi = l_get_be32(beacon + 11), @@ -3062,7 +3061,7 @@ uint8_t packet[30]; uint8_t packet_len; bool segmented = !!((hdr >> SEG_HDR_SHIFT) & true); - uint8_t app_key_id = (hdr >> KEY_HDR_SHIFT) & KEY_ID_MASK; + uint8_t key_aid = (hdr >> KEY_HDR_SHIFT) & KEY_ID_MASK; bool szmic = !!((hdr >> SZMIC_HDR_SHIFT) & true); uint16_t seqZero = (hdr >> SEQ_ZERO_HDR_SHIFT) & SEQ_ZERO_MASK; uint8_t segO = (hdr >> SEGO_HDR_SHIFT) & SEG_MASK; @@ -3075,7 +3074,7 @@ l_debug("segO: %d", segO); if (!mesh_crypto_packet_build(false, ttl, seq, src, dst, 0, - segmented, app_key_id, szmic, false, + segmented, key_aid, szmic, false, seqZero, segO, segN, seg, seg_len, packet + 1, &packet_len)) { l_error("Failed to build packet"); @@ -3197,9 +3196,10 @@ return result; } -void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id, uint32_t iv_index, - uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, - bool rly, uint16_t seqZero, uint32_t ack_flags) +void mesh_net_ack_send(struct mesh_net *net, uint32_t net_key_id, + uint32_t iv_index, uint8_t ttl, uint32_t seq, + uint16_t src, uint16_t dst, bool rly, uint16_t seqZero, + uint32_t ack_flags) { uint32_t hdr; uint8_t data[7]; @@ -3219,13 +3219,13 @@ pkt + 1, &pkt_len)) return; - if (!key_id) { + if (!net_key_id) { struct mesh_subnet *subnet = get_primary_subnet(net); - key_id = subnet->net_key_tx; + net_key_id = subnet->net_key_tx; } - if (!net_key_encrypt(key_id, iv_index, pkt + 1, pkt_len)) { + if (!net_key_encrypt(net_key_id, iv_index, pkt + 1, pkt_len)) { l_error("Failed to encode packet"); return; } @@ -3237,7 +3237,7 @@ print_packet("TX: Friend ACK", pkt + 1, pkt_len); } -void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id, +void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id, uint16_t net_idx, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, const uint8_t *msg, @@ -3265,7 +3265,7 @@ return; /* Enqueue for Friend if forwardable and from us */ - if (!key_id && src >= net->src_addr && src <= net->last_addr) { + if (!net_key_id && src >= net->src_addr && src <= net->last_addr) { uint32_t hdr = msg[0] << OPCODE_HDR_SHIFT; uint8_t frnd_ttl = ttl; @@ -3277,17 +3277,17 @@ /* Deliver to Local entities if applicable */ if (!(dst & 0x8000) && src >= net->src_addr && src <= net->last_addr) - result = ctl_received(net, key_id, iv_index, ttl, + result = ctl_received(net, net_key_id, iv_index, ttl, mesh_net_next_seq_num(net), src, dst, msg[0], 0, msg + 1, msg_len - 1); - if (!key_id) { + if (!net_key_id) { struct mesh_subnet *subnet = l_queue_find(net->subnets, match_key_index, L_UINT_TO_PTR(net_idx)); if (!subnet) return; - key_id = subnet->net_key_tx; + net_key_id = subnet->net_key_tx; use_seq = mesh_net_next_seq_num(net); if (result || (dst >= net->src_addr && dst <= net->last_addr)) @@ -3299,7 +3299,7 @@ msg_len - 1, pkt + 1, &pkt_len)) return; - if (!net_key_encrypt(key_id, iv_index, pkt + 1, pkt_len)) { + if (!net_key_encrypt(net_key_id, iv_index, pkt + 1, pkt_len)) { l_error("Failed to encode packet"); return; } diff -Nru bluez-5.63/mesh/net.h bluez-5.64/mesh/net.h --- bluez-5.63/mesh/net.h 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/mesh/net.h 2022-03-16 15:06:20.000000000 +0000 @@ -186,31 +186,6 @@ } u; }; -struct mesh_frnd_pkt { - uint32_t iv_index; - uint32_t seq; - uint16_t src; - uint16_t dst; - uint16_t size; - uint8_t segN; - uint8_t segO; - uint8_t ttl; - uint8_t tc; - bool szmict; - union { - struct { - uint8_t key_id; - } m; - struct { - uint16_t seq0; - } a; - struct { - uint8_t opcode; - } c; - } u; - uint8_t data[]; -}; - struct mesh_friend_seg_one { uint32_t hdr; uint32_t seq; @@ -261,7 +236,7 @@ uint16_t mesh_net_get_address(struct mesh_net *net); bool mesh_net_register_unicast(struct mesh_net *net, uint16_t unicast, uint8_t num_ele); -void net_local_beacon(uint32_t key_id, uint8_t *beacon); +void net_local_beacon(uint32_t net_key_id, uint8_t *beacon); bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable); bool mesh_net_set_proxy_mode(struct mesh_net *net, bool enable); bool mesh_net_set_relay_mode(struct mesh_net *net, bool enable, uint8_t cnt, @@ -278,23 +253,23 @@ void mesh_net_get_snb_state(struct mesh_net *net, uint8_t *flags, uint32_t *iv_index); bool mesh_net_get_key(struct mesh_net *net, bool new_key, uint16_t idx, - uint32_t *key_id); + uint32_t *net_key_id); bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io); struct mesh_io *mesh_net_detach(struct mesh_net *net); struct l_queue *mesh_net_get_app_keys(struct mesh_net *net); -void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id, +void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id, uint16_t net_idx, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, const uint8_t *msg, uint16_t msg_len); bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, - uint16_t dst, uint8_t key_id, uint16_t net_idx, + uint16_t dst, uint8_t key_aid, uint16_t net_idx, uint8_t ttl, uint8_t cnt, uint16_t interval, uint32_t seq, uint32_t iv_index, bool segmented, bool szmic, const void *msg, uint16_t msg_len); -void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id, +void mesh_net_ack_send(struct mesh_net *net, uint32_t net_key_id, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, bool rly, uint16_t seqZero, uint32_t ack_flags); @@ -317,7 +292,7 @@ uint8_t transition); int mesh_net_key_refresh_phase_get(struct mesh_net *net, uint16_t net_idx, uint8_t *phase); -void mesh_net_send_seg(struct mesh_net *net, uint32_t key_id, +void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, uint32_t hdr, const void *seg, uint16_t seg_len); diff -Nru bluez-5.63/mesh/rpl.c bluez-5.64/mesh/rpl.c --- bluez-5.63/mesh/rpl.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/mesh/rpl.c 2022-03-16 15:06:20.000000000 +0000 @@ -80,7 +80,7 @@ iv_index--; snprintf(src_file, PATH_MAX, "%s%s/%8.8x/%4.4x", node_path, rpl_dir, iv_index, src); - if (remove(src_file) < 0) + if (remove(src_file) < 0 && errno != ENOENT) l_error("Failed to remove(%d): %s", errno, src_file); return result; diff -Nru bluez-5.63/monitor/analyze.c bluez-5.64/monitor/analyze.c --- bluez-5.63/monitor/analyze.c 2021-08-22 04:30:44.000000000 +0000 +++ bluez-5.64/monitor/analyze.c 2022-03-16 15:06:20.000000000 +0000 @@ -161,7 +161,8 @@ break; } - conn->tx_pkt_med = conn->tx_bytes / conn->tx_num; + if (conn->tx_num > 0) + conn->tx_pkt_med = conn->tx_bytes / conn->tx_num; printf(" Found %s connection with handle %u\n", str, conn->handle); /* TODO: Store address type */ diff -Nru bluez-5.63/monitor/avctp.c bluez-5.64/monitor/avctp.c --- bluez-5.63/monitor/avctp.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/monitor/avctp.c 2022-03-16 15:06:20.000000000 +0000 @@ -1192,7 +1192,7 @@ for (; num > 0; num--) { uint32_t attr; - if (!l2cap_frame_get_le32(frame, &attr)) + if (!l2cap_frame_get_be32(frame, &attr)) return false; print_field("%*cAttributeID: 0x%08x (%s)", (indent - 8), diff -Nru bluez-5.63/monitor/bt.h bluez-5.64/monitor/bt.h --- bluez-5.63/monitor/bt.h 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/monitor/bt.h 2022-03-16 15:06:20.000000000 +0000 @@ -488,6 +488,7 @@ struct bt_hci_acl_hdr { uint16_t handle; uint16_t dlen; + uint8_t data[]; } __attribute__ ((packed)); struct bt_hci_sco_hdr { @@ -498,11 +499,13 @@ struct bt_hci_iso_hdr { uint16_t handle; uint16_t dlen; + uint8_t data[]; } __attribute__ ((packed)); struct bt_hci_iso_data_start { uint16_t sn; uint16_t slen; + uint8_t data[]; } __attribute__ ((packed)); struct bt_hci_evt_hdr { @@ -2426,24 +2429,24 @@ #define BT_HCI_CMD_LE_CLEAR_ADV_SETS 0x203d -#define BT_HCI_CMD_LE_SET_PERIODIC_ADV_PARAMS 0x203e -struct bt_hci_cmd_le_set_periodic_adv_params { +#define BT_HCI_CMD_LE_SET_PA_PARAMS 0x203e +struct bt_hci_cmd_le_set_pa_params { uint8_t handle; uint16_t min_interval; uint16_t max_interval; uint16_t properties; } __attribute__ ((packed)); -#define BT_HCI_CMD_LE_SET_PERIODIC_ADV_DATA 0x203f -struct bt_hci_cmd_le_set_periodic_adv_data { +#define BT_HCI_CMD_LE_SET_PA_DATA 0x203f +struct bt_hci_cmd_le_set_pa_data { uint8_t handle; uint8_t operation; uint8_t data_len; uint8_t data[0]; } __attribute__ ((packed)); -#define BT_HCI_CMD_LE_SET_PERIODIC_ADV_ENABLE 0x2040 -struct bt_hci_cmd_le_set_periodic_adv_enable { +#define BT_HCI_CMD_LE_SET_PA_ENABLE 0x2040 +struct bt_hci_cmd_le_set_pa_enable { uint8_t enable; uint8_t handle; } __attribute__ ((packed)); @@ -2489,8 +2492,8 @@ uint16_t max_length; } __attribute__ ((packed)); -#define BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC 0x2044 -struct bt_hci_cmd_le_periodic_adv_create_sync { +#define BT_HCI_CMD_LE_PA_CREATE_SYNC 0x2044 +struct bt_hci_cmd_le_pa_create_sync { uint8_t options; uint8_t sid; uint8_t addr_type; @@ -2500,31 +2503,31 @@ uint8_t sync_cte_type; } __attribute__ ((packed)); -#define BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC_CANCEL 0x2045 +#define BT_HCI_CMD_LE_PA_CREATE_SYNC_CANCEL 0x2045 -#define BT_HCI_CMD_LE_PERIODIC_ADV_TERM_SYNC 0x2046 -struct bt_hci_cmd_le_periodic_adv_term_sync { +#define BT_HCI_CMD_LE_PA_TERM_SYNC 0x2046 +struct bt_hci_cmd_le_pa_term_sync { uint16_t sync_handle; } __attribute__ ((packed)); -#define BT_HCI_CMD_LE_ADD_DEV_PERIODIC_ADV_LIST 0x2047 -struct bt_hci_cmd_le_add_dev_periodic_adv_list { +#define BT_HCI_CMD_LE_ADD_DEV_PA_LIST 0x2047 +struct bt_hci_cmd_le_add_dev_pa_list { uint8_t addr_type; uint8_t addr[6]; uint8_t sid; } __attribute__ ((packed)); -#define BT_HCI_CMD_LE_REMOVE_DEV_PERIODIC_ADV_LIST 0x2048 -struct bt_hci_cmd_le_remove_dev_periodic_adv_list { +#define BT_HCI_CMD_LE_REMOVE_DEV_PA_LIST 0x2048 +struct bt_hci_cmd_le_remove_dev_pa_list { uint8_t addr_type; uint8_t addr[6]; uint8_t sid; } __attribute__ ((packed)); -#define BT_HCI_CMD_LE_CLEAR_PERIODIC_ADV_LIST 0x2049 +#define BT_HCI_CMD_LE_CLEAR_PA_LIST 0x2049 -#define BT_HCI_CMD_LE_READ_PERIODIC_ADV_LIST_SIZE 0x204a -struct bt_hci_rsp_le_read_dev_periodic_adv_list_size { +#define BT_HCI_CMD_LE_READ_PA_LIST_SIZE 0x204a +struct bt_hci_rsp_le_read_dev_pa_list_size { uint8_t status; uint8_t list_size; } __attribute__ ((packed)); @@ -2581,28 +2584,28 @@ uint8_t antenna_ids[0]; } __attribute__ ((packed)); -#define BT_HCI_CMD_SET_PERIODIC_ADV_REC_ENABLE 0x2059 -struct bt_hci_cmd_set_periodic_adv_rec_enable { +#define BT_HCI_CMD_SET_PA_REC_ENABLE 0x2059 +struct bt_hci_cmd_set_pa_rec_enable { uint16_t sync_handle; uint8_t enable; } __attribute__ ((packed)); -#define BT_HCI_CMD_PERIODIC_SYNC_TRANS 0x205a +#define BT_HCI_CMD_PERIODIC_SYNC_TRANS 0x205a struct bt_hci_cmd_periodic_sync_trans { uint16_t handle; uint16_t service_data; uint16_t sync_handle; } __attribute__ ((packed)); -#define BT_HCI_CMD_PERIODIC_ADV_SET_INFO_TRANS 0x205b -struct bt_hci_cmd_periodic_adv_set_info_trans { +#define BT_HCI_CMD_PA_SET_INFO_TRANS 0x205b +struct bt_hci_cmd_pa_set_info_trans { uint16_t handle; uint16_t service_data; uint16_t adv_handle; } __attribute__ ((packed)); -#define BT_HCI_CMD_PERIODIC_ADV_SYNC_TRANS_PARAMS 0x205c -struct bt_hci_cmd_periodic_adv_sync_trans_params { +#define BT_HCI_CMD_PA_SYNC_TRANS_PARAMS 0x205c +struct bt_hci_cmd_pa_sync_trans_params { uint16_t handle; uint8_t mode; uint16_t skip; @@ -2610,8 +2613,8 @@ uint8_t cte_type; } __attribute__ ((packed)); -#define BT_HCI_CMD_DEFAULT_PERIODIC_ADV_SYNC_TRANS_PARAMS 0x205d -struct bt_hci_cmd_default_periodic_adv_sync_trans_params { +#define BT_HCI_CMD_DEFAULT_PA_SYNC_TRANS_PARAMS 0x205d +struct bt_hci_cmd_default_pa_sync_trans_params { uint8_t mode; uint16_t skip; uint16_t sync_timeout; @@ -2757,7 +2760,7 @@ uint8_t handle; uint8_t adv_handle; uint8_t num_bis; - struct bt_hci_bis bis[0]; + struct bt_hci_bis bis; } __attribute__ ((packed)); #define BT_HCI_CMD_LE_CREATE_BIG_TEST 0x2069 @@ -2796,6 +2799,7 @@ #define BT_HCI_CMD_LE_BIG_CREATE_SYNC 0x206b #define BT_HCI_BIT_LE_BIG_CREATE_SYNC BT_HCI_CMD_BIT(43, 0) struct bt_hci_bis_sync { + uint8_t index; } __attribute__ ((packed)); struct bt_hci_cmd_le_big_create_sync { @@ -2815,6 +2819,11 @@ uint8_t handle; } __attribute__ ((packed)); +struct bt_hci_rsp_le_big_term_sync { + uint8_t status; + uint8_t handle; +} __attribute__ ((packed)); + #define BT_HCI_CMD_LE_REQ_PEER_SCA 0x206d #define BT_HCI_BIT_LE_REQ_PEER_SCA BT_HCI_CMD_BIT(43, 2) struct bt_hci_cmd_le_req_peer_sca { @@ -3496,7 +3505,7 @@ uint8_t data[0]; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_PER_SYNC_ESTABLISHED 0x0e +#define BT_HCI_EVT_LE_PA_SYNC_ESTABLISHED 0x0e struct bt_hci_evt_le_per_sync_established { uint8_t status; uint16_t handle; @@ -3508,8 +3517,8 @@ uint8_t clock_accuracy; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_PER_ADV_REPORT 0x0f -struct bt_hci_le_per_adv_report { +#define BT_HCI_EVT_LE_PA_REPORT 0x0f +struct bt_hci_le_pa_report { uint16_t handle; uint8_t tx_power; int8_t rssi; @@ -3519,7 +3528,7 @@ uint8_t data[0]; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_PER_SYNC_LOST 0x10 +#define BT_HCI_EVT_LE_PA_SYNC_LOST 0x10 struct bt_hci_evt_le_per_sync_lost { uint16_t handle; } __attribute__ ((packed)); @@ -3551,8 +3560,8 @@ uint16_t handle; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_PER_ADV_SYNC_TRANS_REC 0x18 -struct bt_hci_evt_le_per_adv_sync_trans_rec { +#define BT_HCI_EVT_LE_PA_SYNC_TRANS_REC 0x18 +struct bt_hci_evt_le_pa_sync_trans_rec { uint8_t status; uint16_t handle; uint16_t service_data; @@ -3565,7 +3574,7 @@ uint8_t clock_accuracy; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_CIS_ESTABLISHED 0x19 +#define BT_HCI_EVT_LE_CIS_ESTABLISHED 0x19 struct bt_hci_evt_le_cis_established { uint8_t status; uint16_t conn_handle; @@ -3585,7 +3594,7 @@ uint16_t interval; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_CIS_REQ 0x1a +#define BT_HCI_EVT_LE_CIS_REQ 0x1a struct bt_hci_evt_le_cis_req { uint16_t acl_handle; uint16_t cis_handle; @@ -3593,7 +3602,7 @@ uint8_t cis_id; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_BIG_COMPLETE 0x1b +#define BT_HCI_EVT_LE_BIG_COMPLETE 0x1b struct bt_hci_evt_le_big_complete { uint8_t status; uint8_t handle; @@ -3610,13 +3619,13 @@ uint16_t bis_handle[0]; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_BIG_TERMINATE 0x1c +#define BT_HCI_EVT_LE_BIG_TERMINATE 0x1c struct bt_hci_evt_le_big_terminate { uint8_t reason; uint8_t handle; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED 0x1d +#define BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED 0x1d struct bt_hci_evt_le_big_sync_estabilished { uint8_t status; uint8_t handle; @@ -3631,13 +3640,13 @@ uint16_t bis[0]; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_BIG_SYNC_LOST 0x1e +#define BT_HCI_EVT_LE_BIG_SYNC_LOST 0x1e struct bt_hci_evt_le_big_sync_lost { uint8_t big_id; uint8_t reason; } __attribute__ ((packed)); -#define BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE 0x1f +#define BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE 0x1f struct bt_hci_evt_le_req_peer_sca_complete { uint8_t status; uint16_t handle; @@ -3656,13 +3665,15 @@ #define BT_HCI_ERR_UNSUPPORTED_FEATURE 0x11 #define BT_HCI_ERR_INVALID_PARAMETERS 0x12 #define BT_HCI_ERR_UNSPECIFIED_ERROR 0x1f -#define BT_HCI_ERR_ADV_TIMEOUT 0x3c +#define BT_HCI_ERR_ADV_TIMEOUT 0x3c #define BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH 0x3e #define BT_HCI_ERR_UNKNOWN_ADVERTISING_ID 0x42 +#define BT_HCI_ERR_CANCELLED 0x44 struct bt_l2cap_hdr { uint16_t len; uint16_t cid; + uint8_t data[]; } __attribute__ ((packed)); struct bt_l2cap_hdr_sig { diff -Nru bluez-5.63/monitor/emulator.h bluez-5.64/monitor/emulator.h --- bluez-5.63/monitor/emulator.h 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.64/monitor/emulator.h 2022-03-16 15:06:20.000000000 +0000 @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2011-2014 Intel Corporation + * Copyright (C) 2002-2010 Marcel Holtmann + * + * + */ + +#define EMU_SUBCMD_TEST_EVENT 0x00 + +struct emu_cmd_test_event { + uint8_t subcmd; + uint8_t evt; + uint8_t data[]; +} __attribute__((packed)); diff -Nru bluez-5.63/monitor/packet.c bluez-5.64/monitor/packet.c --- bluez-5.63/monitor/packet.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/monitor/packet.c 2022-03-16 15:06:20.000000000 +0000 @@ -7400,37 +7400,37 @@ print_handle(cmd->handle); } -static const struct bitfield_data periodic_adv_properties_table[] = { +static const struct bitfield_data pa_properties_table[] = { { 6, "Include TxPower" }, { } }; -static void print_periodic_adv_properties(uint16_t flags) +static void print_pa_properties(uint16_t flags) { uint16_t mask; print_field("Properties: 0x%4.4x", flags); - mask = print_bitfield(2, flags, periodic_adv_properties_table); + mask = print_bitfield(2, flags, pa_properties_table); if (mask) print_text(COLOR_UNKNOWN_ADV_FLAG, " Unknown advertising properties (0x%4.4x)", mask); } -static void le_set_periodic_adv_params_cmd(const void *data, uint8_t size) +static void le_set_pa_params_cmd(const void *data, uint8_t size) { - const struct bt_hci_cmd_le_set_periodic_adv_params *cmd = data; + const struct bt_hci_cmd_le_set_pa_params *cmd = data; print_handle(cmd->handle); print_slot_125("Min interval", cmd->min_interval); print_slot_125("Max interval", cmd->max_interval); - print_periodic_adv_properties(cmd->properties); + print_pa_properties(cmd->properties); } -static void le_set_periodic_adv_data_cmd(const void *data, uint8_t size) +static void le_set_pa_data_cmd(const void *data, uint8_t size) { - const struct bt_hci_cmd_le_set_periodic_adv_data *cmd = data; + const struct bt_hci_cmd_le_set_pa_data *cmd = data; const char *str; print_handle(cmd->handle); @@ -7458,9 +7458,9 @@ print_eir(cmd->data, cmd->data_len, true); } -static void le_set_periodic_adv_enable_cmd(const void *data, uint8_t size) +static void le_set_pa_enable_cmd(const void *data, uint8_t size) { - const struct bt_hci_cmd_le_set_periodic_adv_enable *cmd = data; + const struct bt_hci_cmd_le_set_pa_enable *cmd = data; print_enable("Periodic advertising", cmd->enable); print_handle(cmd->handle); @@ -7657,9 +7657,9 @@ } } -static void le_periodic_adv_create_sync_cmd(const void *data, uint8_t size) +static void le_pa_create_sync_cmd(const void *data, uint8_t size) { - const struct bt_hci_cmd_le_periodic_adv_create_sync *cmd = data; + const struct bt_hci_cmd_le_pa_create_sync *cmd = data; print_create_sync_options(cmd->options); print_field("SID: 0x%2.2x", cmd->sid); @@ -7672,34 +7672,34 @@ print_create_sync_cte_type(cmd->sync_cte_type); } -static void le_periodic_adv_term_sync_cmd(const void *data, uint8_t size) +static void le_pa_term_sync_cmd(const void *data, uint8_t size) { - const struct bt_hci_cmd_le_periodic_adv_term_sync *cmd = data; + const struct bt_hci_cmd_le_pa_term_sync *cmd = data; print_field("Sync handle: 0x%4.4x", cmd->sync_handle); } -static void le_add_dev_periodic_adv_list_cmd(const void *data, uint8_t size) +static void le_add_dev_pa_list_cmd(const void *data, uint8_t size) { - const struct bt_hci_cmd_le_add_dev_periodic_adv_list *cmd = data; + const struct bt_hci_cmd_le_add_dev_pa_list *cmd = data; print_addr_type("Adv address type", cmd->addr_type); print_addr("Adv address", cmd->addr, cmd->addr_type); print_field("SID: 0x%2.2x", cmd->sid); } -static void le_remove_dev_periodic_adv_list_cmd(const void *data, uint8_t size) +static void le_remove_dev_pa_list_cmd(const void *data, uint8_t size) { - const struct bt_hci_cmd_le_remove_dev_periodic_adv_list *cmd = data; + const struct bt_hci_cmd_le_remove_dev_pa_list *cmd = data; print_addr_type("Adv address type", cmd->addr_type); print_addr("Adv address", cmd->addr, cmd->addr_type); print_field("SID: 0x%2.2x", cmd->sid); } -static void le_read_periodic_adv_list_size_rsp(const void *data, uint8_t size) +static void le_read_pa_list_size_rsp(const void *data, uint8_t size) { - const struct bt_hci_rsp_le_read_dev_periodic_adv_list_size *rsp = data; + const struct bt_hci_rsp_le_read_dev_pa_list_size *rsp = data; print_status(rsp->status); print_field("List size: 0x%2.2x", rsp->list_size); @@ -7861,15 +7861,15 @@ print_field(" Antenna ID: %u", cmd->antenna_ids[i]); } -static void le_periodic_adv_rec_enable(const void *data, uint8_t size) +static void le_pa_rec_enable(const void *data, uint8_t size) { - const struct bt_hci_cmd_le_set_periodic_adv_enable *cmd = data; + const struct bt_hci_cmd_le_set_pa_enable *cmd = data; print_field("Sync handle: %d", cmd->handle); print_enable("Reporting", cmd->enable); } -static void le_periodic_adv_sync_trans(const void *data, uint8_t size) +static void le_pa_sync_trans(const void *data, uint8_t size) { const struct bt_hci_cmd_periodic_sync_trans *cmd = data; @@ -7878,9 +7878,9 @@ print_field("Sync handle: %d", cmd->sync_handle); } -static void le_periodic_adv_set_info_trans(const void *data, uint8_t size) +static void le_pa_set_info_trans(const void *data, uint8_t size) { - const struct bt_hci_cmd_periodic_adv_set_info_trans *cmd = data; + const struct bt_hci_cmd_pa_set_info_trans *cmd = data; print_field("Connection handle: %d", cmd->handle); print_field("Service data: 0x%4.4x", cmd->service_data); @@ -7909,9 +7909,9 @@ print_field("Mode: %s (0x%2.2x)", str, mode); } -static void le_periodic_adv_sync_trans_params(const void *data, uint8_t size) +static void le_pa_sync_trans_params(const void *data, uint8_t size) { - const struct bt_hci_cmd_periodic_adv_sync_trans_params *cmd = data; + const struct bt_hci_cmd_pa_sync_trans_params *cmd = data; print_field("Connection handle: %d", cmd->handle); print_sync_mode(cmd->mode); @@ -7922,10 +7922,10 @@ print_create_sync_cte_type(cmd->cte_type); } -static void le_set_default_periodic_adv_sync_trans_params(const void *data, +static void le_set_default_pa_sync_trans_params(const void *data, uint8_t size) { - const struct bt_hci_cmd_default_periodic_adv_sync_trans_params *cmd = data; + const struct bt_hci_cmd_default_pa_sync_trans_params *cmd = data; print_sync_mode(cmd->mode); print_field("Skip: 0x%2.2x", cmd->skip); @@ -8124,9 +8124,9 @@ static void print_cig_handle(const void *data, int i) { - const uint16_t *handle = data; + uint16_t handle = get_le16(data); - print_field("Connection Handle: %d", le16_to_cpu(*handle)); + print_field("Connection Handle #%d: %d", i, handle); } static void le_set_cig_params_rsp(const void *data, uint8_t size) @@ -8200,10 +8200,8 @@ print_reason(cmd->reason); } -static void print_bis(const void *data, int i) +static void print_bis(const struct bt_hci_bis *bis) { - const struct bt_hci_bis *bis = data; - print_usec_interval("SDU Interval", bis->sdu_interval); print_field("Maximum SDU size: %u", le16_to_cpu(bis->sdu)); print_field("Maximum Latency: %u ms (0x%4.4x)", @@ -8223,10 +8221,7 @@ print_field("Handle: 0x%2.2x", cmd->handle); print_field("Advertising Handle: 0x%2.2x", cmd->adv_handle); print_field("Number of BIS: %u", cmd->num_bis); - - size -= sizeof(*cmd); - - print_list(cmd->bis, size, cmd->num_bis, sizeof(*cmd->bis), print_bis); + print_bis(&cmd->bis); } static void print_bis_test(const void *data, int i) @@ -9146,13 +9141,13 @@ null_cmd, 0, true, status_rsp, 1, true }, { 0x203e, 298, "LE Set Periodic Advertising Parameters", - le_set_periodic_adv_params_cmd, 7, true, + le_set_pa_params_cmd, 7, true, status_rsp, 1, true }, { 0x203f, 299, "LE Set Periodic Advertising Data", - le_set_periodic_adv_data_cmd, 3, false, + le_set_pa_data_cmd, 3, false, status_rsp, 1, true }, { 0x2040, 300, "LE Set Periodic Advertising Enable", - le_set_periodic_adv_enable_cmd, 2, true, + le_set_pa_enable_cmd, 2, true, status_rsp, 1, true }, { 0x2041, 301, "LE Set Extended Scan Parameters", le_set_ext_scan_params_cmd, 3, false, @@ -9164,26 +9159,26 @@ le_ext_create_conn_cmd, 10, false, status_rsp, 1, true }, { 0x2044, 304, "LE Periodic Advertising Create Sync", - le_periodic_adv_create_sync_cmd, 14, true, + le_pa_create_sync_cmd, 14, true, status_rsp, 1, true }, { 0x2045, 305, "LE Periodic Advertising Create Sync Cancel", null_cmd, 0, true, status_rsp, 1, true }, { 0x2046, 306, "LE Periodic Advertising Terminate Sync", - le_periodic_adv_term_sync_cmd, 2, true, + le_pa_term_sync_cmd, 2, true, status_rsp, 1, true }, { 0x2047, 307, "LE Add Device To Periodic Advertiser List", - le_add_dev_periodic_adv_list_cmd, 8, true, + le_add_dev_pa_list_cmd, 8, true, status_rsp, 1, true }, { 0x2048, 308, "LE Remove Device From Periodic Advertiser List", - le_remove_dev_periodic_adv_list_cmd, 8, true, + le_remove_dev_pa_list_cmd, 8, true, status_rsp, 1, true }, { 0x2049, 309, "LE Clear Periodic Advertiser List", null_cmd, 0, true, status_rsp, 1, true }, { 0x204a, 310, "LE Read Periodic Advertiser List Size", null_cmd, 0, true, - le_read_periodic_adv_list_size_rsp, 2, true }, + le_read_pa_list_size_rsp, 2, true }, { 0x204b, 311, "LE Read Transmit Power", null_cmd, 0, true, le_read_tx_power_rsp, 3, true }, @@ -9203,20 +9198,20 @@ le_tx_test_cmd_v3, 9, false, status_rsp, 1, true }, { 0x2059, 325, "LE Periodic Advertising Receive Enable", - le_periodic_adv_rec_enable, 3, true, + le_pa_rec_enable, 3, true, status_rsp, 1, true }, { 0x205a, 326, "LE Periodic Advertising Sync Transfer", - le_periodic_adv_sync_trans, 6, true, + le_pa_sync_trans, 6, true, status_handle_rsp, 3, true }, { 0x205b, 327, "LE Periodic Advertising Set Info Transfer", - le_periodic_adv_set_info_trans, 5, true, + le_pa_set_info_trans, 5, true, status_handle_rsp, 3, true }, { 0x205c, 328, "LE Periodic Advertising Sync Transfer Parameters", - le_periodic_adv_sync_trans_params, 8, true, + le_pa_sync_trans_params, 8, true, status_handle_rsp, 3, true}, { 0x205d, 329, "LE Set Default Periodic Advertisng Sync Transfer " "Parameters", - le_set_default_periodic_adv_sync_trans_params, + le_set_default_pa_sync_trans_params, 6, true, status_rsp, 1, true}, { BT_HCI_CMD_LE_READ_BUFFER_SIZE_V2, BT_HCI_BIT_LE_READ_BUFFER_SIZE_V2, @@ -10636,7 +10631,7 @@ } } -static void le_per_adv_sync(const void *data, uint8_t size) +static void le_pa_sync(const void *data, uint8_t size) { const struct bt_hci_evt_le_per_sync_established *evt = data; @@ -10654,9 +10649,9 @@ print_field("Advertiser clock accuracy: 0x%2.2x", evt->clock_accuracy); } -static void le_per_adv_report_evt(const void *data, uint8_t size) +static void le_pa_report_evt(const void *data, uint8_t size) { - const struct bt_hci_le_per_adv_report *evt = data; + const struct bt_hci_le_pa_report *evt = data; const char *color_on; const char *str; @@ -10715,7 +10710,7 @@ packet_hexdump(evt->data, evt->data_len); } -static void le_per_adv_sync_lost(const void *data, uint8_t size) +static void le_pa_sync_lost(const void *data, uint8_t size) { const struct bt_hci_evt_le_per_sync_lost *evt = data; @@ -10773,9 +10768,9 @@ print_field("Connection handle: %d", evt->handle); } -static void le_per_adv_sync_trans_rec_evt(const void *data, uint8_t size) +static void le_pa_sync_trans_rec_evt(const void *data, uint8_t size) { - const struct bt_hci_evt_le_per_adv_sync_trans_rec *evt = data; + const struct bt_hci_evt_le_pa_sync_trans_rec *evt = data; print_status(evt->status); print_field("Handle: %d", evt->handle); @@ -10825,9 +10820,9 @@ static void print_bis_handle(const void *data, int i) { - const uint16_t *handle = data; + uint16_t handle = get_le16(data); - print_field("Connection Handle: %d", le16_to_cpu(*handle)); + print_field("Connection Handle #%d: %d", i, handle); } static void le_big_complete_evt(const void *data, uint8_t size) @@ -10962,11 +10957,11 @@ { 0x0d, "LE Extended Advertising Report", le_ext_adv_report_evt, 1, false}, { 0x0e, "LE Periodic Advertising Sync Established", - le_per_adv_sync, 15, true }, + le_pa_sync, 15, true }, { 0x0f, "LE Periodic Advertising Report", - le_per_adv_report_evt, 7, false}, + le_pa_report_evt, 7, false}, { 0x10, "LE Periodic Advertising Sync Lost", - le_per_adv_sync_lost, 2, true}, + le_pa_sync_lost, 2, true}, { 0x11, "LE Scan Timeout" }, { 0x12, "LE Advertising Set Terminated", le_adv_set_term_evt, 5, true}, @@ -10977,7 +10972,7 @@ { 0x17, "LE CTE Request Failed", le_cte_request_failed_evt, 3, true}, { 0x18, "LE Periodic Advertising Sync Transfer Received", - le_per_adv_sync_trans_rec_evt, 19, + le_pa_sync_trans_rec_evt, 19, true}, { BT_HCI_EVT_LE_CIS_ESTABLISHED, "LE Connected Isochronous Stream Established", diff -Nru bluez-5.63/monitor/sdp.c bluez-5.64/monitor/sdp.c --- bluez-5.63/monitor/sdp.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/monitor/sdp.c 2022-03-16 15:06:20.000000000 +0000 @@ -494,7 +494,7 @@ cont_list[n].data = NULL; cont_list[n].size = 0; } else - memcpy(cont_list[i].cont, data + bytes, data[bytes] + 1); + memcpy(cont_list[n].cont, data + bytes, data[bytes] + 1); } static uint16_t common_rsp(const struct l2cap_frame *frame, diff -Nru bluez-5.63/obexd/src/obex.c bluez-5.64/obexd/src/obex.c --- bluez-5.63/obexd/src/obex.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/obexd/src/obex.c 2022-03-16 15:06:20.000000000 +0000 @@ -40,6 +40,7 @@ #include "mimetype.h" #include "service.h" #include "transport.h" +#include "src/shared/util.h" typedef struct { uint8_t version; @@ -145,7 +146,7 @@ os->path = NULL; } if (os->apparam) { - g_free(os->apparam); + free(os->apparam); os->apparam = NULL; os->apparam_len = 0; } @@ -594,7 +595,7 @@ if (!g_obex_header_get_bytes(hdr, &apparam, &len)) return; - os->apparam = g_memdup(apparam, len); + os->apparam = util_memdup(apparam, len); os->apparam_len = len; DBG("APPARAM"); } diff -Nru bluez-5.63/peripheral/main.c bluez-5.64/peripheral/main.c --- bluez-5.63/peripheral/main.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/peripheral/main.c 2022-03-16 15:06:20.000000000 +0000 @@ -25,13 +25,13 @@ #include #include #include -#include #ifndef WAIT_ANY #define WAIT_ANY (-1) #endif #include "src/shared/mainloop.h" +#include "src/shared/util.h" #include "peripheral/efivars.h" #include "peripheral/attach.h" #include "peripheral/gap.h" @@ -192,7 +192,7 @@ addr, 6) < 0) { printf("Generating new persistent static address\n"); - if (getrandom(addr, sizeof(addr), 0) < 0) { + if (util_getrandom(addr, sizeof(addr), 0) < 0) { perror("Failed to get random static address"); return EXIT_FAILURE; } diff -Nru bluez-5.63/plugins/autopair.c bluez-5.64/plugins/autopair.c --- bluez-5.63/plugins/autopair.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/plugins/autopair.c 2022-03-16 15:06:20.000000000 +0000 @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -29,6 +28,7 @@ #include "src/device.h" #include "src/log.h" #include "src/storage.h" +#include "src/shared/util.h" /* * Plugin to handle automatic pairing of devices with reduced user @@ -131,7 +131,7 @@ if (attempt >= 4) return 0; - if (getrandom(&val, sizeof(val), 0) < 0) { + if (util_getrandom(&val, sizeof(val), 0) < 0) { error("Failed to get a random pincode"); return 0; } diff -Nru bluez-5.63/plugins/neard.c bluez-5.64/plugins/neard.c --- bluez-5.63/plugins/neard.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/plugins/neard.c 2022-03-16 15:06:20.000000000 +0000 @@ -30,6 +30,7 @@ #include "src/eir.h" #include "src/agent.h" #include "src/btd.h" +#include "src/shared/util.h" #define NEARD_NAME "org.neard" #define NEARD_PATH "/" @@ -71,7 +72,7 @@ g_free(params->name); g_free(params->hash); g_free(params->randomizer); - g_free(params->pin); + free(params->pin); } static DBusMessage *error_reply(DBusMessage *msg, int error) @@ -407,10 +408,10 @@ remote->name = g_strndup((char *)n->name, n->name_len); if (marker == 0x01) { - remote->pin = g_memdup(n->authentication, 4); + remote->pin = util_memdup(n->authentication, 4); remote->pin_len = 4; } else if (marker == 0x02) { - remote->pin = g_memdup(n->authentication, 16); + remote->pin = util_memdup(n->authentication, 16); remote->pin_len = 16; } @@ -439,7 +440,7 @@ if (n->name_len > 0) remote->name = g_strndup((char *)n->name, n->name_len); - remote->pin = g_memdup(n->authentication, 4); + remote->pin = util_memdup(n->authentication, 4); remote->pin_len = 4; return 0; @@ -574,14 +575,12 @@ if (process_nokia_com_bt(data, size, remote)) goto error; } else if (strcasecmp(key, "State") == 0) { - DBusMessageIter array; const char *state; if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) goto error; - dbus_message_iter_recurse(&value, &array); dbus_message_iter_get_basic(&value, &state); remote->power_state = process_state(state); diff -Nru bluez-5.63/plugins/policy.c bluez-5.64/plugins/policy.c --- bluez-5.63/plugins/policy.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/plugins/policy.c 2022-03-16 15:06:20.000000000 +0000 @@ -32,6 +32,7 @@ #include "src/profile.h" #include "src/btd.h" #include "src/shared/timeout.h" +#include "src/shared/util.h" #define CONTROL_CONNECT_TIMEOUT 2 #define SOURCE_RETRY_TIMEOUT 2 @@ -855,7 +856,7 @@ reconnect_attempts = default_attempts; reconnect_intervals_len = sizeof(default_intervals) / sizeof(*reconnect_intervals); - reconnect_intervals = g_memdup(default_intervals, + reconnect_intervals = util_memdup(default_intervals, sizeof(default_intervals)); goto done; } @@ -886,7 +887,7 @@ g_clear_error(&gerr); reconnect_intervals_len = sizeof(default_intervals) / sizeof(*reconnect_intervals); - reconnect_intervals = g_memdup(default_intervals, + reconnect_intervals = util_memdup(default_intervals, sizeof(default_intervals)); } @@ -919,7 +920,7 @@ if (reconnect_uuids) g_strfreev(reconnect_uuids); - g_free(reconnect_intervals); + free(reconnect_intervals); g_slist_free_full(reconnects, reconnect_destroy); diff -Nru bluez-5.63/profiles/audio/a2dp.c bluez-5.64/profiles/audio/a2dp.c --- bluez-5.63/profiles/audio/a2dp.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/profiles/audio/a2dp.c 2022-03-16 15:06:20.000000000 +0000 @@ -244,6 +244,15 @@ cb->setup = setup; cb->id = ++cb_id; + return cb; +} + +static struct a2dp_setup_cb *setup_cb_add(struct a2dp_setup *setup) +{ + struct a2dp_setup_cb *cb; + + cb = setup_cb_new(setup); + setup->cb = g_slist_append(setup->cb, cb); return cb; } @@ -832,7 +841,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } data = g_key_file_get_string(key_file, "Endpoints", "LastUsed", @@ -1006,7 +1015,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } sprintf(value, "%02hhx:%02hhx", lseid, rseid); @@ -1840,7 +1849,7 @@ if (!setup) return -ENOMEM; - cb_data = setup_cb_new(setup); + cb_data = setup_cb_add(setup); cb_data->config_cb = reconfig_cb; cb_data->user_data = user_data; @@ -2878,12 +2887,17 @@ if (!setup) return 0; + /* Don't add cb since avdtp_discover can end up disconnecting the + * session causing the cb to be freed. + */ cb_data = setup_cb_new(setup); cb_data->discover_cb = cb; cb_data->user_data = user_data; - if (avdtp_discover(session, discover_cb, setup) == 0) + if (avdtp_discover(session, discover_cb, setup) == 0) { + setup->cb = g_slist_append(setup->cb, cb_data); return cb_data->id; + } setup_cb_free(cb_data); return 0; @@ -2911,7 +2925,7 @@ if (!setup) return 0; - cb_data = setup_cb_new(setup); + cb_data = setup_cb_add(setup); cb_data->select_cb = cb; cb_data->user_data = user_data; @@ -2984,7 +2998,7 @@ if (!setup) return 0; - cb_data = setup_cb_new(setup); + cb_data = setup_cb_add(setup); cb_data->config_cb = cb; cb_data->user_data = user_data; @@ -3075,7 +3089,7 @@ if (!setup) return 0; - cb_data = setup_cb_new(setup); + cb_data = setup_cb_add(setup); cb_data->resume_cb = cb; cb_data->user_data = user_data; @@ -3133,7 +3147,7 @@ if (!setup) return 0; - cb_data = setup_cb_new(setup); + cb_data = setup_cb_add(setup); cb_data->suspend_cb = cb; cb_data->user_data = user_data; diff -Nru bluez-5.63/profiles/audio/avctp.c bluez-5.64/profiles/audio/avctp.c --- bluez-5.63/profiles/audio/avctp.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/profiles/audio/avctp.c 2022-03-16 15:06:20.000000000 +0000 @@ -40,6 +40,7 @@ #include "src/log.h" #include "src/error.h" #include "src/shared/timeout.h" +#include "src/shared/util.h" #include "avctp.h" #include "avrcp.h" @@ -760,7 +761,7 @@ NULL, 0, req->user_data); done: - g_free(req->operands); + free(req->operands); g_free(req); } @@ -776,7 +777,7 @@ req->func(session, NULL, 0, req->user_data); done: - g_free(req->operands); + free(req->operands); g_free(req); } @@ -1727,7 +1728,7 @@ req->subunit = subunit; req->op = opcode; req->func = func; - req->operands = g_memdup(operands, operand_count); + req->operands = util_memdup(operands, operand_count); req->operand_count = operand_count; req->user_data = user_data; @@ -1765,7 +1766,7 @@ req = g_new0(struct avctp_browsing_req, 1); req->func = func; - req->operands = g_memdup(operands, operand_count); + req->operands = util_memdup(operands, operand_count); req->operand_count = operand_count; req->user_data = user_data; diff -Nru bluez-5.63/profiles/audio/avdtp.c bluez-5.64/profiles/audio/avdtp.c --- bluez-5.63/profiles/audio/avdtp.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/profiles/audio/avdtp.c 2022-03-16 15:06:20.000000000 +0000 @@ -497,7 +497,9 @@ single.signal_id = signal_id; memcpy(session->buf, &single, sizeof(single)); - memcpy(session->buf + sizeof(single), data, len); + + if (data) + memcpy(session->buf + sizeof(single), data, len); return try_send(sock, session->buf, sizeof(single) + len); } @@ -569,7 +571,7 @@ if (req->timeout) timeout_remove(req->timeout); - g_free(req->data); + free(req->data); g_free(req); } @@ -1333,7 +1335,7 @@ break; } - cpy = btd_malloc(sizeof(*cpy) + cap->length); + cpy = util_malloc(sizeof(*cpy) + cap->length); memcpy(cpy, cap, sizeof(*cap) + cap->length); size -= sizeof(*cap) + cap->length; @@ -2687,7 +2689,7 @@ return 0; failed: - g_free(req->data); + free(req->data); g_free(req); return err; } @@ -2705,8 +2707,7 @@ req = g_new0(struct pending_req, 1); req->signal_id = signal_id; - req->data = g_malloc(size); - memcpy(req->data, buffer, size); + req->data = util_memdup(buffer, size); req->data_size = size; req->stream = stream; @@ -3323,7 +3324,9 @@ cap = g_malloc(sizeof(struct avdtp_service_capability) + length); cap->category = category; cap->length = length; - memcpy(cap->data, data, length); + + if (data) + memcpy(cap->data, data, length); return cap; } diff -Nru bluez-5.63/profiles/audio/avrcp.c bluez-5.64/profiles/audio/avrcp.c --- bluez-5.63/profiles/audio/avrcp.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/profiles/audio/avrcp.c 2022-03-16 15:06:20.000000000 +0000 @@ -835,7 +835,7 @@ } done: - pdu->params_len = htons(size); + pdu->params_len = cpu_to_be16(size); for (l = player->sessions; l; l = l->next) { struct avrcp *session = l->data; @@ -933,15 +933,17 @@ return attr_len; } +struct avrcp_media_attribute_hdr { + uint32_t id; + uint16_t charset; + uint16_t len; +} __attribute__ ((packed)); + static GList *player_fill_media_attribute(struct avrcp_player *player, GList *attr_ids, uint8_t *buf, uint16_t *pos, uint16_t *offset) { - struct media_attribute_header { - uint32_t id; - uint16_t charset; - uint16_t len; - } *hdr = NULL; + struct avrcp_media_attribute_hdr *hdr = NULL; GList *l; for (l = attr_ids; l != NULL; l = g_list_delete_link(l, l)) { @@ -953,9 +955,9 @@ break; hdr = (void *) &buf[*pos]; - hdr->id = htonl(attr); + hdr->id = cpu_to_be32(attr); /* Always use UTF-8 */ - hdr->charset = htons(AVRCP_CHARSET_UTF8); + hdr->charset = cpu_to_be16(AVRCP_CHARSET_UTF8); *pos += sizeof(*hdr); } @@ -963,7 +965,7 @@ pos, offset); if (hdr != NULL) - hdr->len = htons(attr_len); + hdr->len = cpu_to_be16(attr_len); if (*offset > 0) break; @@ -1062,7 +1064,7 @@ struct avrcp_header *pdu, uint8_t transaction) { - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); unsigned int i; if (len != 1) @@ -1077,7 +1079,8 @@ company_ids[i]); } - pdu->params_len = htons(2 + (3 * G_N_ELEMENTS(company_ids))); + pdu->params_len = cpu_to_be16(2 + + (3 * G_N_ELEMENTS(company_ids))); pdu->params[1] = G_N_ELEMENTS(company_ids); return AVC_CTYPE_STABLE; @@ -1090,12 +1093,12 @@ } } - pdu->params_len = htons(2 + pdu->params[1]); + pdu->params_len = cpu_to_be16(2 + pdu->params[1]); return AVC_CTYPE_STABLE; } err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; @@ -1114,11 +1117,11 @@ uint8_t transaction) { struct avrcp_player *player = target_get_player(session); - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); unsigned int i; if (len != 0) { - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1136,7 +1139,7 @@ done: pdu->params[0] = len; - pdu->params_len = htons(len + 1); + pdu->params_len = cpu_to_be16(len + 1); return AVC_CTYPE_STABLE; } @@ -1146,7 +1149,7 @@ uint8_t transaction) { struct avrcp_player *player = target_get_player(session); - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); unsigned int i; if (len != 1) @@ -1161,12 +1164,12 @@ pdu->params[i] = i; pdu->params[0] = len; - pdu->params_len = htons(len + 1); + pdu->params_len = cpu_to_be16(len + 1); return AVC_CTYPE_STABLE; err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1215,7 +1218,7 @@ uint8_t transaction) { struct avrcp_player *player = target_get_player(session); - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); uint64_t identifier = get_le64(&pdu->params[0]); uint16_t pos; uint8_t nattr; @@ -1273,11 +1276,11 @@ } pdu->params[0] = len; - pdu->params_len = htons(pos); + pdu->params_len = cpu_to_be16(pos); return AVC_CTYPE_STABLE; err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1287,7 +1290,7 @@ uint8_t transaction) { struct avrcp_player *player = target_get_player(session); - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); uint8_t *settings; unsigned int i; @@ -1298,7 +1301,7 @@ * Save a copy of requested settings because we can override them * while responding */ - settings = g_memdup(&pdu->params[1], pdu->params[0]); + settings = util_memdup(&pdu->params[1], pdu->params[0]); len = 0; /* @@ -1323,11 +1326,11 @@ pdu->params[++len] = val; } - g_free(settings); + free(settings); if (len) { pdu->params[0] = len / 2; - pdu->params_len = htons(len + 1); + pdu->params_len = cpu_to_be16(len + 1); return AVC_CTYPE_STABLE; } @@ -1335,7 +1338,7 @@ error("No valid attributes in request"); err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; @@ -1346,7 +1349,7 @@ uint8_t transaction) { struct avrcp_player *player = target_get_player(session); - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); unsigned int i; uint8_t *param; @@ -1375,7 +1378,7 @@ } err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1384,10 +1387,10 @@ struct avrcp_header *pdu, uint8_t transaction) { - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); if (len < 3) { - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1404,7 +1407,7 @@ struct avrcp_header *pdu, uint8_t transaction) { - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); const char *valstr; if (len != 1) @@ -1419,7 +1422,7 @@ return AVC_CTYPE_STABLE; err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1481,12 +1484,12 @@ uint8_t transaction) { struct avrcp_player *player = target_get_player(session); - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); uint32_t position; uint32_t duration; if (len != 0) { - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1494,14 +1497,11 @@ position = player_get_position(player); duration = player_get_duration(player); - position = htonl(position); - duration = htonl(duration); - - memcpy(&pdu->params[0], &duration, 4); - memcpy(&pdu->params[4], &position, 4); + put_be32(duration, &pdu->params[0]); + put_be32(position, &pdu->params[4]); pdu->params[8] = player_get_status(player); - pdu->params_len = htons(9); + pdu->params_len = cpu_to_be16(9); return AVC_CTYPE_STABLE; } @@ -1609,7 +1609,7 @@ { struct avrcp_player *player = target_get_player(session); struct btd_device *dev = session->dev; - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); uint64_t uid; int8_t volume; @@ -1670,12 +1670,12 @@ session->registered_events |= (1 << pdu->params[0]); session->transaction_events[pdu->params[0]] = transaction; - pdu->params_len = htons(len); + pdu->params_len = cpu_to_be16(len); return AVC_CTYPE_INTERIM; err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1685,7 +1685,7 @@ uint8_t transaction) { struct avrcp_player *player = target_get_player(session); - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); struct pending_pdu *pending; if (len != 1 || session->pending_pdu == NULL) @@ -1711,11 +1711,11 @@ pdu->packet_type = AVRCP_PACKET_TYPE_CONTINUING; } - pdu->params_len = htons(len); + pdu->params_len = cpu_to_be16(len); return AVC_CTYPE_STABLE; err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1724,7 +1724,7 @@ struct avrcp_header *pdu, uint8_t transaction) { - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); struct pending_pdu *pending; if (len != 1 || session->pending_pdu == NULL) @@ -1741,7 +1741,7 @@ return AVC_CTYPE_ACCEPTED; err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1750,7 +1750,7 @@ struct avrcp_header *pdu, uint8_t transaction) { - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); int8_t volume; if (len != 1) @@ -1763,7 +1763,7 @@ return AVC_CTYPE_ACCEPTED; err: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INVALID_PARAM; return AVC_CTYPE_REJECTED; } @@ -1821,7 +1821,7 @@ uint8_t transaction) { struct avrcp_player *player; - uint16_t len = ntohs(pdu->params_len); + uint16_t len = be16_to_cpu(pdu->params_len); uint16_t player_id = 0; uint8_t status; @@ -1837,7 +1837,7 @@ if (player) { player->addressed = true; status = AVRCP_STATUS_SUCCESS; - pdu->params_len = htons(len); + pdu->params_len = cpu_to_be16(len); pdu->params[0] = status; } else { status = AVRCP_STATUS_INVALID_PLAYER_ID; @@ -1853,7 +1853,7 @@ return AVC_CTYPE_ACCEPTED; err: - pdu->params_len = htons(sizeof(status)); + pdu->params_len = cpu_to_be16(sizeof(status)); pdu->params[0] = status; return AVC_CTYPE_REJECTED; } @@ -1911,7 +1911,7 @@ } DBG("AVRCP PDU 0x%02X, company 0x%06X len 0x%04X", - pdu->pdu_id, company_id, ntohs(pdu->params_len)); + pdu->pdu_id, company_id, be16_to_cpu(pdu->params_len)); pdu->packet_type = 0; pdu->rsvd = 0; @@ -1924,9 +1924,9 @@ operands += sizeof(*pdu); operand_count -= sizeof(*pdu); - if (ntohs(pdu->params_len) != operand_count) { + if (be16_to_cpu(pdu->params_len) != operand_count) { DBG("AVRCP PDU parameters length don't match"); - pdu->params_len = htons(operand_count); + pdu->params_len = cpu_to_be16(operand_count); } for (handler = session->control_handlers; handler->pdu_id; handler++) { @@ -1952,10 +1952,10 @@ pdu->pdu_id != AVRCP_ABORT_CONTINUING) session_abort_pending_pdu(session); - return AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); + return AVRCP_HEADER_LENGTH + be16_to_cpu(pdu->params_len); err_metadata: - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); *code = AVC_CTYPE_REJECTED; return AVRCP_HEADER_LENGTH + 1; @@ -1972,7 +1972,7 @@ rsp = (void *)pdu->params; rsp->status = AVRCP_STATUS_SUCCESS; - rsp->uid_counter = htons(player_get_uid_counter(player)); + rsp->uid_counter = cpu_to_be16(player_get_uid_counter(player)); rsp->num_items = 0; pdu->param_len = sizeof(*rsp); @@ -1992,22 +1992,22 @@ pdu->param_len += sizeof(*folder); item = (void *)folder->data; - item->player_id = htons(player->id); + item->player_id = cpu_to_be16(player->id); item->type = 0x01; /* Audio */ - item->subtype = htonl(0x01); /* Audio Book */ + item->subtype = cpu_to_be32(0x00000001); /* Audio Book */ item->status = player_get_status(player); /* Assign Default Feature Bit Mask */ memcpy(&item->features, &default_features, sizeof(default_features)); - item->charset = htons(AVRCP_CHARSET_UTF8); + item->charset = cpu_to_be16(AVRCP_CHARSET_UTF8); name = player->cb->get_name(player->user_data); namelen = strlen(name); - item->namelen = htons(namelen); + item->namelen = cpu_to_be16(namelen); memcpy(item->name, name, namelen); - folder->len = htons(sizeof(*item) + namelen); + folder->len = cpu_to_be16(sizeof(*item) + namelen); pdu->param_len += sizeof(*item) + namelen; rsp->num_items++; } @@ -2016,14 +2016,14 @@ if (!rsp->num_items) goto failed; - rsp->num_items = htons(rsp->num_items); - pdu->param_len = htons(pdu->param_len); + rsp->num_items = cpu_to_be16(rsp->num_items); + pdu->param_len = cpu_to_be16(pdu->param_len); return; failed: pdu->params[0] = AVRCP_STATUS_OUT_OF_BOUNDS; - pdu->param_len = htons(1); + pdu->param_len = cpu_to_be16(1); } static void avrcp_handle_get_folder_items(struct avrcp *session, @@ -2035,7 +2035,7 @@ uint8_t scope; uint8_t status = AVRCP_STATUS_SUCCESS; - if (ntohs(pdu->param_len) < 10) { + if (be16_to_cpu(pdu->param_len) < 10) { status = AVRCP_STATUS_INVALID_PARAM; goto failed; } @@ -2069,7 +2069,7 @@ failed: pdu->params[0] = status; - pdu->param_len = htons(1); + pdu->param_len = cpu_to_be16(1); } static void avrcp_handle_media_player_list_num_items(struct avrcp *session, @@ -2080,9 +2080,9 @@ rsp = (void *)pdu->params; rsp->status = AVRCP_STATUS_SUCCESS; - rsp->uid_counter = htons(player_get_uid_counter(player)); - rsp->num_items = htonl(g_slist_length(session->server->players)); - pdu->param_len = htons(sizeof(*rsp)); + rsp->uid_counter = cpu_to_be16(player_get_uid_counter(player)); + rsp->num_items = cpu_to_be32(g_slist_length(session->server->players)); + pdu->param_len = cpu_to_be16(sizeof(*rsp)); } static void avrcp_handle_get_total_number_of_items(struct avrcp *session, @@ -2092,7 +2092,7 @@ uint8_t scope; uint8_t status = AVRCP_STATUS_SUCCESS; - if (ntohs(pdu->param_len) != 1) { + if (be16_to_cpu(pdu->param_len) != 1) { status = AVRCP_STATUS_INVALID_PARAM; goto failed; } @@ -2115,7 +2115,7 @@ failed: pdu->params[0] = status; - pdu->param_len = htons(1); + pdu->param_len = cpu_to_be16(1); } static struct browsing_pdu_handler { @@ -2137,7 +2137,7 @@ pdu->pdu_id = AVRCP_GENERAL_REJECT; status = AVRCP_STATUS_INVALID_COMMAND; - pdu->param_len = htons(sizeof(status)); + pdu->param_len = cpu_to_be16(sizeof(status)); memcpy(pdu->params, &status, (sizeof(status))); return AVRCP_BROWSING_HEADER_LENGTH + sizeof(status); } @@ -2151,7 +2151,7 @@ struct avrcp_browsing_header *pdu = (void *) operands; DBG("AVRCP Browsing PDU 0x%02X, len 0x%04X", pdu->pdu_id, - ntohs(pdu->param_len)); + be16_to_cpu(pdu->param_len)); for (handler = browsing_handlers; handler->pdu_id; handler++) { if (handler->pdu_id == pdu->pdu_id) @@ -2163,7 +2163,7 @@ done: session->transaction = transaction; handler->func(session, pdu, transaction); - return AVRCP_BROWSING_HEADER_LENGTH + ntohs(pdu->param_len); + return AVRCP_BROWSING_HEADER_LENGTH + be16_to_cpu(pdu->param_len); } size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands) @@ -2172,11 +2172,11 @@ uint32_t company_id = get_company_id(pdu->company_id); *code = AVC_CTYPE_REJECTED; - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); pdu->params[0] = AVRCP_STATUS_INTERNAL_ERROR; DBG("rejecting AVRCP PDU 0x%02X, company 0x%06X len 0x%04X", - pdu->pdu_id, company_id, ntohs(pdu->params_len)); + pdu->pdu_id, company_id, be16_to_cpu(pdu->params_len)); return AVRCP_HEADER_LENGTH + 1; } @@ -2227,18 +2227,16 @@ uint8_t status; if (pdu == NULL || code == AVC_CTYPE_REJECTED || - ntohs(pdu->params_len) != 9) + be16_to_cpu(pdu->params_len) != 9) return FALSE; - memcpy(&duration, pdu->params, sizeof(uint32_t)); - duration = ntohl(duration); + duration = get_be32(pdu->params); media_player_set_duration(mp, duration); - memcpy(&position, pdu->params + 4, sizeof(uint32_t)); - position = ntohl(position); + position = get_be32(pdu->params + 4); media_player_set_position(mp, position); - memcpy(&status, pdu->params + 8, sizeof(uint8_t)); + status = get_u8(pdu->params + 8); media_player_set_status(mp, status_to_string(status)); return FALSE; @@ -2335,7 +2333,7 @@ set_company_id(pdu->company_id, IEEEID_BTSIG); pdu->pdu_id = AVRCP_GET_CURRENT_PLAYER_VALUE; pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE; - pdu->params_len = htons(count + 1); + pdu->params_len = cpu_to_be16(count + 1); pdu->params[0] = count; memcpy(pdu->params + 1, attrs, count); @@ -2361,7 +2359,7 @@ len = pdu->params[0]; - if (ntohs(pdu->params_len) < count) { + if (be16_to_cpu(pdu->params_len) < count) { error("Invalid parameters"); return FALSE; } @@ -2404,6 +2402,8 @@ struct media_item *item; int i; + media_player_clear_metadata(mp); + item = media_player_set_playlist_item(mp, player->uid); for (i = 0; count > 0; count--) { @@ -2430,6 +2430,8 @@ i += len; } + + media_player_metadata_changed(mp); } static gboolean avrcp_get_element_attributes_rsp(struct avctp *conn, @@ -2449,7 +2451,7 @@ count = pdu->params[0]; - if (ntohs(pdu->params_len) - 1 < count * 8) { + if (be16_to_cpu(pdu->params_len) - 1 < count * 8) { error("Invalid parameters"); return FALSE; } @@ -2471,10 +2473,10 @@ set_company_id(pdu->company_id, IEEEID_BTSIG); pdu->pdu_id = AVRCP_GET_ELEMENT_ATTRIBUTES; - pdu->params_len = htons(9); + pdu->params_len = cpu_to_be16(9); pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE; - length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); + length = AVRCP_HEADER_LENGTH + be16_to_cpu(pdu->params_len); avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL, buf, length, @@ -2695,12 +2697,11 @@ struct avrcp_player *player = session->controller->player; struct avrcp_browsing_header *pdu = (void *) buf; uint16_t length = AVRCP_BROWSING_HEADER_LENGTH + 10; - uint32_t attribute; memset(buf, 0, sizeof(buf)); pdu->pdu_id = AVRCP_GET_FOLDER_ITEMS; - pdu->param_len = htons(10 + sizeof(uint32_t)); + pdu->param_len = cpu_to_be16(10 + sizeof(uint32_t)); pdu->params[0] = player->scope; @@ -2711,8 +2712,7 @@ /* Only the title (0x01) is mandatory. This can be extended to * support AVRCP_MEDIA_ATTRIBUTE_* attributes */ - attribute = htonl(AVRCP_MEDIA_ATTRIBUTE_TITLE); - memcpy(&pdu->params[10], &attribute, sizeof(uint32_t)); + put_be32(AVRCP_MEDIA_ATTRIBUTE_TITLE, &pdu->params[10]); length += sizeof(uint32_t); @@ -2801,7 +2801,7 @@ break; } - folders[count] = g_memdup(&pdu->params[i], len); + folders[count] = util_memdup(&pdu->params[i], len); i += len; } @@ -2823,9 +2823,9 @@ memset(buf, 0, sizeof(buf)); pdu->pdu_id = AVRCP_SET_BROWSED_PLAYER; - id = htons(player->id); + id = cpu_to_be16(player->id); memcpy(pdu->params, &id, 2); - pdu->param_len = htons(2); + pdu->param_len = cpu_to_be16(2); avctp_send_browsing_req(session->conn, buf, sizeof(buf), avrcp_set_browsed_player_rsp, session); @@ -2853,7 +2853,7 @@ count = pdu->params[1]; - if (ntohs(pdu->param_len) - 1 < count * 8) { + if (be16_to_cpu(pdu->param_len) - 1 < count * 8) { error("Invalid parameters"); return FALSE; } @@ -2877,7 +2877,7 @@ pdu->params[0] = 0x03; put_be64(uid, &pdu->params[1]); put_be16(player->uid_counter, &pdu->params[9]); - pdu->param_len = htons(12); + pdu->param_len = cpu_to_be16(12); avctp_send_browsing_req(session->conn, buf, sizeof(buf), avrcp_get_item_attributes_rsp, session); @@ -2888,7 +2888,7 @@ { struct media_player *mp = player->user_data; - player->features = g_memdup(features, 16); + player->features = util_memdup(features, 16); if (features[7] & 0x08) { media_player_set_browsable(mp, true); @@ -2921,9 +2921,9 @@ pdu->params[0] = 1; pdu->params[1] = attr; pdu->params[2] = val; - pdu->params_len = htons(3); + pdu->params_len = cpu_to_be16(3); - length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); + length = AVRCP_HEADER_LENGTH + be16_to_cpu(pdu->params_len); avctp_send_vendordep_req(session->conn, AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL, buf, length, @@ -2959,9 +2959,9 @@ set_company_id(pdu->company_id, IEEEID_BTSIG); pdu->pdu_id = AVRCP_SET_ADDRESSED_PLAYER; pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE; - id = htons(player->id); + id = cpu_to_be16(player->id); memcpy(pdu->params, &id, 2); - pdu->params_len = htons(2); + pdu->params_len = cpu_to_be16(2); avctp_send_vendordep_req(session->conn, AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL, buf, sizeof(buf), @@ -3189,7 +3189,7 @@ pdu->params[2] = direction; put_be64(uid, &pdu->params[3]); pdu->pdu_id = AVRCP_CHANGE_PATH; - pdu->param_len = htons(11); + pdu->param_len = cpu_to_be16(11); avctp_send_browsing_req(session->conn, buf, sizeof(buf), avrcp_change_path_rsp, session); @@ -3257,7 +3257,7 @@ put_be16(stringlen, &pdu->params[2]); memcpy(&pdu->params[4], string, stringlen); pdu->pdu_id = AVRCP_SEARCH; - pdu->param_len = htons(len - AVRCP_BROWSING_HEADER_LENGTH); + pdu->param_len = cpu_to_be16(len - AVRCP_BROWSING_HEADER_LENGTH); avctp_send_browsing_req(session->conn, buf, len, avrcp_search_rsp, session); @@ -3323,14 +3323,14 @@ set_company_id(pdu->company_id, IEEEID_BTSIG); pdu->pdu_id = AVRCP_PLAY_ITEM; - pdu->params_len = htons(11); + pdu->params_len = cpu_to_be16(11); pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE; pdu->params[0] = player->scope; put_be64(uid, &pdu->params[1]); put_be16(player->uid_counter, &pdu->params[9]); - length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); + length = AVRCP_HEADER_LENGTH + be16_to_cpu(pdu->params_len); avctp_send_vendordep_req(session->conn, AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL, buf, length, @@ -3372,14 +3372,14 @@ set_company_id(pdu->company_id, IEEEID_BTSIG); pdu->pdu_id = AVRCP_ADD_TO_NOW_PLAYING; - pdu->params_len = htons(11); + pdu->params_len = cpu_to_be16(11); pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE; pdu->params[0] = player->scope; put_be64(uid, &pdu->params[1]); put_be16(player->uid_counter, &pdu->params[9]); - length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); + length = AVRCP_HEADER_LENGTH + be16_to_cpu(pdu->params_len); avctp_send_vendordep_req(session->conn, AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL, buf, length, @@ -3447,7 +3447,7 @@ memset(buf, 0, sizeof(buf)); pdu->pdu_id = AVRCP_GET_TOTAL_NUMBER_OF_ITEMS; - pdu->param_len = htons(7 + sizeof(uint32_t)); + pdu->param_len = cpu_to_be16(7 + sizeof(uint32_t)); pdu->params[0] = player->scope; @@ -3622,7 +3622,7 @@ g_slist_free(player->sessions); g_free(player->path); g_free(player->change_path); - g_free(player->features); + free(player->features); g_free(player); } @@ -3715,7 +3715,7 @@ pdu->pdu_id = AVRCP_GET_FOLDER_ITEMS; put_be32(0, &pdu->params[1]); put_be32(UINT32_MAX, &pdu->params[5]); - pdu->param_len = htons(10); + pdu->param_len = cpu_to_be16(10); avctp_send_browsing_req(session->conn, buf, sizeof(buf), avrcp_get_media_player_list_rsp, session); @@ -3935,9 +3935,9 @@ if (event == AVRCP_EVENT_PLAYBACK_POS_CHANGED) bt_put_be32(UINT32_MAX / 1000, &pdu->params[1]); - pdu->params_len = htons(AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH); + pdu->params_len = cpu_to_be16(AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH); - length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); + length = AVRCP_HEADER_LENGTH + be16_to_cpu(pdu->params_len); avctp_send_vendordep_req(session->conn, AVC_CTYPE_NOTIFY, AVC_SUBUNIT_PANEL, buf, length, @@ -4015,7 +4015,6 @@ { uint8_t buf[AVRCP_HEADER_LENGTH + AVRCP_GET_CAPABILITIES_PARAM_LENGTH]; struct avrcp_header *pdu = (void *) buf; - uint8_t length; memset(buf, 0, sizeof(buf)); @@ -4023,12 +4022,10 @@ pdu->pdu_id = AVRCP_GET_CAPABILITIES; pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE; pdu->params[0] = CAP_EVENTS_SUPPORTED; - pdu->params_len = htons(AVRCP_GET_CAPABILITIES_PARAM_LENGTH); - - length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); + pdu->params_len = cpu_to_be16(AVRCP_GET_CAPABILITIES_PARAM_LENGTH); avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS, - AVC_SUBUNIT_PANEL, buf, length, + AVC_SUBUNIT_PANEL, buf, sizeof(buf), avrcp_get_capabilities_resp, session); } @@ -4535,7 +4532,7 @@ return -EINVAL; } - pdu->params_len = htons(size); + pdu->params_len = cpu_to_be16(size); err = avctp_send_vendordep(session->conn, session->transaction_events[id], @@ -4590,7 +4587,7 @@ pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME; pdu->params[0] = volume; - pdu->params_len = htons(1); + pdu->params_len = cpu_to_be16(1); return avctp_send_vendordep_req(session->conn, AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL, diff -Nru bluez-5.63/profiles/audio/media.c bluez-5.64/profiles/audio/media.c --- bluez-5.63/profiles/audio/media.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/profiles/audio/media.c 2022-03-16 15:06:20.000000000 +0000 @@ -241,6 +241,16 @@ return NULL; } +static void endpoint_remove_transport(struct media_endpoint *endpoint, + struct media_transport *transport) +{ + if (!endpoint || !transport) + return; + + endpoint->transports = g_slist_remove(endpoint->transports, transport); + media_transport_destroy(transport); +} + static void clear_configuration(struct media_endpoint *endpoint, struct media_transport *transport) { @@ -260,8 +270,7 @@ DBUS_TYPE_INVALID); g_dbus_send_message(btd_get_dbus_connection(), msg); done: - endpoint->transports = g_slist_remove(endpoint->transports, transport); - media_transport_destroy(transport); + endpoint_remove_transport(endpoint, transport); } static void clear_endpoint(struct media_endpoint *endpoint) @@ -301,12 +310,8 @@ if (dbus_message_is_method_call(request->msg, MEDIA_ENDPOINT_INTERFACE, - "SetConfiguration")) { - if (request->transport == NULL) - error("Expected to destroy transport"); - else - media_transport_destroy(request->transport); - } + "SetConfiguration")) + endpoint_remove_transport(endpoint, request->transport); dbus_error_free(&err); goto done; diff -Nru bluez-5.63/profiles/audio/player.c bluez-5.64/profiles/audio/player.c --- bluez-5.63/profiles/audio/player.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/profiles/audio/player.c 2022-03-16 15:06:20.000000000 +0000 @@ -85,7 +85,6 @@ char *status; uint32_t position; GTimer *progress; - guint process_id; struct player_callback *cb; GSList *pending; GSList *folders; @@ -1233,9 +1232,6 @@ if (mp->settings) g_hash_table_unref(mp->settings); - if (mp->process_id > 0) - g_source_remove(mp->process_id); - if (mp->scope) g_dbus_unregister_interface(btd_get_dbus_connection(), mp->path, @@ -1308,9 +1304,10 @@ g_hash_table_replace(mp->track, g_strdup("Duration"), value); - g_dbus_emit_property_changed(btd_get_dbus_connection(), + g_dbus_emit_property_changed_full(btd_get_dbus_connection(), mp->path, MEDIA_PLAYER_INTERFACE, - "Track"); + "Track", + G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH); } void media_player_set_position(struct media_player *mp, uint32_t position) @@ -1395,26 +1392,20 @@ g_timer_start(mp->progress); } -static gboolean process_metadata_changed(void *user_data) +static gboolean remove_metadata(void *key, void *value, void *user_data) { - struct media_player *mp = user_data; - const char *item; - - mp->process_id = 0; - - g_dbus_emit_property_changed(btd_get_dbus_connection(), - mp->path, MEDIA_PLAYER_INTERFACE, - "Track"); - - item = g_hash_table_lookup(mp->track, "Item"); - if (item == NULL) + if (!strcmp(key, "Duration")) return FALSE; - g_dbus_emit_property_changed(btd_get_dbus_connection(), - item, MEDIA_ITEM_INTERFACE, - "Metadata"); + return strcmp(key, "Item") ? TRUE : FALSE; +} + +void media_player_clear_metadata(struct media_player *mp) +{ + if (!mp) + return; - return FALSE; + g_hash_table_foreach_remove(mp->track, remove_metadata, NULL); } void media_player_set_metadata(struct media_player *mp, @@ -1433,14 +1424,31 @@ return; } - if (mp->process_id == 0) { - g_hash_table_remove_all(mp->track); - mp->process_id = g_idle_add(process_metadata_changed, mp); - } - g_hash_table_replace(mp->track, g_strdup(key), value); } +void media_player_metadata_changed(struct media_player *mp) +{ + char *item; + + if (!mp) + return; + + g_dbus_emit_property_changed_full(btd_get_dbus_connection(), + mp->path, MEDIA_PLAYER_INTERFACE, + "Track", + G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH); + + item = g_hash_table_lookup(mp->track, "Item"); + if (item == NULL) + return; + + g_dbus_emit_property_changed_full(btd_get_dbus_connection(), + item, MEDIA_ITEM_INTERFACE, + "Metadata", + G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH); +} + void media_player_set_type(struct media_player *mp, const char *type) { if (g_strcmp0(mp->type, type) == 0) @@ -1962,6 +1970,7 @@ { struct media_folder *folder = mp->playlist; struct media_item *item; + char *path; DBG("%" PRIu64 "", uid); @@ -1980,16 +1989,11 @@ mp->track = g_hash_table_ref(item->metadata); } - if (item == g_hash_table_lookup(mp->track, "Item")) + path = g_hash_table_lookup(mp->track, "Item"); + if (path && !strcmp(path, item->path)) return item; - if (mp->process_id == 0) { - g_hash_table_remove_all(mp->track); - mp->process_id = g_idle_add(process_metadata_changed, mp); - } - - g_hash_table_replace(mp->track, g_strdup("Item"), - g_strdup(item->path)); + g_hash_table_replace(mp->track, g_strdup("Item"), g_strdup(item->path)); return item; } diff -Nru bluez-5.63/profiles/audio/player.h bluez-5.64/profiles/audio/player.h --- bluez-5.63/profiles/audio/player.h 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/profiles/audio/player.h 2022-03-16 15:06:20.000000000 +0000 @@ -70,9 +70,11 @@ const char *value); const char *media_player_get_status(struct media_player *mp); void media_player_set_status(struct media_player *mp, const char *status); +void media_player_clear_metadata(struct media_player *mp); void media_player_set_metadata(struct media_player *mp, struct media_item *item, const char *key, void *data, size_t len); +void media_player_metadata_changed(struct media_player *mp); void media_player_set_type(struct media_player *mp, const char *type); void media_player_set_subtype(struct media_player *mp, const char *subtype); void media_player_set_name(struct media_player *mp, const char *name); diff -Nru bluez-5.63/profiles/battery/bas.c bluez-5.64/profiles/battery/bas.c --- bluez-5.63/profiles/battery/bas.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/profiles/battery/bas.c 2022-03-16 15:06:20.000000000 +0000 @@ -62,7 +62,7 @@ { bt_bas_detach(bas); - g_free(bas->primary); + free(bas->primary); queue_destroy(bas->gatt_op, (void *) destroy_gatt_req); free(bas); } @@ -75,7 +75,7 @@ bas->gatt_op = queue_new(); if (primary) - bas->primary = g_memdup(primary, sizeof(*bas->primary)); + bas->primary = util_memdup(primary, sizeof(*bas->primary)); return bt_bas_ref(bas); } diff -Nru bluez-5.63/profiles/battery/battery.c bluez-5.64/profiles/battery/battery.c --- bluez-5.63/profiles/battery/battery.c 2021-04-02 08:59:48.000000000 +0000 +++ bluez-5.64/profiles/battery/battery.c 2022-03-16 15:06:20.000000000 +0000 @@ -66,7 +66,7 @@ gatt_db_unref(batt->db); bt_gatt_client_unref(batt->client); btd_device_unref(batt->device); - g_free (batt->initial_value); + free(batt->initial_value); if (batt->battery) btd_battery_unregister(batt->battery); g_free(batt); @@ -159,7 +159,7 @@ if (!length) return; - batt->initial_value = g_memdup(value, length); + batt->initial_value = util_memdup(value, length); /* request notify */ batt->batt_level_cb_id = diff -Nru bluez-5.63/profiles/deviceinfo/dis.c bluez-5.64/profiles/deviceinfo/dis.c --- bluez-5.63/profiles/deviceinfo/dis.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/profiles/deviceinfo/dis.c 2022-03-16 15:06:20.000000000 +0000 @@ -72,7 +72,7 @@ { bt_dis_detach(dis); - g_free(dis->primary); + free(dis->primary); queue_destroy(dis->gatt_op, (void *) destroy_gatt_req); g_free(dis); } @@ -143,7 +143,7 @@ dis->gatt_op = queue_new(); if (primary) - dis->primary = g_memdup(primary, sizeof(*dis->primary)); + dis->primary = util_memdup(primary, sizeof(*dis->primary)); return bt_dis_ref(dis); } diff -Nru bluez-5.63/profiles/health/hdp.c bluez-5.64/profiles/health/hdp.c --- bluez-5.63/profiles/health/hdp.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/profiles/health/hdp.c 2022-03-16 15:06:20.000000000 +0000 @@ -16,7 +16,6 @@ #include #include #include -#include #include @@ -33,6 +32,7 @@ #include "src/device.h" #include "src/sdpd.h" #include "src/shared/timeout.h" +#include "src/shared/util.h" #include "btio/btio.h" #include "hdp_types.h" @@ -576,7 +576,7 @@ "Cannot reconnect: %s", gerr->message); g_dbus_send_message(conn, reply); hdp_tmp_dc_data_unref(dc_data); - g_error_free(gerr); + g_clear_error(&gerr); /* Send abort request because remote side is now in PENDING state */ if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) { @@ -1490,7 +1490,7 @@ if (!buf) return NULL; - if (getrandom(buf, HDP_ECHO_LEN, 0) < 0) { + if (util_getrandom(buf, HDP_ECHO_LEN, 0) < 0) { g_free(buf); return NULL; } @@ -1766,7 +1766,7 @@ return; error("%s", gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_OBJECT_PATH, &hdp_chan->path, @@ -1790,7 +1790,7 @@ ERROR_INTERFACE ".HealthError", "%s", gerr->message); g_dbus_send_message(conn, reply); - g_error_free(gerr); + g_clear_error(&gerr); /* Send abort request because remote side is now in PENDING */ /* state. Then we have to delete it because we couldn't */ diff -Nru bluez-5.63/profiles/health/mcap.c bluez-5.64/profiles/health/mcap.c --- bluez-5.63/profiles/health/mcap.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/profiles/health/mcap.c 2022-03-16 15:06:20.000000000 +0000 @@ -19,7 +19,6 @@ #include #include #include -#include #include @@ -28,6 +27,7 @@ #include "btio/btio.h" #include "src/log.h" #include "src/shared/timeout.h" +#include "src/shared/util.h" #include "mcap.h" @@ -1905,7 +1905,7 @@ mcl->state = MCL_IDLE; bacpy(&mcl->addr, addr); set_default_cb(mcl); - if (getrandom(&val, sizeof(val), 0) < 0) { + if (util_getrandom(&val, sizeof(val), 0) < 0) { mcap_instance_unref(mcl->mi); g_free(mcl); return FALSE; @@ -2049,7 +2049,7 @@ mcl->mi = mcap_instance_ref(mi); bacpy(&mcl->addr, &dst); set_default_cb(mcl); - if (getrandom(&val, sizeof(val), 0) < 0) { + if (util_getrandom(&val, sizeof(val), 0) < 0) { mcap_instance_unref(mcl->mi); g_free(mcl); goto drop; diff -Nru bluez-5.63/profiles/input/device.c bluez-5.64/profiles/input/device.c --- bluez-5.63/profiles/input/device.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/profiles/input/device.c 2022-03-16 15:06:20.000000000 +0000 @@ -1053,7 +1053,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } str = g_key_file_get_string(key_file, "ServiceRecords", handle, NULL); g_key_file_free(key_file); diff -Nru bluez-5.63/profiles/input/hog-lib.c bluez-5.64/profiles/input/hog-lib.c --- bluez-5.63/profiles/input/hog-lib.c 2021-06-13 19:56:37.000000000 +0000 +++ bluez-5.64/profiles/input/hog-lib.c 2022-03-16 15:06:20.000000000 +0000 @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -80,7 +81,8 @@ struct bt_uhid *uhid; int uhid_fd; bool uhid_created; - gboolean has_report_id; + bool uhid_start; + uint64_t uhid_flags; uint16_t bcdhid; uint8_t bcountrycode; uint16_t proto_mode_handle; @@ -90,6 +92,7 @@ uint16_t getrep_id; unsigned int setrep_att; uint16_t setrep_id; + unsigned int report_map_id; struct bt_scpp *scpp; struct bt_dis *dis; struct queue *bas; @@ -97,6 +100,7 @@ struct queue *gatt_op; struct gatt_db *gatt_db; struct gatt_db_attribute *report_map_attr; + struct queue *input; }; struct report_map { @@ -106,6 +110,7 @@ struct report { struct bt_hog *hog; + bool numbered; uint8_t id; uint8_t type; uint16_t handle; @@ -146,13 +151,34 @@ return queue_push_head(hog->gatt_op, req); } -static void destroy_gatt_req(struct gatt_request *req) +static void destroy_gatt_req(void *data) { - queue_remove(req->hog->gatt_op, req); + struct gatt_request *req = data; + bt_hog_unref(req->hog); free(req); } +static void read_report_map(struct bt_hog *hog); + +static void remove_gatt_req(struct gatt_request *req, uint8_t status) +{ + struct bt_hog *hog = req->hog; + + queue_remove(hog->gatt_op, req); + + if (!status && queue_isempty(hog->gatt_op)) { + /* Report Map must be read last since that can result + * in uhid being created and the driver may start to + * use UHID_SET_REPORT which requires the report->id to + * be known what attribute to send to. + */ + read_report_map(hog); + } + + destroy_gatt_req(req); +} + static void write_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle, const uint8_t *value, size_t vlen, GAttribResultFunc func, @@ -178,27 +204,31 @@ } } -static void read_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle, - GAttribResultFunc func, gpointer user_data) +static unsigned int read_char(struct bt_hog *hog, GAttrib *attrib, + uint16_t handle, GAttribResultFunc func, + gpointer user_data) { struct gatt_request *req; unsigned int id; req = create_request(hog, user_data); if (!req) - return; + return 0; id = gatt_read_char(attrib, handle, func, req); if (!id) { error("hog: Could not read char"); - return; + return 0; } if (!set_and_store_gatt_req(hog, req, id)) { error("hog: Failed to queue read char req"); g_attrib_cancel(attrib, id); free(req); + return 0; } + + return id; } static void discover_desc(struct bt_hog *hog, GAttrib *attrib, @@ -318,7 +348,7 @@ ev.type = UHID_INPUT; buf = ev.u.input.data; - if (hog->has_report_id) { + if (report->numbered) { buf[0] = report->id; len = MIN(len, sizeof(ev.u.input.data) - 1); memcpy(buf + 1, pdu, len); @@ -329,11 +359,18 @@ ev.u.input.size = len; } - err = bt_uhid_send(hog->uhid, &ev); - if (err < 0) { - error("bt_uhid_send: %s (%d)", strerror(-err), -err); + /* If uhid had not sent UHID_START yet queue up the input */ + if (!hog->uhid_created || !hog->uhid_start) { + if (!hog->input) + hog->input = queue_new(); + + queue_push_tail(hog->input, util_memdup(&ev, sizeof(ev))); return; } + + err = bt_uhid_send(hog->uhid, &ev); + if (err < 0) + error("bt_uhid_send: %s (%d)", strerror(-err), -err); } static void report_ccc_written_cb(guint8 status, const guint8 *pdu, @@ -343,16 +380,14 @@ struct report *report = req->user_data; struct bt_hog *hog = report->hog; - destroy_gatt_req(req); - if (status != 0) { error("Write report characteristic descriptor failed: %s", att_ecode2str(status)); - return; + goto remove; } if (report->notifyid) - return; + goto remove; report->notifyid = g_attrib_register(hog->attrib, ATT_OP_HANDLE_NOTIFY, @@ -360,6 +395,9 @@ report_value_cb, report, NULL); DBG("Report characteristic descriptor written: notifications enabled"); + +remove: + remove_gatt_req(req, status); } static void write_ccc(struct bt_hog *hog, GAttrib *attrib, uint16_t handle, @@ -379,14 +417,15 @@ struct gatt_request *req = user_data; struct report *report = req->user_data; - destroy_gatt_req(req); - if (status != 0) { error("Error reading CCC value: %s", att_ecode2str(status)); - return; + goto remove; } write_ccc(report->hog, report->hog->attrib, report->ccc_handle, report); + +remove: + remove_gatt_req(req, status); } static const char *type_to_string(uint8_t type) @@ -409,17 +448,15 @@ struct gatt_request *req = user_data; struct report *report = req->user_data; - destroy_gatt_req(req); - if (status != 0) { error("Read Report Reference descriptor failed: %s", att_ecode2str(status)); - return; + goto remove; } if (plen != 3) { error("Malformed ATT read response"); - return; + goto remove; } report->id = pdu[1]; @@ -432,6 +469,9 @@ if (report->type == HOG_REPORT_TYPE_INPUT) read_char(report->hog, report->hog->attrib, report->ccc_handle, ccc_read_cb, report); + +remove: + remove_gatt_req(req, status); } static void external_report_reference_cb(guint8 status, const guint8 *pdu, @@ -442,12 +482,10 @@ struct gatt_request *req = user_data; struct bt_hog *hog = req->user_data; - destroy_gatt_req(req); - if (status != 0) { error("Discover external descriptors failed: %s", att_ecode2str(status)); - return; + goto remove; } for ( ; descs; descs = descs->next) { @@ -457,6 +495,9 @@ external_report_reference_cb, hog); } + +remove: + remove_gatt_req(req, status); } static void discover_external(struct bt_hog *hog, GAttrib *attrib, @@ -480,12 +521,10 @@ struct report *report = req->user_data; struct bt_hog *hog = report->hog; - destroy_gatt_req(req); - if (status != 0) { error("Discover report descriptors failed: %s", att_ecode2str(status)); - return; + goto remove; } for ( ; descs; descs = descs->next) { @@ -501,6 +540,9 @@ break; } } + +remove: + remove_gatt_req(req, status); } static void discover_report(struct bt_hog *hog, GAttrib *attrib, @@ -519,18 +561,19 @@ struct gatt_request *req = user_data; struct report *report = req->user_data; - destroy_gatt_req(req); - if (status != 0) { error("Error reading Report value: %s", att_ecode2str(status)); - return; + goto remove; } if (report->value) - g_free(report->value); + free(report->value); - report->value = g_memdup(pdu, len); + report->value = util_memdup(pdu, len); report->len = len; + +remove: + remove_gatt_req(req, status); } static int report_chrc_cmp(const void *data, const void *user_data) @@ -572,12 +615,11 @@ struct report *report; GSList *l; - destroy_gatt_req(req); - if (status != 0) { const char *str = att_ecode2str(status); + DBG("Discover external service characteristic failed: %s", str); - return; + goto remove; } for (l = chars; l; l = g_slist_next(l)) { @@ -595,6 +637,9 @@ end = (next ? next->handle - 1 : primary->range.end); discover_report(hog, hog->attrib, start, end, report); } + +remove: + remove_gatt_req(req, status); } static void external_report_reference_cb(guint8 status, const guint8 *pdu, @@ -605,17 +650,15 @@ uint16_t uuid16; bt_uuid_t uuid; - destroy_gatt_req(req); - if (status != 0) { error("Read External Report Reference descriptor failed: %s", att_ecode2str(status)); - return; + goto remove; } if (plen != 3) { error("Malformed ATT read response"); - return; + goto remove; } uuid16 = get_le16(&pdu[1]); @@ -624,11 +667,14 @@ /* Do not discover if is not a Report */ if (uuid16 != HOG_REPORT_UUID) - return; + goto remove; bt_uuid16_create(&uuid, uuid16); discover_char(hog, hog->attrib, 0x0001, 0xffff, &uuid, external_service_char_cb, hog); + +remove: + remove_gatt_req(req, status); } static int report_cmp(gconstpointer a, gconstpointer b) @@ -639,8 +685,8 @@ if (ra->type != rb->type) return ra->type - rb->type; - /* skip id check in case of report id 0 */ - if (!rb->id) + /* skip id check in case of reports not being numbered */ + if (!ra->numbered && !rb->numbered) return 0; /* ..then by id */ @@ -652,8 +698,24 @@ struct report cmp; GSList *l; + memset(&cmp, 0, sizeof(cmp)); cmp.type = type; - cmp.id = hog->has_report_id ? id : 0; + cmp.id = id; + + switch (type) { + case HOG_REPORT_TYPE_FEATURE: + if (hog->flags & UHID_DEV_NUMBERED_FEATURE_REPORTS) + cmp.numbered = true; + break; + case HOG_REPORT_TYPE_OUTPUT: + if (hog->flags & UHID_DEV_NUMBERED_OUTPUT_REPORTS) + cmp.numbered = true; + break; + case HOG_REPORT_TYPE_INPUT: + if (hog->flags & UHID_DEV_NUMBERED_INPUT_REPORTS) + cmp.numbered = true; + break; + } l = g_slist_find_custom(hog->reports, &cmp, report_cmp); @@ -687,12 +749,10 @@ { struct gatt_request *req = user_data; - destroy_gatt_req(req); - - if (status != 0) { + if (status != 0) error("Write output report failed: %s", att_ecode2str(status)); - return; - } + + remove_gatt_req(req, status); } static void forward_report(struct uhid_event *ev, void *user_data) @@ -709,7 +769,8 @@ data = ev->u.output.data; size = ev->u.output.size; - if (hog->has_report_id && size > 0) { + + if (report->numbered && size > 0) { data++; --size; } @@ -728,6 +789,57 @@ data, size, NULL, NULL); } +static void set_numbered(void *data, void *user_data) +{ + struct report *report = data; + struct bt_hog *hog = user_data; + + switch (report->type) { + case HOG_REPORT_TYPE_INPUT: + if (hog->uhid_flags & UHID_DEV_NUMBERED_INPUT_REPORTS) + report->numbered = true; + break; + case HOG_REPORT_TYPE_OUTPUT: + if (hog->uhid_flags & UHID_DEV_NUMBERED_OUTPUT_REPORTS) + report->numbered = true; + break; + case HOG_REPORT_TYPE_FEATURE: + if (hog->uhid_flags & UHID_DEV_NUMBERED_FEATURE_REPORTS) + report->numbered = true; + break; + } +} + +static bool input_dequeue(const void *data, const void *match_data) +{ + const struct uhid_event *ev = data; + const struct bt_hog *hog = match_data; + int err; + + err = bt_uhid_send(hog->uhid, ev); + if (err < 0) { + error("bt_uhid_send: %s (%d)", strerror(-err), -err); + return false; + } + + return true; +} + +static void start_flags(struct uhid_event *ev, void *user_data) +{ + struct bt_hog *hog = user_data; + + hog->uhid_start = true; + hog->uhid_flags = ev->u.start.dev_flags; + + DBG("uHID device flags: 0x%16" PRIx64, hog->uhid_flags); + + if (hog->uhid_flags) + g_slist_foreach(hog->reports, set_numbered, hog); + + queue_remove_all(hog->input, input_dequeue, hog, free); +} + static void set_report_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { @@ -775,7 +887,8 @@ data = ev->u.set_report.data; size = ev->u.set_report.size; - if (hog->has_report_id && size > 0) { + + if (report->numbered && size > 0) { data++; --size; } @@ -802,7 +915,7 @@ } static void report_reply(struct bt_hog *hog, uint8_t status, uint8_t id, - uint16_t len, const uint8_t *data) + bool numbered, uint16_t len, const uint8_t *data) { struct uhid_event rsp; int err; @@ -816,7 +929,7 @@ if (status) goto done; - if (hog->has_report_id && len > 0) { + if (numbered && len > 0) { rsp.u.get_report_reply.size = len + 1; rsp.u.get_report_reply.data[0] = id; memcpy(&rsp.u.get_report_reply.data[1], data, len); @@ -859,7 +972,7 @@ ++pdu; exit: - report_reply(hog, status, report->id, len, pdu); + report_reply(hog, status, report->id, report->numbered, len, pdu); } static void get_report(struct uhid_event *ev, void *user_data) @@ -895,136 +1008,57 @@ fail: /* reply with an error on failure */ - report_reply(hog, err, 0, 0, NULL); -} - -static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len, - bool *is_long) -{ - if (!blen) - return false; - - *is_long = (buf[0] == 0xfe); - - if (*is_long) { - if (blen < 3) - return false; - - /* - * long item: - * byte 0 -> 0xFE - * byte 1 -> data size - * byte 2 -> tag - * + data - */ - - *len = buf[1] + 3; - } else { - uint8_t b_size; - - /* - * short item: - * byte 0[1..0] -> data size (=0, 1, 2, 4) - * byte 0[3..2] -> type - * byte 0[7..4] -> tag - * + data - */ - - b_size = buf[0] & 0x03; - *len = (b_size ? 1 << (b_size - 1) : 0) + 1; - } - - /* item length should be no more than input buffer length */ - return *len <= blen; -} - -static char *item2string(char *str, uint8_t *buf, uint8_t len) -{ - char *p = str; - int i; - - /* - * Since long item tags are not defined except for vendor ones, we - * just ensure that short items are printed properly (up to 5 bytes). - */ - for (i = 0; i < 6 && i < len; i++) - p += sprintf(p, " %02x", buf[i]); - - /* - * If there are some data left, just add continuation mark to indicate - * this. - */ - if (i < len) - sprintf(p, " ..."); - - return str; + report_reply(hog, err, 0, false, 0, NULL); } static void uhid_create(struct bt_hog *hog, uint8_t *report_map, - ssize_t report_map_len) + size_t report_map_len) { uint8_t *value = report_map; struct uhid_event ev; - ssize_t vlen = report_map_len; - char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */ + size_t vlen = report_map_len; int i, err; GError *gerr = NULL; - DBG("Report MAP:"); - for (i = 0; i < vlen;) { - ssize_t ilen = 0; - bool long_item = false; - - if (get_descriptor_item_info(&value[i], vlen - i, &ilen, - &long_item)) { - /* Report ID is short item with prefix 100001xx */ - if (!long_item && (value[i] & 0xfc) == 0x84) - hog->has_report_id = TRUE; - - DBG("\t%s", item2string(itemstr, &value[i], ilen)); - - i += ilen; - } else { - error("Report Map parsing failed at %d", i); - - /* Just print remaining items at once and break */ - DBG("\t%s", item2string(itemstr, &value[i], vlen - i)); - break; - } + if (vlen > sizeof(ev.u.create2.rd_data)) { + error("Report MAP too big: %zu > %zu", vlen, + sizeof(ev.u.create2.rd_data)); + return; } /* create uHID device */ memset(&ev, 0, sizeof(ev)); - ev.type = UHID_CREATE; + ev.type = UHID_CREATE2; bt_io_get(g_attrib_get_channel(hog->attrib), &gerr, - BT_IO_OPT_SOURCE, ev.u.create.phys, - BT_IO_OPT_DEST, ev.u.create.uniq, + BT_IO_OPT_SOURCE, ev.u.create2.phys, + BT_IO_OPT_DEST, ev.u.create2.uniq, BT_IO_OPT_INVALID); - /* Phys + uniq are the same size (hw address type) */ - for (i = 0; - i < (int)sizeof(ev.u.create.phys) && ev.u.create.phys[i] != 0; - ++i) { - ev.u.create.phys[i] = tolower(ev.u.create.phys[i]); - ev.u.create.uniq[i] = tolower(ev.u.create.uniq[i]); - } - if (gerr) { error("Failed to connection details: %s", gerr->message); g_error_free(gerr); return; } - strncpy((char *) ev.u.create.name, hog->name, - sizeof(ev.u.create.name) - 1); - ev.u.create.vendor = hog->vendor; - ev.u.create.product = hog->product; - ev.u.create.version = hog->version; - ev.u.create.country = hog->bcountrycode; - ev.u.create.bus = BUS_BLUETOOTH; - ev.u.create.rd_data = value; - ev.u.create.rd_size = vlen; + /* Phys + uniq are the same size (hw address type) */ + for (i = 0; + i < (int)sizeof(ev.u.create2.phys) && ev.u.create2.phys[i] != 0; + ++i) { + ev.u.create2.phys[i] = tolower(ev.u.create2.phys[i]); + ev.u.create2.uniq[i] = tolower(ev.u.create2.uniq[i]); + } + + strncpy((char *) ev.u.create2.name, hog->name, + sizeof(ev.u.create2.name) - 1); + ev.u.create2.vendor = hog->vendor; + ev.u.create2.product = hog->product; + ev.u.create2.version = hog->version; + ev.u.create2.country = hog->bcountrycode; + ev.u.create2.bus = BUS_BLUETOOTH; + ev.u.create2.rd_size = vlen; + + memcpy(ev.u.create2.rd_data, value, vlen); err = bt_uhid_send(hog->uhid, &ev); if (err < 0) { @@ -1032,11 +1066,13 @@ return; } + bt_uhid_register(hog->uhid, UHID_START, start_flags, hog); bt_uhid_register(hog->uhid, UHID_OUTPUT, forward_report, hog); bt_uhid_register(hog->uhid, UHID_GET_REPORT, get_report, hog); bt_uhid_register(hog->uhid, UHID_SET_REPORT, set_report, hog); hog->uhid_created = true; + hog->uhid_start = false; DBG("HoG created uHID device"); } @@ -1056,9 +1092,7 @@ uint8_t value[HOG_REPORT_MAP_MAX_SIZE]; ssize_t vlen; - destroy_gatt_req(req); - - DBG("HoG inspecting report map"); + remove_gatt_req(req, status); if (status != 0) { error("Report Map read failed: %s", att_ecode2str(status)); @@ -1081,6 +1115,19 @@ } } +static void read_report_map(struct bt_hog *hog) +{ + uint16_t handle; + + if (!hog->report_map_attr || hog->uhid_created || hog->report_map_id) + return; + + handle = gatt_db_attribute_get_handle(hog->report_map_attr); + + hog->report_map_id = read_char(hog, hog->attrib, handle, + report_map_read_cb, hog); +} + static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { @@ -1089,18 +1136,16 @@ uint8_t value[HID_INFO_SIZE]; ssize_t vlen; - destroy_gatt_req(req); - if (status != 0) { error("HID Information read failed: %s", att_ecode2str(status)); - return; + goto remove; } vlen = dec_read_resp(pdu, plen, value, sizeof(value)); if (vlen != 4) { error("ATT protocol error"); - return; + goto remove; } hog->bcdhid = get_le16(&value[0]); @@ -1109,6 +1154,9 @@ DBG("bcdHID: 0x%04X bCountryCode: 0x%02X Flags: 0x%02X", hog->bcdhid, hog->bcountrycode, hog->flags); + +remove: + remove_gatt_req(req, status); } static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen, @@ -1119,18 +1167,16 @@ uint8_t value; ssize_t vlen; - destroy_gatt_req(req); - if (status != 0) { error("Protocol Mode characteristic read failed: %s", att_ecode2str(status)); - return; + goto remove; } vlen = dec_read_resp(pdu, plen, &value, sizeof(value)); if (vlen < 0) { error("ATT protocol error"); - return; + goto remove; } if (value == HOG_PROTO_MODE_BOOT) { @@ -1142,6 +1188,9 @@ sizeof(nval), NULL, NULL); } else if (value == HOG_PROTO_MODE_REPORT) DBG("HoG is operating in Report Protocol Mode"); + +remove: + remove_gatt_req(req, status); } static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data) @@ -1155,14 +1204,12 @@ GSList *l; uint16_t info_handle = 0, proto_mode_handle = 0; - destroy_gatt_req(req); - DBG("HoG inspecting characteristics"); if (status != 0) { - const char *str = att_ecode2str(status); - DBG("Discover all characteristics failed: %s", str); - return; + DBG("Discover all characteristics failed: %s", + att_ecode2str(status)); + goto remove; } bt_uuid16_create(&report_uuid, HOG_REPORT_UUID); @@ -1211,20 +1258,25 @@ if (info_handle) read_char(hog, hog->attrib, info_handle, info_read_cb, hog); + +remove: + remove_gatt_req(req, status); } static void report_free(void *data) { struct report *report = data; - g_free(report->value); + free(report->value); g_free(report); } -static void cancel_gatt_req(struct gatt_request *req) +static bool cancel_gatt_req(const void *data, const void *user_data) { - if (g_attrib_cancel(req->hog->attrib, req->id)) - destroy_gatt_req(req); + struct gatt_request *req = (void *) data; + const struct bt_hog *hog = user_data; + + return g_attrib_cancel(hog->attrib, req->id); } static void hog_free(void *data) @@ -1233,6 +1285,7 @@ bt_hog_detach(hog); + queue_destroy(hog->input, free); queue_destroy(hog->bas, (void *) bt_bas_unref); g_slist_free_full(hog->instances, hog_free); @@ -1241,7 +1294,7 @@ bt_uhid_unref(hog->uhid); g_slist_free_full(hog->reports, report_free); g_free(hog->name); - g_free(hog->primary); + free(hog->primary); queue_destroy(hog->gatt_op, (void *) destroy_gatt_req); if (hog->gatt_db) gatt_db_unref(hog->gatt_db); @@ -1386,13 +1439,9 @@ * UHID to optimize reconnection. */ uhid_create(hog, report_map.value, report_map.length); - } else { - read_char(hog, hog->attrib, value_handle, - report_map_read_cb, hog); } gatt_db_service_foreach_desc(attr, foreach_hog_external, hog); - return; } bt_uuid16_create(&info_uuid, HOG_INFO_UUID); @@ -1552,12 +1601,9 @@ DBG(""); - destroy_gatt_req(req); - if (status) { - const char *str = att_ecode2str(status); - DBG("Find included failed: %s", str); - return; + DBG("Find included failed: %s", att_ecode2str(status)); + goto remove; } for (l = services; l; l = l->next) { @@ -1566,6 +1612,9 @@ DBG("included: handle %x, uuid %s", include->handle, include->uuid); } + +remove: + remove_gatt_req(req, status); } static void hog_attach_scpp(struct bt_hog *hog, struct gatt_primary *primary) @@ -1609,7 +1658,7 @@ struct bt_hog *instance; if (!hog->primary) { - hog->primary = g_memdup(primary, sizeof(*primary)); + hog->primary = util_memdup(primary, sizeof(*primary)); discover_char(hog, hog->attrib, primary->range.start, primary->range.end, NULL, char_discovered_cb, hog); @@ -1623,7 +1672,7 @@ if (!instance) return; - instance->primary = g_memdup(primary, sizeof(*primary)); + instance->primary = util_memdup(primary, sizeof(*primary)); find_included(instance, hog->attrib, primary->range.start, primary->range.end, find_included_cb, instance); @@ -1640,17 +1689,14 @@ DBG(""); - destroy_gatt_req(req); - if (status) { - const char *str = att_ecode2str(status); - DBG("Discover primary failed: %s", str); - return; + DBG("Discover primary failed: %s", att_ecode2str(status)); + goto remove; } if (!services) { DBG("No primary service found"); - return; + goto remove; } for (l = services; l; l = l->next) { @@ -1674,6 +1720,9 @@ if (strcmp(primary->uuid, HOG_UUID) == 0) hog_attach_hog(hog, primary); } + +remove: + remove_gatt_req(req, status); } bool bt_hog_attach(struct bt_hog *hog, void *gatt) @@ -1790,7 +1839,7 @@ if (hog->dis) bt_dis_detach(hog->dis); - queue_foreach(hog->gatt_op, (void *) cancel_gatt_req, NULL); + queue_remove_all(hog->gatt_op, cancel_gatt_req, hog, destroy_gatt_req); g_attrib_unref(hog->attrib); hog->attrib = NULL; uhid_destroy(hog); diff -Nru bluez-5.63/profiles/scanparam/scpp.c bluez-5.64/profiles/scanparam/scpp.c --- bluez-5.63/profiles/scanparam/scpp.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/profiles/scanparam/scpp.c 2022-03-16 15:06:20.000000000 +0000 @@ -91,7 +91,7 @@ { bt_scpp_detach(scan); - g_free(scan->primary); + free(scan->primary); queue_destroy(scan->gatt_op, NULL); /* cleared in bt_scpp_detach */ g_free(scan); } @@ -110,7 +110,7 @@ scan->gatt_op = queue_new(); if (primary) - scan->primary = g_memdup(primary, sizeof(*scan->primary)); + scan->primary = util_memdup(primary, sizeof(*scan->primary)); return bt_scpp_ref(scan); } diff -Nru bluez-5.63/src/adapter.c bluez-5.64/src/adapter.c --- bluez-5.63/src/adapter.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/adapter.c 2022-03-16 15:06:20.000000000 +0000 @@ -62,7 +62,6 @@ #include "attrib/gattrib.h" #include "attrib/att.h" #include "attrib/gatt.h" -#include "attrib-server.h" #include "gatt-database.h" #include "advertising.h" #include "adv_monitor.h" @@ -312,15 +311,6 @@ struct oob_handler *oob_handler; - unsigned int load_ltks_id; - unsigned int load_ltks_timeout; - - unsigned int confirm_name_id; - unsigned int confirm_name_timeout; - - unsigned int pair_device_id; - unsigned int pair_device_timeout; - unsigned int db_id; /* Service event handler for GATT db */ bool is_default; /* true if adapter is default one */ @@ -827,10 +817,6 @@ g_dbus_emit_property_changed(dbus_conn, adapter->path, ADAPTER_INTERFACE, "Alias"); - - attrib_gap_set(adapter, GATT_CHARAC_DEVICE_NAME, - (const uint8_t *) adapter->current_alias, - strlen(adapter->current_alias)); } static void set_local_name_complete(uint8_t status, uint16_t length, @@ -4139,21 +4125,6 @@ adapter->dev_id); } -static bool load_ltks_timeout(gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - - btd_error(adapter->dev_id, "Loading LTKs timed out for hci%u", - adapter->dev_id); - - adapter->load_ltks_timeout = 0; - - mgmt_cancel(adapter->mgmt, adapter->load_ltks_id); - adapter->load_ltks_id = 0; - - return FALSE; -} - static void load_ltks_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { @@ -4165,11 +4136,6 @@ adapter->dev_id, mgmt_errstr(status), status); } - adapter->load_ltks_id = 0; - - timeout_remove(adapter->load_ltks_timeout); - adapter->load_ltks_timeout = 0; - DBG("LTKs loaded for hci%u", adapter->dev_id); } @@ -4242,27 +4208,18 @@ } } - adapter->load_ltks_id = mgmt_send(adapter->mgmt, - MGMT_OP_LOAD_LONG_TERM_KEYS, - adapter->dev_id, cp_size, cp, - load_ltks_complete, adapter, NULL); - - g_free(cp); - - if (adapter->load_ltks_id == 0) { - btd_error(adapter->dev_id, "Failed to load LTKs for hci%u", - adapter->dev_id); - return; - } - /* * This timeout handling is needed since the kernel is stupid * and forgets to send a command complete response. However in * case of failures it does send a command status. */ - adapter->load_ltks_timeout = timeout_add_seconds(2, - load_ltks_timeout, adapter, - NULL); + if (!mgmt_send_timeout(adapter->mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, + adapter->dev_id, cp_size, cp, load_ltks_complete, + adapter, NULL, 2)) + btd_error(adapter->dev_id, "Failed to load LTKs for hci%u", + adapter->dev_id); + + g_free(cp); } static void load_irks_complete(uint8_t status, uint16_t length, @@ -4719,7 +4676,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } key_info = get_key_info(key_file, entry->d_name); @@ -5615,15 +5572,6 @@ adapter->passive_scan_timeout = 0; } - if (adapter->load_ltks_timeout > 0) - timeout_remove(adapter->load_ltks_timeout); - - if (adapter->confirm_name_timeout > 0) - timeout_remove(adapter->confirm_name_timeout); - - if (adapter->pair_device_timeout > 0) - timeout_remove(adapter->pair_device_timeout); - if (adapter->auth_idle_id) g_source_remove(adapter->auth_idle_id); @@ -5714,7 +5662,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } g_key_file_set_string(key_file, "General", "Name", value); @@ -5947,7 +5895,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } set_device_type(key_file, type); @@ -6053,7 +6001,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } sprintf(handle_str, "0x%8.8X", handle); @@ -6137,7 +6085,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } store_attribute_uuid(key_file, start, end, prim_uuid, uuid); @@ -6197,7 +6145,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } for (service = services; *service; service++) { @@ -6222,7 +6170,7 @@ if (!g_file_set_contents(filename, data, length, &gerr)) { error("Unable set contents for %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } if (device_type < 0) @@ -6237,7 +6185,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } set_device_type(key_file, device_type); @@ -6293,7 +6241,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } sprintf(group, "%hu", handle); @@ -6349,7 +6297,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } sprintf(group, "%hu", handle); @@ -6404,7 +6352,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } g_key_file_set_string(key_file, alert, "Level", value); @@ -6608,7 +6556,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } /* Get alias */ @@ -6751,21 +6699,6 @@ return &adapter->bdaddr; } -static bool confirm_name_timeout(gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - - btd_error(adapter->dev_id, "Confirm name timed out for hci%u", - adapter->dev_id); - - adapter->confirm_name_timeout = 0; - - mgmt_cancel(adapter->mgmt, adapter->confirm_name_id); - adapter->confirm_name_id = 0; - - return FALSE; -} - static void confirm_name_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { @@ -6775,13 +6708,9 @@ btd_error(adapter->dev_id, "Failed to confirm name for hci%u: %s (0x%02x)", adapter->dev_id, mgmt_errstr(status), status); + return; } - adapter->confirm_name_id = 0; - - timeout_remove(adapter->confirm_name_timeout); - adapter->confirm_name_timeout = 0; - DBG("Confirm name complete for hci%u", adapter->dev_id); } @@ -6795,49 +6724,21 @@ DBG("hci%d bdaddr %s name_known %u", adapter->dev_id, addr, name_known); - /* - * If the kernel does not answer the confirm name command with - * a command complete or command status in time, this might - * race against another device found event that also requires - * to confirm the name. If there is a pending command, just - * cancel it to be safe here. - */ - if (adapter->confirm_name_id > 0) { - btd_warn(adapter->dev_id, - "Found pending confirm name for hci%u", - adapter->dev_id); - mgmt_cancel(adapter->mgmt, adapter->confirm_name_id); - } - - if (adapter->confirm_name_timeout > 0) { - timeout_remove(adapter->confirm_name_timeout); - adapter->confirm_name_timeout = 0; - } - memset(&cp, 0, sizeof(cp)); bacpy(&cp.addr.bdaddr, bdaddr); cp.addr.type = bdaddr_type; cp.name_known = name_known; - adapter->confirm_name_id = mgmt_reply(adapter->mgmt, - MGMT_OP_CONFIRM_NAME, - adapter->dev_id, sizeof(cp), &cp, - confirm_name_complete, adapter, NULL); - - if (adapter->confirm_name_id == 0) { - btd_error(adapter->dev_id, "Failed to confirm name for hci%u", - adapter->dev_id); - return; - } - /* * This timeout handling is needed since the kernel is stupid * and forgets to send a command complete response. However in * case of failures it does send a command status. */ - adapter->confirm_name_timeout = timeout_add_seconds(2, - confirm_name_timeout, adapter, - NULL); + if (!mgmt_reply_timeout(adapter->mgmt, MGMT_OP_CONFIRM_NAME, + adapter->dev_id, sizeof(cp), &cp, + confirm_name_complete, adapter, NULL, 2)) + btd_error(adapter->dev_id, "Failed to confirm name for hci%u", + adapter->dev_id); } static void adapter_msd_notify(struct btd_adapter *adapter, @@ -6991,7 +6892,7 @@ bool duplicate = false; struct queue *matched_monitors = NULL; - if (!btd_adv_monitor_offload_supported(adapter->adv_monitor_manager)) { + if (!btd_adv_monitor_offload_enabled(adapter->adv_monitor_manager)) { if (bdaddr_type != BDADDR_BREDR) ad = bt_ad_new_with_data(data_len, data); @@ -8111,21 +8012,6 @@ g_free(data); } -static bool pair_device_timeout(gpointer user_data) -{ - struct pair_device_data *data = user_data; - struct btd_adapter *adapter = data->adapter; - - btd_error(adapter->dev_id, "Pair device timed out for hci%u", - adapter->dev_id); - - adapter->pair_device_timeout = 0; - - adapter_cancel_bonding(adapter, &data->bdaddr, data->addr_type); - - return FALSE; -} - static void pair_device_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { @@ -8135,13 +8021,6 @@ DBG("%s (0x%02x)", mgmt_errstr(status), status); - adapter->pair_device_id = 0; - - if (adapter->pair_device_timeout > 0) { - timeout_remove(adapter->pair_device_timeout); - adapter->pair_device_timeout = 0; - } - /* Workaround for a kernel bug * * Broken kernels may reply to device pairing command with command @@ -8169,12 +8048,6 @@ int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr, uint8_t addr_type, uint8_t io_cap) { - if (adapter->pair_device_id > 0) { - btd_error(adapter->dev_id, - "Unable pair since another pairing is in progress"); - return -EBUSY; - } - suspend_discovery(adapter); return adapter_bonding_attempt(adapter, bdaddr, addr_type, io_cap); @@ -8206,11 +8079,14 @@ bacpy(&data->bdaddr, bdaddr); data->addr_type = addr_type; - id = mgmt_send(adapter->mgmt, MGMT_OP_PAIR_DEVICE, + /* Due to a bug in the kernel it is possible that a LE pairing + * request never times out. Therefore, add a timer to clean up + * if no response arrives + */ + id = mgmt_send_timeout(adapter->mgmt, MGMT_OP_PAIR_DEVICE, adapter->dev_id, sizeof(cp), &cp, pair_device_complete, data, - free_pair_device_data); - + free_pair_device_data, BONDING_TIMEOUT); if (id == 0) { btd_error(adapter->dev_id, "Failed to pair %s for hci%u", addr, adapter->dev_id); @@ -8218,16 +8094,6 @@ return -EIO; } - adapter->pair_device_id = id; - - /* Due to a bug in the kernel it is possible that a LE pairing - * request never times out. Therefore, add a timer to clean up - * if no response arrives - */ - adapter->pair_device_timeout = timeout_add_seconds(BONDING_TIMEOUT, - pair_device_timeout, data, - NULL); - return 0; } @@ -8348,11 +8214,15 @@ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", btd_adapter_get_storage_dir(adapter), device_addr); + create_file(filename, 0600); + key_file = g_key_file_new(); if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); g_error_free(gerr); + g_key_file_free(key_file); + return; } for (i = 0; i < 16; i++) @@ -8363,8 +8233,6 @@ g_key_file_set_integer(key_file, "LinkKey", "Type", type); g_key_file_set_integer(key_file, "LinkKey", "PINLength", pin_length); - create_file(filename, 0600); - str = g_key_file_to_data(key_file, &length, NULL); if (!g_file_set_contents(filename, str, length, &gerr)) { error("Unable set contents for %s: (%s)", filename, @@ -8445,7 +8313,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } for (i = 0; i < 16; i++) @@ -8611,7 +8479,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } for (i = 0; i < 16; i++) @@ -8789,7 +8657,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } g_key_file_set_integer(key_file, "ConnectionParameters", @@ -9108,6 +8976,11 @@ agent_unref(agent); } + if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) { + adapter->battery_provider_manager = + btd_battery_provider_manager_create(adapter); + } + /* Don't start GATT database and advertising managers on * non-LE controllers. */ @@ -9142,11 +9015,6 @@ } } - if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) { - adapter->battery_provider_manager = - btd_battery_provider_manager_create(adapter); - } - db = btd_gatt_database_get_db(adapter->database); adapter->db_id = gatt_db_register(db, services_modified, services_modified, @@ -9448,7 +9316,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } if (type == BDADDR_BREDR) { @@ -9550,7 +9418,7 @@ &gerr)) { error("Unable to load key file from %s: (%s)", STORAGEDIR "/addresses", gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } addrs = g_key_file_get_string_list(file, "Static", mfg, &len, NULL); if (addrs) { @@ -9939,6 +9807,16 @@ goto failed; } } else { + struct btd_adapter *tmp; + + tmp = adapter_find(&rp->bdaddr); + if (tmp) { + btd_error(adapter->dev_id, + "Bluetooth address for index %u match index %u", + adapter->dev_id, tmp->dev_id); + goto failed; + } + bacpy(&adapter->bdaddr, &rp->bdaddr); if (!(adapter->supported_settings & MGMT_SETTING_LE)) adapter->bdaddr_type = BDADDR_BREDR; @@ -10210,6 +10088,13 @@ return; } + /* Check if at maximum adapters allowed in the system then ignore the + * adapter. + */ + if (btd_opts.max_adapters && + btd_opts.max_adapters == g_slist_length(adapters)) + return; + reset_adv_monitors(index); adapter = btd_adapter_new(index); diff -Nru bluez-5.63/src/adv_monitor.c bluez-5.64/src/adv_monitor.c --- bluez-5.63/src/adv_monitor.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/adv_monitor.c 2022-03-16 15:06:20.000000000 +0000 @@ -1844,12 +1844,10 @@ manager_destroy(manager); } -bool btd_adv_monitor_offload_supported(struct btd_adv_monitor_manager *manager) +bool btd_adv_monitor_offload_enabled(struct btd_adv_monitor_manager *manager) { - if (!manager) { - error("Manager is NULL, get offload support failed"); + if (!manager) return false; - } return !!(manager->enabled_features & MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS); diff -Nru bluez-5.63/src/adv_monitor.h bluez-5.64/src/adv_monitor.h --- bluez-5.63/src/adv_monitor.h 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/adv_monitor.h 2022-03-16 15:06:20.000000000 +0000 @@ -27,7 +27,7 @@ struct mgmt *mgmt); void btd_adv_monitor_manager_destroy(struct btd_adv_monitor_manager *manager); -bool btd_adv_monitor_offload_supported(struct btd_adv_monitor_manager *manager); +bool btd_adv_monitor_offload_enabled(struct btd_adv_monitor_manager *manager); struct queue *btd_adv_monitor_content_filter( struct btd_adv_monitor_manager *manager, diff -Nru bluez-5.63/src/attrib-server.c bluez-5.64/src/attrib-server.c --- bluez-5.63/src/attrib-server.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/attrib-server.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1656 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2010 Marcel Holtmann - * - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "lib/bluetooth.h" -#include "lib/sdp.h" -#include "lib/sdp_lib.h" -#include "lib/uuid.h" - -#include "btio/btio.h" -#include "log.h" -#include "backtrace.h" -#include "adapter.h" -#include "device.h" -#include "src/shared/util.h" -#include "attrib/gattrib.h" -#include "attrib/att.h" -#include "attrib/gatt.h" -#include "attrib/att-database.h" -#include "textfile.h" -#include "storage.h" - -#include "attrib-server.h" - -static GSList *servers = NULL; - -struct gatt_server { - struct btd_adapter *adapter; - GIOChannel *l2cap_io; - GIOChannel *le_io; - uint32_t gatt_sdp_handle; - uint32_t gap_sdp_handle; - GList *database; - GSList *clients; - uint16_t name_handle; - uint16_t appearance_handle; -}; - -struct gatt_channel { - GAttrib *attrib; - guint mtu; - gboolean le; - guint id; - gboolean encrypted; - struct gatt_server *server; - guint cleanup_id; - struct btd_device *device; -}; - -struct group_elem { - uint16_t handle; - uint16_t end; - uint8_t *data; - uint16_t len; -}; - -static bt_uuid_t prim_uuid = { - .type = BT_UUID16, - .value.u16 = GATT_PRIM_SVC_UUID -}; -static bt_uuid_t snd_uuid = { - .type = BT_UUID16, - .value.u16 = GATT_SND_SVC_UUID -}; -static bt_uuid_t ccc_uuid = { - .type = BT_UUID16, - .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID -}; - -static void attrib_free(void *data) -{ - struct attribute *a = data; - - g_free(a->data); - g_free(a); -} - -static void channel_free(struct gatt_channel *channel) -{ - - if (channel->cleanup_id) - g_source_remove(channel->cleanup_id); - - if (channel->device) - btd_device_unref(channel->device); - - g_attrib_unref(channel->attrib); - g_free(channel); -} - -static void gatt_server_free(struct gatt_server *server) -{ - g_list_free_full(server->database, attrib_free); - - if (server->l2cap_io != NULL) { - g_io_channel_shutdown(server->l2cap_io, FALSE, NULL); - g_io_channel_unref(server->l2cap_io); - } - - if (server->le_io != NULL) { - g_io_channel_shutdown(server->le_io, FALSE, NULL); - g_io_channel_unref(server->le_io); - } - - g_slist_free_full(server->clients, (GDestroyNotify) channel_free); - - if (server->gatt_sdp_handle > 0) - adapter_service_remove(server->adapter, - server->gatt_sdp_handle); - - if (server->gap_sdp_handle > 0) - adapter_service_remove(server->adapter, server->gap_sdp_handle); - - if (server->adapter != NULL) - btd_adapter_unref(server->adapter); - - g_free(server); -} - -static int adapter_cmp_addr(gconstpointer a, gconstpointer b) -{ - const struct gatt_server *server = a; - const bdaddr_t *bdaddr = b; - - return bacmp(btd_adapter_get_address(server->adapter), bdaddr); -} - -static int adapter_cmp(gconstpointer a, gconstpointer b) -{ - const struct gatt_server *server = a; - const struct btd_adapter *adapter = b; - - if (server->adapter == adapter) - return 0; - - return -1; -} - -static struct gatt_server *find_gatt_server(const bdaddr_t *bdaddr) -{ - GSList *l; - - l = g_slist_find_custom(servers, bdaddr, adapter_cmp_addr); - if (l == NULL) { - char addr[18]; - - ba2str(bdaddr, addr); - error("No GATT server found in %s", addr); - return NULL; - } - - return l->data; -} - -static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end) -{ - sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto; - uuid_t root_uuid, proto_uuid, l2cap; - sdp_record_t *record; - sdp_data_t *psm, *sh, *eh; - uint16_t lp = ATT_PSM; - - if (uuid == NULL) - return NULL; - - if (start > end) - return NULL; - - record = sdp_record_alloc(); - if (record == NULL) - return NULL; - - sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); - root = sdp_list_append(NULL, &root_uuid); - sdp_set_browse_groups(record, root); - sdp_list_free(root, NULL); - - svclass_id = sdp_list_append(NULL, uuid); - sdp_set_service_classes(record, svclass_id); - sdp_list_free(svclass_id, NULL); - - sdp_uuid16_create(&l2cap, L2CAP_UUID); - proto[0] = sdp_list_append(NULL, &l2cap); - psm = sdp_data_alloc(SDP_UINT16, &lp); - proto[0] = sdp_list_append(proto[0], psm); - apseq = sdp_list_append(NULL, proto[0]); - - sdp_uuid16_create(&proto_uuid, ATT_UUID); - proto[1] = sdp_list_append(NULL, &proto_uuid); - sh = sdp_data_alloc(SDP_UINT16, &start); - proto[1] = sdp_list_append(proto[1], sh); - eh = sdp_data_alloc(SDP_UINT16, &end); - proto[1] = sdp_list_append(proto[1], eh); - apseq = sdp_list_append(apseq, proto[1]); - - aproto = sdp_list_append(NULL, apseq); - sdp_set_access_protos(record, aproto); - - sdp_data_free(psm); - sdp_data_free(sh); - sdp_data_free(eh); - sdp_list_free(proto[0], NULL); - sdp_list_free(proto[1], NULL); - sdp_list_free(apseq, NULL); - sdp_list_free(aproto, NULL); - - return record; -} - -static int handle_cmp(gconstpointer a, gconstpointer b) -{ - const struct attribute *attrib = a; - uint16_t handle = GPOINTER_TO_UINT(b); - - return attrib->handle - handle; -} - -static int attribute_cmp(gconstpointer a1, gconstpointer a2) -{ - const struct attribute *attrib1 = a1; - const struct attribute *attrib2 = a2; - - return attrib1->handle - attrib2->handle; -} - -static struct attribute *find_svc_range(struct gatt_server *server, - uint16_t start, uint16_t *end) -{ - struct attribute *attrib; - guint h = start; - GList *l; - - if (end == NULL) - return NULL; - - l = g_list_find_custom(server->database, GUINT_TO_POINTER(h), - handle_cmp); - if (!l) - return NULL; - - attrib = l->data; - - if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0 && - bt_uuid_cmp(&attrib->uuid, &snd_uuid) != 0) - return NULL; - - *end = start; - - for (l = l->next; l; l = l->next) { - struct attribute *a = l->data; - - if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || - bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) - break; - - *end = a->handle; - } - - return attrib; -} - -static uint32_t attrib_create_sdp_new(struct gatt_server *server, - uint16_t handle, const char *name) -{ - sdp_record_t *record; - struct attribute *a; - uint16_t end = 0; - uuid_t svc, gap_uuid; - - a = find_svc_range(server, handle, &end); - - if (a == NULL) - return 0; - - if (a->len == 2) - sdp_uuid16_create(&svc, get_le16(a->data)); - else if (a->len == 16) { - uint8_t be128[16]; - - /* Converting from LE to BE */ - bswap_128(a->data, be128); - sdp_uuid128_create(&svc, be128); - } else - return 0; - - record = server_record_new(&svc, handle, end); - if (record == NULL) - return 0; - - if (name != NULL) - sdp_set_info_attr(record, name, "BlueZ", NULL); - - sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID); - if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) { - sdp_set_url_attr(record, "http://www.bluez.org/", - "http://www.bluez.org/", - "http://www.bluez.org/"); - } - - if (adapter_service_add(server->adapter, record) == 0) - return record->handle; - - sdp_record_free(record); - return 0; -} - -static struct attribute *attrib_db_add_new(struct gatt_server *server, - uint16_t handle, bt_uuid_t *uuid, - int read_req, int write_req, - const uint8_t *value, size_t len) -{ - struct attribute *a; - guint h = handle; - - DBG("handle=0x%04x", handle); - - if (g_list_find_custom(server->database, GUINT_TO_POINTER(h), - handle_cmp)) - return NULL; - - a = g_new0(struct attribute, 1); - a->len = len; - a->data = g_memdup(value, len); - a->handle = handle; - a->uuid = *uuid; - a->read_req = read_req; - a->write_req = write_req; - - server->database = g_list_insert_sorted(server->database, a, - attribute_cmp); - - return a; -} - -static bool g_attrib_is_encrypted(GAttrib *attrib) -{ - BtIOSecLevel sec_level; - GIOChannel *io = g_attrib_get_channel(attrib); - - if (!bt_io_get(io, NULL, BT_IO_OPT_SEC_LEVEL, &sec_level, - BT_IO_OPT_INVALID)) - return FALSE; - - return sec_level > BT_IO_SEC_LOW; -} - -static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode, - int reqs) -{ - /* FIXME: currently, it is assumed an encrypted link is enough for - * authentication. This will allow to enable the SMP negotiation once - * it is on upstream kernel. High security level should be mapped - * to authentication and medium to encryption permission. */ - if (!channel->encrypted) - channel->encrypted = g_attrib_is_encrypted(channel->attrib); - if (reqs == ATT_AUTHENTICATION && !channel->encrypted) - return ATT_ECODE_AUTHENTICATION; - else if (reqs == ATT_AUTHORIZATION) - return ATT_ECODE_AUTHORIZATION; - - switch (opcode) { - case ATT_OP_READ_BY_GROUP_REQ: - case ATT_OP_READ_BY_TYPE_REQ: - case ATT_OP_READ_REQ: - case ATT_OP_READ_BLOB_REQ: - case ATT_OP_READ_MULTI_REQ: - if (reqs == ATT_NOT_PERMITTED) - return ATT_ECODE_READ_NOT_PERM; - break; - case ATT_OP_PREP_WRITE_REQ: - case ATT_OP_WRITE_REQ: - case ATT_OP_WRITE_CMD: - if (reqs == ATT_NOT_PERMITTED) - return ATT_ECODE_WRITE_NOT_PERM; - break; - } - - return 0; -} - -static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start, - uint16_t end, bt_uuid_t *uuid, - uint8_t *pdu, size_t len) -{ - struct att_data_list *adl; - struct attribute *a; - struct group_elem *cur, *old = NULL; - GSList *l, *groups; - GList *dl, *database; - uint16_t length, last_handle, last_size = 0; - uint8_t status; - int i; - - if (start > end || start == 0x0000) - return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start, - ATT_ECODE_INVALID_HANDLE, pdu, len); - - /* - * Only <> and <> grouping - * types may be used in the Read By Group Type Request. - */ - - if (bt_uuid_cmp(uuid, &prim_uuid) != 0 && - bt_uuid_cmp(uuid, &snd_uuid) != 0) - return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, 0x0000, - ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len); - - last_handle = end; - database = channel->server->database; - for (dl = database, groups = NULL, cur = NULL; dl; dl = dl->next) { - - a = dl->data; - - if (a->handle < start) - continue; - - if (a->handle >= end) - break; - - /* The old group ends when a new one starts */ - if (old && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || - bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)) { - old->end = last_handle; - old = NULL; - } - - if (bt_uuid_cmp(&a->uuid, uuid) != 0) { - /* Still inside a service, update its last handle */ - if (old) - last_handle = a->handle; - continue; - } - - if (last_size && (last_size != a->len)) - break; - - status = att_check_reqs(channel, ATT_OP_READ_BY_GROUP_REQ, - a->read_req); - - if (status == 0x00 && a->read_cb) - status = a->read_cb(a, channel->device, - a->cb_user_data); - - if (status) { - g_slist_free_full(groups, g_free); - return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, - a->handle, status, pdu, len); - } - - cur = g_new0(struct group_elem, 1); - cur->handle = a->handle; - cur->data = a->data; - cur->len = a->len; - - /* Attribute Grouping Type found */ - groups = g_slist_append(groups, cur); - - last_size = a->len; - old = cur; - last_handle = cur->handle; - } - - if (groups == NULL) - return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start, - ATT_ECODE_ATTR_NOT_FOUND, pdu, len); - - if (dl == NULL) - cur->end = a->handle; - else - cur->end = last_handle; - - length = g_slist_length(groups); - - adl = att_data_list_alloc(length, last_size + 4); - if (adl == NULL) { - g_slist_free_full(groups, g_free); - return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start, - ATT_ECODE_UNLIKELY, pdu, len); - } - - for (i = 0, l = groups; l; l = l->next, i++) { - uint8_t *value; - - cur = l->data; - - value = (void *) adl->data[i]; - - put_le16(cur->handle, value); - put_le16(cur->end, &value[2]); - /* Attribute Value */ - memcpy(&value[4], cur->data, cur->len); - } - - length = enc_read_by_grp_resp(adl, pdu, len); - - att_data_list_free(adl); - g_slist_free_full(groups, g_free); - - return length; -} - -static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start, - uint16_t end, bt_uuid_t *uuid, - uint8_t *pdu, size_t len) -{ - struct att_data_list *adl; - GSList *l, *types; - GList *dl, *database; - struct attribute *a; - uint16_t num, length; - uint8_t status; - int i; - - if (start > end || start == 0x0000) - return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start, - ATT_ECODE_INVALID_HANDLE, pdu, len); - - database = channel->server->database; - for (dl = database, length = 0, types = NULL; dl; dl = dl->next) { - - a = dl->data; - - if (a->handle < start) - continue; - - if (a->handle > end) - break; - - if (bt_uuid_cmp(&a->uuid, uuid) != 0) - continue; - - status = att_check_reqs(channel, ATT_OP_READ_BY_TYPE_REQ, - a->read_req); - - if (status == 0x00 && a->read_cb) - status = a->read_cb(a, channel->device, - a->cb_user_data); - - if (status) { - g_slist_free(types); - return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, - a->handle, status, pdu, len); - } - - /* All elements must have the same length */ - if (length == 0) - length = a->len; - else if (a->len != length) - break; - - types = g_slist_append(types, a); - } - - if (types == NULL) - return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start, - ATT_ECODE_ATTR_NOT_FOUND, pdu, len); - - num = g_slist_length(types); - - /* Handle length plus attribute value length */ - length += 2; - - adl = att_data_list_alloc(num, length); - if (adl == NULL) { - g_slist_free(types); - return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start, - ATT_ECODE_UNLIKELY, pdu, len); - } - - for (i = 0, l = types; l; i++, l = l->next) { - uint8_t *value; - - a = l->data; - - value = (void *) adl->data[i]; - - put_le16(a->handle, value); - - /* Attribute Value */ - memcpy(&value[2], a->data, a->len); - } - - length = enc_read_by_type_resp(adl, pdu, len); - - att_data_list_free(adl); - g_slist_free(types); - - return length; -} - -static uint16_t find_info(struct gatt_channel *channel, uint16_t start, - uint16_t end, uint8_t *pdu, size_t len) -{ - struct attribute *a; - struct att_data_list *adl; - GSList *l, *info; - GList *dl, *database; - uint8_t format, last_type = BT_UUID_UNSPEC; - uint16_t length, num; - int i; - - if (start > end || start == 0x0000) - return enc_error_resp(ATT_OP_FIND_INFO_REQ, start, - ATT_ECODE_INVALID_HANDLE, pdu, len); - - database = channel->server->database; - for (dl = database, info = NULL, num = 0; dl; dl = dl->next) { - a = dl->data; - - if (a->handle < start) - continue; - - if (a->handle > end) - break; - - if (last_type == BT_UUID_UNSPEC) - last_type = a->uuid.type; - - if (a->uuid.type != last_type) - break; - - info = g_slist_append(info, a); - num++; - - last_type = a->uuid.type; - } - - if (info == NULL) - return enc_error_resp(ATT_OP_FIND_INFO_REQ, start, - ATT_ECODE_ATTR_NOT_FOUND, pdu, len); - - if (last_type == BT_UUID16) { - length = 2; - format = 0x01; - } else if (last_type == BT_UUID128) { - length = 16; - format = 0x02; - } else { - g_slist_free(info); - return 0; - } - - adl = att_data_list_alloc(num, length + 2); - if (adl == NULL) { - g_slist_free(info); - return enc_error_resp(ATT_OP_FIND_INFO_REQ, start, - ATT_ECODE_UNLIKELY, pdu, len); - } - - for (i = 0, l = info; l; i++, l = l->next) { - uint8_t *value; - - a = l->data; - - value = (void *) adl->data[i]; - - put_le16(a->handle, value); - - /* Attribute Value */ - bt_uuid_to_le(&a->uuid, &value[2]); - } - - length = enc_find_info_resp(format, adl, pdu, len); - - att_data_list_free(adl); - g_slist_free(info); - - return length; -} - -static uint16_t find_by_type(struct gatt_channel *channel, uint16_t start, - uint16_t end, bt_uuid_t *uuid, - const uint8_t *value, size_t vlen, - uint8_t *opdu, size_t mtu) -{ - struct attribute *a; - struct att_range *range; - GSList *matches; - GList *dl, *database; - uint16_t len; - - if (start > end || start == 0x0000) - return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start, - ATT_ECODE_INVALID_HANDLE, opdu, mtu); - - /* Searching first requested handle number */ - database = channel->server->database; - for (dl = database, matches = NULL, range = NULL; dl; dl = dl->next) { - a = dl->data; - - if (a->handle < start) - continue; - - if (a->handle > end) - break; - - /* Primary service? Attribute value matches? */ - if ((bt_uuid_cmp(&a->uuid, uuid) == 0) && (a->len == vlen) && - (memcmp(a->data, value, vlen) == 0)) { - - range = g_new0(struct att_range, 1); - range->start = a->handle; - /* It is allowed to have end group handle the same as - * start handle, for groups with only one attribute. */ - range->end = a->handle; - - matches = g_slist_append(matches, range); - } else if (range) { - /* Update the last found handle or reset the pointer - * to track that a new group started: Primary or - * Secondary service. */ - if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || - bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) - range = NULL; - else - range->end = a->handle; - } - } - - if (matches == NULL) - return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start, - ATT_ECODE_ATTR_NOT_FOUND, opdu, mtu); - - len = enc_find_by_type_resp(matches, opdu, mtu); - - g_slist_free_full(matches, g_free); - - return len; -} - -static int read_device_ccc(struct btd_device *device, uint16_t handle, - uint16_t *value) -{ - char *filename; - GKeyFile *key_file; - GError *gerr = NULL; - char group[6]; - char *str; - unsigned int config; - int err = 0; - - filename = btd_device_get_storage_path(device, "ccc"); - if (!filename) { - warn("Unable to get ccc storage path for device"); - return -ENOENT; - } - - key_file = g_key_file_new(); - if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { - error("Unable to load key file from %s: (%s)", filename, - gerr->message); - g_error_free(gerr); - } - - sprintf(group, "%hu", handle); - - str = g_key_file_get_string(key_file, group, "Value", NULL); - if (!str || sscanf(str, "%04X", &config) != 1) - err = -ENOENT; - else - *value = config; - - g_free(str); - g_free(filename); - g_key_file_free(key_file); - - return err; -} - -static uint16_t read_value(struct gatt_channel *channel, uint16_t handle, - uint8_t *pdu, size_t len) -{ - struct attribute *a; - uint8_t status; - GList *l; - uint16_t cccval; - guint h = handle; - - l = g_list_find_custom(channel->server->database, - GUINT_TO_POINTER(h), handle_cmp); - if (!l) - return enc_error_resp(ATT_OP_READ_REQ, handle, - ATT_ECODE_INVALID_HANDLE, pdu, len); - - a = l->data; - - if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 && - read_device_ccc(channel->device, handle, &cccval) == 0) { - uint8_t config[2]; - - put_le16(cccval, config); - return enc_read_resp(config, sizeof(config), pdu, len); - } - - status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_req); - - if (status == 0x00 && a->read_cb) - status = a->read_cb(a, channel->device, a->cb_user_data); - - if (status) - return enc_error_resp(ATT_OP_READ_REQ, handle, status, pdu, - len); - - return enc_read_resp(a->data, a->len, pdu, len); -} - -static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle, - uint16_t offset, uint8_t *pdu, size_t len) -{ - struct attribute *a; - uint8_t status; - GList *l; - uint16_t cccval; - guint h = handle; - - l = g_list_find_custom(channel->server->database, - GUINT_TO_POINTER(h), handle_cmp); - if (!l) - return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, - ATT_ECODE_INVALID_HANDLE, pdu, len); - - a = l->data; - - if (a->len < offset) - return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, - ATT_ECODE_INVALID_OFFSET, pdu, len); - - if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 && - read_device_ccc(channel->device, handle, &cccval) == 0) { - uint8_t config[2]; - - put_le16(cccval, config); - return enc_read_blob_resp(config, sizeof(config), offset, - pdu, len); - } - - status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_req); - - if (status == 0x00 && a->read_cb) - status = a->read_cb(a, channel->device, a->cb_user_data); - - if (status) - return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, status, - pdu, len); - - return enc_read_blob_resp(a->data, a->len, offset, pdu, len); -} - -static uint16_t write_value(struct gatt_channel *channel, uint16_t handle, - const uint8_t *value, size_t vlen, - uint8_t *pdu, size_t len) -{ - struct attribute *a; - uint8_t status; - GList *l; - GError *gerr = NULL; - guint h = handle; - - l = g_list_find_custom(channel->server->database, - GUINT_TO_POINTER(h), handle_cmp); - if (!l) - return enc_error_resp(ATT_OP_WRITE_REQ, handle, - ATT_ECODE_INVALID_HANDLE, pdu, len); - - a = l->data; - - status = att_check_reqs(channel, ATT_OP_WRITE_REQ, a->write_req); - if (status) - return enc_error_resp(ATT_OP_WRITE_REQ, handle, status, pdu, - len); - - if (bt_uuid_cmp(&ccc_uuid, &a->uuid) != 0) { - - attrib_db_update(channel->server->adapter, handle, NULL, - value, vlen, NULL); - - if (a->write_cb) { - status = a->write_cb(a, channel->device, - a->cb_user_data); - if (status) - return enc_error_resp(ATT_OP_WRITE_REQ, handle, - status, pdu, len); - } - } else { - uint16_t cccval = get_le16(value); - char *filename; - GKeyFile *key_file; - char group[6], value[5]; - char *data; - gsize length = 0; - - filename = btd_device_get_storage_path(channel->device, "ccc"); - if (!filename) { - warn("Unable to get ccc storage path for device"); - return enc_error_resp(ATT_OP_WRITE_REQ, handle, - ATT_ECODE_WRITE_NOT_PERM, - pdu, len); - } - - key_file = g_key_file_new(); - if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { - error("Unable to load key file from %s: (%s)", filename, - gerr->message); - g_error_free(gerr); - } - - sprintf(group, "%hu", handle); - sprintf(value, "%hX", cccval); - g_key_file_set_string(key_file, group, "Value", value); - - data = g_key_file_to_data(key_file, &length, NULL); - if (length > 0) { - create_file(filename, 0600); - if (!g_file_set_contents(filename, data, length, - &gerr)) { - error("Unable set contents for %s: (%s)", - filename, gerr->message); - g_error_free(gerr); - } - } - - g_free(data); - g_free(filename); - g_key_file_free(key_file); - } - - return enc_write_resp(pdu); -} - -static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu, - uint8_t *pdu, size_t len) -{ - GError *gerr = NULL; - GIOChannel *io; - uint16_t imtu; - - if (mtu < ATT_DEFAULT_LE_MTU) - return enc_error_resp(ATT_OP_MTU_REQ, 0, - ATT_ECODE_REQ_NOT_SUPP, pdu, len); - - io = g_attrib_get_channel(channel->attrib); - - bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID); - if (gerr) { - error("bt_io_get: %s", gerr->message); - g_error_free(gerr); - return enc_error_resp(ATT_OP_MTU_REQ, 0, ATT_ECODE_UNLIKELY, - pdu, len); - } - - channel->mtu = MIN(mtu, imtu); - g_attrib_set_mtu(channel->attrib, channel->mtu); - - return enc_mtu_resp(imtu, pdu, len); -} - -static void channel_remove(struct gatt_channel *channel) -{ - channel->server->clients = g_slist_remove(channel->server->clients, - channel); - channel_free(channel); -} - -static gboolean channel_watch_cb(GIOChannel *io, GIOCondition cond, - gpointer user_data) -{ - channel_remove(user_data); - - return FALSE; -} - -static void channel_handler(const uint8_t *ipdu, uint16_t len, - gpointer user_data) -{ - struct gatt_channel *channel = user_data; - uint8_t opdu[channel->mtu]; - uint16_t length, start, end, mtu, offset; - bt_uuid_t uuid; - uint8_t status = 0; - size_t vlen; - uint8_t *value = g_attrib_get_buffer(channel->attrib, &vlen); - - DBG("op 0x%02x", ipdu[0]); - - if (len > vlen) { - error("Too much data on ATT socket"); - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - switch (ipdu[0]) { - case ATT_OP_READ_BY_GROUP_REQ: - length = dec_read_by_grp_req(ipdu, len, &start, &end, &uuid); - if (length == 0) { - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - length = read_by_group(channel, start, end, &uuid, opdu, - channel->mtu); - break; - case ATT_OP_READ_BY_TYPE_REQ: - length = dec_read_by_type_req(ipdu, len, &start, &end, &uuid); - if (length == 0) { - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - length = read_by_type(channel, start, end, &uuid, opdu, - channel->mtu); - break; - case ATT_OP_READ_REQ: - length = dec_read_req(ipdu, len, &start); - if (length == 0) { - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - length = read_value(channel, start, opdu, channel->mtu); - break; - case ATT_OP_READ_BLOB_REQ: - length = dec_read_blob_req(ipdu, len, &start, &offset); - if (length == 0) { - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - length = read_blob(channel, start, offset, opdu, channel->mtu); - break; - case ATT_OP_MTU_REQ: - if (!channel->le) { - status = ATT_ECODE_REQ_NOT_SUPP; - goto done; - } - - length = dec_mtu_req(ipdu, len, &mtu); - if (length == 0) { - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - length = mtu_exchange(channel, mtu, opdu, channel->mtu); - break; - case ATT_OP_FIND_INFO_REQ: - length = dec_find_info_req(ipdu, len, &start, &end); - if (length == 0) { - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - length = find_info(channel, start, end, opdu, channel->mtu); - break; - case ATT_OP_WRITE_REQ: - length = dec_write_req(ipdu, len, &start, value, &vlen); - if (length == 0) { - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - length = write_value(channel, start, value, vlen, opdu, - channel->mtu); - break; - case ATT_OP_WRITE_CMD: - length = dec_write_cmd(ipdu, len, &start, value, &vlen); - if (length > 0) - write_value(channel, start, value, vlen, opdu, - channel->mtu); - return; - case ATT_OP_FIND_BY_TYPE_REQ: - length = dec_find_by_type_req(ipdu, len, &start, &end, - &uuid, value, &vlen); - if (length == 0) { - status = ATT_ECODE_INVALID_PDU; - goto done; - } - - length = find_by_type(channel, start, end, &uuid, value, vlen, - opdu, channel->mtu); - break; - case ATT_OP_HANDLE_CNF: - return; - case ATT_OP_HANDLE_IND: - case ATT_OP_HANDLE_NOTIFY: - /* The attribute client is already handling these */ - return; - case ATT_OP_READ_MULTI_REQ: - case ATT_OP_PREP_WRITE_REQ: - case ATT_OP_EXEC_WRITE_REQ: - default: - DBG("Unsupported request 0x%02x", ipdu[0]); - status = ATT_ECODE_REQ_NOT_SUPP; - goto done; - } - - if (length == 0) - status = ATT_ECODE_IO; - -done: - if (status) - length = enc_error_resp(ipdu[0], 0x0000, status, opdu, - channel->mtu); - - g_attrib_send(channel->attrib, 0, opdu, length, NULL, NULL, NULL); -} - -GAttrib *attrib_from_device(struct btd_device *device) -{ - struct btd_adapter *adapter = device_get_adapter(device); - struct gatt_server *server; - GSList *l; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (!l) - return NULL; - - server = l->data; - - for (l = server->clients; l; l = l->next) { - struct gatt_channel *channel = l->data; - - if (channel->device == device) - return g_attrib_ref(channel->attrib); - } - - return NULL; -} - -guint attrib_channel_attach(GAttrib *attrib) -{ - struct gatt_server *server; - struct btd_device *device; - struct gatt_channel *channel; - bdaddr_t src, dst; - GIOChannel *io; - GError *gerr = NULL; - uint8_t bdaddr_type; - uint16_t cid; - guint mtu = 0; - - io = g_attrib_get_channel(attrib); - - bt_io_get(io, &gerr, - BT_IO_OPT_SOURCE_BDADDR, &src, - BT_IO_OPT_DEST_BDADDR, &dst, - BT_IO_OPT_DEST_TYPE, &bdaddr_type, - BT_IO_OPT_CID, &cid, - BT_IO_OPT_IMTU, &mtu, - BT_IO_OPT_INVALID); - if (gerr) { - error("bt_io_get: %s", gerr->message); - g_error_free(gerr); - return 0; - } - - server = find_gatt_server(&src); - if (server == NULL) - return 0; - - channel = g_new0(struct gatt_channel, 1); - channel->server = server; - - device = btd_adapter_find_device(server->adapter, &dst, bdaddr_type); - if (device == NULL) { - error("Device object not found for attrib server"); - g_free(channel); - return 0; - } - - if (!device_is_bonded(device, bdaddr_type)) { - char *filename; - - filename = btd_device_get_storage_path(device, "ccc"); - if (filename) { - unlink(filename); - g_free(filename); - } - } - - if (cid != ATT_CID) { - channel->le = FALSE; - channel->mtu = mtu; - } else { - channel->le = TRUE; - channel->mtu = ATT_DEFAULT_LE_MTU; - } - - channel->attrib = g_attrib_ref(attrib); - channel->id = g_attrib_register(channel->attrib, GATTRIB_ALL_REQS, - GATTRIB_ALL_HANDLES, channel_handler, channel, NULL); - - channel->cleanup_id = g_io_add_watch(io, G_IO_HUP, channel_watch_cb, - channel); - - channel->device = btd_device_ref(device); - - server->clients = g_slist_append(server->clients, channel); - - return channel->id; -} - -static struct gatt_channel *find_channel(guint id) -{ - GSList *l; - - for (l = servers; l; l = g_slist_next(l)) { - struct gatt_server *server = l->data; - GSList *c; - - for (c = server->clients; c; c = g_slist_next(c)) { - struct gatt_channel *channel = c->data; - - if (channel->id == id) - return channel; - } - } - - return NULL; -} - -gboolean attrib_channel_detach(GAttrib *attrib, guint id) -{ - struct gatt_channel *channel; - - channel = find_channel(id); - if (channel == NULL) - return FALSE; - - g_attrib_unregister(channel->attrib, channel->id); - channel_remove(channel); - - return TRUE; -} - -static void connect_event(GIOChannel *io, GError *gerr, void *user_data) -{ - struct btd_adapter *adapter; - struct btd_device *device; - uint8_t dst_type; - bdaddr_t src, dst; - - DBG(""); - - if (gerr) { - error("%s", gerr->message); - return; - } - - bt_io_get(io, &gerr, - BT_IO_OPT_SOURCE_BDADDR, &src, - BT_IO_OPT_DEST_BDADDR, &dst, - BT_IO_OPT_DEST_TYPE, &dst_type, - BT_IO_OPT_INVALID); - if (gerr) { - error("bt_io_get: %s", gerr->message); - g_error_free(gerr); - return; - } - - adapter = adapter_find(&src); - if (!adapter) - return; - - device = btd_adapter_get_device(adapter, &dst, dst_type); - if (!device) - return; - - device_attach_att(device, io); -} - -static gboolean register_core_services(struct gatt_server *server) -{ - uint8_t atval[256]; - bt_uuid_t uuid; - uint16_t appearance = 0x0000; - - /* GAP service: primary service definition */ - bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID); - put_le16(GENERIC_ACCESS_PROFILE_ID, &atval[0]); - attrib_db_add_new(server, 0x0001, &uuid, ATT_NONE, ATT_NOT_PERMITTED, - atval, 2); - - /* GAP service: device name characteristic */ - server->name_handle = 0x0006; - bt_uuid16_create(&uuid, GATT_CHARAC_UUID); - atval[0] = GATT_CHR_PROP_READ; - put_le16(server->name_handle, &atval[1]); - put_le16(GATT_CHARAC_DEVICE_NAME, &atval[3]); - attrib_db_add_new(server, 0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED, - atval, 5); - - /* GAP service: device name attribute */ - bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME); - attrib_db_add_new(server, server->name_handle, &uuid, ATT_NONE, - ATT_NOT_PERMITTED, NULL, 0); - - /* GAP service: device appearance characteristic */ - server->appearance_handle = 0x0008; - bt_uuid16_create(&uuid, GATT_CHARAC_UUID); - atval[0] = GATT_CHR_PROP_READ; - put_le16(server->appearance_handle, &atval[1]); - put_le16(GATT_CHARAC_APPEARANCE, &atval[3]); - attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED, - atval, 5); - - /* GAP service: device appearance attribute */ - bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE); - put_le16(appearance, &atval[0]); - attrib_db_add_new(server, server->appearance_handle, &uuid, ATT_NONE, - ATT_NOT_PERMITTED, atval, 2); - server->gap_sdp_handle = attrib_create_sdp_new(server, 0x0001, - "Generic Access Profile"); - if (server->gap_sdp_handle == 0) { - error("Failed to register GAP service record"); - return FALSE; - } - - /* GATT service: primary service definition */ - bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID); - put_le16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]); - attrib_db_add_new(server, 0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED, - atval, 2); - - server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0010, - "Generic Attribute Profile"); - if (server->gatt_sdp_handle == 0) { - error("Failed to register GATT service record"); - return FALSE; - } - - return TRUE; -} - -int btd_adapter_gatt_server_start(struct btd_adapter *adapter) -{ - struct gatt_server *server; - GError *gerr = NULL; - const bdaddr_t *addr; - - DBG("Start GATT server in hci%d", btd_adapter_get_index(adapter)); - - server = g_new0(struct gatt_server, 1); - server->adapter = btd_adapter_ref(adapter); - - addr = btd_adapter_get_address(server->adapter); - - /* BR/EDR socket */ - server->l2cap_io = bt_io_listen(connect_event, NULL, NULL, NULL, &gerr, - BT_IO_OPT_SOURCE_BDADDR, addr, - BT_IO_OPT_PSM, ATT_PSM, - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, - BT_IO_OPT_INVALID); - - if (server->l2cap_io == NULL) { - error("%s", gerr->message); - g_error_free(gerr); - gatt_server_free(server); - return -1; - } - - if (!register_core_services(server)) { - gatt_server_free(server); - return -1; - } - - /* LE socket */ - server->le_io = bt_io_listen(connect_event, NULL, - &server->le_io, NULL, &gerr, - BT_IO_OPT_SOURCE_BDADDR, addr, - BT_IO_OPT_SOURCE_TYPE, - btd_adapter_get_address_type(adapter), - BT_IO_OPT_CID, ATT_CID, - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, - BT_IO_OPT_INVALID); - - if (server->le_io == NULL) { - error("%s", gerr->message); - g_error_free(gerr); - /* Doesn't have LE support, continue */ - } - - servers = g_slist_prepend(servers, server); - return 0; -} - -void btd_adapter_gatt_server_stop(struct btd_adapter *adapter) -{ - struct gatt_server *server; - GSList *l; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (l == NULL) - return; - - DBG("Stop GATT server in hci%d", btd_adapter_get_index(adapter)); - - server = l->data; - servers = g_slist_remove(servers, server); - gatt_server_free(server); -} - -uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle, - const char *name) -{ - GSList *l; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (l == NULL) - return 0; - - return attrib_create_sdp_new(l->data, handle, name); -} - -void attrib_free_sdp(struct btd_adapter *adapter, uint32_t sdp_handle) -{ - adapter_service_remove(adapter, sdp_handle); -} - -static uint16_t find_uuid16_avail(struct btd_adapter *adapter, uint16_t nitems) -{ - struct gatt_server *server; - uint16_t handle; - GSList *l; - GList *dl; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (l == NULL) - return 0; - - server = l->data; - if (server->database == NULL) - return 0x0001; - - for (dl = server->database, handle = 0x0001; dl; dl = dl->next) { - struct attribute *a = dl->data; - - if ((bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || - bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) && - a->handle - handle >= nitems) - /* Note: the range above excludes the current handle */ - return handle; - - if (a->len == 16 && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || - bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)) { - /* 128 bit UUID service definition */ - return 0; - } - - if (a->handle == 0xffff) - return 0; - - handle = a->handle + 1; - } - - if (0xffff - handle + 1 >= nitems) - return handle; - - return 0; -} - -static uint16_t find_uuid128_avail(struct btd_adapter *adapter, uint16_t nitems) -{ - uint16_t handle = 0, end = 0xffff; - struct gatt_server *server; - GList *dl; - GSList *l; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (l == NULL) - return 0; - - server = l->data; - if (server->database == NULL) - return 0xffff - nitems + 1; - - for (dl = g_list_last(server->database); dl; dl = dl->prev) { - struct attribute *a = dl->data; - - if (handle == 0) - handle = a->handle; - - if (bt_uuid_cmp(&a->uuid, &prim_uuid) != 0 && - bt_uuid_cmp(&a->uuid, &snd_uuid) != 0) - continue; - - if (end - handle >= nitems) - return end - nitems + 1; - - if (a->len == 2) { - /* 16 bit UUID service definition */ - return 0; - } - - if (a->handle == 0x0001) - return 0; - - end = a->handle - 1; - handle = 0; - } - - if (end - 0x0001 >= nitems) - return end - nitems + 1; - - return 0; -} - -uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid, - uint16_t nitems) -{ - btd_assert(nitems > 0); - - if (svc_uuid->type == BT_UUID16) - return find_uuid16_avail(adapter, nitems); - else if (svc_uuid->type == BT_UUID128) - return find_uuid128_avail(adapter, nitems); - else { - char uuidstr[MAX_LEN_UUID_STR]; - - bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR); - error("Service uuid: %s is neither a 16-bit nor a 128-bit uuid", - uuidstr); - return 0; - } -} - -struct attribute *attrib_db_add(struct btd_adapter *adapter, uint16_t handle, - bt_uuid_t *uuid, int read_req, - int write_req, const uint8_t *value, - size_t len) -{ - GSList *l; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (l == NULL) - return NULL; - - return attrib_db_add_new(l->data, handle, uuid, read_req, write_req, - value, len); -} - -int attrib_db_update(struct btd_adapter *adapter, uint16_t handle, - bt_uuid_t *uuid, const uint8_t *value, - size_t len, struct attribute **attr) -{ - struct gatt_server *server; - struct attribute *a; - GSList *l; - GList *dl; - guint h = handle; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (l == NULL) - return -ENOENT; - - server = l->data; - - DBG("handle=0x%04x", handle); - - dl = g_list_find_custom(server->database, GUINT_TO_POINTER(h), - handle_cmp); - if (dl == NULL) - return -ENOENT; - - a = dl->data; - - a->data = g_try_realloc(a->data, len); - if (len && a->data == NULL) - return -ENOMEM; - - a->len = len; - memcpy(a->data, value, len); - - if (uuid != NULL) - a->uuid = *uuid; - - if (attr) - *attr = a; - - return 0; -} - -int attrib_db_del(struct btd_adapter *adapter, uint16_t handle) -{ - struct gatt_server *server; - struct attribute *a; - GSList *l; - GList *dl; - guint h = handle; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (l == NULL) - return -ENOENT; - - server = l->data; - - DBG("handle=0x%04x", handle); - - dl = g_list_find_custom(server->database, GUINT_TO_POINTER(h), - handle_cmp); - if (dl == NULL) - return -ENOENT; - - a = dl->data; - server->database = g_list_remove(server->database, a); - g_free(a->data); - g_free(a); - - return 0; -} - -int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid, - const uint8_t *value, size_t len) -{ - struct gatt_server *server; - uint16_t handle; - GSList *l; - - l = g_slist_find_custom(servers, adapter, adapter_cmp); - if (l == NULL) - return -ENOENT; - - server = l->data; - - /* FIXME: Missing Privacy and Reconnection Address */ - - switch (uuid) { - case GATT_CHARAC_DEVICE_NAME: - handle = server->name_handle; - break; - case GATT_CHARAC_APPEARANCE: - handle = server->appearance_handle; - break; - default: - return -ENOSYS; - } - - return attrib_db_update(adapter, handle, NULL, value, len, NULL); -} diff -Nru bluez-5.63/src/attrib-server.h bluez-5.64/src/attrib-server.h --- bluez-5.63/src/attrib-server.h 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/src/attrib-server.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2010 Marcel Holtmann - * - * - */ - -uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid, - uint16_t nitems); -struct attribute *attrib_db_add(struct btd_adapter *adapter, uint16_t handle, - bt_uuid_t *uuid, int read_req, - int write_req, const uint8_t *value, - size_t len); -int attrib_db_update(struct btd_adapter *adapter, uint16_t handle, - bt_uuid_t *uuid, const uint8_t *value, - size_t len, struct attribute **attr); -int attrib_db_del(struct btd_adapter *adapter, uint16_t handle); -int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid, - const uint8_t *value, size_t len); -uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle, - const char *name); -void attrib_free_sdp(struct btd_adapter *adapter, uint32_t sdp_handle); -GAttrib *attrib_from_device(struct btd_device *device); -guint attrib_channel_attach(GAttrib *attrib); -gboolean attrib_channel_detach(GAttrib *attrib, guint id); diff -Nru bluez-5.63/src/bluetooth.service.in bluez-5.64/src/bluetooth.service.in --- bluez-5.63/src/bluetooth.service.in 2019-09-19 18:51:03.000000000 +0000 +++ bluez-5.64/src/bluetooth.service.in 2022-03-16 15:06:20.000000000 +0000 @@ -12,8 +12,24 @@ #Restart=on-failure CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE LimitNPROC=1 + +# Filesystem lockdown ProtectHome=true ProtectSystem=full +PrivateTmp=true +ProtectKernelTunables=true +ProtectControlGroups=true +ReadWritePaths=@statedir@ +ReadOnlyPaths=@confdir@ + +# Execute Mappings +MemoryDenyWriteExecute=true + +# Privilege escalation +NoNewPrivileges=true + +# Real-time +RestrictRealtime=true [Install] WantedBy=bluetooth.target diff -Nru bluez-5.63/src/btd.h bluez-5.64/src/btd.h --- bluez-5.63/src/btd.h 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/btd.h 2022-03-16 15:06:20.000000000 +0000 @@ -121,6 +121,7 @@ uint16_t did_version; bt_mode_t mode; + uint16_t max_adapters; bt_gatt_cache_t gatt_cache; uint16_t gatt_mtu; uint8_t gatt_channels; diff -Nru bluez-5.63/src/device.c bluez-5.64/src/device.c --- bluez-5.63/src/device.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/device.c 2022-03-16 15:06:20.000000000 +0000 @@ -62,7 +62,6 @@ #include "agent.h" #include "textfile.h" #include "storage.h" -#include "attrib-server.h" #include "eir.h" #define DISCONNECT_TIMER 2 @@ -544,7 +543,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } data_old = g_key_file_to_data(key_file, &length_old, NULL); @@ -557,7 +556,7 @@ if (!g_file_set_contents(filename, data, length, &gerr)) { error("Unable set contents for %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } } g_free(data); @@ -593,7 +592,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } failed_time = (uint64_t) dev->name_resolve_failed_time; @@ -2667,7 +2666,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } /* Remove current attributes since it might have changed */ @@ -3201,6 +3200,28 @@ "Connected"); } +static bool device_disappeared(gpointer user_data) +{ + struct btd_device *dev = user_data; + + dev->temporary_timer = 0; + + btd_adapter_remove_device(dev->adapter, dev); + + return FALSE; +} + +static void set_temporary_timer(struct btd_device *dev, unsigned int timeout) +{ + clear_temporary_timer(dev); + + if (!timeout) + return; + + dev->temporary_timer = timeout_add_seconds(timeout, device_disappeared, + dev, NULL); +} + void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type) { struct bearer_state *state = get_state(device, bdaddr_type); @@ -3286,7 +3307,7 @@ DEVICE_INTERFACE, "Connected"); if (remove_device) - btd_adapter_remove_device(device->adapter, device); + set_temporary_timer(device, 0); } guint device_add_disconnect_watch(struct btd_device *device, @@ -3636,7 +3657,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } groups = g_key_file_get_groups(key_file, NULL); @@ -3810,7 +3831,7 @@ uint16_t properties, value_handle, handle_int; char uuid_str[MAX_LEN_UUID_STR]; struct gatt_db_attribute *att; - char val_str[32]; + char val_str[33]; uint8_t val[16]; size_t val_len; bt_uuid_t uuid; @@ -4488,12 +4509,24 @@ clock_gettime(CLOCK_MONOTONIC, &now); - /* If now < failed_time, it means the clock has somehow turned back, - * possibly because of system restart. Allow name request in this case. + /* failed_time is empty (0), meaning no prior failure. */ + if (device->name_resolve_failed_time == 0) + return true; + + /* now < failed_time, meaning the clock has somehow turned back, + * possibly because of system restart. Allow just to be safe. + */ + if (now.tv_sec < device->name_resolve_failed_time) + return true; + + /* now >= failed_time + name_request_retry_delay, meaning the + * period of not sending name request is over. */ - return now.tv_sec < device->name_resolve_failed_time || - now.tv_sec >= device->name_resolve_failed_time + - btd_opts.name_request_retry_delay; + if (now.tv_sec >= device->name_resolve_failed_time + + btd_opts.name_request_retry_delay) + return true; + + return false; } void device_name_resolve_fail(struct btd_device *device) @@ -4579,28 +4612,6 @@ store_device_info(device); } -static bool device_disappeared(gpointer user_data) -{ - struct btd_device *dev = user_data; - - dev->temporary_timer = 0; - - btd_adapter_remove_device(dev->adapter, dev); - - return FALSE; -} - -static void set_temporary_timer(struct btd_device *dev, unsigned int timeout) -{ - clear_temporary_timer(dev); - - if (!timeout) - return; - - dev->temporary_timer = timeout_add_seconds(timeout, device_disappeared, - dev, NULL); -} - void device_update_last_seen(struct btd_device *device, uint8_t bdaddr_type) { if (bdaddr_type == BDADDR_BREDR) @@ -6152,7 +6163,7 @@ if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { error("Unable to load key file from %s: (%s)", filename, gerr->message); - g_error_free(gerr); + g_clear_error(&gerr); } /* for bonded devices this is done on every connection so limit writes diff -Nru bluez-5.63/src/eir.c bluez-5.64/src/eir.c --- bluez-5.63/src/eir.c 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/src/eir.c 2022-03-16 15:06:20.000000000 +0000 @@ -53,9 +53,9 @@ eir->services = NULL; g_free(eir->name); eir->name = NULL; - g_free(eir->hash); + free(eir->hash); eir->hash = NULL; - g_free(eir->randomizer); + free(eir->randomizer); eir->randomizer = NULL; g_slist_free_full(eir->msd_list, g_free); eir->msd_list = NULL; @@ -323,13 +323,13 @@ case EIR_SSP_HASH: if (data_len < 16) break; - eir->hash = g_memdup(data, 16); + eir->hash = util_memdup(data, 16); break; case EIR_SSP_RANDOMIZER: if (data_len < 16) break; - eir->randomizer = g_memdup(data, 16); + eir->randomizer = util_memdup(data, 16); break; case EIR_DEVICE_ID: diff -Nru bluez-5.63/src/error.h bluez-5.64/src/error.h --- bluez-5.63/src/error.h 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/src/error.h 2022-03-16 15:06:20.000000000 +0000 @@ -27,7 +27,7 @@ "argument" #define ERR_BREDR_CONN_ADAPTER_NOT_POWERED "br-connection-adapter-not-"\ "powered" -#define ERR_BREDR_CONN_NOT_SUPPORTED "br-connection-not-suuported" +#define ERR_BREDR_CONN_NOT_SUPPORTED "br-connection-not-supported" #define ERR_BREDR_CONN_BAD_SOCKET "br-connection-bad-socket" #define ERR_BREDR_CONN_MEMORY_ALLOC "br-connection-memory-"\ "allocation" diff -Nru bluez-5.63/src/gatt-database.c bluez-5.64/src/gatt-database.c --- bluez-5.63/src/gatt-database.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/gatt-database.c 2022-03-16 15:06:20.000000000 +0000 @@ -378,6 +378,18 @@ return true; } +static struct device_state * +find_device_state_by_att(struct btd_gatt_database *database, struct bt_att *att) +{ + bdaddr_t bdaddr; + uint8_t bdaddr_type; + + if (!get_dst_info(att, &bdaddr, &bdaddr_type)) + return NULL; + + return find_device_state(database, &bdaddr, bdaddr_type); +} + static struct device_state *get_device_state(struct btd_gatt_database *database, struct bt_att *att) { @@ -1018,13 +1030,6 @@ goto done; } - ccc_cb = queue_find(database->ccc_callbacks, ccc_cb_match_handle, - UINT_TO_PTR(gatt_db_attribute_get_handle(attrib))); - if (!ccc_cb) { - ecode = BT_ATT_ERROR_UNLIKELY; - goto done; - } - if (len == 1) val = *value; else @@ -1034,7 +1039,9 @@ if (val == ccc->value) goto done; - if (ccc_cb->callback) { + ccc_cb = queue_find(database->ccc_callbacks, ccc_cb_match_handle, + UINT_TO_PTR(gatt_db_attribute_get_handle(attrib))); + if (ccc_cb) { struct pending_op *op; op = pending_ccc_new(att, attrib, val, @@ -1056,6 +1063,22 @@ gatt_db_attribute_write_result(attrib, id, ecode); } +static void ccc_add_cb(struct btd_gatt_database *database, + struct gatt_db_attribute *ccc, + btd_gatt_database_ccc_write_t callback, + void *user_data, btd_gatt_database_destroy_t destroy) +{ + struct ccc_cb_data *ccc_cb; + + ccc_cb = new0(struct ccc_cb_data, 1); + ccc_cb->handle = gatt_db_attribute_get_handle(ccc); + ccc_cb->callback = callback; + ccc_cb->destroy = destroy; + ccc_cb->user_data = user_data; + + queue_push_tail(database->ccc_callbacks, ccc_cb); +} + static struct gatt_db_attribute * service_add_ccc(struct gatt_db_attribute *service, struct btd_gatt_database *database, @@ -1064,34 +1087,14 @@ btd_gatt_database_destroy_t destroy) { struct gatt_db_attribute *ccc; - struct ccc_cb_data *ccc_cb; - bt_uuid_t uuid; - - ccc_cb = new0(struct ccc_cb_data, 1); - - /* - * Provide a way for the permissions on a characteristic to dictate - * the permissions on the CCC - */ - perm |= BT_ATT_PERM_READ | BT_ATT_PERM_WRITE; - - bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID); - ccc = gatt_db_service_add_descriptor(service, &uuid, perm, - gatt_ccc_read_cb, gatt_ccc_write_cb, database); - if (!ccc) { - error("Failed to create CCC entry in database"); - free(ccc_cb); - return NULL; - } - - gatt_db_attribute_set_fixed_length(ccc, 2); - ccc_cb->handle = gatt_db_attribute_get_handle(ccc); - ccc_cb->callback = write_callback; - ccc_cb->destroy = destroy; - ccc_cb->user_data = user_data; + ccc = gatt_db_service_add_ccc(service, perm); + if (!ccc) + return ccc; - queue_push_tail(database->ccc_callbacks, ccc_cb); + /* Only add ccc_cb if callback is set */ + if (write_callback) + ccc_add_cb(database, ccc, write_callback, user_data, destroy); return ccc; } @@ -1308,13 +1311,6 @@ database_add_record(database, service); } -static void register_core_services(struct btd_gatt_database *database) -{ - populate_gap_service(database); - populate_gatt_service(database); - populate_devinfo_service(database); -} - static void conf_cb(void *user_data) { GDBusProxy *proxy = user_data; @@ -1438,6 +1434,49 @@ } } +static void gatt_notify_cb(struct gatt_db_attribute *attrib, + struct gatt_db_attribute *ccc, + const uint8_t *value, size_t len, + struct bt_att *att, void *user_data) +{ + struct btd_gatt_database *database = user_data; + struct notify notify; + + memset(¬ify, 0, sizeof(notify)); + + notify.database = database; + notify.handle = gatt_db_attribute_get_handle(attrib); + notify.ccc_handle = gatt_db_attribute_get_handle(ccc); + notify.value = (void *) value; + notify.len = len; + + if (attrib == database->svc_chngd) + notify.conf = service_changed_conf; + + /* If a specific att is provided notify only to that device */ + if (att) { + struct device_state *state; + + state = find_device_state_by_att(database, att); + if (!state) + return; + + send_notification_to_device(state, ¬ify); + } else + queue_foreach(database->device_states, + send_notification_to_device, ¬ify); +} + +static void register_core_services(struct btd_gatt_database *database) +{ + gatt_db_ccc_register(database->db, gatt_ccc_read_cb, gatt_ccc_write_cb, + gatt_notify_cb, database); + + populate_gap_service(database); + populate_gatt_service(database); + populate_devinfo_service(database); +} + static void send_notification_to_devices(struct btd_gatt_database *database, uint16_t handle, uint8_t *value, uint16_t len, uint16_t ccc_handle, @@ -1484,8 +1523,9 @@ put_le16(start, value); put_le16(end, value + 2); - send_notification_to_devices(database, handle, value, sizeof(value), - ccc_handle, service_changed_conf, NULL); + if (!gatt_db_attribute_notify(database->svc_chngd, value, sizeof(value), + NULL)) + error("Failed to notify Service Changed"); } static void gatt_db_service_added(struct gatt_db_attribute *attrib, @@ -3384,6 +3424,11 @@ goto fail; } + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { + DBG("UUIDs wrongly formatted"); + goto fail; + } + dbus_message_iter_recurse(&iter, &array); while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { @@ -3923,6 +3968,7 @@ put_le16(0x0001, value); put_le16(0xffff, value + 2); - send_notification_to_devices(database, handle, value, sizeof(value), - ccc_handle, service_changed_conf, NULL); + if (!gatt_db_attribute_notify(database->svc_chngd, value, sizeof(value), + NULL)) + error("Failed to notify Service Changed"); } diff -Nru bluez-5.63/src/main.c bluez-5.64/src/main.c --- bluez-5.63/src/main.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/main.c 2022-03-16 15:06:20.000000000 +0000 @@ -77,6 +77,7 @@ "NameResolving", "DebugKeys", "ControllerMode", + "MaxControllers" "MultiProfile", "FastConnectable", "Privacy", @@ -353,13 +354,22 @@ for (i = 0; i < params_len; ++i) { GError *err = NULL; - int val = g_key_file_get_integer(config, group, - params[i].val_name, &err); + char *str; + + str = g_key_file_get_string(config, group, params[i].val_name, + &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else { - info("%s=%d", params[i].val_name, val); + char *endptr = NULL; + int val; + + val = strtol(str, &endptr, 0); + if (!endptr || *endptr != '\0') + continue; + + info("%s=%s(%d)", params[i].val_name, str, val); val = MAX(val, params[i].min); val = MIN(val, params[i].max); @@ -779,6 +789,14 @@ g_free(str); } + val = g_key_file_get_integer(config, "General", "MaxControllers", &err); + if (err) { + g_clear_error(&err); + } else { + DBG("MaxControllers=%d", val); + btd_opts.max_adapters = val; + } + str = g_key_file_get_string(config, "General", "MultiProfile", &err); if (err) { g_clear_error(&err); diff -Nru bluez-5.63/src/main.conf bluez-5.64/src/main.conf --- bluez-5.63/src/main.conf 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/src/main.conf 2022-03-16 15:06:20.000000000 +0000 @@ -51,6 +51,10 @@ # Possible values: "dual", "bredr", "le" #ControllerMode = dual +# Maximum number of controllers allowed to be exposed to the system. +# Default=0 (unlimited) +#MaxControllers=0 + # Enables Multi Profile Specification support. This allows to specify if # system supports only Multiple Profiles Single Device (MPSD) configuration # or both Multiple Profiles Single Device (MPSD) and Multiple Profiles Multiple diff -Nru bluez-5.63/src/shared/btsnoop.c bluez-5.64/src/shared/btsnoop.c --- bluez-5.63/src/shared/btsnoop.c 2021-04-02 08:59:48.000000000 +0000 +++ bluez-5.64/src/shared/btsnoop.c 2022-03-16 15:06:20.000000000 +0000 @@ -336,7 +336,7 @@ break; case BTSNOOP_FORMAT_MONITOR: - flags = (index << 16) | opcode; + flags = ((uint32_t)index << 16) | opcode; break; default: diff -Nru bluez-5.63/src/shared/gatt-db.c bluez-5.64/src/shared/gatt-db.c --- bluez-5.63/src/shared/gatt-db.c 2021-08-22 04:30:44.000000000 +0000 +++ bluez-5.64/src/shared/gatt-db.c 2022-03-16 15:06:20.000000000 +0000 @@ -43,6 +43,15 @@ .value.u16 = GATT_INCLUDE_UUID }; static const bt_uuid_t ext_desc_uuid = { .type = BT_UUID16, .value.u16 = GATT_CHARAC_EXT_PROPER_UUID }; +static const bt_uuid_t ccc_uuid = { .type = BT_UUID16, + .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID }; + +struct gatt_db_ccc { + gatt_db_read_t read_func; + gatt_db_write_t write_func; + gatt_db_notify_t notify_func; + void *user_data; +}; struct gatt_db { int ref_count; @@ -57,6 +66,8 @@ gatt_db_authorize_cb_t authorize; void *authorize_data; + + struct gatt_db_ccc *ccc; }; struct notify { @@ -101,6 +112,7 @@ gatt_db_read_t read_func; gatt_db_write_t write_func; + gatt_db_notify_t notify_func; void *user_data; unsigned int read_id; @@ -444,6 +456,7 @@ timeout_remove(db->hash_id); queue_destroy(db->services, gatt_db_service_destroy); + free(db->ccc); free(db); } @@ -1038,6 +1051,71 @@ user_data); } +static void find_ccc_value(struct gatt_db_attribute *attrib, void *user_data) +{ + uint16_t *handle = user_data; + + gatt_db_attribute_get_char_data(attrib, NULL, handle, NULL, NULL, NULL); +} + +struct gatt_db_attribute * +gatt_db_service_add_ccc(struct gatt_db_attribute *attrib, uint32_t permissions) +{ + struct gatt_db *db; + struct gatt_db_attribute *ccc; + struct gatt_db_attribute *value; + uint16_t handle = 0; + + if (!attrib) + return NULL; + + db = attrib->service->db; + + if (!db->ccc) + return NULL; + + /* Locate value handle */ + gatt_db_service_foreach_char(attrib, find_ccc_value, &handle); + + if (!handle) + return NULL; + + value = gatt_db_get_attribute(db, handle); + if (!value || value->notify_func) + return NULL; + + ccc = service_insert_descriptor(attrib->service, 0, &ccc_uuid, + permissions, + db->ccc->read_func, + db->ccc->write_func, + db->ccc->user_data); + if (!ccc) + return ccc; + + gatt_db_attribute_set_fixed_length(ccc, 2); + ccc->notify_func = db->ccc->notify_func; + value->notify_func = db->ccc->notify_func; + + return ccc; +} + +void gatt_db_ccc_register(struct gatt_db *db, gatt_db_read_t read_func, + gatt_db_write_t write_func, + gatt_db_notify_t notify_func, + void *user_data) +{ + if (!db) + return; + + if (!db->ccc) + db->ccc = new0(struct gatt_db_ccc, 1); + + db->ccc->read_func = read_func; + db->ccc->write_func = write_func; + db->ccc->notify_func = notify_func; + db->ccc->user_data = user_data; +} + static struct gatt_db_attribute * service_insert_included(struct gatt_db_service *service, uint16_t handle, struct gatt_db_attribute *include) @@ -1450,32 +1528,71 @@ gatt_db_service_foreach(attrib, &characteristic_uuid, func, user_data); } +static int gatt_db_attribute_get_index(struct gatt_db_attribute *attrib) +{ + struct gatt_db_service *service; + int index; + + if (!attrib) + return -1; + + service = attrib->service; + index = attrib->handle - service->attributes[0]->handle; + + if (index > (service->num_handles - 1)) + return -1; + + return index; +} + +static struct gatt_db_attribute * +gatt_db_attribute_get_value(struct gatt_db_attribute *attrib) +{ + struct gatt_db_service *service; + int index; + + if (!attrib) + return NULL; + + index = gatt_db_attribute_get_index(attrib); + if (index < 0) + return NULL; + + service = attrib->service; + + if (!bt_uuid_cmp(&characteristic_uuid, &attrib->uuid)) + index++; + else if (bt_uuid_cmp(&characteristic_uuid, + &service->attributes[index - 1]->uuid)) + return NULL; + + return service->attributes[index]; +} + void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib, gatt_db_attribute_cb_t func, void *user_data) { struct gatt_db_service *service; struct gatt_db_attribute *attr; + int index; uint16_t i; if (!attrib || !func) return; - /* Return if this attribute is not a characteristic declaration */ - if (bt_uuid_cmp(&characteristic_uuid, &attrib->uuid)) + attrib = gatt_db_attribute_get_value(attrib); + if (!attrib) + return; + + index = gatt_db_attribute_get_index(attrib); + if (index < 0) return; service = attrib->service; /* Start from the attribute following the value handle */ - for (i = 0; i < service->num_handles; i++) { - if (service->attributes[i] == attrib) { - i += 2; - break; - } - } - - for (; i < service->num_handles; i++) { + for (i = index + 1; i < service->num_handles; i++) { attr = service->attributes[i]; if (!attr) continue; @@ -2049,6 +2166,54 @@ return true; } + +static void find_ccc(struct gatt_db_attribute *attrib, void *user_data) +{ + struct gatt_db_attribute **ccc = user_data; + + if (*ccc) + return; + + if (bt_uuid_cmp(&ccc_uuid, &attrib->uuid)) + return; + + *ccc = attrib; +} + +struct gatt_db_attribute * +gatt_db_attribute_get_ccc(struct gatt_db_attribute *attrib) +{ + struct gatt_db_attribute *ccc = NULL; + + if (!attrib) + return NULL; + + gatt_db_service_foreach_desc(attrib, find_ccc, &ccc); + + return ccc; +} + +bool gatt_db_attribute_notify(struct gatt_db_attribute *attrib, + const uint8_t *value, size_t len, + struct bt_att *att) +{ + struct gatt_db_attribute *ccc; + + if (!attrib || !attrib->notify_func) + return false; + + attrib = gatt_db_attribute_get_value(attrib); + if (!attrib) + return false; + + ccc = gatt_db_attribute_get_ccc(attrib); + if (!ccc) + return false; + + attrib->notify_func(attrib, ccc, value, len, att, ccc->user_data); + + return true; +} bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib) { diff -Nru bluez-5.63/src/shared/gatt-db.h bluez-5.64/src/shared/gatt-db.h --- bluez-5.63/src/shared/gatt-db.h 2021-02-22 20:26:59.000000000 +0000 +++ bluez-5.64/src/shared/gatt-db.h 2022-03-16 15:06:20.000000000 +0000 @@ -47,6 +47,10 @@ const uint8_t *value, size_t len, uint8_t opcode, struct bt_att *att, void *user_data); +typedef void (*gatt_db_notify_t) (struct gatt_db_attribute *attrib, + struct gatt_db_attribute *ccc, + const uint8_t *value, size_t len, + struct bt_att *att, void *user_data); struct gatt_db_attribute * gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib, @@ -92,6 +96,7 @@ gatt_db_read_t read_func, gatt_db_write_t write_func, void *user_data); + struct gatt_db_attribute * gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib, uint16_t handle, @@ -102,6 +107,9 @@ void *user_data); struct gatt_db_attribute * +gatt_db_service_add_ccc(struct gatt_db_attribute *attrib, uint32_t permissions); + +struct gatt_db_attribute * gatt_db_insert_included(struct gatt_db *db, uint16_t handle, struct gatt_db_attribute *include); @@ -192,6 +200,11 @@ gatt_db_destroy_func_t destroy); bool gatt_db_unregister(struct gatt_db *db, unsigned int id); +void gatt_db_ccc_register(struct gatt_db *db, gatt_db_read_t read_func, + gatt_db_write_t write_func, + gatt_db_notify_t notify_func, + void *user_data); + typedef uint8_t (*gatt_db_authorize_cb_t)(struct gatt_db_attribute *attrib, uint8_t opcode, struct bt_att *att, void *user_data); @@ -268,6 +281,13 @@ bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib, unsigned int id, int err); +struct gatt_db_attribute * +gatt_db_attribute_get_ccc(struct gatt_db_attribute *attrib); + +bool gatt_db_attribute_notify(struct gatt_db_attribute *attrib, + const uint8_t *value, size_t len, + struct bt_att *att); + bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib); void *gatt_db_attribute_get_user_data(struct gatt_db_attribute *attrib); diff -Nru bluez-5.63/src/shared/mgmt.c bluez-5.64/src/shared/mgmt.c --- bluez-5.63/src/shared/mgmt.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/src/shared/mgmt.c 2022-03-16 15:06:20.000000000 +0000 @@ -25,6 +25,7 @@ #include "src/shared/queue.h" #include "src/shared/util.h" #include "src/shared/mgmt.h" +#include "src/shared/timeout.h" struct mgmt { int ref_count; @@ -49,6 +50,7 @@ }; struct mgmt_request { + struct mgmt *mgmt; unsigned int id; uint16_t opcode; uint16_t index; @@ -57,6 +59,8 @@ mgmt_request_func_t callback; mgmt_destroy_func_t destroy; void *user_data; + int timeout; + unsigned int timeout_id; }; struct mgmt_notify { @@ -81,6 +85,9 @@ if (request->destroy) request->destroy(request->user_data); + if (request->timeout_id) + timeout_remove(request->timeout_id); + free(request->buf); free(request); } @@ -150,6 +157,26 @@ mgmt->writer_active = false; } +static bool request_timeout(void *data) +{ + struct mgmt_request *request = data; + + if (!request) + return false; + + request->timeout_id = 0; + + queue_remove_if(request->mgmt->pending_list, NULL, request); + + if (request->callback) + request->callback(MGMT_STATUS_TIMEOUT, 0, NULL, + request->user_data); + + destroy_request(request); + + return false; +} + static bool send_request(struct mgmt *mgmt, struct mgmt_request *request) { struct iovec iov; @@ -169,6 +196,12 @@ return false; } + if (request->timeout) + request->timeout_id = timeout_add_seconds(request->timeout, + request_timeout, + request, + NULL); + util_debug(mgmt->debug_callback, mgmt->debug_data, "[0x%04x] command 0x%04x", request->index, request->opcode); @@ -566,7 +599,8 @@ static struct mgmt_request *create_request(struct mgmt *mgmt, uint16_t opcode, uint16_t index, uint16_t length, const void *param, mgmt_request_func_t callback, - void *user_data, mgmt_destroy_func_t destroy) + void *user_data, mgmt_destroy_func_t destroy, + int timeout) { struct mgmt_request *request; struct mgmt_hdr *hdr; @@ -598,12 +632,18 @@ hdr->index = htobs(index); hdr->len = htobs(length); + /* Use a weak reference so requests don't prevent mgmt_unref to + * cancel requests and free in case of the last reference is dropped by + * the user. + */ + request->mgmt = mgmt; request->opcode = opcode; request->index = index; request->callback = callback; request->destroy = destroy; request->user_data = user_data; + request->timeout = timeout; return request; } @@ -735,10 +775,11 @@ return ret; } -unsigned int mgmt_send(struct mgmt *mgmt, uint16_t opcode, uint16_t index, - uint16_t length, const void *param, - mgmt_request_func_t callback, - void *user_data, mgmt_destroy_func_t destroy) +unsigned int mgmt_send_timeout(struct mgmt *mgmt, uint16_t opcode, + uint16_t index, uint16_t length, + const void *param, mgmt_request_func_t callback, + void *user_data, mgmt_destroy_func_t destroy, + int timeout) { struct mgmt_request *request; @@ -746,7 +787,7 @@ return 0; request = create_request(mgmt, opcode, index, length, param, - callback, user_data, destroy); + callback, user_data, destroy, timeout); if (!request) return 0; @@ -766,6 +807,15 @@ return request->id; } +unsigned int mgmt_send(struct mgmt *mgmt, uint16_t opcode, uint16_t index, + uint16_t length, const void *param, + mgmt_request_func_t callback, + void *user_data, mgmt_destroy_func_t destroy) +{ + return mgmt_send_timeout(mgmt, opcode, index, length, param, callback, + user_data, destroy, 0); +} + unsigned int mgmt_send_nowait(struct mgmt *mgmt, uint16_t opcode, uint16_t index, uint16_t length, const void *param, mgmt_request_func_t callback, @@ -777,7 +827,8 @@ return 0; request = create_request(mgmt, opcode, index, length, param, - callback, user_data, destroy); + callback, user_data, destroy, + 0); if (!request) return 0; @@ -792,10 +843,11 @@ return request->id; } -unsigned int mgmt_reply(struct mgmt *mgmt, uint16_t opcode, uint16_t index, - uint16_t length, const void *param, - mgmt_request_func_t callback, - void *user_data, mgmt_destroy_func_t destroy) +unsigned int mgmt_reply_timeout(struct mgmt *mgmt, uint16_t opcode, + uint16_t index, uint16_t length, + const void *param, mgmt_request_func_t callback, + void *user_data, mgmt_destroy_func_t destroy, + int timeout) { struct mgmt_request *request; @@ -803,7 +855,7 @@ return 0; request = create_request(mgmt, opcode, index, length, param, - callback, user_data, destroy); + callback, user_data, destroy, timeout); if (!request) return 0; @@ -823,6 +875,15 @@ return request->id; } +unsigned int mgmt_reply(struct mgmt *mgmt, uint16_t opcode, uint16_t index, + uint16_t length, const void *param, + mgmt_request_func_t callback, + void *user_data, mgmt_destroy_func_t destroy) +{ + return mgmt_reply_timeout(mgmt, opcode, index, length, param, callback, + user_data, destroy, 0); +} + bool mgmt_cancel(struct mgmt *mgmt, unsigned int id) { struct mgmt_request *request; diff -Nru bluez-5.63/src/shared/mgmt.h bluez-5.64/src/shared/mgmt.h --- bluez-5.63/src/shared/mgmt.h 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/src/shared/mgmt.h 2022-03-16 15:06:20.000000000 +0000 @@ -55,6 +55,11 @@ uint16_t length, const void *param, mgmt_request_func_t callback, void *user_data, mgmt_destroy_func_t destroy); +unsigned int mgmt_send_timeout(struct mgmt *mgmt, uint16_t opcode, + uint16_t index, uint16_t length, + const void *param, mgmt_request_func_t callback, + void *user_data, mgmt_destroy_func_t destroy, + int timeout); unsigned int mgmt_send_nowait(struct mgmt *mgmt, uint16_t opcode, uint16_t index, uint16_t length, const void *param, mgmt_request_func_t callback, @@ -63,6 +68,11 @@ uint16_t length, const void *param, mgmt_request_func_t callback, void *user_data, mgmt_destroy_func_t destroy); +unsigned int mgmt_reply_timeout(struct mgmt *mgmt, uint16_t opcode, + uint16_t index, uint16_t length, + const void *param, mgmt_request_func_t callback, + void *user_data, mgmt_destroy_func_t destroy, + int timeout); bool mgmt_cancel(struct mgmt *mgmt, unsigned int id); bool mgmt_cancel_index(struct mgmt *mgmt, uint16_t index); bool mgmt_cancel_all(struct mgmt *mgmt); diff -Nru bluez-5.63/src/shared/shell.c bluez-5.64/src/shared/shell.c --- bluez-5.63/src/shared/shell.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/src/shared/shell.c 2022-03-16 15:06:20.000000000 +0000 @@ -678,7 +678,6 @@ static void rl_handler(char *input) { - wordexp_t w; HIST_ENTRY *last; if (!input) { @@ -703,16 +702,8 @@ if (data.monitor) bt_log_printf(0xffff, data.name, LOG_INFO, "%s", input); - if (wordexp(input, &w, WRDE_NOCMD)) - goto done; - - if (w.we_wordc == 0) { - wordfree(&w); - goto done; - } + bt_shell_exec(input); - shell_exec(w.we_wordc, w.we_wordv); - wordfree(&w); done: free(input); } @@ -1178,6 +1169,29 @@ return status; } +int bt_shell_exec(const char *input) +{ + wordexp_t w; + int err; + + if (!input) + return 0; + + if (wordexp(input, &w, WRDE_NOCMD)) + return -ENOEXEC; + + if (w.we_wordc == 0) { + wordfree(&w); + return -ENOEXEC; + } + + err = shell_exec(w.we_wordc, w.we_wordv); + + wordfree(&w); + + return err; +} + void bt_shell_cleanup(void) { bt_shell_release_prompt(""); diff -Nru bluez-5.63/src/shared/shell.h bluez-5.64/src/shared/shell.h --- bluez-5.63/src/shared/shell.h 2021-08-22 04:30:44.000000000 +0000 +++ bluez-5.64/src/shared/shell.h 2022-03-16 15:06:20.000000000 +0000 @@ -55,6 +55,7 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt); int bt_shell_run(void); +int bt_shell_exec(const char *input); void bt_shell_quit(int status); void bt_shell_noninteractive_quit(int status); diff -Nru bluez-5.63/src/shared/util.c bluez-5.64/src/shared/util.c --- bluez-5.63/src/shared/util.c 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/src/shared/util.c 2022-03-16 15:06:20.000000000 +0000 @@ -13,6 +13,7 @@ #endif #define _GNU_SOURCE +#include #include #include #include @@ -23,9 +24,13 @@ #include #include +#ifdef HAVE_SYS_RANDOM_H +#include +#endif + #include "src/shared/util.h" -void *btd_malloc(size_t size) +void *util_malloc(size_t size) { if (__builtin_expect(!!size, 1)) { void *ptr; @@ -41,6 +46,22 @@ return NULL; } +void *util_memdup(const void *src, size_t size) +{ + void *cpy; + + if (!src || !size) + return NULL; + + cpy = util_malloc(size); + if (!cpy) + return NULL; + + memcpy(cpy, src, size); + + return cpy; +} + void util_debug_va(util_debug_func_t function, void *user_data, const char *format, va_list va) { @@ -122,6 +143,26 @@ return DT_UNKNOWN; } +/* Helper for getting a random in case getrandom unavailable (glibc < 2.25) */ +ssize_t util_getrandom(void *buf, size_t buflen, unsigned int flags) +{ +#ifdef HAVE_GETRANDOM + return getrandom(buf, buflen, flags); +#else + int fd; + ssize_t bytes; + + fd = open("/dev/urandom", O_CLOEXEC); + if (fd < 0) + return -1; + + bytes = read(fd, buf, buflen); + close(fd); + + return bytes; +#endif +} + /* Helpers for bitfield operations */ /* Find unique id in range from 1 to max but no bigger than 64. */ diff -Nru bluez-5.63/src/shared/util.h bluez-5.64/src/shared/util.h --- bluez-5.63/src/shared/util.h 2021-10-13 18:38:34.000000000 +0000 +++ bluez-5.64/src/shared/util.h 2022-03-16 15:06:20.000000000 +0000 @@ -14,6 +14,7 @@ #include #include #include +#include #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define BIT(n) (1 << (n)) @@ -75,7 +76,7 @@ size_t __n = (size_t) (count); \ size_t __s = sizeof(type); \ void *__p; \ - __p = btd_malloc(__n * __s); \ + __p = util_malloc(__n * __s); \ memset(__p, 0, __n * __s); \ __p; \ })) @@ -86,7 +87,8 @@ char *strdelimit(char *str, char *del, char c); int strsuffix(const char *str, const char *suffix); -void *btd_malloc(size_t size); +void *util_malloc(size_t size); +void *util_memdup(const void *src, size_t size); typedef void (*util_debug_func_t)(const char *str, void *user_data); @@ -102,6 +104,8 @@ unsigned char util_get_dt(const char *parent, const char *name); +ssize_t util_getrandom(void *buf, size_t buflen, unsigned int flags); + uint8_t util_get_uid(uint64_t *bitmap, uint8_t max); void util_clear_uid(uint64_t *bitmap, uint8_t id); diff -Nru bluez-5.63/tools/btgatt-server.c bluez-5.64/tools/btgatt-server.c --- bluez-5.63/tools/btgatt-server.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/tools/btgatt-server.c 2022-03-16 15:06:20.000000000 +0000 @@ -20,7 +20,6 @@ #include #include #include -#include #include "lib/bluetooth.h" #include "lib/hci.h" @@ -287,7 +286,7 @@ uint32_t cur_ee; uint32_t val; - if (getrandom(&val, sizeof(val), 0) < 0) + if (util_getrandom(&val, sizeof(val), 0) < 0) return false; pdu[0] = 0x06; diff -Nru bluez-5.63/tools/btproxy.c bluez-5.64/tools/btproxy.c --- bluez-5.63/tools/btproxy.c 2021-02-22 20:27:00.000000000 +0000 +++ bluez-5.64/tools/btproxy.c 2022-03-16 15:06:20.000000000 +0000 @@ -47,8 +47,9 @@ unsigned short hci_channel; }; #define HCI_CHANNEL_USER 1 +#define HCI_INDEX_NONE 0xffff -static uint16_t hci_index = 0; +static uint16_t hci_index = HCI_INDEX_NONE; static bool client_active = false; static bool debug_enabled = false; static bool emulate_ecc = false; @@ -535,9 +536,12 @@ static int open_channel(uint16_t index) { struct sockaddr_hci addr; - int fd; + int fd, err; - printf("Opening user channel for hci%u\n", hci_index); + if (index == HCI_INDEX_NONE) + index = 0; + + printf("Opening user channel for hci%u\n", index); fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI); if (fd < 0) { @@ -551,7 +555,16 @@ addr.hci_channel = HCI_CHANNEL_USER; if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + err = -errno; close(fd); + + /* Open next available controller if no specific index was + * provided and the error indicates that the controller. + */ + if (hci_index == HCI_INDEX_NONE && + (err == -EBUSY || err == -EUSERS)) + return open_channel(++index); + perror("Failed to bind Bluetooth socket"); return -1; } @@ -588,7 +601,7 @@ return; } - if (client_active) { + if (client_active && hci_index != HCI_INDEX_NONE) { fprintf(stderr, "Active client already present\n"); close(host_fd); return; diff -Nru bluez-5.63/tools/gatt-service.c bluez-5.64/tools/gatt-service.c --- bluez-5.63/tools/gatt-service.c 2021-02-22 20:27:00.000000000 +0000 +++ bluez-5.64/tools/gatt-service.c 2022-03-16 15:06:20.000000000 +0000 @@ -26,6 +26,7 @@ #include "gdbus/gdbus.h" #include "src/error.h" +#include "src/shared/util.h" #define GATT_MGR_IFACE "org.bluez.GattManager1" #define GATT_SERVICE_IFACE "org.bluez.GattService1" @@ -126,8 +127,8 @@ static void desc_write(struct descriptor *desc, const uint8_t *value, int len) { - g_free(desc->value); - desc->value = g_memdup(value, len); + free(desc->value); + desc->value = util_memdup(value, len); desc->vlen = len; g_dbus_emit_property_changed(connection, desc->path, @@ -264,8 +265,8 @@ static void chr_write(struct characteristic *chr, const uint8_t *value, int len) { - g_free(chr->value); - chr->value = g_memdup(value, len); + free(chr->value); + chr->value = util_memdup(value, len); chr->vlen = len; g_dbus_emit_property_changed(connection, chr->path, GATT_CHR_IFACE, @@ -388,7 +389,7 @@ g_free(chr->uuid); g_free(chr->service); - g_free(chr->value); + free(chr->value); g_free(chr->path); g_free(chr); } @@ -398,7 +399,7 @@ struct descriptor *desc = user_data; g_free(desc->uuid); - g_free(desc->value); + free(desc->value); g_free(desc->path); g_free(desc); } @@ -592,7 +593,7 @@ chr = g_new0(struct characteristic, 1); chr->uuid = g_strdup(chr_uuid); - chr->value = g_memdup(value, vlen); + chr->value = util_memdup(value, vlen); chr->vlen = vlen; chr->props = props; chr->service = g_strdup(service_path); diff -Nru bluez-5.63/tools/mesh/cfgcli.c bluez-5.64/tools/mesh/cfgcli.c --- bluez-5.63/tools/mesh/cfgcli.c 2021-10-13 18:38:35.000000000 +0000 +++ bluez-5.64/tools/mesh/cfgcli.c 2022-03-16 15:06:20.000000000 +0000 @@ -1291,7 +1291,7 @@ if (!remote_has_composition(target)) { bt_shell_printf("Node composition is unknown\n"); - bt_shell_printf("Call \"get-composition\" first\n"); + bt_shell_printf("Call \"composition-get\" first\n"); return bt_shell_noninteractive_quit(EXIT_FAILURE); } @@ -1493,7 +1493,7 @@ if (!remote_has_composition(target)) { bt_shell_printf("Node composition is unknown\n"); - bt_shell_printf("Call \"get-composition\" first\n"); + bt_shell_printf("Call \"composition-get\" first\n"); return bt_shell_noninteractive_quit(EXIT_FAILURE); } @@ -1593,7 +1593,7 @@ if (!remote_has_composition(target)) { bt_shell_printf("Node composition is unknown\n"); - bt_shell_printf("Call \"get-composition\" first\n"); + bt_shell_printf("Call \"composition-get\" first\n"); return bt_shell_noninteractive_quit(EXIT_FAILURE); } diff -Nru bluez-5.63/tools/mesh/mesh-db.c bluez-5.64/tools/mesh/mesh-db.c --- bluez-5.63/tools/mesh/mesh-db.c 2021-10-13 18:38:35.000000000 +0000 +++ bluez-5.64/tools/mesh/mesh-db.c 2022-03-16 15:06:20.000000000 +0000 @@ -2007,7 +2007,7 @@ if (!cfg || !cfg->jcfg) return false; - jarray = json_object_object_get(cfg->jcfg, "provisioniers"); + jarray = json_object_object_get(cfg->jcfg, "provisioners"); if (!jarray || json_object_get_type(jarray) != json_type_array) return false; @@ -2041,7 +2041,7 @@ } /* - * This is a simplistic implementation onf allocated range, where + * This is a simplistic implementation of allocated range, where * the range is one contiguous chunk of the address space. */ static bool add_range(json_object *jobj, const char *keyword, uint16_t low, diff -Nru bluez-5.63/tools/mesh-cfgtest.c bluez-5.64/tools/mesh-cfgtest.c --- bluez-5.63/tools/mesh-cfgtest.c 2021-06-13 19:56:37.000000000 +0000 +++ bluez-5.64/tools/mesh-cfgtest.c 2022-03-16 15:06:20.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff -Nru bluez-5.63/tools/mesh-gatt/gatt.c bluez-5.64/tools/mesh-gatt/gatt.c --- bluez-5.63/tools/mesh-gatt/gatt.c 2021-06-13 19:56:37.000000000 +0000 +++ bluez-5.64/tools/mesh-gatt/gatt.c 2022-03-16 15:06:20.000000000 +0000 @@ -24,6 +24,7 @@ #include "src/shared/io.h" #include "src/shared/shell.h" +#include "src/shared/util.h" #include "gdbus/gdbus.h" #include "lib/bluetooth.h" #include "lib/uuid.h" @@ -86,7 +87,7 @@ { struct write_data *data = user_data; - g_free(data->gatt_data); + free(data->gatt_data); free(data); } @@ -338,7 +339,7 @@ /* TODO: should keep in queue in case we need to cancel write? */ data->gatt_len = len; - data->gatt_data = g_memdup(buf, len); + data->gatt_data = util_memdup(buf, len); data->gatt_data[0] &= GATT_TYPE_MASK; data->iov.iov_base = data->gatt_data; data->iov.iov_len = len; diff -Nru bluez-5.63/tools/obexctl.c bluez-5.64/tools/obexctl.c --- bluez-5.63/tools/obexctl.c 2021-02-22 20:27:00.000000000 +0000 +++ bluez-5.64/tools/obexctl.c 2022-03-16 15:06:20.000000000 +0000 @@ -114,6 +114,7 @@ struct connect_args { char *dev; char *target; + uint8_t channel; }; static void connect_args_free(void *data) @@ -139,13 +140,14 @@ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - if (args->target == NULL) - goto done; - - g_dbus_dict_append_entry(&dict, "Target", + if (args->target) + g_dbus_dict_append_entry(&dict, "Target", DBUS_TYPE_STRING, &args->target); -done: + if (args->channel) + g_dbus_dict_append_entry(&dict, "Channel", + DBUS_TYPE_BYTE, &args->channel); + dbus_message_iter_close_container(iter, &dict); } @@ -153,6 +155,7 @@ { struct connect_args *args; const char *target = "opp"; + int channel = 0; if (!client) { bt_shell_printf("Client proxy not available\n"); @@ -162,9 +165,20 @@ if (argc > 2) target = argv[2]; + if (argc > 3) { + char *endptr = NULL; + + channel = strtol(argv[3], &endptr, 0); + if (!endptr || *endptr != '\0' || channel > UINT8_MAX) { + bt_shell_printf("Invalid channel\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + args = g_new0(struct connect_args, 1); args->dev = g_strdup(argv[1]); args->target = g_strdup(target); + args->channel = channel; if (g_dbus_proxy_method_call(client, "CreateSession", connect_setup, connect_reply, args, connect_args_free) == FALSE) { @@ -1832,7 +1846,8 @@ static const struct bt_shell_menu main_menu = { .name = "main", .entries = { - { "connect", " [uuid]", cmd_connect, "Connect session" }, + { "connect", " [uuid] [channel]", cmd_connect, + "Connect session" }, { "disconnect", "[session]", cmd_disconnect, "Disconnect session", session_generator }, { "list", NULL, cmd_list, "List available sessions" }, diff -Nru bluez-5.63/tools/rfcomm-tester.c bluez-5.64/tools/rfcomm-tester.c --- bluez-5.63/tools/rfcomm-tester.c 2021-10-13 18:38:35.000000000 +0000 +++ bluez-5.64/tools/rfcomm-tester.c 2022-03-16 15:06:20.000000000 +0000 @@ -37,8 +37,11 @@ struct hciemu *hciemu; enum hciemu_type hciemu_type; const void *test_data; + GIOChannel *io; unsigned int io_id; uint16_t conn_handle; + uint16_t send_len; + uint16_t recv_len; }; struct rfcomm_client_data { @@ -197,6 +200,9 @@ data->io_id = 0; } + if (data->io) + g_io_channel_unref(data->io); + hciemu_unref(data->hciemu); data->hciemu = NULL; } @@ -297,7 +303,24 @@ .server_channel = 0x0c, .client_channel = 0x0c, .data_len = sizeof(data), - .send_data = data + .send_data = data, +}; + +const uint8_t data_32k[32768] = { [0 ... 4095] = 0x00, + [4096 ... 8191] = 0x01, + [8192 ... 12287] = 0x02, + [12288 ... 16383] = 0x03, + [16384 ... 20479] = 0x04, + [20480 ... 24575] = 0x05, + [24576 ... 28671] = 0x06, + [28672 ... 32767] = 0x07, +}; + +const struct rfcomm_client_data connect_send_32k_success = { + .server_channel = 0x0c, + .client_channel = 0x0c, + .data_len = sizeof(data_32k), + .send_data = data_32k, }; const struct rfcomm_client_data connect_read_success = { @@ -420,6 +443,44 @@ return false; } +static gboolean rc_write_data(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = user_data; + const struct rfcomm_client_data *cli = data->test_data; + int sk; + ssize_t ret; + + if (cond & G_IO_NVAL) + return false; + + if (cond & (G_IO_HUP | G_IO_ERR)) + goto done; + + tester_print("Writing %u bytes of data", + cli->data_len - data->send_len); + + sk = g_io_channel_unix_get_fd(io); + + ret = write(sk, cli->send_data + data->send_len, + cli->data_len - data->send_len); + if (ret < 0) { + tester_warn("Failed to write %u bytes: %s (%d)", + cli->data_len, strerror(errno), errno); + tester_test_failed(); + goto done; + } + + data->send_len += ret; + + tester_print("Written %u/%u bytes", data->send_len, cli->data_len); + + /* Don't retry write since that seems to block bthost from receiving */ +done: + data->io_id = 0; + return false; +} + static gboolean rc_connect_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { @@ -445,17 +506,9 @@ } if (cli->send_data) { - ssize_t ret; - - tester_print("Writing %u bytes of data", cli->data_len); - - ret = write(sk, cli->send_data, cli->data_len); - if (cli->data_len != ret) { - tester_warn("Failed to write %u bytes: %s (%d)", - cli->data_len, strerror(errno), errno); - tester_test_failed(); - } - + data->io = g_io_channel_ref(io); + cond = G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL; + data->io_id = g_io_add_watch(io, cond, rc_write_data, data); return false; } else if (cli->read_data) { g_io_add_watch(io, G_IO_IN, client_received_data, NULL); @@ -483,16 +536,35 @@ tester_print("bthost received %u bytes of data", len); - if (cli->data_len != len) { + if (test_data->recv_len + len > cli->data_len) { + tester_print("received more data than expected"); tester_test_failed(); return; } - ret = memcmp(cli->send_data, data, len); - if (ret) + ret = memcmp(cli->send_data + test_data->recv_len, data, len); + if (ret) { tester_test_failed(); - else - tester_test_passed(); + return; + } + + test_data->recv_len += len; + + tester_print("bthost received progress %u/%u", test_data->recv_len, + cli->data_len); + + if (cli->data_len != test_data->recv_len) { + if (cli->data_len != test_data->send_len) + test_data->io_id = g_io_add_watch(test_data->io, + G_IO_OUT | G_IO_HUP | + G_IO_ERR | G_IO_NVAL, + rc_write_data, test_data); + return; + } + + test_data->recv_len = 0; + + tester_test_passed(); } static void server_hook_func(const void *data, uint16_t len, @@ -735,6 +807,9 @@ test_rfcomm("Basic RFCOMM Socket Client - Write Success", &connect_send_success, setup_powered_client, test_connect); + test_rfcomm("Basic RFCOMM Socket Client - Write 32k Success", + &connect_send_32k_success, setup_powered_client, + test_connect); test_rfcomm("Basic RFCOMM Socket Client - Read Success", &connect_read_success, setup_powered_client, test_connect); diff -Nru bluez-5.63/tools/test-runner.c bluez-5.64/tools/test-runner.c --- bluez-5.63/tools/test-runner.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/tools/test-runner.c 2022-03-16 15:06:20.000000000 +0000 @@ -47,6 +47,7 @@ static bool run_auto = false; static bool start_dbus = false; +static bool start_emulator = false; static bool start_monitor = false; static int num_devs = 0; static const char *qemu_binary = NULL; @@ -249,9 +250,10 @@ "acpi=off pci=noacpi noapic quiet ro init=%s " "bluetooth.enable_ecred=1" "TESTHOME=%s TESTDBUS=%u TESTMONITOR=%u " - "TESTDEVS=%d TESTAUTO=%u TESTARGS=\'%s\'", + "TESTEMULATOR=%u TESTDEVS=%d TESTAUTO=%u " + "TESTARGS=\'%s\'", initcmd, cwd, start_dbus, start_monitor, - num_devs, run_auto, testargs); + start_emulator, num_devs, run_auto, testargs); argv = alloca(sizeof(qemu_argv) + (sizeof(char *) * (4 + (num_devs * 4)))); @@ -600,12 +602,69 @@ return pid; } +static const char *btvirt_table[] = { + "btvirt", + "emulator/btvirt", + "/usr/sbin/btvirt", + NULL +}; + +static pid_t start_btvirt(const char *home) +{ + const char *btvirt = NULL; + char *argv[3], *envp[2]; + pid_t pid; + int i; + + if (chdir(home + 5) < 0) { + perror("Failed to change home directory for daemon"); + return -1; + } + + for (i = 0; btvirt_table[i]; i++) { + struct stat st; + + if (!stat(btvirt_table[i], &st)) { + btvirt = btvirt_table[i]; + break; + } + } + + if (!btvirt) { + fprintf(stderr, "Failed to locate btvirt binary\n"); + return -1; + } + + printf("Using %s\n", btvirt); + + argv[0] = (char *) btvirt; + argv[1] = "-l"; + argv[2] = NULL; + + printf("Starting Emulator\n"); + + pid = fork(); + if (pid < 0) { + perror("Failed to fork new process"); + return -1; + } + + if (pid == 0) { + execve(argv[0], argv, envp); + exit(EXIT_SUCCESS); + } + + printf("Emulator process %d created\n", pid); + + return pid; +} + static void run_command(char *cmdname, char *home) { char *argv[9], *envp[3]; int pos = 0, idx = 0; int serial_fd; - pid_t pid, dbus_pid, daemon_pid, monitor_pid; + pid_t pid, dbus_pid, daemon_pid, monitor_pid, emulator_pid; if (num_devs) { const char *node = "/dev/ttyS1"; @@ -635,6 +694,11 @@ else monitor_pid = -1; + if (start_emulator) + emulator_pid = start_btvirt(home); + else + emulator_pid = -1; + start_next: if (run_auto) { if (chdir(home + 5) < 0) { @@ -657,25 +721,7 @@ argv[0] = (char *) test_table[idx]; argv[1] = "-q"; argv[2] = NULL; - } else { - while (1) { - char *ptr; - - ptr = strchr(cmdname, ' '); - if (!ptr) { - argv[pos++] = cmdname; - break; - } - - *ptr = '\0'; - argv[pos++] = cmdname; - if (pos > 8) - break; - - cmdname = ptr + 1; - } - - argv[pos] = NULL; + cmdname = NULL; } pos = 0; @@ -684,7 +730,7 @@ envp[pos++] = home; envp[pos] = NULL; - printf("Running command %s\n", argv[0]); + printf("Running command %s\n", cmdname ? cmdname : argv[0]); pid = fork(); if (pid < 0) { @@ -699,7 +745,11 @@ perror("Failed to change directory"); } - execve(argv[0], argv, envp); + if (!cmdname) + execve(argv[0], argv, envp); + else + execl("/bin/sh", "sh", "-c", cmdname, NULL); + exit(EXIT_SUCCESS); } @@ -735,6 +785,11 @@ daemon_pid = -1; } + if (corpse == emulator_pid) { + printf("Bluetooth emulator terminated\n"); + emulator_pid = -1; + } + if (corpse == monitor_pid) { printf("Bluetooth monitor terminated\n"); monitor_pid = -1; @@ -755,6 +810,9 @@ if (dbus_pid > 0) kill(dbus_pid, SIGTERM); + if (emulator_pid > 0) + kill(dbus_pid, SIGTERM); + if (monitor_pid > 0) kill(monitor_pid, SIGTERM); @@ -822,6 +880,12 @@ start_monitor = true; } + ptr = strstr(cmdline, "TESTEMULATOR=1"); + if (ptr) { + printf("Emulator requested\n"); + start_emulator = true; + } + ptr = strstr(cmdline, "TESTHOME="); if (ptr) { home = ptr + 4; @@ -842,6 +906,7 @@ "\t-a, --auto Find tests and run them\n" "\t-d, --dbus Start D-Bus daemon\n" "\t-m, --monitor Start btmon\n" + "\t-l, --emulator Start btvirt\n" "\t-u, --unix [path] Provide serial device\n" "\t-q, --qemu QEMU binary\n" "\t-k, --kernel Kernel image (bzImage)\n" @@ -853,6 +918,7 @@ { "auto", no_argument, NULL, 'a' }, { "unix", no_argument, NULL, 'u' }, { "dbus", no_argument, NULL, 'd' }, + { "emulator", no_argument, NULL, 'l' }, { "monitor", no_argument, NULL, 'm' }, { "qemu", required_argument, NULL, 'q' }, { "kernel", required_argument, NULL, 'k' }, @@ -875,7 +941,8 @@ for (;;) { int opt; - opt = getopt_long(argc, argv, "audmq:k:vh", main_options, NULL); + opt = getopt_long(argc, argv, "audlmq:k:vh", main_options, + NULL); if (opt < 0) break; @@ -889,6 +956,9 @@ case 'd': start_dbus = true; break; + case 'l': + start_emulator = true; + break; case 'm': start_monitor = true; break; diff -Nru bluez-5.63/unit/test-avctp.c bluez-5.64/unit/test-avctp.c --- bluez-5.63/unit/test-avctp.c 2021-02-22 20:27:00.000000000 +0000 +++ bluez-5.64/unit/test-avctp.c 2022-03-16 15:06:20.000000000 +0000 @@ -53,7 +53,7 @@ #define raw_pdu(args...) \ { \ .valid = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -64,7 +64,7 @@ }; \ static struct test_data data; \ data.test_name = g_strdup(name); \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ tester_add(name, &data, NULL, function, NULL); \ } while (0) diff -Nru bluez-5.63/unit/test-avdtp.c bluez-5.64/unit/test-avdtp.c --- bluez-5.63/unit/test-avdtp.c 2021-10-13 18:38:35.000000000 +0000 +++ bluez-5.64/unit/test-avdtp.c 2022-03-16 15:06:20.000000000 +0000 @@ -48,7 +48,7 @@ #define raw_pdu(args...) \ { \ .valid = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -56,7 +56,7 @@ { \ .valid = true, \ .fragmented = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -67,7 +67,7 @@ }; \ static struct test_data data; \ data.test_name = g_strdup(name); \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ tester_add(name, &data, NULL, function, NULL); \ } while (0) diff -Nru bluez-5.63/unit/test-avrcp.c bluez-5.64/unit/test-avrcp.c --- bluez-5.63/unit/test-avrcp.c 2021-02-22 20:27:00.000000000 +0000 +++ bluez-5.64/unit/test-avrcp.c 2022-03-16 15:06:20.000000000 +0000 @@ -61,7 +61,7 @@ #define raw_pdu(args...) \ { \ .valid = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -69,7 +69,7 @@ { \ .valid = true, \ .browse = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -77,7 +77,7 @@ { \ .valid = true, \ .fragmented = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -85,7 +85,7 @@ { \ .valid = true, \ .continuing = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -96,7 +96,7 @@ }; \ static struct test_data data; \ data.test_name = g_strdup(name); \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ tester_add(name, &data, NULL, function, NULL); \ } while (0) diff -Nru bluez-5.63/unit/test-gatt.c bluez-5.64/unit/test-gatt.c --- bluez-5.63/unit/test-gatt.c 2021-06-13 19:56:37.000000000 +0000 +++ bluez-5.64/unit/test-gatt.c 2022-03-16 15:06:20.000000000 +0000 @@ -73,7 +73,7 @@ #define raw_pdu(args...) \ { \ .valid = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -94,7 +94,7 @@ data.uuid = bt_uuid; \ data.step = test_step; \ data.source_db = db; \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ tester_add(name, &data, NULL, function, NULL); \ } while (0) diff -Nru bluez-5.63/unit/test-hfp.c bluez-5.64/unit/test-hfp.c --- bluez-5.63/unit/test-hfp.c 2021-02-22 20:27:00.000000000 +0000 +++ bluez-5.64/unit/test-hfp.c 2022-03-16 15:06:20.000000000 +0000 @@ -17,6 +17,7 @@ #include #include "src/shared/hfp.h" #include "src/shared/tester.h" +#include "src/shared/util.h" struct context { guint watch_id; @@ -50,7 +51,7 @@ #define raw_pdu(args...) \ { \ .valid = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } @@ -62,7 +63,7 @@ #define type_pdu(cmd_type, args...) \ { \ .valid = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ .type = cmd_type, \ } @@ -70,7 +71,7 @@ #define frg_pdu(args...) \ { \ .valid = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ .fragmented = true, \ } @@ -82,7 +83,7 @@ }; \ static struct test_data data; \ data.test_name = g_strdup(name); \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ data.result_func = result_function; \ tester_add(name, &data, NULL, function, NULL); \ data.test_handler = test_handler; \ @@ -96,7 +97,7 @@ }; \ static struct test_data data; \ data.test_name = g_strdup(name); \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ data.hf_result_func = result_func; \ data.response_func = response_function; \ tester_add(name, &data, NULL, function, NULL); \ diff -Nru bluez-5.63/unit/test-hog.c bluez-5.64/unit/test-hog.c --- bluez-5.63/unit/test-hog.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/unit/test-hog.c 2022-03-16 15:06:20.000000000 +0000 @@ -59,24 +59,24 @@ #define raw_pdu(args...) \ { \ .valid = true, \ - .data = g_memdup(data(args), sizeof(data(args))), \ + .data = util_memdup(data(args), sizeof(data(args))), \ .size = sizeof(data(args)), \ } -#define false_pdu() \ -{ \ - .valid = false, \ +#define false_pdu() \ +{ \ + .valid = false, \ } -#define define_test(name, function, args...) \ - do { \ - const struct test_pdu pdus[] = { \ - args, { } \ - }; \ - static struct test_data data; \ - data.test_name = g_strdup(name); \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ - tester_add(name, &data, NULL, function, NULL); \ +#define define_test(name, function, args...) \ + do { \ + const struct test_pdu pdus[] = { \ + args, { } \ + }; \ + static struct test_data data; \ + data.test_name = g_strdup(name); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus));\ + tester_add(name, &data, NULL, function, NULL); \ } while (0) static gboolean context_quit(gpointer user_data) diff -Nru bluez-5.63/unit/test-sdp.c bluez-5.64/unit/test-sdp.c --- bluez-5.63/unit/test-sdp.c 2022-01-05 21:53:58.000000000 +0000 +++ bluez-5.64/unit/test-sdp.c 2022-03-16 15:06:20.000000000 +0000 @@ -47,14 +47,16 @@ #define raw_pdu(args...) \ { \ .valid = true, \ - .raw_data = g_memdup(raw_data(args), sizeof(raw_data(args))), \ + .raw_data = util_memdup(raw_data(args), \ + sizeof(raw_data(args))), \ .raw_size = sizeof(raw_data(args)), \ } #define raw_pdu_cont(cont, args...) \ { \ .valid = true, \ - .raw_data = g_memdup(raw_data(args), sizeof(raw_data(args))), \ + .raw_data = util_memdup(raw_data(args), \ + sizeof(raw_data(args))), \ .raw_size = sizeof(raw_data(args)), \ .cont_len = cont, \ } @@ -66,7 +68,7 @@ }; \ static struct test_data data; \ data.mtu = _mtu; \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ tester_add(name, &data, NULL, test_sdp, NULL); \ } while (0) @@ -92,7 +94,7 @@ #define define_test_de_attr(name, input, exp) \ do { \ static struct test_data_de data; \ - data.input_data = g_memdup(input, sizeof(input)); \ + data.input_data = util_memdup(input, sizeof(input)); \ data.input_size = sizeof(input); \ data.expected = exp; \ tester_add("/sdp/DE/ATTR/" name, &data, NULL, \ diff -Nru bluez-5.63/unit/test-uhid.c bluez-5.64/unit/test-uhid.c --- bluez-5.63/unit/test-uhid.c 2021-02-22 20:27:00.000000000 +0000 +++ bluez-5.64/unit/test-uhid.c 2022-03-16 15:06:20.000000000 +0000 @@ -61,7 +61,7 @@ }; \ static struct test_data data; \ data.test_name = g_strdup(name); \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ + data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ tester_add(name, &data, NULL, function, NULL); \ } while (0)