#define MODULE_LOG_PREFIX "emu"

#include "globals.h"

#ifdef WITH_EMU

#include "module-streamrelay.h"
#include "module-emulator-osemu.h"
#include "module-emulator-biss.h"
#include "module-emulator-irdeto.h"
#include "module-emulator-powervu.h"
#include "oscam-conf-chk.h"
#include "oscam-config.h"
#include "oscam-reader.h"
#include "oscam-string.h"

/*
 * Readers in OSCam consist of 2 basic parts.
 * The hardware or the device part. This is where physical smart cards are inserted
 * and made available to OSCam.
 * The software or the emulation part. This is where the actual card reading is done,
 * including ecm and emm processing (i.e emulation of the various cryptosystems).
 * In the Emu reader, the device part has no meaning, but we have to create it in
 * order to be compatible with OSCam's reader structure.
*/

/*
 * Create the Emu "emulation" part. This is of type s_cardsystem.
 * Similar structures are found in the main sources folder (files reader-xxxxxx.c)
 * for every cryptosystem supported by OSCam.
 * Here we read keys from our virtual card (aka the SoftCam.Key file) and we inform
 * OSCam about them. This is done with the emu_card_info() function. Keep in mind
 * that Emu holds all its keys to separate structures for faster access.
 * In addition, ECM and EMM requests are processed here, with the emu_do_ecm() and
 * emu_do_emm() functions.
*/

#define CS_OK    1
#define CS_ERROR 0

extern char cs_confdir[128];
#ifdef MODULE_STREAMRELAY
static int8_t emu_key_data_mutex_init = 0;
#endif
pthread_mutex_t emu_key_data_mutex;

static void set_hexserial_to_version(struct s_reader *rdr)
{
	char cVersion[32];
	uint32_t version = EMU_VERSION;
	uint8_t hversion[2];
	memset(hversion, 0, 2);
	snprintf(cVersion, sizeof(cVersion), "%04d", version);
	char_to_bin(hversion, cVersion, 4);
	rdr->hexserial[3] = hversion[0];
	rdr->hexserial[4] = hversion[1];
}

static void set_prids(struct s_reader *rdr)
{
	int32_t i, j;

	rdr->nprov = 0;

	for (i = 0; (i < rdr->emu_auproviders.nfilts) && (rdr->nprov < CS_MAXPROV); i++)
	{
		for (j = 0; (j < rdr->emu_auproviders.filts[i].nprids) && (rdr->nprov < CS_MAXPROV); j++)
		{
			i2b_buf(4, rdr->emu_auproviders.filts[i].prids[j], rdr->prid[i]);
			rdr->nprov++;
		}
	}
}

static void emu_add_entitlement(struct s_reader *rdr, uint16_t caid, uint32_t provid, uint8_t *key, char *keyName, uint32_t keyLength, uint8_t isData)
{
	if (!rdr->ll_entitlements)
	{
		rdr->ll_entitlements = ll_create("ll_entitlements");
	}

	S_ENTITLEMENT *item;
	if (cs_malloc(&item, sizeof(S_ENTITLEMENT)))
	{
		// fill item
		item->caid = caid;
		item->provid = provid;
		item->id = 0;
		item->class = 0;
		item->start = 0;
		item->end = 2147472000;
		item->type = 0;
		item->isKey = 1;
		memcpy(item->name, keyName, 8);
		item->key = key;
		item->keyLength = keyLength;
		item->isData = isData;

		// add item
		ll_append(rdr->ll_entitlements, item);
	}
}

