Exemple #1
0
/*******************************************************************************
**
** Function         gatt_notify_enc_cmpl
**
** Description      link encryption complete notification for all encryption process
**                  initiated outside GATT.
**
** Returns
**
*******************************************************************************/
void gatt_notify_enc_cmpl(BD_ADDR bd_addr)
{
    tGATT_TCB   *p_tcb;
    tGATT_PENDING_ENC_CLCB  *p_buf;
    UINT16       count;
    UINT8        i = 0;

    if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL) {
        for (i = 0; i < GATT_MAX_APPS; i++) {
            if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) {
                (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr);
            }
        }

        if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
            gatt_set_sec_act(p_tcb, GATT_SEC_NONE);

            count = GKI_queue_length(&p_tcb->pending_enc_clcb);

            for (; count > 0; count --) {
                if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) {
                    gatt_security_check_start(p_buf->p_clcb);
                    GKI_freebuf(p_buf);
                } else {
                    break;
                }
            }
        }
    } else {
        GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device");
    }
    return;
}
Exemple #2
0
/*******************************************************************************
**
** Function         port_flow_control_user
**
** Description      Check the current user flow control and if necessary return
**                  events to be send to the user based on the user's specified
**                  flow control type.
**
** Returns          event mask to be returned to the application
**
*******************************************************************************/
UINT32 port_flow_control_user (tPORT *p_port)
{
    UINT32 event = 0;

    /* Flow control to the user can be caused by flow controlling by the peer */
    /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
    /* tx_queue is full */
    BOOLEAN fc = p_port->tx.peer_fc
              || !p_port->rfc.p_mcb
              || !p_port->rfc.p_mcb->peer_ready
              || (p_port->tx.queue_size > PORT_TX_HIGH_WM)
              || (GKI_queue_length(&p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);

    if (p_port->tx.user_fc == fc)
        return (0);

    p_port->tx.user_fc = fc;

    if (fc)
        event = PORT_EV_FC;
    else
        event = PORT_EV_FC | PORT_EV_FCS;

    return (event);
}
Exemple #3
0
/*******************************************************************************
**
** Function         gatt_enc_cmpl_cback
**
** Description      link encryption complete callback.
**
** Returns
**
*******************************************************************************/
void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, tBTM_STATUS result)
{
    tGATT_TCB   *p_tcb;
    UINT8       sec_flag;
    BOOLEAN     status = FALSE;
    tGATT_PENDING_ENC_CLCB  *p_buf;
    UINT16       count;
    UNUSED(p_ref_data);

    GATT_TRACE_DEBUG("gatt_enc_cmpl_cback");
    if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL) {
        if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
            return;
        }

        if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) {
            if (result == BTM_SUCCESS) {
                if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM ) {
                    BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport);

                    if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
                        status = TRUE;
                    }
                } else {
                    status = TRUE;
                }
            }
            gatt_sec_check_complete(status , p_buf->p_clcb, p_tcb->sec_act);
            GKI_freebuf(p_buf);
            /* start all other pending operation in queue */
            count = GKI_queue_length(&p_tcb->pending_enc_clcb);
            for (; count > 0; count --) {
                if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) {
                    gatt_security_check_start(p_buf->p_clcb);
                    GKI_freebuf(p_buf);
                } else {
                    break;
                }
            }
        } else {
            GATT_TRACE_ERROR("Unknown operation encryption completed");
        }
    } else {
        GATT_TRACE_ERROR("enc callback for unknown bd_addr");
    }
}
Exemple #4
0
UINT8 l2c_data_write (UINT16 cid, BT_HDR *p_data, UINT16 flags)
{
    tL2C_CCB        *p_ccb;

    /* Find the channel control block. We don't know the link it is on. */
    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) {
        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid);
        GKI_freebuf (p_data);
        return (L2CAP_DW_FAILED);
    }

#ifndef TESTER /* Tester may send any amount of data. otherwise sending message
                  bigger than mtu size of peer is a violation of protocol */
    if (p_data->len > p_ccb->peer_cfg.mtu) {
        L2CAP_TRACE_WARNING ("L2CAP - CID: 0x%04x  cannot send message bigger than peer's mtu size", cid);
        GKI_freebuf (p_data);
        return (L2CAP_DW_FAILED);
    }
