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
nfc_jni_disconnect_callback(void * pContext,NFCSTATUS status)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
nfc_jni_connect_callback(void * pContext,uint8_t nErrCode,NFCSTATUS status)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
nfc_jni_receive_callback(void * pContext,NFCSTATUS status)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
nfc_jni_send_callback(void * pContext,NFCSTATUS status)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 */
com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv * e,jobject o,jint nSap)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
com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv * e,jobject o,jstring sn)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 = {NULL, 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
com_android_nfc_NativeLlcpSocket_doClose(JNIEnv * e,jobject o)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
com_android_nfc_NativeLlcpSocket_doSend(JNIEnv * e,jobject o,jbyteArray data)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
com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv * e,jobject o,jbyteArray buffer)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
com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv * e,jobject o)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
com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv * e,jobject o)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
register_com_android_nfc_NativeLlcpSocket(JNIEnv * e)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