Ejemplo n.º 1
0
/*******************************************************************************
**
** Function         avdt_ccb_chk_timer
**
** Description      This function stops the CCB timer if the idle timer is
**                  running.
**
**
** Returns          void.
**
*******************************************************************************/
void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
{
    if (p_ccb->timer_entry.event == BTU_TTYPE_AVDT_CCB_IDLE)
    {
        btu_stop_timer(&p_ccb->timer_entry);
    }
}
Ejemplo n.º 2
0
/*******************************************************************************
**
** Function         l2c_process_held_packets
**
** Description      This function processes any L2CAP packets that arrived before
**                  the HCI connection complete arrived. It is a work around for
**                  badly behaved controllers.
**
** Returns          void
**
*******************************************************************************/
void l2c_process_held_packets (BOOLEAN timed_out)
{
    BT_HDR      *p_buf, *p_buf1;
    BUFFER_Q    *p_rcv_hold_q = &l2cb.rcv_hold_q;

    if (!p_rcv_hold_q->count)
        return;

    if (!timed_out)
    {
        btu_stop_timer(&l2cb.rcv_hold_tle);
        L2CAP_TRACE_WARNING0("L2CAP HOLD CONTINUE");
    }
    else
    {
        L2CAP_TRACE_WARNING0("L2CAP HOLD TIMEOUT");
    }

    /* Update the timeouts in the hold queue */
    for (p_buf = (BT_HDR *)GKI_getfirst (p_rcv_hold_q); p_buf; p_buf = p_buf1)
    {
        p_buf1 = (BT_HDR *)GKI_getnext (p_buf);
        if (!timed_out || (!p_buf->layer_specific) || (--p_buf->layer_specific == 0))
        {
            GKI_remove_from_queue (p_rcv_hold_q, p_buf);
            p_buf->layer_specific = 0xFFFF;
            l2c_rcv_acl_data (p_buf);
        }
    }

    /* If anyone still in the queue, restart the timeout */
    if (p_rcv_hold_q->count)
        btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);
}
Ejemplo n.º 3
0
/*******************************************************************************
**
** Function         l2c_process_held_packets
**
** Description      This function processes any L2CAP packets that arrived before
**                  the HCI connection complete arrived. It is a work around for
**                  badly behaved controllers.
**
** Returns          void
**
*******************************************************************************/
void l2c_process_held_packets(BOOLEAN timed_out)
{
    if (list_is_empty(l2cb.rcv_pending_q)) {
        return;
    }

    if (!timed_out) {
        btu_stop_timer(&l2cb.rcv_hold_tle);
        L2CAP_TRACE_WARNING("L2CAP HOLD CONTINUE");
    } else {
        L2CAP_TRACE_WARNING("L2CAP HOLD TIMEOUT");
    }

    for (const list_node_t *node = list_begin(l2cb.rcv_pending_q);
            node != list_end(l2cb.rcv_pending_q);)  {
        BT_HDR *p_buf = list_node(node);
        node = list_next(node);
        if (!timed_out || (!p_buf->layer_specific) || (--p_buf->layer_specific == 0)) {
            list_remove(l2cb.rcv_pending_q, p_buf);
            p_buf->layer_specific = 0xFFFF;
            l2c_rcv_acl_data(p_buf);
        }
    }

    /* If anyone still in the queue, restart the timeout */
    if (!list_is_empty(l2cb.rcv_pending_q)) {
        btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);
    }
}
Ejemplo n.º 4
0
/*******************************************************************************
**
** Function         bta_pan_scb_dealloc
**
** Description      Deallocate a link control block.
**
**
** Returns          void
**
*******************************************************************************/
void bta_pan_scb_dealloc(tBTA_PAN_SCB *p_scb)
{
    APPL_TRACE_DEBUG("bta_pan_scb_dealloc %d", bta_pan_scb_to_idx(p_scb));
    if (p_scb->is_idle_timer_started == TRUE)
    {
        /* Ensure that timer is stopped */
        btu_stop_timer (&p_scb->idle_tle);
    }
    memset(p_scb, 0, sizeof(tBTA_PAN_SCB));
}
Ejemplo n.º 5
0
/*******************************************************************************
**
** Function         avdt_scb_dealloc
**
** Description      Deallocate a stream control block.
**
**
** Returns          void.
**
*******************************************************************************/
void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
{
    UNUSED(p_data);

    AVDT_TRACE_DEBUG("avdt_scb_dealloc hdl=%d\n", avdt_scb_to_hdl(p_scb));
    btu_stop_timer(&p_scb->timer_entry);

#if AVDT_MULTIPLEXING == TRUE
    /* free fragments we're holding, if any; it shouldn't happen */
    fixed_queue_free(p_scb->frag_q, osi_free_func);
#endif

    memset(p_scb, 0, sizeof(tAVDT_SCB));
}
Ejemplo n.º 6
0
void btu_deregister_timer(TIMER_LIST_ENT *p_tle)
{
    UINT8 i = 0;

    for (; i < BTU_MAX_REG_TIMER; i++)
    {
        if (btu_cb.timer_reg[i].p_tle == p_tle)
        {
            btu_stop_timer(p_tle);
            btu_cb.timer_reg[i].timer_cb = NULL;
            btu_cb.timer_reg[i].p_tle = NULL;
            break;
        }
    }
}
Ejemplo n.º 7
0
/*******************************************************************************
**
** Function         smp_br_data_received
**
** Description      This function is called when data is received from L2CAP on
**                  SMP BR channel.
**
** Returns          void
**
*******************************************************************************/
static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
{
    tSMP_CB *p_cb = &smp_cb;
    UINT8   *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
    UINT8   cmd ;
    SMP_TRACE_EVENT ("SMDBG l2c %s", __func__);

    STREAM_TO_UINT8(cmd, p);

    /* sanity check */
    if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd))
    {
        SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd);
        GKI_freebuf(p_buf);
        return;
    }

    /* reject the pairing request if there is an on-going SMP pairing */
    if (SMP_OPCODE_PAIRING_REQ == cmd)
    {
        if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE))
        {
            p_cb->role = HCI_ROLE_SLAVE;
            p_cb->smp_over_br = TRUE;
            memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
        }
        else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN))
        {
            GKI_freebuf (p_buf);
            smp_reject_unexpected_pairing_command(bd_addr);
            return;
        }
        /* else, out of state pairing request received, passed into State Machine */
    }

    if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0)
    {
        btu_stop_timer (&p_cb->rsp_timer_ent);
        btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
                             SMP_WAIT_FOR_RSP_TOUT);

        p_cb->rcvd_cmd_code = cmd;
        p_cb->rcvd_cmd_len = (UINT8) p_buf->len;
        smp_br_state_machine_event(p_cb, cmd, p);
    }

    GKI_freebuf (p_buf);
}
Ejemplo n.º 8
0
/*******************************************************************************
**
** Function         HID_HostCloseDev
**
** Description      This function disconnects the device.
**
** Returns          void
**
*******************************************************************************/
tHID_STATUS HID_HostCloseDev( UINT8 dev_handle )
{
    if( !hh_cb.reg_flag )
        return (HID_ERR_NOT_REGISTERED);

    if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
        return HID_ERR_INVALID_PARAM;

    hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
    btu_stop_timer( &(hh_cb.devices[dev_handle].conn.timer_entry) ) ;

    if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
        return HID_ERR_NO_CONNECTION;

    hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
    return hidh_conn_disconnect( dev_handle );
}
Ejemplo n.º 9
0
/*******************************************************************************
**
** Function         avdt_scb_dealloc
**
** Description      Deallocate a stream control block.
**
**
** Returns          void.
**
*******************************************************************************/
void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
{
#if AVDT_MULTIPLEXING == TRUE
    void *p_buf;
#endif
    UNUSED(p_data);

    AVDT_TRACE_DEBUG("avdt_scb_dealloc hdl=%d", avdt_scb_to_hdl(p_scb));
    btu_stop_timer(&p_scb->timer_entry);

#if AVDT_MULTIPLEXING == TRUE
    /* free fragments we're holding, if any; it shouldn't happen */
    while ((p_buf = GKI_dequeue (&p_scb->frag_q)) != NULL)
        GKI_freebuf(p_buf);
#endif

    memset(p_scb, 0, sizeof(tAVDT_SCB));
}
Ejemplo n.º 10
0
/*******************************************************************************
**
** Function         btm_read_local_name_complete
**
** Description      This function is called when local name read complete.
**                  message is received from the HCI.
**
** Returns          void
**
*******************************************************************************/
void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len)
{
    tBTM_CMPL_CB   *p_cb = btm_cb.devcb.p_rln_cmpl_cb;
    UINT8           status;
    UNUSED(evt_len);

    btu_stop_timer (&btm_cb.devcb.rln_timer);

    /* If there was a callback address for read local name, call it */
    btm_cb.devcb.p_rln_cmpl_cb = NULL;

    if (p_cb)
    {
        STREAM_TO_UINT8  (status, p);

        if (status == HCI_SUCCESS)
            (*p_cb)(p);
        else
            (*p_cb)(NULL);
    }
}
/*******************************************************************************
**
** Function         l2cble_scanner_conn_comp
**
** Description      This function is called when an HCI Connection Complete
**                  event is received while we are a scanner (so we are master).
**
** Returns          void
**
*******************************************************************************/
void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
                               UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout)
{
    tL2C_LCB            *p_lcb;
    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_or_alloc_dev (bda);

    L2CAP_TRACE_DEBUG5 ("l2cble_scanner_conn_comp: HANDLE=%d addr_type=%d conn_interval=%d slave_latency=%d supervision_tout=%d",
                        handle,  type, conn_interval, conn_latency, conn_timeout);

    l2cb.is_ble_connecting = FALSE;

    /* See if we have a link control block for the remote device */
    p_lcb = l2cu_find_lcb_by_bd_addr (bda);

    /* If we don't have one, create one. this is auto connection complete. */
    if (!p_lcb)
    {
        p_lcb = l2cu_allocate_lcb (bda, FALSE);
        if (!p_lcb)
        {
            btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
            L2CAP_TRACE_ERROR0 ("l2cble_scanner_conn_comp - failed to allocate LCB");
            return;
        }
        else
        {
            if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
            {
                btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
                L2CAP_TRACE_WARNING0 ("l2cble_scanner_conn_comp - LCB but no CCB");
                return ;
            }
        }
    }
    else if (p_lcb->link_state != LST_CONNECTING)
    {
        L2CAP_TRACE_ERROR1 ("L2CAP got BLE scanner conn_comp in bad state: %d", p_lcb->link_state);
        return;
    }
    btu_stop_timer(&p_lcb->timer_entry);

    /* Save the handle */
    p_lcb->handle = handle;

    /* Connected OK. Change state to connected, we were scanning so we are master */
    p_lcb->link_state = LST_CONNECTED;
    p_lcb->link_role  = HCI_ROLE_MASTER;
    p_lcb->is_ble_link = TRUE;

    /* If there are any preferred connection parameters, set them now */
    if ( (p_dev_rec->conn_params.min_conn_int     >= BTM_BLE_CONN_INT_MIN ) &&
         (p_dev_rec->conn_params.min_conn_int     <= BTM_BLE_CONN_INT_MAX ) &&
         (p_dev_rec->conn_params.max_conn_int     >= BTM_BLE_CONN_INT_MIN ) &&
         (p_dev_rec->conn_params.max_conn_int     <= BTM_BLE_CONN_INT_MAX ) &&
         (p_dev_rec->conn_params.slave_latency    <= BTM_BLE_CONN_LATENCY_MAX ) &&
         (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) &&
         (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) &&
         ((conn_interval < p_dev_rec->conn_params.min_conn_int &&
          p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ||
          (conn_interval > p_dev_rec->conn_params.max_conn_int) ||
          (conn_latency > p_dev_rec->conn_params.slave_latency) ||
          (conn_timeout > p_dev_rec->conn_params.supervision_tout)))
    {
        L2CAP_TRACE_ERROR5 ("upd_ll_conn_params: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d",
                            handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int,
                            p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout);

        btsnd_hcic_ble_upd_ll_conn_params (handle,
                                           p_dev_rec->conn_params.min_conn_int,
                                           p_dev_rec->conn_params.max_conn_int,
                                           p_dev_rec->conn_params.slave_latency,
                                           p_dev_rec->conn_params.supervision_tout,
                                           0, 0);
    }

    /* Tell BTM Acl management about the link */
    btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, TRUE);

    if (p_lcb->p_echo_rsp_cb)
    {
        L2CAP_TRACE_ERROR0 ("l2cu_send_peer_echo_req");
        l2cu_send_peer_echo_req (p_lcb, NULL, 0);
    }

    p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT;

    l2cu_process_fixed_chnl_resp (p_lcb);
}
Ejemplo n.º 12
0
/*******************************************************************************
**
** Function         hidh_l2cif_connect_ind
**
** Description      This function handles an inbound connection indication
**                  from L2CAP. This is the case where we are acting as a
**                  server.
**
** Returns          void
**
*******************************************************************************/
static void hidh_l2cif_connect_ind (BD_ADDR  bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
{
    tHID_CONN    *p_hcon;
    BOOLEAN      bAccept = TRUE;
    UINT8        i = HID_HOST_MAX_DEVICES;
    tHID_HOST_DEV_CTB *p_dev;

    HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x  CID 0x%x", psm, l2cap_cid);

    /* always add incoming connection device into HID database by default */
    if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS)
    {
        L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
        return;
    }

    p_hcon = &hh_cb.devices[i].conn;
    p_dev  = &hh_cb.devices[i];

    /* Stop the retry timer if active */
#if (HID_HOST_MAX_CONN_RETRY > 0)
#if (HID_HOST_REPAGE_WIN > 0)
    HIDH_TRACE_DEBUG ("HID-Host stopping retry timer as l2cap is connected from remote side");
    p_dev->conn_tries = HID_HOST_MAX_CONN_RETRY+1;
    btu_stop_timer(&(p_dev->conn.timer_entry));
#endif
#endif

    /* Check we are in the correct state for this */
    if (psm == HID_PSM_INTERRUPT)
    {
        if (p_hcon->ctrl_cid == 0)
        {
            HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
            bAccept = FALSE;
        }
        if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
        {
            HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
                                 p_hcon->conn_state);
            bAccept = FALSE;
        }
    }
    else /* CTRL channel */
    {
#if defined(HID_HOST_ACPT_NEW_CONN) && (HID_HOST_ACPT_NEW_CONN == TRUE)
        p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
        p_hcon->conn_state = HID_CONN_STATE_UNUSED;
#else
        if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
        {
            HIDH_TRACE_WARNING ("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
                                 p_hcon->conn_state);
            bAccept = FALSE;
        }
#endif
    }

    if (!bAccept)
    {
        L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
        return;
    }

    if (psm == HID_PSM_CONTROL)
    {
        p_hcon->conn_flags = 0;
        p_hcon->ctrl_cid   = l2cap_cid;
        p_hcon->ctrl_id    = l2cap_id;
        p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;  /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to 'connection failure' */

        p_hcon->conn_state = HID_CONN_STATE_SECURITY;
        if (!interop_addr_match(INTEROP_DISABLE_AUTH_FOR_HID_POINTING, (bt_bdaddr_t*)p_dev->addr))
        {
            if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
                FALSE, BTM_SEC_PROTO_HID,
                (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
                &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
            {
                L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
            }
        }
        else
        {
            /* device is blacklisted, don't perform authentication */
            L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
            hidh_sec_check_complete_term(p_dev->addr, BT_TRANSPORT_BR_EDR,
                p_dev, BTM_SUCCESS);
        }

        return;
    }

    /* Transition to the next appropriate state, configuration */
    p_hcon->conn_state = HID_CONN_STATE_CONFIG;
    p_hcon->intr_cid   = l2cap_cid;

    /* Send response to the L2CAP layer. */
    L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);

    /* Send a Configuration Request. */
    L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);

    HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x  CID 0x%x",
                       psm, l2cap_cid);
}
Ejemplo n.º 13
0
/*******************************************************************************
**
** Function         rfc_timer_stop
**
** Description      Stop RFC Timer
**
*******************************************************************************/
void rfc_timer_stop (tRFC_MCB *p_mcb)
{
    RFCOMM_TRACE_EVENT ("rfc_timer_stop");

    btu_stop_timer (&p_mcb->tle);
}
Ejemplo n.º 14
0
/*******************************************************************************
**
** Function         process_l2cap_cmd
**
** Description      This function is called when a packet is received on the
**                  L2CAP signalling CID
**
** Returns          void
**
*******************************************************************************/
static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
{
    UINT8           *p_pkt_end, *p_next_cmd, *p_cfg_end, *p_cfg_start;
    UINT8           cmd_code, cfg_code, cfg_len, id;
    tL2C_CONN_INFO  con_info;
    tL2CAP_CFG_INFO cfg_info;
    UINT16          rej_reason, rej_mtu, lcid, rcid, info_type;
    tL2C_CCB        *p_ccb;
    tL2C_RCB        *p_rcb;
    BOOLEAN         cfg_rej;
    UINT16          cfg_rej_len, cmd_len;
    UINT16          result;
    tL2C_CONN_INFO  ci;

#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
    /* if l2cap command received in CID 1 on top of an LE link, ignore this command */
    if (p_lcb->is_ble_link)
        return;
#endif
    p_next_cmd = p;
    p_pkt_end  = p + pkt_len;

    memset (&cfg_info, 0, sizeof(cfg_info));

    /* An L2CAP packet may contain multiple commands */
    while (TRUE)
    {
        /* Smallest command is 4 bytes */
        if ((p = p_next_cmd) > (p_pkt_end - 4))
            break;

        STREAM_TO_UINT8  (cmd_code, p);
        STREAM_TO_UINT8  (id, p);
        STREAM_TO_UINT16 (cmd_len, p);

        if(cmd_len > GKI_BUF2_SIZE)
        {
             L2CAP_TRACE_WARNING0 ("L2CAP - Invalid MTU Size");
             l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_MTU_EXCEEDED, id, 0, 0);
             return;
        }
        /* Check command length does not exceed packet length */
        if ((p_next_cmd = p + cmd_len) > p_pkt_end)
        {
            L2CAP_TRACE_WARNING3 ("Command len bad  pkt_len: %d  cmd_len: %d  code: %d",
                                  pkt_len, cmd_len, cmd_code);
            break;
        }

        switch (cmd_code)
        {
        case L2CAP_CMD_REJECT:
            STREAM_TO_UINT16 (rej_reason, p);
            if (rej_reason == L2CAP_CMD_REJ_MTU_EXCEEDED)
            {
                STREAM_TO_UINT16 (rej_mtu, p);
                /* What to do with the MTU reject ? We have negotiated an MTU. For now */
                /* we will ignore it and let a higher protocol timeout take care of it */

                L2CAP_TRACE_WARNING2 ("L2CAP - MTU rej Handle: %d MTU: %d", p_lcb->handle, rej_mtu);
            }
            if (rej_reason == L2CAP_CMD_REJ_INVALID_CID)
            {
                STREAM_TO_UINT16 (rcid, p);
                STREAM_TO_UINT16 (lcid, p);

                L2CAP_TRACE_WARNING2 ("L2CAP - rej with CID invalid, LCID: 0x%04x RCID: 0x%04x", lcid, rcid);

                /* Remote CID invalid. Treat as a disconnect */
                if (((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
                 && (p_ccb->remote_cid == rcid))
                {
                    /* Fake link disconnect - no reply is generated */
                    l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
                }
            }

            /* SonyEricsson Info request Bug workaround (Continue connection) */
            else if (rej_reason == L2CAP_CMD_REJ_NOT_UNDERSTOOD && p_lcb->w4_info_rsp)
            {
                btu_stop_timer (&p_lcb->info_timer_entry);

                p_lcb->w4_info_rsp = FALSE;
                ci.status = HCI_SUCCESS;
                memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));

                /* For all channels, send the event through their FSMs */
                for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
                {
                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
                }
            }
            break;

        case L2CAP_CMD_CONN_REQ:
            STREAM_TO_UINT16 (con_info.psm, p);
            STREAM_TO_UINT16 (rcid, p);
            if ((p_rcb = l2cu_find_rcb_by_psm (con_info.psm)) == NULL)
            {
                L2CAP_TRACE_WARNING1 ("L2CAP - rcvd conn req for unknown PSM: %d", con_info.psm);
                l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
                break;
            }
            else
            {
                if (!p_rcb->api.pL2CA_ConnectInd_Cb)
                {
                    L2CAP_TRACE_WARNING1 ("L2CAP - rcvd conn req for outgoing-only connection PSM: %d", con_info.psm);
                    l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
                    break;
                }
            }
            if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
            {
                L2CAP_TRACE_ERROR0 ("L2CAP - unable to allocate CCB");
                l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_RESOURCES);
                break;
            }
            p_ccb->remote_id = id;
            p_ccb->p_rcb = p_rcb;
            p_ccb->remote_cid = rcid;

            l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
            break;

        case L2CAP_CMD_CONN_RSP:
            STREAM_TO_UINT16 (con_info.remote_cid, p);
            STREAM_TO_UINT16 (lcid, p);
            STREAM_TO_UINT16 (con_info.l2cap_result, p);
            STREAM_TO_UINT16 (con_info.l2cap_status, p);

            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) == NULL)
            {
                L2CAP_TRACE_WARNING2 ("L2CAP - no CCB for conn rsp, LCID: %d RCID: %d",
                                      lcid, con_info.remote_cid);
                break;
            }
            if (p_ccb->local_id != id)
            {
                L2CAP_TRACE_WARNING2 ("L2CAP - con rsp - bad ID. Exp: %d Got: %d",
                                      p_ccb->local_id, id);
                break;
            }

            if (con_info.l2cap_result == L2CAP_CONN_OK)
                l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info);
            else if (con_info.l2cap_result == L2CAP_CONN_PENDING)
                l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_PND, &con_info);
            else
                l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);

            break;

        case L2CAP_CMD_CONFIG_REQ:
            p_cfg_end = p + cmd_len;
            cfg_rej = FALSE;
            cfg_rej_len = 0;

            STREAM_TO_UINT16 (lcid, p);
            STREAM_TO_UINT16 (cfg_info.flags, p);

            p_cfg_start = p;

            cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present =
            cfg_info.fcr_present = cfg_info.fcs_present = FALSE;

            while (p < p_cfg_end)
            {
                STREAM_TO_UINT8 (cfg_code, p);
                STREAM_TO_UINT8 (cfg_len, p);

                switch (cfg_code & 0x7F)
                {
                case L2CAP_CFG_TYPE_MTU:
                    cfg_info.mtu_present = TRUE;
                    STREAM_TO_UINT16 (cfg_info.mtu, p);
                    break;

                case L2CAP_CFG_TYPE_FLUSH_TOUT:
                    cfg_info.flush_to_present = TRUE;
                    STREAM_TO_UINT16 (cfg_info.flush_to, p);
                    break;

                case L2CAP_CFG_TYPE_QOS:
                    cfg_info.qos_present = TRUE;
                    STREAM_TO_UINT8  (cfg_info.qos.qos_flags, p);
                    STREAM_TO_UINT8  (cfg_info.qos.service_type, p);
                    STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
                    STREAM_TO_UINT32 (cfg_info.qos.token_bucket_size, p);
                    STREAM_TO_UINT32 (cfg_info.qos.peak_bandwidth, p);
                    STREAM_TO_UINT32 (cfg_info.qos.latency, p);
                    STREAM_TO_UINT32 (cfg_info.qos.delay_variation, p);
                    break;

                case L2CAP_CFG_TYPE_FCR:
                    cfg_info.fcr_present = TRUE;
                    STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
                    STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
                    STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
                    STREAM_TO_UINT16 (cfg_info.fcr.rtrans_tout, p);
                    STREAM_TO_UINT16 (cfg_info.fcr.mon_tout, p);
                    STREAM_TO_UINT16 (cfg_info.fcr.mps, p);
                    break;

                case L2CAP_CFG_TYPE_FCS:
                    cfg_info.fcs_present = TRUE;
                    STREAM_TO_UINT8 (cfg_info.fcs, p);
                    break;

                case L2CAP_CFG_TYPE_EXT_FLOW:
                    cfg_info.ext_flow_spec_present = TRUE;
                    STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
                    STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
                    STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.sdu_inter_time, p);
                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p);
                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p);
                    break;

                default:
                    /* sanity check option length */
                    if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len)
                    {
                        p += cfg_len;
                        if ((cfg_code & 0x80) == 0)
                        {
                            cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
                            cfg_rej = TRUE;
                        }
                    }
                    /* bad length; force loop exit */
                    else
                    {
                        p = p_cfg_end;
                        cfg_rej = TRUE;
                    }
                    break;
                }
            }

            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
            {
                p_ccb->remote_id = id;
                if (cfg_rej)
                {
                    l2cu_send_peer_config_rej (p_ccb, p_cfg_start, (UINT16) (cmd_len - L2CAP_CONFIG_REQ_LEN), cfg_rej_len);
                }
                else
                {
                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_REQ, &cfg_info);
                }
            }
            else
            {
                /* updated spec says send command reject on invalid cid */
                l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_INVALID_CID, id, 0, 0);
            }
            break;

        case L2CAP_CMD_CONFIG_RSP:
            p_cfg_end = p + cmd_len;
            STREAM_TO_UINT16 (lcid, p);
            STREAM_TO_UINT16 (cfg_info.flags, p);
            STREAM_TO_UINT16 (cfg_info.result, p);

            cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present =
                cfg_info.fcr_present = cfg_info.fcs_present = FALSE;

            while (p < p_cfg_end)
            {
                STREAM_TO_UINT8 (cfg_code, p);
                STREAM_TO_UINT8 (cfg_len, p);

                switch (cfg_code & 0x7F)
                {
                case L2CAP_CFG_TYPE_MTU:
                    cfg_info.mtu_present = TRUE;
                    STREAM_TO_UINT16 (cfg_info.mtu, p);
                    break;

                case L2CAP_CFG_TYPE_FLUSH_TOUT:
                    cfg_info.flush_to_present = TRUE;
                    STREAM_TO_UINT16 (cfg_info.flush_to, p);
                    break;

                case L2CAP_CFG_TYPE_QOS:
                    cfg_info.qos_present = TRUE;
                    STREAM_TO_UINT8  (cfg_info.qos.qos_flags, p);
                    STREAM_TO_UINT8  (cfg_info.qos.service_type, p);
                    STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
                    STREAM_TO_UINT32 (cfg_info.qos.token_bucket_size, p);
                    STREAM_TO_UINT32 (cfg_info.qos.peak_bandwidth, p);
                    STREAM_TO_UINT32 (cfg_info.qos.latency, p);
                    STREAM_TO_UINT32 (cfg_info.qos.delay_variation, p);
                    break;

                case L2CAP_CFG_TYPE_FCR:
                    cfg_info.fcr_present = TRUE;
                    STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
                    STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
                    STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
                    STREAM_TO_UINT16 (cfg_info.fcr.rtrans_tout, p);
                    STREAM_TO_UINT16 (cfg_info.fcr.mon_tout, p);
                    STREAM_TO_UINT16 (cfg_info.fcr.mps, p);
                    break;

                case L2CAP_CFG_TYPE_FCS:
                    cfg_info.fcs_present = TRUE;
                    STREAM_TO_UINT8 (cfg_info.fcs, p);
                    break;

                case L2CAP_CFG_TYPE_EXT_FLOW:
                    cfg_info.ext_flow_spec_present = TRUE;
                    STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
                    STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
                    STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.sdu_inter_time, p);
                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p);
                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p);
                    break;
                }
            }

            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
            {
                if (p_ccb->local_id != id)
                {
                    L2CAP_TRACE_WARNING2 ("L2CAP - cfg rsp - bad ID. Exp: %d Got: %d",
                                          p_ccb->local_id, id);
                    break;
                }
                if ( (cfg_info.result == L2CAP_CFG_OK) || (cfg_info.result == L2CAP_CFG_PENDING) )
                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_RSP, &cfg_info);
                else
                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_RSP_NEG, &cfg_info);
            }
            else
            {
                L2CAP_TRACE_WARNING1 ("L2CAP - rcvd cfg rsp for unknown CID: 0x%04x", lcid);
            }
            break;


        case L2CAP_CMD_DISC_REQ:
            STREAM_TO_UINT16 (lcid, p);
            STREAM_TO_UINT16 (rcid, p);

            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
            {
                if (p_ccb->remote_cid == rcid)
                {
                    p_ccb->remote_id = id;
                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_REQ, &con_info);
                }
            }
            else
                l2cu_send_peer_disc_rsp (p_lcb, id, lcid, rcid);

            break;

        case L2CAP_CMD_DISC_RSP:
            STREAM_TO_UINT16 (rcid, p);
            STREAM_TO_UINT16 (lcid, p);

            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
            {
                if ((p_ccb->remote_cid == rcid) && (p_ccb->local_id == id))
                {
                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_RSP, &con_info);
                }
            }
            break;

        case L2CAP_CMD_ECHO_REQ:
            l2cu_send_peer_echo_rsp (p_lcb, id, p, cmd_len);
            break;

        case L2CAP_CMD_ECHO_RSP:
            if (p_lcb->p_echo_rsp_cb)
            {
                tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb;

                /* Zero out the callback in case app immediately calls us again */
                p_lcb->p_echo_rsp_cb = NULL;

                (*p_cb) (L2CAP_PING_RESULT_OK);
            }
            break;

        case L2CAP_CMD_INFO_REQ:
            STREAM_TO_UINT16 (info_type, p);
            l2cu_send_peer_info_rsp (p_lcb, id, info_type);
            break;

        case L2CAP_CMD_INFO_RSP:
            /* Stop the link connect timer if sent before L2CAP connection is up */
            if (p_lcb->w4_info_rsp)
            {
                btu_stop_timer (&p_lcb->info_timer_entry);
                p_lcb->w4_info_rsp = FALSE;
            }

            STREAM_TO_UINT16 (info_type, p);
            STREAM_TO_UINT16 (result, p);

            p_lcb->info_rx_bits |= (1 << info_type);

            if ( (info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
              && (result == L2CAP_INFO_RESP_RESULT_SUCCESS) )
            {
                STREAM_TO_UINT32( p_lcb->peer_ext_fea, p );

#if (L2CAP_NUM_FIXED_CHNLS > 0)
                if (p_lcb->peer_ext_fea & L2CAP_EXTFEA_FIXED_CHNLS)
                {
                    l2cu_send_peer_info_req (p_lcb, L2CAP_FIXED_CHANNELS_INFO_TYPE);
                    break;
                }
                else
                {
                    l2cu_process_fixed_chnl_resp (p_lcb);
                }
#endif
            }


#if (L2CAP_NUM_FIXED_CHNLS > 0)
            if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE)
            {
                if (result == L2CAP_INFO_RESP_RESULT_SUCCESS)
                {
                    memcpy (p_lcb->peer_chnl_mask, p, L2CAP_FIXED_CHNL_ARRAY_SIZE);
                }

                l2cu_process_fixed_chnl_resp (p_lcb);
            }
