1 /*
2  * Copyright (C) 2012 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 <errno.h>
18 #include <malloc.h>
19 #include <semaphore.h>
20 #include <string.h>
21 #include "OverrideLog.h"
22 #include "NfcJniUtil.h"
23 #include "JavaClassConstants.h"
24 #include <ScopedLocalRef.h>
25 #include <ScopedPrimitiveArray.h>
26 extern "C"
27 {
28     #include "nfa_api.h"
29     #include "nfa_p2p_api.h"
30 }
31 
32 
33 namespace android
34 {
35 
36 
37 /*****************************************************************************
38 **
39 ** private variables and functions
40 **
41 *****************************************************************************/
42 static sem_t        sConnlessRecvSem;
43 static jboolean     sConnlessRecvWaitingForData = JNI_FALSE;
44 static uint8_t*     sConnlessRecvBuf = NULL;
45 static uint32_t     sConnlessRecvLen = 0;
46 static uint32_t     sConnlessRecvRemoteSap = 0;
47 
48 
49 /*******************************************************************************
50 **
51 ** Function:        nativeLlcpConnectionlessSocket_doSendTo
52 **
53 ** Description:     Send data to peer.
54 **                  e: JVM environment.
55 **                  o: Java object.
56 **                  nsap: service access point.
57 **                  data: buffer for data.
58 **
59 ** Returns:         True if ok.
60 **
61 *******************************************************************************/
nativeLlcpConnectionlessSocket_doSendTo(JNIEnv * e,jobject o,jint nsap,jbyteArray data)62 static jboolean nativeLlcpConnectionlessSocket_doSendTo (JNIEnv *e, jobject o, jint nsap, jbyteArray data)
63 {
64     ALOGD ("%s: nsap = %d", __FUNCTION__, nsap);
65 
66     ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
67     jfieldID f = e->GetFieldID(c.get(), "mHandle", "I");
68     jint handle = e->GetIntField(o, f);
69 
70     ScopedByteArrayRO bytes(e, data);
71     if (bytes.get() == NULL)
72     {
73         return JNI_FALSE;
74     }
75     size_t byte_count = bytes.size();
76 
77     ALOGD("NFA_P2pSendUI: len = %zu", byte_count);
78     UINT8* raw_ptr = const_cast<UINT8*>(reinterpret_cast<const UINT8*>(&bytes[0])); // TODO: API bug; NFA_P2pSendUI should take const*!
79     tNFA_STATUS status = NFA_P2pSendUI((tNFA_HANDLE) handle, nsap, byte_count, raw_ptr);
80 
81     ALOGD("%s: NFA_P2pSendUI done, status = %d", __FUNCTION__, status);
82     if (status != NFA_STATUS_OK)
83     {
84         ALOGE("%s: NFA_P2pSendUI failed, status = %d", __FUNCTION__, status);
85         return JNI_FALSE;
86     }
87     return JNI_TRUE;
88 }
89 
90 
91 /*******************************************************************************
92 **
93 ** Function:        nativeLlcpConnectionlessSocket_receiveData
94 **
95 ** Description:     Receive data from the stack.
96 **                  data: buffer contains data.
97 **                  len: length of data.
98 **                  remoteSap: remote service access point.
99 **
100 ** Returns:         None
101 **
102 *******************************************************************************/
nativeLlcpConnectionlessSocket_receiveData(uint8_t * data,uint32_t len,uint32_t remoteSap)103 void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remoteSap)
104 {
105     ALOGD ("%s: waiting for data = %d, len = %d", __FUNCTION__, sConnlessRecvWaitingForData, len);
106 
107     // Sanity...
108     if (sConnlessRecvLen < len)
109     {
110         len = sConnlessRecvLen;
111     }
112 
113     if (sConnlessRecvWaitingForData)
114     {
115         sConnlessRecvWaitingForData = JNI_FALSE;
116         sConnlessRecvLen = len;
117         memcpy (sConnlessRecvBuf, data, len);
118         sConnlessRecvRemoteSap = remoteSap;
119 
120         sem_post (&sConnlessRecvSem);
121     }
122 }
123 
124 
125 /*******************************************************************************
126 **
127 ** Function:        connectionlessCleanup
128 **
129 ** Description:     Free resources.
130 **
131 ** Returns:         None
132 **
133 *******************************************************************************/
connectionlessCleanup()134 static jobject connectionlessCleanup ()
135 {
136     sConnlessRecvWaitingForData = JNI_FALSE;
137     sConnlessRecvLen = 0;
138     if (sConnlessRecvBuf != NULL)
139     {
140         free (sConnlessRecvBuf);
141         sConnlessRecvBuf = NULL;
142     }
143     return NULL;
144 }
145 
146 
147 /*******************************************************************************
148 **
149 ** Function:        nativeLlcpConnectionlessSocket_abortWait
150 **
151 ** Description:     Abort current operation and unblock threads.
152 **
153 ** Returns:         None
154 **
155 *******************************************************************************/
nativeLlcpConnectionlessSocket_abortWait()156 void nativeLlcpConnectionlessSocket_abortWait ()
157 {
158     sem_post (&sConnlessRecvSem);
159 }
160 
161 
162 /*******************************************************************************
163 **
164 ** Function:        nativeLlcpConnectionlessSocket_doReceiveFrom
165 **
166 ** Description:     Receive data from a peer.
167 **                  e: JVM environment.
168 **                  o: Java object.
169 **                  linkMiu: max info unit
170 **
171 ** Returns:         LlcpPacket Java object.
172 **
173 *******************************************************************************/
nativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv * e,jobject,jint linkMiu)174 static jobject nativeLlcpConnectionlessSocket_doReceiveFrom (JNIEnv* e, jobject, jint linkMiu)
175 {
176     ALOGD ("%s: linkMiu = %d", __FUNCTION__, linkMiu);
177     jobject llcpPacket = NULL;
178     ScopedLocalRef<jclass> clsLlcpPacket(e, NULL);
179 
180     if (sConnlessRecvWaitingForData != JNI_FALSE)
181     {
182         ALOGD ("%s: Already waiting for incoming data", __FUNCTION__);
183         return NULL;
184     }
185 
186     sConnlessRecvBuf = (uint8_t*) malloc (linkMiu);
187     if (sConnlessRecvBuf == NULL)
188     {
189         ALOGD ("%s: Failed to allocate %d bytes memory buffer", __FUNCTION__, linkMiu);
190         return NULL;
191     }
192     sConnlessRecvLen = linkMiu;
193 
194     // Create the write semaphore
195     if (sem_init (&sConnlessRecvSem, 0, 0) == -1)
196     {
197         ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
198         return connectionlessCleanup ();
199     }
200 
201     sConnlessRecvWaitingForData = JNI_TRUE;
202 
203     // Wait for sConnlessRecvSem completion status
204     if (sem_wait (&sConnlessRecvSem))
205     {
206         ALOGE ("%s: Failed to wait for write semaphore (errno=0x%08x)", __FUNCTION__, errno);
207         goto TheEnd;
208     }
209 
210     // Create new LlcpPacket object
211     if (nfc_jni_cache_object_local (e, "com/android/nfc/LlcpPacket", &(llcpPacket)) == -1)
212     {
213         ALOGE ("%s: Find LlcpPacket class error", __FUNCTION__);
214         return connectionlessCleanup ();
215     }
216 
217     // Get NativeConnectionless class object
218     clsLlcpPacket.reset(e->GetObjectClass(llcpPacket));
219     if (e->ExceptionCheck())
220     {
221         e->ExceptionClear();
222         ALOGE ("%s: Get Object class error", __FUNCTION__);
223         return connectionlessCleanup ();
224     }
225 
226     // Set Llcp Packet remote SAP
227     jfieldID f;
228     f = e->GetFieldID(clsLlcpPacket.get(), "mRemoteSap", "I");
229     e->SetIntField(llcpPacket, f, (jbyte) sConnlessRecvRemoteSap);
230 
231     // Set Llcp Packet Buffer
232     ALOGD ("%s: Received Llcp packet buffer size = %d\n", __FUNCTION__, sConnlessRecvLen);
233     f = e->GetFieldID(clsLlcpPacket.get(), "mDataBuffer", "[B");
234 
235     {
236         ScopedLocalRef<jbyteArray> receivedData(e, e->NewByteArray(sConnlessRecvLen));
237         e->SetByteArrayRegion(receivedData.get(), 0, sConnlessRecvLen, (jbyte*) sConnlessRecvBuf);
238         e->SetObjectField(llcpPacket, f, receivedData.get());
239     }
240 
241 TheEnd: // TODO: should all the "return connectionlessCleanup()"s in this function jump here instead?
242     connectionlessCleanup ();
243     if (sem_destroy (&sConnlessRecvSem))
244     {
245         ALOGE ("%s: Failed to destroy sConnlessRecvSem semaphore (errno=0x%08x)", __FUNCTION__, errno);
246     }
247     return llcpPacket;
248 }
249 
250 
251 /*******************************************************************************
252 **
253 ** Function:        nativeLlcpConnectionlessSocket_doClose
254 **
255 ** Description:     Close socket.
256 **                  e: JVM environment.
257 **                  o: Java object.
258 **
259 ** Returns:         True if ok.
260 **
261 *******************************************************************************/
nativeLlcpConnectionlessSocket_doClose(JNIEnv * e,jobject o)262 static jboolean nativeLlcpConnectionlessSocket_doClose (JNIEnv *e, jobject o)
263 {
264     ALOGD ("%s", __FUNCTION__);
265 
266     ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
267     jfieldID f = e->GetFieldID(c.get(), "mHandle", "I");
268     jint handle = e->GetIntField(o, f);
269 
270     tNFA_STATUS status = NFA_P2pDisconnect((tNFA_HANDLE) handle, FALSE);
271     if (status != NFA_STATUS_OK)
272     {
273         ALOGE ("%s: disconnect failed, status = %d", __FUNCTION__, status);
274         return JNI_FALSE;
275     }
276     return JNI_TRUE;
277 }
278 
279 
280 /*****************************************************************************
281 **
282 ** Description:     JNI functions
283 **
284 *****************************************************************************/
285 static JNINativeMethod gMethods[] =
286 {
287     {"doSendTo", "(I[B)Z", (void*) nativeLlcpConnectionlessSocket_doSendTo},
288     {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void*) nativeLlcpConnectionlessSocket_doReceiveFrom},
289     {"doClose", "()Z", (void*) nativeLlcpConnectionlessSocket_doClose},
290 };
291 
292 
293 /*******************************************************************************
294 **
295 ** Function:        register_com_android_nfc_NativeLlcpConnectionlessSocket
296 **
297 ** Description:     Regisgter JNI functions with Java Virtual Machine.
298 **                  e: Environment of JVM.
299 **
300 ** Returns:         Status of registration.
301 **
302 *******************************************************************************/
register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv * e)303 int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e)
304 {
305     return jniRegisterNativeMethods (e, gNativeLlcpConnectionlessSocketClassName, gMethods, NELEM(gMethods));
306 }
307 
308 
309 } // android namespace
310