#endif

    /* channel based, packet based flushable or non-flushable */
    p_data->layer_specific = flags;

    /* If already congested, do not accept any more packets */
    if (p_ccb->cong_sent) {
        L2CAP_TRACE_ERROR ("L2CAP - CID: 0x%04x cannot send, already congested  xmit_hold_q.count: %u  buff_quota: %u",
                           p_ccb->local_cid, GKI_queue_length(&p_ccb->xmit_hold_q), p_ccb->buff_quota);

        GKI_freebuf (p_data);
        return (L2CAP_DW_FAILED);
    }

    //counter_add("l2cap.dyn.tx.bytes", p_data->len);
    //counter_add("l2cap.dyn.tx.pkts", 1);

    l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_data);

    if (p_ccb->cong_sent) {
        return (L2CAP_DW_CONGESTED);
    }
    return (L2CAP_DW_SUCCESS);
}
Exemple #5
0
/*******************************************************************************
**
** Function         port_flow_control_peer
**
** Description      Send flow control messages to the peer for both enabling
**                  and disabling flow control, for both credit-based and
**                  TS 07.10 flow control mechanisms.
**
** Returns          nothing
**
*******************************************************************************/
void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
{
    if (!p_port->rfc.p_mcb)
        return;

    /* If using credit based flow control */
    if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
    {
        /* if want to enable flow from peer */
        if (enable)
        {
            /* update rx credits */
            if (count > p_port->credit_rx)
            {
                p_port->credit_rx = 0;
            }
            else
            {
                p_port->credit_rx -= count;
            }

            /* If credit count is less than low credit watermark, and user */
            /* did not force flow control, send a credit update */
            /* There might be a special case when we just adjusted rx_max */
            if ((p_port->credit_rx <= p_port->credit_rx_low)
             && !p_port->rx.user_fc
             && (p_port->credit_rx_max > p_port->credit_rx))
            {
                rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
                                (UINT8) (p_port->credit_rx_max - p_port->credit_rx));

                p_port->credit_rx = p_port->credit_rx_max;

                p_port->rx.peer_fc = FALSE;
            }
        }
        /* else want to disable flow from peer */
        else
        {
            /* if client registered data callback, just do what they want */
            if (p_port->p_data_callback || p_port->p_data_co_callback)
            {
                p_port->rx.peer_fc = TRUE;
            }
            /* if queue count reached credit rx max, set peer fc */
            else if (GKI_queue_length(&p_port->rx.queue) >= p_port->credit_rx_max)
            {
                p_port->rx.peer_fc = TRUE;
            }
        }
    }
    /* else using TS 07.10 flow control */
    else
    {
        /* if want to enable flow from peer */
        if (enable)
        {
            /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
            /* check if it can be resumed now */
            if (p_port->rx.peer_fc
             && (p_port->rx.queue_size < PORT_RX_LOW_WM)
             && (GKI_queue_length(&p_port->rx.queue) < PORT_RX_BUF_LOW_WM))
            {
                p_port->rx.peer_fc = FALSE;

                /* If user did not force flow control allow traffic now */
                if (!p_port->rx.user_fc)
                    RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, TRUE);
            }
        }
        /* else want to disable flow from peer */
        else
        {
            /* if client registered data callback, just do what they want */
            if (p_port->p_data_callback || p_port->p_data_co_callback)
            {
                p_port->rx.peer_fc = TRUE;
                RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
            }
            /* Check the size of the rx queue.  If it exceeds certain */
            /* level and flow control has not been sent to the peer do it now */
            else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
                     || (GKI_queue_length(&p_port->rx.queue) > PORT_RX_BUF_HIGH_WM))
                     && !p_port->rx.peer_fc)
            {
                RFCOMM_TRACE_EVENT ("PORT_DataInd Data reached HW. Sending FC set.");

                p_port->rx.peer_fc = TRUE;
                RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
            }
        }
    }
}
Exemple #6
0
/*******************************************************************************
**
** Function         PORT_DataInd
**
** Description      This function is called from the RFCOMM layer when data
**                  buffer is received from the peer.
**
*******************************************************************************/
void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
{
    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
    UINT8  rx_char1;
    UINT32 events = 0;
    UINT8  *p;
    int    i;

    RFCOMM_TRACE_EVENT("PORT_DataInd with data length %d, p_mcb:%p,p_port:%p,dlci:%d",
                        p_buf->len, p_mcb, p_port, dlci);
    if (!p_port)
    {
        GKI_freebuf (p_buf);
        return;
    }
    /* If client registered callout callback with flow control we can just deliver receive data */
    if (p_port->p_data_co_callback)
    {
        /* Another packet is delivered to user.  Send credits to peer if required */

        if(p_port->p_data_co_callback(p_port->inx, (UINT8*)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING))
            port_flow_control_peer(p_port, TRUE, 1);
        else port_flow_control_peer(p_port, FALSE, 0);
        //GKI_freebuf (p_buf);
        return;
    }
    else RFCOMM_TRACE_ERROR("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port);
    /* If client registered callback we can just deliver receive data */
    if (p_port->p_data_callback)
    {
        /* Another packet is delivered to user.  Send credits to peer if required */
        port_flow_control_peer(p_port, TRUE, 1);

        p_port->p_data_callback (p_port->inx, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
        GKI_freebuf (p_buf);
        return;
    }

    /* Check if rx queue exceeds the limit */
    if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM)
     || (GKI_queue_length(&p_port->rx.queue) + 1 > p_port->rx_buf_critical))
    {
        RFCOMM_TRACE_EVENT ("PORT_DataInd. Buffer over run. Dropping the buffer");
        GKI_freebuf (p_buf);

        RFCOMM_LineStatusReq (p_mcb, dlci, LINE_STATUS_OVERRUN);
        return;
    }

    /* If user registered to receive notification when a particular byte is */
    /* received we mast check all received bytes */
    if (((rx_char1 = p_port->user_port_pars.rx_char1) != 0)
     && (p_port->ev_mask & PORT_EV_RXFLAG))
    {
        for (i = 0, p = (UINT8 *)(p_buf + 1) + p_buf->offset; i < p_buf->len; i++)
        {
            if (*p++ == rx_char1)
            {
                events |= PORT_EV_RXFLAG;
                break;
            }
        }
    }

    PORT_SCHEDULE_LOCK;

    GKI_enqueue (&p_port->rx.queue, p_buf);
    p_port->rx.queue_size += p_buf->len;

    PORT_SCHEDULE_UNLOCK;

    /* perform flow control procedures if necessary */
    port_flow_control_peer(p_port, FALSE, 0);

    /* If user indicated flow control can not deliver any notifications to him */
    if (p_port->rx.user_fc)
    {
        if (events & PORT_EV_RXFLAG)
            p_port->rx_flag_ev_pending = TRUE;

        return;
    }

    events |= PORT_EV_RXCHAR;

    /* Mask out all events that are not of interest to user */
    events &= p_port->ev_mask;

    if (p_port->p_callback && events)
        p_port->p_callback (events, p_port->inx);
}