summaryrefslogtreecommitdiffstats
path: root/stack/rfcomm
diff options
context:
space:
mode:
Diffstat (limited to 'stack/rfcomm')
-rw-r--r--stack/rfcomm/port_api.c1730
-rw-r--r--stack/rfcomm/port_int.h252
-rw-r--r--stack/rfcomm/port_rfc.c1112
-rw-r--r--stack/rfcomm/port_utils.c582
-rw-r--r--stack/rfcomm/rfc_int.h387
-rw-r--r--stack/rfcomm/rfc_l2cap_if.c443
-rw-r--r--stack/rfcomm/rfc_mx_fsm.c663
-rw-r--r--stack/rfcomm/rfc_port_fsm.c915
-rw-r--r--stack/rfcomm/rfc_port_if.c339
-rw-r--r--stack/rfcomm/rfc_ts_frames.c908
-rw-r--r--stack/rfcomm/rfc_utils.c467
11 files changed, 7798 insertions, 0 deletions
diff --git a/stack/rfcomm/port_api.c b/stack/rfcomm/port_api.c
new file mode 100644
index 0000000..617d31b
--- /dev/null
+++ b/stack/rfcomm/port_api.c
@@ -0,0 +1,1730 @@
+/******************************************************************************
+ *
+ * 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 the Serial Port API code
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "btm_int.h"
+#include "btm_api.h"
+#include "rfc_int.h"
+#include "l2c_api.h"
+#include "sdp_api.h"
+
+/* duration of break in 200ms units */
+#define PORT_BREAK_DURATION 1
+
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+/*******************************************************************************
+**
+** Function RFCOMM_CreateConnection
+**
+** Description RFCOMM_CreateConnection function is used from the application
+** to establish serial port connection to the peer device,
+** or allow RFCOMM to accept a connection from the peer
+** application.
+**
+** Parameters: scn - Service Channel Number as registered with
+** the SDP (server) or obtained using SDP from
+** the peer device (client).
+** is_server - TRUE if requesting application is a server
+** mtu - Maximum frame size the application can accept
+** bd_addr - BD_ADDR of the peer (client)
+** mask - specifies events to be enabled. A value
+** of zero disables all events.
+** p_handle - OUT pointer to the handle.
+** p_mgmt_cb - pointer to callback function to receive
+** connection up/down events.
+** Notes:
+**
+** Server can call this function with the same scn parameter multiple times if
+** it is ready to accept multiple simulteneous connections.
+**
+** DLCI for the connection is (scn * 2 + 1) if client originates connection on
+** existing none initiator multiplexer channel. Otherwise it is (scn * 2).
+** For the server DLCI can be changed later if client will be calling it using
+** (scn * 2 + 1) dlci.
+**
+*******************************************************************************/
+int RFCOMM_CreateConnection (UINT16 uuid, UINT8 scn, BOOLEAN is_server,
+ UINT16 mtu, BD_ADDR bd_addr, UINT16 *p_handle,
+ tPORT_CALLBACK *p_mgmt_cb)
+{
+ tPORT *p_port;
+ int i;
+ UINT8 dlci;
+ tRFC_MCB *p_mcb = port_find_mcb (bd_addr);
+ UINT16 rfcomm_mtu;
+
+ RFCOMM_TRACE_API3 ("RFCOMM_CreateConnection() called SCN: %d is_server:%d mtu:%d",
+ scn, is_server, mtu);
+ RFCOMM_TRACE_API6 ("RFCOMM_CreateConnection() BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ *p_handle = 0;
+
+ if (( scn == 0 )||(scn >= PORT_MAX_RFC_PORTS ))
+ {
+ /* Server Channel Number(SCN) should be in range 1...30 */
+ RFCOMM_TRACE_ERROR0 ("RFCOMM_CreateConnection - invalid SCN");
+ return (PORT_INVALID_SCN);
+ }
+
+ /* For client that originate connection on the existing none initiator */
+ /* multiplexer channel DLCI should be odd */
+ if (p_mcb && !p_mcb->is_initiator && !is_server)
+ dlci = (scn << 1) + 1;
+ else
+ dlci = (scn << 1);
+
+ /* For the server side always allocate a new port. On the client side */
+ /* do not allow the same (dlci, bd_addr) to be opened twice by application */
+ if (!is_server && ((p_port = port_find_port (dlci, bd_addr)) != NULL))
+ {
+ /* if existing port is also a client port */
+ if (p_port->is_server == FALSE)
+ {
+ RFCOMM_TRACE_ERROR3 ("RFCOMM_CreateConnection - already opened state:%d, RFC state:%d, MCB state:%d",
+ p_port->state, p_port->rfc.state, p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0);
+ return (PORT_ALREADY_OPENED);
+ }
+ }
+
+ if ((p_port = port_allocate_port (dlci, bd_addr)) == NULL)
+ {
+ RFCOMM_TRACE_WARNING0 ("RFCOMM_CreateConnection - no resources");
+ return (PORT_NO_RESOURCES);
+ }
+
+ p_port->default_signal_state = (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ switch (uuid)
+ {
+ case UUID_PROTOCOL_OBEX:
+ p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_SERIAL_PORT:
+ p_port->default_signal_state = PORT_SPP_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_LAN_ACCESS_USING_PPP:
+ p_port->default_signal_state = PORT_PPP_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_DIALUP_NETWORKING:
+ case UUID_SERVCLASS_FAX:
+ p_port->default_signal_state = PORT_DUN_DEFAULT_SIGNAL_STATE;
+ break;
+ }
+
+ RFCOMM_TRACE_EVENT2 ("RFCOMM_CreateConnection dlci:%d signal state:0x%x", dlci, p_port->default_signal_state);
+
+ *p_handle = p_port->inx;
+
+ p_port->state = PORT_STATE_OPENING;
+ p_port->uuid = uuid;
+ p_port->is_server = is_server;
+ p_port->scn = scn;
+ p_port->ev_mask = 0;
+
+ /* If the MTU is not specified (0), keep MTU decision until the
+ * PN frame has to be send
+ * at that time connection should be established and we
+ * will know for sure our prefered MTU
+ */
+
+ rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+
+ if (mtu)
+ p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
+ else
+ p_port->mtu = rfcomm_mtu;
+
+ /* server doesn't need to release port when closing */
+ if( is_server )
+ {
+ p_port->keep_port_handle = TRUE;
+
+ /* keep mtu that user asked, p_port->mtu could be updated during param negotiation */
+ p_port->keep_mtu = p_port->mtu;
+ }
+
+ p_port->local_ctrl.modem_signal = p_port->default_signal_state;
+ p_port->local_ctrl.fc = FALSE;
+
+ p_port->p_mgmt_callback = p_mgmt_cb;
+
+ for (i = 0; i < BD_ADDR_LEN; i++)
+ p_port->bd_addr[i] = bd_addr[i];
+
+ /* If this is not initiator of the connection need to just wait */
+ if (p_port->is_server)
+ {
+ return (PORT_SUCCESS);
+ }
+
+ /* Open will be continued after security checks are passed */
+ return port_open_continue (p_port);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_RemoveConnection
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int RFCOMM_RemoveConnection (UINT16 handle)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("RFCOMM_RemoveConnection() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_RemoveConnection() BAD handle:%d", handle);
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_EVENT1 ("RFCOMM_RemoveConnection() Not opened:%d", handle);
+ return (PORT_SUCCESS);
+ }
+
+ p_port->state = PORT_STATE_CLOSING;
+
+ port_start_close (p_port);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function RFCOMM_RemoveServer
+**
+** Description This function is called to close the server port.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int RFCOMM_RemoveServer (UINT16 handle)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("RFCOMM_RemoveServer() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_RemoveServer() BAD handle:%d", handle);
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ /* Do not report any events to the client any more. */
+ p_port->p_mgmt_callback = NULL;
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_EVENT1 ("RFCOMM_RemoveServer() Not opened:%d", handle);
+ return (PORT_SUCCESS);
+ }
+
+ /* this port will be deallocated after closing */
+ p_port->keep_port_handle = FALSE;
+ p_port->state = PORT_STATE_CLOSING;
+
+ port_start_close (p_port);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetEventCallback
+**
+** Description This function is called to provide an address of the
+** function which will be called when one of the events
+** specified in the mask occures.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when an event
+** specified in the mask occures.
+**
+**
+*******************************************************************************/
+int PORT_SetEventCallback (UINT16 port_handle, tPORT_CALLBACK *p_port_cb)
+{
+ tPORT *p_port;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ RFCOMM_TRACE_API1 ("PORT_SetEventCallback() handle:%d", port_handle);
+
+ p_port->p_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_SetDataCallback
+**
+** Description This function is when a data packet is received
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when data packet
+** is received.
+**
+**
+*******************************************************************************/
+int PORT_SetDataCallback (UINT16 port_handle, tPORT_DATA_CALLBACK *p_port_cb)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SetDataCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->p_data_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function PORT_SetCODataCallback
+**
+** Description This function is when a data packet is received
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when data packet
+** is received.
+**
+**
+*******************************************************************************/
+int PORT_SetDataCOCallback (UINT16 port_handle, tPORT_DATA_CO_CALLBACK *p_port_cb)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SetDataCOCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->p_data_co_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function PORT_SetEventMask
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** mask - Bitmask of the events the host is interested in
+**
+*******************************************************************************/
+int PORT_SetEventMask (UINT16 port_handle, UINT32 mask)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SetEventMask() handle:%d mask:0x%x", port_handle, mask);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->ev_mask = mask;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_CheckConnection
+**
+** Description This function returns PORT_SUCCESS if connection referenced
+** by handle is up and running
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** bd_addr - OUT bd_addr of the peer
+** p_lcid - OUT L2CAP's LCID
+**
+*******************************************************************************/
+int PORT_CheckConnection (UINT16 handle, BD_ADDR bd_addr, UINT16 *p_lcid)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_CheckConnection() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb
+ || !p_port->rfc.p_mcb->peer_ready
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ memcpy (bd_addr, p_port->rfc.p_mcb->bd_addr, BD_ADDR_LEN);
+ if (p_lcid)
+ *p_lcid = p_port->rfc.p_mcb->lcid;
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_IsOpening
+**
+** Description This function returns TRUE if there is any RFCOMM connection
+** opening in process.
+**
+** Parameters: TRUE if any connection opening is found
+** bd_addr - bd_addr of the peer
+**
+*******************************************************************************/
+BOOLEAN PORT_IsOpening (BD_ADDR bd_addr)
+{
+ UINT8 xx, yy;
+ tRFC_MCB *p_mcb = NULL;
+ tPORT *p_port;
+ BOOLEAN found_port;
+
+ /* Check for any rfc_mcb which is in the middle of opening. */
+ for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++)
+ {
+ if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) &&
+ (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED))
+ {
+ memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+ return TRUE;
+ }
+
+ if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED)
+ {
+ found_port = FALSE;
+ p_mcb = &rfc_cb.port.rfc_mcb[xx];
+ p_port = &rfc_cb.port.port[0];
+
+ for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ found_port = TRUE;
+ break;
+ }
+ }
+
+ if ((!found_port) ||
+ (found_port && (p_port->rfc.state < RFC_STATE_OPENED)))
+ {
+ /* Port is not established yet. */
+ memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetState
+**
+** Description This function configures connection according to the
+** specifications in the tPORT_STATE structure.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_settings - Pointer to a tPORT_STATE structure containing
+** configuration information for the connection.
+**
+**
+*******************************************************************************/
+int PORT_SetState (UINT16 handle, tPORT_STATE *p_settings)
+{
+ tPORT *p_port;
+ UINT8 baud_rate;
+
+ RFCOMM_TRACE_API1 ("PORT_SetState() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ RFCOMM_TRACE_API2 ("PORT_SetState() handle:%d FC_TYPE:0x%x", handle,
+ p_settings->fc_type);
+
+ baud_rate = p_port->user_port_pars.baud_rate;
+ p_port->user_port_pars = *p_settings;
+
+ /* for now we've been asked to pass only baud rate */
+ if (baud_rate != p_settings->baud_rate)
+ {
+ port_start_par_neg (p_port);
+ }
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_GetRxQueueCnt
+**
+** Description This function return number of buffers on the rx queue.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_rx_queue_count - Pointer to return queue count in.
+**
+*******************************************************************************/
+int PORT_GetRxQueueCnt (UINT16 handle, UINT16 *p_rx_queue_count)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_GetRxQueueCnt() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ *p_rx_queue_count = p_port->rx.queue_size;
+
+ RFCOMM_TRACE_API2 ("PORT_GetRxQueueCnt() p_rx_queue_count:%d, p_port->rx.queue.count = %d",
+ *p_rx_queue_count, p_port->rx.queue_size);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_GetState
+**
+** Description This function is called to fill tPORT_STATE structure
+** with the curremt control settings for the port
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_settings - Pointer to a tPORT_STATE structure in which
+** configuration information is returned.
+**
+*******************************************************************************/
+int PORT_GetState (UINT16 handle, tPORT_STATE *p_settings)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_GetState() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ *p_settings = p_port->user_port_pars;
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Control
+**
+** Description This function directs a specified connection to pass control
+** control information to the peer device.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** signal = specify the function to be passed
+**
+*******************************************************************************/
+int PORT_Control (UINT16 handle, UINT8 signal)
+{
+ tPORT *p_port;
+ UINT8 old_modem_signal;
+
+ RFCOMM_TRACE_API2 ("PORT_Control() handle:%d signal:0x%x", handle, signal);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ old_modem_signal = p_port->local_ctrl.modem_signal;
+ p_port->local_ctrl.break_signal = 0;
+
+ switch (signal)
+ {
+ case PORT_SET_CTSRTS:
+ p_port->local_ctrl.modem_signal |= PORT_CTSRTS_ON;
+ break;
+
+ case PORT_CLR_CTSRTS:
+ p_port->local_ctrl.modem_signal &= ~PORT_CTSRTS_ON;
+ break;
+
+ case PORT_SET_DTRDSR:
+ p_port->local_ctrl.modem_signal |= PORT_DTRDSR_ON;
+ break;
+
+ case PORT_CLR_DTRDSR:
+ p_port->local_ctrl.modem_signal &= ~PORT_DTRDSR_ON;
+ break;
+
+ case PORT_SET_RI:
+ p_port->local_ctrl.modem_signal |= PORT_RING_ON;
+ break;
+
+ case PORT_CLR_RI:
+ p_port->local_ctrl.modem_signal &= ~PORT_RING_ON;
+ break;
+
+ case PORT_SET_DCD:
+ p_port->local_ctrl.modem_signal |= PORT_DCD_ON;
+ break;
+
+ case PORT_CLR_DCD:
+ p_port->local_ctrl.modem_signal &= ~PORT_DCD_ON;
+ break;
+ }
+
+ if (signal == PORT_BREAK)
+ p_port->local_ctrl.break_signal = PORT_BREAK_DURATION;
+ else if (p_port->local_ctrl.modem_signal == old_modem_signal)
+ return (PORT_SUCCESS);
+
+ port_start_control (p_port);
+
+ RFCOMM_TRACE_EVENT4 ("PORT_Control DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_FlowControl
+**
+** Description This function directs a specified connection to pass
+** flow control message to the peer device. Enable flag passed
+** shows if port can accept more data.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** enable - enables data flow
+**
+*******************************************************************************/
+int PORT_FlowControl (UINT16 handle, BOOLEAN enable)
+{
+ tPORT *p_port;
+ BOOLEAN old_fc;
+ UINT32 events;
+
+ RFCOMM_TRACE_API2 ("PORT_FlowControl() handle:%d enable: %d", handle, enable);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb)
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->rx.user_fc = !enable;
+
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+ {
+ if (!p_port->rx.user_fc)
+ {
+ port_flow_control_peer(p_port, TRUE, 0);
+ }
+ }
+ else
+ {
+ old_fc = p_port->local_ctrl.fc;
+
+ /* FC is set if user is set or peer is set */
+ p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
+
+ if (p_port->local_ctrl.fc != old_fc)
+ port_start_control (p_port);
+ }
+
+ /* Need to take care of the case when we could not deliver events */
+ /* to the application because we were flow controlled */
+ if (enable && (p_port->rx.queue_size != 0))
+ {
+ events = PORT_EV_RXCHAR;
+ if (p_port->rx_flag_ev_pending)
+ {
+ p_port->rx_flag_ev_pending = FALSE;
+ events |= PORT_EV_RXFLAG;
+ }
+
+ events &= p_port->ev_mask;
+ if (p_port->p_callback && events)
+ {
+ p_port->p_callback (events, p_port->inx);
+ }
+ }
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_GetModemStatus
+**
+** Description This function retrieves modem control signals. Normally
+** application will call this function after a callback
+** function is called with notification that one of signals
+** has been changed.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_signal - specify the pointer to control signals info
+**
+*******************************************************************************/
+int PORT_GetModemStatus (UINT16 handle, UINT8 *p_signal)
+{
+ tPORT *p_port;
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ *p_signal = p_port->peer_ctrl.modem_signal;
+
+ RFCOMM_TRACE_API2 ("PORT_GetModemStatus() handle:%d signal:%x", handle, *p_signal);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ClearError
+**
+** Description This function retreives information about a communications
+** error and reports current status of a connection. The
+** function should be called when an error occures to clear
+** the connection error flag and to enable additional read
+** and write operations.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_errors - pointer of the variable to receive error codes
+** p_status - pointer to the tPORT_STATUS structur to receive
+** connection status
+**
+*******************************************************************************/
+int PORT_ClearError (UINT16 handle, UINT16 *p_errors, tPORT_STATUS *p_status)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_ClearError() handle:%d", handle);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ *p_errors = p_port->line_status;
+
+ /* This is the only call to clear error status. We can not clear */
+ /* connection failed status. To clean it port should be closed and reopened */
+ p_port->line_status = (p_port->line_status & LINE_STATUS_FAILED);
+
+ PORT_GetQueueStatus (handle, p_status);
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_SendError
+**
+** Description This function send a communications error to the peer device
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** errors - receive error codes
+**
+*******************************************************************************/
+int PORT_SendError (UINT16 handle, UINT8 errors)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SendError() handle:%d errors:0x%x", handle, errors);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb)
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ RFCOMM_LineStatusReq (p_port->rfc.p_mcb, p_port->dlci, errors);
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_GetQueueStatus
+**
+** Description This function reports current status of a connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_status - pointer to the tPORT_STATUS structur to receive
+** connection status
+**
+*******************************************************************************/
+int PORT_GetQueueStatus (UINT16 handle, tPORT_STATUS *p_status)
+{
+ tPORT *p_port;
+
+ /* RFCOMM_TRACE_API1 ("PORT_GetQueueStatus() handle:%d", handle); */
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_status->in_queue_size = (UINT16) p_port->rx.queue_size;
+ p_status->out_queue_size = (UINT16) p_port->tx.queue_size;
+
+ p_status->mtu_size = (UINT16) p_port->peer_mtu;
+
+ p_status->flags = 0;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_CTSRTS_ON))
+ p_status->flags |= PORT_FLAG_CTS_HOLD;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_DTRDSR_ON))
+ p_status->flags |= PORT_FLAG_DSR_HOLD;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_DCD_ON))
+ p_status->flags |= PORT_FLAG_RLSD_HOLD;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Purge
+**
+** Description This function discards all the data from the output or
+** input queues of the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** purge_flags - specify the action to take.
+**
+*******************************************************************************/
+int PORT_Purge (UINT16 handle, UINT8 purge_flags)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT16 count;
+ UINT32 events;
+
+ RFCOMM_TRACE_API2 ("PORT_Purge() handle:%d flags:0x%x", handle, purge_flags);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (purge_flags & PORT_PURGE_RXCLEAR)
+ {
+ PORT_SCHEDULE_LOCK; /* to prevent missing credit */
+
+ count = p_port->rx.queue.count;
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->rx.queue_size = 0;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ /* If we flowed controlled peer based on rx_queue size enable data again */
+ if (count)
+ port_flow_control_peer (p_port, TRUE, count);
+ }
+
+ if (purge_flags & PORT_PURGE_TXCLEAR)
+ {
+ PORT_SCHEDULE_LOCK; /* to prevent tx.queue_size from being negative */
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->tx.queue_size = 0;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ events = PORT_EV_TXEMPTY;
+
+ events |= port_flow_control_user (p_port);
+
+ events &= p_port->ev_mask;
+
+ if ((p_port->p_callback != NULL) && events)
+ (p_port->p_callback)(events, p_port->inx);
+ }
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ReadData
+**
+** Description Normally not GKI aware application will call this function
+** after receiving PORT_EV_RXCHAR event.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+*******************************************************************************/
+int PORT_ReadData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT16 count;
+
+ RFCOMM_TRACE_API2 ("PORT_ReadData() handle:%d max_len:%d", handle, max_len);
+
+ /* Initialize this in case of an error */
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ p_buf = (BT_HDR *)GKI_getfirst (&p_port->rx.queue);
+ if (!p_buf)
+ return (PORT_SUCCESS);
+
+ count = 0;
+
+ while (max_len && p_buf)
+ {
+ if (p_buf->len > max_len)
+ {
+ memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, max_len);
+ p_buf->offset += max_len;
+ p_buf->len -= max_len;
+
+ *p_len += max_len;
+
+ PORT_SCHEDULE_LOCK;
+
+ p_port->rx.queue_size -= max_len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ break;
+ }
+ else
+ {
+ memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ *p_len += p_buf->len;
+ max_len -= p_buf->len;
+
+ PORT_SCHEDULE_LOCK;
+
+ p_port->rx.queue_size -= p_buf->len;
+
+ if (max_len)
+ {
+ p_data += p_buf->len;
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ }
+
+ GKI_freebuf (GKI_dequeue (&p_port->rx.queue));
+
+ PORT_SCHEDULE_UNLOCK;
+
+ count++;
+ }
+ }
+
+ if (*p_len == 1)
+ {
+ RFCOMM_TRACE_EVENT3 ("PORT_ReadData queue:%d returned:%d %x", p_port->rx.queue_size, *p_len, (p_data[0]));
+ }
+ else
+ {
+ RFCOMM_TRACE_EVENT2 ("PORT_ReadData queue:%d returned:%d", p_port->rx.queue_size, *p_len);
+ }
+
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ port_flow_control_peer (p_port, TRUE, count);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Read
+**
+** Description Normally application will call this function after receiving
+** PORT_EV_RXCHAR event.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** pp_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+int PORT_Read (UINT16 handle, BT_HDR **pp_buf)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+
+ RFCOMM_TRACE_API1 ("PORT_Read() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ PORT_SCHEDULE_LOCK;
+
+ p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue);
+ if (p_buf)
+ {
+ p_port->rx.queue_size -= p_buf->len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ port_flow_control_peer (p_port, TRUE, 1);
+ }
+ else
+ {
+ PORT_SCHEDULE_UNLOCK;
+ }
+
+ *pp_buf = p_buf;
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function port_write
+**
+** Description This function when a data packet is received from the apper
+** layer task.
+**
+** Parameters: p_port - pointer to address of port control block
+** p_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+static int port_write (tPORT *p_port, BT_HDR *p_buf)
+{
+ /* We should not allow to write data in to server port when connection is not opened */
+ if (p_port->is_server && (p_port->rfc.state != RFC_STATE_OPENED))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_CLOSED);
+ }
+
+ /* Keep the data in pending queue if peer does not allow data, or */
+ /* Peer is not ready or Port is not yet opened or initial port control */
+ /* command has not been sent */
+ if (p_port->tx.peer_fc
+ || !p_port->rfc.p_mcb
+ || !p_port->rfc.p_mcb->peer_ready
+ || (p_port->rfc.state != RFC_STATE_OPENED)
+ || ((p_port->port_ctrl & (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)) !=
+ (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)))
+ {
+ if ((p_port->tx.queue_size > PORT_TX_CRITICAL_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_CRITICAL_WM))
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_Write: Queue size: %d",
+ p_port->tx.queue_size);
+
+ GKI_freebuf (p_buf);
+
+ if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR))
+ p_port->p_callback (PORT_EV_ERR, p_port->inx);
+
+ return (PORT_TX_FULL);
+ }
+
+ RFCOMM_TRACE_EVENT4 ("PORT_Write : Data is enqued. flow disabled %d peer_ready %d state %d ctrl_state %x",
+ p_port->tx.peer_fc,
+ (p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready),
+ p_port->rfc.state,
+ p_port->port_ctrl);
+
+ GKI_enqueue (&p_port->tx.queue, p_buf);
+ p_port->tx.queue_size += p_buf->len;
+
+ return (PORT_CMD_PENDING);
+ }
+ else
+ {
+ RFCOMM_TRACE_EVENT0 ("PORT_Write : Data is being sent");
+
+ RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+ return (PORT_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+**
+** Function PORT_Write
+**
+** Description This function when a data packet is received from the apper
+** layer task.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** pp_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+int PORT_Write (UINT16 handle, BT_HDR *p_buf)
+{
+ tPORT *p_port;
+ UINT32 event = 0;
+ int rc;
+
+ RFCOMM_TRACE_API1 ("PORT_Write() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_Write: Data dropped line_status:0x%x",
+ p_port->line_status);
+ GKI_freebuf (p_buf);
+ return (PORT_LINE_ERR);
+ }
+
+ rc = port_write (p_port, p_buf);
+ event |= port_flow_control_user (p_port);
+
+ switch (rc)
+ {
+ case PORT_TX_FULL:
+ event |= PORT_EV_ERR;
+ break;
+
+ case PORT_SUCCESS:
+ event |= (PORT_EV_TXCHAR | PORT_EV_TXEMPTY);
+ break;
+ }
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event)
+ (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function PORT_WriteDataCO
+**
+** Description Normally not GKI aware application will call this function
+** to send data to the port by callout functions
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** fd - socket fd
+** p_len - Byte count returned
+**
+*******************************************************************************/
+int PORT_WriteDataCO (UINT16 handle, int* p_len)
+{
+
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT32 event = 0;
+ int rc = 0;
+ UINT16 length;
+
+ RFCOMM_TRACE_API1 ("PORT_WriteDataCO() handle:%d", handle);
+ int written;
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_WriteDataByFd() no port state:%d", p_port->state);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->peer_mtu)
+ {
+ RFCOMM_TRACE_ERROR1 ("PORT_WriteDataByFd() peer_mtu:%d", p_port->peer_mtu);
+ return (PORT_UNKNOWN_ERROR);
+ }
+ int available = 0;
+ //if(ioctl(fd, FIONREAD, &available) < 0)
+ if(p_port->p_data_co_callback(handle, (UINT8*)&available, sizeof(available),
+ DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE) == FALSE)
+ {
+ RFCOMM_TRACE_ERROR1("p_data_co_callback DATA_CO_CALLBACK_TYPE_INCOMING_SIZE failed, available:%d", available);
+ return (PORT_UNKNOWN_ERROR);
+ }
+ /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */
+ length = RFCOMM_DATA_POOL_BUF_SIZE -
+ (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+ /* If there are buffers scheduled for transmission check if requested */
+ /* data fits into the end of the queue */
+ PORT_SCHEDULE_LOCK;
+
+ if (((p_buf = (BT_HDR *)p_port->tx.queue.p_last) != NULL)
+ && (((int)p_buf->len + available) <= (int)p_port->peer_mtu)
+ && (((int)p_buf->len + available) <= (int)length))
+ {
+ //if(recv(fd, (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, available, 0) != available)
+ if(p_port->p_data_co_callback(handle, (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len,
+ available, DATA_CO_CALLBACK_TYPE_OUTGOING) == FALSE)
+
+ {
+ error("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, available:%d", available);
+ return (PORT_UNKNOWN_ERROR);
+ }
+ //memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+ p_port->tx.queue_size += (UINT16)available;
+
+ *p_len = available;
+ p_buf->len += (UINT16)available;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ return (PORT_SUCCESS);
+ }
+
+ PORT_SCHEDULE_UNLOCK;
+
+ //int max_read = length < p_port->peer_mtu ? length : p_port->peer_mtu;
+
+ //max_read = available < max_read ? available : max_read;
+
+ while (available)
+ {
+ /* if we're over buffer high water mark, we're done */
+ if ((p_port->tx.queue_size > PORT_TX_HIGH_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM))
+ break;
+
+ /* continue with rfcomm data write */
+ p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_DATA_POOL_ID);
+ if (!p_buf)
+ break;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+ p_buf->layer_specific = handle;
+
+ if (p_port->peer_mtu < length)
+ length = p_port->peer_mtu;
+ if (available < (int)length)
+ length = (UINT16)available;
+ p_buf->len = length;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ //memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length);
+ //if(recv(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, (int)length, 0) != (int)length)
+ if(p_port->p_data_co_callback(handle, (UINT8 *)(p_buf + 1) + p_buf->offset, length,
+ DATA_CO_CALLBACK_TYPE_OUTGOING) == FALSE)
+ {
+ error("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, length:%d", length);
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+
+ RFCOMM_TRACE_EVENT1 ("PORT_WriteData %d bytes", length);
+
+ rc = port_write (p_port, p_buf);
+
+ /* If queue went below the threashold need to send flow control */
+ event |= port_flow_control_user (p_port);
+
+ if (rc == PORT_SUCCESS)
+ event |= PORT_EV_TXCHAR;
+
+ if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING))
+ break;
+
+ *p_len += length;
+ available -= (int)length;
+ }
+ if (!available && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+ event |= PORT_EV_TXEMPTY;
+
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event)
+ (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function PORT_WriteData
+**
+** Description Normally not GKI aware application will call this function
+** to send data to the port.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+*******************************************************************************/
+int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT32 event = 0;
+ int rc = 0;
+ UINT16 length;
+
+ RFCOMM_TRACE_API1 ("PORT_WriteData() max_len:%d", max_len);
+
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_WriteData() no port state:%d", p_port->state);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!max_len || !p_port->peer_mtu)
+ {
+ RFCOMM_TRACE_ERROR1 ("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu);
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */
+ length = RFCOMM_DATA_POOL_BUF_SIZE -
+ (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+ /* If there are buffers scheduled for transmission check if requested */
+ /* data fits into the end of the queue */
+ PORT_SCHEDULE_LOCK;
+
+ if (((p_buf = (BT_HDR *)p_port->tx.queue.p_last) != NULL)
+ && ((p_buf->len + max_len) <= p_port->peer_mtu)
+ && ((p_buf->len + max_len) <= length))
+ {
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+ p_port->tx.queue_size += max_len;
+
+ *p_len = max_len;
+ p_buf->len += max_len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ return (PORT_SUCCESS);
+ }
+
+ PORT_SCHEDULE_UNLOCK;
+
+ while (max_len)
+ {
+ /* if we're over buffer high water mark, we're done */
+ if ((p_port->tx.queue_size > PORT_TX_HIGH_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM))
+ break;
+
+ /* continue with rfcomm data write */
+ p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_DATA_POOL_ID);
+ if (!p_buf)
+ break;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+ p_buf->layer_specific = handle;
+
+ if (p_port->peer_mtu < length)
+ length = p_port->peer_mtu;
+ if (max_len < length)
+ length = max_len;
+ p_buf->len = length;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length);
+
+ RFCOMM_TRACE_EVENT1 ("PORT_WriteData %d bytes", length);
+
+ rc = port_write (p_port, p_buf);
+
+ /* If queue went below the threashold need to send flow control */
+ event |= port_flow_control_user (p_port);
+
+ if (rc == PORT_SUCCESS)
+ event |= PORT_EV_TXCHAR;
+
+ if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING))
+ break;
+
+ *p_len += length;
+ max_len -= length;
+ p_data += length;
+
+ }
+ if (!max_len && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+ event |= PORT_EV_TXEMPTY;
+
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event)
+ (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Test
+**
+** Description Application can call this function to send RFCOMM Test frame
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+**
+*******************************************************************************/
+int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len)
+{
+ BT_HDR *p_buf;
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_Test() len:%d", len);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (len > ((p_port->mtu == 0) ? RFCOMM_DEFAULT_MTU : p_port->mtu))
+ {
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) != NULL)
+ {
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
+ p_buf->len = len;
+
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+ rfc_send_test (p_port->rfc.p_mcb, TRUE, p_buf);
+ return (PORT_SUCCESS);
+ }
+ else
+ {
+ return (PORT_NO_MEM);
+ }
+}
+
+/*******************************************************************************
+**
+** Function RFCOMM_Init
+**
+** Description This function is called to initialize RFCOMM layer
+**
+*******************************************************************************/
+void RFCOMM_Init (void)
+{
+ memset (&rfc_cb, 0, sizeof (tRFC_CB)); /* Init RFCOMM control block */
+
+ rfc_cb.rfc.last_mux = MAX_BD_CONNECTIONS;
+
+#if defined(RFCOMM_INITIAL_TRACE_LEVEL)
+ rfc_cb.trace_level = RFCOMM_INITIAL_TRACE_LEVEL;
+#else
+ rfc_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ rfcomm_l2cap_if_init ();
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetTraceLevel
+**
+** Description This function sets the trace level for RFCOMM. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 PORT_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ rfc_cb.trace_level = new_level;
+
+ return (rfc_cb.trace_level);
+}
+
diff --git a/stack/rfcomm/port_int.h b/stack/rfcomm/port_int.h
new file mode 100644
index 0000000..2313ace
--- /dev/null
+++ b/stack/rfcomm/port_int.h
@@ -0,0 +1,252 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.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
+{
+ BUFFER_Q 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 */
+ BUFFER_Q 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_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 */
+} 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
diff --git a/stack/rfcomm/port_rfc.c b/stack/rfcomm/port_rfc.c
new file mode 100644
index 0000000..8980330
--- /dev/null
+++ b/stack/rfcomm/port_rfc.c
@@ -0,0 +1,1112 @@
+/******************************************************************************
+ *
+ * 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 module contains functions for port emulation entity and RFCOMM
+ * communications
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "btm_int.h"
+#include "btm_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+/*
+** Local function definitions
+*/
+UINT32 port_rfc_send_tx_data (tPORT *p_port);
+void port_rfc_closed (tPORT *p_port, UINT8 res);
+void port_get_credits (tPORT *p_port, UINT8 k);
+
+
+/*******************************************************************************
+**
+** Function port_open_continue
+**
+** Description This function is called after security manager completes
+** required security checks.
+**
+** Returns void
+**
+*******************************************************************************/
+int port_open_continue (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb;
+
+ RFCOMM_TRACE_EVENT0 ("port_open_continue");
+
+ /* Check if multiplexer channel has already been established */
+ if ((p_mcb = rfc_alloc_multiplexer_channel (p_port->bd_addr, TRUE)) == NULL)
+ {
+ RFCOMM_TRACE_WARNING0 ("port_open_continue no mx channel");
+ port_release_port (p_port);
+ return (PORT_NO_RESOURCES);
+ }
+
+ p_port->rfc.p_mcb = p_mcb;
+
+ p_mcb->port_inx[p_port->dlci] = p_port->inx;
+
+ /* Connection is up and we know local and remote features, select MTU */
+ port_select_mtu (p_port);
+
+ if (p_mcb->state == RFC_MX_STATE_CONNECTED)
+ {
+ RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu);
+ }
+ else if ((p_mcb->state == RFC_MX_STATE_IDLE)
+ ||(p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA))
+ {
+ /* In RFC_MX_STATE_IDLE state, MX state machine will create connection */
+ /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate connection */
+ /* after disconnecting is completed */
+ RFCOMM_StartReq (p_mcb);
+ }
+ else
+ {
+ /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */
+ /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports */
+ RFCOMM_TRACE_DEBUG1 ("port_open_continue: mx state(%d) mx channel is openning", p_mcb->state);
+ }
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function port_start_control
+**
+** Description This function is called in the BTU_TASK context to
+** send control information
+**
+** Returns void
+**
+*******************************************************************************/
+void port_start_control (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+ if (p_mcb == NULL)
+ return;
+
+ RFCOMM_ControlReq (p_mcb, p_port->dlci, &p_port->local_ctrl);
+}
+
+
+/*******************************************************************************
+**
+** Function port_start_par_neg
+**
+** Description This function is called in the BTU_TASK context to
+** send configuration information
+**
+** Returns void
+**
+*******************************************************************************/
+void port_start_par_neg (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+ if (p_mcb == NULL)
+ return;
+
+ RFCOMM_PortNegReq (p_mcb, p_port->dlci, &p_port->user_port_pars);
+}
+
+
+/*******************************************************************************
+**
+** Function port_start_close
+**
+** Description This function is called in the BTU_TASK context to
+** release DLC
+**
+** Returns void
+**
+*******************************************************************************/
+void port_start_close (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+ UINT8 old_signals;
+ UINT32 events = 0;
+
+ /* At first indicate to the user that signals on the connection were dropped */
+ p_port->line_status |= LINE_STATUS_FAILED;
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal);
+
+ if(p_port->ev_mask & PORT_EV_CONNECT_ERR)
+ events |= PORT_EV_CONNECT_ERR;
+
+ if(p_port->ev_mask & PORT_EV_ERR)
+ events |= PORT_EV_ERR;
+
+ if ((p_port->p_callback != NULL) && events)
+ p_port->p_callback (events, p_port->inx);
+
+
+ /* Check if RFCOMM side has been closed while the message was queued */
+ if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED))
+ {
+ /* Call management callback function before calling port_release_port() to clear tPort */
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (PORT_CLOSED, p_port->inx);
+
+ port_release_port (p_port);
+ }
+ else
+ {
+ RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_StartCnf
+**
+** Description This function is called from the RFCOMM layer when
+** establishing of the multiplexer channel is completed.
+** Continue establishing of the connection for all ports that
+** are in the OPENING state
+**
+*******************************************************************************/
+void PORT_StartCnf (tRFC_MCB *p_mcb, UINT16 result)
+{
+ tPORT *p_port;
+ int i;
+ BOOLEAN no_ports_up = TRUE;
+
+ RFCOMM_TRACE_EVENT1 ("PORT_StartCnf result:%d", result);
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ no_ports_up = FALSE;
+
+ if (result == RFCOMM_SUCCESS)
+ RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu);
+ else
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_StartCnf failed result:%d", result);
+
+ /* Warning: result is also set to 4 when l2cap connection
+ fails due to l2cap connect cnf (no_resources) */
+ if( result == HCI_ERR_PAGE_TIMEOUT )
+ p_port->error = PORT_PAGE_TIMEOUT;
+ else
+ p_port->error = PORT_START_FAILED;
+
+ rfc_release_multiplexer_channel (p_mcb);
+ p_port->rfc.p_mcb = NULL;
+
+ /* Send event to the application */
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR))
+ (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (PORT_START_FAILED, p_port->inx);
+
+ port_release_port (p_port);
+ }
+ }
+ }
+
+ /* There can be a situation when after starting connection, user closes the */
+ /* port, we can catch it here to close multiplexor channel */
+ if (no_ports_up)
+ {
+ rfc_check_mcb_active (p_mcb);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_StartInd
+**
+** Description This function is called from the RFCOMM layer when
+** some peer device wants to establish a multiplexer
+** connection. Check if there are any ports open with this
+** or not assigned multiplexer.
+**
+*******************************************************************************/
+void PORT_StartInd (tRFC_MCB *p_mcb)
+{
+ tPORT *p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_StartInd");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if ((p_port->rfc.p_mcb == NULL)
+ || (p_port->rfc.p_mcb == p_mcb))
+ {
+ RFCOMM_StartRsp (p_mcb, RFCOMM_SUCCESS);
+ return;
+ }
+ }
+ RFCOMM_StartRsp (p_mcb, RFCOMM_ERROR);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ParNegInd
+**
+** Description This function is called from the RFCOMM layer to change
+** DLCI parameters (currently only MTU is negotiated).
+** If can not find the port do not accept the request.
+** Otherwise save the MTU size supported by the peer.
+**
+*******************************************************************************/
+void PORT_ParNegInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT8 our_cl;
+ UINT8 our_k;
+
+ RFCOMM_TRACE_EVENT2 ("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu);
+
+ if (!p_port)
+ {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port (dlci);
+ if (!p_port)
+ {
+ /* If the port cannot be opened, send a DM. Per Errata 1205 */
+ rfc_send_dm(p_mcb, dlci, FALSE);
+ /* check if this is the last port open, some headsets have
+ problem, they don't disconnect if we send DM */
+ rfc_check_mcb_active( p_mcb );
+ RFCOMM_TRACE_EVENT0( "PORT_ParNegInd: port not found" );
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ memcpy (p_port->bd_addr, p_mcb->bd_addr, BD_ADDR_LEN);
+
+ /* Connection is up and we know local and remote features, select MTU */
+ port_select_mtu (p_port);
+
+ p_port->rfc.p_mcb = p_mcb;
+ p_port->mtu = (p_port->mtu < mtu) ? p_port->mtu : mtu;
+ p_port->peer_mtu = p_port->mtu;
+
+ /* Negotiate the flow control mechanism. If flow control mechanism for */
+ /* mux has not been set yet, set it now. If either we or peer wants TS 07.10, */
+ /* use that. Otherwise both must want credit based, so use that. If flow is */
+ /* already defined for this mux, we respond with that value. */
+ if (p_mcb->flow == PORT_FC_UNDEFINED)
+ {
+ if ((PORT_FC_DEFAULT == PORT_FC_TS710) || (cl == RFCOMM_PN_CONV_LAYER_TYPE_1))
+ {
+ p_mcb->flow = PORT_FC_TS710;
+ }
+ else
+ {
+ p_mcb->flow = PORT_FC_CREDIT;
+ }
+ }
+
+ /* Regardless of our flow control mechanism, if the PN cl is zero, we must */
+ /* respond with zero. "A responding implementation must set this field to 14 */
+ /* if (and only if) the PN request was 15." This could happen if a PN is sent */
+ /* after the DLCI is already established-- the PN in that case must have cl = 0. */
+ /* See RFCOMM spec 5.5.3 */
+ if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1)
+ {
+ our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+ our_k = 0;
+ }
+ else if (p_mcb->flow == PORT_FC_CREDIT)
+ {
+ /* get credits */
+ port_get_credits (p_port, k);
+
+ /* Set convergence layer and number of credits (k) */
+ our_cl = RFCOMM_PN_CONV_LAYER_CBFC_R;
+ our_k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+ p_port->credit_rx = our_k;
+ }
+ else
+ {
+ /* must not be using credit based flow control; use TS 7.10 */
+ our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+ our_k = 0;
+ }
+ RFCOMM_ParNegRsp (p_mcb, dlci, p_port->mtu, our_cl, our_k);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ParNegCnf
+**
+** Description This function is called from the RFCOMM layer to change
+** DLCI parameters (currently only MTU is negotiated).
+** Save the MTU size supported by the peer.
+** If the confirmation is received during the port opening
+** procedure send EstablishRequest to continue.
+**
+*******************************************************************************/
+void PORT_ParNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT4 ("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu, cl, k);
+
+ if (!p_port)
+ return;
+
+ /* Flow control mechanism not set yet. Negotiate flow control mechanism. */
+ if (p_mcb->flow == PORT_FC_UNDEFINED)
+ {
+ /* Our stack is configured for TS07.10 and they responded with credit-based. */
+ /* This is illegal-- negotiation fails. */
+ if ((PORT_FC_DEFAULT == PORT_FC_TS710) && (cl == RFCOMM_PN_CONV_LAYER_CBFC_R))
+ {
+ rfc_send_disc (p_mcb, p_port->dlci);
+ rfc_port_closed (p_port);
+ return;
+ }
+ /* Our stack is configured for credit-based and they responded with credit-based. */
+ else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R)
+ {
+ p_mcb->flow = PORT_FC_CREDIT;
+ }
+ /* They responded with any other value. Treat this as negotiation to TS07.10. */
+ else
+ {
+ p_mcb->flow = PORT_FC_TS710;
+ }
+ }
+ /* If mux flow control mechanism set, we honor that setting regardless of */
+ /* the CL value in their response. This allows us to gracefully accept any */
+ /* illegal PN negotiation scenarios. */
+
+ p_port->mtu = (p_port->mtu < mtu) ? p_port->mtu : mtu;
+ p_port->peer_mtu = p_port->mtu;
+
+ if (p_mcb->flow == PORT_FC_CREDIT)
+ {
+ port_get_credits (p_port, k);
+ }
+
+ if (p_port->state == PORT_STATE_OPENING)
+ RFCOMM_DlcEstablishReq (p_mcb, p_port->dlci, p_port->mtu);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_DlcEstablishInd
+**
+** Description This function is called from the RFCOMM layer when peer
+** device wants to establish a new DLC. If this is not the
+** first message in the establishment procedure port_handle
+** has a handle to the port control block otherwise the control
+** block should be found based on the muliplexer channel and
+** dlci. The block should be allocated allocated before
+** meaning that application already made open.
+**
+*******************************************************************************/
+void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT2 ("PORT_DlcEstablishInd dlci:%d mtu:%d", dlci, mtu);
+
+ if (!p_port)
+ {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port (dlci);
+ if (!p_port)
+ {
+ RFCOMM_DlcEstablishRsp (p_mcb, dlci, 0, RFCOMM_ERROR);
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ /* If L2CAP's mtu less then RFCOMM's take it */
+ if (mtu && (mtu < p_port->peer_mtu))
+ p_port->peer_mtu = mtu;
+
+ /* If there was an inactivity timer running for MCB stop it */
+ rfc_timer_stop (p_mcb);
+
+ RFCOMM_DlcEstablishRsp (p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS);
+
+ /* This is the server side. If application wants to know when connection */
+ /* is established, thats the place */
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx);
+
+ p_port->state = PORT_STATE_OPENED;
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_DlcEstablishCnf
+**
+** Description This function is called from the RFCOMM layer when peer
+** acknowledges establish procedure (SABME/UA). Send reply
+** to the user and set state to OPENED if result was
+** successfull.
+**
+*******************************************************************************/
+void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT3 ("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, result);
+
+ if (!p_port)
+ return;
+
+ if (result != RFCOMM_SUCCESS)
+ {
+ p_port->error = PORT_START_FAILED;
+ port_rfc_closed (p_port, PORT_START_FAILED);
+ return;
+ }
+
+ /* If L2CAP's mtu less then RFCOMM's take it */
+ if (mtu && (mtu < p_port->peer_mtu))
+ p_port->peer_mtu = mtu;
+
+ /* If there was an inactivity timer running for MCB stop it */
+ rfc_timer_stop (p_mcb);
+
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx);
+
+ p_port->state = PORT_STATE_OPENED;
+
+ /* RPN is required only if we want to tell DTE how the port should be opened */
+ if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING)
+ || (p_port->uuid == UUID_SERVCLASS_FAX))
+ RFCOMM_PortNegReq (p_port->rfc.p_mcb, p_port->dlci, NULL);
+ else
+ RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_PortNegInd
+**
+** Description This function is called from the RFCOMM layer when peer
+** device wants to set parameters of the port. As per the spec
+** this message has to be sent before the first data packet
+** and can be sent before establish. The block should be
+** allocated before meaning that application already made open.
+**
+*******************************************************************************/
+void PORT_PortNegInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars,
+ UINT16 param_mask)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT0 ("PORT_PortNegInd");
+
+ if (!p_port)
+ {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port (dlci);
+ if (!p_port)
+ {
+ RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, 0);
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ /* Check if the flow control is acceptable on local side */
+ p_port->peer_port_pars = *p_pars;
+ RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, param_mask);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_PortNegCnf
+**
+** Description This function is called from the RFCOMM layer to change
+** state for the port. Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_PortNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 result)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT0 ("PORT_PortNegCnf");
+
+ if (!p_port)
+ {
+ RFCOMM_TRACE_WARNING0 ("PORT_PortNegCnf no port");
+ return;
+ }
+ /* Port negotiation failed. Drop the connection */
+ if (result != RFCOMM_SUCCESS)
+ {
+ p_port->error = PORT_PORT_NEG_FAILED;
+
+ RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci);
+
+ port_rfc_closed (p_port, PORT_PORT_NEG_FAILED);
+ return;
+ }
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+ {
+ RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+ }
+ else
+ {
+ RFCOMM_TRACE_WARNING0 ("PORT_PortNegCnf Control Already sent");
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ControlInd
+**
+** Description This function is called from the RFCOMM layer on the modem
+** signal change. Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_ControlInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT32 event;
+ UINT8 old_signals;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_ControlInd");
+
+ if (!p_port)
+ return;
+
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ event = port_get_signal_changes (p_port, old_signals, p_pars->modem_signal);
+
+ p_port->peer_ctrl = *p_pars;
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+ RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+ else
+ {
+ /* If this is the first time we received control RFCOMM is connected */
+ if (!(p_port->port_ctrl & PORT_CTRL_IND_RECEIVED))
+ {
+ event |= (PORT_EV_CONNECTED & p_port->ev_mask);
+ }
+
+ if (p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED)
+ {
+ event |= port_rfc_send_tx_data(p_port);
+ }
+ }
+
+ p_port->port_ctrl |= (PORT_CTRL_IND_RECEIVED | PORT_CTRL_IND_RESPONDED);
+
+ if (p_pars->break_signal)
+ event |= (PORT_EV_BREAK & p_port->ev_mask);
+
+ /* execute call back function only if the application is registered for events */
+ if (event && p_port->p_callback)
+ (p_port->p_callback)(event, p_port->inx);
+
+ RFCOMM_TRACE_EVENT4 ("PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ControlCnf
+**
+** Description This function is called from the RFCOMM layer when
+** peer acknowleges change of the modem signals.
+**
+*******************************************************************************/
+void PORT_ControlCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT32 event = 0;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_ControlCnf");
+
+ if (!p_port)
+ return;
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED))
+ {
+ p_port->port_ctrl |= PORT_CTRL_REQ_CONFIRMED;
+
+ if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)
+ event = (p_port->ev_mask & PORT_EV_CONNECTED);
+ }
+
+ if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)
+ {
+ event |= port_rfc_send_tx_data(p_port);
+ }
+
+ /* execute call back function only if the application is registered for events */
+ if (event && p_port->p_callback)
+ (p_port->p_callback)(event, p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_LineStatusInd
+**
+** Description This function is called from the RFCOMM layer when
+** peer indicates change in the line status
+**
+*******************************************************************************/
+void PORT_LineStatusInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT32 event = 0;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_LineStatusInd");
+
+ if (!p_port)
+ return;
+
+ p_port->line_status |= line_status;
+
+ if (line_status & PORT_ERR_OVERRUN)
+ event |= PORT_EV_OVERRUN;
+
+ if (line_status & PORT_ERR_BREAK)
+ event |= PORT_EV_BREAK;
+
+ if (line_status & ~(PORT_ERR_OVERRUN | PORT_ERR_BREAK))
+ event |= PORT_EV_ERR;
+
+ if ((p_port->p_callback != NULL) && (p_port->ev_mask & event))
+ p_port->p_callback ((p_port->ev_mask & event), p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_DlcReleaseInd
+**
+** Description This function is called from the RFCOMM layer when
+** DLC connection is released.
+**
+*******************************************************************************/
+void PORT_DlcReleaseInd (tRFC_MCB *p_mcb, UINT8 dlci)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT0 ("PORT_DlcReleaseInd");
+
+ if (!p_port)
+ return;
+
+ port_rfc_closed (p_port, PORT_CLOSED);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_CloseInd
+**
+** Description This function is called from the RFCOMM layer when
+** multiplexer connection is released.
+**
+*******************************************************************************/
+void PORT_CloseInd (tRFC_MCB *p_mcb)
+{
+ tPORT *p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_CloseInd");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ port_rfc_closed (p_port, PORT_PEER_CONNECTION_FAILED);
+ }
+ }
+ rfc_release_multiplexer_channel (p_mcb);
+}
+
+/*******************************************************************************
+**
+** Function Port_TimeOutCloseMux
+**
+** Description This function is called when RFCOMM timesout on a command
+** as a result multiplexer connection is closed.
+**
+*******************************************************************************/
+void Port_TimeOutCloseMux (tRFC_MCB *p_mcb)
+{
+ tPORT *p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT0 ("Port_TimeOutCloseMux");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ port_rfc_closed (p_port, PORT_PEER_TIMEOUT);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_DataInd
+**
+** Description This function is called from the RFCOMM layer when data
+** buffer is received from the peer.
+**
+*******************************************************************************/
+void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT8 rx_char1;
+ UINT32 events = 0;
+ UINT8 *p;
+ int i;
+
+ RFCOMM_TRACE_EVENT1 ("PORT_DataInd with data length %d", p_buf->len);
+ if (!p_port)
+ {
+ GKI_freebuf (p_buf);
+ return;
+ }
+ /* If client registered callout callback with flow control we can just deliver receive data */
+ if (p_port->p_data_co_callback)
+ {
+ /* Another packet is delivered to user. Send credits to peer if required */
+
+ if(p_port->p_data_co_callback(p_port->inx, (UINT8*)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING))
+ port_flow_control_peer(p_port, TRUE, 1);
+ else port_flow_control_peer(p_port, FALSE, 0);
+ //GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* If client registered callback we can just deliver receive data */
+ if (p_port->p_data_callback)
+ {
+ /* Another packet is delivered to user. Send credits to peer if required */
+ port_flow_control_peer(p_port, TRUE, 1);
+
+ p_port->p_data_callback (p_port->inx, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* Check if rx queue exceeds the limit */
+ if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM)
+ || (p_port->rx.queue.count + 1 > p_port->rx_buf_critical))
+ {
+ RFCOMM_TRACE_EVENT0 ("PORT_DataInd. Buffer over run. Dropping the buffer");
+ GKI_freebuf (p_buf);
+
+ RFCOMM_LineStatusReq (p_mcb, dlci, LINE_STATUS_OVERRUN);
+ return;
+ }
+
+ /* If user registered to receive notification when a particular byte is */
+ /* received we mast check all received bytes */
+ if (((rx_char1 = p_port->user_port_pars.rx_char1) != 0)
+ && (p_port->ev_mask & PORT_EV_RXFLAG))
+ {
+ for (i = 0, p = (UINT8 *)(p_buf + 1) + p_buf->offset; i < p_buf->len; i++)
+ {
+ if (*p++ == rx_char1)
+ {
+ events |= PORT_EV_RXFLAG;
+ break;
+ }
+ }
+ }
+
+ PORT_SCHEDULE_LOCK;
+
+ GKI_enqueue (&p_port->rx.queue, p_buf);
+ p_port->rx.queue_size += p_buf->len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ /* perform flow control procedures if necessary */
+ port_flow_control_peer(p_port, FALSE, 0);
+
+ /* If user indicated flow control can not deliver any notifications to him */
+ if (p_port->rx.user_fc)
+ {
+ if (events & PORT_EV_RXFLAG)
+ p_port->rx_flag_ev_pending = TRUE;
+
+ return;
+ }
+
+ events |= PORT_EV_RXCHAR;
+
+ /* Mask out all events that are not of interest to user */
+ events &= p_port->ev_mask;
+
+ if (p_port->p_callback && events)
+ p_port->p_callback (events, p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_FlowInd
+**
+** Description This function is called from the RFCOMM layer on the flow
+** control signal change. Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_FlowInd (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN enable_data)
+{
+ tPORT *p_port = (tPORT *)NULL;
+ UINT32 events = 0;
+ int i;
+
+ RFCOMM_TRACE_EVENT1 ("PORT_FlowInd fc:%d", enable_data);
+
+ if (dlci == 0)
+ {
+ p_mcb->peer_ready = enable_data;
+ }
+ else
+ {
+ if ((p_port = port_find_mcb_dlci_port (p_mcb, dlci)) == NULL)
+ return;
+
+ p_port->tx.peer_fc = !enable_data;
+ }
+
+ for (i = 0; i < MAX_RFC_PORTS; i++)
+ {
+ /* If DLCI is 0 event applies to all ports */
+ if (dlci == 0)
+ {
+ p_port = &rfc_cb.port.port[i];
+ if (!p_port->in_use
+ || (p_port->rfc.p_mcb != p_mcb)
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ continue;
+ }
+ events = 0;
+
+ /* Check if flow of data is still enabled */
+ events |= port_flow_control_user (p_port);
+
+ /* Check if data can be sent and send it */
+ events |= port_rfc_send_tx_data (p_port);
+
+ /* Mask out all events that are not of interest to user */
+ events &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && events)
+ (p_port->p_callback)(events, p_port->inx);
+
+ /* If DLCI is not 0 event applies to one port only */
+ if (dlci != 0)
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function port_rfc_send_tx_data
+**
+** Description This function is when forward data can be sent to the peer
+**
+*******************************************************************************/
+UINT32 port_rfc_send_tx_data (tPORT *p_port)
+{
+ UINT32 events = 0;
+ BT_HDR *p_buf;
+
+ /* if there is data to be sent */
+ if (p_port->tx.queue_size > 0)
+ {
+ /* while the rfcomm peer is not flow controlling us, and peer is ready */
+ while (!p_port->tx.peer_fc && p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready)
+ {
+ /* get data from tx queue and send it */
+ PORT_SCHEDULE_LOCK;
+
+ if ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
+ {
+ p_port->tx.queue_size -= p_buf->len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ RFCOMM_TRACE_DEBUG1 ("Sending RFCOMM_DataReq tx.queue_size=%d", p_port->tx.queue_size);
+
+ RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+
+ events |= PORT_EV_TXCHAR;
+
+ if (p_port->tx.queue_size == 0)
+ {
+ events |= PORT_EV_TXEMPTY;
+ break;
+ }
+ }
+ /* queue is empty-- all data sent */
+ else
+ {
+ PORT_SCHEDULE_UNLOCK;
+
+ events |= PORT_EV_TXEMPTY;
+ break;
+ }
+ }
+ /* If we flow controlled user based on the queue size enable data again */
+ events |= port_flow_control_user (p_port);
+ }
+ return (events & p_port->ev_mask);
+}
+
+
+/*******************************************************************************
+**
+** Function port_rfc_closed
+**
+** Description This function when RFCOMM side of port is closed
+**
+*******************************************************************************/
+void port_rfc_closed (tPORT *p_port, UINT8 res)
+{
+ UINT8 old_signals;
+ UINT32 events = 0;
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+ if ((p_port->state == PORT_STATE_OPENING) && (p_port->is_server))
+ {
+ /* The servr side has not been informed that connection is up, ignore */
+ RFCOMM_TRACE_EVENT0 ("port_rfc_closed in OPENING state ignored");
+
+ rfc_port_timer_stop (p_port);
+ p_port->rfc.state = RFC_STATE_CLOSED;
+
+ if (p_mcb)
+ {
+ p_mcb->port_inx[p_port->dlci] = 0;
+
+ /* If there are no more ports opened on this MCB release it */
+ rfc_check_mcb_active (p_mcb);
+ p_port->rfc.p_mcb = NULL;
+ }
+
+ /* Need to restore DLCI to listening state
+ * if the server was on the initiating RFC
+ */
+ p_port->dlci &= 0xfe;
+
+ return;
+ }
+
+ if ((p_port->state != PORT_STATE_CLOSING) && (p_port->state != PORT_STATE_CLOSED))
+ {
+ p_port->line_status |= LINE_STATUS_FAILED;
+
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal);
+
+ if(p_port->ev_mask & PORT_EV_CONNECT_ERR)
+ events |= PORT_EV_CONNECT_ERR;
+ }
+ RFCOMM_TRACE_EVENT2 ("port_rfc_closed state:%d sending events:%x", p_port->state, events);
+
+ if ((p_port->p_callback != NULL) && events)
+ p_port->p_callback (events, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (res, p_port->inx);
+
+ p_port->rfc.state = RFC_STATE_CLOSED;
+
+ port_release_port (p_port);
+}
+
+
+/*******************************************************************************
+**
+** Function port_get_credits
+**
+** Description Set initial values for credits.
+** Adjust max number of rx credits based on negotiated MTU.
+** Check max allowed num of bytes, max allowed num buffers,
+** should be less then 255
+**
+*******************************************************************************/
+void port_get_credits (tPORT *p_port, UINT8 k)
+{
+ p_port->credit_tx = k;
+ if (p_port->credit_tx == 0)
+ p_port->tx.peer_fc = TRUE;
+}
+
+
+
diff --git a/stack/rfcomm/port_utils.c b/stack/rfcomm/port_utils.c
new file mode 100644
index 0000000..ae41682
--- /dev/null
+++ b/stack/rfcomm/port_utils.c
@@ -0,0 +1,582 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "l2cdefs.h"
+#include "btm_int.h"
+#include "btu.h"
+
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+
+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;
+ debug("rfc_cb.port.port[%d] allocated, last_port:%d", yy, rfc_cb.rfc.last_port);
+ 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));
+}
+
+/*******************************************************************************
+**
+** 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_WARNING0 ("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_DEBUG1 ("port_select_mtu selected %d based on connection speed", p_port->mtu);
+ }
+ else
+ {
+ p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+ RFCOMM_TRACE_DEBUG1 ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
+ }
+ }
+ }
+ else
+ {
+ RFCOMM_TRACE_DEBUG1 ("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_DEBUG3 ("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;
+
+ PORT_SCHEDULE_LOCK;
+ debug("port_release_port, p_port:%p", p_port);
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->rx.queue_size = 0;
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->tx.queue_size = 0;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ p_port->state = PORT_STATE_CLOSED;
+
+ if (p_port->rfc.state == RFC_STATE_CLOSED)
+ {
+ RFCOMM_TRACE_DEBUG0 ("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);
+
+ if( p_port->keep_port_handle )
+ {
+ RFCOMM_TRACE_DEBUG1 ("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_DEBUG1 ("port_release_port:Clean-up handle:%d", p_port->inx);
+ 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 */
+ return (&rfc_cb.port.rfc_mcb[i]);
+ }
+ }
+ 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)
+ 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)
+ || (p_port->tx.queue.count > 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));
+
+ p_port->credit_rx = p_port->credit_rx_max;
+
+ p_port->rx.peer_fc = FALSE;
+ }
+ }
+ /* 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 (p_port->rx.queue.count >= 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)
+ && (p_port->rx.queue.count < 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)
+ || (p_port->rx.queue.count > PORT_RX_BUF_HIGH_WM))
+ && !p_port->rx.peer_fc)
+ {
+ RFCOMM_TRACE_EVENT0 ("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);
+ }
+ }
+ }
+}
+
diff --git a/stack/rfcomm/rfc_int.h b/stack/rfcomm/rfc_int.h
new file mode 100644
index 0000000..83a63e3
--- /dev/null
+++ b/stack/rfcomm/rfc_int.h
@@ -0,0 +1,387 @@
+/******************************************************************************
+ *
+ * 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 "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
+RFC_API extern tRFC_CB rfc_cb;
+#else
+RFC_API 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_port_timer_start (tPORT *p_port, UINT16 tout);
+extern void rfc_port_timer_stop (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, 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
+
diff --git a/stack/rfcomm/rfc_l2cap_if.c b/stack/rfcomm/rfc_l2cap_if.c
new file mode 100644
index 0000000..cb50612
--- /dev/null
+++ b/stack/rfcomm/rfc_l2cap_if.c
@@ -0,0 +1,443 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+#include "gki.h"
+
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "rfc_int.h"
+
+
+/*
+** 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);
+
+ 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_DEBUG2 ("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)(GKI_get_tick_count()%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)
+ {
+ L2CA_ConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
+ 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_ERROR1 ("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_DEBUG1 ("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_DEBUG2 ("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_DEBUG1 ("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", p_mcb->pending_lcid);
+
+ /* Peer gave up his connection request, make sure cleaning up L2CAP channel */
+ L2CA_ConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0);
+
+ 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_ERROR1 ("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_ERROR1 ("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)
+{
+}
+
+
+/*******************************************************************************
+**
+** 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_WARNING1 ("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_WARNING1 ("RFCOMM_BufDataInd LCID:0x%x", lcid);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ event = rfc_parse_data (p_mcb, &rfc_cb.rfc.rx_frame, p_buf);
+
+ /* If the frame did not pass validation just ignore it */
+ if (event == RFC_EVENT_BAD_FRAME)
+ {
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI)
+ {
+ /* Take special care of the Multiplexer Control Messages */
+ if (event == RFC_EVENT_UIH)
+ {
+ rfc_process_mx_message (p_mcb, p_buf);
+ return;
+ }
+
+ /* Other multiplexer events go to state machine */
+ rfc_mx_sm_execute (p_mcb, event, NULL);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* The frame was received on the data channel DLCI, verify that DLC exists */
+ if (((p_port = port_find_mcb_dlci_port (p_mcb, rfc_cb.rfc.rx_frame.dlci)) == NULL)
+ || (!p_port->rfc.p_mcb))
+ {
+ /* If this is a SABME on the new port, check if any appl is waiting for it */
+ if (event != RFC_EVENT_SABME)
+ {
+ if (( p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr)
+ || (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr))
+ rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ if ((p_port = port_find_dlci_port (rfc_cb.rfc.rx_frame.dlci)) == NULL)
+ {
+ rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, TRUE);
+ GKI_freebuf (p_buf);
+ return;
+ }
+ p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
+ p_port->rfc.p_mcb = p_mcb;
+ }
+
+ if (event == RFC_EVENT_UIH)
+ {
+ if (p_buf->len > 0)
+ rfc_port_sm_execute (p_port, event, p_buf);
+ else
+ GKI_freebuf (p_buf);
+
+ if (rfc_cb.rfc.rx_frame.credit != 0)
+ rfc_inc_credit (p_port, rfc_cb.rfc.rx_frame.credit);
+
+ return;
+ }
+ rfc_port_sm_execute (p_port, event, NULL);
+ GKI_freebuf (p_buf);
+}
+
+/*******************************************************************************
+**
+** 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_ERROR1 ("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid);
+ return;
+ }
+ else
+ {
+ RFCOMM_TRACE_EVENT1 ("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_ERROR1 ("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_WARNING2 ("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;
+}
diff --git a/stack/rfcomm/rfc_mx_fsm.c b/stack/rfcomm/rfc_mx_fsm.c
new file mode 100644
index 0000000..842f8ee
--- /dev/null
+++ b/stack/rfcomm/rfc_mx_fsm.c
@@ -0,0 +1,663 @@
+/******************************************************************************
+ *
+ * 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 "gki.h"
+#include "bt_types.h"
+#include "rfcdefs.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "l2c_api.h"
+#include "rfc_int.h"
+
+#define L2CAP_SUCCESS 0
+#define L2CAP_ERROR 1
+
+
+/********************************************************************************/
+/* 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)
+{
+ 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)
+{
+ RFCOMM_TRACE_EVENT1 ("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;
+
+ if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 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_ERROR2 ("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);
+ L2CA_ConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0);
+
+ 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_EVENT2 ("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_EVENT1 ("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_START_REQ:
+ RFCOMM_TRACE_ERROR2 ("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_DEBUG2 ("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_DEBUG2 ("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_EVENT2 ("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_EVENT1 ("rfc_mx_sm_state_configure - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_START_REQ:
+ case RFC_MX_EVENT_CONN_CNF:
+
+ RFCOMM_TRACE_ERROR2 ("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ 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_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_sabme_wait_ua
+**
+** Description This function handles events when the multiplexer sent
+** SABME and is waiting for UA reply.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_sabme_wait_ua - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_START_REQ:
+ case RFC_MX_EVENT_CONN_CNF:
+ RFCOMM_TRACE_ERROR2 ("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ /* workaround: we don't support reconfig */
+ /* commented out until we support reconfig
+ case RFC_MX_EVENT_CONF_IND:
+ rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+
+ case RFC_MX_EVENT_CONF_CNF:
+ rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+ */
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd (p_mcb);
+ return;
+
+ case RFC_EVENT_UA:
+ rfc_timer_stop (p_mcb);
+
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = TRUE;
+
+ PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+ return;
+
+ case RFC_EVENT_DM:
+ rfc_timer_stop (p_mcb);
+ /* Case falls through */
+
+ case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
+ case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq (p_mcb->lcid);
+
+ PORT_StartCnf (p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_state_wait_sabme
+**
+** Description This function handles events when the multiplexer is
+** waiting for SABME on the acceptor side after configuration
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_wait_sabme - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd (p_mcb);
+ return;
+
+ case RFC_EVENT_SABME:
+ /* if we gave up outgoing connection request */
+ if (p_mcb->pending_lcid)
+ {
+ p_mcb->pending_lcid = 0;
+
+ rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+
+ rfc_timer_stop (p_mcb);
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = TRUE;
+
+ /* MX channel collision has been resolved, continue to open ports */
+ PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+ }
+ else
+ {
+ rfc_timer_stop (p_mcb);
+ PORT_StartInd (p_mcb);
+ }
+ return;
+
+ case RFC_MX_EVENT_START_RSP:
+ if (*((UINT16 *)p_data) != RFCOMM_SUCCESS)
+ rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE);
+ else
+ {
+ rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = TRUE;
+ }
+ return;
+
+ case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
+ case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq (p_mcb->lcid);
+
+ PORT_CloseInd (p_mcb);
+ return;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_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)
+{
+ RFCOMM_TRACE_EVENT1 ("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_EVENT2 ("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_EVENT1 ("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)
+ {
+ /* Start Request was received while disconnecting. Execute it again */
+ if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 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 *)GKI_dequeue(&p_mcb->cmd_q)) != NULL)
+ GKI_freebuf(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:
+ GKI_freebuf (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_EVENT2 ("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_EVENT0 ("rfc_mx_send_config_req");
+
+ memset (&cfg, 0, sizeof (tL2CAP_CFG_INFO));
+
+ cfg.mtu_present = TRUE;
+ cfg.mtu = L2CAP_MTU_SIZE;
+
+/* 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_EVENT2 ("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, RFC_T2_TIMEOUT);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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, RFC_T2_TIMEOUT);
+ }
+ }
+}
diff --git a/stack/rfcomm/rfc_port_fsm.c b/stack/rfcomm/rfc_port_fsm.c
new file mode 100644
index 0000000..d5335ad
--- /dev/null
+++ b/stack/rfcomm/rfc_port_fsm.c
@@ -0,0 +1,915 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+/********************************************************************************/
+/* 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)
+{
+ if (!p_port)
+ {
+ RFCOMM_TRACE_WARNING1 ("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:
+ GKI_freebuf (p_data);
+ break;
+
+ case RFC_EVENT_SABME:
+ /* make sure the multiplexer disconnect timer is not running (reconnect case) */
+ rfc_timer_stop(p_port->rfc.p_mcb );
+
+ /* Open will be continued after security checks are passed */
+ p_port->rfc.state = RFC_STATE_TERM_WAIT_SEC_CHECK;
+ btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, FALSE,
+ BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2),
+ &rfc_sec_check_complete, p_port);
+ return;
+
+ case RFC_EVENT_UA:
+ return;
+
+ case RFC_EVENT_DM:
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ;
+ RFCOMM_TRACE_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+ }
+
+ RFCOMM_TRACE_WARNING1 ("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_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
+ rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci);
+ p_port->rfc.expected_rsp = 0;
+ p_port->rfc.state = RFC_STATE_DISC_WAIT_UA;
+ return;
+
+ case RFC_EVENT_CLEAR:
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ GKI_freebuf (p_data);
+ break;
+
+ case RFC_EVENT_UA:
+ rfc_port_timer_stop (p_port);
+ p_port->rfc.state = RFC_STATE_OPENED;
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_SUCCESS);
+ return;
+
+ case RFC_EVENT_DM:
+ p_port->rfc.p_mcb->is_disc_initiator = TRUE;
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_SABME:
+ /* Continue to wait for the UA the SABME this side sent */
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ p_port->rfc.state = RFC_STATE_CLOSED;
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ return;
+ }
+ RFCOMM_TRACE_WARNING1 ("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_ERROR2 ("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_ERROR0 ("Port error state Term Wait Sec event Data");
+ GKI_freebuf (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:
+ GKI_freebuf (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);
+ }
+ else
+ {
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+ p_port->rfc.state = RFC_STATE_OPENED;
+ }
+ return;
+ }
+ RFCOMM_TRACE_WARNING1 ("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_ERROR2 ("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_ERROR0 ("Port error state Orig Wait Sec event Data");
+ GKI_freebuf (p_data);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ return;
+ }
+ RFCOMM_TRACE_WARNING1 ("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_ERROR2 ("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(p_port->rx.queue.count)
+ {
+ /* give a chance to upper stack to close port properly */
+ RFCOMM_TRACE_DEBUG0("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_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+ }
+ RFCOMM_TRACE_WARNING1 ("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_ERROR2 ("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:
+ GKI_freebuf (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:
+ GKI_freebuf (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_WARNING1 ("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_WARNING0("***** 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)
+{
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+ GKI_freebuf (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;
+}
+
diff --git a/stack/rfcomm/rfc_port_if.c b/stack/rfcomm/rfc_port_if.c
new file mode 100644
index 0000000..083d9ef
--- /dev/null
+++ b/stack/rfcomm/rfc_port_if.c
@@ -0,0 +1,339 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "l2c_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+
+#if RFC_DYNAMIC_MEMORY == FALSE
+tRFC_CB rfc_cb;
+#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)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+ {
+ PORT_DlcEstablishCnf (p_mcb, dlci, 0, RFCOMM_ERROR);
+ 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)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS))
+ {
+ PORT_DlcReleaseInd (p_mcb, 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)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT8 flow;
+ UINT8 cl;
+ UINT8 k;
+
+ 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)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+ {
+ PORT_PortNegCnf (p_mcb, dlci, NULL, RFCOMM_ERROR);
+ 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->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->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->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);
+}
+
+
diff --git a/stack/rfcomm/rfc_ts_frames.c b/stack/rfcomm/rfc_ts_frames.c
new file mode 100644
index 0000000..4690200
--- /dev/null
+++ b/stack/rfcomm/rfc_ts_frames.c
@@ -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 functions to send TS 07.10 frames
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "l2c_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+/*******************************************************************************
+**
+** 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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);
+}
+
+
+/*******************************************************************************
+**
+** 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;
+
+ /* 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 *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == 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_ERROR1 ("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_ERROR0 ("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_ERROR2 ("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_ERROR0 ("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_ERROR0 ("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_ERROR0 ("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_ERROR0 ("Bad DISC");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ else
+ return (RFC_EVENT_DISC);
+
+ case RFCOMM_UIH:
+ if (!RFCOMM_VALID_DLCI(p_frame->dlci))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad UIH - invalid DLCI");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ else if (!rfc_check_fcs (2, p_start, fcs))
+ {
+ RFCOMM_TRACE_ERROR0 ("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_ERROR0 ("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_ERROR2 ("Illegal MX Frame ea:%d len:%d", p_rx_frame->ea, length);
+ GKI_freebuf (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_ERROR0 ("Bad MX frame");
+ GKI_freebuf (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_ERROR0 ("Bad PN frame");
+ break;
+ }
+
+ GKI_freebuf (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;
+
+ GKI_freebuf (p_buf);
+
+ rfc_process_fcon (p_mcb, is_command);
+ return;
+
+ case RFCOMM_MX_FCOFF:
+ if (length != RFCOMM_MX_FCOFF_LEN)
+ break;
+
+ GKI_freebuf (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_ERROR0 ("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;
+ }
+ GKI_freebuf (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;
+
+ GKI_freebuf (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_ERROR0 ("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;
+ }
+ GKI_freebuf (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_ERROR0 ("Bad RPN frame");
+ break;
+ }
+
+ GKI_freebuf (p_buf);
+
+ rfc_process_rls (p_mcb, is_command, p_rx_frame);
+ return;
+ }
+
+ GKI_freebuf (p_buf);
+
+ if (is_command)
+ rfc_send_nsc (p_mcb);
+}
+
diff --git a/stack/rfcomm/rfc_utils.c b/stack/rfcomm/rfc_utils.c
new file mode 100644
index 0000000..49405ac
--- /dev/null
+++ b/stack/rfcomm/rfc_utils.c
@@ -0,0 +1,467 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+#include "gki.h"
+
+#include "btm_api.h"
+#include "btm_int.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_ext.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "btu.h"
+
+#include <string.h>
+
+/*******************************************************************************
+**
+** 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;
+
+ 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 */
+ /* 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]);
+ 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 */
+ memset (p_mcb, 0, sizeof (tRFC_MCB));
+ memcpy (p_mcb->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ GKI_init_q(&p_mcb->cmd_q);
+
+ p_mcb->is_initiator = is_initiator;
+
+ rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER);
+
+ rfc_cb.rfc.last_mux = (UINT8) j;
+ return (p_mcb);
+ }
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_release_multiplexer_channel
+**
+** Description This function returns existing or new control block for
+** the BD_ADDR.
+**
+*******************************************************************************/
+void rfc_release_multiplexer_channel (tRFC_MCB *p_mcb)
+{
+ void *p_buf;
+
+ rfc_timer_stop (p_mcb);
+
+ while ((p_buf = GKI_dequeue(&p_mcb->cmd_q)) != NULL)
+ GKI_freebuf(p_buf);
+
+ 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_EVENT1 ("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_EVENT0 ("rfc_timer_stop");
+
+ btu_stop_timer (&p_mcb->tle);
+}
+
+
+/*******************************************************************************
+**
+** 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_EVENT1 ("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_EVENT0 ("rfc_port_timer_stop");
+
+ btu_stop_timer (&p_port->rfc.tle);
+}
+
+
+/*******************************************************************************
+**
+** 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, void *p_ref_data, UINT8 res)
+{
+ tPORT *p_port = (tPORT *)p_ref_data;
+
+ /* 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_DEBUG0 ("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_EVENT1 ("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)
+ {
+ GKI_enqueue(&p_mcb->cmd_q, p_buf);
+ }
+
+ /* handle queue if L2CAP not congested */
+ while (p_mcb->l2cap_congested == FALSE)
+ {
+ if ((p = (BT_HDR *) GKI_dequeue(&p_mcb->cmd_q)) == NULL)
+ {
+ break;
+ }
+
+
+ L2CA_DataWrite (p_mcb->lcid, p);
+ }
+}
+
+