SASC
DVBSoftCAM

cccam_ca.c

Go to the documentation of this file.
00001 /* Compile as follows:
00002  * gcc -O -fbuiltin -fomit-frame-pointer -fPIC -shared -o ca.so ca.c -ldl
00003  *
00004  * run cccam with:
00005  * LD_PRELOAD=./ca.so ./xxx.i386
00006  *
00007  * Will then send CWs to vdr-sc cardclient cccam
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Library General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Library General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Library General Public
00020  * License along with this library; if not, write to the
00021  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00022  * Boston, MA 02111-1307, USA.
00023  */
00024 
00025 //#define DEBUG
00026 
00027 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
00028 
00029 #include <dlfcn.h>
00030 #include <stdarg.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <unistd.h>
00034 #include <fcntl.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <linux/dvb/ca.h>
00038 #include <linux/dvb/dmx.h>
00039 #include <linux/dvb/frontend.h>
00040 #include <linux/ioctl.h>
00041 #include <stdio.h>
00042 #include <time.h>
00043 #include <sys/socket.h>
00044 #include <netinet/in.h>
00045 #include <arpa/inet.h>
00046 #include <sys/un.h>
00047 #include <syslog.h>
00048 #include <errno.h>
00049 
00050 #if defined(RTLD_NEXT)
00051 #define REAL_LIBC RTLD_NEXT
00052 #else
00053 #define REAL_LIBC ((void *) -1L)
00054 #endif
00055 
00056 #define PORT 9000
00057 #define MAX_CA  4
00058 
00059 static int cafd[MAX_CA]  = {-1,-1,-1,-1};
00060 static int cafdc[MAX_CA] = {0,0,0,0};
00061 
00062 #define MAX_INDEX 64
00063 #define KEY_SIZE  8
00064 #define INFO_SIZE (2+KEY_SIZE+KEY_SIZE)
00065 #define EVEN_OFF  (2)
00066 #define ODD_OFF   (2+KEY_SIZE)
00067 
00068 static unsigned char ca_info[MAX_CA][MAX_INDEX][INFO_SIZE];
00069 
00070 #define CA_BASE         "/dev/dvb/adapter0/ca"
00071 #define DEMUX_BASE      "/dev/dvb/adapter0/demux"
00072 #define DEMUX_MAP       "/dev/dvb/adapter%d/demux0"
00073 #define CPUINFO_BASE    "/proc/cpuinfo"
00074 #define CPUINFO_MAP     "/tmp/cpuinfo"
00075 
00076 //#define DBG(x...) {syslog(LOG_INFO, x);}
00077 #define DBG(x...)
00078 #define INF(x...) {syslog(LOG_INFO, x);}
00079 #define ERR(x...) {syslog(LOG_ERR, x);}
00080 
00081 int proginfo=0;
00082 #define PROGINFO() {if(!proginfo){syslog(LOG_INFO,"ca.so for cccam V1.09");proginfo=1;}}
00083 
00084 int sendcw(int fd, unsigned char *buff) {
00085   DBG(">>>>>>>> sendcw %02x%02x %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x", buff[0], buff[1], buff[2], buff[3], buff[4], buff[5], buff[6], buff[7], buff[8], buff[9], buff[10], buff[11], buff[12], buff[13], buff[14], buff[15], buff[16], buff[17], buff[18]);
00086   if ( send(fd,buff, 18, 0) == -1 ) { 
00087         ERR("ca.so: Send cw failed %d", errno);
00088     return 0;
00089   } // if
00090   return 1;
00091 } // sendcw
00092 
00093 static int cactl (int fd, int cai, int request, void *argp) {
00094   ca_descr_t *ca = (ca_descr_t *)argp;
00095   ca_pid_t  *cpd = (ca_pid_t  *)argp;
00096   switch (request) {
00097     case CA_SET_DESCR:
00098       DBG(">>>>>>>> cactl CA_SET_DESCR fd %d cai %d req %d par %d idx %d %02x%02x%02x%02x%02x%02x%02x%02x", fd, cai, request, ca->parity, ca->index, ca->cw[0], ca->cw[1], ca->cw[2], ca->cw[3], ca->cw[4], ca->cw[5], ca->cw[6], ca->cw[7]);
00099       if(ca->parity==0)
00100         memcpy(&ca_info[cai][ca->index][EVEN_OFF],ca->cw,KEY_SIZE); // even key
00101       else if(ca->parity==1)
00102         memcpy(&ca_info[cai][ca->index][ODD_OFF],ca->cw,KEY_SIZE); // odd key
00103       else
00104         ERR("ca.so: Invalid parity %d in CA_SET_DESCR for ca id %d", ca->parity, cai);
00105       sendcw(fd, ca_info[cai][ca->index]);
00106       break;
00107     case CA_SET_PID:
00108       DBG(">>>>>>>> cactl CA_SET_PID fd %d cai %d req %d (%d %04x)", fd, cai, request, cpd->index, cpd->pid);
00109       if (cpd->index >=0 && cpd->index < MAX_INDEX) { 
00110         ca_info[cai][cpd->index][0] = (cpd->pid >> 0) & 0xff;
00111                                 ca_info[cai][cpd->index][1] = (cpd->pid >> 8) & 0xff;
00112       } else if (cpd->index == -1) {
00113         memset(&ca_info[cai], 0, sizeof(ca_info[cai]));
00114       } else
00115         ERR("ca.so: Invalid index %d in CA_SET_PID (%d) for ca id %d", cpd->index, MAX_INDEX, cai);
00116       return 1;
00117     case CA_RESET:
00118       DBG(">>>>>>>> cactl CA_RESET cai %d", cai);
00119       break;
00120     case CA_GET_CAP:
00121       DBG(">>>>>>>> cactl CA_GET_CAP cai %d", cai);
00122       break;
00123     case CA_GET_SLOT_INFO:
00124       DBG(">>>>>>>> cactl CA_GET_SLOT_INFO cai %d", cai);
00125       break;
00126     default:
00127       DBG(">>>>>>>> cactl unhandled req %d cai %d", request, cai);
00128       //errno = EINVAL;
00129       //return -1;
00130   } // switch
00131   return 0;
00132 } // cactl
00133 
00134 /* 
00135     CPU Model
00136     Brcm4380 V4.2  // DM8000
00137     Brcm7401 V0.0  // DM800
00138     MIPS 4KEc V4.8 // DM7025
00139 */
00140 
00141 static const char *cpuinfo_file = "\
00142 system type             : ATI XILLEON HDTV SUPERTOLL\n\
00143 processor               : 0\n\
00144 cpu model               : Brcm4380 V4.2\n\
00145 BogoMIPS                : 297.98\n\
00146 wait instruction        : yes\n\
00147 microsecond timers      : yes\n\
00148 tlb_entries             : 16\n\
00149 extra interrupt vector  : yes\n\
00150 hardware watchpoint     : yes\n\
00151 VCED exceptions         : not available\n\
00152 VCEI exceptions         : not available\n\
00153 ";
00154 
00155 int write_cpuinfo (void) {
00156   static FILE* (*func) (const char *, const char *) = NULL;
00157   func = (FILE* (*) (const char *, const char *)) dlsym (REAL_LIBC, "fopen");
00158   FILE* file = func(CPUINFO_MAP, "w");
00159   
00160   
00161   if(file == NULL) {
00162      printf("error \"%s\" opening file\n", strerror(errno));
00163      return -1;
00164   }
00165   int ret = fwrite(cpuinfo_file, strlen(cpuinfo_file), 1, file);
00166   fclose(file);
00167   return 0;
00168 }
00169 
00170 FILE *fopen(const char *path, const char *mode){
00171   static FILE* (*func) (const char *, const char *) = NULL;
00172   write_cpuinfo();
00173   if (!func) func = (FILE* (*) (const char *, const char *)) dlsym (REAL_LIBC, "fopen");
00174   if (!strcmp(path, CPUINFO_BASE)) {
00175     INF("ca.so fopen %s mapped to %s", path, CPUINFO_MAP);
00176     return (*func) (CPUINFO_MAP, mode);
00177   } // if
00178   DBG(">>>>>>>> fopen %s", path);
00179   return (*func) (path, mode);
00180 } // fopen
00181                                                   
00182 int open (const char *pathname, int flags, ...) {
00183   static int (*func) (const char *, int, mode_t) = NULL;
00184   if (!func) func = (int (*) (const char *, int, mode_t)) dlsym (REAL_LIBC, "open");
00185   PROGINFO();
00186   
00187   va_list args;
00188   mode_t mode;
00189 
00190   va_start (args, flags);
00191   mode = va_arg (args, mode_t);
00192   va_end (args);
00193 
00194   if(strstr(pathname, CA_BASE)) {
00195     int cai=pathname[strlen(CA_BASE)]-'0';
00196     if((cai >= 0) && (cai < MAX_CA)) {
00197       DBG(">>>>>>>> open cafd[%d] flags %d %s (%d)", cai, flags, pathname, cafdc[cai]);
00198       if(cafd[cai]==-1) {
00199         cafd[cai] = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
00200         if(cafd[cai]==-1) {
00201           ERR("Failed to open socket (%d)", errno);
00202         } else {
00203           struct sockaddr_in saddr;
00204           fcntl(cafd[cai],F_SETFL,O_NONBLOCK);
00205           bzero(&saddr,sizeof(saddr));
00206           saddr.sin_family = AF_INET;
00207           saddr.sin_port = htons(PORT);
00208           saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
00209           int r = connect(cafd[cai], (struct sockaddr *) &saddr, sizeof(saddr));
00210           if (r<0) {
00211             ERR("Failed to connect socket (%d)", errno);
00212             close(cafd[cai]);
00213             cafd[cai]=-1;
00214           } // if
00215         } // if
00216       } // if
00217       if(cafd[cai]!=-1) 
00218         cafdc[cai]++;
00219       else 
00220         cafdc[cai] = 0;
00221       return (cafd[cai]);
00222     } // if      
00223   } else if (strstr(pathname, DEMUX_BASE)) {
00224     int cai=pathname[strlen(DEMUX_BASE)]-'0';
00225     if((cai >= 0) && (cai < MAX_CA)) {
00226       char dest[256];
00227       sprintf(dest, DEMUX_MAP, cai);
00228       DBG(">>>>>>>> open %s mapped to %s", pathname, dest);
00229       return (*func) (dest, flags, mode);
00230     } // if
00231   } // if
00232   DBG(">>>>>>>> open %s", pathname);
00233   return (*func) (pathname, flags, mode);
00234 } // open
00235 
00236 int ioctl (int fd, int request, void *a) {
00237   static int (*func) (int, int, void *) = NULL;
00238   if (!func) func = (int (*) (int, int, void *)) dlsym (REAL_LIBC, "ioctl");
00239   int i;
00240   for(i=0;i<MAX_CA;i++)
00241     if (fd == cafd[i])
00242       return cactl (fd, i, request, a);
00243   return (*func) (fd, request, a); 
00244 } // ioctl
00245 
00246 int close (int fd) {
00247   static int (*func) (int) = NULL;
00248   if (!func) func = (int (*) (int)) dlsym (REAL_LIBC, "close");
00249   int i;
00250   for(i=0;i<MAX_CA;i++) {
00251     if (fd == cafd[i]) {
00252       DBG(">>>>>>>> close cafd[%d] (%d)", i, cafdc[i]);
00253       if(--cafdc[i]) return 0;
00254       cafd[i] = -1;
00255     } // if
00256   } // for
00257   return (*func) (fd);
00258 } // close
00259 
00260 #endif
00261 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines