1 /** @addtogroup MCD_IMPL_LIB 2 * @{ 3 * @file 4 * 5 * MobiCore Driver API. 6 * 7 * Functions for accessing MobiCore functionality from the normal world. 8 * Handles sessions and notifications via MCI buffer. 9 * 10 * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. The name of the author may not be used to endorse or promote 21 * products derived from this software without specific prior 22 * written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 25 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 28 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 30 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 #include <stdint.h> 37 #include <stdbool.h> 38 #include <list> 39 #include "assert.h" 40 41 #include "public/MobiCoreDriverApi.h" 42 43 #include "mc_linux.h" 44 #include "Connection.h" 45 #include "CMutex.h" 46 #include "Device.h" 47 #include "mcVersionHelper.h" 48 49 #include "Daemon/public/MobiCoreDriverCmd.h" 50 #include "Daemon/public/mcVersion.h" 51 52 #include "log.h" 53 54 #include "Mci/mcimcp.h" 55 56 MC_CHECK_VERSION(DAEMON, 0, 2); 57 58 /** Notification data structure. */ 59 typedef struct { 60 uint32_t sessionId; /**< Session ID. */ 61 int32_t payload; /**< Additional notification information. */ 62 } notification_t; 63 64 using namespace std; 65 66 list<Device *> devices; 67 68 // Forward declarations. 69 uint32_t getDaemonVersion(Connection *devCon, uint32_t *version); 70 71 CMutex devMutex; 72 //------------------------------------------------------------------------------ 73 Device *resolveDeviceId(uint32_t deviceId) 74 { 75 for (list<Device *>::iterator iterator = devices.begin(); 76 iterator != devices.end(); ++iterator) { 77 Device *device = (*iterator); 78 79 if (device->deviceId == deviceId) { 80 return device; 81 } 82 } 83 return NULL; 84 } 85 86 87 //------------------------------------------------------------------------------ 88 void addDevice(Device *device) 89 { 90 devices.push_back(device); 91 } 92 93 94 //------------------------------------------------------------------------------ 95 bool removeDevice(uint32_t deviceId) 96 { 97 for (list<Device *>::iterator iterator = devices.begin(); 98 iterator != devices.end(); 99 ++iterator) { 100 Device *device = (*iterator); 101 102 if (device->deviceId == deviceId) { 103 devices.erase(iterator); 104 delete device; 105 return true; 106 } 107 } 108 return false; 109 } 110 111 //------------------------------------------------------------------------------ 112 // Parameter checking functions 113 // Note that android-ndk renames __func__ to __PRETTY_FUNCTION__ 114 // see also /prebuilt/ndk/android-ndk-r4/platforms/android-8/arch-arm/usr/include/sys/cdefs.h 115 116 #define CHECK_DEVICE(device) \ 117 if (NULL == device) \ 118 { \ 119 LOG_E("Device not found"); \ 120 mcResult = MC_DRV_ERR_UNKNOWN_DEVICE; \ 121 break; \ 122 } 123 124 #define CHECK_NOT_NULL(X) \ 125 if (NULL == X) \ 126 { \ 127 LOG_E("Parameter \""#X "\" is NULL"); \ 128 mcResult = MC_DRV_ERR_NULL_POINTER; \ 129 break; \ 130 } 131 132 #define CHECK_SESSION(S,SID) \ 133 if (NULL == S) \ 134 { \ 135 LOG_E("Session %i not found", SID); \ 136 mcResult = MC_DRV_ERR_UNKNOWN_SESSION; \ 137 break; \ 138 } 139 140 //------------------------------------------------------------------------------ 141 // Socket marshaling and checking functions 142 #define SEND_TO_DAEMON(CONNECTION, COMMAND, ...) \ 143 { \ 144 COMMAND ##_struct x = { \ 145 COMMAND, \ 146 __VA_ARGS__ \ 147 }; \ 148 int ret = CONNECTION->writeData(&x, sizeof x); \ 149 if(ret < 0) { \ 150 LOG_E("sending to Daemon failed."); \ 151 mcResult = MC_DRV_ERR_SOCKET_WRITE; \ 152 break; \ 153 } \ 154 } 155 156 #define RECV_FROM_DAEMON(CONNECTION, RSP_STRUCT) \ 157 { \ 158 int rlen = CONNECTION->readData( \ 159 RSP_STRUCT, \ 160 sizeof(*RSP_STRUCT)); \ 161 if (rlen <= 0) { \ 162 LOG_E("reading from Daemon failed"); \ 163 mcResult = MC_DRV_ERR_SOCKET_READ; \ 164 break; \ 165 } \ 166 if (rlen != sizeof(*RSP_STRUCT) && rlen != sizeof(mcDrvResponseHeader_t)) {\ 167 LOG_E("wrong buffer length %i received from Daemon", rlen); \ 168 mcResult = MC_DRV_ERR_SOCKET_LENGTH; \ 169 break; \ 170 } \ 171 } 172 173 //------------------------------------------------------------------------------ 174 __MC_CLIENT_LIB_API mcResult_t mcOpenDevice(uint32_t deviceId) 175 { 176 mcResult_t mcResult = MC_DRV_OK; 177 178 Connection *devCon = NULL; 179 180 devMutex.lock(); 181 LOG_I("===%s(%i)===", __FUNCTION__, deviceId); 182 183 do { 184 Device *device = resolveDeviceId(deviceId); 185 if (device != NULL) { 186 LOG_E("Device %d already opened", deviceId); 187 mcResult = MC_DRV_ERR_DEVICE_ALREADY_OPEN; 188 break; 189 } 190 191 // Handle SIGPIPE inside write() 192 // If Daemon crashes and ClientLib writes to named socket, 193 // a sigpipe is send to ClientLib/TLC and kills it. 194 signal(SIGPIPE, SIG_IGN); 195 196 // Open new connection to device 197 devCon = new Connection(); 198 if (!devCon->connect(SOCK_PATH)) { 199 LOG_W(" Could not connect to %s socket", SOCK_PATH); 200 mcResult = MC_DRV_ERR_SOCKET_CONNECT; 201 break; 202 } 203 204 // Runtime check of Daemon version. 205 char *errmsg; 206 uint32_t version = 0; 207 mcResult = getDaemonVersion(devCon, &version); 208 if(mcResult != MC_DRV_OK) { 209 break; 210 } 211 if (!checkVersionOkDAEMON(version, &errmsg)) { 212 LOG_E("%s", errmsg); 213 mcResult = MC_DRV_ERR_DAEMON_VERSION; 214 break; 215 } 216 LOG_I(" %s", errmsg); 217 218 // Forward device open to the daemon and read result 219 SEND_TO_DAEMON(devCon, MC_DRV_CMD_OPEN_DEVICE, deviceId); 220 221 RECV_FROM_DAEMON(devCon, &mcResult); 222 223 if (mcResult != MC_DRV_OK) { 224 LOG_W(" %s(): Request at Daemon failed, respId=%x ", __FUNCTION__, mcResult); 225 break; 226 } 227 228 // there is no payload to read 229 230 device = new Device(deviceId, devCon); 231 mcResult = device->open("/dev/" MC_USER_DEVNODE); 232 if (mcResult != MC_DRV_OK) { 233 delete device; 234 // devCon is freed in the Device destructor 235 devCon = NULL; 236 LOG_E("Could not open device file: /dev/%s", MC_USER_DEVNODE); 237 break; 238 } 239 240 addDevice(device); 241 242 } while (false); 243 244 devMutex.unlock(); 245 if (mcResult != MC_DRV_OK) { 246 if (devCon != NULL) 247 delete devCon; 248 LOG_I(" Device not opened."); 249 } else { 250 LOG_I(" Successfully opened the device."); 251 } 252 253 return mcResult; 254 } 255 256 257 //------------------------------------------------------------------------------ 258 __MC_CLIENT_LIB_API mcResult_t mcCloseDevice( 259 uint32_t deviceId 260 ) 261 { 262 mcResult_t mcResult = MC_DRV_OK; 263 devMutex.lock(); 264 LOG_I("===%s(%i)===", __FUNCTION__, deviceId); 265 do { 266 Device *device = resolveDeviceId(deviceId); 267 CHECK_DEVICE(device); 268 269 Connection *devCon = device->connection; 270 271 // Return if not all sessions have been closed 272 // TODO-2012-08-31-haenellu: improve check, if device connection is dead, this makes no more sense. 273 if (device->hasSessions()) { 274 LOG_E("Trying to close device while sessions are still pending."); 275 mcResult = MC_DRV_ERR_SESSION_PENDING; 276 break; 277 } 278 279 SEND_TO_DAEMON(devCon, MC_DRV_CMD_CLOSE_DEVICE); 280 281 RECV_FROM_DAEMON(devCon, &mcResult); 282 283 if (mcResult != MC_DRV_OK) { 284 LOG_W(" %s(): Request at Daemon failed, respId=%d ", __FUNCTION__, mcResult); 285 break; 286 } 287 288 removeDevice(deviceId); 289 290 } while (false); 291 292 devMutex.unlock(); 293 return mcResult; 294 } 295 296 297 //------------------------------------------------------------------------------ 298 __MC_CLIENT_LIB_API mcResult_t mcOpenSession( 299 mcSessionHandle_t *session, 300 const mcUuid_t *uuid, 301 uint8_t *tci, 302 uint32_t len 303 ) 304 { 305 mcResult_t mcResult = MC_DRV_OK; 306 307 devMutex.lock(); 308 LOG_I("===%s()===", __FUNCTION__); 309 310 do { 311 CHECK_NOT_NULL(session); 312 CHECK_NOT_NULL(uuid); 313 CHECK_NOT_NULL(tci); 314 315 if (len > MC_MAX_TCI_LEN) { 316 LOG_E("TCI length is longer than %d", MC_MAX_TCI_LEN); 317 mcResult = MC_DRV_ERR_TCI_TOO_BIG; 318 break; 319 } 320 321 // Get the device associated with the given session 322 Device *device = resolveDeviceId(session->deviceId); 323 CHECK_DEVICE(device); 324 325 Connection *devCon = device->connection; 326 327 // Get the physical address of the given TCI 328 CWsm_ptr pWsm = device->findContiguousWsm(tci); 329 if (pWsm == NULL) { 330 LOG_E("Could not resolve physical address of TCI"); 331 mcResult = MC_DRV_ERR_WSM_NOT_FOUND; 332 break; 333 } 334 335 if (pWsm->len < len) { 336 LOG_E("mcOpenSession(): length is more than allocated TCI"); 337 mcResult = MC_DRV_ERR_TCI_GREATER_THAN_WSM; 338 break; 339 } 340 341 SEND_TO_DAEMON(devCon, MC_DRV_CMD_OPEN_SESSION, 342 session->deviceId, 343 *uuid, 344 (uint32_t)0, 345 (uint32_t)pWsm->handle, 346 len); 347 348 // Read command response 349 RECV_FROM_DAEMON(devCon, &mcResult); 350 351 if (mcResult != MC_DRV_OK) { 352 // TODO-2012-09-06-haenellu: Remove this code once tests can handle it 353 354 if (MC_DRV_ERROR_MAJOR(mcResult) != MC_DRV_ERR_MCP_ERROR) { 355 LOG_E("Daemon could not open session, responseId %d.", mcResult); 356 } else { 357 uint32_t mcpResult = MC_DRV_ERROR_MCP(mcResult); 358 LOG_E("MobiCore reported failing of MC_MCP_CMD_OPEN_SESSION command, mcpResult %d.", mcpResult); 359 360 // IMPROVEMENT-2012-09-03-haenellu: Remove this switch case and use MCP code in tests. 361 switch (mcpResult) { 362 case MC_MCP_RET_ERR_WRONG_PUBLIC_KEY: 363 mcResult = MC_DRV_ERR_WRONG_PUBLIC_KEY; 364 break; 365 case MC_MCP_RET_ERR_CONTAINER_TYPE_MISMATCH: 366 mcResult = MC_DRV_ERR_CONTAINER_TYPE_MISMATCH; 367 break; 368 case MC_MCP_RET_ERR_CONTAINER_LOCKED: 369 mcResult = MC_DRV_ERR_CONTAINER_LOCKED; 370 break; 371 case MC_MCP_RET_ERR_SP_NO_CHILD: 372 mcResult = MC_DRV_ERR_SP_NO_CHILD; 373 break; 374 case MC_MCP_RET_ERR_TL_NO_CHILD: 375 mcResult = MC_DRV_ERR_TL_NO_CHILD; 376 break; 377 case MC_MCP_RET_ERR_UNWRAP_ROOT_FAILED: 378 mcResult = MC_DRV_ERR_UNWRAP_ROOT_FAILED; 379 break; 380 case MC_MCP_RET_ERR_UNWRAP_SP_FAILED: 381 mcResult = MC_DRV_ERR_UNWRAP_SP_FAILED; 382 break; 383 case MC_MCP_RET_ERR_UNWRAP_TRUSTLET_FAILED: 384 mcResult = MC_DRV_ERR_UNWRAP_TRUSTLET_FAILED; 385 break; 386 default: 387 // TODO-2012-09-06-haenellu: Remove line and adapt codes in tests. 388 mcResult = MC_DRV_ERR_MCP_ERROR; 389 break; 390 } 391 } 392 break; // loading of Trustlet failed, unlock mutex and return 393 } 394 395 // read payload 396 mcDrvRspOpenSessionPayload_t rspOpenSessionPayload; 397 RECV_FROM_DAEMON(devCon, &rspOpenSessionPayload); 398 399 // Register session with handle 400 session->sessionId = rspOpenSessionPayload.sessionId; 401 402 LOG_I(" Service is started. Setting up channel for notifications."); 403 404 // Set up second channel for notifications 405 Connection *sessionConnection = new Connection(); 406 if (!sessionConnection->connect(SOCK_PATH)) { 407 LOG_E("Could not connect to %s", SOCK_PATH); 408 delete sessionConnection; 409 // Here we know we couldn't connect to the Daemon. 410 // Maybe we should use existing connection to close Trustlet. 411 mcResult = MC_DRV_ERR_SOCKET_CONNECT; 412 break; 413 } 414 415 do { 416 SEND_TO_DAEMON(sessionConnection, MC_DRV_CMD_NQ_CONNECT, 417 session->deviceId, 418 session->sessionId, 419 rspOpenSessionPayload.deviceSessionId, 420 rspOpenSessionPayload.sessionMagic); 421 422 RECV_FROM_DAEMON(sessionConnection, &mcResult); 423 424 if (mcResult != MC_DRV_OK) { 425 LOG_E("CMD_NQ_CONNECT failed, respId=%d", mcResult); 426 break; 427 } 428 429 } while (0); 430 if (mcResult != MC_DRV_OK) { 431 delete sessionConnection; 432 // Here we know we couldn't communicate well with the Daemon. 433 // Maybe we should use existing connection to close Trustlet. 434 break; // unlock mutex and return 435 } 436 437 // there is no payload. 438 439 // Session has been established, new session object must be created 440 device->createNewSession(session->sessionId, sessionConnection); 441 442 LOG_I(" Successfully opened session %d.", session->sessionId); 443 444 } while (false); 445 446 // TODO: enable as soon as there are more error codes 447 // if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { 448 // LOG_E("Connection is dead, removing device."); 449 // removeDevice(session->deviceId); 450 // } 451 452 devMutex.unlock(); 453 454 return mcResult; 455 } 456 457 458 //------------------------------------------------------------------------------ 459 __MC_CLIENT_LIB_API mcResult_t mcCloseSession(mcSessionHandle_t *session) 460 { 461 mcResult_t mcResult = MC_DRV_OK; 462 463 LOG_I("===%s()===", __FUNCTION__); 464 devMutex.lock(); 465 do { 466 CHECK_NOT_NULL(session); 467 LOG_I(" Closing session %d.", session->sessionId); 468 469 Device *device = resolveDeviceId(session->deviceId); 470 CHECK_DEVICE(device); 471 472 Connection *devCon = device->connection; 473 474 Session *nqSession = device->resolveSessionId(session->sessionId); 475 476 CHECK_SESSION(nqSession, session->sessionId); 477 478 SEND_TO_DAEMON(devCon, MC_DRV_CMD_CLOSE_SESSION, session->sessionId); 479 480 RECV_FROM_DAEMON(devCon, &mcResult); 481 482 if (mcResult != MC_DRV_OK) { 483 LOG_E("CMD_CLOSE_SESSION failed, respId=%d", mcResult); 484 // TODO-2012-08-03-haenellu: Remove once tests can handle it. 485 mcResult = MC_DRV_ERR_UNKNOWN_DEVICE; 486 break; 487 } 488 489 bool r = device->removeSession(session->sessionId); 490 assert(r == true); 491 492 } while (false); 493 494 if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { 495 LOG_E("Connection is dead, removing device."); 496 removeDevice(session->deviceId); 497 } 498 499 devMutex.unlock(); 500 501 return mcResult; 502 } 503 504 505 //------------------------------------------------------------------------------ 506 __MC_CLIENT_LIB_API mcResult_t mcNotify( 507 mcSessionHandle_t *session 508 ) 509 { 510 mcResult_t mcResult = MC_DRV_OK; 511 devMutex.lock(); 512 LOG_I("===%s()===", __FUNCTION__); 513 514 do { 515 CHECK_NOT_NULL(session); 516 LOG_I(" Notifying session %d.", session->sessionId); 517 518 Device *device = resolveDeviceId(session->deviceId); 519 CHECK_DEVICE(device); 520 521 Connection *devCon = device->connection; 522 523 Session *nqsession = device->resolveSessionId(session->sessionId); 524 CHECK_SESSION(nqsession, session->sessionId); 525 526 SEND_TO_DAEMON(devCon, MC_DRV_CMD_NOTIFY, session->sessionId); 527 // Daemon will not return a response 528 } while (false); 529 530 if (mcResult == MC_DRV_ERR_SOCKET_WRITE) { 531 LOG_E("Connection is dead, removing device."); 532 removeDevice(session->deviceId); 533 } 534 535 devMutex.unlock(); 536 return mcResult; 537 } 538 539 540 //------------------------------------------------------------------------------ 541 __MC_CLIENT_LIB_API mcResult_t mcWaitNotification( 542 mcSessionHandle_t *session, 543 int32_t timeout 544 ) 545 { 546 mcResult_t mcResult = MC_DRV_OK; 547 548 devMutex.lock(); 549 LOG_I("===%s()===", __FUNCTION__); 550 551 do { 552 CHECK_NOT_NULL(session); 553 LOG_I(" Waiting for notification of session %d.", session->sessionId); 554 555 Device *device = resolveDeviceId(session->deviceId); 556 CHECK_DEVICE(device); 557 558 Session *nqSession = device->resolveSessionId(session->sessionId); 559 CHECK_SESSION(nqSession, session->sessionId); 560 561 Connection *nqconnection = nqSession->notificationConnection; 562 uint32_t count = 0; 563 564 // Read notification queue till it's empty 565 for (;;) { 566 notification_t notification; 567 ssize_t numRead = nqconnection->readData( 568 ¬ification, 569 sizeof(notification_t), 570 timeout); 571 //Exit on timeout in first run 572 //Later runs have timeout set to 0. -2 means, there is no more data. 573 if (count == 0 && numRead == -2 ) { 574 LOG_W("Timeout hit at %s", __FUNCTION__); 575 mcResult = MC_DRV_ERR_TIMEOUT; 576 break; 577 } 578 if (count == 0 && numRead == 0 ) { 579 LOG_E("Connection is dead, removing device."); 580 removeDevice(session->deviceId); 581 mcResult = MC_DRV_ERR_NOTIFICATION; 582 break; 583 } 584 // After first notification the queue will be drained, Thus we set 585 // no timeout for the following reads 586 timeout = 0; 587 588 if (numRead != sizeof(notification_t)) { 589 if (count == 0) { 590 //failure in first read, notify it 591 mcResult = MC_DRV_ERR_NOTIFICATION; 592 LOG_E("read notification failed, %i bytes received", (int)numRead); 593 break; 594 } else { 595 // Read of the n-th notification failed/timeout. We don't tell the 596 // caller, as we got valid notifications before. 597 mcResult = MC_DRV_OK; 598 break; 599 } 600 } 601 602 count++; 603 LOG_I(" Received notification %d for session %d, payload=%d", 604 count, notification.sessionId, notification.payload); 605 606 if (notification.payload != 0) { 607 // Session end point died -> store exit code 608 nqSession->setErrorInfo(notification.payload); 609 610 mcResult = MC_DRV_INFO_NOTIFICATION; 611 break; 612 } 613 } // for(;;) 614 615 } while (false); 616 617 devMutex.unlock(); 618 return mcResult; 619 } 620 621 622 //------------------------------------------------------------------------------ 623 __MC_CLIENT_LIB_API mcResult_t mcMallocWsm( 624 uint32_t deviceId, 625 uint32_t align, 626 uint32_t len, 627 uint8_t **wsm, 628 uint32_t wsmFlags) 629 { 630 mcResult_t mcResult = MC_DRV_ERR_UNKNOWN; 631 632 LOG_I("===%s(len=%i)===", __FUNCTION__, len); 633 634 devMutex.lock(); 635 636 do { 637 Device *device = resolveDeviceId(deviceId); 638 CHECK_DEVICE(device); 639 640 CHECK_NOT_NULL(wsm); 641 642 CWsm_ptr pWsm; 643 mcResult = device->allocateContiguousWsm(len, &pWsm); 644 if (mcResult != MC_DRV_OK) { 645 LOG_W(" Allocation of WSM failed"); 646 break; 647 } 648 649 *wsm = (uint8_t *)pWsm->virtAddr; 650 mcResult = MC_DRV_OK; 651 652 } while (false); 653 654 devMutex.unlock(); 655 656 return mcResult; 657 } 658 659 660 //------------------------------------------------------------------------------ 661 __MC_CLIENT_LIB_API mcResult_t mcFreeWsm( 662 uint32_t deviceId, 663 uint8_t *wsm 664 ) 665 { 666 mcResult_t mcResult = MC_DRV_ERR_UNKNOWN; 667 Device *device; 668 669 devMutex.lock(); 670 671 LOG_I("===%s(%p)===", __FUNCTION__, wsm); 672 673 do { 674 675 // Get the device associated wit the given session 676 device = resolveDeviceId(deviceId); 677 CHECK_DEVICE(device); 678 679 // find WSM object 680 CWsm_ptr pWsm = device->findContiguousWsm(wsm); 681 if (pWsm == NULL) { 682 LOG_E("address is unknown to mcFreeWsm"); 683 mcResult = MC_DRV_ERR_WSM_NOT_FOUND; 684 break; 685 } 686 687 // Free the given virtual address 688 mcResult = device->freeContiguousWsm(pWsm); 689 if (mcResult != MC_DRV_OK) { 690 LOG_E("Free of virtual address failed"); 691 break; 692 } 693 mcResult = MC_DRV_OK; 694 695 } while (false); 696 697 devMutex.unlock(); 698 699 return mcResult; 700 } 701 702 //------------------------------------------------------------------------------ 703 __MC_CLIENT_LIB_API mcResult_t mcMap( 704 mcSessionHandle_t *sessionHandle, 705 void *buf, 706 uint32_t bufLen, 707 mcBulkMap_t *mapInfo 708 ) 709 { 710 mcResult_t mcResult = MC_DRV_ERR_UNKNOWN; 711 static CMutex mutex; 712 713 LOG_I("===%s()===", __FUNCTION__); 714 715 devMutex.lock(); 716 717 do { 718 CHECK_NOT_NULL(sessionHandle); 719 CHECK_NOT_NULL(mapInfo); 720 CHECK_NOT_NULL(buf); 721 722 // Determine device the session belongs to 723 Device *device = resolveDeviceId(sessionHandle->deviceId); 724 CHECK_DEVICE(device); 725 726 Connection *devCon = device->connection; 727 728 // Get session 729 Session *session = device->resolveSessionId(sessionHandle->sessionId); 730 CHECK_SESSION(session, sessionHandle->sessionId); 731 732 LOG_I(" Mapping %p to session %d.", buf, sessionHandle->sessionId); 733 734 // Register mapped bulk buffer to Kernel Module and keep mapped bulk buffer in mind 735 BulkBufferDescriptor *bulkBuf; 736 mcResult = session->addBulkBuf(buf, bufLen, &bulkBuf); 737 if (mcResult != MC_DRV_OK) { 738 LOG_E("Registering buffer failed. ret=%x", mcResult); 739 break; 740 } 741 742 SEND_TO_DAEMON(devCon, MC_DRV_CMD_MAP_BULK_BUF, 743 session->sessionId, 744 (uint32_t)bulkBuf->handle, 745 (uint32_t)0, 746 (uint32_t)(bulkBuf->virtAddr) & 0xFFF, 747 bulkBuf->len); 748 749 // Read command response 750 RECV_FROM_DAEMON(devCon, &mcResult); 751 752 if (mcResult != MC_DRV_OK) { 753 LOG_E("CMD_MAP_BULK_BUF failed, respId=%d", mcResult); 754 // TODO-2012-09-06-haenellu: Remove once tests can handle it. 755 mcResult = MC_DRV_ERR_DAEMON_UNREACHABLE; 756 757 // Unregister mapped bulk buffer from Kernel Module and remove mapped 758 // bulk buffer from session maintenance 759 if (session->removeBulkBuf(buf) != MC_DRV_OK) { 760 // Removing of bulk buffer not possible 761 LOG_E("Unregistering of bulk memory from Kernel Module failed"); 762 } 763 break; 764 } 765 766 mcDrvRspMapBulkMemPayload_t rspMapBulkMemPayload; 767 RECV_FROM_DAEMON(devCon, &rspMapBulkMemPayload); 768 769 // Set mapping info for internal structures 770 bulkBuf->sVirtualAddr = (void *)rspMapBulkMemPayload.secureVirtualAdr; 771 // Set mapping info for Trustlet 772 mapInfo->sVirtualAddr = bulkBuf->sVirtualAddr; 773 mapInfo->sVirtualLen = bufLen; 774 mcResult = MC_DRV_OK; 775 776 } while (false); 777 778 // // TODO: enable as soon as there are more error codes 779 // if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { 780 // LOG_E("Connection is dead, removing device."); 781 // removeDevice(sessionHandle->deviceId); 782 // } 783 784 devMutex.unlock(); 785 786 return mcResult; 787 } 788 789 //------------------------------------------------------------------------------ 790 __MC_CLIENT_LIB_API mcResult_t mcUnmap( 791 mcSessionHandle_t *sessionHandle, 792 void *buf, 793 mcBulkMap_t *mapInfo 794 ) 795 { 796 mcResult_t mcResult = MC_DRV_ERR_UNKNOWN; 797 static CMutex mutex; 798 799 LOG_I("===%s()===", __FUNCTION__); 800 801 devMutex.lock(); 802 803 do { 804 CHECK_NOT_NULL(sessionHandle); 805 CHECK_NOT_NULL(mapInfo); 806 CHECK_NOT_NULL(buf); 807 808 // Determine device the session belongs to 809 Device *device = resolveDeviceId(sessionHandle->deviceId); 810 CHECK_DEVICE(device); 811 812 Connection *devCon = device->connection; 813 814 // Get session 815 Session *session = device->resolveSessionId(sessionHandle->sessionId); 816 CHECK_SESSION(session, sessionHandle->sessionId); 817 818 uint32_t handle = session->getBufHandle(mapInfo->sVirtualAddr); 819 if (handle == 0) { 820 LOG_E("Unable to find internal handle for buffer %p.", mapInfo->sVirtualAddr); 821 mcResult = MC_DRV_ERR_BLK_BUFF_NOT_FOUND; 822 break; 823 } 824 825 LOG_I(" Unmapping %p(handle=%u) from session %d.", buf, handle, sessionHandle->sessionId); 826 827 SEND_TO_DAEMON(devCon, MC_DRV_CMD_UNMAP_BULK_BUF, 828 session->sessionId, 829 handle, 830 (uint32_t)(mapInfo->sVirtualAddr), 831 mapInfo->sVirtualLen); 832 833 RECV_FROM_DAEMON(devCon, &mcResult); 834 835 if (mcResult != MC_DRV_OK) { 836 LOG_E("Daemon reported failing of UNMAP BULK BUF command, responseId %d.", mcResult); 837 // TODO-2012-09-06-haenellu: Remove once tests can handle it. 838 mcResult = MC_DRV_ERR_DAEMON_UNREACHABLE; 839 break; 840 } 841 842 // Unregister mapped bulk buffer from Kernel Module and remove mapped 843 // bulk buffer from session maintenance 844 mcResult = session->removeBulkBuf(buf); 845 if (mcResult != MC_DRV_OK) { 846 LOG_E("Unregistering of bulk memory from Kernel Module failed."); 847 break; 848 } 849 850 mcResult = MC_DRV_OK; 851 852 } while (false); 853 854 if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { 855 LOG_E("Connection is dead, removing device."); 856 removeDevice(sessionHandle->deviceId); 857 } 858 859 devMutex.unlock(); 860 861 return mcResult; 862 } 863 864 865 //------------------------------------------------------------------------------ 866 __MC_CLIENT_LIB_API mcResult_t mcGetSessionErrorCode( 867 mcSessionHandle_t *session, 868 int32_t *lastErr 869 ) 870 { 871 mcResult_t mcResult = MC_DRV_OK; 872 873 devMutex.lock(); 874 LOG_I("===%s()===", __FUNCTION__); 875 876 do { 877 CHECK_NOT_NULL(session); 878 CHECK_NOT_NULL(lastErr); 879 880 // Get device 881 Device *device = resolveDeviceId(session->deviceId); 882 CHECK_DEVICE(device); 883 884 // Get session 885 Session *nqsession = device->resolveSessionId(session->sessionId); 886 CHECK_SESSION(nqsession, session->sessionId); 887 888 // get session error code from session 889 *lastErr = nqsession->getLastErr(); 890 891 } while (false); 892 893 devMutex.unlock(); 894 return mcResult; 895 } 896 897 //------------------------------------------------------------------------------ 898 __MC_CLIENT_LIB_API mcResult_t mcDriverCtrl( 899 mcDriverCtrl_t param, 900 uint8_t *data, 901 uint32_t len 902 ) 903 { 904 LOG_W("mcDriverCtrl(): not implemented"); 905 return MC_DRV_ERR_NOT_IMPLEMENTED; 906 } 907 908 //------------------------------------------------------------------------------ 909 __MC_CLIENT_LIB_API mcResult_t mcGetMobiCoreVersion( 910 uint32_t deviceId, 911 mcVersionInfo_t *versionInfo 912 ) 913 { 914 mcResult_t mcResult = MC_DRV_OK; 915 916 devMutex.lock(); 917 LOG_I("===%s()===", __FUNCTION__); 918 919 do { 920 Device *device = resolveDeviceId(deviceId); 921 922 CHECK_DEVICE(device); 923 CHECK_NOT_NULL(versionInfo); 924 925 Connection *devCon = device->connection; 926 927 SEND_TO_DAEMON(devCon, MC_DRV_CMD_GET_MOBICORE_VERSION); 928 929 // Read GET MOBICORE VERSION response. 930 931 RECV_FROM_DAEMON(devCon, &mcResult); 932 933 if (mcResult != MC_DRV_OK) { 934 LOG_E("MC_DRV_CMD_GET_MOBICORE_VERSION bad response, respId=%d", mcResult); 935 // TODO-2012-09-06-haenellu: Remove once tests can handle it. 936 mcResult = MC_DRV_ERR_DAEMON_UNREACHABLE; 937 break; 938 } 939 940 // Read payload. 941 mcVersionInfo_t versionInfo_socket; 942 RECV_FROM_DAEMON(devCon, &versionInfo_socket); 943 944 *versionInfo = versionInfo_socket; 945 946 } while (0); 947 948 devMutex.unlock(); 949 return mcResult; 950 } 951 952 953 //------------------------------------------------------------------------------ 954 // Only called by mcOpenDevice() 955 // Must be taken with devMutex locked. 956 uint32_t getDaemonVersion(Connection *devCon, uint32_t *version) 957 { 958 assert(version != NULL); 959 mcResult_t mcResult = MC_DRV_OK; 960 uint32_t v = 0; 961 962 LOG_I("===%s()===", __FUNCTION__); 963 964 do { 965 SEND_TO_DAEMON(devCon, MC_DRV_CMD_GET_VERSION); 966 967 RECV_FROM_DAEMON(devCon, &mcResult); 968 969 if (mcResult != MC_DRV_OK) { 970 LOG_E("MC_DRV_CMD_GET_VERSION bad response, respId=%d", mcResult); 971 // version is still 0, we don't further analyze response here. 972 break; 973 } 974 975 RECV_FROM_DAEMON(devCon, &v); 976 977 } while (0); 978 979 if (MC_DRV_OK == mcResult) { 980 *version = v; 981 } 982 983 return mcResult; 984 } 985 986 /** @} */ 987