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/*
18 *  Import and export general routing data using a XML file.
19 */
20#include "_OverrideLog.h"
21#include "RouteDataSet.h"
22#include "libxml/xmlmemory.h"
23#include <errno.h>
24#include <sys/stat.h>
25
26extern char bcm_nfc_location[];
27
28
29/*******************************************************************************
30**
31** Function:        AidBuffer
32**
33** Description:     Parse a string of hex numbers.  Store result in an array of
34**                  bytes.
35**                  aid: string of hex numbers.
36**
37** Returns:         None.
38**
39*******************************************************************************/
40AidBuffer::AidBuffer (std::string& aid)
41:   mBuffer (NULL),
42    mBufferLen (0)
43{
44    unsigned int num = 0;
45    const char delimiter = ':';
46    std::string::size_type pos1 = 0;
47    std::string::size_type pos2 = aid.find_first_of (delimiter);
48
49    //parse the AID string; each hex number is separated by a colon;
50    mBuffer = new uint8_t [aid.length()];
51    while (true)
52    {
53        num = 0;
54        if (pos2 == std::string::npos)
55        {
56            sscanf (aid.substr(pos1).c_str(), "%x", &num);
57            mBuffer [mBufferLen] = (uint8_t) num;
58            mBufferLen++;
59            break;
60        }
61        else
62        {
63            sscanf (aid.substr(pos1, pos2-pos1+1).c_str(), "%x", &num);
64            mBuffer [mBufferLen] = (uint8_t) num;
65            mBufferLen++;
66            pos1 = pos2 + 1;
67            pos2 = aid.find_first_of (delimiter, pos1);
68        }
69    }
70}
71
72
73/*******************************************************************************
74**
75** Function:        ~AidBuffer
76**
77** Description:     Release all resources.
78**
79** Returns:         None.
80**
81*******************************************************************************/
82AidBuffer::~AidBuffer ()
83{
84    delete [] mBuffer;
85}
86
87
88/*******************************************************************************/
89/*******************************************************************************/
90
91
92const char* RouteDataSet::sConfigFile = "/param/route.xml";
93
94
95/*******************************************************************************
96**
97** Function:        ~RouteDataSet
98**
99** Description:     Release all resources.
100**
101** Returns:         None.
102**
103*******************************************************************************/
104RouteDataSet::~RouteDataSet ()
105{
106    deleteDatabase ();
107}
108
109
110/*******************************************************************************
111**
112** Function:        initialize
113**
114** Description:     Initialize resources.
115**
116** Returns:         True if ok.
117**
118*******************************************************************************/
119bool RouteDataSet::initialize()
120{
121    ALOGV("%s: enter", "RouteDataSet::initialize");
122    //check that the libxml2 version in use is compatible
123    //with the version the software has been compiled with
124    LIBXML_TEST_VERSION
125    ALOGV("%s: exit; return=true", "RouteDataSet::initialize");
126    return true;
127}
128
129
130/*******************************************************************************
131**
132** Function:        deleteDatabase
133**
134** Description:     Delete all routes stored in all databases.
135**
136** Returns:         None.
137**
138*******************************************************************************/
139void RouteDataSet::deleteDatabase()
140{
141    ALOGV("%s: default db size=%zu; sec elem db size=%zu", "RouteDataSet::deleteDatabase",
142            mDefaultRouteDatabase.size(), mSecElemRouteDatabase.size());
143    Database::iterator it;
144
145    for (it = mDefaultRouteDatabase.begin(); it != mDefaultRouteDatabase.end(); it++)
146        delete (*it);
147    mDefaultRouteDatabase.clear ();
148
149    for (it = mSecElemRouteDatabase.begin(); it != mSecElemRouteDatabase.end(); it++)
150        delete (*it);
151    mSecElemRouteDatabase.clear ();
152}
153
154
155/*******************************************************************************
156**
157** Function:        import
158**
159** Description:     Import data from an XML file.  Fill the databases.
160**
161** Returns:         True if ok.
162**
163*******************************************************************************/
164bool RouteDataSet::import ()
165{
166    static const char fn [] = "RouteDataSet::import";
167    ALOGV("%s: enter", fn);
168    bool retval = false;
169    xmlDocPtr doc;
170    xmlNodePtr node1;
171    std::string strFilename(bcm_nfc_location);
172    strFilename += sConfigFile;
173
174    deleteDatabase ();
175
176    doc = xmlParseFile (strFilename.c_str());
177    if (doc == NULL)
178    {
179        ALOGV("%s: fail parse", fn);
180        goto TheEnd;
181    }
182
183    node1 = xmlDocGetRootElement (doc);
184    if (node1 == NULL)
185    {
186        ALOGE("%s: fail root element", fn);
187        goto TheEnd;
188    }
189    ALOGV("%s: root=%s", fn, node1->name);
190
191    node1 = node1->xmlChildrenNode;
192    while (node1) //loop through all elements in <Routes ...
193    {
194        if (xmlStrcmp(node1->name, (const xmlChar*) "Route")==0)
195        {
196            xmlChar* value = xmlGetProp (node1, (const xmlChar*) "Type");
197            if (value && (xmlStrcmp (value, (const xmlChar*) "SecElemSelectedRoutes") == 0))
198            {
199                ALOGV("%s: found SecElemSelectedRoutes", fn);
200                xmlNodePtr node2 = node1->xmlChildrenNode;
201                while (node2) //loop all elements in <Route Type="SecElemSelectedRoutes" ...
202                {
203                    if (xmlStrcmp(node2->name, (const xmlChar*) "Proto")==0)
204                        importProtocolRoute (node2, mSecElemRouteDatabase);
205                    else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0)
206                        importTechnologyRoute (node2, mSecElemRouteDatabase);
207                    node2 = node2->next;
208                } //loop all elements in <Route Type="SecElemSelectedRoutes" ...
209            }
210            else if (value && (xmlStrcmp (value, (const xmlChar*) "DefaultRoutes") == 0))
211            {
212                ALOGV("%s: found DefaultRoutes", fn);
213                xmlNodePtr node2 = node1->xmlChildrenNode;
214                while (node2) //loop all elements in <Route Type="DefaultRoutes" ...
215                {
216                    if (xmlStrcmp(node2->name, (const xmlChar*) "Proto")==0)
217                        importProtocolRoute (node2, mDefaultRouteDatabase);
218                    else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0)
219                        importTechnologyRoute (node2, mDefaultRouteDatabase);
220                    node2 = node2->next;
221                } //loop all elements in <Route Type="DefaultRoutes" ...
222            }
223            if (value)
224                xmlFree (value);
225        } //check <Route ...
226        node1 = node1->next;
227    } //loop through all elements in <Routes ...
228    retval = true;
229
230TheEnd:
231    xmlFreeDoc (doc);
232    xmlCleanupParser ();
233    ALOGV("%s: exit; return=%u", fn, retval);
234    return retval;
235}
236
237
238/*******************************************************************************
239**
240** Function:        saveToFile
241**
242** Description:     Save XML data from a string into a file.
243**                  routesXml: XML that represents routes.
244**
245** Returns:         True if ok.
246**
247*******************************************************************************/
248bool RouteDataSet::saveToFile (const char* routesXml)
249{
250    static const char fn [] = "RouteDataSet::saveToFile";
251    FILE* fh = NULL;
252    size_t actualWritten = 0;
253    bool retval = false;
254    std::string filename (bcm_nfc_location);
255    int stat = 0;
256
257    filename.append (sConfigFile);
258    fh = fopen (filename.c_str (), "w");
259    if (fh == NULL)
260    {
261        ALOGE("%s: fail to open file", fn);
262        return false;
263    }
264
265    actualWritten = fwrite (routesXml, sizeof(char), strlen(routesXml), fh);
266    retval = actualWritten == strlen(routesXml);
267    fclose (fh);
268    ALOGV("%s: wrote %zu bytes", fn, actualWritten);
269    if (retval == false)
270        ALOGE("%s: error during write", fn);
271
272    //set file permission to
273    //owner read, write; group read; other read
274    stat = chmod (filename.c_str (), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
275    if (stat == -1)
276        ALOGE("%s: error during chmod", fn);
277    return retval;
278}
279
280
281/*******************************************************************************
282**
283** Function:        loadFromFile
284**
285** Description:     Load XML data from file into a string.
286**                  routesXml: string to receive XML data.
287**
288** Returns:         True if ok.
289**
290*******************************************************************************/
291bool RouteDataSet::loadFromFile (std::string& routesXml)
292{
293    FILE* fh = NULL;
294    size_t actual = 0;
295    char buffer [1024];
296    std::string filename (bcm_nfc_location);
297
298    filename.append (sConfigFile);
299    fh = fopen (filename.c_str (), "r");
300    if (fh == NULL)
301    {
302        ALOGV("%s: fail to open file", "RouteDataSet::loadFromFile");
303        return false;
304    }
305
306    while (true)
307    {
308        actual = fread (buffer, sizeof(char), sizeof(buffer), fh);
309        if (actual == 0)
310            break;
311        routesXml.append (buffer, actual);
312    }
313    fclose (fh);
314    ALOGV("%s: read %zu bytes", "RouteDataSet::loadFromFile", routesXml.length());
315    return true;
316}
317
318
319
320
321/*******************************************************************************
322**
323** Function:        importProtocolRoute
324**
325** Description:     Parse data for protocol routes.
326**                  element: XML node for one protocol route.
327**                  database: store data in this database.
328**
329** Returns:         None.
330**
331*******************************************************************************/
332void RouteDataSet::importProtocolRoute (xmlNodePtr& element, Database& database)
333{
334    const xmlChar* id = (const xmlChar*) "Id";
335    const xmlChar* secElem = (const xmlChar*) "SecElem";
336    const xmlChar* trueString = (const xmlChar*) "true";
337    const xmlChar* switchOn = (const xmlChar*) "SwitchOn";
338    const xmlChar* switchOff = (const xmlChar*) "SwitchOff";
339    const xmlChar* batteryOff = (const xmlChar*) "BatteryOff";
340    RouteDataForProtocol* data = new RouteDataForProtocol;
341    xmlChar* value = NULL;
342
343    ALOGV_IF(sDebug, "%s: element=%s", "RouteDataSet::importProtocolRoute", element->name);
344    value = xmlGetProp (element, id);
345    if (value)
346    {
347        if (xmlStrcmp (value, (const xmlChar*) "T1T") == 0)
348            data->mProtocol = NFA_PROTOCOL_MASK_T1T;
349        else if (xmlStrcmp (value, (const xmlChar*) "T2T") == 0)
350            data->mProtocol = NFA_PROTOCOL_MASK_T2T;
351        else if (xmlStrcmp (value, (const xmlChar*) "T3T") == 0)
352            data->mProtocol = NFA_PROTOCOL_MASK_T3T;
353        else if (xmlStrcmp (value, (const xmlChar*) "IsoDep") == 0)
354            data->mProtocol = NFA_PROTOCOL_MASK_ISO_DEP;
355        xmlFree (value);
356        ALOGV_IF(sDebug, "%s: %s=0x%X", "RouteDataSet::importProtocolRoute", id, data->mProtocol);
357    }
358
359    value = xmlGetProp (element, secElem);
360    if (value)
361    {
362        data->mNfaEeHandle = strtol ((char*) value, NULL, 16);
363        xmlFree (value);
364        data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
365        ALOGV_IF(sDebug, "%s: %s=0x%X", "RouteDataSet::importProtocolRoute", secElem, data->mNfaEeHandle);
366    }
367
368    value = xmlGetProp (element, switchOn);
369    if (value)
370    {
371        data->mSwitchOn = (xmlStrcmp (value, trueString) == 0);
372        xmlFree (value);
373    }
374
375    value = xmlGetProp (element, switchOff);
376    if (value)
377    {
378        data->mSwitchOff = (xmlStrcmp (value, trueString) == 0);
379        xmlFree (value);
380    }
381
382    value = xmlGetProp (element, batteryOff);
383    if (value)
384    {
385        data->mBatteryOff = (xmlStrcmp (value, trueString) == 0);
386        xmlFree (value);
387    }
388    database.push_back (data);
389}
390
391
392/*******************************************************************************
393**
394** Function:        importTechnologyRoute
395**
396** Description:     Parse data for technology routes.
397**                  element: XML node for one technology route.
398**                  database: store data in this database.
399**
400** Returns:         None.
401**
402*******************************************************************************/
403void RouteDataSet::importTechnologyRoute (xmlNodePtr& element, Database& database)
404{
405    const xmlChar* id = (const xmlChar*) "Id";
406    const xmlChar* secElem = (const xmlChar*) "SecElem";
407    const xmlChar* trueString = (const xmlChar*) "true";
408    const xmlChar* switchOn = (const xmlChar*) "SwitchOn";
409    const xmlChar* switchOff = (const xmlChar*) "SwitchOff";
410    const xmlChar* batteryOff = (const xmlChar*) "BatteryOff";
411    RouteDataForTechnology* data = new RouteDataForTechnology;
412    xmlChar* value = NULL;
413
414    ALOGV_IF(sDebug, "%s: element=%s", "RouteDataSet::importTechnologyRoute", element->name);
415    value = xmlGetProp (element, id);
416    if (value)
417    {
418        if (xmlStrcmp (value, (const xmlChar*) "NfcA") == 0)
419            data->mTechnology = NFA_TECHNOLOGY_MASK_A;
420        else if (xmlStrcmp (value, (const xmlChar*) "NfcB") == 0)
421            data->mTechnology = NFA_TECHNOLOGY_MASK_B;
422        else if (xmlStrcmp (value, (const xmlChar*) "NfcF") == 0)
423            data->mTechnology = NFA_TECHNOLOGY_MASK_F;
424        xmlFree (value);
425        ALOGV_IF(sDebug, "%s: %s=0x%X", "RouteDataSet::importTechnologyRoute", id,
426                data->mTechnology);
427    }
428
429    value = xmlGetProp (element, secElem);
430    if (value)
431    {
432        data->mNfaEeHandle = strtol ((char*) value, NULL, 16);
433        xmlFree (value);
434        data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
435        ALOGV_IF(sDebug, "%s: %s=0x%X", "RouteDataSet::importTechnologyRoute", secElem, data->mNfaEeHandle);
436    }
437
438    value = xmlGetProp (element, switchOn);
439    if (value)
440    {
441        data->mSwitchOn = (xmlStrcmp (value, trueString) == 0);
442        xmlFree (value);
443    }
444
445    value = xmlGetProp (element, switchOff);
446    if (value)
447    {
448        data->mSwitchOff = (xmlStrcmp (value, trueString) == 0);
449        xmlFree (value);
450    }
451
452    value = xmlGetProp (element, batteryOff);
453    if (value)
454    {
455        data->mBatteryOff = (xmlStrcmp (value, trueString) == 0);
456        xmlFree (value);
457    }
458    database.push_back (data);
459}
460
461
462/*******************************************************************************
463**
464** Function:        deleteFile
465**
466** Description:     Delete route data XML file.
467**
468** Returns:         True if ok.
469**
470*******************************************************************************/
471bool RouteDataSet::deleteFile ()
472{
473    static const char fn [] = "RouteDataSet::deleteFile";
474    std::string filename (bcm_nfc_location);
475    filename.append (sConfigFile);
476    int stat = remove (filename.c_str());
477    ALOGV("%s: exit %u", fn, stat==0);
478    return stat == 0;
479}
480
481
482/*******************************************************************************
483**
484** Function:        getDatabase
485**
486** Description:     Obtain a database of routing data.
487**                  selection: which database.
488**
489** Returns:         Pointer to database.
490**
491*******************************************************************************/
492RouteDataSet::Database* RouteDataSet::getDatabase (DatabaseSelection selection)
493{
494    switch (selection)
495    {
496    case DefaultRouteDatabase:
497        return &mDefaultRouteDatabase;
498    case SecElemRouteDatabase:
499        return &mSecElemRouteDatabase;
500    }
501    return NULL;
502}
503
504
505/*******************************************************************************
506**
507** Function:        printDiagnostic
508**
509** Description:     Print some diagnostic output.
510**
511** Returns:         None.
512**
513*******************************************************************************/
514void RouteDataSet::printDiagnostic ()
515{
516    static const char fn [] = "RouteDataSet::printDiagnostic";
517    Database* db = getDatabase (DefaultRouteDatabase);
518
519    ALOGV("%s: default route database", fn);
520    for (Database::iterator iter = db->begin(); iter != db->end(); iter++)
521    {
522        RouteData* routeData = *iter;
523        switch (routeData->mRouteType)
524        {
525        case RouteData::ProtocolRoute:
526            {
527                RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData;
528                ALOGV("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol);
529            }
530            break;
531        case RouteData::TechnologyRoute:
532            {
533                RouteDataForTechnology* tech = (RouteDataForTechnology*) routeData;
534                ALOGV("%s: ee h=0x%X; technology=0x%X", fn, tech->mNfaEeHandle, tech->mTechnology);
535            }
536            break;
537        }
538    }
539
540    ALOGV("%s: sec elem route database", fn);
541    db = getDatabase (SecElemRouteDatabase);
542    for (Database::iterator iter2 = db->begin(); iter2 != db->end(); iter2++)
543    {
544        RouteData* routeData = *iter2;
545        switch (routeData->mRouteType)
546        {
547        case RouteData::ProtocolRoute:
548            {
549                RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData;
550                ALOGV("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol);
551            }
552            break;
553        case RouteData::TechnologyRoute:
554            {
555                RouteDataForTechnology* tech = (RouteDataForTechnology*) routeData;
556                ALOGV("%s: ee h=0x%X; technology=0x%X", fn, tech->mNfaEeHandle, tech->mTechnology);
557            }
558            break;
559        }
560    }
561}
562