1/*
2 * Copyright (C) 2013 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/*
18 *  Manage the listen-mode routing table.
19 */
20
21#include <cutils/log.h>
22#include <ScopedLocalRef.h>
23#include <JNIHelp.h>
24#include "config.h"
25#include "JavaClassConstants.h"
26#include "RoutingManager.h"
27
28extern "C"
29{
30    #include "nfa_ee_api.h"
31    #include "nfa_ce_api.h"
32}
33extern bool gActivated;
34extern SyncEvent gDeactivatedEvent;
35
36
37const JNINativeMethod RoutingManager::sMethods [] =
38{
39    {"doGetDefaultRouteDestination", "()I", (void*) RoutingManager::com_android_nfc_cardemulation_doGetDefaultRouteDestination},
40    {"doGetDefaultOffHostRouteDestination", "()I", (void*) RoutingManager::com_android_nfc_cardemulation_doGetDefaultOffHostRouteDestination},
41    {"doGetAidMatchingMode", "()I", (void*) RoutingManager::com_android_nfc_cardemulation_doGetAidMatchingMode}
42};
43
44static const int MAX_NUM_EE = 5;
45
46RoutingManager::RoutingManager ()
47{
48    static const char fn [] = "RoutingManager::RoutingManager()";
49    unsigned long num = 0;
50
51    // Get the active SE
52    if (GetNumValue("ACTIVE_SE", &num, sizeof(num)))
53        mActiveSe = num;
54    else
55        mActiveSe = 0x00;
56
57    // Get the "default" route
58    if (GetNumValue("DEFAULT_ISODEP_ROUTE", &num, sizeof(num)))
59        mDefaultEe = num;
60    else
61        mDefaultEe = 0x00;
62    ALOGD("%s: default route is 0x%02X", fn, mDefaultEe);
63
64    // Get the default "off-host" route.  This is hard-coded at the Java layer
65    // but we can override it here to avoid forcing Java changes.
66    if (GetNumValue("DEFAULT_OFFHOST_ROUTE", &num, sizeof(num)))
67        mOffHostEe = num;
68    else
69        mOffHostEe = 0xf4;
70
71    if (GetNumValue("AID_MATCHING_MODE", &num, sizeof(num)))
72        mAidMatchingMode = num;
73    else
74        mAidMatchingMode = AID_MATCHING_EXACT_ONLY;
75
76    ALOGD("%s: mOffHostEe=0x%02X", fn, mOffHostEe);
77
78    memset (&mEeInfo, 0, sizeof(mEeInfo));
79    mReceivedEeInfo = false;
80    mSeTechMask = 0x00;
81}
82
83RoutingManager::~RoutingManager ()
84{
85    NFA_EeDeregister (nfaEeCallback);
86}
87
88bool RoutingManager::initialize (nfc_jni_native_data* native)
89{
90    static const char fn [] = "RoutingManager::initialize()";
91    mNativeData = native;
92
93    tNFA_STATUS nfaStat;
94    {
95        SyncEventGuard guard (mEeRegisterEvent);
96        ALOGD ("%s: try ee register", fn);
97        nfaStat = NFA_EeRegister (nfaEeCallback);
98        if (nfaStat != NFA_STATUS_OK)
99        {
100            ALOGE ("%s: fail ee register; error=0x%X", fn, nfaStat);
101            return false;
102        }
103        mEeRegisterEvent.wait ();
104    }
105
106    mRxDataBuffer.clear ();
107
108    if (mActiveSe != 0) {
109        {
110            // Wait for EE info if needed
111            SyncEventGuard guard (mEeInfoEvent);
112            if (!mReceivedEeInfo)
113            {
114                ALOGE("Waiting for EE info");
115                mEeInfoEvent.wait();
116            }
117        }
118        for (UINT8 i = 0; i < mEeInfo.num_ee; i++)
119        {
120             ALOGD ("%s   EE[%u] Handle: 0x%04x  techA: 0x%02x  techB: 0x%02x  techF: 0x%02x  techBprime: 0x%02x",
121                fn, i, mEeInfo.ee_disc_info[i].ee_handle,
122                mEeInfo.ee_disc_info[i].la_protocol,
123                mEeInfo.ee_disc_info[i].lb_protocol,
124                mEeInfo.ee_disc_info[i].lf_protocol,
125                mEeInfo.ee_disc_info[i].lbp_protocol);
126             if (mEeInfo.ee_disc_info[i].ee_handle == (mActiveSe | NFA_HANDLE_GROUP_EE))
127             {
128                 if (mEeInfo.ee_disc_info[i].la_protocol != 0) mSeTechMask |= NFA_TECHNOLOGY_MASK_A;
129
130                 if (mSeTechMask != 0x00)
131                 {
132                     ALOGD("Configuring tech mask 0x%02x on EE 0x%04x", mSeTechMask, mEeInfo.ee_disc_info[i].ee_handle);
133                     nfaStat = NFA_CeConfigureUiccListenTech(mEeInfo.ee_disc_info[i].ee_handle, mSeTechMask);
134                     if (nfaStat != NFA_STATUS_OK)
135                         ALOGE ("Failed to configure UICC listen technologies.");
136                     // Set technology routes to UICC if it's there
137                     nfaStat = NFA_EeSetDefaultTechRouting(mEeInfo.ee_disc_info[i].ee_handle, mSeTechMask, mSeTechMask,
138                             mSeTechMask);
139                     if (nfaStat != NFA_STATUS_OK)
140                         ALOGE ("Failed to configure UICC technology routing.");
141                 }
142             }
143        }
144    }
145
146    // Tell the host-routing to only listen on Nfc-A
147    nfaStat = NFA_CeSetIsoDepListenTech(NFA_TECHNOLOGY_MASK_A);
148    if (nfaStat != NFA_STATUS_OK)
149        ALOGE ("Failed to configure CE IsoDep technologies");
150
151    // Register a wild-card for AIDs routed to the host
152    nfaStat = NFA_CeRegisterAidOnDH (NULL, 0, stackCallback);
153    if (nfaStat != NFA_STATUS_OK)
154        ALOGE("Failed to register wildcard AID for DH");
155
156    return true;
157}
158
159RoutingManager& RoutingManager::getInstance ()
160{
161    static RoutingManager manager;
162    return manager;
163}
164
165void RoutingManager::enableRoutingToHost()
166{
167    tNFA_STATUS nfaStat;
168
169    {
170        SyncEventGuard guard (mRoutingEvent);
171
172        // Route Nfc-A to host if we don't have a SE
173        if (mSeTechMask == 0)
174        {
175            nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEe, NFA_TECHNOLOGY_MASK_A, 0, 0);
176            if (nfaStat == NFA_STATUS_OK)
177                mRoutingEvent.wait ();
178            else
179                ALOGE ("Fail to set default tech routing");
180        }
181
182        // Default routing for IsoDep protocol
183        nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEe, NFA_PROTOCOL_MASK_ISO_DEP, 0, 0);
184        if (nfaStat == NFA_STATUS_OK)
185            mRoutingEvent.wait ();
186        else
187            ALOGE ("Fail to set default proto routing");
188    }
189}
190
191void RoutingManager::disableRoutingToHost()
192{
193    tNFA_STATUS nfaStat;
194
195    {
196        SyncEventGuard guard (mRoutingEvent);
197        // Default routing for NFC-A technology if we don't have a SE
198        if (mSeTechMask == 0)
199        {
200            nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEe, 0, 0, 0);
201            if (nfaStat == NFA_STATUS_OK)
202                mRoutingEvent.wait ();
203            else
204                ALOGE ("Fail to set default tech routing");
205        }
206
207        // Default routing for IsoDep protocol
208        nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEe, 0, 0, 0);
209        if (nfaStat == NFA_STATUS_OK)
210            mRoutingEvent.wait ();
211        else
212            ALOGE ("Fail to set default proto routing");
213    }
214}
215
216bool RoutingManager::addAidRouting(const UINT8* aid, UINT8 aidLen, int route)
217{
218    static const char fn [] = "RoutingManager::addAidRouting";
219    ALOGD ("%s: enter", fn);
220    tNFA_STATUS nfaStat = NFA_EeAddAidRouting(route, aidLen, (UINT8*) aid, 0x01);
221    if (nfaStat == NFA_STATUS_OK)
222    {
223        ALOGD ("%s: routed AID", fn);
224        return true;
225    } else
226    {
227        ALOGE ("%s: failed to route AID", fn);
228        return false;
229    }
230}
231
232bool RoutingManager::removeAidRouting(const UINT8* aid, UINT8 aidLen)
233{
234    static const char fn [] = "RoutingManager::removeAidRouting";
235    ALOGD ("%s: enter", fn);
236    tNFA_STATUS nfaStat = NFA_EeRemoveAidRouting(aidLen, (UINT8*) aid);
237    if (nfaStat == NFA_STATUS_OK)
238    {
239        ALOGD ("%s: removed AID", fn);
240        return true;
241    } else
242    {
243        ALOGE ("%s: failed to remove AID", fn);
244        return false;
245    }
246}
247
248bool RoutingManager::commitRouting()
249{
250    static const char fn [] = "RoutingManager::commitRouting";
251    tNFA_STATUS nfaStat = 0;
252    ALOGD ("%s", fn);
253    {
254        SyncEventGuard guard (mEeUpdateEvent);
255        nfaStat = NFA_EeUpdateNow();
256        if (nfaStat == NFA_STATUS_OK)
257        {
258            mEeUpdateEvent.wait (); //wait for NFA_EE_UPDATED_EVT
259        }
260    }
261    return (nfaStat == NFA_STATUS_OK);
262}
263
264void RoutingManager::onNfccShutdown ()
265{
266    static const char fn [] = "RoutingManager:onNfccShutdown";
267    if (mActiveSe == 0x00) return;
268
269    tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
270    UINT8 actualNumEe = MAX_NUM_EE;
271    tNFA_EE_INFO eeInfo[MAX_NUM_EE];
272
273    memset (&eeInfo, 0, sizeof(eeInfo));
274    if ((nfaStat = NFA_EeGetInfo (&actualNumEe, eeInfo)) != NFA_STATUS_OK)
275    {
276        ALOGE ("%s: fail get info; error=0x%X", fn, nfaStat);
277        return;
278    }
279    if (actualNumEe != 0)
280    {
281        for (UINT8 xx = 0; xx < actualNumEe; xx++)
282        {
283            if ((eeInfo[xx].num_interface != 0)
284                && (eeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS)
285                && (eeInfo[xx].ee_status == NFA_EE_STATUS_ACTIVE))
286            {
287                ALOGD ("%s: Handle: 0x%04x Change Status Active to Inactive", fn, eeInfo[xx].ee_handle);
288                SyncEventGuard guard (mEeSetModeEvent);
289                if ((nfaStat = NFA_EeModeSet (eeInfo[xx].ee_handle, NFA_EE_MD_DEACTIVATE)) == NFA_STATUS_OK)
290                {
291                    mEeSetModeEvent.wait (); //wait for NFA_EE_MODE_SET_EVT
292                }
293                else
294                {
295                    ALOGE ("Failed to set EE inactive");
296                }
297            }
298        }
299    }
300    else
301    {
302        ALOGD ("%s: No active EEs found", fn);
303    }
304}
305
306void RoutingManager::notifyActivated ()
307{
308    JNIEnv* e = NULL;
309    ScopedAttach attach(mNativeData->vm, &e);
310    if (e == NULL)
311    {
312        ALOGE ("jni env is null");
313        return;
314    }
315
316    e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuActivated);
317    if (e->ExceptionCheck())
318    {
319        e->ExceptionClear();
320        ALOGE ("fail notify");
321    }
322}
323
324void RoutingManager::notifyDeactivated ()
325{
326    mRxDataBuffer.clear();
327    JNIEnv* e = NULL;
328    ScopedAttach attach(mNativeData->vm, &e);
329    if (e == NULL)
330    {
331        ALOGE ("jni env is null");
332        return;
333    }
334
335    e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuDeactivated);
336    if (e->ExceptionCheck())
337    {
338        e->ExceptionClear();
339        ALOGE ("fail notify");
340    }
341}
342
343void RoutingManager::handleData (const UINT8* data, UINT32 dataLen, tNFA_STATUS status)
344{
345    if (dataLen <= 0)
346    {
347        ALOGE("no data");
348        goto TheEnd;
349    }
350
351    if (status == NFA_STATUS_CONTINUE)
352    {
353        mRxDataBuffer.insert (mRxDataBuffer.end(), &data[0], &data[dataLen]); //append data; more to come
354        return; //expect another NFA_CE_DATA_EVT to come
355    }
356    else if (status == NFA_STATUS_OK)
357    {
358        mRxDataBuffer.insert (mRxDataBuffer.end(), &data[0], &data[dataLen]); //append data
359        //entire data packet has been received; no more NFA_CE_DATA_EVT
360    }
361    else if (status == NFA_STATUS_FAILED)
362    {
363        ALOGE("RoutingManager::handleData: read data fail");
364        goto TheEnd;
365    }
366
367    {
368        JNIEnv* e = NULL;
369        ScopedAttach attach(mNativeData->vm, &e);
370        if (e == NULL)
371        {
372            ALOGE ("jni env is null");
373            goto TheEnd;
374        }
375
376        ScopedLocalRef<jobject> dataJavaArray(e, e->NewByteArray(mRxDataBuffer.size()));
377        if (dataJavaArray.get() == NULL)
378        {
379            ALOGE ("fail allocate array");
380            goto TheEnd;
381        }
382
383        e->SetByteArrayRegion ((jbyteArray)dataJavaArray.get(), 0, mRxDataBuffer.size(),
384                (jbyte *)(&mRxDataBuffer[0]));
385        if (e->ExceptionCheck())
386        {
387            e->ExceptionClear();
388            ALOGE ("fail fill array");
389            goto TheEnd;
390        }
391
392        e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuData, dataJavaArray.get());
393        if (e->ExceptionCheck())
394        {
395            e->ExceptionClear();
396            ALOGE ("fail notify");
397        }
398    }
399TheEnd:
400    mRxDataBuffer.clear();
401}
402
403void RoutingManager::stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventData)
404{
405    static const char fn [] = "RoutingManager::stackCallback";
406    ALOGD("%s: event=0x%X", fn, event);
407    RoutingManager& routingManager = RoutingManager::getInstance();
408
409    switch (event)
410    {
411    case NFA_CE_REGISTERED_EVT:
412        {
413            tNFA_CE_REGISTERED& ce_registered = eventData->ce_registered;
414            ALOGD("%s: NFA_CE_REGISTERED_EVT; status=0x%X; h=0x%X", fn, ce_registered.status, ce_registered.handle);
415        }
416        break;
417
418    case NFA_CE_DEREGISTERED_EVT:
419        {
420            tNFA_CE_DEREGISTERED& ce_deregistered = eventData->ce_deregistered;
421            ALOGD("%s: NFA_CE_DEREGISTERED_EVT; h=0x%X", fn, ce_deregistered.handle);
422        }
423        break;
424
425    case NFA_CE_ACTIVATED_EVT:
426        {
427            routingManager.notifyActivated();
428        }
429        break;
430
431    case NFA_DEACTIVATED_EVT:
432    case NFA_CE_DEACTIVATED_EVT:
433        {
434            ALOGD("%s: NFA_DEACTIVATED_EVT, NFA_CE_DEACTIVATED_EVT", fn);
435            routingManager.notifyDeactivated();
436            SyncEventGuard g (gDeactivatedEvent);
437            gActivated = false; //guard this variable from multi-threaded access
438            gDeactivatedEvent.notifyOne ();
439        }
440        break;
441
442    case NFA_CE_DATA_EVT:
443        {
444            tNFA_CE_DATA& ce_data = eventData->ce_data;
445            ALOGD("%s: NFA_CE_DATA_EVT; stat=0x%X; h=0x%X; data len=%u", fn, ce_data.status, ce_data.handle, ce_data.len);
446            getInstance().handleData(ce_data.p_data, ce_data.len, ce_data.status);
447        }
448        break;
449    }
450}
451/*******************************************************************************
452**
453** Function:        nfaEeCallback
454**
455** Description:     Receive execution environment-related events from stack.
456**                  event: Event code.
457**                  eventData: Event data.
458**
459** Returns:         None
460**
461*******************************************************************************/
462void RoutingManager::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData)
463{
464    static const char fn [] = "RoutingManager::nfaEeCallback";
465
466    RoutingManager& routingManager = RoutingManager::getInstance();
467
468    switch (event)
469    {
470    case NFA_EE_REGISTER_EVT:
471        {
472            SyncEventGuard guard (routingManager.mEeRegisterEvent);
473            ALOGD ("%s: NFA_EE_REGISTER_EVT; status=%u", fn, eventData->ee_register);
474            routingManager.mEeRegisterEvent.notifyOne();
475        }
476        break;
477
478    case NFA_EE_MODE_SET_EVT:
479        {
480            SyncEventGuard guard (routingManager.mEeSetModeEvent);
481            ALOGD ("%s: NFA_EE_MODE_SET_EVT; status: 0x%04X  handle: 0x%04X  ", fn,
482                    eventData->mode_set.status, eventData->mode_set.ee_handle);
483            routingManager.mEeSetModeEvent.notifyOne();
484        }
485        break;
486
487    case NFA_EE_SET_TECH_CFG_EVT:
488        {
489            ALOGD ("%s: NFA_EE_SET_TECH_CFG_EVT; status=0x%X", fn, eventData->status);
490            SyncEventGuard guard(routingManager.mRoutingEvent);
491            routingManager.mRoutingEvent.notifyOne();
492        }
493        break;
494
495    case NFA_EE_SET_PROTO_CFG_EVT:
496        {
497            ALOGD ("%s: NFA_EE_SET_PROTO_CFG_EVT; status=0x%X", fn, eventData->status);
498            SyncEventGuard guard(routingManager.mRoutingEvent);
499            routingManager.mRoutingEvent.notifyOne();
500        }
501        break;
502
503    case NFA_EE_ACTION_EVT:
504        {
505            tNFA_EE_ACTION& action = eventData->action;
506            if (action.trigger == NFC_EE_TRIG_SELECT)
507                ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=select (0x%X)", fn, action.ee_handle, action.trigger);
508            else if (action.trigger == NFC_EE_TRIG_APP_INIT)
509            {
510                tNFC_APP_INIT& app_init = action.param.app_init;
511                ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=app-init (0x%X); aid len=%u; data len=%u", fn,
512                        action.ee_handle, action.trigger, app_init.len_aid, app_init.len_data);
513            }
514            else if (action.trigger == NFC_EE_TRIG_RF_PROTOCOL)
515                ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf protocol (0x%X)", fn, action.ee_handle, action.trigger);
516            else if (action.trigger == NFC_EE_TRIG_RF_TECHNOLOGY)
517                ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf tech (0x%X)", fn, action.ee_handle, action.trigger);
518            else
519                ALOGE ("%s: NFA_EE_ACTION_EVT; h=0x%X; unknown trigger (0x%X)", fn, action.ee_handle, action.trigger);
520        }
521        break;
522
523    case NFA_EE_DISCOVER_REQ_EVT:
524        {
525            ALOGD ("%s: NFA_EE_DISCOVER_REQ_EVT; status=0x%X; num ee=%u", __FUNCTION__,
526                    eventData->discover_req.status, eventData->discover_req.num_ee);
527            SyncEventGuard guard (routingManager.mEeInfoEvent);
528            memcpy (&routingManager.mEeInfo, &eventData->discover_req, sizeof(routingManager.mEeInfo));
529            routingManager.mReceivedEeInfo = true;
530            routingManager.mEeInfoEvent.notifyOne();
531        }
532        break;
533
534    case NFA_EE_NO_CB_ERR_EVT:
535        ALOGD ("%s: NFA_EE_NO_CB_ERR_EVT  status=%u", fn, eventData->status);
536        break;
537
538    case NFA_EE_ADD_AID_EVT:
539        {
540            ALOGD ("%s: NFA_EE_ADD_AID_EVT  status=%u", fn, eventData->status);
541        }
542        break;
543
544    case NFA_EE_REMOVE_AID_EVT:
545        {
546            ALOGD ("%s: NFA_EE_REMOVE_AID_EVT  status=%u", fn, eventData->status);
547        }
548        break;
549
550    case NFA_EE_NEW_EE_EVT:
551        {
552            ALOGD ("%s: NFA_EE_NEW_EE_EVT  h=0x%X; status=%u", fn,
553                eventData->new_ee.ee_handle, eventData->new_ee.ee_status);
554        }
555        break;
556
557    case NFA_EE_UPDATED_EVT:
558        {
559            ALOGD("%s: NFA_EE_UPDATED_EVT", fn);
560            SyncEventGuard guard(routingManager.mEeUpdateEvent);
561            routingManager.mEeUpdateEvent.notifyOne();
562        }
563        break;
564
565    default:
566        ALOGE ("%s: unknown event=%u ????", fn, event);
567        break;
568    }
569}
570
571int RoutingManager::registerJniFunctions (JNIEnv* e)
572{
573    static const char fn [] = "RoutingManager::registerJniFunctions";
574    ALOGD ("%s", fn);
575    return jniRegisterNativeMethods (e, "com/android/nfc/cardemulation/AidRoutingManager", sMethods, NELEM(sMethods));
576}
577
578int RoutingManager::com_android_nfc_cardemulation_doGetDefaultRouteDestination (JNIEnv*)
579{
580    return getInstance().mDefaultEe;
581}
582
583int RoutingManager::com_android_nfc_cardemulation_doGetDefaultOffHostRouteDestination (JNIEnv*)
584{
585    return getInstance().mOffHostEe;
586}
587
588int RoutingManager::com_android_nfc_cardemulation_doGetAidMatchingMode (JNIEnv*)
589{
590    return getInstance().mAidMatchingMode;
591}
592