TAILQ_HEAD(cwc_queue, cwc);
LIST_HEAD(cwc_transport_list, cwc_transport);
TAILQ_HEAD(cwc_message_queue, cwc_message);
-LIST_HEAD(ecm_channel_list, ecm_channel);
+LIST_HEAD(ecm_section_list, ecm_section);
static struct cwc_queue cwcs;
static pthread_cond_t cwc_config_changed;
/**
*
*/
-typedef struct ecm_channel {
- LIST_ENTRY(ecm_channel) ec_link;
- int ec_failures;
- int ec_channel;
-
- uint16_t ec_seq;
+typedef struct ecm_section {
+ int es_section;
+ int es_channel;
+
+ uint16_t es_seq;
+ char es_nok;
+ char es_pending;
- size_t ec_ecmsize;
- uint8_t ec_ecm[4096];
+ size_t es_ecmsize;
+ uint8_t es_ecm[4070];
-} ecm_channel_t;
+} ecm_section_t;
/**
LIST_ENTRY(cwc_transport) ct_link;
- struct ecm_channel_list ct_ecmchannels; // Status per ECM channel
int ct_okchannel;
/**
uint8_t *ct_tsbcluster;
int ct_fill;
+ int ct_last_section;
+ struct ecm_section *ct_sections[256];
+
} cwc_transport_t;
}
-/**
- *
- */
-static int
-channel_nok(cwc_transport_t *ct, ecm_channel_t *ec)
-{
- ec->ec_failures++;
-
- LIST_FOREACH(ec, &ct->ct_ecmchannels, ec_link)
- if(ec->ec_failures < 2)
- return 0;
- return 1;
-}
-
-
/**
* Login command
*/
cwc_send_msg(cwc, buf, ul + pl + 3, 0, 0);
}
-/**
- * Handle running reply
- * global_lock is held
- */
-static int
-cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len)
+
+
+static void
+handle_ecm_reply(cwc_transport_t *ct, ecm_section_t *es, uint8_t *msg,
+ int len, int seq)
{
- cwc_transport_t *ct;
- uint16_t seq = (msg[2] << 8) | msg[3];
- th_transport_t *t;
- int j;
- ecm_channel_t *ec = NULL;
+ th_transport_t *t = ct->ct_transport;
+ char chaninfo[32];
+ int i;
- len -= 12;
- msg += 12;
+ if(es->es_channel != -1) {
+ snprintf(chaninfo, sizeof(chaninfo), " (channel %d)", es->es_channel);
+ } else {
+ chaninfo[0] = 0;
+ }
- switch(msgtype) {
- case 0x80:
- case 0x81:
- LIST_FOREACH(ct, &cwc->cwc_transports, ct_link) {
- LIST_FOREACH(ec, &ct->ct_ecmchannels, ec_link) {
- if(ec->ec_seq == seq)
- goto gotch;
- }
- }
- tvhlog(LOG_ERR, "cwc", "Got unexpected ECM reply (seqno: %d)", seq);
- return 0;
+ es->es_pending = 0;
- gotch:
- t = ct->ct_transport;
+ if(len < 19) {
+
+ /* ERROR */
- if(len < 19) {
+ if(ct->ct_okchannel == es->es_channel)
+ ct->ct_okchannel = -1;
- if(ct->ct_okchannel == ec->ec_channel)
- ct->ct_okchannel = -1;
+ if(ct->ct_keystate == CT_FORBIDDEN)
+ return; // We already know it's bad
- if(ct->ct_keystate != CT_FORBIDDEN) {
+ es->es_nok = 1;
- if(ec->ec_channel != -1)
- tvhlog(LOG_DEBUG, "cwc", "Received NOK on channel %d (seqno: %d)",
- ec->ec_channel, seq);
+ tvhlog(LOG_DEBUG, "cwc", "Received NOK for service \"%s\"%s (seqno: %d)",
+ t->tht_svcname, chaninfo, seq);
- if(ec->ec_channel != -1 && !channel_nok(ct, ec))
- break;
+ for(i = 0; i <= ct->ct_last_section; i++)
+ if(ct->ct_sections[i] == NULL ||
+ ct->ct_sections[i]->es_pending ||
+ ct->ct_sections[i]->es_nok == 0)
+ return;
- tvhlog(LOG_ERR, "cwc",
- "Can not descramble service \"%s\", access denied (seqno: %d)",
- t->tht_svcname, seq);
- ct->ct_keystate = CT_FORBIDDEN;
- }
-
- } else {
+ tvhlog(LOG_ERR, "cwc",
+ "Can not descramble service \"%s\", access denied (seqno: %d)",
+ t->tht_svcname, seq);
+ ct->ct_keystate = CT_FORBIDDEN;
+ return;
- ct->ct_okchannel = ec->ec_channel;
+ } else {
- char chbuf[32];
+ ct->ct_okchannel = es->es_channel;
+ es->es_nok = 0;
+
+ tvhlog(LOG_DEBUG, "cwc",
+ "Received ECM reply%s for service \"%s\" "
+ "even: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x"
+ " odd: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x (seqno: %d)",
+ chaninfo,
+ t->tht_svcname,
+ msg[3 + 0], msg[3 + 1], msg[3 + 2], msg[3 + 3], msg[3 + 4],
+ msg[3 + 5], msg[3 + 6], msg[3 + 7], msg[3 + 8], msg[3 + 9],
+ msg[3 + 10],msg[3 + 11],msg[3 + 12],msg[3 + 13],msg[3 + 14],
+ msg[3 + 15], seq);
+
+ if(ct->ct_keystate != CT_RESOLVED)
+ tvhlog(LOG_INFO, "cwc",
+ "Obtained key for for service \"%s\"",t->tht_svcname);
+
+ ct->ct_keystate = CT_RESOLVED;
+ pthread_mutex_lock(&t->tht_stream_mutex);
- if(ec->ec_channel != -1) {
- snprintf(chbuf, sizeof(chbuf), " on channel %d", ec->ec_channel);
- } else {
- chbuf[0] = 0;
+ for(i = 0; i < 8; i++)
+ if(msg[3 + i]) {
+ set_even_control_word(ct->ct_keys, msg + 3);
+ break;
+ }
+
+ for(i = 0; i < 8; i++)
+ if(msg[3 + 8 + i]) {
+ set_odd_control_word(ct->ct_keys, msg + 3 + 8);
+ break;
}
-
- tvhlog(LOG_DEBUG, "cwc",
- "Received ECM reply%s for service \"%s\" "
- "even: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x"
- " odd: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x (seqno: %d)",
- chbuf,
- t->tht_svcname,
- msg[3 + 0], msg[3 + 1], msg[3 + 2], msg[3 + 3], msg[3 + 4],
- msg[3 + 5], msg[3 + 6], msg[3 + 7], msg[3 + 8], msg[3 + 9],
- msg[3 + 10],msg[3 + 11],msg[3 + 12],msg[3 + 13],msg[3 + 14],
- msg[3 + 15], seq);
-
- if(ct->ct_keystate != CT_RESOLVED)
- tvhlog(LOG_INFO, "cwc",
- "Obtained key for for service \"%s\"",t->tht_svcname);
- ct->ct_keystate = CT_RESOLVED;
- pthread_mutex_lock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->tht_stream_mutex);
+ }
+}
- for(j = 0; j < 8; j++)
- if(msg[3 + j]) {
- set_even_control_word(ct->ct_keys, msg + 3);
- break;
- }
- for(j = 0; j < 8; j++)
- if(msg[3 + 8 +j]) {
- set_odd_control_word(ct->ct_keys, msg + 3 + 8);
- break;
- }
-
- pthread_mutex_unlock(&t->tht_stream_mutex);
- }
+/**
+ * Handle running reply
+ * global_lock is held
+ */
+static int
+cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len)
+{
+ cwc_transport_t *ct;
+ ecm_section_t *es;
+ uint16_t seq = (msg[2] << 8) | msg[3];
+ int i;
- break;
+ len -= 12;
+ msg += 12;
- default:
- // EMM
+ switch(msgtype) {
+ case 0x80:
+ case 0x81:
+ LIST_FOREACH(ct, &cwc->cwc_transports, ct_link) {
+ for(i = 0; i <= ct->ct_last_section; i++) {
+ es = ct->ct_sections[i];
+ if(es != NULL) {
+ if(es->es_seq == seq && es->es_pending) {
+ handle_ecm_reply(ct, es, msg, len, seq);
+ return 0;
+ }
+ }
+ }
+ }
+ tvhlog(LOG_WARNING, "cwc", "Got unexpected ECM reply (seqno: %d)", seq);
break;
}
return 0;
}
+
/**
*
*/
uint16_t sid = t->tht_dvb_service_id;
cwc_t *cwc = ct->ct_cwc;
int channel;
- ecm_channel_t *ec;
+ int section;
+ ecm_section_t *es;
+ char chaninfo[32];
if(len > 4096)
return;
case 0x80:
case 0x81:
/* ECM */
+
+ ct->ct_last_section = data[5];
+ section = data[4];
if(cwc->cwc_caid >> 8 == 6) {
channel = data[6] << 8 | data[7];
+ snprintf(chaninfo, sizeof(chaninfo), " (channel %d)", channel);
} else {
channel = -1;
+ chaninfo[0] = 0;
}
- LIST_FOREACH(ec, &ct->ct_ecmchannels, ec_link)
- if(ec->ec_channel == channel)
- break;
+ if(ct->ct_sections[section] == NULL)
+ ct->ct_sections[section] = calloc(1, sizeof(ecm_section_t));
- if(ec == NULL) {
- ec = calloc(1, sizeof(ecm_channel_t));
- LIST_INSERT_HEAD(&ct->ct_ecmchannels, ec, ec_link);
- ec->ec_channel = channel;
- }
+ es = ct->ct_sections[section];
- if(ec->ec_ecmsize == len && !memcmp(ec->ec_ecm, data, len))
+ if(es->es_ecmsize == len && !memcmp(es->es_ecm, data, len))
break; /* key already sent */
if(cwc->cwc_fd == -1) {
break;
}
- memcpy(ec->ec_ecm, data, len);
- ec->ec_ecmsize = len;
+ es->es_channel = channel;
+ es->es_section = section;
+ es->es_pending = 1;
+
+ memcpy(es->es_ecm, data, len);
+ es->es_ecmsize = len;
if(ct->ct_okchannel != -1 && channel != -1 &&
ct->ct_okchannel != channel) {
return;
}
- ec->ec_seq = cwc_send_msg(cwc, data, len, sid, 1);
+ es->es_seq = cwc_send_msg(cwc, data, len, sid, 1);
- if(channel != -1) {
- tvhlog(LOG_DEBUG, "cwc",
- "Sending ECM (channel %d) for service %s (seqno: %d)",
- channel, t->tht_svcname, ec->ec_seq);
- } else {
- tvhlog(LOG_DEBUG, "cwc", "Sending ECM for service %s (seqno: %d)",
- t->tht_svcname, ec->ec_seq);
- }
+ tvhlog(LOG_DEBUG, "cwc",
+ "Sending ECM%s section=%d/%d, for service %s (seqno: %d)",
+ chaninfo, section, ct->ct_last_section, t->tht_svcname, es->es_seq);
break;
default:
cwc_transport_destroy(th_descrambler_t *td)
{
cwc_transport_t *ct = (cwc_transport_t *)td;
- ecm_channel_t *ec;
+ int i;
- while((ec = LIST_FIRST(&ct->ct_ecmchannels)) != NULL) {
- LIST_REMOVE(ec, ec_link);
- free(ec);
- }
+ for(i = 0; i < 256; i++)
+ free(ct->ct_sections[i]);
LIST_REMOVE(td, td_transport_link);