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