SASC-NG
DVBSoftCAM

plugin_cam.c

Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include <pthread.h>
00004 #include <string.h>
00005 #include <unistd.h>
00006 #include <fcntl.h>
00007 #include <assert.h>
00008 #include <sys/ioctl.h>
00009 #include <linux/dvb/ca.h>
00010 #include <linux/dvb/dmx.h>
00011 
00012 #include "../sc/include/vdr/plugin.h"
00013 #include "../sc/include/vdr/dvbdevice.h"
00014 #include "../sc/include/vdr/sclink.h"
00015 #include "../sc/include/vdr/channels.h"
00016 #include "../sc/include/vdr/tools.h"
00017 #include "../sc/sasccam.h"
00018 // Hack to disable debug print control from sc
00019 
00020 #include "process_req.h"
00021 #include "plugin_getsid.h"
00022 #include "plugin_cam.h"
00023 #include "plugin_msg.h"
00024 
00025 #define PLUGIN_ID 28
00026 #define DBG_NAME "CAM"
00027 #include "debug.h" //This is required to happen AFTER PLUGIN_ID is defined
00028 
00029 #define ll_find_elem(elem, lhead, item, value, type) {  \
00030   struct list_head *lptr;                               \
00031   type *ptr;                                            \
00032   elem = NULL;                                          \
00033   list_for_each(lptr, &lhead) {                         \
00034     ptr = list_entry(lptr, type);                       \
00035     if(ptr->item == value)                              \
00036       elem = ptr;                                       \
00037   }                                                     \
00038 }
00039 
00040 static int cam_opt = 0;
00041 static int opt_budget = 0;
00042 static int opt_fixcat = 1;
00043 static char opt_camdir[256] = {"./sc_files"};
00044 char * get_camdir() { return opt_camdir;}
00045 static char opt_extau[256];
00046 static struct option Cam_Opts[] = {
00047   {"cam-budget", 0, &cam_opt, 'b'},
00048   {"cam-dir", 1, &cam_opt, 'd'},
00049   {"cam-nofixcat", 0, &cam_opt, 'f'},
00050   {"cam-extau", 1, &cam_opt, 'e'},
00051   {"cam-scopts", 1, &cam_opt, 'o'},
00052   {0, 0, 0, 0},
00053 };
00054 
00055 struct cam_epid {
00056   struct list_head list;
00057   unsigned int epid;
00058   unsigned char type;
00059   unsigned int sid;
00060   int delayclose;
00061 };
00062 
00063 LIST_HEAD(sclist);
00064 
00065 LIST_HEAD(pid_empty_queue);
00066 LIST_HEAD(pid_list);
00067 
00068 struct fdmap_list {
00069   struct list_head list;
00070   unsigned int pid;
00071   int fd;
00072 };
00073 LIST_HEAD(fdmap_empty_queue);
00074 LIST_HEAD(fdmap_ll);
00075 
00076 struct scopt_list {
00077   char cmd[32];
00078   char value[256];
00079 };
00080 struct scopt_list scopts[32] = {{{'\0'}}};
00081 
00082 static cPlugin *sc = NULL;
00083 static char scCap[80];
00084 
00085 extern const char *externalAU;
00086 extern void update_keys(int, unsigned char, int, unsigned char *, int);
00087 extern void SetCAMPrint(const char *_plugin_name, unsigned int plugin_id, unsigned int _print_level, unsigned int *_log_level);
00088 const char *cPlugin::ConfigDirectory(const char *PluginName) {return opt_camdir;}
00089 
00090 static int init_sc(void) {
00091   sc=(cPlugin *)VDRPluginCreator();
00092 
00093   dprintf0("initializing plugin: SoftCam (%s): %s\n", sc->Version(), sc->Description());
00094 #ifndef __x86_64__
00095   //I have no idea why 64bit systems crash with the redirect
00096   SetCAMPrint(DBG_NAME, PLUGIN_ID, 0, &_dbglvl);
00097 #endif
00098   if (!sc->Initialize()) {
00099     dprintf0("Failed to initialize sc\n");
00100     return false;
00101   }
00102   dprintf0("starting plugin:\n");
00103   if (!sc->Start()) {
00104     dprintf0("Failed to start sc plugin\n");
00105     return false;
00106   }
00107 
00108   memset(scCap, 0, 80);
00109   sc->SetupParse("LoggerActive","2");
00110 #ifdef USE_AUXSERVER
00111   sc->SetupParse("Nagra2.AuxServerEnable", "1");
00112   #ifdef AUXSERVER_PORT
00113   sc->SetupParse("Nagra2.AuxServerPort", AUXSERVER_PORT);
00114   #endif
00115   #ifdef AUXSERVER_HOST
00116   sc->SetupParse("Nagra2.AuxServerAddr", AUXSERVER_HOST);
00117   #endif
00118   #ifdef AUXSERVER_PASSWD
00119   sc->SetupParse("Nagra2.AuxServerPass", AUXSERVER_PASSWD);
00120   #endif
00121 #endif
00122   for(int i = 0; i < 32 && scopts[i].cmd[0] != '\0'; i++) {
00123     dprintf0("Setting SC options: %s = %s\n", scopts[i].cmd, scopts[i].value);
00124     sc->SetupParse(scopts[i].cmd, scopts[i].value);
00125   }
00126   return true;
00127 }
00128 
00129 static struct sc_data *find_sc_from_adpt(int adapter) {
00130   struct sc_data *sc_data;
00131   ll_find_elem(sc_data, sclist, real, adapter, struct sc_data);
00132   return sc_data;
00133 }
00134 
00135 void cam_del_pid(struct sc_data *sc_data, struct cam_epid *cam_epid) {
00136   //struct ScLink link;
00137   struct list_head *ptr;
00138   struct cam_epid *cam_epid1;
00139   int epidlist[MAXDPIDS], *epidptr = epidlist;
00140   list_del(&cam_epid->list);
00141   list_for_each(ptr, &pid_list) {
00142     cam_epid1 = list_entry(ptr, struct cam_epid);
00143     if(cam_epid1->sid == cam_epid->sid)
00144       *(epidptr++) = cam_epid1->epid;
00145   }
00146   *epidptr = 0;
00147   sc_data->cam->AddPrg(cam_epid->sid,epidlist,0,0);
00148   //PrepareScLink(&link, sc_data->dev, OP_DELPID);
00149   //link.data.pids.pid=cam_epid->epid;
00150   //link.data.pids.type=cam_epid->type;
00151   //DoScLinkOp(sc, &link);
00152   list_add(&cam_epid->list, &pid_empty_queue);
00153 }
00154 
00155 void _SetCaDescr(int adapter, ca_descr_t *ca_descr) {
00156   struct sc_data *sc_data = find_sc_from_adpt(adapter);
00157   unsigned long cadata;
00158   if(!sc_data)
00159     return;
00160   dprintf1("Sending key(%d) %c %d %x%x...%x\n", sc_data->cafd,
00161            (ca_descr->parity ? 'O' : 'E'), ca_descr->index,
00162            ca_descr->cw[0], ca_descr->cw[1], ca_descr->cw[7]);
00163   
00164   cadata = (ca_descr->index << 1) | (ca_descr->parity==0 ? 0 : 1);
00165   msg_send(MSG_LOW_PRIORITY, MSG_CAMUPDATE, sc_data->virt, (void *)cadata);
00166   if(sc_data->cafd >= 0) {
00167     //Using a real CA
00168     ca_descr_t tmp_dscr;
00169     memcpy(&tmp_dscr, ca_descr, sizeof(tmp_dscr));
00170     tmp_dscr.index--;
00171     if(ioctl(sc_data->cafd,CA_SET_DESCR,&tmp_dscr)<0) {
00172       dprintf0("CA_SET_DESCR failed (%s)\n", strerror(errno));
00173     } else {
00174       update_keys(sc_data->virt, 'N', ca_descr->index, NULL, 0);
00175     }
00176   } else {
00177     update_keys(sc_data->virt, (ca_descr->parity==0) ? 'E' : 'O',
00178                 ca_descr->index, ca_descr->cw, 0);
00179   }
00180 }
00181 
00182 void _SetCaPid(int adapter, ca_pid_t *ca_pid) {
00183   struct sc_data *sc_data = find_sc_from_adpt(adapter);
00184   if(!sc_data)
00185     return;
00186   dprintf1("Sending (%d) key P %d PID: %d\n", sc_data->virt, ca_pid->index,
00187            ca_pid->pid);
00188   if(sc_data->cafd >= 0) {
00189     //Using a real CA
00190     ca_pid_t tmp_pid;
00191     memcpy(&tmp_pid, ca_pid, sizeof(tmp_pid));
00192     tmp_pid.index--;
00193     if(ioctl(sc_data->cafd,CA_SET_PID,&tmp_pid) < 0 && tmp_pid.index > 0) {
00194       dprintf0("CA_SET_PID failed (%s)\n", strerror(errno));
00195     }
00196   }
00197   update_keys(sc_data->virt, 'P', ca_pid->index, NULL, ca_pid->pid);
00198 }
00199 
00200 void process_cam(struct msg *msg, unsigned int priority)
00201 {
00202   struct list_head *ptr;
00203   struct cam_epid *cam_epid;
00204   struct sid_msg *sidmsg;
00205   int match = 0;
00206   cChannel *ch;
00207 
00208   int vpid = 0, ppid = 0, tpid = 0, dcnt = 0;
00209   int apid[MAXAPIDS], dpid[MAXDPIDS];
00210 
00211   //struct ScLink link;
00212   struct sc_data *sc_data;
00213 
00214   if (msg->type == MSG_RESETSID) {
00215     sc_data = find_sc_from_adpt(msg->id);
00216     assert(sc_data);
00217     dprintf1("Got MSG_RESETSID\n");
00218     while(! list_empty(&pid_list)) {
00219       cam_epid = list_entry(pid_list.next, struct cam_epid);
00220       cam_del_pid(sc_data, cam_epid);
00221     }
00222     sc_data->cam->Stop();
00223     //PrepareScLink(&link, sc_data->dev, OP_TUNE);
00224     //link.data.tune.source=0;
00225     //link.data.tune.transponder=0;
00226     //DoScLinkOp(sc, &link);
00227     //sc_data->dev->SetChannelDevice(0, 0);
00228     update_keys(sc_data->virt, 'I', 0, NULL, 0);
00229     sc_data->valid = 0;
00230     msg->type = MSG_PROCESSED;
00231     return;
00232   }
00233   if (msg->type == MSG_REMOVESID) {
00234     unsigned int sid = 0xffff & (unsigned long)(msg->data);
00235     dprintf1("Got MSG_REMOVESID with sid: %d\n", sid);
00236     //delay removal of pids so we can continue to watch for key-rolls
00237     list_for_each(ptr, &pid_list) {
00238       cam_epid = list_entry(ptr, struct cam_epid);
00239       if(cam_epid->sid == sid) {
00240         dprintf1("Mapped sid to %d\n", cam_epid->epid);
00241         cam_epid->delayclose = 1;
00242         //update_keys('C', 0, NULL, cam_epid->epid);
00243         //cam_del_pid(sc_data, cam_epid);
00244       }
00245     }
00246     msg->type = MSG_PROCESSED;
00247     return;
00248   }
00249   if (msg->type == MSG_HOUSEKEEPING) {
00250     sc->Housekeeping();
00251     msg->type = MSG_PROCESSED;
00252     return;
00253   }
00254   if (msg->type != MSG_ADDSID)
00255     return;
00256 
00257   sc_data = find_sc_from_adpt(msg->id);
00258   assert(sc_data);
00259   sidmsg = (struct sid_msg *)msg->data;
00260 
00261   if (sidmsg->calen == 0) {
00262     free_sidmsg(sidmsg);
00263     return;
00264   }
00265   for(ch=Channels.First(); ch; ch=Channels.Next(ch)) {
00266     if((unsigned int)ch->Sid() == sidmsg->sid) {
00267       match = 1;
00268       break;
00269     }
00270   }
00271   if(match) {
00272     //if the sid is the same as last time, and a tune hasn't happened, we're
00273     //already good to go
00274     if(sc_data->valid) {
00275       list_for_each(ptr, &pid_list) {
00276         cam_epid = list_entry(ptr, struct cam_epid);
00277         if(cam_epid->delayclose && cam_epid->sid == sidmsg->sid) {
00278           dprintf1("Reenabling delayed-closed sid: %d\n", sidmsg->sid);
00279           cam_epid->delayclose = 0;
00280         }
00281       }
00282       free_sidmsg(sidmsg);
00283       return;
00284     }
00285   } else {
00286     //the sid is different, but we may be on the same transponder, so clear
00287     //all delayed-close pids before proceeding
00288     while (1) {
00289       ll_find_elem(cam_epid, pid_list, delayclose, 1, struct cam_epid);
00290       if(cam_epid == NULL)
00291         break;
00292       dprintf1("Mapped sid %d to epid %d\n", cam_epid->sid, cam_epid->epid);
00293       update_keys(sc_data->virt, 'C', 0, NULL, cam_epid->epid);
00294       for(ch=Channels.First(); ch; ch=Channels.Next(ch)) {
00295         if((unsigned int)ch->Sid() == cam_epid->sid) {
00296           Channels.Del(ch);
00297           break;
00298         }
00299       }
00300       cam_del_pid(sc_data, cam_epid);
00301     }
00302   }
00303   msg->type = MSG_PROCESSED;
00304 
00305   //create new channel
00306   memset(apid, 0, sizeof(int)*MAXAPIDS);
00307   memset(dpid, 0, sizeof(int)*MAXDPIDS);
00308   ch = new cChannel();
00309 
00310   ch->SetId(0, 1, sidmsg->sid, 0);
00311   if(sidmsg->nit.type==0x43) { //set source type to Satellite.  Use orbit and E/W data
00312     int source = 0x8000 | (BCD2INT(sidmsg->nit.orbit) & 0x7ff) | ((int)sidmsg->nit.is_east << 11);
00313     static char Polarizations[] = { 'h', 'v', 'l', 'r' };
00314     ch->SetSatTransponderData(source, BCD2INT(sidmsg->nit.frequency)/100, Polarizations[sidmsg->nit.polarization], BCD2INT(sidmsg->nit.symbolrate)/10, 0);
00315     }
00316   else if(sidmsg->nit.type==0x44) { //set source type to Cable
00317     ch->SetCableTransponderData(0x4000, BCD2INT(sidmsg->nit.frequency)/10, 0, BCD2INT(sidmsg->nit.symbolrate)/10, 0);
00318     }
00319   dcnt = (MAXDPIDS >= sidmsg->epid_count) ?
00320             sidmsg->epid_count : MAXDPIDS;
00321   memcpy(dpid, sidmsg->epid, sizeof(int)*dcnt);
00322   ch->SetPids(vpid, ppid, apid, NULL, dpid, NULL, tpid);
00323 
00324   if(! sc_data->valid) {
00325     sc_data->valid = 1;
00326     while(Channels.First())
00327       Channels.Del(Channels.First());
00328   }
00329 
00330   Channels.Add(ch);
00331   if(Channels.First() == Channels.Last()) {
00332     sc_data->cam->Tune(ch);
00333     //This is the first channel
00334     //PrepareScLink(&link, sc_data->dev, OP_TUNE);
00335     //link.data.tune.source=ch->Source();
00336     //link.data.tune.transponder=ch->Transponder();
00337     //dprintf0("Sending Tune cmd to SC\n");
00338     //DoScLinkOp(sc, &link);
00339     dprintf0("SC completed  Tune cmd\n");
00340   }
00341 
00342   int i, epidlist[MAXDPIDS], *epidptr = epidlist;
00343   for(i=0; i < sidmsg->epid_count && i < MAXDPIDS; i++) {
00344     pop_entry_from_queue(cam_epid, &pid_empty_queue, struct cam_epid);
00345     cam_epid->delayclose = 0;
00346     cam_epid->epid = sidmsg->epid[i];
00347     cam_epid->type = 5; //epid->type;
00348     cam_epid->sid = sidmsg->sid;
00349     list_add(&cam_epid->list, &pid_list);
00350     *(epidptr++) = sidmsg->epid[i];
00351     dprintf1("Adding pid %d for sid %d to pidlist\n", cam_epid->epid, cam_epid->sid);
00352     //PrepareScLink(&link, sc_data->dev, OP_ADDPID);
00353     //link.data.pids.pid=epid->epid;
00354     //link.data.pids.type = 5; //epid->type;
00355     //DoScLinkOp(sc, &link);
00356   }
00357   *epidptr = 0;
00358   sc_data->cam->AddPrg(sidmsg->sid,epidlist,sidmsg->ca,sidmsg->calen);
00359   free_sidmsg(sidmsg);
00360 }
00361 
00362 //taken and adapted from libdtv, (c) Rolf Hakenes
00363 // CRC32 lookup table for polynomial 0x04c11db7
00364 static unsigned int crc_table[256] = {
00365    0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
00366    0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
00367    0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
00368    0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
00369    0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
00370    0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
00371    0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
00372    0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
00373    0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
00374    0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
00375    0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
00376    0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
00377    0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
00378    0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
00379    0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
00380    0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
00381    0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
00382    0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
00383    0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
00384    0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
00385    0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
00386    0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
00387    0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
00388    0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
00389    0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
00390    0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
00391    0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
00392    0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
00393    0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
00394    0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
00395    0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
00396    0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
00397    0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
00398    0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
00399    0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
00400    0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
00401    0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
00402    0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
00403    0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
00404    0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
00405    0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
00406    0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
00407    0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
00408 
00409 unsigned int crc32 (const unsigned char *d, int len, unsigned int crc)
00410 {
00411    register int i;
00412    const unsigned char *u=(unsigned char*)d; // Saves '& 0xff'
00413 
00414    for (i=0; i<len; i++)
00415       crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)];
00416 
00417    return crc;
00418 }
00419 
00420 static int parse_ca(unsigned char * buf, int len)
00421 {
00422   int count, pos = 0;
00423   int found = 0;
00424   while (pos < len) {
00425     count = buf[pos+1] +2;
00426     //printf("Found CA: %d (len %d)\n", buf[pos], count);
00427     if(buf[pos] == 0x09) {
00428       buf[pos] = 0xff;
00429       found++;
00430     }
00431     pos+=count;
00432   }
00433   return found;
00434 }
00435 
00436 static void replace_cat(unsigned char *buf, int len, int pid)
00437 {
00438   int desc_len, count;
00439   int found = 0;
00440   int pos = 0;
00441   if(len > 0) {
00442     if (buf[0] == 0x02) {
00443       count = (((buf[1] & 0x03) << 8) | buf[2]) + 3 - 4;
00444       desc_len = ((buf[10] & 0x03) << 8) | buf[11];
00445       if(desc_len > len - 12 || count > len) {
00446         //bogus data
00447         return;
00448       }
00449       found+=parse_ca(buf+12, desc_len);
00450       //handle epids here
00451       for(pos = 12 + desc_len; pos < count;) {
00452         desc_len = ((buf[pos+3] & 0x03) << 8) | buf[pos+4];
00453         if(pos+desc_len +5 > count) {
00454           //bogus data
00455           return;
00456         }
00457         found+=parse_ca(buf+pos+5, desc_len);
00458         pos += desc_len + 5;
00459       }
00460       if(found) {
00461         //compute CRC32
00462         int crc = crc32(buf, len-4, 0xFFFFFFFF);
00463         buf[len-4] = (crc >> 24) & 0xff;
00464         buf[len-3] = (crc >> 16) & 0xff;
00465         buf[len-2] = (crc >> 8) & 0xff;
00466         buf[len-1] = (crc >> 0) & 0xff;
00467       }
00468       dprintf1("Replaced %d cas on pid %d (len=%d)\n", found, pid, len);
00469     }
00470   }
00471 }
00472 
00473 static void dmxread_call(struct parser_cmds *pc, struct poll_ll *fdptr,
00474                       cmdret_t *result, int *ret, 
00475                       unsigned long int cmd, unsigned char *data)
00476 {
00477   struct fdmap_list *fd_map;
00478   ll_find_elem(fd_map, fdmap_ll, fd, fdptr->fd, struct fdmap_list);
00479   if(! fd_map)
00480     return;
00481   replace_cat(pc->mmap, *ret, fd_map->pid);
00482 }
00483 
00484 static void dmxioctl_call(struct parser_cmds *pc, struct poll_ll *fdptr,
00485                       cmdret_t *result, int *ret, 
00486                       unsigned long int cmd, unsigned char *data)
00487 {
00488   struct fdmap_list *fd_map;
00489   int pid;
00490   ll_find_elem(fd_map, fdmap_ll, fd, fdptr->fd, struct fdmap_list);
00491   if(fd_map)
00492     return;
00493   if(cmd == DMX_SET_FILTER) {
00494     struct dmx_sct_filter_params *dmx =
00495            (struct dmx_sct_filter_params *)data;
00496     pid = dmx->pid;
00497   } else if(cmd == DMX_SET_PES_FILTER) {
00498     struct dmx_pes_filter_params *dmx =
00499            (struct dmx_pes_filter_params *)data;
00500     pid = dmx->pid;
00501     //supporting PES filters means parsing dvr.  let's skip that for now.
00502     return;
00503   } else {
00504     return;
00505   }
00506   //This is a hack.  We need to get the pmt handels from the pat like getsid
00507   if(pid > 100)
00508     return;
00509   pop_entry_from_queue(fd_map, &fdmap_empty_queue, struct fdmap_list);
00510   fd_map->fd = fdptr->fd;
00511   fd_map->pid = pid;
00512   list_add(&fd_map->list, &fdmap_ll);
00513 }
00514 static void dmxclose_call(struct parser_cmds *pc, struct poll_ll *fdptr,
00515                       cmdret_t *result, int *ret, 
00516                       unsigned long int cmd, unsigned char *data)
00517 {
00518   struct fdmap_list *fd_map;
00519   ll_find_elem(fd_map, fdmap_ll, fd, fdptr->fd, struct fdmap_list);
00520   if(fd_map) {
00521     list_del(&fd_map->list);
00522     list_add(&fd_map->list, &fdmap_empty_queue);
00523   }
00524 }
00525 
00526 void connect_cam(struct parser_adpt *pc_all)
00527 {
00528   int cardnum = pc_all->frontend->common->real_adapt;
00529   struct list_head *ptr;
00530   char *cadev;
00531   char tmpstr[5];
00532   struct sc_data *sc_data;
00533 
00534   if(! sc)
00535     if(! init_sc())
00536       return;
00537  
00538   sc_data = (struct sc_data *)malloc(sizeof(struct sc_data));
00539   memset(sc_data, 0, sizeof(struct sc_data));
00540 
00541 
00542   sprintf(tmpstr," %d",cardnum+1);
00543   strncat(scCap, tmpstr, 80);
00544   sc->SetupParse("ScCaps",scCap);
00545 
00546   sc_data->valid = 0;
00547   sc_data->virt = pc_all->frontend->common->virt_adapt;
00548   sc_data->real = cardnum;
00549   sc_data->cam = new sascCam(cardnum);
00550 
00551   if (opt_budget) {
00552     sc_data->cafd = -1;
00553   } else {
00554     asprintf(&cadev, "/dev/dvb/adapter%d/ca0", cardnum);
00555     sc_data->cafd = open(cadev, O_RDWR|O_NONBLOCK);
00556     if (sc_data->cafd >= 0) {
00557       ca_caps_t ca_caps;
00558       if (ioctl(sc_data->cafd, CA_GET_CAP, &ca_caps) == 0 &&
00559           ca_caps.slot_num > 0 && (ca_caps.slot_type & CA_CI_LINK)) {
00560         dprintf0("Found a FF card\n");
00561       } else {
00562         sc_data->cafd = -1;
00563       }
00564     }
00565     free(cadev);
00566   }
00567   list_add(&sc_data->list, &sclist);
00568   if(opt_fixcat) {
00569     ATTACH_CALLBACK(&pc_all->demux->pre_ioctl, dmxioctl_call, 0);
00570     ATTACH_CALLBACK(&pc_all->demux->post_read, dmxread_call, 0);
00571     ATTACH_CALLBACK(&pc_all->demux->pre_close, dmxclose_call, 0);
00572   }
00573   list_for_each(ptr, &plugin_cmdlist) {
00574     struct plugin_cmd *cmd = list_entry(ptr, struct plugin_cmd);
00575     if(cmd->plugin == PLUGIN_GETSID) {
00576       cmd->send_msg(pc_all->frontend, 1);
00577       break;
00578     }
00579   }
00580 }
00581 
00582 static void launch_cam()
00583 {
00584   //Call housecleaning every 60 seconds
00585   msg_send_replace(MSG_LOW_PRIORITY, MSG_HOUSEKEEPING, 0, NULL,
00586                    60, MSG_RECURRING);
00587 }
00588 
00589 static void shutdown_cam()
00590 {
00591   if (sc)
00592   {
00593     sc->Stop();
00594     struct sc_data *sc_data;
00595     struct list_head *ptr;
00596     list_for_each(ptr, &sclist) {
00597       sc_data = list_entry(ptr, struct sc_data);
00598       if (sc_data->cafd >= 0) {
00599         close(sc_data->cafd);
00600         sc_data->cafd = -1;
00601         sc_data->valid = 0;
00602       }
00603     }
00604     delete sc;
00605     sc = NULL;
00606   }
00607 }
00608 
00609 static void usermsg_cam(char * str) {
00610   char *data;
00611   cString outstr;
00612   int res;
00613   if(sc) {
00614     printf(":: %s ||\n", str);
00615     data = strchr(str, ' ');
00616     if(data) {
00617       *data = '\0';
00618       data++;
00619     }
00620     printf("User Message %s data: %s\n", str, data);
00621     outstr = sc->SVDRPCommand((const char *)str, (const char *)data, res);
00622     printf("%s",*outstr);
00623     printf("User Message %s returned: %d\n", str, res);
00624   }
00625 }
00626 
00627 static struct option *parseopt_cam(arg_enum_t cmd)
00628 {
00629   if(cmd == ARG_INIT) {
00630     return Cam_Opts;
00631   }
00632   if(cmd == ARG_HELP) {
00633     printf("   --cam-budget      : Force budget card mode\n");
00634     printf("   --cam-dir <dir>   : Set directory for sc files (default ./sc_files)\n");
00635     printf("   --cam-nofixcat    : Don't remove cat entries\n");
00636     printf("   --cam-extau <cmd> : Execute cmd to retrieve updated keys\n");
00637     printf("   --cam-scopts <cmd>: Set sc options (opt=value)\n");
00638     return NULL;
00639   }
00640   if(! cam_opt)
00641     return NULL;
00642 
00643   switch(cam_opt) {
00644     case 'b':
00645       opt_budget = 1;
00646       break;
00647     case 'd':
00648       strncpy(opt_camdir, optarg, sizeof(opt_camdir)-1);
00649       opt_camdir[sizeof(opt_camdir)-1]=0;
00650       break;
00651     case 'e':
00652       strncpy(opt_extau, optarg, sizeof(opt_extau)-1);
00653       opt_extau[sizeof(opt_extau)-1]=0;
00654       externalAU = opt_extau;
00655     case 'f':
00656       opt_fixcat = 0;
00657       break;
00658     case 'o':
00659       {
00660         int i;
00661         for(i = 0; i < 32 && scopts[i].cmd[0] != '\0'; i++)
00662           ;
00663         if(i == 32) {
00664           dprintf0("Too many SC options.  Ignoring: %s\n", optarg);
00665         } else {
00666           char *pos =optarg;
00667           while(*pos != '=' && *pos != '\0')
00668             pos++;
00669           if(*pos == '\0') {
00670             dprintf0("Could not parse SC argument: %s\n", optarg);
00671           } else {
00672             memcpy(scopts[i].cmd, optarg, pos - optarg);
00673             memcpy(scopts[i].value, pos+1, strlen(optarg) - (1+pos - optarg));
00674 printf("here: %s %s %d\n", scopts[i].cmd, scopts[i].value, i);
00675             if(i != 31)
00676               scopts[i+1].cmd[0] = '\0';
00677           }
00678         }
00679         break;
00680       }
00681   }
00682   //must reset cam_opt after every call
00683   cam_opt = 0;
00684   return NULL;
00685 }
00686 //list, plugin_id, name, parse_args, connect, launch, message, send_msg
00687 static struct plugin_cmd plugin_cmds = {{NULL, NULL}, PLUGIN_ID, "cam",
00688                  parseopt_cam, connect_cam, launch_cam, process_cam, NULL,
00689                  shutdown_cam, usermsg_cam};
00690 
00691 int __attribute__((constructor)) __cam_init(void)
00692 {
00693   list_add_tail(&plugin_cmds.list, &plugin_cmdlist);
00694   return 0;
00695 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines