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 ¬ification,
569 sizeof(notification_t),
570 timeout);
571 //Exit on timeout in first run
572 //Later runs have timeout set to 0. -2 means, there is no more data.
573 if (count == 0 && numRead == -2 ) {
574 LOG_W("Timeout hit at %s", __FUNCTION__);
575 mcResult = MC_DRV_ERR_TIMEOUT;
576 break;
577 }
578 if (count == 0 && numRead == 0 ) {
579 LOG_E("Connection is dead, removing device.");
580 removeDevice(session->deviceId);
581 mcResult = MC_DRV_ERR_NOTIFICATION;
582 break;
583 }
584 // After first notification the queue will be drained, Thus we set
585 // no timeout for the following reads
586 timeout = 0;
587
588 if (numRead != sizeof(notification_t)) {
589 if (count == 0) {
590 //failure in first read, notify it
591 mcResult = MC_DRV_ERR_NOTIFICATION;
592 LOG_E("read notification failed, %i bytes received", (int)numRead);
593 break;
594 } else {
595 // Read of the n-th notification failed/timeout. We don't tell the
596 // caller, as we got valid notifications before.
597 mcResult = MC_DRV_OK;
598 break;
599 }
600 }
601
602 count++;
603 LOG_I(" Received notification %d for session %d, payload=%d",
604 count, notification.sessionId, notification.payload);
605
606 if (notification.payload != 0) {
607 // Session end point died -> store exit code
608 nqSession->setErrorInfo(notification.payload);
609
610 mcResult = MC_DRV_INFO_NOTIFICATION;
611 break;
612 }
613 } // for(;;)
614
615 } while (false);
616
617 devMutex.unlock();
618 return mcResult;
619 }
620
621
622 //------------------------------------------------------------------------------
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