1 /******************************************************************************
2 *
3 * Copyright 2001-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * this file contains the main BNEP functions
22 *
23 ******************************************************************************/
24
25 #include <bluetooth/log.h>
26 #include <string.h>
27
28 #include <cstdint>
29
30 #include "bnep_api.h"
31 #include "bnep_int.h"
32 #include "bta/include/bta_sec_api.h"
33 #include "hci/controller_interface.h"
34 #include "internal_include/bt_target.h"
35 #include "l2cap_types.h"
36 #include "l2cdefs.h"
37 #include "main/shim/entry.h"
38 #include "main/shim/helpers.h"
39 #include "osi/include/alarm.h"
40 #include "osi/include/allocator.h"
41 #include "osi/include/fixed_queue.h"
42 #include "stack/include/bt_hdr.h"
43 #include "stack/include/bt_psm_types.h"
44 #include "stack/include/bt_types.h"
45 #include "stack/include/l2cap_interface.h"
46 #include "types/bt_transport.h"
47 #include "types/raw_address.h"
48
49 using namespace bluetooth;
50
51 /******************************************************************************/
52 /* G L O B A L B N E P D A T A */
53 /******************************************************************************/
54 tBNEP_CB bnep_cb;
55
56 const uint16_t bnep_frame_hdr_sizes[] = {14, 1, 2, 8, 8};
57
58 /******************************************************************************/
59 /* L O C A L F U N C T I O N P R O T O T Y P E S */
60 /******************************************************************************/
61 static void bnep_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid, uint16_t psm,
62 uint8_t l2cap_id);
63 static void bnep_connect_cfm(uint16_t l2cap_cid, tL2CAP_CONN result);
64 static void bnep_config_cfm(uint16_t l2cap_cid, uint16_t result, tL2CAP_CFG_INFO* p_cfg);
65 static void bnep_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
66 static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
67 static void bnep_congestion_ind(uint16_t lcid, bool is_congested);
68 static void bnep_on_l2cap_error(uint16_t l2cap_cid, uint16_t result);
69 /*******************************************************************************
70 *
71 * Function bnep_register_with_l2cap
72 *
73 * Description This function registers BNEP PSM with L2CAP
74 *
75 * Returns void
76 *
77 ******************************************************************************/
bnep_register_with_l2cap(void)78 tBNEP_RESULT bnep_register_with_l2cap(void) {
79 /* Initialize the L2CAP configuration. We only care about MTU and flush */
80 memset(&bnep_cb.l2cap_my_cfg, 0, sizeof(tL2CAP_CFG_INFO));
81
82 bnep_cb.l2cap_my_cfg.mtu_present = true;
83 bnep_cb.l2cap_my_cfg.mtu = BNEP_MTU_SIZE;
84
85 bnep_cb.reg_info.pL2CA_ConnectInd_Cb = bnep_connect_ind;
86 bnep_cb.reg_info.pL2CA_ConnectCfm_Cb = bnep_connect_cfm;
87 bnep_cb.reg_info.pL2CA_ConfigInd_Cb = nullptr;
88 bnep_cb.reg_info.pL2CA_ConfigCfm_Cb = bnep_config_cfm;
89 bnep_cb.reg_info.pL2CA_DisconnectInd_Cb = bnep_disconnect_ind;
90 bnep_cb.reg_info.pL2CA_DataInd_Cb = bnep_data_ind;
91 bnep_cb.reg_info.pL2CA_CongestionStatus_Cb = bnep_congestion_ind;
92 bnep_cb.reg_info.pL2CA_Error_Cb = bnep_on_l2cap_error;
93
94 /* Now, register with L2CAP */
95 if (!stack::l2cap::get_interface().L2CA_RegisterWithSecurity(
96 BT_PSM_BNEP, bnep_cb.reg_info, false /* enable_snoop */, nullptr, BNEP_MTU_SIZE,
97 BNEP_MTU_SIZE, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) {
98 log::error("BNEP - Registration failed");
99 return BNEP_SECURITY_FAIL;
100 }
101
102 return BNEP_SUCCESS;
103 }
104
105 /*******************************************************************************
106 *
107 * Function bnep_connect_ind
108 *
109 * Description This function handles an inbound connection indication
110 * from L2CAP. This is the case where we are acting as a
111 * server.
112 *
113 * Returns void
114 *
115 ******************************************************************************/
bnep_connect_ind(const RawAddress & bd_addr,uint16_t l2cap_cid,uint16_t,uint8_t)116 static void bnep_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid, uint16_t /* psm */,
117 uint8_t /* l2cap_id */) {
118 tBNEP_CONN* p_bcb = bnepu_find_bcb_by_bd_addr(bd_addr);
119
120 /* If we are not acting as server, or already have a connection, or have */
121 /* no more resources to handle the connection, reject the connection. */
122 if (!(bnep_cb.profile_registered) || (p_bcb) || ((p_bcb = bnepu_allocate_bcb(bd_addr)) == NULL)) {
123 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(l2cap_cid)) {
124 log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", bd_addr, l2cap_cid);
125 }
126 return;
127 }
128
129 /* Transition to the next appropriate state, waiting for config setup. */
130 p_bcb->con_state = BNEP_STATE_CFG_SETUP;
131
132 /* Save the L2CAP Channel ID. */
133 p_bcb->l2cap_cid = l2cap_cid;
134
135 /* Start timer waiting for config setup */
136 alarm_set_on_mloop(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS, bnep_conn_timer_timeout, p_bcb);
137
138 log::debug("BNEP - Rcvd L2CAP conn ind, CID: 0x{:x}", p_bcb->l2cap_cid);
139 }
140
bnep_on_l2cap_error(uint16_t l2cap_cid,uint16_t)141 static void bnep_on_l2cap_error(uint16_t l2cap_cid, uint16_t /* result */) {
142 tBNEP_CONN* p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
143 if (p_bcb == nullptr) {
144 return;
145 }
146
147 /* Tell the upper layer, if there is a callback */
148 if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) {
149 (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
150 }
151
152 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_bcb->l2cap_cid)) {
153 log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", p_bcb->rem_bda, l2cap_cid);
154 }
155
156 bnepu_release_bcb(p_bcb);
157 }
158
159 /*******************************************************************************
160 *
161 * Function bnep_connect_cfm
162 *
163 * Description This function handles the connect confirm events
164 * from L2CAP. This is the case when we are acting as a
165 * client and have sent a connect request.
166 *
167 * Returns void
168 *
169 ******************************************************************************/
bnep_connect_cfm(uint16_t l2cap_cid,tL2CAP_CONN result)170 static void bnep_connect_cfm(uint16_t l2cap_cid, tL2CAP_CONN result) {
171 tBNEP_CONN* p_bcb;
172
173 /* Find CCB based on CID */
174 p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
175 if (p_bcb == NULL) {
176 log::warn("BNEP - Rcvd conn cnf for unknown CID 0x{:x}", l2cap_cid);
177 return;
178 }
179
180 /* If the connection response contains success status, then */
181 /* Transition to the next state and startup the timer. */
182 if ((result == tL2CAP_CONN::L2CAP_CONN_OK) && (p_bcb->con_state == BNEP_STATE_CONN_START)) {
183 p_bcb->con_state = BNEP_STATE_CFG_SETUP;
184
185 /* Start timer waiting for config results */
186 alarm_set_on_mloop(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS, bnep_conn_timer_timeout, p_bcb);
187
188 log::debug("BNEP - got conn cnf, sent cfg req, CID: 0x{:x}", p_bcb->l2cap_cid);
189 } else {
190 log::error("invoked with non OK status");
191 }
192 }
193
194 /*******************************************************************************
195 *
196 * Function bnep_config_cfm
197 *
198 * Description This function processes the L2CAP configuration confirmation
199 * event.
200 *
201 * Returns void
202 *
203 ******************************************************************************/
bnep_config_cfm(uint16_t l2cap_cid,uint16_t,tL2CAP_CFG_INFO *)204 static void bnep_config_cfm(uint16_t l2cap_cid, uint16_t /* initiator */,
205 tL2CAP_CFG_INFO* /* p_cfg */) {
206 tBNEP_CONN* p_bcb;
207
208 log::debug("BNEP - Rcvd cfg cfm, CID: 0x{:x}", l2cap_cid);
209
210 /* Find CCB based on CID */
211 p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
212 if (p_bcb == NULL) {
213 log::warn("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x{:x}", l2cap_cid);
214 return;
215 }
216
217 /* For now, always accept configuration from the other side */
218 p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
219
220 /* Start timer waiting for setup or response */
221 alarm_set_on_mloop(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS, bnep_conn_timer_timeout, p_bcb);
222
223 if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) {
224 bnep_sec_check_complete(&p_bcb->rem_bda, BT_TRANSPORT_BR_EDR, p_bcb);
225 }
226 }
227
228 /*******************************************************************************
229 *
230 * Function bnep_disconnect_ind
231 *
232 * Description This function handles a disconnect event from L2CAP. If
233 * requested to, we ack the disconnect before dropping the CCB
234 *
235 * Returns void
236 *
237 ******************************************************************************/
bnep_disconnect_ind(uint16_t l2cap_cid,bool)238 static void bnep_disconnect_ind(uint16_t l2cap_cid, bool /* ack_needed */) {
239 tBNEP_CONN* p_bcb;
240
241 /* Find CCB based on CID */
242 p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
243 if (p_bcb == NULL) {
244 log::warn("BNEP - Rcvd L2CAP disc, unknown CID: 0x{:x}", l2cap_cid);
245 return;
246 }
247
248 log::debug("BNEP - Rcvd L2CAP disc, CID: 0x{:x}", l2cap_cid);
249
250 /* Tell the user if there is a callback */
251 if (p_bcb->con_state == BNEP_STATE_CONNECTED) {
252 if (bnep_cb.p_conn_state_cb) {
253 (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_DISCONNECTED, false);
254 }
255 } else {
256 if ((bnep_cb.p_conn_state_cb) && ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) ||
257 (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) {
258 (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
259 }
260 }
261
262 bnepu_release_bcb(p_bcb);
263 }
264
265 /*******************************************************************************
266 *
267 * Function bnep_congestion_ind
268 *
269 * Description This is a callback function called by L2CAP when
270 * congestion status changes
271 *
272 ******************************************************************************/
bnep_congestion_ind(uint16_t l2cap_cid,bool is_congested)273 static void bnep_congestion_ind(uint16_t l2cap_cid, bool is_congested) {
274 tBNEP_CONN* p_bcb;
275
276 /* Find BCB based on CID */
277 p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
278 if (p_bcb == NULL) {
279 log::warn("BNEP - Rcvd L2CAP cong, unknown CID: 0x{:x}", l2cap_cid);
280 return;
281 }
282
283 if (is_congested) {
284 p_bcb->con_flags |= BNEP_FLAGS_L2CAP_CONGESTED;
285 if (bnep_cb.p_tx_data_flow_cb) {
286 bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_OFF);
287 }
288 } else {
289 p_bcb->con_flags &= ~BNEP_FLAGS_L2CAP_CONGESTED;
290
291 if (bnep_cb.p_tx_data_flow_cb) {
292 bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_ON);
293 }
294
295 /* While not congested, send as many buffers as we can */
296 while (!(p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED)) {
297 BT_HDR* p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_bcb->xmit_q);
298
299 if (!p_buf) {
300 break;
301 }
302
303 uint16_t len = p_buf->len;
304
305 if (stack::l2cap::get_interface().L2CA_DataWrite(l2cap_cid, p_buf) !=
306 tL2CAP_DW_RESULT::SUCCESS) {
307 log::warn("Unable to write L2CAP data peer:{} cid:{} len:{}", p_bcb->rem_bda, l2cap_cid,
308 len);
309 }
310 }
311 }
312 }
313
314 /*******************************************************************************
315 *
316 * Function bnep_data_ind
317 *
318 * Description This function is called when data is received from L2CAP.
319 * if we are the originator of the connection, we are the SDP
320 * client, and the received message is queued for the client.
321 *
322 * If we are the destination of the connection, we are the SDP
323 * server, so the message is passed to the server processing
324 * function.
325 *
326 * Returns void
327 *
328 ******************************************************************************/
bnep_data_ind(uint16_t l2cap_cid,BT_HDR * p_buf)329 static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
330 tBNEP_CONN* p_bcb;
331 uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
332 uint16_t rem_len = p_buf->len;
333 if (rem_len == 0) {
334 osi_free(p_buf);
335 return;
336 }
337 uint8_t type, ctrl_type, ext_type = 0;
338 bool extension_present, fw_ext_present;
339 uint16_t protocol = 0;
340
341 /* Find CCB based on CID */
342 p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
343 if (p_bcb == NULL) {
344 log::warn("BNEP - Rcvd L2CAP data, unknown CID: 0x{:x}", l2cap_cid);
345 osi_free(p_buf);
346 return;
347 }
348
349 /* Get the type and extension bits */
350 type = *p++;
351 extension_present = type >> 7;
352 type &= 0x7f;
353 if (type >= sizeof(bnep_frame_hdr_sizes) / sizeof(bnep_frame_hdr_sizes[0])) {
354 log::info("BNEP - rcvd frame, bad type: 0x{:02x}", type);
355 osi_free(p_buf);
356 return;
357 }
358 if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE)) {
359 log::debug("BNEP - rcvd frame, bad len: {} type: 0x{:02x}", p_buf->len, type);
360 osi_free(p_buf);
361 return;
362 }
363
364 rem_len--;
365
366 if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
367 (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)) && (type != BNEP_FRAME_CONTROL)) {
368 log::warn("BNEP - Ignored L2CAP data while in state: {}, CID: 0x{:x}", p_bcb->con_state,
369 l2cap_cid);
370
371 if (extension_present) {
372 /*
373 ** When there is no connection if a data packet is received
374 ** with unknown control extension headers then those should be processed
375 ** according to complain/ignore law
376 */
377 uint8_t ext, length;
378 uint16_t org_len, new_len;
379 /* parse the extension headers and process unknown control headers */
380 org_len = rem_len;
381 do {
382 if (org_len < 2) {
383 break;
384 }
385 ext = *p++;
386 length = *p++;
387
388 new_len = (length + 2);
389 if (new_len > org_len) {
390 break;
391 }
392
393 if ((ext & 0x7F) == BNEP_EXTENSION_FILTER_CONTROL) {
394 if (length == 0) {
395 break;
396 }
397 if (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG) {
398 bnep_send_command_not_understood(p_bcb, *p);
399 }
400 }
401
402 p += length;
403
404 org_len -= new_len;
405 } while (ext & 0x80);
406 }
407 osi_free(p_buf);
408 return;
409 }
410
411 if (type > BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY) {
412 log::debug("BNEP - rcvd frame, unknown type: 0x{:02x}", type);
413 osi_free(p_buf);
414 return;
415 }
416
417 log::debug("BNEP - rcv frame, type: {} len: {} Ext: {}", type, p_buf->len, extension_present);
418
419 /* Initialize addresses to 'not supplied' */
420 RawAddress src_addr = RawAddress::kEmpty;
421 RawAddress dst_addr = RawAddress::kEmpty;
422
423 switch (type) {
424 case BNEP_FRAME_GENERAL_ETHERNET:
425 dst_addr = *(RawAddress*)p;
426 p += BD_ADDR_LEN;
427 src_addr = *(RawAddress*)p;
428 p += BD_ADDR_LEN;
429 BE_STREAM_TO_UINT16(protocol, p);
430 rem_len -= 14;
431 break;
432
433 case BNEP_FRAME_CONTROL:
434 ctrl_type = *p;
435 p = bnep_process_control_packet(p_bcb, p, &rem_len, false);
436
437 if (ctrl_type == BNEP_SETUP_CONNECTION_REQUEST_MSG &&
438 p_bcb->con_state != BNEP_STATE_CONNECTED && extension_present && p && rem_len) {
439 osi_free(p_bcb->p_pending_data);
440 p_bcb->p_pending_data = (BT_HDR*)osi_malloc(rem_len + sizeof(BT_HDR));
441 memcpy((uint8_t*)(p_bcb->p_pending_data + 1), p, rem_len);
442 p_bcb->p_pending_data->len = rem_len;
443 p_bcb->p_pending_data->offset = 0;
444 } else {
445 while (extension_present && p && rem_len) {
446 ext_type = *p++;
447 rem_len--;
448 extension_present = ext_type >> 7;
449 ext_type &= 0x7F;
450
451 /* if unknown extension present stop processing */
452 if (ext_type != BNEP_EXTENSION_FILTER_CONTROL) {
453 break;
454 }
455
456 p = bnep_process_control_packet(p_bcb, p, &rem_len, true);
457 }
458 }
459 osi_free(p_buf);
460 return;
461
462 case BNEP_FRAME_COMPRESSED_ETHERNET:
463 BE_STREAM_TO_UINT16(protocol, p);
464 rem_len -= 2;
465 break;
466
467 case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY:
468 src_addr = *(RawAddress*)p;
469 p += BD_ADDR_LEN;
470 BE_STREAM_TO_UINT16(protocol, p);
471 rem_len -= 8;
472 break;
473
474 case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY:
475 dst_addr = *(RawAddress*)p;
476 p += BD_ADDR_LEN;
477 BE_STREAM_TO_UINT16(protocol, p);
478 rem_len -= 8;
479 break;
480 }
481
482 /* Process the header extension if there is one */
483 while (extension_present && p && rem_len) {
484 ext_type = *p;
485 extension_present = ext_type >> 7;
486 ext_type &= 0x7F;
487
488 /* if unknown extension present stop processing */
489 if (ext_type) {
490 log::debug("Data extension type 0x{:x} found", ext_type);
491 break;
492 }
493
494 p++;
495 rem_len--;
496 p = bnep_process_control_packet(p_bcb, p, &rem_len, true);
497 }
498
499 p_buf->offset += p_buf->len - rem_len;
500 p_buf->len = rem_len;
501
502 /* Always give the upper layer MAC addresses */
503 if (src_addr == RawAddress::kEmpty) {
504 src_addr = p_bcb->rem_bda;
505 }
506
507 if (dst_addr == RawAddress::kEmpty) {
508 dst_addr = bluetooth::ToRawAddress(bluetooth::shim::GetController()->GetMacAddress());
509 }
510
511 /* check whether there are any extensions to be forwarded */
512 if (ext_type) {
513 fw_ext_present = true;
514 } else {
515 fw_ext_present = false;
516 }
517
518 if (bnep_cb.p_data_buf_cb) {
519 (*bnep_cb.p_data_buf_cb)(p_bcb->handle, src_addr, dst_addr, protocol, p_buf, fw_ext_present);
520 } else if (bnep_cb.p_data_ind_cb) {
521 (*bnep_cb.p_data_ind_cb)(p_bcb->handle, src_addr, dst_addr, protocol, p, rem_len,
522 fw_ext_present);
523 osi_free(p_buf);
524 }
525 }
526
527 /*******************************************************************************
528 *
529 * Function bnep_conn_timer_timeout
530 *
531 * Description This function processes a timeout. If it is a startup
532 * timeout, we check for reading our BD address. If it
533 * is an L2CAP timeout, we send a disconnect req to L2CAP.
534 *
535 * Returns void
536 *
537 ******************************************************************************/
bnep_conn_timer_timeout(void * data)538 void bnep_conn_timer_timeout(void* data) {
539 tBNEP_CONN* p_bcb = (tBNEP_CONN*)data;
540
541 log::debug("BNEP - CCB timeout in state: {} CID: 0x{:x} flags {:x}, re_transmit {}",
542 p_bcb->con_state, p_bcb->l2cap_cid, p_bcb->con_flags, p_bcb->re_transmits);
543
544 if (p_bcb->con_state == BNEP_STATE_CONN_SETUP) {
545 log::debug("BNEP - CCB timeout in state: {} CID: 0x{:x}", p_bcb->con_state, p_bcb->l2cap_cid);
546
547 if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) {
548 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_bcb->l2cap_cid)) {
549 log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", p_bcb->rem_bda,
550 p_bcb->l2cap_cid);
551 }
552 bnepu_release_bcb(p_bcb);
553 return;
554 }
555
556 if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
557 bnep_send_conn_req(p_bcb);
558 alarm_set_on_mloop(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS, bnep_conn_timer_timeout, p_bcb);
559 } else {
560 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_bcb->l2cap_cid)) {
561 log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", p_bcb->rem_bda,
562 p_bcb->l2cap_cid);
563 }
564
565 if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) {
566 (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
567 }
568
569 bnepu_release_bcb(p_bcb);
570 return;
571 }
572 } else if (p_bcb->con_state != BNEP_STATE_CONNECTED) {
573 log::debug("BNEP - CCB timeout in state: {} CID: 0x{:x}", p_bcb->con_state, p_bcb->l2cap_cid);
574
575 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_bcb->l2cap_cid)) {
576 log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", p_bcb->rem_bda,
577 p_bcb->l2cap_cid);
578 }
579
580 /* Tell the user if there is a callback */
581 if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) {
582 (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
583 }
584
585 bnepu_release_bcb(p_bcb);
586 } else if (p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND) {
587 if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
588 bnepu_send_peer_our_filters(p_bcb);
589 alarm_set_on_mloop(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS, bnep_conn_timer_timeout,
590 p_bcb);
591 } else {
592 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_bcb->l2cap_cid)) {
593 log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", p_bcb->rem_bda,
594 p_bcb->l2cap_cid);
595 }
596
597 /* Tell the user if there is a callback */
598 if (bnep_cb.p_conn_state_cb) {
599 (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_SET_FILTER_FAIL, false);
600 }
601
602 bnepu_release_bcb(p_bcb);
603 return;
604 }
605 } else if (p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND) {
606 if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
607 bnepu_send_peer_our_multi_filters(p_bcb);
608 alarm_set_on_mloop(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS, bnep_conn_timer_timeout,
609 p_bcb);
610 } else {
611 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_bcb->l2cap_cid)) {
612 log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", p_bcb->rem_bda,
613 p_bcb->l2cap_cid);
614 }
615
616 /* Tell the user if there is a callback */
617 if (bnep_cb.p_conn_state_cb) {
618 (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_SET_FILTER_FAIL, false);
619 }
620
621 bnepu_release_bcb(p_bcb);
622 return;
623 }
624 }
625 }
626
627 /*******************************************************************************
628 *
629 * Function bnep_connected
630 *
631 * Description This function is called when a connection is established
632 * (after config).
633 *
634 * Returns void
635 *
636 ******************************************************************************/
bnep_connected(tBNEP_CONN * p_bcb)637 void bnep_connected(tBNEP_CONN* p_bcb) {
638 bool is_role_change;
639
640 if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) {
641 is_role_change = true;
642 } else {
643 is_role_change = false;
644 }
645
646 p_bcb->con_state = BNEP_STATE_CONNECTED;
647 p_bcb->con_flags |= BNEP_FLAGS_CONN_COMPLETED;
648 p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
649
650 /* Ensure timer is stopped */
651 alarm_cancel(p_bcb->conn_timer);
652 p_bcb->re_transmits = 0;
653
654 /* Tell the upper layer, if there is a callback */
655 if (bnep_cb.p_conn_state_cb) {
656 (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_SUCCESS, is_role_change);
657 }
658 }
659