summaryrefslogtreecommitdiffstats
path: root/btif/src
diff options
context:
space:
mode:
Diffstat (limited to 'btif/src')
-rwxr-xr-xbtif/src/bluetooth.c5
-rw-r--r--btif/src/btif_sock.c204
-rw-r--r--btif/src/btif_sock_rfc.c984
-rw-r--r--btif/src/btif_sock_sdp.c580
-rw-r--r--btif/src/btif_sock_thread.c591
-rw-r--r--btif/src/btif_sock_util.c295
6 files changed, 2659 insertions, 0 deletions
diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c
index 358b8c4..5fccd80 100755
--- a/btif/src/bluetooth.c
+++ b/btif/src/bluetooth.c
@@ -60,6 +60,7 @@
#include <hardware/bluetooth.h>
#include <hardware/bt_hf.h>
#include <hardware/bt_av.h>
+#include <hardware/bt_sock.h>
#include <hardware/bt_hh.h>
#include <hardware/bt_hl.h>
@@ -98,6 +99,8 @@ bt_callbacks_t *bt_hal_cbacks = NULL;
extern bthf_interface_t *btif_hf_get_interface();
/* advanced audio profile */
extern btav_interface_t *btif_av_get_interface();
+/*rfc l2cap*/
+extern btsock_interface_t *btif_sock_get_interface();
/* hid host profile */
extern bthh_interface_t *btif_hh_get_interface();
/* health device profile */
@@ -315,6 +318,8 @@ static const void* get_profile_interface (const char *profile_id)
if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
return btif_hf_get_interface();
+ if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID))
+ return btif_sock_get_interface();
if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
return btif_av_get_interface();
diff --git a/btif/src/btif_sock.c b/btif/src/btif_sock.c
new file mode 100644
index 0000000..859c329
--- /dev/null
+++ b/btif/src/btif_sock.c
@@ -0,0 +1,204 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+
+/************************************************************************************
+ *
+ * Filename: btif_sock.c
+ *
+ * Description: Bluetooth Socket Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_rfc.h"
+#include <cutils/log.h>
+#define info(fmt, ...) LOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) LOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) LOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) LOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+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);
+static bt_status_t btsock_connect(const bt_bdaddr_t *bd_addr, btsock_type_t type,
+ const uint8_t* uuid, int channel, int* sock_fd, int flags);
+
+static void btsock_signaled(int fd, int type, int flags, uint32_t user_id);
+
+/*******************************************************************************
+**
+** Function btsock_ini
+**
+** Description initializes the bt socket interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static btsock_interface_t sock_if = {
+ sizeof(sock_if),
+ btsock_listen,
+ btsock_connect
+ };
+btsock_interface_t *btif_sock_get_interface()
+{
+ return &sock_if;
+}
+bt_status_t btif_sock_init()
+{
+ static volatile int binit;
+ if(!binit)
+ {
+ binit = 1;
+ debug("btsock initializing...");
+ btsock_thread_init();
+ int handle = btsock_thread_create(btsock_signaled);
+ if(handle >= 0 && btsock_rfc_init(handle) == BT_STATUS_SUCCESS)
+ {
+ debug("btsock successfully initialized");
+ return BT_STATUS_SUCCESS;
+ }
+ }
+ else error("btsock interface already initialized");
+ return BT_STATUS_FAIL;
+}
+void btif_sock_cleanup()
+{
+ debug("btif_sock_cleanup()");
+}
+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)
+{
+ if((service_uuid == NULL && channel <= 0) || sock_fd == NULL)
+ {
+ error("invalid parameters, uuid:%p, channel:%d, sock_fd:%p", service_uuid, channel, sock_fd);
+ return BT_STATUS_PARM_INVALID;
+ }
+ *sock_fd = -1;
+ bt_status_t status = BT_STATUS_FAIL;
+ switch(type)
+ {
+ case BTSOCK_RFCOMM:
+ status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd, flags);
+ break;
+ case BTSOCK_L2CAP:
+ error("bt l2cap socket type not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ case BTSOCK_SCO:
+ error("bt sco socket not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ default:
+ error("unknown bt socket type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ }
+ return status;
+}
+static bt_status_t btsock_connect(const bt_bdaddr_t *bd_addr, btsock_type_t type,
+ const uint8_t* uuid, int channel, int* sock_fd, int flags)
+{
+ if((uuid == NULL && channel <= 0) || bd_addr == NULL || sock_fd == NULL)
+ {
+ error("invalid parameters, bd_addr:%p, uuid:%p, channel:%d, sock_fd:%p",
+ bd_addr, uuid, channel, sock_fd);
+ return BT_STATUS_PARM_INVALID;
+ }
+ *sock_fd = -1;
+ bt_status_t status = BT_STATUS_FAIL;
+ switch(type)
+ {
+ case BTSOCK_RFCOMM:
+ status = btsock_rfc_connect(bd_addr, uuid, channel, sock_fd, flags);
+ break;
+ case BTSOCK_L2CAP:
+ error("bt l2cap socket type not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ case BTSOCK_SCO:
+ error("bt sco socket not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ default:
+ error("unknown bt socket type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ }
+ return status;
+}
+static void btsock_signaled(int fd, int type, int flags, uint32_t user_id)
+{
+ switch(type)
+ {
+ case BTSOCK_RFCOMM:
+ btsock_rfc_signaled(fd, flags, user_id);
+ break;
+ case BTSOCK_L2CAP:
+ error("bt l2cap socket type not supported, fd:%d, flags:%d", fd, flags);
+ break;
+ case BTSOCK_SCO:
+ error("bt sco socket type not supported, fd:%d, flags:%d", fd, flags);
+ break;
+ default:
+ error("unknown socket type:%d, fd:%d, flags:%d", type, fd, flags);
+ break;
+ }
+}
+
+
+
diff --git a/btif/src/btif_sock_rfc.c b/btif/src/btif_sock_rfc.c
new file mode 100644
index 0000000..b0d0538
--- /dev/null
+++ b/btif/src/btif_sock_rfc.c
@@ -0,0 +1,984 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+
+/************************************************************************************
+ *
+ * Filename: btif_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_util.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 <cutils/log.h>
+#include <hardware/bluetooth.h>
+#define info(fmt, ...) LOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) LOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define warn(fmt, ...) LOGW ("## WARNING : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) LOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) LOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+
+extern void uuid_to_string(bt_uuid_t *p_uuid, char *str);
+static inline void logu(const char* title, const uint8_t * p_uuid)
+{
+ char uuids[128];
+ uuid_to_string((bt_uuid_t*)p_uuid, uuids);
+ LOGD("%s: %s", title, uuids);
+}
+
+
+
+#define MAX_RFC_CHANNEL 30
+#define MAX_RFC_SESSION BTA_JV_MAX_RFC_SR_SESSION //3 by default
+typedef struct {
+ int outgoing_congest : 1;
+ int pending_sdp_request : 1;
+ int doing_sdp_request : 1;
+ int server : 1;
+ int connected : 1;
+ int closing : 1;
+} flags_t;
+
+typedef struct {
+ flags_t f;
+ uint32_t id;
+ int security;
+ int scn;
+ bt_bdaddr_t addr;
+ uint8_t service_uuid[16];
+ char service_name[256];
+ int fd, app_fd;
+ int mtu;
+ uint8_t* packet;
+ int sdp_handle;
+ int rfc_handle;
+ int rfc_port_handle;
+ int role;
+ BUFFER_Q incoming_que;
+} rfc_slot_t;
+
+static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL];
+static uint32_t rfc_slot_id;
+static int pth = -1; //poll thread handle
+
+static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
+static void cleanup_rfc_slot(rfc_slot_t* rs);
+static inline void close_rfc_connection(int rfc_handle, int server);
+static bt_status_t dm_get_remote_service_record(bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid);
+
+static pthread_mutex_t slot_lock;
+static inline void clear_slot_flag(flags_t* f)
+{
+ memset(f, 0, sizeof(*f));
+}
+
+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 inline void free_gki_que(BUFFER_Q* q)
+{
+ while(!GKI_queue_is_empty(q))
+ GKI_freebuf(GKI_dequeue(q));
+}
+static void init_rfc_slots()
+{
+ int i;
+ memset(rfc_slots, 0, sizeof(rfc_slot_t)*MAX_RFC_CHANNEL);
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ rfc_slots[i].scn = -1;
+ rfc_slots[i].sdp_handle = 0;
+ rfc_slots[i].fd = rfc_slots[i].app_fd = -1;
+ GKI_init_q(&rfc_slots[i].incoming_que);
+ }
+ BTA_JvEnable(jv_dm_cback);
+ init_slot_lock(&slot_lock);
+}
+bt_status_t btsock_rfc_init(int poll_thread_handle)
+{
+ pth = poll_thread_handle;
+ init_rfc_slots();
+ return BT_STATUS_SUCCESS;
+}
+static inline rfc_slot_t* find_free_slot()
+{
+ int i;
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].fd == -1)
+ {
+ return &rfc_slots[i];
+ }
+ }
+ return NULL;
+}
+static inline rfc_slot_t* find_rfc_slot_by_id(uint32_t id)
+{
+ int i;
+ if(id)
+ {
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].id == id)
+ {
+ return &rfc_slots[i];
+ }
+ }
+ }
+ warn("invalid rfc slot id: %d", id);
+ return NULL;
+}
+static inline rfc_slot_t* find_rfc_slot_by_pending_sdp()
+{
+ uint32_t min_id = (uint32_t)-1;
+ int slot = -1;
+ int i;
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].id && rfc_slots[i].f.pending_sdp_request)
+ {
+ if(rfc_slots[i].id < min_id)
+ {
+ min_id = rfc_slots[i].id;
+ slot = i;
+ }
+ }
+ }
+ if(0<= slot && slot < MAX_RFC_CHANNEL)
+ return &rfc_slots[slot];
+ return NULL;
+}
+static inline rfc_slot_t* find_rfc_slot_requesting_sdp()
+{
+ int i;
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].id && rfc_slots[i].f.doing_sdp_request)
+ return &rfc_slots[i];
+ }
+ debug("can not find any slot is requesting sdp");
+ return NULL;
+}
+
+static inline rfc_slot_t* find_rfc_slot_by_fd(int fd)
+{
+ int i;
+ if(fd >= 0)
+ {
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].fd == fd)
+ {
+ if(rfc_slots[i].id)
+ return &rfc_slots[i];
+ else
+ {
+ error("invalid rfc slot id, cannot be 0");
+ break;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+static rfc_slot_t* alloc_rfc_slot(const bt_bdaddr_t *addr, const char* name, const uint8_t* uuid, int channel, int flags, BOOLEAN server)
+{
+ int security = 0;
+ if(flags & BTSOCK_FLAG_ENCRYPT)
+ security |= server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT;
+ if(flags & BTSOCK_FLAG_AUTH)
+ security |= server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE;
+
+ rfc_slot_t* rs = find_free_slot();
+ if(rs)
+ {
+ int fds[2] = {-1, -1};
+ if(socketpair(AF_LOCAL, SOCK_STREAM, 0, fds))
+ {
+ error("socketpair failed, errno:%d", errno);
+ return NULL;
+ }
+ rs->fd = fds[0];
+ rs->app_fd = fds[1];
+ rs->security = security;
+ rs->scn = channel;
+ if(uuid)
+ memcpy(rs->service_uuid, uuid, sizeof(rs->service_uuid));
+ if(name && *name)
+ strncpy(rs->service_name, name, sizeof(rs->service_name) -1);
+ if(addr)
+ rs->addr = *addr;
+ ++rfc_slot_id;
+ if(rfc_slot_id == 0)
+ rfc_slot_id = 1; //skip 0 when wrapped
+ rs->id = rfc_slot_id;
+ rs->f.server = server;
+ }
+ return rs;
+}
+// rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, p_open->rem_bda,p_opne->handle, p_open->new_listen_handle);
+static inline rfc_slot_t* create_srv_accept_rfc_slot(rfc_slot_t* srv_rs, const bt_bdaddr_t* addr,
+ int open_handle, int new_listen_handle)
+{
+ rfc_slot_t *accept_rs = alloc_rfc_slot(addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, FALSE);
+ clear_slot_flag(&accept_rs->f);
+ accept_rs->f.server = FALSE;
+ accept_rs->f.connected = TRUE;
+ accept_rs->security = srv_rs->security;
+ accept_rs->mtu = srv_rs->mtu;
+ accept_rs->role = srv_rs->role;
+ accept_rs->rfc_handle = open_handle;
+ accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle);
+ asrt(accept_rs->rfc_handle == srv_rs->rfc_handle);
+ asrt(accept_rs->rfc_port_handle == srv_rs->rfc_port_handle);
+ //now update listen handle of server slot
+ srv_rs->rfc_handle = new_listen_handle;
+ srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle);
+ //now swap the slot id
+ uint32_t new_listen_id = accept_rs->id;
+ accept_rs->id = srv_rs->id;
+ srv_rs->id = new_listen_id;
+ return accept_rs;
+}
+bt_status_t btsock_rfc_listen(const char* service_name, const uint8_t* service_uuid, int channel,
+ int* sock_fd, int flags)
+{
+ if(sock_fd == NULL || (service_uuid == NULL && !is_reserved_rfc_channel(channel)))
+ {
+ error("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ //Check the service_uuid. If it uses a reserved channel number, use it
+ int reserved_channel = get_reserved_rfc_channel(service_uuid);
+ if(reserved_channel >0)
+ {
+ channel = reserved_channel;
+ }
+
+ int status = BT_STATUS_FAIL;
+ *sock_fd = -1;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, TRUE);
+ if(rs)
+ {
+ debug("call BTA_JvCreateRecordByUser, slot id:%d, server fd:%d, app_fd:%d, security:0x%x, scn:%d",
+ rs->id, rs->fd, rs->app_fd, rs->security, rs->scn);
+ BTA_JvCreateRecordByUser((void *)rs->id);
+ *sock_fd = rs->app_fd;
+ rs->app_fd = -1; //the fd ownership is transferred to app
+ status = BT_STATUS_SUCCESS;
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, rs->id);
+ }
+ unlock_slot(&slot_lock);
+ return status;
+}
+bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, const uint8_t* service_uuid,
+ int channel, int* sock_fd, int flags)
+{
+ if(sock_fd == NULL || (service_uuid == NULL && !is_reserved_rfc_channel(channel)))
+ {
+ error("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid);
+ return BT_STATUS_PARM_INVALID;
+ }
+ int status = BT_STATUS_FAIL;
+ *sock_fd = -1;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, FALSE);
+ if(rs)
+ {
+
+ //BTA_API extern tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, UINT16 num_uuid,
+ // tSDP_UUID *p_uuid_list, void* user_data);
+ tSDP_UUID sdp_uuid;
+ sdp_uuid.len = 16;
+ memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128));
+ debug("start service channel discovery, slot id:%d, fd:%d, app_fd:%d, security:0x%x, scn:%d",
+ rs->id, rs->fd, rs->app_fd, rs->security, rs->scn);
+ logu("service_uuid", service_uuid);
+ *sock_fd = rs->app_fd;
+ rs->app_fd = -1; //the fd ownership is transferred to app
+ status = BT_STATUS_SUCCESS;
+ rfc_slot_t* rs_doing_sdp = find_rfc_slot_requesting_sdp();
+ if(rs_doing_sdp == NULL)
+ {
+ BTA_JvStartDiscovery((UINT8*)bd_addr->address, 1, &sdp_uuid, (void*)rs->id);
+ rs->f.pending_sdp_request = FALSE;
+ rs->f.doing_sdp_request = TRUE;
+ }
+ else
+ {
+ rs->f.pending_sdp_request = TRUE;
+ rs->f.doing_sdp_request = FALSE;
+ }
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
+ }
+ unlock_slot(&slot_lock);
+ return status;
+}
+
+static int create_server_sdp_record(rfc_slot_t* rs)
+{
+ int scn = rs->scn;
+ if(rs->scn > 0)
+ {
+ if(BTM_TryAllocateSCN(rs->scn) == FALSE)
+ {
+ error("rfc channel:%d already in use", scn);
+ return FALSE;
+ }
+ }
+ else if((rs->scn = BTM_AllocateSCN()) == 0)
+ {
+ error("run out of rfc channels");
+ return FALSE;
+ }
+ if((rs->sdp_handle = add_rfc_sdp_rec(rs->service_name, rs->service_uuid, rs->scn)) <= 0)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+const char * jv_evt[] = {
+ "BTA_JV_ENABLE_EVT",
+ "BTA_JV_SET_DISCOVER_EVT",
+ "BTA_JV_LOCAL_ADDR_EVT",
+ "BTA_JV_LOCAL_NAME_EVT",
+ "BTA_JV_REMOTE_NAME_EVT",
+ "BTA_JV_SET_ENCRYPTION_EVT",
+ "BTA_JV_GET_SCN_EVT",
+ "BTA_JV_GET_PSM_EVT",
+ "BTA_JV_DISCOVERY_COMP_EVT",
+ "BTA_JV_SERVICES_LEN_EVT",
+ "BTA_JV_SERVICE_SEL_EVT",
+ "BTA_JV_CREATE_RECORD_EVT",
+ "BTA_JV_UPDATE_RECORD_EVT",
+ "BTA_JV_ADD_ATTR_EVT",
+ "BTA_JV_DELETE_ATTR_EVT",
+ "BTA_JV_CANCEL_DISCVRY_EVT",
+
+ "BTA_JV_L2CAP_OPEN_EVT",
+ "BTA_JV_L2CAP_CLOSE_EVT",
+ "BTA_JV_L2CAP_START_EVT",
+ "BTA_JV_L2CAP_CL_INIT_EVT",
+ "BTA_JV_L2CAP_DATA_IND_EVT",
+ "BTA_JV_L2CAP_CONG_EVT",
+ "BTA_JV_L2CAP_READ_EVT",
+ "BTA_JV_L2CAP_RECEIVE_EVT",
+ "BTA_JV_L2CAP_WRITE_EVT",
+
+ "BTA_JV_RFCOMM_OPEN_EVT",
+ "BTA_JV_RFCOMM_CLOSE_EVT",
+ "BTA_JV_RFCOMM_START_EVT",
+ "BTA_JV_RFCOMM_CL_INIT_EVT",
+ "BTA_JV_RFCOMM_DATA_IND_EVT",
+ "BTA_JV_RFCOMM_CONG_EVT",
+ "BTA_JV_RFCOMM_READ_EVT",
+ "BTA_JV_RFCOMM_WRITE_EVT",
+ "BTA_JV_RFCOMM_SRV_OPEN_EVT", // 33 /* open status of Server RFCOMM connection */
+ "BTA_JV_MAX_EVT"
+};
+static inline void free_rfc_slot_scn(rfc_slot_t* rs)
+{
+ if(rs->scn > 0)
+ {
+ if(rs->f.server && !rs->f.closing)
+ {
+ BTA_JvRfcommStopServer(rs->rfc_handle);
+ rs->rfc_handle = 0;
+ }
+ BTM_FreeSCN(rs->scn);
+ rs->scn = 0;
+ }
+}
+static void cleanup_rfc_slot(rfc_slot_t* rs)
+{
+ debug("cleanup slot:%d, fd:%d, scn:%d", rs->id, rs->fd, rs->scn);
+ if(rs->fd != -1)
+ {
+ shutdown(rs->fd, 2);
+ close(rs->fd);
+ rs->fd = -1;
+ }
+ if(rs->app_fd != -1)
+ {
+ close(rs->app_fd);
+ rs->app_fd = -1;
+ }
+ if(rs->sdp_handle > 0)
+ {
+ del_rfc_sdp_rec(rs->sdp_handle);
+ rs->sdp_handle = 0;
+ }
+ if(rs->rfc_handle && !rs->f.closing && !rs->f.server)
+ {
+ debug("closing rfcomm connection, rfc_handle:%d", rs->rfc_handle);
+ BTA_JvRfcommClose(rs->rfc_handle);
+ rs->rfc_handle = 0;
+ }
+ free_rfc_slot_scn(rs);
+ free_gki_que(&rs->incoming_que);
+
+ rs->rfc_port_handle = 0;
+ //cleanup the flag
+ memset(&rs->f, 0, sizeof(rs->f));
+ rs->id = 0;
+}
+static inline BOOLEAN send_app_scn(rfc_slot_t* rs)
+{
+ if(sock_send_all(rs->fd, (const uint8_t*)&rs->scn, sizeof(rs->scn)) == sizeof(rs->scn))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+static BOOLEAN send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel, int status, int send_fd)
+{
+/*
+ typedef struct {
+ short size;
+ bt_bdaddr_t bd_addr;
+ int channel;
+ int status;
+} __attribute__((packed)) sock_connect_signal_t;
+*/
+ sock_connect_signal_t cs;
+ cs.size = sizeof(cs);
+ cs.bd_addr = *addr;
+ cs.channel = channel;
+ cs.status = status;
+ if(send_fd != -1)
+ {
+ if(sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) == sizeof(cs))
+ return TRUE;
+ else 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_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT *p_init, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ if (p_init->status != BTA_JV_SUCCESS)
+ cleanup_rfc_slot(rs);
+ else
+ {
+ rs->rfc_handle = p_init->handle;
+ debug("on_cl_rfc_init, slot id:%d, fd:%d, rfc scn:%d, server:%d", rs->id, rs->fd, rs->scn, rs->f.server);
+ }
+ }
+ unlock_slot(&slot_lock);
+}
+static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START *p_start, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ if (p_start->status != BTA_JV_SUCCESS)
+ cleanup_rfc_slot(rs);
+ else
+ {
+ rs->rfc_handle = p_start->handle;
+ debug("call send_app_scn, slot id:%d, fd:%d, rfc scn:%d, server:%d", rs->id, rs->fd, rs->scn, rs->f.server);
+ if(!send_app_scn(rs))
+ {
+ //closed
+ debug("send_app_scn() failed, close rs->id:%d", rs->id);
+ cleanup_rfc_slot(rs);
+ }
+ }
+ }
+ unlock_slot(&slot_lock);
+}
+static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN *p_open, uint32_t id)
+{
+ uint32_t new_listen_slot_id = 0;
+ lock_slot(&slot_lock);
+ rfc_slot_t* srv_rs = find_rfc_slot_by_id(id);
+ if(srv_rs)
+ {
+ rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, (const bt_bdaddr_t*)p_open->rem_bda,
+ p_open->handle, p_open->new_listen_handle);
+ if(accept_rs)
+ {
+ //start monitor the socket
+ btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id);
+ btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, accept_rs->id);
+ debug("sending connect signal & app fd:%dto app server to accept() the connection", accept_rs->app_fd);
+ debug("server fd:%d, scn:%d", srv_rs->fd, srv_rs->scn);
+ send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd);
+ accept_rs->app_fd = -1; //the fd is closed after sent to app
+ new_listen_slot_id = srv_rs->id;
+ }
+ }
+ unlock_slot(&slot_lock);
+ return new_listen_slot_id;
+}
+static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN *p_open, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs && p_open->status == BTA_JV_SUCCESS)
+ {
+ rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
+ bd_copy(rs->addr.address, p_open->rem_bda, 0);
+ //notify app rfc is connected
+ debug("call send_app_connect_signal, slot id:%d, fd:%d, rfc scn:%d, server:%d", rs->id, rs->fd, rs->scn, rs->f.server);
+ if(send_app_connect_signal(rs->fd, &rs->addr, rs->scn, 0, -1))
+ {
+ //start monitoring the socketpair to get call back when app writing data
+ debug("on_rfc_connect_ind, connect signal sent, slot id:%d, rfc scn:%d, server:%d", rs->id, rs->scn, rs->f.server);
+ rs->f.connected = TRUE;
+ }
+ else error("send_app_connect_signal failed");
+ }
+ else if(rs)
+ cleanup_rfc_slot(rs);
+ unlock_slot(&slot_lock);
+}
+static void on_rfc_close(tBTA_JV_RFCOMM_CLOSE * p_close, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ debug("on_rfc_close, slot id:%d, fd:%d, rfc scn:%d, server:%d", rs->id, rs->fd, rs->scn, rs->f.server);
+ free_rfc_slot_scn(rs);
+ //rfc_handle already closed when receiving rfcomm close event from stack.
+ rs->rfc_handle = 0;
+ rs->f.connected = FALSE;
+ cleanup_rfc_slot(rs);
+ }
+ unlock_slot(&slot_lock);
+}
+static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE *p, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs && !rs->f.outgoing_congest)
+ {
+ //mointer the fd for any outgoing data
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
+ }
+ unlock_slot(&slot_lock);
+}
+static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG *p, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ rs->f.outgoing_congest = p->cong ? 1 : 0;
+ //mointer the fd for any outgoing data
+ if(!rs->f.outgoing_congest)
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
+ }
+ unlock_slot(&slot_lock);
+}
+
+static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
+{
+ int rc;
+ void* new_user_data = NULL;
+ debug("event=%s", jv_evt[event]);
+
+ switch (event)
+ {
+ case BTA_JV_RFCOMM_START_EVT:
+ debug("BTA_JV_RFCOMM_START_EVT");
+ on_srv_rfc_listen_started(&p_data->rfc_start, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_CL_INIT_EVT:
+ debug("BTA_JV_RFCOMM_CL_INIT_EVT");
+ on_cl_rfc_init(&p_data->rfc_cl_init, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_OPEN_EVT:
+ debug("BTA_JV_RFCOMM_OPEN_EVT");
+ on_cli_rfc_connect(&p_data->rfc_open, (uint32_t)user_data);
+ break;
+ case BTA_JV_RFCOMM_SRV_OPEN_EVT:
+ debug("BTA_JV_RFCOMM_SRV_OPEN_EVT");
+ new_user_data = (void*)on_srv_rfc_connect(&p_data->rfc_srv_open, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_CLOSE_EVT:
+ debug("BTA_JV_RFCOMM_CLOSE_EVT");
+ on_rfc_close(&p_data->rfc_close, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_READ_EVT:
+ debug("BTA_JV_RFCOMM_READ_EVT not used");
+ break;
+
+ case BTA_JV_RFCOMM_WRITE_EVT:
+ debug("BTA_JV_RFCOMM_WRITE_EVT");
+ on_rfc_write_done(&p_data->rfc_write, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_DATA_IND_EVT:
+ debug("BTA_JV_RFCOMM_DATA_IND_EVT not used");
+ break;
+
+ case BTA_JV_RFCOMM_CONG_EVT:
+ //on_rfc_cong(&p_data->rfc_cong);
+ debug("BTA_JV_RFCOMM_CONG_EVT");
+ on_rfc_outgoing_congest(&p_data->rfc_cong, (uint32_t)user_data);
+ break;
+ default:
+ error("unhandled event %d, slot id:%d", event, (uint32_t)user_data);
+ break;
+ }
+ return new_user_data;
+}
+
+static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
+{
+ uint32_t id = (uint32_t)user_data;
+ debug("event:%d, slot id:%d", event, id);
+ switch(event)
+ {
+ case BTA_JV_CREATE_RECORD_EVT:
+ {
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs && create_server_sdp_record(rs))
+ {
+ //now start the rfcomm server after sdp & channel # assigned
+ debug("BTA_JvCreateRecordByUser callback BTA_JV_CREATE_RECORD_EVT, slot id:%d, fd:%d, security:0x%x, scn:%d",
+ rs->id, rs->fd, rs->security, rs->scn);
+ BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION, rfcomm_cback, (void*)rs->id);
+ }
+ unlock_slot(&slot_lock);
+ break;
+ }
+ case BTA_JV_DISCOVERY_COMP_EVT:
+ {
+ rfc_slot_t* rs = NULL;
+ lock_slot(&slot_lock);
+ if(p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn)
+ {
+ error("BTA_JV_DISCOVERY_COMP_EVT, slot id:%d, found channle #, status:%d, scn:%d", id, p_data->disc_comp.status,
+ p_data->disc_comp.scn);
+
+ rs = find_rfc_slot_by_id(id);
+ if(rs && rs->f.doing_sdp_request)
+ {
+ if(BTA_JvRfcommConnect(rs->security, rs->role, p_data->disc_comp.scn, rs->addr.address,
+ rfcomm_cback, (void*)rs->id) == BTA_JV_SUCCESS)
+ {
+ rs->scn = p_data->disc_comp.scn;
+ rs->f.doing_sdp_request = FALSE;
+ if(!send_app_scn(rs))
+ cleanup_rfc_slot(rs);
+ }
+ else cleanup_rfc_slot(rs);
+ }
+ else if(rs)
+ {
+ error("BTA_JV_DISCOVERY_COMP_EVT rfc can not find pending sdp request, slot id:%d, \
+ flag sdp pending:%d, flag sdp doing:%d",
+ id, rs->f.pending_sdp_request, rs->f.doing_sdp_request);
+ }
+ }
+ else
+ {
+ error("BTA_JV_DISCOVERY_COMP_EVT slot id:%d, failed to find channle #, status:%d, scn:%d", id, p_data->disc_comp.status,
+ p_data->disc_comp.scn);
+ rs = find_rfc_slot_by_id(id);
+ if(rs)
+ cleanup_rfc_slot(rs);
+ }
+ rs = find_rfc_slot_by_pending_sdp();
+ if(rs)
+ {
+ debug("BTA_JV_DISCOVERY_COMP_EVT, start another pending scn sdp request");
+ tSDP_UUID sdp_uuid;
+ sdp_uuid.len = 16;
+ memcpy(sdp_uuid.uu.uuid128, rs->service_uuid, sizeof(sdp_uuid.uu.uuid128));
+ BTA_JvStartDiscovery((UINT8*)rs->addr.address, 1, &sdp_uuid, (void*)rs->id);
+ rs->f.pending_sdp_request = FALSE;
+ rs->f.doing_sdp_request = TRUE;
+ }
+ unlock_slot(&slot_lock);
+ break;
+ }
+ default:
+ debug("unhandled event:%d, slot id:%d", event, id);
+ break;
+ }
+
+}
+#define SENT_ALL 2
+#define SENT_PARTIAL 1
+#define SENT_NONE 0
+#define SENT_FAILED (-1)
+static int send_data_to_app(int fd, BT_HDR *p_buf)
+{
+ if(p_buf->len == 0)
+ return SENT_ALL;
+ int sent = send(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len, MSG_DONTWAIT);
+ if(sent == p_buf->len)
+ return SENT_ALL;
+
+ if(sent > 0 && sent < p_buf->len)
+ {
+ //sent partial
+ error("send partial, sent:%d, p_buf->len:%d", sent, p_buf->len);
+ p_buf->offset += sent;
+ p_buf->len -= sent;
+ return SENT_PARTIAL;
+
+ }
+ if(sent < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))
+ {
+ error("send none, EAGAIN or EWOULDBLOCK, errno:%d", errno);
+ return SENT_NONE;
+ }
+ error("unknown send() error, sent:%d, p_buf->len:%d, errno:%d", sent, p_buf->len, errno);
+ return SENT_FAILED;
+}
+static BOOLEAN flush_incoming_que_on_wr_signal(rfc_slot_t* rs)
+{
+ while(!GKI_queue_is_empty(&rs->incoming_que))
+ {
+ BT_HDR *p_buf = GKI_dequeue(&rs->incoming_que);
+ int sent = send_data_to_app(rs->fd, p_buf);
+ switch(sent)
+ {
+ case SENT_NONE:
+ case SENT_PARTIAL:
+ //add it back to the queue at same position
+ GKI_enqueue_head (&rs->incoming_que, p_buf);
+ //monitor the fd to get callback when app is ready to receive data
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id);
+ return TRUE;
+ case SENT_ALL:
+ GKI_freebuf(p_buf);
+ break;
+ case SENT_FAILED:
+ GKI_freebuf(p_buf);
+ return FALSE;
+ }
+ }
+
+ //app is ready to receive data, tell stack to start the data flow
+ //fix me: need a jv flow control api to serialize the call in stack
+ PORT_FlowControl(rs->rfc_port_handle, TRUE);
+ return TRUE;
+}
+void btsock_rfc_signaled(int fd, int flags, uint32_t user_id)
+{
+ debug("fd:%d, flags:%x", fd, flags);
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(user_id);
+ if(rs)
+ {
+ debug("rfc slot id:%d, fd:%d, flags:%x", rs->id, fd, flags);
+ BOOLEAN need_close = FALSE;
+ if(flags & SOCK_THREAD_FD_RD)
+ {
+ //data available from app, tell stack we have outgoing data
+ if(!rs->f.server)
+ {
+ if(rs->f.connected)
+ BTA_JvRfcommWrite(rs->rfc_handle, (UINT32)rs->id);
+ else
+ {
+ error("SOCK_THREAD_FD_RD signaled when rfc is not connected, slot id:%d, channel:%d", rs->id, rs->scn);
+ need_close = TRUE;
+ }
+ }
+ }
+ if(flags & SOCK_THREAD_FD_WR)
+ {
+ //app is ready to receive more data, tell stack to enable the data flow
+ if(!rs->f.connected || !flush_incoming_que_on_wr_signal(rs))
+ {
+ need_close = TRUE;
+ error("SOCK_THREAD_FD_WR signaled when rfc is not connected or app closed fd, slot id:%d, channel:%d", rs->id, rs->scn);
+ }
+
+ }
+ if(need_close || (flags & SOCK_THREAD_FD_EXCEPTION))
+ {
+ debug("SOCK_THREAD_FD_EXCEPTION, flags:%x", flags);
+ rs->f.closing = TRUE;
+ if(rs->f.server)
+ BTA_JvRfcommStopServer(rs->rfc_handle);
+ else
+ BTA_JvRfcommClose(rs->rfc_handle);
+ }
+ }
+ unlock_slot(&slot_lock);
+}
+//stack rfcomm callout functions
+//[
+int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
+{
+ uint32_t id = (uint32_t)user_data;
+ int ret = 0;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+
+ int sent = send_data_to_app(rs->fd, p_buf);
+ switch(sent)
+ {
+ case SENT_NONE:
+ case SENT_PARTIAL:
+ //add it to the end of the queue
+ GKI_enqueue(&rs->incoming_que, p_buf);
+ //monitor the fd to get callback when app is ready to receive data
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id);
+ break;
+ case SENT_ALL:
+ GKI_freebuf(p_buf);
+ ret = 1;//enable the data flow
+ break;
+ case SENT_FAILED:
+ GKI_freebuf(p_buf);
+ cleanup_rfc_slot(rs);
+ break;
+ }
+ }
+ unlock_slot(&slot_lock);
+ return ret;//return 0 to disable data flow
+}
+int bta_co_rfc_data_outgoing_size(void *user_data, int *size)
+{
+ uint32_t id = (uint32_t)user_data;
+ int ret = FALSE;
+ *size = 0;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ if(ioctl(rs->fd, FIONREAD, size) == 0)
+ {
+ debug("ioctl read avaiable size:%d, fd:%d", *size, rs->fd);
+ ret = TRUE;
+ }
+ else
+ {
+ error("ioctl FIONREAD error, errno:%d, fd:%d", errno, rs->fd);
+ cleanup_rfc_slot(rs);
+ }
+ }
+ unlock_slot(&slot_lock);
+ return ret;
+}
+int bta_co_rfc_data_outgoing(void *user_data, UINT8* buf, UINT16 size)
+{
+ uint32_t id = (uint32_t)user_data;
+ int ret = FALSE;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ int received = recv(rs->fd, buf, size, 0);
+ if(received == size)
+ ret = TRUE;
+ else
+ {
+ error("recv error, errno:%d, fd:%d, size:%d, received:%d", errno, rs->fd, size, received);
+ cleanup_rfc_slot(rs);
+ }
+ }
+ unlock_slot(&slot_lock);
+ return ret;
+}
+//]
+
diff --git a/btif/src/btif_sock_sdp.c b/btif/src/btif_sock_sdp.c
new file mode 100644
index 0000000..e3156bd
--- /dev/null
+++ b/btif/src/btif_sock_sdp.c
@@ -0,0 +1,580 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#define LOG_TAG "BTIF_SOCK_SDP"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.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 "btif_sock_sdp.h"
+#include "utl.h"
+#include "../bta/ft/bta_fts_int.h"
+#include "../bta/pb/bta_pbs_int.h"
+#include "../bta/op/bta_ops_int.h"
+#include <cutils/log.h>
+#define info(fmt, ...) LOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) LOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) LOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) LOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+
+
+
+#define RESERVED_SCN_PBS 19
+#define RESERVED_SCN_OPS 12
+
+
+static int add_ftp_sdp(const char *p_service_name, int scn)
+{
+ tSDP_PROTOCOL_ELEM protoList [3];
+ UINT16 ftp_service = UUID_SERVCLASS_OBEX_FILE_TRANSFER;
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ BOOLEAN status = FALSE;
+ int sdp_handle;
+
+ info("scn: %d, service name: %s", scn, p_service_name);
+ tBTA_UTL_COD cod;
+
+
+ /* also set cod service bit for now */
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+ if ((sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ error("FTS SDP: Unable to register FTP Service");
+ return sdp_handle;
+ }
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(sdp_handle, 1, &ftp_service))
+ {
+ /* 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] = scn;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+
+ if (SDP_AddProtocolList(sdp_handle, 3, protoList))
+ {
+ status = TRUE; /* All mandatory fields were successful */
+
+ /* optional: if name is not "", add a name entry */
+ if (*p_service_name != '\0')
+ SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name) + 1),
+ (UINT8 *)p_service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+ BTA_FTS_DEFAULT_VERSION);
+
+ } /* end of setting mandatory protocol list */
+ } /* end of setting mandatory service class */
+
+ /* Make the service browseable */
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status)
+ {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ error("bta_fts_sdp_register FAILED");
+ }
+ else
+ {
+ bta_sys_add_uuid(ftp_service); /* UUID_SERVCLASS_OBEX_FILE_TRANSFER */
+ error("FTS: SDP Registered (handle 0x%08x)", sdp_handle);
+ }
+
+ return sdp_handle;
+}
+
+
+static int add_spp_sdp(const char *service_name, int scn)
+{
+#if 0
+ tSPP_STATUS status = SPP_SUCCESS;
+ UINT16 serviceclassid = UUID_SERVCLASS_SERIAL_PORT;
+ tSDP_PROTOCOL_ELEM proto_elem_list[SPP_NUM_PROTO_ELEMS];
+ int sdp_handle;
+
+ info("scn %d, service name %s", scn, service_name);
+
+ /* register the service */
+ if ((sdp_handle = SDP_CreateRecord()) != FALSE)
+ {
+ /*** Fill out the protocol element sequence for SDP ***/
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+
+ proto_elem_list[1].params[0] = scn;
+
+ if (SDP_AddProtocolList(sdp_handle, SPP_NUM_PROTO_ELEMS,
+ proto_elem_list))
+ {
+ if (SDP_AddServiceClassIdList(sdp_handle, 1, &serviceclassid))
+ {
+ if ((SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME,
+ TEXT_STR_DESC_TYPE, (UINT32)(strlen(service_name)+1),
+ (UINT8 *)service_name)) == FALSE)
+
+ status = SPP_ERR_SDP_ATTR;
+ else
+ {
+ UINT16 list[1];
+
+ /* Make the service browseable */
+ list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ if ((SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
+ 1, list)) == FALSE)
+
+ status = SPP_ERR_SDP_CLASSID;
+ }
+ }
+ else
+ status = SPP_ERR_SDP_CLASSID;
+ }
+ else
+ status = SPP_ERR_SDP_PROTO;
+ }
+ else
+ status = SPP_ERR_SDP_REG;
+
+ return spb_handle;
+#endif
+ return 0;
+}
+#define BTM_NUM_PROTO_ELEMS 2
+static int add_sdp_by_uuid(const char *name, const uint8_t *service_uuid, UINT16 channel)
+{
+
+ UINT32 btm_sdp_handle;
+
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTM_NUM_PROTO_ELEMS];
+
+ /* register the service */
+ if ((btm_sdp_handle = SDP_CreateRecord()) != FALSE)
+ {
+ /*** Fill out the protocol element sequence for SDP ***/
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+
+ proto_elem_list[1].params[0] = channel;
+
+ if (SDP_AddProtocolList(btm_sdp_handle, BTM_NUM_PROTO_ELEMS,
+ proto_elem_list))
+ {
+ UINT8 buff[48];
+ UINT8 *p, *type_buf[1];
+ UINT8 type[1], type_len[1];
+ p = type_buf[0] = buff;
+ type[0] = UUID_DESC_TYPE;
+
+// UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
+ ARRAY_TO_BE_STREAM (p, service_uuid, 16);
+ type_len[0] = 16;
+ if( SDP_AddSequence(btm_sdp_handle, (UINT16) ATTR_ID_SERVICE_CLASS_ID_LIST,
+ 1, type, type_len, type_buf) )
+// if (SDP_AddServiceClassIdList(btm_sdp_handle, 1, &service_uuid))
+ {
+ if ((SDP_AddAttribute(btm_sdp_handle, ATTR_ID_SERVICE_NAME,
+ TEXT_STR_DESC_TYPE, (UINT32)(strlen(name)+1),
+ (UINT8 *)name)) )
+ {
+ UINT16 list[1];
+
+ /* Make the service browseable */
+ list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ if ((SDP_AddUuidSequence (btm_sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
+ 1, list)) )
+
+ return btm_sdp_handle;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* Realm Character Set */
+#define BTA_PBS_REALM_CHARSET 0 /* ASCII */
+
+/* Specifies whether or not client's user id is required during obex authentication */
+#define BTA_PBS_USERID_REQ FALSE
+extern const tBTA_PBS_CFG bta_pbs_cfg;
+const tBTA_PBS_CFG bta_pbs_cfg =
+{
+ BTA_PBS_REALM_CHARSET, /* Server only */
+ BTA_PBS_USERID_REQ, /* Server only */
+ (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE),
+ BTA_PBS_REPOSIT_LOCAL,
+};
+
+static int add_pbap_sdp(const char* p_service_name, int scn)
+{
+
+ tSDP_PROTOCOL_ELEM protoList [3];
+ UINT16 pbs_service = UUID_SERVCLASS_PBAP_PSE;
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ BOOLEAN status = FALSE;
+ UINT32 sdp_handle = 0;
+ tBTA_PBS_CFG *p_bta_pbs_cfg = (tBTA_PBS_CFG *)&bta_pbs_cfg;
+
+ info("scn %d, service name %s", scn, p_service_name);
+
+ if ((sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ error("PBS SDP: Unable to register PBS Service");
+ return sdp_handle;
+ }
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(sdp_handle, 1, &pbs_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] = scn;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+
+ if (SDP_AddProtocolList(sdp_handle, 3, protoList))
+ {
+ status = TRUE; /* All mandatory fields were successful */
+
+ /* optional: if name is not "", add a name entry */
+ if (*p_service_name != '\0')
+ SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name) + 1),
+ (UINT8 *)p_service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_PHONE_ACCESS,
+ BTA_PBS_DEFAULT_VERSION);
+
+ } /* end of setting mandatory protocol list */
+ } /* end of setting mandatory service class */
+
+ /* add supported feature and repositories */
+ if (status)
+ {
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&p_bta_pbs_cfg->supported_features);
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&p_bta_pbs_cfg->supported_repositories);
+
+ /* Make the service browseable */
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+ }
+
+ if (!status)
+ {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR0("bta_pbs_sdp_register FAILED");
+ }
+ else
+ {
+ bta_sys_add_uuid(pbs_service); /* UUID_SERVCLASS_PBAP_PSE */
+ APPL_TRACE_DEBUG1("PBS: SDP Registered (handle 0x%08x)", sdp_handle);
+ }
+
+ return sdp_handle;
+}
+
+
+/* object format lookup table */
+static const tBTA_OP_FMT bta_ops_obj_fmt[] =
+{
+ BTA_OP_VCARD21_FMT,
+ BTA_OP_VCARD30_FMT,
+ BTA_OP_VCAL_FMT,
+ BTA_OP_ICAL_FMT,
+ BTA_OP_VNOTE_FMT,
+ BTA_OP_VMSG_FMT,
+ BTA_OP_OTHER_FMT
+};
+
+#define BTA_OPS_NUM_FMTS 7
+#define BTA_OPS_PROTOCOL_COUNT 3
+
+#ifndef BTUI_OPS_FORMATS
+#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_VCARD30_MASK | \
+ BTA_OP_VCAL_MASK | BTA_OP_ICAL_MASK | \
+ BTA_OP_VNOTE_MASK | BTA_OP_VMSG_MASK | \
+ BTA_OP_ANY_MASK )
+#endif
+
+static int add_ops_sdp(const char *p_service_name,int scn)
+{
+
+
+ tSDP_PROTOCOL_ELEM protoList [BTA_OPS_PROTOCOL_COUNT];
+ tOBX_StartParams start_params;
+ UINT16 servclass = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ int i, j;
+ tBTA_UTL_COD cod;
+ tOBX_STATUS status;
+ UINT8 desc_type[BTA_OPS_NUM_FMTS];
+ UINT8 type_len[BTA_OPS_NUM_FMTS];
+ UINT8 *type_value[BTA_OPS_NUM_FMTS];
+ UINT16 browse;
+ UINT32 sdp_handle;
+ tBTA_OP_FMT_MASK formats = BTUI_OPS_FORMATS;
+
+ info("scn %d, service name %s", scn, p_service_name);
+
+ sdp_handle = SDP_CreateRecord();
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(sdp_handle, 1, &servclass))
+ {
+ /* 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] = scn;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+
+ if (SDP_AddProtocolList(sdp_handle, BTA_OPS_PROTOCOL_COUNT, protoList))
+ {
+ SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name) + 1),
+ (UINT8 *)p_service_name);
+
+ SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ 0x0100);
+ }
+ }
+
+ /* Make the service browseable */
+ browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ /* add sequence for supported types */
+ for (i = 0, j = 0; i < BTA_OPS_NUM_FMTS; i++)
+ {
+ if ((formats >> i) & 1)
+ {
+ type_value[j] = (UINT8 *) &bta_ops_obj_fmt[i];
+ desc_type[j] = UINT_DESC_TYPE;
+ type_len[j++] = 1;
+ }
+ }
+
+ SDP_AddSequence(sdp_handle, (UINT16) ATTR_ID_SUPPORTED_FORMATS_LIST,
+ (UINT8) j, desc_type, type_len, type_value);
+
+ /* 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(servclass); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
+
+ return sdp_handle;
+}
+
+
+
+
+
+static int add_rfc_sdp_by_uuid(const char* name, const uint8_t* uuid, int scn)
+{
+ int handle = 0;
+ UINT16 uuid_16bit;
+
+ uuid_16bit = (((UINT16)uuid[2]) << 8) | (UINT16)uuid[3];
+
+ info("name:%s, scn:%d, uuid_16bit: %d", name, scn,uuid_16bit);
+
+ int final_scn = get_reserved_rfc_channel(uuid);
+ if (final_scn == -1)
+ {
+ final_scn=scn;
+ }
+
+ /*
+ Bluetooth Socket API relies on having preregistered bluez sdp records for HSAG, HFAG, OPP & PBAP
+ that are mapped to rc chan 10, 11,12 & 19. Today HSAG and HFAG is routed to BRCM AG and are not
+ using BT socket API so for now we will need to support OPP and PBAP to enable 3rd party developer
+ apps running on BRCM Android.
+
+ To do this we will check the UUID for the requested service and mimic the SDP records of bluez
+ upon reception. See functions add_opush() and add_pbap() in sdptool.c for actual records
+ */
+
+ /* special handling for preregistered bluez services (OPP, PBAP) that we need to mimic */
+
+ if (uuid_16bit == UUID_SERVCLASS_OBEX_OBJECT_PUSH)
+ {
+ handle = add_ops_sdp(name,final_scn);
+ }
+ else if (uuid_16bit == UUID_SERVCLASS_PBAP_PSE)
+ {
+ handle = add_pbap_sdp(name, final_scn); //PBAP Server is always 19
+ }
+ else if(uuid_16bit == UUID_SERVCLASS_OBEX_FILE_TRANSFER)
+ {
+ APPL_TRACE_EVENT0("Stopping btld ftp serivce when 3-party registering ftp service");
+ //BTA_FtsDisable();
+ handle = add_sdp_by_uuid(name, uuid, final_scn);
+ }
+ else
+ {
+ handle = add_sdp_by_uuid(name, uuid, final_scn);
+ }
+ return handle;
+}
+
+BOOLEAN is_reserved_rfc_channel(int scn)
+{
+ switch(scn)
+ {
+ case RESERVED_SCN_PBS:
+ case RESERVED_SCN_OPS:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+int get_reserved_rfc_channel (const uint8_t* uuid)
+{
+ UINT16 uuid_16bit;
+ uuid_16bit = (((UINT16)uuid[2]) << 8) | (UINT16)uuid[3];
+ info("uuid_16bit: %d", uuid_16bit);
+ if (uuid_16bit == UUID_SERVCLASS_PBAP_PSE)
+ {
+ return RESERVED_SCN_PBS;
+ }
+ else if (uuid_16bit == UUID_SERVCLASS_OBEX_OBJECT_PUSH)
+ {
+ return RESERVED_SCN_OPS;
+ }
+
+ return -1;
+}
+
+int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, int scn)
+{
+ int sdp_handle = 0;
+ if(is_uuid_empty(uuid))
+ {
+ switch(scn)
+ {
+ case RESERVED_SCN_PBS: // PBAP Reserved port
+ add_pbap_sdp(name, scn);
+ break;
+ case RESERVED_SCN_OPS:
+ add_ops_sdp(name,scn);
+ break;
+ default://serial port profile
+ sdp_handle = add_spp_sdp(name, scn);
+ break;
+ }
+ }
+ else
+ sdp_handle = add_rfc_sdp_by_uuid(name, uuid, scn);
+ return sdp_handle;
+}
+
+void del_rfc_sdp_rec(int handle)
+{
+ if(handle != -1 && handle != 0)
+ SDP_DeleteRecord( handle );
+}
+
diff --git a/btif/src/btif_sock_thread.c b/btif/src/btif_sock_thread.c
new file mode 100644
index 0000000..5bf014e
--- /dev/null
+++ b/btif/src/btif_sock_thread.c
@@ -0,0 +1,591 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_sock_thread.c
+ *
+ * Description: socket select thread
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+//bta_jv_co_rfc_data
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <ctype.h>
+
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <cutils/sockets.h>
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+#include "btif_sock.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+
+#include <cutils/log.h>
+#define info(fmt, ...) LOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) LOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) LOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) LOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+#define print_events(events) do { \
+ debug("print poll event:%x", events); \
+ if (events & POLLIN) debug( " POLLIN "); \
+ if (events & POLLPRI) debug( " POLLPRI "); \
+ if (events & POLLOUT) debug( " POLLOUT "); \
+ if (events & POLLERR) debug( " POLLERR "); \
+ if (events & POLLHUP) debug( " POLLHUP "); \
+ if (events & POLLNVAL) debug(" POLLNVAL "); \
+ if (events & POLLRDHUP) debug(" POLLRDHUP"); \
+ } while(0)
+
+#define MAX_THREAD 8
+#define MAX_POLL 64
+#define POLL_EXCEPTION_EVENTS (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)
+#define IS_EXCEPTION(e) ((e) & POLL_EXCEPTION_EVENTS)
+#define IS_READ(e) ((e) & POLLIN)
+#define IS_WRITE(e) ((e) & POLLOUT)
+/*cmd executes in socket poll thread */
+#define CMD_WAKEUP 1
+#define CMD_EXIT 2
+#define CMD_ADD_FD 3
+
+typedef struct {
+ struct pollfd pfd;
+ uint32_t user_id;
+ int type;
+ int flags;
+} poll_slot_t;
+typedef struct {
+ int cmd_fdr, cmd_fdw;
+ int poll_count;
+ poll_slot_t ps[MAX_POLL];
+ int psi[MAX_POLL]; //index of poll slot
+ volatile pid_t thread_id;
+ btsock_signaled_cb callback;
+ int used;
+} thread_slot_t;
+static thread_slot_t ts[MAX_THREAD];
+
+
+
+static void *sock_poll_thread(void *arg);
+static inline void close_cmd_fd(int h);
+
+static inline void add_poll(int h, int fd, int type, int flags, uint32_t user_id);
+
+static pthread_mutex_t thread_slot_lock;
+
+
+static inline void set_socket_blocking(int s, int blocking)
+{
+ int opts;
+ opts = fcntl(s, F_GETFL);
+ if (opts<0) error("set blocking (%s)", strerror(errno));
+ if(blocking)
+ opts &= ~O_NONBLOCK;
+ else opts |= O_NONBLOCK;
+ fcntl(s, F_SETFL, opts);
+}
+
+static inline int create_server_socket(const char* name)
+{
+ int s = socket(AF_LOCAL, SOCK_STREAM, 0);
+ debug("covert name to android abstract name:%s", name);
+ if(socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) >= 0)
+ {
+ if(listen(s, 5) == 0)
+ {
+ debug("listen to local socket:%s, fd:%d", name, s);
+ return s;
+ }
+ else error("listen to local socket:%s, fd:%d failed, errno:%d", name, s, errno);
+ }
+ else error("create local socket:%s fd:%d, failed, errno:%d", name, s, errno);
+ close(s);
+ return -1;
+}
+static inline int connect_server_socket(const char* name)
+{
+ int s = socket(AF_LOCAL, SOCK_STREAM, 0);
+ set_socket_blocking(s, TRUE);
+ if(socket_local_client_connect(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) >= 0)
+ {
+ debug("connected to local socket:%s, fd:%d", name, s);
+ return s;
+ }
+ else error("connect to local socket:%s, fd:%d failed, errno:%d", name, s, errno);
+ close(s);
+ return -1;
+}
+static inline int accept_server_socket(int s)
+{
+ struct sockaddr_un client_address;
+ socklen_t clen;
+ int fd = accept(s, (struct sockaddr*)&client_address, &clen);
+ debug("accepted fd:%d for server fd:%d", fd, s);
+ return fd;
+}
+static inline pthread_t 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);
+ pthread_t thread_id = -1;
+ if( pthread_create(&thread_id, &thread_attr, start_routine, arg)!=0 )
+ {
+ error("pthread_create : %s", strerror(errno));
+ return -1;
+ }
+ return thread_id;
+}
+static void init_poll(int cmd_fd);
+static int alloc_thread_slot()
+{
+ int i;
+ //revserd order to save guard uninitialized access to 0 index
+ for(i = MAX_THREAD - 1; i >=0; i--)
+ if(!ts[i].used)
+ return i;
+ error("execeeded max thread count");
+ return -1;
+}
+static void free_thread_slot(int h)
+{
+ if(0 <= h && h < MAX_THREAD)
+ {
+ close_cmd_fd(h);
+ ts[h].used = 0;
+ }
+ else error("invalid thread handle:%d", h);
+}
+int btsock_thread_init()
+{
+ debug("in");
+ init_slot_lock(&thread_slot_lock);
+ int h;
+ for(h = 0; h < MAX_THREAD; h++)
+ {
+ ts[h].cmd_fdr = ts[h].cmd_fdw = -1;
+ ts[h].used = 0;
+ ts[h].thread_id = -1;
+ ts[h].poll_count = 0;
+ ts[h].callback = NULL;
+ }
+ return TRUE;
+}
+int btsock_thread_create(btsock_signaled_cb callback)
+{
+ int ret = FALSE;
+ asrt(callback);
+ lock_slot(&thread_slot_lock);
+ int h = alloc_thread_slot();
+ unlock_slot(&thread_slot_lock);
+ if(h >= 0)
+ {
+ init_poll(h);
+ if((ts[h].thread_id = create_thread(sock_poll_thread, (void*)h)) != -1)
+ {
+ ts[h].callback = callback;
+ }
+ else
+ {
+ free_thread_slot(h);
+ h = -1;
+ }
+ }
+ return h;
+}
+
+/* create dummy socket pair used to wake up select loop */
+static inline void init_cmd_fd(int h)
+{
+ asrt(ts[h].cmd_fdr == -1 && ts[h].cmd_fdw == -1);
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, &ts[h].cmd_fdr) < 0)
+ {
+ error("socketpair failed: %s", strerror(errno));
+ return;
+ }
+ debug("h:%d, cmd_fdr:%d, cmd_fdw:%d", h, ts[h].cmd_fdr, ts[h].cmd_fdw);
+ //add the cmd fd for read & write
+ add_poll(h, ts[h].cmd_fdr, 0, SOCK_THREAD_FD_RD, 0);
+}
+static inline void close_cmd_fd(int h)
+{
+ if(ts[h].cmd_fdr != -1)
+ {
+ close(ts[h].cmd_fdr);
+ ts[h].cmd_fdr = -1;
+ }
+ if(ts[h].cmd_fdw != -1)
+ {
+ close(ts[h].cmd_fdw);
+ ts[h].cmd_fdw = -1;
+ }
+}
+typedef struct
+{
+ int id;
+ int fd;
+ int type;
+ int flags;
+ uint32_t user_id;
+} sock_cmd_t;
+int btsock_thread_add_fd(int h, int fd, int type, int flags, uint32_t user_id)
+{
+ if(h < 0 || h >= MAX_THREAD)
+ {
+ error("invalid bt thread handle:%d", h);
+ return FALSE;
+ }
+ if(ts[h].cmd_fdw == -1)
+ {
+ error("cmd socket is not created. socket thread may not initialized");
+ return FALSE;
+ }
+ if(flags & SOCK_THREAD_ADD_FD_SYNC)
+ {
+ //must executed in socket poll thread
+ asrt(ts[h].thread_id == gettid());
+ //cleanup one-time flags
+ flags &= ~SOCK_THREAD_ADD_FD_SYNC;
+ add_poll(h, fd, type, flags, user_id);
+ return TRUE;
+ }
+ sock_cmd_t cmd = {CMD_ADD_FD, fd, type, flags, user_id};
+ debug("adding fd:%d, flags:0x%x", fd, flags);
+ return send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd);
+}
+
+int btsock_thread_wakeup(int h)
+{
+ if(h < 0 || h >= MAX_THREAD)
+ {
+ error("invalid bt thread handle:%d", h);
+ return FALSE;
+ }
+ if(ts[h].cmd_fdw == -1)
+ {
+ error("thread handle:%d, cmd socket is not created", h);
+ return FALSE;
+ }
+ sock_cmd_t cmd = {CMD_WAKEUP, 0, 0, 0, 0};
+ return send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd);
+}
+int btsock_thread_exit(int h)
+{
+ if(h < 0 || h >= MAX_THREAD)
+ {
+ error("invalid bt thread handle:%d", h);
+ return FALSE;
+ }
+ if(ts[h].cmd_fdw == -1)
+ {
+ error("cmd socket is not created");
+ return FALSE;
+ }
+ sock_cmd_t cmd = {CMD_EXIT, 0, 0, 0, 0};
+ if(send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd))
+ {
+ pthread_join(ts[h].thread_id, 0);
+ lock_slot(&thread_slot_lock);
+ free_thread_slot(h);
+ unlock_slot(&thread_slot_lock);
+ return TRUE;
+ }
+ return FALSE;
+}
+static void init_poll(int h)
+{
+ int i;
+ ts[h].used = 0;
+ ts[h].poll_count = 0;
+ ts[h].thread_id = -1;
+ ts[h].callback = NULL;
+ for(i = 0; i < MAX_POLL; i++)
+ {
+ ts[h].ps[i].pfd.fd = -1;
+ ts[h].psi[i] = -1;
+ }
+ init_cmd_fd(h);
+}
+static inline unsigned int flags2pevents(int flags)
+{
+ unsigned int pevents = 0;
+ if(flags & SOCK_THREAD_FD_WR)
+ pevents |= POLLOUT;
+ if(flags & SOCK_THREAD_FD_RD)
+ pevents |= POLLIN;
+ pevents |= POLL_EXCEPTION_EVENTS;
+ return pevents;
+}
+
+static inline void set_poll(poll_slot_t* ps, int fd, int type, int flags, uint32_t user_id)
+{
+ ps->pfd.fd = fd;
+ ps->user_id = user_id;
+ if(ps->type != 0 && ps->type != type)
+ error("poll socket type should not changed! type was:%d, type now:%d", ps->type, type);
+ ps->type = type;
+ ps->flags = flags;
+ ps->pfd.events = flags2pevents(flags);
+ ps->pfd.revents = 0;
+}
+static inline void add_poll(int h, int fd, int type, int flags, uint32_t user_id)
+{
+ asrt(fd != -1);
+ int i;
+ int empty = -1;
+ poll_slot_t* ps = ts[h].ps;
+
+ for(i = 0; i < MAX_POLL; i++)
+ {
+ if(ps[i].pfd.fd == fd)
+ {
+ debug("update fd poll, count:%d, slot:%d, fd:%d, \
+ type was:%d, now:%d; flags was:%x, now:%x; user_id was:%d, now:%d",
+ ts[h].poll_count, i, fd, ps[i].type, type, ps[i].flags, flags, ps[i].user_id, user_id);
+ asrt(ts[h].poll_count < MAX_POLL);
+
+ set_poll(&ps[i], fd, type, flags | ps[i].flags, user_id);
+ return;
+ }
+ else if(empty < 0 && ps[i].pfd.fd == -1)
+ empty = i;
+ }
+ if(empty >= 0)
+ {
+ asrt(ts[h].poll_count < MAX_POLL);
+ set_poll(&ps[empty], fd, type, flags, user_id);
+ ++ts[h].poll_count;
+ debug("add new fd poll, count:%d, slot:%d, fd:%d, type:%d; flags:%x; user_id:%d",
+ ts[h].poll_count, empty, fd, type, flags, user_id);
+ return;
+ }
+ error("exceeded max poll slot:%d!", MAX_POLL);
+}
+static inline void remove_poll(int h, poll_slot_t* ps, int flags)
+{
+ if(flags == ps->flags)
+ {
+ //all monitored events signaled. To remove it, just clear the slot
+ --ts[h].poll_count;
+ debug("remove poll, count:%d, fd:%d, flags:%x", ts[h].poll_count, ps->pfd.fd, ps->flags);
+ memset(ps, 0, sizeof(*ps));
+ ps->pfd.fd = -1;
+ }
+ else
+ {
+ //one read or one write monitor event signaled, removed the accordding bit
+ debug("remove poll flag, count:%d, fd:%d, flags signaled:%x, poll flags was:%x, new:%x",
+ ts[h].poll_count, ps->pfd.fd, flags, ps->flags, ps->flags & (~flags));
+ ps->flags &= ~flags;
+ //update the poll events mask
+ ps->pfd.events = flags2pevents(ps->flags);
+ }
+}
+static int process_cmd_sock(int h)
+{
+ sock_cmd_t cmd = {-1, 0, 0, 0, 0};
+ int fd = ts[h].cmd_fdr;
+ if(recv(fd, &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
+ {
+ error("recv cmd errno:%d", errno);
+ return FALSE;
+ }
+ debug("cmd.id:%d", cmd.id);
+ switch(cmd.id)
+ {
+ case CMD_ADD_FD:
+ debug("CMD_ADD_FD, fd:%d, flags:%d", cmd.fd, cmd.flags);
+ add_poll(h, cmd.fd, cmd.type, cmd.flags, cmd.user_id);
+ break;
+ case CMD_WAKEUP:
+ debug("CMD_WAKEUP");
+ break;
+ case CMD_EXIT:
+ debug("CMD_EXIT");
+ return FALSE;
+ default:
+ debug("unknown cmd: %d", cmd.id);
+ break;
+ }
+ return TRUE;
+}
+static void process_data_sock(int h, struct pollfd *pfds, int count)
+{
+ debug("in, poll count:%d ts[h].poll_count:%d", count, ts[h].poll_count);
+ asrt(count <= ts[h].poll_count);
+ int i;
+ for( i= 1; i < ts[h].poll_count; i++)
+ {
+ if(pfds[i].revents)
+ {
+ int ps_i = ts[h].psi[i];
+ asrt(pfds[i].fd == ts[h].ps[ps_i].pfd.fd);
+ uint32_t user_id = ts[h].ps[ps_i].user_id;
+ int type = ts[h].ps[ps_i].type;
+ int flags = 0;
+ debug("signaled data fd:%d, start print poll revents[", pfds[i].fd);
+ print_events(pfds[i].revents);
+ debug("signaled data fd:%d, end print poll revents]", pfds[i].fd);
+ if(IS_READ(pfds[i].revents))
+ {
+ debug("read event signaled, fd:%d, user_id:%d", pfds[i].fd, user_id);
+ flags |= SOCK_THREAD_FD_RD;
+ }
+ if(IS_WRITE(pfds[i].revents))
+ {
+ debug("write event signaled, fd:%d, user_id:%d", pfds[i].fd, user_id);
+ flags |= SOCK_THREAD_FD_WR;
+ }
+ if(IS_EXCEPTION(pfds[i].revents))
+ {
+ debug("exception event signaled, fd:%d, user_id:%d", pfds[i].fd, user_id);
+ flags |= SOCK_THREAD_FD_EXCEPTION;
+ //remove the whole slot not flags
+ remove_poll(h, &ts[h].ps[ps_i], ts[h].ps[ps_i].flags);
+ }
+ else if(flags)
+ remove_poll(h, &ts[h].ps[ps_i], flags); //remove the monitor flags that already processed
+ if(flags)
+ ts[h].callback(pfds[i].fd, type, flags, user_id);
+ }
+ }
+ debug("out");
+}
+static void prepare_poll_fds(int h, struct pollfd* pfds)
+{
+ int count = 0;
+ int ps_i = 0;
+ int pfd_i = 0;
+ asrt(ts[h].poll_count <= MAX_POLL);
+ memset(pfds, 0, sizeof(pfds[0])*ts[h].poll_count);
+ while(count < ts[h].poll_count)
+ {
+ if(ps_i >= MAX_POLL)
+ {
+ error("exceed max poll range, ps_i:%d, MAX_POLL:%d, count:%d, ts[h].poll_count:%d",
+ ps_i, MAX_POLL, count, ts[h].poll_count);
+ return;
+ }
+ if(ts[h].ps[ps_i].pfd.fd >= 0)
+ {
+ pfds[pfd_i] = ts[h].ps[ps_i].pfd;
+ ts[h].psi[pfd_i] = ps_i;
+ count++;
+ pfd_i++;
+ }
+ ps_i++;
+ }
+}
+static void *sock_poll_thread(void *arg)
+{
+ struct pollfd pfds[MAX_POLL];
+ memset(pfds, 0, sizeof(pfds));
+ int h = (int)arg;
+ for(;;)
+ {
+ prepare_poll_fds(h, pfds);
+ debug("call poll, thread handle:%d, cmd fd read:%d, ts[h].poll_count:%d",
+ h, ts[h].cmd_fdr, ts[h].poll_count);
+ int ret = poll(pfds, ts[h].poll_count, -1);
+ if(ret == -1)
+ {
+ error("poll ret -1, exit the thread, errno:%d, err:%s", errno, strerror(errno));
+ debug("ts[h].poll_count:%d", ts[h].poll_count);
+ break;
+ }
+ if(ret != 0)
+ {
+ debug("select wake up, ret:%d, ts[h].poll_count:%d", ret, ts[h].poll_count);
+ int need_process_data_fd = TRUE;
+ if(pfds[0].revents) //cmd fd always is the first one
+ {
+ debug("signaled cmd_fd:%d, start print poll revents[", pfds[0].fd);
+ print_events(pfds[0].revents);
+ debug("signaled cmd_fd:%d, end print poll revents]", pfds[0].fd);
+ asrt(pfds[0].fd == ts[h].cmd_fdr);
+ if(!process_cmd_sock(h))
+ {
+ debug("process_cmd_sock failed, exit...");
+ break;
+ }
+ if(ret == 1)
+ need_process_data_fd = FALSE;
+ else ret--; //exclude the cmd fd
+ }
+ if(need_process_data_fd)
+ process_data_sock(h, pfds, ret);
+ }
+ else debug("no data, select ret: %d", ret);
+ }
+ ts[h].thread_id = -1;
+ debug("socket poll thread exiting");
+ return 0;
+}
+
diff --git a/btif/src/btif_sock_util.c b/btif/src/btif_sock_util.c
new file mode 100644
index 0000000..0e81e75
--- /dev/null
+++ b/btif/src/btif_sock_util.c
@@ -0,0 +1,295 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+
+/************************************************************************************
+ *
+ * Filename: btif_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <cutils/sockets.h>
+#include <netinet/tcp.h>
+
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_sdp.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 <cutils/log.h>
+
+#define info(fmt, ...) LOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) LOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) LOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) LOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+
+int sock_send_all(int sock_fd, const uint8_t* buf, int len)
+{
+ int s = len;
+ int ret;
+ while(s)
+ {
+ do ret = send(sock_fd, buf, s, 0);
+ while(ret < 0 && errno == EINTR);
+ if(ret < 0)
+ {
+ error("sock fd:%d send errno:%d", sock_fd, errno);
+ return -1;
+ }
+ buf += ret;
+ s -= ret;
+ }
+ return len;
+}
+int sock_recv_all(int sock_fd, uint8_t* buf, int len)
+{
+ int r = len;
+ int ret = -1;
+ while(r)
+ {
+ do ret = recv(sock_fd, buf, r, MSG_WAITALL);
+ while(ret < 0 && errno == EINTR);
+ if(ret < 0)
+ {
+ error("sock fd:%d recv errno:%d", sock_fd, errno);
+ return -1;
+ }
+ buf += ret;
+ r -= ret;
+ }
+ return len;
+}
+
+int sock_send_fd(int sock_fd, const uint8_t* buf, int len, int send_fd)
+{
+ ssize_t ret;
+ struct msghdr msg;
+ unsigned char *buffer = (unsigned char *)buf;
+ memset(&msg, 0, sizeof(msg));
+
+ struct cmsghdr *cmsg;
+ char msgbuf[CMSG_SPACE(1)];
+ asrt(send_fd != -1);
+ if(sock_fd == -1 || send_fd == -1)
+ return -1;
+ // Add any pending outbound file descriptors to the message
+ // See "man cmsg" really
+ msg.msg_control = msgbuf;
+ msg.msg_controllen = sizeof msgbuf;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof send_fd);
+ memcpy(CMSG_DATA(cmsg), &send_fd, sizeof send_fd);
+
+ // We only write our msg_control during the first write
+ int ret_len = len;
+ while (len > 0) {
+ struct iovec iv;
+ memset(&iv, 0, sizeof(iv));
+
+ iv.iov_base = buffer;
+ iv.iov_len = len;
+
+ msg.msg_iov = &iv;
+ msg.msg_iovlen = 1;
+
+ do {
+ ret = sendmsg(sock_fd, &msg, MSG_NOSIGNAL);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ error("fd:%d, send_fd:%d, sendmsg ret:%d, errno:%d, %s",
+ sock_fd, send_fd, (int)ret, errno, strerror(errno));
+ ret_len = -1;
+ break;
+ }
+
+ buffer += ret;
+ len -= ret;
+
+ // Wipes out any msg_control too
+ memset(&msg, 0, sizeof(msg));
+ }
+ debug("close fd:%d after sent", send_fd);
+ close(send_fd);
+ return ret_len;
+}
+
+
+#define PRINT(s) __android_log_write(ANDROID_LOG_DEBUG, NULL, s)
+static const char* hex_table = "0123456789abcdef";
+static inline void byte2hex(const char* data, char** str)
+{
+ **str = hex_table[(*data >> 4) & 0xf];
+ ++*str;
+ **str = hex_table[*data & 0xf];
+ ++*str;
+}
+static inline void byte2char(const char* data, char** str)
+{
+ **str = *data < ' ' ? '.' : *data > '~' ? '.' : *data;
+ ++(*str);
+}
+static inline void word2hex(const char* data, char** hex)
+{
+ byte2hex(&data[1], hex);
+ byte2hex(&data[0], hex);
+}
+void dump_bin(const char* title, const char* data, int size)
+{
+ char line_buff[256];
+ char *line;
+ int i, j, addr;
+ const int width = 16;
+ LOGD("%s, size:%d, dump started {", title, size);
+ if(size <= 0)
+ return;
+ //write offset
+ line = line_buff;
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ for(j = 0; j < width; j++)
+ {
+ byte2hex((const char*)&j, &line);
+ *line++ = ' ';
+ }
+ *line = 0;
+ PRINT(line_buff);
+
+ for(i = 0; i < size / width; i++)
+ {
+ line = line_buff;
+ //write address:
+ addr = i*width;
+ word2hex((const char*)&addr, &line);
+ *line++ = ':'; *line++ = ' ';
+ //write hex of data
+ for(j = 0; j < width; j++)
+ {
+ byte2hex(&data[j], &line);
+ *line++ = ' ';
+ }
+ //write char of data
+ for(j = 0; j < width; j++)
+ byte2char(data++, &line);
+ //wirte the end of line
+ *line = 0;
+ //output the line
+ PRINT(line_buff);
+ }
+ //last line of left over if any
+ int leftover = size % width;
+ if(leftover > 0)
+ {
+ line = line_buff;
+ //write address:
+ addr = i*width;
+ word2hex((const char*)&addr, &line);
+ *line++ = ':'; *line++ = ' ';
+ //write hex of data
+ for(j = 0; j < leftover; j++) {
+ byte2hex(&data[j], &line);
+ *line++ = ' ';
+ }
+ //write hex padding
+ for(; j < width; j++) {
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ }
+ //write char of data
+ for(j = 0; j < leftover; j++)
+ byte2char(data++, &line);
+ //write the end of line
+ *line = 0;
+ //output the line
+ PRINT(line_buff);
+ }
+ LOGD("%s, size:%d, dump ended }", title, size);
+}
+