#endif
#if (L2CAP_UCD_INCLUDED == TRUE)
            else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE)
            {
                if (result == L2CAP_INFO_RESP_RESULT_SUCCESS)
                {
                    STREAM_TO_UINT16 (p_lcb->ucd_mtu, p);
                }
            }
#endif

            ci.status = HCI_SUCCESS;
            memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
            for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
            {
                l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
            }
            break;

        default:
            L2CAP_TRACE_WARNING1 ("L2CAP - bad cmd code: %d", cmd_code);
            l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
            return;
        }
    }
}
Ejemplo n.º 15
0
/*******************************************************************************
**
** Function         smp_data_received
**
** Description      This function is called when data is received from L2CAP on
**                  SMP channel.
**
**
** Returns          void
**
*******************************************************************************/
static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
{
    tSMP_CB *p_cb = &smp_cb;
    UINT8   *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
    UINT8   cmd ;
    SMP_TRACE_EVENT ("SMDBG l2c %s", __FUNCTION__);

    STREAM_TO_UINT8(cmd, p);

    /* sanity check */
    if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd))
    {
        SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd);
        GKI_freebuf (p_buf);
        return;
    }

    /* reject the pairing request if there is an on-going SMP pairing */
    if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd)
    {
        if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE) &&
            !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD))
        {
            p_cb->role = L2CA_GetBleConnRole(bd_addr);
            memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
        }
        else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN))
        {
            GKI_freebuf (p_buf);
            smp_reject_unexpected_pairing_command(bd_addr);
            return;
        }
        /* else, out of state pairing request/security request received, passed into SM */
    }

    if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0)
    {
        btu_stop_timer (&p_cb->rsp_timer_ent);
        btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
                             SMP_WAIT_FOR_RSP_TOUT);

        if (cmd == SMP_OPCODE_CONFIRM)
        {
            SMP_TRACE_DEBUG ("in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
                              "loc_auth_req = 0x%02x",
                              __FUNCTION__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req);

            if ((p_cb->peer_auth_req  & SMP_SC_SUPPORT_BIT) &&
                (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT))
            {
                cmd = SMP_OPCODE_PAIR_COMMITM;
            }
        }

        p_cb->rcvd_cmd_code = cmd;
        p_cb->rcvd_cmd_len = (UINT8) p_buf->len;
        smp_sm_event(p_cb, cmd, p);
    }

    GKI_freebuf (p_buf);
}