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