[1016] | 1 | /*
|
---|
| 2 | *
|
---|
| 3 | * This program is free software; you can redistribute it and/or modify
|
---|
| 4 | * it under the terms of the GNU General Public License as published by
|
---|
| 5 | * the Free Software Foundation; either version 2 of the License, or
|
---|
| 6 | * (at your option) any later version.
|
---|
| 7 | *
|
---|
| 8 | * This program is distributed in the hope that it will be useful,
|
---|
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 11 | * GNU General Public License for more details.
|
---|
| 12 | *
|
---|
| 13 | * You should have received a copy of the GNU General Public License
|
---|
| 14 | * along with this program; if not, write to the Free Software
|
---|
| 15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
| 16 | *
|
---|
| 17 | */
|
---|
| 18 |
|
---|
| 19 | #ifdef HAVE_DVBAPI_3
|
---|
| 20 |
|
---|
| 21 | #include <errno.h>
|
---|
| 22 | #include <fcntl.h>
|
---|
| 23 | #include <stdio.h>
|
---|
| 24 | #include <stdlib.h>
|
---|
| 25 | #include <string.h>
|
---|
| 26 | #include <sys/ioctl.h>
|
---|
| 27 | #include <sys/poll.h>
|
---|
| 28 | #include <sys/socket.h>
|
---|
| 29 | #include <sys/types.h>
|
---|
| 30 | #include <sys/un.h>
|
---|
| 31 | #include <unistd.h>
|
---|
| 32 |
|
---|
| 33 | #include "globals.h"
|
---|
| 34 |
|
---|
| 35 | #include <linux/dvb/ca.h>
|
---|
| 36 | #include <linux/dvb/dmx.h>
|
---|
| 37 |
|
---|
| 38 | #define CADEV "/dev/dvb/adapter0/ca1"
|
---|
| 39 | #define DMXDEV "/dev/dvb/adapter0/demux0"
|
---|
| 40 | #define CAMDSOCKET "/tmp/camd.socket"
|
---|
| 41 |
|
---|
| 42 | #define BUFSIZE 1024
|
---|
| 43 | #define MAX_CAID 50
|
---|
| 44 |
|
---|
| 45 | typedef struct ca_descriptor_s
|
---|
| 46 | {
|
---|
| 47 | unsigned char descriptor_tag : 8;
|
---|
| 48 | unsigned char descriptor_length : 8;
|
---|
| 49 | unsigned short ca_system_id : 16;
|
---|
| 50 | unsigned char reserved : 3;
|
---|
| 51 | unsigned short ca_pid : 13;
|
---|
| 52 | unsigned char * private_data_byte;
|
---|
| 53 | } __attribute__ ((packed)) ca_descriptor;
|
---|
| 54 |
|
---|
| 55 | typedef struct ca_pmt_program_info_s
|
---|
| 56 | {
|
---|
| 57 | unsigned char ca_pmt_cmd_id : 8;
|
---|
| 58 | ca_descriptor * descriptor;
|
---|
| 59 | } __attribute__ ((packed)) ca_pmt_program_info;
|
---|
| 60 |
|
---|
| 61 | typedef struct ca_pmt_es_info_s
|
---|
| 62 | {
|
---|
| 63 | unsigned char stream_type : 8;
|
---|
| 64 | unsigned char reserved : 3;
|
---|
| 65 | unsigned short elementary_pid : 13;
|
---|
| 66 | unsigned char reserved2 : 4;
|
---|
| 67 | unsigned short es_info_length : 12;
|
---|
| 68 | ca_pmt_program_info * program_info;
|
---|
| 69 | } __attribute__ ((packed)) ca_pmt_es_info;
|
---|
| 70 |
|
---|
| 71 | typedef struct ca_pmt_s
|
---|
| 72 | {
|
---|
| 73 | unsigned char ca_pmt_list_management : 8;
|
---|
| 74 | unsigned short program_number : 16;
|
---|
| 75 | unsigned char reserved1 : 2;
|
---|
| 76 | unsigned char version_number : 5;
|
---|
| 77 | unsigned char current_next_indicator : 1;
|
---|
| 78 | unsigned char reserved2 : 4;
|
---|
| 79 | unsigned short program_info_length : 12;
|
---|
| 80 | ca_pmt_program_info * program_info;
|
---|
| 81 | ca_pmt_es_info * es_info;
|
---|
| 82 | } __attribute__ ((packed)) ca_pmt;
|
---|
| 83 |
|
---|
| 84 | static int camfd = -1;
|
---|
| 85 | static int dmxfd_ecm = -1;
|
---|
| 86 | static int dmxfd_emm = -1;
|
---|
| 87 | static int listenfd = -1;
|
---|
| 88 |
|
---|
| 89 | // if set descrabling
|
---|
| 90 | unsigned short global_capid=0;
|
---|
| 91 | unsigned short global_caid=0;
|
---|
| 92 | unsigned short global_emmpid=0;
|
---|
| 93 |
|
---|
| 94 | unsigned short global_caid_list[MAX_CAID];
|
---|
| 95 |
|
---|
| 96 | unsigned short prg_nr=0;
|
---|
| 97 |
|
---|
| 98 | unsigned char buffer_cache_dmx[12];
|
---|
| 99 | unsigned char buffer_cache_capmt[12];
|
---|
| 100 |
|
---|
| 101 | unsigned char lastcw0[8], lastcw1[8];
|
---|
| 102 |
|
---|
| 103 | typedef struct ECMPIDS
|
---|
| 104 | {
|
---|
| 105 | int CA_PID;
|
---|
| 106 | int CA_System_ID;
|
---|
| 107 | } ECMPIDSTYPE;
|
---|
| 108 |
|
---|
| 109 | ECMPIDSTYPE ECMpids[20];
|
---|
| 110 | int ECMpidcount=0;
|
---|
| 111 |
|
---|
| 112 | unsigned short dvbapi_get_single_ecm(int caid, int pid, unsigned char filt, unsigned char mask)
|
---|
| 113 | {
|
---|
| 114 | unsigned char buf[BUFSIZE];
|
---|
| 115 | int dmx_fd, len;
|
---|
| 116 |
|
---|
| 117 | struct dmx_sct_filter_params sFP;
|
---|
| 118 |
|
---|
| 119 | memset(&sFP, 0, sizeof(sFP));
|
---|
| 120 |
|
---|
| 121 | memset(buf,0,BUFSIZE);
|
---|
| 122 |
|
---|
| 123 |
|
---|
| 124 |
|
---|
| 125 | sFP.pid = pid;
|
---|
| 126 | sFP.timeout = 1000;
|
---|
| 127 | sFP.flags = DMX_ONESHOT | DMX_CHECK_CRC | DMX_IMMEDIATE_START;
|
---|
| 128 | sFP.filter.filter[0] = filt;
|
---|
| 129 | sFP.filter.mask[0] = mask;
|
---|
| 130 |
|
---|
| 131 | if ((dmx_fd = open(DMXDEV, O_RDWR)) < 0)
|
---|
| 132 | return 0;
|
---|
| 133 |
|
---|
| 134 | if (ioctl(dmx_fd, DMX_SET_FILTER, &sFP) < 0)
|
---|
| 135 | return 0;
|
---|
| 136 |
|
---|
| 137 | len=read(dmx_fd, buf, BUFSIZE);
|
---|
| 138 |
|
---|
| 139 | close(dmx_fd);
|
---|
| 140 |
|
---|
| 141 | ECM_REQUEST *er;
|
---|
| 142 |
|
---|
| 143 | if (!(er=get_ecmtask()))
|
---|
| 144 | return 0;
|
---|
| 145 |
|
---|
| 146 | er->srvid = prg_nr;
|
---|
| 147 | er->caid = caid;
|
---|
| 148 | er->pid=pid;
|
---|
| 149 | //er->prid = provid; //FIXME
|
---|
| 150 |
|
---|
| 151 | er->l=len;
|
---|
| 152 | memcpy(er->ecm, buf, er->l);
|
---|
| 153 |
|
---|
| 154 | get_cw(er);
|
---|
| 155 |
|
---|
| 156 | return 0;
|
---|
| 157 | }
|
---|
| 158 |
|
---|
| 159 | unsigned short dvbapi_parse_cat(unsigned short ca_system_id)
|
---|
| 160 | {
|
---|
| 161 | unsigned char buf[BUFSIZE];
|
---|
| 162 | unsigned short i, emmpid;
|
---|
| 163 | int dmx_fd, len;
|
---|
| 164 |
|
---|
| 165 | struct dmx_sct_filter_params sFP;
|
---|
| 166 |
|
---|
| 167 | memset(&sFP, 0, sizeof(sFP));
|
---|
| 168 |
|
---|
| 169 | memset(buf,0,BUFSIZE);
|
---|
| 170 |
|
---|
| 171 | sFP.filter.filter[0] = 0x01;
|
---|
| 172 | sFP.filter.mask[0] = 0xFF;
|
---|
| 173 | sFP.flags = DMX_ONESHOT | DMX_CHECK_CRC | DMX_IMMEDIATE_START;
|
---|
| 174 | sFP.pid = 0x0001;
|
---|
| 175 | sFP.timeout = 3000; //3secs
|
---|
| 176 |
|
---|
| 177 | if ((dmx_fd = open(DMXDEV, O_RDWR)) < 0)
|
---|
| 178 | return 0;
|
---|
| 179 |
|
---|
| 180 | if (ioctl(dmx_fd, DMX_SET_FILTER, &sFP) < 0)
|
---|
| 181 | return 0;
|
---|
| 182 |
|
---|
| 183 | len=read(dmx_fd, buf, BUFSIZE);
|
---|
| 184 |
|
---|
| 185 | close(dmx_fd);
|
---|
| 186 |
|
---|
| 187 | for (i = 8; i < (((buf[1] & 0x0F) << 8) | buf[2]) - 1; i += buf[i + 1] + 2)
|
---|
| 188 | {
|
---|
| 189 | if ((buf[i] == 0x09) && ((((buf[i + 2] & 0x1F) << 8) | buf[i + 3]) == ca_system_id))
|
---|
| 190 | {
|
---|
| 191 | emmpid=(((buf[i + 4] & 0x1F) << 8) | buf[i + 5]);
|
---|
| 192 | return emmpid;
|
---|
| 193 | }
|
---|
| 194 | }
|
---|
| 195 |
|
---|
| 196 | return 0;
|
---|
| 197 | }
|
---|
| 198 |
|
---|
| 199 | int dvbapi_stop_filter(void)
|
---|
| 200 | {
|
---|
| 201 | //cs_log("Stopping filtering...");
|
---|
| 202 |
|
---|
| 203 | if (ioctl(dmxfd_ecm,DMX_STOP)<0)
|
---|
| 204 | return 0;
|
---|
| 205 |
|
---|
| 206 | if (ioctl(dmxfd_emm,DMX_STOP)<0)
|
---|
| 207 | return 0;
|
---|
| 208 |
|
---|
| 209 | return 1;
|
---|
| 210 | }
|
---|
| 211 |
|
---|
| 212 | unsigned short dvbapi_parse_ecm(unsigned char *buf, int len)
|
---|
| 213 | {
|
---|
| 214 | unsigned short provid;
|
---|
| 215 |
|
---|
| 216 | provid=(buf[3]<<8)|buf[4];
|
---|
| 217 | cs_debug("Read %d bytes\tTable-id: %02x\tCA section length: %d\tProvider ID: %04x", len, buf[0], len ,provid);
|
---|
| 218 |
|
---|
| 219 | //calen=((buf[1]<<8)+buf[2])&0x0fff;
|
---|
| 220 |
|
---|
| 221 | /*
|
---|
| 222 | provid=b2i(2, buf+3);
|
---|
| 223 |
|
---|
| 224 | i=(buf[4]==0xD2) ? buf[5] + 2 : 0; // skip d2 nano
|
---|
| 225 | if ((buf[5+i]==3) && ((buf[4+i]==0x90) || (buf[4+i]==0x40)))
|
---|
| 226 | provid=(b2i(3, buf+6+i) & 0xFFFFF0);
|
---|
| 227 |
|
---|
| 228 | //cs_log("PROVIDER: %04x", provid);
|
---|
| 229 | */
|
---|
| 230 |
|
---|
| 231 | if (len>0) {
|
---|
| 232 | ECM_REQUEST *er;
|
---|
| 233 |
|
---|
| 234 | if (!(er=get_ecmtask()))
|
---|
| 235 | return 0;
|
---|
| 236 |
|
---|
| 237 | er->srvid = prg_nr;
|
---|
| 238 | er->caid = global_caid;
|
---|
| 239 | //er->prid = provid; //FIXME
|
---|
| 240 |
|
---|
| 241 | er->l=len;
|
---|
| 242 | memcpy(er->ecm, buf, er->l);
|
---|
| 243 |
|
---|
| 244 | get_cw(er);
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 | return(provid);
|
---|
| 248 | }
|
---|
| 249 |
|
---|
| 250 | int dvbapi_set_filter(int fd, int pid, unsigned char filt, unsigned char mask)
|
---|
| 251 | {
|
---|
| 252 | struct dmx_sct_filter_params sFP;
|
---|
| 253 | cs_debug("Set filter pid:%d, value:%d...",pid, filt);
|
---|
| 254 |
|
---|
| 255 | memset(&sFP,0,sizeof(sFP));
|
---|
| 256 |
|
---|
| 257 | sFP.pid = pid;
|
---|
| 258 | sFP.timeout = 3000; //wait max 3 seconds for ECM message, should be repeated every 500ms
|
---|
| 259 | sFP.flags = DMX_CHECK_CRC | DMX_IMMEDIATE_START;
|
---|
| 260 | sFP.filter.filter[0] = filt;
|
---|
| 261 | sFP.filter.mask[0] = mask;
|
---|
| 262 |
|
---|
| 263 | if (ioctl(fd, DMX_SET_FILTER, &sFP) < 0)
|
---|
| 264 | {
|
---|
| 265 | perror(" Status");
|
---|
| 266 | return 0;
|
---|
| 267 | }
|
---|
| 268 |
|
---|
| 269 | return 1;
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | void dvbapi_stop_descramble()
|
---|
| 273 | {
|
---|
| 274 | dvbapi_stop_filter();
|
---|
| 275 |
|
---|
| 276 | /*
|
---|
| 277 | if (global_capid != 0) {
|
---|
| 278 | // unset pid?? (not working)
|
---|
| 279 | ca_pid_t ca_pid;
|
---|
| 280 | memset(&ca_pid,0,sizeof(ca_pid));
|
---|
| 281 | ca_pid.pid = global_capid;
|
---|
| 282 | ca_pid.index = -1;
|
---|
| 283 | //if (ioctl(camfd, CA_SET_PID, &ca_pid)==-1) perror("Error Remove SET_PID");
|
---|
| 284 | }
|
---|
| 285 | */
|
---|
| 286 |
|
---|
| 287 | global_capid=0;
|
---|
| 288 | global_caid=0;
|
---|
| 289 | global_emmpid=0;
|
---|
| 290 | }
|
---|
| 291 |
|
---|
| 292 | void dvbapi_start_descramble(int caid, int capid) {
|
---|
| 293 |
|
---|
| 294 | cs_log("Softcam: Start descrambling CAID: %04x", caid);
|
---|
| 295 |
|
---|
| 296 | if (!dvbapi_set_filter(dmxfd_ecm,capid,0x80,0xF0)) //filter on ECM pid and 0x80 or 0x81 (mask 0xF0)
|
---|
| 297 | cs_log("Error ECM filtering");
|
---|
| 298 |
|
---|
| 299 | global_capid=capid;
|
---|
| 300 | global_caid=caid;
|
---|
| 301 |
|
---|
| 302 | /*
|
---|
| 303 | * get emm pid and start filter
|
---|
| 304 | * TODO: prase_cat blocks thread */
|
---|
| 305 |
|
---|
| 306 | if (cfg->dvbapi_au==1) {
|
---|
| 307 | short emmpid;
|
---|
| 308 | emmpid=dvbapi_parse_cat(caid);
|
---|
| 309 |
|
---|
| 310 | cs_log("EMMPid: %04x", emmpid);
|
---|
| 311 | dvbapi_set_filter(dmxfd_emm,emmpid,0x80,0xF0);
|
---|
| 312 | global_emmpid=emmpid;
|
---|
| 313 | }
|
---|
| 314 |
|
---|
| 315 | ca_pid_t ca_pid;
|
---|
| 316 | memset(&ca_pid,0,sizeof(ca_pid));
|
---|
| 317 | ca_pid.pid = capid;
|
---|
| 318 | ca_pid.index = 0;
|
---|
| 319 | if (ioctl(camfd, CA_SET_PID, &ca_pid)==-1)
|
---|
| 320 | cs_log("Softcam: Error SET_PID");
|
---|
| 321 | }
|
---|
| 322 |
|
---|
| 323 | // from tuxbox camd
|
---|
| 324 | int dvbapi_parse_capmt(unsigned char *buffer, const unsigned int length)
|
---|
| 325 |
|
---|
| 326 | {
|
---|
| 327 | unsigned short i, j;
|
---|
| 328 | ca_pmt *pmt;
|
---|
| 329 | int n;
|
---|
| 330 |
|
---|
| 331 | cs_dump(buffer, length, "capmt:");
|
---|
| 332 | pmt = (ca_pmt *) malloc(sizeof(ca_pmt));
|
---|
| 333 |
|
---|
| 334 | pmt->ca_pmt_list_management = buffer[0];
|
---|
| 335 | pmt->program_number = (buffer[1] << 8) | buffer[2];
|
---|
| 336 | prg_nr=pmt->program_number;
|
---|
| 337 |
|
---|
| 338 | pmt->program_info_length = ((buffer[4] & 0x0F) << 8) | buffer[5];
|
---|
| 339 |
|
---|
| 340 | cs_log("program number: %04x", pmt->program_number);
|
---|
| 341 | cs_debug("program_info_length: %d", pmt->program_info_length);
|
---|
| 342 |
|
---|
| 343 | switch (pmt->ca_pmt_list_management)
|
---|
| 344 | {
|
---|
| 345 | case 0x01:
|
---|
| 346 | //FIXME?? (first)
|
---|
| 347 | break;
|
---|
| 348 | case 0x03:
|
---|
| 349 | //default (only)
|
---|
| 350 | break;
|
---|
| 351 | default:
|
---|
| 352 | //FIXME?? (unknown)
|
---|
| 353 | break;
|
---|
| 354 | }
|
---|
| 355 |
|
---|
| 356 | ECMpidcount=0;
|
---|
| 357 |
|
---|
| 358 | //CA_PIDS fr alle Streams
|
---|
| 359 | if (pmt->program_info_length != 0)
|
---|
| 360 | {
|
---|
| 361 | pmt->program_info = (ca_pmt_program_info *) malloc(sizeof(ca_pmt_program_info));
|
---|
| 362 | pmt->program_info->ca_pmt_cmd_id = buffer[6];
|
---|
| 363 | //cs_debug("ca_pmt_id: %04x", pmt->program_info->ca_pmt_cmd_id);
|
---|
| 364 | pmt->program_info->descriptor = (ca_descriptor *) malloc(sizeof(ca_descriptor));
|
---|
| 365 |
|
---|
| 366 | for (i = 0; i < pmt->program_info_length - 1; i += pmt->program_info->descriptor->descriptor_length + 2)
|
---|
| 367 | {
|
---|
| 368 | pmt->program_info->descriptor->descriptor_length = buffer[i + 8];
|
---|
| 369 | pmt->program_info->descriptor->ca_system_id = (buffer[i + 9] << 8) | buffer[i + 10];
|
---|
| 370 | pmt->program_info->descriptor->ca_pid = ((buffer[i + 11] & 0x1F) << 8)| buffer[i + 12];
|
---|
| 371 |
|
---|
| 372 | cs_debug("typ: %02x ca_system_id: %04x\t ca_pid: %04x\tca_descriptor_length %d", buffer[i + 7], pmt->program_info->descriptor->ca_system_id, pmt->program_info->descriptor->ca_pid,pmt->program_info->descriptor->descriptor_length);
|
---|
| 373 |
|
---|
| 374 | if (buffer[i + 7] == 0x09) {
|
---|
| 375 | ECMpids[ECMpidcount].CA_PID=pmt->program_info->descriptor->ca_pid; //add the PID
|
---|
| 376 | ECMpids[ECMpidcount].CA_System_ID=pmt->program_info->descriptor->ca_system_id; //add the system id
|
---|
| 377 | ECMpidcount++;
|
---|
| 378 | }
|
---|
| 379 | }
|
---|
| 380 |
|
---|
| 381 | free(pmt->program_info->descriptor);
|
---|
| 382 | free(pmt->program_info);
|
---|
| 383 | }
|
---|
| 384 |
|
---|
| 385 |
|
---|
| 386 | //CA_PIDs fr einzelne Streams
|
---|
| 387 | //
|
---|
| 388 | pmt->es_info = (ca_pmt_es_info *) malloc(sizeof(ca_pmt_es_info));
|
---|
| 389 |
|
---|
| 390 | for (i = pmt->program_info_length + 6; i < length; i += pmt->es_info->es_info_length + 5)
|
---|
| 391 | {
|
---|
| 392 |
|
---|
| 393 | pmt->es_info->stream_type = buffer[i];
|
---|
| 394 | pmt->es_info->elementary_pid = ((buffer[i + 1] & 0x1F) << 8) | buffer[i + 2];
|
---|
| 395 | pmt->es_info->es_info_length = ((buffer[i + 3] & 0x0F) << 8) | buffer[i + 4];
|
---|
| 396 |
|
---|
| 397 | cs_debug("stream_type: %02x\telementary_pid: %04x\tes_info_length: %04x", pmt->es_info->stream_type, pmt->es_info->elementary_pid, pmt->es_info->es_info_length);
|
---|
| 398 |
|
---|
| 399 | if (pmt->es_info->es_info_length != 0)
|
---|
| 400 | {
|
---|
| 401 | pmt->es_info->program_info = (ca_pmt_program_info *) malloc(sizeof(ca_pmt_program_info));
|
---|
| 402 |
|
---|
| 403 | pmt->es_info->program_info->ca_pmt_cmd_id = buffer[i + 5];
|
---|
| 404 | pmt->es_info->program_info->descriptor = (ca_descriptor *)malloc(sizeof(ca_descriptor));
|
---|
| 405 |
|
---|
| 406 | for (j = 0; j < pmt->es_info->es_info_length - 1; j += pmt->es_info->program_info->descriptor->descriptor_length + 2)
|
---|
| 407 | {
|
---|
| 408 | pmt->es_info->program_info->descriptor->descriptor_length = buffer[i + j + 7];
|
---|
| 409 | pmt->es_info->program_info->descriptor->ca_system_id = (buffer[i + j + 8] << 8) | buffer[i + j + 9];
|
---|
| 410 | pmt->es_info->program_info->descriptor->ca_pid = ((buffer[i + j + 10] & 0x1F) << 8) | buffer[i + j + 11];
|
---|
| 411 |
|
---|
| 412 | cs_debug("typ: %02x\tca_system_id: %04x\t ca_pid: %04x", buffer[i + j + 6], pmt->es_info->program_info->descriptor->ca_system_id, pmt->es_info->program_info->descriptor->ca_pid);
|
---|
| 413 |
|
---|
| 414 | if (buffer[i + j + 6] == 0x09) {
|
---|
| 415 | ECMpids[ECMpidcount].CA_PID=pmt->program_info->descriptor->ca_pid; //add the PID
|
---|
| 416 | ECMpids[ECMpidcount].CA_System_ID=pmt->program_info->descriptor->ca_system_id; //add the system id
|
---|
| 417 | ECMpidcount++;
|
---|
| 418 | }
|
---|
| 419 | }
|
---|
| 420 |
|
---|
| 421 | free(pmt->es_info->program_info->descriptor);
|
---|
| 422 | free(pmt->es_info->program_info);
|
---|
| 423 | }
|
---|
| 424 | }
|
---|
| 425 |
|
---|
| 426 | free(pmt->es_info);
|
---|
| 427 | free(pmt);
|
---|
| 428 |
|
---|
| 429 | dvbapi_stop_descramble();
|
---|
| 430 |
|
---|
| 431 | cs_log("Softcam: Found %d ECMpids in PMT", ECMpidcount);
|
---|
| 432 |
|
---|
| 433 | for (n=0; n<ECMpidcount; n++) {
|
---|
| 434 |
|
---|
| 435 | cs_debug("CA_System_ID: %04x CA_PID: %04x", ECMpids[n].CA_System_ID, ECMpids[n].CA_PID);
|
---|
| 436 |
|
---|
| 437 | if (global_caid!=0) continue;
|
---|
| 438 |
|
---|
| 439 | dvbapi_get_single_ecm(ECMpids[n].CA_System_ID,ECMpids[n].CA_PID,0x80,0xF0);
|
---|
| 440 | sleep(3);
|
---|
| 441 | }
|
---|
| 442 |
|
---|
| 443 | return 0;
|
---|
| 444 | }
|
---|
| 445 |
|
---|
| 446 | void dvbapi_handlesockmsg (unsigned char *buffer, ssize_t len)
|
---|
| 447 | {
|
---|
| 448 | int i;
|
---|
| 449 | unsigned int val;
|
---|
| 450 | unsigned int size;
|
---|
| 451 | //cs_dump(buffer, len, "handlesockmsg:");
|
---|
| 452 |
|
---|
| 453 | if (buffer[0] != 0x9F) {
|
---|
| 454 | cs_log("handlesockmsg() unknown socket command: %02x", buffer[0]);
|
---|
| 455 | return;
|
---|
| 456 | }
|
---|
| 457 |
|
---|
| 458 | if (buffer[1] != 0x80) {
|
---|
| 459 | cs_log("handlesockmsg() unknown apdu tag");
|
---|
| 460 | return;
|
---|
| 461 | }
|
---|
| 462 |
|
---|
| 463 |
|
---|
| 464 | if (buffer[3] & 0x80) {
|
---|
| 465 | val = 0;
|
---|
| 466 | size = buffer[3] & 0x7F;
|
---|
| 467 | for (i = 0; i < size; i++)
|
---|
| 468 | val = (val << 8) | buffer[i + 1 + 3];
|
---|
| 469 | size++;
|
---|
| 470 | } else
|
---|
| 471 | {
|
---|
| 472 | val = buffer[3] & 0x7F;
|
---|
| 473 | size = 1;
|
---|
| 474 | }
|
---|
| 475 |
|
---|
| 476 | if (buffer[2] == 0x30) // ca_info_enq
|
---|
| 477 | cs_debug("ca_info!!");
|
---|
| 478 | else if (buffer[2] == 0x32) // ca_pmt
|
---|
| 479 | {
|
---|
| 480 | if ((3 + size + val) == len)
|
---|
| 481 | dvbapi_parse_capmt(buffer + 3 + size, val);
|
---|
| 482 | else
|
---|
| 483 | cs_log("handlesockmsg() ca_pmt invalid length");
|
---|
| 484 | }
|
---|
| 485 | else if (buffer[2] == 0x3f)
|
---|
| 486 | {
|
---|
| 487 | //9F 80 3f 04 83 02 00 00
|
---|
| 488 | //zap?
|
---|
| 489 | //cs_debug("zap!");
|
---|
| 490 | } else
|
---|
| 491 | {
|
---|
| 492 | cs_log("client: handlesockmsg() unknown command");
|
---|
| 493 | cs_dump(buffer, len, "unknown command:");
|
---|
| 494 | }
|
---|
| 495 | }
|
---|
| 496 |
|
---|
| 497 | static int dvbapi_init_listenfd() {
|
---|
| 498 |
|
---|
| 499 | int clilen;
|
---|
| 500 | struct sockaddr_un servaddr;
|
---|
| 501 |
|
---|
| 502 | memset(&servaddr, 0, sizeof(struct sockaddr_un));
|
---|
| 503 | servaddr.sun_family = AF_UNIX;
|
---|
| 504 | strcpy(servaddr.sun_path, cfg->dvbapi_socket);
|
---|
| 505 | clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path);
|
---|
| 506 |
|
---|
| 507 | if ((unlink(cfg->dvbapi_socket) < 0) && (errno != ENOENT))
|
---|
| 508 | return 0;
|
---|
| 509 | if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
---|
| 510 | return 0;
|
---|
| 511 | if (bind(listenfd, (struct sockaddr *) &servaddr, clilen) < 0)
|
---|
| 512 | return 0;
|
---|
| 513 | if (listen(listenfd, 5) < 0)
|
---|
| 514 | return 0;
|
---|
| 515 |
|
---|
| 516 | return 1;
|
---|
| 517 | }
|
---|
| 518 |
|
---|
| 519 | void *thread_check_zap(void *arg) {
|
---|
| 520 | unsigned char buffer[BUFSIZE];
|
---|
| 521 | struct sockaddr_un servaddr;
|
---|
| 522 | ssize_t len;
|
---|
| 523 | int connfd,clilen;
|
---|
| 524 |
|
---|
| 525 | while(1)
|
---|
| 526 | {
|
---|
| 527 | sleep(1); // check every second
|
---|
| 528 | //cs_log("check zap");
|
---|
| 529 |
|
---|
| 530 |
|
---|
| 531 |
|
---|
| 532 | connfd = accept(listenfd, (struct sockaddr *)&servaddr, (socklen_t *)&clilen);
|
---|
| 533 |
|
---|
| 534 | if (connfd <= 0) //socket not available
|
---|
| 535 | break;
|
---|
| 536 |
|
---|
| 537 | len = read(connfd, buffer, sizeof(buffer));
|
---|
| 538 |
|
---|
| 539 | if (len < 3) {
|
---|
| 540 | cs_debug("Client: camd.socket: too short message received");
|
---|
| 541 | break;
|
---|
| 542 | }
|
---|
| 543 |
|
---|
| 544 | // if message begins with an apdu_tag and is longer than three bytes
|
---|
| 545 | if ((buffer[0] == 0x9F) && ((buffer[1] >> 7) == 0x01) && ((buffer[2] >> 7) == 0x00)) {
|
---|
| 546 | if (memcmp(buffer, buffer_cache_capmt, 8) != 0) {
|
---|
| 547 | memcpy(buffer_cache_capmt, buffer, 8);
|
---|
| 548 | dvbapi_handlesockmsg(buffer, len);
|
---|
| 549 | }
|
---|
| 550 | }
|
---|
| 551 |
|
---|
| 552 | close(connfd);
|
---|
| 553 |
|
---|
| 554 | }
|
---|
| 555 | return 0;
|
---|
| 556 | }
|
---|
| 557 |
|
---|
| 558 | void *thread_check_dmx(void *arg) {
|
---|
| 559 |
|
---|
| 560 | struct pollfd pfd2[2];
|
---|
| 561 | int rc,len,i;
|
---|
| 562 | unsigned char buffer[BUFSIZE];
|
---|
| 563 |
|
---|
| 564 | pfd2[0].fd = dmxfd_ecm;
|
---|
| 565 | pfd2[0].events = (POLLIN | POLLPRI);
|
---|
| 566 | pfd2[1].fd = dmxfd_emm;
|
---|
| 567 | pfd2[1].events = (POLLIN | POLLPRI);
|
---|
| 568 |
|
---|
| 569 | while(1)
|
---|
| 570 | {
|
---|
| 571 |
|
---|
| 572 | rc=poll(pfd2, 2, -1);
|
---|
| 573 |
|
---|
| 574 | if (global_capid == 0) {
|
---|
| 575 | dvbapi_stop_filter();
|
---|
| 576 | break;
|
---|
| 577 | }
|
---|
| 578 |
|
---|
| 579 | for (i = 0; i < 2; i++) {
|
---|
| 580 | if (pfd2[i].revents & (POLLIN | POLLPRI)) {
|
---|
| 581 | if (pfd2[i].fd == dmxfd_ecm) {
|
---|
| 582 | if ((len = read(dmxfd_ecm, buffer, BUFSIZE)) <= 0)
|
---|
| 583 | break;
|
---|
| 584 |
|
---|
| 585 | if (len != (((buffer[1] & 0xf) << 8) | buffer[2]) + 3) //invaild CAT length
|
---|
| 586 | break;
|
---|
| 587 |
|
---|
| 588 | if (buffer[0] == 0x80 | buffer[0] == 0x81)
|
---|
| 589 | {
|
---|
| 590 | if (memcmp(buffer, buffer_cache_dmx, 12) != 0) {
|
---|
| 591 | memcpy(buffer_cache_dmx, buffer, 12);
|
---|
| 592 | if (!dvbapi_parse_ecm(buffer,len)) { cs_log("Error while parsing ECM"); }
|
---|
| 593 | }
|
---|
| 594 | }
|
---|
| 595 |
|
---|
| 596 | }
|
---|
| 597 |
|
---|
| 598 | if (pfd2[i].fd == dmxfd_emm) {
|
---|
| 599 | if ((len = read(dmxfd_emm, buffer, BUFSIZE)) <= 0)
|
---|
| 600 | break;
|
---|
| 601 |
|
---|
| 602 | if (len != (((buffer[1] & 0xf) << 8) | buffer[2]) + 3) //invaild CAT length
|
---|
| 603 | break;
|
---|
| 604 |
|
---|
| 605 | /*
|
---|
| 606 | //nagra only???
|
---|
| 607 | int emmtype;
|
---|
| 608 | if( (buffer[0]==0x82) ) emmtype = 0; // U
|
---|
| 609 | if( (buffer[0]==0x83) && (buffer[7]==0x10) ) emmtype = 1; // S
|
---|
| 610 | if( (buffer[0]==0x83) && (buffer[7]==0x00) ) emmtype = 2; // G
|
---|
| 611 |
|
---|
| 612 |
|
---|
| 613 | */
|
---|
| 614 | cs_log("EMM Type: 0x%02x", buffer[0]);
|
---|
| 615 |
|
---|
| 616 | //force emm output
|
---|
| 617 | reader[ridx].logemm=9999;
|
---|
| 618 |
|
---|
| 619 | memset(&epg, 0, sizeof(epg));
|
---|
| 620 |
|
---|
| 621 | epg.caid[0] = (uchar)(global_caid>>8);
|
---|
| 622 | epg.caid[1] = (uchar)(global_caid);
|
---|
| 623 | if (reader[client[cs_idx].au].caid[0]!=b2i(2,epg.caid)) cs_log("caid %04x", b2i(2,epg.caid));
|
---|
| 624 | //memcpy(epg.provid, prov, 4);
|
---|
| 625 |
|
---|
| 626 | epg.l=len;
|
---|
| 627 | memcpy(epg.emm, buffer, epg.l);
|
---|
| 628 | memcpy(epg.hexserial, reader[client[cs_idx].au].hexserial, 8);
|
---|
| 629 |
|
---|
| 630 | do_emm(&epg);
|
---|
| 631 |
|
---|
| 632 | }
|
---|
| 633 | }
|
---|
| 634 | }
|
---|
| 635 |
|
---|
| 636 | }
|
---|
| 637 | return 0;
|
---|
| 638 | }
|
---|
| 639 |
|
---|
| 640 | int dvbapi_main_local()
|
---|
| 641 | {
|
---|
| 642 | struct pollfd pfd2[1];
|
---|
| 643 | int i,rc;
|
---|
| 644 | pthread_t p1, p2;
|
---|
| 645 |
|
---|
| 646 |
|
---|
| 647 | if (cfg->dvbapi_demux[0]==0)
|
---|
| 648 | strncpy(cfg->dvbapi_demux, DMXDEV, sizeof(cfg->dvbapi_demux)-1);
|
---|
| 649 |
|
---|
| 650 | if (cfg->dvbapi_ca[0]==0)
|
---|
| 651 | strncpy(cfg->dvbapi_ca, CADEV, sizeof(cfg->dvbapi_ca)-1);
|
---|
| 652 |
|
---|
| 653 | if (cfg->dvbapi_socket[0]==0)
|
---|
| 654 | strncpy(cfg->dvbapi_socket, CAMDSOCKET, sizeof(cfg->dvbapi_socket)-1);
|
---|
| 655 |
|
---|
| 656 | if (cfg->dvbapi_usr[0]==0) {
|
---|
| 657 | //
|
---|
| 658 | }
|
---|
| 659 |
|
---|
| 660 | for (i=0;i<20;i++) //clean ECMpids array
|
---|
| 661 | {
|
---|
| 662 | ECMpids[i].CA_PID = 0;
|
---|
| 663 | ECMpids[i].CA_System_ID = 0;
|
---|
| 664 | }
|
---|
| 665 |
|
---|
| 666 |
|
---|
| 667 | if ((dmxfd_ecm = open(cfg->dvbapi_demux, O_RDWR)) < 0) {
|
---|
| 668 | cs_log("Could not open dmx device");
|
---|
| 669 | return 1;
|
---|
| 670 | }
|
---|
| 671 |
|
---|
| 672 | if ((dmxfd_emm = open(cfg->dvbapi_demux, O_RDWR)) < 0) {
|
---|
| 673 | cs_log("Could not open dmx device");
|
---|
| 674 | return 1;
|
---|
| 675 | }
|
---|
| 676 |
|
---|
| 677 | if ((camfd = open(cfg->dvbapi_ca, O_RDWR)) < 0) {
|
---|
| 678 | cs_log("Could not open ca device");
|
---|
| 679 | return 1;
|
---|
| 680 | }
|
---|
| 681 |
|
---|
| 682 | if (!dvbapi_init_listenfd()) return 1;
|
---|
| 683 |
|
---|
| 684 | pfd2[0].fd = fd_m2c;
|
---|
| 685 | pfd2[0].events = (POLLIN | POLLPRI);
|
---|
| 686 |
|
---|
| 687 | memset(buffer_cache_capmt,0 ,12);
|
---|
| 688 | memset(buffer_cache_dmx,0 ,12);
|
---|
| 689 |
|
---|
| 690 | pthread_create (&p1, NULL, thread_check_zap, NULL);
|
---|
| 691 | pthread_create (&p2, NULL, thread_check_dmx, NULL);
|
---|
| 692 |
|
---|
| 693 | pfd=dmxfd_ecm;
|
---|
| 694 |
|
---|
| 695 | while (1) {
|
---|
| 696 | if (master_pid!=getppid()) {
|
---|
| 697 | cs_log("master died");
|
---|
| 698 | cs_exit(0);
|
---|
| 699 | }
|
---|
| 700 |
|
---|
| 701 | rc=poll(pfd2, 1, 500);
|
---|
| 702 |
|
---|
| 703 | if (rc<0)
|
---|
| 704 | break;
|
---|
| 705 |
|
---|
| 706 | if (pfd2[0].revents & (POLLIN | POLLPRI)) {
|
---|
| 707 | chk_dcw(fd_m2c);
|
---|
| 708 | }
|
---|
| 709 |
|
---|
| 710 | }
|
---|
| 711 | return 0;
|
---|
| 712 | }
|
---|
| 713 |
|
---|
| 714 | static void dvbapi_send_dcw(ECM_REQUEST *er) {
|
---|
| 715 | unsigned char cw_0[8], cw_1[8];
|
---|
| 716 |
|
---|
| 717 | memcpy(cw_0, er->cw, 8);
|
---|
| 718 | memcpy(cw_1, er->cw+8, 8);
|
---|
| 719 |
|
---|
| 720 | ca_descr_t ca_descr;
|
---|
| 721 | memset(&ca_descr,0,sizeof(ca_descr));
|
---|
| 722 |
|
---|
| 723 |
|
---|
| 724 | if (er->rc==0 && global_caid==0)
|
---|
| 725 | {
|
---|
| 726 | dvbapi_start_descramble(er->caid, er->pid);
|
---|
| 727 | }
|
---|
| 728 |
|
---|
| 729 | if (memcmp(cw_0,lastcw0,8))
|
---|
| 730 | {
|
---|
| 731 | ca_descr.index = 0;
|
---|
| 732 | ca_descr.parity = 0;
|
---|
| 733 | memcpy(lastcw0,cw_0,8);
|
---|
| 734 | memcpy(ca_descr.cw,cw_0,8);
|
---|
| 735 | if (ioctl(camfd,CA_SET_DESCR,&ca_descr) < 0) perror("CA_SET_DESCR");
|
---|
| 736 | }
|
---|
| 737 |
|
---|
| 738 | if (memcmp(cw_1,lastcw1,8))
|
---|
| 739 | {
|
---|
| 740 | ca_descr.index = 0;
|
---|
| 741 | ca_descr.parity = 1;
|
---|
| 742 | memcpy(lastcw1,cw_1,8);
|
---|
| 743 | memcpy(ca_descr.cw,cw_1,8);
|
---|
| 744 | if (ioctl(camfd,CA_SET_DESCR,&ca_descr) < 0) perror("CA_SET_DESCR");
|
---|
| 745 | }
|
---|
| 746 |
|
---|
| 747 | }
|
---|
| 748 |
|
---|
| 749 | static void dvbapi_handler(int idx) {
|
---|
| 750 | static struct s_auth *account=0;
|
---|
| 751 |
|
---|
| 752 | if (cfg->dvbapi_enabled != 1) {
|
---|
| 753 | cs_log("client disabled");
|
---|
| 754 | return;
|
---|
| 755 | }
|
---|
| 756 |
|
---|
| 757 | cs_log("client loaded fd=%d", idx);
|
---|
| 758 |
|
---|
| 759 | switch(cs_fork(0, idx))
|
---|
| 760 | {
|
---|
| 761 | case 0: //master
|
---|
| 762 | case -1:
|
---|
| 763 | return;
|
---|
| 764 | default:
|
---|
| 765 | wait4master();
|
---|
| 766 | }
|
---|
| 767 |
|
---|
| 768 | int ok=0;
|
---|
| 769 |
|
---|
| 770 | if( !account )
|
---|
| 771 | {
|
---|
| 772 | client[cs_idx].usr[0]=0;
|
---|
| 773 | for (ok=0, account=cfg->account; (account) && (!ok); account=account->next)
|
---|
| 774 | if( (ok=!strcmp(cfg->dvbapi_usr, account->usr)) )
|
---|
| 775 | break;
|
---|
| 776 | }
|
---|
| 777 |
|
---|
| 778 | cs_auth_client(ok ? account : (struct s_auth *)(-1), "unknown");
|
---|
| 779 |
|
---|
| 780 | dvbapi_main_local();
|
---|
| 781 |
|
---|
| 782 | cs_log("Module client error");
|
---|
| 783 | cs_exit(0);
|
---|
| 784 |
|
---|
| 785 | return;
|
---|
| 786 |
|
---|
| 787 | }
|
---|
| 788 |
|
---|
| 789 | /*
|
---|
| 790 | * protocol structure
|
---|
| 791 | */
|
---|
| 792 |
|
---|
| 793 | void module_dvbapi(struct s_module *ph)
|
---|
| 794 | {
|
---|
| 795 | strcpy(ph->desc, "dvbapi");
|
---|
| 796 | ph->type=MOD_CONN_SERIAL;
|
---|
| 797 | ph->multi=0;
|
---|
| 798 | ph->watchdog=0;
|
---|
| 799 | ph->s_handler=dvbapi_handler;
|
---|
| 800 | ph->send_dcw=dvbapi_send_dcw;
|
---|
| 801 | }
|
---|
| 802 | #endif // HAVE_DVBAPI_3
|
---|