Add support for viaccess EMMs
This commit is contained in:
parent
45253ad61c
commit
6eb145697d
1 changed files with 223 additions and 0 deletions
223
src/cwc.c
223
src/cwc.c
|
@ -57,6 +57,7 @@ typedef enum {
|
|||
CARD_IRDETO,
|
||||
CARD_CONAX,
|
||||
CARD_SECA,
|
||||
CARD_VIACCESS,
|
||||
CARD_UNKNOWN
|
||||
} card_type_t;
|
||||
|
||||
|
@ -223,6 +224,22 @@ typedef struct cwc {
|
|||
/* Emm forwarding */
|
||||
int cwc_forward_emm;
|
||||
|
||||
/* Emm duplicate cache */
|
||||
struct {
|
||||
#define EMM_CACHE_SIZE (1<<5)
|
||||
#define EMM_CACHE_MASK (EMM_CACHE_SIZE-1)
|
||||
uint32_t cache[EMM_CACHE_SIZE];
|
||||
uint32_t w;
|
||||
uint32_t n;
|
||||
} cwc_emm_cache;
|
||||
|
||||
/* Viaccess EMM assemble state */
|
||||
struct {
|
||||
int shared_toggle;
|
||||
int shared_len;
|
||||
uint8_t * shared_emm;
|
||||
} cwc_viaccess_emm;
|
||||
|
||||
/* Card type */
|
||||
card_type_t cwc_card_type;
|
||||
|
||||
|
@ -255,6 +272,8 @@ static void cwc_detecs_card_type(cwc_t *cwc);
|
|||
void cwc_emm_conax(cwc_t *cwc, uint8_t *data, int len);
|
||||
void cwc_emm_irdeto(cwc_t *cwc, uint8_t *data, int len);
|
||||
void cwc_emm_seca(cwc_t *cwc, uint8_t *data, int len);
|
||||
void cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int len);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -634,6 +653,11 @@ cwc_detecs_card_type(cwc_t *cwc)
|
|||
tvhlog(LOG_INFO, "cwc", "%s: irdeto card",
|
||||
cwc->cwc_hostname);
|
||||
break;
|
||||
case 0x05:
|
||||
cwc->cwc_card_type = CARD_VIACCESS;
|
||||
tvhlog(LOG_INFO, "cwc", "%s: viaccess card",
|
||||
cwc->cwc_hostname);
|
||||
break;
|
||||
case 0x0b:
|
||||
cwc->cwc_card_type = CARD_CONAX;
|
||||
tvhlog(LOG_INFO, "cwc", "%s: conax card",
|
||||
|
@ -1102,6 +1126,29 @@ verify_provider(cwc_t *cwc, uint32_t providerid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
cwc_emm_cache_insert(cwc_t *cwc, uint32_t crc)
|
||||
{
|
||||
/* evict the oldest entry */
|
||||
cwc->cwc_emm_cache.cache[cwc->cwc_emm_cache.w] = crc;
|
||||
cwc->cwc_emm_cache.w = (cwc->cwc_emm_cache.w+1)&EMM_CACHE_MASK;
|
||||
if (cwc->cwc_emm_cache.n < EMM_CACHE_SIZE)
|
||||
cwc->cwc_emm_cache.n++;
|
||||
}
|
||||
|
||||
static int
|
||||
cwc_emm_cache_lookup(cwc_t *cwc, uint32_t crc)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<cwc->cwc_emm_cache.n; i++)
|
||||
if (cwc->cwc_emm_cache.cache[i] == crc)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -1125,6 +1172,9 @@ cwc_emm(uint8_t *data, int len)
|
|||
case CARD_SECA:
|
||||
cwc_emm_seca(cwc, data, len);
|
||||
break;
|
||||
case CARD_VIACCESS:
|
||||
cwc_emm_viaccess(cwc, data, len);
|
||||
break;
|
||||
case CARD_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
@ -1213,6 +1263,179 @@ cwc_emm_seca(cwc_t *cwc, uint8_t *data, int len)
|
|||
cwc_send_msg(cwc, data, len, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* viaccess emm handler
|
||||
* inspired by opensasc-ng, https://opensvn.csie.org/traccgi/opensascng/
|
||||
*/
|
||||
static
|
||||
uint8_t * nano_start(uint8_t * data)
|
||||
{
|
||||
switch(data[0]) {
|
||||
case 0x88: return &data[8];
|
||||
case 0x8e: return &data[7];
|
||||
case 0x8c:
|
||||
case 0x8d: return &data[3];
|
||||
case 0x80:
|
||||
case 0x81: return &data[4];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
uint8_t * nano_checknano90fromnano(uint8_t * data)
|
||||
{
|
||||
if(data && data[0]==0x90 && data[1]==0x03) return data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
uint8_t * nano_checknano90(uint8_t * data)
|
||||
{
|
||||
return nano_checknano90fromnano(nano_start(data));
|
||||
}
|
||||
|
||||
static
|
||||
int sort_nanos(uint8_t *dest, const uint8_t *src, int len)
|
||||
{
|
||||
int w = 0, c = -1;
|
||||
|
||||
while (1) {
|
||||
int j, n;
|
||||
n = 0x100;
|
||||
for (j = 0; j < len;) {
|
||||
int l = src[j + 1] + 2;
|
||||
if (src[j] == c) {
|
||||
if (w + l > len) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest + w, src + j, l);
|
||||
w += l;
|
||||
}
|
||||
else if (src[j] > c && src[j] < n) {
|
||||
n = src[j];
|
||||
}
|
||||
j += l;
|
||||
}
|
||||
if (n == 0x100) {
|
||||
break;
|
||||
}
|
||||
c = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int via_provider_id(uint8_t * data)
|
||||
{
|
||||
const uint8_t * tmp;
|
||||
tmp = nano_checknano90(data);
|
||||
if (!tmp) return 0;
|
||||
return (tmp[2] << 16) | (tmp[3] << 8) | (tmp[4]&0xf0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen)
|
||||
{
|
||||
/* Get SCT len */
|
||||
int len = 3 + ((data[1] & 0x0f) << 8) + data[2];
|
||||
|
||||
switch (data[0])
|
||||
{
|
||||
case 0x8c:
|
||||
case 0x8d:
|
||||
{
|
||||
int match = 0;
|
||||
int i;
|
||||
uint32_t id;
|
||||
|
||||
/* Match provider id */
|
||||
id = via_provider_id(data);
|
||||
if (!id) break;
|
||||
|
||||
for(i = 0; i < cwc->cwc_num_providers; i++)
|
||||
if(cwc->cwc_providers[i].id == id) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
if (!match) break;
|
||||
|
||||
if (data[0] != cwc->cwc_viaccess_emm.shared_toggle) {
|
||||
cwc->cwc_viaccess_emm.shared_len = 0;
|
||||
free(cwc->cwc_viaccess_emm.shared_emm);
|
||||
cwc->cwc_viaccess_emm.shared_emm = (uint8_t*)malloc(len);
|
||||
if (cwc->cwc_viaccess_emm.shared_emm) {
|
||||
cwc->cwc_viaccess_emm.shared_len = len;
|
||||
memcpy(cwc->cwc_viaccess_emm.shared_emm, data, len);
|
||||
}
|
||||
cwc->cwc_viaccess_emm.shared_toggle = data[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x8e:
|
||||
if (cwc->cwc_viaccess_emm.shared_emm) {
|
||||
int match = 0;
|
||||
int i;
|
||||
/* Match SA and provider in shared */
|
||||
for(i = 0; i < cwc->cwc_num_providers; i++) {
|
||||
if(memcmp(&data[3],&cwc->cwc_providers[i].sa[4], 3)) continue;
|
||||
if((data[6]&2)) continue;
|
||||
if(via_provider_id(cwc->cwc_viaccess_emm.shared_emm) != cwc->cwc_providers[i].id) continue;
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
if (!match) break;
|
||||
|
||||
uint8_t * tmp = alloca(len + cwc->cwc_viaccess_emm.shared_len);
|
||||
uint8_t * ass = nano_start(data);
|
||||
len -= (ass - data);
|
||||
if((data[6] & 2) == 0) {
|
||||
int addrlen = len - 8;
|
||||
len=0;
|
||||
tmp[len++] = 0x9e;
|
||||
tmp[len++] = addrlen;
|
||||
memcpy(&tmp[len], &ass[0], addrlen); len += addrlen;
|
||||
tmp[len++] = 0xf0;
|
||||
tmp[len++] = 0x08;
|
||||
memcpy(&tmp[len],&ass[addrlen],8); len += 8;
|
||||
} else {
|
||||
memcpy(tmp, ass, len);
|
||||
}
|
||||
ass = nano_start(cwc->cwc_viaccess_emm.shared_emm);
|
||||
int l = cwc->cwc_viaccess_emm.shared_len - (ass - cwc->cwc_viaccess_emm.shared_emm);
|
||||
memcpy(&tmp[len], ass, l); len += l;
|
||||
|
||||
ass = (uint8_t*) alloca(len+7);
|
||||
if(ass) {
|
||||
uint32_t crc;
|
||||
|
||||
memcpy(ass, data, 7);
|
||||
if (sort_nanos(ass + 7, tmp, len)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set SCT len */
|
||||
len += 4;
|
||||
ass[1] = (len>>8) | 0x70;
|
||||
ass[2] = len & 0xff;
|
||||
len += 3;
|
||||
|
||||
crc = crc32(ass, len, 0xffffffff);
|
||||
if (!cwc_emm_cache_lookup(cwc, crc)) {
|
||||
tvhlog(LOG_DEBUG, "cwc",
|
||||
"Send EMM "
|
||||
"%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x"
|
||||
"...%02x.%02x.%02x.%02x",
|
||||
ass[0], ass[1], ass[2], ass[3],
|
||||
ass[4], ass[5], ass[6], ass[7],
|
||||
ass[len-4], ass[len-3], ass[len-2], ass[len-1]);
|
||||
cwc_send_msg(cwc, ass, len, 0, 1);
|
||||
cwc_emm_cache_insert(cwc, crc);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
Loading…
Add table
Reference in a new issue