static void refresh_entitlements(struct s_reader *rdr)
{
	uint32_t i;
	uint16_t caid;
	KeyData *tmpKeyData;
	LL_ITER itr;
	biss2_rsa_key_t *item;

	cs_clear_entitlement(rdr);

	for (i = 0; i < StreamKeys.keyCount; i++)
	{
		emu_add_entitlement(rdr, b2i(2, StreamKeys.EmuKeys[i].key), StreamKeys.EmuKeys[i].provider, StreamKeys.EmuKeys[i].key,
							StreamKeys.EmuKeys[i].keyName, StreamKeys.EmuKeys[i].keyLength, 1);
	}

	for (i = 0; i < ViKeys.keyCount; i++)
	{
		emu_add_entitlement(rdr, 0x0500, ViKeys.EmuKeys[i].provider, ViKeys.EmuKeys[i].key,
							ViKeys.EmuKeys[i].keyName, ViKeys.EmuKeys[i].keyLength, 0);
	}

	for (i = 0; i < IrdetoKeys.keyCount; i++)
	{
		tmpKeyData = &IrdetoKeys.EmuKeys[i];
		do
		{
			emu_add_entitlement(rdr, tmpKeyData->provider >> 8, tmpKeyData->provider & 0xFF,
								tmpKeyData->key, tmpKeyData->keyName, tmpKeyData->keyLength, 0);

			tmpKeyData = tmpKeyData->nextKey;
		}
		while (tmpKeyData != NULL);
	}

	for (i = 0; i < CwKeys.keyCount; i++)
	{
		emu_add_entitlement(rdr, CwKeys.EmuKeys[i].provider >> 8, CwKeys.EmuKeys[i].provider & 0xFF,
							CwKeys.EmuKeys[i].key, CwKeys.EmuKeys[i].keyName, CwKeys.EmuKeys[i].keyLength, 0);
	}

	for (i = 0; i < PowervuKeys.keyCount; i++)
	{
		emu_add_entitlement(rdr, 0x0E00, PowervuKeys.EmuKeys[i].provider, PowervuKeys.EmuKeys[i].key,
							PowervuKeys.EmuKeys[i].keyName, PowervuKeys.EmuKeys[i].keyLength, 0);
	}

	for (i = 0; i < TandbergKeys.keyCount; i++)
	{
		emu_add_entitlement(rdr, 0x1010, TandbergKeys.EmuKeys[i].provider, TandbergKeys.EmuKeys[i].key,
							TandbergKeys.EmuKeys[i].keyName, TandbergKeys.EmuKeys[i].keyLength, 0);
	}

	for (i = 0; i < NagraKeys.keyCount; i++)
	{
		emu_add_entitlement(rdr, 0x1801, NagraKeys.EmuKeys[i].provider, NagraKeys.EmuKeys[i].key,
							NagraKeys.EmuKeys[i].keyName, NagraKeys.EmuKeys[i].keyLength, 0);
	}

	// Session words for BISS1 mode 1/E (caid 2600) and BISS2 mode 1/E (caid 2602)
	for (i = 0; i < BissSWs.keyCount; i++)
	{
		caid = (BissSWs.EmuKeys[i].keyLength == 8) ? 0x2600 : 0x2602;
		emu_add_entitlement(rdr, caid, BissSWs.EmuKeys[i].provider, BissSWs.EmuKeys[i].key,
							BissSWs.EmuKeys[i].keyName, BissSWs.EmuKeys[i].keyLength, 0);
	}

	// Session keys (ECM keys) for BISS2 mode CA
	for (i = 0; i < Biss2Keys.keyCount; i++)
	{
		emu_add_entitlement(rdr, 0x2610, Biss2Keys.EmuKeys[i].provider, Biss2Keys.EmuKeys[i].key,
							Biss2Keys.EmuKeys[i].keyName, Biss2Keys.EmuKeys[i].keyLength, 0);
	}

	// RSA keys (EMM keys) for BISS2 mode CA
	itr = ll_iter_create(rdr->ll_biss2_rsa_keys);
	while ((item = ll_iter_next(&itr)))
	{
		emu_add_entitlement(rdr, 0x2610, 0, item->ekid, "RSAPRI", 8, 0);
	}

	for (i = 0; i < OmnicryptKeys.keyCount; i++)
	{
		emu_add_entitlement(rdr, 0x00FF, OmnicryptKeys.EmuKeys[i].provider, OmnicryptKeys.EmuKeys[i].key,
							OmnicryptKeys.EmuKeys[i].keyName, OmnicryptKeys.EmuKeys[i].keyLength, 0);
	}
}

static int32_t emu_do_ecm(struct s_reader *rdr, const ECM_REQUEST *er, struct s_ecm_answer *ea)
{
	if (!emu_process_ecm(rdr, er, ea->cw, &ea->cw_ex))
	{
		return CS_OK;
	}

	return CS_ERROR;
}

static int32_t emu_do_emm(struct s_reader *rdr, EMM_PACKET *emm)
{
	uint32_t keysAdded = 0;

	if (emm->emmlen < 3)
	{
		return CS_ERROR;
	}

	if (SCT_LEN(emm->emm) > emm->emmlen)
	{
		return CS_ERROR;
	}

	if (!emu_process_emm(rdr, b2i(2, emm->caid), emm->emm, &keysAdded))
	{
		if (keysAdded > 0)
		{
			refresh_entitlements(rdr);
		}

		return CS_OK;
	}

	return CS_ERROR;
}

