vdr  2.7.6
ci.c
Go to the documentation of this file.
1 /*
2  * ci.c: Common Interface
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: ci.c 5.2 2025/03/02 11:03:35 kls Exp $
8  */
9 
10 #include "ci.h"
11 #include <ctype.h>
12 #include <linux/dvb/ca.h>
13 #include <malloc.h>
14 #include <netinet/in.h>
15 #include <poll.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <sys/ioctl.h>
19 #include <time.h>
20 #include <unistd.h>
21 #include "device.h"
22 #include "mtd.h"
23 #include "pat.h"
24 #include "receiver.h"
25 #include "remux.h"
26 #include "libsi/si.h"
27 #include "skins.h"
28 #include "tools.h"
29 
30 // Set these to 'true' for debug output:
31 static bool DumpTPDUDataTransfer = false;
32 static bool DebugProtocol = false;
33 static bool DumpPolls = false;
34 static bool DumpDateTime = false;
35 
36 #define dbgprotocol(a...) do { if (DebugProtocol) fprintf(stderr, a); } while (0)
37 
38 // --- Helper functions ------------------------------------------------------
39 
40 #define SIZE_INDICATOR 0x80
41 
42 static const uint8_t *GetLength(const uint8_t *Data, int &Length)
46 {
47  Length = *Data++;
48  if ((Length & SIZE_INDICATOR) != 0) {
49  int l = Length & ~SIZE_INDICATOR;
50  Length = 0;
51  for (int i = 0; i < l; i++)
52  Length = (Length << 8) | *Data++;
53  }
54  return Data;
55 }
56 
57 static uint8_t *SetLength(uint8_t *Data, int Length)
60 {
61  uint8_t *p = Data;
62  if (Length < 128)
63  *p++ = Length;
64  else {
65  int n = sizeof(Length);
66  for (int i = n - 1; i >= 0; i--) {
67  int b = (Length >> (8 * i)) & 0xFF;
68  if (p != Data || b)
69  *++p = b;
70  }
71  *Data = (p - Data) | SIZE_INDICATOR;
72  p++;
73  }
74  return p;
75 }
76 
77 static char *CopyString(int Length, const uint8_t *Data)
80 {
81  char *s = MALLOC(char, Length + 1);
82  char *p = s;
83  while (Length > 0) {
84  int c = *Data;
85  if (isprint(c)) // some CAMs send funny characters in their strings, let's just skip them
86  *p++ = c;
87  else if (c == 0x8A) // the character 0x8A is used as newline, so let's put a real '\n' in there
88  *p++ = '\n';
89  Length--;
90  Data++;
91  }
92  *p = 0;
93  return s;
94 }
95 
96 static char *GetString(int &Length, const uint8_t **Data)
100 {
101  if (Length > 0 && Data && *Data) {
102  int l = 0;
103  const uint8_t *d = GetLength(*Data, l);
104  char *s = CopyString(l, d);
105  Length -= d - *Data + l;
106  *Data = d + l;
107  return s;
108  }
109  return NULL;
110 }
111 
112 // --- cCaPidReceiver --------------------------------------------------------
113 
114 // A receiver that is used to make the device receive the ECM pids, as well as the
115 // CAT and the EMM pids.
116 
117 class cCaPidReceiver : public cReceiver {
118 private:
121  uchar buffer[1024]; // CAT table length: 10 bit -> max. 1021 + 3 bytes
123  #define CAT_MAXPACKETS 6 // 6 * 184 = 1104 bytes for CAT table
124  uchar mtdCatBuffer[CAT_MAXPACKETS][TS_SIZE]; // TODO: handle multi table CATs!
126  int length;
129  void AddEmmPid(int Pid);
130  void DelEmmPids(void);
131 public:
132  cCaPidReceiver(void);
133  virtual ~cCaPidReceiver() override { Detach(); }
134  virtual void Receive(const uchar *Data, int Length) override;
135  bool HasCaPids(void) const { return NumPids() - emmPids.Size() - 1 > 0; }
136  void Reset(void) { DelEmmPids(); catVersion = -1; }
137  bool HandlingPid(void);
146  };
147 
149 {
150  catVersion = -1;
151  bufp = NULL;
152  mtdNumCatPackets = 0;
153  length = 0;
154  handlingPid = false;
155  cMutexLock MutexLock(&mutex);
156  handlingPid = true;
157  AddPid(CATPID);
158  handlingPid = false;
159 }
160 
162 {
163  for (int i = 0; i < emmPids.Size(); i++) {
164  if (emmPids[i] == Pid)
165  return;
166  }
167  emmPids.Append(Pid);
168  cMutexLock MutexLock(&mutex);
169  handlingPid = true;
170  AddPid(Pid);
171  handlingPid = false;
172 }
173 
175 {
176  cMutexLock MutexLock(&mutex);
177  handlingPid = true;
178  for (int i = 0; i < emmPids.Size(); i++)
179  DelPid(emmPids[i]);
180  emmPids.Clear();
181  handlingPid = false;
182 }
183 
184 void cCaPidReceiver::Receive(const uchar *Data, int Length)
185 {
186  if (TsPid(Data) == CATPID) {
187  cMtdCamSlot *MtdCamSlot = dynamic_cast<cMtdCamSlot *>(Device()->CamSlot());
188  const uchar *p = NULL;
189  if (TsPayloadStart(Data)) {
190  if (Data[5] == SI::TableIdCAT) {
191  if (bufp) { // incomplete multi-packet CAT
192  catVersion = -1;
193  bufp = NULL;
194  }
195  length = (int(Data[6] & 0x0F) << 8) | Data[7]; // section length (12 bit field)
196  if (length > 5) {
197  int v = (Data[10] & 0x3E) >> 1; // version number
198  if (v != catVersion) {
199  if (Data[11] == 0 && Data[12] == 0) { // section number, last section number
200  length += 3; // with TableIdCAT -> Data[5]
201  if (length > TS_SIZE - 5) {
202  int n = TS_SIZE - 5;
203  memcpy(buffer, Data + 5, n);
204  bufp = buffer + n;
205  length -= n;
206  }
207  else {
208  p = Data + 5; // no need to copy the data
209  }
210  if (MtdCamSlot) {
211  mtdNumCatPackets = 0;
212  memcpy(mtdCatBuffer[mtdNumCatPackets++], Data, TS_SIZE);
213  }
214  }
215  else
216  dsyslog("multi table CAT section - unhandled!");
217  catVersion = v;
218  }
219  else if (MtdCamSlot) {
220  for (int i = 0; i < mtdNumCatPackets; i++)
221  MtdCamSlot->PutCat(mtdCatBuffer[i], TS_SIZE);
222  }
223  }
224  }
225  }
226  else if (bufp && length > 0) {
227  int n = min(length, TS_SIZE - 4);
228  if (bufp + n - buffer <= int(sizeof(buffer))) {
229  memcpy(bufp, Data + 4, n);
230  bufp += n;
231  length -= n;
232  if (length <= 0) {
233  p = buffer;
234  length = bufp - buffer;
235  }
236  if (MtdCamSlot)
237  memcpy(mtdCatBuffer[mtdNumCatPackets++], Data, TS_SIZE);
238  }
239  else {
240  esyslog("ERROR: buffer overflow in cCaPidReceiver::Receive()");
241  bufp = NULL;
242  length = 0;
243  }
244  }
245  if (p) {
246  if (!SI::CRC32::crc32((const char *)p, length, 0xFFFFFFFF)) { // <TableIdCAT,....,crc32>
247  DelEmmPids();
248  for (int i = 8; i < length - 4; i++) { // -4 = checksum
249  if (p[i] == 0x09) {
250  int CaId = int(p[i + 2] << 8) | p[i + 3];
251  int EmmPid = Peek13(p + i + 4);
252  AddEmmPid(EmmPid);
253  if (MtdCamSlot)
254  MtdMapPid(const_cast<uchar *>(p + i + 4), MtdCamSlot->MtdMapper());
255  switch (CaId >> 8) {
256  case 0x01: for (int j = i + 7; j < i + p[i + 1] + 2; j += 4) {
257  EmmPid = Peek13(p + j);
258  AddEmmPid(EmmPid);
259  if (MtdCamSlot)
260  MtdMapPid(const_cast<uchar *>(p + j), MtdCamSlot->MtdMapper());
261  }
262  break;
263  }
264  i += p[i + 1] + 2 - 1; // -1 to compensate for the loop increment
265  }
266  }
267  if (MtdCamSlot) {
268  // update crc32
269  uint32_t crc = SI::CRC32::crc32((const char *)p, length - 4, 0xFFFFFFFF); // <TableIdCAT....>[crc32]
270  uchar *c = const_cast<uchar *>(p + length - 4);
271  *c++ = crc >> 24;
272  *c++ = crc >> 16;
273  *c++ = crc >> 8;
274  *c++ = crc;
275  // modify CAT packets
276  const uchar *t = p;
277  for (int i = 0, j = 5; i < mtdNumCatPackets; i++, j = 4) {
278  int n = min(length, TS_SIZE - j);
279  memcpy(mtdCatBuffer[i] + j, t, n);
280  t += n;
281  length -= n;
282  MtdCamSlot->PutCat(mtdCatBuffer[i], TS_SIZE);
283  }
284  }
285  }
286  else {
287  esyslog("ERROR: wrong checksum in CAT");
288  catVersion = -1;
289  }
290  p = NULL;
291  bufp = NULL;
292  length = 0;
293  }
294  }
295 }
296 
298 {
299  cMutexLock MutexLock(&mutex);
300  return handlingPid;
301 }
302 
303 // --- cCaActivationReceiver -------------------------------------------------
304 
305 // A receiver that is used to make the device stay on a given channel and
306 // keep the CAM slot assigned.
307 
308 #define UNSCRAMBLE_TIME 5 // seconds of receiving purely unscrambled data before considering the smart card "activated"
309 #define TS_PACKET_FACTOR 1024 // only process every TS_PACKET_FACTORth packet to keep the load down
310 
312 private:
316 protected:
317  virtual void Receive(const uchar *Data, int Length) override;
318 public:
319  cCaActivationReceiver(const cChannel *Channel, cCamSlot *CamSlot);
320  virtual ~cCaActivationReceiver() override;
321  };
322 
324 :cReceiver(Channel, MINPRIORITY + 1)
325 {
326  camSlot = CamSlot;
327  lastScrambledTime = time(NULL);
328  numTsPackets = 0;
329 }
330 
332 {
333  Detach();
334 }
335 
336 void cCaActivationReceiver::Receive(const uchar *Data, int Length)
337 {
338  if (numTsPackets++ % TS_PACKET_FACTOR == 0) {
339  time_t Now = time(NULL);
340  if (TsIsScrambled(Data))
341  lastScrambledTime = Now;
342  else if (Now - lastScrambledTime > UNSCRAMBLE_TIME) {
343  dsyslog("CAM %d: activated!", camSlot->MasterSlotNumber());
344  Skins.QueueMessage(mtInfo, tr("CAM activated!"));
345  cDevice *d = Device();
346  Detach();
347  if (d) {
348  if (cCamSlot *s = d->CamSlot())
349  s->CancelActivation(); // this will delete *this* object, so no more code referencing *this* after this call!
350  }
351  }
352  }
353 }
354 
355 // --- cCamResponse ----------------------------------------------------------
356 
357 // CAM Response Actions:
358 
359 #define CRA_NONE 0
360 #define CRA_DISCARD -1
361 #define CRA_CONFIRM -2
362 #define CRA_SELECT -3
363 
364 class cCamResponse : public cListObject {
365 private:
367  char *text;
368  int action;
369 public:
370  cCamResponse(void);
371  ~cCamResponse();
372  bool Parse(const char *s);
373  int Matches(int CamNumber, const char *Text) const;
374  };
375 
377 {
378  camNumber = -1;
379  text = NULL;
380  action = CRA_NONE;
381 }
382 
384 {
385  free(text);
386 }
387 
388 bool cCamResponse::Parse(const char *s)
389 {
390  // Number:
391  s = skipspace(s);
392  if (*s == '*') {
393  camNumber = 0; // all CAMs
394  s++;
395  }
396  else {
397  char *e;
398  camNumber = strtol(s, &e, 10);
399  if (e == s || camNumber <= 0)
400  return false;
401  s = e;
402  }
403  // Text:
404  s = skipspace(s);
405  char *t = const_cast<char *>(s); // might have to modify it
406  char *q = NULL; // holds a copy in case of backslashes
407  bool InQuotes = false;
408  while (*t) {
409  if (*t == '"') {
410  if (t == s) { // opening quotes
411  InQuotes = true;
412  s++;
413  }
414  else if (InQuotes) // closing quotes
415  break;
416  }
417  else if (*t == '\\') {
418  if (!q) { // need to make a copy in order to strip backslashes
419  q = strdup(s);
420  t = q + (t - s);
421  s = q;
422  }
423  memmove(t, t + 1, strlen(t));
424  }
425  else if (*t == ' ') {
426  if (!InQuotes)
427  break;
428  }
429  t++;
430  }
431  free(text); // just for safety
432  text = NULL;
433  if (t != s) {
434  text = strndup(s, t - s);
435  s = t + 1;
436  }
437  free(q);
438  if (!text)
439  return false;
440  // Action:
441  s = skipspace(s);
442  if (strcasecmp(s, "DISCARD") == 0) action = CRA_DISCARD;
443  else if (strcasecmp(s, "CONFIRM") == 0) action = CRA_CONFIRM;
444  else if (strcasecmp(s, "SELECT") == 0) action = CRA_SELECT;
445  else if (isnumber(s)) action = atoi(s);
446  else
447  return false;
448  return true;
449 }
450 
451 int cCamResponse::Matches(int CamNumber, const char *Text) const
452 {
453  if (!camNumber || camNumber == CamNumber) {
454  if (strcmp(text, Text) == 0)
455  return action;
456  }
457  return CRA_NONE;
458 }
459 
460 // --- cCamResponses --------------------------------------------------------
461 
462 class cCamResponses : public cConfig<cCamResponse> {
463 public:
464  int GetMatch(int CamNumber, const char *Text) const;
465  };
466 
467 int cCamResponses::GetMatch(int CamNumber, const char *Text) const
468 {
469  for (const cCamResponse *cr = First(); cr; cr = Next(cr)) {
470  int Action = cr->Matches(CamNumber, Text);
471  if (Action != CRA_NONE) {
472  dsyslog("CAM %d: auto response %4d to '%s'\n", CamNumber, Action, Text);
473  return Action;
474  }
475  }
476  return CRA_NONE;
477 }
478 
480 
481 bool CamResponsesLoad(const char *FileName, bool AllowComments, bool MustExist)
482 {
483  return CamResponses.Load(FileName, AllowComments, MustExist);
484 }
485 
486 // --- cTPDU -----------------------------------------------------------------
487 
488 #define MAX_TPDU_SIZE 4096
489 #define MAX_TPDU_DATA (MAX_TPDU_SIZE - 4)
490 
491 #define DATA_INDICATOR 0x80
492 
493 #define T_SB 0x80
494 #define T_RCV 0x81
495 #define T_CREATE_TC 0x82
496 #define T_CTC_REPLY 0x83
497 #define T_DELETE_TC 0x84
498 #define T_DTC_REPLY 0x85
499 #define T_REQUEST_TC 0x86
500 #define T_NEW_TC 0x87
501 #define T_TC_ERROR 0x88
502 #define T_DATA_LAST 0xA0
503 #define T_DATA_MORE 0xA1
504 
505 class cTPDU {
506 private:
507  int size;
509  const uint8_t *GetData(const uint8_t *Data, int &Length);
510 public:
511  cTPDU(void) { size = 0; }
512  cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag, int Length = 0, const uint8_t *Data = NULL);
513  uint8_t Slot(void) { return buffer[0]; }
514  uint8_t Tcid(void) { return buffer[1]; }
515  uint8_t Tag(void) { return buffer[2]; }
516  const uint8_t *Data(int &Length) { return GetData(buffer + 3, Length); }
517  uint8_t Status(void);
518  uint8_t *Buffer(void) { return buffer; }
519  int Size(void) { return size; }
520  void SetSize(int Size) { size = Size; }
521  int MaxSize(void) { return sizeof(buffer); }
522  void Dump(int SlotNumber, bool Outgoing);
523  };
524 
525 cTPDU::cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag, int Length, const uint8_t *Data)
526 {
527  size = 0;
528  buffer[0] = Slot;
529  buffer[1] = Tcid;
530  buffer[2] = Tag;
531  switch (Tag) {
532  case T_RCV:
533  case T_CREATE_TC:
534  case T_CTC_REPLY:
535  case T_DELETE_TC:
536  case T_DTC_REPLY:
537  case T_REQUEST_TC:
538  buffer[3] = 1; // length
539  buffer[4] = Tcid;
540  size = 5;
541  break;
542  case T_NEW_TC:
543  case T_TC_ERROR:
544  if (Length == 1) {
545  buffer[3] = 2; // length
546  buffer[4] = Tcid;
547  buffer[5] = Data[0];
548  size = 6;
549  }
550  else
551  esyslog("ERROR: invalid data length for TPDU tag 0x%02X: %d (%d/%d)", Tag, Length, Slot, Tcid);
552  break;
553  case T_DATA_LAST:
554  case T_DATA_MORE:
555  if (Length <= MAX_TPDU_DATA) {
556  uint8_t *p = buffer + 3;
557  p = SetLength(p, Length + 1);
558  *p++ = Tcid;
559  if (Length)
560  memcpy(p, Data, Length);
561  size = Length + (p - buffer);
562  }
563  else
564  esyslog("ERROR: invalid data length for TPDU tag 0x%02X: %d (%d/%d)", Tag, Length, Slot, Tcid);
565  break;
566  default:
567  esyslog("ERROR: unknown TPDU tag: 0x%02X (%d/%d)", Tag, Slot, Tcid);
568  }
569  }
570 
571 void cTPDU::Dump(int SlotNumber, bool Outgoing)
572 {
573  if (DumpTPDUDataTransfer && (DumpPolls || Tag() != T_SB)) {
574 #define MAX_DUMP 256
575  fprintf(stderr, " %d: %s ", SlotNumber, Outgoing ? "-->" : "<--");
576  for (int i = 0; i < size && i < MAX_DUMP; i++)
577  fprintf(stderr, "%02X ", buffer[i]);
578  fprintf(stderr, "%s\n", size >= MAX_DUMP ? "..." : "");
579  if (!Outgoing) {
580  fprintf(stderr, " ");
581  for (int i = 0; i < size && i < MAX_DUMP; i++)
582  fprintf(stderr, "%2c ", isprint(buffer[i]) ? buffer[i] : '.');
583  fprintf(stderr, "%s\n", size >= MAX_DUMP ? "..." : "");
584  }
585  }
586 }
587 
588 const uint8_t *cTPDU::GetData(const uint8_t *Data, int &Length)
589 {
590  if (size) {
591  Data = GetLength(Data, Length);
592  if (Length) {
593  Length--; // the first byte is always the tcid
594  return Data + 1;
595  }
596  }
597  return NULL;
598 }
599 
600 uint8_t cTPDU::Status(void)
601 {
602  if (size >= 4 && buffer[size - 4] == T_SB && buffer[size - 3] == 2)
603  return buffer[size - 1];
604  return 0;
605 }
606 
607 // --- cCiTransportConnection ------------------------------------------------
608 
609 #define MAX_SESSIONS_PER_TC 16
610 
612 private:
616  uint8_t tcid;
620  bool hasUserIO;
623  cCiSession *sessions[MAX_SESSIONS_PER_TC + 1]; // session numbering starts with 1
625  void SendTPDU(uint8_t Tag, int Length = 0, const uint8_t *Data = NULL);
626  void SendTag(uint8_t Tag, uint16_t SessionId, uint32_t ResourceId = 0, int Status = -1);
627  void Poll(void);
628  uint32_t ResourceIdToInt(const uint8_t *Data);
629  cCiSession *GetSessionBySessionId(uint16_t SessionId);
630  void OpenSession(int Length, const uint8_t *Data);
631  void CloseSession(uint16_t SessionId);
632  void HandleSessions(cTPDU *TPDU);
633 public:
635  virtual ~cCiTransportConnection();
636  void SetTsPostProcessor(cCiSession *CiSession);
637  bool TsPostProcess(uint8_t *TsPacket);
638  cCamSlot *CamSlot(void) { return camSlot; }
639  uint8_t Tcid(void) const { return tcid; }
642  const char *GetCamName(void);
643  bool Ready(void);
644  bool HasUserIO(void) { return hasUserIO; }
645  void SendData(int Length, const uint8_t *Data);
646  bool Process(cTPDU *TPDU = NULL);
647  cCiSession *GetSessionByResourceId(uint32_t ResourceId);
648  };
649 
650 // --- cCiSession ------------------------------------------------------------
651 
652 // Session Tags:
653 
654 #define ST_SESSION_NUMBER 0x90
655 #define ST_OPEN_SESSION_REQUEST 0x91
656 #define ST_OPEN_SESSION_RESPONSE 0x92
657 #define ST_CREATE_SESSION 0x93
658 #define ST_CREATE_SESSION_RESPONSE 0x94
659 #define ST_CLOSE_SESSION_REQUEST 0x95
660 #define ST_CLOSE_SESSION_RESPONSE 0x96
661 
662 // Session Status:
663 
664 #define SS_OK 0x00
665 #define SS_NOT_ALLOCATED 0xF0
666 
667 // Resource Identifiers:
668 
669 #define RI_RESOURCE_MANAGER 0x00010041
670 #define RI_APPLICATION_INFORMATION 0x00020041
671 #define RI_CONDITIONAL_ACCESS_SUPPORT 0x00030041
672 #define RI_HOST_CONTROL 0x00200041
673 #define RI_DATE_TIME 0x00240041
674 #define RI_MMI 0x00400041
675 
676 // Application Object Tags:
677 
678 #define AOT_NONE 0x000000
679 #define AOT_PROFILE_ENQ 0x9F8010
680 #define AOT_PROFILE 0x9F8011
681 #define AOT_PROFILE_CHANGE 0x9F8012
682 #define AOT_APPLICATION_INFO_ENQ 0x9F8020
683 #define AOT_APPLICATION_INFO 0x9F8021
684 #define AOT_ENTER_MENU 0x9F8022
685 #define AOT_CA_INFO_ENQ 0x9F8030
686 #define AOT_CA_INFO 0x9F8031
687 #define AOT_CA_PMT 0x9F8032
688 #define AOT_CA_PMT_REPLY 0x9F8033
689 #define AOT_TUNE 0x9F8400
690 #define AOT_REPLACE 0x9F8401
691 #define AOT_CLEAR_REPLACE 0x9F8402
692 #define AOT_ASK_RELEASE 0x9F8403
693 #define AOT_DATE_TIME_ENQ 0x9F8440
694 #define AOT_DATE_TIME 0x9F8441
695 #define AOT_CLOSE_MMI 0x9F8800
696 #define AOT_DISPLAY_CONTROL 0x9F8801
697 #define AOT_DISPLAY_REPLY 0x9F8802
698 #define AOT_TEXT_LAST 0x9F8803
699 #define AOT_TEXT_MORE 0x9F8804
700 #define AOT_KEYPAD_CONTROL 0x9F8805
701 #define AOT_KEYPRESS 0x9F8806
702 #define AOT_ENQ 0x9F8807
703 #define AOT_ANSW 0x9F8808
704 #define AOT_MENU_LAST 0x9F8809
705 #define AOT_MENU_MORE 0x9F880A
706 #define AOT_MENU_ANSW 0x9F880B
707 #define AOT_LIST_LAST 0x9F880C
708 #define AOT_LIST_MORE 0x9F880D
709 #define AOT_SUBTITLE_SEGMENT_LAST 0x9F880E
710 #define AOT_SUBTITLE_SEGMENT_MORE 0x9F880F
711 #define AOT_DISPLAY_MESSAGE 0x9F8810
712 #define AOT_SCENE_END_MARK 0x9F8811
713 #define AOT_SCENE_DONE 0x9F8812
714 #define AOT_SCENE_CONTROL 0x9F8813
715 #define AOT_SUBTITLE_DOWNLOAD_LAST 0x9F8814
716 #define AOT_SUBTITLE_DOWNLOAD_MORE 0x9F8815
717 #define AOT_FLUSH_DOWNLOAD 0x9F8816
718 #define AOT_DOWNLOAD_REPLY 0x9F8817
719 #define AOT_COMMS_CMD 0x9F8C00
720 #define AOT_CONNECTION_DESCRIPTOR 0x9F8C01
721 #define AOT_COMMS_REPLY 0x9F8C02
722 #define AOT_COMMS_SEND_LAST 0x9F8C03
723 #define AOT_COMMS_SEND_MORE 0x9F8C04
724 #define AOT_COMMS_RCV_LAST 0x9F8C05
725 #define AOT_COMMS_RCV_MORE 0x9F8C06
726 
727 #define RESOURCE_CLASS_MASK 0xFFFF0000
728 
729 cCiSession::cCiSession(uint16_t SessionId, uint32_t ResourceId, cCiTransportConnection *Tc)
730 {
733  tc = Tc;
734 }
735 
737 {
738 }
739 
740 void cCiSession::SetResourceId(uint32_t Id)
741 {
742  resourceId = Id;
743 }
744 
746 {
747  tc->SetTsPostProcessor(this);
748 }
749 
750 int cCiSession::GetTag(int &Length, const uint8_t **Data)
754 {
755  if (Length >= 3 && Data && *Data) {
756  int t = 0;
757  for (int i = 0; i < 3; i++)
758  t = (t << 8) | *(*Data)++;
759  Length -= 3;
760  return t;
761  }
762  return AOT_NONE;
763 }
764 
765 const uint8_t *cCiSession::GetData(const uint8_t *Data, int &Length)
766 {
767  Data = GetLength(Data, Length);
768  return Length ? Data : NULL;
769 }
770 
771 void cCiSession::SendData(int Tag, int Length, const uint8_t *Data)
772 {
773  uint8_t buffer[MAX_TPDU_SIZE];
774  uint8_t *p = buffer;
775  *p++ = ST_SESSION_NUMBER;
776  *p++ = 0x02;
777  *p++ = (sessionId >> 8) & 0xFF;
778  *p++ = sessionId & 0xFF;
779  *p++ = (Tag >> 16) & 0xFF;
780  *p++ = (Tag >> 8) & 0xFF;
781  *p++ = Tag & 0xFF;
782  p = SetLength(p, Length);
783  if (p - buffer + Length < int(sizeof(buffer))) {
784  if (Data)
785  memcpy(p, Data, Length);
786  p += Length;
787  tc->SendData(p - buffer, buffer);
788  }
789  else
790  esyslog("ERROR: CAM %d: data length (%d) exceeds buffer size", CamSlot()->SlotNumber(), Length);
791 }
792 
794 {
795  return Tc()->CamSlot();
796 }
797 
798 void cCiSession::Process(int Length, const uint8_t *Data)
799 {
800 }
801 
802 // --- cCiResourceManager ----------------------------------------------------
803 
805 private:
806  int state;
807 public:
809  virtual void Process(int Length = 0, const uint8_t *Data = NULL) override;
810  };
811 
813 :cCiSession(SessionId, RI_RESOURCE_MANAGER, Tc)
814 {
815  dbgprotocol("Slot %d: new Resource Manager (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
816  state = 0;
817 }
818 
819 void cCiResourceManager::Process(int Length, const uint8_t *Data)
820 {
821  if (Data) {
822  int Tag = GetTag(Length, &Data);
823  switch (Tag) {
824  case AOT_PROFILE_ENQ: {
825  dbgprotocol("Slot %d: <== Profile Enquiry (%d)\n", CamSlot()->SlotNumber(), SessionId());
826  dbgprotocol("Slot %d: ==> Profile (%d)\n", CamSlot()->SlotNumber(), SessionId());
827  SendData(AOT_PROFILE, CiResourceHandlers.NumIds() * sizeof(uint32_t), (uint8_t*)CiResourceHandlers.Ids());
828  state = 3;
829  }
830  break;
831  case AOT_PROFILE: {
832  dbgprotocol("Slot %d: <== Profile (%d)\n", CamSlot()->SlotNumber(), SessionId());
833  if (state == 1) {
834  int l = 0;
835  const uint8_t *d = GetData(Data, l);
836  if (l > 0 && d)
837  esyslog("ERROR: CAM %d: resource manager: unexpected data", CamSlot()->SlotNumber());
838  dbgprotocol("Slot %d: ==> Profile Change (%d)\n", CamSlot()->SlotNumber(), SessionId());
840  state = 2;
841  }
842  else {
843  esyslog("ERROR: CAM %d: resource manager: unexpected tag %06X in state %d", CamSlot()->SlotNumber(), Tag, state);
844  }
845  }
846  break;
847  default: esyslog("ERROR: CAM %d: resource manager: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
848  }
849  }
850  else if (state == 0) {
851  dbgprotocol("Slot %d: ==> Profile Enq (%d)\n", CamSlot()->SlotNumber(), SessionId());
853  state = 1;
854  }
855 }
856 
857 // --- cCiApplicationInformation ---------------------------------------------
858 
860 :cCiSession(SessionId, RI_APPLICATION_INFORMATION, Tc)
861 {
862  dbgprotocol("Slot %d: new Application Information (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
863  state = 0;
864  menuString = NULL;
865 }
866 
868 {
869  free(menuString);
870 }
871 
872 void cCiApplicationInformation::Process(int Length, const uint8_t *Data)
873 {
874  if (Data) {
875  int Tag = GetTag(Length, &Data);
876  switch (Tag) {
877  case AOT_APPLICATION_INFO: {
878  dbgprotocol("Slot %d: <== Application Info (%d)\n", CamSlot()->SlotNumber(), SessionId());
879  int l = 0;
880  const uint8_t *d = GetData(Data, l);
881  if ((l -= 1) < 0) break;
882  applicationType = *d++;
883  if ((l -= 2) < 0) break;
884  applicationManufacturer = ntohs(get_unaligned((uint16_t *)d));
885  d += 2;
886  if ((l -= 2) < 0) break;
887  manufacturerCode = ntohs(get_unaligned((uint16_t *)d));
888  d += 2;
889  free(menuString);
890  menuString = GetString(l, &d);
891  isyslog("CAM %d: %s, %02X, %04X, %04X", CamSlot()->SlotNumber(), menuString, applicationType, applicationManufacturer, manufacturerCode);
892  state = 2;
893  }
894  break;
895  default: esyslog("ERROR: CAM %d: application information: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
896  }
897  }
898  else if (state == 0) {
899  dbgprotocol("Slot %d: ==> Application Info Enq (%d)\n", CamSlot()->SlotNumber(), SessionId());
901  state = 1;
902  }
903 }
904 
906 {
907  if (state == 2) {
908  dbgprotocol("Slot %d: ==> Enter Menu (%d)\n", CamSlot()->SlotNumber(), SessionId());
910  return true;
911  }
912  return false;
913 }
914 
915 // --- cCiCaPmt --------------------------------------------------------------
916 
917 #define MAXCASYSTEMIDS 64
918 
919 // Ca Pmt List Management:
920 
921 #define CPLM_MORE 0x00
922 #define CPLM_FIRST 0x01
923 #define CPLM_LAST 0x02
924 #define CPLM_ONLY 0x03
925 #define CPLM_ADD 0x04
926 #define CPLM_UPDATE 0x05
927 
928 // Ca Pmt Cmd Ids:
929 
930 #define CPCI_OK_DESCRAMBLING 0x01
931 #define CPCI_OK_MMI 0x02
932 #define CPCI_QUERY 0x03
933 #define CPCI_NOT_SELECTED 0x04
934 
935 class cCiCaPmt {
937 private:
938  uint8_t cmdId;
942  int source;
945  int caSystemIds[MAXCASYSTEMIDS + 1]; // list is zero terminated!
946  void AddCaDescriptors(int Length, const uint8_t *Data);
947 public:
948  cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const int *CaSystemIds);
949  uint8_t CmdId(void) { return cmdId; }
950  void SetListManagement(uint8_t ListManagement);
951  uint8_t ListManagement(void) { return capmt.Get(0); }
952  void AddPid(int Pid, uint8_t StreamType);
953  void MtdMapPids(cMtdMapper *MtdMapper);
954  };
955 
956 cCiCaPmt::cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const int *CaSystemIds)
957 {
958  cmdId = CmdId;
959  source = Source;
960  transponder = Transponder;
961  programNumber = ProgramNumber;
962  int i = 0;
963  if (CaSystemIds) {
964  for (; CaSystemIds[i]; i++)
965  caSystemIds[i] = CaSystemIds[i];
966  }
967  caSystemIds[i] = 0;
970  capmt.Append((ProgramNumber >> 8) & 0xFF);
971  capmt.Append( ProgramNumber & 0xFF);
972  capmt.Append(0x01); // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1
974  capmt.Append(0x00); // program_info_length H (at program level)
975  capmt.Append(0x00); // program_info_length L
977 }
978 
979 void cCiCaPmt::SetListManagement(uint8_t ListManagement)
980 {
982 }
983 
984 void cCiCaPmt::AddPid(int Pid, uint8_t StreamType)
985 {
986  if (Pid) {
988  capmt.Append(StreamType);
989  capmt.Append((Pid >> 8) & 0xFF);
990  capmt.Append( Pid & 0xFF);
992  capmt.Append(0x00); // ES_info_length H (at ES level)
993  capmt.Append(0x00); // ES_info_length L
995  }
996 }
997 
998 void cCiCaPmt::AddCaDescriptors(int Length, const uint8_t *Data)
999 {
1000  if (esInfoLengthPos) {
1001  if (Length || cmdId == CPCI_QUERY) {
1002  capmt.Append(cmdId);
1003  capmt.Append(Data, Length);
1004  int l = capmt.Length() - esInfoLengthPos - 2;
1005  capmt.Set(esInfoLengthPos, (l >> 8) & 0xFF);
1006  capmt.Set(esInfoLengthPos + 1, l & 0xFF);
1007  }
1008  esInfoLengthPos = 0;
1009  }
1010  else
1011  esyslog("ERROR: adding CA descriptor without Pid!");
1012 }
1013 
1014 static int MtdMapCaDescriptor(uchar *p, cMtdMapper *MtdMapper)
1015 {
1016  // See pat.c: cCaDescriptor::cCaDescriptor() for the layout of the data!
1017  if (*p == SI::CaDescriptorTag) {
1018  int l = *++p;
1019  if (l >= 4) {
1020  MtdMapPid(p + 3, MtdMapper);
1021  return l + 2;
1022  }
1023  else
1024  esyslog("ERROR: wrong length (%d) in MtdMapCaDescriptor()", l);
1025  }
1026  else
1027  esyslog("ERROR: wrong tag (%d) in MtdMapCaDescriptor()", *p);
1028  return -1;
1029 }
1030 
1031 static int MtdMapCaDescriptors(uchar *p, cMtdMapper *MtdMapper)
1032 {
1033  int Length = p[0] * 256 + p[1];
1034  if (Length >= 3) {
1035  p += 3;
1036  int m = Length - 1;
1037  while (m > 0) {
1038  int l = MtdMapCaDescriptor(p, MtdMapper);
1039  if (l > 0) {
1040  p += l;
1041  m -= l;
1042  }
1043  }
1044  }
1045  return Length + 2;
1046 }
1047 
1048 static int MtdMapStream(uchar *p, cMtdMapper *MtdMapper)
1049 {
1050  // See ci.c: cCiCaPmt::AddPid() for the layout of the data!
1051  MtdMapPid(p + 1, MtdMapper);
1052  int l = MtdMapCaDescriptors(p + 3, MtdMapper);
1053  if (l > 0)
1054  return l + 3;
1055  return -1;
1056 }
1057 
1058 static int MtdMapStreams(uchar *p, cMtdMapper *MtdMapper, int Length)
1059 {
1060  int m = Length;
1061  while (m >= 5) {
1062  int l = MtdMapStream(p, MtdMapper);
1063  if (l > 0) {
1064  p += l;
1065  m -= l;
1066  }
1067  else
1068  break;
1069  }
1070  return Length;
1071 }
1072 
1074 {
1075  uchar *p = capmt.Data();
1076  int m = capmt.Length();
1077  if (m >= 3) {
1078  MtdMapSid(p + 1, MtdMapper);
1079  p += 4;
1080  m -= 4;
1081  if (m >= 2) {
1082  int l = MtdMapCaDescriptors(p, MtdMapper);
1083  if (l >= 0) {
1084  p += l;
1085  m -= l;
1086  MtdMapStreams(p, MtdMapper, m);
1087  }
1088  }
1089  }
1090 }
1091 
1092 // --- cCiConditionalAccessSupport -------------------------------------------
1093 
1094 // CA Enable Ids:
1095 
1096 #define CAEI_POSSIBLE 0x01
1097 #define CAEI_POSSIBLE_COND_PURCHASE 0x02
1098 #define CAEI_POSSIBLE_COND_TECHNICAL 0x03
1099 #define CAEI_NOT_POSSIBLE_ENTITLEMENT 0x71
1100 #define CAEI_NOT_POSSIBLE_TECHNICAL 0x73
1101 
1102 #define CA_ENABLE_FLAG 0x80
1103 
1104 #define CA_ENABLE(x) (((x) & CA_ENABLE_FLAG) ? (x) & ~CA_ENABLE_FLAG : 0)
1105 
1106 #define QUERY_WAIT_TIME 500 // ms to wait before sending a query
1107 #define QUERY_REPLY_TIMEOUT 2000 // ms to wait for a reply to a query
1108 #define QUERY_RETRIES 6 // max. number of retries to check if there is a reply to a query
1109 
1111 private:
1112  int state;
1114  int caSystemIds[MAXCASYSTEMIDS + 1]; // list is zero terminated!
1118 public:
1120  virtual void Process(int Length = 0, const uint8_t *Data = NULL) override;
1121  const int *GetCaSystemIds(void) { return caSystemIds; }
1122  void SendPMT(cCiCaPmt *CaPmt);
1123  bool RepliesToQuery(void) { return repliesToQuery; }
1124  bool Ready(void) { return state >= 4; }
1125  bool ReceivedReply(void) { return state >= 5; }
1126  bool CanDecrypt(void) { return state == 6; }
1127  };
1128 
1131 {
1132  dbgprotocol("Slot %d: new Conditional Access Support (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
1133  state = 0; // inactive
1134  caSystemIds[numCaSystemIds = 0] = 0;
1135  repliesToQuery = false;
1136  numRetries = 0;
1137 }
1138 
1139 void cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
1140 {
1141  if (Data) {
1142  int Tag = GetTag(Length, &Data);
1143  switch (Tag) {
1144  case AOT_CA_INFO: {
1145  dbgprotocol("Slot %d: <== Ca Info (%d)", CamSlot()->SlotNumber(), SessionId());
1146  cString Ids;
1147  numCaSystemIds = 0;
1148  int l = 0;
1149  const uint8_t *d = GetData(Data, l);
1150  while (l > 1) {
1151  uint16_t id = ((uint16_t)(*d) << 8) | *(d + 1);
1152  Ids = cString::sprintf("%s %04X", *Ids ? *Ids : "", id);
1153  dbgprotocol(" %04X", id);
1154  d += 2;
1155  l -= 2;
1157  caSystemIds[numCaSystemIds++] = id;
1158  else {
1159  esyslog("ERROR: CAM %d: too many CA system IDs!", CamSlot()->SlotNumber());
1160  break;
1161  }
1162  }
1164  dbgprotocol("\n");
1165  if (state == 1) {
1166  timer.Set(0);
1168  state = 2; // got ca info
1169  }
1170  dsyslog("CAM %d: system ids:%s", CamSlot()->SlotNumber(), *Ids ? *Ids : " none");
1171  }
1172  break;
1173  case AOT_CA_PMT_REPLY: {
1174  dbgprotocol("Slot %d: <== Ca Pmt Reply (%d)", CamSlot()->SlotNumber(), SessionId());
1175  if (!repliesToQuery) {
1176  if (CamSlot()->IsMasterSlot())
1177  dsyslog("CAM %d: replies to QUERY - multi channel decryption (MCD) possible", CamSlot()->SlotNumber());
1178  repliesToQuery = true;
1179  if (CamSlot()->MtdAvailable()) {
1180  if (CamSlot()->IsMasterSlot())
1181  dsyslog("CAM %d: supports multi transponder decryption (MTD)", CamSlot()->SlotNumber());
1182  CamSlot()->MtdActivate(true);
1183  }
1184  }
1185  state = 5; // got ca pmt reply
1186  int l = 0;
1187  const uint8_t *d = GetData(Data, l);
1188  if (l > 1) {
1189  uint16_t pnr = ((uint16_t)(*d) << 8) | *(d + 1);
1190  dbgprotocol(" %d", pnr);
1191  d += 2;
1192  l -= 2;
1193  if (l > 0) {
1194  dbgprotocol(" %02X", *d);
1195  d += 1;
1196  l -= 1;
1197  if (l > 0) {
1198  if (l % 3 == 0 && l > 1) {
1199  // The EN50221 standard defines that the next byte is supposed
1200  // to be the CA_enable value at programme level. However, there are
1201  // CAMs (for instance the AlphaCrypt with firmware <= 3.05) that
1202  // insert a two byte length field here.
1203  // This is a workaround to skip this length field:
1204  uint16_t len = ((uint16_t)(*d) << 8) | *(d + 1);
1205  if (len == l - 2) {
1206  d += 2;
1207  l -= 2;
1208  }
1209  }
1210  unsigned char caepl = *d;
1211  dbgprotocol(" %02X", caepl);
1212  d += 1;
1213  l -= 1;
1214  bool ok = true;
1215  if (l <= 2)
1216  ok = CA_ENABLE(caepl) == CAEI_POSSIBLE;
1217  while (l > 2) {
1218  uint16_t pid = ((uint16_t)(*d) << 8) | *(d + 1);
1219  unsigned char caees = *(d + 2);
1220  dbgprotocol(" %d=%02X", pid, caees);
1221  d += 3;
1222  l -= 3;
1223  if (CA_ENABLE(caees) != CAEI_POSSIBLE)
1224  ok = false;
1225  }
1226  if (ok)
1227  state = 6; // descrambling possible
1228  }
1229  }
1230  }
1231  dbgprotocol("\n");
1232  }
1233  break;
1234  default: esyslog("ERROR: CAM %d: conditional access support: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
1235  }
1236  }
1237  else if (state == 0) {
1238  dbgprotocol("Slot %d: ==> Ca Info Enq (%d)\n", CamSlot()->SlotNumber(), SessionId());
1240  state = 1; // enquired ca info
1241  }
1242  else if ((state == 2 || state == 3) && timer.TimedOut()) {
1243  if (numRetries-- > 0) {
1244  cCiCaPmt CaPmt(CPCI_QUERY, 0, 0, 0, NULL);
1245  SendPMT(&CaPmt);
1247  state = 3; // waiting for reply
1248  }
1249  else {
1250  dsyslog("CAM %d: doesn't reply to QUERY - only a single channel can be decrypted", CamSlot()->SlotNumber());
1251  CamSlot()->MtdActivate(false);
1252  state = 4; // normal operation
1253  }
1254  }
1255 }
1256 
1258 {
1259  if (CaPmt && state >= 2) {
1260  dbgprotocol("Slot %d: ==> Ca Pmt (%d) %d %d\n", CamSlot()->SlotNumber(), SessionId(), CaPmt->ListManagement(), CaPmt->CmdId());
1261  SendData(AOT_CA_PMT, CaPmt->capmt.Length(), CaPmt->capmt.Data());
1262  state = 4; // sent ca pmt
1263  }
1264 }
1265 
1266 // --- cCiHostControl --------------------------------------------------------
1267 
1268 class cCiHostControl : public cCiSession {
1269 public:
1271  virtual void Process(int Length = 0, const uint8_t *Data = NULL) override;
1272  };
1273 
1275 :cCiSession(SessionId, RI_HOST_CONTROL, Tc)
1276 {
1277  dbgprotocol("Slot %d: new Host Control (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
1278 }
1279 
1280 void cCiHostControl::Process(int Length, const uint8_t* Data)
1281 {
1282  if (Data) {
1283  int Tag = GetTag(Length, &Data);
1284  switch (Tag) {
1285  case AOT_TUNE:
1286  dbgprotocol("Slot %d: <== Host Control Tune (%d)\n", CamSlot()->SlotNumber(), SessionId());
1287  break;
1288  case AOT_REPLACE:
1289  dbgprotocol("Slot %d: <== Host Control Replace (%d)\n", CamSlot()->SlotNumber(), SessionId());
1290  break;
1291  case AOT_CLEAR_REPLACE:
1292  dbgprotocol("Slot %d: <== Host Control Clear Replace (%d)\n", CamSlot()->SlotNumber(), SessionId());
1293  break;
1294  default: esyslog("ERROR: CAM %d: Host Control: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
1295  }
1296  }
1297 }
1298 
1299 // --- cCiDateTime -----------------------------------------------------------
1300 
1301 class cCiDateTime : public cCiSession {
1302 private:
1304  time_t lastTime;
1305  void SendDateTime(void);
1306 public:
1308  virtual void Process(int Length = 0, const uint8_t *Data = NULL) override;
1309  };
1310 
1312 :cCiSession(SessionId, RI_DATE_TIME, Tc)
1313 {
1314  interval = 0;
1315  lastTime = 0;
1316  dbgprotocol("Slot %d: new Date Time (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
1317 }
1318 
1320 {
1321  time_t t = time(NULL);
1322  struct tm tm_gmt;
1323  struct tm tm_loc;
1324  if (gmtime_r(&t, &tm_gmt) && localtime_r(&t, &tm_loc)) {
1325  int Y = tm_gmt.tm_year;
1326  int M = tm_gmt.tm_mon + 1;
1327  int D = tm_gmt.tm_mday;
1328  int L = (M == 1 || M == 2) ? 1 : 0;
1329  int MJD = 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
1330 #define DEC2BCD(d) uint8_t(((d / 10) << 4) + (d % 10))
1331 #pragma pack(1)
1332  struct tTime { uint16_t mjd; uint8_t h, m, s; short offset; };
1333 #pragma pack()
1334  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)) };
1335  bool OldDumpTPDUDataTransfer = DumpTPDUDataTransfer;
1337  if (DumpDateTime)
1338  dbgprotocol("Slot %d: ==> Date Time (%d)\n", CamSlot()->SlotNumber(), SessionId());
1339  SendData(AOT_DATE_TIME, 7, (uint8_t*)&T);
1340  DumpTPDUDataTransfer = OldDumpTPDUDataTransfer;
1341  }
1342 }
1343 
1344 void cCiDateTime::Process(int Length, const uint8_t *Data)
1345 {
1346  if (Data) {
1347  int Tag = GetTag(Length, &Data);
1348  switch (Tag) {
1349  case AOT_DATE_TIME_ENQ: {
1350  interval = 0;
1351  int l = 0;
1352  const uint8_t *d = GetData(Data, l);
1353  if (l > 0)
1354  interval = *d;
1355  dbgprotocol("Slot %d: <== Date Time Enq (%d), interval = %d\n", CamSlot()->SlotNumber(), SessionId(), interval);
1356  lastTime = time(NULL);
1357  SendDateTime();
1358  }
1359  break;
1360  default: esyslog("ERROR: CAM %d: date time: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
1361  }
1362  }
1363  else if (interval && time(NULL) - lastTime > interval) {
1364  lastTime = time(NULL);
1365  SendDateTime();
1366  }
1367 }
1368 
1369 // --- cCiMMI ----------------------------------------------------------------
1370 
1371 // Display Control Commands:
1372 
1373 #define DCC_SET_MMI_MODE 0x01
1374 #define DCC_DISPLAY_CHARACTER_TABLE_LIST 0x02
1375 #define DCC_INPUT_CHARACTER_TABLE_LIST 0x03
1376 #define DCC_OVERLAY_GRAPHICS_CHARACTERISTICS 0x04
1377 #define DCC_FULL_SCREEN_GRAPHICS_CHARACTERISTICS 0x05
1378 
1379 // MMI Modes:
1380 
1381 #define MM_HIGH_LEVEL 0x01
1382 #define MM_LOW_LEVEL_OVERLAY_GRAPHICS 0x02
1383 #define MM_LOW_LEVEL_FULL_SCREEN_GRAPHICS 0x03
1384 
1385 // Display Reply IDs:
1386 
1387 #define DRI_MMI_MODE_ACK 0x01
1388 #define DRI_LIST_DISPLAY_CHARACTER_TABLES 0x02
1389 #define DRI_LIST_INPUT_CHARACTER_TABLES 0x03
1390 #define DRI_LIST_GRAPHIC_OVERLAY_CHARACTERISTICS 0x04
1391 #define DRI_LIST_FULL_SCREEN_GRAPHIC_CHARACTERISTICS 0x05
1392 #define DRI_UNKNOWN_DISPLAY_CONTROL_CMD 0xF0
1393 #define DRI_UNKNOWN_MMI_MODE 0xF1
1394 #define DRI_UNKNOWN_CHARACTER_TABLE 0xF2
1395 
1396 // Enquiry Flags:
1397 
1398 #define EF_BLIND 0x01
1399 
1400 // Answer IDs:
1401 
1402 #define AI_CANCEL 0x00
1403 #define AI_ANSWER 0x01
1404 
1405 class cCiMMI : public cCiSession {
1406 private:
1407  char *GetText(int &Length, const uint8_t **Data);
1410 public:
1412  virtual ~cCiMMI() override;
1413  virtual void Process(int Length = 0, const uint8_t *Data = NULL) override;
1414  virtual bool HasUserIO(void) { return menu || enquiry; }
1415  cCiMenu *Menu(bool Clear = false);
1416  cCiEnquiry *Enquiry(bool Clear = false);
1417  void SendMenuAnswer(uint8_t Selection);
1418  bool SendAnswer(const char *Text);
1419  bool SendCloseMMI(void);
1420  };
1421 
1422 cCiMMI::cCiMMI(uint16_t SessionId, cCiTransportConnection *Tc)
1423 :cCiSession(SessionId, RI_MMI, Tc)
1424 {
1425  dbgprotocol("Slot %d: new MMI (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
1426  menu = fetchedMenu = NULL;
1427  enquiry = fetchedEnquiry = NULL;
1428 }
1429 
1431 {
1432  if (fetchedMenu) {
1433  cMutexLock MutexLock(fetchedMenu->mutex);
1434  fetchedMenu->mmi = NULL;
1435  }
1436  delete menu;
1437  if (fetchedEnquiry) {
1438  cMutexLock MutexLock(fetchedEnquiry->mutex);
1439  fetchedEnquiry->mmi = NULL;
1440  }
1441  delete enquiry;
1442 }
1443 
1444 char *cCiMMI::GetText(int &Length, const uint8_t **Data)
1448 {
1449  int Tag = GetTag(Length, Data);
1450  if (Tag == AOT_TEXT_LAST) {
1451  char *s = GetString(Length, Data);
1452  dbgprotocol("Slot %d: <== Text Last (%d) '%s'\n", CamSlot()->SlotNumber(), SessionId(), s);
1453  return s;
1454  }
1455  else
1456  esyslog("ERROR: CAM %d: MMI: unexpected text tag: %06X", CamSlot()->SlotNumber(), Tag);
1457  return NULL;
1458 }
1459 
1460 void cCiMMI::Process(int Length, const uint8_t *Data)
1461 {
1462  if (Data) {
1463  int Tag = GetTag(Length, &Data);
1464  switch (Tag) {
1465  case AOT_DISPLAY_CONTROL: {
1466  dbgprotocol("Slot %d: <== Display Control (%d)\n", CamSlot()->SlotNumber(), SessionId());
1467  int l = 0;
1468  const uint8_t *d = GetData(Data, l);
1469  if (l > 0) {
1470  switch (*d) {
1471  case DCC_SET_MMI_MODE:
1472  if (l == 2 && *++d == MM_HIGH_LEVEL) {
1473  struct tDisplayReply { uint8_t id; uint8_t mode; };
1474  tDisplayReply dr = { id : DRI_MMI_MODE_ACK, mode : MM_HIGH_LEVEL };
1475  dbgprotocol("Slot %d: ==> Display Reply (%d)\n", CamSlot()->SlotNumber(), SessionId());
1476  SendData(AOT_DISPLAY_REPLY, 2, (uint8_t *)&dr);
1477  }
1478  break;
1479  default: esyslog("ERROR: CAM %d: MMI: unsupported display control command %02X", CamSlot()->SlotNumber(), *d);
1480  }
1481  }
1482  }
1483  break;
1484  case AOT_LIST_LAST:
1485  case AOT_MENU_LAST: {
1486  dbgprotocol("Slot %d: <== Menu Last (%d)\n", CamSlot()->SlotNumber(), SessionId());
1487  delete menu;
1488  menu = new cCiMenu(this, Tag == AOT_MENU_LAST);
1489  int l = 0;
1490  const uint8_t *d = GetData(Data, l);
1491  if (l > 0) {
1492  // since the specification allows choiceNb to be undefined it is useless, so let's just skip it:
1493  d++;
1494  l--;
1495  if (l > 0) menu->titleText = GetText(l, &d);
1496  if (l > 0) menu->subTitleText = GetText(l, &d);
1497  if (l > 0) menu->bottomText = GetText(l, &d);
1498  int Action = CRA_NONE;
1499  int Select = -1;
1500  int Item = 0;
1501  while (l > 0) {
1502  char *s = GetText(l, &d);
1503  if (s) {
1504  if (!menu->AddEntry(s))
1505  free(s);
1506  else if (Action == CRA_NONE) {
1507  Action = CamResponses.GetMatch(CamSlot()->SlotNumber(), s);
1508  if (Action == CRA_SELECT)
1509  Select = Item;
1510  }
1511  }
1512  else
1513  break;
1514  Item++;
1515  }
1516  if (Action != CRA_NONE) {
1517  delete menu;
1518  menu = NULL;
1519  cCondWait::SleepMs(100);
1520  if (Action == CRA_DISCARD) {
1521  SendCloseMMI();
1522  dsyslog("CAM %d: DISCARD", CamSlot()->SlotNumber());
1523  }
1524  else if (Action == CRA_CONFIRM) {
1525  SendMenuAnswer(1);
1526  dsyslog("CAM %d: CONFIRM", CamSlot()->SlotNumber());
1527  }
1528  else if (Action == CRA_SELECT) {
1529  SendMenuAnswer(Select + 1);
1530  dsyslog("CAM %d: SELECT %d", CamSlot()->SlotNumber(), Select + 1);
1531  }
1532  }
1533  }
1534  }
1535  break;
1536  case AOT_ENQ: {
1537  dbgprotocol("Slot %d: <== Enq (%d)\n", CamSlot()->SlotNumber(), SessionId());
1538  delete enquiry;
1539  enquiry = new cCiEnquiry(this);
1540  int l = 0;
1541  const uint8_t *d = GetData(Data, l);
1542  if (l > 0) {
1543  uint8_t blind = *d++;
1544  //XXX GetByte()???
1545  l--;
1546  enquiry->blind = blind & EF_BLIND;
1547  enquiry->expectedLength = *d++;
1548  l--;
1549  // I really wonder why there is no text length field here...
1550  enquiry->text = CopyString(l, d);
1551  int Action = CamResponses.GetMatch(CamSlot()->SlotNumber(), enquiry->text);
1552  if (Action > CRA_NONE) {
1553  char s[enquiry->expectedLength * 2];
1554  snprintf(s, sizeof(s), "%d", Action);
1555  if (int(strlen(s)) == enquiry->expectedLength) {
1556  delete enquiry;
1557  enquiry = NULL;
1558  SendAnswer(s);
1559  dsyslog("CAM %d: PIN", CamSlot()->SlotNumber());
1560  }
1561  else
1562  esyslog("CAM %d: ERROR: unexpected PIN length %d, expected %d", CamSlot()->SlotNumber(), int(strlen(s)), enquiry->expectedLength);
1563  }
1564  }
1565  }
1566  break;
1567  case AOT_CLOSE_MMI: {
1568  int id = -1;
1569  int delay = -1;
1570  int l = 0;
1571  const uint8_t *d = GetData(Data, l);
1572  if (l > 0) {
1573  id = *d++;
1574  if (l > 1)
1575  delay = *d;
1576  }
1577  dbgprotocol("Slot %d: <== Close MMI (%d) id = %02X delay = %d\n", CamSlot()->SlotNumber(), SessionId(), id, delay);
1578  }
1579  break;
1580  default: esyslog("ERROR: CAM %d: MMI: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
1581  }
1582  }
1583 }
1584 
1585 cCiMenu *cCiMMI::Menu(bool Clear)
1586 {
1587  if (Clear)
1588  fetchedMenu = NULL;
1589  else if (menu) {
1590  fetchedMenu = menu;
1591  menu = NULL;
1592  }
1593  return fetchedMenu;
1594 }
1595 
1597 {
1598  if (Clear)
1599  fetchedEnquiry = NULL;
1600  else if (enquiry) {
1602  enquiry = NULL;
1603  }
1604  return fetchedEnquiry;
1605 }
1606 
1607 void cCiMMI::SendMenuAnswer(uint8_t Selection)
1608 {
1609  dbgprotocol("Slot %d: ==> Menu Answ (%d)\n", CamSlot()->SlotNumber(), SessionId());
1610  SendData(AOT_MENU_ANSW, 1, &Selection);
1611 }
1612 
1613 bool cCiMMI::SendAnswer(const char *Text)
1614 {
1615  dbgprotocol("Slot %d: ==> Answ (%d)\n", CamSlot()->SlotNumber(), SessionId());
1616  struct tAnswer { uint8_t id; char text[256]; };//XXX
1617  tAnswer answer;
1618  answer.id = Text ? AI_ANSWER : AI_CANCEL;
1619  int len = 0;
1620  if (Text) {
1621  len = min(sizeof(answer.text), strlen(Text));
1622  memcpy(answer.text, Text, len);
1623  }
1624  SendData(AOT_ANSW, len + 1, (uint8_t *)&answer);
1625  return true;
1626 }
1627 
1629 {
1630  dbgprotocol("Slot %d: ==> Close MMI (%d)\n", CamSlot()->SlotNumber(), SessionId());
1631  SendData(AOT_CLOSE_MMI, 0);
1632  return true;
1633 }
1634 
1635 // --- cCiMenu ---------------------------------------------------------------
1636 
1637 cCiMenu::cCiMenu(cCiMMI *MMI, bool Selectable)
1638 {
1639  mmi = MMI;
1640  mutex = NULL;
1642  titleText = subTitleText = bottomText = NULL;
1643  numEntries = 0;
1644 }
1645 
1647 {
1648  cMutexLock MutexLock(mutex);
1649  if (mmi)
1650  mmi->Menu(true);
1651  free(titleText);
1652  free(subTitleText);
1653  free(bottomText);
1654  for (int i = 0; i < numEntries; i++)
1655  free(entries[i]);
1656 }
1657 
1658 bool cCiMenu::AddEntry(char *s)
1659 {
1661  entries[numEntries++] = s;
1662  return true;
1663  }
1664  return false;
1665 }
1666 
1668 {
1669  // If the mmi is gone, the menu shall be closed, which also qualifies as 'update'.
1670  return !mmi || mmi->HasUserIO();
1671 }
1672 
1673 void cCiMenu::Select(int Index)
1674 {
1675  cMutexLock MutexLock(mutex);
1676  if (mmi && -1 <= Index && Index < numEntries)
1677  mmi->SendMenuAnswer(Index + 1);
1678 }
1679 
1681 {
1682  Select(-1);
1683 }
1684 
1685 void cCiMenu::Abort(void)
1686 {
1687  cMutexLock MutexLock(mutex);
1688  if (mmi)
1689  mmi->SendCloseMMI();
1690 }
1691 
1692 // --- cCiEnquiry ------------------------------------------------------------
1693 
1695 {
1696  mmi = MMI;
1697  mutex = NULL;
1698  text = NULL;
1699  blind = false;
1700  expectedLength = 0;
1701 }
1702 
1704 {
1705  cMutexLock MutexLock(mutex);
1706  if (mmi)
1707  mmi->Enquiry(true);
1708  free(text);
1709 }
1710 
1711 void cCiEnquiry::Reply(const char *s)
1712 {
1713  cMutexLock MutexLock(mutex);
1714  if (mmi)
1715  mmi->SendAnswer(s);
1716 }
1717 
1719 {
1720  Reply(NULL);
1721 }
1722 
1724 {
1725  cMutexLock MutexLock(mutex);
1726  if (mmi)
1727  mmi->SendCloseMMI();
1728 }
1729 
1730 // --- cCiResourceHandler ----------------------------------------------------
1731 
1733 {
1734 }
1735 
1737 {
1738 }
1739 
1740 // --- cCiDefaultResourceHandler ---------------------------------------------
1741 
1743 public:
1744  virtual const uint32_t *ResourceIds(void) const;
1745  virtual cCiSession *GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc) override;
1746  };
1747 
1748 const uint32_t *cCiDefaultResourceHandler::ResourceIds(void) const
1749 {
1750  static uint32_t Ids[] = {
1755  RI_DATE_TIME,
1756  RI_MMI,
1757  0
1758  };
1759  return Ids;
1760 }
1761 
1763 {
1764  switch (ResourceId) {
1765  case RI_RESOURCE_MANAGER: return new cCiResourceManager(SessionId, Tc); break;
1766  case RI_APPLICATION_INFORMATION: return new cCiApplicationInformation(SessionId, Tc); break;
1767  case RI_CONDITIONAL_ACCESS_SUPPORT: return new cCiConditionalAccessSupport(SessionId, Tc); break;
1768  case RI_HOST_CONTROL: return new cCiHostControl(SessionId, Tc); break;
1769  case RI_DATE_TIME: return new cCiDateTime(SessionId, Tc); break;
1770  case RI_MMI: return new cCiMMI(SessionId, Tc); break;
1771  default: return NULL;
1772  }
1773 }
1774 
1775 // --- cCiResourceHandlers ---------------------------------------------------
1776 
1778 
1780 {
1782 }
1783 
1785 {
1786  if (ResourceHandler) {
1787  Add(ResourceHandler);
1788  if (const uint32_t *r = ResourceHandler->ResourceIds()) {
1789  while (*r) {
1790  resourceIds.Append(htonl(*r));
1791  r++;
1792  }
1793  }
1794  }
1795 }
1796 
1797 cCiSession *cCiResourceHandlers::GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc)
1798 {
1799  for (cCiResourceHandler *r = Last(); r; r = Prev(r)) {
1800  if (cCiSession *CiSession = r->GetNewCiSession(ResourceId, SessionId, Tc))
1801  return CiSession;
1802  }
1803  return NULL;
1804 }
1805 
1806 // --- cCiTransportConnection (cont'd) ---------------------------------------
1807 
1808 #define TC_POLL_TIMEOUT 300 // ms WORKAROUND: TC_POLL_TIMEOUT < 300ms doesn't work with DragonCAM
1809 #define TC_ALIVE_TIMEOUT 2000 // ms after which a transport connection is assumed dead
1810 
1812 {
1813  dbgprotocol("Slot %d: creating connection %d/%d\n", CamSlot->SlotNumber(), CamSlot->SlotIndex(), Tcid);
1814  camSlot = CamSlot;
1815  tcid = Tcid;
1816  state = stIDLE;
1817  createConnectionRequested = false;
1818  deleteConnectionRequested = false;
1819  hasUserIO = false;
1821  for (int i = 0; i <= MAX_SESSIONS_PER_TC; i++) // sessions[0] is not used, but initialized anyway
1822  sessions[i] = NULL;
1823  tsPostProcessor = NULL;
1824 }
1825 
1827 {
1828  for (int i = 1; i <= MAX_SESSIONS_PER_TC; i++)
1829  delete sessions[i];
1830 }
1831 
1833 {
1834  tsPostProcessor = CiSession;
1835 }
1836 
1838 {
1839  cMutexLock MutexLock(&mutex);
1840  if (tsPostProcessor)
1841  return tsPostProcessor->TsPostProcess(TsPacket);
1842  return false;
1843 }
1844 
1846 {
1848  return cas && cas->Ready();
1849 }
1850 
1852 {
1854  return ai ? ai->GetMenuString() : NULL;
1855 }
1856 
1857 void cCiTransportConnection::SendTPDU(uint8_t Tag, int Length, const uint8_t *Data)
1858 {
1859  cTPDU TPDU(camSlot->SlotIndex(), tcid, Tag, Length, Data);
1860  camSlot->Write(&TPDU);
1862 }
1863 
1864 void cCiTransportConnection::SendData(int Length, const uint8_t *Data)
1865 {
1866  // if Length ever exceeds MAX_TPDU_DATA this needs to be handled differently
1867  if (state == stACTIVE && Length > 0)
1868  SendTPDU(T_DATA_LAST, Length, Data);
1869 }
1870 
1871 void cCiTransportConnection::SendTag(uint8_t Tag, uint16_t SessionId, uint32_t ResourceId, int Status)
1872 {
1873  uint8_t buffer[16];
1874  uint8_t *p = buffer;
1875  *p++ = Tag;
1876  *p++ = 0x00; // will contain length
1877  if (Status >= 0)
1878  *p++ = Status;
1879  if (ResourceId) {
1880  put_unaligned(htonl(ResourceId), (uint32_t *)p);
1881  p += 4;
1882  }
1883  put_unaligned(htons(SessionId), (uint16_t *)p);
1884  p += 2;
1885  buffer[1] = p - buffer - 2; // length
1886  SendData(p - buffer, buffer);
1887 }
1888 
1890 {
1891  bool OldDumpTPDUDataTransfer = DumpTPDUDataTransfer;
1893  if (DumpPolls)
1894  dbgprotocol("Slot %d: ==> Poll\n", camSlot->SlotNumber());
1896  DumpTPDUDataTransfer = OldDumpTPDUDataTransfer;
1897 }
1898 
1899 uint32_t cCiTransportConnection::ResourceIdToInt(const uint8_t *Data)
1900 {
1901  return (ntohl(get_unaligned((uint32_t *)Data)));
1902 }
1903 
1905 {
1906  return (SessionId <= MAX_SESSIONS_PER_TC) ? sessions[SessionId] : NULL;
1907 }
1908 
1910 {
1911  cCiSession *CiSession = NULL;
1912  for (int i = 1; i <= MAX_SESSIONS_PER_TC; i++) {
1913  if (cCiSession *s = sessions[i]) {
1914  if (s->ResourceId() == ResourceId)
1915  return s; // prefer exact match
1916  if ((s->ResourceId() & RESOURCE_CLASS_MASK) == (ResourceId & RESOURCE_CLASS_MASK))
1917  CiSession = s;
1918  }
1919  }
1920  return CiSession;
1921 }
1922 
1923 void cCiTransportConnection::OpenSession(int Length, const uint8_t *Data)
1924 {
1925  if (Length == 6 && *(Data + 1) == 0x04) {
1926  uint32_t ResourceId = ResourceIdToInt(Data + 2);
1927  dbgprotocol("Slot %d: open session %08X\n", camSlot->SlotNumber(), ResourceId);
1928  if (!GetSessionByResourceId(ResourceId)) {
1929  for (int i = 1; i <= MAX_SESSIONS_PER_TC; i++) {
1930  if (!sessions[i]) {
1931  sessions[i] = CiResourceHandlers.GetNewCiSession(ResourceId, i, this);
1932  if (sessions[i])
1933  SendTag(ST_OPEN_SESSION_RESPONSE, sessions[i]->SessionId(), sessions[i]->ResourceId(), SS_OK);
1934  else
1935  esyslog("ERROR: CAM %d: unknown resource identifier: %08X (%d/%d)", camSlot->SlotNumber(), ResourceId, camSlot->SlotIndex(), tcid);
1936  return;
1937  }
1938  }
1939  esyslog("ERROR: CAM %d: no free session slot for resource identifier %08X (%d/%d)", camSlot->SlotNumber(), ResourceId, camSlot->SlotIndex(), tcid);
1940  }
1941  else
1942  esyslog("ERROR: CAM %d: session for resource identifier %08X already exists (%d/%d)", camSlot->SlotNumber(), ResourceId, camSlot->SlotIndex(), tcid);
1943  }
1944 }
1945 
1947 {
1948  dbgprotocol("Slot %d: close session %d\n", camSlot->SlotNumber(), SessionId);
1949  cCiSession *Session = GetSessionBySessionId(SessionId);
1950  if (Session && sessions[SessionId] == Session) {
1951  delete Session;
1952  sessions[SessionId] = NULL;
1953  SendTag(ST_CLOSE_SESSION_RESPONSE, SessionId, 0, SS_OK);
1954  }
1955  else {
1956  esyslog("ERROR: CAM %d: unknown session id: %d (%d/%d)", camSlot->SlotNumber(), SessionId, camSlot->SlotIndex(), tcid);
1958  }
1959 }
1960 
1962 {
1963  int Length;
1964  const uint8_t *Data = TPDU->Data(Length);
1965  if (Data && Length > 1) {
1966  switch (*Data) {
1967  case ST_SESSION_NUMBER: if (Length > 4) {
1968  uint16_t SessionId = ntohs(get_unaligned((uint16_t *)&Data[2]));
1969  cCiSession *Session = GetSessionBySessionId(SessionId);
1970  if (Session)
1971  Session->Process(Length - 4, Data + 4);
1972  else
1973  esyslog("ERROR: CAM %d: unknown session id: %d (%d/%d)", camSlot->SlotNumber(), SessionId, camSlot->SlotIndex(), tcid);
1974  }
1975  break;
1976  case ST_OPEN_SESSION_REQUEST: OpenSession(Length, Data);
1977  break;
1978  case ST_CLOSE_SESSION_REQUEST: if (Length == 4)
1979  CloseSession(ntohs(get_unaligned((uint16_t *)&Data[2])));
1980  break;
1981  case ST_CREATE_SESSION_RESPONSE: // not implemented
1982  case ST_CLOSE_SESSION_RESPONSE: // not implemented
1983  default: esyslog("ERROR: CAM %d: unknown session tag: %02X (%d/%d)", camSlot->SlotNumber(), *Data, camSlot->SlotIndex(), tcid);
1984  }
1985  }
1986 }
1987 
1989 {
1990  if (TPDU)
1992  else if (alive.TimedOut())
1993  return false;
1994  switch (state) {
1995  case stIDLE:
1997  dbgprotocol("Slot %d: create connection %d/%d\n", camSlot->SlotNumber(), camSlot->SlotIndex(), tcid);
1998  createConnectionRequested = false;
2000  state = stCREATION;
2001  }
2002  return true;
2003  case stCREATION:
2004  if (TPDU && TPDU->Tag() == T_CTC_REPLY) {
2005  dbgprotocol("Slot %d: connection created %d/%d\n", camSlot->SlotNumber(), camSlot->SlotIndex(), tcid);
2006  Poll();
2007  state = stACTIVE;
2008  }
2009  else if (timer.TimedOut()) {
2010  dbgprotocol("Slot %d: timeout while creating connection %d/%d\n", camSlot->SlotNumber(), camSlot->SlotIndex(), tcid);
2011  state = stIDLE;
2012  }
2013  return true;
2014  case stACTIVE:
2016  dbgprotocol("Slot %d: delete connection requested %d/%d\n", camSlot->SlotNumber(), camSlot->SlotIndex(), tcid);
2017  deleteConnectionRequested = false;
2019  state = stDELETION;
2020  return true;
2021  }
2022  if (TPDU) {
2023  switch (TPDU->Tag()) {
2024  case T_REQUEST_TC:
2025  esyslog("ERROR: CAM %d: T_REQUEST_TC not implemented (%d/%d)", camSlot->SlotNumber(), camSlot->SlotIndex(), tcid);
2026  break;
2027  case T_DATA_MORE:
2028  case T_DATA_LAST:
2029  HandleSessions(TPDU);
2030  // continue with T_SB
2031  case T_SB:
2032  if ((TPDU->Status() & DATA_INDICATOR) != 0) {
2033  dbgprotocol("Slot %d: receive data %d/%d\n", camSlot->SlotNumber(), camSlot->SlotIndex(), tcid);
2034  SendTPDU(T_RCV);
2035  }
2036  break;
2037  case T_DELETE_TC:
2038  dbgprotocol("Slot %d: delete connection %d/%d\n", camSlot->SlotNumber(), camSlot->SlotIndex(), tcid);
2040  state = stIDLE;
2041  return true;
2042  case T_RCV:
2043  case T_CREATE_TC:
2044  case T_CTC_REPLY:
2045  case T_DTC_REPLY:
2046  case T_NEW_TC:
2047  case T_TC_ERROR:
2048  break;
2049  default:
2050  esyslog("ERROR: unknown TPDU tag: 0x%02X (%s)", TPDU->Tag(), __FUNCTION__);
2051  }
2052  }
2053  else if (timer.TimedOut())
2054  Poll();
2055  hasUserIO = false;
2056  for (int i = 1; i <= MAX_SESSIONS_PER_TC; i++) {
2057  if (sessions[i]) {
2058  sessions[i]->Process();
2059  if (sessions[i]->HasUserIO())
2060  hasUserIO = true;
2061  }
2062  }
2063  break;
2064  case stDELETION:
2065  if (TPDU && TPDU->Tag() == T_DTC_REPLY || timer.TimedOut()) {
2066  dbgprotocol("Slot %d: connection deleted %d/%d\n", camSlot->SlotNumber(), camSlot->SlotIndex(), tcid);
2067  state = stIDLE;
2068  }
2069  return true;
2070  default:
2071  esyslog("ERROR: unknown state: %d (%s)", state, __FUNCTION__);
2072  }
2073  return true;
2074 }
2075 
2076 // --- cCiCaPidData ----------------------------------------------------------
2077 
2078 class cCiCaPidData : public cListObject {
2079 public:
2080  bool active;
2081  int pid;
2083  cCiCaPidData(int Pid, int StreamType)
2084  {
2085  active = false;
2086  pid = Pid;
2087  streamType = StreamType;
2088  }
2089  };
2090 
2091 // --- cCiCaProgramData ------------------------------------------------------
2092 
2094 public:
2096  bool modified;
2098  cCiCaProgramData(int ProgramNumber)
2099  {
2100  programNumber = ProgramNumber;
2101  modified = false;
2102  }
2103  bool Active(void)
2104  {
2105  for (cCiCaPidData *p = pidList.First(); p; p = pidList.Next(p)) {
2106  if (p->active)
2107  return true;
2108  }
2109  return false;
2110  }
2111  };
2112 
2113 // --- cCiAdapter ------------------------------------------------------------
2114 
2116 :cThread("CI adapter")
2117 {
2118  for (int i = 0; i < MAX_CAM_SLOTS_PER_ADAPTER; i++)
2119  camSlots[i] = NULL;
2120 }
2121 
2123 {
2124  Cancel(3);
2125  for (int i = 0; i < MAX_CAM_SLOTS_PER_ADAPTER; i++)
2126  delete camSlots[i];
2127 }
2128 
2130 {
2131  if (CamSlot) {
2132  for (int i = 0; i < MAX_CAM_SLOTS_PER_ADAPTER; i++) {
2133  if (!camSlots[i]) {
2134  CamSlot->slotIndex = i;
2135  camSlots[i] = CamSlot;
2136  return;
2137  }
2138  }
2139  esyslog("ERROR: no free CAM slot in CI adapter");
2140  }
2141 }
2142 
2144 {
2145  if (Iter >= 0) {
2146  for (; Iter < MAX_CAM_SLOTS_PER_ADAPTER; ) {
2147  if (cCamSlot *Found = camSlots[Iter++])
2148  return Found;
2149  }
2150  }
2151  return NULL;
2152 }
2153 
2155 {
2156  cTPDU TPDU;
2157  while (Running()) {
2158  int n = Read(TPDU.Buffer(), TPDU.MaxSize());
2159  if (n > 0 && TPDU.Slot() < MAX_CAM_SLOTS_PER_ADAPTER) {
2160  TPDU.SetSize(n);
2161  cCamSlot *cs = camSlots[TPDU.Slot()];
2162  TPDU.Dump(cs ? cs->SlotNumber() : 0, false);
2163  if (cs)
2164  cs->Process(&TPDU);
2165  }
2166  for (int i = 0; i < MAX_CAM_SLOTS_PER_ADAPTER; i++) {
2167  if (camSlots[i])
2168  camSlots[i]->Process();
2169  }
2170  }
2171 }
2172 
2173 // --- cCamSlot --------------------------------------------------------------
2174 
2175 #define MODULE_CHECK_INTERVAL 500 // ms
2176 #define MODULE_RESET_TIMEOUT 2 // s
2177 
2178 cCamSlot::cCamSlot(cCiAdapter *CiAdapter, bool WantsTsData, cCamSlot *MasterSlot)
2179 {
2180  ciAdapter = CiAdapter;
2182  assignedDevice = NULL;
2183  caPidReceiver = WantsTsData ? new cCaPidReceiver : NULL;
2184  caActivationReceiver = NULL;
2185  slotIndex = -1;
2186  mtdAvailable = false;
2187  mtdHandler = NULL;
2188  lastModuleStatus = msReset; // avoids initial reset log message
2189  resetTime = 0;
2190  resendPmt = false;
2191  for (int i = 0; i <= MAX_CONNECTIONS_PER_CAM_SLOT; i++) // tc[0] is not used, but initialized anyway
2192  tc[i] = NULL;
2193  if (MasterSlot)
2195  if (ciAdapter) {
2196  CamSlots.Add(this);
2197  slotNumber = Index() + 1;
2198  ciAdapter->AddCamSlot(this);
2199  Reset();
2200  }
2201 }
2202 
2204 {
2205  Assign(NULL);
2206  delete caPidReceiver;
2207  delete caActivationReceiver;
2208  CamSlots.Del(this, false);
2210  delete mtdHandler;
2211 }
2212 
2214 {
2215  cMutexLock MutexLock(&mutex);
2216  if (mtdHandler)
2217  return mtdHandler->GetMtdCamSlot(this);
2218  return this;
2219 }
2220 
2221 bool cCamSlot::Assign(cDevice *Device, bool Query)
2222 {
2223  cMutexLock MutexLock(&mutex);
2224  if (Device == assignedDevice)
2225  return true;
2226  if (ciAdapter) {
2227  int OldDeviceNumber = 0;
2228  if (assignedDevice && !Query) {
2229  OldDeviceNumber = assignedDevice->DeviceNumber() + 1;
2230  if (caPidReceiver)
2232  assignedDevice->SetCamSlot(NULL);
2233  assignedDevice = NULL;
2234  }
2235  if (ciAdapter->Assign(Device, true)) {
2236  if (!Query) {
2237  StopDecrypting();
2238  if (ciAdapter->Assign(Device)) {
2239  if (Device) {
2240  Device->SetCamSlot(this);
2242  if (caPidReceiver) {
2243  caPidReceiver->Reset();
2245  }
2246  dsyslog("CAM %d: assigned to device %d", MasterSlotNumber(), Device->DeviceNumber() + 1);
2247  }
2248  else {
2249  CancelActivation();
2250  dsyslog("CAM %d: unassigned from device %d", MasterSlotNumber(), OldDeviceNumber);
2251  }
2252  }
2253  else
2254  return false;
2255  }
2256  return true;
2257  }
2258  }
2259  return false;
2260 }
2261 
2262 bool cCamSlot::Devices(cVector<int> &DeviceNumbers)
2263 {
2264  cMutexLock MutexLock(&mutex);
2265  if (mtdHandler)
2266  return mtdHandler->Devices(DeviceNumbers);
2267  if (assignedDevice)
2268  DeviceNumbers.Append(assignedDevice->DeviceNumber());
2269  return DeviceNumbers.Size() > 0;
2270 }
2271 
2273 {
2274  cMutexLock MutexLock(&mutex);
2275  for (int i = 1; i <= MAX_CONNECTIONS_PER_CAM_SLOT; i++) {
2276  if (!tc[i]) {
2277  tc[i] = new cCiTransportConnection(this, i);
2278  tc[i]->CreateConnection();
2279  return;
2280  }
2281  }
2282  esyslog("ERROR: CAM %d: can't create new transport connection!", slotNumber);
2283 }
2284 
2286 {
2287  cMutexLock MutexLock(&mutex);
2288  for (int i = 1; i <= MAX_CONNECTIONS_PER_CAM_SLOT; i++) {
2289  delete tc[i];
2290  tc[i] = NULL;
2291  }
2292 }
2293 
2295 {
2296  cMutexLock MutexLock(&mutex);
2297  if (TPDU) {
2298  int n = TPDU->Tcid();
2299  if (1 <= n && n <= MAX_CONNECTIONS_PER_CAM_SLOT) {
2300  if (tc[n])
2301  tc[n]->Process(TPDU);
2302  }
2303  }
2304  for (int i = 1; i <= MAX_CONNECTIONS_PER_CAM_SLOT; i++) {
2305  if (tc[i]) {
2306  if (!tc[i]->Process()) {
2307  Reset();
2308  return;
2309  }
2310  }
2311  }
2312  if (moduleCheckTimer.TimedOut()) {
2313  eModuleStatus ms = ModuleStatus();
2314  if (ms != lastModuleStatus) {
2315  switch (ms) {
2316  case msNone:
2317  dbgprotocol("Slot %d: no module present\n", slotNumber);
2318  isyslog("CAM %d: no module present", slotNumber);
2319  StopDecrypting();
2321  CancelActivation();
2322  if (mtdHandler)
2324  else
2325  Assign(NULL);
2326  break;
2327  case msReset:
2328  dbgprotocol("Slot %d: module reset\n", slotNumber);
2329  isyslog("CAM %d: module reset", slotNumber);
2331  break;
2332  case msPresent:
2333  dbgprotocol("Slot %d: module present\n", slotNumber);
2334  isyslog("CAM %d: module present", slotNumber);
2335  break;
2336  case msReady:
2337  dbgprotocol("Slot %d: module ready\n", slotNumber);
2338  isyslog("CAM %d: module ready", slotNumber);
2339  NewConnection();
2340  resendPmt = true;
2341  break;
2342  default:
2343  esyslog("ERROR: unknown module status %d (%s)", ms, __FUNCTION__);
2344  }
2345  lastModuleStatus = ms;
2346  }
2348  }
2349  if (resendPmt && Ready()) {
2350  if (mtdHandler) {
2352  resendPmt = false;
2353  }
2354  else if (caProgramList.Count())
2355  StartDecrypting();
2356  }
2357  processed.Broadcast();
2358 }
2359 
2361 {
2362  cMutexLock MutexLock(&mutex);
2363  return tc[1] ? tc[1]->GetSessionByResourceId(ResourceId) : NULL;
2364 }
2365 
2367 {
2368  cMutexLock MutexLock(&mutex);
2369  if (ciAdapter && TPDU->Size()) {
2370  TPDU->Dump(SlotNumber(), true);
2371  ciAdapter->Write(TPDU->Buffer(), TPDU->Size());
2372  }
2373 }
2374 
2376 {
2377  cMutexLock MutexLock(&mutex);
2380  if (ciAdapter) {
2381  dbgprotocol("Slot %d: reset...", slotNumber);
2382  if (ciAdapter->Reset(slotIndex)) {
2383  resetTime = time(NULL);
2384  dbgprotocol("ok.\n");
2386  return true;
2387  }
2388  dbgprotocol("failed!\n");
2389  }
2390  return false;
2391 }
2392 
2394 {
2395  return ModuleStatus() == msReady;
2396 }
2397 
2399 {
2400  cMutexLock MutexLock(&mutex);
2401  if (!caActivationReceiver) {
2402  if (cDevice *d = Device()) {
2404  if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel())) {
2405  caActivationReceiver = new cCaActivationReceiver(Channel, this);
2406  d->AttachReceiver(caActivationReceiver);
2407  dsyslog("CAM %d: activating on device %d with channel %d (%s)", SlotNumber(), d->DeviceNumber() + 1, Channel->Number(), Channel->Name());
2408  }
2409  }
2410  }
2411 }
2412 
2414 {
2415  cMutexLock MutexLock(&mutex);
2416  if (mtdHandler)
2418  else {
2419  delete caActivationReceiver;
2420  caActivationReceiver = NULL;
2421  }
2422 }
2423 
2425 {
2426  if (mtdHandler)
2427  return mtdHandler->IsActivating();
2428  return caActivationReceiver;
2429 }
2430 
2432 {
2433  cMutexLock MutexLock(&mutex);
2435  if (resetTime) {
2436  if (ms <= msReset) {
2437  if (time(NULL) - resetTime < MODULE_RESET_TIMEOUT)
2438  return msReset;
2439  }
2440  resetTime = 0;
2441  }
2442  return ms;
2443 }
2444 
2445 const char *cCamSlot::GetCamName(void)
2446 {
2447  cMutexLock MutexLock(&mutex);
2448  return tc[1] ? tc[1]->GetCamName() : NULL;
2449 }
2450 
2452 {
2453  cMutexLock MutexLock(&mutex);
2454  return ModuleStatus() == msNone || tc[1] && tc[1]->Ready();
2455 }
2456 
2458 {
2460 }
2461 
2463 {
2464  cMutexLock MutexLock(&mutex);
2465  return tc[1] && tc[1]->HasUserIO();
2466 }
2467 
2469 {
2470  cMutexLock MutexLock(&mutex);
2472  return api ? api->EnterMenu() : false;
2473 }
2474 
2476 {
2477  cMutexLock MutexLock(&mutex);
2479  if (mmi) {
2480  cCiMenu *Menu = mmi->Menu();
2481  if (Menu)
2482  Menu->mutex = &mutex;
2483  return Menu;
2484  }
2485  return NULL;
2486 }
2487 
2489 {
2490  cMutexLock MutexLock(&mutex);
2492  if (mmi) {
2493  cCiEnquiry *Enquiry = mmi->Enquiry();
2494  if (Enquiry)
2495  Enquiry->mutex = &mutex;
2496  return Enquiry;
2497  }
2498  return NULL;
2499 }
2500 
2502 {
2503  for (int i = 0; i < caPmts.Size(); i++)
2504  delete caPmts[i];
2505 }
2506 
2507 cCiCaPmt *cCiCaPmtList::Add(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const int *CaSystemIds)
2508 {
2509  cCiCaPmt *p = new cCiCaPmt(CmdId, Source, Transponder, ProgramNumber, CaSystemIds);
2510  caPmts.Append(p);
2511  return p;
2512 }
2513 
2515 {
2516  if (caPmts.RemoveElement(CaPmt))
2517  delete CaPmt;
2518 }
2519 
2521 {
2522  cMutexLock MutexLock(&mutex);
2524  return cas && cas->RepliesToQuery();
2525 }
2526 
2527 void cCamSlot::BuildCaPmts(uint8_t CmdId, cCiCaPmtList &CaPmtList, cMtdMapper *MtdMapper)
2528 {
2529  cMutexLock MutexLock(&mutex);
2530  CaPmtList.caPmts.Clear();
2531  const int *CaSystemIds = GetCaSystemIds();
2532  if (CaSystemIds && *CaSystemIds) {
2533  if (caProgramList.Count()) {
2534  for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
2535  if (p->modified || resendPmt) {
2536  bool Active = p->Active();
2537  cCiCaPmt *CaPmt = CaPmtList.Add(Active ? CmdId : CPCI_NOT_SELECTED, source, transponder, p->programNumber, CaSystemIds);
2538  for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {
2539  if (q->active)
2540  CaPmt->AddPid(q->pid, q->streamType);
2541  }
2542  if (caPidReceiver) {
2543  int CaPids[MAXRECEIVEPIDS + 1];
2544  if (GetCaPids(source, transponder, p->programNumber, CaSystemIds, MAXRECEIVEPIDS + 1, CaPids) > 0) {
2545  if (Active)
2546  caPidReceiver->AddPids(CaPids);
2547  else {
2548  KeepSharedCaPids(p->programNumber, CaSystemIds, CaPids);
2549  caPidReceiver->DelPids(CaPids);
2550  }
2551  }
2552  }
2553  if (RepliesToQuery())
2554  CaPmt->SetListManagement(Active ? CPLM_ADD : CPLM_UPDATE);
2555  if (MtdMapper)
2556  CaPmt->MtdMapPids(MtdMapper);
2557  p->modified = false;
2558  }
2559  }
2560  }
2561  else if (CmdId == CPCI_NOT_SELECTED)
2562  CaPmtList.Add(CmdId, 0, 0, 0, NULL);
2563  }
2564 }
2565 
2566 void cCamSlot::KeepSharedCaPids(int ProgramNumber, const int *CaSystemIds, int *CaPids)
2567 {
2568  int numPids = 0;
2569  int *pCaPids = CaPids;
2570  while (*pCaPids) {
2571  numPids++;
2572  pCaPids++;
2573  }
2574  if (numPids <= 0)
2575  return;
2576  int CaPids2[MAXRECEIVEPIDS + 1];
2577  for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
2578  if (p->Active()) {
2579  if (GetCaPids(source, transponder, p->programNumber, CaSystemIds, MAXRECEIVEPIDS + 1, CaPids2) > 0) {
2580  int *pCaPids2 = CaPids2;
2581  while (*pCaPids2) {
2582  pCaPids = CaPids;
2583  while (*pCaPids) {
2584  if (*pCaPids == *pCaPids2) {
2585  dsyslog("CAM %d: keeping shared CA pid %d", SlotNumber(), *pCaPids);
2586  // To remove *pCaPids from CaPids we overwrite it with the last valie in the list, and then strip the last value:
2587  *pCaPids = CaPids[numPids - 1];
2588  numPids--;
2589  CaPids[numPids] = 0;
2590  if (numPids <= 0)
2591  return;
2592  }
2593  else
2594  pCaPids++;
2595  }
2596  pCaPids2++;
2597  }
2598  }
2599  }
2600  }
2601 }
2602 
2604 {
2605  cMutexLock MutexLock(&mutex);
2607  if (cas) {
2608  for (int i = 0; i < CaPmtList.caPmts.Size(); i++)
2609  cas->SendPMT(CaPmtList.caPmts[i]);
2610  }
2611  resendPmt = false;
2612 }
2613 
2614 void cCamSlot::SendCaPmt(uint8_t CmdId)
2615 {
2616  cMutexLock MutexLock(&mutex);
2617  cCiCaPmtList CaPmtList;
2618  BuildCaPmts(CmdId, CaPmtList);
2619  SendCaPmts(CaPmtList);
2620 }
2621 
2623 {
2624  mtdAvailable = true;
2625 }
2626 
2628 {
2629  if (McdAvailable() && MtdAvailable()) {
2630  if (On) {
2631  if (!mtdHandler) {
2632  dsyslog("CAM %d: activating MTD support", SlotNumber());
2633  mtdHandler = new cMtdHandler;
2634  }
2635  }
2636  else if (mtdHandler) {
2637  dsyslog("CAM %d: deactivating MTD support", SlotNumber());
2638  delete mtdHandler;
2639  mtdHandler = NULL;
2640  }
2641  }
2642 }
2643 
2644 int cCamSlot::MtdPutData(uchar *Data, int Count)
2645 {
2646  return mtdHandler->Put(Data, Count);
2647 }
2648 
2650 {
2651  cMutexLock MutexLock(&mutex);
2653  return cas ? cas->GetCaSystemIds() : NULL;
2654 }
2655 
2657 {
2658  if (mtdHandler)
2659  return mtdHandler->Priority();
2660  cDevice *d = Device();
2661  return d ? d->Priority() : IDLEPRIORITY;
2662 }
2663 
2664 bool cCamSlot::ProvidesCa(const int *CaSystemIds)
2665 {
2666  cMutexLock MutexLock(&mutex);
2668  if (cas) {
2669  for (const int *ids = cas->GetCaSystemIds(); ids && *ids; ids++) {
2670  for (const int *id = CaSystemIds; *id; id++) {
2671  if (*id == *ids)
2672  return true;
2673  }
2674  }
2675  }
2676  return false;
2677 }
2678 
2679 void cCamSlot::AddPid(int ProgramNumber, int Pid, int StreamType)
2680 {
2681  cMutexLock MutexLock(&mutex);
2682  cCiCaProgramData *ProgramData = NULL;
2683  for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
2684  if (p->programNumber == ProgramNumber) {
2685  ProgramData = p;
2686  for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {
2687  if (q->pid == Pid)
2688  return;
2689  }
2690  }
2691  }
2692  if (!ProgramData)
2693  caProgramList.Add(ProgramData = new cCiCaProgramData(ProgramNumber));
2694  ProgramData->pidList.Add(new cCiCaPidData(Pid, StreamType));
2695 }
2696 
2697 void cCamSlot::SetPid(int Pid, bool Active)
2698 {
2700  return;
2701  cMutexLock MutexLock(&mutex);
2702  for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
2703  for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {
2704  if (q->pid == Pid) {
2705  if (q->active != Active) {
2706  q->active = Active;
2707  p->modified = true;
2708  }
2709  return;
2710  }
2711  }
2712  }
2713 }
2714 
2715 // see ISO/IEC 13818-1
2716 #define STREAM_TYPE_VIDEO 0x02
2717 #define STREAM_TYPE_AUDIO 0x04
2718 #define STREAM_TYPE_PRIVATE 0x06
2719 
2720 void cCamSlot::AddChannel(const cChannel *Channel)
2721 {
2722  cMutexLock MutexLock(&mutex);
2723  if (source != Channel->Source() || transponder != Channel->Transponder())
2724  StopDecrypting();
2725  source = Channel->Source();
2726  transponder = Channel->Transponder();
2727  if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
2728  AddPid(Channel->Sid(), Channel->Vpid(), STREAM_TYPE_VIDEO);
2729  for (const int *Apid = Channel->Apids(); *Apid; Apid++)
2730  AddPid(Channel->Sid(), *Apid, STREAM_TYPE_AUDIO);
2731  for (const int *Dpid = Channel->Dpids(); *Dpid; Dpid++)
2732  AddPid(Channel->Sid(), *Dpid, STREAM_TYPE_PRIVATE);
2733  for (const int *Spid = Channel->Spids(); *Spid; Spid++)
2734  AddPid(Channel->Sid(), *Spid, STREAM_TYPE_PRIVATE);
2735  }
2736 }
2737 
2738 #define QUERY_REPLY_WAIT 100 // ms to wait between checks for a reply
2739 
2740 bool cCamSlot::CanDecrypt(const cChannel *Channel, cMtdMapper *MtdMapper)
2741 {
2742  if (Channel->Ca() < CA_ENCRYPTED_MIN)
2743  return true; // channel not encrypted
2744  if (!IsDecrypting())
2745  return true; // any CAM can decrypt at least one channel
2746  cMutexLock MutexLock(&mutex);
2748  if (cas && cas->RepliesToQuery()) {
2749  cCiCaPmt CaPmt(CPCI_QUERY, Channel->Source(), Channel->Transponder(), Channel->Sid(), GetCaSystemIds());
2750  CaPmt.SetListManagement(CPLM_ADD); // WORKAROUND: CPLM_ONLY doesn't work with Alphacrypt 3.09 (deletes existing CA_PMTs)
2751  CaPmt.AddPid(Channel->Vpid(), STREAM_TYPE_VIDEO);
2752  for (const int *Apid = Channel->Apids(); *Apid; Apid++)
2753  CaPmt.AddPid(*Apid, STREAM_TYPE_AUDIO);
2754  for (const int *Dpid = Channel->Dpids(); *Dpid; Dpid++)
2755  CaPmt.AddPid(*Dpid, STREAM_TYPE_PRIVATE);
2756  for (const int *Spid = Channel->Spids(); *Spid; Spid++)
2757  CaPmt.AddPid(*Spid, STREAM_TYPE_PRIVATE);
2758  if (MtdMapper)
2759  CaPmt.MtdMapPids(MtdMapper);
2760  cas->SendPMT(&CaPmt);
2761  cTimeMs Timeout(QUERY_REPLY_TIMEOUT);
2762  do {
2764  if ((cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT)) != NULL) { // must re-fetch it, there might have been a reset
2765  if (cas->ReceivedReply())
2766  return cas->CanDecrypt();
2767  }
2768  else
2769  return false;
2770  } while (!Timeout.TimedOut());
2771  dsyslog("CAM %d: didn't reply to QUERY", SlotNumber());
2772  }
2773  return false;
2774 }
2775 
2777 {
2779 }
2780 
2782 {
2783  cMutexLock MutexLock(&mutex);
2784  if (mtdHandler) {
2786  return;
2787  }
2788  if (caProgramList.Count()) {
2789  caProgramList.Clear();
2790  if (!dynamic_cast<cMtdCamSlot *>(this) || !MasterSlot()->IsDecrypting())
2792  }
2793 }
2794 
2796 {
2797  cMutexLock MutexLock(&mutex);
2798  if (mtdHandler)
2799  return mtdHandler->IsDecrypting();
2800  if (caProgramList.Count()) {
2801  for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
2802  if (p->modified)
2803  return true; // any modifications need to be processed before we can assume it's no longer decrypting
2804  for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {
2805  if (q->active)
2806  return true;
2807  }
2808  }
2809  }
2810  return false;
2811 }
2812 
2813 uchar *cCamSlot::Decrypt(uchar *Data, int &Count)
2814 {
2815  if (Data)
2816  Count = TS_SIZE;
2817  return Data;
2818 }
2819 
2821 {
2822  return tc[1] ? tc[1]->TsPostProcess(Data) : false;
2823 }
2824 
2825 bool cCamSlot::Inject(uchar *Data, int Count)
2826 {
2827  return true;
2828 }
2829 
2830 void cCamSlot::InjectEit(int Sid)
2831 {
2832  cEitGenerator Eit(Sid);
2833  Inject(Eit.Data(), Eit.Length());
2834 }
2835 
2836 // --- cCamSlots -------------------------------------------------------------
2837 
2839 
2841 {
2842  int n = 0;
2843  for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
2844  if (CamSlot->IsMasterSlot() && CamSlot->ModuleStatus() == msReady)
2845  n++;
2846  }
2847  return n;
2848 }
2849 
2851 {
2852  bool ready = true;
2853  for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
2854  ready = true;
2855  for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
2856  if (!CamSlot->Ready()) {
2857  ready = false;
2858  cCondWait::SleepMs(100);
2859  }
2860  }
2861  if (ready)
2862  break;
2863  }
2864  for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot))
2865  dsyslog("CAM %d: %sready, %s", CamSlot->SlotNumber(), CamSlot->Ready() ? "" : "not ", CamSlot->IsMasterSlot() ? *cString::sprintf("master (%s)", CamSlot->GetCamName() ? CamSlot->GetCamName() : "empty") : *cString::sprintf("slave of CAM %d", CamSlot->MasterSlotNumber()));
2866  return ready;
2867 }
2868 
2869 // --- cChannelCamRelation ---------------------------------------------------
2870 
2871 #define CAM_CHECKED_TIMEOUT 15 // seconds before a CAM that has been checked for a particular channel will be checked again
2872 
2874 private:
2878  time_t lastChecked;
2879 public:
2881  bool TimedOut(void);
2882  tChannelID ChannelID(void) { return channelID; }
2883  bool CamChecked(int CamSlotNumber);
2884  bool CamDecrypt(int CamSlotNumber);
2885  void SetChecked(int CamSlotNumber);
2886  void SetDecrypt(int CamSlotNumber);
2887  void ClrChecked(int CamSlotNumber);
2888  void ClrDecrypt(int CamSlotNumber);
2889  };
2890 
2892 {
2893  channelID = ChannelID;
2894  camSlotsChecked = 0;
2895  camSlotsDecrypt = 0;
2896  lastChecked = 0;
2897 }
2898 
2900 {
2901  return !camSlotsDecrypt && time(NULL) - lastChecked > CAM_CHECKED_TIMEOUT;
2902 }
2903 
2904 bool cChannelCamRelation::CamChecked(int CamSlotNumber)
2905 {
2906  if (lastChecked && time(NULL) - lastChecked > CAM_CHECKED_TIMEOUT) {
2907  lastChecked = 0;
2908  camSlotsChecked = 0;
2909  }
2910  return camSlotsChecked & (1 << (CamSlotNumber - 1));
2911 }
2912 
2913 bool cChannelCamRelation::CamDecrypt(int CamSlotNumber)
2914 {
2915  return camSlotsDecrypt & (1 << (CamSlotNumber - 1));
2916 }
2917 
2918 void cChannelCamRelation::SetChecked(int CamSlotNumber)
2919 {
2920  camSlotsChecked |= (1 << (CamSlotNumber - 1));
2921  lastChecked = time(NULL);
2922  ClrDecrypt(CamSlotNumber);
2923 }
2924 
2925 void cChannelCamRelation::SetDecrypt(int CamSlotNumber)
2926 {
2927  camSlotsDecrypt |= (1 << (CamSlotNumber - 1));
2928  ClrChecked(CamSlotNumber);
2929 }
2930 
2931 void cChannelCamRelation::ClrChecked(int CamSlotNumber)
2932 {
2933  camSlotsChecked &= ~(1 << (CamSlotNumber - 1));
2934  lastChecked = 0;
2935 }
2936 
2937 void cChannelCamRelation::ClrDecrypt(int CamSlotNumber)
2938 {
2939  camSlotsDecrypt &= ~(1 << (CamSlotNumber - 1));
2940 }
2941 
2942 // --- cChannelCamRelations --------------------------------------------------
2943 
2944 #define MAX_CAM_NUMBER 32
2945 #define CHANNEL_CAM_RELATIONS_CLEANUP_INTERVAL 3600 // seconds between cleanups
2946 
2948 
2950 {
2951  lastCleanup = time(NULL);
2952 }
2953 
2955 {
2956  cMutexLock MutexLock(&mutex);
2958  for (cChannelCamRelation *ccr = First(); ccr; ) {
2959  cChannelCamRelation *c = ccr;
2960  ccr = Next(ccr);
2961  if (c->TimedOut())
2962  Del(c);
2963  }
2964  lastCleanup = time(NULL);
2965  }
2966 }
2967 
2969 {
2970  cMutexLock MutexLock(&mutex);
2971  Cleanup();
2972  for (cChannelCamRelation *ccr = First(); ccr; ccr = Next(ccr)) {
2973  if (ccr->ChannelID() == ChannelID)
2974  return ccr;
2975  }
2976  return NULL;
2977 }
2978 
2980 {
2981  cMutexLock MutexLock(&mutex);
2982  cChannelCamRelation *ccr = GetEntry(ChannelID);
2983  if (!ccr)
2984  Add(ccr = new cChannelCamRelation(ChannelID));
2985  return ccr;
2986 }
2987 
2988 void cChannelCamRelations::Reset(int CamSlotNumber)
2989 {
2990  cMutexLock MutexLock(&mutex);
2991  for (cChannelCamRelation *ccr = First(); ccr; ccr = Next(ccr)) {
2992  ccr->ClrChecked(CamSlotNumber);
2993  ccr->ClrDecrypt(CamSlotNumber);
2994  }
2995 }
2996 
2997 bool cChannelCamRelations::CamChecked(tChannelID ChannelID, int CamSlotNumber)
2998 {
2999  cMutexLock MutexLock(&mutex);
3000  cChannelCamRelation *ccr = GetEntry(ChannelID);
3001  return ccr ? ccr->CamChecked(CamSlotNumber) : false;
3002 }
3003 
3004 bool cChannelCamRelations::CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
3005 {
3006  cMutexLock MutexLock(&mutex);
3007  cChannelCamRelation *ccr = GetEntry(ChannelID);
3008  return ccr ? ccr->CamDecrypt(CamSlotNumber) : false;
3009 }
3010 
3011 void cChannelCamRelations::SetChecked(tChannelID ChannelID, int CamSlotNumber)
3012 {
3013  cMutexLock MutexLock(&mutex);
3014  cChannelCamRelation *ccr = AddEntry(ChannelID);
3015  if (ccr)
3016  ccr->SetChecked(CamSlotNumber);
3017 }
3018 
3019 void cChannelCamRelations::SetDecrypt(tChannelID ChannelID, int CamSlotNumber)
3020 {
3021  cMutexLock MutexLock(&mutex);
3022  cChannelCamRelation *ccr = AddEntry(ChannelID);
3023  if (ccr)
3024  ccr->SetDecrypt(CamSlotNumber);
3025 }
3026 
3027 void cChannelCamRelations::ClrChecked(tChannelID ChannelID, int CamSlotNumber)
3028 {
3029  cMutexLock MutexLock(&mutex);
3030  cChannelCamRelation *ccr = GetEntry(ChannelID);
3031  if (ccr)
3032  ccr->ClrChecked(CamSlotNumber);
3033 }
3034 
3035 void cChannelCamRelations::ClrDecrypt(tChannelID ChannelID, int CamSlotNumber)
3036 {
3037  cMutexLock MutexLock(&mutex);
3038  cChannelCamRelation *ccr = GetEntry(ChannelID);
3039  if (ccr)
3040  ccr->ClrDecrypt(CamSlotNumber);
3041 }
3042 
3043 void cChannelCamRelations::Load(const char *FileName)
3044 {
3045  cMutexLock MutexLock(&mutex);
3046  fileName = FileName;
3047  if (access(fileName, R_OK) == 0) {
3048  dsyslog("loading %s", *fileName);
3049  if (FILE *f = fopen(fileName, "r")) {
3050  cReadLine ReadLine;
3051  char *s;
3052  while ((s = ReadLine.Read(f)) != NULL) {
3053  if (char *p = strchr(s, ' ')) {
3054  *p = 0;
3055  if (*++p) {
3056  tChannelID ChannelID = tChannelID::FromString(s);
3057  if (ChannelID.Valid()) {
3058  char *q;
3059  char *strtok_next;
3060  while ((q = strtok_r(p, " ", &strtok_next)) != NULL) {
3061  int CamSlotNumber = atoi(q);
3062  if (CamSlotNumber >= 1 && CamSlotNumber <= MAX_CAM_NUMBER)
3063  SetDecrypt(ChannelID, CamSlotNumber);
3064  p = NULL;
3065  }
3066  }
3067  }
3068  }
3069  }
3070  fclose(f);
3071  }
3072  else
3074  }
3075 }
3076 
3078 {
3079  if (!*fileName)
3080  return;
3081  cMutexLock MutexLock(&mutex);
3082  struct stat st;
3083  if (stat(fileName, &st) == 0) {
3084  if ((st.st_mode & S_IWUSR) == 0) {
3085  dsyslog("not saving %s (file is read-only)", *fileName);
3086  return;
3087  }
3088  }
3089  dsyslog("saving %s", *fileName);
3090  cSafeFile f(fileName);
3091  if (f.Open()) {
3092  for (cChannelCamRelation *ccr = First(); ccr; ccr = Next(ccr)) {
3093  if (ccr->ChannelID().Valid()) {
3094  cString s;
3095  for (int i = 1; i <= MAX_CAM_NUMBER; i++) {
3096  if (ccr->CamDecrypt(i))
3097  s = cString::sprintf("%s%s%d", *s ? *s : "", *s ? " " : "", i);
3098  }
3099  if (*s)
3100  fprintf(f, "%s %s\n", *ccr->ChannelID().ToString(), *s);
3101  }
3102  }
3103  f.Close();
3104  }
3105  else
3107 }
#define CA_ENCRYPTED_MIN
Definition: channels.h:44
#define LOCK_CHANNELS_READ
Definition: channels.h:273
static bool DumpTPDUDataTransfer
Definition: ci.c:31
#define ST_CREATE_SESSION_RESPONSE
Definition: ci.c:658
#define T_DATA_MORE
Definition: ci.c:503
#define AOT_PROFILE_CHANGE
Definition: ci.c:681
#define AOT_APPLICATION_INFO_ENQ
Definition: ci.c:682
cChannelCamRelations ChannelCamRelations
Definition: ci.c:2947
#define AOT_ENTER_MENU
Definition: ci.c:684
#define ST_OPEN_SESSION_REQUEST
Definition: ci.c:655
#define QUERY_REPLY_TIMEOUT
Definition: ci.c:1107
#define AOT_ENQ
Definition: ci.c:702
#define AI_ANSWER
Definition: ci.c:1403
#define CPLM_ONLY
Definition: ci.c:924
#define MAX_CAM_NUMBER
Definition: ci.c:2944
#define DEC2BCD(d)
#define AOT_PROFILE_ENQ
Definition: ci.c:679
#define SS_NOT_ALLOCATED
Definition: ci.c:665
#define CRA_DISCARD
Definition: ci.c:360
#define DRI_MMI_MODE_ACK
Definition: ci.c:1387
static const uint8_t * GetLength(const uint8_t *Data, int &Length)
Definition: ci.c:42
cCamSlots CamSlots
Definition: ci.c:2838
#define QUERY_REPLY_WAIT
Definition: ci.c:2738
#define MM_HIGH_LEVEL
Definition: ci.c:1381
#define MAX_TPDU_SIZE
Definition: ci.c:488
#define AOT_APPLICATION_INFO
Definition: ci.c:683
cCiResourceHandlers CiResourceHandlers
Definition: ci.c:1777
static int MtdMapCaDescriptors(uchar *p, cMtdMapper *MtdMapper)
Definition: ci.c:1031
#define T_CREATE_TC
Definition: ci.c:495
static bool DumpDateTime
Definition: ci.c:34
#define SIZE_INDICATOR
Definition: ci.c:40
#define ST_CLOSE_SESSION_REQUEST
Definition: ci.c:659
#define RI_DATE_TIME
Definition: ci.c:673
#define SS_OK
Definition: ci.c:664
#define AOT_TEXT_LAST
Definition: ci.c:698
#define TC_ALIVE_TIMEOUT
Definition: ci.c:1809
#define MAXCASYSTEMIDS
Definition: ci.c:917
#define MODULE_RESET_TIMEOUT
Definition: ci.c:2176
#define RI_MMI
Definition: ci.c:674
#define T_DTC_REPLY
Definition: ci.c:498
#define AOT_CLOSE_MMI
Definition: ci.c:695
#define AOT_TUNE
Definition: ci.c:689
#define AOT_LIST_LAST
Definition: ci.c:707
#define CPCI_OK_DESCRAMBLING
Definition: ci.c:930
#define CPCI_QUERY
Definition: ci.c:932
#define STREAM_TYPE_VIDEO
Definition: ci.c:2716
#define ST_CLOSE_SESSION_RESPONSE
Definition: ci.c:660
#define T_TC_ERROR
Definition: ci.c:501
#define EF_BLIND
Definition: ci.c:1398
#define AOT_MENU_LAST
Definition: ci.c:704
#define QUERY_WAIT_TIME
Definition: ci.c:1106
#define AOT_DATE_TIME
Definition: ci.c:694
#define CPCI_NOT_SELECTED
Definition: ci.c:933
#define STREAM_TYPE_AUDIO
Definition: ci.c:2717
#define CA_ENABLE(x)
Definition: ci.c:1104
#define RI_RESOURCE_MANAGER
Definition: ci.c:669
#define T_REQUEST_TC
Definition: ci.c:499
#define DATA_INDICATOR
Definition: ci.c:491
#define MAX_DUMP
static uint8_t * SetLength(uint8_t *Data, int Length)
Definition: ci.c:57
#define T_CTC_REPLY
Definition: ci.c:496
#define CRA_NONE
Definition: ci.c:359
#define RI_CONDITIONAL_ACCESS_SUPPORT
Definition: ci.c:671
#define AOT_ANSW
Definition: ci.c:703
#define T_DELETE_TC
Definition: ci.c:497
#define CHANNEL_CAM_RELATIONS_CLEANUP_INTERVAL
Definition: ci.c:2945
#define AOT_PROFILE
Definition: ci.c:680
#define AOT_CA_INFO_ENQ
Definition: ci.c:685
static bool DebugProtocol
Definition: ci.c:32
#define AI_CANCEL
Definition: ci.c:1402
#define CPLM_ADD
Definition: ci.c:925
#define MAX_TPDU_DATA
Definition: ci.c:489
#define AOT_CA_INFO
Definition: ci.c:686
static char * GetString(int &Length, const uint8_t **Data)
Definition: ci.c:96
#define T_RCV
Definition: ci.c:494
#define CAM_CHECKED_TIMEOUT
Definition: ci.c:2871
#define T_DATA_LAST
Definition: ci.c:502
#define RI_APPLICATION_INFORMATION
Definition: ci.c:670
#define RI_HOST_CONTROL
Definition: ci.c:672
static int MtdMapStreams(uchar *p, cMtdMapper *MtdMapper, int Length)
Definition: ci.c:1058
static int MtdMapCaDescriptor(uchar *p, cMtdMapper *MtdMapper)
Definition: ci.c:1014
#define ST_OPEN_SESSION_RESPONSE
Definition: ci.c:656
#define AOT_DISPLAY_CONTROL
Definition: ci.c:696
#define CAEI_POSSIBLE
Definition: ci.c:1096
#define RESOURCE_CLASS_MASK
Definition: ci.c:727
#define AOT_CA_PMT
Definition: ci.c:687
#define TC_POLL_TIMEOUT
Definition: ci.c:1808
#define CRA_CONFIRM
Definition: ci.c:361
static bool DumpPolls
Definition: ci.c:33
#define UNSCRAMBLE_TIME
Definition: ci.c:308
#define CRA_SELECT
Definition: ci.c:362
cCamResponses CamResponses
Definition: ci.c:479
#define STREAM_TYPE_PRIVATE
Definition: ci.c:2718
#define dbgprotocol(a...)
Definition: ci.c:36
#define CPLM_UPDATE
Definition: ci.c:926
#define AOT_CLEAR_REPLACE
Definition: ci.c:691
#define DCC_SET_MMI_MODE
Definition: ci.c:1373
#define AOT_CA_PMT_REPLY
Definition: ci.c:688
#define AOT_NONE
Definition: ci.c:678
#define AOT_DATE_TIME_ENQ
Definition: ci.c:693
#define TS_PACKET_FACTOR
Definition: ci.c:309
#define T_SB
Definition: ci.c:493
#define T_NEW_TC
Definition: ci.c:500
static char * CopyString(int Length, const uint8_t *Data)
Definition: ci.c:77
#define MAX_SESSIONS_PER_TC
Definition: ci.c:609
static int MtdMapStream(uchar *p, cMtdMapper *MtdMapper)
Definition: ci.c:1048
#define AOT_REPLACE
Definition: ci.c:690
bool CamResponsesLoad(const char *FileName, bool AllowComments, bool MustExist)
Definition: ci.c:481
#define MODULE_CHECK_INTERVAL
Definition: ci.c:2175
#define QUERY_RETRIES
Definition: ci.c:1108
#define AOT_MENU_ANSW
Definition: ci.c:706
#define AOT_DISPLAY_REPLY
Definition: ci.c:697
#define CAT_MAXPACKETS
Definition: ci.c:123
#define ST_SESSION_NUMBER
Definition: ci.c:654
eModuleStatus
Definition: ci.h:170
@ msReady
Definition: ci.h:170
@ msPresent
Definition: ci.h:170
@ msNone
Definition: ci.h:170
@ msReset
Definition: ci.h:170
#define MAX_CAM_SLOTS_PER_ADAPTER
Definition: ci.h:20
#define MAX_CONNECTIONS_PER_CAM_SLOT
Definition: ci.h:21
static u_int32_t crc32(const char *d, int len, u_int32_t CRCvalue)
Definition: util.c:267
virtual ~cCaActivationReceiver() override
Definition: ci.c:331
cCaActivationReceiver(const cChannel *Channel, cCamSlot *CamSlot)
Definition: ci.c:323
virtual void Receive(const uchar *Data, int Length) override
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
Definition: ci.c:336
time_t lastScrambledTime
Definition: ci.c:314
cCamSlot * camSlot
Definition: ci.c:313
bool handlingPid
Definition: ci.c:128
virtual ~cCaPidReceiver() override
Definition: ci.c:133
cMutex mutex
Definition: ci.c:127
void Reset(void)
Definition: ci.c:136
void DelEmmPids(void)
Definition: ci.c:174
uchar mtdCatBuffer[CAT_MAXPACKETS][TS_SIZE]
Definition: ci.c:124
virtual void Receive(const uchar *Data, int Length) override
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
Definition: ci.c:184
cCaPidReceiver(void)
Definition: ci.c:148
uchar buffer[1024]
Definition: ci.c:121
bool HandlingPid(void)
The cCaPidReceiver adds/deletes PIDs to/from the base class cReceiver, which in turn does the same on...
Definition: ci.c:297
int catVersion
Definition: ci.c:119
int mtdNumCatPackets
Definition: ci.c:125
int length
Definition: ci.c:126
uchar * bufp
Definition: ci.c:122
bool HasCaPids(void) const
Definition: ci.c:135
cVector< int > emmPids
Definition: ci.c:120
void AddEmmPid(int Pid)
Definition: ci.c:161
cCamResponse(void)
Definition: ci.c:376
~cCamResponse()
Definition: ci.c:383
char * text
Definition: ci.c:367
int action
Definition: ci.c:368
bool Parse(const char *s)
Definition: ci.c:388
int camNumber
Definition: ci.c:366
int Matches(int CamNumber, const char *Text) const
Definition: ci.c:451
int GetMatch(int CamNumber, const char *Text) const
Definition: ci.c:467
Definition: ci.h:232
bool Devices(cVector< int > &DeviceNumbers)
Adds the numbers of any devices that currently use this CAM to the given DeviceNumbers.
Definition: ci.c:2262
virtual bool RepliesToQuery(void)
Returns true if the CAM in this slot replies to queries and thus supports MCD ("Multi Channel Decrypt...
Definition: ci.c:2520
virtual bool IsDecrypting(void)
Returns true if the CAM in this slot is currently used for decrypting.
Definition: ci.c:2795
virtual bool Ready(void)
Returns 'true' if the CAM in this slot is ready to decrypt.
Definition: ci.c:2451
virtual void InjectEit(int Sid)
Injects a generated EIT with a "present event" for the given Sid into the TS data stream sent to the ...
Definition: ci.c:2830
int Priority(void)
Returns the priority of the device this slot is currently assigned to, or IDLEPRIORITY if it is not a...
Definition: ci.c:2656
cMutex mutex
Definition: ci.h:238
virtual const char * GetCamName(void)
Returns the name of the CAM in this slot, or NULL if there is no ready CAM in this slot.
Definition: ci.c:2445
void DeleteAllConnections(void)
Definition: ci.c:2285
friend class cCiTransportConnection
Definition: ci.h:234
int source
Definition: ci.h:252
int slotIndex
Definition: ci.h:245
cCiSession * GetSessionByResourceId(uint32_t ResourceId)
Definition: ci.c:2360
virtual bool CanDecrypt(const cChannel *Channel, cMtdMapper *MtdMapper=NULL)
Returns true if there is a CAM in this slot that is able to decrypt the given Channel (or at least cl...
Definition: ci.c:2740
void KeepSharedCaPids(int ProgramNumber, const int *CaSystemIds, int *CaPids)
Definition: ci.c:2566
virtual bool Inject(uchar *Data, int Count)
Sends all Count bytes of the given Data to the CAM, and returns true if this was possible.
Definition: ci.c:2825
void MtdEnable(void)
Enables MTD support for this CAM.
Definition: ci.c:2622
bool McdAvailable(void)
Returns true if this CAM supports MCD ("Multi Channel Decyption").
Definition: ci.h:284
virtual bool EnterMenu(void)
Requests the CAM in this slot to start its menu.
Definition: ci.c:2468
virtual uchar * Decrypt(uchar *Data, int &Count)
If this is a CAM slot that can be freely assigned to any device, but will not be directly inserted in...
Definition: ci.c:2813
virtual void AddPid(int ProgramNumber, int Pid, int StreamType)
Adds the given PID information to the list of PIDs.
Definition: ci.c:2679
cDevice * assignedDevice
Definition: ci.h:242
int MasterSlotNumber(void)
Returns the number of this CAM's master slot within the whole system.
Definition: ci.h:347
virtual cCiEnquiry * GetEnquiry(void)
Gets a pending enquiry, or NULL if there is no enquiry.
Definition: ci.c:2488
bool mtdAvailable
Definition: ci.h:255
void Process(cTPDU *TPDU=NULL)
Definition: ci.c:2294
cMtdHandler * mtdHandler
Definition: ci.h:256
cCaActivationReceiver * caActivationReceiver
Definition: ci.h:244
virtual eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition: ci.c:2431
void MtdActivate(bool On)
Activates (On == true) or deactivates (On == false) MTD.
Definition: ci.c:2627
eModuleStatus lastModuleStatus
Definition: ci.h:248
virtual ~cCamSlot() override
Definition: ci.c:2203
cCaPidReceiver * caPidReceiver
Definition: ci.h:243
virtual void AddChannel(const cChannel *Channel)
Adds all PIDs of the given Channel to the current list of PIDs.
Definition: ci.c:2720
void NewConnection(void)
Definition: ci.c:2272
bool resendPmt
Definition: ci.h:251
int transponder
Definition: ci.h:253
virtual bool HasUserIO(void)
Returns true if there is a pending user interaction, which shall be retrieved via GetMenu() or GetEnq...
Definition: ci.c:2462
virtual const int * GetCaSystemIds(void)
Definition: ci.c:2649
time_t resetTime
Definition: ci.h:249
bool WantsTsData(void) const
Returns true if this CAM slot wants to receive the TS data through its Decrypt() function.
Definition: ci.h:338
virtual bool Assign(cDevice *Device, bool Query=false)
Assigns this CAM slot to the given Device, if this is possible.
Definition: ci.c:2221
virtual cCiMenu * GetMenu(void)
Gets a pending menu, or NULL if there is no menu.
Definition: ci.c:2475
cTimeMs moduleCheckTimer
Definition: ci.h:250
virtual void SendCaPmt(uint8_t CmdId)
Definition: ci.c:2614
cCondVar processed
Definition: ci.h:239
virtual bool Reset(void)
Resets the CAM in this slot.
Definition: ci.c:2375
int slotNumber
Definition: ci.h:246
virtual void SetPid(int Pid, bool Active)
Sets the given Pid (which has previously been added through a call to AddPid()) to Active.
Definition: ci.c:2697
virtual void StartActivation(void)
Puts the CAM in this slot into a mode where an inserted smart card can be activated.
Definition: ci.c:2398
virtual void StartDecrypting(void)
Sends all CA_PMT entries to the CAM that have been modified since the last call to this function.
Definition: ci.c:2776
virtual bool IsActivating(void)
Returns true if this CAM slot is currently activating a smart card.
Definition: ci.c:2424
bool MtdAvailable(void)
Returns true if this CAM supports MTD ("Multi Transponder Decryption").
Definition: ci.h:286
cCiTransportConnection * tc[MAX_CONNECTIONS_PER_CAM_SLOT+1]
Definition: ci.h:247
virtual bool TsPostProcess(uchar *Data)
If there is a cCiSession that needs to do additional processing on TS packets (after the CAM has done...
Definition: ci.c:2820
int MtdPutData(uchar *Data, int Count)
Sends at most Count bytes of the given Data to the individual MTD CAM slots that are using this CAM.
Definition: ci.c:2644
void Write(cTPDU *TPDU)
Definition: ci.c:2366
int SlotIndex(void)
Returns the index of this CAM slot within its CI adapter.
Definition: ci.h:341
cCiAdapter * ciAdapter
Definition: ci.h:240
cList< cCiCaProgramData > caProgramList
Definition: ci.h:254
virtual void StopDecrypting(void)
Clears the list of CA_PMT entries and tells the CAM to stop decrypting.
Definition: ci.c:2781
void SendCaPmts(cCiCaPmtList &CaPmtList)
Sends the given list of CA_PMTs to the CAM.
Definition: ci.c:2603
virtual bool HasMMI(void)
Returns 'true' if the CAM in this slot has an active MMI.
Definition: ci.c:2457
virtual bool CanActivate(void)
Returns true if there is a CAM in this slot that can be put into activation mode.
Definition: ci.c:2393
cCamSlot(cCiAdapter *CiAdapter, bool WantsTsData=false, cCamSlot *MasterSlot=NULL)
Creates a new CAM slot for the given CiAdapter.
Definition: ci.c:2178
cDevice * Device(void)
Returns the device this CAM slot is currently assigned to.
Definition: ci.h:332
cCamSlot * MtdSpawn(void)
If this CAM slot can do MTD ("Multi Transponder Decryption"), a call to this function returns a cMtdC...
Definition: ci.c:2213
cCamSlot * masterSlot
Definition: ci.h:241
void BuildCaPmts(uint8_t CmdId, cCiCaPmtList &CaPmtList, cMtdMapper *MtdMapper=NULL)
Generates all CA_PMTs with the given CmdId and stores them in the given CaPmtList.
Definition: ci.c:2527
cCamSlot * MasterSlot(void)
Returns this CAM slot's master slot, or a pointer to itself if it is a master slot.
Definition: ci.h:309
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition: ci.h:344
virtual void CancelActivation(void)
Cancels a previously started activation (if any).
Definition: ci.c:2413
virtual bool ProvidesCa(const int *CaSystemIds)
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition: ci.c:2664
Definition: ci.h:493
bool WaitForAllCamSlotsReady(int Timeout=0)
Waits until all CAM slots have become ready, or the given Timeout (seconds) has expired.
Definition: ci.c:2850
int NumReadyMasterSlots(void)
Returns the number of master CAM slots in the system that are ready to decrypt.
Definition: ci.c:2840
bool CamChecked(int CamSlotNumber)
Definition: ci.c:2904
void ClrChecked(int CamSlotNumber)
Definition: ci.c:2931
bool TimedOut(void)
Definition: ci.c:2899
time_t lastChecked
Definition: ci.c:2878
uint32_t camSlotsDecrypt
Definition: ci.c:2877
tChannelID ChannelID(void)
Definition: ci.c:2882
void SetChecked(int CamSlotNumber)
Definition: ci.c:2918
cChannelCamRelation(tChannelID ChannelID)
Definition: ci.c:2891
void SetDecrypt(int CamSlotNumber)
Definition: ci.c:2925
bool CamDecrypt(int CamSlotNumber)
Definition: ci.c:2913
uint32_t camSlotsChecked
Definition: ci.c:2876
tChannelID channelID
Definition: ci.c:2875
void ClrDecrypt(int CamSlotNumber)
Definition: ci.c:2937
void ClrDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:3035
void Load(const char *FileName)
Definition: ci.c:3043
void SetChecked(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:3011
cMutex mutex
Definition: ci.h:512
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:3004
cChannelCamRelations(void)
Definition: ci.c:2949
void Cleanup(void)
Definition: ci.c:2954
bool CamChecked(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2997
time_t lastCleanup
Definition: ci.h:516
cChannelCamRelation * GetEntry(tChannelID ChannelID)
Definition: ci.c:2968
cChannelCamRelation * AddEntry(tChannelID ChannelID)
Definition: ci.c:2979
void SetDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:3019
cString fileName
Definition: ci.h:513
void ClrChecked(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:3027
void Save(void)
Definition: ci.c:3077
void Reset(int CamSlotNumber)
Definition: ci.c:2988
const int * Dpids(void) const
Definition: channels.h:160
int Vpid(void) const
Definition: channels.h:156
int Source(void) const
Definition: channels.h:154
int Ca(int Index=0) const
Definition: channels.h:175
const int * Spids(void) const
Definition: channels.h:161
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:155
int Sid(void) const
Definition: channels.h:178
const int * Apids(void) const
Definition: channels.h:159
Definition: ci.h:172
cCamSlot * camSlots[MAX_CAM_SLOTS_PER_ADAPTER]
Definition: ci.h:175
virtual bool Reset(int Slot)
Resets the CAM in the given Slot.
Definition: ci.h:194
cCiAdapter(void)
Definition: ci.c:2115
virtual eModuleStatus ModuleStatus(int Slot)
Returns the status of the CAM in the given Slot.
Definition: ci.h:197
cCamSlot * ItCamSlot(int &Iter)
Iterates over all added CAM slots of this adapter.
Definition: ci.c:2143
virtual bool Assign(cDevice *Device, bool Query=false)
Assigns this adapter to the given Device, if this is possible.
Definition: ci.h:199
virtual ~cCiAdapter() override
The derived class must call Cancel(3) in its destructor.
Definition: ci.c:2122
void AddCamSlot(cCamSlot *CamSlot)
Adds the given CamSlot to this CI adapter.
Definition: ci.c:2129
virtual void Action(void) override
Handles the attached CAM slots in a separate thread.
Definition: ci.c:2154
virtual void Write(const uint8_t *Buffer, int Length)
Writes Length bytes of the given Buffer.
Definition: ci.h:192
virtual int Read(uint8_t *Buffer, int MaxLength)
Reads one chunk of data into the given Buffer, up to MaxLength bytes.
Definition: ci.h:187
virtual ~cCiApplicationInformation() override
Definition: ci.c:867
virtual void Process(int Length=0, const uint8_t *Data=NULL) override
Definition: ci.c:872
const char * GetMenuString(void)
Definition: ci.h:80
uint16_t manufacturerCode
Definition: ci.h:73
cCiApplicationInformation(uint16_t SessionId, cCiTransportConnection *Tc)
Definition: ci.c:859
bool EnterMenu(void)
Definition: ci.c:905
uint8_t applicationType
Definition: ci.h:71
uint16_t applicationManufacturer
Definition: ci.h:72
cCiCaPidData(int Pid, int StreamType)
Definition: ci.c:2083
int pid
Definition: ci.c:2081
int streamType
Definition: ci.c:2082
bool active
Definition: ci.c:2080
Definition: ci.c:935
int transponder
Definition: ci.c:943
int programNumber
Definition: ci.c:944
int esInfoLengthPos
Definition: ci.c:939
int caSystemIds[MAXCASYSTEMIDS+1]
Definition: ci.c:945
cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const int *CaSystemIds)
Definition: ci.c:956
uint8_t CmdId(void)
Definition: ci.c:949
void AddPid(int Pid, uint8_t StreamType)
Definition: ci.c:984
void SetListManagement(uint8_t ListManagement)
Definition: ci.c:979
cDynamicBuffer capmt
Definition: ci.c:941
cDynamicBuffer caDescriptors
Definition: ci.c:940
int source
Definition: ci.c:942
void MtdMapPids(cMtdMapper *MtdMapper)
Definition: ci.c:1073
void AddCaDescriptors(int Length, const uint8_t *Data)
Definition: ci.c:998
uint8_t cmdId
Definition: ci.c:938
uint8_t ListManagement(void)
Definition: ci.c:951
int programNumber
Definition: ci.c:2095
bool modified
Definition: ci.c:2096
cList< cCiCaPidData > pidList
Definition: ci.c:2097
cCiCaProgramData(int ProgramNumber)
Definition: ci.c:2098
bool Active(void)
Definition: ci.c:2103
bool RepliesToQuery(void)
Definition: ci.c:1123
bool CanDecrypt(void)
Definition: ci.c:1126
int caSystemIds[MAXCASYSTEMIDS+1]
Definition: ci.c:1114
cCiConditionalAccessSupport(uint16_t SessionId, cCiTransportConnection *Tc)
Definition: ci.c:1129
bool ReceivedReply(void)
Definition: ci.c:1125
virtual void Process(int Length=0, const uint8_t *Data=NULL) override
Definition: ci.c:1139
const int * GetCaSystemIds(void)
Definition: ci.c:1121
void SendPMT(cCiCaPmt *CaPmt)
Definition: ci.c:1257
int interval
Definition: ci.c:1303
time_t lastTime
Definition: ci.c:1304
void SendDateTime(void)
Definition: ci.c:1319
virtual void Process(int Length=0, const uint8_t *Data=NULL) override
Definition: ci.c:1344
cCiDateTime(uint16_t SessionId, cCiTransportConnection *Tc)
Definition: ci.c:1311
virtual cCiSession * GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc) override
Returns a new cCiSession, according to the given ResourceId.
Definition: ci.c:1762
virtual const uint32_t * ResourceIds(void) const
Returns a pointer to an array of resource identifiers, where the last value is zero.
Definition: ci.c:1748
Definition: ci.h:148
void Cancel(void)
Definition: ci.c:1718
cCiEnquiry(cCiMMI *MMI)
Definition: ci.c:1694
~cCiEnquiry()
Definition: ci.c:1703
cCiMMI * mmi
Definition: ci.h:152
char * text
Definition: ci.h:154
cMutex * mutex
Definition: ci.h:153
void Abort(void)
Definition: ci.c:1723
void Reply(const char *s)
Definition: ci.c:1711
bool blind
Definition: ci.h:155
int expectedLength
Definition: ci.h:156
cCiHostControl(uint16_t SessionId, cCiTransportConnection *Tc)
Definition: ci.c:1274
virtual void Process(int Length=0, const uint8_t *Data=NULL) override
Definition: ci.c:1280
Definition: ci.c:1405
cCiEnquiry * Enquiry(bool Clear=false)
Definition: ci.c:1596
cCiMenu * Menu(bool Clear=false)
Definition: ci.c:1585
cCiEnquiry * enquiry
Definition: ci.c:1409
virtual bool HasUserIO(void)
Definition: ci.c:1414
cCiMMI(uint16_t SessionId, cCiTransportConnection *Tc)
Definition: ci.c:1422
cCiMenu * menu
Definition: ci.c:1408
cCiEnquiry * fetchedEnquiry
Definition: ci.c:1409
bool SendCloseMMI(void)
Definition: ci.c:1628
virtual ~cCiMMI() override
Definition: ci.c:1430
bool SendAnswer(const char *Text)
Definition: ci.c:1613
char * GetText(int &Length, const uint8_t **Data)
Definition: ci.c:1444
void SendMenuAnswer(uint8_t Selection)
Definition: ci.c:1607
virtual void Process(int Length=0, const uint8_t *Data=NULL) override
Definition: ci.c:1460
cCiMenu * fetchedMenu
Definition: ci.c:1408
Definition: ci.h:119
bool selectable
Definition: ci.h:126
void Abort(void)
Definition: ci.c:1685
char * bottomText
Definition: ci.h:129
bool HasUpdate(void)
Definition: ci.c:1667
char * subTitleText
Definition: ci.h:128
cMutex * mutex
Definition: ci.h:125
void Cancel(void)
Definition: ci.c:1680
bool Selectable(void)
Definition: ci.h:141
int numEntries
Definition: ci.h:131
bool AddEntry(char *s)
Definition: ci.c:1658
cCiMenu(cCiMMI *MMI, bool Selectable)
Definition: ci.c:1637
~cCiMenu()
Definition: ci.c:1646
void Select(int Index)
Definition: ci.c:1673
char * titleText
Definition: ci.h:127
cCiMMI * mmi
Definition: ci.h:124
@ MAX_CIMENU_ENTRIES
Definition: ci.h:123
char * entries[MAX_CIMENU_ENTRIES]
Definition: ci.h:130
virtual const uint32_t * ResourceIds(void) const =0
Returns a pointer to an array of resource identifiers, where the last value is zero.
cCiResourceHandler(void)
Creates a new resource handler, through which the available resources can be provides.
Definition: ci.c:1732
virtual ~cCiResourceHandler() override
Definition: ci.c:1736
const uint32_t * Ids(void)
Definition: ci.h:110
cCiResourceHandlers(void)
Creates the default list of resourceIds.
Definition: ci.c:1779
int NumIds(void)
Definition: ci.h:111
cVector< uint32_t > resourceIds
Definition: ci.h:101
void Register(cCiResourceHandler *ResourceHandler)
Adds the given ResourceHandler to the list of resource handlers and appends its ResourceIds to the gl...
Definition: ci.c:1784
cCiSession * GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc)
Definition: ci.c:1797
cCiResourceManager(uint16_t SessionId, cCiTransportConnection *Tc)
Definition: ci.c:812
virtual void Process(int Length=0, const uint8_t *Data=NULL) override
Definition: ci.c:819
Definition: ci.h:32
uint16_t SessionId(void)
Definition: ci.h:52
int GetTag(int &Length, const uint8_t **Data)
Definition: ci.c:750
void SendData(int Tag, int Length=0, const uint8_t *Data=NULL)
Definition: ci.c:771
cCiTransportConnection * tc
Definition: ci.h:36
uint32_t resourceId
Definition: ci.h:35
cCiSession(uint16_t SessionId, uint32_t ResourceId, cCiTransportConnection *Tc)
Definition: ci.c:729
void SetResourceId(uint32_t Id)
If this is a class that has been derived from an existing cCiSession class, but implements a differen...
Definition: ci.c:740
uint32_t ResourceId(void)
Definition: ci.h:53
virtual bool TsPostProcess(uint8_t *TsPacket)
If this cCiSession needs to do additional processing on TS packets (after the CAM has done the decryp...
Definition: ci.h:57
cCamSlot * CamSlot(void)
Definition: ci.c:793
const uint8_t * GetData(const uint8_t *Data, int &Length)
Definition: ci.c:765
void SetTsPostProcessor(void)
If this cCiSession implements the TsPostProcess() function, it shall call SetTsPostProcessor() to reg...
Definition: ci.c:745
uint16_t sessionId
Definition: ci.h:34
cCiTransportConnection * Tc(void)
Definition: ci.h:48
virtual void Process(int Length=0, const uint8_t *Data=NULL)
Definition: ci.c:798
virtual ~cCiSession()
Definition: ci.c:736
virtual ~cCiTransportConnection()
Definition: ci.c:1826
cCiSession * GetSessionBySessionId(uint16_t SessionId)
Definition: ci.c:1904
void CreateConnection(void)
Definition: ci.c:640
cTimeMs timer
Definition: ci.c:622
bool TsPostProcess(uint8_t *TsPacket)
Definition: ci.c:1837
void OpenSession(int Length, const uint8_t *Data)
Definition: ci.c:1923
bool createConnectionRequested
Definition: ci.c:618
cCiSession * sessions[MAX_SESSIONS_PER_TC+1]
Definition: ci.c:623
cCamSlot * camSlot
Definition: ci.c:615
uint8_t tcid
Definition: ci.c:616
cCiSession * tsPostProcessor
Definition: ci.c:624
bool Ready(void)
Definition: ci.c:1845
void SetTsPostProcessor(cCiSession *CiSession)
Definition: ci.c:1832
const char * GetCamName(void)
Definition: ci.c:1851
void SendTag(uint8_t Tag, uint16_t SessionId, uint32_t ResourceId=0, int Status=-1)
Definition: ci.c:1871
cCiTransportConnection(cCamSlot *CamSlot, uint8_t Tcid)
Definition: ci.c:1811
cCamSlot * CamSlot(void)
Definition: ci.c:638
void Poll(void)
Definition: ci.c:1889
void DeleteConnection(void)
Definition: ci.c:641
void SendTPDU(uint8_t Tag, int Length=0, const uint8_t *Data=NULL)
Definition: ci.c:1857
cTimeMs alive
Definition: ci.c:621
void CloseSession(uint16_t SessionId)
Definition: ci.c:1946
void SendData(int Length, const uint8_t *Data)
Definition: ci.c:1864
uint32_t ResourceIdToInt(const uint8_t *Data)
Definition: ci.c:1899
bool deleteConnectionRequested
Definition: ci.c:619
bool HasUserIO(void)
Definition: ci.c:644
void HandleSessions(cTPDU *TPDU)
Definition: ci.c:1961
bool Process(cTPDU *TPDU=NULL)
Definition: ci.c:1988
uint8_t Tcid(void) const
Definition: ci.c:639
cCiSession * GetSessionByResourceId(uint32_t ResourceId)
Definition: ci.c:1909
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition: thread.c:133
void Broadcast(void)
Definition: thread.c:151
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:73
bool Load(const char *FileName=NULL, bool AllowComments=false, bool MustExist=false)
Definition: config.h:135
int Priority(bool IgnoreOccupied=false) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),...
Definition: device.c:1714
void SetCamSlot(cCamSlot *CamSlot)
Sets the given CamSlot to be used with this device.
Definition: device.c:459
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition: device.c:167
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition: device.c:1835
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition: device.h:371
void Detach(cFilter *Filter)
Detaches the given filter from this device.
Definition: device.c:718
cCamSlot * CamSlot(void) const
Returns the CAM slot that is currently used with this device, or NULL if no CAM slot is in use.
Definition: device.h:493
void Set(int Index, uchar Data)
Definition: tools.h:876
uchar Get(int Index)
Definition: tools.h:877
int Length(void)
Definition: tools.h:880
void Append(const uchar *Data, int Length)
Definition: tools.c:2353
uchar * Data(void)
Definition: tools.h:879
uchar * Data(void)
Definition: remux.h:442
int Length(void)
Definition: remux.h:443
virtual void Clear(void)
Definition: tools.c:2254
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2209
int Count(void) const
Definition: tools.h:627
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2177
int Index(void) const
Definition: tools.c:2097
cListObject * Next(void) const
Definition: tools.h:547
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:650
const cCiResourceHandler * Last(void) const
Returns the last element in this list, or NULL if the list is empty.
Definition: tools.h:645
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:643
const cCiResourceHandler * Prev(const cCiResourceHandler *Object) const
Definition: tools.h:647
int PutCat(const uchar *Data, int Count)
Definition: mtd.c:367
cMtdMapper * MtdMapper(void)
Definition: mtd.h:170
int Put(const uchar *Data, int Count)
Puts at most Count bytes of Data into the CAM slot which's index is derived from the PID of the TS pa...
Definition: mtd.c:60
bool IsActivating(void)
Returns true if any of the active MTD CAM slots is currently activating.
Definition: mtd.c:129
void StartDecrypting(void)
Tells all active MTD CAM slots to start decrypting.
Definition: mtd.c:105
bool IsDecrypting(void)
Returns true if any of the active MTD CAM slots is currently decrypting.
Definition: mtd.c:96
void CancelActivation(void)
Tells all active MTD CAM slots to cancel activation.
Definition: mtd.c:123
cMtdCamSlot * GetMtdCamSlot(cCamSlot *MasterSlot)
Creates a new MTD CAM slot, or reuses an existing one that is currently unused.
Definition: mtd.c:46
void StopDecrypting(void)
Tells all active MTD CAM slots to stop decrypting.
Definition: mtd.c:115
int Priority(void)
Returns the maximum priority of any of the active MTD CAM slots.
Definition: mtd.c:88
void UnAssignAll(void)
Unassigns all MTD CAM slots from their devices.
Definition: mtd.c:145
bool Devices(cVector< int > &DeviceNumbers)
Adds the numbers of the devices of any active MTD CAM slots to the given DeviceNumbers.
Definition: mtd.c:138
Definition: thread.h:67
char * Read(FILE *f)
Definition: tools.c:1527
bool AddPids(const int *Pids)
Adds the given zero terminated list of Pids to the list of PIDs of this receiver.
Definition: receiver.c:60
cDevice * Device(void)
Definition: receiver.h:32
void Detach(void)
Definition: receiver.c:125
bool AddPid(int Pid)
Adds the given Pid to the list of PIDs of this receiver.
Definition: receiver.c:42
void DelPids(const int *Pids)
Deletes the given zero terminated list of Pids from the list of PIDs of this receiver.
Definition: receiver.c:106
int NumPids(void) const
Definition: receiver.h:81
void DelPid(int Pid)
Deletes the given Pid from the list of PIDs of this receiver.
Definition: receiver.c:90
bool Open(void)
Definition: tools.c:1761
bool Close(void)
Definition: tools.c:1771
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition: skins.c:330
Definition: tools.h:178
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1195
Definition: ci.c:505
uint8_t Status(void)
Definition: ci.c:600
uint8_t * Buffer(void)
Definition: ci.c:518
int MaxSize(void)
Definition: ci.c:521
void Dump(int SlotNumber, bool Outgoing)
Definition: ci.c:571
const uint8_t * Data(int &Length)
Definition: ci.c:516
uint8_t buffer[MAX_TPDU_SIZE]
Definition: ci.c:508
int size
Definition: ci.c:507
int Size(void)
Definition: ci.c:519
uint8_t Tcid(void)
Definition: ci.c:514
uint8_t Tag(void)
Definition: ci.c:515
void SetSize(int Size)
Definition: ci.c:520
uint8_t Slot(void)
Definition: ci.c:513
cTPDU(void)
Definition: ci.c:511
const uint8_t * GetData(const uint8_t *Data, int &Length)
Definition: ci.c:588
Definition: thread.h:79
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition: thread.h:101
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
Definition: thread.c:355
Definition: tools.h:404
void Set(int Ms=0)
Sets the timer.
Definition: tools.c:808
bool TimedOut(void) const
Definition: tools.c:813
int Size(void) const
Definition: tools.h:754
virtual void Clear(void)
Definition: tools.h:805
virtual void Append(T Data)
Definition: tools.h:774
bool RemoveElement(const T &Data)
Definition: tools.h:796
#define MINPRIORITY
Definition: config.h:46
#define IDLEPRIORITY
Definition: config.h:49
#define tr(s)
Definition: i18n.h:85
void MtdMapPid(uchar *p, cMtdMapper *MtdMapper)
Definition: mtd.c:241
void MtdMapSid(uchar *p, cMtdMapper *MtdMapper)
Definition: mtd.c:233
@ TableIdCAT
Definition: si.h:24
@ CaDescriptorTag
Definition: si.h:59
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)
Gets all CA pids for a given channel.
Definition: pat.c:273
void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
Gets all CA descriptors for a given channel.
Definition: pat.c:268
#define MAXRECEIVEPIDS
Definition: receiver.h:15
int TsPid(const uchar *p)
Definition: remux.h:82
#define CATPID
Definition: remux.h:53
bool TsIsScrambled(const uchar *p)
Definition: remux.h:93
#define TS_SIZE
Definition: remux.h:34
bool TsPayloadStart(const uchar *p)
Definition: remux.h:72
cSkins Skins
Definition: skins.c:253
@ mtInfo
Definition: skins.h:37
~cCiCaPmtList()
Definition: ci.c:2501
void Del(cCiCaPmt *CaPmt)
Definition: ci.c:2514
cVector< cCiCaPmt * > caPmts
Definition: ci.h:226
cCiCaPmt * Add(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const int *CaSystemIds)
Definition: ci.c:2507
bool Valid(void) const
Definition: channels.h:60
static tChannelID FromString(const char *s)
Definition: channels.c:24
bool isnumber(const char *s)
Definition: tools.c:372
T get_unaligned(T *p)
Definition: tools.h:82
char * skipspace(const char *s)
Definition: tools.h:244
uint16_t Peek13(const uchar *p)
Definition: tools.h:293
#define LOG_ERROR_STR(s)
Definition: tools.h:40
unsigned char uchar
Definition: tools.h:31
#define dsyslog(a...)
Definition: tools.h:37
#define MALLOC(type, size)
Definition: tools.h:47
T min(T a, T b)
Definition: tools.h:63
#define esyslog(a...)
Definition: tools.h:35
void put_unaligned(unsigned int v, T *p)
Definition: tools.h:88
#define isyslog(a...)
Definition: tools.h:36