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