static int32_t emu_card_info(struct s_reader *rdr)
{
	SAFE_MUTEX_LOCK(&emu_key_data_mutex);

	// Delete keys from Emu's memory
	emu_clear_keydata();

	// Delete BISS2 mode CA RSA keys
	ll_destroy_data(&rdr->ll_biss2_rsa_keys);

	// Read keys built in the OSCam-Emu binary
	emu_read_keymemory(rdr);

	// Read keys from SoftCam.Key file
	emu_set_keyfile_path(cs_confdir);

	if (!emu_read_keyfile(rdr, cs_confdir))
	{
		if (emu_read_keyfile(rdr, "/var/keys/"))
		{
			emu_set_keyfile_path("/var/keys/");
		}
	}

	// Read BISS2 mode CA RSA keys from PEM files
	biss_read_pem(rdr, BISS2_MAX_RSA_KEYS);

	cs_log("Total keys in memory: W:%d V:%d N:%d I:%d F:%d G:%d O:%d P:%d T:%d A:%d",
			CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, IrdetoKeys.keyCount, BissSWs.keyCount,
			Biss2Keys.keyCount, OmnicryptKeys.keyCount, PowervuKeys.keyCount, TandbergKeys.keyCount,
			StreamKeys.keyCount);

	// Inform OSCam about all available keys.
	// This is used for listing the "entitlements" in the webif's reader page.
	refresh_entitlements(rdr);

	SAFE_MUTEX_UNLOCK(&emu_key_data_mutex);

	set_prids(rdr);

	set_hexserial_to_version(rdr);

	return CS_OK;
}

/*
static int32_t emu_card_init(struct s_reader *UNUSED(rdr), struct s_ATR *UNUSED(atr))
{
	return CS_ERROR;
}
*/

int32_t emu_get_via3_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
	uint32_t provid = 0;

	if(ep->emm[3] == 0x90 && ep->emm[4] == 0x03)
	{
		provid = b2i(3, ep->emm + 5);
		provid &= 0xFFFFF0;
		i2b_buf(4, provid, ep->provid);
	}

	switch (ep->emm[0])
	{
		case 0x88:
			ep->type = UNIQUE;
			memset(ep->hexserial, 0, 8);
			memcpy(ep->hexserial, ep->emm + 4, 4);
			rdr_log_dbg(rdr, D_EMM, "UNIQUE");
			return 1;

		case 0x8A:
		case 0x8B:
			ep->type = GLOBAL;
			rdr_log_dbg(rdr, D_EMM, "GLOBAL");
			return 1;

		case 0x8C:
		case 0x8D:
			ep->type = SHARED;
			rdr_log_dbg(rdr, D_EMM, "SHARED (part)");
			// We need those packets to pass otherwise we would never
			// be able to complete EMM reassembly
			return 1;

		case 0x8E:
			ep->type = SHARED;
			rdr_log_dbg(rdr, D_EMM, "SHARED");
			memset(ep->hexserial, 0, 8);
			memcpy(ep->hexserial, ep->emm + 3, 3);
			return 1;

		default:
			ep->type = UNKNOWN;
			rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
			return 1;
	}
}

int32_t emu_get_ird2_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
	int32_t l = (ep->emm[3] & 0x07);
	int32_t base = (ep->emm[3] >> 3);
	char dumprdrserial[l * 3], dumpemmserial[l * 3];

	switch (l)
	{
		case 0:
			// global emm, 0 bytes addressed
			ep->type = GLOBAL;
			rdr_log_dbg(rdr, D_EMM, "GLOBAL base = %02x", base);
			return 1;

		case 2:
			// shared emm, 2 bytes addressed
			ep->type = SHARED;
			memset(ep->hexserial, 0, 8);
			memcpy(ep->hexserial, ep->emm + 4, l);
			cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial));
			cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial));
			rdr_log_dbg_sensitive(rdr, D_EMM, "SHARED l = %d ep = {%s} rdr = {%s} base = %02x",
									l, dumpemmserial, dumprdrserial, base);
			return 1;

		case 3:
			// unique emm, 3 bytes addressed
			ep->type = UNIQUE;
			memset(ep->hexserial, 0, 8);
			memcpy(ep->hexserial, ep->emm + 4, l);
			cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial));
			cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial));
			rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE l = %d ep = {%s} rdr = {%s} base = %02x",
									l, dumpemmserial, dumprdrserial, base);
			return 1;

		default:
			ep->type = UNKNOWN;
			rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
			return 1;
	}
}

