/******************************************************************************* ** ** 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); }
/******************************************************************************* ** ** 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); }
/******************************************************************************* ** ** 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 rfc_process_rls ** ** Description This function handles Remote Line Status command. ** Pass command to the user. ** *******************************************************************************/ void rfc_process_rls (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame) { tPORT *p_port; if (is_command) { PORT_LineStatusInd (p_mcb, p_frame->dlci, p_frame->u.rls.line_status); rfc_send_rls (p_mcb, p_frame->dlci, FALSE, p_frame->u.rls.line_status); } else { p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci); /* If we are not awaiting response just ignore it */ if (!p_port || !(p_port->rfc.expected_rsp & RFC_RSP_RLS)) { return; } p_port->rfc.expected_rsp &= ~RFC_RSP_RLS; rfc_port_timer_stop (p_port); } }
/******************************************************************************* ** ** Function rfc_port_closed ** ** Description The function is called when port is released based on the ** event received from the lower layer, typically L2CAP ** connection down, DISC, or DM frame. ** ** Returns void ** *******************************************************************************/ void rfc_port_closed (tPORT *p_port) { tRFC_MCB *p_mcb = p_port->rfc.p_mcb; RFCOMM_TRACE_DEBUG ("rfc_port_closed"); rfc_port_timer_stop (p_port); p_port->rfc.state = RFC_STATE_CLOSED; /* If multiplexer channel was up mark it as down */ if (p_mcb) { p_mcb->port_inx[p_port->dlci] = 0; /* If there are no more ports opened on this MCB release it */ rfc_check_mcb_active (p_mcb); } /* Notify port that RFC connection is gone */ port_rfc_closed (p_port, PORT_CLOSED); }
/******************************************************************************* ** ** Function rfc_process_msc ** ** Description This function handles Modem Status Command. ** Pass command to the user. ** *******************************************************************************/ void rfc_process_msc (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame) { tPORT_CTRL pars; tPORT *p_port; UINT8 modem_signals = p_frame->u.msc.signals; BOOLEAN new_peer_fc = FALSE; p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci); if (p_port == NULL) { return; } pars.modem_signal = 0; if (modem_signals & RFCOMM_MSC_RTC) { pars.modem_signal |= MODEM_SIGNAL_DTRDSR; } if (modem_signals & RFCOMM_MSC_RTR) { pars.modem_signal |= MODEM_SIGNAL_RTSCTS; } if (modem_signals & RFCOMM_MSC_IC) { pars.modem_signal |= MODEM_SIGNAL_RI; } if (modem_signals & RFCOMM_MSC_DV) { pars.modem_signal |= MODEM_SIGNAL_DCD; } pars.fc = ((modem_signals & RFCOMM_MSC_FC) == RFCOMM_MSC_FC); pars.break_signal = (p_frame->u.msc.break_present) ? p_frame->u.msc.break_duration : 0; pars.discard_buffers = 0; pars.break_signal_seq = RFCOMM_CTRL_BREAK_IN_SEQ; /* this is default */ /* Check if this command is passed only to indicate flow control */ if (is_command) { rfc_send_msc (p_mcb, p_frame->dlci, FALSE, &pars); if (p_port->rfc.p_mcb->flow != PORT_FC_CREDIT) { /* Spec 1.1 indicates that only FC bit is used for flow control */ p_port->peer_ctrl.fc = new_peer_fc = pars.fc; if (new_peer_fc != p_port->tx.peer_fc) { PORT_FlowInd (p_mcb, p_frame->dlci, (BOOLEAN)!new_peer_fc); } } PORT_ControlInd (p_mcb, p_frame->dlci, &pars); return; } /* If we are not awaiting response just ignore it */ if (!(p_port->rfc.expected_rsp & RFC_RSP_MSC)) { return; } p_port->rfc.expected_rsp &= ~RFC_RSP_MSC; rfc_port_timer_stop (p_port); PORT_ControlCnf (p_port->rfc.p_mcb, p_port->dlci, &pars); }
/******************************************************************************* ** ** 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 port_release_port ** ** Description Release port infor control block. ** ** Returns Pointer to the PORT or NULL if not found ** *******************************************************************************/ void port_release_port (tPORT *p_port) { BT_HDR *p_buf; UINT32 mask; tPORT_CALLBACK *p_port_cb; tPORT_STATE user_port_pars; PORT_SCHEDULE_LOCK; RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port); while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL) GKI_freebuf (p_buf); p_port->rx.queue_size = 0; while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL) GKI_freebuf (p_buf); p_port->tx.queue_size = 0; PORT_SCHEDULE_UNLOCK; p_port->state = PORT_STATE_CLOSED; if (p_port->rfc.state == RFC_STATE_CLOSED) { RFCOMM_TRACE_DEBUG ("rfc_port_closed DONE"); if (p_port->rfc.p_mcb) { p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0; /* If there are no more ports opened on this MCB release it */ rfc_check_mcb_active (p_port->rfc.p_mcb); } rfc_port_timer_stop (p_port); RFCOMM_TRACE_DEBUG ("port_release_port:p_port->keep_port_handle:%d", p_port->keep_port_handle); if( p_port->keep_port_handle ) { RFCOMM_TRACE_DEBUG ("port_release_port:Initialize handle:%d", p_port->inx); /* save event mask and callback */ mask = p_port->ev_mask; p_port_cb = p_port->p_callback; user_port_pars = p_port->user_port_pars; port_set_defaults(p_port); /* restore */ p_port->ev_mask = mask; p_port->p_callback = p_port_cb; p_port->user_port_pars = user_port_pars; p_port->mtu = p_port->keep_mtu; p_port->state = PORT_STATE_OPENING; p_port->rfc.p_mcb = NULL; if(p_port->is_server) p_port->dlci &= 0xfe; p_port->local_ctrl.modem_signal = p_port->default_signal_state; memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN); } else { RFCOMM_TRACE_DEBUG ("port_release_port:Clean-up handle:%d", p_port->inx); memset (p_port, 0, sizeof (tPORT)); } } }