2017-03-18 16:33:59 +01:00
/*
* mtd . c : Multi Transponder Decryption
*
* See the main source file ' vdr . c ' for copyright information and
* how to reach the author .
*
2017-03-27 14:26:04 +02:00
* $ Id : mtd . c 1.9 2017 / 03 / 27 14 : 26 : 04 kls Exp $
2017-03-18 16:33:59 +01:00
*/
# 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 )
{
2017-03-19 14:20:22 +01:00
int Used = 0 ;
while ( Count > = TS_SIZE ) {
2017-03-27 09:09:37 +02:00
if ( int Skipped = TS_SYNC ( Data , Count ) )
return Used + Skipped ;
2017-03-19 14:20:22 +01:00
int Pid = TsPid ( Data ) ;
if ( Pid ! = CATPID ) { // the original CAT with mapped PIDs must be skipped here!
2017-03-18 16:33:59 +01:00
# ifdef KEEPPIDS
2017-03-19 14:20:22 +01:00
int Index = 0 ;
2017-03-18 16:33:59 +01:00
# else
2017-03-19 14:20:22 +01:00
int Index = ( Pid > > UNIQ_PID_SHIFT ) - 1 ;
2017-03-18 16:33:59 +01:00
# endif // KEEPPIDS
2017-03-19 14:20:22 +01:00
if ( Index > = 0 & & Index < camSlots . Size ( ) ) {
int w = camSlots [ Index ] - > PutData ( Data , TS_SIZE ) ;
if ( w = = 0 )
break ;
else if ( w ! = TS_SIZE )
esyslog ( " ERROR: incomplete MTD packet written (%d) in PID %d (%04X) " , Index + 1 , Pid , Pid ) ;
}
2017-03-27 14:26:04 +02:00
else if ( Index > = 0 ) // we silently ignore Index -1 (i.e. MTD number 0), since there are several hundred empty TS packets when switching to an encrypted channel for the first time since startup
2017-03-19 14:20:22 +01:00
esyslog ( " ERROR: invalid MTD number (%d) in PID %d (%04X) " , Index + 1 , Pid , Pid ) ;
}
Data + = TS_SIZE ;
Count - = TS_SIZE ;
Used + = TS_SIZE ;
}
return Used ;
2017-03-18 16:33:59 +01:00
}
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 ( )
{
2017-03-25 14:09:31 +01:00
Assign ( NULL ) ;
2017-03-18 16:33:59 +01:00
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 ) ;
}
2017-03-23 14:34:53 +01:00
bool cMtdCamSlot : : CanDecrypt ( const cChannel * Channel , cMtdMapper * MtdMapper )
2017-03-18 16:33:59 +01:00
{
2017-03-23 14:34:53 +01:00
return MasterSlot ( ) - > CanDecrypt ( Channel , mtdMapper ) ;
2017-03-18 16:33:59 +01:00
}
void cMtdCamSlot : : StartDecrypting ( void )
{
MasterSlot ( ) - > StartDecrypting ( ) ;
cCamSlot : : StartDecrypting ( ) ;
}
void cMtdCamSlot : : StopDecrypting ( void )
{
cCamSlot : : StopDecrypting ( ) ;
2017-03-23 14:34:53 +01:00
if ( ! MasterSlot ( ) - > IsDecrypting ( ) )
MasterSlot ( ) - > StopDecrypting ( ) ;
2017-03-27 08:35:29 +02:00
cMutexLock MutexLock ( & clearMutex ) ;
2017-03-18 16:33:59 +01:00
mtdMapper - > Clear ( ) ;
2017-03-26 13:07:01 +02:00
mtdBuffer - > Clear ( ) ;
delivered = false ;
2017-03-18 16:33:59 +01:00
}
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:
2017-03-27 08:35:29 +02:00
cMutexLock MutexLock ( & clearMutex ) ;
2017-03-18 16:33:59 +01:00
if ( delivered ) {
mtdBuffer - > Del ( TS_SIZE ) ;
delivered = false ;
}
// Receive data from buffer:
int c = 0 ;
uchar * d = mtdBuffer - > Get ( c ) ;
if ( d ) {
2017-03-26 13:07:01 +02:00
if ( int Skipped = TS_SYNC ( d , c ) ) {
mtdBuffer - > Del ( Skipped ) ;
return NULL ;
}
2017-03-18 16:33:59 +01:00
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 )
{
2017-03-26 13:07:01 +02:00
int Free = mtdBuffer - > Free ( ) ;
Free - = Free % TS_SIZE ;
if ( Free < TS_SIZE )
return 0 ;
if ( Free < Count )
Count = Free ;
2017-03-18 16:33:59 +01:00
return mtdBuffer - > Put ( Data , Count ) ;
}
int cMtdCamSlot : : PutCat ( const uchar * Data , int Count )
{
MasterSlot ( ) - > Decrypt ( const_cast < uchar * > ( Data ) , Count ) ;
return Count ;
}