Home | History | Annotate | Download | only in ClientLib
      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                                   &notification,
    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