예제 #1
0
/*******************************************************************************
**
** Function         port_allocate_port
**
** Description      Look through the Port Control Blocks for a free one.  Note
**                  that one server can open several ports with the same SCN
**                  if it can support simulteneous requests from different
**                  clients.
**
** Returns          Pointer to the PORT or NULL if not found
**
*******************************************************************************/
tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr)
{
    tPORT  *p_port = &rfc_cb.port.port[0];
    UINT8  xx, yy;

    for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++)
    {
        if (yy >= MAX_RFC_PORTS)
            yy = 0;

        p_port = &rfc_cb.port.port[yy];
        if (!p_port->in_use)
        {
            memset (p_port, 0, sizeof (tPORT));

            p_port->in_use = TRUE;
            p_port->inx    = yy + 1;

            p_port->dlci   = dlci;
            memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN);

            /* During the open set default state for the port connection */
            port_set_defaults (p_port);

            rfc_cb.rfc.last_port = yy;
            RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy, p_port, rfc_cb.rfc.last_port);
            RFCOMM_TRACE_DEBUG("port_allocate_port:bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
                                bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
            return (p_port);
        }
    }

    /* If here, no free PORT found */
    return (NULL);
}
예제 #2
0
/*******************************************************************************
**
** Function         port_select_mtu
**
** Description      Select MTU which will best serve connection from our
**                  point of view.
**                  If our device is 1.2 or lower we calculate how many DH5s
**                  fit into 1 RFCOMM buffer.
**
**
*******************************************************************************/
void port_select_mtu (tPORT *p_port)
{
    UINT16 packet_size;

    /* Will select MTU only if application did not setup something */
    if (p_port->mtu == 0)
    {
        /* find packet size which connection supports */
        packet_size = btm_get_max_packet_size (p_port->bd_addr);
        if (packet_size == 0)
        {
            /* something is very wrong */
            RFCOMM_TRACE_WARNING ("port_select_mtu bad packet size");
            p_port->mtu = RFCOMM_DEFAULT_MTU;
        }
        else
        {
            /* We try to negotiate MTU that each packet can be split into whole
            number of max packets.  For example if link is 1.2 max packet size is 339 bytes.
            At first calculate how many whole packets it is.  MAX L2CAP is 1691 + 4 overhead.
            1695, that will be 5 Dh5 packets.  Now maximum RFCOMM packet is
            5 * 339 = 1695. Minus 4 bytes L2CAP header 1691.  Minus RFCOMM 6 bytes header overhead 1685

            For EDR 2.0 packet size is 1027.  So we better send RFCOMM packet as 1 3DH5 packet
            1 * 1027 = 1027.  Minus 4 bytes L2CAP header 1023.  Minus RFCOMM 6 bytes header overhead 1017 */
            if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size)
            {
                p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
                RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on connection speed", p_port->mtu);
            }
            else
            {
                p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
                RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
            }
        }
    }
    else
    {
        RFCOMM_TRACE_DEBUG ("port_select_mtu application selected %d", p_port->mtu);
    }
    p_port->credit_rx_max  = (PORT_RX_HIGH_WM / p_port->mtu);
    if( p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM )
        p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
    p_port->credit_rx_low  = (PORT_RX_LOW_WM / p_port->mtu);
    if( p_port->credit_rx_low > PORT_RX_BUF_LOW_WM )
        p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
    p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
    if( p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM )
        p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
    RFCOMM_TRACE_DEBUG ("port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
                          p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
}
예제 #3
0
/*******************************************************************************
**
** Function         port_open_continue
**
** Description      This function is called after security manager completes
**                  required security checks.
**
** Returns          void
**
*******************************************************************************/
int port_open_continue (tPORT *p_port)
{
    tRFC_MCB *p_mcb;

    RFCOMM_TRACE_EVENT ("port_open_continue, p_port:%p", p_port);

    /* Check if multiplexer channel has already been established */
    if ((p_mcb = rfc_alloc_multiplexer_channel (p_port->bd_addr, TRUE)) == NULL) {
        RFCOMM_TRACE_WARNING ("port_open_continue no mx channel");
        port_release_port (p_port);
        return (PORT_NO_RESOURCES);
    }

    p_port->rfc.p_mcb = p_mcb;

    p_mcb->port_inx[p_port->dlci] = p_port->inx;

    /* Connection is up and we know local and remote features, select MTU */
    port_select_mtu (p_port);

    if (p_mcb->state == RFC_MX_STATE_CONNECTED) {
        RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu);
    } else if ((p_mcb->state == RFC_MX_STATE_IDLE)
               || (p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA)) {
        /* In RFC_MX_STATE_IDLE state, MX state machine will create connection           */
        /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate connection */
        /*    after disconnecting is completed                                           */
        RFCOMM_StartReq (p_mcb);
    } else {
        /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */
        /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports */
        RFCOMM_TRACE_DEBUG ("port_open_continue: mx state(%d) mx channel is openning", p_mcb->state);
    }
    return (PORT_SUCCESS);
}
예제 #4
0
/*******************************************************************************
**
** Function         port_find_mcb
**
** Description      This function checks if connection exists to device with
**                  the BD_ADDR.
**
*******************************************************************************/
tRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
{
    int      i;

    for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
        if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
                && !memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN)) {
            /* Multiplexer channel found do not change anything */
            RFCOMM_TRACE_DEBUG("port_find_mcb: found  bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
                               bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
            RFCOMM_TRACE_DEBUG("port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d",
                               i, &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
            return (&rfc_cb.port.rfc_mcb[i]);
        }
    }
    RFCOMM_TRACE_DEBUG("port_find_mcb: not found, bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
                       bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
    return (NULL);
}
예제 #5
0
/*******************************************************************************
**
** Function         PORT_DlcEstablishInd
**
** Description      This function is called from the RFCOMM layer when peer
**                  device wants to establish a new DLC.  If this is not the
**                  first message in the establishment procedure port_handle
**                  has a handle to the port control block otherwise the control
**                  block should be found based on the muliplexer channel and
**                  dlci.  The block should be allocated allocated before
**                  meaning that application already made open.
**
*******************************************************************************/
void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
{
    tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);

    RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", p_mcb, dlci, mtu, p_port);
    RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb addr:%02x:%02x:%02x:%02x:%02x:%02x",
                        p_mcb->bd_addr[0], p_mcb->bd_addr[1], p_mcb->bd_addr[2],
                        p_mcb->bd_addr[3], p_mcb->bd_addr[4], p_mcb->bd_addr[5]);

    if (!p_port) {
        /* This can be a first request for this port */
        p_port = port_find_dlci_port (dlci);
        if (!p_port) {
            RFCOMM_DlcEstablishRsp (p_mcb, dlci, 0, RFCOMM_ERROR);
            return;
        }
        p_mcb->port_inx[dlci] = p_port->inx;
    }

    /* If L2CAP's mtu less then RFCOMM's take it */
    if (mtu && (mtu < p_port->peer_mtu)) {
        p_port->peer_mtu = mtu;
    }

    /* If there was an inactivity timer running for MCB stop it */
    rfc_timer_stop (p_mcb);

    RFCOMM_DlcEstablishRsp (p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS);

    /* This is the server side.  If application wants to know when connection */
    /* is established, thats the place */
    if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED)) {
        (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
    }

    if (p_port->p_mgmt_callback) {
        p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx);
    }

    p_port->state = PORT_STATE_OPENED;
}
예제 #6
0
/*******************************************************************************
**
** Function         rfc_alloc_multiplexer_channel
**
** Description      This function returns existing or new control block for
**                  the BD_ADDR.
**
*******************************************************************************/
tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator)
{
    int i, j;
    tRFC_MCB *p_mcb = NULL;
    RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel: bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
                       bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
    RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d", is_initiator);

    for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
        RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel rfc_cb.port.rfc_mcb[%d].state:%d",
                           i, rfc_cb.port.rfc_mcb[i].state);
        RFCOMM_TRACE_DEBUG("(rfc_cb.port.rfc_mcb[i].bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
                           rfc_cb.port.rfc_mcb[i].bd_addr[0], rfc_cb.port.rfc_mcb[i].bd_addr[1],
                           rfc_cb.port.rfc_mcb[i].bd_addr[2], rfc_cb.port.rfc_mcb[i].bd_addr[3],
                           rfc_cb.port.rfc_mcb[i].bd_addr[4], rfc_cb.port.rfc_mcb[i].bd_addr[5]);

        if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
                && (!memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN))) {
            /* Multiplexer channel found do not change anything */
            /* If there was an inactivity timer running stop it now */
            if (rfc_cb.port.rfc_mcb[i].state == RFC_MX_STATE_CONNECTED) {
                rfc_timer_stop (&rfc_cb.port.rfc_mcb[i]);
            }
            RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, found, state:%d, p_mcb:%p",
                               is_initiator, rfc_cb.port.rfc_mcb[i].state, &rfc_cb.port.rfc_mcb[i]);
            return (&rfc_cb.port.rfc_mcb[i]);
        }
    }

    /* connection with bd_addr does not exist */
    for (i = 0, j = rfc_cb.rfc.last_mux + 1; i < MAX_BD_CONNECTIONS; i++, j++) {
        if (j >= MAX_BD_CONNECTIONS) {
            j = 0;
        }

        p_mcb = &rfc_cb.port.rfc_mcb[j];
        if (rfc_cb.port.rfc_mcb[j].state == RFC_MX_STATE_IDLE) {
            /* New multiplexer control block */
            fixed_queue_free(p_mcb->cmd_q, NULL);
            memset (p_mcb, 0, sizeof (tRFC_MCB));
            memcpy (p_mcb->bd_addr, bd_addr, BD_ADDR_LEN);
            RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, create new p_mcb:%p, index:%d",
                               is_initiator, &rfc_cb.port.rfc_mcb[j], j);

            p_mcb->cmd_q = fixed_queue_new(SIZE_MAX);

            p_mcb->is_initiator = is_initiator;

            rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER);

            rfc_cb.rfc.last_mux = (UINT8) j;
            return (p_mcb);
        }
    }
    return (NULL);
}
예제 #7
0
/*******************************************************************************
**
** Function         port_rfc_send_tx_data
**
** Description      This function is when forward data can be sent to the peer
**
*******************************************************************************/
UINT32 port_rfc_send_tx_data (tPORT *p_port)
{
    UINT32 events = 0;
    BT_HDR *p_buf;

    /* if there is data to be sent */
    if (p_port->tx.queue_size > 0)
    {
        /* while the rfcomm peer is not flow controlling us, and peer is ready */
        while (!p_port->tx.peer_fc && p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready)
        {
            /* get data from tx queue and send it */
            PORT_SCHEDULE_LOCK;

            if ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
            {
                p_port->tx.queue_size -= p_buf->len;

                PORT_SCHEDULE_UNLOCK;

                RFCOMM_TRACE_DEBUG ("Sending RFCOMM_DataReq tx.queue_size=%d", p_port->tx.queue_size);

                RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf);

                events |= PORT_EV_TXCHAR;

                if (p_port->tx.queue_size == 0)
                {
                    events |= PORT_EV_TXEMPTY;
                    break;
                }
            }
            /* queue is empty-- all data sent */
            else
            {
                PORT_SCHEDULE_UNLOCK;

                events |= PORT_EV_TXEMPTY;
                break;
            }
        }
        /* If we flow controlled user based on the queue size enable data again */
        events |= port_flow_control_user (p_port);
    }
    return (events & p_port->ev_mask);
}
예제 #8
0
/*******************************************************************************
**
** Function         PORT_StartInd
**
** Description      This function is called from the RFCOMM layer when
**                  some peer device wants to establish a multiplexer
**                  connection.  Check if there are any ports open with this
**                  or not assigned multiplexer.
**
*******************************************************************************/
void PORT_StartInd (tRFC_MCB *p_mcb)
{
    tPORT *p_port;
    int   i;

    RFCOMM_TRACE_EVENT ("PORT_StartInd");

    p_port = &rfc_cb.port.port[0];
    for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
        if ((p_port->rfc.p_mcb == NULL)
                || (p_port->rfc.p_mcb == p_mcb)) {
            RFCOMM_TRACE_DEBUG("PORT_StartInd, RFCOMM_StartRsp RFCOMM_SUCCESS: p_mcb:%p", p_mcb);
            RFCOMM_StartRsp (p_mcb, RFCOMM_SUCCESS);
            return;
        }
    }
    RFCOMM_StartRsp (p_mcb, RFCOMM_ERROR);
}
/*******************************************************************************
**
** Function         RFCOMM_ConnectInd
**
** Description      This is a callback function called by L2CAP when
**                  L2CA_ConnectInd received.  Allocate multiplexer control block
**                  and dispatch the event to it.
**
*******************************************************************************/
void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
{
    tRFC_MCB *p_mcb = rfc_alloc_multiplexer_channel(bd_addr, FALSE);
    UNUSED(psm);

    if ((p_mcb)&&(p_mcb->state != RFC_MX_STATE_IDLE))
    {
        /* if this is collision case */
        if ((p_mcb->is_initiator)&&(p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF))
        {
            p_mcb->pending_lcid = lcid;
            p_mcb->pending_id   = id;

            /* wait random timeout (2 - 12) to resolve collision */
            /* if peer gives up then local device rejects incoming connection and continues as initiator */
            /* if timeout, local device disconnects outgoing connection and continues as acceptor */
            RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectInd start timer for collision, initiator's LCID(0x%x), acceptor's LCID(0x%x)",
                                  p_mcb->lcid, p_mcb->pending_lcid);

            rfc_timer_start(p_mcb, (UINT16)(GKI_get_tick_count()%10 + 2));
            return;
        }
        else
        {
            /* we cannot accept connection request from peer at this state */
            /* don't update lcid */
            p_mcb = NULL;
        }
    }
    else
    {
        /* store mcb even if null */
        rfc_save_lcid_mcb (p_mcb, lcid);
    }

    if (p_mcb == NULL)
    {
        L2CA_ConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
        return;
    }
    p_mcb->lcid     = lcid;

    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &id);
}
예제 #10
0
/*******************************************************************************
**
** Function         port_find_mcb_dlci_port
**
** Description      Find port on the multiplexer channel based on DLCI.  If
**                  this port with DLCI not found try to use even DLCI.  This
**                  is for the case when client is establishing connection on
**                  none-initiator MCB.
**
** Returns          Pointer to the PORT or NULL if not found
**
*******************************************************************************/
tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci)
{
    UINT8 inx;

    if (!p_mcb)
        return (NULL);

    if (dlci > RFCOMM_MAX_DLCI)
        return (NULL);

    inx = p_mcb->port_inx[dlci];
    if (inx == 0)
    {
        RFCOMM_TRACE_DEBUG("port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb, dlci);
        return (NULL);
    }
    else
        return (&rfc_cb.port.port[inx - 1]);
}
예제 #11
0
/*******************************************************************************
**
** Function         rfc_port_closed
**
** Description      The function is called when port is released based on the
**                  event received from the lower layer, typically L2CAP
**                  connection down, DISC, or DM frame.
**
** Returns          void
**
*******************************************************************************/
void rfc_port_closed (tPORT *p_port)
{
    tRFC_MCB *p_mcb = p_port->rfc.p_mcb;

    RFCOMM_TRACE_DEBUG ("rfc_port_closed");

    rfc_port_timer_stop (p_port);

    p_port->rfc.state = RFC_STATE_CLOSED;

    /* If multiplexer channel was up mark it as down */
    if (p_mcb) {
        p_mcb->port_inx[p_port->dlci] = 0;

        /* If there are no more ports opened on this MCB release it */
        rfc_check_mcb_active (p_mcb);
    }

    /* Notify port that RFC connection is gone */
    port_rfc_closed (p_port, PORT_CLOSED);
}
예제 #12
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) {
        osi_free (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);
        }
        //osi_free (p_buf);
        return;
    } else {
        RFCOMM_TRACE_DEBUG("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);
        osi_free (p_buf);
        return;
    }

    /* Check if rx queue exceeds the limit */
    if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM)
     || (fixed_queue_length(p_port->rx.queue) + 1 > p_port->rx_buf_critical)) {
        RFCOMM_TRACE_EVENT ("PORT_DataInd. Buffer over run. Dropping the buffer");
        osi_free (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;
            }
        }
    }

    osi_mutex_global_lock();

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

    osi_mutex_global_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);
    }
}
예제 #13
0
/*******************************************************************************
**
** Function         rfc_port_sm_opened
**
** Description      This function handles events for the port in the OPENED
**                  state
**
** Returns          void
**
*******************************************************************************/
void rfc_port_sm_opened (tPORT *p_port, UINT16 event, void *p_data)
{
    switch (event) {
    case RFC_EVENT_OPEN:
        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
        return;

    case RFC_EVENT_CLOSE:
        rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
        rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci);
        p_port->rfc.expected_rsp = 0;
        p_port->rfc.state = RFC_STATE_DISC_WAIT_UA;
        return;

    case RFC_EVENT_CLEAR:
        rfc_port_closed (p_port);
        return;

    case RFC_EVENT_DATA:
        /* Send credits in the frame.  Pass them in the layer specific member of the hdr. */
        /* There might be an initial case when we reduced rx_max and credit_rx is still */
        /* bigger.  Make sure that we do not send 255 */
        if ((p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
                && (((BT_HDR *)p_data)->len < p_port->peer_mtu)
                && (!p_port->rx.user_fc)
                && (p_port->credit_rx_max > p_port->credit_rx)) {
            ((BT_HDR *)p_data)->layer_specific = (UINT8) (p_port->credit_rx_max - p_port->credit_rx);
            p_port->credit_rx = p_port->credit_rx_max;
        } else {
            ((BT_HDR *)p_data)->layer_specific = 0;
        }
        rfc_send_buf_uih (p_port->rfc.p_mcb, p_port->dlci, (BT_HDR *)p_data);
        rfc_dec_credit (p_port);
        return;

    case RFC_EVENT_UA:
        return;

    case RFC_EVENT_SABME:
        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
        return;

    case RFC_EVENT_DM:
        PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
        rfc_port_closed (p_port);
        return;

    case RFC_EVENT_DISC:
        p_port->rfc.state = RFC_STATE_CLOSED;
        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
        if (! fixed_queue_is_empty(p_port->rx.queue)) {
            /* give a chance to upper stack to close port properly */
            RFCOMM_TRACE_DEBUG("port queue is not empty");
            rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
        } else {
            PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
        }
        return;

    case RFC_EVENT_UIH:
        rfc_port_uplink_data (p_port, (BT_HDR *)p_data);
        return;

    case RFC_EVENT_TIMEOUT:
        Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ;
        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
        return;
    }
    RFCOMM_TRACE_WARNING ("Port state opened Event ignored %d", event);
}
/*******************************************************************************
**
** Function         RFCOMM_ConnectCnf
**
** Description      This is a callback function called by L2CAP when
**                  L2CA_ConnectCnf received.  Save L2CAP handle and dispatch
**                  event to the FSM.
**
*******************************************************************************/
void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 result)
{
    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);

    if (!p_mcb)
    {
        RFCOMM_TRACE_ERROR ("RFCOMM_ConnectCnf LCID:0x%x", lcid);
        return;
    }

    if (p_mcb->pending_lcid)
    {
        /* if peer rejects our connect request but peer's connect request is pending */
        if (result != L2CAP_CONN_OK )
        {
            UINT16 i;
            UINT8  idx;

            RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", p_mcb->pending_lcid);

            /* remove mcb from mapping table */
            rfc_save_lcid_mcb (NULL, p_mcb->lcid);

            p_mcb->lcid         = p_mcb->pending_lcid;
            p_mcb->is_initiator = FALSE;
            p_mcb->state        = RFC_MX_STATE_IDLE;

            /* store mcb into mapping table */
            rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);

            /* update direction bit */
            for (i = 0; i < RFCOMM_MAX_DLCI; i += 2)
            {
                if ((idx = p_mcb->port_inx[i]) != 0)
                {
                    p_mcb->port_inx[i] = 0;
                    p_mcb->port_inx[i+1] = idx;
                    rfc_cb.port.port[idx - 1].dlci += 1;
                    RFCOMM_TRACE_DEBUG ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci);
                }
            }

            rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
            return;
        }
        else
        {
            RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", p_mcb->pending_lcid);

            /* Peer gave up his connection request, make sure cleaning up L2CAP channel */
            L2CA_ConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0);

            p_mcb->pending_lcid = 0;
        }
    }

    /* Save LCID to be used in all consecutive calls to L2CAP */
    p_mcb->lcid         = lcid;

    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_CNF, &result);
}
예제 #15
0
/*******************************************************************************
**
** Function         port_release_port
**
** Description      Release port infor control block.
**
** Returns          Pointer to the PORT or NULL if not found
**
*******************************************************************************/
void port_release_port (tPORT *p_port)
{
    BT_HDR *p_buf;
    UINT32 mask;
    tPORT_CALLBACK *p_port_cb;
    tPORT_STATE user_port_pars;

    PORT_SCHEDULE_LOCK;
    RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port);
    while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL)
        GKI_freebuf (p_buf);

    p_port->rx.queue_size = 0;

    while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
        GKI_freebuf (p_buf);

    p_port->tx.queue_size = 0;

    PORT_SCHEDULE_UNLOCK;

    p_port->state = PORT_STATE_CLOSED;

    if (p_port->rfc.state == RFC_STATE_CLOSED)
    {
        RFCOMM_TRACE_DEBUG ("rfc_port_closed DONE");
        if (p_port->rfc.p_mcb)
        {
            p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;

            /* If there are no more ports opened on this MCB release it */
            rfc_check_mcb_active (p_port->rfc.p_mcb);
        }
        rfc_port_timer_stop (p_port);
        RFCOMM_TRACE_DEBUG ("port_release_port:p_port->keep_port_handle:%d", p_port->keep_port_handle);
        if( p_port->keep_port_handle )
        {
            RFCOMM_TRACE_DEBUG ("port_release_port:Initialize handle:%d", p_port->inx);
            /* save event mask and callback */
            mask = p_port->ev_mask;
            p_port_cb = p_port->p_callback;
            user_port_pars = p_port->user_port_pars;

            port_set_defaults(p_port);
            /* restore */
            p_port->ev_mask         = mask;
            p_port->p_callback      = p_port_cb;
            p_port->user_port_pars  = user_port_pars;
            p_port->mtu             = p_port->keep_mtu;

            p_port->state           = PORT_STATE_OPENING;
            p_port->rfc.p_mcb       = NULL;
            if(p_port->is_server)
                p_port->dlci       &= 0xfe;

            p_port->local_ctrl.modem_signal = p_port->default_signal_state;
            memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
        }
        else
        {
            RFCOMM_TRACE_DEBUG ("port_release_port:Clean-up handle:%d", p_port->inx);
            memset (p_port, 0, sizeof (tPORT));
        }
    }
}