int32_t emu_get_pvu_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
	if (ep->emm[0] == 0x82)
	{
		ep->type = UNIQUE;
		memset(ep->hexserial, 0, 8);
		memcpy(ep->hexserial, ep->emm + 12, 4);
	}
	else
	{
		ep->type = UNKNOWN;
		rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
	}
	return 1;
}

int32_t emu_get_tan_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
	if (ep->emm[0] == 0x82 || ep->emm[0] == 0x83)
	{
		ep->type = GLOBAL;
	}
	else
	{
		ep->type = UNKNOWN;
		rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
	}
	return 1;
}

int32_t emu_get_biss_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
	switch (ep->emm[0])
	{
		case 0x81: // Spec say this is for EMM, but oscam (and all other crypto systems) use it for ECM
		case 0x82:
		case 0x83:
		case 0x84:
		case 0x85:
		case 0x86:
		case 0x87:
		case 0x88:
		case 0x89:
		case 0x8A:
		case 0x8B:
		case 0x8C:
		case 0x8D:
		case 0x8E:
		case 0x8F:
			ep->type = GLOBAL;
			return 1;

		default:
			ep->type = UNKNOWN;
			rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
			return 1;
	}
}

static int32_t emu_get_emm_type(struct emm_packet_t *ep, struct s_reader *rdr)
{
	uint16_t caid = b2i(2, ep->caid);

	if (caid_is_viaccess(caid))     return emu_get_via3_emm_type(ep, rdr);
	if (caid_is_irdeto(caid))       return emu_get_ird2_emm_type(ep, rdr);
	if (caid_is_powervu(caid))      return emu_get_pvu_emm_type(ep, rdr);
	if (caid_is_director(caid))     return emu_get_tan_emm_type(ep, rdr);
	if (caid_is_biss_dynamic(caid)) return emu_get_biss_emm_type(ep, rdr);

	return CS_ERROR;
}

FILTER *get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid)
{
	int32_t i;

	for (i = 0; i < rdr->emu_auproviders.nfilts; i++)
	{
		if (caid == rdr->emu_auproviders.filts[i].caid)
		{
			return &rdr->emu_auproviders.filts[i];
		}
	}

	return NULL;
}

static int32_t emu_get_via3_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid))
{
	if (*emm_filters == NULL)
	{
		const unsigned int max_filter_count = 1;
		if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
		{
			return CS_ERROR;
		}

		struct s_csystem_emm_filter *filters = *emm_filters;
		*filter_count = 0;

		int32_t idx = 0;

		filters[idx].type = EMM_GLOBAL;
		filters[idx].enabled   = 1;
		filters[idx].filter[0] = 0x8A;
		filters[idx].mask[0]   = 0xFE;
		filters[idx].filter[3] = 0x80;
		filters[idx].mask[3]   = 0x80;
		idx++;

		*filter_count = idx;
	}

	return CS_OK;
}

