diff --git a/HISTORY b/HISTORY index c7c76f5d..497732a1 100644 --- a/HISTORY +++ b/HISTORY @@ -2039,3 +2039,5 @@ Video Disk Recorder Revision History - Using masks in EIT filtering to reduce the number of filters (thanks to Andreas Schultz). - Fixed handling Ca descriptors (thanks to Stefan Huelswitt). +- Now only those Ca descriptors are sent to a CAM that are actually understood + by that CAM. diff --git a/ci.c b/ci.c index a3d64df3..8f38ee4e 100644 --- a/ci.c +++ b/ci.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ci.c 1.9 2003/03/23 15:18:40 kls Exp $ + * $Id: ci.c 1.10 2003/04/18 12:48:49 kls Exp $ */ /* XXX TODO @@ -769,7 +769,7 @@ public: cCiApplicationInformation::cCiApplicationInformation(int SessionId, cCiTransportConnection *Tc) :cCiSession(SessionId, RI_APPLICATION_INFORMATION, Tc) { - dbgprotocol("New Aplication Information (session id %d)\n", SessionId); + dbgprotocol("New Application Information (session id %d)\n", SessionId); state = 0; creationTime = time(NULL); menuString = NULL; @@ -827,12 +827,17 @@ bool cCiApplicationInformation::EnterMenu(void) // --- cCiConditionalAccessSupport ------------------------------------------- +#define MAXCASYSTEMIDS 16 + class cCiConditionalAccessSupport : public cCiSession { private: int state; + int numCaSystemIds; + unsigned short caSystemIds[MAXCASYSTEMIDS + 1]; // list is zero terminated! public: cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc); virtual bool Process(int Length = 0, const uint8_t *Data = NULL); + const unsigned short *GetCaSystemIds(void) { return caSystemIds; } bool SendPMT(cCiCaPmt &CaPmt); }; @@ -841,6 +846,7 @@ cCiConditionalAccessSupport::cCiConditionalAccessSupport(int SessionId, cCiTrans { dbgprotocol("New Conditional Access Support (session id %d)\n", SessionId); state = 0; + caSystemIds[numCaSystemIds = 0] = 0; } bool cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data) @@ -853,9 +859,16 @@ bool cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data) int l = 0; const uint8_t *d = GetData(Data, l); while (l > 1) { - dbgprotocol(" %04X", ((unsigned int)(*d) << 8) | *(d + 1)); + unsigned short id = ((unsigned short)(*d) << 8) | *(d + 1); + dbgprotocol(" %04X", id); d += 2; l -= 2; + if (numCaSystemIds < MAXCASYSTEMIDS) { + caSystemIds[numCaSystemIds++] = id; + caSystemIds[numCaSystemIds] = 0; + } + else + esyslog("ERROR: too many CA system IDs!"); } dbgprotocol("\n"); } @@ -1274,6 +1287,7 @@ cCiHandler::cCiHandler(int Fd, int NumSlots) { numSlots = NumSlots; enabled = true; + newCaSupport = false; for (int i = 0; i < MAX_CI_SESSION; i++) sessions[i] = NULL; tpl = new cCiTransportLayer(Fd, numSlots); @@ -1358,7 +1372,8 @@ cCiSession *cCiHandler::CreateSession(int ResourceId) switch (ResourceId) { case RI_RESOURCE_MANAGER: return sessions[i] = new cCiResourceManager(i + 1, tc); case RI_APPLICATION_INFORMATION: return sessions[i] = new cCiApplicationInformation(i + 1, tc); - case RI_CONDITIONAL_ACCESS_SUPPORT: return sessions[i] = new cCiConditionalAccessSupport(i + 1, tc); + case RI_CONDITIONAL_ACCESS_SUPPORT: newCaSupport = true; + return sessions[i] = new cCiConditionalAccessSupport(i + 1, tc); case RI_HOST_CONTROL: break; //XXX case RI_DATE_TIME: return sessions[i] = new cCiDateTime(i + 1, tc); case RI_MMI: return sessions[i] = new cCiMMI(i + 1, tc); @@ -1470,6 +1485,8 @@ bool cCiHandler::Process(void) if (sessions[i]) sessions[i]->Process(); } + if (newCaSupport) + newCaSupport = result = false; // triggers new SetCaPmt at caller! return result; } @@ -1502,16 +1519,18 @@ cCiEnquiry *cCiHandler::GetEnquiry(void) return NULL; } -bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt) +const unsigned short *cCiHandler::GetCaSystemIds(int Slot) { cMutexLock MutexLock(&mutex); - bool result = false; - for (int Slot = 0; Slot < numSlots; Slot++) { - cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot); - if (cas) - result |= cas->SendPMT(CaPmt); - } - return result; + cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot); + return cas ? cas->GetCaSystemIds() : NULL; +} + +bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int Slot) +{ + cMutexLock MutexLock(&mutex); + cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot); + return cas && cas->SendPMT(CaPmt); } bool cCiHandler::Reset(int Slot) diff --git a/ci.h b/ci.h index a9f27f1e..0c247f82 100644 --- a/ci.h +++ b/ci.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ci.h 1.4 2003/03/23 15:18:40 kls Exp $ + * $Id: ci.h 1.5 2003/04/18 12:41:48 kls Exp $ */ #ifndef __CI_H @@ -81,6 +81,7 @@ private: cMutex mutex; int numSlots; bool enabled; + bool newCaSupport; cCiSession *sessions[MAX_CI_SESSION]; cCiTransportLayer *tpl; cCiTransportConnection *tc; @@ -96,12 +97,14 @@ private: public: ~cCiHandler(); static cCiHandler *CreateCiHandler(const char *FileName); + int NumSlots(void) { return numSlots; } void SetEnabled(bool Enabled) { enabled = Enabled; } bool Process(void); bool EnterMenu(int Slot); cCiMenu *GetMenu(void); cCiEnquiry *GetEnquiry(void); - bool SetCaPmt(cCiCaPmt &CaPmt); + const unsigned short *GetCaSystemIds(int Slot); + bool SetCaPmt(cCiCaPmt &CaPmt, int Slot); bool Reset(int Slot); }; diff --git a/dvbdevice.c b/dvbdevice.c index 9bbac2d2..19a7c431 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.c 1.51 2003/04/12 15:06:11 kls Exp $ + * $Id: dvbdevice.c 1.52 2003/04/18 11:35:08 kls Exp $ */ #include "dvbdevice.h" @@ -264,27 +264,29 @@ void cDvbTuner::Action(void) } } if (tunerStatus >= tsLocked) { - if (ciHandler && channel.Ca()) { + if (ciHandler && channel.Ca() > CACONFBASE) { if (ciHandler->Process()) { if (tunerStatus != tsCam) {//XXX TODO update in case the CA descriptors have changed - uchar buffer[2048]; - int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer); - if (length > 0) { - cCiCaPmt CaPmt(channel.Sid()); - CaPmt.AddCaDescriptor(length, buffer); - if (channel.Vpid()) - CaPmt.AddPid(channel.Vpid()); - if (channel.Apid1()) - CaPmt.AddPid(channel.Apid1()); - if (channel.Apid2()) - CaPmt.AddPid(channel.Apid2()); - if (channel.Dpid1()) - CaPmt.AddPid(channel.Dpid1()); - if (ciHandler->SetCaPmt(CaPmt)) { - tunerStatus = tsCam; - startTime = 0; - } - } + for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) { + uchar buffer[2048]; + int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), ciHandler->GetCaSystemIds(Slot), sizeof(buffer), buffer); + if (length > 0) { + cCiCaPmt CaPmt(channel.Sid()); + CaPmt.AddCaDescriptor(length, buffer); + if (channel.Vpid()) + CaPmt.AddPid(channel.Vpid()); + if (channel.Apid1()) + CaPmt.AddPid(channel.Apid1()); + if (channel.Apid2()) + CaPmt.AddPid(channel.Apid2()); + if (channel.Dpid1()) + CaPmt.AddPid(channel.Dpid1()); + if (ciHandler->SetCaPmt(CaPmt, Slot)) { + tunerStatus = tsCam; + startTime = 0; + } + } + } } } else diff --git a/eit.c b/eit.c index de52e7c6..f4075df6 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.70 2003/04/18 11:29:11 kls Exp $ + * $Id: eit.c 1.71 2003/04/18 11:30:42 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -1059,12 +1059,8 @@ public: const cCaDescriptor *cCaDescriptors::Get(int Source, int Transponder, int ServiceId, int CaSystem) { for (cCaDescriptor *ca = First(); ca; ca = Next(ca)) { - if (ca->source == Source && ca->transponder == Transponder && ca->serviceId == ServiceId) { - if (CaSystem == -1 || ca->caSystem == CaSystem) - return ca; - if (CaSystem < 0) - CaSystem++; - } + if (ca->source == Source && ca->transponder == Transponder && ca->serviceId == ServiceId && ca->caSystem == CaSystem) + return ca; } return NULL; } @@ -1452,24 +1448,24 @@ void cSIProcessor::NewCaDescriptor(struct Descriptor *d, int ProgramID) } } -int cSIProcessor::GetCaDescriptors(int Source, int Transponder, int ServiceId, int BufSize, uchar *Data) +int cSIProcessor::GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data) { + if (!CaSystemIds || !*CaSystemIds) + return 0; if (BufSize > 0 && Data) { cMutexLock MutexLock(&caDescriptorsMutex); int length = 0; - for (int i = -1; ; i--) { - const cCaDescriptor *d = caDescriptors->Get(Source, Transponder, ServiceId, i); - if (d) { - if (length + d->Length() <= BufSize) { - memcpy(Data + length, d->Data(), d->Length()); - length += d->Length(); - } - else - return -1; - } - else - break; - } + do { + const cCaDescriptor *d = caDescriptors->Get(Source, Transponder, ServiceId, *CaSystemIds); + if (d) { + if (length + d->Length() <= BufSize) { + memcpy(Data + length, d->Data(), d->Length()); + length += d->Length(); + } + else + return -1; + } + } while (*++CaSystemIds); return length; } return -1; diff --git a/eit.h b/eit.h index f8a91051..0adf4816 100644 --- a/eit.h +++ b/eit.h @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.26 2003/04/13 14:01:24 kls Exp $ + * $Id: eit.h 1.27 2003/04/18 11:30:42 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -168,10 +168,11 @@ public: // Caller must provide a cMutexLock which has to survive the entire // time the returned cSchedules is accessed. Once the cSchedules is no // longer used, the cMutexLock must be destroyed. - static int GetCaDescriptors(int Source, int Transponder, int ServiceId, int BufSize, uchar *Data); + static int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data); ///< Gets all CA descriptors for a given channel. ///< Copies all available CA descriptors for the given Source, Transponder and ServiceId - ///< into the provided buffer at Data (at most BufSize bytes). + ///< into the provided buffer at Data (at most BufSize bytes). Only those CA descriptors + ///< are copied that match one of the given CA system IDs. ///< \return Returns the number of bytes copied into Data (0 if no CA descriptors are ///< available), or -1 if BufSize was too small to hold all CA descriptors. static bool Read(FILE *f = NULL);