| /** @addtogroup MCD_IMPL_LIB |
| * @{ |
| * @file |
| * |
| * <t-base Driver API. |
| * |
| * Functions for accessing <t-base functionality from the normal world. |
| * Handles sessions and notifications via MCI buffer. |
| * |
| * |
| * Copyright (c) 2013 TRUSTONIC LIMITED |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * 3. Neither the name of the TRUSTONIC LIMITED nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| #include <stdint.h> |
| #ifndef WIN32 |
| #include <stdbool.h> |
| #include <list> |
| #include "assert.h" |
| #endif |
| |
| #include "public/MobiCoreDriverApi.h" |
| |
| #ifndef WIN32 |
| #include "mc_linux.h" |
| #include "Connection.h" |
| #include "CMutex.h" |
| #include "Device.h" |
| #include "mcVersionHelper.h" |
| |
| #include "Daemon/public/MobiCoreDriverCmd.h" |
| #include "Daemon/public/mcVersion.h" |
| |
| #include "log.h" |
| |
| #include "Mci/mcimcp.h" |
| |
| MC_CHECK_VERSION(DAEMON, 0, 2); |
| |
| /** Notification data structure. */ |
| typedef struct { |
| uint32_t sessionId; /**< Session ID. */ |
| int32_t payload; /**< Additional notification information. */ |
| } notification_t; |
| |
| using namespace std; |
| |
| static list<Device *> devices; |
| |
| // Forward declarations. |
| uint32_t getDaemonVersion(Connection *devCon, uint32_t *version); |
| |
| static CMutex devMutex; |
| //------------------------------------------------------------------------------ |
| Device *resolveDeviceId(uint32_t deviceId) |
| { |
| for (list<Device *>::iterator iterator = devices.begin(); |
| iterator != devices.end(); |
| ++iterator) { |
| Device *device = (*iterator); |
| |
| if (device->deviceId == deviceId) { |
| return device; |
| } |
| } |
| return NULL; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| void addDevice(Device *device) |
| { |
| devices.push_back(device); |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| bool removeDevice(uint32_t deviceId) |
| { |
| for (list<Device *>::iterator iterator = devices.begin(); |
| iterator != devices.end(); |
| ++iterator) { |
| Device *device = (*iterator); |
| |
| if (device->deviceId == deviceId) { |
| devices.erase(iterator); |
| delete device; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Parameter checking functions |
| // Note that android-ndk renames __func__ to __PRETTY_FUNCTION__ |
| // see also /prebuilt/ndk/android-ndk-r4/platforms/android-8/arch-arm/usr/include/sys/cdefs.h |
| |
| #define CHECK_DEVICE(device) \ |
| if (NULL == device) \ |
| { \ |
| LOG_E("Device has not been found"); \ |
| mcResult = MC_DRV_ERR_UNKNOWN_DEVICE; \ |
| break; \ |
| } |
| |
| #define CHECK_DEVICE_CLOSED(device, deviceId) \ |
| if (NULL == device && MC_DEVICE_ID_DEFAULT == deviceId) \ |
| { \ |
| LOG_E("Device not open"); \ |
| mcResult = MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN; \ |
| break; \ |
| } else \ |
| CHECK_DEVICE(device); |
| |
| |
| |
| #define CHECK_NOT_NULL(X) \ |
| if (NULL == X) \ |
| { \ |
| LOG_E("Parameter \""#X "\" is NULL"); \ |
| mcResult = MC_DRV_ERR_NULL_POINTER; \ |
| break; \ |
| } |
| |
| #define CHECK_SESSION(S,SID) \ |
| if (NULL == S) \ |
| { \ |
| LOG_E("Session %i not found", SID); \ |
| mcResult = MC_DRV_ERR_UNKNOWN_SESSION; \ |
| break; \ |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Socket marshaling and checking functions |
| #define SEND_TO_DAEMON(CONNECTION, COMMAND, ...) \ |
| { \ |
| COMMAND ##_struct x = { \ |
| COMMAND, \ |
| __VA_ARGS__ \ |
| }; \ |
| int ret = CONNECTION->writeData(&x, sizeof x); \ |
| if(ret < 0) { \ |
| LOG_E("sending to Daemon failed."); \ |
| mcResult = MC_DRV_ERR_SOCKET_WRITE; \ |
| break; \ |
| } \ |
| } |
| |
| #define RECV_FROM_DAEMON(CONNECTION, RSP_STRUCT) \ |
| { \ |
| int rlen = CONNECTION->readData( \ |
| RSP_STRUCT, \ |
| sizeof(*RSP_STRUCT)); \ |
| if (rlen <= 0) { \ |
| LOG_E("reading from Daemon failed"); \ |
| mcResult = MC_DRV_ERR_SOCKET_READ; \ |
| break; \ |
| } \ |
| if (rlen != sizeof(*RSP_STRUCT) && rlen != sizeof(mcDrvResponseHeader_t)) {\ |
| LOG_E("wrong buffer length %i received from Daemon", rlen); \ |
| mcResult = MC_DRV_ERR_SOCKET_LENGTH; \ |
| break; \ |
| } \ |
| } |
| #endif /* WIN32 */ |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcOpenDevice(uint32_t deviceId) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| Connection *devCon = NULL; |
| |
| devMutex.lock(); |
| LOG_I("===%s(%i)===", __FUNCTION__, deviceId); |
| |
| do { |
| Device *device = resolveDeviceId(deviceId); |
| if (device != NULL) { |
| LOG_E("Device %d already opened", deviceId); |
| mcResult = MC_DRV_ERR_DEVICE_ALREADY_OPEN; |
| break; |
| } |
| |
| // Handle SIGPIPE inside write() |
| // If Daemon crashes and ClientLib writes to named socket, |
| // a sigpipe is send to ClientLib/TLC and kills it. |
| signal(SIGPIPE, SIG_IGN); |
| |
| // Open new connection to device |
| devCon = new Connection(); |
| if (!devCon->connect(SOCK_PATH)) { |
| LOG_W(" Could not connect to %s socket", SOCK_PATH); |
| mcResult = MC_DRV_ERR_SOCKET_CONNECT; |
| break; |
| } |
| |
| // Runtime check of Daemon version. |
| char *errmsg; |
| uint32_t version = 0; |
| mcResult = getDaemonVersion(devCon, &version); |
| if (mcResult != MC_DRV_OK) { |
| break; |
| } |
| if (!checkVersionOkDAEMON(version, &errmsg)) { |
| LOG_E("%s", errmsg); |
| mcResult = MC_DRV_ERR_DAEMON_VERSION; |
| break; |
| } |
| LOG_I(" %s", errmsg); |
| |
| // Forward device open to the daemon and read result |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_OPEN_DEVICE, deviceId); |
| |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_W(" %s(): Request at Daemon failed, respId=%x ", __FUNCTION__, mcResult); |
| break; |
| } |
| |
| // there is no payload to read |
| |
| device = new Device(deviceId, devCon); |
| mcResult = device->open("/dev/" MC_USER_DEVNODE); |
| if (mcResult != MC_DRV_OK) { |
| delete device; |
| // devCon is freed in the Device destructor |
| devCon = NULL; |
| LOG_E("Could not open device file: /dev/%s", MC_USER_DEVNODE); |
| break; |
| } |
| |
| addDevice(device); |
| |
| } while (false); |
| |
| devMutex.unlock(); |
| if (mcResult != MC_DRV_OK) { |
| if (devCon != NULL) |
| delete devCon; |
| LOG_I(" Device not opened."); |
| } else { |
| LOG_I(" Successfully opened the device."); |
| } |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcCloseDevice( |
| uint32_t deviceId |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| devMutex.lock(); |
| LOG_I("===%s(%i)===", __FUNCTION__, deviceId); |
| do { |
| Device *device = resolveDeviceId(deviceId); |
| // CHECK_DEVICE(device); |
| CHECK_DEVICE_CLOSED(device, deviceId); |
| |
| Connection *devCon = device->connection; |
| |
| // Check if daemon is still alive |
| if (!devCon->isConnectionAlive()) { |
| removeDevice(deviceId); |
| LOG_E("Daemon is dead removing device"); |
| mcResult = MC_DRV_ERR_DAEMON_UNREACHABLE; |
| break; |
| } |
| |
| // Return if not all sessions have been closed |
| // TODO-2012-08-31-haenellu: improve check, if device connection is dead, this makes no more sense. |
| if (device->hasSessions()) { |
| LOG_E("Trying to close device while sessions are still pending."); |
| mcResult = MC_DRV_ERR_SESSION_PENDING; |
| break; |
| } |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_CLOSE_DEVICE); |
| |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_W(" %s(): Request at Daemon failed, respId=%d ", __FUNCTION__, mcResult); |
| break; |
| } |
| |
| removeDevice(deviceId); |
| |
| } while (false); |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcOpenSession( |
| mcSessionHandle_t *session, |
| const mcUuid_t *uuid, |
| uint8_t *tci, |
| uint32_t len |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| devMutex.lock(); |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| BulkBufferDescriptor *bulkBuf = NULL; |
| |
| do { |
| uint32_t handle = 0; |
| CHECK_NOT_NULL(session); |
| CHECK_NOT_NULL(uuid); |
| |
| if (len > MC_MAX_TCI_LEN) { |
| LOG_E("TCI length is longer than %d", MC_MAX_TCI_LEN); |
| mcResult = MC_DRV_ERR_TCI_TOO_BIG; |
| break; |
| } |
| |
| // Get the device associated with the given session |
| Device *device = resolveDeviceId(session->deviceId); |
| CHECK_DEVICE(device); |
| |
| Connection *devCon = device->connection; |
| |
| // First assume the TCI is a contiguous buffer |
| // Get the physical address of the given TCI |
| CWsm_ptr pWsm = device->findContiguousWsm(tci); |
| if (pWsm == NULL) { |
| if (tci != NULL && len != 0) { |
| // Then assume it's a normal buffer that needs to be mapped |
| mcResult = device->mapBulkBuf(tci, len, &bulkBuf); |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("Registering buffer failed. ret=%x", mcResult); |
| mcResult = MC_DRV_ERR_WSM_NOT_FOUND; |
| break; |
| } |
| handle = bulkBuf->handle; |
| } else if ( len != 0 ) { |
| LOG_E("mcOpenSession(): length is more than allocated TCI"); |
| mcResult = MC_DRV_ERR_TCI_GREATER_THAN_WSM; |
| break; |
| } |
| } else { |
| if (pWsm->len < len) { |
| LOG_E("mcOpenSession(): length is more than allocated TCI"); |
| mcResult = MC_DRV_ERR_TCI_GREATER_THAN_WSM; |
| break; |
| } |
| handle = pWsm->handle; |
| } |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_OPEN_SESSION, |
| session->deviceId, |
| *uuid, |
| (uint32_t)(tci) & 0xFFF, |
| (uint32_t)handle, |
| len); |
| |
| // Read command response |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| // TODO-2012-09-06-haenellu: Remove this code once tests can handle it |
| |
| if (MC_DRV_ERROR_MAJOR(mcResult) != MC_DRV_ERR_MCP_ERROR) { |
| LOG_E("Daemon could not open session, responseId %d.", mcResult); |
| } else { |
| uint32_t mcpResult = MC_DRV_ERROR_MCP(mcResult); |
| LOG_E("<t-base reported failing of MC_MCP_CMD_OPEN_SESSION command, mcpResult %d.", mcpResult); |
| |
| // IMPROVEMENT-2012-09-03-haenellu: Remove this switch case and use MCP code in tests. |
| switch (mcpResult) { |
| case MC_MCP_RET_ERR_WRONG_PUBLIC_KEY: |
| mcResult = MC_DRV_ERR_WRONG_PUBLIC_KEY; |
| break; |
| case MC_MCP_RET_ERR_CONTAINER_TYPE_MISMATCH: |
| mcResult = MC_DRV_ERR_CONTAINER_TYPE_MISMATCH; |
| break; |
| case MC_MCP_RET_ERR_CONTAINER_LOCKED: |
| mcResult = MC_DRV_ERR_CONTAINER_LOCKED; |
| break; |
| case MC_MCP_RET_ERR_SP_NO_CHILD: |
| mcResult = MC_DRV_ERR_SP_NO_CHILD; |
| break; |
| case MC_MCP_RET_ERR_TL_NO_CHILD: |
| mcResult = MC_DRV_ERR_TL_NO_CHILD; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_ROOT_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_ROOT_FAILED; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_SP_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_SP_FAILED; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_TRUSTLET_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_TRUSTLET_FAILED; |
| break; |
| default: |
| // TODO-2012-09-06-haenellu: Remove line and adapt codes in tests. |
| mcResult = MC_DRV_ERR_MCP_ERROR; |
| break; |
| } |
| } |
| break; // loading of Trustlet failed, unlock mutex and return |
| } |
| |
| // read payload |
| mcDrvRspOpenSessionPayload_t rspOpenSessionPayload; |
| RECV_FROM_DAEMON(devCon, &rspOpenSessionPayload); |
| |
| // Register session with handle |
| session->sessionId = rspOpenSessionPayload.sessionId; |
| |
| LOG_I(" Service is started. Setting up channel for notifications."); |
| |
| // Set up second channel for notifications |
| Connection *sessionConnection = new Connection(); |
| if (!sessionConnection->connect(SOCK_PATH)) { |
| LOG_E("Could not connect to %s", SOCK_PATH); |
| delete sessionConnection; |
| // Here we know we couldn't connect to the Daemon. |
| // Maybe we should use existing connection to close Trustlet. |
| mcResult = MC_DRV_ERR_SOCKET_CONNECT; |
| break; |
| } |
| |
| do { |
| SEND_TO_DAEMON(sessionConnection, MC_DRV_CMD_NQ_CONNECT, |
| session->deviceId, |
| session->sessionId, |
| rspOpenSessionPayload.deviceSessionId, |
| rspOpenSessionPayload.sessionMagic); |
| |
| RECV_FROM_DAEMON(sessionConnection, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("CMD_NQ_CONNECT failed, respId=%d", mcResult); |
| break; |
| } |
| |
| } while (0); |
| if (mcResult != MC_DRV_OK) { |
| delete sessionConnection; |
| // Here we know we couldn't communicate well with the Daemon. |
| // Maybe we should use existing connection to close Trustlet. |
| break; // unlock mutex and return |
| } |
| |
| // there is no payload. |
| |
| // Session has been established, new session object must be created |
| Session *sessionObj = device->createNewSession(session->sessionId, sessionConnection); |
| // If the session tci was a mapped buffer then register it |
| if (bulkBuf) |
| sessionObj->addBulkBuf(bulkBuf); |
| |
| LOG_I(" Successfully opened session %d.", session->sessionId); |
| |
| } while (false); |
| |
| if (mcResult != MC_DRV_OK && bulkBuf) { |
| delete bulkBuf; |
| } |
| |
| // TODO: enable as soon as there are more error codes |
| // if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { |
| // LOG_E("Connection is dead, removing device."); |
| // removeDevice(session->deviceId); |
| // } |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcOpenTrustlet( |
| mcSessionHandle_t *session, |
| mcSpid_t spid, |
| uint8_t *trustlet, |
| uint32_t tlen, |
| uint8_t *tci, |
| uint32_t len |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| devMutex.lock(); |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| BulkBufferDescriptor *bulkBuf = NULL; |
| |
| do { |
| uint32_t handle = 0; |
| CHECK_NOT_NULL(session); |
| CHECK_NOT_NULL(trustlet); |
| CHECK_NOT_NULL(tci); |
| |
| if (len > MC_MAX_TCI_LEN) { |
| LOG_E("TCI length is longer than %d", MC_MAX_TCI_LEN); |
| mcResult = MC_DRV_ERR_TCI_TOO_BIG; |
| break; |
| } |
| |
| // Get the device associated with the given session |
| Device *device = resolveDeviceId(session->deviceId); |
| CHECK_DEVICE(device); |
| |
| Connection *devCon = device->connection; |
| |
| // First assume the TCI is a contiguous buffer |
| // Get the physical address of the given TCI |
| CWsm_ptr pWsm = device->findContiguousWsm(tci); |
| if (pWsm == NULL) { |
| // Then assume it's a normal buffer that needs to be mapped |
| mcResult = device->mapBulkBuf(tci, len, &bulkBuf); |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("Registering buffer failed. ret=%x", mcResult); |
| mcResult = MC_DRV_ERR_WSM_NOT_FOUND;; |
| break; |
| } |
| handle = bulkBuf->handle; |
| } else { |
| if (pWsm->len < len) { |
| LOG_E("mcOpenSession(): length is more than allocated TCI"); |
| mcResult = MC_DRV_ERR_TCI_GREATER_THAN_WSM; |
| break; |
| } |
| handle = pWsm->handle; |
| } |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_OPEN_TRUSTLET, |
| session->deviceId, |
| spid, |
| (uint32_t)tlen, |
| (uint32_t)(tci) & 0xFFF, |
| (uint32_t)handle, |
| len); |
| |
| // Send the full trustlet data |
| int ret = devCon->writeData(trustlet, tlen); |
| if (ret < 0) { |
| LOG_E("sending to Daemon failed."); |
| \ |
| mcResult = MC_DRV_ERR_SOCKET_WRITE; |
| \ |
| break; |
| } |
| |
| // Read command response |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| // TODO-2012-09-06-haenellu: Remove this code once tests can handle it |
| |
| if (MC_DRV_ERROR_MAJOR(mcResult) != MC_DRV_ERR_MCP_ERROR) { |
| LOG_E("Daemon could not open session, responseId %d.", mcResult); |
| } else { |
| uint32_t mcpResult = MC_DRV_ERROR_MCP(mcResult); |
| LOG_E("<t-base reported failing of MC_MCP_CMD_OPEN_SESSION command, mcpResult %d.", mcpResult); |
| |
| // IMPROVEMENT-2012-09-03-haenellu: Remove this switch case and use MCP code in tests. |
| switch (mcpResult) { |
| case MC_MCP_RET_ERR_WRONG_PUBLIC_KEY: |
| mcResult = MC_DRV_ERR_WRONG_PUBLIC_KEY; |
| break; |
| case MC_MCP_RET_ERR_CONTAINER_TYPE_MISMATCH: |
| mcResult = MC_DRV_ERR_CONTAINER_TYPE_MISMATCH; |
| break; |
| case MC_MCP_RET_ERR_CONTAINER_LOCKED: |
| mcResult = MC_DRV_ERR_CONTAINER_LOCKED; |
| break; |
| case MC_MCP_RET_ERR_SP_NO_CHILD: |
| mcResult = MC_DRV_ERR_SP_NO_CHILD; |
| break; |
| case MC_MCP_RET_ERR_TL_NO_CHILD: |
| mcResult = MC_DRV_ERR_TL_NO_CHILD; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_ROOT_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_ROOT_FAILED; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_SP_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_SP_FAILED; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_TRUSTLET_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_TRUSTLET_FAILED; |
| break; |
| default: |
| // TODO-2012-09-06-haenellu: Remove line and adapt codes in tests. |
| mcResult = MC_DRV_ERR_MCP_ERROR; |
| break; |
| } |
| } |
| break; // loading of Trustlet failed, unlock mutex and return |
| } |
| |
| // read payload |
| mcDrvRspOpenSessionPayload_t rspOpenSessionPayload; |
| RECV_FROM_DAEMON(devCon, &rspOpenSessionPayload); |
| |
| // Register session with handle |
| session->sessionId = rspOpenSessionPayload.sessionId; |
| |
| LOG_I(" Service is started. Setting up channel for notifications."); |
| |
| // Set up second channel for notifications |
| Connection *sessionConnection = new Connection(); |
| if (!sessionConnection->connect(SOCK_PATH)) { |
| LOG_E("Could not connect to %s", SOCK_PATH); |
| delete sessionConnection; |
| // Here we know we couldn't connect to the Daemon. |
| // Maybe we should use existing connection to close Trustlet. |
| mcResult = MC_DRV_ERR_SOCKET_CONNECT; |
| break; |
| } |
| |
| do { |
| SEND_TO_DAEMON(sessionConnection, MC_DRV_CMD_NQ_CONNECT, |
| session->deviceId, |
| session->sessionId, |
| rspOpenSessionPayload.deviceSessionId, |
| rspOpenSessionPayload.sessionMagic); |
| |
| RECV_FROM_DAEMON(sessionConnection, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("CMD_NQ_CONNECT failed, respId=%d", mcResult); |
| break; |
| } |
| |
| } while (0); |
| |
| if (mcResult != MC_DRV_OK) { |
| delete sessionConnection; |
| // Here we know we couldn't communicate well with the Daemon. |
| // Maybe we should use existing connection to close Trustlet. |
| break; // unlock mutex and return |
| } |
| |
| // there is no payload. |
| |
| // Session has been established, new session object must be created |
| Session *sessionObj = device->createNewSession(session->sessionId, sessionConnection); |
| // If the session tci was a mapped buffer then register it |
| if (bulkBuf) |
| sessionObj->addBulkBuf(bulkBuf); |
| |
| LOG_I(" Successfully opened session %d.", session->sessionId); |
| |
| } while (false); |
| |
| if (mcResult != MC_DRV_OK && bulkBuf) { |
| delete bulkBuf; |
| } |
| |
| // TODO: enable as soon as there are more error codes |
| // if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { |
| // LOG_E("Connection is dead, removing device."); |
| // removeDevice(session->deviceId); |
| // } |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcOpenGPTA( |
| mcSessionHandle_t *session, |
| const mcUuid_t *uuid, |
| uint8_t *tci, |
| uint32_t len |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| |
| #ifndef WIN32 |
| devMutex.lock(); |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| BulkBufferDescriptor *bulkBuf = NULL; |
| |
| do { |
| uint32_t handle = 0; |
| CHECK_NOT_NULL(session); |
| CHECK_NOT_NULL(uuid); |
| |
| if (len > MC_MAX_TCI_LEN) { |
| LOG_E("TCI length is longer than %d", MC_MAX_TCI_LEN); |
| mcResult = MC_DRV_ERR_TCI_TOO_BIG; |
| break; |
| } |
| |
| // Get the device associated with the given session |
| Device *device = resolveDeviceId(session->deviceId); |
| CHECK_DEVICE(device); |
| |
| Connection *devCon = device->connection; |
| |
| // First assume the TCI is a contiguous buffer |
| // Get the physical address of the given TCI |
| CWsm_ptr pWsm = device->findContiguousWsm(tci); |
| if (pWsm == NULL) { |
| if (tci != NULL && len != 0) { |
| // Then assume it's a normal buffer that needs to be mapped |
| mcResult = device->mapBulkBuf(tci, len, &bulkBuf); |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("Registering buffer failed. ret=%x", mcResult); |
| mcResult = MC_DRV_ERR_WSM_NOT_FOUND; |
| break; |
| } |
| handle = bulkBuf->handle; |
| } else if ( len != 0 ) { |
| LOG_E("mcOpenSession(): length is more than allocated TCI"); |
| mcResult = MC_DRV_ERR_TCI_GREATER_THAN_WSM; |
| break; |
| } |
| } else { |
| if (pWsm->len < len) { |
| LOG_E("mcOpenSession(): length is more than allocated TCI"); |
| mcResult = MC_DRV_ERR_TCI_GREATER_THAN_WSM; |
| break; |
| } |
| handle = pWsm->handle; |
| } |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_OPEN_TRUSTED_APP, |
| session->deviceId, |
| *uuid, |
| (uint32_t)(tci) & 0xFFF, |
| (uint32_t)handle, |
| len); |
| |
| // Read command response |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| // TODO-2012-09-06-haenellu: Remove this code once tests can handle it |
| |
| if (MC_DRV_ERROR_MAJOR(mcResult) != MC_DRV_ERR_MCP_ERROR) { |
| LOG_E("Daemon could not open session, responseId %d.", mcResult); |
| } else { |
| uint32_t mcpResult = MC_DRV_ERROR_MCP(mcResult); |
| LOG_E("<t-base reported failing of MC_MCP_CMD_OPEN_SESSION command, mcpResult %d.", mcpResult); |
| |
| // IMPROVEMENT-2012-09-03-haenellu: Remove this switch case and use MCP code in tests. |
| switch (mcpResult) { |
| case MC_MCP_RET_ERR_WRONG_PUBLIC_KEY: |
| mcResult = MC_DRV_ERR_WRONG_PUBLIC_KEY; |
| break; |
| case MC_MCP_RET_ERR_CONTAINER_TYPE_MISMATCH: |
| mcResult = MC_DRV_ERR_CONTAINER_TYPE_MISMATCH; |
| break; |
| case MC_MCP_RET_ERR_CONTAINER_LOCKED: |
| mcResult = MC_DRV_ERR_CONTAINER_LOCKED; |
| break; |
| case MC_MCP_RET_ERR_SP_NO_CHILD: |
| mcResult = MC_DRV_ERR_SP_NO_CHILD; |
| break; |
| case MC_MCP_RET_ERR_TL_NO_CHILD: |
| mcResult = MC_DRV_ERR_TL_NO_CHILD; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_ROOT_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_ROOT_FAILED; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_SP_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_SP_FAILED; |
| break; |
| case MC_MCP_RET_ERR_UNWRAP_TRUSTLET_FAILED: |
| mcResult = MC_DRV_ERR_UNWRAP_TRUSTLET_FAILED; |
| break; |
| default: |
| // TODO-2012-09-06-haenellu: Remove line and adapt codes in tests. |
| mcResult = MC_DRV_ERR_MCP_ERROR; |
| break; |
| } |
| } |
| break; // loading of Trustlet failed, unlock mutex and return |
| } |
| |
| // read payload |
| mcDrvRspOpenSessionPayload_t rspOpenSessionPayload; |
| RECV_FROM_DAEMON(devCon, &rspOpenSessionPayload); |
| |
| // Register session with handle |
| session->sessionId = rspOpenSessionPayload.sessionId; |
| |
| LOG_I(" Service is started. Setting up channel for notifications."); |
| |
| // Set up second channel for notifications |
| Connection *sessionConnection = new Connection(); |
| if (!sessionConnection->connect(SOCK_PATH)) { |
| LOG_E("Could not connect to %s", SOCK_PATH); |
| delete sessionConnection; |
| // Here we know we couldn't connect to the Daemon. |
| // Maybe we should use existing connection to close Trustlet. |
| mcResult = MC_DRV_ERR_SOCKET_CONNECT; |
| break; |
| } |
| |
| do { |
| SEND_TO_DAEMON(sessionConnection, MC_DRV_CMD_NQ_CONNECT, |
| session->deviceId, |
| session->sessionId, |
| rspOpenSessionPayload.deviceSessionId, |
| rspOpenSessionPayload.sessionMagic); |
| |
| RECV_FROM_DAEMON(sessionConnection, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("CMD_NQ_CONNECT failed, respId=%d", mcResult); |
| break; |
| } |
| |
| } while (0); |
| if (mcResult != MC_DRV_OK) { |
| delete sessionConnection; |
| // Here we know we couldn't communicate well with the Daemon. |
| // Maybe we should use existing connection to close Trustlet. |
| break; // unlock mutex and return |
| } |
| |
| // there is no payload. |
| |
| // Session has been established, new session object must be created |
| Session *sessionObj = device->createNewSession(session->sessionId, sessionConnection); |
| // If the session tci was a mapped buffer then register it |
| if (bulkBuf) |
| sessionObj->addBulkBuf(bulkBuf); |
| |
| LOG_I(" Successfully opened session %d.", session->sessionId); |
| |
| } while (false); |
| |
| if (mcResult != MC_DRV_OK && bulkBuf) { |
| delete bulkBuf; |
| } |
| |
| // TODO: enable as soon as there are more error codes |
| // if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { |
| // LOG_E("Connection is dead, removing device."); |
| // removeDevice(session->deviceId); |
| // } |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcCloseSession(mcSessionHandle_t *session) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| LOG_I("===%s()===", __FUNCTION__); |
| devMutex.lock(); |
| do { |
| CHECK_NOT_NULL(session); |
| LOG_I(" Closing session %d.", session->sessionId); |
| |
| Device *device = resolveDeviceId(session->deviceId); |
| CHECK_DEVICE(device); |
| |
| Connection *devCon = device->connection; |
| |
| Session *nqSession = device->resolveSessionId(session->sessionId); |
| |
| CHECK_SESSION(nqSession, session->sessionId); |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_CLOSE_SESSION, session->sessionId); |
| |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("CMD_CLOSE_SESSION failed, respId=%d", mcResult); |
| // TODO-2012-08-03-haenellu: Remove once tests can handle it. |
| mcResult = MC_DRV_ERR_UNKNOWN_DEVICE; |
| break; |
| } |
| |
| bool r = device->removeSession(session->sessionId); |
| if (!r) |
| { |
| LOG_E("removeSession failed"); |
| assert(0); |
| } |
| |
| |
| |
| } while (false); |
| |
| if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { |
| LOG_E("Connection is dead, removing device."); |
| removeDevice(session->deviceId); |
| } |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcNotify( |
| mcSessionHandle_t *session |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| devMutex.lock(); |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| do { |
| CHECK_NOT_NULL(session); |
| LOG_I(" Notifying session %d.", session->sessionId); |
| |
| Device *device = resolveDeviceId(session->deviceId); |
| CHECK_DEVICE(device); |
| |
| Connection *devCon = device->connection; |
| |
| Session *nqsession = device->resolveSessionId(session->sessionId); |
| CHECK_SESSION(nqsession, session->sessionId); |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_NOTIFY, session->sessionId); |
| // Daemon will not return a response |
| } while (false); |
| |
| if (mcResult == MC_DRV_ERR_SOCKET_WRITE) { |
| LOG_E("Connection is dead, removing device."); |
| removeDevice(session->deviceId); |
| } |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcWaitNotification( |
| mcSessionHandle_t *session, |
| int32_t timeout |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| // TODO-2012-11-02-gurel: devMutex locking and unlocking had to be commented out |
| // below. Otherwise, when there are multiple threads in Nwd TLC side, we endup a |
| // deadlock situation, e.g. one thread waits for notification and another one sends |
| // notification. |
| |
| //devMutex.lock(); |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| do { |
| CHECK_NOT_NULL(session); |
| LOG_I(" Waiting for notification of session %d.", session->sessionId); |
| |
| Device *device = resolveDeviceId(session->deviceId); |
| CHECK_DEVICE(device); |
| |
| Session *nqSession = device->resolveSessionId(session->sessionId); |
| CHECK_SESSION(nqSession, session->sessionId); |
| |
| Connection *nqconnection = nqSession->notificationConnection; |
| uint32_t count = 0; |
| |
| // Read notification queue till it's empty |
| for (;;) { |
| notification_t notification; |
| ssize_t numRead = nqconnection->readData( |
| ¬ification, |
| sizeof(notification_t), |
| timeout); |
| //Exit on timeout in first run |
| //Later runs have timeout set to 0. -2 means, there is no more data. |
| if (count == 0 && numRead == -2 ) { |
| LOG_W("Timeout hit at %s", __FUNCTION__); |
| mcResult = MC_DRV_ERR_TIMEOUT; |
| break; |
| } |
| if (count == 0 && numRead == 0 ) { |
| LOG_E("Connection is dead, removing device."); |
| removeDevice(session->deviceId); |
| mcResult = MC_DRV_ERR_NOTIFICATION; |
| break; |
| } |
| // After first notification the queue will be drained, Thus we set |
| // no timeout for the following reads |
| timeout = 0; |
| |
| if (numRead != sizeof(notification_t)) { |
| if (count == 0) { |
| //failure in first read, notify it |
| mcResult = MC_DRV_ERR_NOTIFICATION; |
| LOG_E("read notification failed, %i bytes received", (int)numRead); |
| break; |
| } else { |
| // Read of the n-th notification failed/timeout. We don't tell the |
| // caller, as we got valid notifications before. |
| mcResult = MC_DRV_OK; |
| break; |
| } |
| } |
| |
| count++; |
| LOG_I(" Received notification %d for session %d, payload=%d", |
| count, notification.sessionId, notification.payload); |
| |
| if (notification.payload != 0) { |
| // Session end point died -> store exit code |
| nqSession->setErrorInfo(notification.payload); |
| |
| mcResult = MC_DRV_INFO_NOTIFICATION; |
| break; |
| } |
| } // for(;;) |
| |
| } while (false); |
| |
| //devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcMallocWsm( |
| uint32_t deviceId, |
| uint32_t align, |
| uint32_t len, |
| uint8_t **wsm, |
| uint32_t wsmFlags) |
| { |
| mcResult_t mcResult = MC_DRV_ERR_UNKNOWN; |
| #ifndef WIN32 |
| |
| LOG_I("===%s(len=%i)===", __FUNCTION__, len); |
| |
| devMutex.lock(); |
| |
| do { |
| Device *device = resolveDeviceId(deviceId); |
| |
| // Is the device known |
| // CHECK_DEVICE(device); |
| |
| // Is the device opened. |
| CHECK_DEVICE_CLOSED(device, deviceId) |
| |
| CHECK_NOT_NULL(wsm); |
| |
| CWsm_ptr pWsm; |
| mcResult = device->allocateContiguousWsm(len, &pWsm); |
| if (mcResult != MC_DRV_OK) { |
| LOG_W(" Allocation of WSM failed"); |
| break; |
| } |
| |
| *wsm = (uint8_t *)pWsm->virtAddr; |
| mcResult = MC_DRV_OK; |
| |
| } while (false); |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcFreeWsm( |
| uint32_t deviceId, |
| uint8_t *wsm |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_ERR_UNKNOWN; |
| #ifndef WIN32 |
| |
| Device *device; |
| |
| devMutex.lock(); |
| |
| LOG_I("===%s(%p)===", __FUNCTION__, wsm); |
| |
| do { |
| |
| // Get the device associated wit the given session |
| device = resolveDeviceId(deviceId); |
| |
| // Is the device known |
| CHECK_DEVICE(device); |
| |
| // Is the device opened. |
| CHECK_DEVICE_CLOSED(device, deviceId) |
| |
| // find WSM object |
| CWsm_ptr pWsm = device->findContiguousWsm(wsm); |
| if (pWsm == NULL) { |
| LOG_E("address is unknown to mcFreeWsm"); |
| mcResult = MC_DRV_ERR_WSM_NOT_FOUND; |
| break; |
| } |
| |
| // Free the given virtual address |
| mcResult = device->freeContiguousWsm(pWsm); |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("Free of virtual address failed"); |
| break; |
| } |
| mcResult = MC_DRV_OK; |
| |
| } while (false); |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcMap( |
| mcSessionHandle_t *sessionHandle, |
| void *buf, |
| uint32_t bufLen, |
| mcBulkMap_t *mapInfo |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_ERR_UNKNOWN; |
| #ifndef WIN32 |
| |
| static CMutex mutex; |
| |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| devMutex.lock(); |
| |
| do { |
| CHECK_NOT_NULL(sessionHandle); |
| CHECK_NOT_NULL(mapInfo); |
| CHECK_NOT_NULL(buf); |
| |
| // Determine device the session belongs to |
| Device *device = resolveDeviceId(sessionHandle->deviceId); |
| // Is the device known |
| CHECK_DEVICE(device); |
| |
| // Is the device opened. |
| CHECK_DEVICE_CLOSED(device, sessionHandle->deviceId) |
| |
| Connection *devCon = device->connection; |
| |
| // Get session |
| Session *session = device->resolveSessionId(sessionHandle->sessionId); |
| CHECK_SESSION(session, sessionHandle->sessionId); |
| |
| LOG_I(" Mapping %p to session %d.", buf, sessionHandle->sessionId); |
| |
| // Register mapped bulk buffer to Kernel Module and keep mapped bulk buffer in mind |
| BulkBufferDescriptor *bulkBuf; |
| mcResult = session->addBulkBuf(buf, bufLen, &bulkBuf); |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("Registering buffer failed. ret=%x", mcResult); |
| break; |
| } |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_MAP_BULK_BUF, |
| session->sessionId, |
| (uint32_t)bulkBuf->handle, |
| (uint32_t)0, |
| (uint32_t)(bulkBuf->virtAddr) & 0xFFF, |
| bulkBuf->len); |
| |
| // Read command response |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("CMD_MAP_BULK_BUF failed, respId=%d", mcResult); |
| // TODO-2012-09-06-haenellu: Remove once tests can handle it. |
| mcResult = MC_DRV_ERR_DAEMON_UNREACHABLE; |
| |
| // Unregister mapped bulk buffer from Kernel Module and remove mapped |
| // bulk buffer from session maintenance |
| if (session->removeBulkBuf(buf) != MC_DRV_OK) { |
| // Removing of bulk buffer not possible |
| LOG_E("Unregistering of bulk memory from Kernel Module failed"); |
| } |
| break; |
| } |
| |
| mcDrvRspMapBulkMemPayload_t rspMapBulkMemPayload; |
| RECV_FROM_DAEMON(devCon, &rspMapBulkMemPayload); |
| |
| // Set mapping info for internal structures |
| bulkBuf->sVirtualAddr = (void *)rspMapBulkMemPayload.secureVirtualAdr; |
| // Set mapping info for Trustlet |
| mapInfo->sVirtualAddr = bulkBuf->sVirtualAddr; |
| mapInfo->sVirtualLen = bufLen; |
| mcResult = MC_DRV_OK; |
| |
| } while (false); |
| |
| // // TODO: enable as soon as there are more error codes |
| // if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { |
| // LOG_E("Connection is dead, removing device."); |
| // removeDevice(sessionHandle->deviceId); |
| // } |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcUnmap( |
| mcSessionHandle_t *sessionHandle, |
| void *buf, |
| mcBulkMap_t *mapInfo |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_ERR_UNKNOWN; |
| #ifndef WIN32 |
| |
| static CMutex mutex; |
| |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| devMutex.lock(); |
| |
| do { |
| CHECK_NOT_NULL(sessionHandle); |
| CHECK_NOT_NULL(mapInfo); |
| CHECK_NOT_NULL(mapInfo->sVirtualAddr); |
| CHECK_NOT_NULL(buf); |
| |
| // Determine device the session belongs to |
| Device *device = resolveDeviceId(sessionHandle->deviceId); |
| // Is the device known |
| CHECK_DEVICE(device); |
| |
| // Is the device opened. |
| CHECK_DEVICE_CLOSED(device, sessionHandle->deviceId) |
| |
| Connection *devCon = device->connection; |
| |
| // Get session |
| Session *session = device->resolveSessionId(sessionHandle->sessionId); |
| CHECK_SESSION(session, sessionHandle->sessionId); |
| |
| uint32_t handle = session->getBufHandle(mapInfo->sVirtualAddr, mapInfo->sVirtualLen); |
| if (handle == 0) { |
| LOG_E("Unable to find internal handle for buffer %p.", mapInfo->sVirtualAddr); |
| mcResult = MC_DRV_ERR_BLK_BUFF_NOT_FOUND; |
| break; |
| } |
| |
| LOG_I(" Unmapping %p(handle=%u) from session %d.", buf, handle, sessionHandle->sessionId); |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_UNMAP_BULK_BUF, |
| session->sessionId, |
| handle, |
| (uint32_t)(mapInfo->sVirtualAddr), |
| mapInfo->sVirtualLen); |
| |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("Daemon reported failing of UNMAP BULK BUF command, responseId %d.", mcResult); |
| // TODO-2012-09-06-haenellu: Remove once tests can handle it. |
| mcResult = MC_DRV_ERR_DAEMON_UNREACHABLE; |
| break; |
| } |
| |
| // Unregister mapped bulk buffer from Kernel Module and remove mapped |
| // bulk buffer from session maintenance |
| mcResult = session->removeBulkBuf(buf); |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("Unregistering of bulk memory from Kernel Module failed."); |
| break; |
| } |
| |
| mcResult = MC_DRV_OK; |
| |
| } while (false); |
| |
| if (mcResult == MC_DRV_ERR_SOCKET_WRITE || mcResult == MC_DRV_ERR_SOCKET_READ) { |
| LOG_E("Connection is dead, removing device."); |
| removeDevice(sessionHandle->deviceId); |
| } |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcGetSessionErrorCode( |
| mcSessionHandle_t *session, |
| int32_t *lastErr |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| devMutex.lock(); |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| do { |
| CHECK_NOT_NULL(session); |
| CHECK_NOT_NULL(lastErr); |
| |
| // Get device |
| Device *device = resolveDeviceId(session->deviceId); |
| // Is the device known |
| CHECK_DEVICE(device); |
| |
| // Is the device opened. |
| CHECK_DEVICE_CLOSED(device, session->deviceId) |
| |
| // Get session |
| Session *nqsession = device->resolveSessionId(session->sessionId); |
| CHECK_SESSION(nqsession, session->sessionId); |
| |
| // get session error code from session |
| *lastErr = nqsession->getLastErr(); |
| |
| } while (false); |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcDriverCtrl( |
| mcDriverCtrl_t param, |
| uint8_t *data, |
| uint32_t len |
| ) |
| { |
| #ifndef WIN32 |
| |
| LOG_W("mcDriverCtrl(): not implemented"); |
| |
| #endif /* WIN32 */ |
| return MC_DRV_ERR_NOT_IMPLEMENTED; |
| } |
| |
| //------------------------------------------------------------------------------ |
| __MC_CLIENT_LIB_API mcResult_t mcGetMobiCoreVersion( |
| uint32_t deviceId, |
| mcVersionInfo_t *versionInfo |
| ) |
| { |
| mcResult_t mcResult = MC_DRV_OK; |
| #ifndef WIN32 |
| |
| devMutex.lock(); |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| do { |
| Device *device = resolveDeviceId(deviceId); |
| |
| // Is the device known |
| CHECK_DEVICE(device); |
| |
| // Is the device opened. |
| CHECK_DEVICE_CLOSED(device, deviceId) |
| |
| CHECK_NOT_NULL(versionInfo); |
| |
| Connection *devCon = device->connection; |
| |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_GET_MOBICORE_VERSION); |
| |
| // Read GET MOBICORE VERSION response. |
| |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("MC_DRV_CMD_GET_MOBICORE_VERSION bad response, respId=%d", mcResult); |
| // TODO-2012-09-06-haenellu: Remove once tests can handle it. |
| mcResult = MC_DRV_ERR_DAEMON_UNREACHABLE; |
| break; |
| } |
| |
| // Read payload. |
| mcVersionInfo_t versionInfo_socket; |
| RECV_FROM_DAEMON(devCon, &versionInfo_socket); |
| |
| *versionInfo = versionInfo_socket; |
| |
| } while (0); |
| |
| devMutex.unlock(); |
| |
| #endif /* WIN32 */ |
| return mcResult; |
| } |
| |
| #ifndef WIN32 |
| //------------------------------------------------------------------------------ |
| // Only called by mcOpenDevice() |
| // Must be taken with devMutex locked. |
| uint32_t getDaemonVersion(Connection *devCon, uint32_t *version) |
| { |
| assert(devCon != NULL); |
| assert(version != NULL); |
| mcResult_t mcResult = MC_DRV_OK; |
| uint32_t v = 0; |
| |
| LOG_I("===%s()===", __FUNCTION__); |
| |
| do { |
| SEND_TO_DAEMON(devCon, MC_DRV_CMD_GET_VERSION); |
| |
| RECV_FROM_DAEMON(devCon, &mcResult); |
| |
| if (mcResult != MC_DRV_OK) { |
| LOG_E("MC_DRV_CMD_GET_VERSION bad response, respId=%d", mcResult); |
| // version is still 0, we don't further analyze response here. |
| break; |
| } |
| |
| RECV_FROM_DAEMON(devCon, &v); |
| |
| } while (0); |
| |
| if (mcResult == MC_DRV_OK) { |
| *version = v; |
| } |
| |
| return mcResult; |
| } |
| #endif /* WIN32 */ |
| |
| /** @} */ |