Project

General

Profile

RE: Biss key » tvheadend-001-biss.patch

Nikolay Voronov, 2014-07-06 07:29

View differences:

Makefile 2014-06-10 23:31:37.000000000 +0300 → Makefile 2014-07-05 12:00:40.000000000 +0300
283 283
	
284 284
# CAPMT
285 285
SRCS-${CONFIG_CAPMT} += \
286
	src/descrambler/capmt.c
286
	src/descrambler/capmt.c \
287
	src/descrambler/ccw.c \
287 288

  
288 289
# FFdecsa
289 290
ifneq ($(CONFIG_DVBCSA),yes)
src/descrambler/capmt.c 2014-07-05 11:47:02.000000000 +0300 → src/descrambler/capmt.c 2014-07-05 12:23:11.000000000 +0300
1824 1824
                               capmt->capmt_port);
1825 1825
    td->td_nicename    = strdup(buf);
1826 1826
    td->td_service     = s;
1827
    td->dtype          = 0;
1827 1828
    td->td_stop        = capmt_service_destroy;
1828 1829
    td->td_caid_change = capmt_caid_change;
1829 1830
    LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
src/descrambler/ccw.c 1970-01-01 03:00:00.000000000 +0300 → src/descrambler/ccw.c 2014-07-05 21:20:43.121814393 +0300
1
/*
2
 *  tvheadend, CCW
3
 *  Copyright (C) 2012
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation, either version 3 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

  
19
#include <pthread.h>
20
#include <assert.h>
21
#include <string.h>
22
#include <stdio.h>
23
#include <unistd.h>
24
#include <stdlib.h>
25
#include <stdarg.h>
26
#include <errno.h>
27
#include <netinet/in.h>
28
#include <arpa/inet.h>
29
#include <ctype.h>
30
#include <signal.h>
31
#include <sys/types.h>
32
#include <sys/socket.h>
33
#include <openssl/des.h>
34

  
35
#include "tvheadend.h"
36
#include "tcp.h"
37
#include "ccw.h"
38
#include "notify.h"
39
#include "atomic.h"
40
#include "dtable.h"
41
#include "subscriptions.h"
42
#include "service.h"
43
#include "input.h"
44
#include "input/mpegts/tsdemux.h"
45
#include "tvhcsa.h"
46
#include "input/mpegts/linuxdvb/linuxdvb_private.h"
47

  
48
/**
49
 *
50
 */
51
TAILQ_HEAD(ccw_queue, ccw);
52
LIST_HEAD(ccw_service_list, ccw_service);
53
static struct ccw_queue ccws;
54
static pthread_cond_t ccw_config_changed;
55

  
56
/**
57
 *
58
 */
59
typedef struct ccw_service {
60
  th_descrambler_t;
61

  
62
  mpegts_service_t *ct_service;
63

  
64
  struct ccw *ct_ccw;
65

  
66
  LIST_ENTRY(ccw_service) ct_link;
67

  
68
  /**
69
   * Status of the key(s) in ct_keys
70
   */
71
  enum {
72
    CT_UNKNOWN,
73
    CT_RESOLVED,
74
    CT_FORBIDDEN
75
  } ct_keystate;
76
  
77
  tvhcsa_t cs_csa;
78

  
79
  /* buffer for keystruct */
80
  void    *ct_keys;
81

  
82
  /* CSA */
83
  int      ct_cluster_size;
84
  uint8_t *ct_tsbcluster;
85
  int      ct_fill;
86

  
87
  uint8_t ccw_evenkey[8];
88
  uint8_t ccw_oddkey[8];
89

  
90
} ccw_service_t;
91

  
92
/**
93
 *
94
 */
95
typedef struct ccw {
96
  pthread_cond_t ccw_cond;
97

  
98
  TAILQ_ENTRY(ccw) ccw_link; /* Linkage protected via global_lock */
99

  
100
  struct ccw_service_list ccw_services;
101

  
102
  uint16_t ccw_caid;  // CAID
103
  uint16_t ccw_tid;   // Transponder ID
104
  uint16_t ccw_sid;   // Channel ID
105
  uint8_t ccw_confedkey[8];  // Key
106
  char *ccw_comment;
107
  char *ccw_id;
108

  
109
  int   ccw_enabled;
110
  int   ccw_running;
111
  int   ccw_reconfigure;
112

  
113
} ccw_t;
114

  
115
/**
116
 * global_lock is held
117
 * s_stream_mutex is held
118
 */
