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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 101 RouteDataSet::~RouteDataSet() { deleteDatabase(); } 102 103 /******************************************************************************* 104 ** 105 ** Function: initialize 106 ** 107 ** Description: Initialize resources. 108 ** 109 ** Returns: True if ok. 110 ** 111 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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