1 /*
2  * Copyright (C) 2014-2020 Catalin Toda <catalinii@yahoo.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  * USA
18  *
19  */
20 
21 #include "tables.h"
22 #include "adapter.h"
23 #include "ca.h"
24 #include "dvb.h"
25 #include "dvbapi.h"
26 #include "minisatip.h"
27 #include <arpa/inet.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <math.h>
32 #include <net/if.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/ioctl.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <time.h>
44 #include <unistd.h>
45 
46 #ifndef DISABLE_DDCI
47 #include "ddci.h"
48 #endif
49 
50 #define DEFAULT_LOG LOG_TABLES
51 
52 SCA ca[MAX_CA];
53 int nca;
54 SMutex ca_mutex;
55 
add_ca(SCA_op * op,uint64_t adapter_mask)56 int add_ca(SCA_op *op, uint64_t adapter_mask) {
57     int i, new_ca;
58     del_ca(op);
59     for (i = 0; i < MAX_CA; i++)
60         if (!ca[i].enabled) {
61             mutex_lock(&ca_mutex);
62             if (!ca[i].enabled)
63                 break;
64             mutex_unlock(&ca_mutex);
65         }
66     if (i == MAX_CA)
67         LOG_AND_RETURN(0, "No free CA slots for %p", ca);
68     new_ca = i;
69 
70     ca[new_ca].enabled = 1;
71     ca[new_ca].adapter_mask = adapter_mask;
72     ca[new_ca].id = new_ca;
73     ca[new_ca].op = op;
74     memset(ca[new_ca].ad_info, 0, sizeof(ca[new_ca].ad_info));
75 
76     if (new_ca >= nca)
77         nca = new_ca + 1;
78 
79     init_ca_device(&ca[new_ca]);
80     mutex_unlock(&ca_mutex);
81     return new_ca;
82 }
83 extern SPMT *pmts[];
del_ca(SCA_op * op)84 void del_ca(SCA_op *op) {
85     int i, k, mask = 1;
86     adapter *ad;
87     mutex_lock(&ca_mutex);
88 
89     for (i = 0; i < MAX_CA; i++) {
90         if (ca[i].enabled) {
91             if (ca[i].op == op) {
92                 ca[i].enabled = 0;
93                 for (k = 0; k < MAX_ADAPTERS;
94                      k++) // delete ca_mask for all adapters
95                 {
96                     if ((ad = get_adapter_nw(k)))
97                         ad->ca_mask &= ~mask;
98                 }
99                 for (k = 0; k < npmts; k++) // delete ca_mask for all the PMTs
100                     if (pmts[k] && pmts[k]->enabled && pmts[k]->state &&
101                         (pmts[k]->ca_mask & mask))
102                         pmts[k]->ca_mask &= ~mask;
103             }
104         }
105         mask = mask << 1;
106     }
107     i = MAX_CA;
108     while (--i >= 0 && !ca[i].enabled)
109         ;
110     nca = i + 1;
111 
112     //	if (nca == 1)
113     //		nca = 0;
114 
115     mutex_unlock(&ca_mutex);
116 }
117 
tables_ca_ts(adapter * ad)118 void tables_ca_ts(adapter *ad) {
119     int i, mask = 1;
120 
121     for (i = 0; i < nca; i++) {
122         if (ca[i].enabled && (ad->ca_mask & mask) && ca[i].op->ca_ts) {
123             ca[i].op->ca_ts(ad);
124         }
125         mask = mask << 1;
126     }
127 }
128 
add_caid_mask(int ica,int aid,int caid,int mask)129 void add_caid_mask(int ica, int aid, int caid, int mask) {
130     int i;
131     adapter *ad = get_adapter(aid);
132     if (!ad) {
133         LOG("%s: No adapter %d found ", __FUNCTION__, aid);
134         return;
135     }
136     if (ca[ica].enabled && ca[ica].ad_info[aid].caids < MAX_CAID_LEN) {
137         for (i = 0; i < ca[ica].ad_info[aid].caids; i++)
138             if (ca[ica].ad_info[aid].caid[i] == caid &&
139                 ca[ica].ad_info[aid].mask[i] == mask)
140                 return;
141         i = ca[ica].ad_info[aid].caids++;
142         ca[ica].ad_info[aid].caid[i] = caid;
143         ca[ica].ad_info[aid].mask[i] = mask;
144         LOG("CA %d can handle CAID %04X mask %04X on adapter %d at position %d",
145             ica, caid, mask, ad->id, i);
146     } else
147         LOG("CA not enabled %d or too many added CAIDs %d", ica,
148             ca[ica].ad_info[aid].caids);
149 }
150 
tables_init_ca_for_device(int i,adapter * ad)151 int tables_init_ca_for_device(int i, adapter *ad) {
152     uint64_t mask = (1ULL << i);
153     int rv = 0;
154     if (i < 0 || i >= nca)
155         return 0;
156 
157     if ((ca[i].adapter_mask & mask) &&
158         !(ad->ca_mask & mask)) // CA registered and not already initialized
159     {
160         if (ca[i].enabled && ca[i].op->ca_init_dev) {
161             if (ca[i].op->ca_init_dev(ad) == TABLES_RESULT_OK) {
162                 LOGM("CA %d will handle adapter %d", i, ad->id);
163                 ad->ca_mask = ad->ca_mask | mask;
164                 rv = 1;
165             } else
166                 LOGM("CA %d is disabled for adapter %d", i, ad->id);
167         }
168     }
169     return rv;
170 }
171 
match_caid(SPMT * pmt,int caid,int mask)172 int match_caid(SPMT *pmt, int caid, int mask) {
173     int i;
174     for (i = 0; i < pmt->caids; i++)
175         if ((pmt->ca[i].id & mask) == caid) {
176             LOGM("%s: match caid %04X (%d/%d) with CA caid %04X and mask %04X",
177                  __FUNCTION__, pmt->ca[i].id, i, pmt->caids, caid, mask);
178             return 1;
179         }
180     return 0;
181 }
182 
close_pmt_for_ca(int i,adapter * ad,SPMT * pmt)183 void close_pmt_for_ca(int i, adapter *ad, SPMT *pmt) {
184     uint64_t mask = 1ULL << i;
185     if (!ad)
186         ad = get_adapter(pmt->adapter);
187     if (!ad)
188         return;
189     if (ca[i].enabled && (ad->ca_mask & mask) && (pmt->ca_mask & mask)) {
190         LOGM("Closing pmt %d for ca %d and adapter %d", pmt->id, i, ad->id);
191         if (ad && ca[i].op->ca_del_pmt)
192             ca[i].op->ca_del_pmt(ad, pmt);
193         pmt->ca_mask &= ~mask;
194     }
195 }
196 
close_pmt_for_cas(adapter * ad,SPMT * pmt)197 int close_pmt_for_cas(adapter *ad, SPMT *pmt) {
198     int i;
199     if (!pmt || !pmt->ca_mask)
200         return 0;
201 
202     if (!ad)
203         return 0;
204 
205     LOGM("Closing pmt %d for adapter %d", pmt->id, ad->id);
206     for (i = 0; i < nca; i++)
207         if (ca[i].enabled)
208             close_pmt_for_ca(i, ad, pmt);
209     return 0;
210 }
211 
disable_pmt_for_ca(int i,SPMT * pmt)212 void disable_pmt_for_ca(int i, SPMT *pmt) {
213     uint64_t mask = 1ULL << i;
214     if (i >= MAX_CA || i < 0)
215         return;
216     if (ca[i].enabled) {
217         close_pmt_for_ca(i, NULL, pmt);
218         pmt->disabled_ca_mask |= mask;
219     }
220 }
221 
send_pmt_to_ca(int i,adapter * ad,SPMT * pmt)222 int send_pmt_to_ca(int i, adapter *ad, SPMT *pmt) {
223     uint64_t mask;
224     int rv = 0, result = 0;
225     mask = 1ULL << i;
226 
227     if (ca[i].enabled && (ad->ca_mask & mask) && ca[i].op->ca_add_pmt &&
228         !(pmt->disabled_ca_mask & mask) && !(pmt->ca_mask & mask)) {
229         int j, send = 0;
230         for (j = 0; j < ca[i].ad_info[ad->id].caids; j++)
231             if (match_caid(pmt, ca[i].ad_info[ad->id].caid[j],
232                            ca[i].ad_info[ad->id].mask[j])) {
233                 LOG("CAID %04X and mask %04X matched PMT %d",
234                     ca[i].ad_info[ad->id].caid[j],
235                     ca[i].ad_info[ad->id].mask[j], pmt->id);
236                 send = 1;
237                 break;
238             }
239         result = TABLES_RESULT_ERROR_NORETRY;
240         if (send || ca[i].ad_info[ad->id].caids == 0) {
241             result = ca[i].op->ca_add_pmt(ad, pmt);
242         }
243 
244         if (result == TABLES_RESULT_OK) {
245             pmt->ca_mask |= mask;
246         } else if (result == TABLES_RESULT_ERROR_NORETRY)
247             pmt->disabled_ca_mask |= mask;
248         disable_cw(pmt->id);
249         rv += (1 - result);
250         LOGM("In processing PMT %d, ca %d, CA matched %d, ca_pmt_add "
251              "returned %d, new ca_mask %d new disabled_ca_mask %d",
252              pmt->id, i, send, result, pmt->ca_mask, pmt->disabled_ca_mask);
253     }
254     return rv;
255 }
256 
send_pmt_to_cas(adapter * ad,SPMT * pmt)257 int send_pmt_to_cas(adapter *ad, SPMT *pmt) {
258     int i, rv = 1;
259     if (!ad || (ad->ca_mask == (pmt->disabled_ca_mask | pmt->ca_mask))) {
260         LOGM("PMT %d does not require to be sent to any CA: ad_ca_mask %X, "
261              "pmt_ca_mask %X, disabled_ca_mask %X",
262              pmt->id, ad ? ad->ca_mask : -2, pmt->ca_mask,
263              pmt->disabled_ca_mask);
264         return 0;
265     }
266 
267     LOG("Sending PMT %d to all CAs: ad_ca_mask %X, "
268         "pmt_ca_mask %X, disabled_ca_mask %X",
269         pmt->id, ad ? ad->ca_mask : -2, pmt->ca_mask, pmt->disabled_ca_mask);
270     for (i = 0; i < nca; i++)
271         if (ca[i].enabled)
272             rv += send_pmt_to_ca(i, ad, pmt);
273     if (pmt->state == PMT_STARTING)
274         pmt->state = PMT_RUNNING;
275     return rv;
276 }
277 
send_pmt_to_ca_for_device(SCA * c,adapter * ad)278 void send_pmt_to_ca_for_device(SCA *c, adapter *ad) {
279     SPMT *pmt;
280     int i;
281     for (i = 0; i < npmts; i++)
282         if ((pmt = get_pmt(i)) && pmt->adapter == ad->id && pmt->state)
283             send_pmt_to_ca(c->id, ad, pmt);
284 }
285 
tables_update_encrypted_status(adapter * ad,SPMT * pmt)286 void tables_update_encrypted_status(adapter *ad, SPMT *pmt) {
287     int i;
288     int status = pmt->encrypted;
289     if (!ad)
290         return;
291     LOGM("Updating status %d for pmt %d, ad mask %08X, pmt mask %08X", status,
292          pmt->id, ad->ca_mask, pmt->ca_mask);
293     for (i = 0; i < nca; i++)
294         if (ca[i].enabled && (ad->ca_mask & (1ULL << i)) &&
295             (pmt->ca_mask & (1ULL << i))) {
296             LOGM("Updating status %d pmt %d for ca %d and adapter %d", status,
297                  pmt->id, i, ad->id);
298             if (status == TABLES_CHANNEL_ENCRYPTED && ca[i].op->ca_encrypted)
299                 ca[i].op->ca_encrypted(ad, pmt);
300             else if (status == TABLES_CHANNEL_DECRYPTED &&
301                      ca[i].op->ca_decrypted)
302                 ca[i].op->ca_decrypted(ad, pmt);
303         }
304 }
305 
tables_add_pid(adapter * ad,SPMT * pmt,int pid)306 void tables_add_pid(adapter *ad, SPMT *pmt, int pid) {
307     uint64_t i, mask;
308     for (i = 0; i < nca; i++) {
309         mask = 1ULL << i;
310         if (ca[i].enabled && (pmt->ca_mask & mask) && ca[i].op->ca_add_pid)
311             ca[i].op->ca_add_pid(ad, pmt, pid);
312     }
313 }
314 
tables_del_pid(adapter * ad,SPMT * pmt,int pid)315 void tables_del_pid(adapter *ad, SPMT *pmt, int pid) {
316     uint64_t mask, i;
317     for (i = 0; i < nca; i++) {
318         mask = 1ULL << i;
319         if (ca[i].enabled && (pmt->ca_mask & mask) && ca[i].op->ca_del_pid)
320             ca[i].op->ca_del_pid(ad, pmt, pid);
321     }
322 }
323 
register_ca_for_adapter(int i,int aid)324 int register_ca_for_adapter(int i, int aid) {
325     adapter *ad = get_adapter(aid);
326     uint64_t mask, rv;
327     if (i < 0 || i >= nca)
328         return 1;
329     if (!ad)
330         return 1;
331 
332     mask = (1ULL << ad->id);
333     if ((ca[i].adapter_mask & mask) == 0) {
334         ca[i].adapter_mask |= mask;
335         rv = tables_init_ca_for_device(i, ad);
336         if (rv)
337             send_pmt_to_ca_for_device(&ca[i], ad);
338         return 0;
339     }
340     return 2;
341 }
342 
unregister_ca_for_adapter(int i,int aid)343 int unregister_ca_for_adapter(int i, int aid) {
344     adapter *ad = get_adapter(aid);
345     uint64_t mask;
346     if (i < 0 || i >= nca)
347         return 1;
348     if (!ad)
349         return 1;
350 
351     mask = (1ULL << ad->id);
352     ca[i].adapter_mask &= ~mask;
353     mask = (1ULL << i);
354     if (ad->ca_mask & mask) {
355         if (ca[i].op->ca_close_dev)
356             ca[i].op->ca_close_dev(ad);
357         ad->ca_mask &= ~mask;
358         LOG("Unregistering CA %d for adapter %d", i, ad->id);
359     }
360     return 0;
361 }
362 
tables_init_device(adapter * ad)363 int tables_init_device(adapter *ad) {
364     int i;
365     int rv = 0;
366     for (i = 0; i < nca; i++)
367         if (ca[i].enabled)
368             rv += tables_init_ca_for_device(i, ad);
369     return rv;
370 }
371 
init_ca_device(SCA * c)372 void init_ca_device(SCA *c) {
373     uint64_t init_cm;
374     int i;
375     adapter *ad;
376     if (!c->op->ca_add_pmt)
377         return;
378 
379     for (i = 0; i < MAX_ADAPTERS; i++)
380         if ((ad = get_adapter_nw(i))) {
381             init_cm = ad->ca_mask;
382             //			tables_init_device(ad);
383             tables_init_ca_for_device(c->id, ad);
384             if (init_cm != ad->ca_mask) {
385                 send_pmt_to_ca_for_device(c, ad);
386             }
387         }
388 }
389 
tables_close_device(adapter * ad)390 int tables_close_device(adapter *ad) {
391     uint64_t i, mask = 1;
392     int rv = 0;
393 
394     for (i = 0; i < nca; i++) {
395         if (ca[i].enabled && (ad->ca_mask & mask) && ca[i].op->ca_close_dev) {
396             ca[i].op->ca_close_dev(ad);
397         }
398     }
399 
400     ad->ca_mask = 0;
401     return rv;
402 }
403 
tables_init()404 int tables_init() {
405     mutex_init(&ca_mutex);
406 #ifndef DISABLE_DVBCA
407     dvbca_init();
408 #endif
409 #ifndef DISABLE_DVBAPI
410     init_dvbapi();
411 #endif
412     return 0;
413 }
414 
tables_destroy()415 int tables_destroy() {
416     int i;
417     for (i = 0; i < nca; i++) {
418         if (ca[i].enabled && ca[i].op->ca_close_ca)
419             ca[i].op->ca_close_ca(&ca[i]);
420     }
421     return 0;
422 }
423