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