Example #1
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 #2
0
/*******************************************************************************
**
** Function         rfc_mx_sm_state_idle
**
** Description      This function handles events when the multiplexer is in
**                  IDLE state. This state exists when connection is being
**                  initially established.
**
** Returns          void
**
*******************************************************************************/
void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
{
    RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_idle - evt:%d", event);
    switch (event)
    {
    case RFC_MX_EVENT_START_REQ:

        /* Initialize L2CAP MTU */
        p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;

        if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0)
        {
            PORT_StartCnf (p_mcb, RFCOMM_ERROR);
            return;
        }
        /* Save entry for quicker access to mcb based on the LCID */
        rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);

        p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
        return;

    case RFC_MX_EVENT_START_RSP:
    case RFC_MX_EVENT_CONN_CNF:
    case RFC_MX_EVENT_CONF_IND:
    case RFC_MX_EVENT_CONF_CNF:
        RFCOMM_TRACE_ERROR2 ("Mx error state %d event %d", p_mcb->state, event);
        return;

    case RFC_MX_EVENT_CONN_IND:

        rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT);
        L2CA_ConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0);

        rfc_mx_send_config_req (p_mcb);

        p_mcb->state = RFC_MX_STATE_CONFIGURE;
        return;

    case RFC_EVENT_SABME:
        break;

    case RFC_EVENT_UA:
    case RFC_EVENT_DM:
        return;

    case RFC_EVENT_DISC:
        rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE);
        return;

    case RFC_EVENT_UIH:
        rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, FALSE);
        return;
    }
    RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
}
Example #3
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 #4
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 #5
0
/*******************************************************************************
**
** Function         rfc_mx_sm_state_wait_sabme
**
** Description      This function handles events when the multiplexer is
**                  waiting for SABME on the acceptor side after configuration
**
** Returns          void
**
*******************************************************************************/
void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
{
    RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_wait_sabme - evt:%d", event);
    switch (event)
    {
    case RFC_MX_EVENT_DISC_IND:
        p_mcb->state = RFC_MX_STATE_IDLE;
        PORT_CloseInd (p_mcb);
        return;

    case RFC_EVENT_SABME:
        /* if we gave up outgoing connection request */
        if (p_mcb->pending_lcid)
        {
            p_mcb->pending_lcid = 0;

            rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);

            rfc_timer_stop (p_mcb);
            p_mcb->state      = RFC_MX_STATE_CONNECTED;
            p_mcb->peer_ready = TRUE;

            /* MX channel collision has been resolved, continue to open ports */
            PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
        }
        else
        {
            rfc_timer_stop (p_mcb);
            PORT_StartInd (p_mcb);
        }
        return;

    case RFC_MX_EVENT_START_RSP:
        if (*((UINT16 *)p_data) != RFCOMM_SUCCESS)
            rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE);
        else
        {
            rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);

            p_mcb->state      = RFC_MX_STATE_CONNECTED;
            p_mcb->peer_ready = TRUE;
        }
        return;

    case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
    case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
    case RFC_EVENT_TIMEOUT:
        p_mcb->state = RFC_MX_STATE_IDLE;
        L2CA_DisconnectReq (p_mcb->lcid);

        PORT_CloseInd (p_mcb);
        return;
    }
    RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
}
Example #6
0
/*******************************************************************************
**
** Function         PORT_ParNegInd
**
** Description      This function is called from the RFCOMM layer to change
**                  DLCI parameters (currently only MTU is negotiated).
**                  If can not find the port do not accept the request.
**                  Otherwise save the MTU size supported by the peer.
**
*******************************************************************************/
void PORT_ParNegInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
{
    tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
    UINT8 our_cl;
    UINT8 our_k;

    RFCOMM_TRACE_EVENT ("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu);

    if (!p_port) {
        /* This can be a first request for this port */
        p_port = port_find_dlci_port (dlci);
        if (!p_port) {
            /* If the port cannot be opened, send a DM.  Per Errata 1205 */
            rfc_send_dm(p_mcb, dlci, FALSE);
            /* check if this is the last port open, some headsets have
            problem, they don't disconnect if we send DM */
            rfc_check_mcb_active( p_mcb );
            RFCOMM_TRACE_EVENT( "PORT_ParNegInd: port not found" );
            return;
        }
        p_mcb->port_inx[dlci] = p_port->inx;
    }

    memcpy (p_port->bd_addr, p_mcb->bd_addr, BD_ADDR_LEN);

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

    p_port->rfc.p_mcb   = p_mcb;
    p_port->mtu         = (p_port->mtu < mtu) ? p_port->mtu : mtu;
    p_port->peer_mtu    = p_port->mtu;

    /* Negotiate the flow control mechanism.  If flow control mechanism for */
    /* mux has not been set yet, set it now.  If either we or peer wants TS 07.10, */
    /* use that.  Otherwise both must want credit based, so use that. If flow is */
    /* already defined for this mux, we respond with that value. */
    if (p_mcb->flow == PORT_FC_UNDEFINED) {
        if ((PORT_FC_DEFAULT == PORT_FC_TS710) || (cl == RFCOMM_PN_CONV_LAYER_TYPE_1)) {
            p_mcb->flow = PORT_FC_TS710;
        } else {
            p_mcb->flow = PORT_FC_CREDIT;
        }
    }

    /* Regardless of our flow control mechanism, if the PN cl is zero, we must */
    /* respond with zero.  "A responding implementation must set this field to 14 */
    /* if (and only if) the PN request was 15."  This could happen if a PN is sent */
    /* after the DLCI is already established-- the PN in that case must have cl = 0. */
    /* See RFCOMM spec 5.5.3 */
    if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1) {
        our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
        our_k = 0;
    } else if (p_mcb->flow == PORT_FC_CREDIT) {
        /* get credits */
        port_get_credits (p_port, k);

        /* Set convergence layer and number of credits (k) */
        our_cl = RFCOMM_PN_CONV_LAYER_CBFC_R;
        our_k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
        p_port->credit_rx = our_k;
    } else {
        /* must not be using credit based flow control; use TS 7.10 */
        our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
        our_k = 0;
    }
    RFCOMM_ParNegRsp (p_mcb, dlci, p_port->mtu, our_cl, our_k);
}
Example #7
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);
}
Example #9
0
/*******************************************************************************
**
** Function         rfc_mx_sm_state_disc_wait_ua
**
** Description      This function handles events when the multiplexer sent
**                  DISC and is waiting for UA reply.
**
** Returns          void
**
*******************************************************************************/
void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
{
    BT_HDR *p_buf;

    RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_disc_wait_ua - evt:%d", event);
    switch (event)
    {
    case RFC_EVENT_UA:
    case RFC_EVENT_DM:
    case RFC_EVENT_TIMEOUT:
        L2CA_DisconnectReq (p_mcb->lcid);

        if (p_mcb->restart_required)
        {
            /* Start Request was received while disconnecting.  Execute it again */
            if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0)
            {
                PORT_StartCnf (p_mcb, RFCOMM_ERROR);
                return;
            }
            /* Save entry for quicker access to mcb based on the LCID */
            rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);

            /* clean up before reuse it */
            while ((p_buf = (BT_HDR *)GKI_dequeue(&p_mcb->cmd_q)) != NULL)
                GKI_freebuf(p_buf);

            rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER);

            p_mcb->is_initiator     = TRUE;
            p_mcb->restart_required = FALSE;
            p_mcb->local_cfg_sent   = FALSE;
            p_mcb->peer_cfg_rcvd    = FALSE;

            p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
            return;
        }
        rfc_release_multiplexer_channel (p_mcb);
        return;

    case RFC_EVENT_DISC:
        rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
        return;

    case RFC_EVENT_UIH:
        GKI_freebuf (p_data);
        rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, FALSE);
        return;

    case RFC_MX_EVENT_START_REQ:
        p_mcb->restart_required = TRUE;
        return;

    case RFC_MX_EVENT_DISC_IND:
        p_mcb->state = RFC_MX_STATE_IDLE;
        PORT_CloseInd (p_mcb);
        return;

    case RFC_MX_EVENT_CLOSE_REQ:
        return;

    case RFC_MX_EVENT_QOS_VIOLATION_IND:
        break;
    }
    RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
}