/******************************************************************************* ** ** Function PORT_DlcEstablishInd ** ** Description This function is called from the RFCOMM layer when peer ** device wants to establish a new DLC. If this is not the ** first message in the establishment procedure port_handle ** has a handle to the port control block otherwise the control ** block should be found based on the muliplexer channel and ** dlci. The block should be allocated allocated before ** meaning that application already made open. ** *******************************************************************************/ void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu) { tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", p_mcb, dlci, mtu, p_port); RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb addr:%02x:%02x:%02x:%02x:%02x:%02x", p_mcb->bd_addr[0], p_mcb->bd_addr[1], p_mcb->bd_addr[2], p_mcb->bd_addr[3], p_mcb->bd_addr[4], p_mcb->bd_addr[5]); if (!p_port) { /* This can be a first request for this port */ p_port = port_find_dlci_port (dlci); if (!p_port) { RFCOMM_DlcEstablishRsp (p_mcb, dlci, 0, RFCOMM_ERROR); return; } p_mcb->port_inx[dlci] = p_port->inx; } /* If L2CAP's mtu less then RFCOMM's take it */ if (mtu && (mtu < p_port->peer_mtu)) { p_port->peer_mtu = mtu; } /* If there was an inactivity timer running for MCB stop it */ rfc_timer_stop (p_mcb); RFCOMM_DlcEstablishRsp (p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS); /* This is the server side. If application wants to know when connection */ /* is established, thats the place */ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED)) { (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx); } if (p_port->p_mgmt_callback) { p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx); } p_port->state = PORT_STATE_OPENED; }
/******************************************************************************* ** ** Function PORT_PortNegInd ** ** Description This function is called from the RFCOMM layer when peer ** device wants to set parameters of the port. As per the spec ** this message has to be sent before the first data packet ** and can be sent before establish. The block should be ** allocated before meaning that application already made open. ** *******************************************************************************/ void PORT_PortNegInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 param_mask) { tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); RFCOMM_TRACE_EVENT ("PORT_PortNegInd"); if (!p_port) { /* This can be a first request for this port */ p_port = port_find_dlci_port (dlci); if (!p_port) { RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, 0); return; } p_mcb->port_inx[dlci] = p_port->inx; } /* Check if the flow control is acceptable on local side */ p_port->peer_port_pars = *p_pars; RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, param_mask); }
/******************************************************************************* ** ** 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 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); }