//------------------------------------------------------------------------------
Connection *MobiCoreDevice::getSessionConnection(uint32_t sessionId, notification_t *notification)
{
    Connection *con = NULL;
    TrustletSession *ts = NULL;

    ts = getTrustletSession(sessionId);
    if (ts == NULL) {
        return NULL;
    }

    con = ts->notificationConnection;
    if (con == NULL) {
        ts->queueNotification(notification);
        return NULL;
    }

    return con;
}
//------------------------------------------------------------------------------
mcResult_t MobiCoreDevice::unmapBulk(uint32_t sessionId, uint32_t handle,
                                     uint32_t secureVirtualAdr, uint32_t lenBulkMem)
{
    TrustletSession *ts = getTrustletSession(sessionId);
    if (ts == NULL) {
        LOG_E("no session found with id=%d", sessionId);
        return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
    }

    // Write MCP unmap command to buffer
    mcpMessage->cmdUnmap.cmdHeader.cmdId = MC_MCP_CMD_UNMAP;
    mcpMessage->cmdUnmap.sessionId = sessionId;
    mcpMessage->cmdUnmap.wsmType = WSM_L2;
    mcpMessage->cmdUnmap.secureVirtualAdr = secureVirtualAdr;
    mcpMessage->cmdUnmap.lenVirtualBuffer = lenBulkMem;

    // Notify MC about the availability of a new command inside the MCP buffer
    notify(SID_MCP);

    // Wait till response from MC is available
    if (!waitMcpNotification()) {
        return MC_DRV_ERR_DAEMON_MCI_ERROR;
    }

    // Check if the command response ID is correct
    if (mcpMessage->rspHeader.rspId != (MC_MCP_CMD_UNMAP | FLAG_RESPONSE)) {
        LOG_E("CMD_OPEN_SESSION got invalid MCP response");
        return MC_DRV_ERR_DAEMON_MCI_ERROR;
    }

    uint32_t mcRet = mcpMessage->rspUnmap.rspHeader.result;

    if (mcRet != MC_MCP_RET_OK) {
        LOG_E("MCP UNMAP returned code %d.", mcRet);
        return MAKE_MC_DRV_MCP_ERROR(mcRet);
    } else {
        // Just remove the buffer
        // TODO-2012-09-06-haenellu: Haven't we removed it already?
        if (!ts->removeBulkBuff(handle))
            LOG_I("unmapBulk(): no buffer found found with handle=%u", handle);
    }

    return MC_DRV_OK;
}
//------------------------------------------------------------------------------
mcResult_t MobiCoreDevice::mapBulk(uint32_t sessionId, uint32_t handle, uint32_t pAddrL2,
                                   uint32_t offsetPayload, uint32_t lenBulkMem, uint32_t *secureVirtualAdr)
{
    TrustletSession *ts = getTrustletSession(sessionId);
    if (ts == NULL) {
        LOG_E("no session found with id=%d", sessionId);
        return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
    }

    // TODO-2012-09-06-haenellu: Think about not ignoring the error case, ClientLib does not allow this.
    ts->addBulkBuff(new CWsm((void *)offsetPayload, lenBulkMem, handle, (void *)pAddrL2));
    // Write MCP map message to buffer
    mcpMessage->cmdMap.cmdHeader.cmdId = MC_MCP_CMD_MAP;
    mcpMessage->cmdMap.sessionId = sessionId;
    mcpMessage->cmdMap.wsmType = WSM_L2;
    mcpMessage->cmdMap.adrBuffer = (uint32_t)(pAddrL2);
    mcpMessage->cmdMap.ofsBuffer = offsetPayload;
    mcpMessage->cmdMap.lenBuffer = lenBulkMem;

    // Notify MC about the availability of a new command inside the MCP buffer
    notify(SID_MCP);

    // Wait till response from MC is available
    if (!waitMcpNotification()) {
        return MC_DRV_ERR_DAEMON_MCI_ERROR;
    }

    // Check if the command response ID is correct
    if (mcpMessage->rspHeader.rspId != (MC_MCP_CMD_MAP | FLAG_RESPONSE)) {
        LOG_E("CMD_MAP got invalid MCP response");
        return MC_DRV_ERR_DAEMON_MCI_ERROR;
    }

    uint32_t mcRet = mcpMessage->rspMap.rspHeader.result;

    if (mcRet != MC_MCP_RET_OK) {
        LOG_E("MCP MAP returned code %d.", mcRet);
        return MAKE_MC_DRV_MCP_ERROR(mcRet);
    }

    *secureVirtualAdr = mcpMessage->rspMap.secureVirtualAdr;
    return MC_DRV_OK;
}
/**
 * TODO-2012-09-19-haenellu: Do some more checks here, otherwise rogue clientLib
 * can close sessions from different TLCs. That is, deviceConnection is ignored below.
 *
 * Need connection as well as according session ID, so that a client can not
 * close sessions not belonging to him.
 */
