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