summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bta/Android.mk10
-rw-r--r--bta/dm/bta_dm_pm.c5
-rw-r--r--bta/include/bta_api.h24
-rw-r--r--bta/include/bta_jv_api.h410
-rw-r--r--bta/include/bta_jv_co.h4
-rw-r--r--bta/include/bta_sdp_api.h145
-rw-r--r--bta/jv/bta_jv_act.c1255
-rw-r--r--bta/jv/bta_jv_api.c604
-rw-r--r--bta/jv/bta_jv_int.h161
-rw-r--r--bta/jv/bta_jv_main.c13
-rw-r--r--bta/sdp/bta_sdp.c75
-rw-r--r--bta/sdp/bta_sdp_act.c570
-rw-r--r--bta/sdp/bta_sdp_api.c173
-rw-r--r--bta/sdp/bta_sdp_cfg.c40
-rw-r--r--bta/sdp/bta_sdp_int.h115
-rw-r--r--bta/sys/bta_sys.h9
-rw-r--r--btif/include/btif_sdp.h34
-rw-r--r--btif/include/btif_sock_l2cap.h23
-rw-r--r--btif/include/btif_sock_sdp.h4
-rw-r--r--btif/src/bluetooth.c7
-rw-r--r--btif/src/btif_core.c1
-rw-r--r--btif/src/btif_dm.c8
-rw-r--r--btif/src/btif_sdp.c197
-rw-r--r--btif/src/btif_sdp_server.c721
-rw-r--r--btif/src/btif_sock.c29
-rw-r--r--btif/src/btif_sock_l2cap.c1070
-rw-r--r--btif/src/btif_sock_rfc.c135
-rw-r--r--btif/src/btif_sock_sdp.c98
-rw-r--r--btif/src/btif_sock_thread.c21
-rw-r--r--btif/src/btif_sock_util.c2
-rw-r--r--conf/bt_stack.conf1
-rw-r--r--include/bt_target.h126
-rw-r--r--main/Android.mk4
-rw-r--r--stack/Android.mk2
-rw-r--r--stack/gap/gap_conn.c1284
-rw-r--r--stack/gap/gap_int.h79
-rw-r--r--stack/gap/gap_utils.c436
-rw-r--r--stack/gatt/gatt_main.c12
-rw-r--r--stack/include/gap_api.h234
-rw-r--r--stack/include/l2c_api.h6
-rw-r--r--stack/include/l2cdefs.h5
-rw-r--r--stack/include/sdpdefs.h6
-rw-r--r--stack/l2cap/l2c_api.c4
-rw-r--r--stack/l2cap/l2c_ble.c18
-rw-r--r--stack/l2cap/l2c_csm.c13
-rw-r--r--stack/l2cap/l2c_fcr.c3
-rw-r--r--stack/l2cap/l2c_link.c8
-rw-r--r--stack/l2cap/l2c_main.c3
-rw-r--r--stack/l2cap/l2c_utils.c38
-rw-r--r--stack/smp/smp_l2c.c9
50 files changed, 8001 insertions, 253 deletions
diff --git a/bta/Android.mk b/bta/Android.mk
index e5e853f27..cb11643d1 100644
--- a/bta/Android.mk
+++ b/bta/Android.mk
@@ -70,17 +70,17 @@ LOCAL_SRC_FILES:= \
./hl/bta_hl_utils.c \
./hl/bta_hl_sdp.c \
./hl/bta_hl_ci.c \
- ./mce/bta_mce_api.c \
- ./mce/bta_mce_main.c \
- ./mce/bta_mce_act.c \
- ./mce/bta_mce_cfg.c \
+ ./sdp/bta_sdp_api.c \
+ ./sdp/bta_sdp_act.c \
+ ./sdp/bta_sdp.c \
+ ./sdp/bta_sdp_cfg.c \
./sys/bta_sys_main.c \
./sys/bta_sys_conn.c \
./sys/utl.c \
./jv/bta_jv_act.c \
./jv/bta_jv_cfg.c \
./jv/bta_jv_main.c \
- ./jv/bta_jv_api.c \
+ ./jv/bta_jv_api.c
LOCAL_MODULE := libbt-brcm_bta
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
diff --git a/bta/dm/bta_dm_pm.c b/bta/dm/bta_dm_pm.c
index c3c05de53..7cee9c35a 100644
--- a/bta/dm/bta_dm_pm.c
+++ b/bta/dm/bta_dm_pm.c
@@ -124,6 +124,7 @@ void bta_dm_disable_pm(void)
static void bta_dm_pm_stop_timer(BD_ADDR peer_addr)
{
UINT8 i;
+ APPL_TRACE_DEBUG("%s: ", __func__);
for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
{
@@ -448,8 +449,8 @@ static void bta_dm_pm_set_mode(BD_ADDR peer_addr, BOOLEAN timed_out )
/* dont initiate SNIFF, if link_policy has it disabled */
if (p_peer_device->link_policy & HCI_ENABLE_SNIFF_MODE)
{
- p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF;
- bta_dm_pm_sniff(p_peer_device, (UINT8)(pm_action & 0x0F) );
+ p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF;
+ bta_dm_pm_sniff(p_peer_device, (UINT8)(pm_action & 0x0F) );
}
else
{
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index c7aab8322..efa8d32d1 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -85,19 +85,19 @@ typedef UINT8 tBTA_STATUS;
#define BTA_MN_SERVICE_ID 26 /* Message Notification Service */
#define BTA_HDP_SERVICE_ID 27 /* Health Device Profile */
#define BTA_PCE_SERVICE_ID 28 /* PhoneBook Access Client*/
-
+#define BTA_SDP_SERVICE_ID 29 /* SDP Search*/
#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
/* BLE profile service ID */
-#define BTA_BLE_SERVICE_ID 29 /* GATT profile */
+#define BTA_BLE_SERVICE_ID 30 /* GATT profile */
// btla-specific ++
-#define BTA_USER_SERVICE_ID 30 /* User requested UUID */
+#define BTA_USER_SERVICE_ID 31 /* User requested UUID */
-#define BTA_MAX_SERVICE_ID 31
+#define BTA_MAX_SERVICE_ID 32
// btla-specific --
#else
-#define BTA_USER_SERVICE_ID 29 /* User requested UUID */
-#define BTA_MAX_SERVICE_ID 30
+#define BTA_USER_SERVICE_ID 30 /* User requested UUID */
+#define BTA_MAX_SERVICE_ID 31
#endif
/* service IDs (BTM_SEC_SERVICE_FIRST_EMPTY + 1) to (BTM_SEC_MAX_SERVICES - 1)
* are used by BTA JV */
@@ -214,7 +214,7 @@ typedef tBT_TRANSPORT tBTA_TRANSPORT;
#define BTA_DM_CONN_PAIRED 1
/* Inquiry Modes */
-#define BTA_DM_INQUIRY_NONE BTM_INQUIRY_NONE /*No BR inquiry. */
+#define BTA_DM_INQUIRY_NONE BTM_INQUIRY_NONE /*No BR inquiry. */
#define BTA_DM_GENERAL_INQUIRY BTM_GENERAL_INQUIRY /* Perform general inquiry. */
#define BTA_DM_LIMITED_INQUIRY BTM_LIMITED_INQUIRY /* Perform limited inquiry. */
@@ -497,10 +497,10 @@ typedef tBTM_BLE_TRACK_ADV_ACTION tBTA_BLE_TRACK_ADV_ACTION;
#define BTA_BLE_RSSI_ALERT_LO 2
typedef UINT8 tBTA_DM_BLE_RSSI_ALERT_TYPE;
-#define BTA_BLE_RSSI_ALERT_NONE BTM_BLE_RSSI_ALERT_NONE /* (0) */
-#define BTA_BLE_RSSI_ALERT_HI_BIT BTM_BLE_RSSI_ALERT_HI_BIT /* (1) */
-#define BTA_BLE_RSSI_ALERT_RANGE_BIT BTM_BLE_RSSI_ALERT_RANGE_BIT /* (1 << 1) */
-#define BTA_BLE_RSSI_ALERT_LO_BIT BTM_BLE_RSSI_ALERT_LO_BIT /* (1 << 2) */
+#define BTA_BLE_RSSI_ALERT_NONE BTM_BLE_RSSI_ALERT_NONE /* (0) */
+#define BTA_BLE_RSSI_ALERT_HI_BIT BTM_BLE_RSSI_ALERT_HI_BIT /* (1) */
+#define BTA_BLE_RSSI_ALERT_RANGE_BIT BTM_BLE_RSSI_ALERT_RANGE_BIT /* (1 << 1) */
+#define BTA_BLE_RSSI_ALERT_LO_BIT BTM_BLE_RSSI_ALERT_LO_BIT /* (1 << 2) */
typedef UINT8 tBTA_DM_BLE_RSSI_ALERT_MASK;
@@ -510,7 +510,7 @@ typedef void (tBTA_DM_BLE_RSSI_CBACK) (BD_ADDR bd_addr, tBTA_DM_BLE_RSSI_ALERT_T
#define BTA_DM_BLE_MAX_UUID_FILTER BTM_BLE_MAX_UUID_FILTER /* 8 */
#define BTA_DM_BLE_MAX_ADDR_FILTER BTM_BLE_MAX_ADDR_FILTER /* 8 */
#define BTA_DM_BLE_PF_STR_COND_MAX BTM_BLE_PF_STR_COND_MAX /* 4 apply to manu data , or local name */
-#define BTA_DM_BLE_PF_STR_LEN_MAX BTM_BLE_PF_STR_LEN_MAX /* match for first 20 bytes */
+#define BTA_DM_BLE_PF_STR_LEN_MAX BTM_BLE_PF_STR_LEN_MAX /* match for first 20 bytes */
#define BTA_DM_BLE_PF_LOGIC_OR 0
#define BTA_DM_BLE_PF_LOGIC_AND 1
diff --git a/bta/include/bta_jv_api.h b/bta/include/bta_jv_api.h
index a61588a16..9996da98a 100644
--- a/bta/include/bta_jv_api.h
+++ b/bta/include/bta_jv_api.h
@@ -28,6 +28,8 @@
#include "bt_types.h"
#include "bta_api.h"
#include "btm_api.h"
+#include "l2c_api.h"
+
/*****************************************************************************
** Constants and data types
*****************************************************************************/
@@ -44,6 +46,7 @@ typedef UINT8 tBTA_JV_STATUS;
#define BTA_JV_MAX_UUIDS SDP_MAX_UUID_FILTERS
#define BTA_JV_MAX_ATTRS SDP_MAX_ATTR_FILTERS
#define BTA_JV_MAX_SDP_REC SDP_MAX_RECORDS
+#define BTA_JV_MAX_L2C_CONN GAP_MAX_CONNECTIONS /* GAP handle is used as index, hence do not change this value */
#define BTA_JV_MAX_SCN PORT_MAX_RFC_PORTS /* same as BTM_MAX_SCN (in btm_int.h) */
#define BTA_JV_MAX_RFC_CONN MAX_RFC_PORTS
@@ -51,7 +54,6 @@ typedef UINT8 tBTA_JV_STATUS;
#define BTA_JV_DEF_RFC_MTU (3*330)
#endif
-/* */
#ifndef BTA_JV_MAX_RFC_SR_SESSION
#define BTA_JV_MAX_RFC_SR_SESSION MAX_BD_CONNECTIONS
#endif
@@ -118,23 +120,41 @@ enum
};
typedef UINT8 tBTA_JV_CONN_STATE;
+/* JV Connection types */
+#define BTA_JV_CONN_TYPE_RFCOMM 0
+#define BTA_JV_CONN_TYPE_L2CAP 1
+#define BTA_JV_CONN_TYPE_L2CAP_LE 2
+
/* Java I/F callback events */
/* events received by tBTA_JV_DM_CBACK */
#define BTA_JV_ENABLE_EVT 0 /* JV enabled */
+#define BTA_JV_GET_SCN_EVT 6 /* Reserved an SCN */
+#define BTA_JV_GET_PSM_EVT 7 /* Reserved a PSM */
#define BTA_JV_DISCOVERY_COMP_EVT 8 /* SDP discovery complete */
#define BTA_JV_CREATE_RECORD_EVT 11 /* the result for BTA_JvCreateRecord */
+/* events received by tBTA_JV_L2CAP_CBACK */
+#define BTA_JV_L2CAP_OPEN_EVT 16 /* open status of L2CAP connection */
+#define BTA_JV_L2CAP_CLOSE_EVT 17 /* L2CAP connection closed */
+#define BTA_JV_L2CAP_START_EVT 18 /* L2CAP server started */
+#define BTA_JV_L2CAP_CL_INIT_EVT 19 /* L2CAP client initiated a connection */
+#define BTA_JV_L2CAP_DATA_IND_EVT 20 /* L2CAP connection received data */
+#define BTA_JV_L2CAP_CONG_EVT 21 /* L2CAP connection congestion status changed */
+#define BTA_JV_L2CAP_READ_EVT 22 /* the result for BTA_JvL2capRead */
+#define BTA_JV_L2CAP_RECEIVE_EVT 23 /* the result for BTA_JvL2capReceive*/
+#define BTA_JV_L2CAP_WRITE_EVT 24 /* the result for BTA_JvL2capWrite*/
+#define BTA_JV_L2CAP_WRITE_FIXED_EVT 25 /* the result for BTA_JvL2capWriteFixed */
/* events received by tBTA_JV_RFCOMM_CBACK */
-#define BTA_JV_RFCOMM_OPEN_EVT 25 /* open status of RFCOMM Client connection */
-#define BTA_JV_RFCOMM_CLOSE_EVT 26 /* RFCOMM connection closed */
-#define BTA_JV_RFCOMM_START_EVT 27 /* RFCOMM server started */
-#define BTA_JV_RFCOMM_CL_INIT_EVT 28 /* RFCOMM client initiated a connection */
-#define BTA_JV_RFCOMM_DATA_IND_EVT 29 /* RFCOMM connection received data */
-#define BTA_JV_RFCOMM_CONG_EVT 30 /* RFCOMM connection congestion status changed */
-#define BTA_JV_RFCOMM_READ_EVT 31 /* the result for BTA_JvRfcommRead */
-#define BTA_JV_RFCOMM_WRITE_EVT 32 /* the result for BTA_JvRfcommWrite*/
-#define BTA_JV_RFCOMM_SRV_OPEN_EVT 33 /* open status of Server RFCOMM connection */
-#define BTA_JV_MAX_EVT 34 /* max number of JV events */
+#define BTA_JV_RFCOMM_OPEN_EVT 26 /* open status of RFCOMM Client connection */
+#define BTA_JV_RFCOMM_CLOSE_EVT 27 /* RFCOMM connection closed */
+#define BTA_JV_RFCOMM_START_EVT 28 /* RFCOMM server started */
+#define BTA_JV_RFCOMM_CL_INIT_EVT 29 /* RFCOMM client initiated a connection */
+#define BTA_JV_RFCOMM_DATA_IND_EVT 30 /* RFCOMM connection received data */
+#define BTA_JV_RFCOMM_CONG_EVT 31 /* RFCOMM connection congestion status changed */
+#define BTA_JV_RFCOMM_READ_EVT 32 /* the result for BTA_JvRfcommRead */
+#define BTA_JV_RFCOMM_WRITE_EVT 33 /* the result for BTA_JvRfcommWrite*/
+#define BTA_JV_RFCOMM_SRV_OPEN_EVT 34 /* open status of Server RFCOMM connection */
+#define BTA_JV_MAX_EVT 35 /* max number of JV events */
typedef UINT16 tBTA_JV_EVT;
@@ -158,6 +178,104 @@ typedef struct
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
} tBTA_JV_CREATE_RECORD;
+/* data associated with BTA_JV_L2CAP_OPEN_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ BD_ADDR rem_bda; /* The peer address */
+ INT32 tx_mtu; /* The transmit MTU */
+} tBTA_JV_L2CAP_OPEN;
+
+/* data associated with BTA_JV_L2CAP_OPEN_EVT for LE sockets */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ BD_ADDR rem_bda; /* The peer address */
+ INT32 tx_mtu; /* The transmit MTU */
+ void **p_p_cback; /* set them for new socket */
+ void **p_user_data;/* set them for new socket */
+
+} tBTA_JV_L2CAP_LE_OPEN;
+
+
+/* data associated with BTA_JV_L2CAP_CLOSE_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ BOOLEAN async; /* FALSE, if local initiates disconnect */
+} tBTA_JV_L2CAP_CLOSE;
+
+/* data associated with BTA_JV_L2CAP_START_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ UINT8 sec_id; /* security ID used by this server */
+} tBTA_JV_L2CAP_START;
+
+/* data associated with BTA_JV_L2CAP_CL_INIT_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ UINT8 sec_id; /* security ID used by this client */
+} tBTA_JV_L2CAP_CL_INIT;
+
+/* data associated with BTA_JV_L2CAP_CONG_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ BOOLEAN cong; /* TRUE, congested. FALSE, uncongested */
+} tBTA_JV_L2CAP_CONG;
+
+/* data associated with BTA_JV_L2CAP_READ_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ UINT32 req_id; /* The req_id in the associated BTA_JvL2capRead() */
+ UINT8 *p_data; /* This points the same location as the p_data
+ * parameter in BTA_JvL2capRead () */
+ UINT16 len; /* The length of the data read. */
+} tBTA_JV_L2CAP_READ;
+
+/* data associated with BTA_JV_L2CAP_RECEIVE_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ UINT32 req_id; /* The req_id in the associated BTA_JvL2capReceive() */
+ UINT8 *p_data; /* This points the same location as the p_data
+ * parameter in BTA_JvL2capReceive () */
+ UINT16 len; /* The length of the data read. */
+} tBTA_JV_L2CAP_RECEIVE;
+
+/* data associated with BTA_JV_L2CAP_WRITE_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT32 handle; /* The connection handle */
+ UINT32 req_id; /* The req_id in the associated BTA_JvL2capWrite() */
+ UINT16 len; /* The length of the data written. */
+ BOOLEAN cong; /* congestion status */
+} tBTA_JV_L2CAP_WRITE;
+
+
+/* data associated with BTA_JV_L2CAP_WRITE_FIXED_EVT */
+typedef struct
+{
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ UINT16 channel; /* The connection channel */
+ BD_ADDR addr; /* The peer address */
+ UINT32 req_id; /* The req_id in the associated BTA_JvL2capWrite() */
+ UINT16 len; /* The length of the data written. */
+ BOOLEAN cong; /* congestion status */
+} tBTA_JV_L2CAP_WRITE_FIXED;
+
/* data associated with BTA_JV_RFCOMM_OPEN_EVT */
typedef struct
{
@@ -207,6 +325,14 @@ typedef struct
UINT32 handle; /* The connection handle */
} tBTA_JV_DATA_IND;
+/*data associated with BTA_JV_L2CAP_DATA_IND_EVT if used for LE */
+typedef struct
+{
+ UINT32 handle; /* The connection handle */
+ BT_HDR *p_buf; /* The incoming data */
+} tBTA_JV_LE_DATA_IND;
+
+
/* data associated with BTA_JV_RFCOMM_CONG_EVT */
typedef struct
{
@@ -258,7 +384,16 @@ typedef union
tBTA_JV_STATUS status; /* BTA_JV_ENABLE_EVT */
tBTA_JV_DISCOVERY_COMP disc_comp; /* BTA_JV_DISCOVERY_COMP_EVT */
tBTA_JV_SET_DISCOVER set_discover; /* BTA_JV_SET_DISCOVER_EVT */
+ UINT8 scn; /* BTA_JV_GET_SCN_EVT */
+ UINT16 psm; /* BTA_JV_GET_PSM_EVT */
tBTA_JV_CREATE_RECORD create_rec; /* BTA_JV_CREATE_RECORD_EVT */
+ tBTA_JV_L2CAP_OPEN l2c_open; /* BTA_JV_L2CAP_OPEN_EVT */
+ tBTA_JV_L2CAP_CLOSE l2c_close; /* BTA_JV_L2CAP_CLOSE_EVT */
+ tBTA_JV_L2CAP_START l2c_start; /* BTA_JV_L2CAP_START_EVT */
+ tBTA_JV_L2CAP_CL_INIT l2c_cl_init; /* BTA_JV_L2CAP_CL_INIT_EVT */
+ tBTA_JV_L2CAP_CONG l2c_cong; /* BTA_JV_L2CAP_CONG_EVT */
+ tBTA_JV_L2CAP_READ l2c_read; /* BTA_JV_L2CAP_READ_EVT */
+ tBTA_JV_L2CAP_WRITE l2c_write; /* BTA_JV_L2CAP_WRITE_EVT */
tBTA_JV_RFCOMM_OPEN rfc_open; /* BTA_JV_RFCOMM_OPEN_EVT */
tBTA_JV_RFCOMM_SRV_OPEN rfc_srv_open; /* BTA_JV_RFCOMM_SRV_OPEN_EVT */
tBTA_JV_RFCOMM_CLOSE rfc_close; /* BTA_JV_RFCOMM_CLOSE_EVT */
@@ -267,8 +402,11 @@ typedef union
tBTA_JV_RFCOMM_CONG rfc_cong; /* BTA_JV_RFCOMM_CONG_EVT */
tBTA_JV_RFCOMM_READ rfc_read; /* BTA_JV_RFCOMM_READ_EVT */
tBTA_JV_RFCOMM_WRITE rfc_write; /* BTA_JV_RFCOMM_WRITE_EVT */
- tBTA_JV_DATA_IND data_ind; /* BTA_JV_L2CAP_DATA_IND_EVT
+ tBTA_JV_DATA_IND data_ind; /* BTA_JV_L2CAP_DATA_IND_EVT
BTA_JV_RFCOMM_DATA_IND_EVT */
+ tBTA_JV_LE_DATA_IND le_data_ind; /* BTA_JV_L2CAP_LE_DATA_IND_EVT */
+ tBTA_JV_L2CAP_LE_OPEN l2c_le_open; /* BTA_JV_L2CAP_OPEN_EVT */
+ tBTA_JV_L2CAP_WRITE_FIXED l2c_write_fixed; /* BTA_JV_L2CAP_WRITE_FIXED_EVT */
} tBTA_JV;
/* JAVA DM Interface callback */
@@ -277,6 +415,9 @@ typedef void (tBTA_JV_DM_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void * user_
/* JAVA RFCOMM interface callback */
typedef void* (tBTA_JV_RFCOMM_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
+/* JAVA L2CAP interface callback */
+typedef void (tBTA_JV_L2CAP_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_Data);
+
/* JV configuration structure */
typedef struct
{
@@ -338,6 +479,43 @@ extern BOOLEAN BTA_JvIsEncrypted(BD_ADDR bd_addr);
/*******************************************************************************
**
+** Function BTA_JvGetChannelId
+**
+** Description This function reserves a SCN/PSM for applications running
+** over RFCOMM or L2CAP. It is primarily called by
+** server profiles/applications to register their SCN/PSM into the
+** SDP database. The SCN is reported by the tBTA_JV_DM_CBACK
+** callback with a BTA_JV_GET_SCN_EVT.
+** If the SCN/PSM reported is 0, that means all SCN resources are
+** exhausted.
+** The channel parameter can be used to request a specific
+** channel. If the request on the specific channel fails, the
+** SCN/PSM returned in the EVT will be 0 - no attempt to request
+** a new channel will be made. set channel to <= 0 to automatically
+** assign an channel ID.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void* user_data,
+ INT32 channel);
+
+/*******************************************************************************
+**
+** Function BTA_JvFreeChannel
+**
+** Description This function frees a SCN/PSM that was used
+** by an application running over RFCOMM or L2CAP.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvFreeChannel(UINT16 channel, int conn_type);
+
+/*******************************************************************************
+**
** Function BTA_JvStartDiscovery
**
** Description This function performs service discovery for the services
@@ -379,6 +557,214 @@ extern tBTA_JV_STATUS BTA_JvDeleteRecord(UINT32 handle);
/*******************************************************************************
**
+** Function BTA_JvL2capConnectLE
+**
+** Description Initiate a connection as an LE L2CAP client to the given BD
+** Address.
+** When the connection is initiated or failed to initiate,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+** When the connection is established or failed,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_chan,
+ UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capConnect
+**
+** Description Initiate a connection as a L2CAP client to the given BD
+** Address.
+** When the connection is initiated or failed to initiate,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+** When the connection is established or failed,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_psm,
+ UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capClose
+**
+** Description This function closes an L2CAP client connection
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capCloseLE
+**
+** Description This function closes an L2CAP client connection for Fixed Channels
+** Function is idempotent and no callbacks are called!
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capCloseLE(UINT32 handle);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStartServer
+**
+** Description This function starts an L2CAP server and listens for an L2CAP
+** connection from a remote Bluetooth device. When the server
+** is started successfully, tBTA_JV_L2CAP_CBACK is called with
+** BTA_JV_L2CAP_START_EVT. When the connection is established,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info,
+ UINT16 local_psm, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStartServerLE
+**
+** Description This function starts an LE L2CAP server and listens for an L2CAP
+** connection from a remote Bluetooth device on a fixed channel
+** over an LE link. When the server
+** is started successfully, tBTA_JV_L2CAP_CBACK is called with
+** BTA_JV_L2CAP_START_EVT. When the connection is established,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info,
+ UINT16 local_chan, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStopServerLE
+**
+** Description This function stops the LE L2CAP server. If the server has an
+** active connection, it would be closed.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capStopServerLE(UINT16 local_chan, void *user_data);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStopServerLE
+**
+** Description This function stops the LE L2CAP server. If the server has an
+** active connection, it would be closed.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capStopServer(UINT16 local_psm, void *user_data);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capRead
+**
+** Description This function reads data from an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_READ_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id,
+ UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capReceive
+**
+** Description This function reads data from an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_RECEIVE_EVT.
+** If there are more data queued in L2CAP than len, the extra data will be discarded.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capReceive(UINT32 handle, UINT32 req_id,
+ UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capReady
+**
+** Description This function determined if there is data to read from
+** an L2CAP connection
+**
+** Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+** BTA_JV_FAILURE, if error.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capReady(UINT32 handle, UINT32 *p_data_size);
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capWrite
+**
+** Description This function writes data to an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_WRITE_EVT. Works for
+** PSM-based connections
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capWrite(UINT32 handle, UINT32 req_id,
+ UINT8 *p_data, UINT16 len, void *user_data);
+
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capWriteFixed
+**
+** Description This function writes data to an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_WRITE_FIXED_EVT. Works for
+** fixed-channel connections
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT32 req_id,
+ tBTA_JV_L2CAP_CBACK *p_cback,
+ UINT8 *p_data, UINT16 len, void *user_data);
+
+/*******************************************************************************
+**
** Function BTA_JvRfcommConnect
**
** Description This function makes an RFCOMM conection to a remote BD
diff --git a/bta/include/bta_jv_co.h b/bta/include/bta_jv_co.h
index 24315c207..198424890 100644
--- a/bta/include/bta_jv_co.h
+++ b/bta/include/bta_jv_co.h
@@ -46,4 +46,8 @@ extern int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf);
extern int bta_co_rfc_data_outgoing_size(void *user_data, int *size);
extern int bta_co_rfc_data_outgoing(void *user_data, UINT8* buf, UINT16 size);
+extern int bta_co_l2cap_data_incoming(void *user_data, BT_HDR *p_buf);
+extern int bta_co_l2cap_data_outgoing_size(void *user_data, int *size);
+extern int bta_co_l2cap_data_outgoing(void *user_data, UINT8* buf, UINT16 size);
+
#endif /* BTA_DG_CO_H */
diff --git a/bta/include/bta_sdp_api.h b/bta/include/bta_sdp_api.h
new file mode 100644
index 000000000..6fa13137c
--- /dev/null
+++ b/bta/include/bta_sdp_api.h
@@ -0,0 +1,145 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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 is the public interface file for the BTA SDP I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_SDP_API_H
+#define BTA_SDP_API_H
+
+#include <hardware/bt_sdp.h>
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "btm_api.h"
+
+/* status values */
+#define BTA_SDP_SUCCESS 0 /* Successful operation. */
+#define BTA_SDP_FAILURE 1 /* Generic failure. */
+#define BTA_SDP_BUSY 2 /* Temporarily can not handle this request. */
+
+typedef UINT8 tBTA_SDP_STATUS;
+
+/* SDP I/F callback events */
+/* events received by tBTA_SDP_DM_CBACK */
+#define BTA_SDP_ENABLE_EVT 0 /* SDP service i/f enabled*/
+#define BTA_SDP_SEARCH_EVT 1 /* SDP Service started */
+#define BTA_SDP_SEARCH_COMP_EVT 2 /* SDP search complete */
+#define BTA_SDP_CREATE_RECORD_USER_EVT 3 /* SDP search complete */
+#define BTA_SDP_REMOVE_RECORD_USER_EVT 4 /* SDP search complete */
+#define BTA_SDP_MAX_EVT 5 /* max number of SDP events */
+
+#define BTA_SDP_MAX_RECORDS 15
+
+typedef UINT16 tBTA_SDP_EVT;
+
+/* data associated with BTA_SDP_DISCOVERY_COMP_EVT */
+typedef struct
+{
+ tBTA_SDP_STATUS status;
+ BD_ADDR remote_addr;
+ tBT_UUID uuid;
+ int record_count;
+ bluetooth_sdp_record records[BTA_SDP_MAX_RECORDS];
+} tBTA_SDP_SEARCH_COMP;
+
+typedef union
+{
+ tBTA_SDP_STATUS status; /* BTA_SDP_SEARCH_EVT */
+ tBTA_SDP_SEARCH_COMP sdp_search_comp; /* BTA_SDP_SEARCH_COMP_EVT */
+} tBTA_SDP;
+
+/* SDP DM Interface callback */
+typedef void (tBTA_SDP_DM_CBACK)(tBTA_SDP_EVT event, tBTA_SDP *p_data, void * user_data);
+
+/* MCE configuration structure */
+typedef struct
+{
+ UINT16 sdp_db_size; /* The size of p_sdp_db */
+ tSDP_DISCOVERY_DB *p_sdp_db; /* The data buffer to keep SDP database */
+} tBTA_SDP_CFG;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/*******************************************************************************
+**
+** Function BTA_SdpEnable
+**
+** Description Enable the SDP I/F service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_SDP_ENABLE_EVT. This function must
+** be called before other functions in the MCE API are
+** called.
+**
+** Returns BTA_SDP_SUCCESS if successful.
+** BTA_SDP_FAIL if internal failure.
+**
+*******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_SdpSearch
+**
+** Description Start a search for sdp records for a specific BD_ADDR with a
+** specific profile uuid.
+** When the search operation is completed, the callback function
+** will be called with a BTA_SDP_SEARCH_EVT.
+** Returns BTA_SDP_SUCCESS if successful.
+** BTA_SDP_FAIL if internal failure.
+**
+*******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpSearch(BD_ADDR bd_addr,tSDP_UUID *uuid);
+
+/*******************************************************************************
+**
+** Function BTA_SdpCreateRecordByUser
+**
+** Description This function is used to request a callback to create a SDP
+** record. The registered callback will be called with event
+** BTA_SDP_CREATE_RECORD_USER_EVT.
+**
+** Returns BTA_SDP_SUCCESS, if the request is being processed.
+** BTA_SDP_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data);
+
+/*******************************************************************************
+**
+** Function BTA_SdpRemoveRecordByUser
+**
+** Description This function is used to request a callback to remove a SDP
+** record. The registered callback will be called with event
+** BTA_SDP_REMOVE_RECORD_USER_EVT.
+**
+** Returns BTA_SDP_SUCCESS, if the request is being processed.
+** BTA_SDP_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void* user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_SDP_API_H */
diff --git a/bta/jv/bta_jv_act.c b/bta/jv/bta_jv_act.c
index 224450ad6..46b8f7b38 100644
--- a/bta/jv/bta_jv_act.c
+++ b/bta/jv/bta_jv_act.c
@@ -23,6 +23,7 @@
******************************************************************************/
#include <hardware/bluetooth.h>
#include <arpa/inet.h>
+#include <pthread.h>
#include "bt_types.h"
#include "gki.h"
@@ -42,6 +43,57 @@
#include "avct_api.h"
#include "avdt_api.h"
#include "gap_api.h"
+#include "l2c_api.h"
+
+
+/* one of these exists for each client */
+struct fc_client {
+ struct fc_client *next_all_list;
+ struct fc_client *next_chan_list;
+ BD_ADDR remote_addr;
+ uint32_t id;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+ uint16_t handle;
+ uint16_t chan;
+ uint8_t sec_id;
+ unsigned server : 1;
+ unsigned init_called : 1;
+};
+
+/* one of these exists for each channel we're dealing with */
+struct fc_channel {
+ struct fc_channel *next;
+ struct fc_client *clients;
+ uint8_t has_server : 1;
+ uint16_t chan;
+};
+
+
+static struct fc_client *fc_clients;
+static struct fc_channel *fc_channels;
+static uint32_t fc_next_id;
+static pthread_once_t fc_init_once = PTHREAD_ONCE_INIT;
+
+
+static void fc_init_work(void)
+{
+ fc_clients = NULL;
+ fc_channels = NULL;
+ fc_next_id = 0;
+
+ //more init here if needed...
+}
+
+static void fc_init(void)
+{
+ pthread_once(&fc_init_once, fc_init_work);
+}
+
+
+static void fcchan_conn_chng_cbk(UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
+ UINT16 reason, tBT_TRANSPORT );
+static void fcchan_data_cbk(UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf);
extern void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str);
@@ -330,16 +382,43 @@ static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
}
/*******************************************************************************
- **
- ** Function bta_jv_clear_pm_cb
- **
- ** Description clears jv pm control block and optionally calls bta_sys_conn_close()
- ** In general close_conn should be set to TRUE to remove registering with
- ** dm pm!
- **
- ** WARNING: Make sure to clear pointer form port or l2c to this control block too!
- **
- *******************************************************************************/
+**
+** Function bta_jv_free_l2c_cb
+**
+** Description free the given L2CAP control block
+**
+** Returns
+**
+*******************************************************************************/
+tBTA_JV_STATUS bta_jv_free_l2c_cb(tBTA_JV_L2C_CB *p_cb)
+{
+ tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+
+ if(BTA_JV_ST_NONE != p_cb->state)
+ {
+ bta_jv_free_set_pm_profile_cb((UINT32)p_cb->handle);
+ if (GAP_ConnClose(p_cb->handle) != BT_PASS)
+ status = BTA_JV_FAILURE;
+ }
+ p_cb->psm = 0;
+ p_cb->state = BTA_JV_ST_NONE;
+ bta_jv_free_sec_id(&p_cb->sec_id);
+ p_cb->p_cback = NULL;
+ return status;
+}
+
+/*******************************************************************************
+**
+**
+** Function bta_jv_clear_pm_cb
+**
+** Description clears jv pm control block and optionally calls bta_sys_conn_close()
+** In general close_conn should be set to TRUE to remove registering with
+** dm pm!
+**
+** WARNING: Make sure to clear pointer form port or l2c to this control block too!
+**
+*******************************************************************************/
static void bta_jv_clear_pm_cb(tBTA_JV_PM_CB *p_pm_cb, BOOLEAN close_conn)
{
/* needs to be called if registered with bta pm, otherwise we may run out of dm pm slots! */
@@ -381,10 +460,10 @@ static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle)
appid_counter++;
}
- APPL_TRACE_API("bta_jv_free_set_pm_profile_cb(jv_handle: 0x%2x), idx: %d, "
- "app_id: 0x%x", jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
- APPL_TRACE_API("bta_jv_free_set_pm_profile_cb, bd_counter = %d, "
- "appid_counter = %d", bd_counter, appid_counter);
+ APPL_TRACE_API("%s(jv_handle: 0x%2x), idx: %d, "
+ "app_id: 0x%x",__func__, jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
+ APPL_TRACE_API("%s, bd_counter = %d, "
+ "appid_counter = %d", __func__, bd_counter, appid_counter);
if (bd_counter > 1)
{
bta_jv_pm_conn_idle(&bta_jv_cb.pm_cb[i]);
@@ -410,14 +489,24 @@ static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle)
if (p_pcb)
{
if (NULL == p_pcb->p_pm_cb)
- APPL_TRACE_WARNING("bta_jv_free_set_pm_profile_cb(jv_handle:"
+ APPL_TRACE_WARNING("%s(jv_handle:"
" 0x%x):port_handle: 0x%x, p_pm_cb: %d: no link to "
- "pm_cb?", jv_handle, p_pcb->port_handle, i);
+ "pm_cb?", __func__, jv_handle, p_pcb->port_handle, i);
p_cb = &p_pcb->p_pm_cb;
}
}
}
-
+ else
+ {
+ if (jv_handle < BTA_JV_MAX_L2C_CONN)
+ {
+ tBTA_JV_L2C_CB *p_l2c_cb = &bta_jv_cb.l2c_cb[jv_handle];
+ if (NULL == p_l2c_cb->p_pm_cb)
+ APPL_TRACE_WARNING("%s(jv_handle: "
+ "0x%x): p_pm_cb: %d: no link to pm_cb?", __func__, jv_handle, i);
+ p_cb = &p_l2c_cb->p_pm_cb;
+ }
+ }
if (p_cb)
{
*p_cb = NULL;
@@ -466,6 +555,23 @@ static tBTA_JV_PM_CB *bta_jv_alloc_set_pm_profile_cb(UINT32 jv_handle, tBTA_JV_P
}
}
}
+ else
+ {
+ /* use jv handle for l2cap bd address retrieval */
+ for (j = 0; j < BTA_JV_MAX_L2C_CONN; j++)
+ {
+ if (jv_handle == bta_jv_cb.l2c_cb[j].handle)
+ {
+ pp_cb = &bta_jv_cb.l2c_cb[j].p_pm_cb;
+ UINT8 *p_bd_addr = GAP_ConnGetRemoteAddr((UINT16)jv_handle);
+ if (NULL != p_bd_addr)
+ bdcpy(peer_bd_addr, p_bd_addr);
+ else
+ i = BTA_JV_PM_MAX_NUM;
+ break;
+ }
+ }
+ }
APPL_TRACE_API("bta_jv_alloc_set_pm_profile_cb(handle 0x%2x, app_id %d): "
"idx: %d, (BTA_JV_PM_MAX_NUM: %d), pp_cb: 0x%x", jv_handle, app_id,
i, BTA_JV_PM_MAX_NUM, pp_cb);
@@ -489,6 +595,72 @@ static tBTA_JV_PM_CB *bta_jv_alloc_set_pm_profile_cb(UINT32 jv_handle, tBTA_JV_P
/*******************************************************************************
**
+** Function bta_jv_check_psm
+**
+** Description for now use only the legal PSM per JSR82 spec
+**
+** Returns TRUE, if allowed
+**
+*******************************************************************************/
+BOOLEAN bta_jv_check_psm(UINT16 psm)
+{
+ BOOLEAN ret = FALSE;
+
+ if (L2C_IS_VALID_PSM(psm))
+ {
+ if (psm < 0x1001)
+ {
+ /* see if this is defined by spec */
+ switch (psm)
+ {
+ case SDP_PSM: /* 1 */
+ case BT_PSM_RFCOMM: /* 3 */
+ /* do not allow java app to use these 2 PSMs */
+ break;
+
+ case TCS_PSM_INTERCOM: /* 5 */
+ case TCS_PSM_CORDLESS: /* 7 */
+ if( FALSE == bta_sys_is_register(BTA_ID_CT) &&
+ FALSE == bta_sys_is_register(BTA_ID_CG) )
+ ret = TRUE;
+ break;
+
+ case BT_PSM_BNEP: /* F */
+ if(FALSE == bta_sys_is_register(BTA_ID_PAN))
+ ret = TRUE;
+ break;
+
+ case HID_PSM_CONTROL: /* 0x11 */
+ case HID_PSM_INTERRUPT: /* 0x13 */
+ //FIX: allow HID Device and HID Host to coexist
+ if( FALSE == bta_sys_is_register(BTA_ID_HD) ||
+ FALSE == bta_sys_is_register(BTA_ID_HH) )
+ ret = TRUE;
+ break;
+
+ case AVCT_PSM: /* 0x17 */
+ case AVDT_PSM: /* 0x19 */
+ if ((FALSE == bta_sys_is_register(BTA_ID_AV)) &&
+ (FALSE == bta_sys_is_register(BTA_ID_AVK)))
+ ret = TRUE;
+ break;
+
+ default:
+ ret = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ ret = TRUE;
+ }
+ }
+ return ret;
+
+}
+
+/*******************************************************************************
+**
** Function bta_jv_enable
**
** Description Initialises the JAVA I/F
@@ -501,6 +673,7 @@ void bta_jv_enable(tBTA_JV_MSG *p_data)
tBTA_JV_STATUS status = BTA_JV_SUCCESS;
bta_jv_cb.p_dm_cback = p_data->enable.p_cback;
bta_jv_cb.p_dm_cback(BTA_JV_ENABLE_EVT, (tBTA_JV *)&status, 0);
+ memset(bta_jv_cb.free_psm_list,0,sizeof(bta_jv_cb.free_psm_list));
}
/*******************************************************************************
@@ -517,9 +690,135 @@ void bta_jv_disable (tBTA_JV_MSG *p_data)
{
UNUSED(p_data);
- APPL_TRACE_ERROR("bta_jv_disable not used");
+ APPL_TRACE_ERROR("%s",__func__);
+}
+
+
+/**
+ * We keep a list of PSM's that have been freed from JAVA, for reuse.
+ * This function will return a free PSM, and delete it from the free
+ * list.
+ * If no free PSMs exist, 0 will be returned.
+ */
+static UINT16 bta_jv_get_free_psm() {
+ const int cnt = sizeof(bta_jv_cb.free_psm_list)/sizeof(bta_jv_cb.free_psm_list[0]);
+ for (int i = 0; i < cnt; i++) {
+ UINT16 psm = bta_jv_cb.free_psm_list[i];
+ if (psm != 0) {
+ APPL_TRACE_DEBUG("%s(): Reusing PSM: 0x%04d", __func__, psm)
+ bta_jv_cb.free_psm_list[i] = 0;
+ return psm;
+ }
+ }
+ return 0;
+}
+
+static void bta_jv_set_free_psm(UINT16 psm) {
+ int free_index = -1;
+ const int cnt = sizeof(bta_jv_cb.free_psm_list)/sizeof(bta_jv_cb.free_psm_list[0]);
+ for (int i = 0; i < cnt; i++) {
+ if (bta_jv_cb.free_psm_list[i] == 0) {
+ free_index = i;
+ } else if (psm == bta_jv_cb.free_psm_list[i]) {
+ return; // PSM already freed?
+ }
+ }
+ if (free_index != -1) {
+ bta_jv_cb.free_psm_list[free_index] = psm;
+ APPL_TRACE_DEBUG("%s(): Recycling PSM: 0x%04d", __func__, psm)
+ } else {
+ APPL_TRACE_ERROR("%s unable to free psm 0x%x no more free slots",__func__, psm);
+ }
}
+/*******************************************************************************
+**
+** Function bta_jv_get_channel_id
+**
+** Description Obtain a free SCN (Server Channel Number)
+** (RFCOMM channel or L2CAP PSM)
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_get_channel_id(tBTA_JV_MSG *p_data)
+{
+ UINT16 psm = 0;
+
+ switch (p_data->alloc_channel.type) {
+ case BTA_JV_CONN_TYPE_RFCOMM: {
+ INT32 channel = p_data->alloc_channel.channel;
+ UINT8 scn = 0;
+ if (channel > 0)
+ {
+ if (BTM_TryAllocateSCN(channel) == FALSE)
+ {
+ APPL_TRACE_ERROR("rfc channel:%d already in use or invalid", channel);
+ channel = 0;
+ }
+ } else if ((channel = BTM_AllocateSCN()) == 0) {
+ APPL_TRACE_ERROR("run out of rfc channels");
+ channel = 0;
+ }
+ if (channel != 0) {
+ bta_jv_cb.scn[channel-1] = TRUE;
+ scn = (UINT8) channel;
+ }
+ if (bta_jv_cb.p_dm_cback)
+ bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, (tBTA_JV *)&scn,
+ p_data->alloc_channel.user_data);
+ return;
+ }
+ case BTA_JV_CONN_TYPE_L2CAP:
+ psm = bta_jv_get_free_psm();
+ if (psm == 0) {
+ psm = L2CA_AllocatePSM();
+ APPL_TRACE_DEBUG("%s() returned PSM: 0x%04x", __func__, psm);
+ }
+ break;
+ case BTA_JV_CONN_TYPE_L2CAP_LE:
+ break;
+ default:
+ break;
+ }
+
+ if (bta_jv_cb.p_dm_cback)
+ bta_jv_cb.p_dm_cback(BTA_JV_GET_PSM_EVT, (tBTA_JV *)&psm, p_data->alloc_channel.user_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_free_scn
+**
+** Description free a SCN
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_free_scn(tBTA_JV_MSG *p_data)
+{
+ UINT16 scn = p_data->free_channel.scn;
+
+ switch (p_data->free_channel.type) {
+ case BTA_JV_CONN_TYPE_RFCOMM: {
+ if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn-1])
+ {
+ /* this scn is used by JV */
+ bta_jv_cb.scn[scn-1] = FALSE;
+ BTM_FreeSCN(scn);
+ }
+ break;
+ }
+ case BTA_JV_CONN_TYPE_L2CAP:
+ bta_jv_set_free_psm(scn);
+ break;
+ case BTA_JV_CONN_TYPE_L2CAP_LE:
+ // TODO: Not yet implemented...
+ break;
+ default:
+ break;
+ }
+}
static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u)
{
static uint8_t bt_base_uuid[] =
@@ -587,7 +886,7 @@ static void bta_jv_start_discovery_cback(UINT16 result, void * user_data)
logu("shorten uuid:", su.uu.uuid128);
p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec);
APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec);
- if(p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe))
{
dcomp.scn = (UINT8) pe.params[0];
status = BTA_JV_SUCCESS;
@@ -690,6 +989,450 @@ void bta_jv_delete_record(tBTA_JV_MSG *p_data)
/*******************************************************************************
**
+** Function bta_jv_l2cap_client_cback
+**
+** Description handles the l2cap client events
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_jv_l2cap_client_cback(UINT16 gap_handle, UINT16 event)
+{
+ tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+ tBTA_JV evt_data;
+
+ if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback)
+ return;
+
+ APPL_TRACE_DEBUG( "%s: %d evt:x%x",__func__, gap_handle, event);
+ evt_data.l2c_open.status = BTA_JV_SUCCESS;
+ evt_data.l2c_open.handle = gap_handle;
+
+ switch (event)
+ {
+ case GAP_EVT_CONN_OPENED:
+ bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+ evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+ p_cb->state = BTA_JV_ST_CL_OPEN;
+ p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
+ break;
+
+ case GAP_EVT_CONN_CLOSED:
+ p_cb->state = BTA_JV_ST_NONE;
+ bta_jv_free_sec_id(&p_cb->sec_id);
+ evt_data.l2c_close.async = TRUE;
+ p_cb->p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, p_cb->user_data);
+ p_cb->p_cback = NULL;
+ break;
+
+ case GAP_EVT_CONN_DATA_AVAIL:
+ evt_data.data_ind.handle = gap_handle;
+ /* Reset idle timer to avoid requesting sniff mode while receiving data */
+ bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+ p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, p_cb->user_data);
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
+ case GAP_EVT_CONN_CONGESTED:
+ case GAP_EVT_CONN_UNCONGESTED:
+ p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE;
+ evt_data.l2c_cong.cong = p_cb->cong;
+ p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->user_data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_connect
+**
+** Description makes an l2cap client connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2C_CB *p_cb;
+ tBTA_JV_L2CAP_CL_INIT evt_data;
+ UINT16 handle=GAP_INVALID_HANDLE;
+ UINT8 sec_id;
+ tL2CAP_CFG_INFO cfg;
+ tBTA_JV_API_L2CAP_CONNECT *cc = &(p_data->l2cap_connect);
+ UINT8 chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+ tL2CAP_ERTM_INFO *ertm_info = NULL;
+
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ if (cc->has_cfg == TRUE)
+ {
+ cfg = cc->cfg;
+ if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+ }
+ }
+
+ if (cc->has_ertm_info == TRUE)
+ {
+ ertm_info = &(cc->ertm_info);
+ }
+
+ /* We need to use this value for MTU to be able to handle cases where cfg is not set in req. */
+ cfg.mtu_present = TRUE;
+ cfg.mtu = cc->rx_mtu;
+
+ /* TODO: DM role manager
+ L2CA_SetDesireRole(cc->role);
+ */
+
+ sec_id = bta_jv_alloc_sec_id();
+ evt_data.sec_id = sec_id;
+ evt_data.status = BTA_JV_FAILURE;
+
+ if (sec_id)
+ {
+ if (bta_jv_check_psm(cc->remote_psm)) /* allowed */
+ {
+ if ((handle = GAP_ConnOpen("", sec_id, 0, cc->peer_bd_addr, cc->remote_psm,
+ &cfg, ertm_info, cc->sec_mask, chan_mode_mask,
+ bta_jv_l2cap_client_cback)) != GAP_INVALID_HANDLE )
+ {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+ }
+ }
+
+ if (evt_data.status == BTA_JV_SUCCESS)
+ {
+ p_cb = &bta_jv_cb.l2c_cb[handle];
+ p_cb->handle = handle;
+ p_cb->p_cback = cc->p_cback;
+ p_cb->user_data = cc->user_data;
+ p_cb->psm = 0; /* not a server */
+ p_cb->sec_id = sec_id;
+ p_cb->state = BTA_JV_ST_CL_OPENING;
+ }
+ else
+ {
+ bta_jv_free_sec_id(&sec_id);
+ }
+
+ evt_data.handle = handle;
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV *)&evt_data, cc->user_data);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_close
+**
+** Description Close an L2CAP client connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_close(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2CAP_CLOSE evt_data;
+ tBTA_JV_API_L2CAP_CLOSE *cc = &(p_data->l2cap_close);
+ tBTA_JV_L2CAP_CBACK *p_cback = cc->p_cb->p_cback;
+ void *user_data = cc->p_cb->user_data;
+
+ evt_data.handle = cc->handle;
+ evt_data.status = bta_jv_free_l2c_cb(cc->p_cb);
+ evt_data.async = FALSE;
+
+ if (p_cback)
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_server_cback
+**
+** Description handles the l2cap server callback
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_jv_l2cap_server_cback(UINT16 gap_handle, UINT16 event)
+{
+ tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+ tBTA_JV evt_data;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+
+ if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback)
+ return;
+
+ APPL_TRACE_DEBUG( "%s: %d evt:x%x", __func__, gap_handle, event);
+ evt_data.l2c_open.status = BTA_JV_SUCCESS;
+ evt_data.l2c_open.handle = gap_handle;
+
+ switch (event)
+ {
+ case GAP_EVT_CONN_OPENED:
+ bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+ evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+ p_cb->state = BTA_JV_ST_SR_OPEN;
+ p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
+ break;
+
+ case GAP_EVT_CONN_CLOSED:
+ evt_data.l2c_close.async = TRUE;
+ evt_data.l2c_close.handle = p_cb->handle;
+ p_cback = p_cb->p_cback;
+ user_data = p_cb->user_data;
+ evt_data.l2c_close.status = bta_jv_free_l2c_cb(p_cb);
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, user_data);
+ break;
+
+ case GAP_EVT_CONN_DATA_AVAIL:
+ evt_data.data_ind.handle = gap_handle;
+ /* Reset idle timer to avoid requesting sniff mode while receiving data */
+ bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+ p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, p_cb->user_data);
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
+ case GAP_EVT_CONN_CONGESTED:
+ case GAP_EVT_CONN_UNCONGESTED:
+ p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE;
+ evt_data.l2c_cong.cong = p_cb->cong;
+ p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->user_data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_start_server
+**
+** Description starts an L2CAP server
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_start_server(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2C_CB *p_cb;
+ UINT8 sec_id;
+ UINT16 handle;
+ tL2CAP_CFG_INFO cfg;
+ tBTA_JV_L2CAP_START evt_data;
+ tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
+ INT32 use_etm = FALSE;
+ UINT8 chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+ tL2CAP_ERTM_INFO *ertm_info = NULL;
+
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ if (ls->has_cfg == TRUE) {
+ cfg = ls->cfg;
+ if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+ }
+ }
+
+ if (ls->has_ertm_info == TRUE) {
+ ertm_info = &(ls->ertm_info);
+ }
+
+ //FIX: MTU=0 means not present
+ if (ls->rx_mtu >0)
+ {
+ cfg.mtu_present = TRUE;
+ cfg.mtu = ls->rx_mtu;
+ }
+ else
+ {
+ cfg.mtu_present = FALSE;
+ cfg.mtu = 0;
+ }
+
+ /* TODO DM role manager
+ L2CA_SetDesireRole(ls->role);
+ */
+
+ sec_id = bta_jv_alloc_sec_id();
+ if (0 == sec_id || (FALSE == bta_jv_check_psm(ls->local_psm)) ||
+ (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, 0, ls->local_psm, &cfg, ertm_info,
+ ls->sec_mask, chan_mode_mask, bta_jv_l2cap_server_cback)) == GAP_INVALID_HANDLE)
+ {
+ bta_jv_free_sec_id(&sec_id);
+ evt_data.status = BTA_JV_FAILURE;
+ }
+ else
+ {
+ p_cb = &bta_jv_cb.l2c_cb[handle];
+ evt_data.status = BTA_JV_SUCCESS;
+ evt_data.handle = handle;
+ evt_data.sec_id = sec_id;
+ p_cb->p_cback = ls->p_cback;
+ p_cb->user_data = ls->user_data;
+ p_cb->handle = handle;
+ p_cb->sec_id = sec_id;
+ p_cb->state = BTA_JV_ST_SR_LISTEN;
+ p_cb->psm = ls->local_psm;
+ }
+
+ ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data, ls->user_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_stop_server
+**
+** Description stops an L2CAP server
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_stop_server(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2C_CB *p_cb;
+ tBTA_JV_L2CAP_CLOSE evt_data;
+ tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+ for (int i = 0; i < BTA_JV_MAX_L2C_CONN; i++)
+ {
+ if (bta_jv_cb.l2c_cb[i].psm == ls->local_psm)
+ {
+ p_cb = &bta_jv_cb.l2c_cb[i];
+ p_cback = p_cb->p_cback;
+ user_data = p_cb->user_data;
+ evt_data.handle = p_cb->handle;
+ evt_data.status = bta_jv_free_l2c_cb(p_cb);
+ evt_data.async = FALSE;
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
+ break;
+ }
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_read
+**
+** Description Read data from an L2CAP connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_read(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2CAP_READ evt_data;
+ tBTA_JV_API_L2CAP_READ *rc = &(p_data->l2cap_read);
+
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = rc->handle;
+ evt_data.req_id = rc->req_id;
+ evt_data.p_data = rc->p_data;
+ evt_data.len = 0;
+
+ if (BT_PASS == GAP_ConnReadData(rc->handle, rc->p_data, rc->len, &evt_data.len))
+ {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+
+ rc->p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data, rc->user_data);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_write
+**
+** Description Write data to an L2CAP connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_write(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2CAP_WRITE evt_data;
+ tBTA_JV_API_L2CAP_WRITE *ls = &(p_data->l2cap_write);
+
+ /* As we check this callback exists before the tBTA_JV_API_L2CAP_WRITE can be send through the
+ * API this check should not be needed.
+ * But the API is not designed to be used (safely at least) in a multi-threaded scheduler, hence
+ * if the peer device disconnects the l2cap link after the API is called, but before this
+ * message is handled, the ->p_cback will be cleared at this point. At first glanch this seems
+ * highly unlikely, but for all obex-profiles with two channels connected - e.g. MAP, this
+ * happens around 1 of 4 disconnects, as a disconnect on the server channel causes a disconnect
+ * to be send on the client (notification) channel, but at the peer typically disconnects both
+ * the OBEX disconnect request crosses the incoming l2cap disconnect.
+ * If p_cback is cleared, we simply discard the data.
+ * RISK: The caller must handle any cleanup based on another signal than BTA_JV_L2CAP_WRITE_EVT,
+ * which is typically not possible, as the pointer to the allocated buffer is stored
+ * in this message, and can therefore not be freed, hence we have a mem-leak-by-design.*/
+ if (ls->p_cb->p_cback != NULL) {
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = ls->handle;
+ evt_data.req_id = ls->req_id;
+ evt_data.cong = ls->p_cb->cong;
+ evt_data.len = 0;
+ bta_jv_pm_conn_busy(ls->p_cb->p_pm_cb);
+ if (!evt_data.cong &&
+ BT_PASS == GAP_ConnWriteData(ls->handle, ls->p_data, ls->len, &evt_data.len))
+ {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+ ls->p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, (tBTA_JV *)&evt_data, ls->user_data);
+ bta_jv_set_pm_conn_state(ls->p_cb->p_pm_cb, BTA_JV_CONN_IDLE);
+ } else {
+ /* As this pointer is checked in the API function, this occurs only when the channel is
+ * disconnected after the API function is called, but before the message is handled. */
+ APPL_TRACE_ERROR("%s() ls->p_cb->p_cback == NULL", __func__);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_write_fixed
+**
+** Description Write data to an L2CAP connection using Fixed channels
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_write_fixed(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2CAP_WRITE_FIXED evt_data;
+ tBTA_JV_API_L2CAP_WRITE_FIXED *ls = &(p_data->l2cap_write_fixed);
+ BT_HDR *msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + ls->len + L2CAP_MIN_OFFSET);
+ if (!msg)
+ {
+ APPL_TRACE_ERROR("%s() could not allocate msg buffer",__func__);
+ return;
+ }
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.channel = ls->channel;
+ memcpy(evt_data.addr, ls->addr, sizeof(evt_data.addr));
+ evt_data.req_id = ls->req_id;
+ evt_data.len = 0;
+
+
+ memcpy(((uint8_t*)(msg + 1)) + L2CAP_MIN_OFFSET, ls->p_data, ls->len);
+ msg->len = ls->len;
+ msg->offset = L2CAP_MIN_OFFSET;
+
+ L2CA_SendFixedChnlData(ls->channel, ls->addr, msg);
+
+ ls->p_cback(BTA_JV_L2CAP_WRITE_FIXED_EVT, (tBTA_JV *)&evt_data, ls->user_data);
+}
+
+/*******************************************************************************
+**
** Function bta_jv_port_data_co_cback
**
** Description port data callback function of rfcomm
@@ -703,8 +1446,7 @@ static int bta_jv_port_data_co_cback(UINT16 port_handle, UINT8 *buf, UINT16 len,
tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
int ret = 0;
- APPL_TRACE_DEBUG("bta_jv_port_data_co_cback, p_cb:%p, p_pcb:%p, len:%d, type:%d",
- p_cb, p_pcb, len, type);
+ APPL_TRACE_DEBUG("%s, p_cb:%p, p_pcb:%p, len:%d, type:%d", __func__, p_cb, p_pcb, len, type);
if (p_pcb != NULL)
{
switch(type)
@@ -797,7 +1539,7 @@ static void bta_jv_port_event_cl_cback(UINT32 code, UINT16 port_handle)
tBTA_JV evt_data;
APPL_TRACE_DEBUG( "bta_jv_port_event_cl_cback:%d", port_handle);
- if(NULL == p_cb || NULL == p_cb->p_cback)
+ if (NULL == p_cb || NULL == p_cb->p_cback)
return;
APPL_TRACE_DEBUG( "bta_jv_port_event_cl_cback code=x%x port_handle:%d handle:%d",
@@ -961,6 +1703,38 @@ void bta_jv_rfcomm_close(tBTA_JV_MSG *p_data)
/*******************************************************************************
**
+** Function bta_jv_get_num_rfc_listen
+**
+** Description when a RFCOMM connection goes down, make sure that there's only
+** one port stays listening on this scn.
+**
+** Returns
+**
+*******************************************************************************/
+static UINT8 bta_jv_get_num_rfc_listen(tBTA_JV_RFC_CB *p_cb)
+{
+ UINT8 listen=1;
+
+ if (p_cb->max_sess > 1)
+ {
+ listen = 0;
+ for (UINT8 i=0; i<p_cb->max_sess; i++)
+ {
+ if (p_cb->rfc_hdl[i] != 0)
+ {
+ const tBTA_JV_PCB *p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1];
+ if (BTA_JV_ST_SR_LISTEN == p_pcb->state)
+ {
+ listen++;
+ }
+ }
+ }
+ }
+ return listen;
+}
+
+/*******************************************************************************
+**
** Function bta_jv_port_mgmt_sr_cback
**
** Description callback for port mamangement function of rfcomm
@@ -979,7 +1753,7 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle)
UINT8 num;
UINT32 si;
APPL_TRACE_DEBUG("bta_jv_port_mgmt_sr_cback, code:%d, port_handle:%d", code, port_handle);
- if(NULL == p_cb || NULL == p_cb->p_cback)
+ if (NULL == p_cb || NULL == p_cb->p_cback)
{
APPL_TRACE_ERROR("bta_jv_port_mgmt_sr_cback, p_cb:%p, p_cb->p_cback%p",
p_cb, p_cb ? p_cb->p_cback : NULL);
@@ -1018,7 +1792,7 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle)
tBTA_JV_RFCOMM_CBACK *p_cback = p_cb->p_cback;
APPL_TRACE_DEBUG("PORT_CLOSED before BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
p_cb->curr_sess, p_cb->max_sess);
- if(BTA_JV_ST_SR_CLOSING == p_pcb->state)
+ if (BTA_JV_ST_SR_CLOSING == p_pcb->state)
{
evt_data.rfc_close.async = FALSE;
evt_data.rfc_close.status = BTA_JV_SUCCESS;
@@ -1047,7 +1821,7 @@ static void bta_jv_port_event_sr_cback(UINT32 code, UINT16 port_handle)
tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV evt_data;
- if(NULL == p_cb || NULL == p_cb->p_cback)
+ if (NULL == p_cb || NULL == p_cb->p_cback)
return;
APPL_TRACE_DEBUG( "bta_jv_port_event_sr_cback code=x%x port_handle:%d handle:%d",
@@ -1101,7 +1875,7 @@ static tBTA_JV_PCB * bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
if (p_pcb->state == BTA_JV_ST_SR_LISTEN)
{
listen++;
- if(p_pcb_open == p_pcb)
+ if (p_pcb_open == p_pcb)
{
APPL_TRACE_DEBUG("bta_jv_add_rfc_port, port_handle:%d, change the listen port to open state",
p_pcb->port_handle);
@@ -1208,7 +1982,7 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
- if(!p_cb)
+ if (!p_cb)
{
APPL_TRACE_ERROR("bta_jv_rfcomm_start_server, run out of rfc control block");
break;
@@ -1236,15 +2010,15 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
} while (0);
rs->p_cback(BTA_JV_RFCOMM_START_EVT, (tBTA_JV *)&evt_data, rs->user_data);
- if(evt_data.status == BTA_JV_SUCCESS)
+ if (evt_data.status == BTA_JV_SUCCESS)
{
PORT_SetDataCOCallback (handle, bta_jv_port_data_co_cback);
}
else
{
- if(sec_id)
+ if (sec_id)
bta_jv_free_sec_id(&sec_id);
- if(handle)
+ if (handle)
RFCOMM_RemoveConnection(handle);
}
}
@@ -1265,13 +2039,13 @@ void bta_jv_rfcomm_stop_server(tBTA_JV_MSG *p_data)
tBTA_JV_RFC_CB *p_cb = NULL;
tBTA_JV_PCB *p_pcb = NULL;
APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server");
- if(!ls->handle)
+ if (!ls->handle)
{
APPL_TRACE_ERROR("bta_jv_rfcomm_stop_server, jv handle is null");
return;
}
void* user_data = ls->user_data;
- if(!find_rfc_pcb(user_data, &p_cb, &p_pcb))
+ if (!find_rfc_pcb(user_data, &p_cb, &p_pcb))
return;
APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server: p_pcb:%p, p_pcb->port_handle:%d",
p_pcb, p_pcb->port_handle);
@@ -1535,3 +2309,420 @@ static void bta_jv_pm_state_change(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_STATE
break;
}
}
+/**********************************************************************************************/
+
+
+static struct fc_channel *fcchan_get(uint16_t chan, char create)
+{
+ struct fc_channel *t = fc_channels;
+ static tL2CAP_FIXED_CHNL_REG fcr = {
+ .pL2CA_FixedConn_Cb = fcchan_conn_chng_cbk,
+ .pL2CA_FixedData_Cb = fcchan_data_cbk,
+ .default_idle_tout = 0xffff,
+ .fixed_chnl_opts = {
+ .mode = L2CAP_FCR_BASIC_MODE,
+ .max_transmit = 0xFF,
+ .rtrans_tout = 2000,
+ .mon_tout = 12000,
+ .mps = 670,
+ .tx_win_sz = 1,
+ },
+ };
+
+ while (t && t->chan != chan)
+ t = t->next;
+
+ if (t)
+ return t;
+ else if (!create)
+ return NULL; /* we cannot alloc a struct if not asked to */
+
+ t = calloc(sizeof(*t), 1);
+ if (!t)
+ return NULL;
+
+ t->chan = chan;
+
+ if (!L2CA_RegisterFixedChannel(chan, &fcr)) {
+ free(t);
+ return NULL;
+ }
+
+ //link it in
+ t->next = fc_channels;
+ fc_channels = t;
+
+ return t;
+}
+
+/* pass NULL to find servers */
+static struct fc_client *fcclient_find_by_addr(struct fc_client *start, BD_ADDR addr)
+{
+ struct fc_client *t = start;
+
+ while (t) {
+
+ /* match client if have addr */
+ if (addr && !memcmp(addr, &t->remote_addr, sizeof(t->remote_addr)))
+ break;
+
+ /* match server if do not have addr */
+ if (!addr && t->server)
+ break;
+
+ t = t->next_all_list;
+ }
+
+ return t;
+}
+
+static struct fc_client *fcclient_find_by_id(uint32_t id)
+{
+ struct fc_client *t = fc_clients;
+
+ while (t && t->id != id)
+ t = t->next_all_list;
+
+ return t;
+}
+
+static struct fc_client *fcclient_alloc(uint16_t chan, char server, const uint8_t *sec_id_to_use)
+{
+ struct fc_channel *fc = fcchan_get(chan, TRUE);
+ struct fc_client *t;
+ uint8_t sec_id;
+
+ if (!fc)
+ return NULL;
+
+ if (fc->has_server && server)
+ return NULL; /* no way to have multiple servers on same channel */
+
+ if (sec_id_to_use)
+ sec_id = *sec_id_to_use;
+ else
+ sec_id = bta_jv_alloc_sec_id();
+
+ t = calloc(sizeof(*t), 1);
+ if (t) {
+ //allocate it a unique ID
+ do {
+ t->id = ++fc_next_id;
+ } while (!t->id || fcclient_find_by_id(t->id));
+
+ //populate some params
+ t->chan = chan;
+ t->server = server;
+
+ //get a security id
+ t->sec_id = sec_id;
+
+ //link it in to global list
+ t->next_all_list = fc_clients;
+ fc_clients = t;
+
+ //link it in to channel list
+ t->next_chan_list = fc->clients;
+ fc->clients = t;
+
+ //update channel if needed
+ if (server)
+ fc->has_server = TRUE;
+ } else if (!sec_id_to_use)
+ bta_jv_free_sec_id(&sec_id);
+
+ return t;
+}
+
+static void fcclient_free(struct fc_client *fc)
+{
+ struct fc_client *t = fc_clients;
+ struct fc_channel *tc = fcchan_get(fc->chan, FALSE);
+
+ //remove from global list
+ while (t && t->next_all_list != fc)
+ t = t->next_all_list;
+
+ if (!t && fc != fc_clients)
+ return; /* prevent double-free */
+
+ if (t)
+ t->next_all_list = fc->next_all_list;
+ else
+ fc_clients = fc->next_all_list;
+
+ //remove from channel list
+ if (tc) {
+ t = tc->clients;
+
+ while (t && t->next_chan_list != fc)
+ t = t->next_chan_list;
+
+ if (t)
+ t->next_chan_list = fc->next_chan_list;
+ else
+ tc->clients = fc->next_chan_list;
+
+ //if was server then channel no longer has a server
+ if (fc->server)
+ tc->has_server = FALSE;
+ }
+
+ //free security id
+ bta_jv_free_sec_id(&fc->sec_id);
+
+ free(fc);
+}
+
+static void fcchan_conn_chng_cbk(UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport)
+{
+ tBTA_JV init_evt;
+ tBTA_JV open_evt;
+ struct fc_channel *tc;
+ struct fc_client *t = NULL, *new_conn;
+ tBTA_JV_L2CAP_CBACK *p_cback = NULL;
+ char call_init = FALSE;
+ void *user_data = NULL;
+
+
+ tc = fcchan_get(chan, FALSE);
+ if (tc) {
+ t = fcclient_find_by_addr(tc->clients, bd_addr); // try to find an open socked for that addr
+ if (t) {
+ p_cback = t->p_cback;
+ user_data = t->user_data;
+ } else {
+ t = fcclient_find_by_addr(tc->clients, NULL); // try to find a listening socked for that channel
+ if (t) {
+ //found: create a normal connection socket and assign the connection to it
+ new_conn = fcclient_alloc(chan, FALSE, &t->sec_id);
+ if (new_conn){
+
+ memcpy(&new_conn->remote_addr, bd_addr, sizeof(new_conn->remote_addr));
+ new_conn->p_cback = NULL; //for now
+ new_conn->init_called = TRUE; /*nop need to do it again */
+
+ p_cback = t->p_cback;
+ user_data = t->user_data;
+
+ t = new_conn;
+ }
+ } else {
+ //drop it
+ return;
+ }
+ }
+ }
+
+ if (t) {
+
+ if (!t->init_called) {
+
+ call_init = TRUE;
+ t->init_called = TRUE;
+
+ init_evt.l2c_cl_init.handle = t->id;
+ init_evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+ init_evt.l2c_cl_init.sec_id = t->sec_id;
+ }
+
+ open_evt.l2c_open.handle = t->id;
+ open_evt.l2c_open.tx_mtu = 23; /* 23, why not ?*/
+ memcpy(&open_evt.l2c_le_open.rem_bda, &t->remote_addr, sizeof(open_evt.l2c_le_open.rem_bda));
+ open_evt.l2c_le_open.p_p_cback = (void**)&t->p_cback;
+ open_evt.l2c_le_open.p_user_data = &t->user_data;
+ open_evt.l2c_le_open.status = BTA_JV_SUCCESS;
+
+ if (connected) {
+ open_evt.l2c_open.status = BTA_JV_SUCCESS;
+ } else {
+ fcclient_free(t);
+ open_evt.l2c_open.status = BTA_JV_FAILURE;
+ }
+ }
+
+ if (call_init)
+ p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &init_evt, user_data);
+
+ //call this with lock taken so socket does not disappear from under us */
+ if (p_cback) {
+ p_cback(BTA_JV_L2CAP_OPEN_EVT, &open_evt, user_data);
+ if (!t->p_cback) /* no callback set, means they do not want this one... */
+ fcclient_free(t);
+ }
+}
+
+static void fcchan_data_cbk(UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+ tBTA_JV evt_data;
+ tBTA_JV evt_open;
+ struct fc_channel *tc;
+ struct fc_client *t = NULL;
+ tBTA_JV_L2CAP_CBACK *sock_cback = NULL;
+ void *sock_user_data;
+
+ tc = fcchan_get(chan, FALSE);
+ if (tc) {
+ t = fcclient_find_by_addr(tc->clients, bd_addr); // try to find an open socked for that addr and channel
+ if (!t) {
+ //no socket -> drop it
+ return;
+ }
+ }
+
+ sock_cback = t->p_cback;
+ sock_user_data = t->user_data;
+ evt_data.le_data_ind.handle = t->id;
+ evt_data.le_data_ind.p_buf = p_buf;
+
+ if (sock_cback)
+ sock_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, sock_user_data);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_connect_le
+**
+** Description makes an le l2cap client connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_connect_le(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_API_L2CAP_CONNECT *cc = &(p_data->l2cap_connect);
+ tBTA_JV evt;
+ uint32_t id;
+ char call_init_f = TRUE;
+ struct fc_client *t;
+
+ evt.l2c_cl_init.handle = GAP_INVALID_HANDLE;
+ evt.l2c_cl_init.status = BTA_JV_FAILURE;
+
+ t = fcclient_alloc(cc->remote_chan, FALSE, NULL);
+ if (!t) {
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
+ return;
+ }
+
+ t->p_cback = cc->p_cback;
+ t->user_data = cc->user_data;
+ memcpy(&t->remote_addr, &cc->peer_bd_addr, sizeof(t->remote_addr));
+ id = t->id;
+ t->init_called = FALSE;
+
+ if (L2CA_ConnectFixedChnl(t->chan, t->remote_addr)) {
+
+ evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+ evt.l2c_cl_init.handle = id;
+ }
+
+ //it could have been deleted/moved from under us, so re-find it */
+ t = fcclient_find_by_id(id);
+ if (t) {
+ if (evt.l2c_cl_init.status == BTA_JV_SUCCESS)
+ call_init_f = !t->init_called;
+ else
+ fcclient_free(t);
+ }
+ if (call_init_f)
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
+ t->init_called = TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_stop_server_le
+**
+** Description stops an LE L2CAP server
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV evt;
+ tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
+ tBTA_JV_L2CAP_CBACK *p_cback = NULL;
+ struct fc_channel *fcchan;
+ struct fc_client *fcclient;
+ void *user_data;
+
+ evt.l2c_close.status = BTA_JV_FAILURE;
+ evt.l2c_close.async = FALSE;
+ evt.l2c_close.handle = GAP_INVALID_HANDLE;
+
+ fcchan = fcchan_get(ls->local_chan, FALSE);
+ if (fcchan) {
+ while((fcclient = fcchan->clients)) {
+ p_cback = fcclient->p_cback;
+ user_data = fcclient->user_data;
+
+ evt.l2c_close.handle = fcclient->id;
+ evt.l2c_close.status = BTA_JV_SUCCESS;
+ evt.l2c_close.async = FALSE;
+
+ fcclient_free(fcclient);
+
+ if (p_cback)
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt, user_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_start_server_le
+**
+** Description starts an LE L2CAP server
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_start_server_le(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_API_L2CAP_SERVER *ss = &(p_data->l2cap_server);
+ tBTA_JV_L2CAP_START evt_data;
+ struct fc_client *t;
+ uint16_t handle;
+
+ evt_data.handle = GAP_INVALID_HANDLE;
+ evt_data.status = BTA_JV_FAILURE;
+
+
+ t = fcclient_alloc(ss->local_chan, TRUE, NULL);
+ if (!t)
+ goto out;
+
+ t->p_cback = ss->p_cback;
+ t->user_data = ss->user_data;
+
+ //if we got here, we're registered...
+ evt_data.status = BTA_JV_SUCCESS;
+ evt_data.handle = t->id;
+ evt_data.sec_id = t->sec_id;
+
+out:
+ ss->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data, ss->user_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_close_fixed
+**
+** Description close a fixed channel connection. calls no callbacks. idempotent
+**
+** Returns void
+**
+*******************************************************************************/
+extern void bta_jv_l2cap_close_fixed (tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_API_L2CAP_CLOSE *cc = &(p_data->l2cap_close);
+ struct fc_client *t;
+
+ t = fcclient_find_by_id(cc->handle);
+ if (t)
+ fcclient_free(t);
+}
diff --git a/bta/jv/bta_jv_api.c b/bta/jv/bta_jv_api.c
index a242f455b..41506cdee 100644
--- a/bta/jv/bta_jv_api.c
+++ b/bta/jv/bta_jv_api.c
@@ -31,6 +31,7 @@
#include "port_api.h"
#include "sdp_api.h"
#include "utl.h"
+#include "gap_api.h"
/*****************************************************************************
** Constants
@@ -150,6 +151,78 @@ BOOLEAN BTA_JvIsEncrypted(BD_ADDR bd_addr)
}
return is_encrypted;
}
+/*******************************************************************************
+**
+** Function BTA_JvGetChannelId
+**
+** Description This function reserves a SCN (server channel number) for
+** applications running over RFCOMM, L2CAP of L2CAP_LE.
+** It is primarily called by server profiles/applications to
+** register their SCN into the SDP database. The SCN is reported
+** by the tBTA_JV_DM_CBACK callback with a BTA_JV_GET_SCN_EVT
+** for RFCOMM channels and BTA_JV_GET_PSM_EVT for L2CAP and LE.
+** If the SCN/PSM reported is 0, that means all resources are
+** exhausted.
+** Parameters
+** conn_type one of BTA_JV_CONN_TYPE_
+** user_data Any uservalue - will be returned in the resulting event.
+** channel Only used for RFCOMM - to try to allocate a specific RFCOMM
+** channel.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void* user_data, INT32 channel)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_ALLOC_CHANNEL *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+ if ((p_msg = (tBTA_JV_API_ALLOC_CHANNEL *)GKI_getbuf(sizeof(tBTA_JV_API_ALLOC_CHANNEL))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_GET_CHANNEL_EVT;
+ p_msg->type = conn_type;
+ p_msg->channel = channel;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvFreeChannel
+**
+** Description This function frees a server channel number that was used
+** by an application running over RFCOMM.
+** Parameters
+** channel The channel to free
+** conn_type one of BTA_JV_CONN_TYPE_
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvFreeChannel(UINT16 channel, int conn_type)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_FREE_CHANNEL *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+ if ((p_msg = (tBTA_JV_API_FREE_CHANNEL *)GKI_getbuf(sizeof(tBTA_JV_API_FREE_CHANNEL))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_FREE_SCN_EVT;
+ p_msg->scn = channel;
+ p_msg->type = conn_type;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
/*******************************************************************************
**
@@ -243,6 +316,537 @@ tBTA_JV_STATUS BTA_JvDeleteRecord(UINT32 handle)
/*******************************************************************************
**
+** Function BTA_JvL2capConnectLE
+**
+** Description Initiate an LE connection as a L2CAP client to the given BD
+** Address.
+** When the connection is initiated or failed to initiate,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+** When the connection is established or failed,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_chan,
+ UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_CONNECT *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (p_cback &&
+ (p_msg =
+ (tBTA_JV_API_L2CAP_CONNECT *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CONNECT))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_LE_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->remote_chan = remote_chan;
+ p_msg->rx_mtu = rx_mtu;
+ if(cfg != NULL) {
+ p_msg->has_cfg = TRUE;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = FALSE;
+ }
+ if(ertm_info != NULL) {
+ p_msg->has_ertm_info = TRUE;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = FALSE;
+ }
+ memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+ p_msg->p_cback = p_cback;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capConnect
+**
+** Description Initiate a connection as a L2CAP client to the given BD
+** Address.
+** When the connection is initiated or failed to initiate,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+** When the connection is established or failed,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_psm,
+ UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_CONNECT *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_CONNECT *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CONNECT))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->remote_psm = remote_psm;
+ p_msg->rx_mtu = rx_mtu;
+ if(cfg != NULL) {
+ p_msg->has_cfg = TRUE;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = FALSE;
+ }
+ if(ertm_info != NULL) {
+ p_msg->has_ertm_info = TRUE;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = FALSE;
+ }
+ memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+ p_msg->p_cback = p_cback;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capClose
+**
+** Description This function closes an L2CAP client connection
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_CLOSE *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_CLOSE *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CLOSE))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_EVT;
+ p_msg->handle = handle;
+ p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capCloseLE
+**
+** Description This function closes an L2CAP client connection for Fixed Channels
+** Function is idempotent and no callbacks are called!
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capCloseLE(UINT32 handle)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_CLOSE *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if ((p_msg = (tBTA_JV_API_L2CAP_CLOSE *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CLOSE))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_FIXED_EVT;
+ p_msg->handle = handle;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStartServer
+**
+** Description This function starts an L2CAP server and listens for an L2CAP
+** connection from a remote Bluetooth device. When the server
+** is started successfully, tBTA_JV_L2CAP_CBACK is called with
+** BTA_JV_L2CAP_START_EVT. When the connection is established,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info,UINT16 local_psm, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->local_psm = local_psm;
+ p_msg->rx_mtu = rx_mtu;
+ if(cfg != NULL) {
+ p_msg->has_cfg = TRUE;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = FALSE;
+ }
+ if(ertm_info != NULL) {
+ p_msg->has_ertm_info = TRUE;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = FALSE;
+ }
+ p_msg->p_cback = p_cback;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStartServerLE
+**
+** Description This function starts an LE L2CAP server and listens for an L2CAP
+** connection from a remote Bluetooth device. When the server
+** is started successfully, tBTA_JV_L2CAP_CBACK is called with
+** BTA_JV_L2CAP_START_EVT. When the connection is established,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info,UINT16 local_chan, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_LE_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->local_chan = local_chan;
+ p_msg->rx_mtu = rx_mtu;
+ if(cfg != NULL) {
+ p_msg->has_cfg = TRUE;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = FALSE;
+ }
+ if(ertm_info != NULL) {
+ p_msg->has_ertm_info = TRUE;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = FALSE;
+ }
+ p_msg->p_cback = p_cback;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStopServer
+**
+** Description This function stops the L2CAP server. If the server has an
+** active connection, it would be closed.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServer(UINT16 local_psm, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if ((p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_EVT;
+ p_msg->local_psm = local_psm;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStopServerLE
+**
+** Description This function stops the LE L2CAP server. If the server has an
+** active connection, it would be closed.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServerLE(UINT16 local_chan, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if ((p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT;
+ p_msg->local_chan = local_chan;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capRead
+**
+** Description This function reads data from an L2CAP connecti;
+ tBTA_JV_RFC_CB *p_cb = rc->p_cb;
+on
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_READ_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_L2CAP_READ evt_data;
+
+ APPL_TRACE_API( "%s", __func__);
+
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback)
+ {
+ status = BTA_JV_SUCCESS;
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = handle;
+ evt_data.req_id = req_id;
+ evt_data.p_data = p_data;
+ evt_data.len = 0;
+
+ if (BT_PASS == GAP_ConnReadData((UINT16)handle, p_data, len, &evt_data.len))
+ {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+ bta_jv_cb.l2c_cb[handle].p_cback(
+ BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data, bta_jv_cb.l2c_cb[handle].user_data);
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capReceive
+**
+** Description This function reads data from an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_RECEIVE_EVT.
+** If there are more data queued in L2CAP than len, the extra data will be discarded.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReceive(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_L2CAP_RECEIVE evt_data;
+ UINT32 left_over = 0;
+ UINT16 max_len, read_len;
+
+ APPL_TRACE_API( "%s", __func__);
+
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback)
+ {
+ status = BTA_JV_SUCCESS;
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = handle;
+ evt_data.req_id = req_id;
+ evt_data.p_data = p_data;
+ evt_data.len = 0;
+
+ if (BT_PASS == GAP_ConnReadData((UINT16)handle, p_data, len, &evt_data.len))
+ {
+ evt_data.status = BTA_JV_SUCCESS;
+ GAP_GetRxQueueCnt ((UINT16)handle, &left_over);
+ while (left_over)
+ {
+ max_len = (left_over > 0xFFFF)?0xFFFF:left_over;
+ GAP_ConnReadData ((UINT16)handle, NULL, max_len, &read_len);
+ left_over -= read_len;
+ }
+ }
+ bta_jv_cb.l2c_cb[handle].p_cback(
+ BTA_JV_L2CAP_RECEIVE_EVT, (tBTA_JV *)&evt_data, bta_jv_cb.l2c_cb[handle].user_data);
+ }
+
+ return(status);
+}
+/*******************************************************************************
+**
+** Function BTA_JvL2capReady
+**
+** Description This function determined if there is data to read from
+** an L2CAP connection
+**
+** Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+** BTA_JV_FAILURE, if error.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReady(UINT32 handle, UINT32 *p_data_size)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+ APPL_TRACE_API( "%s: %d", __func__, handle);
+ if (p_data_size && handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback)
+ {
+ *p_data_size = 0;
+ if(BT_PASS == GAP_GetRxQueueCnt((UINT16)handle, p_data_size) )
+ {
+ status = BTA_JV_SUCCESS;
+ }
+ }
+
+ return(status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capWrite
+**
+** Description This function writes data to an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_WRITE_EVT. Works for
+** PSM-based connections
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWrite(UINT32 handle, UINT32 req_id, UINT8 *p_data,
+ UINT16 len, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_WRITE *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_WRITE *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_WRITE))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_EVT;
+ p_msg->handle = handle;
+ p_msg->req_id = req_id;
+ p_msg->p_data = p_data;
+ p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+ p_msg->len = len;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capWriteFixed
+**
+** Description This function writes data to an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_WRITE_EVT. Works for
+** fixed-channel connections
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT32 req_id,
+ tBTA_JV_L2CAP_CBACK *p_cback, UINT8 *p_data, UINT16 len, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_WRITE_FIXED *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if ((p_msg =
+ (tBTA_JV_API_L2CAP_WRITE_FIXED *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_WRITE_FIXED))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_FIXED_EVT;
+ p_msg->channel = channel;
+ memcpy(p_msg->addr, addr, sizeof(p_msg->addr));
+ p_msg->req_id = req_id;
+ p_msg->p_data = p_data;
+ p_msg->p_cback = p_cback;
+ p_msg->len = len;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
** Function BTA_JvRfcommConnect
**
** Description This function makes an RFCOMM conection to a remote BD
diff --git a/bta/jv/bta_jv_int.h b/bta/jv/bta_jv_int.h
index a76664704..eaaa75ca0 100644
--- a/bta/jv/bta_jv_int.h
+++ b/bta/jv/bta_jv_int.h
@@ -39,9 +39,17 @@ enum
/* these events are handled by the state machine */
BTA_JV_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_JV),
BTA_JV_API_DISABLE_EVT,
+ BTA_JV_API_GET_CHANNEL_EVT,
+ BTA_JV_API_FREE_SCN_EVT,
BTA_JV_API_START_DISCOVERY_EVT,
BTA_JV_API_CREATE_RECORD_EVT,
BTA_JV_API_DELETE_RECORD_EVT,
+ BTA_JV_API_L2CAP_CONNECT_EVT,
+ BTA_JV_API_L2CAP_CLOSE_EVT,
+ BTA_JV_API_L2CAP_START_SERVER_EVT,
+ BTA_JV_API_L2CAP_STOP_SERVER_EVT,
+ BTA_JV_API_L2CAP_READ_EVT,
+ BTA_JV_API_L2CAP_WRITE_EVT,
BTA_JV_API_RFCOMM_CONNECT_EVT,
BTA_JV_API_RFCOMM_CLOSE_EVT,
BTA_JV_API_RFCOMM_START_SERVER_EVT,
@@ -50,6 +58,11 @@ enum
BTA_JV_API_RFCOMM_WRITE_EVT,
BTA_JV_API_SET_PM_PROFILE_EVT,
BTA_JV_API_PM_STATE_CHANGE_EVT,
+ BTA_JV_API_L2CAP_CONNECT_LE_EVT,
+ BTA_JV_API_L2CAP_START_SERVER_LE_EVT,
+ BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT,
+ BTA_JV_API_L2CAP_WRITE_FIXED_EVT,
+ BTA_JV_API_L2CAP_CLOSE_FIXED_EVT,
BTA_JV_MAX_INT_EVT
};
@@ -104,6 +117,18 @@ enum
} ;
typedef UINT8 tBTA_JV_STATE;
#define BTA_JV_ST_CL_MAX BTA_JV_ST_CL_CLOSING
+/* JV L2CAP control block */
+typedef struct
+{
+ tBTA_JV_L2CAP_CBACK *p_cback; /* the callback function */
+ UINT16 psm; /* the psm used for this server connection */
+ tBTA_JV_STATE state; /* the state of this control block */
+ tBTA_SERVICE_ID sec_id; /* service id */
+ UINT32 handle; /* the handle reported to java app (same as gap handle) */
+ BOOLEAN cong; /* TRUE, if congested */
+ tBTA_JV_PM_CB *p_pm_cb; /* ptr to pm control block, NULL: unused */
+ void *user_data; /* user data for callback from higher layers */
+} tBTA_JV_L2C_CB;
#define BTA_JV_RFC_HDL_MASK 0xFF
#define BTA_JV_RFCOMM_MASK 0x80
@@ -115,12 +140,12 @@ typedef UINT8 tBTA_JV_STATE;
typedef struct
{
UINT32 handle; /* the rfcomm session handle at jv */
- UINT16 port_handle; /* port handle */
+ UINT16 port_handle;/* port handle */
tBTA_JV_STATE state; /* the state of this control block */
UINT8 max_sess; /* max sessions */
void *user_data; /* piggyback caller's private data*/
BOOLEAN cong; /* TRUE, if congested */
- tBTA_JV_PM_CB *p_pm_cb; /* ptr to pm control block, NULL: unused */
+ tBTA_JV_PM_CB *p_pm_cb; /* ptr to pm control block, NULL: unused */
} tBTA_JV_PCB;
/* JV RFCOMM control block */
@@ -135,6 +160,90 @@ typedef struct
int curr_sess; /* current sessions count*/
} tBTA_JV_RFC_CB;
+/* data type for BTA_JV_API_L2CAP_CONNECT_EVT & BTA_JV_API_L2CAP_CONNECT_LE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SEC sec_mask;
+ tBTA_JV_ROLE role;
+ union {
+ UINT16 remote_psm;
+ UINT16 remote_chan;
+ };
+ UINT16 rx_mtu;
+ BD_ADDR peer_bd_addr;
+ INT32 has_cfg;
+ tL2CAP_CFG_INFO cfg;
+ INT32 has_ertm_info;
+ tL2CAP_ERTM_INFO ertm_info;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+} tBTA_JV_API_L2CAP_CONNECT;
+
+/* data type for BTA_JV_API_L2CAP_SERVER_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SEC sec_mask;
+ tBTA_JV_ROLE role;
+ union {
+ UINT16 local_psm;
+ UINT16 local_chan;
+ };
+ UINT16 rx_mtu;
+ INT32 has_cfg;
+ tL2CAP_CFG_INFO cfg;
+ INT32 has_ertm_info;
+ tL2CAP_ERTM_INFO ertm_info;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+} tBTA_JV_API_L2CAP_SERVER;
+
+/* data type for BTA_JV_API_L2CAP_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 handle;
+ tBTA_JV_L2C_CB *p_cb;
+} tBTA_JV_API_L2CAP_CLOSE;
+
+/* data type for BTA_JV_API_L2CAP_READ_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 handle;
+ UINT32 req_id;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ UINT8* p_data;
+ UINT16 len;
+ void *user_data;
+} tBTA_JV_API_L2CAP_READ;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 handle;
+ UINT32 req_id;
+ tBTA_JV_L2C_CB *p_cb;
+ UINT8 *p_data;
+ UINT16 len;
+ void *user_data;
+} tBTA_JV_API_L2CAP_WRITE;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 channel;
+ BD_ADDR addr;
+ UINT32 req_id;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ UINT8 *p_data;
+ UINT16 len;
+ void *user_data;
+} tBTA_JV_API_L2CAP_WRITE_FIXED;
+
/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */
typedef struct
{
@@ -196,7 +305,7 @@ typedef struct
UINT32 handle;
UINT32 req_id;
UINT8 *p_data;
- int len;
+ int len;
tBTA_JV_RFC_CB *p_cb;
tBTA_JV_PCB *p_pcb;
} tBTA_JV_API_RFCOMM_WRITE;
@@ -208,7 +317,7 @@ typedef struct
UINT32 handle;
tBTA_JV_RFC_CB *p_cb;
tBTA_JV_PCB *p_pcb;
- void *user_data;
+ void *user_data;
} tBTA_JV_API_RFCOMM_CLOSE;
/* data type for BTA_JV_API_CREATE_RECORD_EVT */
@@ -228,6 +337,22 @@ typedef struct
INT32 value_size;
} tBTA_JV_API_ADD_ATTRIBUTE;
+/* data type for BTA_JV_API_FREE_SCN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ INT32 type; /* One of BTA_JV_CONN_TYPE_ */
+ UINT16 scn;
+} tBTA_JV_API_FREE_CHANNEL;
+
+/* data type for BTA_JV_API_ALLOC_CHANNEL_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ INT32 type; /* One of BTA_JV_CONN_TYPE_ */
+ INT32 channel; /* optionally request a specific channel */
+ void *user_data;
+} tBTA_JV_API_ALLOC_CHANNEL;
/* union of all data types */
typedef union
{
@@ -235,8 +360,15 @@ typedef union
BT_HDR hdr;
tBTA_JV_API_ENABLE enable;
tBTA_JV_API_START_DISCOVERY start_discovery;
+ tBTA_JV_API_ALLOC_CHANNEL alloc_channel;
+ tBTA_JV_API_FREE_CHANNEL free_channel;
tBTA_JV_API_CREATE_RECORD create_record;
tBTA_JV_API_ADD_ATTRIBUTE add_attr;
+ tBTA_JV_API_L2CAP_CONNECT l2cap_connect;
+ tBTA_JV_API_L2CAP_READ l2cap_read;
+ tBTA_JV_API_L2CAP_WRITE l2cap_write;
+ tBTA_JV_API_L2CAP_CLOSE l2cap_close;
+ tBTA_JV_API_L2CAP_SERVER l2cap_server;
tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
tBTA_JV_API_RFCOMM_READ rfcomm_read;
tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
@@ -244,6 +376,7 @@ typedef union
tBTA_JV_API_PM_STATE_CHANGE change_pm_state;
tBTA_JV_API_RFCOMM_CLOSE rfcomm_close;
tBTA_JV_API_RFCOMM_SERVER rfcomm_server;
+ tBTA_JV_API_L2CAP_WRITE_FIXED l2cap_write_fixed;
} tBTA_JV_MSG;
/* JV control block */
@@ -255,9 +388,14 @@ typedef struct
UINT32 sdp_handle[BTA_JV_MAX_SDP_REC]; /* SDP records created */
UINT8 *p_sel_raw_data;/* the raw data of last service select */
tBTA_JV_DM_CBACK *p_dm_cback;
+ tBTA_JV_L2C_CB l2c_cb[BTA_JV_MAX_L2C_CONN]; /* index is GAP handle (index) */
tBTA_JV_RFC_CB rfc_cb[BTA_JV_MAX_RFC_CONN];
- tBTA_JV_PCB port_cb[MAX_RFC_PORTS]; /* index of this array is the port_handle, */
+ tBTA_JV_PCB port_cb[MAX_RFC_PORTS]; /* index of this array is
+ the port_handle, */
UINT8 sec_id[BTA_JV_NUM_SERVICE_ID]; /* service ID */
+ BOOLEAN scn[BTA_JV_MAX_SCN]; /* SCN allocated by java */
+ UINT16 free_psm_list[BTA_JV_MAX_L2C_CONN]; /* PSMs freed by java
+ (can be reused) */
UINT8 sdp_active; /* see BTA_JV_SDP_ACT_* */
tSDP_UUID uuid; /* current uuid of sdp discovery*/
tBTA_JV_PM_CB pm_cb[BTA_JV_PM_MAX_NUM]; /* PM on a per JV handle bases */
@@ -285,9 +423,17 @@ extern BOOLEAN bta_jv_sm_execute(BT_HDR *p_msg);
extern void bta_jv_enable (tBTA_JV_MSG *p_data);
extern void bta_jv_disable (tBTA_JV_MSG *p_data);
+extern void bta_jv_get_channel_id (tBTA_JV_MSG *p_data);
+extern void bta_jv_free_scn (tBTA_JV_MSG *p_data);
extern void bta_jv_start_discovery (tBTA_JV_MSG *p_data);
extern void bta_jv_create_record (tBTA_JV_MSG *p_data);
extern void bta_jv_delete_record (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_connect (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_close (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_start_server (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_stop_server (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_read (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_write (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_connect (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_close (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_start_server (tBTA_JV_MSG *p_data);
@@ -296,5 +442,10 @@ extern void bta_jv_rfcomm_read (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_write (tBTA_JV_MSG *p_data);
extern void bta_jv_set_pm_profile (tBTA_JV_MSG *p_data);
extern void bta_jv_change_pm_state(tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_connect_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_start_server_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_stop_server_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_write_fixed (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_close_fixed (tBTA_JV_MSG *p_data);
#endif /* BTA_JV_INT_H */
diff --git a/bta/jv/bta_jv_main.c b/bta/jv/bta_jv_main.c
index 97e2b818e..eb22338f7 100644
--- a/bta/jv/bta_jv_main.c
+++ b/bta/jv/bta_jv_main.c
@@ -46,9 +46,17 @@ const tBTA_JV_ACTION bta_jv_action[] =
{
bta_jv_enable, /* BTA_JV_API_ENABLE_EVT */
bta_jv_disable, /* BTA_JV_API_DISABLE_EVT */
+ bta_jv_get_channel_id, /* BTA_JV_API_GET_CHANNEL_EVT */
+ bta_jv_free_scn, /* BTA_JV_API_FREE_SCN_EVT */
bta_jv_start_discovery, /* BTA_JV_API_START_DISCOVERY_EVT */
bta_jv_create_record, /* BTA_JV_API_CREATE_RECORD_EVT */
bta_jv_delete_record, /* BTA_JV_API_DELETE_RECORD_EVT */
+ bta_jv_l2cap_connect, /* BTA_JV_API_L2CAP_CONNECT_EVT */
+ bta_jv_l2cap_close, /* BTA_JV_API_L2CAP_CLOSE_EVT */
+ bta_jv_l2cap_start_server, /* BTA_JV_API_L2CAP_START_SERVER_EVT */
+ bta_jv_l2cap_stop_server, /* BTA_JV_API_L2CAP_STOP_SERVER_EVT */
+ bta_jv_l2cap_read, /* BTA_JV_API_L2CAP_READ_EVT */
+ bta_jv_l2cap_write, /* BTA_JV_API_L2CAP_WRITE_EVT */
bta_jv_rfcomm_connect, /* BTA_JV_API_RFCOMM_CONNECT_EVT */
bta_jv_rfcomm_close, /* BTA_JV_API_RFCOMM_CLOSE_EVT */
bta_jv_rfcomm_start_server, /* BTA_JV_API_RFCOMM_START_SERVER_EVT */
@@ -57,6 +65,11 @@ const tBTA_JV_ACTION bta_jv_action[] =
bta_jv_rfcomm_write, /* BTA_JV_API_RFCOMM_WRITE_EVT */
bta_jv_set_pm_profile, /* BTA_JV_API_SET_PM_PROFILE_EVT */
bta_jv_change_pm_state, /* BTA_JV_API_PM_STATE_CHANGE_EVT */
+ bta_jv_l2cap_connect_le, /* BTA_JV_API_L2CAP_CONNECT_LE_EVT */
+ bta_jv_l2cap_start_server_le, /* BTA_JV_API_L2CAP_START_SERVER_LE_EVT */
+ bta_jv_l2cap_stop_server_le, /* BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT */
+ bta_jv_l2cap_write_fixed, /* BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+ bta_jv_l2cap_close_fixed, /* BTA_JV_API_L2CAP_CLOSE_FIXED_EVT */
};
/*******************************************************************************
diff --git a/bta/sdp/bta_sdp.c b/bta/sdp/bta_sdp.c
new file mode 100644
index 000000000..e1a2995cf
--- /dev/null
+++ b/bta/sdp/bta_sdp.c
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+
+ * 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 is the main implementation file for the BTA MCE I/F
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_SDP_CB bta_sdp_cb;
+#endif
+
+/* state machine action enumeration list */
+#define BTA_SDP_NUM_ACTIONS (BTA_SDP_MAX_INT_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_SDP_ACTION)(tBTA_SDP_MSG *p_data);
+
+/* action function list */
+const tBTA_SDP_ACTION bta_sdp_action[] =
+{
+ bta_sdp_enable, /* BTA_SDP_API_ENABLE_EVT */
+ bta_sdp_search, /* BTA_SDP_API_SEARCH_EVT */
+ bta_sdp_create_record, /* BTA_SDP_API_CREATE_RECORD_USER_EVT */
+ bta_sdp_remove_record, /* BTA_SDP_API_REMOVE_RECORD_USER_EVT */
+};
+
+/*******************************************************************************
+** Function bta_sdp_sm_execute
+**
+** Description State machine event handling function for SDP search
+**
+** Returns void
+*******************************************************************************/
+BOOLEAN bta_sdp_sm_execute(BT_HDR *p_msg)
+{
+ if(p_msg == NULL) return FALSE;
+
+ BOOLEAN ret = FALSE;
+ UINT16 action = (p_msg->event & 0x00ff);
+
+ /* execute action functions */
+ if(action < BTA_SDP_NUM_ACTIONS)
+ {
+ (*bta_sdp_action[action])((tBTA_SDP_MSG*)p_msg);
+ ret = TRUE;
+ }
+
+ return(ret);
+}
diff --git a/bta/sdp/bta_sdp_act.c b/bta/sdp/bta_sdp_act.c
new file mode 100644
index 000000000..e45042ce2
--- /dev/null
+++ b/bta/sdp/bta_sdp_act.c
@@ -0,0 +1,570 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 action functions for SDP search.
+ ******************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+#include <arpa/inet.h>
+
+#include "bt_types.h"
+#include "gki.h"
+#include "utl.h"
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "sdp_api.h"
+#include <string.h>
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_MAP_MNS[] = {0x00, 0x00, 0x11, 0x33, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_SPP[] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+
+// TODO:
+// Both the fact that the UUIDs are declared in multiple places, plus the fact
+// that there is a mess of UUID comparison and shortening methods will have to
+// be fixed.
+// The btcore->uuid module should be used for all instances.
+
+#define UUID_MAX_LENGTH 16
+#define IS_UUID(u1,u2) !memcmp(u1,u2,UUID_MAX_LENGTH)
+
+static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u)
+{
+ static uint8_t bt_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
+
+ APPL_TRACE_DEBUG("uuid len:%d", u->len);
+ if(u->len != 16)
+ return *u;
+
+ if(memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) != 0)
+ return *u;
+
+ tBT_UUID su;
+ memset(&su, 0, sizeof(su));
+ if(u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0)
+ {
+ su.len = 2;
+ uint16_t u16;
+ memcpy(&u16, &u->uu.uuid128[2], sizeof(u16));
+ su.uu.uuid16 = ntohs(u16);
+ } else {
+ su.len = 4;
+ uint32_t u32;
+ memcpy(&u32, &u->uu.uuid128[0], sizeof(u32));
+ su.uu.uuid32 = ntohl(u32);
+ }
+ return su;
+}
+
+static void bta_create_mns_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
+{
+ tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
+ tSDP_DISC_ATTR *p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT16 pversion = 0;
+ UINT8 offset = 0;
+ record->mns.hdr.type = SDP_TYPE_MAP_MNS;
+ record->mns.hdr.service_name_length = 0;
+ record->mns.hdr.service_name = NULL;
+ record->mns.hdr.rfcomm_channel_number = 0;
+ record->mns.hdr.l2cap_psm = -1;
+ record->mns.hdr.profile_version = 0;
+ record->mns.supported_features = 0x0000001F; //default value if not found
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES)) != NULL)
+ {
+ record->mns.supported_features = p_attr->attr_value.v.u32;
+ APPL_TRACE_DEBUG("Found supported_features: %d", record->mns.supported_features );
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ record->mns.hdr.service_name_length = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->mns.hdr.service_name = (char *)p_attr->attr_value.v.array;
+ APPL_TRACE_DEBUG("Found service name with length: %d", record->mns.hdr.service_name_length);
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_MAP_PROFILE, &pversion))
+ {
+ record->mns.hdr.profile_version = pversion;
+ APPL_TRACE_DEBUG("Found profile_version: %d", record->mns.hdr.profile_version);
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ record->mns.hdr.rfcomm_channel_number = pe.params[0];
+ APPL_TRACE_DEBUG("Found rfcomm_channel_number: %d", record->mns.hdr.rfcomm_channel_number);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) != NULL)
+ {
+ record->mns.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+ APPL_TRACE_DEBUG("Found l2cap_psm: %d", record->mns.hdr.l2cap_psm);
+ }
+}
+
+static void bta_create_mas_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
+{
+ tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
+ tSDP_DISC_ATTR *p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT16 pversion = -1;
+
+ record->mas.hdr.type = SDP_TYPE_MAP_MAS;
+ record->mas.hdr.service_name_length = 0;
+ record->mas.hdr.service_name = NULL;
+ record->mas.hdr.rfcomm_channel_number = 0;
+ record->mas.hdr.l2cap_psm = -1;
+ record->mas.hdr.profile_version = 0;
+ record->mas.mas_instance_id = 0;
+ record->mas.supported_features = 0x0000001F;
+ record->mas.supported_message_types = 0;
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAS_INSTANCE_ID)) != NULL)
+ {
+ record->mas.mas_instance_id = p_attr->attr_value.v.u8;
+ APPL_TRACE_DEBUG("Found mas_instance_id: %d", record->mas.mas_instance_id);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_MSG_TYPE)) != NULL)
+ {
+ record->mas.supported_message_types = p_attr->attr_value.v.u8;
+ APPL_TRACE_DEBUG("Found supported_message_types: %d", record->mas.supported_message_types);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES)) != NULL)
+ {
+ record->mas.supported_features = p_attr->attr_value.v.u32;
+ APPL_TRACE_DEBUG("Found supported_features: %d", record->mas.supported_features);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ record->mas.hdr.service_name_length = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->mas.hdr.service_name = (char *)p_attr->attr_value.v.array;
+ APPL_TRACE_DEBUG("Found service name with length: %d", record->mas.hdr.service_name_length);
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_MAP_PROFILE, &pversion))
+ {
+ record->mas.hdr.profile_version = pversion;
+ APPL_TRACE_DEBUG("Found profile_version: %d", record->mas.hdr.profile_version);
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ record->mas.hdr.rfcomm_channel_number = pe.params[0];
+ APPL_TRACE_DEBUG("Found rfcomm_channel_number: %d", record->mas.hdr.rfcomm_channel_number);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) != NULL)
+ {
+ record->mas.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+ APPL_TRACE_DEBUG("Found l2cap_psm: %d", record->mas.hdr.l2cap_psm);
+
+ }
+}
+
+static void bta_create_pse_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
+{
+ tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
+ tSDP_DISC_ATTR *p_attr;
+ UINT16 pversion;
+ tSDP_PROTOCOL_ELEM pe;
+
+ record->pse.hdr.type = SDP_TYPE_PBAP_PSE;
+ record->pse.hdr.service_name_length = 0;
+ record->pse.hdr.service_name = NULL;
+ record->pse.hdr.rfcomm_channel_number = 0;
+ record->pse.hdr.l2cap_psm = -1;
+ record->pse.hdr.profile_version = 0;
+ record->pse.supported_features = 0x00000003;
+ record->pse.supported_repositories = 0;
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_REPOSITORIES)) != NULL)
+ {
+ record->pse.supported_repositories = p_attr->attr_value.v.u8;
+ APPL_TRACE_DEBUG("Found supported_repositories: %d", record->pse.supported_repositories);
+ }
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PBAP_SUPPORTED_FEATURES)) != NULL)
+ {
+ record->pse.supported_features = p_attr->attr_value.v.u32;
+ APPL_TRACE_DEBUG("Found supported_features: %d", record->pse.supported_features);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ record->pse.hdr.service_name_length = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->pse.hdr.service_name = (char *)p_attr->attr_value.v.array;
+ APPL_TRACE_DEBUG("Found service name with length: %d", record->pse.hdr.service_name_length);
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_PHONE_ACCESS, &pversion))
+ {
+ record->pse.hdr.profile_version = pversion;
+ APPL_TRACE_DEBUG("Found profile_version: %d", record->pse.hdr.profile_version);
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ record->pse.hdr.rfcomm_channel_number = pe.params[0];
+ APPL_TRACE_DEBUG("Found rfcomm_channel_number: %d", record->pse.hdr.rfcomm_channel_number);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) != NULL)
+ {
+ record->pse.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+ APPL_TRACE_DEBUG("Found l2cap_psm: %d", record->pse.hdr.l2cap_psm);
+ }
+
+}
+
+static void bta_create_ops_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
+{
+ tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT16 pversion = -1;
+
+ record->ops.hdr.type = SDP_TYPE_OPP_SERVER;
+ record->ops.hdr.service_name_length = 0;
+ record->ops.hdr.service_name = NULL;
+ record->ops.hdr.rfcomm_channel_number = 0;
+ record->ops.hdr.l2cap_psm = -1;
+ record->ops.hdr.profile_version = 0;
+ record->ops.supported_formats_list_len = 0;
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ record->ops.hdr.service_name_length = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->ops.hdr.service_name = (char *)p_attr->attr_value.v.array;
+ APPL_TRACE_DEBUG("Found service name with length: %d", record->ops.hdr.service_name_length);
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_OBEX_OBJECT_PUSH, &pversion))
+ {
+ record->ops.hdr.profile_version = pversion;
+ APPL_TRACE_DEBUG("Found profile_version: %d", record->ops.hdr.profile_version);
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ record->ops.hdr.rfcomm_channel_number = pe.params[0];
+ APPL_TRACE_DEBUG("Found rfcomm_channel_number: %d", record->ops.hdr.rfcomm_channel_number);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) != NULL)
+ {
+ record->ops.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+ APPL_TRACE_DEBUG("Found l2cap_psm: %d", record->ops.hdr.l2cap_psm);
+
+ }
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FORMATS_LIST)) != NULL)
+ {
+ /* Safety check - each entry should itself be a sequence */
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
+ record->ops.supported_formats_list_len = 0;
+ APPL_TRACE_ERROR("supported_formats_list - wrong attribute length/type:"
+ " 0x%02x - expected 0x06",p_attr->attr_len_type);
+ } else {
+ int count = 0;
+ /* 1 byte for type/length 1 byte for value */
+ record->ops.supported_formats_list_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type)/2;
+
+ /* Extract each value into */
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr;
+ p_sattr != NULL; p_sattr = p_sattr->p_next_attr)
+ {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE)
+ && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 1))
+ {
+ if(count == sizeof(record->ops.supported_formats_list)) {
+ APPL_TRACE_ERROR("supported_formats_list - count overflow - "
+ "too many sub attributes!!");
+ /* If you hit this, new formats have been added,
+ * update SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH */
+ break;
+ }
+ record->ops.supported_formats_list[count] = p_sattr->attr_value.v.u8;
+ count++;
+ } else {
+ APPL_TRACE_ERROR("supported_formats_list - wrong sub attribute "
+ "length/type: 0x%02x - expected 0x80"
+ ,p_sattr->attr_len_type);
+ break;
+ }
+ }
+ if(record->ops.supported_formats_list_len != count) {
+ APPL_TRACE_WARNING("supported_formats_list - Length of attribute different "
+ "from the actual number of sub-attributes in the sequence "
+ "att-length: %d - number of elements: %d"
+ ,record->ops.supported_formats_list_len , count);
+
+ }
+ record->ops.supported_formats_list_len = count;
+ }
+
+ APPL_TRACE_DEBUG("Found supported_formats_list - length: %d",
+ record->ops.supported_formats_list_len);
+ }
+}
+
+static void bta_create_raw_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
+{
+ tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
+ tSDP_DISC_ATTR *p_attr;
+ UINT16 pversion;
+ tSDP_PROTOCOL_ELEM pe;
+
+ record->hdr.type = SDP_TYPE_RAW;
+ record->hdr.service_name_length = 0;
+ record->hdr.service_name = NULL;
+ record->hdr.rfcomm_channel_number = -1;
+ record->hdr.l2cap_psm = -1;
+ record->hdr.profile_version = -1;
+
+ /* Try to extract a service name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ record->pse.hdr.service_name_length = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->pse.hdr.service_name = (char *)p_attr->attr_value.v.array;
+ APPL_TRACE_DEBUG("Found service name with length: %d", record->pse.hdr.service_name_length);
+ }
+
+ /* Try to extract an RFCOMM channel */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ record->pse.hdr.rfcomm_channel_number = pe.params[0];
+ APPL_TRACE_DEBUG("Found rfcomm_channel_number: %d", record->pse.hdr.rfcomm_channel_number);
+ }
+ record->hdr.user1_ptr_len = p_bta_sdp_cfg->p_sdp_db->raw_size;
+ record->hdr.user1_ptr = p_bta_sdp_cfg->p_sdp_db->raw_data;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_sdp_search_cback
+**
+** Description Callback from btm after search is completed
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_sdp_search_cback(UINT16 result, void * user_data)
+{
+ tSDP_DISC_REC *p_rec = NULL;
+ tBTA_SDP_SEARCH_COMP evt_data = {0}; // We need to zero-initialize
+ tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+ UINT16 uuid16 = 0;
+ int count = 0;
+ tBT_UUID su;
+ APPL_TRACE_DEBUG("bta_sdp_search_cback res: 0x%x", result);
+
+ bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_NONE;
+
+ if (bta_sdp_cb.p_dm_cback == NULL) return;
+
+ bdcpy(evt_data.remote_addr, bta_sdp_cb.remote_addr);
+ tBT_UUID *uuid = (tBT_UUID*)user_data;
+ memcpy(&evt_data.uuid, uuid, sizeof(tBT_UUID));
+ su = shorten_sdp_uuid(uuid);
+
+ if (result == SDP_SUCCESS || result == SDP_DB_FULL)
+ {
+ do {
+ p_rec = SDP_FindServiceUUIDInDb(p_bta_sdp_cfg->p_sdp_db, &su, p_rec);
+ /* generate the matching record data pointer */
+ if(p_rec != NULL){
+ status = BTA_SDP_SUCCESS;
+ if (IS_UUID(UUID_MAP_MAS,uuid->uu.uuid128)) {
+ APPL_TRACE_DEBUG("%s() - found MAP (MAS) uuid", __func__);
+ bta_create_mas_sdp_record(&evt_data.records[count], p_rec);
+
+ }else if (IS_UUID(UUID_MAP_MNS,uuid->uu.uuid128)) {
+ APPL_TRACE_DEBUG("%s() - found MAP (MNS) uuid", __func__);
+ bta_create_mns_sdp_record(&evt_data.records[count], p_rec);
+
+ }else if(IS_UUID(UUID_PBAP_PSE,uuid->uu.uuid128)){
+ APPL_TRACE_DEBUG("%s() - found PBAP (PSE) uuid", __func__);
+ bta_create_pse_sdp_record(&evt_data.records[count], p_rec);
+ }else if(IS_UUID(UUID_OBEX_OBJECT_PUSH,uuid->uu.uuid128)){
+ APPL_TRACE_DEBUG("%s() - found Object Push Server (OPS) uuid", __func__);
+ bta_create_ops_sdp_record(&evt_data.records[count], p_rec);
+ }else {
+
+ /* we do not have specific structure for this */
+ APPL_TRACE_DEBUG("%s() - profile not identified. using raw data", __func__);
+ bta_create_raw_sdp_record(&evt_data.records[count], p_rec);
+ p_rec = NULL; // Terminate loop
+ /* For raw, we only extract the first entry, and then return the entire
+ raw data chunk.
+ TODO: Find a way to split the raw data into record chunks, and iterate
+ to extract generic data for each chunk - e.g. rfcomm channel and
+ service name. */
+ }
+ count++;
+ } else {
+ APPL_TRACE_DEBUG("%s() - UUID not found", __func__);
+ }
+ } while (p_rec != NULL && count < BTA_SDP_MAX_RECORDS);
+
+ evt_data.record_count = count;
+ }
+ evt_data.status = status;
+
+ bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP*) &evt_data, (void*)&uuid->uu.uuid128);
+ free(user_data); // We no longer need the user data to track the search
+}
+
+/*******************************************************************************
+**
+** Function bta_sdp_enable
+**
+** Description Initializes the SDP I/F
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sdp_enable(tBTA_SDP_MSG *p_data)
+{
+ APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active);
+ tBTA_SDP_STATUS status = BTA_SDP_SUCCESS;
+ bta_sdp_cb.p_dm_cback = p_data->enable.p_cback;
+ bta_sdp_cb.p_dm_cback(BTA_SDP_ENABLE_EVT, (tBTA_SDP *)&status, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_sdp_search
+**
+** Description Discovers all sdp records for an uuid on remote device
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sdp_search(tBTA_SDP_MSG *p_data)
+{
+ int x=0;
+ // TODO: Leaks!!! but needed as user-data pointer
+ tBT_UUID *bta_sdp_search_uuid = malloc(sizeof(tBT_UUID));
+ if(p_data == NULL)
+ {
+ APPL_TRACE_DEBUG("SDP control block handle is null");
+ return;
+ }
+ tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+
+ APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active);
+
+ if (bta_sdp_cb.sdp_active != BTA_SDP_ACTIVE_NONE)
+ {
+ /* SDP is still in progress */
+ status = BTA_SDP_BUSY;
+ if(bta_sdp_cb.p_dm_cback) {
+ tBTA_SDP_SEARCH_COMP result = {0};
+ result.uuid = p_data->get_search.uuid;
+ bdcpy(result.remote_addr, p_data->get_search.bd_addr);
+ result.status = status;
+ bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP *)&result, NULL);
+ }
+ return;
+ }
+
+ bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_YES;
+ bdcpy(bta_sdp_cb.remote_addr, p_data->get_search.bd_addr);
+ /* set the uuid used in the search */
+ memcpy(bta_sdp_search_uuid, &(p_data->get_search.uuid),sizeof(tBT_UUID));
+
+ /* initialize the search for the uuid */
+ APPL_TRACE_DEBUG("%s init discovery with UUID(len: %d):",
+ __func__, bta_sdp_search_uuid->len);
+ for(x = 0; x<bta_sdp_search_uuid->len;x++){
+ APPL_TRACE_DEBUG("%X",bta_sdp_search_uuid->uu.uuid128[x]);
+ }
+ SDP_InitDiscoveryDb (p_bta_sdp_cfg->p_sdp_db, p_bta_sdp_cfg->sdp_db_size, 1,
+ bta_sdp_search_uuid, 0, NULL);
+
+ if (!SDP_ServiceSearchAttributeRequest2(p_data->get_search.bd_addr, p_bta_sdp_cfg->p_sdp_db,
+ bta_sdp_search_cback, (void*)bta_sdp_search_uuid))
+ {
+ bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_NONE;
+
+ /* failed to start SDP. report the failure right away */
+ if (bta_sdp_cb.p_dm_cback) {
+ tBTA_SDP_SEARCH_COMP result = {0};
+ result.uuid = p_data->get_search.uuid;
+ bdcpy(result.remote_addr, p_data->get_search.bd_addr);
+ result.status = status;
+ bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP *)&result, NULL);
+ }
+ }
+ /*
+ else report the result when the cback is called
+ */
+}
+
+/*******************************************************************************
+**
+** Function bta_sdp_record
+**
+** Description Discovers all sdp records for an uuid on remote device
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sdp_create_record(tBTA_SDP_MSG *p_data)
+{
+ APPL_TRACE_DEBUG("%s() event: %d", __func__, p_data->record.hdr.event);
+ if (bta_sdp_cb.p_dm_cback)
+ bta_sdp_cb.p_dm_cback(BTA_SDP_CREATE_RECORD_USER_EVT, NULL, p_data->record.user_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_sdp_create_record
+**
+** Description Discovers all sdp records for an uuid on remote device
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sdp_remove_record(tBTA_SDP_MSG *p_data)
+{
+ APPL_TRACE_DEBUG("%s() event: %d", __func__, p_data->record.hdr.event);
+ if (bta_sdp_cb.p_dm_cback)
+ bta_sdp_cb.p_dm_cback(BTA_SDP_REMOVE_RECORD_USER_EVT, NULL, p_data->record.user_data);
+}
diff --git a/bta/sdp/bta_sdp_api.c b/bta/sdp/bta_sdp_api.c
new file mode 100644
index 000000000..d98ddca38
--- /dev/null
+++ b/bta/sdp/bta_sdp_api.c
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 is the implementation of the API for SDP search subsystem
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+#include "gki.h"
+#include <string.h>
+#include "port_api.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_sdp_reg =
+{
+ bta_sdp_sm_execute,
+ NULL
+};
+
+/*******************************************************************************
+**
+** Function BTA_SdpEnable
+**
+** Description Enable the SDP search I/F service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_SDP_ENABLE_EVT. This function must
+** be called before other functions in the SDP search API are
+** called.
+**
+** Returns BTA_SDP_SUCCESS if successful.
+** BTA_SDP_FAIL if internal failure.
+**
+*******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK *p_cback)
+{
+ tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+ tBTA_SDP_API_ENABLE *p_buf;
+
+ APPL_TRACE_API(__FUNCTION__);
+ if(p_cback && FALSE == bta_sys_is_register(BTA_ID_SDP))
+ {
+ memset(&bta_sdp_cb, 0, sizeof(tBTA_SDP_CB));
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_SDP, &bta_sdp_reg);
+
+ if (p_cback &&
+ (p_buf = (tBTA_SDP_API_ENABLE *) GKI_getbuf(sizeof(tBTA_SDP_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_SDP_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ bta_sys_sendmsg(p_buf);
+ status = BTA_SDP_SUCCESS;
+ }
+ }
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_SdpSearch
+**
+** Description This function performs service discovery for a specific service
+** on given peer device. When the operation is completed
+** the tBTA_SDP_DM_CBACK callback function will be called with
+** a BTA_SDP_SEARCH_COMPLETE_EVT.
+**
+** Returns BTA_SDP_SUCCESS, if the request is being processed.
+** BTA_SDP_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpSearch(BD_ADDR bd_addr, tSDP_UUID *uuid)
+{
+ tBTA_SDP_STATUS ret = BTA_SDP_FAILURE;
+ tBTA_SDP_API_SEARCH *p_msg;
+
+ APPL_TRACE_API(__FUNCTION__);
+ if ((p_msg = (tBTA_SDP_API_SEARCH *)GKI_getbuf(sizeof(tBTA_SDP_API_SEARCH))) != NULL)
+ {
+ p_msg->hdr.event = BTA_SDP_API_SEARCH_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ //p_msg->uuid = uuid;
+ memcpy(&(p_msg->uuid), uuid, sizeof(tSDP_UUID));
+ bta_sys_sendmsg(p_msg);
+ ret = BTA_SDP_SUCCESS;
+ }
+
+ return(ret);
+}
+
+/*******************************************************************************
+**
+** Function BTA_SdpCreateRecordByUser
+**
+** Description This function is used to request a callback to create a SDP
+** record. The registered callback will be called with event
+** BTA_SDP_CREATE_RECORD_USER_EVT.
+**
+** Returns BTA_SDP_SUCCESS, if the request is being processed.
+** BTA_SDP_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data)
+{
+ tBTA_SDP_STATUS ret = BTA_SDP_FAILURE;
+ tBTA_SDP_API_RECORD_USER *p_msg;
+
+ APPL_TRACE_API(__FUNCTION__);
+ if ((p_msg = (tBTA_SDP_API_RECORD_USER *)GKI_getbuf(sizeof(tBTA_SDP_API_RECORD_USER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_SDP_API_CREATE_RECORD_USER_EVT;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ ret = BTA_SDP_SUCCESS;
+ }
+
+ return(ret);
+}
+
+/*******************************************************************************
+**
+** Function BTA_SdpRemoveRecordByUser
+**
+** Description This function is used to request a callback to remove a SDP
+** record. The registered callback will be called with event
+** BTA_SDP_REMOVE_RECORD_USER_EVT.
+**
+** Returns BTA_SDP_SUCCESS, if the request is being processed.
+** BTA_SDP_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void* user_data)
+{
+ tBTA_SDP_STATUS ret = BTA_SDP_FAILURE;
+ tBTA_SDP_API_RECORD_USER *p_msg;
+
+ APPL_TRACE_API(__FUNCTION__);
+ if ((p_msg = (tBTA_SDP_API_RECORD_USER *)GKI_getbuf(sizeof(tBTA_SDP_API_RECORD_USER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_SDP_API_REMOVE_RECORD_USER_EVT;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ ret = BTA_SDP_SUCCESS;
+ }
+
+ return(ret);
+}
+
+
diff --git a/bta/sdp/bta_sdp_cfg.c b/bta/sdp/bta_sdp_cfg.c
new file mode 100644
index 000000000..eef2511a5
--- /dev/null
+++ b/bta/sdp/bta_sdp_cfg.c
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 compile-time configurable constants for SDP Search
+ ******************************************************************************/
+
+#include "gki.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+
+#ifndef BTA_SDP_DB_SIZE
+#define BTA_SDP_DB_SIZE 4500
+#endif
+
+static UINT8 __attribute__ ((aligned(4))) bta_sdp_db_data[BTA_SDP_DB_SIZE];
+
+/* SDP configuration structure */
+const tBTA_SDP_CFG bta_sdp_cfg =
+{
+ BTA_SDP_DB_SIZE,
+ (tSDP_DISCOVERY_DB *)bta_sdp_db_data /* The data buffer to keep SDP database */
+};
+
+tBTA_SDP_CFG *p_bta_sdp_cfg = (tBTA_SDP_CFG *) &bta_sdp_cfg;
diff --git a/bta/sdp/bta_sdp_int.h b/bta/sdp/bta_sdp_int.h
new file mode 100644
index 000000000..4f3f6a53d
--- /dev/null
+++ b/bta/sdp/bta_sdp_int.h
@@ -0,0 +1,115 @@
+
+
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2003-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 is the private interface file for the BTA SDP I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_SDP_INT_H
+#define BTA_SDP_INT_H
+
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_SDP_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SDP),
+ BTA_SDP_API_SEARCH_EVT,
+ BTA_SDP_API_CREATE_RECORD_USER_EVT,
+ BTA_SDP_API_REMOVE_RECORD_USER_EVT,
+ BTA_SDP_MAX_INT_EVT
+};
+
+enum
+{
+ BTA_SDP_ACTIVE_NONE = 0,
+ BTA_SDP_ACTIVE_YES /* waiting for SDP result */
+};
+
+
+
+/* data type for BTA_SDP_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SDP_DM_CBACK *p_cback;
+} tBTA_SDP_API_ENABLE;
+
+/* data type for BTA_SDP_API_SEARCH_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tSDP_UUID uuid;
+} tBTA_SDP_API_SEARCH;
+
+/* data type for BTA_SDP_API_SEARCH_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ void* user_data;
+} tBTA_SDP_API_RECORD_USER;
+
+/* union of all data types */
+typedef union
+{
+ /* GKI event buffer header */
+ BT_HDR hdr;
+ tBTA_SDP_API_ENABLE enable;
+ tBTA_SDP_API_SEARCH get_search;
+ tBTA_SDP_API_RECORD_USER record;
+} tBTA_SDP_MSG;
+
+/* SDP control block */
+typedef struct
+{
+ UINT8 sdp_active; /* see BTA_SDP_SDP_ACT_* */
+ BD_ADDR remote_addr;
+ tBTA_SDP_DM_CBACK *p_dm_cback;
+} tBTA_SDP_CB;
+
+
+/* SDP control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_SDP_CB bta_sdp_cb;
+#else
+extern tBTA_SDP_CB *bta_sdp_cb_ptr;
+#define bta_sdp_cb (*bta_sdp_cb_ptr)
+#endif
+
+/* config struct */
+extern tBTA_SDP_CFG *p_bta_sdp_cfg;
+
+extern BOOLEAN bta_sdp_sm_execute(BT_HDR *p_msg);
+
+extern void bta_sdp_enable (tBTA_SDP_MSG *p_data);
+extern void bta_sdp_search (tBTA_SDP_MSG *p_data);
+extern void bta_sdp_create_record(tBTA_SDP_MSG *p_data);
+extern void bta_sdp_remove_record(tBTA_SDP_MSG *p_data);
+
+#endif /* BTA_SDP_INT_H */
diff --git a/bta/sys/bta_sys.h b/bta/sys/bta_sys.h
index f42ee0ae5..4146f9830 100644
--- a/bta/sys/bta_sys.h
+++ b/bta/sys/bta_sys.h
@@ -91,7 +91,8 @@ typedef UINT16 tBTA_SYS_HW_MODULE;
#define BTA_ID_HL 30 /* Health Device Profile*/
#define BTA_ID_GATTC 31 /* GATT Client */
#define BTA_ID_GATTS 32 /* GATT Client */
-#define BTA_ID_BLUETOOTH_MAX 33 /* last BT profile */
+#define BTA_ID_SDP 33 /* SDP Client */
+#define BTA_ID_BLUETOOTH_MAX 34 /* last BT profile */
/* GENERIC */
#define BTA_ID_PRM 38
@@ -102,10 +103,10 @@ typedef UINT16 tBTA_SYS_HW_MODULE;
/* JV */
-#define BTA_ID_JV1 43 /* JV1 */
-#define BTA_ID_JV2 44 /* JV2 */
+#define BTA_ID_JV1 44 /* JV1 */
+#define BTA_ID_JV2 45 /* JV2 */
-#define BTA_ID_MAX (43 + BTA_DM_NUM_JV_ID)
+#define BTA_ID_MAX (44 + BTA_DM_NUM_JV_ID)
typedef UINT8 tBTA_SYS_ID;
diff --git a/btif/include/btif_sdp.h b/btif/include/btif_sdp.h
new file mode 100644
index 000000000..2aac1c31d
--- /dev/null
+++ b/btif/include/btif_sdp.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sdp.h
+ *
+ * Description: Bluetooth SDP search Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_SDP_H
+#define BTIF_SDP_H
+
+#include <hardware/bt_sdp.h>
+
+btsdp_interface_t *btif_sdp_get_interface();
+
+#endif
diff --git a/btif/include/btif_sock_l2cap.h b/btif/include/btif_sock_l2cap.h
new file mode 100644
index 000000000..9425dc90c
--- /dev/null
+++ b/btif/include/btif_sock_l2cap.h
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * L2CAP Socket Interface
+ *******************************************************************************/
+
+#ifndef BTIF_SOCK_L2CAP_H
+#define BTIF_SOCK_L2CAP_H
+
+
+
+#define L2CAP_MASK_FIXED_CHANNEL 0x10000
+
+
+bt_status_t btsock_l2cap_init(int handle);
+bt_status_t btsock_l2cap_cleanup();
+bt_status_t btsock_l2cap_listen(const char* name, int channel,
+ int* sock_fd, int flags);
+bt_status_t btsock_l2cap_connect(const bt_bdaddr_t *bd_addr,
+ int channel, int* sock_fd, int flags);
+void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id);
+void on_l2cap_psm_assigned(int id, int psm);
+
+#endif
+
diff --git a/btif/include/btif_sock_sdp.h b/btif/include/btif_sock_sdp.h
index 857c2fba2..3cbc70c9d 100644
--- a/btif/include/btif_sock_sdp.h
+++ b/btif/include/btif_sock_sdp.h
@@ -25,14 +25,14 @@ static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {0x00, 0x00, 0x11, 0x05, 0x00, 0
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_MAPS_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 0x10, 0x00,
+static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
static const uint8_t UUID_SPP[] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
static inline bool is_uuid_empty(const uint8_t* uuid)
{
- static uint8_t empty_uuid[16];
+ static uint8_t empty_uuid[16];
return uuid == NULL || memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0;
}
diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c
index 075e9cf86..4558705d4 100644
--- a/btif/src/bluetooth.c
+++ b/btif/src/bluetooth.c
@@ -40,6 +40,7 @@
#include <hardware/bt_mce.h>
#include <hardware/bt_gatt.h>
#include <hardware/bt_rc.h>
+#include <hardware/bt_sdp.h>
#define LOG_NDDEBUG 0
#define LOG_TAG "bt_bluedroid"
@@ -98,6 +99,8 @@ extern btgatt_interface_t *btif_gatt_get_interface();
extern btrc_interface_t *btif_rc_get_interface();
/* avrc controller */
extern btrc_interface_t *btif_rc_ctrl_get_interface();
+/*SDP search client*/
+extern btsdp_interface_t *btif_sdp_get_interface();
/************************************************************************************
** Functions
@@ -337,8 +340,8 @@ static const void* get_profile_interface (const char *profile_id)
if (is_profile(profile_id, BT_PROFILE_HEALTH_ID))
return btif_hl_get_interface();
- if (is_profile(profile_id, BT_PROFILE_MAP_CLIENT_ID))
- return btif_mce_get_interface();
+ if (is_profile(profile_id, BT_PROFILE_SDP_CLIENT_ID))
+ return btif_sdp_get_interface();
#if ( BTA_GATT_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
if (is_profile(profile_id, BT_PROFILE_GATT_ID))
diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c
index 9462bce1e..1049673fd 100644
--- a/btif/src/btif_core.c
+++ b/btif/src/btif_core.c
@@ -47,7 +47,6 @@
#include "btif_av.h"
#include "btif_config.h"
#include "btif_pan.h"
-#include "btif_mce.h"
#include "btif_profile_queue.h"
#include "btif_config.h"
#include "btif_sock.h"
diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
index 073fc7d1b..7a7ec01a3 100644
--- a/btif/src/btif_dm.c
+++ b/btif/src/btif_dm.c
@@ -47,6 +47,7 @@
#include "btif_storage.h"
#include "btif_hh.h"
#include "btif_config.h"
+#include "btif_sdp.h"
#include "bta_gatt_api.h"
#include "include/stack_config.h"
@@ -242,7 +243,7 @@ extern bt_status_t btif_hf_execute_service(BOOLEAN b_enable);
extern bt_status_t btif_av_execute_service(BOOLEAN b_enable);
extern bt_status_t btif_hh_execute_service(BOOLEAN b_enable);
extern bt_status_t btif_hf_client_execute_service(BOOLEAN b_enable);
-extern bt_status_t btif_mce_execute_service(BOOLEAN b_enable);
+extern bt_status_t btif_sdp_execute_service(BOOLEAN b_enable);
extern int btif_hh_connect(bt_bdaddr_t *bd_addr);
extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16);
@@ -254,6 +255,7 @@ extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UIN
bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
BOOLEAN b_enable)
{
+ BTIF_TRACE_DEBUG("%s service_id: %d", __FUNCTION__, service_id);
/* Check the service_ID and invoke the profile's BT state changed API */
switch (service_id)
{
@@ -274,9 +276,9 @@ bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
{
btif_hf_client_execute_service(b_enable);
}break;
- case BTA_MAP_SERVICE_ID:
+ case BTA_SDP_SERVICE_ID:
{
- btif_mce_execute_service(b_enable);
+ btif_sdp_execute_service(b_enable);
}break;
default:
BTIF_TRACE_ERROR("%s: Unknown service being enabled", __FUNCTION__);
diff --git a/btif/src/btif_sdp.c b/btif/src/btif_sdp.c
new file mode 100644
index 000000000..c5fd81386
--- /dev/null
+++ b/btif/src/btif_sdp.c
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Samsung System LSI
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_sdp.c
+ * Description: SDP Bluetooth Interface.
+ * Implements the generic message handling and search functionality.
+ * References btif_sdp_server.c for SDP record creation.
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+#include <stdlib.h>
+
+#define LOG_TAG "BTIF_SDP"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btif_profile_queue.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+
+/*****************************************************************************
+** Functions implemented in sdp_server.c
+******************************************************************************/
+bt_status_t sdp_server_init();
+void sdp_server_cleanup();
+bt_status_t create_sdp_record(bluetooth_sdp_record *records, int* record_handles);
+bt_status_t remove_sdp_record(int record_handle);
+void on_create_record_event(int handle);
+void on_remove_record_event(int handle);
+
+// Utility functions:
+int get_sdp_records_size(bluetooth_sdp_record* in_record, int count);
+void copy_sdp_records(bluetooth_sdp_record* in_records,
+ bluetooth_sdp_record* out_records, int count);
+
+
+/*****************************************************************************
+** Static variables
+******************************************************************************/
+
+static btsdp_callbacks_t *bt_sdp_callbacks = NULL;
+
+static void btif_sdp_search_comp_evt(UINT16 event, char *p_param)
+{
+ tBTA_SDP_SEARCH_COMP *evt_data = (tBTA_SDP_SEARCH_COMP*) p_param;
+ bt_bdaddr_t addr;
+ BTIF_TRACE_DEBUG("%s: event = %d", __FUNCTION__, event);
+
+ if (event != BTA_SDP_SEARCH_COMP_EVT)
+ return;
+
+ bdcpy(addr.address, evt_data->remote_addr);
+
+ HAL_CBACK(bt_sdp_callbacks, sdp_search_cb, evt_data->status,
+ &addr, (uint8_t*)(evt_data->uuid.uu.uuid128),
+ evt_data->record_count, evt_data->records);
+}
+
+static void sdp_search_comp_copy_cb(UINT16 event, char *p_dest, char *p_src)
+{
+ tBTA_SDP_SEARCH_COMP *p_dest_data = (tBTA_SDP_SEARCH_COMP *) p_dest;
+ tBTA_SDP_SEARCH_COMP *p_src_data = (tBTA_SDP_SEARCH_COMP *) p_src;
+
+ if (!p_src)
+ return;
+
+ if (event != BTA_SDP_SEARCH_COMP_EVT)
+ return;
+
+ memcpy(p_dest_data, p_src_data, sizeof(tBTA_SDP_SEARCH_COMP));
+
+ copy_sdp_records(p_src_data->records, p_dest_data->records, p_src_data->record_count);
+}
+
+static void sdp_dm_cback(tBTA_SDP_EVT event, tBTA_SDP *p_data, void *user_data)
+{
+ switch (event)
+ {
+ case BTA_SDP_SEARCH_COMP_EVT:
+ {
+ int size = sizeof(tBTA_SDP);
+ size += get_sdp_records_size(p_data->sdp_search_comp.records,
+ p_data->sdp_search_comp.record_count);
+
+ /* need to deep copy the record content */
+ btif_transfer_context(btif_sdp_search_comp_evt, event,
+ (char*)p_data, size, sdp_search_comp_copy_cb);
+ break;
+ }
+ case BTA_SDP_CREATE_RECORD_USER_EVT:
+ {
+ on_create_record_event((int)user_data);
+ break;
+ }
+ case BTA_SDP_REMOVE_RECORD_USER_EVT:
+ {
+ on_remove_record_event((int)user_data);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static bt_status_t init(btsdp_callbacks_t* callbacks)
+{
+ BTIF_TRACE_DEBUG("Sdp Search %s", __FUNCTION__);
+
+ bt_sdp_callbacks = callbacks;
+ sdp_server_init();
+
+ btif_enable_service(BTA_SDP_SERVICE_ID);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t deinit()
+{
+ BTIF_TRACE_DEBUG("Sdp Search %s", __FUNCTION__);
+
+ bt_sdp_callbacks = NULL;
+ sdp_server_cleanup();
+ btif_disable_service(BTA_SDP_SERVICE_ID);
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+static bt_status_t search(bt_bdaddr_t *bd_addr, const uint8_t *uuid)
+{
+ bdstr_t bdstr;
+ tSDP_UUID sdp_uuid;
+ sdp_uuid.len = 16;
+ memcpy(sdp_uuid.uu.uuid128, uuid, sizeof(sdp_uuid.uu.uuid128));
+
+ BTA_SdpSearch(bd_addr->address, &sdp_uuid);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static const btsdp_interface_t sdp_if = {
+ sizeof(btsdp_interface_t),
+ init,
+ deinit,
+ search,
+ create_sdp_record,
+ remove_sdp_record
+};
+
+const btsdp_interface_t *btif_sdp_get_interface(void)
+{
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ return &sdp_if;
+}
+
+/*******************************************************************************
+**
+** Function btif_sdp_execute_service
+**
+** Description Initializes/Shuts down the service
+**
+** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_sdp_execute_service(BOOLEAN b_enable)
+{
+ BTIF_TRACE_DEBUG("%s enable:%d", __FUNCTION__, b_enable);
+
+ if (b_enable)
+ {
+ BTA_SdpEnable(sdp_dm_cback);
+ }
+ else
+ {
+ /* This is called on BT disable so no need to extra cleanup */
+ }
+ return BT_STATUS_SUCCESS;
+}
+
diff --git a/btif/src/btif_sdp_server.c b/btif/src/btif_sdp_server.c
new file mode 100644
index 000000000..ec35cf796
--- /dev/null
+++ b/btif/src/btif_sdp_server.c
@@ -0,0 +1,721 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Samsung System LSI
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_sdp_server.c
+ * Description: SDP server Bluetooth Interface to create and remove SDP records.
+ * To be used in combination with the RFCOMM/L2CAP(LE) sockets.
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+#include <stdlib.h>
+
+#define LOG_TAG "BTIF_SDP_SERVER"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "bta_sdp_api.h"
+#include "bta_sys.h"
+#include "utl.h"
+#include "btif_sock_util.h"
+
+#if __GLIBC__
+static pthread_mutex_t sdp_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+#else
+static pthread_mutex_t sdp_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+#endif
+
+
+/**
+ * The need for a state variable have been reduced to two states.
+ * The remaining state control is handled by program flow
+ */
+typedef enum {
+ SDP_RECORD_FREE = 0,
+ SDP_RECORD_ALLOCED,
+} sdp_state_t;
+
+typedef struct {
+ sdp_state_t state;
+ int sdp_handle;
+ bluetooth_sdp_record* record_data;
+} sdp_slot_t;
+
+#define MAX_SDP_SLOTS 128
+static sdp_slot_t sdp_slots[MAX_SDP_SLOTS];
+
+/*****************************************************************************
+ * LOCAL Functions
+ *****************************************************************************/
+static int add_maps_sdp(const bluetooth_sdp_mas_record* rec);
+static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec);
+static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec);
+static int add_opps_sdp(const bluetooth_sdp_ops_record* rec);
+bt_status_t remove_sdp_record(int record_id);
+static int free_sdp_slot(int id);
+
+/******************************************************************************
+ * WARNING: Functions below are not called in BTU context.
+ * Introduced to make it possible to create SDP records from JAVA with both a
+ * RFCOMM channel and a L2CAP PSM.
+ * Overall architecture:
+ * 1) JAVA calls createRecord() which returns a pseudo ID which at a later
+ * point will be linked to a specific SDP handle.
+ * 2) createRecord() requests the BTU task(thread) to call a callback in SDP
+ * which creates the actual record, and updates the ID<->SDPHandle map
+ * based on the ID beeing passed to BTA as user_data.
+ *****************************************************************************/
+
+static void init_sdp_slots()
+{
+ int i;
+ memset(sdp_slots, 0, sizeof(sdp_slot_t)*MAX_SDP_SLOTS);
+ /* if SDP_RECORD_FREE is zero - no need to set the value */
+ if(SDP_RECORD_FREE != 0) {
+ for(i = 0; i < MAX_SDP_SLOTS; i++)
+ {
+ sdp_slots[i].state = SDP_RECORD_FREE;
+ }
+ }
+}
+
+bt_status_t sdp_server_init()
+{
+ BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
+ init_sdp_slots();
+ return BT_STATUS_SUCCESS;
+}
+
+void sdp_server_cleanup()
+{
+ BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
+ pthread_mutex_lock(&sdp_lock);
+ int i;
+ for(i = 0; i < MAX_SDP_SLOTS; i++)
+ {
+ /*remove_sdp_record(i); we cannot send messages to the other threads, since they might
+ * have been shut down already. Just do local cleanup.
+ */
+ free_sdp_slot(i);
+ }
+ pthread_mutex_unlock(&sdp_lock);
+}
+
+
+int get_sdp_records_size(bluetooth_sdp_record* in_record, int count) {
+ bluetooth_sdp_record* record = in_record;
+ int records_size = 0;
+ int i;
+ for(i=0; i<count; i++) {
+ record = &in_record[i];
+ records_size += sizeof(bluetooth_sdp_record);
+ records_size += record->hdr.service_name_length;
+ if(record->hdr.service_name_length > 0){
+ records_size++; /* + '\0' termination of string */
+ }
+ records_size += record->hdr.user1_ptr_len;
+ records_size += record->hdr.user2_ptr_len;
+ }
+ return records_size;
+}
+
+/* Deep copy all content of in_records into out_records.
+ * out_records must point to a chunk of memory large enough to contain all
+ * the data. Use getSdpRecordsSize() to calculate the needed size. */
+void copy_sdp_records(bluetooth_sdp_record* in_records,
+ bluetooth_sdp_record* out_records, int count) {
+ int i;
+ bluetooth_sdp_record* in_record;
+ bluetooth_sdp_record* out_record;
+ char* free_ptr = (char*)(&out_records[count]); /* set pointer to after the last entry */
+
+ for(i=0; i<count; i++) {
+ in_record = &in_records[i];
+ out_record = &out_records[i];
+ *out_record = *in_record;
+
+ if(in_record->hdr.service_name == NULL || in_record->hdr.service_name_length == 0) {
+ out_record->hdr.service_name = NULL;
+ out_record->hdr.service_name_length = 0;
+ } else {
+ out_record->hdr.service_name = free_ptr; // Update service_name pointer
+ // Copy string
+ memcpy(free_ptr, in_record->hdr.service_name, in_record->hdr.service_name_length);
+ free_ptr += in_record->hdr.service_name_length;
+ *(free_ptr) = '\0'; // Set '\0' termination of string
+ free_ptr++;
+ }
+ if(in_record->hdr.user1_ptr != NULL) {
+ out_record->hdr.user1_ptr = (UINT8*)free_ptr; // Update pointer
+ memcpy(free_ptr, in_record->hdr.user1_ptr, in_record->hdr.user1_ptr_len); // Copy content
+ free_ptr += in_record->hdr.user1_ptr_len;
+ }
+ if(in_record->hdr.user2_ptr != NULL) {
+ out_record->hdr.user2_ptr = (UINT8*)free_ptr; // Update pointer
+ memcpy(free_ptr, in_record->hdr.user2_ptr, in_record->hdr.user2_ptr_len); // Copy content
+ free_ptr += in_record->hdr.user2_ptr_len;
+ }
+ }
+ return;
+}
+
+/* Reserve a slot in sdp_slots, copy data and set a reference to the copy.
+ * The record_data will contain both the record and any data pointed to by
+ * the record.
+ * Currently this covers:
+ * service_name string,
+ * user1_ptr and
+ * user2_ptr. */
+static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
+ int i;
+ char* tmp_ptr = NULL;
+ int record_size = get_sdp_records_size(in_record, 1);
+ bluetooth_sdp_record* record = malloc(record_size);
+
+ copy_sdp_records(in_record, record, 1);
+
+ /* We are optimists here, and preallocate the record.
+ * This is to reduce the time we hold the sdp_lock. */
+ pthread_mutex_lock(&sdp_lock);
+ for(i = 0; i < MAX_SDP_SLOTS; i++)
+ {
+ if(sdp_slots[i].state == SDP_RECORD_FREE) {
+ sdp_slots[i].state = SDP_RECORD_ALLOCED;
+ sdp_slots[i].record_data = record;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&sdp_lock);
+ if(i >= MAX_SDP_SLOTS) {
+ APPL_TRACE_ERROR("alloc_sdp_slot failed - no more free slots!");
+ /* Rearly the optimist is too optimistic, and cleanup is needed...*/
+ free(record);
+ return -1;
+ }
+ return i;
+}
+
+static int free_sdp_slot(int id) {
+ int handle = -1;
+ bluetooth_sdp_record* record = NULL;
+ if(id >= MAX_SDP_SLOTS) {
+ APPL_TRACE_ERROR("free_sdp_slot failed - id %d is invalid", id);
+ return handle;
+ }
+ pthread_mutex_lock(&sdp_lock);
+ handle = sdp_slots[id].sdp_handle;
+ sdp_slots[id].sdp_handle = 0;
+ if(sdp_slots[id].state != SDP_RECORD_FREE)
+ {
+ /* safe a copy of the pointer, and free after unlock() */
+ record = sdp_slots[id].record_data;
+ }
+ sdp_slots[id].state = SDP_RECORD_FREE;
+ pthread_mutex_unlock(&sdp_lock);
+
+ if(record != NULL) {
+ free(record);
+ } else {
+ // Record have already been freed
+ handle = -1;
+ }
+ return handle;
+}
+
+/***
+ * Use this to get a reference to a SDP slot AND change the state to
+ * SDP_RECORD_CREATE_INITIATED.
+ */
+static const sdp_slot_t* start_create_sdp(int id) {
+ sdp_slot_t* sdp_slot;
+ if(id >= MAX_SDP_SLOTS) {
+ APPL_TRACE_ERROR("start_create_sdp failed - id %d is invalid", id);
+ return NULL;
+ }
+ pthread_mutex_lock(&sdp_lock);
+ if(sdp_slots[id].state == SDP_RECORD_ALLOCED) {
+ sdp_slot = &(sdp_slots[id]);
+ } else {
+ /* The record have been removed before this event occurred - e.g. deinit */
+ sdp_slot = NULL;
+ }
+ pthread_mutex_unlock(&sdp_lock);
+ if(sdp_slot == NULL) {
+ APPL_TRACE_ERROR("start_create_sdp failed - state for id %d is "
+ "sdp_slots[id].state = %d expected %d",
+ id, sdp_slots[id].state, SDP_RECORD_ALLOCED);
+ }
+ return sdp_slot;
+}
+
+static void set_sdp_handle(int id, int handle) {
+ pthread_mutex_lock(&sdp_lock);
+ sdp_slots[id].sdp_handle = handle;
+ pthread_mutex_unlock(&sdp_lock);
+ BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x",
+ __FUNCTION__, id, handle);
+
+}
+
+
+bt_status_t create_sdp_record(bluetooth_sdp_record *record, int* record_handle) {
+ int handle;
+
+ handle = alloc_sdp_slot(record);
+ BTIF_TRACE_DEBUG("Sdp Server %s handle = 0x%08x", __FUNCTION__, handle);
+
+ if(handle < 0)
+ return BT_STATUS_FAIL;
+
+ BTA_SdpCreateRecordByUser((void*) handle);
+
+ *record_handle = handle;
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t remove_sdp_record(int record_id) {
+ int handle;
+
+ /* Get the Record handle, and free the slot */
+ handle = free_sdp_slot(record_id);
+ BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x",
+ __FUNCTION__, record_id, handle);
+
+ /* Pass the actual record handle */
+ if(handle > 0) {
+ BTA_SdpRemoveRecordByUser((void*) handle);
+ return BT_STATUS_SUCCESS;
+ }
+ BTIF_TRACE_DEBUG("Sdp Server %s - record already removed - or never created", __FUNCTION__);
+ return BT_STATUS_FAIL;
+}
+
+
+/******************************************************************************
+ * CALLBACK FUNCTIONS
+ * Called in BTA context to create/remove SDP records.
+ ******************************************************************************/
+
+void on_create_record_event(int id) {
+ /*
+ * 1) Fetch the record pointer, and change its state?
+ * 2) switch on the type to create the correct record
+ * 3) Update state on completion
+ * 4) What to do at fail?
+ * */
+ BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
+ const sdp_slot_t* sdp_slot = start_create_sdp(id);
+ /* In the case we are shutting down, sdp_slot is NULL */
+ if(sdp_slot != NULL) {
+ bluetooth_sdp_record* record = sdp_slot->record_data;
+ int handle = -1;
+ switch(record->hdr.type) {
+ case SDP_TYPE_MAP_MAS:
+ handle = add_maps_sdp(&record->mas);
+ break;
+ case SDP_TYPE_MAP_MNS:
+ handle = add_mapc_sdp(&record->mns);
+ break;
+ case SDP_TYPE_PBAP_PSE:
+ handle = add_pbaps_sdp(&record->pse);
+ break;
+ case SDP_TYPE_OPP_SERVER:
+ handle = add_opps_sdp(&record->ops);
+ break;
+ case SDP_TYPE_PBAP_PCE:
+ // break; not yet supported
+ default:
+ BTIF_TRACE_DEBUG("Record type %d is not supported",record->hdr.type);
+ break;
+ }
+ if(handle != -1) {
+ set_sdp_handle(id, handle);
+ }
+ }
+}
+
+void on_remove_record_event(int handle) {
+ BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
+
+ // User data carries the actual SDP handle, not the ID.
+ if(handle != -1 && handle != 0) {
+ BOOLEAN result;
+ result = SDP_DeleteRecord( handle );
+ if(result == FALSE) {
+ BTIF_TRACE_ERROR(" Unable to remove handle 0x%08x", handle);
+ }
+ }
+}
+
+/****
+ * Below the actual functions accessing BTA context data - hence only call from BTA context!
+ */
+
+/* Create a MAP MAS SDP record based on information stored in a bluetooth_sdp_mas_record */
+static int add_maps_sdp(const bluetooth_sdp_mas_record* rec)
+{
+
+ tSDP_PROTOCOL_ELEM protoList [3];
+ UINT16 service = UUID_SERVCLASS_MESSAGE_ACCESS;
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ BOOLEAN status = TRUE;
+ UINT32 sdp_handle = 0;
+ UINT8 temp[4];
+ UINT8* p_temp = temp;
+
+ APPL_TRACE_DEBUG("add_mas_sdp: MASID = 0x%02x, scn 0x%02x, psm = 0x%04x\n service name %s",
+ rec->mas_instance_id, rec->hdr.rfcomm_channel_number,
+ rec->hdr.l2cap_psm, rec->hdr.service_name);
+
+ APPL_TRACE_DEBUG(" msg_types: 0x%02x, feature_bits: 0x%08x",
+ rec->supported_message_types, rec->supported_features);
+
+ if ((sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ APPL_TRACE_ERROR("MAPS SDP: Unable to register MAPS Service");
+ return sdp_handle;
+ }
+
+ /* add service class */
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+ memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
+
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+ status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(rec->hdr.service_name_length + 1),
+ (UINT8 *)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_MAP_PROFILE,
+ rec->hdr.profile_version);
+
+ /* Add MAS instance ID */
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&rec->mas_instance_id);
+
+ /* Add supported message types */
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&rec->supported_message_types);
+
+ /* Add supported feature */
+ UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (UINT32)4, temp);
+
+ /* Add the L2CAP PSM if present */
+ if(rec->hdr.l2cap_psm != -1) {
+ p_temp = temp;// The macro modifies p_temp, hence rewind.
+ UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+ UINT_DESC_TYPE, (UINT32)2, temp);
+ }
+
+ /* Make the service browseable */
+ status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status)
+ {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("add_maps_sdp FAILED");
+ }
+ else
+ {
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+ APPL_TRACE_DEBUG("MAPS: SDP Registered (handle 0x%08x)", sdp_handle);
+ }
+ return sdp_handle;
+}
+
+/* Create a MAP MNS SDP record based on information stored in a bluetooth_sdp_mns_record */
+static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec)
+{
+
+ tSDP_PROTOCOL_ELEM protoList [3];
+ UINT16 service = UUID_SERVCLASS_MESSAGE_NOTIFICATION;
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ BOOLEAN status = TRUE;
+ UINT32 sdp_handle = 0;
+ UINT8 temp[4];
+ UINT8* p_temp = temp;
+
+ APPL_TRACE_DEBUG("add_mas_sdp: scn 0x%02x, psm = 0x%04x\n service name %s",
+ rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm, rec->hdr.service_name);
+
+ APPL_TRACE_DEBUG(" feature_bits: 0x%08x", rec->supported_features);
+
+ if ((sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ APPL_TRACE_ERROR("add_mapc_sdp: Unable to register MAP Notification Service");
+ return sdp_handle;
+ }
+
+ /* add service class */
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+ memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
+
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+ status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(rec->hdr.service_name_length + 1),
+ (UINT8 *)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_MAP_PROFILE,
+ rec->hdr.profile_version);
+
+ /* Add supported feature */
+ UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (UINT32)4, temp);
+
+ /* Add the L2CAP PSM if present */
+ if(rec->hdr.l2cap_psm != -1) {
+ p_temp = temp;// The macro modifies p_temp, hence rewind.
+ UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+ UINT_DESC_TYPE, (UINT32)2, temp);
+ }
+
+ /* Make the service browseable */
+ status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status)
+ {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("add_mapc_sdp FAILED");
+ }
+ else
+ {
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+ APPL_TRACE_DEBUG("MAPC: SDP Registered (handle 0x%08x)", sdp_handle);
+ }
+ return sdp_handle;
+}
+
+/* Create a PBAP Server SDP record based on information stored in a bluetooth_sdp_pse_record */
+static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec)
+{
+
+ tSDP_PROTOCOL_ELEM protoList [3];
+ UINT16 service = UUID_SERVCLASS_PBAP_PSE;
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ BOOLEAN status = TRUE;
+ UINT32 sdp_handle = 0;
+ UINT8 temp[4];
+ UINT8* p_temp = temp;
+
+ APPL_TRACE_DEBUG("add_pbaps_sdp: scn 0x%02x, psm = 0x%04x\n service name %s",
+ rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm, rec->hdr.service_name);
+
+ APPL_TRACE_DEBUG(" supported_repositories: 0x%08x, feature_bits: 0x%08x",
+ rec->supported_repositories, rec->supported_features);
+
+ if ((sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ APPL_TRACE_ERROR("add_pbaps_sdp: Unable to register PBAP Server Service");
+ return sdp_handle;
+ }
+
+ /* add service class */
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+ memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
+
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+ status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(rec->hdr.service_name_length + 1),
+ (UINT8 *)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_PHONE_ACCESS,
+ rec->hdr.profile_version);
+
+ /* Add supported repositories 1 byte */
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES,
+ UINT_DESC_TYPE, (UINT32)1, (UINT8*)&rec->supported_repositories);
+
+ /* Add supported feature 4 bytes*/
+ UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_PBAP_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (UINT32)4, temp);
+
+ /* Add the L2CAP PSM if present */
+ if(rec->hdr.l2cap_psm != -1) {
+ p_temp = temp;// The macro modifies p_temp, hence rewind.
+ UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+ UINT_DESC_TYPE, (UINT32)2, temp);
+ }
+
+ /* Make the service browseable */
+ status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status)
+ {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("add_pbaps_sdp FAILED");
+ }
+ else
+ {
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+ APPL_TRACE_DEBUG("PBAPS: SDP Registered (handle 0x%08x)", sdp_handle);
+ }
+ return sdp_handle;
+}
+
+
+/* Create a OPP Server SDP record based on information stored in a bluetooth_sdp_ops_record */
+static int add_opps_sdp(const bluetooth_sdp_ops_record* rec)
+{
+
+ tSDP_PROTOCOL_ELEM protoList [3];
+ UINT16 service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ UINT8 type_len[rec->supported_formats_list_len];
+ UINT8 desc_type[rec->supported_formats_list_len];
+ UINT8 *type_value[rec->supported_formats_list_len];
+ BOOLEAN status = TRUE;
+ UINT32 sdp_handle = 0;
+ UINT8 temp[4];
+ UINT8* p_temp = temp;
+ tBTA_UTL_COD cod;
+ int i,j;
+
+ APPL_TRACE_DEBUG("add_opps_sdp: scn 0x%02x, psm = 0x%04x\n service name %s",
+ rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm, rec->hdr.service_name);
+
+ APPL_TRACE_DEBUG(" supported formats count: %d",
+ rec->supported_formats_list_len);
+
+ if ((sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ APPL_TRACE_ERROR("add_opps_sdp: Unable to register Object Push Server Service");
+ return sdp_handle;
+ }
+
+ /* add service class */
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+ memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
+
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+ status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(rec->hdr.service_name_length + 1),
+ (UINT8 *)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ rec->hdr.profile_version);
+
+ /* add sequence for supported types */
+ for (i = 0, j = 0; i < rec->supported_formats_list_len; i++)
+ {
+ type_value[j] = (UINT8 *) &rec->supported_formats_list[i];
+ desc_type[j] = UINT_DESC_TYPE;
+ type_len[j++] = 1;
+ }
+
+ status &= SDP_AddSequence(sdp_handle, (UINT16) ATTR_ID_SUPPORTED_FORMATS_LIST,
+ (UINT8) rec->supported_formats_list_len, desc_type, type_len, type_value);
+
+ /* Add the L2CAP PSM if present */
+ if(rec->hdr.l2cap_psm != -1) {
+ p_temp = temp;// The macro modifies p_temp, hence rewind.
+ UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+ UINT_DESC_TYPE, (UINT32)2, temp);
+ }
+
+ /* Make the service browseable */
+ status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status)
+ {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("add_opps_sdp FAILED");
+ }
+ else
+ {
+ /* set class of device */
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
+ APPL_TRACE_DEBUG("OPPS: SDP Registered (handle 0x%08x)", sdp_handle);
+ }
+ return sdp_handle;
+}
+
+
diff --git a/btif/src/btif_sock.c b/btif/src/btif_sock.c
index 831ae7341..c441eebce 100644
--- a/btif/src/btif_sock.c
+++ b/btif/src/btif_sock.c
@@ -27,9 +27,9 @@
#include "btif_sock_rfc.h"
#include "btif_sock_sco.h"
#include "btif_sock_thread.h"
+#include "btif_sock_l2cap.h"
+#include "btif_sock_sdp.h"
#include "btif_util.h"
-#include "osi/include/osi.h"
-#include "osi/include/log.h"
#include "osi/include/thread.h"
static bt_status_t btsock_listen(btsock_type_t type, const char *service_name, const uint8_t *uuid, int channel, int *sock_fd, int flags);
@@ -47,6 +47,7 @@ btsock_interface_t *btif_sock_get_interface(void) {
btsock_connect
};
+
return &interface;
}
@@ -67,6 +68,12 @@ bt_status_t btif_sock_init(void) {
goto error;
}
+ status = btsock_l2cap_init(thread_handle);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG_ERROR("%s error initializing L2CAP sockets: %d", __func__, status);
+ goto error;
+ }
+
thread = thread_new("btif_sock");
if (!thread) {
LOG_ERROR("%s error creating new thread.", __func__);
@@ -101,14 +108,17 @@ void btif_sock_cleanup(void) {
btsock_thread_exit(thread_handle);
btsock_rfc_cleanup();
btsock_sco_cleanup();
+ btsock_l2cap_cleanup();
thread_free(thread);
thread_handle = -1;
thread = NULL;
}
static bt_status_t btsock_listen(btsock_type_t type, const char *service_name, const uint8_t *service_uuid, int channel, int *sock_fd, int flags) {
- assert(service_uuid != NULL || channel > 0);
- assert(sock_fd != NULL);
+ if((flags & BTSOCK_FLAG_NO_SDP) == 0) {
+ assert(service_uuid != NULL || channel > 0);
+ assert(sock_fd != NULL);
+ }
*sock_fd = INVALID_FD;
bt_status_t status = BT_STATUS_FAIL;
@@ -117,6 +127,9 @@ static bt_status_t btsock_listen(btsock_type_t type, const char *service_name, c
case BTSOCK_RFCOMM:
status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd, flags);
break;
+ case BTSOCK_L2CAP:
+ status = btsock_l2cap_listen(service_name, channel, sock_fd, flags);
+ break;
case BTSOCK_SCO:
status = btsock_sco_listen(sock_fd, flags);
@@ -143,6 +156,10 @@ static bt_status_t btsock_connect(const bt_bdaddr_t *bd_addr, btsock_type_t type
status = btsock_rfc_connect(bd_addr, uuid, channel, sock_fd, flags);
break;
+ case BTSOCK_L2CAP:
+ status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags);
+ break;
+
case BTSOCK_SCO:
status = btsock_sco_connect(bd_addr, sock_fd, flags);
break;
@@ -160,7 +177,9 @@ static void btsock_signaled(int fd, int type, int flags, uint32_t user_id) {
case BTSOCK_RFCOMM:
btsock_rfc_signaled(fd, flags, user_id);
break;
-
+ case BTSOCK_L2CAP:
+ btsock_l2cap_signaled(fd, flags, user_id);
+ break;
default:
assert(false && "Invalid socket type");
break;
diff --git a/btif/src/btif_sock_l2cap.c b/btif/src/btif_sock_l2cap.c
new file mode 100644
index 000000000..8e5ef1d74
--- /dev/null
+++ b/btif/src/btif_sock_l2cap.c
@@ -0,0 +1,1070 @@
+/*
+* Copyright (C) 2014 Samsung System LSI
+* Copyright (C) 2013 The Android Open Source Project
+*
+* 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.
+*/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <pthread.h>
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bta_api.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_util.h"
+#include "btif_sock_l2cap.h"
+#include "l2cdefs.h"
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "sdp_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "port_api.h"
+#include "l2c_api.h"
+
+#include <cutils/log.h>
+#include <hardware/bluetooth.h>
+#define asrt(s) if (!(s)) APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##",__FUNCTION__, \
+ #s, __LINE__)
+
+#if __GLIBC__
+static pthread_mutex_t slot_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+#else
+static pthread_mutex_t slot_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+#endif
+
+
+struct packet {
+ struct packet *next, *prev;
+ uint32_t len;
+ uint8_t *data;
+};
+
+typedef struct l2cap_socket {
+
+ struct l2cap_socket *prev; //link to prev list item
+ struct l2cap_socket *next; //link to next list item
+ bt_bdaddr_t addr; //other side's address
+ char name[256]; //user-friendly name of the service
+ uint32_t id; //just a tag to find this struct
+ int handle; //handle from lower layers
+ unsigned security; //security flags
+ int channel; //channel (fixed_chan) or PSM (!fixed_chan)
+ int our_fd; //fd from our side
+ int app_fd; //fd from app's side
+
+ unsigned bytes_buffered;
+ struct packet *first_packet; //fist packet to be delivered to app
+ struct packet *last_packet; //last packet to be delivered to app
+
+ BUFFER_Q incoming_que; //data that came in but has not yet been read
+ unsigned fixed_chan :1; //fixed channel (or psm?)
+ unsigned server :1; //is a server? (or connecting?)
+ unsigned connected :1; //is connected?
+ unsigned outgoing_congest :1; //should we hold?
+ unsigned server_psm_sent :1; //The server shall only send PSM once.
+}l2cap_socket;
+
+static bt_status_t btSock_start_l2cap_server_l(l2cap_socket *sock);
+
+static pthread_mutex_t state_lock;
+
+l2cap_socket *socks = NULL;
+static int pth = -1;
+
+static void btsock_l2cap_cbk(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
+
+/* TODO: Consider to remove this buffer, as we have a buffer in l2cap as well, and we risk
+ * a buffer overflow with this implementation if the socket data is not read from
+ * JAVA for a while. In such a case we should use flow control to tell the sender to
+ * back off.
+ * BUT remember we need to avoid blocking the BTA task execution - hence we cannot
+ * directly write to the socket.
+ * we should be able to change to store the data pointer here, and just wait
+ * confirming the l2cap_ind until we have more space in the buffer. */
+
+/* returns FALSE if none - caller must free "data" memory when done with it */
+static char packet_get_head_l(l2cap_socket *sock, uint8_t **data, uint32_t *len)
+{
+ struct packet *p = sock->first_packet;
+
+ if (!p)
+ return FALSE;
+
+ if (data)
+ *data = sock->first_packet->data;
+ if (len)
+ *len = sock->first_packet->len;
+ sock->first_packet = p->next;
+ if (sock->first_packet)
+ sock->first_packet->prev = NULL;
+ else
+ sock->last_packet = NULL;
+
+ if(len)
+ sock->bytes_buffered -= *len;
+
+ free(p);
+
+ return TRUE;
+}
+
+static struct packet *packet_alloc(const uint8_t *data, uint32_t len)
+{
+ struct packet *p = calloc(1, sizeof(*p));
+ uint8_t *buf = malloc(len);
+
+ if (p && buf) {
+
+ p->data = buf;
+ p->len = len;
+ memcpy(p->data, data, len);
+ return p;
+
+ } else if (p)
+ free(p);
+ else if (buf)
+ free(buf);
+
+ return NULL;
+}
+
+/* makes a copy of the data, returns TRUE on success */
+static char packet_put_head_l(l2cap_socket *sock, const void *data, uint32_t len)
+{
+ struct packet *p = packet_alloc((const uint8_t*)data, len);
+
+ /*
+ * We do not check size limits here since this is used to undo "getting" a
+ * packet that the user read incompletely. That is to say the packet was
+ * already in the queue. We do check thos elimits in packet_put_tail_l() since
+ * that function is used to put new data into the queue.
+ */
+
+ if (!p)
+ return FALSE;
+
+ p->prev = NULL;
+ p->next = sock->first_packet;
+ sock->first_packet = p;
+ if (p->next)
+ p->next->prev = p;
+ else
+ sock->last_packet = p;
+
+ sock->bytes_buffered += len;
+
+ return TRUE;
+}
+
+/* makes a copy of the data, returns TRUE on success */
+static char packet_put_tail_l(l2cap_socket *sock, const void *data, uint32_t len)
+{
+ struct packet *p = packet_alloc((const uint8_t*)data, len);
+
+ if (sock->bytes_buffered >= L2CAP_MAX_RX_BUFFER) {
+ ALOGE("packet_put_tail_l: buffer overflow");
+ return FALSE;
+ }
+
+ if (!p) {
+ ALOGE("packet_put_tail_l: unable to allocate packet...");
+ return FALSE;
+ }
+
+ p->next = NULL;
+ p->prev = sock->last_packet;
+ sock->last_packet = p;
+ if (p->prev)
+ p->prev->next = p;
+ else
+ sock->first_packet = p;
+
+ sock->bytes_buffered += len;
+
+ return TRUE;
+}
+
+static inline void bd_copy(UINT8* dest, UINT8* src, BOOLEAN swap)
+{
+ if (swap) {
+ int i;
+ for (i =0; i < 6 ;i++)
+ dest[i]= src[5-i];
+ }
+ else memcpy(dest, src, 6);
+}
+
+static char is_inited(void)
+{
+ char ret;
+
+
+ pthread_mutex_lock(&state_lock);
+ ret = pth != -1;
+ pthread_mutex_unlock(&state_lock);
+
+ return ret;
+}
+
+/* only call with mutex taken */
+static l2cap_socket *btsock_l2cap_find_by_id_l(uint32_t id)
+{
+ l2cap_socket *sock = socks;
+
+ while (sock && sock->id != id)
+ sock = sock->next;
+
+ return sock;
+}
+
+static void btsock_l2cap_free_l(l2cap_socket *sock)
+{
+ uint8_t *buf;
+ l2cap_socket *t = socks;
+
+ while(t && t != sock)
+ t = t->next;
+
+ if (!t) /* prever double-frees */
+ return;
+
+ if (sock->next)
+ sock->next->prev = sock->prev;
+
+ if (sock->prev)
+ sock->prev->next = sock->next;
+ else
+ socks = sock->next;
+
+ shutdown(sock->our_fd, SHUT_RDWR);
+ close(sock->our_fd);
+ if (sock->app_fd != -1) {
+ close(sock->app_fd);
+ } else {
+ APPL_TRACE_ERROR("SOCK_LIST: free(id = %d) - NO app_fd!", sock->id);
+ }
+
+ while (packet_get_head_l(sock, &buf, NULL))
+ free(buf);
+
+ //lower-level close() should be idempotent... so let's call it and see...
+ // Only call if we are non server connections
+ if (sock->handle && (sock->server == FALSE)) {
+ if (sock->fixed_chan)
+ BTA_JvL2capCloseLE(sock->handle);
+ else
+ BTA_JvL2capClose(sock->handle);
+ }
+ if ((sock->channel >= 0) && (sock->server == TRUE)) {
+ if (sock->fixed_chan) {
+ BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP_LE);
+ } else {
+ BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+ }
+ }
+
+ APPL_TRACE_DEBUG("SOCK_LIST: free(id = %d)", sock->id);
+ free(sock);
+}
+
+static void btsock_l2cap_free(l2cap_socket *sock)
+{
+ pthread_mutex_lock(&state_lock);
+ btsock_l2cap_free_l(sock);
+ pthread_mutex_unlock(&state_lock);
+}
+
+static l2cap_socket *btsock_l2cap_alloc_l(const char *name, const bt_bdaddr_t *addr,
+ char is_server, int flags)
+{
+ l2cap_socket *sock;
+ unsigned security = 0;
+ int fds[2];
+
+ if (flags & BTSOCK_FLAG_ENCRYPT)
+ security |= is_server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT;
+ if (flags & BTSOCK_FLAG_AUTH)
+ security |= is_server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE;
+
+ sock = calloc(1, sizeof(*sock));
+ if (!sock) {
+ APPL_TRACE_ERROR("alloc failed");
+ goto fail_alloc;
+ }
+
+ if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, fds)) {
+ APPL_TRACE_ERROR("socketpair failed, errno:%d", errno);
+ goto fail_sockpair;
+ }
+
+ sock->our_fd = fds[0];
+ sock->app_fd = fds[1];
+ sock->security = security;
+ sock->server = is_server;
+ sock->connected = FALSE;
+ sock->handle = 0;
+ sock->server_psm_sent = FALSE;
+
+ if (name)
+ strncpy(sock->name, name, sizeof(sock->name) - 1);
+ if (addr)
+ sock->addr = *addr;
+
+ sock->first_packet = NULL;
+ sock->last_packet = NULL;
+
+ sock->next = socks;
+ sock->prev = NULL;
+ if (socks)
+ socks->prev = sock;
+ sock->id = (socks ? socks->id : 0) + 1;
+ socks = sock;
+ /* paranoia cap on: verify no ID duplicates due to overflow and fix as needed */
+ while (1) {
+ l2cap_socket *t;
+ t = socks->next;
+ while (t && t->id != sock->id) {
+ t = t->next;
+ }
+ if (!t && sock->id) /* non-zeor handle is unique -> we're done */
+ break;
+ /* if we're here, we found a duplicate */
+ if (!++sock->id) /* no zero IDs allowed */
+ sock->id++;
+ }
+ APPL_TRACE_DEBUG("SOCK_LIST: alloc(id = %d)", sock->id);
+ return sock;
+
+fail_sockpair:
+ free(sock);
+
+fail_alloc:
+ return NULL;
+}
+
+static l2cap_socket *btsock_l2cap_alloc(const char *name, const bt_bdaddr_t *addr,
+ char is_server, int flags)
+{
+ l2cap_socket *ret;
+
+ pthread_mutex_lock(&state_lock);
+ ret = btsock_l2cap_alloc_l(name, addr, is_server, flags);
+ pthread_mutex_unlock(&state_lock);
+
+ return ret;
+}
+
+bt_status_t btsock_l2cap_init(int handle)
+{
+ APPL_TRACE_DEBUG("btsock_l2cap_init...");
+ pthread_mutex_lock(&state_lock);
+ pth = handle;
+ socks = NULL;
+ pthread_mutex_unlock(&state_lock);
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_l2cap_cleanup()
+{
+ pthread_mutex_lock(&state_lock);
+ pth = -1;
+ while (socks)
+ btsock_l2cap_free_l(socks);
+ pthread_mutex_unlock(&state_lock);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static inline BOOLEAN send_app_psm_or_chan_l(l2cap_socket *sock)
+{
+ return sock_send_all(sock->our_fd, (const uint8_t*)&sock->channel, sizeof(sock->channel))
+ == sizeof(sock->channel);
+}
+
+static BOOLEAN send_app_connect_signal(int fd, const bt_bdaddr_t* addr,
+ int channel, int status, int send_fd, int tx_mtu)
+{
+ sock_connect_signal_t cs;
+ cs.size = sizeof(cs);
+ cs.bd_addr = *addr;
+ cs.channel = channel;
+ cs.status = status;
+ cs.max_rx_packet_size = L2CAP_MAX_SDU_LENGTH;
+ cs.max_tx_packet_size = tx_mtu;
+ if (send_fd != -1) {
+ if (sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) == sizeof(cs))
+ return TRUE;
+ else APPL_TRACE_ERROR("sock_send_fd failed, fd:%d, send_fd:%d", fd, send_fd);
+ } else if (sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void on_srv_l2cap_listen_started(tBTA_JV_L2CAP_START *p_start, uint32_t id)
+{
+ l2cap_socket *sock;
+
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (sock) {
+ if (p_start->status != BTA_JV_SUCCESS) {
+ APPL_TRACE_ERROR("Error starting l2cap_listen - status: 0x%04x", p_start->status);
+ btsock_l2cap_free_l(sock);
+ }
+ else {
+ sock->handle = p_start->handle;
+ APPL_TRACE_DEBUG("on_srv_l2cap_listen_started() sock->handle =%d id:%d",
+ sock->handle, sock->id);
+ if(sock->server_psm_sent == FALSE) {
+ if (!send_app_psm_or_chan_l(sock)) {
+ //closed
+ APPL_TRACE_DEBUG("send_app_psm() failed, close rs->id:%d", sock->id);
+ btsock_l2cap_free_l(sock);
+ } else {
+ sock->server_psm_sent = TRUE;
+ }
+ }
+ }
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+static void on_cl_l2cap_init(tBTA_JV_L2CAP_CL_INIT *p_init, uint32_t id)
+{
+ l2cap_socket *sock;
+
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (sock) {
+ if (p_init->status != BTA_JV_SUCCESS) {
+ btsock_l2cap_free_l(sock);
+ } else {
+ sock->handle = p_init->handle;
+ }
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+/**
+ * Here we allocate a new sock instance to mimic the BluetoothSocket. The socket will be a clone
+ * of the sock representing the BluetoothServerSocket.
+ * */
+static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN *p_open, l2cap_socket *sock)
+{
+ l2cap_socket *accept_rs;
+ uint32_t new_listen_id;
+
+ // Mutex locked by caller
+ accept_rs = btsock_l2cap_alloc_l(sock->name, (const bt_bdaddr_t*)p_open->rem_bda, FALSE, 0);
+ accept_rs->connected = TRUE;
+ accept_rs->security = sock->security;
+ accept_rs->fixed_chan = sock->fixed_chan;
+ accept_rs->channel = sock->channel;
+ accept_rs->handle = sock->handle;
+ sock->handle = -1; /* We should no longer associate this handle with the server socket */
+
+ /* Swap IDs to hand over the GAP connection to the accepted socket, and start a new server on
+ the newly create socket ID. */
+ new_listen_id = accept_rs->id;
+ accept_rs->id = sock->id;
+ sock->id = new_listen_id;
+
+ if (accept_rs) {
+ //start monitor the socket
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_EXCEPTION, sock->id);
+ btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+ accept_rs->id);
+ APPL_TRACE_DEBUG("sending connect signal & app fd: %d to app server to accept() the"
+ " connection", accept_rs->app_fd);
+ APPL_TRACE_DEBUG("server fd:%d, scn:%d", sock->our_fd, sock->channel);
+ send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
+ accept_rs->app_fd, p_open->tx_mtu);
+ accept_rs->app_fd = -1; // The fd is closed after sent to app in send_app_connect_signal()
+ // But for some reason we still leak a FD - either the server socket
+ // one or the accept socket one.
+ if(btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS) {
+ btsock_l2cap_free_l(sock);
+ }
+ }
+}
+
+static void on_srv_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN *p_open, l2cap_socket *sock)
+{
+ l2cap_socket *accept_rs;
+ uint32_t new_listen_id;
+
+ // mutex locked by caller
+ accept_rs = btsock_l2cap_alloc_l(sock->name, (const bt_bdaddr_t*)p_open->rem_bda, FALSE, 0);
+ if (accept_rs) {
+
+ //swap IDs
+ new_listen_id = accept_rs->id;
+ accept_rs->id = sock->id;
+ sock->id = new_listen_id;
+
+ accept_rs->handle = p_open->handle;
+ accept_rs->connected = TRUE;
+ accept_rs->security = sock->security;
+ accept_rs->fixed_chan = sock->fixed_chan;
+ accept_rs->channel = sock->channel;
+
+ //if we do not set a callback, this socket will be dropped */
+ *(p_open->p_p_cback) = (void*)btsock_l2cap_cbk;
+ *(p_open->p_user_data) = (void*)accept_rs->id;
+
+ //start monitor the socket
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_EXCEPTION, sock->id);
+ btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+ accept_rs->id);
+ APPL_TRACE_DEBUG("sending connect signal & app fd:%dto app server to accept() the"
+ " connection", accept_rs->app_fd);
+ APPL_TRACE_DEBUG("server fd:%d, scn:%d", sock->our_fd, sock->channel);
+ send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
+ accept_rs->app_fd, p_open->tx_mtu);
+ accept_rs->app_fd = -1; //the fd is closed after sent to app
+ }
+}
+
+static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN *p_open, l2cap_socket *sock)
+{
+ bd_copy(sock->addr.address, p_open->rem_bda, 0);
+
+ if (!send_app_psm_or_chan_l(sock)) {
+ APPL_TRACE_ERROR("send_app_psm_or_chan_l failed");
+ return;
+ }
+
+ if (send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1, p_open->tx_mtu)) {
+ //start monitoring the socketpair to get call back when app writing data
+ APPL_TRACE_DEBUG("on_l2cap_connect_ind, connect signal sent, slot id:%d, psm:%d,"
+ " server:%d", sock->id, sock->channel, sock->server);
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
+ sock->connected = TRUE;
+ }
+ else APPL_TRACE_ERROR("send_app_connect_signal failed");
+}
+
+static void on_cl_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN *p_open, l2cap_socket *sock)
+{
+ bd_copy(sock->addr.address, p_open->rem_bda, 0);
+
+ if (!send_app_psm_or_chan_l(sock)) {
+ APPL_TRACE_ERROR("send_app_psm_or_chan_l failed");
+ return;
+ }
+
+ if (send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1, p_open->tx_mtu)) {
+ //start monitoring the socketpair to get call back when app writing data
+ APPL_TRACE_DEBUG("on_l2cap_connect_ind, connect signal sent, slot id:%d, Chan:%d,"
+ " server:%d", sock->id, sock->channel, sock->server);
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
+ sock->connected = TRUE;
+ }
+ else APPL_TRACE_ERROR("send_app_connect_signal failed");
+}
+
+static void on_l2cap_connect(tBTA_JV *p_data, uint32_t id)
+{
+ l2cap_socket *sock;
+ tBTA_JV_L2CAP_OPEN *psm_open = &p_data->l2c_open;
+ tBTA_JV_L2CAP_LE_OPEN *le_open = &p_data->l2c_le_open;
+
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) {
+ APPL_TRACE_ERROR("on_l2cap_connect on unknown socket");
+ } else {
+ if (sock->fixed_chan && le_open->status == BTA_JV_SUCCESS) {
+ if (!sock->server)
+ on_cl_l2cap_le_connect_l(le_open, sock);
+ else
+ on_srv_l2cap_le_connect_l(le_open, sock);
+ } else if (!sock->fixed_chan && psm_open->status == BTA_JV_SUCCESS) {
+ if (!sock->server)
+ on_cl_l2cap_psm_connect_l(psm_open, sock);
+ else
+ on_srv_l2cap_psm_connect_l(psm_open, sock);
+ }
+ else
+ btsock_l2cap_free_l(sock);
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+static void on_l2cap_close(tBTA_JV_L2CAP_CLOSE * p_close, uint32_t id)
+{
+ l2cap_socket *sock;
+
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (sock) {
+ APPL_TRACE_DEBUG("on_l2cap_close, slot id:%d, fd:%d, %s:%d, server:%d",
+ sock->id, sock->our_fd, sock->fixed_chan ? "fixed_chan" : "PSM",
+ sock->channel, sock->server);
+ sock->handle = 0;
+ // TODO: This does not seem to be called...
+ // I'm not sure if this will be called for non-server sockets?
+ if(!sock->fixed_chan && (sock->server == TRUE)) {
+ BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+ }
+ btsock_l2cap_free_l(sock);
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+static void on_l2cap_outgoing_congest(tBTA_JV_L2CAP_CONG *p, uint32_t id)
+{
+ l2cap_socket *sock;
+
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (sock) {
+ sock->outgoing_congest = p->cong ? 1 : 0;
+ //mointer the fd for any outgoing data
+ if (!sock->outgoing_congest) {
+ APPL_TRACE_DEBUG("on_l2cap_outgoing_congest: adding fd to btsock_thread...");
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
+
+ }
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+static void on_l2cap_write_done(void* req_id, uint32_t id)
+{
+ l2cap_socket *sock;
+
+ if (req_id != NULL) {
+ free(req_id); //free the buffer
+ }
+
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (sock && !sock->outgoing_congest) {
+ //monitor the fd for any outgoing data
+ APPL_TRACE_DEBUG("on_l2cap_write_done: adding fd to btsock_thread...");
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+static void on_l2cap_write_fixed_done(void* req_id, uint32_t id)
+{
+ l2cap_socket *sock;
+
+ if (req_id != NULL) {
+ free(req_id); //free the buffer
+ }
+
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (sock && !sock->outgoing_congest) {
+ //monitor the fd for any outgoing data
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+
+
+static void on_l2cap_data_ind(tBTA_JV *evt, uint32_t id)
+{
+ l2cap_socket *sock;
+
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (sock) {
+ if (sock->fixed_chan) { /* we do these differently */
+
+ tBTA_JV_LE_DATA_IND *p_le_data_ind = &evt->le_data_ind;
+ BT_HDR *p_buf = p_le_data_ind->p_buf;
+ uint8_t *data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ if (packet_put_tail_l(sock, data, p_buf->len))
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR, sock->id);
+ else {//connection must be dropped
+ APPL_TRACE_DEBUG("on_l2cap_data_ind() unable to push data to socket - closing"
+ " fixed channel");
+ BTA_JvL2capCloseLE(sock->handle);
+ btsock_l2cap_free_l(sock);
+ }
+
+ } else {
+
+ tBTA_JV_DATA_IND *p_data_ind = &evt->data_ind;
+ UINT8 buffer[L2CAP_MAX_SDU_LENGTH];
+ UINT32 count;
+
+ if (BTA_JvL2capReady(sock->handle, &count) == BTA_JV_SUCCESS) {
+ if (BTA_JvL2capRead(sock->handle, sock->id, buffer, count) == BTA_JV_SUCCESS) {
+ if (packet_put_tail_l(sock, buffer, count))
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR,
+ sock->id);
+ else {//connection must be dropped
+ APPL_TRACE_DEBUG("on_l2cap_data_ind() unable to push data to socket"
+ " - closing channel");
+ BTA_JvL2capClose(sock->handle);
+ btsock_l2cap_free_l(sock);
+ }
+ }
+ }
+ }
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+static void btsock_l2cap_cbk(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
+{
+ int rc;
+
+ switch (event) {
+ case BTA_JV_L2CAP_START_EVT:
+ on_srv_l2cap_listen_started(&p_data->l2c_start, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_L2CAP_CL_INIT_EVT:
+ on_cl_l2cap_init(&p_data->l2c_cl_init, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_L2CAP_OPEN_EVT:
+ on_l2cap_connect(p_data, (uint32_t)user_data);
+ BTA_JvSetPmProfile(p_data->l2c_open.handle,BTA_JV_PM_ID_1,BTA_JV_CONN_OPEN);
+ break;
+
+ case BTA_JV_L2CAP_CLOSE_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_CLOSE_EVT: user_data:%d", (uint32_t)user_data);
+ on_l2cap_close(&p_data->l2c_close, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_L2CAP_DATA_IND_EVT:
+ on_l2cap_data_ind(p_data, (uint32_t)user_data);
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_DATA_IND_EVT");
+ break;
+
+ case BTA_JV_L2CAP_READ_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_READ_EVT not used");
+ break;
+
+ case BTA_JV_L2CAP_RECEIVE_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_RECEIVE_EVT not used");
+ break;
+
+ case BTA_JV_L2CAP_WRITE_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_EVT id: %d", (int)user_data);
+ on_l2cap_write_done((void*)p_data->l2c_write.req_id, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_L2CAP_WRITE_FIXED_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_FIXED_EVT id: %d", (int)user_data);
+ on_l2cap_write_fixed_done((void*)p_data->l2c_write_fixed.req_id, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_L2CAP_CONG_EVT:
+ on_l2cap_outgoing_congest(&p_data->l2c_cong, (uint32_t)user_data);
+ break;
+
+ default:
+ APPL_TRACE_ERROR("unhandled event %d, slot id:%d", event, (uint32_t)user_data);
+ break;
+ }
+}
+
+/* L2CAP default options for OBEX socket connections */
+const tL2CAP_FCR_OPTS obex_l2c_fcr_opts_def =
+{
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for OBEX over l2cap */
+ OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR,/* Tx window size */
+ OBX_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ OBX_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ OBX_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ OBX_FCR_OPT_MAX_PDU_SIZE /* MPS segment size */
+};
+const tL2CAP_ERTM_INFO obex_l2c_etm_opt =
+{
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for OBEX over l2cap */
+ L2CAP_FCR_CHAN_OPT_ERTM, /* Mandatory for OBEX over l2cap */
+ OBX_USER_RX_POOL_ID,
+ OBX_USER_TX_POOL_ID,
+ OBX_FCR_RX_POOL_ID,
+ OBX_FCR_TX_POOL_ID
+};
+
+/**
+ * When using a dynamic PSM, a PSM allocation is requested from btsock_l2cap_listen_or_connect().
+ * The PSM allocation event is refeived in the JV-callback - currently located in RFC-code -
+ * and this function is called with the newly allocated PSM.
+ */
+void on_l2cap_psm_assigned(int id, int psm) {
+ l2cap_socket *sock;
+ /* Setup ETM settings:
+ * mtu will be set below */
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ sock->channel = psm;
+
+ if(btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS) {
+ btsock_l2cap_free_l(sock);
+ }
+
+ pthread_mutex_unlock(&state_lock);
+
+}
+
+static bt_status_t btSock_start_l2cap_server_l(l2cap_socket *sock) {
+ tL2CAP_CFG_INFO cfg;
+ bt_status_t stat = BT_STATUS_SUCCESS;
+ /* Setup ETM settings:
+ * mtu will be set below */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ cfg.fcr_present = TRUE;
+ cfg.fcr = obex_l2c_fcr_opts_def;
+
+ if (sock->fixed_chan) {
+
+ if (BTA_JvL2capStartServerLE(sock->security, 0, NULL, sock->channel,
+ L2CAP_DEFAULT_MTU, NULL, btsock_l2cap_cbk, (void*)sock->id)
+ != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+
+ } else {
+ /* If we have a channel specified in the request, just start the server,
+ * else we request a PSM and start the server after we receive a PSM. */
+ if(sock->channel < 0) {
+ if(BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP, (void*)sock->id, 0)
+ != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ } else {
+ if (BTA_JvL2capStartServer(sock->security, 0, &obex_l2c_etm_opt,
+ sock->channel, L2CAP_MAX_SDU_LENGTH, &cfg, btsock_l2cap_cbk, (void*)sock->id)
+ != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ }
+ }
+ return stat;
+}
+
+static bt_status_t btsock_l2cap_listen_or_connect(const char *name, const bt_bdaddr_t *addr,
+ int channel, int* sock_fd, int flags, char listen)
+{
+ bt_status_t stat;
+ int fixed_chan = 1;
+ l2cap_socket *sock;
+ tL2CAP_CFG_INFO cfg;
+
+ if (!sock_fd)
+ return BT_STATUS_PARM_INVALID;
+
+ if(channel < 0) {
+ // We need to auto assign a PSM
+ fixed_chan = 0;
+ } else {
+ fixed_chan = (channel & L2CAP_MASK_FIXED_CHANNEL) != 0;
+ channel &=~ L2CAP_MASK_FIXED_CHANNEL;
+ }
+
+ if (!is_inited())
+ return BT_STATUS_NOT_READY;
+
+ // TODO: This is kind of bad to lock here, but it is needed for the current design.
+ pthread_mutex_lock(&state_lock);
+
+ sock = btsock_l2cap_alloc_l(name, addr, listen, flags);
+ if (!sock)
+ return BT_STATUS_NOMEM;
+
+ sock->fixed_chan = fixed_chan;
+ sock->channel = channel;
+
+ stat = BT_STATUS_SUCCESS;
+
+ /* Setup ETM settings:
+ * mtu will be set below */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ cfg.fcr_present = TRUE;
+ cfg.fcr = obex_l2c_fcr_opts_def;
+
+ /* "role" is never initialized in rfcomm code */
+ if (listen) {
+ stat = btSock_start_l2cap_server_l(sock);
+ } else {
+ if (fixed_chan) {
+ if (BTA_JvL2capConnectLE(sock->security, 0, NULL, channel,
+ L2CAP_DEFAULT_MTU, NULL, sock->addr.address, btsock_l2cap_cbk,
+ (void*)sock->id) != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+
+ } else {
+ if (BTA_JvL2capConnect(sock->security, 0, &obex_l2c_etm_opt,
+ channel, L2CAP_MAX_SDU_LENGTH, &cfg, sock->addr.address,
+ btsock_l2cap_cbk, (void*)sock->id) != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ }
+ }
+
+ if (stat == BT_STATUS_SUCCESS) {
+ *sock_fd = sock->app_fd;
+ /* We pass the FD to JAVA, but since it runs in another process, we need to also close
+ * it in native, either straight away, as done when accepting an incoming connection,
+ * or when doing cleanup after this socket */
+ sock->app_fd = -1; /*This leaks the file descriptor. The FD should be closed in
+ JAVA but it apparently do not work */
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_EXCEPTION,
+ sock->id);
+ } else {
+ btsock_l2cap_free_l(sock);
+ }
+ pthread_mutex_unlock(&state_lock);
+
+ return stat;
+}
+
+bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd, int flags)
+{
+ return btsock_l2cap_listen_or_connect(name, NULL, channel, sock_fd, flags, 1);
+}
+
+bt_status_t btsock_l2cap_connect(const bt_bdaddr_t *bd_addr, int channel, int* sock_fd, int flags)
+{
+ return btsock_l2cap_listen_or_connect(NULL, bd_addr, channel, sock_fd, flags, 0);
+}
+
+/* return TRUE if we have more to send and should wait for user readiness, FALSE else
+ * (for example: unrecoverable error or no data)
+ */
+static BOOLEAN flush_incoming_que_on_wr_signal_l(l2cap_socket *sock)
+{
+ uint8_t *buf;
+ uint32_t len;
+
+ while (packet_get_head_l(sock, &buf, &len)) {
+ int sent = send(sock->our_fd, buf, len, MSG_DONTWAIT);
+
+ if (sent == (signed)len)
+ free(buf);
+ else if (sent >= 0) {
+ packet_put_head_l(sock, buf + sent, len - sent);
+ free(buf);
+ if (!sent) /* special case if other end not keeping up */
+ return TRUE;
+ }
+ else {
+ packet_put_head_l(sock, buf, len);
+ free(buf);
+ return errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN;
+ }
+ }
+
+ return FALSE;
+}
+
+void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id)
+{
+ l2cap_socket *sock;
+ char drop_it = FALSE;
+
+ /* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to hold the lock. */
+ pthread_mutex_lock(&state_lock);
+ sock = btsock_l2cap_find_by_id_l(user_id);
+ if (sock) {
+ if ((flags & SOCK_THREAD_FD_RD) && !sock->server) {
+ //app sending data
+ if (sock->connected) {
+ int size = 0;
+
+ if (!(flags & SOCK_THREAD_FD_EXCEPTION) || (ioctl(sock->our_fd, FIONREAD, &size)
+ == 0 && size)) {
+ uint8_t *buffer = malloc(L2CAP_MAX_SDU_LENGTH);
+ //uint8_t *buffer = (uint8_t*)GKI_getbuf(L2CAP_MAX_SDU_LENGTH);
+ /* Apparently we hijack the req_id (UINT32) to pass the pointer to the buffer to
+ * the write complete callback, which call a free... wonder if this works on a
+ * 64 bit platform? */
+ if (buffer != NULL) {
+ /* The socket is created with SOCK_SEQPACKET, hence we read one message at
+ * the time. The maximum size of a message is allocated to ensure data is
+ * not lost. This is okay to do as Android uses virtual memory, hence even
+ * if we only use a fraction of the memory it should not block for others
+ * to use the memory. As the definition of ioctl(FIONREAD) do not clearly
+ * define what value will be returned if multiple messages are written to
+ * the socket before any message is read from the socket, we could
+ * potentially risk to allocate way more memory than needed. One of the use
+ * cases for this socket is obex where multiple 64kbyte messages are
+ * typically written to the socket in a tight loop, hence we risk the ioctl
+ * will return the total amount of data in the buffer, which could be
+ * multiple 64kbyte chunks.
+ * UPDATE: As bluedroid cannot handle 64kbyte buffers, the size is reduced
+ * to around 8kbyte - and using malloc for buffer allocation here seems to
+ * be wrong
+ * UPDATE: Since we are responsible for freeing the buffer in the
+ * write_complete_ind, it is OK to use malloc. */
+
+ int count = recv(fd, buffer, L2CAP_MAX_SDU_LENGTH,
+ MSG_NOSIGNAL | MSG_DONTWAIT);
+ APPL_TRACE_DEBUG("btsock_l2cap_signaled - %d bytes received from socket",
+ count);
+ if (sock->fixed_chan) {
+ if(BTA_JvL2capWriteFixed(sock->channel, (BD_ADDR*)&sock->addr,
+ (UINT32)buffer, btsock_l2cap_cbk, buffer, count,
+ (void *)user_id) != BTA_JV_SUCCESS) {
+ // On fail, free the buffer
+ on_l2cap_write_fixed_done(buffer, user_id);
+ }
+ } else {
+ if(BTA_JvL2capWrite(sock->handle, (UINT32)buffer, buffer, count,
+ (void *)user_id) != BTA_JV_SUCCESS) {
+ // On fail, free the buffer
+ on_l2cap_write_done(buffer, user_id);
+ }
+ }
+ } else {
+ // This cannot happen.
+ APPL_TRACE_ERROR("Unable to allocate memory for data packet from JAVA...")
+ }
+ }
+ } else
+ drop_it = TRUE;
+ }
+ if (flags & SOCK_THREAD_FD_WR) {
+ //app is ready to receive more data, tell stack to enable the data flow
+ if (flush_incoming_que_on_wr_signal_l(sock) && sock->connected)
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR, sock->id);
+ }
+ if (drop_it || (flags & SOCK_THREAD_FD_EXCEPTION)) {
+ int size = 0;
+ if (drop_it || ioctl(sock->our_fd, FIONREAD, &size) != 0 || size == 0)
+ btsock_l2cap_free_l(sock);
+ }
+ }
+ pthread_mutex_unlock(&state_lock);
+}
+
+
+
diff --git a/btif/src/btif_sock_rfc.c b/btif/src/btif_sock_rfc.c
index 0ece691c5..01326ab48 100644
--- a/btif/src/btif_sock_rfc.c
+++ b/btif/src/btif_sock_rfc.c
@@ -36,6 +36,11 @@
#include "btif_sock_sdp.h"
#include "btif_sock_thread.h"
#include "btif_sock_util.h"
+/* The JV interface can have only one user, hence we need to call a few
+ * L2CAP functions from this file. */
+#include "btif_sock_l2cap.h"
+
+
#include "btif_util.h"
#include "btm_api.h"
#include "btm_int.h"
@@ -66,7 +71,9 @@ typedef struct {
uint32_t id; // Non-zero indicates a valid (in-use) slot.
int security;
int scn; // Server channel number
+ int scn_notified;
bt_bdaddr_t addr;
+ int is_service_uuid_valid;
uint8_t service_uuid[16];
char service_name[256];
int fd;
@@ -93,7 +100,7 @@ static rfc_slot_t *find_free_slot(void);
static void cleanup_rfc_slot(rfc_slot_t *rs);
static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
-static bool send_app_scn(const rfc_slot_t *rs);
+static bool send_app_scn(rfc_slot_t *rs);
static bool is_init_done(void) {
return pth != -1;
@@ -194,14 +201,18 @@ static rfc_slot_t *alloc_rfc_slot(const bt_bdaddr_t *addr, const char *name, con
slot->security = security;
slot->scn = channel;
- if (uuid)
+ if(!is_uuid_empty(uuid)) {
memcpy(slot->service_uuid, uuid, sizeof(slot->service_uuid));
- else
- memset(&slot->service_uuid, 0, sizeof(slot->service_uuid));
-
- if (name)
+ slot->is_service_uuid_valid = true;
+ } else {
+ memset(slot->service_uuid, 0, sizeof(slot->service_uuid));
+ slot->is_service_uuid_valid = false;
+ }
+ if(name && *name) {
strlcpy(slot->service_name, name, sizeof(slot->service_name));
-
+ } else {
+ memset(slot->service_name, 0, sizeof(slot->service_name));
+ }
if (addr)
slot->addr = *addr;
@@ -241,7 +252,9 @@ static rfc_slot_t *create_srv_accept_rfc_slot(rfc_slot_t *srv_rs, const bt_bdadd
bt_status_t btsock_rfc_listen(const char *service_name, const uint8_t *service_uuid, int channel, int *sock_fd, int flags) {
assert(sock_fd != NULL);
- assert(service_uuid != NULL || (channel >= 1 && channel <= MAX_RFC_CHANNEL));
+ assert((service_uuid != NULL)
+ || (channel >= 1 && channel <= MAX_RFC_CHANNEL)
+ || ((flags & BTSOCK_FLAG_NO_SDP) != 0));
*sock_fd = INVALID_FD;
@@ -250,13 +263,18 @@ bt_status_t btsock_rfc_listen(const char *service_name, const uint8_t *service_u
if (!is_init_done())
return BT_STATUS_NOT_READY;
- if (!is_uuid_empty(service_uuid)) {
- // Use a pre-defined channel # if the UUID is reserved.
- int reserved_channel = get_reserved_rfc_channel(service_uuid);
- if (reserved_channel != -1)
- channel = reserved_channel;
- } else {
- service_uuid = UUID_SPP; // Use serial port profile to listen to specified channel
+ if((flags & BTSOCK_FLAG_NO_SDP) == 0) {
+ if(is_uuid_empty(service_uuid)) {
+ APPL_TRACE_DEBUG("BTA_JvGetChannelId: service_uuid not set AND "
+ "BTSOCK_FLAG_NO_SDP is not set - changing to SPP");
+ service_uuid = UUID_SPP; // Use serial port profile to listen to specified channel
+ } else {
+ //Check the service_uuid. overwrite the channel # if reserved
+ int reserved_channel = get_reserved_rfc_channel(service_uuid);
+ if (reserved_channel > 0) {
+ channel = reserved_channel;
+ }
+ }
}
int status = BT_STATUS_FAIL;
@@ -267,9 +285,16 @@ bt_status_t btsock_rfc_listen(const char *service_name, const uint8_t *service_u
LOG_ERROR("%s unable to allocate RFCOMM slot.", __func__);
goto out;
}
-
- BTA_JvCreateRecordByUser((void *)(uintptr_t)slot->id);
+ APPL_TRACE_DEBUG("BTA_JvGetChannelId: service_name: %s - channel: %d", service_name, channel);
+ BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, (void*) slot->id, channel);
*sock_fd = slot->app_fd; // Transfer ownership of fd to caller.
+ /*TODO:
+ * We are leaking one of the app_fd's - either the listen socket, or the connection socket.
+ * WE need to close this in native, as the FD might belong to another process
+ - This is the server socket FD
+ - For accepted connections, we close the FD after passing it to JAVA.
+ - Try to simply remove the = -1 to free the FD at rs cleanup.*/
+// close(rs->app_fd);
slot->app_fd = INVALID_FD; // Drop our reference to the fd.
btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, slot->id);
@@ -339,16 +364,9 @@ out:;
}
static int create_server_sdp_record(rfc_slot_t *slot) {
- if (slot->scn > 0) {
- if (!BTM_TryAllocateSCN(slot->scn)) {
- LOG_ERROR("%s attempting to allocate fixed channel %d which is already in use.", __func__, slot->scn);
- return false;
+ if(slot->scn == 0) {
+ return false;
}
- } else if ((slot->scn = BTM_AllocateSCN()) == 0) {
- LOG_ERROR("%s unable to allocate RFCOMM server channel.", __func__);
- return false;
- }
-
slot->sdp_handle = add_rfc_sdp_rec(slot->service_name, slot->service_uuid, slot->scn);
return (slot->sdp_handle > 0);
}
@@ -395,9 +413,15 @@ static void cleanup_rfc_slot(rfc_slot_t *slot) {
slot->rfc_port_handle = 0;
memset(&slot->f, 0, sizeof(slot->f));
slot->id = 0;
+ slot->scn_notified = false;
}
-static bool send_app_scn(const rfc_slot_t *slot) {
+static bool send_app_scn(rfc_slot_t *slot) {
+ if(slot->scn_notified == true) {
+ //already send, just return success.
+ return true;
+ }
+ slot->scn_notified = true;
return sock_send_all(slot->fd, (const uint8_t*)&slot->scn, sizeof(slot->scn)) == sizeof(slot->scn);
}
@@ -407,7 +431,8 @@ static bool send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel
cs.bd_addr = *addr;
cs.channel = channel;
cs.status = status;
-
+ cs.max_rx_packet_size = 0; // not used for RFCOMM
+ cs.max_tx_packet_size = 0; // not used for RFCOMM
if (send_fd == INVALID_FD)
return sock_send_all(fd, (const uint8_t *)&cs, sizeof(cs)) == sizeof(cs);
@@ -439,11 +464,6 @@ static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START *p_start, uint32_t id
if (p_start->status == BTA_JV_SUCCESS) {
slot->rfc_handle = p_start->handle;
-
- if (!send_app_scn(slot)) {
- LOG_ERROR("%s unable to send server channel number for slot %d.", __func__, slot->id);
- cleanup_rfc_slot(slot);
- }
} else
cleanup_rfc_slot(slot);
@@ -583,6 +603,52 @@ static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) {
static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) {
uint32_t id = (uintptr_t)user_data;
switch(event) {
+ case BTA_JV_GET_SCN_EVT:
+ {
+ pthread_mutex_lock(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ int new_scn = p_data->scn;
+
+ if(rs && (new_scn != 0))
+ {
+ rs->scn = new_scn;
+ /* BTA_JvCreateRecordByUser will only create a record if a UUID is specified,
+ * else it just allocate a RFC channel and start the RFCOMM thread - needed
+ * for the java
+ * layer to get a RFCOMM channel.
+ * If uuid is null the create_sdp_record() will be called from Java when it
+ * has received the RFCOMM and L2CAP channel numbers through the sockets.*/
+
+ // Send channel ID to java layer
+ if(!send_app_scn(rs)){
+ //closed
+ APPL_TRACE_DEBUG("send_app_scn() failed, close rs->id:%d", rs->id);
+ cleanup_rfc_slot(rs);
+ } else {
+ if(rs->is_service_uuid_valid == true) {
+ // We already have data for SDP record, create it (RFC-only profiles)
+ BTA_JvCreateRecordByUser((void *)rs->id);
+ } else {
+ APPL_TRACE_DEBUG("is_service_uuid_valid==false - don't set SDP-record, "
+ "just start the RFCOMM server", rs->id);
+ //now start the rfcomm server after sdp & channel # assigned
+ BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION,
+ rfcomm_cback, (void*)rs->id);
+ }
+ }
+ } else if(rs) {
+ APPL_TRACE_ERROR("jv_dm_cback: Error: allocate channel %d, slot found:%p", rs->scn, rs);
+ cleanup_rfc_slot(rs);
+ }
+ pthread_mutex_unlock(&slot_lock);
+ break;
+ }
+ case BTA_JV_GET_PSM_EVT:
+ {
+ APPL_TRACE_DEBUG("Received PSM: 0x%04x", p_data->psm);
+ on_l2cap_psm_assigned(id, p_data->psm);
+ break;
+ }
case BTA_JV_CREATE_RECORD_EVT: {
pthread_mutex_lock(&slot_lock);
@@ -717,6 +783,9 @@ void btsock_rfc_signaled(UNUSED_ATTR int fd, int flags, uint32_t user_id) {
// Make sure there's data pending in case the peer closed the socket.
int size = 0;
if (!(flags & SOCK_THREAD_FD_EXCEPTION) || (ioctl(slot->fd, FIONREAD, &size) == 0 && size))
+ //unlock before BTA_JvRfcommWrite to avoid deadlock on concurrnet multi rfcomm connectoins
+ //concurrnet multi rfcomm connectoins
+ pthread_mutex_unlock(&slot_lock);
BTA_JvRfcommWrite(slot->rfc_handle, slot->id);
} else {
LOG_ERROR("%s socket signaled for read while disconnected, slot: %d, channel: %d", __func__, slot->id, slot->scn);
diff --git a/btif/src/btif_sock_sdp.c b/btif/src/btif_sock_sdp.c
index 1fcae8f4f..375a3d3f3 100644
--- a/btif/src/btif_sock_sdp.c
+++ b/btif/src/btif_sock_sdp.c
@@ -29,6 +29,7 @@
#include "btif_common.h"
#include "btif_util.h"
+#include "btif_sock_util.h"
#include "bta_api.h"
#include "bt_target.h"
#include "gki.h"
@@ -91,35 +92,7 @@ static const tBTA_OP_FMT bta_ops_obj_fmt[OBEX_PUSH_NUM_FORMATS] = {
| BTA_OP_ANY_MASK)
#endif
-/*
- * This is horrible design - to reserve channel ID's and use them to magically
- * link a channel number to a hard coded SDP entry.
- *
- * TODO: expose a prober SDP API, to avoid hacks like this, and make it possible
- * to set useful names for the ServiceName
- */
-#define BTA_MAP_MSG_TYPE_EMAIL 0x01
-#define BTA_MAP_MSG_TYPE_SMS_GSM 0x02
-#define BTA_MAP_MSG_TYPE_SMS_CDMA 0x04
-#define BTA_MAP_MSG_TYPE_MMS 0x08
-
-#define BTA_MAP_MAS_ID_SMSMMS 0
-#define BTA_MAP_MAS_ID_EMAIL 1
-
-// MAP 1.1
-#define BTA_MAP_DEFAULT_VERSION 0x0101
-
-typedef struct {
- uint8_t mas_id; // the MAS instance id
- const char *service_name; // Description of the MAS instance
- uint8_t supported_message_types; // Server supported message types - SMS/MMS/EMAIL
-} tBTA_MAP_CFG;
-
-const tBTA_MAP_CFG bta_map_cfg_sms = {
- BTA_MAP_MAS_ID_SMSMMS,
- "MAP SMS",
- BTA_MAP_MSG_TYPE_SMS_GSM | BTA_MAP_MSG_TYPE_SMS_CDMA
-};
+
#define RESERVED_SCN_PBS 19
#define RESERVED_SCN_OPS 12
@@ -289,67 +262,6 @@ error:
"service_name: %s", stage, name);
return 0;
}
-
-// Registers a service with the given |name| and |channel| in the SDP database
-// as a MAP protocol.
-static int add_maps_sdp(const char *name, const int channel) {
- APPL_TRACE_DEBUG("add_maps_sdp: scn %d, service_name %s", channel,
- name);
-
- uint32_t handle = SDP_CreateRecord();
- if (handle == 0) {
- APPL_TRACE_ERROR("add_maps_sdp: failed to create sdp record, "
- "service_name: %s", name);
- return 0;
- }
-
- // Create the base SDP record.
- char *stage = "create_base_record";
- if (!create_base_record(handle, name, channel, TRUE /* with_obex */))
- goto error;
-
- // add service class
- uint16_t service = UUID_SERVCLASS_MESSAGE_ACCESS;
- stage = "service_class";
- if (!SDP_AddServiceClassIdList(handle, 1, &service))
- goto error;
-
- // TODO: To add support for EMAIL set below depending on the scn to either
- // SMS or Email
- const tBTA_MAP_CFG *bta_map_cfg = &bta_map_cfg_sms;
-
- // Add in the Bluetooth Profile Descriptor List
- stage = "profile_descriptor_list";
- if (!SDP_AddProfileDescriptorList(handle,
- UUID_SERVCLASS_MAP_PROFILE,
- BTA_MAP_DEFAULT_VERSION))
- goto error;
-
- stage = "mas_instance_id";
- if (!SDP_AddAttribute(handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
- (uint32_t)1, (uint8_t*)(&bta_map_cfg->mas_id)))
- goto error;
-
- stage = "support_message_types";
- if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
- (uint32_t)1,
- (uint8_t*)(&bta_map_cfg->supported_message_types)))
- goto error;
-
- // Notify the system that we've got a new service class UUID.
- bta_sys_add_uuid(service); // UUID_SERVCLASS_MESSAGE_ACCESS
- APPL_TRACE_DEBUG("ad_maps_sdp: service registered successfully, "
- "service_name: %s, handle 0x%08x)", name, handle);
-
- return handle;
-
-error:
- SDP_DeleteRecord(handle);
- APPL_TRACE_ERROR("add_maps_sdp: failed to register MAP service, stage: %s, "
- "service_name: %s", stage, name);
- return 0;
-}
-
// Registers a service with the given |name| and |channel| as an OBEX Push
// protocol.
static int add_ops_sdp(const char *name, const int channel) {
@@ -489,9 +401,9 @@ static int add_rfc_sdp_by_uuid(const char *name, const uint8_t *uuid,
handle = add_pbap_sdp(name, final_channel);
} else if (UUID_MATCHES(UUID_SPP, uuid)) {
handle = add_spp_sdp(name, final_channel);
- } else if (UUID_MATCHES(UUID_MAPS_MAS,uuid)) {
- // MAP Server is always channel 19
- handle = add_maps_sdp(name, final_channel);
+ } else if (UUID_MATCHES(UUID_MAP_MAS,uuid)) {
+ // Record created by new SDP create record interface
+ handle = 0xff;
} else {
handle = add_sdp_by_uuid(name, uuid, final_channel);
}
diff --git a/btif/src/btif_sock_thread.c b/btif/src/btif_sock_thread.c
index 810601383..18d5fa0d0 100644
--- a/btif/src/btif_sock_thread.c
+++ b/btif/src/btif_sock_thread.c
@@ -176,9 +176,26 @@ static inline int create_thread(void *(*start_routine)(void *), void * arg,
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
- return pthread_create(thread_id, &thread_attr, start_routine, arg);
-}
+ int policy;
+ int min_pri=0;
+ int ret = -1;
+ struct sched_param param;
+ if ((ret = pthread_create(thread_id, &thread_attr, start_routine, arg))!=0 )
+ {
+ APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
+ return ret;
+ }
+ /* We need to lower the priority of this thread to ensure the stack gets
+ * priority over transfer to a socket */
+ pthread_getschedparam(*thread_id, &policy, &param);
+ min_pri = sched_get_priority_min(policy);
+ if (param.sched_priority > min_pri) {
+ param.sched_priority -= 1;
+ }
+ pthread_setschedparam(*thread_id, policy, &param);
+ return ret;
+}
static void init_poll(int cmd_fd);
static int alloc_thread_slot()
{
diff --git a/btif/src/btif_sock_util.c b/btif/src/btif_sock_util.c
index ee49eeba5..baa3ed3d9 100644
--- a/btif/src/btif_sock_util.c
+++ b/btif/src/btif_sock_util.c
@@ -157,6 +157,8 @@ int sock_send_fd(int sock_fd, const uint8_t* buf, int len, int send_fd)
memset(&msg, 0, sizeof(msg));
}
BTIF_TRACE_DEBUG("close fd:%d after sent", send_fd);
+ // TODO: This seems wrong - if the FD is not opened in JAVA before this is called
+ // we get a "socket closed" exception in java, when reading from the socket...
close(send_fd);
return ret_len;
}
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf
index 711fe519b..b1f848e34 100644
--- a/conf/bt_stack.conf
+++ b/conf/bt_stack.conf
@@ -36,3 +36,4 @@ TRC_GATT=2
TRC_SMP=2
TRC_BTAPP=2
TRC_BTIF=2
+TRC_GAP=2
diff --git a/include/bt_target.h b/include/bt_target.h
index 82f487743..bf49ac30a 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -257,6 +257,13 @@
#define BTM_CMD_POOL_ID GKI_POOL_ID_2
#endif
+#ifndef OBX_LRG_DATA_POOL_SIZE
+#define OBX_LRG_DATA_POOL_SIZE GKI_BUF4_SIZE
+#endif
+
+#ifndef OBX_LRG_DATA_POOL_ID
+#define OBX_LRG_DATA_POOL_ID GKI_POOL_ID_4
+#endif
/* Used to send data to L2CAP. */
#ifndef GAP_DATA_POOL_ID
#define GAP_DATA_POOL_ID GKI_POOL_ID_3
@@ -699,7 +706,7 @@
/* Used for features using fixed channels; set to zero if no fixed channels supported (BLE, etc.) */
/* Excluding L2CAP signaling channel and UCD */
#ifndef L2CAP_NUM_FIXED_CHNLS
-#define L2CAP_NUM_FIXED_CHNLS 4
+#define L2CAP_NUM_FIXED_CHNLS 32
#endif
/* First fixed channel supported */
@@ -731,6 +738,15 @@
#define L2CAP_CONFORMANCE_TESTING FALSE
#endif
+/*
+ * Max bytes per connection to buffer locally before dropping the
+ * connection if local client does not receive it - default is 1MB
+ */
+#ifndef L2CAP_MAX_RX_BUFFER
+#define L2CAP_MAX_RX_BUFFER 0x100000
+#endif
+
+
#ifndef TIMER_PARAM_TYPE
#define TIMER_PARAM_TYPE UINT32
#endif
@@ -906,7 +922,7 @@
/* The maximum number of SDP records the server can support. */
#ifndef SDP_MAX_RECORDS
-#define SDP_MAX_RECORDS 20
+#define SDP_MAX_RECORDS 30
#endif
/* The maximum number of attributes in each record. */
@@ -1075,6 +1091,93 @@
/******************************************************************************
**
+** OBEX
+**
+******************************************************************************/
+#define OBX_14_INCLUDED FALSE
+/* This option is application when OBX_14_INCLUDED=TRUE
+ Pool ID where to reassemble the SDU.
+ This Pool will allow buffers to be used that are larger than
+ the L2CAP_MAX_MTU. */
+#ifndef OBX_USER_RX_POOL_ID
+#define OBX_USER_RX_POOL_ID OBX_LRG_DATA_POOL_ID
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+ Pool ID where to hold the SDU.
+ This Pool will allow buffers to be used that are larger than
+ the L2CAP_MAX_MTU. */
+#ifndef OBX_USER_TX_POOL_ID
+#define OBX_USER_TX_POOL_ID OBX_LRG_DATA_POOL_ID
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+GKI Buffer Pool ID used to hold MPS segments during SDU reassembly
+*/
+#ifndef OBX_FCR_RX_POOL_ID
+#define OBX_FCR_RX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+GKI Buffer Pool ID used to hold MPS segments used in (re)transmissions.
+L2CAP_DEFAULT_ERM_POOL_ID is specified to use the HCI ACL data pool.
+Note: This pool needs to have enough buffers to hold two times the window size negotiated
+ in the L2CA_SetFCROptions (2 * tx_win_size) to allow for retransmissions.
+ The size of each buffer must be able to hold the maximum MPS segment size passed in
+ L2CA_SetFCROptions plus BT_HDR (8) + HCI preamble (4) + L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
+*/
+#ifndef OBX_FCR_TX_POOL_ID
+#define OBX_FCR_TX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Size of the transmission window when using enhanced retransmission mode. Not used
+in basic and streaming modes. Range: 1 - 63
+*/
+#ifndef OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR
+#define OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR 20
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Number of transmission attempts for a single I-Frame before taking
+Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+Streaming modes.
+Range: 0, 1-0xFF
+0 - infinite retransmissions
+1 - single transmission
+*/
+#ifndef OBX_FCR_OPT_MAX_TX_B4_DISCNT
+#define OBX_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Retransmission Timeout
+Range: Minimum 2000 (2 secs) on BR/EDR when supporting PBF.
+ */
+#ifndef OBX_FCR_OPT_RETX_TOUT
+#define OBX_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Monitor Timeout
+Range: Minimum 12000 (12 secs) on BR/EDR when supporting PBF.
+*/
+#ifndef OBX_FCR_OPT_MONITOR_TOUT
+#define OBX_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Maximum PDU payload size.
+Suggestion: The maximum amount of data that will fit into a 3-DH5 packet.
+Range: 2 octets
+*/
+#ifndef OBX_FCR_OPT_MAX_PDU_SIZE
+#define OBX_FCR_OPT_MAX_PDU_SIZE L2CAP_MPS_OVER_BR_EDR
+#endif
+
+
+/******************************************************************************
+**
** BNEP
**
******************************************************************************/
@@ -1280,6 +1383,25 @@
**
******************************************************************************/
+#ifndef GAP_INCLUDED
+#define GAP_INCLUDED TRUE
+#endif
+
+/* This is set to enable use of GAP L2CAP connections. */
+#ifndef GAP_CONN_INCLUDED
+#define GAP_CONN_INCLUDED TRUE
+#endif
+
+/* This is set to enable posting event for data write */
+#ifndef GAP_CONN_POST_EVT_INCLUDED
+#define GAP_CONN_POST_EVT_INCLUDED FALSE
+#endif
+
+/* The maximum number of simultaneous GAP L2CAP connections. */
+#ifndef GAP_MAX_CONNECTIONS
+#define GAP_MAX_CONNECTIONS 30
+#endif
+
/* keep the raw data received from SDP server in database. */
#ifndef SDP_RAW_DATA_INCLUDED
#define SDP_RAW_DATA_INCLUDED TRUE
diff --git a/main/Android.mk b/main/Android.mk
index ffb2fefaa..d0c4956a4 100644
--- a/main/Android.mk
+++ b/main/Android.mk
@@ -35,7 +35,7 @@ LOCAL_SRC_FILES += \
../btif/src/btif_hf_client.c \
../btif/src/btif_hh.c \
../btif/src/btif_hl.c \
- ../btif/src/btif_mce.c \
+ ../btif/src/btif_sdp.c \
../btif/src/btif_media_task.c \
../btif/src/btif_pan.c \
../btif/src/btif_profile_queue.c \
@@ -43,9 +43,11 @@ LOCAL_SRC_FILES += \
../btif/src/btif_sm.c \
../btif/src/btif_sock.c \
../btif/src/btif_sock_rfc.c \
+ ../btif/src/btif_sock_l2cap.c \
../btif/src/btif_sock_sco.c \
../btif/src/btif_sock_sdp.c \
../btif/src/btif_sock_thread.c \
+ ../btif/src/btif_sdp_server.c \
../btif/src/btif_sock_util.c \
../btif/src/btif_storage.c \
../btif/src/btif_util.c \
diff --git a/stack/Android.mk b/stack/Android.mk
index 9a48f62d4..22f013f82 100644
--- a/stack/Android.mk
+++ b/stack/Android.mk
@@ -153,6 +153,8 @@ LOCAL_SRC_FILES:= \
./l2cap/l2cap_client.c \
./gap/gap_api.c \
./gap/gap_ble.c \
+ ./gap/gap_conn.c \
+ ./gap/gap_utils.c \
../vnd/ble/vendor_ble.c
LOCAL_MODULE := libbt-brcm_stack
diff --git a/stack/gap/gap_conn.c b/stack/gap/gap_conn.c
new file mode 100644
index 000000000..67b89225a
--- /dev/null
+++ b/stack/gap/gap_conn.c
@@ -0,0 +1,1284 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btu.h"
+#include "gap_int.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include <string.h>
+#if GAP_CONN_INCLUDED == TRUE
+#include "btm_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 gap_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id);
+static void gap_connect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void gap_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
+static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested);
+
+static tGAP_CCB *gap_find_ccb_by_cid (UINT16 cid);
+static tGAP_CCB *gap_find_ccb_by_handle (UINT16 handle);
+static tGAP_CCB *gap_allocate_ccb (void);
+static void gap_release_ccb (tGAP_CCB *p_ccb);
+
+/*******************************************************************************
+**
+** Function gap_conn_init
+**
+** Description This function is called to initialize GAP connection management
+**
+** Returns void
+**
+*******************************************************************************/
+void gap_conn_init (void)
+{
+#if AMP_INCLUDED == TRUE
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
+ gap_cb.conn.reg_info.pAMP_ConnectCfm_Cb = gap_connect_cfm;
+ gap_cb.conn.reg_info.pAMP_ConnectPnd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_ConfigInd_Cb = gap_config_ind;
+ gap_cb.conn.reg_info.pAMP_ConfigCfm_Cb = gap_config_cfm;
+ gap_cb.conn.reg_info.pAMP_DisconnectInd_Cb = gap_disconnect_ind;
+ gap_cb.conn.reg_info.pAMP_DisconnectCfm_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_QoSViolationInd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_DataInd_Cb = gap_data_ind;
+ gap_cb.conn.reg_info.pAMP_CongestionStatus_Cb = gap_congestion_ind;
+ gap_cb.conn.reg_info.pAMP_TxComplete_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveInd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveRsp_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveCfm_Cb = NULL; //gap_move_cfm
+ gap_cb.conn.reg_info.pAMP_MoveCfmRsp_Cb = NULL; //gap_move_cfm_rsp
+
+#else
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
+ gap_cb.conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm;
+ gap_cb.conn.reg_info.pL2CA_ConnectPnd_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind;
+ gap_cb.conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm;
+ gap_cb.conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind;
+ gap_cb.conn.reg_info.pL2CA_DisconnectCfm_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind;
+ gap_cb.conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;
+ gap_cb.conn.reg_info.pL2CA_TxComplete_Cb = NULL;
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnOpen
+**
+** Description This function is called to open an L2CAP connection.
+**
+** Parameters: is_server - If TRUE, the connection is not created
+** but put into a "listen" mode waiting for
+** the remote side to connect.
+**
+** service_id - Unique service ID from
+** BTM_SEC_SERVICE_FIRST_EMPTY (6)
+** to BTM_SEC_MAX_SERVICE_RECORDS (32)
+**
+** p_rem_bda - Pointer to remote BD Address.
+** If a server, and we don't care about the
+** remote BD Address, then NULL should be passed.
+**
+** psm - the PSM used for the connection
+**
+** p_config - Optional pointer to configuration structure.
+** If NULL, the default GAP configuration will
+** be used.
+**
+** security - security flags
+** chan_mode_mask - (GAP_FCR_CHAN_OPT_BASIC, GAP_FCR_CHAN_OPT_ERTM,
+** GAP_FCR_CHAN_OPT_STREAM)
+**
+** p_cb - Pointer to callback function for events.
+**
+** Returns handle of the connection if successful, else GAP_INVALID_HANDLE
+**
+*******************************************************************************/
+UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
+ BD_ADDR p_rem_bda, UINT16 psm, tL2CAP_CFG_INFO *p_cfg,
+ tL2CAP_ERTM_INFO *ertm_info, UINT16 security, UINT8 chan_mode_mask,
+ tGAP_CONN_CALLBACK *p_cb)
+{
+ tGAP_CCB *p_ccb;
+ UINT16 cid;
+ tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}};
+
+ GAP_TRACE_EVENT ("GAP_CONN - Open Request");
+
+ /* Allocate a new CCB. Return if none available. */
+ if ((p_ccb = gap_allocate_ccb()) == NULL)
+ return (GAP_INVALID_HANDLE);
+
+ /* If caller specified a BD address, save it */
+ if (p_rem_bda)
+ {
+ /* the bd addr is not BT_BD_ANY, then a bd address was specified */
+ if (memcmp (p_rem_bda, BT_BD_ANY, BD_ADDR_LEN))
+ p_ccb->rem_addr_specified = TRUE;
+
+ memcpy (&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN);
+ }
+ else if (!is_server)
+ {
+ /* remore addr is not specified and is not a server -> bad */
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* A client MUST have specified a bd addr to connect with */
+ if (!p_ccb->rem_addr_specified && !is_server)
+ {
+ gap_release_ccb (p_ccb);
+ GAP_TRACE_ERROR ("GAP ERROR: Client must specify a remote BD ADDR to connect to!");
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* Check if configuration was specified */
+ if (p_cfg)
+ p_ccb->cfg = *p_cfg;
+
+ p_ccb->p_callback = p_cb;
+
+ /* If originator, use a dynamic PSM */
+#if AMP_INCLUDED == TRUE
+ if (!is_server)
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = NULL;
+ else
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
+#else
+ if (!is_server)
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = NULL;
+ else
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
+#endif
+
+ /* Register the PSM with L2CAP */
+ if ((p_ccb->psm = L2CA_REGISTER (psm, &gap_cb.conn.reg_info,
+ AMP_AUTOSWITCH_ALLOWED|AMP_USE_AMP_IF_POSSIBLE)) == 0)
+ {
+ GAP_TRACE_ERROR ("GAP_ConnOpen: Failure registering PSM 0x%04x", psm);
+ gap_release_ccb (p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* Register with Security Manager for the specific security level */
+ p_ccb->service_id = service_id;
+ if (!BTM_SetSecurityLevel ((UINT8)!is_server, p_serv_name,
+ p_ccb->service_id, security, p_ccb->psm, 0, 0))
+ {
+ GAP_TRACE_ERROR ("GAP_CONN - Security Error");
+ gap_release_ccb (p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* Fill in eL2CAP parameter data */
+ if( p_ccb->cfg.fcr_present )
+ {
+ if(ertm_info == NULL) {
+ p_ccb->ertm_info.preferred_mode = p_ccb->cfg.fcr.mode;
+ p_ccb->ertm_info.user_rx_pool_id = GAP_DATA_POOL_ID;
+ p_ccb->ertm_info.user_tx_pool_id = GAP_DATA_POOL_ID;
+ p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_DEFAULT_ERM_POOL_ID;
+ p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_DEFAULT_ERM_POOL_ID;
+ } else {
+ p_ccb->ertm_info = *ertm_info;
+ }
+ }
+
+ /* optional FCR channel modes */
+ if(ertm_info != NULL) {
+ p_ccb->ertm_info.allowed_modes =
+ (chan_mode_mask) ? chan_mode_mask : (UINT8)L2CAP_FCR_CHAN_OPT_BASIC;
+ }
+
+ if (is_server)
+ {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; /* assume btm/l2cap would handle it */
+ p_ccb->con_state = GAP_CCB_STATE_LISTENING;
+ return (p_ccb->gap_handle);
+ }
+ else
+ {
+ /* We are the originator of this connection */
+ p_ccb->con_flags = GAP_CCB_FLAGS_IS_ORIG;
+
+ /* Transition to the next appropriate state, waiting for connection confirm. */
+ p_ccb->con_state = GAP_CCB_STATE_CONN_SETUP;
+
+ /* mark security done flag, when security is not required */
+ if ((security & (BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT) ) == 0)
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+
+ /* Check if L2CAP started the connection process */
+ if (p_rem_bda && ((cid = L2CA_CONNECT_REQ (p_ccb->psm, p_rem_bda, &p_ccb->ertm_info, &bt_uuid)) != 0))
+ {
+ p_ccb->connection_id = cid;
+ return (p_ccb->gap_handle);
+ }
+ else
+ {
+ gap_release_ccb (p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnClose
+**
+** Description This function is called to close a connection.
+**
+** Parameters: handle - Handle of the connection returned by GAP_ConnOpen
+**
+** Returns BT_PASS - closed OK
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+UINT16 GAP_ConnClose (UINT16 gap_handle)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+ GAP_TRACE_EVENT ("GAP_CONN - close handle: 0x%x", gap_handle);
+
+ if (p_ccb)
+ {
+ /* Check if we have a connection ID */
+ if (p_ccb->con_state != GAP_CCB_STATE_LISTENING)
+ L2CA_DISCONNECT_REQ (p_ccb->connection_id);
+
+ gap_release_ccb (p_ccb);
+
+ return (BT_PASS);
+ }
+
+ return (GAP_ERR_BAD_HANDLE);
+}
+
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnReadData
+**
+** Description Normally not GKI aware application will call this function
+** after receiving GAP_EVT_RXDATA event.
+**
+** Parameters: handle - Handle of the connection returned in the Open
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_NO_DATA_AVAIL - no data available
+**
+*******************************************************************************/
+UINT16 GAP_ConnReadData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+ BT_HDR *p_buf;
+ UINT16 copy_len;
+
+ if (!p_ccb)
+ return (GAP_ERR_BAD_HANDLE);
+
+ *p_len = 0;
+
+ p_buf = (BT_HDR *)GKI_getfirst (&p_ccb->rx_queue);
+ if (!p_buf)
+ return (GAP_NO_DATA_AVAIL);
+
+ GKI_disable();
+
+ while (max_len && p_buf)
+ {
+ copy_len = (p_buf->len > max_len)?max_len:p_buf->len;
+ max_len -= copy_len;
+ *p_len += copy_len;
+ if (p_data)
+ {
+ memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, copy_len);
+ p_data += copy_len;
+ }
+
+ if (p_buf->len > copy_len)
+ {
+ p_buf->offset += copy_len;
+ p_buf->len -= copy_len;
+ break;
+ }
+ else
+ {
+ if (max_len)
+ {
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ }
+ GKI_freebuf (GKI_dequeue (&p_ccb->rx_queue));
+ }
+ }
+
+ p_ccb->rx_queue_size -= *p_len;
+
+ GKI_enable();
+
+ GAP_TRACE_EVENT ("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
+ p_ccb->rx_queue_size, *p_len);
+
+ return (BT_PASS);
+}
+
+/*******************************************************************************
+**
+** Function GAP_GetRxQueueCnt
+**
+** Description This function return number of bytes on the rx queue.
+**
+** Parameters: handle - Handle returned in the GAP_ConnOpen
+** p_rx_queue_count - Pointer to return queue count in.
+**
+**
+*******************************************************************************/
+int GAP_GetRxQueueCnt (UINT16 handle, UINT32 *p_rx_queue_count)
+{
+ tGAP_CCB *p_ccb;
+ int rc = BT_PASS;
+
+ /* Check that handle is valid */
+ if (handle < GAP_MAX_CONNECTIONS)
+ {
+ p_ccb = &gap_cb.conn.ccb_pool[handle];
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
+ {
+ *p_rx_queue_count = p_ccb->rx_queue_size;
+ }
+ else
+ rc = GAP_INVALID_HANDLE;
+ }
+ else
+ rc = GAP_INVALID_HANDLE;
+
+ GAP_TRACE_EVENT ("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d",
+ rc , *p_rx_queue_count);
+
+ return (rc);
+}
+
+/*******************************************************************************
+**
+** Function GAP_ConnBTRead
+**
+** Description Bluetooth aware applications will call this function after receiving
+** GAP_EVT_RXDATA event.
+**
+** Parameters: handle - Handle of the connection returned in the Open
+** pp_buf - pointer to address of buffer with data,
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_NO_DATA_AVAIL - no data available
+**
+*******************************************************************************/
+UINT16 GAP_ConnBTRead (UINT16 gap_handle, BT_HDR **pp_buf)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+ BT_HDR *p_buf;
+
+ if (!p_ccb)
+ return (GAP_ERR_BAD_HANDLE);
+
+ p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->rx_queue);
+
+ if (p_buf)
+ {
+ *pp_buf = p_buf;
+
+ p_ccb->rx_queue_size -= p_buf->len;
+ return (BT_PASS);
+ }
+ else
+ {
+ *pp_buf = NULL;
+ return (GAP_NO_DATA_AVAIL);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnBTWrite
+**
+** Description Bluetooth Aware applications can call this function to write data.
+**
+** Parameters: handle - Handle of the connection returned in the Open
+** p_buf - pointer to address of buffer with data,
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_ERR_BAD_STATE - connection not established
+** GAP_INVALID_BUF_OFFSET - buffer offset is invalid
+*******************************************************************************/
+UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+ if (!p_ccb)
+ {
+ GKI_freebuf (p_buf);
+ return (GAP_ERR_BAD_HANDLE);
+ }
+
+ if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED)
+ {
+ GKI_freebuf (p_buf);
+ return (GAP_ERR_BAD_STATE);
+ }
+
+ if (p_buf->offset < L2CAP_MIN_OFFSET)
+ {
+ GKI_freebuf (p_buf);
+ return (GAP_ERR_BUF_OFFSET);
+ }
+
+ GKI_enqueue (&p_ccb->tx_queue, p_buf);
+
+ if (p_ccb->is_congested)
+ {
+ return (BT_PASS);
+ }
+
+ /* Send the buffer through L2CAP */
+#if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
+ gap_send_event (gap_handle);
+#else
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL)
+ {
+ UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED)
+ {
+ p_ccb->is_congested = TRUE;
+ break;
+ }
+ else if (status != L2CAP_DW_SUCCESS)
+ return (GAP_ERR_BAD_STATE);
+ }
+#endif
+ return (BT_PASS);
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnWriteData
+**
+** Description Normally not GKI aware application will call this function
+** to send data to the connection.
+**
+** Parameters: handle - Handle of the connection returned in the Open
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_ERR_BAD_STATE - connection not established
+** GAP_CONGESTION - system is congested
+**
+*******************************************************************************/
+UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+ BT_HDR *p_buf;
+
+ *p_len = 0;
+
+ if (!p_ccb)
+ return (GAP_ERR_BAD_HANDLE);
+
+ if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED)
+ return (GAP_ERR_BAD_STATE);
+
+ while (max_len)
+ {
+ if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ {
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (p_ccb->ertm_info.user_tx_pool_id)) == NULL)
+ return (GAP_ERR_CONGESTED);
+ }
+ else
+ {
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (GAP_DATA_POOL_ID)) == NULL)
+ return (GAP_ERR_CONGESTED);
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+ *p_len += p_buf->len;
+ max_len -= p_buf->len;
+ p_data += p_buf->len;
+
+ GAP_TRACE_EVENT ("GAP_WriteData %d bytes", p_buf->len);
+
+ GKI_enqueue (&p_ccb->tx_queue, p_buf);
+ }
+
+ if (p_ccb->is_congested)
+ {
+ return (BT_PASS);
+ }
+
+ /* Send the buffer through L2CAP */
+#if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
+ gap_send_event (gap_handle);
+#else
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL)
+ {
+ UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED)
+ {
+ p_ccb->is_congested = TRUE;
+ break;
+ }
+ else if (status != L2CAP_DW_SUCCESS)
+ return (GAP_ERR_BAD_STATE);
+ }
+#endif
+ return (BT_PASS);
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnReconfig
+**
+** Description Applications can call this function to reconfigure the connection.
+**
+** Parameters: handle - Handle of the connection
+** p_cfg - Pointer to new configuration
+**
+** Returns BT_PASS - config process started
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+UINT16 GAP_ConnReconfig (UINT16 gap_handle, tL2CAP_CFG_INFO *p_cfg)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+ if (!p_ccb)
+ return (GAP_ERR_BAD_HANDLE);
+
+ p_ccb->cfg = *p_cfg;
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
+ L2CA_CONFIG_REQ (p_ccb->connection_id, p_cfg);
+
+ return (BT_PASS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnSetIdleTimeout
+**
+** Description Higher layers call this function to set the idle timeout for
+** a connection, or for all future connections. The "idle timeout"
+** is the amount of time that a connection can remain up with
+** no L2CAP channels on it. A timeout of zero means that the
+** connection will be torn down immediately when the last channel
+** is removed. A timeout of 0xFFFF means no timeout. Values are
+** in seconds.
+**
+** Parameters: handle - Handle of the connection
+** timeout - in secs
+** 0 = immediate disconnect when last channel is removed
+** 0xFFFF = no idle timeout
+**
+** Returns BT_PASS - config process started
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+UINT16 GAP_ConnSetIdleTimeout (UINT16 gap_handle, UINT16 timeout)
+{
+ tGAP_CCB *p_ccb;
+
+ if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL)
+ return (GAP_ERR_BAD_HANDLE);
+
+ if (L2CA_SetIdleTimeout (p_ccb->connection_id, timeout, FALSE))
+ return (BT_PASS);
+ else
+ return (GAP_ERR_BAD_HANDLE);
+}
+
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetRemoteAddr
+**
+** Description This function is called to get the remote BD address
+** of a connection.
+**
+** Parameters: handle - Handle of the connection returned by GAP_ConnOpen
+**
+** Returns BT_PASS - closed OK
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+UINT8 *GAP_ConnGetRemoteAddr (UINT16 gap_handle)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+ GAP_TRACE_EVENT ("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle);
+
+ if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING))
+ {
+ GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr bda :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", \
+ p_ccb->rem_dev_address[0],p_ccb->rem_dev_address[1],p_ccb->rem_dev_address[2],
+ p_ccb->rem_dev_address[3],p_ccb->rem_dev_address[4],p_ccb->rem_dev_address[5]);
+ return (p_ccb->rem_dev_address);
+ }
+ else
+ {
+ GAP_TRACE_EVENT ("GAP_ConnGetRemoteAddr return Error ");
+ return (NULL);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetRemMtuSize
+**
+** Description Returns the remote device's MTU size
+**
+** Parameters: handle - Handle of the connection
+**
+** Returns UINT16 - maximum size buffer that can be transmitted to the peer
+**
+*******************************************************************************/
+UINT16 GAP_ConnGetRemMtuSize (UINT16 gap_handle)
+{
+ tGAP_CCB *p_ccb;
+
+ if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL)
+ return (0);
+
+ return (p_ccb->rem_mtu_size);
+}
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetL2CAPCid
+**
+** Description Returns the L2CAP channel id
+**
+** Parameters: handle - Handle of the connection
+**
+** Returns UINT16 - The L2CAP channel id
+** 0, if error
+**
+*******************************************************************************/
+UINT16 GAP_ConnGetL2CAPCid (UINT16 gap_handle)
+{
+ tGAP_CCB *p_ccb;
+
+ if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL)
+ return (0);
+
+ return (p_ccb->connection_id);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
+{
+ UINT16 xx;
+ tGAP_CCB *p_ccb;
+ tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}};
+
+ /* See if we have a CCB listening for the connection */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+ {
+ if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING)
+ && (p_ccb->psm == psm)
+ && ((p_ccb->rem_addr_specified == FALSE)
+ || (!memcmp (bd_addr, p_ccb->rem_dev_address, BD_ADDR_LEN))))
+ break;
+ }
+
+ if (xx == GAP_MAX_CONNECTIONS)
+ {
+ GAP_TRACE_WARNING("*******");
+ GAP_TRACE_WARNING("WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting");
+ GAP_TRACE_WARNING("*******");
+
+ /* Disconnect because it is an unexpected connection */
+ L2CA_DISCONNECT_REQ (l2cap_cid);
+ return;
+ }
+
+ /* Transition to the next appropriate state, waiting for config setup. */
+ p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy (&p_ccb->rem_dev_address[0], bd_addr, BD_ADDR_LEN);
+ p_ccb->connection_id = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_CONNECT_RSP (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK, &p_ccb->ertm_info, &bt_uuid);
+
+ GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x", p_ccb->connection_id);
+
+ /* Send a Configuration Request. */
+ L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg);
+}
+
+/*******************************************************************************
+**
+** Function gap_checks_con_flags
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_checks_con_flags (tGAP_CCB *p_ccb)
+{
+ GAP_TRACE_EVENT ("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags);
+ /* if all the required con_flags are set, report the OPEN event now */
+ if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE)
+ {
+ p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
+
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_sec_check_complete
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
+{
+ tGAP_CCB *p_ccb = (tGAP_CCB *)p_ref_data;
+ UNUSED(bd_addr);
+ UNUSED (transport);
+
+ GAP_TRACE_EVENT ("gap_sec_check_complete conn_state:%d, conn_flags:0x%x, status:%d",
+ p_ccb->con_state, p_ccb->con_flags, res);
+ if (p_ccb->con_state == GAP_CCB_STATE_IDLE)
+ return;
+
+ if (res == BTM_SUCCESS)
+ {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+ gap_checks_con_flags (p_ccb);
+ }
+ else
+ {
+ /* security failed - disconnect the channel */
+ L2CA_DISCONNECT_REQ (p_ccb->connection_id);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_connect_cfm
+**
+** Description This function handles the connect confirm events
+** from L2CAP. This is the case when we are acting as a
+** client and have sent a connect request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_connect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ tGAP_CCB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+ return;
+
+ /* initiate security process, if needed */
+ if ( (p_ccb->con_flags & GAP_CCB_FLAGS_SEC_DONE) == 0)
+ {
+ btm_sec_mx_access_request (p_ccb->rem_dev_address, p_ccb->psm, TRUE,
+ 0, 0, &gap_sec_check_complete, p_ccb);
+ }
+
+ /* If the connection response contains success status, then */
+ /* Transition to the next state and startup the timer. */
+ if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == GAP_CCB_STATE_CONN_SETUP))
+ {
+ p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
+
+ /* Send a Configuration Request. */
+ L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg);
+ }
+ else
+ {
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_callback)
+ (*p_ccb->p_callback) (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+
+ gap_release_ccb (p_ccb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_config_ind
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tGAP_CCB *p_ccb;
+ UINT16 local_mtu_size;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+ return;
+
+ /* Remember the remote MTU size */
+
+ if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ {
+ local_mtu_size = GKI_get_pool_bufsize (p_ccb->ertm_info.user_tx_pool_id)
+ - sizeof(BT_HDR) - L2CAP_MIN_OFFSET;
+ }
+ else
+ local_mtu_size = L2CAP_MTU_SIZE;
+
+ if ((!p_cfg->mtu_present)||(p_cfg->mtu > local_mtu_size))
+ {
+ p_ccb->rem_mtu_size = local_mtu_size;
+ }
+ else
+ p_ccb->rem_mtu_size = p_cfg->mtu;
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = L2CAP_CFG_OK;
+ p_cfg->fcs_present = FALSE;
+
+ L2CA_CONFIG_RSP (l2cap_cid, p_cfg);
+
+ p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
+
+ gap_checks_con_flags (p_ccb);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_config_cfm
+**
+** Description This function processes the L2CAP configuration confirmation
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tGAP_CCB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+ return;
+
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
+
+
+ if (p_ccb->cfg.fcr_present)
+ p_ccb->cfg.fcr.mode = p_cfg->fcr.mode;
+ else
+ p_ccb->cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+
+ gap_checks_con_flags (p_ccb);
+ }
+ else
+ {
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+ gap_release_ccb (p_ccb);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_disconnect_ind
+**
+** Description This function handles a disconnect event from L2CAP. If
+** requested to, we ack the disconnect before dropping the CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
+{
+ tGAP_CCB *p_ccb;
+
+ GAP_TRACE_EVENT ("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+ return;
+
+ if (ack_needed)
+ L2CA_DISCONNECT_RSP (l2cap_cid);
+
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+ gap_release_ccb (p_ccb);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
+{
+ tGAP_CCB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ GKI_freebuf (p_msg);
+ return;
+ }
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
+ {
+ GKI_enqueue (&p_ccb->rx_queue, p_msg);
+
+ p_ccb->rx_queue_size += p_msg->len;
+ /*
+ GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d",
+ p_ccb->rx_queue_size, p_msg->len);
+ */
+
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
+ }
+ else
+ {
+ GKI_freebuf (p_msg);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_congestion_ind
+**
+** Description This is a callback function called by L2CAP when
+** data L2CAP congestion status changes
+**
+*******************************************************************************/
+static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested)
+{
+ tGAP_CCB *p_ccb;
+ UINT16 event;
+ BT_HDR *p_buf;
+ UINT8 status;
+
+ GAP_TRACE_EVENT ("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
+ is_congested, lcid);
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (lcid)) == NULL)
+ return;
+
+ p_ccb->is_congested = is_congested;
+
+ event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED;
+ p_ccb->p_callback (p_ccb->gap_handle, event);
+
+ if (!is_congested)
+ {
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL)
+ {
+ status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED)
+ {
+ p_ccb->is_congested = TRUE;
+ break;
+ }
+ else if (status != L2CAP_DW_SUCCESS)
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_find_ccb_by_cid
+**
+** Description This function searches the CCB table for an entry with the
+** passed CID.
+**
+** Returns the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_find_ccb_by_cid (UINT16 cid)
+{
+ UINT16 xx;
+ tGAP_CCB *p_ccb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+ {
+ if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->connection_id == cid))
+ return (p_ccb);
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_find_ccb_by_handle
+**
+** Description This function searches the CCB table for an entry with the
+** passed handle.
+**
+** Returns the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_find_ccb_by_handle (UINT16 handle)
+{
+ tGAP_CCB *p_ccb;
+
+ /* Check that handle is valid */
+ if (handle < GAP_MAX_CONNECTIONS)
+ {
+ p_ccb = &gap_cb.conn.ccb_pool[handle];
+
+ if (p_ccb->con_state != GAP_CCB_STATE_IDLE)
+ return (p_ccb);
+ }
+
+ /* If here, handle points to invalid connection */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_allocate_ccb
+**
+** Description This function allocates a new CCB.
+**
+** Returns CCB address, or NULL if none available.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_allocate_ccb (void)
+{
+ UINT16 xx;
+ tGAP_CCB *p_ccb;
+
+ /* Look through each connection control block for a free one */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+ {
+ if (p_ccb->con_state == GAP_CCB_STATE_IDLE)
+ {
+ memset (p_ccb, 0, sizeof (tGAP_CCB));
+
+ p_ccb->gap_handle = xx;
+ p_ccb->rem_mtu_size = L2CAP_MTU_SIZE;
+
+ return (p_ccb);
+ }
+ }
+
+ /* If here, no free CCB found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_release_ccb
+**
+** Description This function releases a CCB.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_release_ccb (tGAP_CCB *p_ccb)
+{
+ UINT16 xx;
+ UINT16 psm = p_ccb->psm;
+ UINT8 service_id = p_ccb->service_id;
+
+ /* Drop any buffers we may be holding */
+ p_ccb->rx_queue_size = 0;
+
+ while (p_ccb->rx_queue._p_first)
+ GKI_freebuf (GKI_dequeue (&p_ccb->rx_queue));
+
+ while (p_ccb->tx_queue._p_first)
+ GKI_freebuf (GKI_dequeue (&p_ccb->tx_queue));
+
+ p_ccb->con_state = GAP_CCB_STATE_IDLE;
+
+ /* If no-one else is using the PSM, deregister from L2CAP */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+ {
+ if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->psm == psm))
+ return;
+ }
+
+ /* Free the security record for this PSM */
+ BTM_SecClrService(service_id);
+ L2CA_DEREGISTER (psm);
+}
+
+#if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function gap_send_event
+**
+** Description Send BT_EVT_TO_GAP_MSG event to BTU task
+**
+** Returns None
+**
+*******************************************************************************/
+void gap_send_event (UINT16 gap_handle)
+{
+ BT_HDR *p_msg;
+
+ if ((p_msg = (BT_HDR*)GKI_getbuf(BT_HDR_SIZE)) != NULL)
+ {
+ p_msg->event = BT_EVT_TO_GAP_MSG;
+ p_msg->len = 0;
+ p_msg->offset = 0;
+ p_msg->layer_specific = gap_handle;
+
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_msg);
+ }
+ else
+ {
+ GAP_TRACE_ERROR("Unable to allocate message buffer for event.");
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_proc_btu_event
+**
+** Description Event handler for BT_EVT_TO_GAP_MSG event from BTU task
+**
+** Returns None
+**
+*******************************************************************************/
+void gap_proc_btu_event(BT_HDR *p_msg)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (p_msg->layer_specific);
+ UINT8 status;
+ BT_HDR *p_buf;
+
+ if (!p_ccb)
+ {
+ return;
+ }
+
+ if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED)
+ {
+ return;
+ }
+
+ if (p_ccb->is_congested)
+ {
+ return;
+ }
+
+ /* Send the buffer through L2CAP */
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL)
+ {
+ status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED)
+ {
+ p_ccb->is_congested = TRUE;
+ break;
+ }
+ else if (status != L2CAP_DW_SUCCESS)
+ break;
+ }
+
+}
+#endif /* (GAP_CONN_POST_EVT_INCLUDED == TRUE) */
+#endif /* GAP_CONN_INCLUDED */
diff --git a/stack/gap/gap_int.h b/stack/gap/gap_int.h
index 40fe96a08..0f63f3aba 100644
--- a/stack/gap/gap_int.h
+++ b/stack/gap/gap_int.h
@@ -24,6 +24,77 @@
#include "gap_api.h"
#include "gki.h"
#include "gatt_api.h"
+#define GAP_MAX_BLOCKS 2 /* Concurrent GAP commands pending at a time*/
+/* Define the Generic Access Profile control structure */
+typedef struct
+{
+ void *p_data; /* Pointer to any data returned in callback */
+ tGAP_CALLBACK *gap_cback; /* Pointer to users callback function */
+ tGAP_CALLBACK *gap_inq_rslt_cback; /* Used for inquiry results */
+ UINT16 event; /* Passed back in the callback */
+ UINT8 index; /* Index of this control block and callback */
+ BOOLEAN in_use; /* True when structure is allocated */
+} tGAP_INFO;
+
+/* Define the control block for the FindAddrByName operation (Only 1 active at a time) */
+typedef struct
+{
+ tGAP_CALLBACK *p_cback;
+ tBTM_INQ_INFO *p_cur_inq; /* Pointer to the current inquiry database entry */
+ tGAP_FINDADDR_RESULTS results;
+ BOOLEAN in_use;
+} tGAP_FINDADDR_CB;
+
+/* Define the GAP Connection Control Block.
+*/
+typedef struct
+{
+#define GAP_CCB_STATE_IDLE 0
+#define GAP_CCB_STATE_LISTENING 1
+#define GAP_CCB_STATE_CONN_SETUP 2
+#define GAP_CCB_STATE_CFG_SETUP 3
+#define GAP_CCB_STATE_WAIT_SEC 4
+#define GAP_CCB_STATE_CONNECTED 5
+ UINT8 con_state;
+
+#define GAP_CCB_FLAGS_IS_ORIG 0x01
+#define GAP_CCB_FLAGS_HIS_CFG_DONE 0x02
+#define GAP_CCB_FLAGS_MY_CFG_DONE 0x04
+#define GAP_CCB_FLAGS_SEC_DONE 0x08
+#define GAP_CCB_FLAGS_CONN_DONE 0x0E
+ UINT8 con_flags;
+
+ UINT8 service_id; /* Used by BTM */
+ UINT16 gap_handle; /* GAP handle */
+ UINT16 connection_id; /* L2CAP CID */
+ BOOLEAN rem_addr_specified;
+ UINT8 chan_mode_mask; /* Supported channel modes (FCR) */
+ BD_ADDR rem_dev_address;
+ UINT16 psm;
+ UINT16 rem_mtu_size;
+
+ BOOLEAN is_congested;
+ BUFFER_Q tx_queue; /* Queue of buffers waiting to be sent */
+ BUFFER_Q rx_queue; /* Queue of buffers waiting to be read */
+
+ UINT32 rx_queue_size; /* Total data count in rx_queue */
+
+ tGAP_CONN_CALLBACK *p_callback; /* Users callback function */
+
+ tL2CAP_CFG_INFO cfg; /* Configuration */
+ tL2CAP_ERTM_INFO ertm_info; /* Pools and modes for ertm */
+} tGAP_CCB;
+
+typedef struct
+{
+#if AMP_INCLUDED == TRUE
+ tAMP_APPL_INFO reg_info;
+#else
+ tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
+#endif
+ tGAP_CCB ccb_pool[GAP_MAX_CONNECTIONS];
+} tGAP_CONN;
+
#if BLE_INCLUDED == TRUE
#define GAP_MAX_CHAR_NUM 5
@@ -68,7 +139,15 @@ typedef struct
typedef struct
{
+ tGAP_INFO blk[GAP_MAX_BLOCKS];
+ tBTM_CMPL_CB *btm_cback[GAP_MAX_BLOCKS];
UINT8 trace_level;
+ tGAP_FINDADDR_CB findaddr_cb; /* Contains the control block for finding a device addr */
+ tBTM_INQ_INFO *cur_inqptr;
+
+#if GAP_CONN_INCLUDED == TRUE
+ tGAP_CONN conn;
+#endif
/* LE GAP attribute database */
#if BLE_INCLUDED == TRUE
diff --git a/stack/gap/gap_utils.c b/stack/gap/gap_utils.c
new file mode 100644
index 000000000..e7dfb200c
--- /dev/null
+++ b/stack/gap/gap_utils.c
@@ -0,0 +1,436 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gap_int.h"
+
+/*****************************************************************************/
+/* G L O B A L GAP D A T A */
+/*****************************************************************************/
+tGAP_CB gap_cb;
+
+#if 0
+/*****************************************************************************
+** Callbacks passed to BTM -
+** There are different callbacks based on the control block index so that
+** more than one command can be pending at a time.
+** NOTE: There must be 1 callback for each control block defined
+** GAP_MAX_BLOCKS
+**
+** Also, the inquiry results event has its own callback; Not handled here!
+******************************************************************************/
+static void btm_cback(UINT16 index, void *p_data)
+{
+ tGAP_INFO *p_cb;
+ tGAP_INQ_CMPL inq_cmpl;
+
+ /* Make sure that the index is valid AND it is in use */
+ if (index < GAP_MAX_BLOCKS && gap_cb.blk[index].in_use)
+ {
+ p_cb = &gap_cb.blk[index];
+
+ /* If the callback is non-NULL, call it with the specified event */
+ switch (p_cb->event)
+ {
+
+ case GAP_EVT_INQUIRY_COMPLETE:
+ /* pass the number of results to caller */
+ inq_cmpl.num_results = ((tBTM_INQUIRY_CMPL *)p_data)->num_resp;
+
+ inq_cmpl.status = (((tBTM_INQUIRY_CMPL *)p_data)->status == BTM_SUCCESS) ? BT_PASS : GAP_ERR_PROCESSING;
+
+ p_data = &inq_cmpl;
+
+ GAP_TRACE_EVENT(" GAP Inquiry Complete Event (Status 0x%04x, Result(s) %d)",
+ inq_cmpl.status, inq_cmpl.num_results);
+ break;
+
+ case GAP_EVT_DISCOVERY_COMPLETE:
+ if (*((UINT16 *) p_data))
+ {
+ GAP_TRACE_EVENT(" GAP Discovery Complete Event(SDP Result: 0x%04x)", *((UINT16 *) p_data));
+ }
+ else
+ {
+ GAP_TRACE_EVENT(" GAP Discovery Successfully Completed");
+ }
+
+ break;
+
+ case GAP_EVT_REM_NAME_COMPLETE:
+ /* override the BTM error code with a GAP error code */
+ ((tGAP_REMOTE_DEV_NAME *)p_data)->status =
+ gap_convert_btm_status ((tBTM_STATUS)((tBTM_REMOTE_DEV_NAME *)p_data)->status);
+
+ GAP_TRACE_EVENT(" GAP Remote Name Complete Event (status 0x%04x)", ((tGAP_REMOTE_DEV_NAME *)p_data)->status);
+
+ break;
+ };
+
+ if (p_cb->gap_cback)
+ p_cb->gap_cback(p_cb->event, p_data);
+
+ /* Deallocate the control block */
+ gap_free_cb(p_cb);
+ }
+}
+
+
+/*** Callback functions for BTM_CMPL_CB ***/
+void gap_btm_cback0(void *p1)
+{
+ btm_cback(0, p1);
+}
+
+#if GAP_MAX_BLOCKS > 1
+void gap_btm_cback1(void *p1)
+{
+ btm_cback(1, p1);
+}
+#endif
+#if GAP_MAX_BLOCKS > 2
+void gap_btm_cback2(void *p1)
+{
+ btm_cback(2, p1);
+}
+#endif
+
+/* There is only one instance of this because only 1 inquiry can be active at a time */
+void gap_inq_results_cb(tBTM_INQ_RESULTS *p_results, UINT8 *p_eir)
+{
+ tGAP_INFO *p_cb;
+ UINT8 index;
+ UNUSED(p_eir);
+
+ GAP_TRACE_EVENT ("GAP Inquiry Results Callback (bdaddr [%02x%02x%02x%02x%02x%02x])",
+ p_results->remote_bd_addr[0], p_results->remote_bd_addr[1],
+ p_results->remote_bd_addr[2], p_results->remote_bd_addr[3],
+ p_results->remote_bd_addr[4], p_results->remote_bd_addr[5]);
+ GAP_TRACE_EVENT (" (COD [%02x%02x%02x], clkoff 0x%04x)",
+ p_results->dev_class[0], p_results->dev_class[1], p_results->dev_class[2],
+ p_results->clock_offset);
+
+ /* Find the control block which has an Inquiry Active and call its results callback */
+ for (index = 0, p_cb = &gap_cb.blk[0]; index < GAP_MAX_BLOCKS; index++, p_cb++)
+ {
+ /* Look for the control block that is using inquiry */
+ if (p_cb->in_use && (p_cb->event == GAP_EVT_INQUIRY_COMPLETE))
+ {
+ /* Notify the higher layer if they care */
+ if (p_cb->gap_inq_rslt_cback)
+ p_cb->gap_inq_rslt_cback (GAP_EVT_INQUIRY_RESULTS, (tGAP_INQ_RESULTS *)p_results);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_find_addr_name_cb
+**
+** Description Processes the remote name request event when the Find Addr by Name
+** request is active. The following procedure takes place:
+** 1. Check the resulting name (If return status is ok)
+** 2. If name matches requested name, we're done, call the appl's callback
+** with the BD ADDR.
+** 3. Otherwise get the next BD ADDR out of the inquiry database and intiate
+** another remote name request.
+** 4. If there are no more BD ADDRs, then call the appl's callback with a FAIL
+** status.
+**
+** Returns void
+**
+*******************************************************************************/
+void gap_find_addr_name_cb (tBTM_REMOTE_DEV_NAME *p)
+{
+ tGAP_FINDADDR_CB *p_cb = &gap_cb.findaddr_cb;
+ tGAP_FINDADDR_RESULTS *p_result = &p_cb->results;
+
+ if (p_cb->in_use)
+ {
+ if (p->status == BTM_SUCCESS)
+ {
+ GAP_TRACE_EVENT(" GAP: FindAddrByName Rem Name Cmpl Evt (Status 0x%04x, Name [%s])",
+ p->status, p->remote_bd_name);
+
+ /* See if the returned name matches the desired name; if not initiate another search */
+ if (!strncmp ((char *)p_result->devname, (char *) p->remote_bd_name, strlen ((char *) p_result->devname)))
+ {
+ /* We found the device! Copy it into the return structure */
+ memcpy (p_result->bd_addr, p_cb->p_cur_inq->results.remote_bd_addr, BD_ADDR_LEN);
+ p_result->status = BT_PASS;
+ }
+ else /* The name doesn't match so initiate another search */
+ {
+ /* Get the device address of the next database entry */
+ if ((p_cb->p_cur_inq = BTM_InqDbNext(p_cb->p_cur_inq)) != NULL)
+ {
+ if ((BTM_ReadRemoteDeviceName (p_cb->p_cur_inq->results.remote_bd_addr,
+ (tBTM_CMPL_CB *) gap_find_addr_name_cb, BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+ return; /* This routine will get called again with the next results */
+ else
+ p_result->status = gap_convert_btm_status ((tBTM_STATUS) p->status);
+ }
+ else
+ p_result->status = GAP_EOINQDB; /* No inquiry results; we're done! */
+ }
+ }
+ else
+ {
+ GAP_TRACE_EVENT(" GAP: FindAddrByName Rem Name Cmpl Evt (Status 0x%04x)", p->status);
+ p_result->status = gap_convert_btm_status ((tBTM_STATUS) p->status);
+ }
+
+ /* If this code is reached, the process has completed so call the appl's callback with results */
+ if (p_cb->p_cback)
+ p_cb->p_cback (GAP_EVT_FIND_ADDR_COMPLETE, (tGAP_FINDADDR_RESULTS *) p_result);
+
+ /* Clear out the control block */
+ p_cb->in_use = FALSE;
+ p_cb->p_cback = (tGAP_CALLBACK *) NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_find_addr_inq_cb
+**
+** Description Processes the inquiry complete event when the Find Addr by Name
+** request is active. This callback performs one of the two following
+** steps:
+** 1. If the remote name is retrieved automatically, the DB is searched
+** immediately, and the results are returned in the appls callback.
+**
+** 2. If remote name is not automatic, retrieve the first BTM INQ
+** database entry and initiate a remote name request.
+**
+** Returns void
+**
+*******************************************************************************/
+void gap_find_addr_inq_cb (tBTM_INQUIRY_CMPL *p)
+{
+ tGAP_FINDADDR_CB *p_cb = &gap_cb.findaddr_cb;
+ tGAP_FINDADDR_RESULTS *p_result = &p_cb->results;
+
+ if (p_cb->in_use)
+ {
+
+ GAP_TRACE_EVENT(" GAP: FindAddrByName Inq Cmpl Evt (Status 0x%04x, Result(s) %d)",
+ p->status, p->num_resp);
+
+ if (p->status == BTM_SUCCESS)
+ {
+ /* Step 1: If automatically retrieving remote names then search the local database */
+ if ((p_result->status = gap_find_local_addr_by_name (p_result->devname, p_result->bd_addr)) == GAP_NO_DATA_AVAIL)
+ {
+ /* Step 2: The name is not stored automatically, so a search of all devices needs to
+ * be initiated.
+ */
+ if ((p_cb->p_cur_inq = BTM_InqDbFirst()) != NULL)
+ {
+ if ((BTM_ReadRemoteDeviceName (p_cb->p_cur_inq->results.remote_bd_addr,
+ (tBTM_CMPL_CB *) gap_find_addr_name_cb, BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+ return; /* Wait for the response in gap_find_addr_name_cb() */
+ else
+ p_result->status = gap_convert_btm_status (p->status);
+ }
+ else
+ p_result->status = GAP_EOINQDB; /* No inquiry results; we're done! */
+ }
+ }
+ else
+ p_result->status = gap_convert_btm_status (p->status);
+
+ /* If this code is reached, the process has completed so call the appl's callback with results */
+ if (p_cb->p_cback)
+ p_cb->p_cback (GAP_EVT_FIND_ADDR_COMPLETE, (tGAP_FINDADDR_RESULTS *) p_result);
+
+ /* Clear out the control block */
+ p_cb->in_use = FALSE;
+ p_cb->p_cback = (tGAP_CALLBACK *) NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_find_local_addr_by_name
+**
+** Description Searches through the internal inquiry database for a device
+** that has the same name as the one passed in. If found, the
+** device address is filled in.
+**
+** NOTE: It only searches up to the first BTM_MAX_REM_BD_NAME_LEN
+** bytes because the inquiry database uses tBTM_BD_NAME.
+**
+** Returns BT_PASS if the name was found and the device address is filled in
+** GAP_EOINQDB if the name was not found in the database
+** GAP_NO_DATA_AVAIL if the name is not saved with the inquiry
+**
+*******************************************************************************/
+UINT16 gap_find_local_addr_by_name (const tBTM_BD_NAME devname, BD_ADDR bd_addr)
+{
+
+/* If the remote name is retrieved automatically during an inquiry search the local db */
+#if (BTM_INQ_GET_REMOTE_NAME == TRUE)
+ tBTM_INQ_INFO *p_result;
+
+ p_result = BTM_InqDbFirst();
+
+ while (p_result)
+ {
+ /* Check the entry for a device name match */
+ if (!strncmp ((char *)devname, (char *)p_result->remote_name, BTM_MAX_REM_BD_NAME_LEN))
+ {
+ memcpy (bd_addr, p_result->results.remote_bd_addr, BD_ADDR_LEN);
+ return (BT_PASS);
+ }
+ else
+ p_result = BTM_InqDbNext(p_result);
+ };
+
+ return (GAP_EOINQDB);
+#else
+ UNUSED(devname);
+ UNUSED(bd_addr);
+ /* No data available because we are not automatically saving the data */
+ return (GAP_NO_DATA_AVAIL);
+#endif
+}
+#endif
+
+/*******************************************************************************
+**
+** Function gap_allocate_cb
+**
+** Description Look through the GAP Control Blocks for a free one.
+**
+** Returns Pointer to the control block or NULL if not found
+**
+*******************************************************************************/
+tGAP_INFO *gap_allocate_cb (void)
+{
+ tGAP_INFO *p_cb = &gap_cb.blk[0];
+ UINT8 x;
+
+ for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++)
+ {
+ if (!p_cb->in_use)
+ {
+ memset (p_cb, 0, sizeof (tGAP_INFO));
+
+ p_cb->in_use = TRUE;
+ p_cb->index = x;
+ p_cb->p_data = (void *)NULL;
+ return (p_cb);
+ }
+ }
+
+ /* If here, no free control blocks found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_free_cb
+**
+** Description Release GAP control block.
+**
+** Returns Pointer to the control block or NULL if not found
+**
+*******************************************************************************/
+void gap_free_cb (tGAP_INFO *p_cb)
+{
+ if (p_cb)
+ {
+ p_cb->gap_cback = NULL;
+ p_cb->in_use = FALSE;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_is_service_busy
+**
+** Description Look through the GAP Control Blocks that are in use
+** and check to see if the event waiting for is the command
+** requested.
+**
+** Returns TRUE if already in use
+** FALSE if not busy
+**
+*******************************************************************************/
+BOOLEAN gap_is_service_busy (UINT16 request)
+{
+ tGAP_INFO *p_cb = &gap_cb.blk[0];
+ UINT8 x;
+
+ for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++)
+ {
+ if (p_cb->in_use && p_cb->event == request)
+ return (TRUE);
+ }
+
+ /* If here, service is not busy */
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_convert_btm_status
+**
+** Description Converts a BTM error status into a GAP error status
+**
+**
+** Returns GAP_UNKNOWN_BTM_STATUS is returned if not recognized
+**
+*******************************************************************************/
+UINT16 gap_convert_btm_status (tBTM_STATUS btm_status)
+{
+ switch (btm_status)
+ {
+ case BTM_SUCCESS:
+ return (BT_PASS);
+
+ case BTM_CMD_STARTED:
+ return (GAP_CMD_INITIATED);
+
+ case BTM_BUSY:
+ return (GAP_ERR_BUSY);
+
+ case BTM_MODE_UNSUPPORTED:
+ case BTM_ILLEGAL_VALUE:
+ return (GAP_ERR_ILL_PARM);
+
+ case BTM_WRONG_MODE:
+ return (GAP_DEVICE_NOT_UP);
+
+ case BTM_UNKNOWN_ADDR:
+ return (GAP_BAD_BD_ADDR);
+
+ case BTM_DEVICE_TIMEOUT:
+ return (GAP_ERR_TIMEOUT);
+
+ default:
+ return (GAP_ERR_PROCESSING);
+ }
+}
diff --git a/stack/gatt/gatt_main.c b/stack/gatt/gatt_main.c
index f0a0229ec..e1e9564f9 100644
--- a/stack/gatt/gatt_main.c
+++ b/stack/gatt/gatt_main.c
@@ -44,11 +44,13 @@
/********************************************************************************/
/* 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 gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport);
-static void gatt_le_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf);
+static void gatt_le_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
+ UINT16 reason, tBT_TRANSPORT transport);
+static void gatt_le_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf);
static void gatt_le_cong_cback(BD_ADDR remote_bda, BOOLEAN congest);
-static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id);
+static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 l2cap_cid,
+ UINT16 psm, UINT8 l2cap_id);
static void gatt_l2cif_connect_cfm_cback (UINT16 l2cap_cid, UINT16 result);
static void gatt_l2cif_config_ind_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
static void gatt_l2cif_config_cfm_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
@@ -399,7 +401,7 @@ BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr, tBT_TRANSPORT trans
** connected (conn = TRUE)/disconnected (conn = FALSE).
**
*******************************************************************************/
-static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected,
+static void gatt_le_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
UINT16 reason, tBT_TRANSPORT transport)
{
@@ -544,7 +546,7 @@ static void gatt_le_cong_cback(BD_ADDR remote_bda, BOOLEAN congested)
** Returns void
**
*******************************************************************************/
-static void gatt_le_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf)
+static void gatt_le_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf)
{
tGATT_TCB *p_tcb;
diff --git a/stack/include/gap_api.h b/stack/include/gap_api.h
index 0d86d0723..59c1294cb 100644
--- a/stack/include/gap_api.h
+++ b/stack/include/gap_api.h
@@ -19,9 +19,53 @@
#ifndef GAP_API_H
#define GAP_API_H
+#include "profiles_api.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+
/*****************************************************************************
** Constants
*****************************************************************************/
+/*** GAP Error and Status Codes ***/
+#define GAP_UNSUPPORTED (GAP_ERR_GRP + 0x01) /* Unsupported call */
+#define GAP_EOINQDB (GAP_ERR_GRP + 0x02) /* End of inquiry database marker */
+#define GAP_ERR_BUSY (GAP_ERR_GRP + 0x03) /* The requested function was busy */
+#define GAP_ERR_NO_CTRL_BLK (GAP_ERR_GRP + 0x04) /* No control blocks available */
+#define GAP_ERR_STARTING_CMD (GAP_ERR_GRP + 0x05) /* Error occurred while initiating the command */
+#define GAP_NO_BDADDR_REC (GAP_ERR_GRP + 0x06) /* No Inquiry DB record for BD_ADDR */
+#define GAP_ERR_ILL_MODE (GAP_ERR_GRP + 0x07) /* An illegal mode parameter was detected */
+#define GAP_ERR_ILL_INQ_TIME (GAP_ERR_GRP + 0x08) /* An illegal time parameter was detected */
+#define GAP_ERR_ILL_PARM (GAP_ERR_GRP + 0x09) /* An illegal parameter was detected */
+#define GAP_ERR_REM_NAME (GAP_ERR_GRP + 0x0a) /* Error starting the remote device name request */
+#define GAP_CMD_INITIATED (GAP_ERR_GRP + 0x0b) /* The GAP command was started (result pending) */
+#define GAP_DEVICE_NOT_UP (GAP_ERR_GRP + 0x0c) /* The device was not up; the request was not executed */
+#define GAP_BAD_BD_ADDR (GAP_ERR_GRP + 0x0d) /* The bd addr passed in was not found or invalid */
+
+#define GAP_ERR_BAD_HANDLE (GAP_ERR_GRP + 0x0e) /* Bad GAP handle */
+#define GAP_ERR_BUF_OFFSET (GAP_ERR_GRP + 0x0f) /* Buffer offset invalid */
+#define GAP_ERR_BAD_STATE (GAP_ERR_GRP + 0x10) /* Connection is in invalid state */
+#define GAP_NO_DATA_AVAIL (GAP_ERR_GRP + 0x11) /* No data available */
+#define GAP_ERR_CONGESTED (GAP_ERR_GRP + 0x12) /* BT stack is congested */
+#define GAP_ERR_SECURITY (GAP_ERR_GRP + 0x13) /* Security failed */
+
+#define GAP_ERR_PROCESSING (GAP_ERR_GRP + 0x14) /* General error processing BTM request */
+#define GAP_ERR_TIMEOUT (GAP_ERR_GRP + 0x15) /* Timeout occurred while processing cmd */
+#define GAP_EVT_CONN_OPENED 0x0100
+#define GAP_EVT_CONN_CLOSED 0x0101
+#define GAP_EVT_CONN_DATA_AVAIL 0x0102
+#define GAP_EVT_CONN_CONGESTED 0x0103
+#define GAP_EVT_CONN_UNCONGESTED 0x0104
+/* Values for 'chan_mode_mask' field */
+/* GAP_ConnOpen() - optional channels to negotiate */
+#define GAP_FCR_CHAN_OPT_BASIC L2CAP_FCR_CHAN_OPT_BASIC
+#define GAP_FCR_CHAN_OPT_ERTM L2CAP_FCR_CHAN_OPT_ERTM
+#define GAP_FCR_CHAN_OPT_STREAM L2CAP_FCR_CHAN_OPT_STREAM
+/*** used in connection variables and functions ***/
+#define GAP_INVALID_HANDLE 0xFFFF
+
+/* This is used to change the criteria for AMP */
+#define GAP_PROTOCOL_ID (UUID_PROTOCOL_UDP)
+
#ifndef GAP_PREFER_CONN_INT_MAX
#define GAP_PREFER_CONN_INT_MAX BTM_BLE_CONN_INT_MIN
@@ -42,6 +86,25 @@
/*****************************************************************************
** Type Definitions
*****************************************************************************/
+/*
+** Callback function for connection services
+*/
+typedef void (tGAP_CONN_CALLBACK) (UINT16 gap_handle, UINT16 event);
+
+/*
+** Define the callback function prototypes. Parameters are specific
+** to each event and are described below
+*/
+typedef void (tGAP_CALLBACK) (UINT16 event, void *p_data);
+
+
+/* Definition of the GAP_FindAddrByName results structure */
+typedef struct
+{
+ UINT16 status;
+ BD_ADDR bd_addr;
+ tBTM_BD_NAME devname;
+} tGAP_FINDADDR_RESULTS;
typedef struct
{
@@ -69,6 +132,177 @@ typedef void (tGAP_BLE_RECONN_ADDR_CBACK)(BOOLEAN status, BD_ADDR addr, BD_ADDR
** External Function Declarations
*****************************************************************************/
+/*** Functions for L2CAP connection interface ***/
+
+/*******************************************************************************
+**
+** Function GAP_ConnOpen
+**
+** Description This function is called to open a generic L2CAP connection.
+**
+** Returns handle of the connection if successful, else GAP_INVALID_HANDLE
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
+ BD_ADDR p_rem_bda, UINT16 psm, tL2CAP_CFG_INFO *p_cfg,
+ tL2CAP_ERTM_INFO *ertm_info,
+ UINT16 security, UINT8 chan_mode_mask, tGAP_CONN_CALLBACK *p_cb);
+
+/*******************************************************************************
+**
+** Function GAP_ConnClose
+**
+** Description This function is called to close a connection.
+**
+** Returns BT_PASS - closed OK
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnClose (UINT16 gap_handle);
+
+/*******************************************************************************
+**
+** Function GAP_ConnReadData
+**
+** Description GKI buffer unaware application will call this function
+** after receiving GAP_EVT_RXDATA event. A data copy is made
+** into the receive buffer parameter.
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_NO_DATA_AVAIL - no data available
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnReadData (UINT16 gap_handle, UINT8 *p_data,
+ UINT16 max_len, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function GAP_GetRxQueueCnt
+**
+** Description This function return number of bytes on the rx queue.
+**
+** Parameters: handle - Handle returned in the GAP_ConnOpen
+** p_rx_queue_count - Pointer to return queue count in.
+**
+**
+*******************************************************************************/
+extern int GAP_GetRxQueueCnt (UINT16 handle, UINT32 *p_rx_queue_count);
+
+/*******************************************************************************
+**
+** Function GAP_ConnBTRead
+**
+** Description GKI buffer aware applications will call this function after
+** receiving an GAP_EVT_RXDATA event to process the incoming
+** data buffer.
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_NO_DATA_AVAIL - no data available
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnBTRead (UINT16 gap_handle, BT_HDR **pp_buf);
+
+/*******************************************************************************
+**
+** Function GAP_ConnBTWrite
+**
+** Description GKI buffer aware applications can call this function to write data
+** by passing a pointer to the GKI buffer of data.
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_ERR_BAD_STATE - connection not established
+** GAP_INVALID_BUF_OFFSET - buffer offset is invalid
+*******************************************************************************/
+extern UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function GAP_ConnWriteData
+**
+** Description GKI buffer unaware application will call this function
+** to send data to the connection. A data copy is made into a GKI
+** buffer.
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_ERR_BAD_STATE - connection not established
+** GAP_CONGESTION - system is congested
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data,
+ UINT16 max_len, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function GAP_ConnReconfig
+**
+** Description Applications can call this function to reconfigure the connection.
+**
+** Returns BT_PASS - config process started
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnReconfig (UINT16 gap_handle, tL2CAP_CFG_INFO *p_cfg);
+
+/*******************************************************************************
+**
+** Function GAP_ConnSetIdleTimeout
+**
+** Description Higher layers call this function to set the idle timeout for
+** a connection, or for all future connections. The "idle timeout"
+** is the amount of time that a connection can remain up with
+** no L2CAP channels on it. A timeout of zero means that the
+** connection will be torn down immediately when the last channel
+** is removed. A timeout of 0xFFFF means no timeout. Values are
+** in seconds.
+**
+** Returns BT_PASS - config process started
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnSetIdleTimeout (UINT16 gap_handle, UINT16 timeout);
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetRemoteAddr
+**
+** Description This function is called to get the remote BD address
+** of a connection.
+**
+** Returns BT_PASS - closed OK
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+extern UINT8 *GAP_ConnGetRemoteAddr (UINT16 gap_handle);
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetRemMtuSize
+**
+** Description Returns the remote device's MTU size.
+**
+** Returns UINT16 - maximum size buffer that can be transmitted to the peer
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnGetRemMtuSize (UINT16 gap_handle);
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetL2CAPCid
+**
+** Description Returns the L2CAP channel id
+**
+** Parameters: handle - Handle of the connection
+**
+** Returns UINT16 - The L2CAP channel id
+** 0, if error
+**
+*******************************************************************************/
+extern UINT16 GAP_ConnGetL2CAPCid (UINT16 gap_handle);
+
/*******************************************************************************
**
** Function GAP_SetTraceLevel
diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h
index 010161428..c89efdd76 100644
--- a/stack/include/l2c_api.h
+++ b/stack/include/l2c_api.h
@@ -931,18 +931,20 @@ extern BOOLEAN L2CA_UCDSetTxPriority ( BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY pri
*******************************************************************************/
/* Fixed channel connected and disconnected. Parameters are
+** channel
** BD Address of remote
** TRUE if channel is connected, FALSE if disconnected
** Reason for connection failure
** transport : physical transport, BR/EDR or LE
*/
-typedef void (tL2CA_FIXED_CHNL_CB) (BD_ADDR, BOOLEAN, UINT16, tBT_TRANSPORT);
+typedef void (tL2CA_FIXED_CHNL_CB) (UINT16, BD_ADDR, BOOLEAN, UINT16, tBT_TRANSPORT);
/* Signalling data received. Parameters are
+** channel
** BD Address of remote
** Pointer to buffer with data
*/
-typedef void (tL2CA_FIXED_DATA_CB) (BD_ADDR, BT_HDR *);
+typedef void (tL2CA_FIXED_DATA_CB) (UINT16, BD_ADDR, BT_HDR *);
/* Congestion status callback protype. This callback is optional. If
** an application tries to send data when the transmit queue is full,
diff --git a/stack/include/l2cdefs.h b/stack/include/l2cdefs.h
index 1063749dd..86044bf9a 100644
--- a/stack/include/l2cdefs.h
+++ b/stack/include/l2cdefs.h
@@ -253,6 +253,11 @@
#define L2CAP_EXT_CONTROL_OVERHEAD 4 /* Extended Control Field */
#define L2CAP_MAX_HEADER_FCS (L2CAP_PKT_OVERHEAD + L2CAP_EXT_CONTROL_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN)
/* length(2), channel(2), control(4), SDU length(2) FCS(2) */
+/* To optimize this, it must be a multiplum of the L2CAP PDU length AND match the 3DH5 air
+ * including the l2cap headers in each packet - to match the latter - the -5 is added
+ */
+#define L2CAP_MAX_SDU_LENGTH (GKI_BUF4_SIZE - (L2CAP_MIN_OFFSET + L2CAP_MAX_HEADER_FCS) -5)
+
/* Part of L2CAP_MIN_OFFSET that is not part of L2CAP
*/
#define L2CAP_OFFSET_WO_L2HDR (L2CAP_MIN_OFFSET-(L2CAP_PKT_OVERHEAD+L2CAP_FCR_OVERHEAD))
diff --git a/stack/include/sdpdefs.h b/stack/include/sdpdefs.h
index 22d87c1ad..44d87e74b 100644
--- a/stack/include/sdpdefs.h
+++ b/stack/include/sdpdefs.h
@@ -64,13 +64,14 @@
#define ATTR_ID_IP_SUBNET 0x0200 /* PAN Profile (***) */
#define ATTR_ID_VERSION_NUMBER_LIST 0x0200
+#define ATTR_ID_GOEP_L2CAP_PSM 0x0200
#define ATTR_ID_GROUP_ID 0x0200
#define ATTR_ID_SERVICE_DATABASE_STATE 0x0201
#define ATTR_ID_SERVICE_VERSION 0x0300
#define ATTR_ID_HCRP_1284ID 0x0300
#define ATTR_ID_SUPPORTED_DATA_STORES 0x0301
-#define ATTR_ID_NETWORK 0x0301
+#define ATTR_ID_NETWORK 0x0301
#define ATTR_ID_EXTERNAL_NETWORK 0x0301
#define ATTR_ID_FAX_CLASS_1_SUPPORT 0x0302
#define ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
@@ -92,6 +93,9 @@
#define ATTR_ID_SUPPORTED_REPOSITORIES 0x0314 /* Phone book access Profile */
#define ATTR_ID_MAS_INSTANCE_ID 0x0315 /* MAP profile */
#define ATTR_ID_SUPPORTED_MSG_TYPE 0x0316 /* MAP profile */
+#define ATTR_ID_MAP_SUPPORTED_FEATURES 0x0317 /* MAP profile */
+#define ATTR_ID_PBAP_SUPPORTED_FEATURES 0x0317 /* PBAP profile */
+
/* These values are for the BPP profile */
#define ATTR_ID_DOCUMENT_FORMATS_SUPPORTED 0x0350
diff --git a/stack/l2cap/l2c_api.c b/stack/l2cap/l2c_api.c
index 959f4d254..839ad1b5e 100644
--- a/stack/l2cap/l2c_api.c
+++ b/stack/l2cap/l2c_api.c
@@ -1445,10 +1445,10 @@ BOOLEAN L2CA_ConnectFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda)
#if BLE_INCLUDED == TRUE
(*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb)
- (p_lcb->remote_bd_addr, TRUE, 0, p_lcb->transport);
+ (fixed_cid,p_lcb->remote_bd_addr, TRUE, 0, p_lcb->transport);
#else
(*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb)
- (p_lcb->remote_bd_addr, TRUE, 0, BT_TRANSPORT_BR_EDR);
+ (fixed_cid, p_lcb->remote_bd_addr, TRUE, 0, BT_TRANSPORT_BR_EDR);
#endif
return TRUE;
}
diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
index 65ac7ce08..a2b0a75c9 100644
--- a/stack/l2cap/l2c_ble.c
+++ b/stack/l2cap/l2c_ble.c
@@ -264,6 +264,7 @@ void l2cble_notify_le_connection (BD_ADDR bda)
void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout)
{
+ int i;
tL2C_LCB *p_lcb;
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda);
@@ -352,6 +353,14 @@ void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT;
btm_ble_set_conn_st(BLE_CONN_IDLE);
+ /*
+ * This is wrong. However, querying the other side is wrong too, since as per spec they
+ * cannot really tell us when they have fixed channels open. Yes, bluedroid breaks the
+ * spec in EDR mode in that respect, but that it a whole new story.
+ */
+ for(i = 0; i < L2CAP_FIXED_CHNL_ARRAY_SIZE; i++)
+ p_lcb->peer_chnl_mask[i] = 0xFF;
+ l2cu_process_fixed_chnl_resp (p_lcb);
}
@@ -368,6 +377,7 @@ void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
void l2cble_advertiser_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout)
{
+ int i;
tL2C_LCB *p_lcb;
tBTM_SEC_DEV_REC *p_dev_rec;
UNUSED(type);
@@ -430,6 +440,14 @@ void l2cble_advertiser_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE typ
{
L2CA_CancelBleConnectReq(bda);
}
+ /*
+ * This is wrong. However, querying the other side is wrong too, since as per spec they
+ * cannot really tell us when they have fixed channels open. Yes, bluedroid breaks the
+ * spec in EDR mode in that respect, but that it a whole new story.
+ */
+ for(i = 0; i < L2CAP_FIXED_CHNL_ARRAY_SIZE; i++)
+ p_lcb->peer_chnl_mask[i] = 0xFF;
+ l2cu_process_fixed_chnl_resp (p_lcb);
}
/*******************************************************************************
diff --git a/stack/l2cap/l2c_csm.c b/stack/l2cap/l2c_csm.c
index 325f72039..97372ba4d 100644
--- a/stack/l2cap/l2c_csm.c
+++ b/stack/l2cap/l2c_csm.c
@@ -103,6 +103,7 @@ void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
break;
default:
+ L2CAP_TRACE_DEBUG("Unhandled event! event = %d",event);
break;
}
}
@@ -890,7 +891,8 @@ static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
if (p_ccb->local_cid < L2CAP_BASE_APPL_CID)
{
if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
- (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_ccb->p_lcb->remote_bd_addr,(BT_HDR *)p_data);
+ (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+ (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr,(BT_HDR *)p_data);
else
GKI_freebuf (p_data);
break;
@@ -909,7 +911,8 @@ static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
case L2CEVT_TIMEOUT:
l2cu_send_peer_disc_req (p_ccb);
- L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
l2cu_release_ccb (p_ccb);
(*disconnect_ind)(local_cid, FALSE);
break;
@@ -936,7 +939,8 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
UINT8 cfg_result;
#if (BT_TRACE_VERBOSE == TRUE)
- L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: OPEN evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+ L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: OPEN evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
L2CAP_TRACE_EVENT ("L2CAP - st: OPEN evt: %d", event);
#endif
@@ -956,7 +960,8 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
switch (event)
{
case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
- L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
l2cu_release_ccb (p_ccb);
if (p_ccb->p_rcb)
(*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE);
diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
index ec9a4ef88..3df5cba7e 100644
--- a/stack/l2cap/l2c_fcr.c
+++ b/stack/l2cap/l2c_fcr.c
@@ -1477,7 +1477,8 @@ static BOOLEAN do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_wo
(p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL && p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL))
{
if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
- (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_ccb->p_lcb->remote_bd_addr, p_buf);
+ (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+ (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr, p_buf);
}
else
#endif
diff --git a/stack/l2cap/l2c_link.c b/stack/l2cap/l2c_link.c
index 615e9a705..836f4ba54 100644
--- a/stack/l2cap/l2c_link.c
+++ b/stack/l2cap/l2c_link.c
@@ -442,11 +442,11 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason)
if (p_lcb->p_fixed_ccbs[xx] && p_lcb->p_fixed_ccbs[xx] != p_lcb->p_pending_ccb)
{
#if BLE_INCLUDED == TRUE
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE,
- p_lcb->disc_reason, p_lcb->transport);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport);
#else
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE,
- p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
#endif
l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]);
diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c
index 5f541b5e3..ef8f4bc83 100644
--- a/stack/l2cap/l2c_main.c
+++ b/stack/l2cap/l2c_main.c
@@ -274,7 +274,8 @@ void l2c_rcv_acl_data (BT_HDR *p_msg)
if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
l2c_fcr_proc_pdu (p_ccb, p_msg);
else
- (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_lcb->remote_bd_addr, p_msg);
+ (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+ (rcv_cid, p_lcb->remote_bd_addr, p_msg);
}
else
GKI_freebuf (p_msg);
diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c
index ef155ff8b..00ff2e7b5 100644
--- a/stack/l2cap/l2c_utils.c
+++ b/stack/l2cap/l2c_utils.c
@@ -1216,7 +1216,7 @@ void l2cu_send_peer_info_rsp (tL2C_LCB *p_lcb, UINT8 remote_id, UINT16 info_type
for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL)
- p[0] |= 1 << (xx + L2CAP_FIRST_FIXED_CHNL);
+ p[(xx + L2CAP_FIRST_FIXED_CHNL) / 8] |= 1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8);
}
#endif
}
@@ -2836,22 +2836,27 @@ void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb)
#endif
if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL)
{
- if (p_lcb->peer_chnl_mask[0] & (1 << (xx + L2CAP_FIRST_FIXED_CHNL)))
+ if (p_lcb->peer_chnl_mask[(xx + L2CAP_FIRST_FIXED_CHNL) / 8]
+ & (1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8)))
{
if (p_lcb->p_fixed_ccbs[xx])
p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN;
#if BLE_INCLUDED == TRUE
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, TRUE, 0, p_lcb->transport);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, TRUE, 0, p_lcb->transport);
#else
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, TRUE, 0, BT_TRANSPORT_BR_EDR);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, TRUE, 0, BT_TRANSPORT_BR_EDR);
#endif
}
else
{
#if BLE_INCLUDED == TRUE
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport);
#else
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
#endif
if (p_lcb->p_fixed_ccbs[xx])
@@ -2898,18 +2903,22 @@ void l2cu_process_fixed_disc_cback (tL2C_LCB *p_lcb)
p_lcb->p_fixed_ccbs[xx] = NULL;
l2cu_release_ccb(p_l2c_chnl_ctrl_block);
#if BLE_INCLUDED == TRUE
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport);
#else
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
#endif
}
}
else if ( (peer_channel_mask & (1 << (xx + L2CAP_FIRST_FIXED_CHNL)))
&& (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) )
#if BLE_INCLUDED == TRUE
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport);
#else
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
#endif
}
#endif
@@ -2926,7 +2935,8 @@ void l2cu_process_fixed_disc_cback (tL2C_LCB *p_lcb)
** Returns void
**
*******************************************************************************/
-void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout)
+void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int,
+ UINT16 latency, UINT16 timeout)
{
BT_HDR *p_buf;
UINT8 *p;
@@ -2935,7 +2945,8 @@ void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int
p_lcb->id++;
l2cu_adj_id (p_lcb, L2CAP_ADJ_ID);
- if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_REQ_LEN, L2CAP_CMD_BLE_UPDATE_REQ, p_lcb->id)) == NULL )
+ if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_REQ_LEN,
+ L2CAP_CMD_BLE_UPDATE_REQ, p_lcb->id)) == NULL )
{
L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_par_req - no buffer");
return;
@@ -2967,7 +2978,8 @@ void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id)
BT_HDR *p_buf;
UINT8 *p;
- if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_RSP_LEN, L2CAP_CMD_BLE_UPDATE_RSP, rem_id)) == NULL )
+ if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_RSP_LEN,
+ L2CAP_CMD_BLE_UPDATE_RSP, rem_id)) == NULL )
{
L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_par_rsp - no buffer");
return;
diff --git a/stack/smp/smp_l2c.c b/stack/smp/smp_l2c.c
index 63c851c79..3c91cc08e 100644
--- a/stack/smp/smp_l2c.c
+++ b/stack/smp/smp_l2c.c
@@ -34,8 +34,9 @@
-static void smp_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport);
-static void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf);
+static void smp_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
+ UINT16 reason, tBT_TRANSPORT transport);
+static void smp_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf);
/*******************************************************************************
**
@@ -74,7 +75,7 @@ void smp_l2cap_if_init (void)
** connected (conn = TRUE)/disconnected (conn = FALSE).
**
*******************************************************************************/
-static void smp_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
+static void smp_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
tBT_TRANSPORT transport)
{
tSMP_CB *p_cb = &smp_cb;
@@ -129,7 +130,7 @@ static void smp_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason
** Returns void
**
*******************************************************************************/
-static void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf)
+static void smp_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf)
{
tSMP_CB *p_cb = &smp_cb;
UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;