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