/******************************************************************************* ** ** 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) ; }
/******************************************************************************* ** ** 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); }
/******************************************************************************* ** ** 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); }
/******************************************************************************* ** ** 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) ; }
/******************************************************************************* ** ** 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) ; }
/******************************************************************************* ** ** 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); }
/******************************************************************************* ** ** 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) ; }
/******************************************************************************* ** ** 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) ; }
/******************************************************************************* ** ** 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_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); }
/******************************************************************************* ** ** 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); } }
/******************************************************************************* ** ** 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); }