capmt: add simplified OSCam dvbapi protocol as new capmt mode

The new mode uses one domain socket connection for all subscribed
services. The CA_SET_PID and CA_SET_DESCR are received over same
socket connection instead of one UDP socket per adapter.

The minimum OSCam version for use with this mode is svn rev 9063.
This commit is contained in:
Mariusz Bialonczyk 2013-12-01 08:00:36 +01:00
parent 782cb80f2f
commit a02d9f8625

View file

@ -203,6 +203,9 @@ typedef struct capmt {
uint16_t capmt_seq;
} capmt_t;
static void capmt_enumerate_services(capmt_t *capmt, int es_pid, int force);
static void capmt_send_request(capmt_service_t *ct, int es_pid, int lm);
/**
*
*/
@ -210,48 +213,49 @@ static int
capmt_send_msg(capmt_t *capmt, int sid, const uint8_t *buf, size_t len)
{
if (capmt->capmt_oscam) {
int i;
// dumping current SID table
for (i = 0; i < MAX_SOCKETS; i++)
tvhlog(LOG_DEBUG, "capmt", "%s: SOCKETS TABLE DUMP [%d]: sid=%d socket=%d", __FUNCTION__, i, capmt->sids[i], capmt->capmt_sock[i]);
if (sid == 0) {
tvhlog(LOG_DEBUG, "capmt", "%s: got empty SID - returning from function", __FUNCTION__);
return -1;
}
// searching for the SID and socket
int i = 0;
int found = 0;
for (i = 0; i < MAX_SOCKETS; i++) {
if (capmt->sids[i] == sid) {
found = 1;
break;
if (capmt->capmt_oscam == 1) {
// dumping current SID table
for (i = 0; i < MAX_SOCKETS; i++)
tvhlog(LOG_DEBUG, "capmt", "%s: SOCKETS TABLE DUMP [%d]: sid=%d socket=%d", __FUNCTION__, i, capmt->sids[i], capmt->capmt_sock[i]);
if (sid == 0) {
tvhlog(LOG_DEBUG, "capmt", "%s: got empty SID - returning from function", __FUNCTION__);
return -1;
}
}
if (found)
tvhlog(LOG_DEBUG, "capmt", "%s: found sid, reusing socket, i=%d", __FUNCTION__, i);
else { //not found - adding to first free in table
// searching for the SID and socket
for (i = 0; i < MAX_SOCKETS; i++) {
if (capmt->sids[i] == 0) {
capmt->sids[i] = sid;
if (capmt->sids[i] == sid) {
found = 1;
break;
}
}
}
if (i == MAX_SOCKETS) {
tvhlog(LOG_DEBUG, "capmt", "%s: no free space for new SID!!!", __FUNCTION__);
return -1;
} else {
capmt->sids[i] = sid;
tvhlog(LOG_DEBUG, "capmt", "%s: added: i=%d", __FUNCTION__, i);
if (found)
tvhlog(LOG_DEBUG, "capmt", "%s: found sid, reusing socket, i=%d", __FUNCTION__, i);
else { //not found - adding to first free in table
for (i = 0; i < MAX_SOCKETS; i++) {
if (capmt->sids[i] == 0) {
capmt->sids[i] = sid;
break;
}
}
}
if (i == MAX_SOCKETS) {
tvhlog(LOG_DEBUG, "capmt", "%s: no free space for new SID!!!", __FUNCTION__);
return -1;
} else {
capmt->sids[i] = sid;
tvhlog(LOG_DEBUG, "capmt", "%s: added: i=%d", __FUNCTION__, i);
}
}
// check if the socket is still alive by writing 0 bytes
if (capmt->capmt_sock[i] > 0) {
if (write(capmt->capmt_sock[i], NULL, 0) < 0)
capmt->capmt_sock[i] = 0;
else if (found)
else if (capmt->capmt_oscam != 2 && found)
return 0;
}
@ -350,7 +354,8 @@ capmt_service_destroy(th_descrambler_t *td)
capmt_service_t *ct = (capmt_service_t *)td;
/* send stop to client */
capmt_send_stop(ct);
if (ct->ct_capmt->capmt_oscam != 2)
capmt_send_stop(ct);
capmt_caid_ecm_t *cce;
while (!LIST_EMPTY(&ct->ct_caid_ecm))
@ -367,6 +372,9 @@ capmt_service_destroy(th_descrambler_t *td)
tvhcsa_destroy(&ct->ct_csa);
free(ct);
if (ct->ct_capmt->capmt_oscam == 2)
capmt_enumerate_services(ct->ct_capmt, 0, 1);
}
static void
@ -374,11 +382,12 @@ handle_ca0(capmt_t* capmt) {
capmt_service_t *ct;
mpegts_service_t *t;
int ret, bufsize;
int *request;
int *request = NULL;
ca_descr_t *ca;
ca_pid_t *cpd;
int process_key, process_next, cai;
int i, j;
int recvsock = 0;
if (capmt->capmt_oscam)
bufsize = sizeof(int) + sizeof(ca_descr_t);
@ -407,36 +416,62 @@ handle_ca0(capmt_t* capmt) {
break;
}
} else {
process_next = 0;
if (capmt->capmt_sock_ca0[i] > 0) {
ret = recv(capmt->capmt_sock_ca0[i], buffer, bufsize, MSG_DONTWAIT);
if (ret < 0)
process_next = 1;
process_next = 1;
if (capmt->capmt_oscam == 2)
recvsock = capmt->capmt_sock[0];
else
recvsock = capmt->capmt_sock_ca0[i];
if (recvsock > 0) {
request = NULL;
ret = recv(recvsock, buffer, (capmt->capmt_oscam == 2) ? sizeof(int) : bufsize, MSG_DONTWAIT);
if (ret > 0) {
request = (int *) &buffer;
if (capmt->capmt_oscam != 2)
process_next = 0;
else {
int ret = 0;
if (*request == CA_SET_PID) //receive CA_SET_PID
ret = recv(recvsock, buffer+sizeof(int), sizeof(ca_pid_t), MSG_DONTWAIT);
else if (*request == CA_SET_DESCR) //receive CA_SET_DESCR
ret = recv(recvsock, buffer+sizeof(int), sizeof(ca_descr_t), MSG_DONTWAIT);
if (ret > 0)
process_next = 0;
}
}
else if (ret == 0) {
// normal socket shutdown
tvhlog(LOG_INFO, "capmt", "normal socket shutdown");
close(capmt->capmt_sock_ca0[i]);
capmt->capmt_sock_ca0[i] = -1;
int still_left = 0;
for (j = 0; j < MAX_CA; j++) {
if (capmt->capmt_sock_ca0[j] > 0) {
still_left = 1;
break;
// we are not connected any more - set services as unavailable
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
if (ct->ct_keystate != CT_FORBIDDEN) {
ct->ct_keystate = CT_FORBIDDEN;
}
}
if (still_left) //this socket is closed but there are others active
process_next = 1;
else //all sockets closed
int still_left = 0;
if (capmt->capmt_oscam != 2) {
close(capmt->capmt_sock_ca0[i]);
capmt->capmt_sock_ca0[i] = -1;
for (j = 0; j < MAX_CA; j++) {
if (capmt->capmt_sock_ca0[j] > 0) {
still_left = 1;
break;
}
}
}
if (!still_left) //all sockets closed
break;
}
} else
process_next = 1;
}
}
if (process_next) {
i++;
if (i >= MAX_CA)
i = 0;
if (capmt->capmt_oscam != 2) {
i++;
if (i >= MAX_CA)
i = 0;
}
usleep(10 * 1000);
continue;
}
@ -444,8 +479,9 @@ handle_ca0(capmt_t* capmt) {
// parsing data
if (capmt->capmt_oscam) {
if (!request)
continue;
cai = i;
request = (int *) &buffer;
if (*request == CA_SET_PID) {
cpd = (ca_pid_t *)&buffer[sizeof(int)];
tvhlog(LOG_DEBUG, "capmt", "CA_SET_PID cai %d req %d (%d %04x)", cai, *request, cpd->index, cpd->pid);
@ -484,35 +520,35 @@ handle_ca0(capmt_t* capmt) {
process_key = 1;
}
// processing key
if (process_key) {
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
t = ct->ct_service;
// processing key
if (process_key) {
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
t = ct->ct_service;
if(ret < bufsize) {
if(ct->ct_keystate != CT_FORBIDDEN) {
tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->s_dvb_svcname);
if (!capmt->capmt_oscam && ret < bufsize) {
if(ct->ct_keystate != CT_FORBIDDEN) {
tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->s_dvb_svcname);
ct->ct_keystate = CT_FORBIDDEN;
ct->ct_keystate = CT_FORBIDDEN;
}
continue;
}
continue;
if(seq != ct->ct_seq)
continue;
if (memcmp(even, invalid, 8))
tvhcsa_set_key_even(&ct->ct_csa, even);
if (memcmp(odd, invalid, 8))
tvhcsa_set_key_odd(&ct->ct_csa, odd);
if(ct->ct_keystate != CT_RESOLVED)
tvhlog(LOG_DEBUG, "capmt", "Obtained key for service \"%s\"",t->s_dvb_svcname);
ct->ct_keystate = CT_RESOLVED;
}
if(seq != ct->ct_seq)
continue;
if (memcmp(even, invalid, 8))
tvhcsa_set_key_even(&ct->ct_csa, even);
if (memcmp(odd, invalid, 8))
tvhcsa_set_key_odd(&ct->ct_csa, odd);
if(ct->ct_keystate != CT_RESOLVED)
tvhlog(LOG_DEBUG, "capmt", "Obtained key for service \"%s\"",t->s_dvb_svcname);
ct->ct_keystate = CT_RESOLVED;
}
}
}
tvhlog(LOG_INFO, "capmt", "connection from client closed ...");
@ -563,44 +599,45 @@ capmt_thread(void *aux)
pthread_mutex_unlock(&global_lock);
/* open connection to camd.socket */
capmt->capmt_sock[0] = tvh_socket(AF_LOCAL, SOCK_STREAM, 0);
if (capmt->capmt_oscam == 2)
handle_ca0(capmt);
else {
/* open connection to camd.socket */
capmt->capmt_sock[0] = tvh_socket(AF_LOCAL, SOCK_STREAM, 0);
struct sockaddr_un serv_addr_un;
memset(&serv_addr_un, 0, sizeof(serv_addr_un));
serv_addr_un.sun_family = AF_LOCAL;
snprintf(serv_addr_un.sun_path, sizeof(serv_addr_un.sun_path), "%s", capmt->capmt_sockfile);
struct sockaddr_un serv_addr_un;
memset(&serv_addr_un, 0, sizeof(serv_addr_un));
serv_addr_un.sun_family = AF_LOCAL;
snprintf(serv_addr_un.sun_path, sizeof(serv_addr_un.sun_path), "%s", capmt->capmt_sockfile);
if (connect(capmt->capmt_sock[0], (const struct sockaddr*)&serv_addr_un, sizeof(serv_addr_un)) == 0) {
capmt->capmt_connected = 1;
if (connect(capmt->capmt_sock[0], (const struct sockaddr*)&serv_addr_un, sizeof(serv_addr_un)) == 0) {
capmt->capmt_connected = 1;
/* open connection to emulated ca0 device */
if (!capmt->capmt_oscam) {
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[0],
capmt->capmt_port);
} else {
int i, n;
extern const idclass_t linuxdvb_adapter_class;
linuxdvb_adapter_t *la;
idnode_set_t *is = idnode_find_all(&linuxdvb_adapter_class);
for (i = 0; i < is->is_count; i++) {
la = (linuxdvb_adapter_t*)is->is_array[i];
if (!la || !la->la_is_enabled(la)) continue;
n = la->la_dvb_number;
if (n < 0 || n > MAX_CA) {
tvhlog(LOG_ERR, "capmt", "adapter number > MAX_CA");
continue;
/* open connection to emulated ca0 device */
if (!capmt->capmt_oscam) {
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[0], capmt->capmt_port);
} else {
int i, n;
extern const idclass_t linuxdvb_adapter_class;
linuxdvb_adapter_t *la;
idnode_set_t *is = idnode_find_all(&linuxdvb_adapter_class);
for (i = 0; i < is->is_count; i++) {
la = (linuxdvb_adapter_t*)is->is_array[i];
if (!la || !la->la_is_enabled(la)) continue;
n = la->la_dvb_number;
if (n < 0 || n > MAX_CA) {
tvhlog(LOG_ERR, "capmt", "adapter number > MAX_CA");
continue;
}
tvhlog(LOG_INFO, "capmt", "created UDP socket %d", n);
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[n], capmt->capmt_port + n);
}
tvhlog(LOG_INFO, "capmt", "created UDP socket %d", n);
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[n],
capmt->capmt_port + n);
}
}
if (bind_ok)
handle_ca0(capmt);
} else
tvhlog(LOG_ERR, "capmt", "Error connecting to %s: %s", capmt->capmt_sockfile, strerror(errno));
if (bind_ok)
handle_ca0(capmt);
} else
tvhlog(LOG_ERR, "capmt", "Error connecting to %s: %s", capmt->capmt_sockfile, strerror(errno));
}
capmt->capmt_connected = 0;
/* close opened sockets */
@ -647,7 +684,6 @@ capmt_table_input(struct th_descrambler *td, struct service *s,
capmt_t *capmt = ct->ct_capmt;
mpegts_service_t *t = (mpegts_service_t*)s;
linuxdvb_frontend_t *lfe;
int adapter_num = -1;
int total_caids = 0, current_caid = 0;
/* Validate */
@ -657,7 +693,6 @@ capmt_table_input(struct th_descrambler *td, struct service *s,
lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input;
if (!idnode_is_instance(&lfe->ti_id, &linuxdvb_frontend_class))
return;
adapter_num = lfe->lfe_adapter->la_dvb_number;
caid_t *c;
@ -684,7 +719,7 @@ capmt_table_input(struct th_descrambler *td, struct service *s,
uint16_t caid = c->caid;
/* search ecmpid in list */
capmt_caid_ecm_t *cce, *cce2;
capmt_caid_ecm_t *cce;
LIST_FOREACH(cce, &ct->ct_caid_ecm, cce_link)
if (cce->cce_caid == caid)
break;
@ -711,133 +746,17 @@ capmt_table_input(struct th_descrambler *td, struct service *s,
break;
}
uint16_t sid = t->s_dvb_service_id;
uint16_t ecmpid = st->es_pid;
uint16_t transponder = t->s_dvb_mux->mm_tsid;
uint16_t onid = t->s_dvb_mux->mm_onid;
/* don't do too much requests */
if (current_caid == total_caids && caid != ct->ct_caid_last)
return;
static uint8_t pmtversion = 1;
/* buffer for capmt */
int pos = 0;
uint8_t buf[4094];
capmt_header_t head = {
.capmt_indicator = { 0x9F, 0x80, 0x32, 0x82, 0x00, 0x00 },
.capmt_list_management = CAPMT_LIST_ONLY,
.program_number = sid,
.version_number = 0,
.current_next_indicator = 0,
.program_info_length = 0,
.capmt_cmd_id = CAPMT_CMD_OK_DESCRAMBLING,
};
memcpy(&buf[pos], &head, sizeof(head));
pos += sizeof(head);
if (capmt->capmt_oscam)
{
capmt_descriptor_t dmd = {
.cad_type = CAPMT_DESC_DEMUX,
.cad_length = 0x02,
.cad_data = {
0, adapter_num }};
memcpy(&buf[pos], &dmd, dmd.cad_length + 2);
pos += dmd.cad_length + 2;
}
capmt_descriptor_t prd = {
.cad_type = CAPMT_DESC_PRIVATE,
.cad_length = 0x08,
.cad_data = { 0x00, 0x00, 0x00, 0x00, // enigma namespace goes here
transponder >> 8, transponder & 0xFF,
onid >> 8, onid & 0xFF
}};
memcpy(&buf[pos], &prd, prd.cad_length + 2);
pos += prd.cad_length + 2;
if (!capmt->capmt_oscam)
{
capmt_descriptor_t dmd = {
.cad_type = CAPMT_DESC_DEMUX,
.cad_length = 0x02,
.cad_data = {
1 << adapter_num, adapter_num }};
memcpy(&buf[pos], &dmd, dmd.cad_length + 2);
pos += dmd.cad_length + 2;
}
capmt_descriptor_t ecd = {
.cad_type = CAPMT_DESC_PID,
.cad_length = 0x02,
.cad_data = {
ecmpid >> 8, ecmpid & 0xFF }};
memcpy(&buf[pos], &ecd, ecd.cad_length + 2);
pos += ecd.cad_length + 2;
LIST_FOREACH(cce2, &ct->ct_caid_ecm, cce_link) {
capmt_descriptor_t cad = {
.cad_type = 0x09,
.cad_length = 0x04,
.cad_data = {
cce2->cce_caid >> 8, cce2->cce_caid & 0xFF,
cce2->cce_ecmpid >> 8 | 0xE0, cce2->cce_ecmpid & 0xFF}};
if (cce2->cce_providerid) { //we need to add provider ID to the data
if (cce2->cce_caid >> 8 == 0x01) {
cad.cad_length = 0x11;
cad.cad_data[4] = cce2->cce_providerid >> 8;
cad.cad_data[5] = cce2->cce_providerid & 0xffffff;
} else if (cce2->cce_caid >> 8 == 0x05) {
cad.cad_length = 0x0f;
cad.cad_data[10] = 0x14;
cad.cad_data[11] = cce2->cce_providerid >> 24;
cad.cad_data[12] = cce2->cce_providerid >> 16;
cad.cad_data[13] = cce2->cce_providerid >> 8;
cad.cad_data[14] = cce2->cce_providerid & 0xffffff;
} else if (cce2->cce_caid >> 8 == 0x18) {
cad.cad_length = 0x07;
cad.cad_data[5] = cce2->cce_providerid >> 8;
cad.cad_data[6] = cce2->cce_providerid & 0xffffff;
} else if (cce2->cce_caid >> 8 == 0x4a) {
cad.cad_length = 0x05;
cad.cad_data[4] = cce2->cce_providerid & 0xffffff;
} else
tvhlog(LOG_WARNING, "capmt", "Unknown CAID type, don't know where to put provider ID");
}
memcpy(&buf[pos], &cad, cad.cad_length + 2);
pos += cad.cad_length + 2;
tvhlog(LOG_DEBUG, "capmt", "adding ECMPID=0x%X (%d), CAID=0x%X (%d) PROVID=0x%X (%d)",
cce2->cce_ecmpid, cce2->cce_ecmpid,
cce2->cce_caid, cce2->cce_caid,
cce2->cce_providerid, cce2->cce_providerid);
}
uint8_t end[] = {
0x01, (ct->ct_seq >> 8) & 0xFF, ct->ct_seq & 0xFF, 0x00, 0x06 };
memcpy(&buf[pos], end, sizeof(end));
pos += sizeof(end);
buf[10] = ((pos - 5 - 12) & 0xF00) >> 8;
buf[11] = ((pos - 5 - 12) & 0xFF);
buf[4] = ((pos - 6) >> 8);
buf[5] = ((pos - 6) & 0xFF);
buf[7] = sid >> 8;
buf[8] = sid & 0xFF;
memcpy(cce->cce_ecm, data, len);
cce->cce_ecmsize = len;
if(ct->ct_keystate != CT_RESOLVED)
tvhlog(LOG_DEBUG, "capmt",
"Trying to obtain key for service \"%s\"",t->s_dvb_svcname);
buf[9] = pmtversion;
pmtversion = (pmtversion + 1) & 0x1F;
capmt_send_msg(capmt, sid, buf, pos);
if (capmt->capmt_oscam == 2)
capmt_enumerate_services(capmt, st->es_pid, 0);
else
capmt_send_request(ct, st->es_pid, CAPMT_LIST_ONLY);
break;
}
default:
@ -847,6 +766,166 @@ capmt_table_input(struct th_descrambler *td, struct service *s,
}
}
static void
capmt_send_request(capmt_service_t *ct, int es_pid, int lm)
{
capmt_t *capmt = ct->ct_capmt;
mpegts_service_t *t = ct->ct_service;
uint16_t sid = t->s_dvb_service_id;
uint16_t ecmpid = es_pid;
uint16_t transponder = t->s_dvb_mux->mm_tsid;
uint16_t onid = t->s_dvb_mux->mm_onid;
static uint8_t pmtversion = 1;
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input;
int adapter_num = lfe->lfe_adapter->la_dvb_number;
/* buffer for capmt */
int pos = 0;
uint8_t buf[4094];
capmt_header_t head = {
.capmt_indicator = { 0x9F, 0x80, 0x32, 0x82, 0x00, 0x00 },
.capmt_list_management = lm,
.program_number = sid,
.version_number = 0,
.current_next_indicator = 0,
.program_info_length = 0,
.capmt_cmd_id = CAPMT_CMD_OK_DESCRAMBLING,
};
memcpy(&buf[pos], &head, sizeof(head));
pos += sizeof(head);
if (capmt->capmt_oscam) {
capmt_descriptor_t dmd = {
.cad_type = CAPMT_DESC_DEMUX,
.cad_length = 0x02,
.cad_data = {
0, adapter_num }};
memcpy(&buf[pos], &dmd, dmd.cad_length + 2);
pos += dmd.cad_length + 2;
}
capmt_descriptor_t prd = {
.cad_type = CAPMT_DESC_PRIVATE,
.cad_length = 0x08,
.cad_data = { 0x00, 0x00, 0x00, 0x00, // enigma namespace goes here
transponder >> 8, transponder & 0xFF,
onid >> 8, onid & 0xFF }};
memcpy(&buf[pos], &prd, prd.cad_length + 2);
pos += prd.cad_length + 2;
if (!capmt->capmt_oscam) {
capmt_descriptor_t dmd = {
.cad_type = CAPMT_DESC_DEMUX,
.cad_length = 0x02,
.cad_data = {
1 << adapter_num, adapter_num }};
memcpy(&buf[pos], &dmd, dmd.cad_length + 2);
pos += dmd.cad_length + 2;
}
capmt_descriptor_t ecd = {
.cad_type = CAPMT_DESC_PID,
.cad_length = 0x02,
.cad_data = {
ecmpid >> 8, ecmpid & 0xFF }};
memcpy(&buf[pos], &ecd, ecd.cad_length + 2);
pos += ecd.cad_length + 2;
capmt_caid_ecm_t *cce2;
LIST_FOREACH(cce2, &ct->ct_caid_ecm, cce_link) {
capmt_descriptor_t cad = {
.cad_type = 0x09,
.cad_length = 0x04,
.cad_data = {
cce2->cce_caid >> 8, cce2->cce_caid & 0xFF,
cce2->cce_ecmpid >> 8 | 0xE0, cce2->cce_ecmpid & 0xFF}};
if (cce2->cce_providerid) { //we need to add provider ID to the data
if (cce2->cce_caid >> 8 == 0x01) {
cad.cad_length = 0x11;
cad.cad_data[4] = cce2->cce_providerid >> 8;
cad.cad_data[5] = cce2->cce_providerid & 0xffffff;
} else if (cce2->cce_caid >> 8 == 0x05) {
cad.cad_length = 0x0f;
cad.cad_data[10] = 0x14;
cad.cad_data[11] = cce2->cce_providerid >> 24;
cad.cad_data[12] = cce2->cce_providerid >> 16;
cad.cad_data[13] = cce2->cce_providerid >> 8;
cad.cad_data[14] = cce2->cce_providerid & 0xffffff;
} else if (cce2->cce_caid >> 8 == 0x18) {
cad.cad_length = 0x07;
cad.cad_data[5] = cce2->cce_providerid >> 8;
cad.cad_data[6] = cce2->cce_providerid & 0xffffff;
} else if (cce2->cce_caid >> 8 == 0x4a) {
cad.cad_length = 0x05;
cad.cad_data[4] = cce2->cce_providerid & 0xffffff;
} else
tvhlog(LOG_WARNING, "capmt", "Unknown CAID type, don't know where to put provider ID");
}
memcpy(&buf[pos], &cad, cad.cad_length + 2);
pos += cad.cad_length + 2;
tvhlog(LOG_DEBUG, "capmt", "adding ECMPID=0x%X (%d), CAID=0x%X (%d) PROVID=0x%X (%d)",
cce2->cce_ecmpid, cce2->cce_ecmpid,
cce2->cce_caid, cce2->cce_caid,
cce2->cce_providerid, cce2->cce_providerid);
}
uint8_t end[] = {
0x01, (ct->ct_seq >> 8) & 0xFF, ct->ct_seq & 0xFF, 0x00, 0x06 };
memcpy(&buf[pos], end, sizeof(end));
pos += sizeof(end);
buf[10] = ((pos - 5 - 12) & 0xF00) >> 8;
buf[11] = ((pos - 5 - 12) & 0xFF);
buf[4] = ((pos - 6) >> 8);
buf[5] = ((pos - 6) & 0xFF);
buf[7] = sid >> 8;
buf[8] = sid & 0xFF;
if(ct->ct_keystate != CT_RESOLVED)
tvhlog(LOG_DEBUG, "capmt",
"Trying to obtain key for service \"%s\"",t->s_dvb_svcname);
buf[9] = pmtversion;
pmtversion = (pmtversion + 1) & 0x1F;
capmt_send_msg(capmt, sid, buf, pos);
}
static void
capmt_enumerate_services(capmt_t *capmt, int es_pid, int force)
{
int lm = CAPMT_LIST_FIRST; //list management
int all_srv_count = 0; //all services
int res_srv_count = 0; //services with resolved state
int i = 0;
capmt_service_t *ct;
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
all_srv_count++;
if (ct->ct_keystate == CT_RESOLVED)
res_srv_count++;
}
if (!all_srv_count && !res_srv_count) {
// closing socket (oscam handle this as event and stop decrypting)
tvhlog(LOG_DEBUG, "capmt", "%s: no subscribed services, closing socket, fd=%d", __FUNCTION__, capmt->capmt_sock[0]);
if (capmt->capmt_sock[0] > 0)
close(capmt->capmt_sock[0]);
capmt->capmt_sock[0] = 0;
}
else if (force || (res_srv_count != all_srv_count)) {
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
if (all_srv_count == i + 1)
lm |= CAPMT_LIST_LAST;
capmt_send_request(ct, es_pid, lm);
lm = CAPMT_LIST_MORE;
i++;
}
}
}
/**
*