vdr  2.4.0
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.12 2017/10/31 12:16:39 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++)
119 }
120 
122 {
123  for (int i = 0; i < camSlots.Size(); i++) {
124  if (camSlots[i]->IsActivating())
125  return true;
126  }
127  return false;
128 }
129 
131 {
132  for (int i = 0; i < camSlots.Size(); i++)
133  camSlots[i]->Devices(CardIndexes);
134  return CardIndexes.Size() > 0;
135 }
136 
138 {
139  for (int i = 0; i < camSlots.Size(); i++)
140  camSlots[i]->Assign(NULL);
141 }
142 
143 // --- cMtdMapper ------------------------------------------------------------
144 
145 #define MTD_INVALID_PID 0xFFFF
146 
147 class cMtdMapper {
148 private:
149  int number;
152  uint16_t uniqPids[MAX_REAL_PIDS]; // maps a real PID to a unique PID
153  uint16_t realPids[MAX_UNIQ_PIDS]; // maps a unique PID to a real PID
155  uint16_t MakeUniqPid(uint16_t RealPid);
156 public:
157  cMtdMapper(int Number, int MasterCamSlotNumber);
158  ~cMtdMapper();
159  uint16_t RealToUniqPid(uint16_t RealPid) { if (uniqPids[RealPid]) return uniqPids[RealPid]; return MakeUniqPid(RealPid); }
160  uint16_t UniqToRealPid(uint16_t UniqPid) { return realPids[UniqPid & UNIQ_PID_MASK]; }
161  uint16_t RealToUniqSid(uint16_t RealSid);
162  void Clear(void);
163  };
164 
165 cMtdMapper::cMtdMapper(int Number, int MasterCamSlotNumber)
166 {
167  number = Number;
168  masterCamSlotNumber = MasterCamSlotNumber;
169  nextUniqPid = 0;
170  Clear();
171 }
172 
174 {
175 }
176 
177 uint16_t cMtdMapper::MakeUniqPid(uint16_t RealPid)
178 {
179 #ifdef KEEPPIDS
180  uniqPids[RealPid] = realPids[RealPid] = RealPid;
181  DBGMTD("CAM %d/%d: mapped PID %d (%04X) to %d (%04X)", masterCamSlotNumber, number, RealPid, RealPid, uniqPids[RealPid], uniqPids[RealPid]);
182  return uniqPids[RealPid];
183 #else
184  for (int p = 0; p < MAX_UNIQ_PIDS; p++) {
185  int i = nextUniqPid + p;
186  if (i >= MAX_UNIQ_PIDS)
187  i -= MAX_UNIQ_PIDS;
188  if (realPids[i] == MTD_INVALID_PID) { // 0x0000 is a valid PID (PAT)!
189  realPids[i] = RealPid;
190  uniqPids[RealPid] = (number << UNIQ_PID_SHIFT) | i;
191  DBGMTD("CAM %d/%d: mapped PID %d (%04X) to %d (%04X)", masterCamSlotNumber, number, RealPid, RealPid, uniqPids[RealPid], uniqPids[RealPid]);
192  nextUniqPid = i + 1;
193  return uniqPids[RealPid];
194  }
195  }
196 #endif // KEEPPIDS
197  esyslog("ERROR: MTD %d: mapper ran out of unique PIDs", number);
198  return 0;
199 }
200 
201 uint16_t cMtdMapper::RealToUniqSid(uint16_t RealSid)
202 {
203 #ifdef KEEPPIDS
204  return RealSid;
205 #endif // KEEPPIDS
206  int UniqSid = uniqSids.IndexOf(RealSid);
207  if (UniqSid < 0) {
208  UniqSid = uniqSids.Size();
209  uniqSids.Append(RealSid);
210  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));
211  }
212  UniqSid |= number << UNIQ_PID_SHIFT;
213  return UniqSid;
214 }
215 
217 {
218  DBGMTD("CAM %d/%d: MTD mapper cleared", masterCamSlotNumber, number);
219  memset(uniqPids, 0, sizeof(uniqPids));
220  memset(realPids, MTD_INVALID_PID, sizeof(realPids));
221  // do not reset nextUniqPid here!
222  uniqSids.Clear();
223 }
224 
225 void MtdMapSid(uchar *p, cMtdMapper *MtdMapper)
226 {
227  Poke13(p, MtdMapper->RealToUniqSid(Peek13(p)));
228 }
229 
230 void MtdMapPid(uchar *p, cMtdMapper *MtdMapper)
231 {
232  Poke13(p, MtdMapper->RealToUniqPid(Peek13(p)));
233 }
234 
235 // --- cMtdCamSlot -----------------------------------------------------------
236 
237 #define MTD_BUFFER_SIZE MEGABYTE(1)
238 
239 cMtdCamSlot::cMtdCamSlot(cCamSlot *MasterSlot, int Index)
240 :cCamSlot(NULL, true, MasterSlot)
241 {
242  mtdBuffer = new cRingBufferLinear(MTD_BUFFER_SIZE, TS_SIZE, true, "MTD buffer");
244  delivered = false;
245  ciAdapter = MasterSlot->ciAdapter; // we don't pass the CI adapter in the constructor, to prevent this one from being inserted into CamSlots
246 }
247 
249 {
250  Assign(NULL);
251  delete mtdMapper;
252  delete mtdBuffer;
253 }
254 
256 {
257  return MasterSlot()->GetCaSystemIds();
258 }
259 
260 void cMtdCamSlot::SendCaPmt(uint8_t CmdId)
261 {
262  cMutexLock MutexLock(&mutex);
263  cCiCaPmtList CaPmtList;
264  BuildCaPmts(CmdId, CaPmtList, mtdMapper);
265  MasterSlot()->SendCaPmts(CaPmtList);
266 }
267 
269 {
270  return MasterSlot()->RepliesToQuery();
271 }
272 
273 bool cMtdCamSlot::ProvidesCa(const int *CaSystemIds)
274 {
275  return MasterSlot()->ProvidesCa(CaSystemIds);
276 }
277 
278 bool cMtdCamSlot::CanDecrypt(const cChannel *Channel, cMtdMapper *MtdMapper)
279 {
280  return MasterSlot()->CanDecrypt(Channel, mtdMapper);
281 }
282 
284 {
287 }
288 
290 {
292  if (!MasterSlot()->IsDecrypting())
294  cMutexLock MutexLock(&clearMutex);
295  mtdMapper->Clear();
296  mtdBuffer->Clear();
297  delivered = false;
298 }
299 
300 uchar *cMtdCamSlot::Decrypt(uchar *Data, int &Count)
301 {
302  // Send data to CAM:
303  if (Count >= TS_SIZE) {
304  Count = TS_SIZE;
305  int Pid = TsPid(Data);
306  TsSetPid(Data, mtdMapper->RealToUniqPid(Pid));
307  MasterSlot()->Decrypt(Data, Count);
308  if (Count == 0)
309  TsSetPid(Data, Pid); // must restore PID for later retry
310  }
311  else
312  Count = 0;
313  // Drop delivered data from previous call:
314  cMutexLock MutexLock(&clearMutex);
315  if (delivered) {
317  delivered = false;
318  }
319  // Receive data from buffer:
320  int c = 0;
321  uchar *d = mtdBuffer->Get(c);
322  if (d) {
323  if (int Skipped = TS_SYNC(d, c)) {
324  mtdBuffer->Del(Skipped);
325  return NULL;
326  }
327  if (c >= TS_SIZE) {
329  delivered = true;
330  }
331  else
332  d = NULL;
333  }
334  return d;
335 }
336 
338 {
340 }
341 
342 int cMtdCamSlot::PutData(const uchar *Data, int Count)
343 {
344  int Free = mtdBuffer->Free();
345  Free -= Free % TS_SIZE;
346  if (Free < TS_SIZE)
347  return 0;
348  if (Free < Count)
349  Count = Free;
350  return mtdBuffer->Put(Data, Count);
351 }
352 
353 int cMtdCamSlot::PutCat(const uchar *Data, int Count)
354 {
355  MasterSlot()->Decrypt(const_cast<uchar *>(Data), Count);
356  return Count;
357 }
int number
Definition: mtd.c:149
unsigned char uchar
Definition: tools.h:31
cMutex mutex
Definition: ci.h:238
virtual void Clear(void)
Immediately clears the ring buffer.
Definition: ringbuffer.c:217
#define dsyslog(a...)
Definition: tools.h:37
virtual bool ProvidesCa(const int *CaSystemIds)
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition: ci.c:2586
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: mtd.c:337
bool Devices(cVector< int > &CardIndexes)
Adds the card indexes of the devices of any active MTD CAM slots to the given CardIndexes.
Definition: mtd.c:130
int PutData(const uchar *Data, int Count)
Definition: mtd.c:342
uint16_t Peek13(const uchar *p)
Definition: tools.h:258
#define MAX_REAL_PIDS
Definition: mtd.c:22
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:2748
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:2698
~cMtdMapper()
Definition: mtd.c:173
virtual const int * GetCaSystemIds(void)
Definition: mtd.c:255
virtual void Append(T Data)
Definition: tools.h:737
cMtdCamSlot(cCamSlot *MasterSlot, int Index)
Creates a new "Multi Transponder Decryption" CAM slot, connected to the given physical MasterSlot,...
Definition: mtd.c:239
uint16_t realPids[MAX_UNIQ_PIDS]
Definition: mtd.c:153
~cMtdHandler()
Definition: mtd.c:38
#define esyslog(a...)
Definition: tools.h:35
cMtdMapper * mtdMapper
Definition: mtd.h:157
void TsSetPid(uchar *p, int Pid)
Definition: remux.h:87
int Index(void) const
Definition: tools.c:2072
T max(T a, T b)
Definition: tools.h:60
int Put(const uchar *Data, int Count)
Puts at most Count bytes of Data into the ring buffer.
Definition: ringbuffer.c:306
int IndexOf(const T &Data)
Definition: tools.h:709
cMtdHandler(void)
Creates a new MTD handler that distributes TS data received through calls to the Put() function to th...
Definition: mtd.c:34
int TsPid(const uchar *p)
Definition: remux.h:82
bool delivered
Definition: mtd.h:159
void CancelActivation(void)
Tells all active MTD CAM slots to cancel activation.
Definition: mtd.c:115
void MtdMapPid(uchar *p, cMtdMapper *MtdMapper)
Definition: mtd.c:230
#define IDLEPRIORITY
Definition: config.h:47
uint16_t RealToUniqSid(uint16_t RealSid)
Definition: mtd.c:201
cVector< cMtdCamSlot * > camSlots
Definition: mtd.h:113
cMutex clearMutex
Definition: mtd.h:156
virtual int Free(void)
Definition: ringbuffer.h:80
#define MTD_INVALID_PID
Definition: mtd.c:145
int Size(void) const
Definition: tools.h:717
virtual void StartDecrypting(void)
Sends all CA_PMT entries to the CAM that have been modified since the last call to this function.
Definition: mtd.c:283
virtual ~cMtdCamSlot()
Definition: mtd.c:248
cRingBufferLinear * mtdBuffer
Definition: mtd.h:158
void StartDecrypting(void)
Tells all active MTD CAM slots to start decrypting.
Definition: mtd.c:105
#define UNIQ_PID_SHIFT
Definition: mtd.c:29
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: mtd.c:300
virtual bool ProvidesCa(const int *CaSystemIds)
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition: mtd.c:273
cMtdCamSlot * GetMtdCamSlot(cCamSlot *MasterSlot)
Creates a new MTD CAM slot, or reuses an existing one that is currently unused.
Definition: mtd.c:46
uint16_t uniqPids[MAX_REAL_PIDS]
Definition: mtd.c:152
Definition: ci.h:232
cMtdMapper(int Number, int MasterCamSlotNumber)
Definition: mtd.c:165
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:2488
void Clear(void)
Definition: mtd.c:216
cCiAdapter * ciAdapter
Definition: ci.h:240
cVector< uint16_t > uniqSids
Definition: mtd.c:154
int masterCamSlotNumber
Definition: mtd.c:150
virtual const int * GetCaSystemIds(void)
Definition: ci.c:2571
void Poke13(uchar *p, uint16_t v)
Definition: tools.h:263
virtual void StopDecrypting(void)
Clears the list of CA_PMT entries and tells the CAM to stop decrypting.
Definition: mtd.c:289
void Del(int Count)
Deletes at most Count bytes from the ring buffer.
Definition: ringbuffer.c:371
cCamSlot * MasterSlot(void)
Returns this CAM slot's master slot, or a pointer to itself if it is a master slot.
Definition: ci.h:308
int PutCat(const uchar *Data, int Count)
Definition: mtd.c:353
#define DBGMTD(a...)
Definition: mtd.c:17
void SendCaPmts(cCiCaPmtList &CaPmtList)
Sends the given list of CA_PMTs to the CAM.
Definition: ci.c:2525
virtual bool IsDecrypting(void)
Returns true if the CAM in this slot is currently used for decrypting.
Definition: ci.c:2713
#define UNIQ_PID_MASK
Definition: mtd.c:28
bool IsDecrypting(void)
Returns true if any of the active MTD CAM slots is currently decrypting.
Definition: mtd.c:96
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: mtd.c:278
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
void MtdMapSid(uchar *p, cMtdMapper *MtdMapper)
Definition: mtd.c:225
uint16_t RealToUniqPid(uint16_t RealPid)
Definition: mtd.c:159
#define TS_SYNC(Data, Length)
Definition: remux.h:149
uchar * Get(int &Count)
Gets data from the ring buffer.
Definition: ringbuffer.c:346
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:2731
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:2662
uint16_t MakeUniqPid(uint16_t RealPid)
Definition: mtd.c:177
virtual void StopDecrypting(void)
Clears the list of CA_PMT entries and tells the CAM to stop decrypting.
Definition: ci.c:2703
#define TS_SIZE
Definition: remux.h:34
void UnAssignAll(void)
Unassigns all MTD CAM slots from their devices.
Definition: mtd.c:137
#define MTD_BUFFER_SIZE
Definition: mtd.c:237
#define MAX_UNIQ_PIDS
Definition: mtd.c:27
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:2182
bool IsActivating(void)
Returns true if any of the active MTD CAM slots is currently activating.
Definition: mtd.c:121
virtual void SendCaPmt(uint8_t CmdId)
Definition: mtd.c:260
int Priority(void)
Returns the maximum priority of any of the active MTD CAM slots.
Definition: mtd.c:88
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition: ci.h:343
int nextUniqPid
Definition: mtd.c:151
uint16_t UniqToRealPid(uint16_t UniqPid)
Definition: mtd.c:160
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:2481
virtual bool RepliesToQuery(void)
Returns true if the CAM in this slot replies to queries and thus supports MCD ("Multi Channel Decrypt...
Definition: mtd.c:268