/*******************************************************************************
**
** 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);
}
Beispiel #2
0
/*******************************************************************************
**
** Function         l2c_rcv_acl_data
**
** Description      This function is called from the HCI Interface when an ACL
**                  data packet is received.
**
** Returns          void
**
*******************************************************************************/
void l2c_rcv_acl_data (BT_HDR *p_msg)
{
    UINT8       *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
    UINT16      handle, hci_len;
    UINT8       pkt_type;
    tL2C_LCB    *p_lcb;
    tL2C_CCB    *p_ccb = NULL;
    UINT16      l2cap_len, rcv_cid, psm;

    /* Extract the handle */
    STREAM_TO_UINT16 (handle, p);
    pkt_type = HCID_GET_EVENT (handle);
    handle   = HCID_GET_HANDLE (handle);

    /* Since the HCI Transport is putting segmented packets back together, we */
    /* should never get a valid packet with the type set to "continuation"    */
    if (pkt_type != L2CAP_PKT_CONTINUE)
    {
        /* Find the LCB based on the handle */
        if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
        {
            UINT8       cmd_code;

            /* There is a slight possibility (specifically with USB) that we get an */
            /* L2CAP connection request before we get the HCI connection complete.  */
            /* So for these types of messages, hold them for up to 2 seconds.       */
            STREAM_TO_UINT16 (hci_len, p);
            STREAM_TO_UINT16 (l2cap_len, p);
            STREAM_TO_UINT16 (rcv_cid, p);
            STREAM_TO_UINT8  (cmd_code, p);

            if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID)
                && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ))
            {
                L2CAP_TRACE_WARNING5 ("L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
                                    handle, p_msg->layer_specific, rcv_cid, cmd_code,
                                    l2cb.rcv_hold_q.count);
                p_msg->layer_specific = 2;
                GKI_enqueue (&l2cb.rcv_hold_q, p_msg);

                if (l2cb.rcv_hold_q.count == 1)
                    btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);

                return;
            }
            else
            {
                L2CAP_TRACE_ERROR5 ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
                                    handle, p_msg->layer_specific, rcv_cid, cmd_code, l2cb.rcv_hold_q.count);
            }
            GKI_freebuf (p_msg);
            return;
        }
    }
    else
    {
        L2CAP_TRACE_WARNING1 ("L2CAP - expected pkt start or complete, got: %d", pkt_type);
        GKI_freebuf (p_msg);
        return;
    }

    /* Extract the length and update the buffer header */
    STREAM_TO_UINT16 (hci_len, p);
    p_msg->offset += 4;

#if (L2CAP_HOST_FLOW_CTRL == TRUE)
    /* Send ack if we hit the threshold */
    if (++p_lcb->link_pkts_unacked >= p_lcb->link_ack_thresh)
        btu_hcif_send_host_rdy_for_data();
#endif

    /* Extract the length and CID */
    STREAM_TO_UINT16 (l2cap_len, p);
    STREAM_TO_UINT16 (rcv_cid, p);

    /* Find the CCB for this CID */
    if (rcv_cid >= L2CAP_BASE_APPL_CID)
    {
        if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL)
        {
            L2CAP_TRACE_WARNING1 ("L2CAP - unknown CID: 0x%04x", rcv_cid);
            GKI_freebuf (p_msg);
            return;
        }
    }

    if (hci_len >= L2CAP_PKT_OVERHEAD)  /* Must receive at least the L2CAP length and CID.*/
    {
        p_msg->len    = hci_len - L2CAP_PKT_OVERHEAD;
        p_msg->offset += L2CAP_PKT_OVERHEAD;
    }
    else
    {
        L2CAP_TRACE_WARNING0 ("L2CAP - got incorrect hci header" );
        GKI_freebuf (p_msg);
        return;
    }

    if (l2cap_len != p_msg->len)
    {
        L2CAP_TRACE_WARNING2 ("L2CAP - bad length in pkt. Exp: %d  Act: %d",
                              l2cap_len, p_msg->len);

        GKI_freebuf (p_msg);
        return;
    }

    /* Send the data through the channel state machine */
    if (rcv_cid == L2CAP_SIGNALLING_CID)
    {
        process_l2cap_cmd (p_lcb, p, l2cap_len);
        GKI_freebuf (p_msg);
    }
    else if (rcv_cid == L2CAP_CONNECTIONLESS_CID)
    {
        /* process_connectionless_data (p_lcb); */
        STREAM_TO_UINT16 (psm, p);
        L2CAP_TRACE_DEBUG1( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ;
#if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
        if (psm == TCS_PSM_INTERCOM || psm == TCS_PSM_CORDLESS)
        {
            p_msg->offset += L2CAP_BCST_OVERHEAD;
            p_msg->len -= L2CAP_BCST_OVERHEAD;
            tcs_proc_bcst_msg( p_lcb->remote_bd_addr, p_msg ) ;
            GKI_freebuf (p_msg);
        }
        else
#endif

#if (L2CAP_UCD_INCLUDED == TRUE)
        /* if it is not broadcast, check UCD registration */
        if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) )
        {
            /* nothing to do */
        }
        else
#endif
            GKI_freebuf (p_msg);
    }
#if (BLE_INCLUDED == TRUE)
    else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID)
    {
        l2cble_process_sig_cmd (p_lcb, p, l2cap_len);
        GKI_freebuf (p_msg);
    }
#endif
#if (L2CAP_NUM_FIXED_CHNLS > 0)
    else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
             (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) )
    {
        /* If no CCB for this channel, allocate one */
        if (l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
        {
            p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];

            if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
                l2c_fcr_proc_pdu (p_ccb, p_msg);
            else
                (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_lcb->remote_bd_addr, p_msg);
        }
        else
            GKI_freebuf (p_msg);
    }
#endif

    else
    {
        if (p_ccb == NULL)
            GKI_freebuf (p_msg);
        else
        {
            /* Basic mode packets go straight to the state machine */
            if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
                l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg);
            else
            {
                /* eRTM or streaming mode, so we need to validate states first */
                if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG))
                    l2c_fcr_proc_pdu (p_ccb, p_msg);
                else
                    GKI_freebuf (p_msg);
            }
        }
    }
}