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 #define _GNU_SOURCE
21 #define _FILE_OFFSET_BITS 64
22 
23 #include "ca.h"
24 #include "ddci.h"
25 #include "dvb.h"
26 #include "minisatip.h"
27 #include "socketworks.h"
28 #include "utils.h"
29 #include <arpa/inet.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <math.h>
34 #include <net/if.h>
35 #include <netdb.h>
36 #include <netinet/in.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdint.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/ioctl.h>
44 #include <sys/mman.h>
45 #include <sys/socket.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 #include <sys/ucontext.h>
49 #include <syslog.h>
50 #include <time.h>
51 #include <unistd.h>
52 
53 #define DEFAULT_LOG LOG_DVBCA
54 
55 extern ddci_device_t *ddci_devices[MAX_ADAPTERS];
56 extern adapter *a[MAX_ADAPTERS];
57 extern SPMT *pmts[MAX_PMT];
58 extern int npmts;
59 extern int dvbca_id;
60 extern ca_device_t *ca_devices[MAX_ADAPTERS];
61 extern SHashTable channels;
62 extern SFilter *filters[MAX_FILTERS];
63 
64 typedef struct ca_device {
65     int enabled;
66     SCAPMT capmt[MAX_CA_PMT];
67     int max_ca_pmt, multiple_pmt;
68     int fd;
69     int slot_id;
70     int tc;
71     int id;
72     int ignore_close;
73     int init_ok;
74 } ca_device_t;
75 
create_pmt(SPMT * pmt,int id,int ad,int sid,int pid1,int pid2,int caid1,int caid2)76 void create_pmt(SPMT *pmt, int id, int ad, int sid, int pid1, int pid2,
77                 int caid1, int caid2) {
78     memset(pmt, 0, sizeof(*pmt));
79     pmt->id = id;
80     pmt->sid = sid;
81     pmt->adapter = ad;
82     pmt->pid = id * 1000;
83     pmt->stream_pid[0].pid = pid1;
84     pmt->stream_pid[0].type = 2;
85     pmt->stream_pid[1].pid = pid2;
86     pmt->stream_pid[0].type = 6;
87     pmt->stream_pids = 2;
88     pmt->ca[0].id = caid1;
89     pmt->ca[0].pid = caid1;
90     pmt->ca[1].id = caid2;
91     pmt->ca[1].pid = caid2;
92     pmt->caids = 2;
93     pmts[id] = pmt;
94     if (npmts <= id) {
95         npmts = id + 1;
96     }
97 }
98 
create_adapter(adapter * ad,int id)99 void create_adapter(adapter *ad, int id) {
100     memset(ad, 0, sizeof(adapter));
101     ad->enabled = 1;
102     ad->id = id;
103     a[id] = ad;
104 }
105 
test_channels()106 int test_channels() {
107     SHashTable h;
108     int i;
109     Sddci_channel c, *t;
110     memset(&h, 0, sizeof(h));
111     create_hash_table(&h, 10);
112     memset(&c, 0, sizeof(c));
113     c.sid = 200;
114     c.ddci[1].ddci = 1;
115     c.ddcis = 1;
116     setItem(&h, c.sid, &c, sizeof(c));
117     save_channels(&h, "/tmp/minisatip.channels");
118     free_hash(&h);
119     create_hash_table(&h, 10);
120     load_channels(&h, "/tmp/minisatip.channels");
121     ASSERT(getItem(&h, 200) != NULL, "Saved SID not found in table");
122     int ch = 0;
123     FOREACH_ITEM(&h, t) { ch++; }
124     ASSERT(ch == 1, "Expected one channel after loading");
125     free_hash(&h);
126     return 0;
127 }
128 
test_add_del_pmt()129 int test_add_del_pmt() {
130     int i;
131     SPMT pmt0, pmt1, pmt2, pmt3;
132     ddci_device_t d0, d1;
133     ca_device_t ca0, ca1;
134     adapter ad, a0, a1;
135 
136     create_adapter(&ad, 8);
137     create_adapter(&a0, 0);
138     create_adapter(&a1, 1);
139 
140     create_pmt(&pmt0, 0, 8, 100, 101, 102, 0x100, 0x1800);
141     create_pmt(&pmt1, 1, 8, 200, 201, 202, 0x100, 0x500);
142     create_pmt(&pmt2, 2, 8, 300, 301, 302, 0x500, 0x100);
143     create_pmt(&pmt3, 3, 8, 400, 401, 402, 0x600, 0x601);
144     memset(&d0, 0, sizeof(d0));
145     memset(&d1, 0, sizeof(d1));
146     memset(&d0.pmt, -1, sizeof(d0.pmt));
147     memset(&d1.pmt, -1, sizeof(d1.pmt));
148     d0.id = 0;
149     d1.id = 1;
150     d0.enabled = d1.enabled = 1;
151     ddci_devices[0] = &d0;
152     ddci_devices[1] = &d1;
153     create_hash_table(&d0.mapping, 30);
154     create_hash_table(&d1.mapping, 30);
155     create_hash_table(&channels, 30);
156 
157     dvbca_init();
158     // DD 0 - 0x100, DD 1 - 0x500
159     add_caid_mask(dvbca_id, 0, 0x100, 0xFFFF);
160     add_caid_mask(dvbca_id, 1, 0x500, 0xFFFF);
161     memset(&ca0, 0, sizeof(ca0));
162     memset(&ca1, 0, sizeof(ca1));
163     ca0.id = 0;
164     ca1.id = 1;
165     ca0.enabled = ca1.enabled = 1;
166     ca0.init_ok = 0;
167     ca1.init_ok = 1;
168     d0.max_channels = d1.max_channels = 1;
169     ca_devices[0] = &ca0;
170     ca_devices[1] = &ca1;
171     // No matching DDCI
172     ASSERT(ddci_process_pmt(&ad, &pmt3) == TABLES_RESULT_ERROR_RETRY,
173            "DDCI not ready, expected retry");
174 
175     ca0.init_ok = 1;
176     ASSERT(ddci_process_pmt(&ad, &pmt3) == TABLES_RESULT_ERROR_NORETRY,
177            "DDCI ready, expected no retry");
178 
179     // One matching channel
180     ASSERT(ddci_process_pmt(&ad, &pmt0) == TABLES_RESULT_OK,
181            "DDCI matching DD 0");
182     ASSERT(d0.pmt[0].id == 0, "PMT 0 using DDCI 0");
183 
184     ASSERT(ddci_process_pmt(&ad, &pmt1) == TABLES_RESULT_OK,
185            "DDCI matching DD 1");
186     ASSERT(d1.pmt[0].id == 1, "PMT 1 using DDCI 1");
187     d0.max_channels = d1.max_channels = 2;
188 
189     // Multiple PMTs
190     ASSERT(ddci_process_pmt(&ad, &pmt2) == TABLES_RESULT_OK,
191            "DDCI matching DD 0 for second PMT");
192     ASSERT(d0.pmt[1].id == 2, "PMT 2 using DDCI 0");
193     blacklist_pmt_for_ddci(&pmt2, 0);
194     ddci_del_pmt(&ad, &pmt2);
195 
196     // make sure we still have pids enabled from the first PMT
197     int ec = 0, j, k;
198     ddci_mapping_table_t *m;
199     int pmt_pids[MAX_ADAPTERS];
200     memset(pmt_pids, 0, sizeof(pmt_pids));
201     for (k = 0; k < 2; k++) {
202         FOREACH_ITEM(&ddci_devices[k]->mapping, m) {
203             ec++;
204             for (j = 0; j < m->npmt; j++)
205                 if (m->pmt[j] >= 0)
206                     pmt_pids[m->pmt[j]]++;
207         }
208     }
209     ASSERT(ec > 3, "Deleted Pids from the previously added PMT");
210     ASSERT(pmt_pids[0] > 0, "PMT 0 expected to have pids");
211     ASSERT(pmt_pids[1] > 0, "PMT 1 expected to have pids");
212     ASSERT(pmt_pids[2] == 0, "PMT 2 expected to NOT have pids");
213 
214     ASSERT(ddci_process_pmt(&ad, &pmt2) == TABLES_RESULT_OK,
215            "DDCI matching DD 1 for second PMT");
216     ASSERT(d1.pmt[1].id == 2, "PMT 2 using DDCI 1");
217 
218     int s = pmt2.stream_pids++;
219     int c = pmt2.caids++;
220     pmt2.stream_pid[s].pid = 0xFF;
221     pmt2.stream_pid[s].type = 2;
222     pmt2.ca[c].id = 0x502;
223     pmt2.ca[c].pid = 0xFE;
224 
225     ASSERT(ddci_process_pmt(&ad, &pmt2) == TABLES_RESULT_OK,
226            "DDCI matching DD 1 for adding again the PMT");
227 
228     m = get_pid_mapping_allddci(ad.id, 0xFF);
229     ASSERT(m != NULL, "Newly added pid not found in mapping table");
230     m = get_pid_mapping_allddci(ad.id, 0xFE);
231     ASSERT(m != NULL, "Newly added capid not found in mapping table");
232     blacklist_pmt_for_ddci(&pmt2, 0);
233     ddci_del_pmt(&ad, &pmt2);
234     ASSERT(ddci_process_pmt(&ad, &pmt2) == TABLES_RESULT_ERROR_NORETRY,
235            "DDCI should be blacklisted on all DDCIs");
236 
237     ddci_del_pmt(&ad, &pmt1);
238     ddci_del_pmt(&ad, &pmt0);
239 
240     ec = 0;
241     FOREACH_ITEM(&d0.mapping, m) { ec++; }
242     FOREACH_ITEM(&d1.mapping, m) { ec++; }
243     ASSERT(ec == 0, "No pid should be enabled");
244     free_hash(&d0.mapping);
245     free_hash(&d1.mapping);
246     free_hash(&channels);
247     free_filters();
248 
249     return 0;
250 }
251 
test_push_ts_to_ddci()252 int test_push_ts_to_ddci() {
253     ddci_device_t d;
254     adapter ad;
255     uint8_t buf[188 * 10];
256     d.id = 0;
257     d.enabled = 1;
258     d.out = malloc1(DDCI_BUFFER + 10);
259     d.wo = DDCI_BUFFER - 188;
260     memset(d.ro, -1, sizeof(d.ro));
261     d.ro[0] = 188;
262     memset(ddci_devices, 0, sizeof(ddci_devices));
263     ddci_devices[0] = &d;
264     create_adapter(&ad, 0);
265     push_ts_to_ddci_buffer(&d, buf, 376);
266     if (d.ro[0] != 376)
267         LOG_AND_RETURN(1, "test drop a packet when pushing 2 with wrap");
268     push_ts_to_ddci_buffer(&d, buf, 376);
269     if (d.ro[0] != 752 || d.wo != 564)
270         LOG_AND_RETURN(1, "test dropping 2 packets without wrapping");
271     d.ro[0] = 752;
272     d.wo = 0;
273     push_ts_to_ddci_buffer(&d, buf, 376);
274     if (d.wo != 376 || d.ro[0] != 752)
275         LOG_AND_RETURN(1, "push 376 bytes");
276     free1(d.out);
277     return 0;
278 }
279 
test_copy_ts_from_ddci()280 int test_copy_ts_from_ddci() {
281     ddci_device_t d;
282     ddci_mapping_table_t *m;
283     adapter ad;
284     uint8_t buf[188 * 10], buf2[188 * 10];
285     memset(&d, 0, sizeof(d));
286     memset(buf, 0, sizeof(buf));
287     memset(buf2, 0, sizeof(buf2));
288     d.id = 0;
289     d.enabled = 1;
290     d.out = malloc1(DDCI_BUFFER + 10);
291     create_hash_table(&d.mapping, 30);
292     memset(ddci_devices, 0, sizeof(ddci_devices));
293     ddci_devices[0] = &d;
294 
295     create_adapter(&ad, 1);
296     ad.buf = buf2;
297     ad.lbuf = sizeof(buf2);
298     int pid = 1000;
299     __attribute__((unused)) int ad_pos = 0;
300     buf[0] = buf2[0] = 0x47;
301     add_pid_mapping_table(2, pid, 9, &d,
302                           0); // forcing mapping to a different pid
303     add_pid_mapping_table(1, pid, 0, &d, 0);
304     m = get_pid_mapping_allddci(1, pid);
305     ASSERT(m != NULL, "Pid not found in mapping table");
306     int new_pid = m->ddci_pid;
307     ASSERT(new_pid == 1001, "Unexpected pid found after conflict");
308     ad.rlen = 188;
309     set_pid_ts(buf, new_pid);
310     set_pid_ts(buf2, 0x1FFF);
311 
312     if (push_ts_to_adapter(&ad, buf, pid, &ad_pos))
313         LOG_AND_RETURN(1, "could not copy the packet to the adapter");
314     if (PID_FROM_TS(buf2) != 1000)
315         LOG_AND_RETURN(1, "found pid %d expected %d", PID_FROM_TS(buf2), pid);
316     if (PID_FROM_TS(buf) != 0x1FFF)
317         LOG_AND_RETURN(1, "PID from the DDCI buffer not marked correctly %d",
318                        PID_FROM_TS(buf));
319 
320     set_pid_ts(buf, new_pid);
321     if (push_ts_to_adapter(&ad, buf, pid, &ad_pos))
322         LOG_AND_RETURN(1, "could not copy the packet to the adapter");
323     if (ad.rlen != 376)
324         LOG_AND_RETURN(1, "rlen not marked correctly %d", ad.rlen);
325     ad.rlen = ad.lbuf;
326     set_pid_ts(buf, new_pid);
327     if (1 != push_ts_to_adapter(&ad, buf, pid, &ad_pos))
328         LOG_AND_RETURN(1, "buffer full not returned correctly");
329 
330     free1(d.out);
331     free_hash(&d.mapping);
332     return 0;
333 }
334 
335 int is_err = 0;
336 int expected_pid = 0;
337 int did_write = 0;
xwritev(int fd,const struct iovec * io,int len)338 int xwritev(int fd, const struct iovec *io, int len) {
339     unsigned char *b = io[0].iov_base;
340     LOGM("called writev with len %d, first pid %d", len, PID_FROM_TS(b));
341     did_write = 1;
342     if (len != 1) {
343         is_err = 1;
344         LOG_AND_RETURN(
345             -1, "writev did not receive proper arguments, expected 1, got %d",
346             len);
347     }
348 
349     if (PID_FROM_TS(b) != expected_pid) {
350         is_err = 1;
351         LOG_AND_RETURN(-1,
352                        "writev did not receive proper TS, expected %d, got %d",
353                        expected_pid, PID_FROM_TS(b));
354     }
355     return len * 188;
356 }
357 
test_ddci_process_ts()358 int test_ddci_process_ts() {
359     ddci_device_t d;
360     uint8_t buf[188 * 10];
361     int i;
362     adapter ad;
363     memset(&d, 0, sizeof(d));
364     memset(buf, 0, sizeof(buf));
365     d.id = 0;
366     d.enabled = 1;
367     d.out = malloc1(DDCI_BUFFER + 10);
368     create_hash_table(&d.mapping, 30);
369     memset(ddci_devices, 0, sizeof(ddci_devices));
370     ddci_devices[0] = &d;
371     mutex_init(&d.mutex);
372     create_adapter(&ad, 1);
373     ad.buf = buf;
374     ad.lbuf = sizeof(buf);
375     for (i = 0; i < ad.lbuf; i += 188) {
376         buf[i] = 0x47;
377         set_pid_ts(buf + i, 2121); // unmapped pid
378     }
379     a[0]->enabled = 1;
380     a[1] = &ad;
381     buf[0] = 0x47;
382     pmts[0] = NULL;
383     add_pid_mapping_table(5, 1000, 0, &d, 0);
384     add_pid_mapping_table(5, 2000, 0, &d, 0);
385     int new_pid = add_pid_mapping_table(1, 1000, 0, &d, 0);
386     int new_pid2 = add_pid_mapping_table(1, 2000, 0, &d, 0);
387     ad.rlen = ad.lbuf - 188; // allow just 1 packet + 1 cleared that it will
388                              // be written to the socket
389     set_pid_ts(ad.buf + 188, 1000);
390     memset(d.ro, -1, sizeof(d.ro));
391     d.ro[1] = DDCI_BUFFER - 188;          // 1 packet before end of buffer
392     d.wo = 188 * 2;                       // 2 after end of the buffer
393     set_pid_ts(d.out + d.ro[1], new_pid); // first packet, expected 1000
394     set_pid_ts(d.out, new_pid2);
395     set_pid_ts(d.out + 188, new_pid2);
396     expected_pid = new_pid;
397     _writev = (mywritev)&xwritev;
398     d.last_pmt = getTick(); // prevent adding PMT/EPG
399     ddci_process_ts(&ad, &d);
400     if (is_err)
401         LOG_AND_RETURN(1, "is_err is set");
402     if (!did_write)
403         LOG_AND_RETURN(1, "no writev called");
404     if (PID_FROM_TS(ad.buf + 188) != 1000)
405         LOG_AND_RETURN(1, "expected pid 1000 in the adapter buffer, got %d",
406                        PID_FROM_TS(ad.buf + 188));
407     if (PID_FROM_TS(ad.buf + ad.lbuf - 188) != 2000)
408         LOG_AND_RETURN(1, "expected pid 2000 in the adapter buffer, got %d",
409                        PID_FROM_TS(ad.buf + ad.lbuf - 188));
410     if (ad.rlen != ad.lbuf)
411         LOG_AND_RETURN(1, "adapter buffer length mismatch %d != %d", ad.rlen,
412                        ad.lbuf);
413     if (d.ro[1] != 188 && d.wo != 188 * 2)
414         LOG_AND_RETURN(1, "indexes in DDCI devices set wrong ro %d wo %d", d.ro,
415                        d.wo);
416     free1(d.out);
417     free_hash(&d.mapping);
418     return 0;
419 }
test_create_pat()420 int test_create_pat() {
421     ddci_device_t d;
422     uint8_t psi[188];
423     uint8_t packet[188];
424     SPMT pmt;
425     char cc;
426     int psi_len;
427     SFilter f;
428     adapter ad;
429     memset(&pmt, 0, sizeof(pmt));
430     create_adapter(&ad, 0);
431 
432     memset(&d, 0, sizeof(d));
433     d.id = 0;
434     d.enabled = 1;
435     create_hash_table(&d.mapping, 30);
436     memset(ddci_devices, 0, sizeof(ddci_devices));
437     ddci_devices[0] = &d;
438     int pid = 4096;
439     add_pid_mapping_table(9, pid, 0, &d, 0);
440     int dpid = add_pid_mapping_table(0, pid, 0, &d, 0);
441     f.flags = FILTER_CRC;
442     f.id = 0;
443     f.adapter = 0;
444     d.pmt[0].id = 1;   // set to pmt 1
445     pmts[1] = &pmt; // enable pmt 1
446     npmts = 2;
447     pmt.enabled = 1;
448     pmt.sid = 0x66;
449     pmt.pid = pid;
450     psi_len = ddci_create_pat(&d, psi);
451     cc = 1;
452     buffer_to_ts(packet, 188, psi, psi_len, &cc, 0);
453     int len = assemble_packet(&f, packet);
454     if (!len)
455         return 1;
456     int new_sid = packet[17] * 256 + packet[18];
457     int new_pid = packet[19] * 256 + packet[20];
458     new_pid &= 0x1FFF;
459     if (new_pid != dpid)
460         LOG_AND_RETURN(1, "PAT pid %d != mapping table pid %d", new_pid, dpid);
461     if (new_sid != pmt.sid)
462         LOG_AND_RETURN(1, "PAT sid %d != pmt sid %d", new_sid, pmt.sid);
463     free_hash(&d.mapping);
464     return 0;
465 }
466 
test_create_pmt()467 int test_create_pmt() {
468     ddci_device_t d;
469     uint8_t psi[188];
470     uint8_t packet[188];
471 
472     SPMT pmt;
473     char cc;
474     int psi_len;
475     SFilter f;
476     memset(&d, 0, sizeof(d));
477     memset(&pmt, 0, sizeof(pmt));
478     d.id = 0;
479     d.enabled = 1;
480     a[0] = 0;
481     create_hash_table(&d.mapping, 30);
482     memset(ddci_devices, 0, sizeof(ddci_devices));
483     ddci_devices[0] = &d;
484     int pid = 1023;
485     int capid = 7068;
486     int dpid = add_pid_mapping_table(0, pid, 0, &d, 0);
487     int dcapid = add_pid_mapping_table(0, capid, 0, &d, 0);
488     f.flags = FILTER_CRC;
489     f.id = 0;
490     f.adapter = 0;
491     filters[0] = &f;
492     d.pmt[0].id = 1;   // set to pmt 1
493     pmts[1] = &pmt; // enable pmt 1
494     npmts = 2;
495     pmt.enabled = 1;
496     pmt.sid = 0x66;
497     pmt.pid = pid;
498     strcpy(pmt.name, "TEST CHANNEL HD");
499     pmt.pmt_len = 0;
500     pmt.caids = 1;
501     pmt.ca[0].id = 0x100;
502     pmt.ca[0].pid = capid;
503     pmt.ca[0].private_data_len = 2;
504     pmt.ca[0].private_data[0] = 1;
505     pmt.ca[0].private_data[1] = 2;
506     pmt.stream_pids = 2;
507     pmt.stream_pid[0].type = 0x1B;
508     pmt.stream_pid[0].pid = pid;
509     pmt.stream_pid[0].desc_len = 2;
510     pmt.stream_pid[0].desc[0] = 0x54;
511     pmt.stream_pid[0].desc[1] = 0;
512     pmt.stream_pid[1].type = 3;
513     pmt.stream_pid[1].pid = 0x55;
514 
515     psi_len = ddci_create_pmt(&d, &pmt, psi, sizeof(psi), 0, 8191);
516     cc = 1;
517     _hexdump("PACK: ", psi, psi_len);
518     buffer_to_ts(packet, 188, psi, psi_len, &cc, 0x63);
519     _hexdump("TS: ", packet, 188);
520     int len = assemble_packet(&f, packet);
521     if (!len) {
522         LOG("Assemble packet failed");
523         return 1;
524     }
525     int new_pid = packet[26] * 256 + packet[27];
526     int new_capid = packet[21] * 256 + packet[22];
527     new_pid &= 0x1FFF;
528     new_capid &= 0x1FFF;
529     if (new_pid != dpid)
530         LOG_AND_RETURN(1, "PMT stream pid %04X != mapping table pid %04X",
531                        new_pid, dpid);
532     if (new_capid != dcapid)
533         LOG_AND_RETURN(1, "PMT PSI pid %04X != mapping table pid %04X",
534                        new_capid, dcapid);
535     SPMT new_pmt;
536     memset(&new_pmt, 0, sizeof(pmt));
537     new_pmt.enabled = 1;
538     f.adapter = 0;
539     f.next_filter = -1;
540     f.pid = 0x99;
541     f.enabled = 1;
542     new_pmt.version = 1;
543     adapter ad;
544     ad.id = 0;
545     ad.enabled = 1;
546     a[0] = &ad;
547     ad.pids[0].pid = 0x99;
548     ad.pids[0].flags=1;
549     process_pmt(0, psi + 1, psi_len, &new_pmt);
550     filters[0] = NULL;
551     ASSERT(new_pmt.stream_pids == pmt.stream_pids,
552            "Number of streampids does not matches between generated PMT and "
553            "read PMT");
554     ASSERT(new_pmt.caids == pmt.caids, "Number of caids does not matches "
555                                        "between generated PMT and read PMT");
556 
557     free_hash(&d.mapping);
558     return 0;
559 }
560 
main()561 int main() {
562     opts.log = 65535;
563     opts.debug = 0;
564     strcpy(thread_name, "test");
565     TEST_FUNC(test_channels(), "testing test_channels");
566     TEST_FUNC(test_add_del_pmt(), "testing adding and removing pmts");
567     TEST_FUNC(test_push_ts_to_ddci(), "testing test_push_ts_to_ddci");
568     TEST_FUNC(test_copy_ts_from_ddci(), "testing test_copy_ts_from_ddci");
569     TEST_FUNC(test_ddci_process_ts(), "testing ddci_process_ts");
570     TEST_FUNC(test_create_pat(), "testing create_pat");
571     TEST_FUNC(test_create_pmt(), "testing create_pmt");
572     fflush(stdout);
573     return 0;
574 }
575