119
static void 
120
ccw_service_destroy(th_descrambler_t *td)
121
{
122
  tvhlog(LOG_INFO, "ccw", "Removing CCW key from service");
123

  
124
  ccw_service_t *ct = (ccw_service_t *)td;
125

  
126
  LIST_REMOVE(td, td_service_link);
127
  LIST_REMOVE(ct, ct_link);
128

  
129
  free_key_struct(ct->ct_keys);
130
  free(ct->ct_tsbcluster);
131
  
132
  tvhcsa_destroy(&ct->cs_csa);
133
  free(ct);
134
}
135

  
136
/**
137
 *
138
 */
139

  
140
static int
141
ccw_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
142
     const uint8_t *tsb)
143
{
144
  ccw_service_t *ct = (ccw_service_t *)td;
145
  int r, i;
146
  unsigned char *vec[3];
147
  uint8_t *t0;
148

  
149
  tvhlog(LOG_DEBUG, "ccw", "ccw_descramble");
150

  
151
  if(ct->ct_keystate == CT_FORBIDDEN)
152
    return 1;
153

  
154
  if(ct->ct_keystate != CT_RESOLVED)
155
    return -1;
156

  
157
  memcpy(ct->ct_tsbcluster + ct->ct_fill * 188, tsb, 188);
158
  ct->ct_fill++;
159

  
160
  if(ct->ct_fill != ct->ct_cluster_size)
161
    return 0;
162

  
163
  ct->ct_fill = 0;
164

  
165
  vec[0] = ct->ct_tsbcluster;
166
  vec[1] = ct->ct_tsbcluster + ct->ct_cluster_size * 188;
167
  vec[2] = NULL;
168

  
169
  while(1) {
170
    t0 = vec[0];
171
    r = decrypt_packets(ct->ct_keys, vec);
172
    if(r == 0)
173
      break;
174
    for(i = 0; i < r; i++) {
175
      ts_recv_packet2((mpegts_service_t*)t, t0);
176
      t0 += 188;
177
    }
178
  }
179
  return 0;
180
}
181

  
182
/**
183
 *
184
 */
185
static inline elementary_stream_t *
186
ccw_find_stream_by_caid(service_t *t, int caid)
187
{
188
  elementary_stream_t *st;
189
  caid_t *c;
190

  
191
  TAILQ_FOREACH(st, &t->s_components, es_link) {
192
    LIST_FOREACH(c, &st->es_caids, link) {
193
      if(c->caid == caid)
194
    return st;
195
    }
196
  }
197
  return NULL;
198
}
199

  
200
/**
201
 * Check if our CAID's matches, and if so, link
202
 *
203
 * global_lock is held
204
 */
205
void
206
ccw_service_start(service_t *t)
207
{
208
  ccw_t *ccw;
209
  ccw_service_t *ct;
210
  th_descrambler_t *td;
211
  mpegts_service_t *ms = (mpegts_service_t*)t;
212
  linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)ms->s_dvb_active_input;
213
  int adapter_num = lfe->lfe_adapter->la_dvb_number;
214
  char buf[512];
215

  
216
  lock_assert(&global_lock);
217
  
218
  extern const idclass_t mpegts_service_class;
219
  if (!idnode_is_instance(&t->s_id, &mpegts_service_class))
220
    return;
