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