1 /*
2 * tvheadend, tsdebug code word interface
3 * Copyright (C) 2014 Jaroslav Kysela
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 <ctype.h>
20 #include "tvheadend.h"
21 #include "caclient.h"
22 #include "service.h"
23 #include "input.h"
24
25 /**
26 *
27 */
28 typedef struct tsdebugcw_service {
29 th_descrambler_t;
30
31 int tdcw_type;
32 uint8_t tdcw_key_even[16]; /* DES or AES key */
33 uint8_t tdcw_key_odd [16]; /* DES or AES key */
34
35 } tsdebugcw_service_t;
36
37 typedef struct tsdebugcw_request {
38 TAILQ_ENTRY(tsdebugcw_request) link;
39 tsdebugcw_service_t *ct;
40 } tsdebugcw_request_t;
41
42 pthread_mutex_t tsdebugcw_mutex;
43 TAILQ_HEAD(,tsdebugcw_request) tsdebugcw_requests;
44
45 /*
46 *
47 */
48 static int
tsdebugcw_ecm_reset(th_descrambler_t * th)49 tsdebugcw_ecm_reset(th_descrambler_t *th)
50 {
51 return 1;
52 }
53
54 /**
55 * s_stream_mutex is held
56 */
57 static void
tsdebugcw_service_destroy(th_descrambler_t * td)58 tsdebugcw_service_destroy(th_descrambler_t *td)
59 {
60 tsdebugcw_service_t *ct = (tsdebugcw_service_t *)td;
61 tsdebugcw_request_t *ctr, *ctrnext;
62
63 pthread_mutex_lock(&tsdebugcw_mutex);
64 for (ctr = TAILQ_FIRST(&tsdebugcw_requests); ctr; ctr = ctrnext) {
65 ctrnext = TAILQ_NEXT(ctr, link);
66 if (ctr->ct == ct) {
67 TAILQ_REMOVE(&tsdebugcw_requests, ctr, link);
68 free(ctr);
69 }
70 }
71 pthread_mutex_unlock(&tsdebugcw_mutex);
72
73 LIST_REMOVE(td, td_service_link);
74 free(ct->td_nicename);
75 free(ct);
76 }
77
78 /**
79 * global_lock is held. Not that we care about that, but either way, it is.
80 */
81 void
tsdebugcw_service_start(service_t * t)82 tsdebugcw_service_start(service_t *t)
83 {
84 tsdebugcw_service_t *ct;
85 th_descrambler_t *td;
86 char buf[128];
87
88 extern const idclass_t mpegts_service_class;
89 if (!idnode_is_instance(&t->s_id, &mpegts_service_class))
90 return;
91
92 LIST_FOREACH(td, &t->s_descramblers, td_service_link)
93 if (td->td_stop == tsdebugcw_service_destroy)
94 break;
95 if (td)
96 return;
97
98 ct = calloc(1, sizeof(tsdebugcw_service_t));
99 td = (th_descrambler_t *)ct;
100 snprintf(buf, sizeof(buf), "tsdebugcw");
101 td->td_nicename = strdup(buf);
102 td->td_service = t;
103 td->td_stop = tsdebugcw_service_destroy;
104 td->td_ecm_reset = tsdebugcw_ecm_reset;
105 LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
106 }
107
108 /*
109 *
110 */
111 void
tsdebugcw_new_keys(service_t * t,int type,uint8_t * odd,uint8_t * even)112 tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even)
113 {
114 static char empty[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
115 th_descrambler_t *td;
116 tsdebugcw_service_t *ct;
117 tsdebugcw_request_t *ctr;
118 int keylen = type == DESCRAMBLER_AES ? 16 : 8;
119
120 LIST_FOREACH(td, &t->s_descramblers, td_service_link)
121 if (td->td_stop == tsdebugcw_service_destroy)
122 break;
123 if (!td)
124 return;
125 ct = (tsdebugcw_service_t *)td;
126 ct->tdcw_type = type;
127 if (memcmp(empty, odd, keylen))
128 memcpy(ct->tdcw_key_odd, odd, keylen);
129 if (memcmp(empty, even, keylen))
130 memcpy(ct->tdcw_key_even, even, keylen);
131 ctr = malloc(sizeof(*ctr));
132 ctr->ct = ct;
133 pthread_mutex_lock(&tsdebugcw_mutex);
134 TAILQ_INSERT_TAIL(&tsdebugcw_requests, ctr, link);
135 pthread_mutex_unlock(&tsdebugcw_mutex);
136 }
137
138 /*
139 *
140 */
141 void
tsdebugcw_go(void)142 tsdebugcw_go(void)
143 {
144 tsdebugcw_request_t *ctr;
145 tsdebugcw_service_t *ct;
146
147 while (1) {
148 pthread_mutex_lock(&tsdebugcw_mutex);
149 ctr = TAILQ_FIRST(&tsdebugcw_requests);
150 if (ctr)
151 TAILQ_REMOVE(&tsdebugcw_requests, ctr, link);
152 pthread_mutex_unlock(&tsdebugcw_mutex);
153 if (!ctr) break;
154 ct = ctr->ct;
155 descrambler_keys((th_descrambler_t *)ct, ct->tdcw_type,
156 ct->tdcw_key_odd, ct->tdcw_key_even);
157 free(ctr);
158 }
159 }
160
161 /*
162 *
163 */
164 void
tsdebugcw_init(void)165 tsdebugcw_init(void)
166 {
167 pthread_mutex_init(&tsdebugcw_mutex, NULL);
168 TAILQ_INIT(&tsdebugcw_requests);
169 }
170