221

  
222
  TAILQ_FOREACH(ccw, &ccws, ccw_link) {
223
    if(ccw->ccw_caid == 0)
224
      continue;
225

  
226
    if(ccw_find_stream_by_caid(t, ccw->ccw_caid) == NULL)
227
      continue;
228

  
229
    if(ms->s_dvb_service_id != ccw->ccw_sid)
230
      continue;
231

  
232
    if(ms->s_dvb_mux->mm_tsid != ccw->ccw_tid)
233
      continue;
234

  
235
    tvhlog(LOG_INFO, "ccw","Starting ccw key for service \"%s\" on tuner %d", ms->s_dvb_svcname,adapter_num);
236

  
237
    /* create new ccw service */
238
    ct                  = calloc(1, sizeof(ccw_service_t));
239
    ct->ct_cluster_size = get_suggested_cluster_size();
240
    ct->ct_tsbcluster   = malloc(ct->ct_cluster_size * 188);
241

  
242
    ct->ct_keys       = get_key_struct();
243
    ct->ct_ccw      = ccw;
244
    ct->ct_service  = ms;
245

  
246
    memcpy(ct->ccw_evenkey,ccw->ccw_confedkey,8);
247
    memcpy(ct->ccw_oddkey,ccw->ccw_confedkey,8);
248

  
249
    set_even_control_word(ct->ct_keys, ct->ccw_evenkey);
250
    set_odd_control_word(ct->ct_keys, ct->ccw_oddkey);
251
    if(ct->ct_keystate != CT_RESOLVED)
252
        tvhlog(LOG_INFO, "ccw", "Obtained key for service \"%s\"",ms->s_dvb_svcname);
253

  
254
    tvhlog(LOG_DEBUG, "ccw",
255
       "Key for service \"%s\" "
256
       "even: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x"
257
       " odd: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x",
258
       ms->s_dvb_svcname,
259
       ct->ccw_evenkey[0], ct->ccw_evenkey[1], ct->ccw_evenkey[2], ct->ccw_evenkey[3],
260
           ct->ccw_evenkey[4], ct->ccw_evenkey[5], ct->ccw_evenkey[6], ct->ccw_evenkey[7],
261
           ct->ccw_oddkey[0], ct->ccw_oddkey[1], ct->ccw_oddkey[2], ct->ccw_oddkey[3],
262
           ct->ccw_oddkey[4], ct->ccw_oddkey[5], ct->ccw_oddkey[6],  ct->ccw_oddkey[7]);
263
    ct->ct_keystate = CT_RESOLVED;
264

  
265
    td = (th_descrambler_t *)ct;
266
    tvhcsa_init(td->td_csa = &ct->cs_csa);
267
    snprintf(buf, sizeof(buf), "ccw-%i-%i", ccw->ccw_tid, ccw->ccw_sid);
268
    td->td_nicename      = strdup(buf);
269
    td->td_service       = t;
270
    td->dtype            = 1;
271
    td->td_stop          = ccw_service_destroy;
272
    td->td_descramble    = ccw_descramble;
273
    LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
274

  
275
    LIST_INSERT_HEAD(&ccw->ccw_services, ct, ct_link);
276
  }
277
}
278

  
279
/**
280
 *
281
 */
282
static void
283
ccw_destroy(ccw_t *ccw)
284
{
285
  lock_assert(&global_lock);
286
  TAILQ_REMOVE(&ccws, ccw, ccw_link);
287
  ccw->ccw_running = 0;
288
  pthread_cond_signal(&ccw->ccw_cond);
289
}
290

  
291
/**
292
 *
293
 */
294
static ccw_t *
295
ccw_entry_find(const char *id, int create)
296
{
297
//  pthread_attr_t attr;
298
//  pthread_t ptid;
299
  char buf[20];
300
  ccw_t *ccw;
301
  static int tally;
302

  
303
  if(id != NULL) {
304
    TAILQ_FOREACH(ccw, &ccws, ccw_link)
305
      if(!strcmp(ccw->ccw_id, id))
306
  return ccw;
307
  }
308
  if(create == 0)
309
    return NULL;
310

  
311
  if(id == NULL) {
312
    tally++;
313
    snprintf(buf, sizeof(buf), "%d", tally);
314
    id = buf;
315
  } else {
316
    tally = MAX(atoi(id), tally);
317
  }
318

  
319
  ccw = calloc(1, sizeof(ccw_t));
320
  pthread_cond_init(&ccw->ccw_cond, NULL);
321
  ccw->ccw_id      = strdup(id);
322
  ccw->ccw_running = 1;
323

  
324
  TAILQ_INSERT_TAIL(&ccws, ccw, ccw_link);
325

  
326
//  pthread_attr_init(&attr);
327
//  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
328
//  pthread_create(&ptid, &attr, ccw_thread, ccw);
329
//  pthread_attr_destroy(&attr);
330

  
331
  return ccw;
332
}
333

  
334
/**
335
 *
336
 */
