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