diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000000..60d318f805ff1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + checks: write + pull-requests: write + +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: bluez/action-ci@main + with: + task: ci + base_folder: src + space: kernel + github_token: ${{ secrets.GITHUB_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + patchwork_user: ${{ secrets.PATCHWORK_USER }} + diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 0000000000000..5e95af92ab1ab --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,44 @@ +name: Sync + +on: + schedule: + - cron: "*/5 * * * *" + +jobs: + sync_repo: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: master + + - name: Sync Repo + uses: bluez/action-ci@main + with: + task: sync + workflow: workflow + upstream_repo: 'https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git' + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Cleanup PR + uses: bluez/action-ci@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: bluez/action-ci@main + with: + task: patchwork + workflow: workflow + space: kernel + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + patchwork_user: ${{ secrets.PATCHWORK_USER }} diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c12cd6873f65e..d7a2df82ff387 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -769,7 +769,6 @@ struct hci_conn { struct delayed_work disc_work; struct delayed_work auto_accept_work; struct delayed_work idle_work; - struct delayed_work le_conn_timeout; struct device dev; struct dentry *debugfs; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8de98af2fb581..cfcc5d055d5a8 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -697,48 +697,6 @@ static void hci_conn_auto_accept(struct work_struct *work) &conn->dst); } -static void le_disable_advertising(struct hci_dev *hdev) -{ - if (ext_adv_capable(hdev)) { - struct hci_cp_le_set_ext_adv_enable cp; - - cp.enable = 0x00; - cp.num_of_sets = 0x00; - - hci_send_cmd(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE, sizeof(cp), - &cp); - } else { - u8 enable = 0x00; - hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), - &enable); - } -} - -static void le_conn_timeout(struct work_struct *work) -{ - struct hci_conn *conn = container_of(work, struct hci_conn, - le_conn_timeout.work); - struct hci_dev *hdev = conn->hdev; - - BT_DBG(""); - - /* We could end up here due to having done directed advertising, - * so clean up the state if necessary. This should however only - * happen with broken hardware or if low duty cycle was used - * (which doesn't have a timeout of its own). - */ - if (conn->role == HCI_ROLE_SLAVE) { - /* Disable LE Advertising */ - le_disable_advertising(hdev); - hci_dev_lock(hdev); - hci_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); - hci_dev_unlock(hdev); - return; - } - - hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM); -} - struct iso_list_data { union { u8 cig; @@ -1131,7 +1089,6 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); INIT_DELAYED_WORK(&conn->auto_accept_work, hci_conn_auto_accept); INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle); - INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout); spin_lock_init(&conn->proto_lock); @@ -1279,8 +1236,6 @@ void hci_conn_del(struct hci_conn *conn) hdev->acl_cnt += conn->sent; break; case LE_LINK: - cancel_delayed_work(&conn->le_conn_timeout); - if (hdev->le_pkts) { if (!hci_conn_num(hdev, LE_LINK) || hdev->le_cnt + conn->sent > hdev->le_pkts) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2f5e21ff97529..b0af5635f831f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1595,22 +1595,10 @@ static u8 hci_cc_le_set_adv_enable(struct hci_dev *hdev, void *data, hci_dev_lock(hdev); - /* If we're doing connection initiation as peripheral. Set a - * timeout in case something goes wrong. - */ - if (*sent) { - struct hci_conn *conn; - + if (*sent) hci_dev_set_flag(hdev, HCI_LE_ADV); - - conn = hci_lookup_le_connect(hdev); - if (conn) - queue_delayed_work(hdev->workqueue, - &conn->le_conn_timeout, - conn->conn_timeout); - } else { + else hci_dev_clear_flag(hdev, HCI_LE_ADV); - } hci_dev_unlock(hdev); @@ -1642,20 +1630,12 @@ static u8 hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev, void *data, adv = hci_find_adv_instance(hdev, set->handle); if (cp->enable) { - struct hci_conn *conn; - hci_dev_set_flag(hdev, HCI_LE_ADV); if (adv) adv->enabled = true; else if (!set->handle) hci_dev_set_flag(hdev, HCI_LE_ADV_0); - - conn = hci_lookup_le_connect(hdev); - if (conn) - queue_delayed_work(hdev->workqueue, - &conn->le_conn_timeout, - conn->conn_timeout); } else { if (cp->num_of_sets) { if (adv) @@ -1676,6 +1656,7 @@ static u8 hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev, void *data, list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) adv->enabled = false; + hci_dev_clear_flag(hdev, HCI_LE_ADV_0); } hci_dev_clear_flag(hdev, HCI_LE_ADV); @@ -5764,10 +5745,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, hci_store_wake_reason(hdev, bdaddr, bdaddr_type); /* Advertising stops when a connection is created. On a failed - * connection it keeps running, so leave the state bit alone. + * connection it keeps running, so leave the state bits alone. */ - if (!status) + if (!status) { hci_dev_clear_flag(hdev, HCI_LE_ADV); + hci_dev_clear_flag(hdev, HCI_LE_ADV_0); + } /* Check for existing connection: * @@ -5814,8 +5797,6 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, &conn->init_addr_type); } } - } else { - cancel_delayed_work(&conn->le_conn_timeout); } /* The HCI_LE_Connection_Complete event is only sent once per connection. diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 7150037a864b4..7e092e827ab82 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -6639,6 +6639,19 @@ static bool conn_use_rpa(struct hci_conn *conn) return hci_dev_test_flag(hdev, HCI_PRIVACY); } +static int hci_le_wait_directed_adv_complete_sync(struct hci_dev *hdev, + struct hci_conn *conn) +{ + /* LE Set (Extended) Advertising Enable returns a command complete + * event, so it cannot wait for LE Connection Complete. + */ + return __hci_cmd_sync_status_sk(hdev, HCI_OP_NOP, 0, NULL, + use_enhanced_conn_complete(hdev) ? + HCI_EV_LE_ENHANCED_CONN_COMPLETE : + HCI_EV_LE_CONN_COMPLETE, + conn->conn_timeout, NULL); +} + static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev, struct hci_conn *conn) { @@ -6704,7 +6717,11 @@ static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev, return err; } - return hci_enable_ext_advertising_sync(hdev, 0x00); + err = hci_enable_ext_advertising_sync(hdev, 0x00); + if (err) + return err; + + return hci_le_wait_directed_adv_complete_sync(hdev, conn); } static int hci_le_directed_advertising_sync(struct hci_dev *hdev, @@ -6755,8 +6772,13 @@ static int hci_le_directed_advertising_sync(struct hci_dev *hdev, enable = 0x01; - return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE, - sizeof(enable), &enable, HCI_CMD_TIMEOUT); + status = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE, + sizeof(enable), &enable, + HCI_CMD_TIMEOUT); + if (status) + return status; + + return hci_le_wait_directed_adv_complete_sync(hdev, conn); } static void set_ext_conn_params(struct hci_conn *conn, @@ -6860,6 +6882,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) /* Pause advertising while doing directed advertising. */ hci_pause_advertising_sync(hdev); + set_bit(HCI_CONN_CREATE, &conn->flags); err = hci_le_directed_advertising_sync(hdev, conn); goto done; } @@ -6946,7 +6969,9 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) done: clear_bit(HCI_CONN_CREATE, &conn->flags); - if (err == -ETIMEDOUT) + if (err && conn->role == HCI_ROLE_SLAVE) + hci_disable_advertising_sync(hdev); + else if (err == -ETIMEDOUT) hci_le_connect_cancel_sync(hdev, conn, 0x00); /* Re-enable advertising after the connection attempt is finished. */ @@ -7283,9 +7308,8 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) if (conn != hci_lookup_le_connect(hdev)) goto unlock; - /* Flush to make sure we send create conn cancel command if needed */ - flush_delayed_work(&conn->le_conn_timeout); - hci_conn_failed(conn, bt_status(err)); + hci_conn_failed(conn, conn->role == HCI_ROLE_SLAVE && err == -ETIMEDOUT ? + HCI_ERROR_ADVERTISING_TIMEOUT : bt_status(err)); unlock: hci_dev_unlock(hdev);