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