15deb0bb6SMatthias Ringwald /*
25deb0bb6SMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH
35deb0bb6SMatthias Ringwald *
45deb0bb6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
55deb0bb6SMatthias Ringwald * modification, are permitted provided that the following conditions
65deb0bb6SMatthias Ringwald * are met:
75deb0bb6SMatthias Ringwald *
85deb0bb6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
95deb0bb6SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
105deb0bb6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
115deb0bb6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
125deb0bb6SMatthias Ringwald * documentation and/or other materials provided with the distribution.
135deb0bb6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
145deb0bb6SMatthias Ringwald * contributors may be used to endorse or promote products derived
155deb0bb6SMatthias Ringwald * from this software without specific prior written permission.
165deb0bb6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
175deb0bb6SMatthias Ringwald * personal benefit and not for any commercial purpose or for
185deb0bb6SMatthias Ringwald * monetary gain.
195deb0bb6SMatthias Ringwald *
205deb0bb6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
215deb0bb6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
225deb0bb6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
235deb0bb6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
245deb0bb6SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
255deb0bb6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
265deb0bb6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
275deb0bb6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
285deb0bb6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
295deb0bb6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
305deb0bb6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
315deb0bb6SMatthias Ringwald * SUCH DAMAGE.
325deb0bb6SMatthias Ringwald *
335deb0bb6SMatthias Ringwald * Please inquire about commercial licensing options at
345deb0bb6SMatthias Ringwald * [email protected]
355deb0bb6SMatthias Ringwald *
365deb0bb6SMatthias Ringwald */
375deb0bb6SMatthias Ringwald
385deb0bb6SMatthias Ringwald #define BTSTACK_FILE__ "broadcast_audio_scan_service_server.c"
395deb0bb6SMatthias Ringwald
405deb0bb6SMatthias Ringwald #include <stdio.h>
415deb0bb6SMatthias Ringwald
425deb0bb6SMatthias Ringwald #include "ble/att_db.h"
435deb0bb6SMatthias Ringwald #include "ble/att_server.h"
445deb0bb6SMatthias Ringwald #include "bluetooth_gatt.h"
455deb0bb6SMatthias Ringwald #include "btstack_debug.h"
465deb0bb6SMatthias Ringwald #include "btstack_defines.h"
475deb0bb6SMatthias Ringwald #include "btstack_event.h"
485deb0bb6SMatthias Ringwald #include "btstack_util.h"
495deb0bb6SMatthias Ringwald
505deb0bb6SMatthias Ringwald #include "le-audio/gatt-service/broadcast_audio_scan_service_util.h"
515deb0bb6SMatthias Ringwald #include "le-audio/le_audio.h"
525deb0bb6SMatthias Ringwald #include "le-audio/le_audio_util.h"
535deb0bb6SMatthias Ringwald
545deb0bb6SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
555deb0bb6SMatthias Ringwald #include <stdio.h>
565deb0bb6SMatthias Ringwald #endif
575deb0bb6SMatthias Ringwald
585deb0bb6SMatthias Ringwald // offset gives position into fully serialized bass record
bass_util_source_data_header_virtual_memcpy(const bass_source_data_t * data,uint16_t * source_offset,uint16_t buffer_offset,uint8_t * buffer,uint16_t buffer_size)596e96f7c7SMatthias Ringwald uint16_t bass_util_source_data_header_virtual_memcpy(const bass_source_data_t * data, uint16_t *source_offset, uint16_t buffer_offset, uint8_t * buffer, uint16_t buffer_size){
605deb0bb6SMatthias Ringwald uint16_t stored_bytes = 0;
615deb0bb6SMatthias Ringwald uint8_t field_data[16];
625deb0bb6SMatthias Ringwald
635deb0bb6SMatthias Ringwald field_data[0] = (uint8_t)data->address_type;
6454461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, *source_offset, buffer, buffer_size,
6554461c80SMatthias Ringwald buffer_offset);
665deb0bb6SMatthias Ringwald (*source_offset)++;
675deb0bb6SMatthias Ringwald
685deb0bb6SMatthias Ringwald reverse_bd_addr(data->address, &field_data[0]);
6954461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 6, *source_offset, buffer, buffer_size,
7054461c80SMatthias Ringwald buffer_offset);
715deb0bb6SMatthias Ringwald (*source_offset) += 6;
725deb0bb6SMatthias Ringwald
735deb0bb6SMatthias Ringwald field_data[0] = data->adv_sid;
7454461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, *source_offset, buffer, buffer_size,
7554461c80SMatthias Ringwald buffer_offset);
765deb0bb6SMatthias Ringwald (*source_offset)++;
775deb0bb6SMatthias Ringwald
785deb0bb6SMatthias Ringwald little_endian_store_24(field_data, 0, data->broadcast_id);
7954461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 3, *source_offset, buffer, buffer_size,
8054461c80SMatthias Ringwald buffer_offset);
815deb0bb6SMatthias Ringwald (*source_offset) += 3;
825deb0bb6SMatthias Ringwald
835deb0bb6SMatthias Ringwald return stored_bytes;
845deb0bb6SMatthias Ringwald }
855deb0bb6SMatthias Ringwald
865deb0bb6SMatthias Ringwald // offset gives position into fully serialized bass record
875deb0bb6SMatthias Ringwald uint16_t
bass_util_source_data_subgroups_virtual_memcpy(const bass_source_data_t * data,bool use_state_fields,uint16_t * source_offset,uint16_t buffer_offset,uint8_t * buffer,uint16_t buffer_size)886e96f7c7SMatthias Ringwald bass_util_source_data_subgroups_virtual_memcpy(const bass_source_data_t *data, bool use_state_fields, uint16_t *source_offset,
895deb0bb6SMatthias Ringwald uint16_t buffer_offset, uint8_t *buffer, uint16_t buffer_size) {
905deb0bb6SMatthias Ringwald uint16_t stored_bytes = 0;
915deb0bb6SMatthias Ringwald uint8_t field_data[16];
925deb0bb6SMatthias Ringwald
935deb0bb6SMatthias Ringwald field_data[0] = (uint8_t)data->subgroups_num;
9454461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, *source_offset, buffer, buffer_size,
9554461c80SMatthias Ringwald buffer_offset);
965deb0bb6SMatthias Ringwald (*source_offset)++;
975deb0bb6SMatthias Ringwald
985deb0bb6SMatthias Ringwald uint8_t i;
995deb0bb6SMatthias Ringwald for (i = 0; i < data->subgroups_num; i++){
1005deb0bb6SMatthias Ringwald bass_subgroup_t subgroup = data->subgroups[i];
1015deb0bb6SMatthias Ringwald
1025deb0bb6SMatthias Ringwald if (use_state_fields) {
1035deb0bb6SMatthias Ringwald little_endian_store_32(field_data, 0, subgroup.bis_sync_state);
1045deb0bb6SMatthias Ringwald } else {
1055deb0bb6SMatthias Ringwald little_endian_store_32(field_data, 0, subgroup.bis_sync);
1065deb0bb6SMatthias Ringwald }
10754461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 4, *source_offset, buffer, buffer_size,
10854461c80SMatthias Ringwald buffer_offset);
1095deb0bb6SMatthias Ringwald (*source_offset) += 4;
11054461c80SMatthias Ringwald stored_bytes += le_audio_util_metadata_virtual_memcpy(&subgroup.metadata, subgroup.metadata_length,
11154461c80SMatthias Ringwald source_offset, buffer, buffer_size, buffer_offset);
1125deb0bb6SMatthias Ringwald }
1135deb0bb6SMatthias Ringwald return stored_bytes;
1145deb0bb6SMatthias Ringwald }
1155deb0bb6SMatthias Ringwald
bass_util_pa_sync_state_and_subgroups_in_valid_range(const uint8_t * buffer,uint16_t buffer_size)11618f91b9cSMatthias Ringwald bool bass_util_pa_sync_state_and_subgroups_in_valid_range(const uint8_t *buffer, uint16_t buffer_size){
1175deb0bb6SMatthias Ringwald uint8_t pos = 0;
1185deb0bb6SMatthias Ringwald // pa_sync_state
1195deb0bb6SMatthias Ringwald uint8_t pa_sync_state = buffer[pos++];
1205deb0bb6SMatthias Ringwald if (pa_sync_state >= (uint8_t)LE_AUDIO_PA_SYNC_STATE_RFU){
1215deb0bb6SMatthias Ringwald log_info("Unexpected pa_sync_state 0x%02X", pa_sync_state);
1225deb0bb6SMatthias Ringwald return false;
1235deb0bb6SMatthias Ringwald }
1245deb0bb6SMatthias Ringwald
1255deb0bb6SMatthias Ringwald // pa_interval
1265deb0bb6SMatthias Ringwald pos += 2;
1275deb0bb6SMatthias Ringwald uint8_t num_subgroups = buffer[pos++];
1285deb0bb6SMatthias Ringwald if (num_subgroups > BASS_SUBGROUPS_MAX_NUM){
1295deb0bb6SMatthias Ringwald log_info("Number of subgroups %u exceedes maximum %u", num_subgroups, BASS_SUBGROUPS_MAX_NUM);
1305deb0bb6SMatthias Ringwald return false;
1315deb0bb6SMatthias Ringwald }
1325deb0bb6SMatthias Ringwald
1335deb0bb6SMatthias Ringwald // If a BIS_Sync parameter value is not 0xFFFFFFFF for a subgroup,
1345deb0bb6SMatthias Ringwald // and if a BIS_index value written by a client is set to a value of 0b1 in more than one subgroup,
1355deb0bb6SMatthias Ringwald // the server shall ignore the operation.
1365deb0bb6SMatthias Ringwald uint8_t i;
1375deb0bb6SMatthias Ringwald uint32_t mask_total = 0;
1385deb0bb6SMatthias Ringwald for (i = 0; i < num_subgroups; i++){
1395deb0bb6SMatthias Ringwald // bis_sync
1405deb0bb6SMatthias Ringwald uint32_t bis_sync = little_endian_read_32(buffer, pos);
1415deb0bb6SMatthias Ringwald pos += 4;
1425deb0bb6SMatthias Ringwald
1435deb0bb6SMatthias Ringwald if (bis_sync != 0xFFFFFFFF){
1445deb0bb6SMatthias Ringwald uint32_t mask_add = mask_total + ~bis_sync;
1455deb0bb6SMatthias Ringwald uint32_t mask_or = mask_total | ~bis_sync;
1465deb0bb6SMatthias Ringwald if (mask_add != mask_or){
1475deb0bb6SMatthias Ringwald // not disjunct
1485deb0bb6SMatthias Ringwald return false;
1495deb0bb6SMatthias Ringwald }
1505deb0bb6SMatthias Ringwald mask_total = mask_add;
1515deb0bb6SMatthias Ringwald }
1525deb0bb6SMatthias Ringwald
1535deb0bb6SMatthias Ringwald // check if we can read metadata_length
1545deb0bb6SMatthias Ringwald if (pos >= buffer_size){
1555deb0bb6SMatthias Ringwald log_info("Metadata length not specified, subgroup %u", i);
1565deb0bb6SMatthias Ringwald return false;
1575deb0bb6SMatthias Ringwald }
1585deb0bb6SMatthias Ringwald
1595deb0bb6SMatthias Ringwald uint8_t metadata_length = buffer[pos++];
1605deb0bb6SMatthias Ringwald
1615deb0bb6SMatthias Ringwald if ((buffer_size - pos) < metadata_length){
1625deb0bb6SMatthias Ringwald log_info("Metadata length %u exceedes remaining buffer %u", metadata_length, buffer_size - pos);
1635deb0bb6SMatthias Ringwald return false;
1645deb0bb6SMatthias Ringwald }
1655deb0bb6SMatthias Ringwald // metadata
1665deb0bb6SMatthias Ringwald pos += metadata_length;
1675deb0bb6SMatthias Ringwald }
1685deb0bb6SMatthias Ringwald
1695deb0bb6SMatthias Ringwald return (pos == buffer_size);
1705deb0bb6SMatthias Ringwald }
1715deb0bb6SMatthias Ringwald
bass_util_source_buffer_in_valid_range(const uint8_t * buffer,uint16_t buffer_size)17218f91b9cSMatthias Ringwald bool bass_util_source_buffer_in_valid_range(const uint8_t *buffer, uint16_t buffer_size){
1735deb0bb6SMatthias Ringwald if (buffer_size < 15){
1745deb0bb6SMatthias Ringwald log_info("Add Source opcode, buffer too small");
1755deb0bb6SMatthias Ringwald return false;
1765deb0bb6SMatthias Ringwald }
1775deb0bb6SMatthias Ringwald
1785deb0bb6SMatthias Ringwald uint8_t pos = 0;
1795deb0bb6SMatthias Ringwald // addr type
1805deb0bb6SMatthias Ringwald uint8_t adv_type = buffer[pos++];
1815deb0bb6SMatthias Ringwald if (adv_type > (uint8_t)BD_ADDR_TYPE_LE_RANDOM){
1825deb0bb6SMatthias Ringwald log_info("Unexpected adv_type 0x%02X", adv_type);
1835deb0bb6SMatthias Ringwald return false;
1845deb0bb6SMatthias Ringwald }
1855deb0bb6SMatthias Ringwald
1865deb0bb6SMatthias Ringwald // address
1875deb0bb6SMatthias Ringwald pos += 6;
1885deb0bb6SMatthias Ringwald
1895deb0bb6SMatthias Ringwald // advertising_sid Range: 0x00-0x0F
1905deb0bb6SMatthias Ringwald uint8_t advertising_sid = buffer[pos++];
1915deb0bb6SMatthias Ringwald if (advertising_sid > 0x0F){
1925deb0bb6SMatthias Ringwald log_info("Advertising sid out of range 0x%02X", advertising_sid);
1935deb0bb6SMatthias Ringwald return false;
1945deb0bb6SMatthias Ringwald }
1955deb0bb6SMatthias Ringwald
1965deb0bb6SMatthias Ringwald // broadcast_id
1975deb0bb6SMatthias Ringwald pos += 3;
1985deb0bb6SMatthias Ringwald return bass_util_pa_sync_state_and_subgroups_in_valid_range(buffer+pos, buffer_size-pos);
1995deb0bb6SMatthias Ringwald }
2005deb0bb6SMatthias Ringwald
2015deb0bb6SMatthias Ringwald void
bass_util_pa_info_and_subgroups_parse(const uint8_t * buffer,uint16_t buffer_size,bass_source_data_t * source_data,bool is_broadcast_receive_state)20218f91b9cSMatthias Ringwald bass_util_pa_info_and_subgroups_parse(const uint8_t *buffer, uint16_t buffer_size, bass_source_data_t *source_data,
2035deb0bb6SMatthias Ringwald bool is_broadcast_receive_state) {
2045deb0bb6SMatthias Ringwald UNUSED(buffer_size);
2055deb0bb6SMatthias Ringwald uint8_t pos = 0;
2065deb0bb6SMatthias Ringwald // for Broadcast Receive state, we have BIG_Encryption + Bad_Code, while for Add/Modify we have PA_Interval
2075deb0bb6SMatthias Ringwald if (is_broadcast_receive_state){
2085deb0bb6SMatthias Ringwald source_data->pa_sync_state = (le_audio_pa_sync_state_t)buffer[pos++];
209*5d948380SMatthias Ringwald source_data->big_encryption = (le_audio_big_encryption_t) buffer[pos++];
210*5d948380SMatthias Ringwald if (source_data->big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){
211*5d948380SMatthias Ringwald memcpy(source_data->bad_code, &buffer[pos], 16);
2125deb0bb6SMatthias Ringwald pos += 16;
213*5d948380SMatthias Ringwald } else {
214*5d948380SMatthias Ringwald memset(source_data->bad_code, 0, 16);
2155deb0bb6SMatthias Ringwald }
2165deb0bb6SMatthias Ringwald } else {
2175deb0bb6SMatthias Ringwald source_data->pa_sync = (le_audio_pa_sync_t)buffer[pos++];
2185deb0bb6SMatthias Ringwald source_data->pa_interval = little_endian_read_16(buffer, pos);
2195deb0bb6SMatthias Ringwald pos += 2;
2205deb0bb6SMatthias Ringwald }
2215deb0bb6SMatthias Ringwald
2225deb0bb6SMatthias Ringwald source_data->subgroups_num = buffer[pos++];
2235deb0bb6SMatthias Ringwald uint8_t i;
2245deb0bb6SMatthias Ringwald for (i = 0; i < source_data->subgroups_num; i++){
2255deb0bb6SMatthias Ringwald // bis_sync / state
2265deb0bb6SMatthias Ringwald if (is_broadcast_receive_state){
2275deb0bb6SMatthias Ringwald source_data->subgroups[i].bis_sync_state = little_endian_read_32(buffer, pos);
2285deb0bb6SMatthias Ringwald } else {
2295deb0bb6SMatthias Ringwald source_data->subgroups[i].bis_sync = little_endian_read_32(buffer, pos);
2305deb0bb6SMatthias Ringwald }
2315deb0bb6SMatthias Ringwald pos += 4;
2325deb0bb6SMatthias Ringwald
23354461c80SMatthias Ringwald uint8_t metadata_bytes_read = le_audio_util_metadata_parse(&buffer[pos], buffer_size - pos,
23454461c80SMatthias Ringwald &source_data->subgroups[i].metadata);
2355deb0bb6SMatthias Ringwald source_data->subgroups[i].metadata_length = metadata_bytes_read - 1;
2365deb0bb6SMatthias Ringwald pos += metadata_bytes_read;
2375deb0bb6SMatthias Ringwald }
2385deb0bb6SMatthias Ringwald }
2395deb0bb6SMatthias Ringwald
bass_util_source_data_parse(const uint8_t * buffer,uint16_t buffer_size,bass_source_data_t * source_data,bool is_broadcast_receive_state)24018f91b9cSMatthias Ringwald void bass_util_source_data_parse(const uint8_t *buffer, uint16_t buffer_size, bass_source_data_t *source_data,
2415deb0bb6SMatthias Ringwald bool is_broadcast_receive_state) {
2425deb0bb6SMatthias Ringwald UNUSED(buffer_size);
2435deb0bb6SMatthias Ringwald uint8_t pos = 0;
2445deb0bb6SMatthias Ringwald
2455deb0bb6SMatthias Ringwald source_data->address_type = (bd_addr_type_t)buffer[pos++];
2465deb0bb6SMatthias Ringwald
2475deb0bb6SMatthias Ringwald reverse_bd_addr(&buffer[pos], source_data->address);
2485deb0bb6SMatthias Ringwald pos += 6;
2495deb0bb6SMatthias Ringwald
2505deb0bb6SMatthias Ringwald source_data->adv_sid = buffer[pos++];
2515deb0bb6SMatthias Ringwald
2525deb0bb6SMatthias Ringwald source_data->broadcast_id = little_endian_read_24(buffer, pos);
2535deb0bb6SMatthias Ringwald pos += 3;
2545deb0bb6SMatthias Ringwald
2556e96f7c7SMatthias Ringwald bass_util_pa_info_and_subgroups_parse(buffer + pos, buffer_size - pos, source_data, is_broadcast_receive_state);
2565deb0bb6SMatthias Ringwald }