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