12 #include <linux/dvb/ca.h>
14 #include <netinet/in.h>
17 #include <sys/ioctl.h>
30 #define dbgprotocol(a...) do { if (DebugProtocol) fprintf(stderr, a); } while (0)
34 #define SIZE_INDICATOR 0x80
36 static const uint8_t *
GetLength(
const uint8_t *Data,
int &Length)
43 int l = Length & ~SIZE_INDICATOR;
45 for (
int i = 0; i < l; i++)
46 Length = (Length << 8) | *Data++;
51 static uint8_t *
SetLength(uint8_t *Data,
int Length)
59 int n =
sizeof(Length);
60 for (
int i = n - 1; i >= 0; i--) {
61 int b = (Length >> (8 * i)) & 0xFF;
77 while (Length > 0 && (*Data ==
' ' || *Data == 0x05 || *Data == 0x96 || *Data == 0x97)) {
81 char *s =
MALLOC(
char, Length + 1);
82 strncpy(s, (
char *)Data, Length);
89 static char *
GetString(
int &Length,
const uint8_t **Data)
94 if (Length > 0 && Data && *Data) {
98 Length -= d - *Data + l;
107 #define MAX_TPDU_SIZE 2048
108 #define MAX_TPDU_DATA (MAX_TPDU_SIZE - 4)
110 #define DATA_INDICATOR 0x80
114 #define T_CREATE_TC 0x82
115 #define T_CTC_REPLY 0x83
116 #define T_DELETE_TC 0x84
117 #define T_DTC_REPLY 0x85
118 #define T_REQUEST_TC 0x86
119 #define T_NEW_TC 0x87
120 #define T_TC_ERROR 0x88
121 #define T_DATA_LAST 0xA0
122 #define T_DATA_MORE 0xA1
128 const uint8_t *
GetData(
const uint8_t *
Data,
int &Length);
141 void Dump(
int SlotNumber,
bool Outgoing);
144 cTPDU::cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag,
int Length,
const uint8_t *Data)
170 esyslog(
"ERROR: invalid data length for TPDU tag 0x%02X: %d (%d/%d)", Tag, Length, Slot, Tcid);
179 memcpy(p, Data, Length);
183 esyslog(
"ERROR: invalid data length for TPDU tag 0x%02X: %d (%d/%d)", Tag, Length, Slot, Tcid);
186 esyslog(
"ERROR: unknown TPDU tag: 0x%02X (%d/%d)", Tag, Slot, Tcid);
194 fprintf(stderr,
" %d: %s ", SlotNumber, Outgoing ?
"-->" :
"<--");
196 fprintf(stderr,
"%02X ",
buffer[i]);
197 fprintf(stderr,
"%s\n",
size >= MAX_DUMP ?
"..." :
"");
199 fprintf(stderr,
" ");
200 for (
int i = 0; i <
size && i < MAX_DUMP; i++)
201 fprintf(stderr,
"%2c ", isprint(
buffer[i]) ?
buffer[i] :
'.');
202 fprintf(stderr,
"%s\n",
size >= MAX_DUMP ?
"..." :
"");
228 #define MAX_SESSIONS_PER_TC 16
242 void SendTPDU(uint8_t Tag,
int Length = 0,
const uint8_t *Data = NULL);
243 void SendTag(uint8_t Tag, uint16_t SessionId, uint32_t ResourceId = 0,
int Status = -1);
260 void SendData(
int Length,
const uint8_t *Data);
269 #define ST_SESSION_NUMBER 0x90
270 #define ST_OPEN_SESSION_REQUEST 0x91
271 #define ST_OPEN_SESSION_RESPONSE 0x92
272 #define ST_CREATE_SESSION 0x93
273 #define ST_CREATE_SESSION_RESPONSE 0x94
274 #define ST_CLOSE_SESSION_REQUEST 0x95
275 #define ST_CLOSE_SESSION_RESPONSE 0x96
280 #define SS_NOT_ALLOCATED 0xF0
284 #define RI_RESOURCE_MANAGER 0x00010041
285 #define RI_APPLICATION_INFORMATION 0x00020041
286 #define RI_CONDITIONAL_ACCESS_SUPPORT 0x00030041
287 #define RI_HOST_CONTROL 0x00200041
288 #define RI_DATE_TIME 0x00240041
289 #define RI_MMI 0x00400041
293 #define AOT_NONE 0x000000
294 #define AOT_PROFILE_ENQ 0x9F8010
295 #define AOT_PROFILE 0x9F8011
296 #define AOT_PROFILE_CHANGE 0x9F8012
297 #define AOT_APPLICATION_INFO_ENQ 0x9F8020
298 #define AOT_APPLICATION_INFO 0x9F8021
299 #define AOT_ENTER_MENU 0x9F8022
300 #define AOT_CA_INFO_ENQ 0x9F8030
301 #define AOT_CA_INFO 0x9F8031
302 #define AOT_CA_PMT 0x9F8032
303 #define AOT_CA_PMT_REPLY 0x9F8033
304 #define AOT_TUNE 0x9F8400
305 #define AOT_REPLACE 0x9F8401
306 #define AOT_CLEAR_REPLACE 0x9F8402
307 #define AOT_ASK_RELEASE 0x9F8403
308 #define AOT_DATE_TIME_ENQ 0x9F8440
309 #define AOT_DATE_TIME 0x9F8441
310 #define AOT_CLOSE_MMI 0x9F8800
311 #define AOT_DISPLAY_CONTROL 0x9F8801
312 #define AOT_DISPLAY_REPLY 0x9F8802
313 #define AOT_TEXT_LAST 0x9F8803
314 #define AOT_TEXT_MORE 0x9F8804
315 #define AOT_KEYPAD_CONTROL 0x9F8805
316 #define AOT_KEYPRESS 0x9F8806
317 #define AOT_ENQ 0x9F8807
318 #define AOT_ANSW 0x9F8808
319 #define AOT_MENU_LAST 0x9F8809
320 #define AOT_MENU_MORE 0x9F880A
321 #define AOT_MENU_ANSW 0x9F880B
322 #define AOT_LIST_LAST 0x9F880C
323 #define AOT_LIST_MORE 0x9F880D
324 #define AOT_SUBTITLE_SEGMENT_LAST 0x9F880E
325 #define AOT_SUBTITLE_SEGMENT_MORE 0x9F880F
326 #define AOT_DISPLAY_MESSAGE 0x9F8810
327 #define AOT_SCENE_END_MARK 0x9F8811
328 #define AOT_SCENE_DONE 0x9F8812
329 #define AOT_SCENE_CONTROL 0x9F8813
330 #define AOT_SUBTITLE_DOWNLOAD_LAST 0x9F8814
331 #define AOT_SUBTITLE_DOWNLOAD_MORE 0x9F8815
332 #define AOT_FLUSH_DOWNLOAD 0x9F8816
333 #define AOT_DOWNLOAD_REPLY 0x9F8817
334 #define AOT_COMMS_CMD 0x9F8C00
335 #define AOT_CONNECTION_DESCRIPTOR 0x9F8C01
336 #define AOT_COMMS_REPLY 0x9F8C02
337 #define AOT_COMMS_SEND_LAST 0x9F8C03
338 #define AOT_COMMS_SEND_MORE 0x9F8C04
339 #define AOT_COMMS_RCV_LAST 0x9F8C05
340 #define AOT_COMMS_RCV_MORE 0x9F8C06
348 int GetTag(
int &Length,
const uint8_t **Data);
349 const uint8_t *
GetData(
const uint8_t *Data,
int &Length);
350 void SendData(
int Tag,
int Length = 0,
const uint8_t *Data = NULL);
358 virtual void Process(
int Length = 0,
const uint8_t *Data = NULL);
377 if (Length >= 3 && Data && *Data) {
379 for (
int i = 0; i < 3; i++)
380 t = (t << 8) | *(*Data)++;
390 return Length ? Data : NULL;
395 uint8_t buffer[2048];
401 *p++ = (Tag >> 16) & 0xFF;
402 *p++ = (Tag >> 8) & 0xFF;
405 if (p - buffer + Length <
int(
sizeof(buffer))) {
406 memcpy(p, Data, Length);
411 esyslog(
"ERROR: CAM %d: data length (%d) exceeds buffer size",
Tc()->CamSlot()->SlotNumber(), Length);
425 virtual void Process(
int Length = 0,
const uint8_t *Data = NULL);
438 int Tag =
GetTag(Length, &Data);
457 const uint8_t *d =
GetData(Data, l);
459 esyslog(
"ERROR: CAM %d: resource manager: unexpected data",
Tc()->CamSlot()->SlotNumber());
465 esyslog(
"ERROR: CAM %d: resource manager: unexpected tag %06X in state %d",
Tc()->CamSlot()->SlotNumber(), Tag,
state);
469 default:
esyslog(
"ERROR: CAM %d: resource manager: unknown tag %06X",
Tc()->CamSlot()->SlotNumber(), Tag);
472 else if (
state == 0) {
491 virtual void Process(
int Length = 0,
const uint8_t *Data = NULL);
512 int Tag =
GetTag(Length, &Data);
517 const uint8_t *d =
GetData(Data, l);
518 if ((l -= 1) < 0)
break;
520 if ((l -= 2) < 0)
break;
523 if ((l -= 2) < 0)
break;
532 default:
esyslog(
"ERROR: CAM %d: application information: unknown tag %06X",
Tc()->CamSlot()->SlotNumber(), Tag);
535 else if (
state == 0) {
554 #define MAXCASYSTEMIDS 64
558 #define CPLM_MORE 0x00
559 #define CPLM_FIRST 0x01
560 #define CPLM_LAST 0x02
561 #define CPLM_ONLY 0x03
562 #define CPLM_ADD 0x04
563 #define CPLM_UPDATE 0x05
567 #define CPCI_OK_DESCRAMBLING 0x01
568 #define CPCI_OK_MMI 0x02
569 #define CPCI_QUERY 0x03
570 #define CPCI_NOT_SELECTED 0x04
585 cCiCaPmt(uint8_t
CmdId,
int Source,
int Transponder,
int ProgramNumber,
const int *CaSystemIds);
589 void AddPid(
int Pid, uint8_t StreamType);
592 cCiCaPmt::cCiCaPmt(uint8_t CmdId,
int Source,
int Transponder,
int ProgramNumber,
const int *CaSystemIds)
600 for (; CaSystemIds[i]; i++)
604 uint8_t caDescriptors[512];
625 uint8_t caDescriptors[512];
648 capmt[esInfoLengthPos + 1] = l & 0xFF;
652 esyslog(
"ERROR: buffer overflow in CA descriptor");
656 esyslog(
"ERROR: adding CA descriptor without Pid!");
663 #define CAEI_POSSIBLE 0x01
664 #define CAEI_POSSIBLE_COND_PURCHASE 0x02
665 #define CAEI_POSSIBLE_COND_TECHNICAL 0x03
666 #define CAEI_NOT_POSSIBLE_ENTITLEMENT 0x71
667 #define CAEI_NOT_POSSIBLE_TECHNICAL 0x73
669 #define CA_ENABLE_FLAG 0x80
671 #define CA_ENABLE(x) (((x) & CA_ENABLE_FLAG) ? (x) & ~CA_ENABLE_FLAG : 0)
673 #define QUERY_WAIT_TIME 1000 // ms to wait before sending a query
674 #define QUERY_REPLY_TIMEOUT 2000 // ms to wait for a reply to a query
685 virtual void Process(
int Length = 0,
const uint8_t *Data = NULL);
706 int Tag =
GetTag(Length, &Data);
712 const uint8_t *d =
GetData(Data, l);
714 uint16_t
id = ((uint16_t)(*d) << 8) | *(d + 1);
721 esyslog(
"ERROR: CAM %d: too many CA system IDs!",
Tc()->CamSlot()->SlotNumber());
736 dsyslog(
"CAM %d: replies to QUERY - multi channel decryption possible",
Tc()->CamSlot()->SlotNumber());
741 const uint8_t *d =
GetData(Data, l);
743 uint16_t pnr = ((uint16_t)(*d) << 8) | *(d + 1);
752 if (l % 3 == 0 && l > 1) {
758 uint16_t len = ((uint16_t)(*d) << 8) | *(d + 1);
764 unsigned char caepl = *d;
772 uint16_t pid = ((uint16_t)(*d) << 8) | *(d + 1);
773 unsigned char caees = *(d + 2);
788 default:
esyslog(
"ERROR: CAM %d: conditional access support: unknown tag %06X",
Tc()->CamSlot()->SlotNumber(), Tag);
791 else if (
state == 0) {
803 dsyslog(
"CAM %d: doesn't reply to QUERY - only a single channel can be decrypted",
Tc()->CamSlot()->SlotNumber());
810 if (CaPmt &&
state >= 2) {
826 virtual void Process(
int Length = 0,
const uint8_t *Data = NULL);
839 time_t t = time(NULL);
842 if (gmtime_r(&t, &tm_gmt) && localtime_r(&t, &tm_loc)) {
843 int Y = tm_gmt.tm_year;
844 int M = tm_gmt.tm_mon + 1;
845 int D = tm_gmt.tm_mday;
846 int L = (M == 1 || M == 2) ? 1 : 0;
847 int MJD = 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
848 #define DEC2BCD(d) uint8_t(((d / 10) << 4) + (d % 10))
849 struct tTime { uint16_t mjd; uint8_t h, m, s;
short offset; };
850 tTime T = { mjd : htons(MJD), h :
DEC2BCD(tm_gmt.tm_hour), m :
DEC2BCD(tm_gmt.tm_min), s :
DEC2BCD(tm_gmt.tm_sec), offset : short(htons(tm_loc.tm_gmtoff / 60)) };
863 int Tag =
GetTag(Length, &Data);
868 const uint8_t *d =
GetData(Data, l);
876 default:
esyslog(
"ERROR: CAM %d: date time: unknown tag %06X",
Tc()->CamSlot()->SlotNumber(), Tag);
889 #define DCC_SET_MMI_MODE 0x01
890 #define DCC_DISPLAY_CHARACTER_TABLE_LIST 0x02
891 #define DCC_INPUT_CHARACTER_TABLE_LIST 0x03
892 #define DCC_OVERLAY_GRAPHICS_CHARACTERISTICS 0x04
893 #define DCC_FULL_SCREEN_GRAPHICS_CHARACTERISTICS 0x05
897 #define MM_HIGH_LEVEL 0x01
898 #define MM_LOW_LEVEL_OVERLAY_GRAPHICS 0x02
899 #define MM_LOW_LEVEL_FULL_SCREEN_GRAPHICS 0x03
903 #define DRI_MMI_MODE_ACK 0x01
904 #define DRI_LIST_DISPLAY_CHARACTER_TABLES 0x02
905 #define DRI_LIST_INPUT_CHARACTER_TABLES 0x03
906 #define DRI_LIST_GRAPHIC_OVERLAY_CHARACTERISTICS 0x04
907 #define DRI_LIST_FULL_SCREEN_GRAPHIC_CHARACTERISTICS 0x05
908 #define DRI_UNKNOWN_DISPLAY_CONTROL_CMD 0xF0
909 #define DRI_UNKNOWN_MMI_MODE 0xF1
910 #define DRI_UNKNOWN_CHARACTER_TABLE 0xF2
914 #define EF_BLIND 0x01
918 #define AI_CANCEL 0x00
919 #define AI_ANSWER 0x01
923 char *
GetText(
int &Length,
const uint8_t **Data);
929 virtual void Process(
int Length = 0,
const uint8_t *Data = NULL);
965 int Tag =
GetTag(Length, Data);
972 esyslog(
"ERROR: CAM %d: MMI: unexpected text tag: %06X",
Tc()->CamSlot()->SlotNumber(), Tag);
979 int Tag =
GetTag(Length, &Data);
984 const uint8_t *d =
GetData(Data, l);
989 struct tDisplayReply { uint8_t id; uint8_t mode; };
995 default:
esyslog(
"ERROR: CAM %d: MMI: unsupported display control command %02X",
Tc()->CamSlot()->SlotNumber(), *d);
1006 const uint8_t *d =
GetData(Data, l);
1031 const uint8_t *d =
GetData(Data, l);
1033 uint8_t blind = *d++;
1048 const uint8_t *d =
GetData(Data, l);
1054 dbgprotocol(
"Slot %d: <== Close MMI (%d) id = %02X delay = %d\n",
Tc()->CamSlot()->SlotNumber(),
SessionId(),
id, delay);
1057 default:
esyslog(
"ERROR: CAM %d: MMI: unknown tag %06X",
Tc()->CamSlot()->SlotNumber(), Tag);
1093 struct tAnswer { uint8_t id;
char text[256]; };
1097 strncpy(answer.text, Text,
sizeof(answer.text));
1205 #define TC_POLL_TIMEOUT 300 // ms WORKAROUND: TC_POLL_TIMEOUT < 300ms doesn't work with DragonCAM
1206 #define TC_ALIVE_TIMEOUT 2000 // ms after which a transport connection is assumed dead
1231 return cas && cas->
Ready();
1257 uint8_t *p = buffer;
1268 buffer[1] = p - buffer - 2;
1303 if (Length == 6 && *(Data + 1) == 0x04) {
1309 switch (ResourceId) {
1334 if (Session &&
sessions[SessionId] == Session) {
1348 const uint8_t *Data = TPDU->
Data(Length);
1349 if (Data && Length > 1) {
1352 uint16_t SessionId = ntohs(
get_unaligned((uint16_t *)&Data[2]));
1355 Session->
Process(Length - 4, Data + 4);
1407 switch (TPDU->
Tag()) {
1434 esyslog(
"ERROR: unknown TPDU tag: 0x%02X (%s)", TPDU->
Tag(), __FUNCTION__);
1455 esyslog(
"ERROR: unknown state: %d (%s)",
state, __FUNCTION__);
1516 esyslog(
"ERROR: no free CAM slot in CI adapter");
1552 #define MODULE_CHECK_INTERVAL 500 // ms
1553 #define MODULE_RESET_TIMEOUT 2 // s
1574 CamSlots.
Del(
this,
false);
1611 if (d && d->
CamSlot() ==
this)
1643 int n = TPDU->
Tcid();
1682 esyslog(
"ERROR: unknown module status %d (%s)", ms, __FUNCTION__);
1802 if (CaSystemIds && *CaSystemIds) {
1804 for (
int Loop = 1; Loop <= 2; Loop++) {
1807 bool Active =
false;
1811 CaPmt.
AddPid(q->pid, q->streamType);
1815 if ((Loop == 1) != Active) {
1820 p->modified =
false;
1828 cCiCaPmt CaPmt(CmdId, 0, 0, 0, NULL);
1853 for (
const int *ids = cas->
GetCaSystemIds(); ids && *ids; ids++) {
1854 for (
const int *
id = CaSystemIds; *id;
id++) {
1868 if (p->programNumber == ProgramNumber) {
1886 if (q->pid == Pid) {
1887 if (q->active != Active) {
1898 #define STREAM_TYPE_VIDEO 0x02
1899 #define STREAM_TYPE_AUDIO 0x04
1900 #define STREAM_TYPE_PRIVATE 0x06
1911 for (
const int *Apid = Channel->
Apids(); *Apid; Apid++)
1913 for (
const int *Dpid = Channel->
Dpids(); *Dpid; Dpid++)
1915 for (
const int *Spid = Channel->
Spids(); *Spid; Spid++)
1922 #define QUERY_REPLY_WAIT 100 // ms to wait between checks for a reply
1936 for (
const int *Apid = Channel->
Apids(); *Apid; Apid++)
1938 for (
const int *Dpid = Channel->
Dpids(); *Dpid; Dpid++)
1940 for (
const int *Spid = Channel->
Spids(); *Spid; Spid++)
1993 #define CAM_CHECKED_TIMEOUT 15 // seconds before a CAM that has been checked for a particular channel will be checked again
2066 #define CHANNEL_CAM_RELATIONS_CLEANUP_INTERVAL 3600 // seconds between cleanups
2094 if (ccr->ChannelID() == ChannelID)
2113 ccr->ClrChecked(CamSlotNumber);
2114 ccr->ClrDecrypt(CamSlotNumber);
2122 return ccr ? ccr->
CamChecked(CamSlotNumber) :
false;
2129 return ccr ? ccr->
CamDecrypt(CamSlotNumber) :
false;