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