337
static htsmsg_t *
338
ccw_record_build(ccw_t *ccw)
339
{
340
  htsmsg_t *e = htsmsg_create_map();
341
  char buf[100];
342

  
343
  htsmsg_add_str(e, "id", ccw->ccw_id);
344
  htsmsg_add_u32(e, "enabled",  !!ccw->ccw_enabled);
345

  
346
  htsmsg_add_u32(e, "caid", ccw->ccw_caid);
347
  htsmsg_add_u32(e, "tid", ccw->ccw_tid);
348
  htsmsg_add_u32(e, "sid", ccw->ccw_sid);
349

  
350
  snprintf(buf, sizeof(buf),
351
       "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
352
       ccw->ccw_confedkey[0],
353
       ccw->ccw_confedkey[1],
354
       ccw->ccw_confedkey[2],
355
       ccw->ccw_confedkey[3],
356
       ccw->ccw_confedkey[4],
357
       ccw->ccw_confedkey[5],
358
       ccw->ccw_confedkey[6],
359
       ccw->ccw_confedkey[7]);
360

  
361
  htsmsg_add_str(e, "key", buf);
362
  htsmsg_add_str(e, "comment", ccw->ccw_comment ?: "");
363

  
364
  return e;
365
}
366

  
367
/**
368
 *
369
 */
370
static int
371
nibble(char c)
372
{
373
  switch(c) {
374
  case '0' ... '9':
375
    return c - '0';
376
  case 'a' ... 'f':
377
    return c - 'a' + 10;
378
  case 'A' ... 'F':
379
    return c - 'A' + 10;
380
  default:
381
    return 0;
382
  }
383
}
384

  
385
/**
386
 *
387
 */
388
static htsmsg_t *
389
ccw_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
390
{
391
  ccw_t *ccw;
392
  const char *s;
393
  uint32_t u32;
394
  uint8_t key[8];
395
  int u, l, i;
396

  
397
  if((ccw = ccw_entry_find(id, maycreate)) == NULL)
398
    return NULL;
399

  
400
  lock_assert(&global_lock);
401

  
402
  if(!htsmsg_get_u32(values, "caid", &u32))
403
    ccw->ccw_caid = u32;
404
  if(!htsmsg_get_u32(values, "tid", &u32))
405
    ccw->ccw_tid = u32;
406
  if(!htsmsg_get_u32(values, "sid", &u32))
407
    ccw->ccw_sid = u32;
408

  
409
  if((s = htsmsg_get_str(values, "key")) != NULL) {
410
    for(i = 0; i < 8; i++) {
411
      while(*s != 0 && !isxdigit(*s)) s++;
412
      if(*s == 0)
413
    break;
414
      u = nibble(*s++);
415
      while(*s != 0 && !isxdigit(*s)) s++;
416
      if(*s == 0)
417
    break;
418
      l = nibble(*s++);
419
      key[i] = (u << 4) | l;
420
    }
421
    memcpy(ccw->ccw_confedkey, key, 8);
422
  }
423

  
424
  if((s = htsmsg_get_str(values, "comment")) != NULL) {
425
    free(ccw->ccw_comment);
426
    ccw->ccw_comment = strdup(s);
427
  }
428

  
429
  if(!htsmsg_get_u32(values, "enabled", &u32)) 
430
    ccw->ccw_enabled = u32;
431

  
432
  ccw->ccw_reconfigure = 1;
433

  
434
  pthread_cond_signal(&ccw->ccw_cond);
435

  
436
  pthread_cond_broadcast(&ccw_config_changed);
437

  
438
  return ccw_record_build(ccw);
439
}
440

  
441
/**
442
 *
443
 */
