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
56MC_CHECK_VERSION(DAEMON, 0, 2);
57
58/** Notification data structure. */
59typedef struct {
60    uint32_t sessionId; /**< Session ID. */
61    int32_t payload; /**< Additional notification information. */
62} notification_t;
63
64using namespace std;
65
66list<Device *> devices;
67
68// Forward declarations.
69uint32_t getDaemonVersion(Connection *devCon, uint32_t *version);
70
71CMutex devMutex;
72//------------------------------------------------------------------------------
73Device *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//------------------------------------------------------------------------------
88void addDevice(Device *device)
89{
90    devices.push_back(device);
91}
92
93
94//------------------------------------------------------------------------------
95bool 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.
956uint32_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