vdr  2.7.6
mtd.c
Go to the documentation of this file.
1 /*
2  * mtd.c: Multi Transponder Decryption
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: mtd.c 1.16 2020/06/16 14:33:32 kls Exp $
8  */
9 
10 #include "mtd.h"
11 #include "receiver.h"
12 
13 //#define DEBUG_MTD
14 #ifdef DEBUG_MTD
15 #define DBGMTD(a...) dsyslog(a)
16 #else
17 #define DBGMTD(a...)
18 #endif
19 
20 //#define KEEPPIDS // for testing and debugging - USE ONLY IF YOU KNOW WHAT YOU ARE DOING!
21 
22 #define MAX_REAL_PIDS MAXPID // real PIDs are 13 bit (0x0000 - 0x1FFF)
23 #ifdef KEEPPIDS
24 #define MAX_UNIQ_PIDS MAXPID
25 #define UNIQ_PID_MASK 0x1FFF
26 #else
27 #define MAX_UNIQ_PIDS 256 // uniq PIDs are 8 bit (0x00 - 0xFF)
28 #define UNIQ_PID_MASK 0x00FF
29 #define UNIQ_PID_SHIFT 8
30 #endif // KEEPPIDS
31 
32 // --- cMtdHandler -----------------------------------------------------------
33 
35 {
36 }
37 
39 {
40  for (int i = 0; i < camSlots.Size(); i++) {
41  dsyslog("CAM %d/%d: deleting MTD CAM slot", camSlots[i]->MasterSlot()->SlotNumber(), i + 1);
42  delete camSlots[i];
43  }
44 }
45 
47 {
48  for (int i = 0; i < camSlots.Size(); i++) {
49  if (!camSlots[i]->Device()) {
50  dsyslog("CAM %d/%d: reusing MTD CAM slot", MasterSlot->SlotNumber(), i + 1);
51  return camSlots[i];
52  }
53  }
54  dsyslog("CAM %d/%d: creating new MTD CAM slot", MasterSlot->SlotNumber(), camSlots.Size() + 1);
55  cMtdCamSlot *s = new cMtdCamSlot(MasterSlot, camSlots.Size());
56  camSlots.Append(s);
57  return s;
58 }
59 
60 int cMtdHandler::Put(const uchar *Data, int Count)
61 {
62  int Used = 0;
63  while (Count >= TS_SIZE) {
64  if (int Skipped = TS_SYNC(Data, Count))
65  return Used + Skipped;
66  int Pid = TsPid(Data);
67 #ifdef KEEPPIDS
68  int Index = 0;
69 #else
70  int Index = (Pid >> UNIQ_PID_SHIFT) - 1;
71 #endif // KEEPPIDS
72  if (Index >= 0 && Index < camSlots.Size()) {
73  int w = camSlots[Index]->PutData(Data, TS_SIZE);
74  if (w == 0)
75  break;
76  else if (w != TS_SIZE)
77  esyslog("ERROR: incomplete MTD packet written (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
78  }
79  else if (Index >= 0) // anything with Index -1 (i.e. MTD number 0) is either garbage or an actual CAT or EIT, which need not be returned to the device
80  esyslog("ERROR: invalid MTD number (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
81  Data += TS_SIZE;
82  Count -= TS_SIZE;
83  Used += TS_SIZE;
84  }
85  return Used;
86 }
87 
89 {
90  int p = IDLEPRIORITY;
91  for (int i = 0; i < camSlots.Size(); i++)
92  p = max(p, camSlots[i]->Priority());
93  return p;
94 }
95 
97 {
98  for (int i = 0; i < camSlots.Size(); i++) {
99  if (camSlots[i]->IsDecrypting())
100  return true;
101  }
102  return false;
103 }
104 
106 {
107  for (int i = 0; i < camSlots.Size(); i++) {
108  if (camSlots[i]->Device()) {
109  camSlots[i]->TriggerResendPmt();
110  camSlots[i]->StartDecrypting();
111  }
112  }
113 }
114 
116 {
117  for (int i = 0; i < camSlots.Size(); i++) {
118  if (camSlots[i]->Device())
119  camSlots[i]->StopDecrypting();
120  }
121 }
122 
124 {
125  for (int i = 0; i < camSlots.Size(); i++)
127 }
128 
130 {
131  for (int i = 0; i < camSlots.Size(); i++) {
132  if (camSlots[i]->IsActivating())
133  return true;
134  }
135  return false;
136 }
137 
138 bool cMtdHandler::Devices(cVector<int> &DeviceNumbers)
139 {
140  for (int i = 0; i < camSlots.Size(); i++)
141  camSlots[i]->Devices(DeviceNumbers);
142  return DeviceNumbers.Size() > 0;
143 }
144 
146 {
147  for (int i = 0; i < camSlots.Size(); i++)
148  camSlots[i]->Assign(NULL);
149 }
150 
151 // --- cMtdMapper ------------------------------------------------------------
152 
153 #define MTD_INVALID_PID 0xFFFF
154 
155 class cMtdMapper {
156 private:
157  int number;
160  uint16_t uniqPids[MAX_REAL_PIDS]; // maps a real PID to a unique PID
161  uint16_t realPids[MAX_UNIQ_PIDS]; // maps a unique PID to a real PID
163  uint16_t MakeUniqPid(uint16_t RealPid);
164 public:
165  cMtdMapper(int Number, int MasterCamSlotNumber);
166  ~cMtdMapper();
167  uint16_t RealToUniqPid(uint16_t RealPid) { if (uniqPids[RealPid]) return uniqPids[RealPid]; return MakeUniqPid(RealPid); }
168  uint16_t UniqToRealPid(uint16_t UniqPid) { return realPids[UniqPid & UNIQ_PID_MASK]; }
169  uint16_t RealToUniqSid(uint16_t RealSid);
170  void Clear(void);
171  };
172 
173 cMtdMapper::cMtdMapper(int Number, int MasterCamSlotNumber)
174 {
175  number = Number;
176  masterCamSlotNumber = MasterCamSlotNumber;
177  nextUniqPid = 0;
178  Clear();
179 }
180 
182 {
183 }
184 
185 uint16_t cMtdMapper::MakeUniqPid(uint16_t RealPid)
186 {
187 #ifdef KEEPPIDS
188  uniqPids[RealPid] = realPids[RealPid] = RealPid;
189  DBGMTD("CAM %d/%d: mapped PID %d (%04X) to %d (%04X)", masterCamSlotNumber, number, RealPid, RealPid, uniqPids[RealPid], uniqPids[RealPid]);
190  return uniqPids[RealPid];
191 #else
192  for (int p = 0; p < MAX_UNIQ_PIDS; p++) {
193  int i = nextUniqPid + p;
194  if (i >= MAX_UNIQ_PIDS)
195  i -= MAX_UNIQ_PIDS;
196  if (realPids[i] == MTD_INVALID_PID) { // 0x0000 is a valid PID (PAT)!
197  realPids[i] = RealPid;
198  uniqPids[RealPid] = (number << UNIQ_PID_SHIFT) | i;
199  DBGMTD("CAM %d/%d: mapped PID %d (%04X) to %d (%04X)", masterCamSlotNumber, number, RealPid, RealPid, uniqPids[RealPid], uniqPids[RealPid]);
200  nextUniqPid = i + 1;
201  return uniqPids[RealPid];
202  }
203  }
204 #endif // KEEPPIDS
205  esyslog("ERROR: MTD %d: mapper ran out of unique PIDs", number);
206  return 0;
207 }
208 
209 uint16_t cMtdMapper::RealToUniqSid(uint16_t RealSid)
210 {
211 #ifdef KEEPPIDS
212  return RealSid;
213 #endif // KEEPPIDS
214  int UniqSid = uniqSids.IndexOf(RealSid);
215  if (UniqSid < 0) {
216  UniqSid = uniqSids.Size();
217  uniqSids.Append(RealSid);
218  DBGMTD("CAM %d/%d: mapped SID %d (%04X) to %d (%04X)", masterCamSlotNumber, number, RealSid, RealSid, UniqSid | (number << UNIQ_PID_SHIFT), UniqSid | (number << UNIQ_PID_SHIFT));
219  }
220  UniqSid |= number << UNIQ_PID_SHIFT;
221  return UniqSid;
222 }
223 
225 {
226  DBGMTD("CAM %d/%d: MTD mapper cleared", masterCamSlotNumber, number);
227  memset(uniqPids, 0, sizeof(uniqPids));
228  memset(realPids, MTD_INVALID_PID, sizeof(realPids));
229  // do not reset nextUniqPid here!
230  uniqSids.Clear();
231 }
232 
233 void MtdMapSid(uchar *p, cMtdMapper *MtdMapper)
234 {
235  uint16_t RealSid = p[0] << 8 | p[1];
236  uint16_t UniqSid = MtdMapper->RealToUniqSid(RealSid);
237  p[0] = UniqSid >> 8;
238  p[1] = UniqSid & 0xff;
239 }
240 
241 void MtdMapPid(uchar *p, cMtdMapper *MtdMapper)
242 {
243  Poke13(p, MtdMapper->RealToUniqPid(Peek13(p)));
244 }
245 
246 // --- cMtdCamSlot -----------------------------------------------------------
247 
248 #define MTD_BUFFER_SIZE MEGABYTE(1)
249 
250 cMtdCamSlot::cMtdCamSlot(cCamSlot *MasterSlot, int Index)
251 :cCamSlot(NULL, true, MasterSlot)
252 {
253  mtdBuffer = new cRingBufferLinear(MTD_BUFFER_SIZE, TS_SIZE, true, "MTD buffer");
255  delivered = false;
256  ciAdapter = MasterSlot->ciAdapter; // we don't pass the CI adapter in the constructor, to prevent this one from being inserted into CamSlots
257 }
258 
260 {
261  Assign(NULL);
262  delete mtdMapper;
263  delete mtdBuffer;
264 }
265 
267 {
268  return MasterSlot()->GetCaSystemIds();
269 }
270 
271 void cMtdCamSlot::SendCaPmt(uint8_t CmdId)
272 {
273  cMutexLock MutexLock(&mutex);
274  cCiCaPmtList CaPmtList;
275  BuildCaPmts(CmdId, CaPmtList, mtdMapper);
276  MasterSlot()->SendCaPmts(CaPmtList);
277 }
278 
280 {
281  return MasterSlot()->RepliesToQuery();
282 }
283 
284 bool cMtdCamSlot::ProvidesCa(const int *CaSystemIds)
285 {
286  return MasterSlot()->ProvidesCa(CaSystemIds);
287 }
288 
289 bool cMtdCamSlot::CanDecrypt(const cChannel *Channel, cMtdMapper *MtdMapper)
290 {
291  return MasterSlot()->CanDecrypt(Channel, mtdMapper);
292 }
293 
295 {
298 }
299 
301 {
303  cMutexLock MutexLock(&clearMutex);
304  mtdMapper->Clear();
305  mtdBuffer->Clear();
306  delivered = false;
307 }
308 
309 uchar *cMtdCamSlot::Decrypt(uchar *Data, int &Count)
310 {
311  // Send data to CAM:
312  if (Count >= TS_SIZE) {
313  Count = TS_SIZE;
314  int Pid = TsPid(Data);
315  TsSetPid(Data, mtdMapper->RealToUniqPid(Pid));
316  MasterSlot()->Decrypt(Data, Count);
317  if (Count == 0)
318  TsSetPid(Data, Pid); // must restore PID for later retry
319  }
320  else
321  Count = 0;
322  // Drop delivered data from previous call:
323  cMutexLock MutexLock(&clearMutex);
324  if (delivered) {
326  delivered = false;
327  }
328  // Receive data from buffer:
329  int c = 0;
330  uchar *d = mtdBuffer->Get(c);
331  if (d) {
332  if (int Skipped = TS_SYNC(d, c)) {
333  mtdBuffer->Del(Skipped);
334  return NULL;
335  }
336  if (c >= TS_SIZE) {
338  delivered = true;
339  }
340  else
341  d = NULL;
342  }
343  return d;
344 }
345 
347 {
348  return MasterSlot()->TsPostProcess(Data);
349 }
350 
352 {
354 }
355 
356 int cMtdCamSlot::PutData(const uchar *Data, int Count)
357 {
358  int Free = mtdBuffer->Free();
359  Free -= Free % TS_SIZE;
360  if (Free < TS_SIZE)
361  return 0;
362  if (Free < Count)
363  Count = Free;
364  return mtdBuffer->Put(Data, Count);
365 }
366 
367 int cMtdCamSlot::PutCat(const uchar *Data, int Count)
368 {
369  MasterSlot()->Decrypt(const_cast<uchar *>(Data), Count);
370  return Count;
371 }
Definition: ci.h:232
virtual bool RepliesToQuery(void)
Returns true if the CAM in this slot replies to queries and thus supports MCD ("Multi Channel Decrypt...
Definition: ci.c:2520
virtual void InjectEit(int Sid)
Injects a generated EIT with a "present event" for the given Sid into the TS data stream sent to the ...
Definition: ci.c:2830
cMutex mutex
Definition: ci.h:238
friend class cMtdCamSlot
Definition: ci.h:236
virtual bool CanDecrypt(const cChannel *Channel, cMtdMapper *MtdMapper=NULL)
Returns true if there is a CAM in this slot that is able to decrypt the given Channel (or at least cl...
Definition: ci.c:2740
virtual uchar * Decrypt(uchar *Data, int &Count)
If this is a CAM slot that can be freely assigned to any device, but will not be directly inserted in...
Definition: ci.c:2813
virtual const int * GetCaSystemIds(void)
Definition: ci.c:2649
virtual bool Assign(cDevice *Device, bool Query=false)
Assigns this CAM slot to the given Device, if this is possible.
Definition: ci.c:2221
virtual void StartDecrypting(void)
Sends all CA_PMT entries to the CAM that have been modified since the last call to this function.
Definition: ci.c:2776
virtual bool TsPostProcess(uchar *Data)
If there is a cCiSession that needs to do additional processing on TS packets (after the CAM has done...
Definition: ci.c:2820
cCiAdapter * ciAdapter
Definition: ci.h:240
virtual void StopDecrypting(void)
Clears the list of CA_PMT entries and tells the CAM to stop decrypting.
Definition: ci.c:2781
void SendCaPmts(cCiCaPmtList &CaPmtList)
Sends the given list of CA_PMTs to the CAM.
Definition: ci.c:2603
void BuildCaPmts(uint8_t CmdId, cCiCaPmtList &CaPmtList, cMtdMapper *MtdMapper=NULL)
Generates all CA_PMTs with the given CmdId and stores them in the given CaPmtList.
Definition: ci.c:2527
cCamSlot * MasterSlot(void)
Returns this CAM slot's master slot, or a pointer to itself if it is a master slot.
Definition: ci.h:309
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition: ci.h:344
virtual bool ProvidesCa(const int *CaSystemIds)
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition: ci.c:2664
int Index(void) const
Definition: tools.c:2097
virtual void StopDecrypting(void) override
Clears the list of CA_PMT entries and tells the CAM to stop decrypting.
Definition: mtd.c:300
cMutex clearMutex
Definition: mtd.h:158
virtual void InjectEit(int Sid) override
Injects a generated EIT with a "present event" for the given Sid into the TS data stream sent to the ...
Definition: mtd.c:351
virtual bool CanDecrypt(const cChannel *Channel, cMtdMapper *MtdMapper=NULL) override
Returns true if there is a CAM in this slot that is able to decrypt the given Channel (or at least cl...
Definition: mtd.c:289
virtual bool ProvidesCa(const int *CaSystemIds) override
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition: mtd.c:284
cRingBufferLinear * mtdBuffer
Definition: mtd.h:160
virtual void StartDecrypting(void) override
Sends all CA_PMT entries to the CAM that have been modified since the last call to this function.
Definition: mtd.c:294
bool delivered
Definition: mtd.h:161
virtual ~cMtdCamSlot() override
Definition: mtd.c:259
int PutCat(const uchar *Data, int Count)
Definition: mtd.c:367
virtual uchar * Decrypt(uchar *Data, int &Count) override
If this is a CAM slot that can be freely assigned to any device, but will not be directly inserted in...
Definition: mtd.c:309
cMtdMapper * mtdMapper
Definition: mtd.h:159
virtual bool RepliesToQuery(void) override
Returns true if the CAM in this slot replies to queries and thus supports MCD ("Multi Channel Decrypt...
Definition: mtd.c:279
virtual bool TsPostProcess(uchar *Data) override
If there is a cCiSession that needs to do additional processing on TS packets (after the CAM has done...
Definition: mtd.c:346
virtual const int * GetCaSystemIds(void) override
Definition: mtd.c:266
virtual void SendCaPmt(uint8_t CmdId) override
Definition: mtd.c:271
int PutData(const uchar *Data, int Count)
Definition: mtd.c:356
int Put(const uchar *Data, int Count)
Puts at most Count bytes of Data into the CAM slot which's index is derived from the PID of the TS pa...
Definition: mtd.c:60
~cMtdHandler()
Definition: mtd.c:38
bool IsActivating(void)
Returns true if any of the active MTD CAM slots is currently activating.
Definition: mtd.c:129
cVector< cMtdCamSlot * > camSlots
Definition: mtd.h:113
void StartDecrypting(void)
Tells all active MTD CAM slots to start decrypting.
Definition: mtd.c:105
cMtdHandler(void)
Creates a new MTD handler that distributes TS data received through calls to the Put() function to th...
Definition: mtd.c:34
bool IsDecrypting(void)
Returns true if any of the active MTD CAM slots is currently decrypting.
Definition: mtd.c:96
void CancelActivation(void)
Tells all active MTD CAM slots to cancel activation.
Definition: mtd.c:123
cMtdCamSlot * GetMtdCamSlot(cCamSlot *MasterSlot)
Creates a new MTD CAM slot, or reuses an existing one that is currently unused.
Definition: mtd.c:46
void StopDecrypting(void)
Tells all active MTD CAM slots to stop decrypting.
Definition: mtd.c:115
int Priority(void)
Returns the maximum priority of any of the active MTD CAM slots.
Definition: mtd.c:88
void UnAssignAll(void)
Unassigns all MTD CAM slots from their devices.
Definition: mtd.c:145
bool Devices(cVector< int > &DeviceNumbers)
Adds the numbers of the devices of any active MTD CAM slots to the given DeviceNumbers.
Definition: mtd.c:138
cVector< uint16_t > uniqSids
Definition: mtd.c:162
uint16_t MakeUniqPid(uint16_t RealPid)
Definition: mtd.c:185
uint16_t uniqPids[MAX_REAL_PIDS]
Definition: mtd.c:160
int nextUniqPid
Definition: mtd.c:159
uint16_t realPids[MAX_UNIQ_PIDS]
Definition: mtd.c:161
uint16_t RealToUniqPid(uint16_t RealPid)
Definition: mtd.c:167
uint16_t RealToUniqSid(uint16_t RealSid)
Definition: mtd.c:209
~cMtdMapper()
Definition: mtd.c:181
uint16_t UniqToRealPid(uint16_t UniqPid)
Definition: mtd.c:168
void Clear(void)
Definition: mtd.c:224
int masterCamSlotNumber
Definition: mtd.c:158
cMtdMapper(int Number, int MasterCamSlotNumber)
Definition: mtd.c:173
int number
Definition: mtd.c:157
void Del(int Count)
Deletes at most Count bytes from the ring buffer.
Definition: ringbuffer.c:371
virtual void Clear(void) override
Immediately clears the ring buffer.
Definition: ringbuffer.c:217
virtual int Free(void) override
Definition: ringbuffer.h:80
int Put(const uchar *Data, int Count)
Puts at most Count bytes of Data into the ring buffer.
Definition: ringbuffer.c:306
uchar * Get(int &Count)
Gets data from the ring buffer.
Definition: ringbuffer.c:346
int Size(void) const
Definition: tools.h:754
int IndexOf(const T &Data)
Definition: tools.h:746
virtual void Clear(void)
Definition: tools.h:805
virtual void Append(T Data)
Definition: tools.h:774
#define IDLEPRIORITY
Definition: config.h:49
void MtdMapPid(uchar *p, cMtdMapper *MtdMapper)
Definition: mtd.c:241
#define UNIQ_PID_MASK
Definition: mtd.c:28
#define MAX_UNIQ_PIDS
Definition: mtd.c:27
#define UNIQ_PID_SHIFT
Definition: mtd.c:29
#define MTD_INVALID_PID
Definition: mtd.c:153
#define MTD_BUFFER_SIZE
Definition: mtd.c:248
#define MAX_REAL_PIDS
Definition: mtd.c:22
#define DBGMTD(a...)
Definition: mtd.c:17
void MtdMapSid(uchar *p, cMtdMapper *MtdMapper)
Definition: mtd.c:233
int TsPid(const uchar *p)
Definition: remux.h:82
#define TS_SIZE
Definition: remux.h:34
void TsSetPid(uchar *p, int Pid)
Definition: remux.h:87
#define TS_SYNC(Data, Length)
Definition: remux.h:149
uint16_t Peek13(const uchar *p)
Definition: tools.h:293
unsigned char uchar
Definition: tools.h:31
#define dsyslog(a...)
Definition: tools.h:37
void Poke13(uchar *p, uint16_t v)
Definition: tools.h:298
T max(T a, T b)
Definition: tools.h:64
#define esyslog(a...)
Definition: tools.h:35