Fork ESP-IDF's bluetooth component
i want better sbc encoding, and no cla will stop me
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* This file contains definitions internal to the PORT unit
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef PORT_INT_H
|
||||
#define PORT_INT_H
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/rfcdefs.h"
|
||||
#include "stack/port_api.h"
|
||||
#include "osi/fixed_queue.h"
|
||||
#include "common/bt_defs.h"
|
||||
|
||||
/* Local events passed when application event is sent from the api to PORT */
|
||||
/* ???*/
|
||||
#define PORT_EVENT_OPEN (1 | BT_EVT_TO_BTU_SP_EVT)
|
||||
#define PORT_EVENT_CONTROL (2 | BT_EVT_TO_BTU_SP_EVT)
|
||||
#define PORT_EVENT_SET_STATE (3 | BT_EVT_TO_BTU_SP_EVT)
|
||||
#define PORT_EVENT_SET_CALLBACK (5 | BT_EVT_TO_BTU_SP_EVT)
|
||||
#define PORT_EVENT_WRITE (6 | BT_EVT_TO_BTU_SP_EVT)
|
||||
#define PORT_EVENT_PURGE (7 | BT_EVT_TO_BTU_SP_EVT)
|
||||
#define PORT_EVENT_SEND_ERROR (8 | BT_EVT_TO_BTU_SP_EVT)
|
||||
#define PORT_EVENT_FLOW_CONTROL (9 | BT_EVT_TO_BTU_SP_EVT)
|
||||
|
||||
/*
|
||||
** Flow control configuration values for the mux
|
||||
*/
|
||||
#define PORT_FC_UNDEFINED 0 /* mux flow control mechanism not defined yet */
|
||||
#define PORT_FC_TS710 1 /* use TS 07.10 flow control */
|
||||
#define PORT_FC_CREDIT 2 /* use RFCOMM credit based flow control */
|
||||
|
||||
/*
|
||||
** Define Port Data Transfere control block
|
||||
*/
|
||||
typedef struct {
|
||||
fixed_queue_t *queue; /* Queue of buffers waiting to be sent */
|
||||
BOOLEAN peer_fc; /* TRUE if flow control is set based on peer's request */
|
||||
BOOLEAN user_fc; /* TRUE if flow control is set based on user's request */
|
||||
UINT32 queue_size; /* Number of data bytes in the queue */
|
||||
tPORT_CALLBACK *p_callback; /* Address of the callback function */
|
||||
} tPORT_DATA;
|
||||
|
||||
/*
|
||||
** Port control structure used to pass modem info
|
||||
*/
|
||||
typedef struct {
|
||||
#define MODEM_SIGNAL_DTRDSR 0x01
|
||||
#define MODEM_SIGNAL_RTSCTS 0x02
|
||||
#define MODEM_SIGNAL_RI 0x04
|
||||
#define MODEM_SIGNAL_DCD 0x08
|
||||
|
||||
UINT8 modem_signal; /* [DTR/DSR | RTS/CTS | RI | DCD ] */
|
||||
|
||||
UINT8 break_signal; /* 0-3 s in steps of 200 ms */
|
||||
|
||||
UINT8 discard_buffers; /* 0 - do not discard, 1 - discard */
|
||||
|
||||
#define RFCOMM_CTRL_BREAK_ASAP 0
|
||||
#define RFCOMM_CTRL_BREAK_IN_SEQ 1
|
||||
|
||||
UINT8 break_signal_seq; /* as soon as possible | in sequence (default) */
|
||||
|
||||
BOOLEAN fc; /* TRUE when the device is unable to accept frames */
|
||||
} tPORT_CTRL;
|
||||
|
||||
|
||||
/*
|
||||
** RFCOMM multiplexer Control Block
|
||||
*/
|
||||
typedef struct {
|
||||
TIMER_LIST_ENT tle; /* Timer list entry */
|
||||
fixed_queue_t *cmd_q; /* Queue for command messages on this mux */
|
||||
UINT8 port_inx[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to */
|
||||
/* tPORT based on dlci */
|
||||
BD_ADDR bd_addr; /* BD ADDR of the peer if initiator */
|
||||
UINT16 lcid; /* Local cid used for this channel */
|
||||
UINT16 peer_l2cap_mtu; /* Max frame that can be sent to peer L2CAP */
|
||||
UINT8 state; /* Current multiplexer channel state */
|
||||
UINT8 is_initiator; /* TRUE if this side sends SABME (dlci=0) */
|
||||
BOOLEAN local_cfg_sent;
|
||||
BOOLEAN peer_cfg_rcvd;
|
||||
BOOLEAN restart_required; /* TRUE if has to restart channel after disc */
|
||||
BOOLEAN peer_ready; /* True if other side can accept frames */
|
||||
UINT8 flow; /* flow control mechanism for this mux */
|
||||
BOOLEAN l2cap_congested; /* TRUE if L2CAP is congested */
|
||||
BOOLEAN is_disc_initiator; /* TRUE if initiated disc of port */
|
||||
UINT16 pending_lcid; /* store LCID for incoming connection while connecting */
|
||||
UINT8 pending_id; /* store l2cap ID for incoming connection while connecting */
|
||||
} tRFC_MCB;
|
||||
|
||||
|
||||
/*
|
||||
** RFCOMM Port Connection Control Block
|
||||
*/
|
||||
struct t_rfc_port {
|
||||
#define RFC_PORT_STATE_IDLE 0
|
||||
#define RFC_PORT_STATE_WAIT_START 1
|
||||
#define RFC_PORT_STATE_OPENING 2
|
||||
#define RFC_PORT_STATE_OPENED 3
|
||||
#define RFC_PORT_STATE_CLOSING 4
|
||||
|
||||
UINT8 state; /* Current state of the connection */
|
||||
|
||||
#define RFC_RSP_PN 0x01
|
||||
#define RFC_RSP_RPN_REPLY 0x02
|
||||
#define RFC_RSP_RPN 0x04
|
||||
#define RFC_RSP_MSC 0x08
|
||||
#define RFC_RSP_RLS 0x10
|
||||
|
||||
UINT8 expected_rsp;
|
||||
|
||||
tRFC_MCB *p_mcb;
|
||||
|
||||
TIMER_LIST_ENT tle; /* Timer list entry */
|
||||
};
|
||||
typedef struct t_rfc_port tRFC_PORT;
|
||||
|
||||
|
||||
/*
|
||||
** Define control block containing information about PORT connection
|
||||
*/
|
||||
struct t_port_info {
|
||||
UINT8 inx; /* Index of this control block in the port_info array */
|
||||
BOOLEAN in_use; /* True when structure is allocated */
|
||||
|
||||
#define PORT_STATE_CLOSED 0
|
||||
#define PORT_STATE_OPENING 1
|
||||
#define PORT_STATE_OPENED 2
|
||||
#define PORT_STATE_CLOSING 3
|
||||
|
||||
UINT8 state; /* State of the application */
|
||||
|
||||
UINT8 scn; /* Service channel number */
|
||||
UINT16 uuid; /* Service UUID */
|
||||
|
||||
BD_ADDR bd_addr; /* BD ADDR of the device for the multiplexer channel */
|
||||
BOOLEAN is_server; /* TRUE if the server application */
|
||||
UINT8 dlci; /* DLCI of the connection */
|
||||
|
||||
UINT8 error; /* Last error detected */
|
||||
|
||||
UINT8 line_status; /* Line status as reported by peer */
|
||||
|
||||
UINT8 default_signal_state; /* Initial signal state depending on uuid */
|
||||
|
||||
UINT16 mtu; /* Max MTU that port can receive */
|
||||
UINT16 peer_mtu; /* Max MTU that port can send */
|
||||
|
||||
tPORT_DATA tx; /* Control block for data from app to peer */
|
||||
tPORT_DATA rx; /* Control block for data from peer to app */
|
||||
|
||||
tPORT_STATE user_port_pars; /* Port parameters for user connection */
|
||||
tPORT_STATE peer_port_pars; /* Port parameters for user connection */
|
||||
|
||||
tPORT_CTRL local_ctrl;
|
||||
tPORT_CTRL peer_ctrl;
|
||||
|
||||
#define PORT_CTRL_REQ_SENT 0x01
|
||||
#define PORT_CTRL_REQ_CONFIRMED 0x02
|
||||
#define PORT_CTRL_IND_RECEIVED 0x04
|
||||
#define PORT_CTRL_IND_RESPONDED 0x08
|
||||
|
||||
UINT8 port_ctrl; /* Modem Status Command */
|
||||
|
||||
BOOLEAN rx_flag_ev_pending; /* RXFLAG Character is received */
|
||||
|
||||
tRFC_PORT rfc; /* RFCOMM port control block */
|
||||
|
||||
UINT32 ev_mask; /* Event mask for the callback */
|
||||
tPORT_CALLBACK *p_callback; /* Pointer to users callback function */
|
||||
tPORT_MGMT_CALLBACK *p_mgmt_callback; /* Callback function to receive connection up/down */
|
||||
tPORT_DATA_CALLBACK *p_data_callback; /* Callback function to receive data indications */
|
||||
tPORT_DATA_CO_CALLBACK *p_data_co_callback; /* Callback function with callouts and flowctrl */
|
||||
UINT16 credit_tx; /* Flow control credits for tx path */
|
||||
UINT16 credit_rx; /* Flow control credits for rx path, this is */
|
||||
/* number of buffers peer is allowed to sent */
|
||||
UINT16 credit_rx_max; /* Max number of credits we will allow this guy to sent */
|
||||
UINT16 credit_rx_low; /* Number of credits when we send credit update */
|
||||
UINT16 rx_buf_critical; /* port receive queue critical watermark level */
|
||||
BOOLEAN keep_port_handle; /* TRUE if port is not deallocated when closing */
|
||||
/* it is set to TRUE for server when allocating port */
|
||||
UINT16 keep_mtu; /* Max MTU that port can receive by server */
|
||||
};
|
||||
typedef struct t_port_info tPORT;
|
||||
|
||||
|
||||
/* Define the PORT/RFCOMM control structure
|
||||
*/
|
||||
typedef struct {
|
||||
tPORT port[MAX_RFC_PORTS]; /* Port info pool */
|
||||
tRFC_MCB rfc_mcb[MAX_BD_CONNECTIONS]; /* RFCOMM bd_connections pool */
|
||||
BOOLEAN enable_l2cap_ertm; /* enable/disable l2cap ertm */
|
||||
} tPORT_CB;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Functions provided by the port_utils.c
|
||||
*/
|
||||
extern tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr);
|
||||
extern void port_set_defaults (tPORT *p_port);
|
||||
extern void port_select_mtu (tPORT *p_port);
|
||||
extern void port_release_port (tPORT *p_port);
|
||||
extern tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci);
|
||||
extern tRFC_MCB *port_find_mcb (BD_ADDR bd_addr);
|
||||
extern tPORT *port_find_dlci_port (UINT8 dlci);
|
||||
extern tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr);
|
||||
extern UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal);
|
||||
extern UINT32 port_flow_control_user (tPORT *p_port);
|
||||
extern void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count);
|
||||
|
||||
/*
|
||||
** Functions provided by the port_rfc.c
|
||||
*/
|
||||
extern int port_open_continue (tPORT *p_port);
|
||||
extern void port_start_port_open (tPORT *p_port);
|
||||
extern void port_start_par_neg (tPORT *p_port);
|
||||
extern void port_start_control (tPORT *p_port);
|
||||
extern void port_start_close (tPORT *p_port);
|
||||
extern void port_rfc_closed (tPORT *p_port, UINT8 res);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,378 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* This file contains definitions internal to the RFC unit
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef RFC_INT_H
|
||||
#define RFC_INT_H
|
||||
|
||||
#include "stack/l2c_api.h"
|
||||
#include "port_int.h"
|
||||
|
||||
/*
|
||||
** Define RFCOMM result codes
|
||||
*/
|
||||
#define RFCOMM_SUCCESS 0
|
||||
#define RFCOMM_ERROR 1
|
||||
#define RFCOMM_LOW_RESOURCES 2
|
||||
#define RFCOMM_TRY_LATER 3
|
||||
|
||||
#define RFCOMM_USER_ERR 111
|
||||
#define RFCOMM_SECURITY_ERR 112
|
||||
|
||||
/*
|
||||
** Define max and min RFCOMM MTU (N1)
|
||||
*/
|
||||
#define RFCOMM_MIN_MTU 23
|
||||
#define RFCOMM_MAX_MTU 32767
|
||||
|
||||
extern void RFCOMM_StartReq (tRFC_MCB *p_mcb);
|
||||
extern void RFCOMM_StartRsp (tRFC_MCB *p_mcb, UINT16 result);
|
||||
|
||||
extern void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu);
|
||||
extern void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result);
|
||||
|
||||
extern void RFCOMM_DataReq (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf);
|
||||
|
||||
extern void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, UINT8 dlci);
|
||||
|
||||
extern void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu);
|
||||
extern void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k);
|
||||
|
||||
extern void RFCOMM_TestReq (UINT8 *p_data, UINT16 len);
|
||||
|
||||
#define RFCOMM_FLOW_STATE_DISABLE 0
|
||||
#define RFCOMM_FLOW_STATE_ENABLE 1
|
||||
|
||||
extern void RFCOMM_FlowReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 state);
|
||||
|
||||
extern void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars);
|
||||
extern void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 param_mask);
|
||||
|
||||
extern void RFCOMM_ControlReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars);
|
||||
extern void RFCOMM_ControlRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars);
|
||||
|
||||
extern void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status);
|
||||
/*
|
||||
** Define logical struct used for sending and decoding MX frames
|
||||
*/
|
||||
typedef struct {
|
||||
UINT8 dlci;
|
||||
UINT8 type;
|
||||
UINT8 cr;
|
||||
UINT8 ea;
|
||||
UINT8 pf;
|
||||
UINT8 credit;
|
||||
|
||||
union {
|
||||
struct {
|
||||
UINT8 dlci;
|
||||
UINT8 frame_type;
|
||||
UINT8 conv_layer;
|
||||
UINT8 priority;
|
||||
UINT8 t1;
|
||||
UINT16 mtu;
|
||||
UINT8 n2;
|
||||
UINT8 k;
|
||||
} pn;
|
||||
struct {
|
||||
UINT8 *p_data;
|
||||
UINT16 data_len;
|
||||
} test;
|
||||
struct {
|
||||
UINT8 dlci;
|
||||
UINT8 signals;
|
||||
UINT8 break_present;
|
||||
UINT8 break_duration;
|
||||
} msc;
|
||||
struct {
|
||||
UINT8 ea;
|
||||
UINT8 cr;
|
||||
UINT8 type;
|
||||
} nsc;
|
||||
struct {
|
||||
UINT8 dlci;
|
||||
UINT8 is_request;
|
||||
UINT8 baud_rate;
|
||||
UINT8 byte_size;
|
||||
UINT8 stop_bits;
|
||||
UINT8 parity;
|
||||
UINT8 parity_type;
|
||||
UINT8 fc_type;
|
||||
UINT8 xon_char;
|
||||
UINT8 xoff_char;
|
||||
UINT16 param_mask;
|
||||
} rpn;
|
||||
struct {
|
||||
UINT8 dlci;
|
||||
UINT8 line_status;
|
||||
} rls;
|
||||
} u;
|
||||
} MX_FRAME;
|
||||
|
||||
#define LINE_STATUS_NO_ERROR 0x00
|
||||
#define LINE_STATUS_OVERRUN 0x02 /* Receive Overrun Error */
|
||||
#define LINE_STATUS_RXPARITY 0x04 /* Receive Parity Error */
|
||||
#define LINE_STATUS_FRAME 0x08 /* Receive Framing error */
|
||||
#define LINE_STATUS_FAILED 0x10 /* Connection Failed */
|
||||
|
||||
/*
|
||||
** Define states and events for the RFC multiplexer state machine
|
||||
*/
|
||||
#define RFC_MX_STATE_IDLE 0
|
||||
#define RFC_MX_STATE_WAIT_CONN_CNF 1
|
||||
#define RFC_MX_STATE_CONFIGURE 2
|
||||
#define RFC_MX_STATE_SABME_WAIT_UA 3
|
||||
#define RFC_MX_STATE_WAIT_SABME 4
|
||||
#define RFC_MX_STATE_CONNECTED 5
|
||||
#define RFC_MX_STATE_DISC_WAIT_UA 6
|
||||
|
||||
/*
|
||||
** Define port states
|
||||
*/
|
||||
#define RFC_STATE_CLOSED 0
|
||||
#define RFC_STATE_SABME_WAIT_UA 1
|
||||
#define RFC_STATE_ORIG_WAIT_SEC_CHECK 2
|
||||
#define RFC_STATE_TERM_WAIT_SEC_CHECK 3
|
||||
#define RFC_STATE_OPENED 4
|
||||
#define RFC_STATE_DISC_WAIT_UA 5
|
||||
|
||||
/*
|
||||
** Events that can be received by multiplexer as well as port state machines
|
||||
*/
|
||||
#define RFC_EVENT_SABME 0
|
||||
#define RFC_EVENT_UA 1
|
||||
#define RFC_EVENT_DM 2
|
||||
#define RFC_EVENT_DISC 3
|
||||
#define RFC_EVENT_UIH 4
|
||||
#define RFC_EVENT_TIMEOUT 5
|
||||
#define RFC_EVENT_BAD_FRAME 50
|
||||
/*
|
||||
** Multiplexer events
|
||||
*/
|
||||
#define RFC_MX_EVENT_START_REQ 6
|
||||
#define RFC_MX_EVENT_START_RSP 7
|
||||
#define RFC_MX_EVENT_CLOSE_REQ 8
|
||||
#define RFC_MX_EVENT_CONN_CNF 9
|
||||
#define RFC_MX_EVENT_CONN_IND 10
|
||||
#define RFC_MX_EVENT_CONF_CNF 11
|
||||
#define RFC_MX_EVENT_CONF_IND 12
|
||||
#define RFC_MX_EVENT_QOS_VIOLATION_IND 13
|
||||
#define RFC_MX_EVENT_DISC_IND 14
|
||||
#define RFC_MX_EVENT_TEST_CMD 15
|
||||
#define RFC_MX_EVENT_TEST_RSP 16
|
||||
#define RFC_MX_EVENT_FCON_CMD 17
|
||||
#define RFC_MX_EVENT_FCOFF_CMD 18
|
||||
#define RFC_MX_EVENT_NSC 19
|
||||
#define RFC_MX_EVENT_NSC_RSP 20
|
||||
|
||||
/*
|
||||
** Port events
|
||||
*/
|
||||
#define RFC_EVENT_OPEN 9
|
||||
#define RFC_EVENT_ESTABLISH_RSP 11
|
||||
#define RFC_EVENT_CLOSE 12
|
||||
#define RFC_EVENT_CLEAR 13
|
||||
#define RFC_EVENT_DATA 14
|
||||
#define RFC_EVENT_SEC_COMPLETE 15
|
||||
|
||||
// btla-specific ++
|
||||
#define RFC_T1_TIMEOUT 20 /* seconds to wait for reply with Poll bit */
|
||||
#define RFC_PORT_T1_TIMEOUT 60 /* seconds to wait for reply with Poll bit other than MX */
|
||||
#define RFC_T2_TIMEOUT 20 /* timeout to wait for Mx UIH */
|
||||
// btla-specific --
|
||||
#define RFC_DISC_TIMEOUT 3 /* If something goes wrong and we send DISC we should not wait for min */
|
||||
#define RFC_CLOSE_TIMEOUT 10
|
||||
#define RFCOMM_CONN_TIMEOUT 120 /* first connection to be established on Mx */
|
||||
|
||||
|
||||
/* Define RFComm control block
|
||||
*/
|
||||
typedef struct {
|
||||
MX_FRAME rx_frame;
|
||||
tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
|
||||
tRFC_MCB *p_rfc_lcid_mcb[MAX_L2CAP_CHANNELS]; /* MCB based on the L2CAP's lcid */
|
||||
BOOLEAN peer_rx_disabled; /* If TRUE peer sent FCOFF */
|
||||
UINT8 last_mux; /* Last mux allocated */
|
||||
UINT8 last_port; /* Last port allocated */
|
||||
} tRFCOMM_CB;
|
||||
|
||||
/* Main Control Block for the RFCOMM Layer (PORT and RFC) */
|
||||
typedef struct {
|
||||
tRFCOMM_CB rfc;
|
||||
tPORT_CB port;
|
||||
UINT8 trace_level;
|
||||
} tRFC_CB;
|
||||
|
||||
|
||||
#if RFC_DYNAMIC_MEMORY == FALSE
|
||||
extern tRFC_CB rfc_cb;
|
||||
#else
|
||||
extern tRFC_CB *rfc_cb_ptr;
|
||||
#define rfc_cb (*rfc_cb_ptr)
|
||||
#endif
|
||||
|
||||
/* Timer running on the multiplexor channel while no DLCI connection is opened */
|
||||
#define RFC_MCB_INIT_INACT_TIMER 60 /* in seconds */
|
||||
|
||||
/* Timer running on the multiplexor channel after last DLCI is released */
|
||||
#define RFC_MCB_RELEASE_INACT_TIMER 2 /* in seconds */
|
||||
|
||||
/*
|
||||
** Define RFCOMM frame processing errors
|
||||
*/
|
||||
#define RFCOMM_ERR_BAD_SABME 1
|
||||
#define RFCOMM_ERR_BAD_UA 2
|
||||
#define RFCOMM_ERR_BAD_DM 3
|
||||
#define RFCOMM_ERR_BAD_DISC 4
|
||||
#define RFCOMM_ERR_BAD_UIH 5
|
||||
|
||||
#ifdef RFCOMM_PRECALC_FCS
|
||||
|
||||
#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_sabme_fcs[cr][dlci]
|
||||
#define RFCOMM_UA_FCS(p_data, cr, dlci) rfc_ua_fcs[cr][dlci]
|
||||
#define RFCOMM_DM_FCS(p_data, cr, dlci) rfc_dm_fcs[cr][dlci]
|
||||
#define RFCOMM_DISC_FCS(p_data, cr, dlci) rfc_disc_fcs[cr][dlci]
|
||||
#define RFCOMM_UIH_FCS(p_data, dlci) rfc_uih_fcs[dlci]
|
||||
|
||||
#else
|
||||
|
||||
extern UINT8 rfc_calc_fcs (UINT16 len, UINT8 *p);
|
||||
|
||||
#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
|
||||
#define RFCOMM_UA_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
|
||||
#define RFCOMM_DM_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
|
||||
#define RFCOMM_DISC_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
|
||||
#define RFCOMM_UIH_FCS(p_data, dlci) rfc_calc_fcs(2, p_data)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void rfc_mx_sm_execute (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
|
||||
|
||||
/*
|
||||
** Functions provided by the rfc_port_fsm.c
|
||||
*/
|
||||
extern void rfc_port_sm_execute (tPORT *p_port, UINT16 event, void *p_data);
|
||||
|
||||
|
||||
extern void rfc_process_pn (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame);
|
||||
extern void rfc_process_msc (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame);
|
||||
extern void rfc_process_rpn (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, BOOLEAN is_request, MX_FRAME *p_frame);
|
||||
extern void rfc_process_rls (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame);
|
||||
extern void rfc_process_nsc (tRFC_MCB *p_rfc_mcb, MX_FRAME *p_frame);
|
||||
extern void rfc_process_test_rsp (tRFC_MCB *p_rfc_mcb, BT_HDR *p_buf);
|
||||
extern void rfc_process_fcon (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command);
|
||||
extern void rfc_process_fcoff (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command);
|
||||
extern void rfc_process_l2cap_congestion (tRFC_MCB *p_mcb, BOOLEAN is_congested);
|
||||
|
||||
/*
|
||||
** Functions provided by the rfc_utils.c
|
||||
*/
|
||||
tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator);
|
||||
extern void rfc_release_multiplexer_channel (tRFC_MCB *p_rfc_mcb);
|
||||
extern void rfc_timer_start (tRFC_MCB *p_rfc_mcb, UINT16 timeout);
|
||||
extern void rfc_timer_stop (tRFC_MCB *p_rfc_mcb);
|
||||
extern void rfc_timer_free (tRFC_MCB *p_rfc_mcb);
|
||||
extern void rfc_port_timer_start (tPORT *p_port, UINT16 tout);
|
||||
extern void rfc_port_timer_stop (tPORT *p_port);
|
||||
extern void rfc_port_timer_free (tPORT *p_port);
|
||||
|
||||
BOOLEAN rfc_check_uih_fcs (UINT8 dlci, UINT8 received_fcs);
|
||||
BOOLEAN rfc_check_fcs (UINT16 len, UINT8 *p, UINT8 received_fcs);
|
||||
tRFC_MCB *rfc_find_lcid_mcb (UINT16 lcid);
|
||||
extern void rfc_save_lcid_mcb (tRFC_MCB *p_rfc_mcb, UINT16 lcid);
|
||||
extern void rfc_check_mcb_active (tRFC_MCB *p_mcb);
|
||||
extern void rfc_port_closed (tPORT *p_port);
|
||||
extern void rfc_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res);
|
||||
extern void rfc_inc_credit (tPORT *p_port, UINT8 credit);
|
||||
extern void rfc_dec_credit (tPORT *p_port);
|
||||
extern void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf);
|
||||
|
||||
/*
|
||||
** Functions provided by the rfc_ts_frames.c
|
||||
*/
|
||||
extern void rfc_send_sabme (tRFC_MCB *p_rfc_mcb, UINT8 dlci);
|
||||
extern void rfc_send_ua (tRFC_MCB *p_rfc_mcb, UINT8 dlci);
|
||||
extern void rfc_send_dm (tRFC_MCB *p_rfc_mcb, UINT8 dlci, BOOLEAN pf);
|
||||
extern void rfc_send_disc (tRFC_MCB *p_rfc_mcb, UINT8 dlci);
|
||||
extern void rfc_send_pn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT16 mtu,
|
||||
UINT8 cl, UINT8 k);
|
||||
extern void rfc_send_test (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, BT_HDR *p_buf);
|
||||
extern void rfc_send_msc (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command,
|
||||
tPORT_CTRL *p_pars);
|
||||
extern void rfc_send_rls (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT8 status);
|
||||
extern void rfc_send_rpn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command,
|
||||
tPORT_STATE *p_pars, UINT16 mask);
|
||||
extern void rfc_send_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command);
|
||||
extern void rfc_send_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command);
|
||||
extern void rfc_send_buf_uih (tRFC_MCB *p_rfc_mcb, UINT8 dlci, BT_HDR *p_buf);
|
||||
extern void rfc_send_credit(tRFC_MCB *p_mcb, UINT8 dlci, UINT8 credit);
|
||||
extern void rfc_process_mx_message (tRFC_MCB *p_rfc_mcb, BT_HDR *p_buf);
|
||||
extern UINT8 rfc_parse_data (tRFC_MCB *p_rfc_mcb, MX_FRAME *p_frame, BT_HDR *p_buf);
|
||||
|
||||
/*
|
||||
** Functions provided by the rfc_disp.c
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Call back functions from RFCOMM */
|
||||
extern void rfcomm_l2cap_if_init (void);
|
||||
|
||||
extern void PORT_StartInd (tRFC_MCB *p_mcb);
|
||||
extern void PORT_StartCnf (tRFC_MCB *p_mcb, UINT16 result);
|
||||
|
||||
extern void PORT_CloseInd (tRFC_MCB *p_mcb);
|
||||
extern void Port_TimeOutCloseMux (tRFC_MCB *p_mcb);
|
||||
|
||||
extern void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu);
|
||||
extern void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result);
|
||||
|
||||
extern void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf);
|
||||
|
||||
extern void PORT_DlcReleaseInd (tRFC_MCB *p_mcb, UINT8 dlci);
|
||||
|
||||
extern void PORT_ParNegInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k);
|
||||
extern void PORT_ParNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k);
|
||||
|
||||
extern void PORT_TestCnf (tRFC_MCB *p_mcb, UINT8 *p_data, UINT16 len);
|
||||
|
||||
extern void PORT_FlowInd (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN fc);
|
||||
|
||||
extern void PORT_PortNegInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 param_mask);
|
||||
extern void PORT_PortNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 result);
|
||||
|
||||
extern void PORT_ControlInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars);
|
||||
extern void PORT_ControlCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars);
|
||||
|
||||
extern void PORT_LineStatusInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,576 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Port Emulation entity utilities
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <string.h>
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/rfcdefs.h"
|
||||
#include "stack/port_api.h"
|
||||
#include "port_int.h"
|
||||
#include "rfc_int.h"
|
||||
#include "stack/l2cdefs.h"
|
||||
#include "btm_int.h"
|
||||
#include "stack/btu.h"
|
||||
#include "osi/mutex.h"
|
||||
#include "osi/allocator.h"
|
||||
#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
static const tPORT_STATE default_port_pars = {
|
||||
PORT_BAUD_RATE_9600,
|
||||
PORT_8_BITS,
|
||||
PORT_ONESTOPBIT,
|
||||
PORT_PARITY_NO,
|
||||
PORT_ODD_PARITY,
|
||||
PORT_FC_OFF,
|
||||
0, /* No rx_char */
|
||||
PORT_XON_DC1,
|
||||
PORT_XOFF_DC3,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_allocate_port
|
||||
**
|
||||
** Description Look through the Port Control Blocks for a free one. Note
|
||||
** that one server can open several ports with the same SCN
|
||||
** if it can support simulteneous requests from different
|
||||
** clients.
|
||||
**
|
||||
** Returns Pointer to the PORT or NULL if not found
|
||||
**
|
||||
*******************************************************************************/
|
||||
tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr)
|
||||
{
|
||||
tPORT *p_port = &rfc_cb.port.port[0];
|
||||
UINT8 xx, yy;
|
||||
|
||||
for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) {
|
||||
if (yy >= MAX_RFC_PORTS) {
|
||||
yy = 0;
|
||||
}
|
||||
|
||||
p_port = &rfc_cb.port.port[yy];
|
||||
if (!p_port->in_use) {
|
||||
memset (p_port, 0, sizeof (tPORT));
|
||||
|
||||
p_port->in_use = TRUE;
|
||||
p_port->inx = yy + 1;
|
||||
|
||||
p_port->dlci = dlci;
|
||||
memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN);
|
||||
|
||||
/* During the open set default state for the port connection */
|
||||
port_set_defaults (p_port);
|
||||
|
||||
rfc_cb.rfc.last_port = yy;
|
||||
RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy, p_port, rfc_cb.rfc.last_port);
|
||||
RFCOMM_TRACE_DEBUG("port_allocate_port: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]);
|
||||
return (p_port);
|
||||
}
|
||||
}
|
||||
|
||||
/* If here, no free PORT found */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_set_defaults
|
||||
**
|
||||
** Description Set defualt port parameters
|
||||
**
|
||||
**
|
||||
*******************************************************************************/
|
||||
void port_set_defaults (tPORT *p_port)
|
||||
{
|
||||
p_port->ev_mask = 0;
|
||||
p_port->p_callback = NULL;
|
||||
p_port->port_ctrl = 0;
|
||||
p_port->error = 0;
|
||||
p_port->line_status = 0;
|
||||
p_port->rx_flag_ev_pending = FALSE;
|
||||
p_port->peer_mtu = RFCOMM_DEFAULT_MTU;
|
||||
|
||||
p_port->user_port_pars = default_port_pars;
|
||||
p_port->peer_port_pars = default_port_pars;
|
||||
|
||||
p_port->credit_tx = 0;
|
||||
p_port->credit_rx = 0;
|
||||
/* p_port->credit_rx_max = PORT_CREDIT_RX_MAX; Determined later */
|
||||
/* p_port->credit_rx_low = PORT_CREDIT_RX_LOW; Determined later */
|
||||
|
||||
memset (&p_port->local_ctrl, 0, sizeof (p_port->local_ctrl));
|
||||
memset (&p_port->peer_ctrl, 0, sizeof (p_port->peer_ctrl));
|
||||
memset (&p_port->rx, 0, sizeof (p_port->rx));
|
||||
memset (&p_port->tx, 0, sizeof (p_port->tx));
|
||||
|
||||
p_port->tx.queue = fixed_queue_new(QUEUE_SIZE_MAX);
|
||||
p_port->rx.queue = fixed_queue_new(QUEUE_SIZE_MAX);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_select_mtu
|
||||
**
|
||||
** Description Select MTU which will best serve connection from our
|
||||
** point of view.
|
||||
** If our device is 1.2 or lower we calculate how many DH5s
|
||||
** fit into 1 RFCOMM buffer.
|
||||
**
|
||||
**
|
||||
*******************************************************************************/
|
||||
void port_select_mtu (tPORT *p_port)
|
||||
{
|
||||
UINT16 packet_size;
|
||||
|
||||
/* Will select MTU only if application did not setup something */
|
||||
if (p_port->mtu == 0) {
|
||||
/* find packet size which connection supports */
|
||||
packet_size = btm_get_max_packet_size (p_port->bd_addr);
|
||||
if (packet_size == 0) {
|
||||
/* something is very wrong */
|
||||
RFCOMM_TRACE_WARNING ("port_select_mtu bad packet size");
|
||||
p_port->mtu = RFCOMM_DEFAULT_MTU;
|
||||
} else {
|
||||
/* We try to negotiate MTU that each packet can be split into whole
|
||||
number of max packets. For example if link is 1.2 max packet size is 339 bytes.
|
||||
At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4 overhead.
|
||||
1695, that will be 5 Dh5 packets. Now maximum RFCOMM packet is
|
||||
5 * 339 = 1695. Minus 4 bytes L2CAP header 1691. Minus RFCOMM 6 bytes header overhead 1685
|
||||
|
||||
For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1 3DH5 packet
|
||||
1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. Minus RFCOMM 6 bytes header overhead 1017 */
|
||||
if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size) {
|
||||
p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
|
||||
RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on connection speed", p_port->mtu);
|
||||
} else {
|
||||
p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
|
||||
RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RFCOMM_TRACE_DEBUG ("port_select_mtu application selected %d", p_port->mtu);
|
||||
}
|
||||
p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
|
||||
if ( p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM ) {
|
||||
p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
|
||||
}
|
||||
p_port->credit_rx_low = (PORT_RX_LOW_WM / p_port->mtu);
|
||||
if ( p_port->credit_rx_low > PORT_RX_BUF_LOW_WM ) {
|
||||
p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
|
||||
}
|
||||
p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
|
||||
if ( p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM ) {
|
||||
p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
|
||||
}
|
||||
RFCOMM_TRACE_DEBUG ("port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
|
||||
p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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;
|
||||
|
||||
osi_mutex_global_lock();
|
||||
RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port);
|
||||
if (p_port->rx.queue != NULL) {
|
||||
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue, 0)) != NULL) {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
p_port->rx.queue_size = 0;
|
||||
|
||||
if (p_port->tx.queue != NULL) {
|
||||
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue, 0)) != NULL) {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
p_port->tx.queue_size = 0;
|
||||
|
||||
osi_mutex_global_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);
|
||||
fixed_queue_free(p_port->tx.queue, NULL);
|
||||
p_port->tx.queue = NULL;
|
||||
fixed_queue_free(p_port->rx.queue, NULL);
|
||||
p_port->rx.queue = NULL;
|
||||
|
||||
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);
|
||||
rfc_port_timer_free (p_port);
|
||||
memset (p_port, 0, sizeof (tPORT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_find_mcb
|
||||
**
|
||||
** Description This function checks if connection exists to device with
|
||||
** the BD_ADDR.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
|
||||
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 */
|
||||
RFCOMM_TRACE_DEBUG("port_find_mcb: found 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("port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d",
|
||||
i, &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
|
||||
return (&rfc_cb.port.rfc_mcb[i]);
|
||||
}
|
||||
}
|
||||
RFCOMM_TRACE_DEBUG("port_find_mcb: not found, 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]);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_find_mcb_dlci_port
|
||||
**
|
||||
** Description Find port on the multiplexer channel based on DLCI. If
|
||||
** this port with DLCI not found try to use even DLCI. This
|
||||
** is for the case when client is establishing connection on
|
||||
** none-initiator MCB.
|
||||
**
|
||||
** Returns Pointer to the PORT or NULL if not found
|
||||
**
|
||||
*******************************************************************************/
|
||||
tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci)
|
||||
{
|
||||
UINT8 inx;
|
||||
|
||||
if (!p_mcb) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (dlci > RFCOMM_MAX_DLCI) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
inx = p_mcb->port_inx[dlci];
|
||||
if (inx == 0) {
|
||||
RFCOMM_TRACE_DEBUG("port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb, dlci);
|
||||
return (NULL);
|
||||
} else {
|
||||
return (&rfc_cb.port.port[inx - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_find_dlci_port
|
||||
**
|
||||
** Description Find port with DLCI not assigned to multiplexer channel
|
||||
**
|
||||
** Returns Pointer to the PORT or NULL if not found
|
||||
**
|
||||
*******************************************************************************/
|
||||
tPORT *port_find_dlci_port (UINT8 dlci)
|
||||
{
|
||||
UINT16 i;
|
||||
tPORT *p_port;
|
||||
|
||||
for (i = 0; i < MAX_RFC_PORTS; i++) {
|
||||
p_port = &rfc_cb.port.port[i];
|
||||
|
||||
if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) {
|
||||
if (p_port->dlci == dlci) {
|
||||
return (p_port);
|
||||
} else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) {
|
||||
p_port->dlci++;
|
||||
return (p_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_find_port
|
||||
**
|
||||
** Description Find port with DLCI, BD_ADDR
|
||||
**
|
||||
** Returns Pointer to the PORT or NULL if not found
|
||||
**
|
||||
*******************************************************************************/
|
||||
tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr)
|
||||
{
|
||||
UINT16 i;
|
||||
tPORT *p_port;
|
||||
|
||||
for (i = 0; i < MAX_RFC_PORTS; i++) {
|
||||
p_port = &rfc_cb.port.port[i];
|
||||
if (p_port->in_use
|
||||
&& (p_port->dlci == dlci)
|
||||
&& !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN)) {
|
||||
return (p_port);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_flow_control_user
|
||||
**
|
||||
** Description Check the current user flow control and if necessary return
|
||||
** events to be send to the user based on the user's specified
|
||||
** flow control type.
|
||||
**
|
||||
** Returns event mask to be returned to the application
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT32 port_flow_control_user (tPORT *p_port)
|
||||
{
|
||||
UINT32 event = 0;
|
||||
|
||||
/* Flow control to the user can be caused by flow controlling by the peer */
|
||||
/* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
|
||||
/* tx_queue is full */
|
||||
BOOLEAN fc = p_port->tx.peer_fc
|
||||
|| !p_port->rfc.p_mcb
|
||||
|| !p_port->rfc.p_mcb->peer_ready
|
||||
|| (p_port->tx.queue_size > PORT_TX_HIGH_WM)
|
||||
|| (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
|
||||
|
||||
if (p_port->tx.user_fc == fc) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
p_port->tx.user_fc = fc;
|
||||
|
||||
if (fc) {
|
||||
event = PORT_EV_FC;
|
||||
} else {
|
||||
event = PORT_EV_FC | PORT_EV_FCS;
|
||||
}
|
||||
|
||||
return (event);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_get_signal_changes
|
||||
**
|
||||
** Description Check modem signals that has been changed
|
||||
**
|
||||
** Returns event mask to be returned to the application
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal)
|
||||
{
|
||||
UINT8 changed_signals = (signal ^ old_signals);
|
||||
UINT32 events = 0;
|
||||
|
||||
if (changed_signals & PORT_DTRDSR_ON) {
|
||||
events |= PORT_EV_DSR;
|
||||
|
||||
if (signal & PORT_DTRDSR_ON) {
|
||||
events |= PORT_EV_DSRS;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed_signals & PORT_CTSRTS_ON) {
|
||||
events |= PORT_EV_CTS;
|
||||
|
||||
if (signal & PORT_CTSRTS_ON) {
|
||||
events |= PORT_EV_CTSS;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed_signals & PORT_RING_ON) {
|
||||
events |= PORT_EV_RING;
|
||||
}
|
||||
|
||||
if (changed_signals & PORT_DCD_ON) {
|
||||
events |= PORT_EV_RLSD;
|
||||
|
||||
if (signal & PORT_DCD_ON) {
|
||||
events |= PORT_EV_RLSDS;
|
||||
}
|
||||
}
|
||||
|
||||
return (p_port->ev_mask & events);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function port_flow_control_peer
|
||||
**
|
||||
** Description Send flow control messages to the peer for both enabling
|
||||
** and disabling flow control, for both credit-based and
|
||||
** TS 07.10 flow control mechanisms.
|
||||
**
|
||||
** Returns nothing
|
||||
**
|
||||
*******************************************************************************/
|
||||
void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
|
||||
{
|
||||
if (!p_port->rfc.p_mcb) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If using credit based flow control */
|
||||
if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
|
||||
/* if want to enable flow from peer */
|
||||
if (enable) {
|
||||
/* update rx credits */
|
||||
if (count > p_port->credit_rx) {
|
||||
p_port->credit_rx = 0;
|
||||
} else {
|
||||
p_port->credit_rx -= count;
|
||||
}
|
||||
|
||||
/* If credit count is less than low credit watermark, and user */
|
||||
/* did not force flow control, send a credit update */
|
||||
/* There might be a special case when we just adjusted rx_max */
|
||||
if ((p_port->credit_rx <= p_port->credit_rx_low)
|
||||
&& !p_port->rx.user_fc
|
||||
&& (p_port->credit_rx_max > p_port->credit_rx)) {
|
||||
rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
|
||||
(UINT8) (p_port->credit_rx_max - p_port->credit_rx));
|
||||
RFCOMM_TRACE_DEBUG("send credit: max %d, rx %d, count %d", p_port->credit_rx_max, p_port->credit_rx, count);
|
||||
p_port->credit_rx = p_port->credit_rx_max;
|
||||
|
||||
p_port->rx.peer_fc = FALSE;
|
||||
} else {
|
||||
RFCOMM_TRACE_DEBUG("credit: max %d, rx %d, low %d", p_port->credit_rx_max, p_port->credit_rx, p_port->credit_rx_low);
|
||||
}
|
||||
}
|
||||
/* else want to disable flow from peer */
|
||||
else {
|
||||
/* if client registered data callback, just do what they want */
|
||||
if (p_port->p_data_callback || p_port->p_data_co_callback) {
|
||||
p_port->rx.peer_fc = TRUE;
|
||||
}
|
||||
/* if queue count reached credit rx max, set peer fc */
|
||||
else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max) {
|
||||
p_port->rx.peer_fc = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* else using TS 07.10 flow control */
|
||||
else {
|
||||
/* if want to enable flow from peer */
|
||||
if (enable) {
|
||||
/* If rfcomm suspended traffic from the peer based on the rx_queue_size */
|
||||
/* check if it can be resumed now */
|
||||
if (p_port->rx.peer_fc
|
||||
&& (p_port->rx.queue_size < PORT_RX_LOW_WM)
|
||||
&& (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) {
|
||||
p_port->rx.peer_fc = FALSE;
|
||||
|
||||
/* If user did not force flow control allow traffic now */
|
||||
if (!p_port->rx.user_fc) {
|
||||
RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* else want to disable flow from peer */
|
||||
else {
|
||||
/* if client registered data callback, just do what they want */
|
||||
if (p_port->p_data_callback || p_port->p_data_co_callback) {
|
||||
p_port->rx.peer_fc = TRUE;
|
||||
RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
|
||||
}
|
||||
/* Check the size of the rx queue. If it exceeds certain */
|
||||
/* level and flow control has not been sent to the peer do it now */
|
||||
else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
|
||||
|| (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM))
|
||||
&& !p_port->rx.peer_fc) {
|
||||
RFCOMM_TRACE_EVENT ("PORT_DataInd Data reached HW. Sending FC set.");
|
||||
|
||||
p_port->rx.peer_fc = TRUE;
|
||||
RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
@@ -0,0 +1,432 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This file contains L2CAP interface functions
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "common/bt_target.h"
|
||||
|
||||
#include "stack/rfcdefs.h"
|
||||
#include "stack/port_api.h"
|
||||
#include "port_int.h"
|
||||
#include "stack/l2c_api.h"
|
||||
#include "stack/l2cdefs.h"
|
||||
#include "rfc_int.h"
|
||||
#include "common/bt_defs.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/mutex.h"
|
||||
#include "osi/alarm.h"
|
||||
#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
static tL2CAP_ERTM_INFO rfc_l2c_etm_opt =
|
||||
{
|
||||
L2CAP_FCR_ERTM_MODE,
|
||||
L2CAP_FCR_CHAN_OPT_ERTM|L2CAP_FCR_CHAN_OPT_BASIC, /* Some devices do not support ERTM */
|
||||
L2CAP_USER_RX_BUF_SIZE,
|
||||
L2CAP_USER_TX_BUF_SIZE,
|
||||
L2CAP_FCR_RX_BUF_SIZE,
|
||||
L2CAP_FCR_TX_BUF_SIZE
|
||||
};
|
||||
|
||||
/*
|
||||
** Define Callback functions to be called by L2CAP
|
||||
*/
|
||||
static void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
|
||||
static void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 err);
|
||||
static void RFCOMM_ConfigInd (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
|
||||
static void RFCOMM_ConfigCnf (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
|
||||
static void RFCOMM_DisconnectInd (UINT16 lcid, BOOLEAN is_clear);
|
||||
static void RFCOMM_QoSViolationInd (BD_ADDR bd_addr);
|
||||
static void RFCOMM_BufDataInd (UINT16 lcid, BT_HDR *p_buf);
|
||||
static void RFCOMM_CongestionStatusInd (UINT16 lcid, BOOLEAN is_congested);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfcomm_l2cap_if_init
|
||||
**
|
||||
** Description This function is called during the RFCOMM task startup
|
||||
** to register interface functions with L2CAP.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfcomm_l2cap_if_init (void)
|
||||
{
|
||||
tL2CAP_APPL_INFO *p_l2c = &rfc_cb.rfc.reg_info;
|
||||
|
||||
p_l2c->pL2CA_ConnectInd_Cb = RFCOMM_ConnectInd;
|
||||
p_l2c->pL2CA_ConnectCfm_Cb = RFCOMM_ConnectCnf;
|
||||
p_l2c->pL2CA_ConnectPnd_Cb = NULL;
|
||||
p_l2c->pL2CA_ConfigInd_Cb = RFCOMM_ConfigInd;
|
||||
p_l2c->pL2CA_ConfigCfm_Cb = RFCOMM_ConfigCnf;
|
||||
p_l2c->pL2CA_DisconnectInd_Cb = RFCOMM_DisconnectInd;
|
||||
p_l2c->pL2CA_DisconnectCfm_Cb = NULL;
|
||||
p_l2c->pL2CA_QoSViolationInd_Cb = RFCOMM_QoSViolationInd;
|
||||
p_l2c->pL2CA_DataInd_Cb = RFCOMM_BufDataInd;
|
||||
p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd;
|
||||
p_l2c->pL2CA_TxComplete_Cb = NULL;
|
||||
|
||||
|
||||
L2CA_Register (BT_PSM_RFCOMM, p_l2c);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_ConnectInd
|
||||
**
|
||||
** Description This is a callback function called by L2CAP when
|
||||
** L2CA_ConnectInd received. Allocate multiplexer control block
|
||||
** and dispatch the event to it.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
|
||||
{
|
||||
tRFC_MCB *p_mcb = rfc_alloc_multiplexer_channel(bd_addr, FALSE);
|
||||
UNUSED(psm);
|
||||
|
||||
if ((p_mcb) && (p_mcb->state != RFC_MX_STATE_IDLE)) {
|
||||
/* if this is collision case */
|
||||
if ((p_mcb->is_initiator) && (p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF)) {
|
||||
p_mcb->pending_lcid = lcid;
|
||||
p_mcb->pending_id = id;
|
||||
|
||||
/* wait random timeout (2 - 12) to resolve collision */
|
||||
/* if peer gives up then local device rejects incoming connection and continues as initiator */
|
||||
/* if timeout, local device disconnects outgoing connection and continues as acceptor */
|
||||
RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectInd start timer for collision, initiator's LCID(0x%x), acceptor's LCID(0x%x)",
|
||||
p_mcb->lcid, p_mcb->pending_lcid);
|
||||
|
||||
rfc_timer_start(p_mcb, (UINT16)(osi_time_get_os_boottime_ms() % 10 + 2));
|
||||
return;
|
||||
} else {
|
||||
/* we cannot accept connection request from peer at this state */
|
||||
/* don't update lcid */
|
||||
p_mcb = NULL;
|
||||
}
|
||||
} else {
|
||||
/* store mcb even if null */
|
||||
rfc_save_lcid_mcb (p_mcb, lcid);
|
||||
}
|
||||
|
||||
if (p_mcb == NULL) {
|
||||
tL2CAP_ERTM_INFO *ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
|
||||
L2CA_ErtmConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0, ertm_opt);
|
||||
return;
|
||||
}
|
||||
p_mcb->lcid = lcid;
|
||||
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &id);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_ConnectCnf
|
||||
**
|
||||
** Description This is a callback function called by L2CAP when
|
||||
** L2CA_ConnectCnf received. Save L2CAP handle and dispatch
|
||||
** event to the FSM.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 result)
|
||||
{
|
||||
tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
|
||||
|
||||
if (!p_mcb) {
|
||||
RFCOMM_TRACE_ERROR ("RFCOMM_ConnectCnf LCID:0x%x", lcid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_mcb->pending_lcid) {
|
||||
/* if peer rejects our connect request but peer's connect request is pending */
|
||||
if (result != L2CAP_CONN_OK ) {
|
||||
UINT16 i;
|
||||
UINT8 idx;
|
||||
|
||||
RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", p_mcb->pending_lcid);
|
||||
|
||||
/* remove mcb from mapping table */
|
||||
rfc_save_lcid_mcb (NULL, p_mcb->lcid);
|
||||
|
||||
p_mcb->lcid = p_mcb->pending_lcid;
|
||||
p_mcb->is_initiator = FALSE;
|
||||
p_mcb->state = RFC_MX_STATE_IDLE;
|
||||
|
||||
/* store mcb into mapping table */
|
||||
rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
|
||||
|
||||
/* update direction bit */
|
||||
for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
|
||||
if ((idx = p_mcb->port_inx[i]) != 0) {
|
||||
p_mcb->port_inx[i] = 0;
|
||||
p_mcb->port_inx[i + 1] = idx;
|
||||
rfc_cb.port.port[idx - 1].dlci += 1;
|
||||
RFCOMM_TRACE_DEBUG ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci);
|
||||
}
|
||||
}
|
||||
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
|
||||
return;
|
||||
} else {
|
||||
RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", p_mcb->pending_lcid);
|
||||
|
||||
tL2CAP_ERTM_INFO *ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
|
||||
/* Peer gave up his connection request, make sure cleaning up L2CAP channel */
|
||||
L2CA_ErtmConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0, ertm_opt);
|
||||
|
||||
p_mcb->pending_lcid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save LCID to be used in all consecutive calls to L2CAP */
|
||||
p_mcb->lcid = lcid;
|
||||
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_CNF, &result);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_ConfigInd
|
||||
**
|
||||
** Description This is a callback function called by L2CAP when
|
||||
** L2CA_ConfigInd received. Save parameters in the control
|
||||
** block and dispatch event to the FSM.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_ConfigInd (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
|
||||
{
|
||||
tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
|
||||
|
||||
if (!p_mcb) {
|
||||
RFCOMM_TRACE_ERROR ("RFCOMM_ConfigInd LCID:0x%x", lcid);
|
||||
return;
|
||||
}
|
||||
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONF_IND, (void *)p_cfg);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_ConfigCnf
|
||||
**
|
||||
** Description This is a callback function called by L2CAP when
|
||||
** L2CA_ConfigCnf received. Save L2CAP handle and dispatch
|
||||
** event to the FSM.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_ConfigCnf (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
|
||||
{
|
||||
tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
|
||||
|
||||
if (!p_mcb) {
|
||||
RFCOMM_TRACE_ERROR ("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid);
|
||||
return;
|
||||
}
|
||||
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONF_CNF, (void *)p_cfg);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_QoSViolationInd
|
||||
**
|
||||
** Description This is a callback function called by L2CAP when
|
||||
** L2CA_QoSViolationIndInd received. Dispatch event to the FSM.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_QoSViolationInd (BD_ADDR bd_addr)
|
||||
{
|
||||
UNUSED(bd_addr);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_DisconnectInd
|
||||
**
|
||||
** Description This is a callback function called by L2CAP when
|
||||
** L2CA_DisconnectInd received. Dispatch event to the FSM.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_DisconnectInd (UINT16 lcid, BOOLEAN is_conf_needed)
|
||||
{
|
||||
tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
|
||||
|
||||
if (is_conf_needed) {
|
||||
L2CA_DisconnectRsp (lcid);
|
||||
}
|
||||
|
||||
if (!p_mcb) {
|
||||
RFCOMM_TRACE_WARNING ("RFCOMM_DisconnectInd LCID:0x%x", lcid);
|
||||
return;
|
||||
}
|
||||
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_DISC_IND, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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);
|
||||
osi_free (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) {
|
||||
osi_free (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);
|
||||
osi_free (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);
|
||||
}
|
||||
osi_free (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);
|
||||
osi_free (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 {
|
||||
osi_free (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);
|
||||
osi_free (p_buf);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_CongestionStatusInd
|
||||
**
|
||||
** Description This is a callback function called by L2CAP when
|
||||
** data RFCOMM L2CAP congestion status changes
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_CongestionStatusInd (UINT16 lcid, BOOLEAN is_congested)
|
||||
{
|
||||
tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
|
||||
|
||||
if (!p_mcb) {
|
||||
RFCOMM_TRACE_ERROR ("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid);
|
||||
return;
|
||||
} else {
|
||||
RFCOMM_TRACE_EVENT ("RFCOMM_CongestionStatusInd LCID:0x%x", lcid);
|
||||
}
|
||||
rfc_process_l2cap_congestion (p_mcb, is_congested);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_find_lcid_mcb
|
||||
**
|
||||
** Description This function returns MCB block supporting local cid
|
||||
**
|
||||
*******************************************************************************/
|
||||
tRFC_MCB *rfc_find_lcid_mcb (UINT16 lcid)
|
||||
{
|
||||
tRFC_MCB *p_mcb;
|
||||
|
||||
if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS) {
|
||||
RFCOMM_TRACE_ERROR ("rfc_find_lcid_mcb LCID:0x%x", lcid);
|
||||
return (NULL);
|
||||
} else {
|
||||
if ((p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID]) != NULL) {
|
||||
if (p_mcb->lcid != lcid) {
|
||||
RFCOMM_TRACE_WARNING ("rfc_find_lcid_mcb LCID reused LCID:0x%x current:0x%x", lcid, p_mcb->lcid);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (p_mcb);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_save_lcid_mcb
|
||||
**
|
||||
** Description This function returns MCB block supporting local cid
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_save_lcid_mcb (tRFC_MCB *p_mcb, UINT16 lcid)
|
||||
{
|
||||
rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
|
||||
}
|
||||
|
||||
#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
@@ -0,0 +1,683 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This file contains state machine and action routines for multiplexer
|
||||
* channel of the RFCOMM unit
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <string.h>
|
||||
#include "stack/bt_types.h"
|
||||
#include "stack/rfcdefs.h"
|
||||
#include "stack/l2cdefs.h"
|
||||
#include "stack/port_api.h"
|
||||
#include "port_int.h"
|
||||
#include "stack/l2c_api.h"
|
||||
#include "rfc_int.h"
|
||||
#include "common/bt_defs.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/mutex.h"
|
||||
#include "common/bt_target.h"
|
||||
#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
#define L2CAP_SUCCESS 0
|
||||
#define L2CAP_ERROR 1
|
||||
|
||||
static tL2CAP_ERTM_INFO rfc_l2c_etm_opt =
|
||||
{
|
||||
L2CAP_FCR_ERTM_MODE,
|
||||
L2CAP_FCR_CHAN_OPT_ERTM|L2CAP_FCR_CHAN_OPT_BASIC, /* Some devices do not support ERTM */
|
||||
L2CAP_USER_RX_BUF_SIZE,
|
||||
L2CAP_USER_TX_BUF_SIZE,
|
||||
L2CAP_FCR_RX_BUF_SIZE,
|
||||
L2CAP_FCR_TX_BUF_SIZE
|
||||
};
|
||||
|
||||
static tL2CAP_FCR_OPTS rfc_l2c_fcr_opts_def =
|
||||
{
|
||||
L2CAP_FCR_ERTM_MODE,
|
||||
RFC_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
|
||||
RFC_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
|
||||
RFC_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
|
||||
RFC_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
|
||||
RFC_FCR_OPT_MAX_PDU_SIZE /* MPS segment size */
|
||||
};
|
||||
|
||||
/********************************************************************************/
|
||||
/* L O C A L F U N C T I O N P R O T O T Y P E S */
|
||||
/********************************************************************************/
|
||||
static void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
|
||||
static void rfc_mx_sm_state_wait_conn_cnf (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
|
||||
static void rfc_mx_sm_state_configure (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
|
||||
static void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
|
||||
static void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
|
||||
static void rfc_mx_sm_state_connected (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
|
||||
static void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
|
||||
|
||||
static void rfc_mx_send_config_req (tRFC_MCB *p_mcb);
|
||||
static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg);
|
||||
static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_sm_execute
|
||||
**
|
||||
** Description This function sends multiplexor events through the state
|
||||
** machine.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_mx_sm_execute (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
|
||||
{
|
||||
RFCOMM_TRACE_DEBUG("%s st:%d, evt:%d\n", __func__, p_mcb->state, event);
|
||||
|
||||
switch (p_mcb->state) {
|
||||
case RFC_MX_STATE_IDLE:
|
||||
rfc_mx_sm_state_idle (p_mcb, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_MX_STATE_WAIT_CONN_CNF:
|
||||
rfc_mx_sm_state_wait_conn_cnf (p_mcb, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_MX_STATE_CONFIGURE:
|
||||
rfc_mx_sm_state_configure (p_mcb, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_MX_STATE_SABME_WAIT_UA:
|
||||
rfc_mx_sm_sabme_wait_ua (p_mcb, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_MX_STATE_WAIT_SABME:
|
||||
rfc_mx_sm_state_wait_sabme (p_mcb, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_MX_STATE_CONNECTED:
|
||||
rfc_mx_sm_state_connected (p_mcb, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_MX_STATE_DISC_WAIT_UA:
|
||||
rfc_mx_sm_state_disc_wait_ua (p_mcb, event, p_data);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_sm_state_idle
|
||||
**
|
||||
** Description This function handles events when the multiplexer is in
|
||||
** IDLE state. This state exists when connection is being
|
||||
** initially established.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
|
||||
{
|
||||
tL2CAP_ERTM_INFO *ertm_opt = NULL;
|
||||
|
||||
RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_idle - evt:%d", event);
|
||||
|
||||
switch (event) {
|
||||
case RFC_MX_EVENT_START_REQ:
|
||||
|
||||
/* Initialize L2CAP MTU */
|
||||
p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
|
||||
|
||||
ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
|
||||
p_mcb->lcid = L2CA_ErtmConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr, ertm_opt);
|
||||
|
||||
if (p_mcb->lcid == 0) {
|
||||
PORT_StartCnf (p_mcb, RFCOMM_ERROR);
|
||||
return;
|
||||
}
|
||||
/* Save entry for quicker access to mcb based on the LCID */
|
||||
rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
|
||||
|
||||
p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_START_RSP:
|
||||
case RFC_MX_EVENT_CONN_CNF:
|
||||
case RFC_MX_EVENT_CONF_IND:
|
||||
case RFC_MX_EVENT_CONF_CNF:
|
||||
RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event);
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_CONN_IND:
|
||||
|
||||
rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT);
|
||||
ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
|
||||
L2CA_ErtmConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0, ertm_opt);
|
||||
|
||||
rfc_mx_send_config_req (p_mcb);
|
||||
|
||||
p_mcb->state = RFC_MX_STATE_CONFIGURE;
|
||||
return;
|
||||
|
||||
case RFC_EVENT_SABME:
|
||||
break;
|
||||
|
||||
case RFC_EVENT_UA:
|
||||
case RFC_EVENT_DM:
|
||||
return;
|
||||
|
||||
case RFC_EVENT_DISC:
|
||||
rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_UIH:
|
||||
rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, FALSE);
|
||||
return;
|
||||
}
|
||||
RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_sm_state_wait_conn_cnf
|
||||
**
|
||||
** Description This function handles events when the multiplexer is
|
||||
** waiting for Connection Confirm from L2CAP.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_mx_sm_state_wait_conn_cnf (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
|
||||
{
|
||||
RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event);
|
||||
switch (event) {
|
||||
case RFC_MX_EVENT_START_REQ:
|
||||
RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event);
|
||||
return;
|
||||
|
||||
/* There is some new timing so that Config Ind comes before security is completed
|
||||
so we are still waiting fo the confirmation. */
|
||||
case RFC_MX_EVENT_CONF_IND:
|
||||
rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_CONN_CNF:
|
||||
if (*((UINT16 *)p_data) != L2CAP_SUCCESS) {
|
||||
p_mcb->state = RFC_MX_STATE_IDLE;
|
||||
|
||||
PORT_StartCnf (p_mcb, *((UINT16 *)p_data));
|
||||
return;
|
||||
}
|
||||
p_mcb->state = RFC_MX_STATE_CONFIGURE;
|
||||
rfc_mx_send_config_req (p_mcb);
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_DISC_IND:
|
||||
p_mcb->state = RFC_MX_STATE_IDLE;
|
||||
PORT_CloseInd (p_mcb);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_TIMEOUT:
|
||||
p_mcb->state = RFC_MX_STATE_IDLE;
|
||||
L2CA_DisconnectReq (p_mcb->lcid);
|
||||
|
||||
/* we gave up outgoing connection request then try peer's request */
|
||||
if (p_mcb->pending_lcid) {
|
||||
UINT16 i;
|
||||
UINT8 idx;
|
||||
|
||||
RFCOMM_TRACE_DEBUG ("RFCOMM MX retry as acceptor in collision case - evt:%d in state:%d", event, p_mcb->state);
|
||||
|
||||
rfc_save_lcid_mcb (NULL, p_mcb->lcid);
|
||||
p_mcb->lcid = p_mcb->pending_lcid;
|
||||
rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
|
||||
|
||||
p_mcb->is_initiator = FALSE;
|
||||
|
||||
/* update direction bit */
|
||||
for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
|
||||
if ((idx = p_mcb->port_inx[i]) != 0) {
|
||||
p_mcb->port_inx[i] = 0;
|
||||
p_mcb->port_inx[i + 1] = idx;
|
||||
rfc_cb.port.port[idx - 1].dlci += 1;
|
||||
RFCOMM_TRACE_DEBUG ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci);
|
||||
}
|
||||
}
|
||||
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
|
||||
} else {
|
||||
PORT_CloseInd (p_mcb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_sm_state_configure
|
||||
**
|
||||
** Description This function handles events when the multiplexer in the
|
||||
** configuration state.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_mx_sm_state_configure (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
|
||||
{
|
||||
RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_configure - evt:%d", event);
|
||||
switch (event) {
|
||||
case RFC_MX_EVENT_START_REQ:
|
||||
case RFC_MX_EVENT_CONN_CNF:
|
||||
|
||||
RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event);
|
||||
return;
|
||||
|
||||
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_TIMEOUT:
|
||||
p_mcb->state = RFC_MX_STATE_IDLE;
|
||||
L2CA_DisconnectReq (p_mcb->lcid);
|
||||
|
||||
PORT_StartCnf (p_mcb, RFCOMM_ERROR);
|
||||
return;
|
||||
}
|
||||
RFCOMM_TRACE_EVENT ("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)
|
||||
{
|
||||
UNUSED(p_data);
|
||||
|
||||
RFCOMM_TRACE_EVENT ("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_ERROR ("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_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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_EVENT ("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_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_sm_state_connected
|
||||
**
|
||||
** Description This function handles events when the multiplexer is
|
||||
** in the CONNECTED state
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_mx_sm_state_connected (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
|
||||
{
|
||||
UNUSED(p_data);
|
||||
|
||||
RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_connected - evt:%d", event);
|
||||
|
||||
switch (event) {
|
||||
case RFC_EVENT_TIMEOUT:
|
||||
case RFC_MX_EVENT_CLOSE_REQ:
|
||||
rfc_timer_start (p_mcb, RFC_DISC_TIMEOUT);
|
||||
p_mcb->state = RFC_MX_STATE_DISC_WAIT_UA;
|
||||
rfc_send_disc (p_mcb, RFCOMM_MX_DLCI);
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_DISC_IND:
|
||||
p_mcb->state = RFC_MX_STATE_IDLE;
|
||||
PORT_CloseInd (p_mcb);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_DISC:
|
||||
/* Reply with UA. If initiator bring down L2CAP connection */
|
||||
/* If server wait for some time if client decide to reinitiate channel */
|
||||
rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
|
||||
if (p_mcb->is_initiator) {
|
||||
L2CA_DisconnectReq (p_mcb->lcid);
|
||||
}
|
||||
/* notify all ports that connection is gone */
|
||||
PORT_CloseInd (p_mcb);
|
||||
return;
|
||||
}
|
||||
RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_sm_state_disc_wait_ua
|
||||
**
|
||||
** Description This function handles events when the multiplexer sent
|
||||
** DISC and is waiting for UA reply.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
|
||||
RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_disc_wait_ua - evt:%d", event);
|
||||
switch (event) {
|
||||
case RFC_EVENT_UA:
|
||||
case RFC_EVENT_DM:
|
||||
case RFC_EVENT_TIMEOUT:
|
||||
L2CA_DisconnectReq (p_mcb->lcid);
|
||||
|
||||
if (p_mcb->restart_required) {
|
||||
tL2CAP_ERTM_INFO *ertm_opt = rfc_cb.port.enable_l2cap_ertm ? &rfc_l2c_etm_opt : NULL;
|
||||
/* Start Request was received while disconnecting. Execute it again */
|
||||
p_mcb->lcid = L2CA_ErtmConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr, ertm_opt);
|
||||
|
||||
if (p_mcb->lcid == 0) {
|
||||
PORT_StartCnf (p_mcb, RFCOMM_ERROR);
|
||||
return;
|
||||
}
|
||||
/* Save entry for quicker access to mcb based on the LCID */
|
||||
rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
|
||||
|
||||
/* clean up before reuse it */
|
||||
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_mcb->cmd_q, 0)) != NULL) {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
|
||||
rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER);
|
||||
|
||||
p_mcb->is_initiator = TRUE;
|
||||
p_mcb->restart_required = FALSE;
|
||||
p_mcb->local_cfg_sent = FALSE;
|
||||
p_mcb->peer_cfg_rcvd = FALSE;
|
||||
|
||||
p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
|
||||
return;
|
||||
}
|
||||
rfc_release_multiplexer_channel (p_mcb);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_DISC:
|
||||
rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_UIH:
|
||||
osi_free (p_data);
|
||||
rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, FALSE);
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_START_REQ:
|
||||
p_mcb->restart_required = TRUE;
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_DISC_IND:
|
||||
p_mcb->state = RFC_MX_STATE_IDLE;
|
||||
PORT_CloseInd (p_mcb);
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_CLOSE_REQ:
|
||||
return;
|
||||
|
||||
case RFC_MX_EVENT_QOS_VIOLATION_IND:
|
||||
break;
|
||||
}
|
||||
RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_send_config_req
|
||||
**
|
||||
** Description This function handles L2CA_ConnectInd message from the
|
||||
** L2CAP. Accept connection.
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void rfc_mx_send_config_req (tRFC_MCB *p_mcb)
|
||||
{
|
||||
tL2CAP_CFG_INFO cfg;
|
||||
|
||||
RFCOMM_TRACE_EVENT ("rfc_mx_send_config_req");
|
||||
|
||||
memset (&cfg, 0, sizeof (tL2CAP_CFG_INFO));
|
||||
|
||||
cfg.mtu_present = TRUE;
|
||||
cfg.mtu = L2CAP_MTU_SIZE;
|
||||
|
||||
if (rfc_cb.port.enable_l2cap_ertm) {
|
||||
cfg.fcr_present = TRUE;
|
||||
cfg.fcr = rfc_l2c_fcr_opts_def;
|
||||
}
|
||||
|
||||
/* Defaults set by memset
|
||||
cfg.flush_to_present = FALSE;
|
||||
cfg.qos_present = FALSE;
|
||||
cfg.fcr_present = FALSE;
|
||||
cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
|
||||
cfg.fcs_present = FALSE;
|
||||
cfg.fcs = N/A when fcs_present is FALSE;
|
||||
*/
|
||||
L2CA_ConfigReq (p_mcb->lcid, &cfg);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_conf_cnf
|
||||
**
|
||||
** Description This function handles L2CA_ConfigCnf message from the
|
||||
** L2CAP. If result is not success tell upper layer that
|
||||
** start has not been accepted. If initiator send SABME
|
||||
** on DLCI 0. T1 is still running.
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg)
|
||||
{
|
||||
// RFCOMM_TRACE_EVENT ("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg, (p_cfg) ? p_cfg->result : 0);
|
||||
|
||||
if (p_cfg->result != L2CAP_CFG_OK) {
|
||||
if (p_mcb->is_initiator) {
|
||||
PORT_StartCnf (p_mcb, p_cfg->result);
|
||||
L2CA_DisconnectReq (p_mcb->lcid);
|
||||
}
|
||||
rfc_release_multiplexer_channel (p_mcb);
|
||||
return;
|
||||
}
|
||||
|
||||
p_mcb->local_cfg_sent = TRUE;
|
||||
if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->peer_cfg_rcvd) {
|
||||
if (p_mcb->is_initiator) {
|
||||
p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
|
||||
rfc_send_sabme (p_mcb, RFCOMM_MX_DLCI);
|
||||
rfc_timer_start (p_mcb, RFC_T1_TIMEOUT);
|
||||
} else {
|
||||
p_mcb->state = RFC_MX_STATE_WAIT_SABME;
|
||||
rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT); /* - increased from T2=20 to CONN=120
|
||||
to allow the user more than 10 sec to type in the
|
||||
pin which can be e.g. 16 digits */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_mx_conf_ind
|
||||
**
|
||||
** Description This function handles L2CA_ConfigInd message from the
|
||||
** L2CAP. Send the L2CA_ConfigRsp message.
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg)
|
||||
{
|
||||
/* Save peer L2CAP MTU if present */
|
||||
/* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */
|
||||
if (p_cfg->mtu_present) {
|
||||
p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1;
|
||||
} else {
|
||||
p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
|
||||
}
|
||||
|
||||
p_cfg->mtu_present = FALSE;
|
||||
p_cfg->flush_to_present = FALSE;
|
||||
p_cfg->qos_present = FALSE;
|
||||
|
||||
p_cfg->result = L2CAP_CFG_OK;
|
||||
|
||||
L2CA_ConfigRsp (p_mcb->lcid, p_cfg);
|
||||
|
||||
p_mcb->peer_cfg_rcvd = TRUE;
|
||||
if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->local_cfg_sent) {
|
||||
if (p_mcb->is_initiator) {
|
||||
p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
|
||||
rfc_send_sabme (p_mcb, RFCOMM_MX_DLCI);
|
||||
rfc_timer_start (p_mcb, RFC_T1_TIMEOUT);
|
||||
} else {
|
||||
p_mcb->state = RFC_MX_STATE_WAIT_SABME;
|
||||
rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT); /* - increased from T2=20 to CONN=120
|
||||
to allow the user more than 10 sec to type in the
|
||||
pin which can be e.g. 16 digits */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
@@ -0,0 +1,908 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This file contains state machine and action routines for a port of the
|
||||
* RFCOMM unit
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <string.h>
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/rfcdefs.h"
|
||||
#include "stack/btm_api.h"
|
||||
#include "btm_int.h"
|
||||
#include "stack/port_api.h"
|
||||
#include "port_int.h"
|
||||
#include "rfc_int.h"
|
||||
#include "common/bt_defs.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/mutex.h"
|
||||
#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
/********************************************************************************/
|
||||
/* L O C A L F U N C T I O N P R O T O T Y P E S */
|
||||
/********************************************************************************/
|
||||
static void rfc_port_sm_state_closed (tPORT *p_port, UINT16 event, void *p_data);
|
||||
static void rfc_port_sm_sabme_wait_ua (tPORT *p_port, UINT16 event, void *p_data);
|
||||
static void rfc_port_sm_opened (tPORT *p_port, UINT16 event, void *p_data);
|
||||
static void rfc_port_sm_orig_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data);
|
||||
static void rfc_port_sm_term_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data);
|
||||
static void rfc_port_sm_disc_wait_ua (tPORT *p_port, UINT16 event, void *p_data);
|
||||
|
||||
static void rfc_port_uplink_data (tPORT *p_port, BT_HDR *p_buf);
|
||||
|
||||
static void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_port_sm_execute
|
||||
**
|
||||
** Description This function sends port events through the state
|
||||
** machine.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_port_sm_execute (tPORT *p_port, UINT16 event, void *p_data)
|
||||
{
|
||||
RFCOMM_TRACE_DEBUG("%s st:%d, evt:%d\n", __func__, p_port->rfc.state, event);
|
||||
|
||||
if (!p_port) {
|
||||
RFCOMM_TRACE_WARNING ("NULL port event %d", event);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_port->rfc.state) {
|
||||
case RFC_STATE_CLOSED:
|
||||
rfc_port_sm_state_closed (p_port, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_STATE_SABME_WAIT_UA:
|
||||
rfc_port_sm_sabme_wait_ua (p_port, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_STATE_ORIG_WAIT_SEC_CHECK:
|
||||
rfc_port_sm_orig_wait_sec_check (p_port, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_STATE_TERM_WAIT_SEC_CHECK:
|
||||
rfc_port_sm_term_wait_sec_check (p_port, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_STATE_OPENED:
|
||||
rfc_port_sm_opened (p_port, event, p_data);
|
||||
break;
|
||||
|
||||
case RFC_STATE_DISC_WAIT_UA:
|
||||
rfc_port_sm_disc_wait_ua (p_port, event, p_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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:
|
||||
osi_free (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:
|
||||
osi_free (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_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:
|
||||
osi_free (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:
|
||||
osi_free (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_port_sm_term_wait_sec_check
|
||||
**
|
||||
** Description This function handles events for the port in the
|
||||
** WAIT_SEC_CHECK state. SABME has been received from the
|
||||
** peer and Security Manager verifes BD_ADDR, before we can
|
||||
** send ESTABLISH_IND to the Port entity
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_port_sm_term_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data)
|
||||
{
|
||||
switch (event) {
|
||||
case RFC_EVENT_SEC_COMPLETE:
|
||||
if (*((UINT8 *)p_data) != BTM_SUCCESS) {
|
||||
/* Authentication/authorization failed. If link is still */
|
||||
/* up send DM and check if we need to start inactive timer */
|
||||
if (p_port->rfc.p_mcb) {
|
||||
rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
|
||||
p_port->rfc.p_mcb->is_disc_initiator = TRUE;
|
||||
port_rfc_closed (p_port, PORT_SEC_FAILED);
|
||||
}
|
||||
} else {
|
||||
PORT_DlcEstablishInd (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu);
|
||||
}
|
||||
return;
|
||||
|
||||
case RFC_EVENT_OPEN:
|
||||
case RFC_EVENT_CLOSE:
|
||||
RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_CLEAR:
|
||||
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 Term Wait Sec event Data");
|
||||
osi_free (p_data);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_SABME:
|
||||
/* Ignore SABME retransmission if client dares to do so */
|
||||
return;
|
||||
|
||||
case RFC_EVENT_DISC:
|
||||
btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
|
||||
p_port->rfc.state = RFC_STATE_CLOSED;
|
||||
rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
|
||||
|
||||
PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_UIH:
|
||||
osi_free (p_data);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_ESTABLISH_RSP:
|
||||
if (*((UINT8 *)p_data) != RFCOMM_SUCCESS) {
|
||||
if (p_port->rfc.p_mcb) {
|
||||
rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
|
||||
if (*((UINT8 *)p_data) == RFCOMM_LOW_RESOURCES) {
|
||||
port_rfc_closed(p_port, PORT_NO_RESOURCES);
|
||||
} else {
|
||||
port_rfc_closed(p_port, PORT_UNKNOWN_ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
|
||||
p_port->rfc.state = RFC_STATE_OPENED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
RFCOMM_TRACE_WARNING ("Port state term_wait_sec_check Event ignored %d", event);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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");
|
||||
osi_free (p_data);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_UIH:
|
||||
osi_free (p_data);
|
||||
return;
|
||||
}
|
||||
RFCOMM_TRACE_WARNING ("Port state orig_wait_sec_check Event ignored %d", event);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_port_sm_disc_wait_ua
|
||||
**
|
||||
** Description This function handles events when DISC on the DLC was
|
||||
** sent and SM is waiting for UA or DM.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_port_sm_disc_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_CLEAR:
|
||||
rfc_port_closed (p_port);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_DATA:
|
||||
osi_free (p_data);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_UA:
|
||||
p_port->rfc.p_mcb->is_disc_initiator = TRUE;
|
||||
/* Case falls through */
|
||||
|
||||
case RFC_EVENT_DM:
|
||||
rfc_port_closed (p_port);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_SABME:
|
||||
rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_DISC:
|
||||
rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_UIH:
|
||||
osi_free (p_data);
|
||||
rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
|
||||
return;
|
||||
|
||||
case RFC_EVENT_TIMEOUT:
|
||||
rfc_port_closed (p_port);
|
||||
return;
|
||||
}
|
||||
|
||||
RFCOMM_TRACE_WARNING ("Port state disc_wait_ua Event ignored %d", event);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_port_uplink_data
|
||||
**
|
||||
** Description This function handles uplink information data frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_port_uplink_data (tPORT *p_port, BT_HDR *p_buf)
|
||||
{
|
||||
PORT_DataInd (p_port->rfc.p_mcb, p_port->dlci, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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 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_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_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_process_nsc
|
||||
**
|
||||
** Description This function handles None Supported Command frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_process_nsc (tRFC_MCB *p_mcb, MX_FRAME *p_frame)
|
||||
{
|
||||
UNUSED(p_mcb);
|
||||
UNUSED(p_frame);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_process_test
|
||||
**
|
||||
** Description This function handles Test frame. If this is a command
|
||||
** reply to it. Otherwise pass response to the user.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_process_test_rsp (tRFC_MCB *p_mcb, BT_HDR *p_buf)
|
||||
{
|
||||
UNUSED(p_mcb);
|
||||
|
||||
osi_free (p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_process_fcon
|
||||
**
|
||||
** Description This function handles FCON frame. The peer entity is able
|
||||
** to receive new information
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_process_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command)
|
||||
{
|
||||
if (is_command) {
|
||||
rfc_cb.rfc.peer_rx_disabled = FALSE;
|
||||
|
||||
rfc_send_fcon (p_mcb, FALSE);
|
||||
|
||||
if (!p_mcb->l2cap_congested) {
|
||||
PORT_FlowInd (p_mcb, 0, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_process_fcoff
|
||||
**
|
||||
** Description This function handles FCOFF frame. The peer entity is unable
|
||||
** to receive new information
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_process_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command)
|
||||
{
|
||||
if (is_command) {
|
||||
rfc_cb.rfc.peer_rx_disabled = TRUE;
|
||||
|
||||
if (!p_mcb->l2cap_congested) {
|
||||
PORT_FlowInd (p_mcb, 0, FALSE);
|
||||
}
|
||||
|
||||
rfc_send_fcoff (p_mcb, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_process_l2cap_congestion
|
||||
**
|
||||
** Description This function handles L2CAP congestion messages
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_process_l2cap_congestion (tRFC_MCB *p_mcb, BOOLEAN is_congested)
|
||||
{
|
||||
p_mcb->l2cap_congested = is_congested;
|
||||
|
||||
if (!is_congested) {
|
||||
rfc_check_send_cmd(p_mcb, NULL);
|
||||
}
|
||||
|
||||
if (!rfc_cb.rfc.peer_rx_disabled) {
|
||||
if (!is_congested) {
|
||||
PORT_FlowInd (p_mcb, 0, TRUE);
|
||||
} else {
|
||||
PORT_FlowInd (p_mcb, 0, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_set_port_pars
|
||||
**
|
||||
** Description This function sets the tPORT_STATE structure given a p_frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
||||
void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame)
|
||||
{
|
||||
if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_BIT_RATE) {
|
||||
port_pars->baud_rate = p_frame->u.rpn.baud_rate;
|
||||
}
|
||||
if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_DATA_BITS) {
|
||||
port_pars->byte_size = p_frame->u.rpn.byte_size;
|
||||
}
|
||||
if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_STOP_BITS) {
|
||||
port_pars->stop_bits = p_frame->u.rpn.stop_bits;
|
||||
}
|
||||
if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY) {
|
||||
port_pars->parity = p_frame->u.rpn.parity;
|
||||
}
|
||||
if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY_TYPE) {
|
||||
port_pars->parity_type = p_frame->u.rpn.parity_type;
|
||||
}
|
||||
if (p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_XONXOFF_ON_INPUT |
|
||||
RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT |
|
||||
RFCOMM_RPN_PM_RTR_ON_INPUT |
|
||||
RFCOMM_RPN_PM_RTR_ON_OUTPUT |
|
||||
RFCOMM_RPN_PM_RTC_ON_INPUT |
|
||||
RFCOMM_RPN_PM_RTC_ON_OUTPUT)) {
|
||||
port_pars->fc_type = p_frame->u.rpn.fc_type;
|
||||
}
|
||||
if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XON_CHAR) {
|
||||
port_pars->xon_char = p_frame->u.rpn.xon_char;
|
||||
}
|
||||
if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XOFF_CHAR) {
|
||||
port_pars->xoff_char = p_frame->u.rpn.xoff_char;
|
||||
}
|
||||
}
|
||||
|
||||
#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
@@ -0,0 +1,379 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* This file contains functions callable by an application
|
||||
* running on top of RFCOMM
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/rfcdefs.h"
|
||||
#include "stack/port_api.h"
|
||||
#include "stack/l2c_api.h"
|
||||
#include "port_int.h"
|
||||
#include "rfc_int.h"
|
||||
#include "common/bt_defs.h"
|
||||
|
||||
#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
#if RFC_DYNAMIC_MEMORY == FALSE
|
||||
tRFC_CB rfc_cb;
|
||||
#else
|
||||
tRFC_CB *rfc_cb_ptr;
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_StartReq
|
||||
**
|
||||
** Description This function handles Start Request from the upper layer.
|
||||
** If RFCOMM multiplexer channel can not be allocated
|
||||
** send start not accepted confirmation. Otherwise dispatch
|
||||
** start event to the state machine.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_StartReq (tRFC_MCB *p_mcb)
|
||||
{
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_REQ, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_StartRsp
|
||||
**
|
||||
** Description This function handles Start Response from the upper layer.
|
||||
** Save upper layer handle and result of the Start Indication
|
||||
** in the control block and dispatch event to the FSM.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_StartRsp (tRFC_MCB *p_mcb, UINT16 result)
|
||||
{
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_RSP, &result);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_DlcEstablishReq
|
||||
**
|
||||
** Description This function is called by the user app to establish
|
||||
** connection with the specific dlci on a specific bd device.
|
||||
** It will allocate RFCOMM connection control block if not
|
||||
** allocated before and dispatch open event to the state
|
||||
** machine.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
|
||||
{
|
||||
UNUSED(mtu);
|
||||
if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
|
||||
PORT_DlcEstablishCnf (p_mcb, dlci, 0, 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;
|
||||
}
|
||||
|
||||
rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_DlcEstablishRsp
|
||||
**
|
||||
** Description This function is called by the port emulation entity
|
||||
** acks Establish Indication.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result)
|
||||
{
|
||||
UNUSED(mtu);
|
||||
if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS)) {
|
||||
PORT_DlcReleaseInd (p_mcb, dlci);
|
||||
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;
|
||||
}
|
||||
rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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_ParNegRsp
|
||||
**
|
||||
** Description This function is called by the user app to acknowledge
|
||||
** DLC parameter negotiation.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
|
||||
{
|
||||
if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send Parameter Negotiation Response UIH frame */
|
||||
rfc_send_pn (p_mcb, dlci, FALSE, mtu, cl, k);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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 RFCOMM_PortNegRsp
|
||||
**
|
||||
** Description This function is called by the user app to acknowledge
|
||||
** Port parameters negotiation.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars,
|
||||
UINT16 param_mask)
|
||||
{
|
||||
if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
rfc_send_rpn (p_mcb, dlci, FALSE, p_pars, param_mask);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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 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_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_DlcReleaseReq
|
||||
**
|
||||
** Description This function is called by the PORT unit to close DLC
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, UINT8 dlci)
|
||||
{
|
||||
rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_CLOSE, 0);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function RFCOMM_DataReq
|
||||
**
|
||||
** Description This function is called by the user app to send data buffer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void RFCOMM_DataReq (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
|
||||
{
|
||||
rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_DATA, p_buf);
|
||||
}
|
||||
|
||||
|
||||
#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
@@ -0,0 +1,953 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This file contains functions to send TS 07.10 frames
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/rfcdefs.h"
|
||||
#include "stack/port_api.h"
|
||||
#include "stack/l2c_api.h"
|
||||
#include "port_int.h"
|
||||
#include "rfc_int.h"
|
||||
#include "osi/mutex.h"
|
||||
#include "osi/allocator.h"
|
||||
#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_sabme
|
||||
**
|
||||
** Description This function sends SABME frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_sabme (tRFC_MCB *p_mcb, UINT8 dlci)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE);
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
/* SABME frame, command, PF = 1, dlci */
|
||||
*p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = RFCOMM_SABME | RFCOMM_PF;
|
||||
*p_data++ = RFCOMM_EA | 0;
|
||||
|
||||
*p_data = RFCOMM_SABME_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
|
||||
|
||||
p_buf->len = 4;
|
||||
|
||||
rfc_check_send_cmd(p_mcb, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_ua
|
||||
**
|
||||
** Description This function sends UA frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_ua (tRFC_MCB *p_mcb, UINT8 dlci)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, FALSE);
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
/* ua frame, response, PF = 1, dlci */
|
||||
*p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = RFCOMM_UA | RFCOMM_PF;
|
||||
*p_data++ = RFCOMM_EA | 0;
|
||||
|
||||
*p_data = RFCOMM_UA_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
|
||||
|
||||
p_buf->len = 4;
|
||||
|
||||
rfc_check_send_cmd(p_mcb, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_dm
|
||||
**
|
||||
** Description This function sends DM frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_dm (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN pf)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, FALSE);
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
/* DM frame, response, PF = 1, dlci */
|
||||
*p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = RFCOMM_DM | ((pf) ? RFCOMM_PF : 0);
|
||||
*p_data++ = RFCOMM_EA | 0;
|
||||
|
||||
*p_data = RFCOMM_DM_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
|
||||
|
||||
p_buf->len = 4;
|
||||
|
||||
rfc_check_send_cmd(p_mcb, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_disc
|
||||
**
|
||||
** Description This function sends DISC frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_disc (tRFC_MCB *p_mcb, UINT8 dlci)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE);
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
/* DISC frame, command, PF = 1, dlci */
|
||||
*p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = RFCOMM_DISC | RFCOMM_PF;
|
||||
*p_data++ = RFCOMM_EA | 0;
|
||||
|
||||
*p_data = RFCOMM_DISC_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
|
||||
|
||||
p_buf->len = 4;
|
||||
|
||||
rfc_check_send_cmd(p_mcb, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_buf_uih
|
||||
**
|
||||
** Description This function sends UIH frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_buf_uih (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
|
||||
{
|
||||
UINT8 *p_data;
|
||||
UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE);
|
||||
UINT8 credits;
|
||||
|
||||
p_buf->offset -= RFCOMM_CTRL_FRAME_LEN;
|
||||
if (p_buf->len > 127) {
|
||||
p_buf->offset--;
|
||||
}
|
||||
|
||||
if (dlci) {
|
||||
credits = (UINT8)p_buf->layer_specific;
|
||||
} else {
|
||||
credits = 0;
|
||||
}
|
||||
|
||||
if (credits) {
|
||||
p_buf->offset--;
|
||||
}
|
||||
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
/* UIH frame, command, PF = 0, dlci */
|
||||
*p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = RFCOMM_UIH | ((credits) ? RFCOMM_PF : 0);
|
||||
if (p_buf->len <= 127) {
|
||||
*p_data++ = RFCOMM_EA | (p_buf->len << 1);
|
||||
p_buf->len += 3;
|
||||
} else {
|
||||
*p_data++ = (p_buf->len & 0x7f) << 1;
|
||||
*p_data++ = p_buf->len >> RFCOMM_SHIFT_LENGTH2;
|
||||
p_buf->len += 4;
|
||||
}
|
||||
|
||||
if (credits) {
|
||||
*p_data++ = credits;
|
||||
p_buf->len++;
|
||||
}
|
||||
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len++;
|
||||
|
||||
*p_data = RFCOMM_UIH_FCS ((UINT8 *)(p_buf + 1) + p_buf->offset, dlci);
|
||||
|
||||
if (dlci == RFCOMM_MX_DLCI) {
|
||||
rfc_check_send_cmd(p_mcb, p_buf);
|
||||
} else {
|
||||
L2CA_DataWrite (p_mcb->lcid, p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_pn
|
||||
**
|
||||
** Description This function sends DLC Parameters Negotiation Frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_pn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT16 mtu, UINT8 cl, UINT8 k)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_PN;
|
||||
*p_data++ = RFCOMM_EA | (RFCOMM_MX_PN_LEN << 1);
|
||||
|
||||
*p_data++ = dlci;
|
||||
*p_data++ = RFCOMM_PN_FRAM_TYPE_UIH | cl;
|
||||
|
||||
/* It appeared that we need to reply with the same priority bits as we received.
|
||||
** We will use the fact that we reply in the same context so rx_frame can still be used.
|
||||
*/
|
||||
if (is_command) {
|
||||
*p_data++ = RFCOMM_PN_PRIORITY_0;
|
||||
} else {
|
||||
*p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority;
|
||||
}
|
||||
|
||||
*p_data++ = RFCOMM_T1_DSEC;
|
||||
*p_data++ = mtu & 0xFF;
|
||||
*p_data++ = mtu >> 8;
|
||||
*p_data++ = RFCOMM_N2;
|
||||
*p_data = k;
|
||||
|
||||
/* Total length is sizeof PN data + mx header 2 */
|
||||
p_buf->len = RFCOMM_MX_PN_LEN + 2;
|
||||
|
||||
rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_fcon
|
||||
**
|
||||
** Description This function sends Flow Control On Command.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCON;
|
||||
*p_data++ = RFCOMM_EA | (RFCOMM_MX_FCON_LEN << 1);
|
||||
|
||||
/* Total length is sizeof FCON data + mx header 2 */
|
||||
p_buf->len = RFCOMM_MX_FCON_LEN + 2;
|
||||
|
||||
rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_fcoff
|
||||
**
|
||||
** Description This function sends Flow Control Off Command.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCOFF;
|
||||
*p_data++ = RFCOMM_EA | (RFCOMM_MX_FCOFF_LEN << 1);
|
||||
|
||||
/* Total length is sizeof FCOFF data + mx header 2 */
|
||||
p_buf->len = RFCOMM_MX_FCOFF_LEN + 2;
|
||||
|
||||
rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_msc
|
||||
**
|
||||
** Description This function sends Modem Status Command Frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_msc (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command,
|
||||
tPORT_CTRL *p_pars)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
UINT8 signals;
|
||||
UINT8 break_duration;
|
||||
UINT8 len;
|
||||
|
||||
signals = p_pars->modem_signal;
|
||||
break_duration = p_pars->break_signal;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
if (break_duration) {
|
||||
len = RFCOMM_MX_MSC_LEN_WITH_BREAK;
|
||||
} else {
|
||||
len = RFCOMM_MX_MSC_LEN_NO_BREAK;
|
||||
}
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_MSC;
|
||||
*p_data++ = RFCOMM_EA | (len << 1);
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = RFCOMM_EA |
|
||||
((p_pars->fc) ? RFCOMM_MSC_FC : 0) |
|
||||
((signals & MODEM_SIGNAL_DTRDSR) ? RFCOMM_MSC_RTC : 0) |
|
||||
((signals & MODEM_SIGNAL_RTSCTS) ? RFCOMM_MSC_RTR : 0) |
|
||||
((signals & MODEM_SIGNAL_RI) ? RFCOMM_MSC_IC : 0) |
|
||||
((signals & MODEM_SIGNAL_DCD) ? RFCOMM_MSC_DV : 0);
|
||||
|
||||
if (break_duration) {
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_MSC_BREAK_PRESENT_MASK |
|
||||
(break_duration << RFCOMM_MSC_SHIFT_BREAK);
|
||||
}
|
||||
|
||||
/* Total length is sizeof MSC data + mx header 2 */
|
||||
p_buf->len = len + 2;
|
||||
|
||||
rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_rls
|
||||
**
|
||||
** Description This function sends Remote Line Status Command Frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_rls (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT8 status)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RLS;
|
||||
*p_data++ = RFCOMM_EA | (RFCOMM_MX_RLS_LEN << 1);
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = RFCOMM_RLS_ERROR | status;
|
||||
|
||||
/* Total length is sizeof RLS data + mx header 2 */
|
||||
p_buf->len = RFCOMM_MX_RLS_LEN + 2;
|
||||
|
||||
rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_nsc
|
||||
**
|
||||
** Description This function sends Non Supported Command Response.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_nsc (tRFC_MCB *p_mcb)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_I_CR(FALSE) | RFCOMM_MX_NSC;
|
||||
*p_data++ = RFCOMM_EA | (RFCOMM_MX_NSC_LEN << 1);
|
||||
|
||||
*p_data++ = rfc_cb.rfc.rx_frame.ea |
|
||||
(rfc_cb.rfc.rx_frame.cr << RFCOMM_SHIFT_CR) |
|
||||
rfc_cb.rfc.rx_frame.type;
|
||||
|
||||
/* Total length is sizeof NSC data + mx header 2 */
|
||||
p_buf->len = RFCOMM_MX_NSC_LEN + 2;
|
||||
|
||||
rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_rpn
|
||||
**
|
||||
** Description This function sends Remote Port Negotiation Command
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_rpn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command,
|
||||
tPORT_STATE *p_pars, UINT16 mask)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RPN;
|
||||
|
||||
if (!p_pars) {
|
||||
*p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_REQ_LEN << 1);
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
|
||||
p_buf->len = RFCOMM_MX_RPN_REQ_LEN + 2;
|
||||
} else {
|
||||
*p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_LEN << 1);
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = p_pars->baud_rate;
|
||||
*p_data++ = (p_pars->byte_size << RFCOMM_RPN_BITS_SHIFT)
|
||||
| (p_pars->stop_bits << RFCOMM_RPN_STOP_BITS_SHIFT)
|
||||
| (p_pars->parity << RFCOMM_RPN_PARITY_SHIFT)
|
||||
| (p_pars->parity_type << RFCOMM_RPN_PARITY_TYPE_SHIFT);
|
||||
*p_data++ = p_pars->fc_type;
|
||||
*p_data++ = p_pars->xon_char;
|
||||
*p_data++ = p_pars->xoff_char;
|
||||
*p_data++ = (mask & 0xFF);
|
||||
*p_data++ = (mask >> 8);
|
||||
|
||||
/* Total length is sizeof RPN data + mx header 2 */
|
||||
p_buf->len = RFCOMM_MX_RPN_LEN + 2;
|
||||
}
|
||||
|
||||
rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
|
||||
}
|
||||
|
||||
#if BT_RFCOMM_BQB_INCLUDED
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_bqb_send_msc_cmd
|
||||
**
|
||||
** Description This function sends msc command for BQB test.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_bqb_send_msc_cmd(BD_ADDR cert_pts_addr)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT8 dlci;
|
||||
BOOLEAN get_dlci = FALSE;
|
||||
tPORT *p_port;
|
||||
tPORT_CTRL *p_pars;
|
||||
tRFC_MCB *p_mcb;
|
||||
|
||||
if ((p_pars = (tPORT_CTRL *)osi_malloc(sizeof(tPORT_CTRL))) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_pars->modem_signal = 0;
|
||||
p_pars->break_signal = 0;
|
||||
p_pars->fc = TRUE;
|
||||
|
||||
p_mcb = port_find_mcb (cert_pts_addr);
|
||||
|
||||
for (i = 0; i < MAX_RFC_PORTS; i++) {
|
||||
p_port = &rfc_cb.port.port[i];
|
||||
if (p_port->in_use && !memcmp (p_port->bd_addr, cert_pts_addr, BD_ADDR_LEN)) {
|
||||
dlci = p_port->dlci;
|
||||
get_dlci = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (get_dlci) {
|
||||
rfc_send_msc(p_mcb, dlci, TRUE, p_pars);
|
||||
} else {
|
||||
RFCOMM_TRACE_ERROR ("Get dlci fail");
|
||||
}
|
||||
osi_free(p_pars);
|
||||
}
|
||||
#endif /* BT_RFCOMM_BQB_INCLUDED */
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_test
|
||||
**
|
||||
** Description This function sends Test frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_test (tRFC_MCB *p_mcb, BOOLEAN is_command, BT_HDR *p_buf)
|
||||
{
|
||||
UINT8 *p_data;
|
||||
UINT16 xx;
|
||||
UINT8 *p_src, *p_dest;
|
||||
|
||||
BT_HDR *p_buf_new;
|
||||
if ((p_buf_new = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
memcpy(p_buf_new, p_buf, sizeof(BT_HDR) + p_buf->offset + p_buf->len);
|
||||
osi_free(p_buf);
|
||||
p_buf = p_buf_new;
|
||||
/* Shift buffer to give space for header */
|
||||
if (p_buf->offset < (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2)) {
|
||||
p_src = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len - 1;
|
||||
p_dest = (UINT8 *) (p_buf + 1) + L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2 + p_buf->len - 1;
|
||||
|
||||
for (xx = 0; xx < p_buf->len; xx++) {
|
||||
*p_dest-- = *p_src--;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
|
||||
}
|
||||
|
||||
/* Adjust offset by number of bytes we are going to fill */
|
||||
p_buf->offset -= 2;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
*p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_TEST;
|
||||
*p_data++ = RFCOMM_EA | (p_buf->len << 1);
|
||||
|
||||
p_buf->len += 2;
|
||||
|
||||
rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_send_credit
|
||||
**
|
||||
** Description This function sends a flow control credit in UIH frame.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_send_credit(tRFC_MCB *p_mcb, UINT8 dlci, UINT8 credit)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT8 *p_data;
|
||||
UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE);
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
*p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
|
||||
*p_data++ = RFCOMM_UIH | RFCOMM_PF;
|
||||
*p_data++ = RFCOMM_EA | 0;
|
||||
*p_data++ = credit;
|
||||
*p_data = RFCOMM_UIH_FCS ((UINT8 *)(p_buf + 1) + p_buf->offset, dlci);
|
||||
|
||||
p_buf->len = 5;
|
||||
|
||||
rfc_check_send_cmd(p_mcb, p_buf);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_parse_data
|
||||
**
|
||||
** Description This function processes data packet received from L2CAP
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT8 rfc_parse_data (tRFC_MCB *p_mcb, MX_FRAME *p_frame, BT_HDR *p_buf)
|
||||
{
|
||||
UINT8 ead, eal, fcs;
|
||||
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
UINT8 *p_start = p_data;
|
||||
UINT16 len;
|
||||
|
||||
if (p_buf->len < RFCOMM_CTRL_FRAME_LEN) {
|
||||
RFCOMM_TRACE_ERROR ("Bad Length1: %d", p_buf->len);
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
}
|
||||
|
||||
RFCOMM_PARSE_CTRL_FIELD (ead, p_frame->cr, p_frame->dlci, p_data);
|
||||
if ( !ead ) {
|
||||
RFCOMM_TRACE_ERROR ("Bad Address(EA must be 1)");
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
}
|
||||
RFCOMM_PARSE_TYPE_FIELD (p_frame->type, p_frame->pf, p_data);
|
||||
RFCOMM_PARSE_LEN_FIELD (eal, len, p_data);
|
||||
|
||||
p_buf->len -= (3 + !ead + !eal + 1); /* Additional 1 for FCS */
|
||||
p_buf->offset += (3 + !ead + !eal);
|
||||
|
||||
/* handle credit if credit based flow control */
|
||||
if ((p_mcb->flow == PORT_FC_CREDIT) && (p_frame->type == RFCOMM_UIH) &&
|
||||
(p_frame->dlci != RFCOMM_MX_DLCI) && (p_frame->pf == 1)) {
|
||||
p_frame->credit = *p_data++;
|
||||
p_buf->len--;
|
||||
p_buf->offset++;
|
||||
} else {
|
||||
p_frame->credit = 0;
|
||||
}
|
||||
|
||||
if (p_buf->len != len) {
|
||||
RFCOMM_TRACE_ERROR ("Bad Length2 %d %d", p_buf->len, len);
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
}
|
||||
|
||||
fcs = *(p_data + len);
|
||||
|
||||
/* All control frames that we are sending are sent with P=1, expect */
|
||||
/* reply with F=1 */
|
||||
/* According to TS 07.10 spec ivalid frames are discarded without */
|
||||
/* notification to the sender */
|
||||
switch (p_frame->type) {
|
||||
case RFCOMM_SABME:
|
||||
if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)
|
||||
|| !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci)
|
||||
|| !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad SABME");
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
} else {
|
||||
return (RFC_EVENT_SABME);
|
||||
}
|
||||
|
||||
case RFCOMM_UA:
|
||||
if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr)
|
||||
|| !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci)
|
||||
|| !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad UA");
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
} else {
|
||||
return (RFC_EVENT_UA);
|
||||
}
|
||||
|
||||
case RFCOMM_DM:
|
||||
if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr)
|
||||
|| len || !RFCOMM_VALID_DLCI(p_frame->dlci)
|
||||
|| !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad DM");
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
} else {
|
||||
return (RFC_EVENT_DM);
|
||||
}
|
||||
|
||||
case RFCOMM_DISC:
|
||||
if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)
|
||||
|| !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci)
|
||||
|| !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad DISC");
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
} else {
|
||||
return (RFC_EVENT_DISC);
|
||||
}
|
||||
|
||||
case RFCOMM_UIH:
|
||||
if (!RFCOMM_VALID_DLCI(p_frame->dlci)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad UIH - invalid DLCI");
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
} else if (!rfc_check_fcs (2, p_start, fcs)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad UIH - FCS");
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
} else if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)) {
|
||||
/* we assume that this is ok to allow bad implementations to work */
|
||||
RFCOMM_TRACE_ERROR ("Bad UIH - response");
|
||||
return (RFC_EVENT_UIH);
|
||||
} else {
|
||||
return (RFC_EVENT_UIH);
|
||||
}
|
||||
}
|
||||
|
||||
return (RFC_EVENT_BAD_FRAME);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_process_mx_message
|
||||
**
|
||||
** Description This function processes UIH frames received on the
|
||||
** multiplexer control channel.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
|
||||
{
|
||||
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
MX_FRAME *p_rx_frame = &rfc_cb.rfc.rx_frame;
|
||||
UINT16 length = p_buf->len;
|
||||
UINT8 ea, cr, mx_len;
|
||||
BOOLEAN is_command;
|
||||
|
||||
p_rx_frame->ea = *p_data & RFCOMM_EA;
|
||||
p_rx_frame->cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
|
||||
p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK);
|
||||
|
||||
if (!p_rx_frame->ea || !length) {
|
||||
RFCOMM_TRACE_ERROR ("Illegal MX Frame ea:%d len:%d", p_rx_frame->ea, length);
|
||||
osi_free (p_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
is_command = p_rx_frame->cr;
|
||||
|
||||
ea = *p_data & RFCOMM_EA;
|
||||
|
||||
mx_len = *p_data++ >> RFCOMM_SHIFT_LENGTH1;
|
||||
length--;
|
||||
|
||||
if (!ea) {
|
||||
mx_len += *p_data++ << RFCOMM_SHIFT_LENGTH2;
|
||||
length --;
|
||||
}
|
||||
|
||||
if (mx_len != length) {
|
||||
RFCOMM_TRACE_ERROR ("Bad MX frame");
|
||||
osi_free (p_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_rx_frame->type) {
|
||||
case RFCOMM_MX_PN:
|
||||
if (length != RFCOMM_MX_PN_LEN) {
|
||||
break;
|
||||
}
|
||||
|
||||
p_rx_frame->dlci = *p_data++ & RFCOMM_PN_DLCI_MASK;
|
||||
p_rx_frame->u.pn.frame_type = *p_data & RFCOMM_PN_FRAME_TYPE_MASK;
|
||||
p_rx_frame->u.pn.conv_layer = *p_data++ & RFCOMM_PN_CONV_LAYER_MASK;
|
||||
p_rx_frame->u.pn.priority = *p_data++ & RFCOMM_PN_PRIORITY_MASK;
|
||||
p_rx_frame->u.pn.t1 = *p_data++;
|
||||
p_rx_frame->u.pn.mtu = *p_data + (*(p_data + 1) << 8);
|
||||
p_data += 2;
|
||||
p_rx_frame->u.pn.n2 = *p_data++;
|
||||
p_rx_frame->u.pn.k = *p_data++ & RFCOMM_PN_K_MASK;
|
||||
|
||||
if (!p_rx_frame->dlci
|
||||
|| !RFCOMM_VALID_DLCI (p_rx_frame->dlci)
|
||||
|| (p_rx_frame->u.pn.mtu < RFCOMM_MIN_MTU)
|
||||
|| (p_rx_frame->u.pn.mtu > RFCOMM_MAX_MTU)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad PN frame");
|
||||
break;
|
||||
}
|
||||
|
||||
osi_free (p_buf);
|
||||
|
||||
rfc_process_pn (p_mcb, is_command, p_rx_frame);
|
||||
return;
|
||||
|
||||
case RFCOMM_MX_TEST:
|
||||
if (!length) {
|
||||
break;
|
||||
}
|
||||
|
||||
p_rx_frame->u.test.p_data = p_data;
|
||||
p_rx_frame->u.test.data_len = length;
|
||||
|
||||
p_buf->offset += 2;
|
||||
p_buf->len -= 2;
|
||||
|
||||
if (is_command) {
|
||||
rfc_send_test (p_mcb, FALSE, p_buf);
|
||||
} else {
|
||||
rfc_process_test_rsp (p_mcb, p_buf);
|
||||
}
|
||||
return;
|
||||
|
||||
case RFCOMM_MX_FCON:
|
||||
if (length != RFCOMM_MX_FCON_LEN) {
|
||||
break;
|
||||
}
|
||||
|
||||
osi_free (p_buf);
|
||||
|
||||
rfc_process_fcon (p_mcb, is_command);
|
||||
return;
|
||||
|
||||
case RFCOMM_MX_FCOFF:
|
||||
if (length != RFCOMM_MX_FCOFF_LEN) {
|
||||
break;
|
||||
}
|
||||
|
||||
osi_free (p_buf);
|
||||
|
||||
rfc_process_fcoff (p_mcb, is_command);
|
||||
return;
|
||||
|
||||
case RFCOMM_MX_MSC:
|
||||
|
||||
ea = *p_data & RFCOMM_EA;
|
||||
cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
|
||||
p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
|
||||
|
||||
if (!ea || !cr || !p_rx_frame->dlci
|
||||
|| !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad MSC frame");
|
||||
break;
|
||||
}
|
||||
|
||||
p_rx_frame->u.msc.signals = *p_data++;
|
||||
|
||||
if (mx_len == RFCOMM_MX_MSC_LEN_WITH_BREAK) {
|
||||
p_rx_frame->u.msc.break_present = *p_data & RFCOMM_MSC_BREAK_PRESENT_MASK;
|
||||
p_rx_frame->u.msc.break_duration = (*p_data & RFCOMM_MSC_BREAK_MASK) >> RFCOMM_MSC_SHIFT_BREAK;
|
||||
} else {
|
||||
p_rx_frame->u.msc.break_present = FALSE;
|
||||
p_rx_frame->u.msc.break_duration = 0;
|
||||
}
|
||||
osi_free (p_buf);
|
||||
|
||||
rfc_process_msc (p_mcb, is_command, p_rx_frame);
|
||||
return;
|
||||
|
||||
case RFCOMM_MX_NSC:
|
||||
if ((length != RFCOMM_MX_NSC_LEN) || !is_command) {
|
||||
break;
|
||||
}
|
||||
|
||||
p_rx_frame->u.nsc.ea = *p_data & RFCOMM_EA;
|
||||
p_rx_frame->u.nsc.cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
|
||||
p_rx_frame->u.nsc.type = *p_data++ >> RFCOMM_SHIFT_DLCI;
|
||||
|
||||
osi_free (p_buf);
|
||||
|
||||
rfc_process_nsc (p_mcb, p_rx_frame);
|
||||
return;
|
||||
|
||||
case RFCOMM_MX_RPN:
|
||||
if ((length != RFCOMM_MX_RPN_REQ_LEN) && (length != RFCOMM_MX_RPN_LEN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ea = *p_data & RFCOMM_EA;
|
||||
cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
|
||||
p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
|
||||
|
||||
if (!ea || !cr || !p_rx_frame->dlci
|
||||
|| !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad RPN frame");
|
||||
break;
|
||||
}
|
||||
|
||||
p_rx_frame->u.rpn.is_request = (length == RFCOMM_MX_RPN_REQ_LEN);
|
||||
|
||||
if (!p_rx_frame->u.rpn.is_request) {
|
||||
p_rx_frame->u.rpn.baud_rate = *p_data++;
|
||||
p_rx_frame->u.rpn.byte_size = (*p_data >> RFCOMM_RPN_BITS_SHIFT) & RFCOMM_RPN_BITS_MASK;
|
||||
p_rx_frame->u.rpn.stop_bits = (*p_data >> RFCOMM_RPN_STOP_BITS_SHIFT) & RFCOMM_RPN_STOP_BITS_MASK;
|
||||
p_rx_frame->u.rpn.parity = (*p_data >> RFCOMM_RPN_PARITY_SHIFT) & RFCOMM_RPN_PARITY_MASK;
|
||||
p_rx_frame->u.rpn.parity_type = (*p_data++ >> RFCOMM_RPN_PARITY_TYPE_SHIFT) & RFCOMM_RPN_PARITY_TYPE_MASK;
|
||||
|
||||
p_rx_frame->u.rpn.fc_type = *p_data++ & RFCOMM_FC_MASK;
|
||||
p_rx_frame->u.rpn.xon_char = *p_data++;
|
||||
p_rx_frame->u.rpn.xoff_char = *p_data++;
|
||||
p_rx_frame->u.rpn.param_mask = (*p_data + (*(p_data + 1) << 8)) & RFCOMM_RPN_PM_MASK;
|
||||
}
|
||||
osi_free (p_buf);
|
||||
|
||||
rfc_process_rpn (p_mcb, is_command, p_rx_frame->u.rpn.is_request, p_rx_frame);
|
||||
return;
|
||||
|
||||
case RFCOMM_MX_RLS:
|
||||
if (length != RFCOMM_MX_RLS_LEN) {
|
||||
break;
|
||||
}
|
||||
|
||||
ea = *p_data & RFCOMM_EA;
|
||||
cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
|
||||
|
||||
p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
|
||||
p_rx_frame->u.rls.line_status = (*p_data & ~0x01);
|
||||
|
||||
if (!ea || !cr || !p_rx_frame->dlci
|
||||
|| !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) {
|
||||
RFCOMM_TRACE_ERROR ("Bad RPN frame");
|
||||
break;
|
||||
}
|
||||
|
||||
osi_free (p_buf);
|
||||
|
||||
rfc_process_rls (p_mcb, is_command, p_rx_frame);
|
||||
return;
|
||||
}
|
||||
|
||||
osi_free (p_buf);
|
||||
|
||||
if (is_command) {
|
||||
rfc_send_nsc (p_mcb);
|
||||
}
|
||||
}
|
||||
|
||||
#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
@@ -0,0 +1,510 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* This file contains collection of utility functions used the RFCOMM unit
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "common/bt_target.h"
|
||||
|
||||
#include "stack/btm_api.h"
|
||||
#include "btm_int.h"
|
||||
#include "stack/rfcdefs.h"
|
||||
#include "stack/port_api.h"
|
||||
#include "stack/port_ext.h"
|
||||
#include "port_int.h"
|
||||
#include "rfc_int.h"
|
||||
#include "stack/btu.h"
|
||||
#include "common/bt_defs.h"
|
||||
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/mutex.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_calc_fcs
|
||||
**
|
||||
** Description Reversed CRC Table , 8-bit, poly=0x07
|
||||
** (GSM 07.10 TS 101 369 V6.3.0)
|
||||
*******************************************************************************/
|
||||
static const UINT8 rfc_crctable[] = {
|
||||
0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
|
||||
0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
|
||||
0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
|
||||
0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
|
||||
|
||||
0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
|
||||
0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
|
||||
0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
|
||||
0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
|
||||
|
||||
0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
|
||||
0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
|
||||
0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
|
||||
0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
|
||||
|
||||
0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
|
||||
0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
|
||||
0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
|
||||
0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_calc_fcs
|
||||
**
|
||||
** Description This function calculate FCS for the RFCOMM frame
|
||||
** (GSM 07.10 TS 101 369 V6.3.0)
|
||||
**
|
||||
** Input len - number of bytes in the message
|
||||
** p - points to message
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT8 rfc_calc_fcs (UINT16 len, UINT8 *p)
|
||||
{
|
||||
UINT8 fcs = 0xFF;
|
||||
|
||||
while (len--) {
|
||||
fcs = rfc_crctable[fcs ^ *p++];
|
||||
}
|
||||
|
||||
/* Ones compliment */
|
||||
return (0xFF - fcs);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_check_fcs
|
||||
**
|
||||
** Description This function checks FCS for the RFCOMM frame
|
||||
** (GSM 07.10 TS 101 369 V6.3.0)
|
||||
**
|
||||
** Input len - number of bytes in the message
|
||||
** p - points to message
|
||||
** received_fcs - received FCS
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN rfc_check_fcs (UINT16 len, UINT8 *p, UINT8 received_fcs)
|
||||
{
|
||||
UINT8 fcs = 0xFF;
|
||||
|
||||
while (len--) {
|
||||
fcs = rfc_crctable[fcs ^ *p++];
|
||||
}
|
||||
|
||||
/* Ones compliment */
|
||||
fcs = rfc_crctable[fcs ^ received_fcs];
|
||||
|
||||
/*0xCF is the reversed order of 11110011.*/
|
||||
return (fcs == 0xCF);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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);
|
||||
rfc_timer_free(p_mcb);
|
||||
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(QUEUE_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);
|
||||
}
|
||||
|
||||
void osi_free_fun(void *p)
|
||||
{
|
||||
osi_free(p);
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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_free (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 rfc_timer_start
|
||||
**
|
||||
** Description Start RFC Timer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_timer_start (tRFC_MCB *p_mcb, UINT16 timeout)
|
||||
{
|
||||
TIMER_LIST_ENT *p_tle = &p_mcb->tle;
|
||||
|
||||
RFCOMM_TRACE_EVENT ("rfc_timer_start - timeout:%d", timeout);
|
||||
|
||||
p_tle->param = (UINT32)p_mcb;
|
||||
|
||||
btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_MFC, timeout);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_timer_stop
|
||||
**
|
||||
** Description Stop RFC Timer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_timer_stop (tRFC_MCB *p_mcb)
|
||||
{
|
||||
RFCOMM_TRACE_EVENT ("rfc_timer_stop");
|
||||
|
||||
btu_stop_timer (&p_mcb->tle);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_timer_free
|
||||
**
|
||||
** Description Stop and free RFC Timer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_timer_free (tRFC_MCB *p_mcb)
|
||||
{
|
||||
RFCOMM_TRACE_EVENT ("rfc_timer_free");
|
||||
|
||||
btu_free_timer (&p_mcb->tle);
|
||||
memset(&p_mcb->tle, 0, sizeof(TIMER_LIST_ENT));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_port_timer_start
|
||||
**
|
||||
** Description Start RFC Timer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_port_timer_start (tPORT *p_port, UINT16 timeout)
|
||||
{
|
||||
TIMER_LIST_ENT *p_tle = &p_port->rfc.tle;
|
||||
|
||||
RFCOMM_TRACE_EVENT ("rfc_port_timer_start - timeout:%d", timeout);
|
||||
|
||||
p_tle->param = (UINT32)p_port;
|
||||
|
||||
btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_PORT, timeout);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_port_timer_stop
|
||||
**
|
||||
** Description Stop RFC Timer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_port_timer_stop (tPORT *p_port)
|
||||
{
|
||||
RFCOMM_TRACE_EVENT ("rfc_port_timer_stop");
|
||||
|
||||
btu_stop_timer (&p_port->rfc.tle);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_port_timer_free
|
||||
**
|
||||
** Description Stop and free RFC Timer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_port_timer_free (tPORT *p_port)
|
||||
{
|
||||
RFCOMM_TRACE_EVENT ("rfc_port_timer_stop");
|
||||
|
||||
btu_free_timer (&p_port->rfc.tle);
|
||||
memset(&p_port->rfc.tle, 0, sizeof(TIMER_LIST_ENT));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_check_mcb_active
|
||||
**
|
||||
** Description Check if there are any opened ports on the MCB if not
|
||||
** start MCB Inact timer.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_check_mcb_active (tRFC_MCB *p_mcb)
|
||||
{
|
||||
UINT16 i;
|
||||
|
||||
for (i = 0; i < RFCOMM_MAX_DLCI; i++) {
|
||||
if (p_mcb->port_inx[i] != 0) {
|
||||
p_mcb->is_disc_initiator = FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* The last port was DISCed. On the client side start disconnecting Mx */
|
||||
/* On the server side start inactivity timer */
|
||||
if (p_mcb->is_disc_initiator) {
|
||||
p_mcb->is_disc_initiator = FALSE;
|
||||
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CLOSE_REQ, NULL);
|
||||
} else {
|
||||
rfc_timer_start (p_mcb, RFC_MCB_RELEASE_INACT_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfcomm_process_timeout
|
||||
**
|
||||
** Description The function called every second to check RFCOMM timers
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfcomm_process_timeout (TIMER_LIST_ENT *p_tle)
|
||||
{
|
||||
switch (p_tle->event) {
|
||||
case BTU_TTYPE_RFCOMM_MFC:
|
||||
rfc_mx_sm_execute ((tRFC_MCB *)p_tle->param, RFC_EVENT_TIMEOUT, NULL);
|
||||
break;
|
||||
|
||||
case BTU_TTYPE_RFCOMM_PORT:
|
||||
rfc_port_sm_execute ((tPORT *)p_tle->param, RFC_EVENT_TIMEOUT, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_sec_check_complete
|
||||
**
|
||||
** Description The function called when Security Manager finishes
|
||||
** verification of the service side connection
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
|
||||
{
|
||||
tPORT *p_port = (tPORT *)p_ref_data;
|
||||
UNUSED(bd_addr);
|
||||
UNUSED(transport);
|
||||
|
||||
/* Verify that PORT is still waiting for Security to complete */
|
||||
if (!p_port->in_use
|
||||
|| ((p_port->rfc.state != RFC_STATE_ORIG_WAIT_SEC_CHECK)
|
||||
&& (p_port->rfc.state != RFC_STATE_TERM_WAIT_SEC_CHECK))) {
|
||||
return;
|
||||
}
|
||||
|
||||
rfc_port_sm_execute ((tPORT *)p_ref_data, RFC_EVENT_SEC_COMPLETE, &res);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** 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_inc_credit
|
||||
**
|
||||
** Description The function is called when a credit is received in a UIH
|
||||
** frame. It increments the TX credit count, and if data
|
||||
** flow had halted, it restarts it.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_inc_credit (tPORT *p_port, UINT8 credit)
|
||||
{
|
||||
if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
|
||||
p_port->credit_tx += credit;
|
||||
|
||||
RFCOMM_TRACE_EVENT ("rfc_inc_credit:%d", p_port->credit_tx);
|
||||
|
||||
if (p_port->tx.peer_fc == TRUE) {
|
||||
PORT_FlowInd(p_port->rfc.p_mcb, p_port->dlci, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_dec_credit
|
||||
**
|
||||
** Description The function is called when a UIH frame of user data is
|
||||
** sent. It decrements the credit count. If credit count
|
||||
** Reaches zero, peer_fc is set.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_dec_credit (tPORT *p_port)
|
||||
{
|
||||
if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
|
||||
if (p_port->credit_tx > 0) {
|
||||
p_port->credit_tx--;
|
||||
}
|
||||
|
||||
if (p_port->credit_tx == 0) {
|
||||
p_port->tx.peer_fc = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function rfc_check_send_cmd
|
||||
**
|
||||
** Description This function is called to send an RFCOMM command message
|
||||
** or to handle the RFCOMM command message queue.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf)
|
||||
{
|
||||
BT_HDR *p;
|
||||
|
||||
/* if passed a buffer queue it */
|
||||
if (p_buf != NULL) {
|
||||
if (p_mcb->cmd_q == NULL) {
|
||||
RFCOMM_TRACE_ERROR("%s: empty queue: p_mcb = %p p_mcb->lcid = %u cached p_mcb = %p",
|
||||
__func__, p_mcb, p_mcb->lcid,
|
||||
rfc_find_lcid_mcb(p_mcb->lcid));
|
||||
}
|
||||
fixed_queue_enqueue(p_mcb->cmd_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
|
||||
}
|
||||
|
||||
/* handle queue if L2CAP not congested */
|
||||
while (p_mcb->l2cap_congested == FALSE) {
|
||||
if ((p = (BT_HDR *)fixed_queue_dequeue(p_mcb->cmd_q, 0)) == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
L2CA_DataWrite (p_mcb->lcid, p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
|
||||
Reference in New Issue
Block a user