static int32_t emu_get_ird2_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t UNUSED(provid))
{
	uint8_t hexserial[3], prid[4];
	FILTER *emu_provids;
	int8_t have_provid = 0, have_serial = 0;
	int32_t i;

	SAFE_MUTEX_LOCK(&emu_key_data_mutex);
	if(irdeto2_get_hexserial(caid, hexserial))
	{
		have_serial = 1;
	}
	SAFE_MUTEX_UNLOCK(&emu_key_data_mutex);

	emu_provids = get_emu_prids_for_caid(rdr, caid);
	if (emu_provids != NULL && emu_provids->nprids > 0)
	{
		have_provid = 1;
	}

	if (*emm_filters == NULL)
	{
		const unsigned int max_filter_count = have_serial + (2 * (have_provid ? emu_provids->nprids : 0));
		if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
		{
			return CS_ERROR;
		}

		struct s_csystem_emm_filter *filters = *emm_filters;
		*filter_count = 0;

		unsigned int idx = 0;

		if (have_serial)
		{
			filters[idx].type = EMM_UNIQUE;
			filters[idx].enabled   = 1;
			filters[idx].filter[0] = 0x82;
			filters[idx].mask[0]   = 0xFF;
			filters[idx].filter[1] = 0xFB;
			filters[idx].mask[1]   = 0x07;
			memcpy(&filters[idx].filter[2], hexserial, 3);
			memset(&filters[idx].mask[2], 0xFF, 3);
			idx++;
		}

		for (i = 0; have_provid && i < emu_provids->nprids; i++)
		{
			i2b_buf(4, emu_provids->prids[i], prid);

			filters[idx].type = EMM_UNIQUE;
			filters[idx].enabled   = 1;
			filters[idx].filter[0] = 0x82;
			filters[idx].mask[0]   = 0xFF;
			filters[idx].filter[1] = 0xFB;
			filters[idx].mask[1]   = 0x07;
			memcpy(&filters[idx].filter[2], &prid[1], 3);
			memset(&filters[idx].mask[2], 0xFF, 3);
			idx++;

			filters[idx].type = EMM_SHARED;
			filters[idx].enabled   = 1;
			filters[idx].filter[0] = 0x82;
			filters[idx].mask[0]   = 0xFF;
			filters[idx].filter[1] = 0xFA;
			filters[idx].mask[1]   = 0x07;
			memcpy(&filters[idx].filter[2], &prid[1], 2);
			memset(&filters[idx].mask[2], 0xFF, 2);
			idx++;
		}

		*filter_count = idx;
	}

	return CS_OK;
}

static int32_t emu_get_pvu_emm_filter(struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count,
										uint16_t caid, uint16_t srvid, uint16_t tsid, uint16_t onid, uint32_t ens)
{
	uint8_t hexserials[32][4];
	uint32_t i, count = 0;

	SAFE_MUTEX_LOCK(&emu_key_data_mutex);
	count = powervu_get_hexserials_new(hexserials, 32, caid, tsid, onid, ens);
	if (count == 0)
	{
		count = powervu_get_hexserials(hexserials, 32, srvid);
		if (count == 0)
		{
			SAFE_MUTEX_UNLOCK(&emu_key_data_mutex);
			return CS_ERROR;
		}
	}
	SAFE_MUTEX_UNLOCK(&emu_key_data_mutex);

	if (*emm_filters == NULL)
	{
		const unsigned int max_filter_count = count;
		if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
		{
			return CS_ERROR;
		}

		struct s_csystem_emm_filter *filters = *emm_filters;
		*filter_count = 0;

		int32_t idx = 0;

		for (i = 0; i < count; i++)
		{
			filters[idx].type = EMM_UNIQUE;
			filters[idx].enabled    = 1;
			filters[idx].filter[0]  = 0x82;
			filters[idx].filter[10] = hexserials[i][0];
			filters[idx].filter[11] = hexserials[i][1];
			filters[idx].filter[12] = hexserials[i][2];
			filters[idx].filter[13] = hexserials[i][3];
			filters[idx].mask[0]    = 0xFF;
			filters[idx].mask[10]   = 0xFF;
			filters[idx].mask[11]   = 0xFF;
			filters[idx].mask[12]   = 0xFF;
			filters[idx].mask[13]   = 0xFF;
			idx++;
		}

		*filter_count = idx;
	}

	return CS_OK;
}

static int32_t emu_get_tan_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid))
{
	if (*emm_filters == NULL)
	{
		const unsigned int max_filter_count = 2;
		uint8_t buf[8];

		if (!emu_find_key('T', 0x40, 0, "MK", buf, 8, 0, 0, 0, NULL) &&
			!emu_find_key('T', 0x40, 0, "MK01", buf, 8, 0, 0, 0, NULL))
		{
			return CS_ERROR;
		}

		if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
		{
			return CS_ERROR;
		}

		struct s_csystem_emm_filter *filters = *emm_filters;
		*filter_count = 0;

		int32_t idx = 0;

		filters[idx].type = EMM_GLOBAL;
		filters[idx].enabled   = 1;
		filters[idx].filter[0] = 0x82;
		filters[idx].mask[0]   = 0xFF;
		idx++;

		filters[idx].type = EMM_GLOBAL;
		filters[idx].enabled   = 1;
		filters[idx].filter[0] = 0x83;
		filters[idx].mask[0]   = 0xFF;
		idx++;

		*filter_count = idx;
	}

	return CS_OK;
}

