Example #1
0
/*******************************************************************************
**
** Function         PORT_PortNegCnf
**
** Description      This function is called from the RFCOMM layer to change
**                  state for the port.  Propagate change to the user.
**
*******************************************************************************/
void PORT_PortNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 result)
{
    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
    UNUSED(p_pars);

    RFCOMM_TRACE_EVENT ("PORT_PortNegCnf");

    if (!p_port) {
        RFCOMM_TRACE_WARNING ("PORT_PortNegCnf no port");
        return;
    }
    /* Port negotiation failed. Drop the connection */
    if (result != RFCOMM_SUCCESS) {
        p_port->error = PORT_PORT_NEG_FAILED;

        RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci);

        port_rfc_closed (p_port, PORT_PORT_NEG_FAILED);
        return;
    }

    if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT)) {
        RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
    } else {
        RFCOMM_TRACE_WARNING ("PORT_PortNegCnf Control Already sent");
    }
}
Example #2
0
/*******************************************************************************
**
** Function         rfc_process_pn
**
** Description      This function handles DLC parameter negotiation frame.
**                  Record MTU and pass indication to the upper layer.
**
*******************************************************************************/
void rfc_process_pn (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame)
{
    tPORT *p_port;
    UINT8 dlci = p_frame->dlci;

    if (is_command) {
        /* Ignore if Multiplexer is being shut down */
        if (p_mcb->state != RFC_MX_STATE_DISC_WAIT_UA) {
            PORT_ParNegInd (p_mcb, dlci, p_frame->u.pn.mtu,
                            p_frame->u.pn.conv_layer, p_frame->u.pn.k);
        } else {
            rfc_send_dm(p_mcb, dlci, FALSE);
            RFCOMM_TRACE_WARNING("***** MX PN while disconnecting *****");
        }

        return;
    }
    /* If we are not awaiting response just ignore it */
    p_port = port_find_mcb_dlci_port (p_mcb, dlci);
    if ((p_port == NULL) || !(p_port->rfc.expected_rsp & RFC_RSP_PN)) {
        return;
    }

    p_port->rfc.expected_rsp &= ~RFC_RSP_PN;

    rfc_port_timer_stop (p_port);

    PORT_ParNegCnf (p_mcb, dlci, p_frame->u.pn.mtu,
                    p_frame->u.pn.conv_layer, p_frame->u.pn.k);
}
Example #3
0
/*******************************************************************************
**
** Function         rfc_port_sm_execute
**
** Description      This function sends port events through the state
**                  machine.
**
** Returns          void
**
*******************************************************************************/
void rfc_port_sm_execute (tPORT *p_port, UINT16 event, void *p_data)
{
    if (!p_port) {
        RFCOMM_TRACE_WARNING ("NULL port event %d", event);
        return;
    }

    switch (p_port->rfc.state) {
    case RFC_STATE_CLOSED:
        rfc_port_sm_state_closed (p_port, event, p_data);
        break;

    case RFC_STATE_SABME_WAIT_UA:
        rfc_port_sm_sabme_wait_ua (p_port, event, p_data);
        break;

    case RFC_STATE_ORIG_WAIT_SEC_CHECK:
        rfc_port_sm_orig_wait_sec_check (p_port, event, p_data);
        break;

    case RFC_STATE_TERM_WAIT_SEC_CHECK:
        rfc_port_sm_term_wait_sec_check (p_port, event, p_data);
        break;

    case RFC_STATE_OPENED:
        rfc_port_sm_opened (p_port, event, p_data);
        break;

    case RFC_STATE_DISC_WAIT_UA:
        rfc_port_sm_disc_wait_ua (p_port, event, p_data);
        break;
    }
}
Example #4
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);
}
Example #5
0
/*******************************************************************************
**
** Function         RFCOMM_PortNegReq
**
** Description      This function is called by the user app to start
**                  Remote Port parameter negotiation.  Port emulation can
**                  send this request before actually establishing the DLC.
**                  In this case the function will allocate RFCOMM connection
**                  control block.
**
*******************************************************************************/
void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars)
{
    if (p_mcb->state != RFC_MX_STATE_CONNECTED)
    {
        PORT_PortNegCnf (p_mcb, dlci, NULL, RFCOMM_ERROR);
        return;
    }

    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    if (p_port == NULL) {
        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
                dlci);
        return;
    }

    /* Send Parameter Negotiation Command UIH frame */
    if (!p_pars)
        p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
    else
        p_port->rfc.expected_rsp |= RFC_RSP_RPN;

    rfc_send_rpn (p_mcb, dlci, TRUE, p_pars, RFCOMM_RPN_PM_MASK);
    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;

}
Example #6
0
/*******************************************************************************
**
** Function         port_rfc_closed
**
** Description      This function when RFCOMM side of port is closed
**
*******************************************************************************/
void port_rfc_closed (tPORT *p_port, UINT8 res)
{
    UINT8     old_signals;
    UINT32    events = 0;
    tRFC_MCB *p_mcb = p_port->rfc.p_mcb;

    if ((p_port->state == PORT_STATE_OPENING) && (p_port->is_server)) {
        /* The servr side has not been informed that connection is up, ignore */
        RFCOMM_TRACE_EVENT ("port_rfc_closed in OPENING state ignored");

        rfc_port_timer_stop (p_port);
        p_port->rfc.state = RFC_STATE_CLOSED;

        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);
            p_port->rfc.p_mcb = NULL;
        }

        /* Need to restore DLCI to listening state
         * if the server was on the initiating RFC
         */
        p_port->dlci &= 0xfe;

        return;
    }

    if ((p_port->state != PORT_STATE_CLOSING) && (p_port->state != PORT_STATE_CLOSED)) {
        p_port->line_status |= LINE_STATUS_FAILED;

        old_signals = p_port->peer_ctrl.modem_signal;

        p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);

        events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal);

        if (p_port->ev_mask & PORT_EV_CONNECT_ERR) {
            events |= PORT_EV_CONNECT_ERR;
        }
    }
    RFCOMM_TRACE_EVENT ("port_rfc_closed state:%d sending events:%x", p_port->state, events);

    if ((p_port->p_callback != NULL) && events) {
        p_port->p_callback (events, p_port->inx);
    }

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

    p_port->rfc.state = RFC_STATE_CLOSED;

    RFCOMM_TRACE_WARNING ("%s RFCOMM connection in state %d closed: %s (res: %d)",
                          __func__, p_port->state, PORT_GetResultString(res), res);

    port_release_port (p_port);
}
Example #7
0
/*******************************************************************************
**
** Function         rfc_port_sm_sabme_wait_ua
**
** Description      This function handles events when SABME on the DLC was
**                  sent and SM is waiting for UA or DM.
**
** Returns          void
**
*******************************************************************************/
void rfc_port_sm_sabme_wait_ua (tPORT *p_port, UINT16 event, void *p_data)
{
    switch (event)
    {
    case RFC_EVENT_OPEN:
    case RFC_EVENT_ESTABLISH_RSP:
        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:
        GKI_freebuf (p_data);
        break;

    case RFC_EVENT_UA:
        rfc_port_timer_stop (p_port);
        p_port->rfc.state = RFC_STATE_OPENED;
        PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_SUCCESS);
        return;

    case RFC_EVENT_DM:
        p_port->rfc.p_mcb->is_disc_initiator = TRUE;
        PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
        rfc_port_closed (p_port);
        return;

    case RFC_EVENT_DISC:
        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
        PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
        rfc_port_closed (p_port);
        return;

    case RFC_EVENT_SABME:
        /* Continue to wait for the UA the SABME this side sent */
        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
        return;

    case RFC_EVENT_UIH:
        GKI_freebuf (p_data);
        return;

    case RFC_EVENT_TIMEOUT:
        p_port->rfc.state = RFC_STATE_CLOSED;
        PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
        return;
    }
    RFCOMM_TRACE_WARNING ("Port state sabme_wait_ua Event ignored %d", event);
}
Example #8
0
/*******************************************************************************
**
** Function         rfc_port_sm_state_closed
**
** Description      This function handles events when the port is in
**                  CLOSED state. This state exists when port is
**                  being initially established.
**
** Returns          void
**
*******************************************************************************/
void rfc_port_sm_state_closed (tPORT *p_port, UINT16 event, void *p_data)
{
    switch (event)
    {
    case RFC_EVENT_OPEN:
        p_port->rfc.state = RFC_STATE_ORIG_WAIT_SEC_CHECK;
        btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, TRUE,
                                   BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2),
                                   &rfc_sec_check_complete, p_port);
        return;

    case RFC_EVENT_CLOSE:
        break;

    case RFC_EVENT_CLEAR:
        return;

    case RFC_EVENT_DATA:
        GKI_freebuf (p_data);
        break;

    case RFC_EVENT_SABME:
        /* make sure the multiplexer disconnect timer is not running (reconnect case) */
        rfc_timer_stop(p_port->rfc.p_mcb );

        /* Open will be continued after security checks are passed */
        p_port->rfc.state = RFC_STATE_TERM_WAIT_SEC_CHECK;
        btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, FALSE,
                                   BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2),
                                   &rfc_sec_check_complete, p_port);
        return;

    case RFC_EVENT_UA:
        return;

    case RFC_EVENT_DM:
        rfc_port_closed (p_port);
        return;

    case RFC_EVENT_UIH:
        GKI_freebuf (p_data);
        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
        return;

    case RFC_EVENT_DISC:
        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
        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 closed Event ignored %d", event);
    return;
}
Example #9
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);
}
Example #10
0
/*******************************************************************************
**
** Function         PORT_StartCnf
**
** Description      This function is called from the RFCOMM layer when
**                  establishing of the multiplexer channel is completed.
**                  Continue establishing of the connection for all ports that
**                  are in the OPENING state
**
*******************************************************************************/
void PORT_StartCnf (tRFC_MCB *p_mcb, UINT16 result)
{
    tPORT   *p_port;
    int     i;
    BOOLEAN no_ports_up = TRUE;

    RFCOMM_TRACE_EVENT ("PORT_StartCnf result:%d", result);

    p_port = &rfc_cb.port.port[0];
    for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
    {
        if (p_port->rfc.p_mcb == p_mcb)
        {
            no_ports_up = FALSE;

            if (result == RFCOMM_SUCCESS)
                RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu);
            else
            {
                RFCOMM_TRACE_WARNING ("PORT_StartCnf failed result:%d", result);

                /* Warning: result is also set to 4 when l2cap connection
                   fails due to l2cap connect cnf (no_resources) */
                if( result == HCI_ERR_PAGE_TIMEOUT )
                    p_port->error = PORT_PAGE_TIMEOUT;
                else
                    p_port->error = PORT_START_FAILED;

                rfc_release_multiplexer_channel (p_mcb);
                p_port->rfc.p_mcb = NULL;

                /* Send event to the application */
                if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR))
                    (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx);

                if (p_port->p_mgmt_callback)
                    p_port->p_mgmt_callback (PORT_START_FAILED, p_port->inx);

                port_release_port (p_port);
            }
        }
    }

    /* There can be a situation when after starting connection, user closes the */
    /* port, we can catch it here to close multiplexor channel */
    if (no_ports_up)
    {
        rfc_check_mcb_active (p_mcb);
    }
}
Example #11
0
/*******************************************************************************
**
** Function         RFCOMM_DlcEstablishRsp
**
** Description      This function is called by the port emulation entity
**                  acks Establish Indication.
**
*******************************************************************************/
void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result)
{
    UNUSED(mtu);
    if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS))
    {
        PORT_DlcReleaseInd (p_mcb, dlci);
        return;
    }

    tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
    if (p_port == NULL) {
        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
                dlci);
        return;
    }
    rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result);
}
/*******************************************************************************
**
** Function         RFCOMM_DisconnectInd
**
** Description      This is a callback function called by L2CAP when
**                  L2CA_DisconnectInd received.  Dispatch event to the FSM.
**
*******************************************************************************/
void RFCOMM_DisconnectInd (UINT16 lcid, BOOLEAN is_conf_needed)
{
    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);

    if (is_conf_needed)
    {
        L2CA_DisconnectRsp (lcid);
    }

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

    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_DISC_IND, NULL);
}
Example #13
0
/*******************************************************************************
**
** Function         rfc_port_sm_disc_wait_ua
**
** Description      This function handles events when DISC on the DLC was
**                  sent and SM is waiting for UA or DM.
**
** Returns          void
**
*******************************************************************************/
void rfc_port_sm_disc_wait_ua (tPORT *p_port, UINT16 event, void *p_data)
{
    switch (event)
    {
    case RFC_EVENT_OPEN:
    case RFC_EVENT_ESTABLISH_RSP:
        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
        return;

    case RFC_EVENT_CLEAR:
        rfc_port_closed (p_port);
        return;

    case RFC_EVENT_DATA:
        GKI_freebuf (p_data);
        return;

    case RFC_EVENT_UA:
        p_port->rfc.p_mcb->is_disc_initiator = TRUE;
        /* Case falls through */

   case RFC_EVENT_DM:
        rfc_port_closed (p_port);
        return;

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

    case RFC_EVENT_DISC:
        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
        return;

    case RFC_EVENT_UIH:
        GKI_freebuf (p_data);
        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
        return;

    case RFC_EVENT_TIMEOUT:
        rfc_port_closed (p_port);
        return;
    }

    RFCOMM_TRACE_WARNING ("Port state disc_wait_ua Event ignored %d", event);
}
Example #14
0
/*******************************************************************************
**
** Function         RFCOMM_DlcEstablishReq
**
** Description      This function is called by the user app to establish
**                  connection with the specific dlci on a specific bd device.
**                  It will allocate RFCOMM connection control block if not
**                  allocated before and dispatch open event to the state
**                  machine.
**
*******************************************************************************/
void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
{
    UNUSED(mtu);
    if (p_mcb->state != RFC_MX_STATE_CONNECTED)
    {
        PORT_DlcEstablishCnf (p_mcb, dlci, 0, RFCOMM_ERROR);
        return;
    }

    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    if (p_port == NULL) {
        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
                dlci);
        return;
    }

    rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, NULL);
}
Example #15
0
/*******************************************************************************
**
** Function         RFCOMM_LineStatusReq
**
** Description      This function is called by the port entity when line
**                  status should be delivered to the peer.
**
*******************************************************************************/
void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 status)
{
    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    if (p_port == NULL) {
        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
                dlci);
        return;
    }

    if ((p_port->state != PORT_STATE_OPENED)
     || (p_port->rfc.state  != RFC_STATE_OPENED))
        return;

    p_port->rfc.expected_rsp |= RFC_RSP_RLS;

    rfc_send_rls (p_mcb, dlci, TRUE, status);
    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT);
}
Example #16
0
/*******************************************************************************
**
** Function         RFCOMM_ParNegReq
**
** Description      This function is called by the user app to start
**                  DLC parameter negotiation.  Port emulation can send this
**                  request before actually establishing the DLC.  In this
**                  case the function will allocate RFCOMM connection control
**                  block.
**
*******************************************************************************/
void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
{
    UINT8 flow;
    UINT8 cl;
    UINT8 k;

    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    if (p_port == NULL) {
        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
                dlci);
        return;
    }

    if (p_mcb->state != RFC_MX_STATE_CONNECTED)
    {
        p_port->error = PORT_PAR_NEG_FAILED;
        return;
    }

    /* Negotiate the flow control mechanism.  If flow control mechanism for */
    /* mux has not been set yet, use our default value.  If it has been set, */
    /* use that value. */
    flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_DEFAULT : p_mcb->flow;

    /* Set convergence layer and number of credits (k) */
    if (flow == PORT_FC_CREDIT)
    {
        cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
        k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
        p_port->credit_rx = k;
    }
    else
    {
        cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
        k = 0;
    }

    /* Send Parameter Negotiation Command UIH frame */
    p_port->rfc.expected_rsp |= RFC_RSP_PN;

    rfc_send_pn (p_mcb, dlci, TRUE, mtu, cl, k);

    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
}
Example #17
0
/*******************************************************************************
**
** Function         RFCOMM_FlowReq
**
** Description      This function is called by the port entity when flow
**                  control state has changed.  Enable flag passed shows if
**                  port can accept more data.
**
*******************************************************************************/
void RFCOMM_FlowReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 enable)
{
    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    if (p_port == NULL) {
        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
                dlci);
        return;
    }

    if ((p_port->state != PORT_STATE_OPENED)
     || (p_port->rfc.state  != RFC_STATE_OPENED))
        return;

    p_port->local_ctrl.fc = !enable;

    p_port->rfc.expected_rsp |= RFC_RSP_MSC;

    rfc_send_msc (p_mcb, dlci, TRUE, &p_port->local_ctrl);
    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;

}
Example #18
0
/*******************************************************************************
**
** Function         RFCOMM_ControlReq
**
** Description      This function is called by the port entity to send control
**                  parameters to remote port emulation entity.
**
*******************************************************************************/
void RFCOMM_ControlReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars)
{
    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    if (p_port == NULL) {
        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
                dlci);
        return;
    }

    if ((p_port->state != PORT_STATE_OPENED)
     || (p_port->rfc.state  != RFC_STATE_OPENED))
        return;

    p_port->port_ctrl |= PORT_CTRL_REQ_SENT;

    p_port->rfc.expected_rsp |= RFC_RSP_MSC;

    rfc_send_msc (p_mcb, dlci, TRUE, p_pars);
    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;

}
/*******************************************************************************
**
** Function         rfc_find_lcid_mcb
**
** Description      This function returns MCB block supporting local cid
**
*******************************************************************************/
tRFC_MCB *rfc_find_lcid_mcb (UINT16 lcid)
{
    tRFC_MCB *p_mcb;

    if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS)
    {
        RFCOMM_TRACE_ERROR ("rfc_find_lcid_mcb LCID:0x%x", lcid);
        return (NULL);
    }
    else
    {
        if ((p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID]) != NULL)
        {
            if (p_mcb->lcid != lcid)
            {
                RFCOMM_TRACE_WARNING ("rfc_find_lcid_mcb LCID reused LCID:0x%x current:0x%x", lcid, p_mcb->lcid);
                return (NULL);
            }
        }
    }
    return (p_mcb);
}
Example #20
0
/*******************************************************************************
**
** Function         rfc_port_sm_orig_wait_sec_check
**
** Description      This function handles events for the port in the
**                  ORIG_WAIT_SEC_CHECK state.  RFCOMM is waiting for Security
**                  manager to finish before sending SABME to the peer
**
** Returns          void
**
*******************************************************************************/
void rfc_port_sm_orig_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data)
{
    switch (event)
    {
    case RFC_EVENT_SEC_COMPLETE:
        if (*((UINT8 *)p_data) != BTM_SUCCESS)
        {
            p_port->rfc.p_mcb->is_disc_initiator = TRUE;
            PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, 0, RFCOMM_SECURITY_ERR);
            rfc_port_closed (p_port);
            return;
        }
        rfc_send_sabme (p_port->rfc.p_mcb, p_port->dlci);
        rfc_port_timer_start (p_port, RFC_PORT_T1_TIMEOUT);
        p_port->rfc.state = RFC_STATE_SABME_WAIT_UA;
        return;

    case RFC_EVENT_OPEN:
    case RFC_EVENT_SABME:       /* Peer should not use the same dlci */
        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
        return;

    case RFC_EVENT_CLOSE:
        btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
        rfc_port_closed (p_port);
        return;

    case RFC_EVENT_DATA:
        RFCOMM_TRACE_ERROR ("Port error state Orig Wait Sec event Data");
        GKI_freebuf (p_data);
        return;

    case RFC_EVENT_UIH:
        GKI_freebuf (p_data);
        return;
    }
    RFCOMM_TRACE_WARNING ("Port state orig_wait_sec_check Event ignored %d", event);
}
Example #21
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);
}
Example #22
0
/*******************************************************************************
**
** Function         rfc_port_sm_term_wait_sec_check
**
** Description      This function handles events for the port in the
**                  WAIT_SEC_CHECK state.  SABME has been received from the
**                  peer and Security Manager verifes BD_ADDR, before we can
**                  send ESTABLISH_IND to the Port entity
**
** Returns          void
**
*******************************************************************************/
void rfc_port_sm_term_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data)
{
    switch (event) {
    case RFC_EVENT_SEC_COMPLETE:
        if (*((UINT8 *)p_data) != BTM_SUCCESS) {
            /* Authentication/authorization failed.  If link is still  */
            /* up send DM and check if we need to start inactive timer */
            if (p_port->rfc.p_mcb) {
                rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
                p_port->rfc.p_mcb->is_disc_initiator = TRUE;
                port_rfc_closed (p_port, PORT_SEC_FAILED);
            }
        } else {
            PORT_DlcEstablishInd (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu);
        }
        return;

    case RFC_EVENT_OPEN:
    case RFC_EVENT_CLOSE:
        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
        return;

    case RFC_EVENT_CLEAR:
        btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
        rfc_port_closed (p_port);
        return;

    case RFC_EVENT_DATA:
        RFCOMM_TRACE_ERROR ("Port error state Term Wait Sec event Data");
        osi_free (p_data);
        return;

    case RFC_EVENT_SABME:
        /* Ignore SABME retransmission if client dares to do so */
        return;

    case RFC_EVENT_DISC:
        btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
        p_port->rfc.state = RFC_STATE_CLOSED;
        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);

        PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
        return;

    case RFC_EVENT_UIH:
        osi_free (p_data);
        return;

    case RFC_EVENT_ESTABLISH_RSP:
        if (*((UINT8 *)p_data) != RFCOMM_SUCCESS) {
            if (p_port->rfc.p_mcb) {
                rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
            }
        } else {
            rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
            p_port->rfc.state = RFC_STATE_OPENED;
        }
        return;
    }
    RFCOMM_TRACE_WARNING ("Port state term_wait_sec_check Event ignored %d", event);
}
/*******************************************************************************
**
** Function         RFCOMM_BufDataInd
**
** Description      This is a callback function called by L2CAP when
**                  data RFCOMM frame is received.  Parse the frames, check
**                  the checksum and dispatch event to multiplexer or port
**                  state machine depending on the frame destination.
**
*******************************************************************************/
void RFCOMM_BufDataInd (UINT16 lcid, BT_HDR *p_buf)
{
    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
    tPORT    *p_port;
    UINT8    event;


    if (!p_mcb)
    {
        RFCOMM_TRACE_WARNING ("RFCOMM_BufDataInd LCID:0x%x", lcid);
        GKI_freebuf (p_buf);
        return;
    }

    event = rfc_parse_data (p_mcb, &rfc_cb.rfc.rx_frame, p_buf);

    /* If the frame did not pass validation just ignore it */
    if (event == RFC_EVENT_BAD_FRAME)
    {
        GKI_freebuf (p_buf);
        return;
    }

    if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI)
    {
        /* Take special care of the Multiplexer Control Messages */
        if (event == RFC_EVENT_UIH)
        {
            rfc_process_mx_message (p_mcb, p_buf);
            return;
        }

        /* Other multiplexer events go to state machine */
        rfc_mx_sm_execute (p_mcb, event, NULL);
        GKI_freebuf (p_buf);
        return;
    }

    /* The frame was received on the data channel DLCI, verify that DLC exists */
    if (((p_port = port_find_mcb_dlci_port (p_mcb, rfc_cb.rfc.rx_frame.dlci)) == NULL)
     || (!p_port->rfc.p_mcb))
    {
        /* If this is a SABME on the new port, check if any appl is waiting for it */
        if (event != RFC_EVENT_SABME)
        {
            if (( p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr)
             || (!p_mcb->is_initiator &&  rfc_cb.rfc.rx_frame.cr))
                rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
            GKI_freebuf (p_buf);
            return;
        }

        if ((p_port = port_find_dlci_port (rfc_cb.rfc.rx_frame.dlci)) == NULL)
        {
            rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, TRUE);
            GKI_freebuf (p_buf);
            return;
        }
        p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
        p_port->rfc.p_mcb = p_mcb;
    }

    if (event == RFC_EVENT_UIH)
    {
        if (p_buf->len > 0)
            rfc_port_sm_execute (p_port, event, p_buf);
        else
            GKI_freebuf (p_buf);

        if (rfc_cb.rfc.rx_frame.credit != 0)
            rfc_inc_credit (p_port, rfc_cb.rfc.rx_frame.credit);

        return;
    }
    rfc_port_sm_execute (p_port, event,  NULL);
    GKI_freebuf (p_buf);
}