/******************************************************************************* ** ** Function rfc_mx_sm_state_wait_sabme ** ** Description This function handles events when the multiplexer is ** waiting for SABME on the acceptor side after configuration ** ** Returns void ** *******************************************************************************/ void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data) { RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_wait_sabme - evt:%d", event); switch (event) { case RFC_MX_EVENT_DISC_IND: p_mcb->state = RFC_MX_STATE_IDLE; PORT_CloseInd (p_mcb); return; case RFC_EVENT_SABME: /* if we gave up outgoing connection request */ if (p_mcb->pending_lcid) { p_mcb->pending_lcid = 0; rfc_send_ua (p_mcb, RFCOMM_MX_DLCI); rfc_timer_stop (p_mcb); p_mcb->state = RFC_MX_STATE_CONNECTED; p_mcb->peer_ready = TRUE; /* MX channel collision has been resolved, continue to open ports */ PORT_StartCnf (p_mcb, RFCOMM_SUCCESS); } else { rfc_timer_stop (p_mcb); PORT_StartInd (p_mcb); } return; case RFC_MX_EVENT_START_RSP: if (*((UINT16 *)p_data) != RFCOMM_SUCCESS) rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE); else { rfc_send_ua (p_mcb, RFCOMM_MX_DLCI); p_mcb->state = RFC_MX_STATE_CONNECTED; p_mcb->peer_ready = TRUE; } return; case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */ case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */ case RFC_EVENT_TIMEOUT: p_mcb->state = RFC_MX_STATE_IDLE; L2CA_DisconnectReq (p_mcb->lcid); PORT_CloseInd (p_mcb); return; } RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); }
/******************************************************************************* ** ** Function rfc_mx_sm_sabme_wait_ua ** ** Description This function handles events when the multiplexer sent ** SABME and is waiting for UA reply. ** ** Returns void ** *******************************************************************************/ void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data) { RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_sabme_wait_ua - evt:%d", event); switch (event) { case RFC_MX_EVENT_START_REQ: case RFC_MX_EVENT_CONN_CNF: RFCOMM_TRACE_ERROR2 ("Mx error state %d event %d", p_mcb->state, event); return; /* workaround: we don't support reconfig */ /* commented out until we support reconfig case RFC_MX_EVENT_CONF_IND: rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data); return; case RFC_MX_EVENT_CONF_CNF: rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data); return; */ case RFC_MX_EVENT_DISC_IND: p_mcb->state = RFC_MX_STATE_IDLE; PORT_CloseInd (p_mcb); return; case RFC_EVENT_UA: rfc_timer_stop (p_mcb); p_mcb->state = RFC_MX_STATE_CONNECTED; p_mcb->peer_ready = TRUE; PORT_StartCnf (p_mcb, RFCOMM_SUCCESS); return; case RFC_EVENT_DM: rfc_timer_stop (p_mcb); /* Case falls through */ case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */ case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */ case RFC_EVENT_TIMEOUT: p_mcb->state = RFC_MX_STATE_IDLE; L2CA_DisconnectReq (p_mcb->lcid); PORT_StartCnf (p_mcb, RFCOMM_ERROR); return; } RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); }
/******************************************************************************* ** ** Function rfc_port_sm_state_closed ** ** Description This function handles events when the port is in ** CLOSED state. This state exists when port is ** being initially established. ** ** Returns void ** *******************************************************************************/ void rfc_port_sm_state_closed (tPORT *p_port, UINT16 event, void *p_data) { switch (event) { case RFC_EVENT_OPEN: p_port->rfc.state = RFC_STATE_ORIG_WAIT_SEC_CHECK; btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, TRUE, BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2), &rfc_sec_check_complete, p_port); return; case RFC_EVENT_CLOSE: break; case RFC_EVENT_CLEAR: return; case RFC_EVENT_DATA: GKI_freebuf (p_data); break; case RFC_EVENT_SABME: /* make sure the multiplexer disconnect timer is not running (reconnect case) */ rfc_timer_stop(p_port->rfc.p_mcb ); /* Open will be continued after security checks are passed */ p_port->rfc.state = RFC_STATE_TERM_WAIT_SEC_CHECK; btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, FALSE, BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2), &rfc_sec_check_complete, p_port); return; case RFC_EVENT_UA: return; case RFC_EVENT_DM: rfc_port_closed (p_port); return; case RFC_EVENT_UIH: GKI_freebuf (p_data); rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE); return; case RFC_EVENT_DISC: rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE); 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 closed Event ignored %d", event); return; }
/******************************************************************************* ** ** Function rfc_alloc_multiplexer_channel ** ** Description This function returns existing or new control block for ** the BD_ADDR. ** *******************************************************************************/ tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator) { int i, j; tRFC_MCB *p_mcb = NULL; RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel: bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d", is_initiator); for (i = 0; i < MAX_BD_CONNECTIONS; i++) { RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel rfc_cb.port.rfc_mcb[%d].state:%d", i, rfc_cb.port.rfc_mcb[i].state); RFCOMM_TRACE_DEBUG("(rfc_cb.port.rfc_mcb[i].bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", rfc_cb.port.rfc_mcb[i].bd_addr[0], rfc_cb.port.rfc_mcb[i].bd_addr[1], rfc_cb.port.rfc_mcb[i].bd_addr[2], rfc_cb.port.rfc_mcb[i].bd_addr[3], rfc_cb.port.rfc_mcb[i].bd_addr[4], rfc_cb.port.rfc_mcb[i].bd_addr[5]); if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE) && (!memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN))) { /* Multiplexer channel found do not change anything */ /* If there was an inactivity timer running stop it now */ if (rfc_cb.port.rfc_mcb[i].state == RFC_MX_STATE_CONNECTED) { rfc_timer_stop (&rfc_cb.port.rfc_mcb[i]); } RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, found, state:%d, p_mcb:%p", is_initiator, rfc_cb.port.rfc_mcb[i].state, &rfc_cb.port.rfc_mcb[i]); return (&rfc_cb.port.rfc_mcb[i]); } } /* connection with bd_addr does not exist */ for (i = 0, j = rfc_cb.rfc.last_mux + 1; i < MAX_BD_CONNECTIONS; i++, j++) { if (j >= MAX_BD_CONNECTIONS) { j = 0; } p_mcb = &rfc_cb.port.rfc_mcb[j]; if (rfc_cb.port.rfc_mcb[j].state == RFC_MX_STATE_IDLE) { /* New multiplexer control block */ fixed_queue_free(p_mcb->cmd_q, NULL); memset (p_mcb, 0, sizeof (tRFC_MCB)); memcpy (p_mcb->bd_addr, bd_addr, BD_ADDR_LEN); RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, create new p_mcb:%p, index:%d", is_initiator, &rfc_cb.port.rfc_mcb[j], j); p_mcb->cmd_q = fixed_queue_new(SIZE_MAX); p_mcb->is_initiator = is_initiator; rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER); rfc_cb.rfc.last_mux = (UINT8) j; return (p_mcb); } } return (NULL); }
/******************************************************************************* ** ** Function rfc_release_multiplexer_channel ** ** Description This function returns existing or new control block for ** the BD_ADDR. ** *******************************************************************************/ void rfc_release_multiplexer_channel (tRFC_MCB *p_mcb) { rfc_timer_stop (p_mcb); fixed_queue_free(p_mcb->cmd_q, osi_free_fun); memset (p_mcb, 0, sizeof (tRFC_MCB)); p_mcb->state = RFC_MX_STATE_IDLE; }
/******************************************************************************* ** ** Function PORT_DlcEstablishCnf ** ** Description This function is called from the RFCOMM layer when peer ** acknowledges establish procedure (SABME/UA). Send reply ** to the user and set state to OPENED if result was ** successfull. ** *******************************************************************************/ void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result) { tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); RFCOMM_TRACE_EVENT ("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, result); if (!p_port) { return; } if (result != RFCOMM_SUCCESS) { p_port->error = PORT_START_FAILED; port_rfc_closed (p_port, PORT_START_FAILED); return; } /* 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); 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; /* RPN is required only if we want to tell DTE how the port should be opened */ if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING) || (p_port->uuid == UUID_SERVCLASS_FAX)) { RFCOMM_PortNegReq (p_port->rfc.p_mcb, p_port->dlci, NULL); } else { RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl); } }
/******************************************************************************* ** ** 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; }