static int32_t emu_get_biss_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid))
{
	if (*emm_filters == NULL)
	{
		const unsigned int max_filter_count = 15;
		if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
		{
			return CS_ERROR;
		}

		struct s_csystem_emm_filter *filters = *emm_filters;
		*filter_count = 0;

		int32_t idx = 0;
		uint8_t i;

		for (i = 0; i < max_filter_count; i++)
		{
			filters[idx].type = EMM_GLOBAL;
			filters[idx].enabled   = 1;
			filters[idx].filter[0] = 0x81 + i; // What about table 0x81?
			filters[idx].mask[0]   = 0xFF;
			idx++;

			*filter_count = idx;
		}
	}
	return CS_OK;
}

static int32_t emu_get_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **UNUSED(emm_filters), unsigned int *UNUSED(filter_count))
{
	return CS_ERROR;
}

static int32_t emu_get_emm_filter_adv(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count,
										uint16_t caid, uint32_t provid, uint16_t srvid, uint16_t tsid, uint16_t onid, uint32_t ens)
{
	if (caid_is_viaccess(caid))     return emu_get_via3_emm_filter(rdr, emm_filters, filter_count, caid, provid);
	if (caid_is_irdeto(caid))       return emu_get_ird2_emm_filter(rdr, emm_filters, filter_count, caid, provid);
	if (caid_is_powervu(caid))      return emu_get_pvu_emm_filter(emm_filters, filter_count, caid, srvid, tsid, onid, ens);
	if (caid_is_director(caid))     return emu_get_tan_emm_filter(rdr, emm_filters, filter_count, caid, provid);
	if (caid_is_biss_dynamic(caid)) return emu_get_biss_emm_filter(rdr, emm_filters, filter_count, caid, provid);

	return CS_ERROR;
}

const struct s_cardsystem reader_emu =
{
	.desc = "emu",
	.caids = (uint16_t[]){ 0x05, 0x06, 0x0D, 0x0E, 0x10, 0x18, 0x26, 0 },
	.do_ecm = emu_do_ecm,
	.do_emm = emu_do_emm,
	.card_info = emu_card_info,
	//.card_init = emu_card_init, // apparently this is not needed at all
	.get_emm_type = emu_get_emm_type,
	.get_emm_filter = emu_get_emm_filter, // needed to pass checks
	.get_emm_filter_adv = emu_get_emm_filter_adv,
};

/*
 * Create the Emu virtual "device" part. This is of type s_cardreader.
 * Similar structures are found in the csctapi (Card System Card Terminal API)
 * folder for every IFD (InterFace Device), aka smart card reader.
 * Since we have no hardware to initialize, we start our Stream Relay server
 * with the emu_reader_init() function.
 * At Emu shutdown, we remove keys from memory with the emu_close() function.
*/

#define CR_OK    0
#define CR_ERROR 1

static int32_t emu_reader_init(struct s_reader *UNUSED(reader))
{
#ifdef MODULE_STREAMRELAY
	if (cfg.stream_relay_enabled && (stream_server_thread_init == 0))
	{
		int32_t i;
		stream_server_thread_init = 1;
		SAFE_MUTEX_INIT(&emu_fixed_key_srvid_mutex, NULL);

		for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
		{
			SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL);
			ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys");
			memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data));
		}

		start_thread("stream_key_delayer", stream_key_delayer, NULL, NULL, 1, 1);
		cs_log("Stream key delayer initialized");
	}

	// Initialize mutex for exclusive access to key database and key file
	if (!emu_key_data_mutex_init)
	{
		SAFE_MUTEX_INIT(&emu_key_data_mutex, NULL);
		emu_key_data_mutex_init = 1;
	}
#endif
	return CR_OK;
}

static int32_t emu_close(struct s_reader *UNUSED(reader))
{
	cs_log("Reader is shutting down");

	// Delete keys from Emu's memory
	SAFE_MUTEX_LOCK(&emu_key_data_mutex);
	emu_clear_keydata();
	SAFE_MUTEX_UNLOCK(&emu_key_data_mutex);

	return CR_OK;
}

