diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..a3a54d1a1b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: [pull_request] + +jobs: + ci: + runs-on: ubuntu-latest + name: CI for Pull Request + steps: + - name: Checkout the source code + uses: actions/checkout@v3 + with: + path: src/src + + - name: CI + uses: tedd-an/bzcafe@main + with: + task: ci + base_folder: src + space: user + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + patchwork_user: ${{ secrets.PATCHWORK_USER }} + diff --git a/.github/workflows/code_scan.yml b/.github/workflows/code_scan.yml new file mode 100644 index 0000000000..181d08c32d --- /dev/null +++ b/.github/workflows/code_scan.yml @@ -0,0 +1,26 @@ +name: Code Scan + +on: + schedule: + - cron: "40 7 * * FRI" + +jobs: + code-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout the source + uses: actions/checkout@v2 + with: + fetch-depth: 0 + path: src + - name: Code Scan + uses: BluezTestBot/action-code-scan@main + with: + src_path: src + github_token: ${{ secrets.GITHUB_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + - uses: actions/upload-artifact@v2 + with: + name: scan_report + path: scan_report.tar.gz + diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 0000000000..d935cca9fa --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,43 @@ +name: Sync + +on: + schedule: + - cron: "*/30 * * * *" + +jobs: + sync_repo: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: master + + - name: Sync Repo + uses: tedd-an/bzcafe@main + with: + task: sync + upstream_repo: 'https://git.kernel.org/pub/scm/bluetooth/bluez.git' + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Cleanup PR + uses: tedd-an/bzcafe@main + with: + task: cleanup + github_token: ${{ secrets.ACTION_TOKEN }} + + sync_patchwork: + needs: sync_repo + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Sync Patchwork + uses: tedd-an/bzcafe@main + with: + task: patchwork + space: user + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + patchwork_user: ${{ secrets.PATCHWORK_USER }} + diff --git a/btio/btio.c b/btio/btio.c index 7ea17c7754..14f2b700e3 100644 --- a/btio/btio.c +++ b/btio/btio.c @@ -1649,6 +1649,27 @@ static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args) return TRUE; } +static bool get_bc_sid(int sock, uint8_t *sid, GError **err) +{ + struct { + struct sockaddr_iso iso; + struct sockaddr_iso_bc bc; + } addr; + socklen_t olen; + + olen = sizeof(addr); + memset(&addr, 0, olen); + if (getpeername(sock, (void *)&addr, &olen) < 0 || + olen != sizeof(addr)) { + ERROR_FAILED(err, "getpeername", errno); + return false; + } + + *sid = addr.iso.iso_bc->bc_sid; + + return true; +} + static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) { BtIOOption opt = opt1; @@ -1657,6 +1678,7 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) struct bt_iso_base base; socklen_t len; uint32_t phy; + uint8_t bc_sid; len = sizeof(qos); memset(&qos, 0, len); @@ -1721,6 +1743,12 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) case BT_IO_OPT_BASE: *(va_arg(args, struct bt_iso_base *)) = base; break; + case BT_IO_OPT_ISO_BC_SID: + if (!get_bc_sid(sock, &bc_sid, err)) + return FALSE; + + *(va_arg(args, uint8_t *)) = bc_sid; + break; case BT_IO_OPT_HANDLE: case BT_IO_OPT_CLASS: case BT_IO_OPT_DEFER_TIMEOUT: @@ -1736,7 +1764,6 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) case BT_IO_OPT_FLUSHABLE: case BT_IO_OPT_PRIORITY: case BT_IO_OPT_VOICE: - case BT_IO_OPT_ISO_BC_SID: case BT_IO_OPT_ISO_BC_NUM_BIS: case BT_IO_OPT_ISO_BC_BIS: case BT_IO_OPT_INVALID: diff --git a/emulator/btdev.c b/emulator/btdev.c index 7e4cb93935..76bae5ea1a 100644 --- a/emulator/btdev.c +++ b/emulator/btdev.c @@ -105,12 +105,14 @@ struct le_ext_adv { uint8_t scan_data_len; unsigned int broadcast_id; unsigned int timeout_id; + uint8_t sid; }; struct le_per_adv { struct btdev *dev; uint8_t addr_type; uint8_t addr[6]; + uint8_t sid; uint16_t sync_handle; }; @@ -4923,6 +4925,7 @@ static int cmd_set_ext_adv_params(struct btdev *dev, const void *data, ext_adv->direct_addr_type = cmd->peer_addr_type; memcpy(ext_adv->direct_addr, cmd->peer_addr, 6); ext_adv->filter_policy = cmd->filter_policy; + ext_adv->sid = cmd->sid; rsp.status = BT_HCI_ERR_SUCCESS; rsp.tx_power = 0; @@ -5019,6 +5022,7 @@ static void send_ext_adv(struct btdev *btdev, const struct btdev *remote, /* Right now we dont care about phy in adv report */ meta_event.lear.primary_phy = 0x01; meta_event.lear.secondary_phy = 0x01; + meta_event.lear.sid = ext_adv->sid; /* Scan or advertising response */ if (is_scan_rsp) { @@ -5420,17 +5424,32 @@ static bool match_dev(const void *data, const void *match_data) per_adv->addr_type); } +static bool match_sid(const void *data, const void *match_data) +{ + const struct le_ext_adv *ext_adv = data; + uint8_t sid = PTR_TO_UINT(match_data); + + return ext_adv->sid == sid; +} + 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 le_per_adv *per_adv; + struct le_ext_adv *ext_adv; uint16_t sync_handle = SYNC_HANDLE; per_adv = queue_find(dev->le_per_adv, match_dev, remote); if (!per_adv) return; + /* Match SID */ + ext_adv = queue_find(remote->le_ext_adv, match_sid, + UINT_TO_PTR(per_adv->sid)); + if (!ext_adv) + return; + memset(&ev, 0, sizeof(ev)); ev.status = status; @@ -5701,8 +5720,8 @@ static int cmd_ext_create_conn_complete(struct btdev *dev, const void *data, return 0; } -static struct le_per_adv *le_per_adv_new(struct btdev *btdev, - uint8_t addr_type, const uint8_t *addr) +static struct le_per_adv *le_per_adv_new(struct btdev *btdev, uint8_t addr_type, + const uint8_t *addr, uint8_t sid) { struct le_per_adv *per_adv; @@ -5711,6 +5730,7 @@ static struct le_per_adv *le_per_adv_new(struct btdev *btdev, per_adv->dev = btdev; per_adv->addr_type = addr_type; memcpy(per_adv->addr, addr, 6); + per_adv->sid = sid; per_adv->sync_handle = INV_HANDLE; /* Add to queue */ @@ -5728,8 +5748,14 @@ static int cmd_pa_create_sync(struct btdev *dev, const void *data, uint8_t len) uint8_t status = BT_HCI_ERR_SUCCESS; struct le_per_adv *per_adv; + if (cmd->sid > 0x0f) { + cmd_status(dev, BT_HCI_ERR_INVALID_PARAMETERS, + BT_HCI_CMD_LE_PA_CREATE_SYNC); + return 0; + } + /* Create new train */ - per_adv = le_per_adv_new(dev, cmd->addr_type, cmd->addr); + per_adv = le_per_adv_new(dev, cmd->addr_type, cmd->addr, cmd->sid); if (!per_adv) status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c index fd9b751cc1..88d1705859 100644 --- a/profiles/audio/bap.c +++ b/profiles/audio/bap.c @@ -74,6 +74,7 @@ struct bap_setup { unsigned int io_id; bool recreate; bool cig_active; + uint8_t sid; struct iovec *caps; struct iovec *metadata; unsigned int id; @@ -1053,8 +1054,9 @@ static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data) } static void create_stream_for_bis(struct bap_data *bap_data, - struct bt_bap_pac *lpac, struct bt_bap_qos *qos, - struct iovec *caps, struct iovec *meta, char *path) + struct bt_bap_pac *lpac, uint8_t sid, + struct bt_bap_qos *qos, struct iovec *caps, + struct iovec *meta, char *path) { struct bap_setup *setup; @@ -1072,6 +1074,7 @@ static void create_stream_for_bis(struct bap_data *bap_data, setup->stream = bt_bap_stream_new(bap_data->bap, lpac, NULL, &setup->qos, caps); + setup->sid = sid; bt_bap_stream_set_user_data(setup->stream, path); bt_bap_stream_config(setup->stream, &setup->qos, caps, NULL, NULL); @@ -1079,29 +1082,27 @@ static void create_stream_for_bis(struct bap_data *bap_data, NULL, NULL); } -static void bis_handler(uint8_t bis, uint8_t sgrp, struct iovec *caps, - struct iovec *meta, struct bt_bap_qos *qos, void *user_data) +static void bis_handler(uint8_t sid, uint8_t bis, uint8_t sgrp, + struct iovec *caps, struct iovec *meta, + struct bt_bap_qos *qos, void *user_data) { struct bap_data *data = user_data; struct bt_bap_pac *lpac; char *path; - bt_bap_bis_probe(data->bap, bis, sgrp, caps, meta, qos); + bt_bap_bis_probe(data->bap, sid, bis, sgrp, caps, meta, qos); /* Check if this BIS matches any local PAC */ - bt_bap_verify_bis(data->bap, bis, - caps, &lpac); + bt_bap_verify_bis(data->bap, bis, caps, &lpac); if (!lpac) return; - if (asprintf(&path, "%s/bis%d", - device_get_path(data->device), - bis) < 0) + if (asprintf(&path, "%s/sid%d/bis%d", device_get_path(data->device), + sid, bis) < 0) return; - create_stream_for_bis(data, lpac, qos, - caps, meta, path); + create_stream_for_bis(data, lpac, sid, qos, caps, meta, path); } static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond, @@ -1113,12 +1114,14 @@ static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond, struct bt_iso_qos qos; struct iovec iov; struct bt_bap_qos bap_qos = {0}; + uint8_t sid; DBG("BIG Info received"); bt_io_get(io, &err, BT_IO_OPT_BASE, &base, BT_IO_OPT_QOS, &qos, + BT_IO_OPT_ISO_BC_SID, &sid, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); @@ -1147,7 +1150,7 @@ static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond, /* Create BAP QoS structure */ bt_bap_iso_qos_to_bap_qos(&qos, &bap_qos); - bt_bap_parse_base(&iov, &bap_qos, bap_debug, bis_handler, data); + bt_bap_parse_base(sid, &iov, &bap_qos, bap_debug, bis_handler, data); util_iov_free(bap_qos.bcast.bcode, 1); @@ -2813,6 +2816,7 @@ static void bap_detached(struct bt_bap *bap, void *user_data) static int pa_sync(struct bap_data *data) { GError *err = NULL; + uint8_t sid = 0xff; if (data->listen_io) { DBG("Already probed"); @@ -2833,6 +2837,7 @@ static int pa_sync(struct bap_data *data) btd_device_get_bdaddr_type(data->device), BT_IO_OPT_MODE, BT_IO_MODE_ISO, BT_IO_OPT_QOS, &bap_sink_pa_qos, + BT_IO_OPT_ISO_BC_SID, sid, BT_IO_OPT_INVALID); if (!data->listen_io) { error("%s", err->message); @@ -2939,6 +2944,7 @@ static void pa_and_big_sync(struct bap_setup *setup) btd_device_get_bdaddr_type(bap_data->device), BT_IO_OPT_MODE, BT_IO_MODE_ISO, BT_IO_OPT_QOS, &bap_sink_pa_qos, + BT_IO_OPT_ISO_BC_SID, setup->sid, BT_IO_OPT_INVALID); if (!bap_data->listen_io) { error("%s", err->message); diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c index c36f432776..46ac0f4894 100644 --- a/profiles/audio/bass.c +++ b/profiles/audio/bass.c @@ -141,8 +141,9 @@ static struct bass_data *bass_data_new(struct btd_device *device); static void bass_data_add(struct bass_data *data); static void bass_data_remove(struct bass_data *data); -static void bis_probe(uint8_t bis, uint8_t sgrp, struct iovec *caps, - struct iovec *meta, struct bt_bap_qos *qos, void *user_data); +static void bis_probe(uint8_t sid, uint8_t bis, uint8_t sgrp, + struct iovec *caps, struct iovec *meta, + struct bt_bap_qos *qos, void *user_data); static void bis_remove(struct bt_bap *bap, void *user_data); @@ -482,8 +483,9 @@ static void bass_add_bis(struct bass_setup *setup) setup_configure_stream(setup); } -static void bis_handler(uint8_t bis, uint8_t sgrp, struct iovec *caps, - struct iovec *meta, struct bt_bap_qos *qos, void *user_data) +static void bis_handler(uint8_t sid, uint8_t bis, uint8_t sgrp, + struct iovec *caps, struct iovec *meta, + struct bt_bap_qos *qos, void *user_data) { struct bass_delegator *dg = user_data; struct bt_bap_pac *lpac; @@ -526,12 +528,14 @@ static gboolean big_info_cb(GIOChannel *io, GIOCondition cond, struct bt_iso_qos qos; struct iovec iov; struct bt_bap_qos bap_qos = {0}; + uint8_t sid; dg->io_id = 0; bt_io_get(io, &err, BT_IO_OPT_BASE, &base, BT_IO_OPT_QOS, &qos, + BT_IO_OPT_ISO_BC_SID, &sid, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); @@ -545,7 +549,7 @@ static gboolean big_info_cb(GIOChannel *io, GIOCondition cond, /* Create BAP QoS structure */ bt_bap_iso_qos_to_bap_qos(&qos, &bap_qos); - bt_bap_parse_base(&iov, &bap_qos, bass_debug, bis_handler, dg); + bt_bap_parse_base(sid, &iov, &bap_qos, bass_debug, bis_handler, dg); util_iov_free(bap_qos.bcast.bcode, 1); @@ -1107,8 +1111,9 @@ static struct bass_assistant *assistant_new(struct btd_adapter *adapter, return assistant; } -static void bis_probe(uint8_t bis, uint8_t sgrp, struct iovec *caps, - struct iovec *meta, struct bt_bap_qos *qos, void *user_data) +static void bis_probe(uint8_t sid, uint8_t bis, uint8_t sgrp, + struct iovec *caps, struct iovec *meta, + struct bt_bap_qos *qos, void *user_data) { struct btd_device *device = user_data; const struct queue_entry *entry; diff --git a/src/shared/bap.c b/src/shared/bap.c index 3758aa0000..3a11cb0820 100644 --- a/src/shared/bap.c +++ b/src/shared/bap.c @@ -5721,8 +5721,9 @@ bool bt_bap_bis_cb_unregister(struct bt_bap *bap, unsigned int id) return false; } -void bt_bap_bis_probe(struct bt_bap *bap, uint8_t bis, uint8_t sgrp, - struct iovec *caps, struct iovec *meta, struct bt_bap_qos *qos) +void bt_bap_bis_probe(struct bt_bap *bap, uint8_t sid, uint8_t bis, + uint8_t sgrp, struct iovec *caps, struct iovec *meta, + struct bt_bap_qos *qos) { const struct queue_entry *entry; @@ -5737,7 +5738,7 @@ void bt_bap_bis_probe(struct bt_bap *bap, uint8_t bis, uint8_t sgrp, entry = entry->next; if (cb->probe) - cb->probe(bis, sgrp, caps, meta, qos, cb->data); + cb->probe(sid, bis, sgrp, caps, meta, qos, cb->data); } bt_bap_unref(bap); @@ -7341,7 +7342,7 @@ void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index, } -bool bt_bap_parse_base(struct iovec *iov, +bool bt_bap_parse_base(uint8_t sid, struct iovec *iov, struct bt_bap_qos *qos, util_debug_func_t func, bt_bap_bis_func_t handler, @@ -7452,7 +7453,7 @@ bool bt_bap_parse_base(struct iovec *iov, if (!bis_cc) continue; - handler(bis_index, idx, bis_cc, &meta, + handler(sid, bis_index, idx, bis_cc, &meta, qos, user_data); util_iov_free(bis_cc, 1); diff --git a/src/shared/bap.h b/src/shared/bap.h index dfd1699807..d10581428e 100644 --- a/src/shared/bap.h +++ b/src/shared/bap.h @@ -40,9 +40,9 @@ typedef void (*bt_bap_stream_func_t)(struct bt_bap_stream *stream, void *user_data); typedef void (*bt_bap_func_t)(struct bt_bap *bap, void *user_data); -typedef void (*bt_bap_bis_func_t)(uint8_t bis, uint8_t sgrp, - struct iovec *caps, struct iovec *meta, - struct bt_bap_qos *qos, void *user_data); +typedef void (*bt_bap_bis_func_t)(uint8_t sid, uint8_t bis, uint8_t sgrp, + struct iovec *caps, struct iovec *meta, + struct bt_bap_qos *qos, void *user_data); typedef void (*bt_bap_bcode_reply_t)(void *user_data, int err); @@ -271,7 +271,7 @@ void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index, struct iovec *caps, struct bt_bap_pac **lpac); -bool bt_bap_parse_base(struct iovec *base, +bool bt_bap_parse_base(uint8_t sid, struct iovec *base, struct bt_bap_qos *qos, util_debug_func_t func, bt_bap_bis_func_t handler, @@ -284,8 +284,9 @@ unsigned int bt_bap_bis_cb_register(struct bt_bap *bap, bt_bap_destroy_func_t destroy); bool bt_bap_bis_cb_unregister(struct bt_bap *bap, unsigned int id); -void bt_bap_bis_probe(struct bt_bap *bap, uint8_t bis, uint8_t sgrp, - struct iovec *caps, struct iovec *meta, struct bt_bap_qos *qos); +void bt_bap_bis_probe(struct bt_bap *bap, uint8_t sid, uint8_t bis, + uint8_t sgrp, struct iovec *caps, struct iovec *meta, + struct bt_bap_qos *qos); void bt_bap_bis_remove(struct bt_bap *bap); void bt_bap_req_bcode(struct bt_bap_stream *stream, diff --git a/tools/iso-tester.c b/tools/iso-tester.c index 350775fddc..63f6951e3d 100644 --- a/tools/iso-tester.c +++ b/tools/iso-tester.c @@ -495,6 +495,7 @@ struct iso_client_data { uint8_t pkt_status; const uint8_t *base; size_t base_len; + uint8_t sid; bool listen_bind; bool pa_bind; bool big; @@ -1419,6 +1420,16 @@ static const struct iso_client_data bcast_16_2_1_recv2 = { .big = true, }; +static const struct iso_client_data bcast_16_2_1_recv_sid = { + .qos = QOS_IN_16_2_1, + .expect_err = 0, + .recv = &send_16_2_1, + .bcast = true, + .server = true, + .big = true, + .sid = 0xff, +}; + static const struct iso_client_data bcast_enc_16_2_1_recv = { .qos = QOS_IN_ENC_16_2_1, .expect_err = 0, @@ -2564,6 +2575,40 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, } } + if (isodata->sid == 0xff) { + struct { + struct sockaddr_iso iso; + struct sockaddr_iso_bc bc; + } addr; + socklen_t olen; + + olen = sizeof(addr); + + memset(&addr, 0, olen); + if (getpeername(sk, (void *)&addr, &olen) < 0) { + tester_warn("getpeername: %s (%d)", + strerror(errno), errno); + data->step = 0; + tester_test_failed(); + return FALSE; + } + + if (olen != sizeof(addr)) { + tester_warn("getpeername: olen %d != %zu sizeof(addr)", + olen, sizeof(addr)); + data->step = 0; + tester_test_failed(); + return FALSE; + } + + if (addr.bc.bc_sid > 0x0f) { + tester_warn("Invalid SID: %d", addr.bc.bc_sid); + data->step = 0; + tester_test_failed(); + return FALSE; + } + } + len = sizeof(sk_err); if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0) @@ -2843,6 +2888,7 @@ static int listen_iso_sock(struct test_data *data, uint8_t num) bacpy(&addr->iso_bc->bc_bdaddr, (void *) dst); addr->iso_bc->bc_bdaddr_type = BDADDR_LE_PUBLIC; + addr->iso_bc->bc_sid = isodata->sid; if (!isodata->defer || isodata->listen_bind) { addr->iso_bc->bc_num_bis = 1; @@ -3817,6 +3863,10 @@ int main(int argc, char *argv[]) test_iso("ISO Broadcaster Receiver - Success", &bcast_16_2_1_recv, setup_powered, test_bcast_recv); + test_iso("ISO Broadcaster Receiver SID 0xff - Success", + &bcast_16_2_1_recv_sid, + setup_powered, + test_bcast_recv); test_iso2("ISO Broadcaster Receiver2 - Success", &bcast_16_2_1_recv2, setup_powered, test_bcast_recv2);