static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   phLibNfc_Handle hLlcpSocket;
   nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();

   TRACE("Close Service socket");

   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
   /* TODO: implement accept abort */
   pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
   pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);

   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Close(hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret == NFCSTATUS_SUCCESS)
   {
      TRACE("Close Service socket OK");
      return TRUE;
   }
   else
   {
      LOGD("Close Service socket KO");
      return FALSE;
   }
}
static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   phLibNfc_Handle hLlcpSocket;
   phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;

   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);   

   TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)");
   REENTRANCE_LOCK();
   ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hLlcpSocket,
                                               &remoteSocketOption);
   REENTRANCE_UNLOCK();
   if(ret == NFCSTATUS_SUCCESS)
   {
      TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return remoteSocketOption.rw;
   }
   else
   {
      LOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return 0;
   }
}
static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn)
{
   NFCSTATUS ret;
   struct timespec ts;
   phNfc_sData_t serviceName = {0};
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   struct nfc_jni_callback_data cb_data;
   jboolean result = JNI_FALSE;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   /* Service socket */
   serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
   serviceName.length = (uint32_t)e->GetStringUTFLength(sn);

   TRACE("phLibNfc_Llcp_ConnectByUri()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice,
                                    hLlcpSocket,
                                    &serviceName,
                                    nfc_jni_connect_callback,
                                    (void*)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   if (serviceName.buffer != NULL) {
      e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
   }
   nfc_cb_data_deinit(&cb_data);
   return result;
}
static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray  data)
{
   NFCSTATUS ret;
   struct timespec ts;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sSendBuffer = {NULL, 0};
   struct nfc_jni_callback_data cb_data;
   jboolean result = JNI_FALSE;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
   sSendBuffer.length = (uint32_t)e->GetArrayLength(data);

   TRACE("phLibNfc_Llcp_Send()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Send(hRemoteDevice,
                            hLlcpSocket,
                            &sSendBuffer,
                            nfc_jni_send_callback,
                            (void*)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
       goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   if (sSendBuffer.buffer != NULL)
   {
      e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
   }
   nfc_cb_data_deinit(&cb_data);
   return result;
}
static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o)
{
	uint32_t handle = nfc_jni_get_nfc_socket_handle(e, o);
	bool_t canUse = W_FALSE;

    jclass target_cls = NULL;
    jfieldID f;
	if(IS_SERVER_SOCKET(handle))
	{
		canUse = isServerSoketValid(handle);
	}
	else if(IS_CLIENT_SOCKET(handle))
	{
		canUse = isClientSoketValid(handle);
	}
	if(canUse==W_FALSE)
	{
		return JNI_FALSE;
	}
    target_cls = e->GetObjectClass(o);

    f = e->GetFieldID(target_cls, "mGeneralBytes", "[B");

	jbyteArray generalBytes = NULL;

    generalBytes = e->NewByteArray(GENERAL_BYTES_LENGTH);

    e->SetByteArrayRegion(generalBytes, 0, GENERAL_BYTES_LENGTH, (jbyte *)GENERAL_BYTES);

    e->SetObjectField(o, f, generalBytes);
	return JNI_TRUE;
}
static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)");
   REENTRANCE_LOCK();
   ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
                                               hLlcpSocket,
                                               &remoteSocketOption);
   REENTRANCE_UNLOCK();
   if(ret == NFCSTATUS_SUCCESS)
   {
      TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return remoteSocketOption.miu;
   }
   else
   {
      ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return 0;
   }
}
/*******************************************************************************
**
** Function:        nativeLlcpSocket_doGetRemoteSocketMIU
**
** Description:     Get peer's maximum information unit.
**                  e: JVM environment.
**                  o: Java object.
**
** Returns:         Peer's maximum information unit.
**
*******************************************************************************/
static jint nativeLlcpSocket_doGetRemoteSocketMIU (JNIEnv* e, jobject o)
{
    ALOGD ("%s: enter", __FUNCTION__);

    PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle(e, o);
    jint miu = PeerToPeer::getInstance().getRemoteMaxInfoUnit(jniHandle);

    ALOGD ("%s: exit", __FUNCTION__);
    return miu;
}
/*******************************************************************************
**
** Function:        nativeLlcpSocket_doClose
**
** Description:     Close socket.
**                  e: JVM environment.
**                  o: Java object.
**
** Returns:         True if ok.
**
*******************************************************************************/
static jboolean nativeLlcpSocket_doClose(JNIEnv *e, jobject o)
{
    ALOGD ("%s: enter", __FUNCTION__);

    PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle(e, o);
    bool stat = PeerToPeer::getInstance().disconnectConnOriented (jniHandle);

    ALOGD ("%s: exit", __FUNCTION__);
    return stat ? JNI_TRUE : JNI_FALSE;
}
/*******************************************************************************
**
** Function:        nativeLlcpSocket_doGetRemoteSocketRW
**
** Description:     Get peer's receive window size.
**                  e: JVM environment.
**                  o: Java object.
**
** Returns:         Peer's receive window size.
**
*******************************************************************************/
static jint nativeLlcpSocket_doGetRemoteSocketRW (JNIEnv* e, jobject o)
{
    ALOGD ("%s: enter", __FUNCTION__);

    PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle(e, o);
    jint rw = PeerToPeer::getInstance().getRemoteRecvWindow (jniHandle);

    ALOGD ("%s: exit", __FUNCTION__);
    return rw;
}
/*
 * Methods
 */
