Beispiel #1
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) ;

}
Beispiel #2
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);
}
Beispiel #3
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->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);
}
Beispiel #4
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->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) ;

}
Beispiel #5
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->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) ;

}
Beispiel #6
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);
}
Beispiel #7
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) ;
}
Beispiel #8
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) ;

}
Beispiel #9
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) ;

}
Beispiel #10
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);
}
Beispiel #11
0
/*******************************************************************************
**
** Function         rfc_process_rpn
**
** Description      This function handles Remote DLC parameter negotiation
**                  command/response.  Pass command to the user.
**
*******************************************************************************/
void rfc_process_rpn (tRFC_MCB *p_mcb, BOOLEAN is_command,
                      BOOLEAN is_request, MX_FRAME *p_frame)
{
    tPORT_STATE port_pars;
    tPORT       *p_port;

    if ((p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci)) == NULL) {
        /* This is the first command on the port */
        if (is_command) {

            memset(&port_pars, 0, sizeof(tPORT_STATE));
            rfc_set_port_state(&port_pars, p_frame);

            PORT_PortNegInd(p_mcb, p_frame->dlci, &port_pars, p_frame->u.rpn.param_mask);
        }
        return;
    }

    if (is_command && is_request) {
        /* This is the special situation when peer just request local pars */
        port_pars = p_port->peer_port_pars;
        rfc_send_rpn (p_mcb, p_frame->dlci, FALSE, &p_port->peer_port_pars, 0);
        return;
    }

    port_pars = p_port->peer_port_pars;

    rfc_set_port_state(&port_pars, p_frame);

    if (is_command) {
        PORT_PortNegInd (p_mcb, p_frame->dlci, &port_pars, p_frame->u.rpn.param_mask);
        return;
    }

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

    /* If we sent a request for port parameters to the peer he is replying with */
    /* mask 0. */
    rfc_port_timer_stop (p_port);

    if (p_port->rfc.expected_rsp & RFC_RSP_RPN_REPLY) {
        p_port->rfc.expected_rsp &= ~RFC_RSP_RPN_REPLY;

        p_port->peer_port_pars = port_pars;

        if ((port_pars.fc_type == (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT))
                || (port_pars.fc_type == (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT))) {
            /* This is satisfactory port parameters.  Set mask as it was Ok */
            p_frame->u.rpn.param_mask = RFCOMM_RPN_PM_MASK;
        } else {
            /* Current peer parameters are not good, try to fix them */
            p_port->peer_port_pars.fc_type = (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT);

            p_port->rfc.expected_rsp |= RFC_RSP_RPN;
            rfc_send_rpn (p_mcb, p_frame->dlci, TRUE, &p_port->peer_port_pars,
                          RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT);
            rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
            return;
        }
    } else {
        p_port->rfc.expected_rsp &= ~RFC_RSP_RPN;
    }

    /* Check if all suggested parameters were accepted */
    if (((p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT)) ==
            (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT))
            || ((p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT)) ==
                (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT))) {
        PORT_PortNegCnf (p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS);
        return;
    }

    /* If we were proposing RTR flow control try RTC flow control */
    /* If we were proposing RTC flow control try no flow control */
    /* otherwise drop the connection */
    if (p_port->peer_port_pars.fc_type == (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT)) {
        /* Current peer parameters are not good, try to fix them */
        p_port->peer_port_pars.fc_type = (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT);

        p_port->rfc.expected_rsp |= RFC_RSP_RPN;

        rfc_send_rpn (p_mcb, p_frame->dlci, TRUE, &p_port->peer_port_pars,
                      RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT);
        rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
        return;
    }

    /* Other side does not support flow control */
    if (p_port->peer_port_pars.fc_type == (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT)) {
        p_port->peer_port_pars.fc_type = RFCOMM_FC_OFF;
        PORT_PortNegCnf (p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS);
    }
}
Beispiel #12
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);
}