summaryrefslogtreecommitdiff
path: root/mtd.h
diff options
context:
space:
mode:
Diffstat (limited to 'mtd.h')
-rw-r--r--mtd.h187
1 files changed, 187 insertions, 0 deletions
diff --git a/mtd.h b/mtd.h
new file mode 100644
index 00000000..9dd016be
--- /dev/null
+++ b/mtd.h
@@ -0,0 +1,187 @@
+/*
+ * mtd.h: Multi Transponder Decryption
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: mtd.h 1.1 2017/03/17 16:06:34 kls Exp $
+ */
+
+#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.
+ ///< 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.
+ bool Devices(cVector<int> &CardIndexes);
+ ///< Adds the card indexes of the devices of any active MTD CAM slots to
+ ///< the given CardIndexes.
+ ///< Returns true if the array is not empty.
+ };
+
+#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:
+ 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);
+ virtual bool CanDecrypt(const cChannel *Channel);
+ virtual void StartDecrypting(void);
+ virtual void StopDecrypting(void);
+ virtual bool IsDecrypting(void);
+ virtual uchar *Decrypt(uchar *Data, int &Count);
+ 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