|
SASC-NG
DVBSoftCAM
|
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 }