static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap)
{
   NFCSTATUS ret;
   struct timespec ts;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   struct nfc_jni_callback_data cb_data;
   jboolean result = JNI_FALSE;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   TRACE("phLibNfc_Llcp_Connect(%d)",nSap);
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Connect(hRemoteDevice,
                               hLlcpSocket,
                               nSap,
                               nfc_jni_connect_callback,
                               (void*)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      ALOGW("LLCP Connect request failed");
      goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   return result;
}
/*******************************************************************************
**
** Function:        nativeLlcpSocket_doSend
**
** Description:     Send data to peer.
**                  e: JVM environment.
**                  o: Java object.
**                  data: Buffer of data.
**
** Returns:         True if sent ok.
**
*******************************************************************************/
static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data)
{
    ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__);

    ScopedByteArrayRO bytes(e, data);

    PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle(e, o);
    UINT8* raw_ptr = const_cast<UINT8*>(reinterpret_cast<const UINT8*>(&bytes[0])); // TODO: API bug: send should take const*!
    bool stat = PeerToPeer::getInstance().send(jniHandle, raw_ptr, bytes.size());

    ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit", __FUNCTION__);
    return stat ? JNI_TRUE : JNI_FALSE;
}
/*******************************************************************************
**
** Function:        nativeLlcpSocket_doConnectBy
**
** Description:     Establish a connection to the peer.
**                  e: JVM environment.
**                  o: Java object.
**                  sn: Service name.
**
** Returns:         True if ok.
**
*******************************************************************************/
static jboolean nativeLlcpSocket_doConnectBy (JNIEnv* e, jobject o, jstring sn)
{
    ALOGD ("%s: enter", __FUNCTION__);

    PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle(e, o);

    ScopedUtfChars serviceName(e, sn);
    if (serviceName.c_str() == NULL)
    {
        return JNI_FALSE;
    }
    bool stat = PeerToPeer::getInstance().connectConnOriented(jniHandle, serviceName.c_str());

    ALOGD ("%s: exit", __FUNCTION__);
    return stat ? JNI_TRUE : JNI_FALSE;
}
static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o)
{
	uint32_t handle = nfc_jni_get_nfc_socket_handle(e, o);
	bool_t canUse = W_FALSE;

    jclass target_cls = NULL;
    jfieldID f;
	if(IS_SERVER_SOCKET(handle))
	{
		return serverSocketDisconnect(handle);
	}
	else if(IS_CLIENT_SOCKET(handle))
	{
		return socketDisconnect(handle);
	}
	return JNI_FALSE;
}
static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e,
   jobject o, jbyteArray data)
{
	uint32_t handle = nfc_jni_get_nfc_socket_handle(e, o);
	bool_t canUse = W_FALSE;

    jclass target_cls = NULL;
    jfieldID f;
	if(IS_SERVER_SOCKET(handle))
	{
		return serverSocketTransceive(e, handle, data);
	}
	else if(IS_CLIENT_SOCKET(handle))
	{
		return socketTransceive(e, handle, data);
	}
	return NULL;
}
static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray  buffer)
{
   NFCSTATUS ret;
   struct timespec ts;  
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sReceiveBuffer;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
   sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);
   
   TRACE("phLibNfc_Llcp_Recv()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Recv(hLlcpSocket,
                            &sReceiveBuffer,
                            nfc_jni_receive_callback,
                            (void*)hLlcpSocket);
   REENTRANCE_UNLOCK();
   if((ret != NFCSTATUS_SUCCESS) && (ret != NFCSTATUS_PENDING))
   {
       /* Return status should be either SUCCESS or PENDING */
       LOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
       return 0;
   }
   TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response (happen if status is either SUCCESS or PENDING) */
   if(sem_wait(nfc_jni_llcp_sem) == -1)
   {
      return 0;
   }

   if(nfc_jni_cb_status == NFCSTATUS_SUCCESS)
   {
      return sReceiveBuffer.length;
   }
   else
   {
      return 0;
   }
}
static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   phLibNfc_Handle hLlcpSocket;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   TRACE("phLibNfc_Llcp_Close()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Close(hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_SUCCESS)
   {
      LOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return FALSE; 
   }
   TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
   return TRUE;
}
static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray  data)
{
   NFCSTATUS ret;
   struct timespec ts;  
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sSendBuffer;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
   sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
   
   TRACE("phLibNfc_Llcp_Send()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Send(hLlcpSocket,
                            &sSendBuffer,
                            nfc_jni_send_callback,
                            (void*)hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return FALSE;
   } 
   TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
   
   /* Wait for callback response */
   if(sem_wait(nfc_jni_llcp_sem) == -1)
      return FALSE;   


   if(nfc_jni_cb_status == NFCSTATUS_SUCCESS)
   {
      return TRUE; 
   }
   else
   {
      return FALSE;    
   }     
}
static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn)
{
   NFCSTATUS ret;
   struct timespec ts;
   phNfc_sData_t serviceName;   
   phLibNfc_Handle hLlcpSocket;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   /* Service socket */
   serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
   serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
   
   TRACE("phLibNfc_Llcp_ConnectByUri()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_ConnectByUri(hLlcpSocket,
                                    &serviceName,
                                    nfc_jni_connect_callback,
                                    (void*)hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return FALSE;
   }   
   TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
   
   /* Wait for callback response */
   if(sem_wait(nfc_jni_llcp_sem) == -1)
      return FALSE;
   
   if(nfc_jni_cb_status == NFCSTATUS_SUCCESS)
   {
      return TRUE; 
   }
   else
   {
      return FALSE;    
   }   
}
/*******************************************************************************
**
** Function:        nativeLlcpSocket_doReceive
**
** Description:     Receive data from peer.
**                  e: JVM environment.
**                  o: Java object.
**                  origBuffer: Buffer to put received data.
**
** Returns:         Number of bytes received.
**
*******************************************************************************/
static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuffer)
{
    ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__);

    ScopedByteArrayRW bytes(e, origBuffer);

    PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle(e, o);
    uint16_t actualLen = 0;
    bool stat = PeerToPeer::getInstance().receive(jniHandle, reinterpret_cast<UINT8*>(&bytes[0]), bytes.size(), actualLen);

    jint retval = 0;
    if (stat && (actualLen>0))
    {
        retval = actualLen;
    }
    else
        retval = -1;

    ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit; actual len=%d", __FUNCTION__, retval);
    return retval;
}
/*
 * Methods
 */
