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 
26 extern 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 *******************************************************************************/
AidBuffer(std::string & aid)40 AidBuffer::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 *******************************************************************************/
~AidBuffer()82 AidBuffer::~AidBuffer ()
83 {
84     delete [] mBuffer;
85 }
86 
87 
88 /*******************************************************************************/
89 /*******************************************************************************/
90 
91 
92 const 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 *******************************************************************************/
~RouteDataSet()104 RouteDataSet::~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 *******************************************************************************/
initialize()119 bool 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 *******************************************************************************/
deleteDatabase()140 void 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 *******************************************************************************/
import()165 bool 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 
231 TheEnd:
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 *******************************************************************************/
saveToFile(const char * routesXml)249 bool 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 *******************************************************************************/
loadFromFile(std::string & routesXml)292 bool 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 *******************************************************************************/
importProtocolRoute(xmlNodePtr & element,Database & database)334 void 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 *******************************************************************************/
importTechnologyRoute(xmlNodePtr & element,Database & database)406 void 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 *******************************************************************************/
deleteFile()474 bool 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 *******************************************************************************/
getDatabase(DatabaseSelection selection)495 RouteDataSet::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 *******************************************************************************/
printDiagnostic()517 void 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