diff options
Diffstat (limited to 'mtd.c')
-rw-r--r-- | mtd.c | 323 |
1 files changed, 323 insertions, 0 deletions
@@ -0,0 +1,323 @@ +/* + * mtd.c: Multi Transponder Decryption + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: mtd.c 1.1 2017/03/18 14:31:34 kls Exp $ + */ + +#include "mtd.h" +#include "receiver.h" + +//#define DEBUG_MTD +#ifdef DEBUG_MTD +#define DBGMTD(a...) dsyslog(a) +#else +#define DBGMTD(a...) +#endif + +//#define KEEPPIDS // for testing and debugging - USE ONLY IF YOU KNOW WHAT YOU ARE DOING! + +#define MAX_REAL_PIDS MAXPID // real PIDs are 13 bit (0x0000 - 0x1FFF) +#ifdef KEEPPIDS +#define MAX_UNIQ_PIDS MAXPID +#define UNIQ_PID_MASK 0x1FFF +#else +#define MAX_UNIQ_PIDS 256 // uniq PIDs are 8 bit (0x00 - 0xFF) +#define UNIQ_PID_MASK 0x00FF +#define UNIQ_PID_SHIFT 8 +#endif // KEEPPIDS + +// --- cMtdHandler ----------------------------------------------------------- + +cMtdHandler::cMtdHandler(void) +{ +} + +cMtdHandler::~cMtdHandler() +{ + for (int i = 0; i < camSlots.Size(); i++) { + dsyslog("CAM %d/%d: deleting MTD CAM slot", camSlots[i]->MasterSlot()->SlotNumber(), i + 1); + delete camSlots[i]; + } +} + +cMtdCamSlot *cMtdHandler::GetMtdCamSlot(cCamSlot *MasterSlot) +{ + for (int i = 0; i < camSlots.Size(); i++) { + if (!camSlots[i]->Device()) { + dsyslog("CAM %d/%d: reusing MTD CAM slot", MasterSlot->SlotNumber(), i + 1); + return camSlots[i]; + } + } + dsyslog("CAM %d/%d: creating new MTD CAM slot", MasterSlot->SlotNumber(), camSlots.Size() + 1); + cMtdCamSlot *s = new cMtdCamSlot(MasterSlot, camSlots.Size()); + camSlots.Append(s); + return s; +} + +int cMtdHandler::Put(const uchar *Data, int Count) +{ + // TODO maybe handle more than one TS packet? + if (Count > TS_SIZE) + Count = TS_SIZE; + else if (Count < TS_SIZE) + return 0; + int Pid = TsPid(Data); + if (Pid == CATPID) + return Count; // this is the original CAT with mapped PIDs +#ifdef KEEPPIDS + int Index = 0; +#else + int Index = (Pid >> UNIQ_PID_SHIFT) - 1; +#endif // KEEPPIDS + if (Index >= 0 && Index < camSlots.Size()) + return camSlots[Index]->PutData(Data, Count); + else + esyslog("ERROR: invalid MTD number (%d) in PID %d (%04X)", Index + 1, Pid, Pid); + return Count; // no such buffer - let's just drop the data so nothing stacks up +} + +int cMtdHandler::Priority(void) +{ + int p = IDLEPRIORITY; + for (int i = 0; i < camSlots.Size(); i++) + p = max(p, camSlots[i]->Priority()); + return p; +} + +bool cMtdHandler::IsDecrypting(void) +{ + for (int i = 0; i < camSlots.Size(); i++) { + if (camSlots[i]->IsDecrypting()) + return true; + } + return false; +} + +void cMtdHandler::StartDecrypting(void) +{ + for (int i = 0; i < camSlots.Size(); i++) { + if (camSlots[i]->Device()) { + camSlots[i]->TriggerResendPmt(); + camSlots[i]->StartDecrypting(); + } + } +} + +void cMtdHandler::CancelActivation(void) +{ + for (int i = 0; i < camSlots.Size(); i++) + camSlots[i]->CancelActivation(); +} + +bool cMtdHandler::IsActivating(void) +{ + for (int i = 0; i < camSlots.Size(); i++) { + if (camSlots[i]->IsActivating()) + return true; + } + return false; +} + +bool cMtdHandler::Devices(cVector<int> &CardIndexes) +{ + for (int i = 0; i < camSlots.Size(); i++) + camSlots[i]->Devices(CardIndexes); + return CardIndexes.Size() > 0; +} + +// --- cMtdMapper ------------------------------------------------------------ + +#define MTD_INVALID_PID 0xFFFF + +class cMtdMapper { +private: + int number; + int masterCamSlotNumber; + uint16_t uniqPids[MAX_REAL_PIDS]; // maps a real PID to a unique PID + uint16_t realPids[MAX_UNIQ_PIDS]; // maps a unique PID to a real PID + cVector<uint16_t> uniqSids; + uint16_t MakeUniqPid(uint16_t RealPid); +public: + cMtdMapper(int Number, int MasterCamSlotNumber); + ~cMtdMapper(); + uint16_t RealToUniqPid(uint16_t RealPid) { if (uniqPids[RealPid]) return uniqPids[RealPid]; return MakeUniqPid(RealPid); } + uint16_t UniqToRealPid(uint16_t UniqPid) { return realPids[UniqPid & UNIQ_PID_MASK]; } + uint16_t RealToUniqSid(uint16_t RealSid); + void Clear(void); + }; + +cMtdMapper::cMtdMapper(int Number, int MasterCamSlotNumber) +{ + number = Number; + masterCamSlotNumber = MasterCamSlotNumber; + Clear(); +} + +cMtdMapper::~cMtdMapper() +{ +} + +uint16_t cMtdMapper::MakeUniqPid(uint16_t RealPid) +{ +#ifdef KEEPPIDS + uniqPids[RealPid] = realPids[RealPid] = RealPid; + DBGMTD("CAM %d/%d: mapped PID %d (%04X) to %d (%04X)", masterCamSlotNumber, number, RealPid, RealPid, uniqPids[RealPid], uniqPids[RealPid]); + return uniqPids[RealPid]; +#else + for (int i = 0; i < MAX_UNIQ_PIDS; i++) { + if (realPids[i] == MTD_INVALID_PID) { // 0x0000 is a valid PID (PAT)! + realPids[i] = RealPid; + uniqPids[RealPid] = (number << UNIQ_PID_SHIFT) | i; + DBGMTD("CAM %d/%d: mapped PID %d (%04X) to %d (%04X)", masterCamSlotNumber, number, RealPid, RealPid, uniqPids[RealPid], uniqPids[RealPid]); + return uniqPids[RealPid]; + } + } +#endif // KEEPPIDS + esyslog("ERROR: MTD %d: mapper ran out of unique PIDs", number); + return 0; +} + +uint16_t cMtdMapper::RealToUniqSid(uint16_t RealSid) +{ +#ifdef KEEPPIDS + return RealSid; +#endif // KEEPPIDS + int UniqSid = uniqSids.IndexOf(RealSid); + if (UniqSid < 0) { + UniqSid = uniqSids.Size(); + uniqSids.Append(RealSid); + 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)); + } + UniqSid |= number << UNIQ_PID_SHIFT; + return UniqSid; +} + +void cMtdMapper::Clear(void) +{ + DBGMTD("CAM %d/%d: MTD mapper cleared", masterCamSlotNumber, number); + memset(uniqPids, 0, sizeof(uniqPids)); + memset(realPids, MTD_INVALID_PID, sizeof(realPids)); + uniqSids.Clear(); +} + +void MtdMapSid(uchar *p, cMtdMapper *MtdMapper) +{ + Poke13(p, MtdMapper->RealToUniqSid(Peek13(p))); +} + +void MtdMapPid(uchar *p, cMtdMapper *MtdMapper) +{ + Poke13(p, MtdMapper->RealToUniqPid(Peek13(p))); +} + +// --- cMtdCamSlot ----------------------------------------------------------- + +#define MTD_BUFFER_SIZE MEGABYTE(1) + +cMtdCamSlot::cMtdCamSlot(cCamSlot *MasterSlot, int Index) +:cCamSlot(NULL, true, MasterSlot) +{ + mtdBuffer = new cRingBufferLinear(MTD_BUFFER_SIZE, TS_SIZE, true, "MTD buffer"); + mtdMapper = new cMtdMapper(Index + 1, MasterSlot->SlotNumber()); + delivered = false; + ciAdapter = MasterSlot->ciAdapter; // we don't pass the CI adapter in the constructor, to prevent this one from being inserted into CamSlots +} + +cMtdCamSlot::~cMtdCamSlot() +{ + delete mtdMapper; + delete mtdBuffer; +} + +const int *cMtdCamSlot::GetCaSystemIds(void) +{ + return MasterSlot()->GetCaSystemIds(); +} + +void cMtdCamSlot::SendCaPmt(uint8_t CmdId) +{ + cMutexLock MutexLock(&mutex); + cCiCaPmtList CaPmtList; + BuildCaPmts(CmdId, CaPmtList, mtdMapper); + MasterSlot()->SendCaPmts(CaPmtList); +} + +bool cMtdCamSlot::RepliesToQuery(void) +{ + return MasterSlot()->RepliesToQuery(); +} + +bool cMtdCamSlot::ProvidesCa(const int *CaSystemIds) +{ + return MasterSlot()->ProvidesCa(CaSystemIds); +} + +bool cMtdCamSlot::CanDecrypt(const cChannel *Channel) +{ + //TODO PID mapping? + return MasterSlot()->CanDecrypt(Channel); +} + +void cMtdCamSlot::StartDecrypting(void) +{ + MasterSlot()->StartDecrypting(); + cCamSlot::StartDecrypting(); +} + +void cMtdCamSlot::StopDecrypting(void) +{ + cCamSlot::StopDecrypting(); + mtdMapper->Clear(); + //XXX mtdBuffer->Clear(); //XXX would require locking? +} + +bool cMtdCamSlot::IsDecrypting(void) +{ + return cCamSlot::IsDecrypting(); +} + +uchar *cMtdCamSlot::Decrypt(uchar *Data, int &Count) +{ + // Send data to CAM: + if (Count >= TS_SIZE) { + Count = TS_SIZE; + int Pid = TsPid(Data); + TsSetPid(Data, mtdMapper->RealToUniqPid(Pid)); + MasterSlot()->Decrypt(Data, Count); + if (Count == 0) + TsSetPid(Data, Pid); // must restore PID for later retry + } + else + Count = 0; + // Drop delivered data from previous call: + if (delivered) { + mtdBuffer->Del(TS_SIZE); + delivered = false; + } + // Receive data from buffer: + int c = 0; + uchar *d = mtdBuffer->Get(c); + if (d) { + if (c >= TS_SIZE) { + TsSetPid(d, mtdMapper->UniqToRealPid(TsPid(d))); + delivered = true; + } + else + d = NULL; + } + return d; +} + +int cMtdCamSlot::PutData(const uchar *Data, int Count) +{ + return mtdBuffer->Put(Data, Count); +} + +int cMtdCamSlot::PutCat(const uchar *Data, int Count) +{ + MasterSlot()->Decrypt(const_cast<uchar *>(Data), Count); + return Count; +} |