static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap)
{
   NFCSTATUS ret;
   struct timespec ts;
   phLibNfc_Handle hLlcpSocket;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   TRACE("phLibNfc_Llcp_Connect(%d)",nSap);
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Connect(hLlcpSocket,
                               nSap,
                               nfc_jni_connect_callback,
                               (void*)hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
      return FALSE;
   }
   TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
   
   /* Wait for callback response */
   if(sem_wait(nfc_jni_llcp_sem) == -1)
      return FALSE;
   
   if(nfc_jni_cb_status == NFCSTATUS_SUCCESS)
   {
      TRACE("LLCP Connect request OK");
      return TRUE; 
   }
   else
   {
      LOGD("LLCP Connect request KO");
      return FALSE;    
   }
}
static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray  buffer)
{
   NFCSTATUS ret;
   struct timespec ts;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sReceiveBuffer = {NULL, 0};
   struct nfc_jni_callback_data cb_data;
   jint result = -1;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
   sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);

   TRACE("phLibNfc_Llcp_Recv()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Recv(hRemoteDevice,
                            hLlcpSocket,
                            &sReceiveBuffer,
                            nfc_jni_receive_callback,
                            (void*)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret == NFCSTATUS_PENDING)
   {
      /* Wait for callback response */
      if(sem_wait(&cb_data.sem))
      {
         ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
         goto clean_and_return;
      }

      if(cb_data.status == NFCSTATUS_SUCCESS)
      {
         result = sReceiveBuffer.length;
      }
   }
   else if (ret == NFCSTATUS_SUCCESS)
   {
      result = sReceiveBuffer.length;
   }
   else
   {
      /* Return status should be either SUCCESS or PENDING */
      ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

clean_and_return:
   if (sReceiveBuffer.buffer != NULL)
   {
      e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0);
   }
   nfc_cb_data_deinit(&cb_data);
   return result;
}
/*
 * Methods
 */ 
