xref: /btstack/test/l2cap-cbm/l2cap_cbm_test.cpp (revision 5058b333e7143eb74d7b34b0384e82050a25734e)
1 
2 // hal_cpu
3 #include "hal_cpu.h"
4 void hal_cpu_disable_irqs(void){}
5 void hal_cpu_enable_irqs(void){}
6 void hal_cpu_enable_irqs_and_sleep(void){}
7 
8 // mock_sm.c
9 #include "ble/sm.h"
10 void sm_add_event_handler(btstack_packet_callback_registration_t * callback_handler){}
11 void sm_request_pairing(hci_con_handle_t con_handle){}
12 
13 // mock_hci_transport.h
14 #include "hci_transport.h"
15 void mock_hci_transport_receive_packet(uint8_t packet_type, uint8_t * packet, uint16_t size);
16 const hci_transport_t * mock_hci_transport_mock_get_instance(void);
17 
18 // mock_hci_transport.c
19 #include <stddef.h>
20 static uint8_t  mock_hci_transport_outgoing_packet_buffer[HCI_ACL_PAYLOAD_SIZE];
21 static uint16_t mock_hci_transport_outgoing_packet_size;
22 static uint8_t  mock_hci_transport_outgoing_packet_type;
23 
24 static void (*mock_hci_transport_packet_handler)(uint8_t packet_type, uint8_t * packet, uint16_t size);
25 static void mock_hci_transport_register_packet_handler(void (*packet_handler)(uint8_t packet_type, uint8_t * packet, uint16_t size)){
26     mock_hci_transport_packet_handler = packet_handler;
27 }
28 static int mock_hci_transport_send_packet(uint8_t packet_type, uint8_t *packet, int size){
29     mock_hci_transport_outgoing_packet_type = packet_type;
30     mock_hci_transport_outgoing_packet_size = size;
31     memcpy(mock_hci_transport_outgoing_packet_buffer, packet, size);
32     return 0;
33 }
34 const hci_transport_t * mock_hci_transport_mock_get_instance(void){
35     static hci_transport_t mock_hci_transport = {
36         /*  .transport.name                          = */  "mock",
37         /*  .transport.init                          = */  NULL,
38         /*  .transport.open                          = */  NULL,
39         /*  .transport.close                         = */  NULL,
40         /*  .transport.register_packet_handler       = */  &mock_hci_transport_register_packet_handler,
41         /*  .transport.can_send_packet_now           = */  NULL,
42         /*  .transport.send_packet                   = */  &mock_hci_transport_send_packet,
43         /*  .transport.set_baudrate                  = */  NULL,
44     };
45     return &mock_hci_transport;
46 }
47 void mock_hci_transport_receive_packet(uint8_t packet_type, const uint8_t * packet, uint16_t size){
48     (*mock_hci_transport_packet_handler)(packet_type, (uint8_t *) packet, size);
49 }
50 
51 //
52 
53 #include <stdint.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #include "CppUTest/TestHarness.h"
59 #include "CppUTest/CommandLineTestRunner.h"
60 #include "CppUTestExt/MockSupport.h"
61 
62 #include "hci_dump.h"
63 #include "btstack_debug.h"
64 #include "l2cap.h"
65 #include "btstack_memory.h"
66 #include "btstack_run_loop_embedded.h"
67 #include "hci_dump_posix_stdout.h"
68 #include "btstack_event.h"
69 
70 #define TEST_PACKET_SIZE       100
71 #define HCI_CON_HANDLE_TEST_LE 0x0005
72 #define TEST_PSM 0x1001
73 
74 static bool l2cap_channel_accept_incoming;
75 static uint16_t initial_credits = L2CAP_LE_AUTOMATIC_CREDITS;
76 static uint8_t data_channel_buffer[TEST_PACKET_SIZE];
77 static uint16_t l2cap_cid;
78 static bool l2cap_channel_opened;
79 static btstack_packet_callback_registration_t l2cap_event_callback_registration;
80 
81 // l2cap fuzz api
82 extern "C" void l2cap_setup_test_channels_fuzz(void);
83 extern "C" void l2cap_free_channels_fuzz(void);
84 extern "C" l2cap_channel_t * l2cap_get_dynamic_channel_fuzz(void);
85 
86 // l2cap random public function
87 extern "C"  void l2cap_finalize_channel_close(l2cap_channel_t * channel);
88 
89 const uint8_t le_data_channel_conn_request_1[] = {
90         0x05, 0x20, 0x12, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x14, 0x01, 0x0a, 0x00, 0x01, 0x10, 0x41, 0x00,
91         0x64, 0x00, 0x30, 0x00, 0xff, 0xff
92 };
93 
94 const uint8_t le_data_channel_invalid_pdu[] = {
95         0x05, 0x20, 0x12, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x11, 0x01, 0x0a, 0x00, 0x01, 0x10, 0x41, 0x00,
96         0x64, 0x00, 0x30, 0x00, 0xff, 0xff
97 };
98 
99 const uint8_t le_data_channel_conn_response_1[] = {
100         0x05, 0x20, 0x12, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x15, 0x01, 0x0a, 0x00, 0x41, 0x00, 0x64, 0x00,
101         0x30, 0x00, 0xff, 0xff, 0x00, 0x00
102 };
103 
104 const uint8_t le_data_channel_data_1[] = {
105         0x05, 0x20, 0x04, 0x00, 0x00, 0x00, 0x41, 0x00
106 };
107 
108 static void fix_boundary_flags(uint8_t * packet, uint16_t size){
109     uint8_t acl_flags = packet[1] >> 4;
110     if (acl_flags == 0){
111         acl_flags = 2;  // first fragment
112     }
113     packet[1] = (packet[1] & 0x0f) | (acl_flags << 4);
114 }
115 
116 static void print_acl(const char * name, const uint8_t * packet, uint16_t size){
117     printf("const uint8_t %s[] = {", name);
118     uint16_t i;
119     for (i=0;i<size;i++){
120         if (i != 0){
121             printf(", ");
122         }
123         if ((i % 16) == 0){
124             printf("\n    ");
125         }
126         printf("0x%02x", packet[i]);
127     }
128     printf("\n};\n");
129 }
130 
131 static void l2cap_channel_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
132     UNUSED(channel);
133     UNUSED(size);
134     uint16_t cid;
135     switch (packet_type) {
136         case HCI_EVENT_PACKET:
137             switch (hci_event_packet_get_type(packet)) {
138                 case L2CAP_EVENT_CBM_INCOMING_CONNECTION:
139                     cid = l2cap_event_cbm_incoming_connection_get_local_cid(packet);
140                     if (l2cap_channel_accept_incoming){
141                         l2cap_cbm_accept_connection(cid, data_channel_buffer, sizeof(data_channel_buffer), initial_credits);
142                     } else {
143                         l2cap_cbm_decline_connection(cid, L2CAP_CBM_CONNECTION_RESULT_NO_RESOURCES_AVAILABLE);
144                     }
145                     break;
146                 case L2CAP_EVENT_CBM_CHANNEL_OPENED:
147                     l2cap_channel_opened = true;
148                     break;
149                 default:
150                     break;
151             }
152             break;
153         default:
154             break;
155     }
156 }
157 
158 TEST_GROUP(L2CAP_CHANNELS){
159     const hci_transport_t * hci_transport;
160     void setup(void){
161         btstack_memory_init();
162         btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
163         hci_transport = mock_hci_transport_mock_get_instance();
164         hci_init(hci_transport, NULL);
165         l2cap_init();
166         l2cap_event_callback_registration.callback = &l2cap_channel_packet_handler;
167         l2cap_add_event_handler(&l2cap_event_callback_registration);
168         l2cap_register_fixed_channel(&l2cap_channel_packet_handler, L2CAP_CID_ATTRIBUTE_PROTOCOL);
169         hci_dump_init(hci_dump_posix_stdout_get_instance());
170         l2cap_channel_opened = false;
171     }
172     void teardown(void){
173         l2cap_remove_event_handler(&l2cap_event_callback_registration);
174         l2cap_deinit();
175         hci_deinit();
176         btstack_memory_deinit();
177         btstack_run_loop_deinit();
178     }
179 };
180 
181 TEST(L2CAP_CHANNELS, fixed_channel){
182     hci_setup_test_connections_fuzz();
183     // channel does not exist
184     l2cap_request_can_send_fix_channel_now_event(HCI_CON_HANDLE_TEST_LE, 0x003f);
185     // att
186     l2cap_request_can_send_fix_channel_now_event(HCI_CON_HANDLE_TEST_LE, L2CAP_CID_ATTRIBUTE_PROTOCOL);
187     //
188     (void) l2cap_can_send_fixed_channel_packet_now(HCI_CON_HANDLE_TEST_LE, L2CAP_CID_ATTRIBUTE_PROTOCOL);
189     // packet buffer not reserved
190     log_info("ignore error in next line (calling .. without reserving buffer first");
191     l2cap_send_prepared_connectionless(HCI_CON_HANDLE_TEST_LE, L2CAP_CID_ATTRIBUTE_PROTOCOL, 5);
192     // packet buffer reserved
193     l2cap_reserve_packet_buffer();
194     l2cap_send_prepared_connectionless(HCI_CON_HANDLE_TEST_LE, L2CAP_CID_ATTRIBUTE_PROTOCOL, 5);
195     //
196     l2cap_send_connectionless(HCI_CON_HANDLE_TEST_LE, L2CAP_CID_ATTRIBUTE_PROTOCOL, (uint8_t *) "hallo", 5);
197 }
198 
199 TEST(L2CAP_CHANNELS, some_functions){
200     hci_setup_test_connections_fuzz();
201     l2cap_reserve_packet_buffer();
202     (void) l2cap_get_outgoing_buffer();
203     l2cap_release_packet_buffer();
204     l2cap_set_max_le_mtu(30);
205     l2cap_set_max_le_mtu(30);
206     l2cap_cbm_unregister_service(TEST_PSM);
207     l2cap_cbm_accept_connection(0X01, NULL, 0, 0);
208     l2cap_cbm_decline_connection(0x01, L2CAP_CBM_CONNECTION_RESULT_NO_RESOURCES_AVAILABLE);
209     l2cap_cbm_available_credits(0x01);
210     l2cap_disconnect(0x01);
211 
212     uint16_t credits = 10;
213     uint16_t mtu = 23;
214     uint8_t  buffer[10];
215     uint16_t out_local_cid;
216 
217     l2cap_le_register_service(&l2cap_channel_packet_handler, TEST_PSM, LEVEL_2);
218     l2cap_le_unregister_service(TEST_PSM);
219     l2cap_le_accept_connection(0X01, buffer, mtu, credits);
220     l2cap_le_decline_connection(0X01);
221     l2cap_le_create_channel(&l2cap_channel_packet_handler, HCI_CON_HANDLE_TEST_LE, TEST_PSM, buffer, mtu, credits, LEVEL_2, &out_local_cid);
222     l2cap_le_provide_credits(0X01, credits);
223     l2cap_le_can_send_now(0X01);
224     l2cap_le_request_can_send_now_event(0X01);
225     l2cap_le_send_data(0X01, (const uint8_t * )buffer, sizeof(buffer));
226     l2cap_le_disconnect(0X01);
227 }
228 
229 TEST(L2CAP_CHANNELS, outgoing_no_connection){
230     l2cap_cbm_create_channel(&l2cap_channel_packet_handler, HCI_CON_HANDLE_TEST_LE, TEST_PSM, data_channel_buffer,
231                             sizeof(data_channel_buffer), L2CAP_LE_AUTOMATIC_CREDITS, LEVEL_0, &l2cap_cid);
232 }
233 
234 TEST(L2CAP_CHANNELS, outgoing_security_1){
235     hci_setup_test_connections_fuzz();
236     l2cap_cbm_create_channel(&l2cap_channel_packet_handler, HCI_CON_HANDLE_TEST_LE, TEST_PSM, data_channel_buffer,
237                             sizeof(data_channel_buffer), L2CAP_LE_AUTOMATIC_CREDITS, LEVEL_2, NULL);
238     l2cap_cbm_create_channel(&l2cap_channel_packet_handler, HCI_CON_HANDLE_TEST_LE, TEST_PSM, data_channel_buffer,
239                             sizeof(data_channel_buffer), L2CAP_LE_AUTOMATIC_CREDITS, LEVEL_2, &l2cap_cid);
240 }
241 
242 TEST(L2CAP_CHANNELS, outgoing_1){
243     hci_setup_test_connections_fuzz();
244     l2cap_cbm_create_channel(&l2cap_channel_packet_handler, HCI_CON_HANDLE_TEST_LE, TEST_PSM, data_channel_buffer,
245                             sizeof(data_channel_buffer), L2CAP_LE_AUTOMATIC_CREDITS, LEVEL_0, &l2cap_cid);
246     // fix_boundary_flags(mock_hci_transport_outgoing_packet_buffer, mock_hci_transport_outgoing_packet_size);
247     // print_acl("le_data_channel_conn_request_1", mock_hci_transport_outgoing_packet_buffer, mock_hci_transport_outgoing_packet_size);
248     // simulate conn response
249     mock_hci_transport_receive_packet(HCI_ACL_DATA_PACKET, le_data_channel_conn_response_1, sizeof(le_data_channel_conn_response_1));
250     CHECK(l2cap_channel_opened);
251     CHECK(hci_number_free_acl_slots_for_handle(HCI_CON_HANDLE_TEST_LE) > 0);
252     bool can_send_now = l2cap_can_send_packet_now(l2cap_cid);
253     CHECK(can_send_now);
254     l2cap_request_can_send_now_event(l2cap_cid);
255     CHECK(hci_number_free_acl_slots_for_handle(HCI_CON_HANDLE_TEST_LE) > 0);
256     l2cap_send(l2cap_cid, (uint8_t *) "hallo", 5);
257     // CHECK(hci_number_free_acl_slots_for_handle(HCI_CON_HANDLE_TEST) > 0);
258     // fix_boundary_flags(mock_hci_transport_outgoing_packet_buffer, mock_hci_transport_outgoing_packet_size);
259     // print_acl("le_data_channel_data_1", mock_hci_transport_outgoing_packet_buffer, mock_hci_transport_outgoing_packet_size);
260     // simulate data
261     mock_hci_transport_receive_packet(HCI_ACL_DATA_PACKET, le_data_channel_data_1, sizeof(le_data_channel_data_1));
262     l2cap_disconnect(l2cap_cid);
263 }
264 
265 TEST(L2CAP_CHANNELS, incoming_1){
266     hci_setup_test_connections_fuzz();
267     l2cap_cbm_register_service(&l2cap_channel_packet_handler, TEST_PSM, LEVEL_0);
268     // simulate conn request
269     l2cap_channel_accept_incoming = true;
270     mock_hci_transport_receive_packet(HCI_ACL_DATA_PACKET, le_data_channel_conn_request_1, sizeof(le_data_channel_conn_request_1));
271     // fix_boundary_flags(mock_hci_transport_outgoing_packet_buffer, mock_hci_transport_outgoing_packet_size);
272     // print_acl("le_data_channel_conn_response_1", mock_hci_transport_outgoing_packet_buffer, mock_hci_transport_outgoing_packet_size);
273     // TODO: verify data
274     l2cap_cbm_unregister_service(TEST_PSM);
275 }
276 
277 TEST(L2CAP_CHANNELS, incoming_2){
278     hci_setup_test_connections_fuzz();
279     l2cap_cbm_register_service(&l2cap_channel_packet_handler, TEST_PSM, LEVEL_2);
280     // simulate conn request
281     l2cap_channel_accept_incoming = true;
282     mock_hci_transport_receive_packet(HCI_ACL_DATA_PACKET, le_data_channel_conn_request_1, sizeof(le_data_channel_conn_request_1));
283 }
284 
285 TEST(L2CAP_CHANNELS, incoming_3){
286     hci_setup_test_connections_fuzz();
287     l2cap_cbm_register_service(&l2cap_channel_packet_handler, TEST_PSM, LEVEL_0);
288     // simulate conn request
289     l2cap_channel_accept_incoming = true;
290     mock_hci_transport_receive_packet(HCI_ACL_DATA_PACKET, le_data_channel_invalid_pdu, sizeof(le_data_channel_invalid_pdu));
291 }
292 
293 TEST(L2CAP_CHANNELS, incoming_decline){
294     hci_setup_test_connections_fuzz();
295     l2cap_cbm_register_service(&l2cap_channel_packet_handler, TEST_PSM, LEVEL_0);
296     // simulate conn request
297     l2cap_channel_accept_incoming = false;
298     mock_hci_transport_receive_packet(HCI_ACL_DATA_PACKET, le_data_channel_conn_request_1, sizeof(le_data_channel_conn_request_1));
299     // fix_boundary_flags(mock_hci_transport_outgoing_packet_buffer, mock_hci_transport_outgoing_packet_size);
300     // print_acl("le_data_channel_conn_response_1", mock_hci_transport_outgoing_packet_buffer, mock_hci_transport_outgoing_packet_size);
301     // TODO: verify data
302 }
303 TEST(L2CAP_CHANNELS, fuzz) {
304     l2cap_setup_test_channels_fuzz();
305     l2cap_channel_t * channel = l2cap_get_dynamic_channel_fuzz();
306     l2cap_free_channels_fuzz();
307     l2cap_get_dynamic_channel_fuzz();
308 }
309 
310 int main (int argc, const char * argv[]){
311     return CommandLineTestRunner::RunAllTests(argc, argv);
312 }
313