mcResult_t MobiCoreDevice::closeSession(Connection *deviceConnection, uint32_t sessionId)
{
    TrustletSession *ts = getTrustletSession(sessionId);
    if (ts == NULL) {
        LOG_E("no session found with id=%d", sessionId);
        return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
    }

    uint32_t mcRet = closeSession(sessionId);
    if (mcRet != MC_DRV_OK) {
        return mcRet;
    }

    // remove objects
    removeTrustletSession(sessionId);
    delete ts;

    return MC_DRV_OK;
}
//------------------------------------------------------------------------------
void TrustZoneDevice::notify(
    uint32_t sessionId
)
{
    // Check if it is MCP session - handle openSession() command
    if (sessionId != SID_MCP) {
        // Check if session ID exists to avoid flooding of nq by clients
        TrustletSession *ts = getTrustletSession(sessionId);
        if (ts == NULL) {
            LOG_E("no session with id=%d", sessionId);
            return;
        }

        LOG_I(" Sending notification for session %d to MobiCore", sessionId);
    } else {
        LOG_I(" Sending MCP notification to MobiCore");
    }

    // Notify MobiCore about new data

    notification_t notification = {
        .sessionId = sessionId,
        .payload = 0
    };

    nq->putNotification(&notification);
    //IMPROVEMENT-2012-03-07-maneaval What happens when/if nsiq fails?
    //In the old days an exception would be thrown but it was uncertain
    //where it was handled, some server(sock or Netlink). In that case
    //the server would just die but never actually signaled to the client
    //any error condition
    nsiq();
}

//------------------------------------------------------------------------------
uint32_t TrustZoneDevice::getMobicoreStatus(void)
{
    uint32_t status;

    pMcKMod->fcInfo(1, &status, NULL);

    return status;
}
//------------------------------------------------------------------------------
void TrustZoneDevice::notify(
    uint32_t sessionId
) {
	do
	{
        // Check if it is MCP session - handle openSession() command
        if (SID_MCP != sessionId)
        {
            // Check if session ID exists to avoid flooding of nq by clients
            TrustletSession* ts = getTrustletSession(sessionId);
            if (NULL == ts)
            {
                LOG_E("notify(): no session with id=%d", sessionId);
                break;
            }
        }

		LOG_I("notify(): Send notification for id=%d", sessionId);
        // Notify MobiCore about new data

        notification_t notification = {
                // C++ does not support C99 designated initializers
                    /* .sessionId = */ sessionId,
                    /* .payload = */ 0
                };

        nq->putNotification(&notification);
        //IMPROVEMENT-2012-03-07-maneaval What happens when/if nsiq fails?
        //In the old days an exception would be thrown but it was uncertain
        //where it was handled, some server(sock or Netlink). In that case
        //the server would just die but never actually signaled to the client
        //any error condition
		nsiq();

	} while(0);
}