| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <string.h> |
| #include <errno.h> |
| #include "testutil/testutil.h" |
| #include "nimble/ble.h" |
| #include "host/ble_hs_test.h" |
| #include "host/ble_uuid.h" |
| #include "ble_hs_test_util.h" |
| |
| struct ble_gatt_disc_s_test_svc { |
| uint16_t start_handle; |
| uint16_t end_handle; |
| const ble_uuid_t *uuid; |
| }; |
| |
| #define BLE_GATT_DISC_S_TEST_MAX_SERVICES 256 |
| static struct ble_gatt_svc |
| ble_gatt_disc_s_test_svcs[BLE_GATT_DISC_S_TEST_MAX_SERVICES]; |
| static int ble_gatt_disc_s_test_num_svcs; |
| static int ble_gatt_disc_s_test_rx_complete; |
| |
| static void |
| ble_gatt_disc_s_test_init(void) |
| { |
| ble_hs_test_util_init(); |
| ble_gatt_disc_s_test_num_svcs = 0; |
| ble_gatt_disc_s_test_rx_complete = 0; |
| } |
| |
| static int |
| ble_gatt_disc_s_test_misc_svc_length(struct ble_gatt_disc_s_test_svc *service) |
| { |
| if (service->uuid->type == BLE_UUID_TYPE_16) { |
| return 6; |
| } else { |
| return 20; |
| } |
| } |
| |
| static int |
| ble_gatt_disc_s_test_misc_rx_all_rsp_once( |
| uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) |
| { |
| struct ble_att_read_group_type_rsp rsp; |
| uint8_t buf[1024]; |
| int off; |
| int rc; |
| int i; |
| |
| /* Send the pending ATT Read By Group Type Request. */ |
| |
| rsp.bagp_length = ble_gatt_disc_s_test_misc_svc_length(services); |
| ble_att_read_group_type_rsp_write(buf, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ, |
| &rsp); |
| |
| off = BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ; |
| for (i = 0; ; i++) { |
| if (services[i].start_handle == 0) { |
| /* No more services. */ |
| break; |
| } |
| |
| rc = ble_gatt_disc_s_test_misc_svc_length(services + i); |
| if (rc != rsp.bagp_length) { |
| /* UUID length is changing; Need a separate response. */ |
| break; |
| } |
| |
| if (services[i].uuid->type == BLE_UUID_TYPE_16) { |
| if (off + BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16 > |
| ble_att_mtu(conn_handle)) { |
| |
| /* Can't fit any more entries. */ |
| break; |
| } |
| } else { |
| if (off + BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128 > |
| ble_att_mtu(conn_handle)) { |
| |
| /* Can't fit any more entries. */ |
| break; |
| } |
| } |
| |
| put_le16(buf + off, services[i].start_handle); |
| off += 2; |
| |
| put_le16(buf + off, services[i].end_handle); |
| off += 2; |
| |
| ble_uuid_flat(services[i].uuid, buf + off); |
| off += ble_uuid_length(services[i].uuid); |
| } |
| |
| rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, |
| buf, off); |
| TEST_ASSERT(rc == 0); |
| |
| return i; |
| } |
| |
| static void |
| ble_gatt_disc_s_test_misc_rx_all_rsp( |
| uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) |
| { |
| int count; |
| int idx; |
| |
| idx = 0; |
| while (services[idx].start_handle != 0) { |
| count = ble_gatt_disc_s_test_misc_rx_all_rsp_once(conn_handle, |
| services + idx); |
| idx += count; |
| } |
| |
| if (services[idx - 1].end_handle != 0xffff) { |
| /* Send the pending ATT Request. */ |
| ble_hs_test_util_rx_att_err_rsp(conn_handle, |
| BLE_ATT_OP_READ_GROUP_TYPE_REQ, |
| BLE_ATT_ERR_ATTR_NOT_FOUND, |
| services[idx - 1].start_handle); |
| } |
| } |
| |
| static int |
| ble_gatt_disc_s_test_misc_rx_uuid_rsp_once( |
| uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) |
| { |
| uint8_t buf[1024]; |
| int off; |
| int rc; |
| int i; |
| |
| /* Send the pending ATT Find By Type Value Request. */ |
| |
| buf[0] = BLE_ATT_OP_FIND_TYPE_VALUE_RSP; |
| off = BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ; |
| for (i = 0; ; i++) { |
| if (services[i].start_handle == 0) { |
| /* No more services. */ |
| break; |
| } |
| |
| if (off + BLE_ATT_FIND_TYPE_VALUE_HINFO_BASE_SZ > |
| ble_att_mtu(conn_handle)) { |
| |
| /* Can't fit any more entries. */ |
| break; |
| } |
| |
| put_le16(buf + off, services[i].start_handle); |
| off += 2; |
| |
| put_le16(buf + off, services[i].end_handle); |
| off += 2; |
| } |
| |
| rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, |
| buf, off); |
| TEST_ASSERT(rc == 0); |
| |
| return i; |
| } |
| |
| static void |
| ble_gatt_disc_s_test_misc_rx_uuid_rsp( |
| uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) |
| { |
| int count; |
| int idx; |
| |
| idx = 0; |
| while (services[idx].start_handle != 0) { |
| count = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(conn_handle, |
| services + idx); |
| idx += count; |
| } |
| |
| if (services[idx - 1].end_handle != 0xffff) { |
| /* Send the pending ATT Request. */ |
| ble_hs_test_util_rx_att_err_rsp(conn_handle, |
| BLE_ATT_OP_FIND_TYPE_VALUE_REQ, |
| BLE_ATT_ERR_ATTR_NOT_FOUND, |
| services[idx - 1].start_handle); |
| } |
| } |
| |
| static void |
| ble_gatt_disc_s_test_misc_verify_services( |
| struct ble_gatt_disc_s_test_svc *services) |
| { |
| int i; |
| |
| for (i = 0; services[i].start_handle != 0; i++) { |
| TEST_ASSERT(services[i].start_handle == |
| ble_gatt_disc_s_test_svcs[i].start_handle); |
| TEST_ASSERT(services[i].end_handle == |
| ble_gatt_disc_s_test_svcs[i].end_handle); |
| |
| TEST_ASSERT(ble_uuid_cmp(services[i].uuid, |
| &ble_gatt_disc_s_test_svcs[i].uuid.u) == 0); |
| } |
| |
| TEST_ASSERT(i == ble_gatt_disc_s_test_num_svcs); |
| TEST_ASSERT(ble_gatt_disc_s_test_rx_complete); |
| } |
| |
| static int |
| ble_gatt_disc_s_test_misc_disc_cb(uint16_t conn_handle, |
| const struct ble_gatt_error *error, |
| const struct ble_gatt_svc *service, |
| void *arg) |
| { |
| TEST_ASSERT(error != NULL); |
| TEST_ASSERT(!ble_gatt_disc_s_test_rx_complete); |
| |
| switch (error->status) { |
| case 0: |
| TEST_ASSERT(service != NULL); |
| TEST_ASSERT_FATAL(ble_gatt_disc_s_test_num_svcs < |
| BLE_GATT_DISC_S_TEST_MAX_SERVICES); |
| ble_gatt_disc_s_test_svcs[ble_gatt_disc_s_test_num_svcs++] = *service; |
| break; |
| |
| case BLE_HS_EDONE: |
| TEST_ASSERT(service == NULL); |
| ble_gatt_disc_s_test_rx_complete = 1; |
| break; |
| |
| case BLE_HS_ETIMEOUT: |
| ble_gatt_disc_s_test_rx_complete = 1; |
| break; |
| |
| default: |
| TEST_ASSERT(0); |
| } |
| |
| return 0; |
| } |
| |
| static void |
| ble_gatt_disc_s_test_misc_good_all(struct ble_gatt_disc_s_test_svc *services) |
| { |
| int rc; |
| |
| ble_gatt_disc_s_test_init(); |
| |
| ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), |
| NULL, NULL); |
| |
| rc = ble_gattc_disc_all_svcs(2, ble_gatt_disc_s_test_misc_disc_cb, NULL); |
| TEST_ASSERT(rc == 0); |
| |
| ble_gatt_disc_s_test_misc_rx_all_rsp(2, services); |
| ble_gatt_disc_s_test_misc_verify_services(services); |
| } |
| |
| static void |
| ble_gatt_disc_s_test_misc_good_uuid( |
| struct ble_gatt_disc_s_test_svc *services) |
| { |
| int rc; |
| |
| ble_gatt_disc_s_test_init(); |
| |
| ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), |
| NULL, NULL); |
| |
| rc = ble_gattc_disc_svc_by_uuid(2, services[0].uuid, |
| ble_gatt_disc_s_test_misc_disc_cb, NULL); |
| TEST_ASSERT(rc == 0); |
| |
| ble_hs_test_util_verify_tx_disc_svc_uuid(services[0].uuid); |
| |
| ble_gatt_disc_s_test_misc_rx_uuid_rsp(2, services); |
| ble_gatt_disc_s_test_misc_verify_services(services); |
| } |
| |
| TEST_CASE(ble_gatt_disc_s_test_disc_all) |
| { |
| /*** One 128-bit service. */ |
| ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 0 } |
| }); |
| |
| /*** Two 128-bit services. */ |
| ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 10, 50, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, |
| { 0 } |
| }); |
| |
| /*** Five 128-bit services. */ |
| ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 10, 50, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, |
| { 80, 120, BLE_UUID128_DECLARE(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ), }, |
| { 123, 678, BLE_UUID128_DECLARE(4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ), }, |
| { 751, 999, BLE_UUID128_DECLARE(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ), }, |
| { 0 } |
| }); |
| |
| /*** One 128-bit service, one 16-bit-service. */ |
| ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 6, 7, BLE_UUID16_DECLARE(0x1234) }, |
| { 0 } |
| }); |
| |
| /*** End with handle 0xffff. */ |
| ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 7, 0xffff,BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, |
| { 0 } |
| }); |
| } |
| |
| TEST_CASE(ble_gatt_disc_s_test_disc_uuid) |
| { |
| /*** 128-bit service; one entry. */ |
| ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 0 } |
| }); |
| |
| /*** 128-bit service; two entries. */ |
| ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 8, 43, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 0 } |
| }); |
| |
| /*** 128-bit service; five entries. */ |
| ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 8, 43, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 67, 100, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 102, 103, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 262, 900, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 0 } |
| }); |
| |
| /*** 128-bit service; end with handle 0xffff. */ |
| ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 7, 0xffff,BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 0 } |
| }); |
| |
| /*** 16-bit service; one entry. */ |
| ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID16_DECLARE(0x1234) }, |
| { 0 } |
| }); |
| |
| /*** 16-bit service; two entries. */ |
| ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID16_DECLARE(0x1234) }, |
| { 85, 243, BLE_UUID16_DECLARE(0x1234) }, |
| { 0 } |
| }); |
| |
| /*** 16-bit service; five entries. */ |
| ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID16_DECLARE(0x1234) }, |
| { 85, 243, BLE_UUID16_DECLARE(0x1234) }, |
| { 382, 383, BLE_UUID16_DECLARE(0x1234) }, |
| { 562, 898, BLE_UUID16_DECLARE(0x1234) }, |
| { 902, 984, BLE_UUID16_DECLARE(0x1234) }, |
| { 0 } |
| }); |
| |
| /*** 16-bit service; end with handle 0xffff. */ |
| ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { |
| { 1, 5, BLE_UUID16_DECLARE(0x1234) }, |
| { 9, 0xffff,BLE_UUID16_DECLARE(0x1234) }, |
| { 0 } |
| }); |
| } |
| |
| TEST_CASE(ble_gatt_disc_s_test_oom_all) |
| { |
| struct ble_gatt_disc_s_test_svc svcs[] = { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 6, 10, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, |
| { 0 }, |
| }; |
| |
| struct os_mbuf *oms; |
| int32_t ticks_until; |
| int num_svcs; |
| int rc; |
| |
| ble_gatt_disc_s_test_init(); |
| |
| ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), |
| NULL, NULL); |
| |
| /* Initiate a discover all services procedure. */ |
| rc = ble_gattc_disc_all_svcs(1, ble_gatt_disc_s_test_misc_disc_cb, NULL); |
| TEST_ASSERT_FATAL(rc == 0); |
| |
| /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ |
| oms = ble_hs_test_util_mbuf_alloc_all_but(1); |
| num_svcs = ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs); |
| |
| /* Make sure there are still undiscovered services. */ |
| TEST_ASSERT_FATAL(num_svcs < sizeof svcs / sizeof svcs[0] - 1); |
| |
| /* Ensure no follow-up request got sent. It should not have gotten sent |
| * due to mbuf exhaustion. |
| */ |
| ble_hs_test_util_prev_tx_queue_clear(); |
| TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); |
| |
| /* Verify that we will resume the stalled GATT procedure in one second. */ |
| ticks_until = ble_gattc_timer(); |
| TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); |
| |
| /* Verify the procedure proceeds after mbufs become available. */ |
| rc = os_mbuf_free_chain(oms); |
| TEST_ASSERT_FATAL(rc == 0); |
| os_time_advance(ticks_until); |
| ble_gattc_timer(); |
| |
| /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ |
| oms = ble_hs_test_util_mbuf_alloc_all_but(1); |
| ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs + num_svcs); |
| |
| /* Ensure no follow-up request got sent. It should not have gotten sent |
| * due to mbuf exhaustion. |
| */ |
| ble_hs_test_util_prev_tx_queue_clear(); |
| TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); |
| |
| /* Verify that we will resume the stalled GATT procedure in one second. */ |
| ticks_until = ble_gattc_timer(); |
| TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); |
| |
| rc = os_mbuf_free_chain(oms); |
| TEST_ASSERT_FATAL(rc == 0); |
| os_time_advance(ticks_until); |
| ble_gattc_timer(); |
| |
| ble_hs_test_util_rx_att_err_rsp(1, |
| BLE_ATT_OP_READ_GROUP_TYPE_REQ, |
| BLE_ATT_ERR_ATTR_NOT_FOUND, |
| 1); |
| ble_gatt_disc_s_test_misc_verify_services(svcs); |
| } |
| |
| TEST_CASE(ble_gatt_disc_s_test_oom_uuid) |
| { |
| /* Retrieve enough services to require two transactions. */ |
| struct ble_gatt_disc_s_test_svc svcs[] = { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 6, 10, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 11, 15, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 16, 20, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 21, 25, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 26, 30, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 0 }, |
| }; |
| |
| struct os_mbuf *oms; |
| int32_t ticks_until; |
| int num_svcs; |
| int rc; |
| |
| ble_gatt_disc_s_test_init(); |
| |
| ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), |
| NULL, NULL); |
| |
| /* Initiate a discover all services procedure. */ |
| rc = ble_gattc_disc_svc_by_uuid(1, svcs[0].uuid, |
| ble_gatt_disc_s_test_misc_disc_cb, NULL); |
| TEST_ASSERT_FATAL(rc == 0); |
| |
| /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ |
| oms = ble_hs_test_util_mbuf_alloc_all_but(1); |
| num_svcs = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, svcs); |
| |
| /* Make sure there are still undiscovered services. */ |
| TEST_ASSERT_FATAL(num_svcs < sizeof svcs / sizeof svcs[0] - 1); |
| |
| /* Ensure no follow-up request got sent. It should not have gotten sent |
| * due to mbuf exhaustion. |
| */ |
| ble_hs_test_util_prev_tx_queue_clear(); |
| TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); |
| |
| /* Verify that we will resume the stalled GATT procedure in one second. */ |
| ticks_until = ble_gattc_timer(); |
| TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); |
| |
| /* Verify the procedure proceeds after mbufs become available. */ |
| rc = os_mbuf_free_chain(oms); |
| TEST_ASSERT_FATAL(rc == 0); |
| os_time_advance(ticks_until); |
| ble_gattc_timer(); |
| |
| /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ |
| oms = ble_hs_test_util_mbuf_alloc_all_but(1); |
| ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, svcs + num_svcs); |
| |
| /* Ensure no follow-up request got sent. It should not have gotten sent |
| * due to mbuf exhaustion. |
| */ |
| ble_hs_test_util_prev_tx_queue_clear(); |
| TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); |
| |
| /* Verify that we will resume the stalled GATT procedure in one second. */ |
| ticks_until = ble_gattc_timer(); |
| TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); |
| |
| /* Verify that procedure completes when mbufs are available. */ |
| rc = os_mbuf_free_chain(oms); |
| TEST_ASSERT_FATAL(rc == 0); |
| os_time_advance(ticks_until); |
| ble_gattc_timer(); |
| |
| ble_hs_test_util_rx_att_err_rsp(1, |
| BLE_ATT_OP_READ_GROUP_TYPE_REQ, |
| BLE_ATT_ERR_ATTR_NOT_FOUND, |
| 1); |
| ble_gatt_disc_s_test_misc_verify_services(svcs); |
| } |
| |
| TEST_CASE(ble_gatt_disc_s_test_oom_timeout) |
| { |
| struct ble_gatt_disc_s_test_svc svcs[] = { |
| { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, |
| { 6, 10, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, |
| { 0 }, |
| }; |
| |
| struct os_mbuf *oms_temp; |
| struct os_mbuf *oms; |
| int32_t ticks_until; |
| int rc; |
| int i; |
| |
| ble_gatt_disc_s_test_init(); |
| |
| ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), |
| NULL, NULL); |
| |
| /* Initiate a discover all services procedure. */ |
| rc = ble_gattc_disc_all_svcs(1, ble_gatt_disc_s_test_misc_disc_cb, NULL); |
| TEST_ASSERT_FATAL(rc == 0); |
| |
| /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ |
| oms = ble_hs_test_util_mbuf_alloc_all_but(1); |
| ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs); |
| |
| /* Keep trying to resume for 30 seconds, but never free any mbufs. Verify |
| * procedure eventually times out. |
| */ |
| for (i = 0; i < 30; i++) { |
| /* Ensure no follow-up request got sent. It should not have gotten |
| * sent due to mbuf exhaustion. |
| */ |
| ble_hs_test_util_prev_tx_queue_clear(); |
| TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); |
| |
| oms_temp = ble_hs_test_util_mbuf_alloc_all_but(0); |
| if (oms_temp != NULL) { |
| os_mbuf_concat(oms, oms_temp); |
| } |
| |
| /* Verify that we will resume the stalled GATT procedure in one |
| * second. |
| */ |
| ticks_until = ble_gattc_timer(); |
| TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); |
| |
| os_time_advance(ticks_until); |
| } |
| |
| /* Verify the procedure has timed out. The connection should now be |
| * in the process of being terminated. XXX: Check this. |
| */ |
| ble_hs_test_util_hci_ack_set_disconnect(0); |
| ble_gattc_timer(); |
| |
| ticks_until = ble_gattc_timer(); |
| TEST_ASSERT(ticks_until == BLE_HS_FOREVER); |
| TEST_ASSERT(!ble_gattc_any_jobs()); |
| |
| rc = os_mbuf_free_chain(oms); |
| TEST_ASSERT_FATAL(rc == 0); |
| } |
| |
| TEST_SUITE(ble_gatt_disc_s_test_suite) |
| { |
| tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); |
| |
| ble_gatt_disc_s_test_disc_all(); |
| ble_gatt_disc_s_test_disc_uuid(); |
| ble_gatt_disc_s_test_oom_all(); |
| ble_gatt_disc_s_test_oom_uuid(); |
| ble_gatt_disc_s_test_oom_timeout(); |
| } |
| |
| int |
| ble_gatt_disc_s_test_all(void) |
| { |
| ble_gatt_disc_s_test_suite(); |
| |
| return tu_any_failed; |
| } |