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