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);
}
示例#3
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.
}
示例#4
0
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;
}
示例#5
0
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(&eth_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(&eth_hdr))
        {
            forward_bnep(&eth_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);
    }
}
示例#6
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;
}
示例#7
0
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);
}
示例#10
0
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);
}
示例#12
0
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);
}
示例#15
0
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;
}