444
static int
445
ccw_entry_delete(void *opaque, const char *id)
446
{
447
  ccw_t *ccw;
448

  
449
  pthread_cond_broadcast(&ccw_config_changed);
450

  
451
  if((ccw = ccw_entry_find(id, 0)) == NULL)
452
    return -1;
453
  ccw_destroy(ccw);
454
  return 0;
455
}
456

  
457
/**
458
 *
459
 */
460
static htsmsg_t *
461
ccw_entry_get_all(void *opaque)
462
{
463
  htsmsg_t *r = htsmsg_create_list();
464
  ccw_t *ccw;
465

  
466
  TAILQ_FOREACH(ccw, &ccws, ccw_link)
467
    htsmsg_add_msg(r, NULL, ccw_record_build(ccw));
468

  
469
  return r;
470
}
471

  
472
/**
473
 *
474
 */
475
static htsmsg_t *
476
ccw_entry_get(void *opaque, const char *id)
477
{
478
  ccw_t *ccw;
479

  
480

  
481
  if((ccw = ccw_entry_find(id, 0)) == NULL)
482
    return NULL;
483
  return ccw_record_build(ccw);
484
}
485

  
486
/**
487
 *
488
 */
489
static htsmsg_t *
490
ccw_entry_create(void *opaque)
491
{
492
  pthread_cond_broadcast(&ccw_config_changed);
493
  return ccw_record_build(ccw_entry_find(NULL, 1));
494
}
495

  
496
/**
497
 *
498
 */
499
static const dtable_class_t ccw_dtc = {
500
  .dtc_record_get     = ccw_entry_get,
501
  .dtc_record_get_all = ccw_entry_get_all,
502
  .dtc_record_create  = ccw_entry_create,
503
  .dtc_record_update  = ccw_entry_update,
504
  .dtc_record_delete  = ccw_entry_delete,
505
  .dtc_read_access = ACCESS_ADMIN,
506
  .dtc_write_access = ACCESS_ADMIN,
507
  .dtc_mutex = &global_lock,
508
};
509

  
510
/**
511
 *
512
 */
513
void
514
ccw_init(void)
515
{
516
  dtable_t *dt;
517

  
518
  TAILQ_INIT(&ccws);
519

  
520
  pthread_cond_init(&ccw_config_changed, NULL);
521

  
522
  dt = dtable_create(&ccw_dtc, "ccw", NULL);
523
  dtable_load(dt);
524

  
525
}
526

  
527
/**
528
 *
529
 */
530
void
531
ccw_done(void)
532
{
533
  ccw_t *ccw;
534

  
535
  dtable_delete("ccw");
536
  pthread_mutex_lock(&global_lock);
537
  //pthread_mutex_lock(&ccw_mutex);
538
  while ((ccw = TAILQ_FIRST(&ccws)) != NULL)
539
    ccw_destroy(ccw);
540
  //pthread_mutex_unlock(&ccw_mutex);
541
  pthread_mutex_unlock(&global_lock);
542
}
src/descrambler/ccw.h 1970-01-01 03:00:00.000000000 +0300 → src/descrambler/ccw.h 2014-07-05 12:00:26.000000000 +0300
1
/*
2
 *  tvheadend, CCW
3
 *  Copyright (C) 2012
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation, either version 3 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

  
19
#ifndef CCW_H_
20
#define CCW_H_
21

  
22
void ccw_init(void);
23

  
24
void ccw_done(void);
25

  
26
void ccw_service_start(struct service *t);
27

  
28
#endif /* CCW_H_ */
src/descrambler/cwc.c 2014-06-25 13:34:10.000000000 +0300 → src/descrambler/cwc.c 2014-07-05 12:24:53.000000000 +0300
1997 1997
    snprintf(buf, sizeof(buf), "cwc-%s-%i", cwc->cwc_hostname, cwc->cwc_port);
1998 1998
    td->td_nicename      = strdup(buf);
1999 1999
    td->td_service       = t;
2000
    td->dtype            = 0;
2000 2001
    td->td_stop          = cwc_service_destroy;
2001 2002
    LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
