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