//------------------------------------------------------------------------------
void MobiCoreDriverDaemon::processNqConnect(
    Connection  *connection
) {
	do
	{
		// Set up the channel for sending SWd notifications to the client
		// MC_DRV_CMD_NQ_CONNECT is only allowed on new connections not
		// associated with a device. If a device is registered to the
		// connection NQ_CONNECT is not allowed.

		// Read entire command data
		mcDrvCmdNqConnectPayload_t  cmdNqConnectPayload;
		size_t rlen = connection->readData(
										&(cmdNqConnectPayload),
										sizeof(cmdNqConnectPayload));
		if (rlen != sizeof(cmdNqConnectPayload))
		{
			LOG_E("processNqConnect(): NqConnect length error: %d",rlen);
			writeResult(connection,MC_DRV_RSP_PAYLOAD_LENGTH_ERROR);
			break;
		}

		// device must be empty
		MobiCoreDevice *device = (MobiCoreDevice *)(connection->connectionData);
		if (NULL != device)
		{
			LOG_E("processNqConnect(): device already set\n");
			writeResult(connection,MC_DRV_RSP_COMMAND_NOT_ALLOWED);
			break;
		}

		// Remove the connection from the list of known client connections
		for (int i = 0; i < MAX_SERVERS; i++) {
			servers[i]->detachConnection(connection);
		}

		device = getDevice(cmdNqConnectPayload.deviceId);
		if (NULL == device)
		{
			//TODO xgal: how about ...NO_SUCH_DEVICE
			LOG_E("processNqConnect(): no device found\n");
			writeResult(connection, MC_DRV_RSP_FAILED);
			break;
		}

		TrustletSession* ts = device->registerTrustletConnection(
								connection,
								&cmdNqConnectPayload);
		if (!ts) {
			LOG_E("processNqConnect(): registerTrustletConnection() failed!");
			writeResult(connection, MC_DRV_RSP_FAILED);
			break;
		}

		writeResult(connection, MC_DRV_RSP_OK);
		ts->processQueuedNotifications();
		

	} while (false);
}
//------------------------------------------------------------------------------
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;
}
//------------------------------------------------------------------------------
void MobiCoreDriverDaemon::processNqConnect(Connection *connection)
{
    // Set up the channel for sending SWd notifications to the client
    // MC_DRV_CMD_NQ_CONNECT is only allowed on new connections not
    // associated with a device. If a device is registered to the
    // connection NQ_CONNECT is not allowed.

    // Read entire command data
    MC_DRV_CMD_NQ_CONNECT_struct cmd;
    RECV_PAYLOAD_FROM_CLIENT(connection, &cmd);

    // device must be empty since this is a new connection
    MobiCoreDevice *device = (MobiCoreDevice *)(connection->connectionData);
    if (device != NULL) {
        LOG_E("device already set\n");
        writeResult(connection, MC_DRV_ERR_NQ_FAILED);
        return;
    }

    // Remove the connection from the list of known client connections
    for (int i = 0; i < MAX_SERVERS; i++) {
        servers[i]->detachConnection(connection);
    }

    device = getDevice(cmd.deviceId);
    // Check if a device for the given name has been found
    if (NULL == device) {
        LOG_E("invalid deviceId");
        writeResult(connection, MC_DRV_ERR_UNKNOWN_DEVICE);
        return;
    }

    TrustletSession *ts = device->registerTrustletConnection(
                              connection,
                              &cmd);
    if (!ts) {
        LOG_E("registerTrustletConnection() failed!");
        writeResult(connection, MC_DRV_ERR_UNKNOWN);
        return;
    }

    writeResult(connection, MC_DRV_OK);
    ts->processQueuedNotifications();
}
//------------------------------------------------------------------------------
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;
}
//------------------------------------------------------------------------------
mcResult_t MobiCoreDevice::openSession(
    Connection                      *deviceConnection,
    loadDataOpenSession_ptr         pLoadDataOpenSession,
    MC_DRV_CMD_OPEN_SESSION_struct  *cmdOpenSession,
    mcDrvRspOpenSessionPayload_ptr  pRspOpenSessionPayload
)
{
    do {
        addr_t tci;
        uint32_t len;
        uint32_t handle = cmdOpenSession->handle;

        if (!findContiguousWsm(handle, &tci, &len)) {
            LOG_E("Failed to find contiguous WSM %u", handle);
            return MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND;
        }

        if (!lockWsmL2(handle)) {
            LOG_E("Failed to lock contiguous WSM %u", handle);
            return MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND;
        }

        // Write MCP open message to buffer
        mcpMessage->cmdOpen.cmdHeader.cmdId = MC_MCP_CMD_OPEN_SESSION;
        mcpMessage->cmdOpen.uuid = cmdOpenSession->uuid;
        mcpMessage->cmdOpen.wsmTypeTci = WSM_CONTIGUOUS;
        mcpMessage->cmdOpen.adrTciBuffer = (uint32_t)(tci);
        mcpMessage->cmdOpen.ofsTciBuffer = 0;
        mcpMessage->cmdOpen.lenTciBuffer = len;

        LOG_I(" Using phys=%p, len=%d as TCI buffer",
              (addr_t)(cmdOpenSession->tci),
              cmdOpenSession->len);

        // check if load data is provided
        mcpMessage->cmdOpen.wsmTypeLoadData = WSM_L2;
        mcpMessage->cmdOpen.adrLoadData = (uint32_t)pLoadDataOpenSession->baseAddr;
        mcpMessage->cmdOpen.ofsLoadData = pLoadDataOpenSession->offs;
        mcpMessage->cmdOpen.lenLoadData = pLoadDataOpenSession->len;
        memcpy(&mcpMessage->cmdOpen.tlHeader, pLoadDataOpenSession->tlHeader, sizeof(*pLoadDataOpenSession->tlHeader));

        // Clear the notifications queue. We asume the race condition we have
        // seen in openSession never happens elsewhere
        notifications = std::queue<notification_t>();
        // Notify MC about a new command inside the MCP buffer
        notify(SID_MCP);

        // Wait till response from MC is available
        if (!waitMcpNotification()) {
            // Here Mobicore can be considered dead.
            unlockWsmL2(handle);
            return MC_DRV_ERR_DAEMON_MCI_ERROR;
        }

        // Check if the command response ID is correct
        if ((MC_MCP_CMD_OPEN_SESSION | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
            LOG_E("CMD_OPEN_SESSION got invalid MCP command response(0x%X)", mcpMessage->rspHeader.rspId);
            // Something is messing with our MCI memory, we cannot know if the Trustlet was loaded.
            // Had in been loaded, we are loosing track of it here.
            unlockWsmL2(handle);
            return MC_DRV_ERR_DAEMON_MCI_ERROR;
        }

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

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

        LOG_I(" After MCP OPEN, we have %d queued notifications",
              notifications.size());
        // Read MC answer from MCP buffer
        TrustletSession *trustletSession = new TrustletSession(
            deviceConnection,
            mcpMessage->rspOpen.sessionId);

        pRspOpenSessionPayload->sessionId = trustletSession->sessionId;
        pRspOpenSessionPayload->deviceSessionId = (uint32_t)trustletSession;
        pRspOpenSessionPayload->sessionMagic = trustletSession->sessionMagic;

        trustletSessions.push_back(trustletSession);

        trustletSession->addBulkBuff(new CWsm((void *)pLoadDataOpenSession->offs, pLoadDataOpenSession->len, handle, 0));

        // We have some queued notifications and we need to send them to them
        // trustlet session
        while (!notifications.empty()) {
            trustletSession->queueNotification(&notifications.front());
            notifications.pop();
        }

    } while (0);
    return MC_DRV_OK;
}