static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength)
{
   NFCSTATUS ret = NFCSTATUS_SUCCESS;
   struct timespec ts;
   phLibNfc_Llcp_sSocketOptions_t sOptions;
   phNfc_sData_t sWorkingBuffer;
   jfieldID f;   
   jclass clsNativeLlcpSocket;
   jobject clientSocket = NULL;
   struct nfc_jni_callback_data cb_data;
   phLibNfc_Handle hIncomingSocket, hServerSocket;
   nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   /* Get server socket */
   hServerSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Set socket options with the socket options of the service */
   sOptions.miu = miu;
   sOptions.rw = rw;
   
   /* Allocate Working buffer length */
   sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength);
   sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;

   while(cb_data.status != NFCSTATUS_SUCCESS)
   {
      /* Wait for tag Notification */
      pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
      while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) {
         pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex);
      }
      pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);

      /* Accept the incomming socket */
      TRACE("phLibNfc_Llcp_Accept()");
      REENTRANCE_LOCK();
      ret = phLibNfc_Llcp_Accept( hIncomingSocket,
                                  &sOptions,
                                  &sWorkingBuffer,
                                  nfc_jni_llcp_transport_socket_err_callback,
                                  nfc_jni_llcp_accept_socket_callback,
                                  (void*)&cb_data);
      REENTRANCE_UNLOCK();
      if(ret != NFCSTATUS_PENDING)
      {
         // NOTE: This may happen if link went down since incoming socket detected, then
         //       just drop it and start a new accept loop.
         LOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
         continue;
      }
      TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

      /* Wait for callback response */
      if(sem_wait(&cb_data.sem))
      {
         LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
         goto clean_and_return;
      }

      if(cb_data.status != NFCSTATUS_SUCCESS)
      {
         /* NOTE: Do not generate an error if the accept failed to avoid error in server application */
         LOGD("Failed to accept incoming socket  0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status));
      }
   }

   /* Create new LlcpSocket object */
   if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1)
   {
      LOGD("LLCP Socket creation error");
      goto clean_and_return;
   }

   /* Get NativeConnectionOriented class object */
   clsNativeLlcpSocket = e->GetObjectClass(clientSocket);
   if(e->ExceptionCheck())
   {
      LOGD("LLCP Socket get class object error");
      goto clean_and_return;
   }

   /* Set socket handle */
   f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I");
   e->SetIntField(clientSocket, f,(jint)hIncomingSocket);

   /* Set socket MIU */
   f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I");
   e->SetIntField(clientSocket, f,(jint)miu);

   /* Set socket RW */
   f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I");
   e->SetIntField(clientSocket, f,(jint)rw);

   TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw);

clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   return clientSocket;
}
static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu)
{
   NFCSTATUS ret;
   struct timespec ts;
   uint8_t ssap;
   jobject llcpPacket = NULL;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sReceiveBuffer;
   jclass clsLlcpPacket;
   jfieldID f;
   jbyteArray receivedData = NULL;
   struct nfc_jni_callback_data cb_data;

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   /* Create new LlcpPacket object */
   if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1)
   {
      ALOGE("Find LlcpPacket class error");
      goto clean_and_return;
   }

   /* Get NativeConnectionless class object */
   clsLlcpPacket = e->GetObjectClass(llcpPacket);
   if(e->ExceptionCheck())
   {
      ALOGE("Get Object class error");
      goto clean_and_return;
   } 

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu);

   sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu);
   sReceiveBuffer.length = linkMiu;

   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice,
                                hLlcpSocket,
                                &sReceiveBuffer,
                                nfc_jni_receive_callback,
                                &cb_data);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS)
   {
      ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   } 
   TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
       goto clean_and_return;
   }

   ssap = (uint32_t)cb_data.pContext;
   TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length);

   /* Set Llcp Packet remote SAP */
   f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I");
   e->SetIntField(llcpPacket, f,(jbyte)ssap);

   /* Set Llcp Packet Buffer */
   ALOGD("Set LlcpPacket Data Buffer\n");
   f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B");
   receivedData = e->NewByteArray(sReceiveBuffer.length);
   e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer);
   e->SetObjectField(llcpPacket, f, receivedData);

clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   return llcpPacket;
}