2002 2003

  
src/descrambler/descrambler.c 2014-06-28 23:02:56.000000000 +0300 → src/descrambler/descrambler.c 2014-07-05 21:22:18.201818591 +0300
19 19
#include "tvheadend.h"
20 20
#include "descrambler.h"
21 21
#include "cwc.h"
22
#include "ccw.h"
22 23
#include "capmt.h"
23 24
#include "ffdecsa/FFdecsa.h"
24 25
#include "input.h"
......
86 87
#endif
87 88
#if ENABLE_CAPMT
88 89
  capmt_init();
90
  ccw_init();
89 91
#endif
90 92
#if (ENABLE_CWC || ENABLE_CAPMT) && !ENABLE_DVBCSA
91 93
  ffdecsa_init();
......
97 99
{
98 100
#if ENABLE_CAPMT
99 101
  capmt_done();
102
  ccw_done();
100 103
#endif
101 104
#if ENABLE_CWC
102 105
  cwc_done();
......
118 121
#endif
119 122
#if ENABLE_CAPMT
120 123
  capmt_service_start(t);
124
  ccw_service_start(t);
121 125
#endif
122 126
  if (t->s_descramble == NULL) {
123 127
    t->s_descramble = dr = calloc(1, sizeof(th_descrambler_runtime_t));
......
254 258
    }
255 259
    if (td->td_keystate != DS_RESOLVED)
256 260
      continue;
261
    if (td->dtype == 1) 
262
      continue;
257 263
    if (dr->dr_buf.sb_ptr > 0) {
258 264
      for (off = 0, size = dr->dr_buf.sb_ptr; off < size; off += 188) {
259 265
        tsb2 = dr->dr_buf.sb_data + off;
src/descrambler.h 2014-06-19 01:57:26.000000000 +0300 → src/descrambler.h 2014-07-05 14:13:09.000000000 +0300
52 52
  void (*td_stop)       (struct th_descrambler *d);
53 53
  void (*td_caid_change)(struct th_descrambler *d);
54 54

  
55
  int dtype;
56

  
57
  int (*td_descramble)(struct th_descrambler *d, struct service *t,
58
           struct elementary_stream *st, const uint8_t *tsb);
59

  
55 60
} th_descrambler_t;
56 61

  
57 62
typedef struct th_descrambler_runtime {
src/input/mpegts/tsdemux.c 2014-06-13 13:15:46.000000000 +0300 → src/input/mpegts/tsdemux.c 2014-07-05 21:34:52.657851910 +0300
156 156
  (mpegts_service_t *t, const uint8_t *tsb, int64_t *pcrp, int table)
157 157
{
158 158
  elementary_stream_t *st;
159
  int pid, r;
159
  int pid, n, m, r;
160
  th_descrambler_t *td;
160 161
  int error = 0;
161 162
  int64_t pcr = PTS_UNSET;
162 163
  
......
198 199

  
199 200
  pid = (tsb[1] & 0x1f) << 8 | tsb[2];
200 201

  
202
  if(pid==0x1FFF){  // ignore NULL stream
203
    pthread_mutex_unlock(&t->s_stream_mutex);
204
    return 0;
205
  }
206

  
201 207
  st = service_stream_find((service_t*)t, pid);
202 208

  
203 209
  /* Extract PCR */
......
224 230
      t->s_scrambled_seen |= service_is_encrypted((service_t*)t);
225 231

  
226 232
    /* scrambled stream */
233
    n = m = 0;
234

  
235
    LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
236
      n++;
237
      
238
      if(td->dtype == 1) {
239
        r = td->td_descramble(td, (service_t*)t, st, tsb);
240
        if(r == 0) {
241
          pthread_mutex_unlock(&t->s_stream_mutex);
242
          return 1;
243
        }
244
      }
245

  
246
      if(r == 1)
247
        m++;
248
    }
249

  
227 250
    r = descrambler_descramble((service_t *)t, st, tsb);
228 251
    if(r > 0) {
229 252
      pthread_mutex_unlock(&t->s_stream_mutex);
src/webui/extjs.c 2014-06-19 01:57:26.000000000 +0300 → src/webui/extjs.c 2014-07-05 12:00:40.000000000 +0300
150 150
#endif
151 151
#if ENABLE_CAPMT
152 152
  extjs_load(hq, "static/app/capmteditor.js");
153
  extjs_load(hq, "static/app/ccweditor.js");
153 154
#endif
154 155
  extjs_load(hq, "static/app/tvadapters.js");
155 156
  extjs_load(hq, "static/app/idnode.js");
src/webui/static/app/ccweditor.js 1970-01-01 03:00:00.000000000 +0300 → src/webui/static/app/ccweditor.js 2014-07-05 12:00:26.000000000 +0300
1
tvheadend.ccweditor = function() {
2
    var fm = Ext.form;
3

  
4
    var enabledColumn = new Ext.grid.CheckColumn({
5
	header : "Enabled",
6
	dataIndex : 'enabled',
7
	width : 60
8
    });
9

  
10
    function setMetaAttr(meta, record) {
11
	var enabled = record.get('enabled');
12
	if (enabled == 1) {
13
	    meta.attr = 'style="color:green;"';
14
	}
15
	else {
16
	    meta.attr = 'style="color:red;"';
17
	}
18
    }
19

  
20
    var cm = new Ext.grid.ColumnModel({
21
            defaultSortable: true,
22
            columns: [ enabledColumn, {
23
	header: "CAID",
24
	dataIndex: 'caid',
25
	renderer: function(value, metadata, record, row, col, store) {
26
	    setMetaAttr(metadata, record);
27
	    return value;
28
	},
29
	editor: new fm.TextField({allowBlank: false})
30
    }, {
31
	header: "Mux ID",
32
	dataIndex: 'tid',
33
	renderer: function(value, metadata, record, row, col, store) {
34
	    setMetaAttr(metadata, record);
35
	    return value;
36
	},
37
	editor: new fm.TextField({allowBlank: false})
38
    }, {
39
	header: "SID",
40
	dataIndex: 'sid',
41
	renderer: function(value, metadata, record, row, col, store) {
42
	    setMetaAttr(metadata, record);
43
	    return value;
44
	},
45
	editor: new fm.TextField({allowBlank: false})
46
    }, {
47
	header: "Key",
48
	dataIndex: 'key',
49
	width: 200,
50
	renderer: function(value, metadata, record, row, col, store) {
51
	    setMetaAttr(metadata, record);
52
	    return value;
53
	},
54
	editor: new fm.TextField({allowBlank: false})
55
    }, {
56
	header : "Comment",
57
	dataIndex : 'comment',
58
	width : 400,
59
	renderer : function(value, metadata, record, row, col, store) {
60
	    setMetaAttr(metadata, record);
61
	    return value;
62
	},
63
	editor : new fm.TextField()
64
    } ]});
65

  
66
    var rec = Ext.data.Record.create([ 'enabled','caid','tid','sid','key','comment' ]);
67

  
68
    store = new Ext.data.JsonStore({
69
	root: 'entries',
70
	fields: rec,
71
	url: "tablemgr",
72
	autoLoad: true,
73
	id: 'id',
74
	baseParams: {table: 'ccw', op: "get"}
75
    });
76

  
77
    tvheadend.comet.on('ccwStatus', function(server) {
78
	var rec = store.getById(server.id);
79
	if(rec){
80
	    rec.set('connected', server.connected);
81
	}
82
    });
83

  
84
    return new tvheadend.tableEditor('CCW Keys', 'ccw', cm, rec,
85
		     [enabledColumn], store,
86
		'config_ccw.html', 'key');
87
}
src/webui/static/app/tvheadend.js 2014-06-10 23:31:37.000000000 +0300 → src/webui/static/app/tvheadend.js 2014-07-05 14:31:23.296729787 +0300
285 285
        tabs2 = [];
286 286
        if (tvheadend.capabilities.indexOf('cwc')   !== -1)
287 287
          tabs2.push(new tvheadend.cwceditor);
288
        if (tvheadend.capabilities.indexOf('capmt') !== -1)
288
        if (tvheadend.capabilities.indexOf('capmt') !== -1) {
289 289
          tabs2.push(new tvheadend.capmteditor);
290
	  tabs2.push(new tvheadend.ccweditor);
291
        }
290 292
        if (tabs2.length > 0) {
291 293
            tvheadend.conf_csa = new Ext.TabPanel({
292 294
                activeTab: 0,
(1-1/2)