static int32_t emu_get_status(struct s_reader *UNUSED(reader), int32_t *in) { *in = 1; return CR_OK; }
static int32_t emu_activate(struct s_reader *UNUSED(reader), struct s_ATR *UNUSED(atr)) { return CR_OK; }
static int32_t emu_transmit(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(expectedlen), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; }
static int32_t emu_receive(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; }
static int32_t emu_write_settings(struct s_reader *UNUSED(reader), struct s_cardreader_settings *UNUSED(s)) { return CR_OK; }
static int32_t emu_card_write(struct s_reader *UNUSED(pcsc_reader), const uint8_t *UNUSED(buf), uint8_t *UNUSED(cta_res), uint16_t *UNUSED(cta_lr), int32_t UNUSED(l)) { return CR_OK; }
static int32_t emu_set_protocol(struct s_reader *UNUSED(rdr), uint8_t *UNUSED(params), uint32_t *UNUSED(length), uint32_t UNUSED(len_request)) { return CR_OK; }

const struct s_cardreader cardreader_emu =
{
	.desc                   = "emu",
	.typ                    = R_EMU,
	.skip_extra_atr_parsing = 1,
	.reader_init            = emu_reader_init,
	.get_status             = emu_get_status,
	.activate               = emu_activate,
	.transmit               = emu_transmit,
	.receive                = emu_receive,
	.close                  = emu_close,
	.write_settings         = emu_write_settings,
	.card_write             = emu_card_write,
	.set_protocol           = emu_set_protocol,
};

void add_emu_reader(void)
{
	// This function is called inside oscam.c and creates an emu [reader] with default
	// settings in oscam.server file. If an emu [reader] already exists, it uses that.

	LL_ITER itr;
	struct s_reader *rdr;
	int8_t haveEmuReader = 0;
	char emuName[] = "emulator";
	char *ctab, *ftab, *emu_auproviders, *disablecrccws_only_for;

	// Check if emu [reader] entry already exists in oscam.server file and get it
	itr = ll_iter_create(configured_readers);
	while ((rdr = ll_iter_next(&itr)))
	{
		if (rdr->typ == R_EMU)
		{
			haveEmuReader = 1;
			break;
		}
	}

	rdr = NULL;

	// If there's no emu [reader] in oscam.server, create one with default settings
	if (!haveEmuReader)
	{
		if (!cs_malloc(&rdr, sizeof(struct s_reader)))
		{
			return;
		}

		reader_set_defaults(rdr);

		rdr->enable = 1;
		rdr->typ = R_EMU;
		cs_strncpy(rdr->label, emuName, sizeof(emuName));
		cs_strncpy(rdr->device, emuName, sizeof(emuName));

		// CAIDs
		ctab = strdup("0500,0604,0D00,0E00,1010,1801,2600,2602,2610");
		chk_caidtab(ctab, &rdr->ctab);
		NULLFREE(ctab);

		// Idents
		ftab = strdup("0500:020A00,021110;"
					  "0604:000000;"
					  "0D00:0000C0;"
					  "0E00:000000;"
					  "1010:000000;"
					  "1801:000000,001101,002111,007301;"
					  "2600:000000;"
					  "2602:000000;"
					  "2610:000000;"
					 );
		chk_ftab(ftab, &rdr->ftab);
		NULLFREE(ftab);

		// AU providers
		emu_auproviders = strdup("0604:010200;0E00:000000;1010:000000;2610:000000;");
		chk_ftab(emu_auproviders, &rdr->emu_auproviders);
		NULLFREE(emu_auproviders);

		// EMM cache
		rdr->cachemm = 2;
		rdr->rewritemm = 1;
		rdr->logemm = 2;
		rdr->deviceemm = 1;

		// User group
		rdr->grp = 0x1ULL;

		// Add the "device" part to our emu reader
		rdr->crdr = &cardreader_emu;

		// Disable CW checksum test for PowerVu
		disablecrccws_only_for = strdup("0E00:000000");
		chk_ftab(disablecrccws_only_for, &rdr->disablecrccws_only_for);
		NULLFREE(disablecrccws_only_for);

		reader_fixups_fn(rdr);
		ll_append(configured_readers, rdr);
	}

	// Set DVB Api delayer option
#ifdef HAVE_DVBAPI
	if (cfg.dvbapi_enabled && cfg.dvbapi_delayer < 60)
	{
		cfg.dvbapi_delayer = 60;
	}
#endif

	cs_log("OSCam-Emu version %d", EMU_VERSION);
}

#endif // WITH_EMU
