1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <semaphore.h> 18 #include <errno.h> 19 20 #include "com_android_nfc.h" 21 22 namespace android { 23 24 /* 25 * Callbacks 26 */ 27 28 static void nfc_jni_disconnect_callback(void* pContext, 29 NFCSTATUS status) 30 { 31 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 32 LOG_CALLBACK("nfc_jni_disconnect_callback", status); 33 34 /* Report the callback status and wake up the caller */ 35 pCallbackData->status = status; 36 sem_post(&pCallbackData->sem); 37 } 38 39 40 static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) 41 { 42 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 43 LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); 44 45 if(status == NFCSTATUS_SUCCESS) 46 { 47 TRACE("Socket connected\n"); 48 } 49 else 50 { 51 ALOGD("Socket not connected:"); 52 switch(nErrCode) 53 { 54 case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: 55 { 56 ALOGD("> SAP NOT ACTIVE\n"); 57 }break; 58 59 case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: 60 { 61 ALOGD("> SAP NOT FOUND\n"); 62 }break; 63 64 case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: 65 { 66 ALOGD("> CONNECT REJECTED\n"); 67 }break; 68 69 case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: 70 { 71 ALOGD("> CONNECT NOT ACCEPTED\n"); 72 }break; 73 74 case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: 75 { 76 ALOGD("> SOCKET NOT AVAILABLE\n"); 77 }break; 78 } 79 } 80 81 /* Report the callback status and wake up the caller */ 82 pCallbackData->status = status; 83 sem_post(&pCallbackData->sem); 84 } 85 86 87 88 89 static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) 90 { 91 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 92 LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); 93 94 /* Report the callback status and wake up the caller */ 95 pCallbackData->status = status; 96 sem_post(&pCallbackData->sem); 97 } 98 99 static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) 100 { 101 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 102 LOG_CALLBACK("nfc_jni_llcp_send_callback", status); 103 104 /* Report the callback status and wake up the caller */ 105 pCallbackData->status = status; 106 sem_post(&pCallbackData->sem); 107 } 108 109 /* 110 * Methods 111 */ 112 static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) 113 { 114 NFCSTATUS ret; 115 struct timespec ts; 116 phLibNfc_Handle hRemoteDevice; 117 phLibNfc_Handle hLlcpSocket; 118 struct nfc_jni_callback_data cb_data; 119 jboolean result = JNI_FALSE; 120 121 /* Retrieve handles */ 122 hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); 123 hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); 124 125 /* Create the local semaphore */ 126 if (!nfc_cb_data_init(&cb_data, NULL)) 127 { 128 goto clean_and_return; 129 } 130 131 TRACE("phLibNfc_Llcp_Connect(%d)",nSap); 132 REENTRANCE_LOCK(); 133 ret = phLibNfc_Llcp_Connect(hRemoteDevice, 134 hLlcpSocket, 135 nSap, 136 nfc_jni_connect_callback, 137 (void*)&cb_data); 138 REENTRANCE_UNLOCK(); 139 if(ret != NFCSTATUS_PENDING) 140 { 141 ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); 142 goto clean_and_return; 143 } 144 TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); 145 146 /* Wait for callback response */ 147 if(sem_wait(&cb_data.sem)) 148 { 149 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 150 goto clean_and_return; 151 } 152 153 if(cb_data.status != NFCSTATUS_SUCCESS) 154 { 155 ALOGW("LLCP Connect request failed"); 156 goto clean_and_return; 157 } 158 159 result = JNI_TRUE; 160 161 clean_and_return: 162 nfc_cb_data_deinit(&cb_data); 163 return result; 164 } 165 166 static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) 167 { 168 NFCSTATUS ret; 169 struct timespec ts; 170 phNfc_sData_t serviceName = {0}; 171 phLibNfc_Handle hRemoteDevice; 172 phLibNfc_Handle hLlcpSocket; 173 struct nfc_jni_callback_data cb_data; 174 jboolean result = JNI_FALSE; 175 176 /* Retrieve handles */ 177 hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); 178 hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); 179 180 /* Create the local semaphore */ 181 if (!nfc_cb_data_init(&cb_data, NULL)) 182 { 183 goto clean_and_return; 184 } 185 186 /* Service socket */ 187 serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); 188 serviceName.length = (uint32_t)e->GetStringUTFLength(sn); 189 190 TRACE("phLibNfc_Llcp_ConnectByUri()"); 191 REENTRANCE_LOCK(); 192 ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, 193 hLlcpSocket, 194 &serviceName, 195 nfc_jni_connect_callback, 196 (void*)&cb_data); 197 REENTRANCE_UNLOCK(); 198 if(ret != NFCSTATUS_PENDING) 199 { 200 ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 201 goto clean_and_return; 202 } 203 TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 204 205 /* Wait for callback response */ 206 if(sem_wait(&cb_data.sem)) 207 { 208 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 209 goto clean_and_return; 210 } 211 212 if(cb_data.status != NFCSTATUS_SUCCESS) 213 { 214 goto clean_and_return; 215 } 216 217 result = JNI_TRUE; 218 219 clean_and_return: 220 if (serviceName.buffer != NULL) { 221 e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); 222 } 223 nfc_cb_data_deinit(&cb_data); 224 return result; 225 } 226 227 static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) 228 { 229 NFCSTATUS ret; 230 phLibNfc_Handle hLlcpSocket; 231 232 /* Retrieve socket handle */ 233 hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); 234 235 TRACE("phLibNfc_Llcp_Close()"); 236 REENTRANCE_LOCK(); 237 ret = phLibNfc_Llcp_Close(hLlcpSocket); 238 REENTRANCE_UNLOCK(); 239 if(ret != NFCSTATUS_SUCCESS) 240 { 241 ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 242 return FALSE; 243 } 244 TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 245 return TRUE; 246 } 247 248 static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) 249 { 250 NFCSTATUS ret; 251 struct timespec ts; 252 phLibNfc_Handle hRemoteDevice; 253 phLibNfc_Handle hLlcpSocket; 254 phNfc_sData_t sSendBuffer = {NULL, 0}; 255 struct nfc_jni_callback_data cb_data; 256 jboolean result = JNI_FALSE; 257 258 /* Retrieve handles */ 259 hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); 260 hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); 261 262 /* Create the local semaphore */ 263 if (!nfc_cb_data_init(&cb_data, NULL)) 264 { 265 goto clean_and_return; 266 } 267 268 sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); 269 sSendBuffer.length = (uint32_t)e->GetArrayLength(data); 270 271 TRACE("phLibNfc_Llcp_Send()"); 272 REENTRANCE_LOCK(); 273 ret = phLibNfc_Llcp_Send(hRemoteDevice, 274 hLlcpSocket, 275 &sSendBuffer, 276 nfc_jni_send_callback, 277 (void*)&cb_data); 278 REENTRANCE_UNLOCK(); 279 if(ret != NFCSTATUS_PENDING) 280 { 281 ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 282 goto clean_and_return; 283 } 284 TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 285 286 /* Wait for callback response */ 287 if(sem_wait(&cb_data.sem)) 288 { 289 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 290 goto clean_and_return; 291 } 292 293 if(cb_data.status != NFCSTATUS_SUCCESS) 294 { 295 goto clean_and_return; 296 } 297 298 result = JNI_TRUE; 299 300 clean_and_return: 301 if (sSendBuffer.buffer != NULL) 302 { 303 e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); 304 } 305 nfc_cb_data_deinit(&cb_data); 306 return result; 307 } 308 309 static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) 310 { 311 NFCSTATUS ret; 312 struct timespec ts; 313 phLibNfc_Handle hRemoteDevice; 314 phLibNfc_Handle hLlcpSocket; 315 phNfc_sData_t sReceiveBuffer = {NULL, 0}; 316 struct nfc_jni_callback_data cb_data; 317 jint result = -1; 318 319 /* Retrieve handles */ 320 hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); 321 hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); 322 323 /* Create the local semaphore */ 324 if (!nfc_cb_data_init(&cb_data, NULL)) 325 { 326 goto clean_and_return; 327 } 328 329 sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); 330 sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); 331 332 TRACE("phLibNfc_Llcp_Recv()"); 333 REENTRANCE_LOCK(); 334 ret = phLibNfc_Llcp_Recv(hRemoteDevice, 335 hLlcpSocket, 336 &sReceiveBuffer, 337 nfc_jni_receive_callback, 338 (void*)&cb_data); 339 REENTRANCE_UNLOCK(); 340 if(ret == NFCSTATUS_PENDING) 341 { 342 /* Wait for callback response */ 343 if(sem_wait(&cb_data.sem)) 344 { 345 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 346 goto clean_and_return; 347 } 348 349 if(cb_data.status == NFCSTATUS_SUCCESS) 350 { 351 result = sReceiveBuffer.length; 352 } 353 } 354 else if (ret == NFCSTATUS_SUCCESS) 355 { 356 result = sReceiveBuffer.length; 357 } 358 else 359 { 360 /* Return status should be either SUCCESS or PENDING */ 361 ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 362 goto clean_and_return; 363 } 364 TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 365 366 clean_and_return: 367 if (sReceiveBuffer.buffer != NULL) 368 { 369 e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); 370 } 371 nfc_cb_data_deinit(&cb_data); 372 return result; 373 } 374 375 static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) 376 { 377 NFCSTATUS ret; 378 phLibNfc_Handle hRemoteDevice; 379 phLibNfc_Handle hLlcpSocket; 380 phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; 381 382 /* Retrieve handles */ 383 hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); 384 hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); 385 386 TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); 387 REENTRANCE_LOCK(); 388 ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, 389 hLlcpSocket, 390 &remoteSocketOption); 391 REENTRANCE_UNLOCK(); 392 if(ret == NFCSTATUS_SUCCESS) 393 { 394 TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 395 return remoteSocketOption.miu; 396 } 397 else 398 { 399 ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 400 return 0; 401 } 402 } 403 404 static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) 405 { 406 NFCSTATUS ret; 407 phLibNfc_Handle hRemoteDevice; 408 phLibNfc_Handle hLlcpSocket; 409 phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; 410 411 /* Retrieve handles */ 412 hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); 413 hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); 414 415 TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); 416 REENTRANCE_LOCK(); 417 ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, 418 hLlcpSocket, 419 &remoteSocketOption); 420 REENTRANCE_UNLOCK(); 421 if(ret == NFCSTATUS_SUCCESS) 422 { 423 TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 424 return remoteSocketOption.rw; 425 } 426 else 427 { 428 ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); 429 return 0; 430 } 431 } 432 433 434 /* 435 * JNI registration. 436 */ 437 static JNINativeMethod gMethods[] = 438 { 439 {"doConnect", "(I)Z", 440 (void *)com_android_nfc_NativeLlcpSocket_doConnect}, 441 442 {"doConnectBy", "(Ljava/lang/String;)Z", 443 (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, 444 445 {"doClose", "()Z", 446 (void *)com_android_nfc_NativeLlcpSocket_doClose}, 447 448 {"doSend", "([B)Z", 449 (void *)com_android_nfc_NativeLlcpSocket_doSend}, 450 451 {"doReceive", "([B)I", 452 (void *)com_android_nfc_NativeLlcpSocket_doReceive}, 453 454 {"doGetRemoteSocketMiu", "()I", 455 (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, 456 457 {"doGetRemoteSocketRw", "()I", 458 (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, 459 }; 460 461 462 int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) 463 { 464 return jniRegisterNativeMethods(e, 465 "com/android/nfc/dhimpl/NativeLlcpSocket",gMethods, NELEM(gMethods)); 466 } 467 468 } // namespace android 469