./ MultiCS.r82 / ecmdata.c
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#ifdef WIN32
#include <windows.h>
#include <sys/types.h>
#include <sys/_default_fcntl.h>
#include <sys/poll.h>
#include <cygwin/types.h>
#include <cygwin/socket.h>
#include <sys/errno.h>
#include <cygwin/in.h>
#include <sched.h>
#include <netdb.h>
#include <netinet/tcp.h>
#else
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <poll.h>
#endif
#include "debug.h"
#include "convert.h"
#include "tools.h"
#include "threads.h"
#include "dcw.h"
#include "ecmdata.h"
#ifdef CCCAM
#include "msg-cccam.h"
#endif
#include "config.h"
extern struct config_data cfg;
struct ecm_request *ecmdata = NULL;
int ecmindex = 0;
void init_ecmdata()
{
ecmdata = NULL;
}
uint32_t hashCode( uint8_t *buf, int count)
{
int h = 0;
int i;
for (i = 0; i < count; i++) h = 31*h + buf[i];
return h;
}
uint8_t checkECMD5(uint8_t *ecmd5)
{
int8_t i;
for (i=0;i<16;i++)
if (ecmd5[i]) return 1;
return 0;
}
uint32_t ecm_getprovid( uint8_t *ecm, uint16_t caid )
{
int32_t i, len, descriptor_length = 0;
uint32_t provid = 0;
switch(caid >> 8) {
case 0x01: // seca
provid = (ecm[3]<<8)|ecm[4];
break;
case 0x05:
// viaccess
i = (ecm[4] == 0xD2) ? ecm[5]+2 : 0; // skip d2 nano
if((ecm[5+i] == 3) && ((ecm[4+i] == 0x90) || (ecm[4+i] == 0x40)))
provid = (ecm[i+6]<<16)|(ecm[i+7]<<8)|(ecm[i+8]&0xF0);
i = (ecm[6] == 0xD2) ? ecm[7]+2 : 0; // skip d2 nano long ecm
if((ecm[7+i] == 7) && ((ecm[6+i] == 0x90) || (ecm[6+i] == 0x40)))
provid = (ecm[i+8]<<16)|(ecm[i+9]<<8)|(ecm[i+10]&0xF0);
break;
case 0x0D:
// cryptoworks
len = (((ecm[1] & 0xf) << 8) | ecm[2])+3;
for(i=8; i<len; i+=descriptor_length+2) {
descriptor_length = ecm[i+1];
if (ecm[i] == 0x83) {
provid = (uint32_t)ecm[i+2] & 0xFE;
break;
}
}
break;
}
return(provid);
}
uint16_t ecm_getchid( uint8_t *ecm, uint16_t caid )
{
if ( (caid>>8)==0x06 ) return (ecm[6]<<8)|ecm[7];
return 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void cs_addecmdata(struct cardserver_data *cs, struct ecm_request *new )
{
if (!cs->ecmdata) {
new->csnext = NULL;
new->csprev = NULL;
cs->ecmdata = new;
}
else if (!cs->ecmdata->csnext) {
cs->ecmdata->csnext = new;
cs->ecmdata->csprev = new;
new->csnext = cs->ecmdata;
new->csprev = cs->ecmdata;
cs->ecmdata = new;
}
else {
struct ecm_request *prev = cs->ecmdata->csprev;
struct ecm_request *next = cs->ecmdata;
new->csnext = next;
new->csprev = prev;
prev->csnext = new;
next->csprev = new;
cs->ecmdata = new;
}
cs->totalecm++;
//debugf(0," [%s] new ecmdata %p size = %d\n", cs->name, cs->ecmdata, cs->totalecm);
}
void cs_delecmdata(struct cardserver_data *cs, struct ecm_request *old )
{
if (!cs->ecmdata) {
old->csprev = NULL;
old->csnext = NULL;
return;
}
if (cs->ecmdata==old) {
// move to next
if (!cs->ecmdata->csnext) {
cs->ecmdata = NULL;
}
else {
cs->ecmdata = old->csnext;
if (old->csnext==old->csprev) { // only 2 ecmdata
cs->ecmdata->csnext = NULL;
cs->ecmdata->csprev = NULL;
}
else {
old->csprev->csnext = old->csnext;
old->csnext->csprev = old->csprev;
}
}
}
else if (old->csnext==old->csprev) {
cs->ecmdata->csnext = NULL;
cs->ecmdata->csprev = NULL;
}
else {
old->csprev->csnext = old->csnext;
old->csnext->csprev = old->csprev;
}
old->csprev = NULL;
old->csnext = NULL;
cs->totalecm--;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int totalecm = 0;
struct ecm_request *store_ecmdata(struct cardserver_data *cs,uint8_t *ecm,int ecmlen, unsigned short sid, unsigned short caid, unsigned int provid)
{
struct ecm_request *new;
uint32_t ticks = GetTickCount();
// add new or use dead data
if (!ecmdata) {
// nothing so add new
//debugf(0," first ecmdata\n");
totalecm++;
new = malloc( sizeof(struct ecm_request) );
memset( new, 0, sizeof(struct ecm_request) );
new->next = NULL;
new->prev = NULL;
ecmdata = new; // it becomes the current one
}
else if (!ecmdata->next) {
//debugf(0," second ecmdata\n");
totalecm++;
new = malloc( sizeof(struct ecm_request) );
memset( new, 0, sizeof(struct ecm_request) );
new->prev = ecmdata;
new->next = ecmdata;
ecmdata->prev = new;
ecmdata->next = new;
ecmdata = new; // it becomes the current one
}
else {
new = ecmdata->prev;
if ( (new->recvtime+TIME_ECMALIVE*2) < ticks ) {
cs_delecmdata(new->cs, new);
// cache is dead, add data to this one without allocating new data
struct ecm_request *tmp = new->prev; // store previous
memset( new, 0, sizeof(struct ecm_request) );
new->prev = tmp;
new->next = ecmdata;
ecmdata = new; // it becomes the current one
}
else { // allocate new data
totalecm++;
//debugf(0," new ecmdata size = %d\n", totalecm);
new = malloc( sizeof(struct ecm_request) );
memset( new, 0, sizeof(struct ecm_request) );
new->prev = ecmdata->prev;
new->next = ecmdata;
//
new->prev->next = new;
//
ecmdata->prev = new;
//
ecmdata = new; // it becomes the current one
}
}
cs_addecmdata(cs, new);
//
memcpy( new->ecm, ecm, ecmlen);
new->cs = cs;
new->chid = ecm_getchid(ecm, caid);
new->ecmlen = ecmlen;
new->recvtime = ticks;
new->lastrecvtime = ticks;
new->hash = hashCode(ecm+3, ecmlen-3);
#ifdef CACHEEX
int32_t offset = 3;
if ( (caid>>8)==0x17 ) offset = 13;
MD5( ecm+offset, ecmlen-offset, new->ecmd5);
#endif
new->dcwstatus = STAT_DCW_WAIT;
new->sid = sid;
new->caid = caid;
new->provid = provid;
// new->id = ecmindex;
memset( &new->server, 0, sizeof(new->server) );
new->waitcache = 0;
new->cachestatus = 0; //ECM_CACHE_NONE;
//new->dcwsrvtype = DCW_SOURCE_NONE;
new->period = 1; // First try
#ifdef CHECK_NEXTDCW
//checkfreeze_storeECM(new);
#endif
return new;
}
////////////////////////////////////////////////////////////////////////////////
// SEARCH FUNCTIONS
////////////////////////////////////////////////////////////////////////////////
struct ecm_request *search_ecmdata_dcw( uint8_t *ecm, int ecmlen, unsigned short sid)
{
uint32_t ticks = GetTickCount();
uint32_t hash = hashCode(ecm+3, ecmlen-3);
struct ecm_request *req = ecmdata;
while (req) {
if ( (req->recvtime+TIME_ECMALIVE) < ticks ) return NULL;
if (req->dcwstatus!=STAT_DCW_FAILED)
if (hash==req->hash)
if (ecm[0]==req->ecm[0])
if (ecmlen==req->ecmlen)
if (sid==req->sid)
if ( !memcmp(ecm+3, req->ecm+3, ecmlen-3) ) return req;
req = req->next;
if (req==ecmdata) break;
}
return NULL;
}
struct ecm_request *search_ecmdata_any(struct cardserver_data *cs, uint8_t *ecm, int ecmlen, unsigned short sid, unsigned short caid)
{
uint32_t hash = hashCode(ecm+3, ecmlen-3);
uint32_t ticks = GetTickCount();
struct ecm_request *req = cs->ecmdata;
while (req) {
if ( (req->recvtime+TIME_ECMALIVE) < ticks ) return NULL;
if (hash==req->hash)
if (ecmlen==req->ecmlen)
if (sid==req->sid)
if (caid==req->caid)
if ( !memcmp(ecm, req->ecm, ecmlen) ) return req;
req = req->csnext;
if (req==cs->ecmdata) break;
}
return NULL;
}
struct ecm_request *search_ecmdata_byhash( uint16_t caid, uint16_t sid,uint32_t hash )
{
uint32_t ticks = GetTickCount();
struct ecm_request *req = ecmdata;
while (req) {
if ( (req->recvtime+TIME_ECMALIVE) < ticks ) return NULL;
if (hash==req->hash)
if (caid==req->caid)
if (sid==req->sid) return req;
req = req->next;
if (req==ecmdata) break;
}
return NULL;
}
#ifdef CACHEEX
struct ecm_request *search_ecmdata_byecmd5( uint16_t caid, uint32_t provid, uint8_t ecmd5[16] )
{
uint32_t ticks = GetTickCount();
struct ecm_request *req = ecmdata;
while (req) {
if ( (req->recvtime+TIME_ECMALIVE) < ticks ) return NULL;
if (caid==req->caid)
if (provid==req->provid)
if ( !memcmp(ecmd5, req->ecmd5, 16) ) return req;
req = req->next;
if (req==ecmdata) break;
}
return NULL;
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
int ecmdata_check_cw( uint8_t tag, uint32_t hash, unsigned short caid, unsigned int provid , unsigned short sid, uint8_t cw[16], int cwpart )
{
struct ecm_request *req = ecmdata;
while (req) {
if (req->dcwstatus==STAT_DCW_SUCCESS)
if (hash!=req->hash)
if (provid==req->provid)
if (caid==req->caid)
if (sid==req->sid) {
switch (cwpart) {
case 0:
if ( dcwcmp8(req->cw,cw) ) return 0;
if ( dcwcmp8(req->cw+8,cw) ) return 0;
break;
case 1:
if ( dcwcmp8(req->cw,cw+8) ) return 0;
if ( dcwcmp8(req->cw+8,cw+8) ) return 0;
break;
case 2:
if ( dcwcmp16(req->cw,cw) ) return 0;
break;
}
}
req = req->next;
if (req==ecmdata) break;
}
return 1;
}
////////////////////////////////////////////////////////////////////////////////
// IP FUNCTIONS
////////////////////////////////////////////////////////////////////////////////
// Client IP
void ecm_addip( ECM_DATA *ecm, unsigned int ip)
{
register int i;
for(i=0; i<20; i++) {
if (!ecm->iplist[i]) {
ecm->iplist[i] = ip;
return;
}
if (ecm->iplist[i]==ip) return;
}
}
int ecm_checkip(ECM_DATA *ecm, unsigned int ip)
{
register int i;
for(i=0; i<20; i++) {
if (!ecm->iplist[i]) return FALSE;
if (ecm->iplist[i]==ip) return TRUE; // found
}
return FALSE;
}
//SRV IP
void ecm_addsrvip(ECM_DATA *ecm, unsigned int ip)
{
register int i;
for(i=0; i<20; i++) {
if (!ecm->srviplist[i]) {
ecm->srviplist[i] = ip;
return;
}
if (ecm->srviplist[i]==ip) return;
}
}
int ecm_checksrvip(ECM_DATA *ecm, unsigned int ip)
{
register int i;
for(i=0; i<20; i++) {
if (!ecm->srviplist[i]) return FALSE;
if (ecm->srviplist[i]==ip) return TRUE; // found
}
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////
// SERVER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////
int ecm_nbservers(ECM_DATA *ecm)
{
int i;
int count=0;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
count++;
} else break;
}
return count;
}
int ecm_nbsentsrv(ECM_DATA *ecm)
{
int i;
int count=0;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].flag!=ECM_SRV_EXCLUDE) count++;
} else break;
}
return count;
}
int ecm_nbwaitsrv(ECM_DATA *ecm)
{
int i;
int count=0;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].flag==ECM_SRV_REQUEST) count++;
} else break;
}
return count;
}
int ecm_addsrv(ECM_DATA *ecm, unsigned int srvid)
{
int i;
uint32_t ticks = GetTickCount();
for(i=0; i<20; i++) {
if (!ecm->server[i].srvid) {
ecm->server[i].srvid = srvid;
ecm->server[i].flag = ECM_SRV_REQUEST;
ecm->server[i].sendtime = ticks;
ecm->server[i].statustime = ticks; // last changed status time
ecm->server_totalsent = ecm_nbsentsrv(ecm);
ecm->server_totalwait = ecm_nbwaitsrv(ecm);
return 1;
}
}
return 0;
}
int ecm_setsrvflag(ECM_DATA *ecm, unsigned int srvid, int flag)
{
int i;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].srvid==srvid) {
ecm->server[i].flag=flag;
ecm->server[i].statustime = GetTickCount();
ecm->server_totalsent = ecm_nbsentsrv(ecm);
ecm->server_totalwait = ecm_nbwaitsrv(ecm);
return 1;
}
} else break;
}
return 0;
}
int ecm_setsrvflagdcw(ECM_DATA *ecm, unsigned int srvid, int flag, uint8_t dcw[16])
{
int i;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].srvid==srvid) {
ecm->server[i].flag=flag;
ecm->server[i].statustime = GetTickCount();
memcpy(ecm->server[i].dcw, dcw, 16);
ecm->server_totalsent = ecm_nbsentsrv(ecm);
ecm->server_totalwait = ecm_nbwaitsrv(ecm);
return 1;
}
} else break;
}
return 0;
}
int ecm_getsrvflag(ECM_DATA *ecm, unsigned int srvid)
{
int i;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].srvid==srvid) {
return ecm->server[i].flag;
}
} else break;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// DCW CHECK
///////////////////////////////////////////////////////////////////////////////
#ifdef CHECK_NEXTDCW
// Get Last DCW for the same Channel
void checkfreeze_storeECM(ECM_DATA *ecm)
{
struct ecm_request *xecm = NULL;
// find after storing ecm
if (!ecm) return;
if ( (!ecm->lastdecode.ecm)&&(ecm->dcwstatus!=STAT_DCW_SUCCESS) ) {
//debugf(0," \n[SROTE ECM] New (%04x:%06x:%04x/%08x)\n",ecm->caid, ecm->provid, ecm->sid, ecm->hash);
uint32_t ticks = GetTickCount();
struct ecm_request *oldecm = ecm->csnext;
while (oldecm) {
if ( (oldecm->recvtime+TIME_ECMALIVE*2) < ticks ) break;
if ( (oldecm->ecmlen==ecm->ecmlen)&&(oldecm->caid==ecm->caid)&&(oldecm->provid==ecm->provid)&&(oldecm->sid==ecm->sid) ) {
if ( (oldecm->dcwstatus==STAT_DCW_SUCCESS)&&(oldecm->hash!=ecm->hash)&&(oldecm->ecm[0]!=ecm->ecm[0]) ) {
//ecm->lastdecode.request = oldecm;
if ( (oldecm->lastdecode.ecm)&&(oldecm->lastdecode.counter>1) ) {
if ((ecm->recvtime-oldecm->recvtime)<(oldecm->lastdecode.dcwchangetime*3/2)) xecm = oldecm;
break;
}
else if (!xecm) xecm = oldecm;
}
else if ( (oldecm->dcwstatus==STAT_DCW_FAILED)&&(oldecm->hash==ecm->hash)&& !memcmp(oldecm->ecm+3, ecm->ecm+3, ecm->ecmlen-3) ) { // the same channel but we have freeze
memcpy( &ecm->lastdecode, &oldecm->lastdecode, sizeof(ecm->lastdecode) );
return; // copy and exit
//fdebugf(" Updating Cycles data after freeze ch %04x:%06x:%04x:%08x (%d)\n",ecm->caid, ecm->provid, ecm->sid, ecm->hash, ecm->lastdecode.counter);
}
}
oldecm = oldecm->csnext;
if (oldecm==ecm) break;
}
if (xecm) {
ecm->lastdecode.ecm = xecm; // status -> last ecm
ecm->lastdecode.counter = xecm->lastdecode.counter;
ecm->lastdecode.dcwchangetime = (xecm->lastdecode.dcwchangetime*xecm->lastdecode.counter+(ecm->recvtime-xecm->recvtime)) / (xecm->lastdecode.counter+1);
ecm->lastdecode.dcwchangetime = ((ecm->lastdecode.dcwchangetime+500)/1000)*1000;
memcpy( ecm->lastdecode.dcw, xecm->lastdecode.dcw, 16); // Store latest DCW
#ifdef TESTCHANNEL
int testchannel = ( (ecm->caid==cfg.testchn.caid) && (ecm->provid==cfg.testchn.provid) && (ecm->sid==cfg.testchn.sid) );
if (testchannel) {
char dump[64];
array2hex( xecm->cw, dump, 16);
fdebugf(" Update Cycle ch %04x:%06x:%04x %02x:%08x ( %02x:%08x %s/%d)\n",ecm->caid, ecm->provid, ecm->sid, ecm->ecm[0],ecm->hash,
xecm->ecm[0], xecm->hash, dump, ecm->lastdecode.counter);
}
#endif
}
}
}
void checkfreeze_checkECM( ECM_DATA *ecm, ECM_DATA *oldecm )
{
if (!ecm) return;
if (!oldecm) return;
if (ecm->lastdecode.ecm==oldecm) return;
if ( (ecm->recvtime-oldecm->recvtime) > TIME_ECMALIVE*2) return;
if ( (oldecm->ecmlen==ecm->ecmlen) && (oldecm->caid==ecm->caid) && (oldecm->provid==ecm->provid) && (oldecm->sid==ecm->sid) ) {
if ( (oldecm->dcwstatus==STAT_DCW_SUCCESS) && (oldecm->ecm[0]!=ecm->ecm[0]) && (oldecm->hash!=ecm->hash) ) {
if ( (oldecm->lastdecode.ecm)&&(oldecm->lastdecode.counter>1) ) {
if ((ecm->recvtime-oldecm->recvtime)<(oldecm->lastdecode.dcwchangetime*2)) {
// Setup Cw Cycle
if (oldecm->lastdecode.cwcycle=='0') ecm->lastdecode.cwcycle = '1';
else if (oldecm->lastdecode.cwcycle=='1') ecm->lastdecode.cwcycle = '0';
else return;
// check for cw1cycle
if (ecm->cw1cycle==0x80) { // cw1 cycle on tag=0x80
if ( (ecm->ecm[0]==0x80)&&(ecm->lastdecode.cwcycle!='1') ) return;
if ( (ecm->ecm[0]==0x81)&&(ecm->lastdecode.cwcycle!='0') ) return;
}
else if (ecm->cw1cycle==0x81) { // cw1 cycle on tag=0x81
if ( (ecm->ecm[0]==0x81)&&(ecm->lastdecode.cwcycle!='1') ) return;
if ( (ecm->ecm[0]==0x80)&&(ecm->lastdecode.cwcycle!='0') ) return;
}
//
ecm->lastdecode.ecm = oldecm;
ecm->lastdecode.counter = oldecm->lastdecode.counter;
// get average of ecm change time
ecm->lastdecode.dcwchangetime = (oldecm->lastdecode.dcwchangetime*oldecm->lastdecode.counter+(ecm->recvtime-oldecm->recvtime)) / (oldecm->lastdecode.counter+1);
ecm->lastdecode.dcwchangetime = ((ecm->lastdecode.dcwchangetime+300)/1000)*1000;
memcpy( ecm->lastdecode.dcw, oldecm->cw, 16); // Store latest DCW
}
}
else { //if (!ecm->lastdecode.ecm) {
// maybe??
ecm->lastdecode.ecm = oldecm;
ecm->lastdecode.counter = oldecm->lastdecode.counter;
ecm->lastdecode.dcwchangetime = ecm->recvtime-oldecm->recvtime;
memcpy( ecm->lastdecode.dcw, oldecm->cw, 16); // Store latest DCW
}
#ifdef TESTCHANNEL
int testchannel = ( (ecm->caid==cfg.testchn.caid) && (ecm->provid==cfg.testchn.provid) && (ecm->sid==cfg.testchn.sid) );
if (testchannel) {
char dump[64];
array2hex( oldecm->cw, dump, 16);
fdebugf(" Update Cycle ch %04x:%06x:%04x %02x:%08x ( %02x:%08x %s/%d)\n",ecm->caid, ecm->provid, ecm->sid, ecm->ecm[0],ecm->hash,
oldecm->ecm[0], oldecm->hash, dump, ecm->lastdecode.counter);
}
#endif
}
else if ( (oldecm->dcwstatus==STAT_DCW_FAILED) && (oldecm->hash==ecm->hash) && (oldecm->ecm[0]==ecm->ecm[0]) && !memcmp(oldecm->ecm+3, ecm->ecm+3, ecm->ecmlen-3) ){ // the same channel but we have freeze
memcpy( &ecm->lastdecode, &oldecm->lastdecode, sizeof(ecm->lastdecode) );
#ifdef TESTCHANNEL
int testchannel = ( (ecm->caid==cfg.testchn.caid) && (ecm->provid==cfg.testchn.provid) && (ecm->sid==cfg.testchn.sid) );
if (testchannel) {
char dump[64];
array2hex( oldecm->cw, dump, 16);
fdebugf(" Update Cycle after freeze ch %04x:%06x:%04x:%08x (%s/%d)\n",ecm->caid, ecm->provid, ecm->sid, ecm->hash, dump, ecm->lastdecode.counter);
}
#endif
}
}
}
// 1: success
// 2: inc
// 4: cwcycle
// return 0:wrong dcw, 1: good dcw
int checkfreeze_setdcw( ECM_DATA *ecm, uint8_t dcw[16] )
{
char nullcw[8] = "\0\0\0\0\0\0\0\0";
if (!ecm) return 0;
if (!ecm->lastdecode.ecm) return 1; // no old successful decode, random select
if ( dcwcmp16(dcw,ecm->lastdecode.dcw) ) return 0;
if ( dcwcmp8(dcw,nullcw) || dcwcmp8(dcw+8,nullcw) ) return 0;
if ( ecm->cw1cycle ) {
if ( dcwcmp8(dcw,ecm->lastdecode.dcw) && !dcwcmp8(dcw+8,ecm->lastdecode.dcw+8) && (ecm->cw1cycle==ecm->ecm[0]) ) return 7;
else if ( !dcwcmp8(dcw,ecm->lastdecode.dcw) && dcwcmp8(dcw+8,ecm->lastdecode.dcw+8) && (ecm->cw1cycle!=ecm->ecm[0]) ) return 3;
else if (ecm->lastdecode.counter>0) return 0;
else return 1;
}
else if ( ecm->lastdecode.cwcycle ) {
if ( dcwcmp8(dcw,ecm->lastdecode.dcw) && !dcwcmp8(dcw+8,ecm->lastdecode.dcw+8) && (ecm->lastdecode.cwcycle=='1') ) return 7;
else if ( !dcwcmp8(dcw,ecm->lastdecode.dcw) && dcwcmp8(dcw+8,ecm->lastdecode.dcw+8) && (ecm->lastdecode.cwcycle=='0') ) return 3;
else if (ecm->lastdecode.counter>0) return 0;
else return 1;
}
else {
if ( dcwcmp8(dcw,ecm->lastdecode.dcw) && !dcwcmp8(dcw+8,ecm->lastdecode.dcw+8) ) return 7;
else if ( !dcwcmp8(dcw,ecm->lastdecode.dcw) && dcwcmp8(dcw+8,ecm->lastdecode.dcw+8) ) return 3;
else return 1;
}
return 0;
}
#endif