2017-03-18 16:33:59 +01:00
|
|
|
/*
|
|
|
|
* mtd.h: Multi Transponder Decryption
|
|
|
|
*
|
|
|
|
* See the main source file 'vdr.c' for copyright information and
|
|
|
|
* how to reach the author.
|
|
|
|
*
|
2019-05-28 15:54:22 +02:00
|
|
|
* $Id: mtd.h 1.9 2019/05/28 15:00:10 kls Exp $
|
2017-03-18 16:33:59 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __MTD_H
|
|
|
|
#define __MTD_H
|
|
|
|
|
|
|
|
/*
|
|
|
|
Multiple Transponder Decryption (MTD) is the method of sending TS packets
|
|
|
|
from channels on different transponders to one single CAM for decryption.
|
|
|
|
While decrypting several channels from the same transponder ("Multi Channel
|
|
|
|
Decryption") is straightforward, because the PIDs are unique within one
|
|
|
|
transponder, channels on different transponders might use the same PIDs
|
|
|
|
for different streams.
|
|
|
|
|
|
|
|
Here's a summary of how MTD is implemented in VDR:
|
|
|
|
|
|
|
|
Identifying the relevant source code
|
|
|
|
------------------------------------
|
|
|
|
|
|
|
|
The actual code that implements the MTD handling is located in the files
|
|
|
|
mtd.h and mtd.c. There are also a few places in ci.[hc], device.c and
|
|
|
|
menu.c where things need to be handled differently for MTD. All functions
|
|
|
|
and variables that have to do with MTD have the three letters "mtd" (upper-
|
|
|
|
and/or lowercase) in their name, so that these code lines can be easily
|
|
|
|
identified if necessary.
|
|
|
|
|
|
|
|
What a plugin implementing a cCiAdapter/cCamSlot needs to do
|
|
|
|
------------------------------------------------------------
|
|
|
|
|
|
|
|
If an implementation of cCiAdapter/cCamSlot supports MTD, it needs to
|
|
|
|
fulfill the following requirements:
|
|
|
|
- The cCiAdapter's Assign() function needs to return true for any given
|
|
|
|
device.
|
|
|
|
- The cCamSlot's constructor needs to call MtdEnable().
|
|
|
|
- The cCamSlot's Decrypt() function shall accept the given TS packet,
|
|
|
|
but shall *not* return a decrypted packet. Decypted packets shall be
|
|
|
|
delivered through a call to MtdPutData(), one at a time.
|
|
|
|
- The cCamSlot's Decrypt() function needs to be thread safe, because
|
|
|
|
it will be called from several cMtdCamSlot objects.
|
|
|
|
|
|
|
|
Physical vs. virtual CAMs
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
MTD is done by having one physical CAM (accessed through a plugin's
|
|
|
|
implementation of cCiAdapter/cCamSlot) and several "virtual" CAMs,
|
|
|
|
implemented through cMtdCamSlot objects ("MTD CAMs"). For each device
|
|
|
|
that requires the physical CAM, one instance of a cMtdCamSlot is created
|
|
|
|
on the fly at runtime, and that MTD CAM is assigned to the device.
|
|
|
|
The MTD CAM takes care of mapping the PIDs, and a cMtdHandler in the
|
|
|
|
physical CAM object distributes the decrypted TS packets to the proper
|
|
|
|
devices.
|
|
|
|
|
|
|
|
Mapping the PIDs
|
|
|
|
----------------
|
|
|
|
|
|
|
|
The main problem with MTD is that the TS packets from different devices
|
|
|
|
(and thus different transponders with possibly overlapping PIDs) need to
|
|
|
|
be combined into one stream, sent to the physical CAM, and finally be sorted
|
|
|
|
apart again and returned to the devices they came from. Both aspects are
|
|
|
|
solved in VDR by mapping the "real" PIDs into "unique" PIDs. Real PIDs
|
|
|
|
are in the range 0x0000-0x1FFF (13 bit). Unique PIDs use the upper 5 bit
|
|
|
|
to indicate the number of the MTD CAM a TS packet came from, and the lower
|
|
|
|
8 bit as individual PID values. Mapping is done with a single array lookup
|
|
|
|
and is thus very fast. The cMtdHandler class takes care of distributing
|
|
|
|
the TS packets to the individual cMtdCamSlot objects, while mapping the
|
|
|
|
PIDs (in both directions) is done by the cMtdMapper class.
|
|
|
|
|
|
|
|
Mapping the SIDs
|
|
|
|
----------------
|
|
|
|
|
|
|
|
Besides the PIDs there are also the "service ids" (SIDs, a.k.a. "programme
|
|
|
|
numbers" or PNRs) that need to be taken care of. SIDs only appear in the
|
|
|
|
CA-PMTs sent to the CAM, so they only need to be mapped from real to unique
|
|
|
|
(not the other way) and since the are only mapped when switching channels,
|
|
|
|
mapping doesn't need to be very fast. Mapping SIDs is also done by the
|
|
|
|
cMtdMapper class.
|
|
|
|
|
|
|
|
Handling the CAT
|
|
|
|
----------------
|
|
|
|
|
|
|
|
Each transponder carries a CAT ("Conditional Access Table") with the fixed PID 1.
|
|
|
|
The CAT contains a list of EMM PIDs, which are necessary to convey entitlement
|
|
|
|
messages to the smart card. Since the CAM only recognizes the CAT if it has
|
|
|
|
its fixed PID of 1, this PID cannot be mapped and has to be sent to the CAM
|
|
|
|
as is. However, the cCaPidReceiver also needs to see the CAM in order to
|
|
|
|
request from the device the TS packets with the EMM PIDs. Since any receivers
|
|
|
|
only get the TS packets after they have been sent through the CAM, we need
|
|
|
|
to send the CAT in both ways, with mapped PID but unmapped EMM PIDs for the
|
|
|
|
cCaPidReceiver, and with unmapped PID but mapped EMM PIDs for the CAM itself.
|
|
|
|
Since the PID 0x0001 can always be distinguished from any mapped PID (which
|
|
|
|
always have a non-zero upper byte), the CAT can be easily channeled in both
|
|
|
|
ways.
|
|
|
|
|
|
|
|
Handling the CA-PMTs
|
|
|
|
--------------------
|
|
|
|
|
|
|
|
The CA-PMTs that are sent to the CAM contain both SIDs and PIDs, which are
|
|
|
|
mapped in cCiCaPmt::MtdMapPids().
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ci.h"
|
|
|
|
#include "remux.h"
|
|
|
|
#include "ringbuffer.h"
|
|
|
|
|
|
|
|
class cMtdHandler {
|
|
|
|
private:
|
|
|
|
cVector<cMtdCamSlot *> camSlots;
|
|
|
|
public:
|
|
|
|
cMtdHandler(void);
|
|
|
|
///< Creates a new MTD handler that distributes TS data received through
|
|
|
|
///< calls to the Put() function to the individual CAM slots that have been
|
|
|
|
///< created via GetMtdCamSlot(). It also distributes several function
|
|
|
|
///< calls from the physical master CAM slot to the individual MTD CAM slots.
|
|
|
|
~cMtdHandler();
|
|
|
|
cMtdCamSlot *GetMtdCamSlot(cCamSlot *MasterSlot);
|
|
|
|
///< Creates a new MTD CAM slot, or reuses an existing one that is currently
|
|
|
|
///< unused.
|
|
|
|
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 packets.
|
2017-03-19 10:48:52 +01:00
|
|
|
///< Data must point to the beginning of a TS packet.
|
2017-03-18 16:33:59 +01:00
|
|
|
///< Returns the number of bytes actually stored.
|
|
|
|
int Priority(void);
|
|
|
|
///< Returns the maximum priority of any of the active MTD CAM slots.
|
|
|
|
bool IsDecrypting(void);
|
|
|
|
///< Returns true if any of the active MTD CAM slots is currently decrypting.
|
|
|
|
void StartDecrypting(void);
|
|
|
|
///< Tells all active MTD CAM slots to start decrypting.
|
|
|
|
void CancelActivation(void);
|
|
|
|
///< Tells all active MTD CAM slots to cancel activation.
|
|
|
|
bool IsActivating(void);
|
|
|
|
///< Returns true if any of the active MTD CAM slots is currently activating.
|
2019-05-28 15:54:22 +02:00
|
|
|
bool Devices(cVector<int> &DeviceNumbers);
|
|
|
|
///< Adds the numbers of the devices of any active MTD CAM slots to
|
|
|
|
///< the given DeviceNumbers.
|
2017-03-18 16:33:59 +01:00
|
|
|
///< Returns true if the array is not empty.
|
2017-04-26 09:18:26 +02:00
|
|
|
void UnAssignAll(void);
|
|
|
|
///< Unassigns all MTD CAM slots from their devices.
|
2017-03-18 16:33:59 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#define MTD_DONT_CALL(v) dsyslog("PROGRAMMING ERROR (%s,%d): DON'T CALL %s", __FILE__, __LINE__, __FUNCTION__); return v;
|
|
|
|
|
|
|
|
class cMtdMapper;
|
|
|
|
|
|
|
|
void MtdMapSid(uchar *p, cMtdMapper *MtdMapper);
|
|
|
|
void MtdMapPid(uchar *p, cMtdMapper *MtdMapper);
|
|
|
|
|
|
|
|
class cMtdCamSlot : public cCamSlot {
|
|
|
|
private:
|
2017-03-27 08:35:29 +02:00
|
|
|
cMutex clearMutex;
|
2017-03-18 16:33:59 +01:00
|
|
|
cMtdMapper *mtdMapper;
|
|
|
|
cRingBufferLinear *mtdBuffer;
|
|
|
|
bool delivered;
|
|
|
|
protected:
|
|
|
|
virtual const int *GetCaSystemIds(void);
|
|
|
|
virtual void SendCaPmt(uint8_t CmdId);
|
|
|
|
public:
|
|
|
|
cMtdCamSlot(cCamSlot *MasterSlot, int Index);
|
|
|
|
///< Creates a new "Multi Transponder Decryption" CAM slot, connected to the
|
|
|
|
///< given physical MasterSlot, using the given Index for mapping PIDs.
|
|
|
|
virtual ~cMtdCamSlot();
|
|
|
|
cMtdMapper *MtdMapper(void) { return mtdMapper; }
|
|
|
|
virtual bool RepliesToQuery(void);
|
|
|
|
virtual bool ProvidesCa(const int *CaSystemIds);
|
2017-03-23 14:34:53 +01:00
|
|
|
virtual bool CanDecrypt(const cChannel *Channel, cMtdMapper *MtdMapper = NULL);
|
2017-03-18 16:33:59 +01:00
|
|
|
virtual void StartDecrypting(void);
|
|
|
|
virtual void StopDecrypting(void);
|
|
|
|
virtual uchar *Decrypt(uchar *Data, int &Count);
|
2017-05-01 09:32:32 +02:00
|
|
|
virtual void InjectEit(int Sid);
|
2017-03-18 16:33:59 +01:00
|
|
|
int PutData(const uchar *Data, int Count);
|
|
|
|
int PutCat(const uchar *Data, int Count);
|
|
|
|
// The following functions shall not be called for a cMtdCamSlot:
|
|
|
|
virtual cCamSlot *Spawn(void) { MTD_DONT_CALL(NULL); }
|
|
|
|
virtual bool Reset(void) { MTD_DONT_CALL(false); }
|
|
|
|
virtual eModuleStatus ModuleStatus(void) { MTD_DONT_CALL(msNone); }
|
|
|
|
virtual const char *GetCamName(void) { MTD_DONT_CALL(NULL); }
|
|
|
|
virtual bool Ready(void) { MTD_DONT_CALL(false); }
|
|
|
|
virtual bool HasMMI(void) { MTD_DONT_CALL(false); }
|
|
|
|
virtual bool HasUserIO(void) { MTD_DONT_CALL(false); }
|
|
|
|
virtual bool EnterMenu(void) { MTD_DONT_CALL(false); }
|
|
|
|
virtual cCiMenu *GetMenu(void) { MTD_DONT_CALL(NULL); }
|
|
|
|
virtual cCiEnquiry *GetEnquiry(void) { MTD_DONT_CALL(NULL); }
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif //__MTD_H
|