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); APPL_TRACE_DEBUG1("sending connect signal & app fd:%dto app server to accept() the connection", accept_rs->app_fd); APPL_TRACE_DEBUG2("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; }
void create_tap_read_thread(int tap_fd) { if(pan_pth < 0) pan_pth = btsock_thread_create(btpan_tap_fd_signaled, NULL); if(pan_pth >= 0) btsock_thread_add_fd(pan_pth, tap_fd, 0, SOCK_THREAD_FD_RD, 0); }
int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf) { pthread_mutex_lock(&slot_lock); int ret = 0; uint32_t id = (uintptr_t)user_data; rfc_slot_t *slot = find_rfc_slot_by_id(id); if (!slot) goto out; if (list_is_empty(slot->incoming_queue)) { switch (send_data_to_app(slot->fd, p_buf)) { case SENT_NONE: case SENT_PARTIAL: list_append(slot->incoming_queue, p_buf); btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, slot->id); break; case SENT_ALL: GKI_freebuf(p_buf); ret = 1; // Enable data flow. break; case SENT_FAILED: GKI_freebuf(p_buf); cleanup_rfc_slot(slot); break; } } else { list_append(slot->incoming_queue, p_buf); } out:; pthread_mutex_unlock(&slot_lock); return ret; // Return 0 to disable data flow. }
static bool flush_incoming_que_on_wr_signal(rfc_slot_t *slot) { while (!list_is_empty(slot->incoming_queue)) { BT_HDR *p_buf = list_front(slot->incoming_queue); switch (send_data_to_app(slot->fd, p_buf)) { case SENT_NONE: case SENT_PARTIAL: //monitor the fd to get callback when app is ready to receive data btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, slot->id); return true; case SENT_ALL: list_remove(slot->incoming_queue, p_buf); break; case SENT_FAILED: list_remove(slot->incoming_queue, 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 APPL_TRACE_DEBUG("enable data flow, rfc_handle:0x%x, rfc_port_handle:0x%x, user_id:%d", slot->rfc_handle, slot->rfc_port_handle, slot->id); extern int PORT_FlowControl_MaxCredit(uint16_t handle, bool enable); PORT_FlowControl_MaxCredit(slot->rfc_port_handle, true); return true; }
static void btpan_tap_fd_signaled(int fd, int type, int flags, uint32_t user_id) { char packet[MAX_PACKET_SIZE]; tETH_HDR eth_hdr; if(flags & SOCK_THREAD_FD_EXCEPTION) { BTIF_TRACE_ERROR1("pan tap fd:%d exception", fd); } else if(flags & SOCK_THREAD_FD_RD) { /* debug("tab fd read trigged, data"); */ int size = read(fd, packet, MAX_PACKET_SIZE); /* debug("tap fd read trigged, read size:%d", size); */ memcpy(ð_hdr, &packet, sizeof(tETH_HDR)); /* debug("eth src = %02x:%02x:%02x:%02x:%02x:%02x", */ /* eth_hdr.h_src[0], eth_hdr.h_src[1], eth_hdr.h_src[2], eth_hdr.h_src[3], */ /* eth_hdr.h_src[4], eth_hdr.h_src[5]); */ /* debug("eth dest = %02x:%02x:%02x:%02x:%02x:%02x", */ /* eth_hdr.h_dest[0], eth_hdr.h_dest[1], eth_hdr.h_dest[2], eth_hdr.h_dest[3], */ /* eth_hdr.h_dest[4], eth_hdr.h_dest[5]); */ //dump_bin("eth packet received", packet, size); if(should_forward(ð_hdr)) { forward_bnep(ð_hdr, packet + sizeof(tETH_HDR), size - sizeof(tETH_HDR)); } btsock_thread_add_fd(pth, fd, 0, SOCK_THREAD_FD_RD | SOCK_THREAD_ADD_FD_SYNC, 0); } }
bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, 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)); *sock_fd = INVALID_FD; // TODO(sharvil): not sure that this check makes sense; seems like a logic error to call // functions on RFCOMM sockets before initializing the module. Probably should be an assert. if (!is_init_done()) return BT_STATUS_NOT_READY; int status = BT_STATUS_FAIL; pthread_mutex_lock(&slot_lock); rfc_slot_t *slot = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, false); if (!slot) { LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__); goto out; } if (is_uuid_empty(service_uuid)) { tBTA_JV_STATUS ret = BTA_JvRfcommConnect(slot->security, slot->role, slot->scn, slot->addr.address, rfcomm_cback, (void *)(uintptr_t)slot->id); if (ret != BTA_JV_SUCCESS) { LOG_ERROR(LOG_TAG, "%s unable to initiate RFCOMM connection: %d", __func__, ret); cleanup_rfc_slot(slot); goto out; } if (!send_app_scn(slot)) { LOG_ERROR(LOG_TAG, "%s unable to send channel number.", __func__); cleanup_rfc_slot(slot); goto out; } } else { tSDP_UUID sdp_uuid; sdp_uuid.len = 16; memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128)); if (!is_requesting_sdp()) { BTA_JvStartDiscovery((uint8_t *)bd_addr->address, 1, &sdp_uuid, (void *)(uintptr_t)slot->id); slot->f.pending_sdp_request = false; slot->f.doing_sdp_request = true; } else { slot->f.pending_sdp_request = true; slot->f.doing_sdp_request = false; } } *sock_fd = slot->app_fd; // Transfer ownership of fd to caller. slot->app_fd = INVALID_FD; // Drop our reference to the fd. btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, slot->id); status = BT_STATUS_SUCCESS; out:; pthread_mutex_unlock(&slot_lock); return status; }
static void on_rfc_write_done(UNUSED_ATTR tBTA_JV_RFCOMM_WRITE *p, uint32_t id) { pthread_mutex_lock(&slot_lock); rfc_slot_t *slot = find_rfc_slot_by_id(id); if (slot && !slot->f.outgoing_congest) btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, slot->id); pthread_mutex_unlock(&slot_lock); }
void btpan_set_flow_control(BOOLEAN enable) { if (btpan_cb.tap_fd == -1) return; btpan_cb.flow = enable; if (enable) { btsock_thread_add_fd(pan_pth, btpan_cb.tap_fd, 0, SOCK_THREAD_FD_RD, 0); bta_dmexecutecallback(btu_exec_tap_fd_read, (void *)btpan_cb.tap_fd); } }
static void on_l2c_write_done(tBTA_JV_L2CAP_WRITE *p, uint32_t id) { lock_slot(&slot_lock); l2c_slot_t* ls = find_l2c_slot_by_id(id); if(ls && !ls->f.outgoing_congest) { //mointer the fd for any outgoing data btsock_thread_add_fd(pth, ls->fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, ls->id); } unlock_slot(&slot_lock); }
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) || ((flags & BTSOCK_FLAG_NO_SDP) != 0)); *sock_fd = INVALID_FD; // TODO(sharvil): not sure that this check makes sense; seems like a logic error to call // functions on RFCOMM sockets before initializing the module. Probably should be an assert. if (!is_init_done()) return BT_STATUS_NOT_READY; 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; pthread_mutex_lock(&slot_lock); rfc_slot_t *slot = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, true); if (!slot) { LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__); goto out; } APPL_TRACE_DEBUG("BTA_JvGetChannelId: service_name: %s - channel: %d", service_name, channel); BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, UINT_TO_PTR(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); status = BT_STATUS_SUCCESS; out:; pthread_mutex_unlock(&slot_lock); return status; }
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) { pthread_mutex_lock(&slot_lock); rfc_slot_t *slot = find_rfc_slot_by_id(id); if (slot) { slot->f.outgoing_congest = p->cong ? 1 : 0; if (!slot->f.outgoing_congest) btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, slot->id); } pthread_mutex_unlock(&slot_lock); }
static void on_l2c_outgoing_congest(tBTA_JV_L2CAP_CONG *p, uint32_t id) { lock_slot(&slot_lock); l2c_slot_t* ls = find_l2c_slot_by_id(id); if(ls) { ls->f.outgoing_congest = p->cong ? 1 : 0; //mointer the fd for any outgoing data if(!ls->f.outgoing_congest) btsock_thread_add_fd(pth, ls->fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, ls->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 uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN *p_open, uint32_t id) { uint32_t new_listen_slot_id = 0; pthread_mutex_lock(&slot_lock); rfc_slot_t *srv_rs = find_rfc_slot_by_id(id); if (!srv_rs) goto out; 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) goto out; // Start monitoring 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); send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd); accept_rs->app_fd = INVALID_FD; // Ownership of the application fd has been transferred. new_listen_slot_id = srv_rs->id; out:; pthread_mutex_unlock(&slot_lock); return new_listen_slot_id; }
bt_status_t btsock_l2c_listen(const char* service_name, const uint8_t* service_uuid, int channel, int* sock_fd, int flags) { int status = BT_STATUS_FAIL; APPL_TRACE_DEBUG("btsock_l2c_listen, service_name:%s", service_name); /* TODO find the available psm list for obex */ if(sock_fd == NULL || (service_uuid == NULL)) { APPL_TRACE_ERROR("invalid sock_fd:%p, uuid:%p", sock_fd, service_uuid); return BT_STATUS_PARM_INVALID; } *sock_fd = -1; if(!is_init_done()) return BT_STATUS_NOT_READY; /* validate it for FTP and OPP */ //Check the service_uuid. overwrite the channel # if reserved int reserved_channel = get_reserved_l2c_channel(service_uuid); if(reserved_channel > 0) { channel = reserved_channel; } else { return BT_STATUS_FAIL; } lock_slot(&slot_lock); l2c_slot_t* ls = alloc_l2c_slot(NULL, service_name, service_uuid, channel, flags, TRUE); if(ls) { APPL_TRACE_DEBUG("BTA_JvCreateRecordByUser:%s", service_name); BTA_JvCreateRecordByUser((void *)(ls->id)); APPL_TRACE_DEBUG("BTA_JvCreateRecordByUser userdata :%d", service_name); *sock_fd = ls->app_fd; ls->app_fd = -1; //the fd ownelship is transferred to app status = BT_STATUS_SUCCESS; btsock_thread_add_fd(pth, ls->fd, BTSOCK_L2CAP, SOCK_THREAD_FD_EXCEPTION, ls->id); } unlock_slot(&slot_lock); return status; }
bt_status_t btsock_rfc_listen(const char* service_name, const uint8_t* service_uuid, int channel, int* sock_fd, int flags) { APPL_TRACE_DEBUG1("btsock_rfc_listen, service_name:%s", service_name); if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30))) { APPL_TRACE_ERROR3("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid); return BT_STATUS_PARM_INVALID; } *sock_fd = -1; if(!is_init_done()) return BT_STATUS_NOT_READY; if(is_uuid_empty(service_uuid)) 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; lock_slot(&slot_lock); rfc_slot_t* rs = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, TRUE); if(rs) { APPL_TRACE_DEBUG1("BTA_JvCreateRecordByUser:%s", service_name); 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 && (channel < 1 || channel > 30))) { APPL_TRACE_ERROR3("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid); return BT_STATUS_PARM_INVALID; } *sock_fd = -1; if(!is_init_done()) return BT_STATUS_NOT_READY; int status = BT_STATUS_FAIL; lock_slot(&slot_lock); rfc_slot_t* rs = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, FALSE); if(rs) { if(is_uuid_empty(service_uuid)) { APPL_TRACE_DEBUG1("connecting to rfcomm channel:%d without service discovery", channel); if(BTA_JvRfcommConnect(rs->security, rs->role, rs->scn, rs->addr.address, rfcomm_cback, (void*)rs->id) == BTA_JV_SUCCESS) { if(send_app_scn(rs)) { btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id); *sock_fd = rs->app_fd; rs->app_fd = -1; //the fd ownership is transferred to app status = BT_STATUS_SUCCESS; } else cleanup_rfc_slot(rs); } else cleanup_rfc_slot(rs); } else { tSDP_UUID sdp_uuid; sdp_uuid.len = 16; memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128)); 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 void btu_exec_tap_fd_read(void *p_param) { struct pollfd ufd; int fd = (int)p_param; if (fd == -1 || fd != btpan_cb.tap_fd) return; // Don't occupy BTU context too long, avoid GKI buffer overruns and // give other profiles a chance to run by limiting the amount of memory // PAN can use from the shared pool buffer. for(int i = 0; i < PAN_POOL_MAX && btif_is_enabled() && btpan_cb.flow; i++) { BT_HDR *buffer = (BT_HDR *)GKI_getpoolbuf(PAN_POOL_ID); if (!buffer) { BTIF_TRACE_WARNING("%s unable to allocate buffer for packet.", __func__); break; } buffer->offset = PAN_MINIMUM_OFFSET; buffer->len = GKI_get_buf_size(buffer) - sizeof(BT_HDR) - buffer->offset; UINT8 *packet = (UINT8 *)buffer + sizeof(BT_HDR) + buffer->offset; // If we don't have an undelivered packet left over, pull one from the TAP driver. // We save it in the congest_packet right away in case we can't deliver it in this // attempt. if (!btpan_cb.congest_packet_size) { ssize_t ret = read(fd, btpan_cb.congest_packet, sizeof(btpan_cb.congest_packet)); switch (ret) { case -1: BTIF_TRACE_ERROR("%s unable to read from driver: %s", __func__, strerror(errno)); GKI_freebuf(buffer); return; case 0: BTIF_TRACE_WARNING("%s end of file reached.", __func__); GKI_freebuf(buffer); return; default: btpan_cb.congest_packet_size = ret; break; } } memcpy(packet, btpan_cb.congest_packet, MIN(btpan_cb.congest_packet_size, buffer->len)); buffer->len = MIN(btpan_cb.congest_packet_size, buffer->len); if (buffer->len > sizeof(tETH_HDR) && should_forward((tETH_HDR *)packet)) { // Extract the ethernet header from the buffer since the PAN_WriteBuf inside // forward_bnep can't handle two pointers that point inside the same GKI buffer. tETH_HDR hdr; memcpy(&hdr, packet, sizeof(tETH_HDR)); // Skip the ethernet header. buffer->len -= sizeof(tETH_HDR); buffer->offset += sizeof(tETH_HDR); if (forward_bnep(&hdr, buffer) != FORWARD_CONGEST) btpan_cb.congest_packet_size = 0; } else { BTIF_TRACE_WARNING("%s dropping packet of length %d", __func__, buffer->len); btpan_cb.congest_packet_size = 0; GKI_freebuf(buffer); } // Bail out of the loop if reading from the TAP fd would block. ufd.fd = fd; ufd.events = POLLIN; ufd.revents = 0; if(poll(&ufd, 1, 0) <= 0 || IS_EXCEPTION(ufd.revents)) { btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0); return; } } }
bt_status_t btsock_l2c_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)) { APPL_TRACE_ERROR("invalid sock_fd:%p, uuid:%p", sock_fd, service_uuid); return BT_STATUS_PARM_INVALID; } *sock_fd = -1; if(!is_init_done()) return BT_STATUS_NOT_READY; int status = BT_STATUS_FAIL; lock_slot(&slot_lock); l2c_slot_t* ls = alloc_l2c_slot(bd_addr, NULL, service_uuid, channel, flags, FALSE); if(ls) { ls->f.client = TRUE; if(is_uuid_empty(service_uuid)) { APPL_TRACE_DEBUG("connecting to l2cap channel:%d without service discovery", channel); if(BTA_JvL2capConnect(ls->security, ls->role, ls->psm, 672, ls->addr.address, l2cap_cback, (void*)ls->id) == BTA_JV_SUCCESS) { if(send_app_psm(ls)) { btsock_thread_add_fd(pth, ls->fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, ls->id); *sock_fd = ls->app_fd; ls->app_fd = -1; //the fd ownelship is transferred to app status = BT_STATUS_SUCCESS; } else cleanup_l2c_slot(ls); } else cleanup_l2c_slot(ls); } else { tSDP_UUID sdp_uuid; sdp_uuid.len = 16; memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128)); logu("service_uuid", service_uuid); *sock_fd = ls->app_fd; ls->app_fd = -1; //the fd ownelship is transferred to app status = BT_STATUS_SUCCESS; l2c_slot_t* ls_doing_sdp = find_l2c_slot_requesting_sdp(); if(ls_doing_sdp == NULL) { BTA_JvStartDiscovery((UINT8*)bd_addr->address, 1, &sdp_uuid, (void*)(ls->id)); ls->f.pending_sdp_request = FALSE; ls->f.doing_sdp_request = TRUE; } else { ls->f.pending_sdp_request = TRUE; ls->f.doing_sdp_request = FALSE; } btsock_thread_add_fd(pth, ls->fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, ls->id); } } unlock_slot(&slot_lock); return status; }