• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //------------------------------------------------------------------------------
resolveDeviceId(uint32_t deviceId)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 //------------------------------------------------------------------------------
addDevice(Device * device)88 void addDevice(Device *device)
89 {
90     devices.push_back(device);
91 }
92 
93 
94 //------------------------------------------------------------------------------
removeDevice(uint32_t deviceId)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 //------------------------------------------------------------------------------
mcOpenDevice(uint32_t deviceId)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 //------------------------------------------------------------------------------
mcCloseDevice(uint32_t deviceId)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 //------------------------------------------------------------------------------
mcOpenSession(mcSessionHandle_t * session,const mcUuid_t * uuid,uint8_t * tci,uint32_t len)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 //------------------------------------------------------------------------------
mcCloseSession(mcSessionHandle_t * session)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 //------------------------------------------------------------------------------
mcNotify(mcSessionHandle_t * session)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 //------------------------------------------------------------------------------
mcWaitNotification(mcSessionHandle_t * session,int32_t timeout)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 //------------------------------------------------------------------------------
mcMallocWsm(uint32_t deviceId,uint32_t align,uint32_t len,uint8_t ** wsm,uint32_t wsmFlags)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 //------------------------------------------------------------------------------
mcFreeWsm(uint32_t deviceId,uint8_t * wsm)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 //------------------------------------------------------------------------------
mcMap(mcSessionHandle_t * sessionHandle,void * buf,uint32_t bufLen,mcBulkMap_t * mapInfo)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 //------------------------------------------------------------------------------
mcUnmap(mcSessionHandle_t * sessionHandle,void * buf,mcBulkMap_t * mapInfo)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 //------------------------------------------------------------------------------
mcGetSessionErrorCode(mcSessionHandle_t * session,int32_t * lastErr)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 //------------------------------------------------------------------------------
mcDriverCtrl(mcDriverCtrl_t param,uint8_t * data,uint32_t len)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 //------------------------------------------------------------------------------
mcGetMobiCoreVersion(uint32_t deviceId,mcVersionInfo_t * versionInfo)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.
getDaemonVersion(Connection * devCon,uint32_t * version)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