source: titan/titan/ca.h @ 32089

Last change on this file since 32089 was 31051, checked in by obi, 9 years ago

fix simulate i386 building

File size: 48.1 KB
Line 
1#ifndef CA_H
2#define CA_H
3
4//wait for a module inserted
5void cawait(struct stimerthread* self, struct dvbdev* dvbnode, int tout)
6{
7        unsigned int i = 0;
8        ca_slot_info_t info;
9
10        if(dvbnode == NULL || self == NULL) return;
11        info.num = dvbnode->devnr;
12
13        while(self->aktion == START)
14        {
15                if(cagetslotinfo(dvbnode, &info) == 0)
16                {
17                        if(info.flags & CA_CI_MODULE_READY)
18                                break;
19                }
20                sleep(1);
21                i++;
22                if(i >= tout) break;
23
24                if(dvbnode->caslot != NULL && dvbnode->caslot->status == 100) break;
25        }
26}
27
28//flag 0: don't flash buffer
29//flag 1: flush buffer
30void careseting(struct stimerthread* self, struct dvbdev* dvbnode, int flag)
31{
32        if(dvbnode != NULL)
33        {
34                struct queue* qe = NULL;
35                unsigned char buf[256];
36
37                ciclose(dvbnode, -1);
38                usleep(300000);
39                ciopen(dvbnode);
40
41                //flush buffer
42                if(flag == 1)
43                        while(dvbreadfd(dvbnode->fd, buf, 0, 256, -1, 0) > 0);
44
45                //flush queue
46                qe = getqueue(dvbnode->devnr);
47                while(qe != NULL)
48                {
49                        delqueue(qe, 0);
50                        qe = getqueue(dvbnode->devnr);
51                }
52
53                careset(dvbnode, dvbnode->devnr);
54                cawait(self, dvbnode, 10);
55        }
56}
57
58//wait for a while for some data und read it if some
59int caread(struct dvbdev* dvbnode, unsigned char* buf, int* len)
60{
61        int ret = 0, c = 0;
62        struct pollfd fds;
63
64        if(dvbnode == NULL || dvbnode->fd < 0) return -1;
65
66        fds.fd = dvbnode->fd;
67        fds.events = POLLOUT | POLLPRI | POLLIN;
68
69        ret = TEMP_FAILURE_RETRY(poll(&fds, 1, 300));
70
71        if(ret < 0)
72        {
73                err("poll data");
74                return -1; //error
75        }
76        else if(ret == 0)
77                return -2; //timeout
78        else if(ret > 0)
79        {
80                if(fds.revents & POLLIN)
81                {
82                        int readret = 0;
83retry:
84                        readret = TEMP_FAILURE_RETRY(read(dvbnode->fd, buf, *len));
85
86                        if(readret > 0)
87                        {
88                                if(debug_level == 620)
89                                {
90                                        int i = 0;
91                                        printf("CA Read (fd %d): > ", dvbnode->fd);
92                                        for(i = 0; i < readret; i++)
93                                                printf("%02x ", buf[i]);
94                                        printf("\n");
95                                }
96
97                                *len = readret;
98                                return 0; //ready
99                        }
100                        if(readret < 0 && errno == EAGAIN && c < 10)
101                        {
102                                c++;
103                                usleep(300000);
104                                goto retry;
105                        }
106                        *len = 0;
107                        if(fds.revents & POLLOUT && c == 10 && getqueue(dvbnode->devnr) != NULL)
108                        {
109                                perr("caread but queue not empty, so test a write, ret = %d", readret);
110                                return 1;
111                        }
112                        perr("caread ret = %d", readret);
113                        return -1; //error
114                }
115                else if(fds.revents & POLLOUT)
116                        return 1; //write
117                else if(fds.revents & POLLPRI)
118                        return 2; //change
119        }
120
121        perr("capoll ret = %d", ret);
122        return -1; //error
123}
124
125int cawrite(struct dvbdev* dvbnode, int fd, unsigned char* buf, int count, int flag, int tout)
126{
127        int ret = 0;
128
129        if(dvbnode != NULL)
130        {
131                if(debug_level == 620)
132                {
133                        int i = 0;
134                        printf("CA Write (slot %d fd %d): > ", dvbnode->devnr, dvbnode->fd);
135                        for(i = 0; i < count; i++)
136                                printf("%02x ", buf[i]);
137                        printf("\n");
138                }
139
140                if(dvbnode->caslot != NULL && flag == 0) dvbnode->caslot->fastrun = getconfigint("camwait", NULL);
141        }
142
143        ret = dvbwrite(fd, buf, count, tout);
144        if(ret >= 0 && ret == count && dvbnode != NULL && dvbnode->caslot != NULL) dvbnode->caslot->poll = 0;
145
146        return ret;
147}
148
149//send some data on an fd, for a special slot and connid
150int casend(struct dvbdev* dvbnode, unsigned char* buf, int len)
151{
152        unsigned char *tmpbuf = NULL;
153        int flag = 0;
154
155        if(dvbnode == NULL || dvbnode->caslot == NULL) return 1;
156        tmpbuf = (unsigned char*) malloc(len + 10);
157        if(tmpbuf == NULL)
158        {
159                err("no mem");
160                return 1;
161        }
162       
163#ifdef MIPSEL
164        memcpy(tmpbuf, buf, len);
165#else
166        // should we send a data last ?
167        if(buf != NULL)
168        {
169                if((buf[2] >= T_SB) && (buf[2] <= T_NEW_T_C))
170                        memcpy(tmpbuf, buf, len);
171                else
172                {
173                        //send data_last and data
174                        int lenfield = 0;
175
176                        tmpbuf[0] = dvbnode->devnr;
177                        tmpbuf[1] = dvbnode->caslot->connid;
178                        tmpbuf[2] = T_DATA_LAST;
179                        lenfield = writelengthfield(tmpbuf + 3, len + 1); //len
180                        tmpbuf[3 + lenfield] = dvbnode->caslot->connid; //transport connection identifier
181                       
182                        memcpy(tmpbuf + (4 + lenfield), buf, len);
183                        len += (4 + lenfield);
184                }
185        }
186        else
187        {
188                //send a data last only
189                tmpbuf[0] = dvbnode->devnr;
190                tmpbuf[1] = dvbnode->caslot->connid;
191                tmpbuf[2] = T_DATA_LAST;
192                tmpbuf[3] = 1; //len
193                tmpbuf[4] = dvbnode->caslot->connid; //transport connection identifier
194                len = 5;
195                flag = 1;
196        }
197#endif
198
199        if(debug_level == 620)
200        {
201                int i = 0;
202                printf("CA casend to queue (slot %d fd %d): > ", dvbnode->devnr, dvbnode->fd);
203                for(i = 0; i < len; i++)
204                        printf("%02x ", tmpbuf[i]);
205                printf("\n");
206        }
207       
208#ifdef MIPSEL
209        int ret = cawrite(dvbnode, dvbnode->fd, tmpbuf, len, flag, -1);
210        if(ret < 0 || ret != len)
211        {
212                err("writing data to queue, slot %d", dvbnode->devnr);
213                return 1; //error
214        }
215#else
216        struct queue* qe = addqueue(dvbnode->devnr, tmpbuf, len, NULL, 0, flag, NULL);
217        free(tmpbuf); tmpbuf = NULL;
218        if(qe == NULL)
219        {
220                err("writing data to queue, slot %d", dvbnode->devnr);
221                return 1; //error
222        }
223#endif
224
225        return 0; //ready
226}
227
228void sendSPDU(struct dvbdev* dvbnode, unsigned char tag, void *data, int len, int sessionnr, void *apdu, int alen)
229{
230        unsigned char* buf = NULL;
231        unsigned char *tmpbuf = NULL;
232
233        buf = calloc(1, MINMALLOC);
234        if(buf == NULL)
235        {
236                err("no mem");
237                return;
238        }
239
240        debug(620, "send SPDU, nr %d", sessionnr);
241
242        tmpbuf = buf;
243
244        *tmpbuf++ = tag;
245        tmpbuf += writelengthfield(tmpbuf, len + 2);
246
247        if(data != NULL) memcpy(tmpbuf, data, len);
248        tmpbuf += len;
249        *tmpbuf++ = sessionnr >> 8;
250        *tmpbuf++ = sessionnr;
251
252        if(apdu != NULL) memcpy(tmpbuf, apdu, alen);
253        tmpbuf += alen;
254
255        casend(dvbnode, buf, tmpbuf - buf);
256        free(buf); buf = NULL;
257}
258
259void sendAPDU(struct dvbdev* dvbnode, int sessionnr, unsigned char *tag, void *data, int len)
260{
261        debug(620, "send APDU, nr %d", sessionnr);
262
263        unsigned char buf[len + 3 + 4];
264        int lenfield = 0;
265
266        memcpy(buf, tag, 3);
267        lenfield = writelengthfield(buf + 3, len);
268
269        if(data != NULL) memcpy(buf + 3 + lenfield, data, len);
270        sendSPDU(dvbnode, 0x90, NULL, 0, sessionnr, buf, len + 3 + lenfield);
271}
272
273int parselenfield(unsigned char *buf, int* len)
274{
275        int i;
276
277        *len = 0;
278
279        if(!(*buf & 0x80))
280        {
281                *len = *buf;
282                return 1;
283        }
284
285        for(i = 0; i < (buf[0] & 0x7F); ++i)
286        {
287                *len <<= 8;
288                *len |= buf[i + 1];
289        }
290
291        return (buf[0] & 0x7F) + 1;
292}
293
294int asn1decode(uint16_t* lenret, unsigned char* asn1array, uint32_t asn1arraylen)
295{
296        uint8_t len;
297
298        if(asn1arraylen < 1 || asn1array == NULL) return -1;
299        len = asn1array[0];
300
301        if(len < 0x80)
302        {
303                //there is only one word
304                *lenret = len & 0x7f;
305                return 1;
306        }
307        else if(len == 0x81)
308        {
309                if(asn1arraylen < 2) return -1;
310                *lenret = asn1array[1];
311                return 2;
312        }
313        else if(len == 0x82)
314        {
315                if(asn1arraylen < 3) return -1;
316                *lenret = (asn1array[1] << 8) | asn1array[2];
317                return 3;
318        }
319
320        return -1;
321}
322
323//mmi functions
324
325int cammistop(struct dvbdev* dvbnode, int sessionnr)
326{
327        debug(620, "cammistop");
328
329        unsigned char tag[] = {0x9f, 0x88, 0x00};
330        unsigned char data[] = {0x00};
331        sendAPDU(dvbnode, sessionnr, tag, data, 1);
332
333        return 0;
334}
335
336int cammianswer(struct dvbdev* dvbnode, int sessionnr, int answer)
337{
338        debug(620, "cammianswer: %d", answer);
339
340        unsigned char tag[] = {0x9f, 0x88, 0x0B};
341        unsigned char data[] = {0x00};
342        data[0] = answer & 0xff;
343        sendAPDU(dvbnode, sessionnr, tag, data, 1);
344
345        return 0;
346}
347
348int cammianswerenq(struct dvbdev* dvbnode, int sessionnr, char *answer, int len)
349{
350        debug(620, "cammianswerenq (%d): %s", len, answer);
351
352        unsigned char data[len + 1];
353        data[0] = 0x01; //answer ok
354        memcpy(data + 1, answer, len);
355
356        unsigned char tag[] = {0x9f, 0x88, 0x08};
357        sendAPDU(dvbnode, sessionnr, tag, data, len + 1);
358
359        return 0;
360}
361
362int cammicancelenq(struct dvbdev* dvbnode, int sessionnr)
363{
364        debug(620, "cammicancelenq");
365
366        unsigned char tag[] = {0x9f, 0x88, 0x08};
367        unsigned char data[] = {0x00}; // canceled
368        sendAPDU(dvbnode, sessionnr, tag, data, 1);
369
370        return 0;
371}
372
373int cammiaction(struct dvbdev* dvbnode, int sessionnr)
374{
375        struct casession* casession = NULL;
376
377        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
378        casession = dvbnode->caslot->casession;
379
380        debug(620, "cammiaction nr %d, stat %d", sessionnr, casession[sessionnr].state);
381
382        switch(casession[sessionnr].state)
383        {
384                case CASESSIONSTART:
385                        debug(620, "state mmi sessionstart");
386                        casession[sessionnr].state = CAMMIIDLE;
387                        break;
388                case CAMMIDISPLAYREPLAY:
389                {
390                        debug(620, "state cammidisplayreplay");
391                        unsigned char tag[] = {0x9f, 0x88, 0x02};
392                        unsigned char data[] = {0x01, 0x01};
393                        sendAPDU(dvbnode, sessionnr, tag, data, 2);
394                        casession[sessionnr].state = CAMMIIDLE;
395                        //casession[sessionnr].state = CAMMIFAKEOK;
396                        //return 1;
397                        break;
398                }
399                case CAMMIFAKEOK:
400                {
401                        debug(620, "state cammifakeok");
402                        unsigned char tag[] = {0x9f, 0x88, 0x0b};
403                        unsigned char data[] = {5};
404                        sendAPDU(dvbnode, sessionnr, tag, data, 1);
405                        casession[sessionnr].state = CAMMIIDLE;
406                        break;
407                }
408                case CAMMIIDLE:
409                        debug(620, "state cammiidle");
410                        break;
411                default:
412                        break;
413        }
414        return 0;
415}
416
417int cammiAPDU(struct dvbdev* dvbnode, int sessionnr, unsigned char *tag, void *data, int len)
418{
419        char* tmpstr = NULL, *tmpstr1 = NULL;
420        struct casession* casession = NULL;
421        struct menulist* mlist = NULL, *mbox = NULL;
422
423        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
424        casession = dvbnode->caslot->casession;
425
426        debug(620, "mmi manager %02x %02x %02x", tag[0], tag[1], tag[2]);
427
428        if(debug_level == 620)
429        {
430                int i = 0;
431                printf("CA manager data (len %d): > ", len);
432                for(i = 0; i < len; i++)
433                        printf("%02x ", ((unsigned char*)data)[i]);
434                printf("\n");
435        }
436
437        if(tag[0] == 0x9f && tag[1] == 0x88)
438        {
439                switch(tag[2])
440                {
441                        case 0x00: //close
442                                cammistop(dvbnode, sessionnr);
443                                break;
444                        case 0x01: //display control
445                                casession[sessionnr].state = CAMMIDISPLAYREPLAY;
446                                return 1;
447                                break;
448                        case 0x07: //menu enq
449                        {
450                                unsigned char *tmpdata = data;
451                                unsigned char *max = tmpdata + len;
452                                int textlen = len - 2;
453
454                                if(tmpdata + 2 > max) break;
455                                int blind = *tmpdata++ & 1;
456                                int alen = *tmpdata++;
457
458                                debug(620, "mmi manager text len: %d, blind: %d", textlen, blind);
459
460                                if(tmpdata + textlen > max) break;
461
462                                char* str = malloc(textlen + 1);
463                                if(str == NULL)
464                                {
465                                        cammicancelenq(dvbnode, sessionnr);
466                                        break;
467                                }
468
469                                memcpy(str, tmpdata, textlen);
470                                str[textlen] = '\0';
471                                str = string_newline(str);
472
473                                debug(620, "mmi manager text: %s", str);
474
475                                int i = 0;
476                                for(i = 0; i < alen; i++) tmpstr1 = ostrcat(tmpstr1, "0", 1, 0);
477                                tmpstr = textinput(str, tmpstr1);
478                                if(tmpstr == NULL)
479                                        cammicancelenq(dvbnode, sessionnr);
480                                else
481                                {
482                                        if(strlen(tmpstr) > alen) tmpstr[alen] = '\0';
483                                        cammianswerenq(dvbnode, sessionnr, tmpstr, strlen(tmpstr));
484                                }
485                                free(tmpstr); tmpstr = NULL;
486                                free(tmpstr1); tmpstr1 = NULL;
487
488                        }
489                        break;
490                        case 0x09: //menu last
491                        case 0x0c: //list last
492                        {
493                                unsigned char *tmpdata = data;
494                                unsigned char *max= tmpdata + len;
495                                int pos = 0;
496
497                                if(tag[2] == 0x09)
498                                {
499                                        debug(620, "mmi manager menu last");
500                                }
501                                else
502                                {
503                                        debug(620, "mmi manager list last");
504                                }
505
506                                if(tmpdata > max) break;
507
508                                int n = *tmpdata++;
509
510                                if(n == 0xFF)
511                                        n = 0;
512                                else
513                                        n++;
514
515                                int i = 0;
516                                for(i = 0; i < (n + 3); ++i)
517                                {
518                                        int textlen = 0;
519                                        if(tmpdata + 3 > max) break;
520
521                                        debug(620, "mmi text tag: %02x %02x %02x", tmpdata[0], tmpdata[1], tmpdata[2]);
522                                        tmpdata += 3;
523                                        tmpdata += parselenfield(tmpdata, &textlen);
524
525                                        debug(620, "mmi manager text len: %d", textlen);
526                                        if(tmpdata + textlen > max) break;
527
528                                        char* str = malloc(textlen + 1);
529                                        if(str == NULL) break;
530                                        memcpy(str, tmpdata, textlen);
531                                        str[textlen] = '\0';
532                                        str = string_newline(str);
533
534                                        int type = pos++;
535
536                                        if(type == 0) // title
537                                                casession->mmititle = ostrcat(casession->mmititle, str, 1, 0);
538                                        else if(type == 1) // subtitle
539                                                casession->mmisubtitle = ostrcat(casession->mmisubtitle, str, 1, 0);
540                                        else if(type == 2) // bottom
541                                                casession->mmibottom = ostrcat(casession->mmibottom, str, 1, 0);
542                                        else // text
543                                        {
544                                                casession->mmitext = ostrcat(casession->mmitext, str, 1, 0);
545                                                casession->mmitext = ostrcat(casession->mmitext, "\n", 1, 0);
546                                        }
547
548                                        if(debug_level == 620)
549                                        {
550                                                printf("MMI Text: > ");
551                                                while(textlen--)
552                                                        printf("%c", *tmpdata++);
553                                                printf("\n");
554                                        }
555                                        else
556                                        {
557                                                while(textlen--)
558                                                        tmpdata++;
559                                        }
560
561                                }
562
563                                if(tag[2] == 0x09) //MENU
564                                {
565                                        tmpstr = ostrcat(tmpstr, casession->mmititle, 1, 0);
566                                        tmpstr = ostrcat(tmpstr, " - ", 1, 0);
567                                        tmpstr = ostrcat(tmpstr, casession->mmisubtitle, 1, 0);
568                                        tmpstr1 = ostrcat(tmpstr1, casession->mmitext, 1, 0);
569                                       
570                                        addmenulistall(&mlist, tmpstr1, NULL, 0, NULL);
571                                        mbox = menulistbox(mlist, "menulist", tmpstr, NULL, NULL, NULL, 1, 0);
572                                        if(mbox == NULL) //exit
573                                                cammistop(dvbnode, sessionnr);
574                                        else //got selnr
575                                        {
576                                                int i = 0, len = 0, slen = 0, selnr = 0, cmp = 1;
577
578                                                if(casession->mmitext != NULL)
579                                                        len = strlen(casession->mmitext);
580                                                slen = strlen(mbox->name);
581                                                for(i = 0; i < len; i++)
582                                                {
583                                                        if(cmp == 1)
584                                                        {
585                                                                cmp = 0;
586                                                                if(ostrncmp(mbox->name, &casession->mmitext[i], slen) == 0)
587                                                                        break;
588                                                        }
589
590                                                        if(casession->mmitext[i] == '\n')
591                                                        {
592                                                                selnr++;
593                                                                cmp = 1;
594                                                        }
595                                                }
596
597                                                cammianswer(dvbnode, sessionnr, selnr + 1);
598                                        }
599                                        freemenulist(mlist, 1); mlist = NULL;
600                                        free(tmpstr); tmpstr = NULL;
601                                        free(tmpstr1); tmpstr1 = NULL;
602                                        free(casession->mmititle); casession->mmititle = NULL;
603                                        free(casession->mmisubtitle); casession->mmisubtitle = NULL;
604                                        free(casession->mmitext); casession->mmitext = NULL;
605                                        free(casession->mmibottom); casession->mmibottom = NULL;
606                                }
607                                else //LIST
608                                {
609                                        tmpstr = ostrcat(tmpstr, casession->mmititle, 1, 0);
610                                        if(casession->mmisubtitle != NULL)
611                                        {
612                                                tmpstr1 = ostrcat(tmpstr1, casession->mmisubtitle, 1, 0);
613                                                tmpstr1 = ostrcat(tmpstr1, "\n\n", 1, 0);
614                                        }
615                                        if(casession->mmitext != NULL)
616                                        {
617                                                tmpstr1 = ostrcat(tmpstr1, casession->mmitext, 1, 0);
618                                                tmpstr1 = ostrcat(tmpstr1, "\n\n", 1, 0);
619                                        }
620                                        tmpstr1 = ostrcat(tmpstr1, casession->mmibottom, 1, 0);
621                                        if(getconfigint("nocamsg", NULL) == 0)
622                                                textbox(_(tmpstr), _(tmpstr1), NULL, getrcconfigint("rcok", NULL), NULL, getrcconfigint("rcexit", NULL), NULL, 0, NULL, 0, 600, 300, 7, 0);
623                                        free(tmpstr); tmpstr = NULL;
624                                        free(tmpstr1); tmpstr1 = NULL;
625                                        free(casession->mmititle); casession->mmititle = NULL;
626                                        free(casession->mmisubtitle); casession->mmisubtitle = NULL;
627                                        free(casession->mmitext); casession->mmitext = NULL;
628                                        free(casession->mmibottom); casession->mmibottom = NULL;
629                                        cammistop(dvbnode, sessionnr);
630                                }
631
632                        }
633                        break;
634                }
635        }
636        return 0;
637}
638
639//ca functions
640
641int cacaaction(struct dvbdev* dvbnode, int sessionnr)
642{
643        struct casession* casession = NULL;
644
645        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
646        casession = dvbnode->caslot->casession;
647
648        debug(620, "cacaaction nr %d, stat %d", sessionnr, casession[sessionnr].state);
649
650        switch(casession[sessionnr].state)
651        {
652                case CASESSIONSTART:
653                {
654                        debug(620, "state ca sessionstart");
655                        unsigned char tag[3] = {0x9F, 0x80, 0x30}; //ca info enq
656                        sendAPDU(dvbnode, sessionnr, tag, NULL, 0);
657                        casession[sessionnr].state = CASESSIONFINAL;
658                        return 0;
659                }
660                case CASESSIONFINAL:
661                        debug(620, "state cacafinal and action is not ok");
662                default:
663                        return 0;
664        }
665}
666
667int cacaAPDU(struct dvbdev* dvbnode, int sessionnr, unsigned char *tag, void *data, int len)
668{
669        int i = 0;
670        struct casession* casession = NULL;
671
672        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
673        casession = dvbnode->caslot->casession;
674
675        debug(620, "ca manager %02x %02x %02x", tag[0], tag[1], tag[2]);
676
677        if(debug_level == 620)
678        {
679                i = 0;
680                printf("CA manager data (len %d): > ", len);
681                for(i = 0; i < len; i++)
682                        printf("%02x ", ((unsigned char*)data)[i]);
683                printf("\n");
684        }
685
686        if(tag[0] == 0x9f && tag[1] == 0x80)
687        {
688                switch(tag[2])
689                {
690                        case 0x31: //ca info
691                                if(debug_level == 620)
692                                {
693                                        i = 0;
694                                        printf("Ca info (len %d): > ", len);
695                                        for(i = 0; i < len; i += 2)
696                                        {
697                                                printf("%04x ", (((unsigned char*)data)[i] << 8) | (((unsigned char*)data)[i + 1]));
698                                        }
699                                        printf("\n");
700                                }
701
702                                free(dvbnode->caslot->caids);
703                                dvbnode->caslot->caids = NULL;
704                                i = 0;
705                                for(i = 0; i < len; i += 2)
706                                {
707                                        dvbnode->caslot->caids = ostrcat(dvbnode->caslot->caids, "#", 1, 0);
708                                        dvbnode->caslot->caids = ostrcat(dvbnode->caslot->caids, oitoa((((unsigned char*)data)[i] << 8) | ((unsigned char*)data)[i + 1]), 1, 1);
709                                        dvbnode->caslot->caids = ostrcat(dvbnode->caslot->caids, "#", 1, 0);
710                                }
711                                break;
712                        case 0x33: //ca pmt reply
713                                if(len > 3)
714                                {
715                                        if(((unsigned char*)data)[3] == 0x81) //can descrambling
716                                        {
717                                                status.checkcamdecrypt = -1;
718                                                debug(620, "cam say's he can handel decrypt");
719                                        }
720                                        else
721                                        {
722                                                status.checkcamdecrypt = -2;
723                                                debug(620, "cam say's he can not handel decrypt");
724                                        }
725                                }
726                                break;
727                        default:
728                                debug(620, "unknown APDU tag 9F 80 %02x\n", tag[2]);
729                                break;
730                }
731        }
732        return 0;
733}
734
735//datetime functions
736
737int cadatetimeaction(struct dvbdev* dvbnode, int sessionnr)
738{
739        struct casession* casession = NULL;
740
741        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
742        casession = dvbnode->caslot->casession;
743
744        debug(620, "cadatetimeaction nr %d, stat %d", sessionnr, casession[sessionnr].state);
745
746        switch(casession[sessionnr].state)
747        {
748                case CASESSIONSTART:
749                        debug(620, "state cadatetime sessionstart");
750                        return 0;
751                case CADATETIMESEND:
752                {
753                        debug(620, "state cadatetimesend");
754                        unsigned char tag[3] = {0x9f, 0x84, 0x41}; //datetime response
755                        unsigned char msg[7] = {0, 0, 0, 0, 0, 0, 0};
756                        sendAPDU(dvbnode, sessionnr, tag, msg, 7);
757                        return 0;
758                }
759                case CASESSIONFINAL:
760                        debug(620, "state cadatetimefinal and action is not ok");
761                default:
762                        return 0;
763        }
764}
765
766int cadatetimeAPDU(struct dvbdev* dvbnode, int sessionnr, unsigned char *tag, void *data, int len)
767{
768        struct casession* casession = NULL;
769
770        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
771        casession = dvbnode->caslot->casession;
772
773        debug(620, "datetime manager %02x %02x %02x", tag[0], tag[1], tag[2]);
774
775        if(debug_level == 620)
776        {
777                int i = 0;
778                printf("Datetime manager data (len %d): > ", len);
779                for(i = 0; i < len; i++)
780                        printf("%02x ", ((unsigned char*)data)[i]);
781                printf("\n");
782        }
783
784        if(tag[0] == 0x9f && tag[1] == 0x84)
785        {
786                switch(tag[2])
787                {
788                        case 0x40:
789                                casession[sessionnr].state = CADATETIMESEND;
790                                return 1;
791                                break;
792                        default:
793                                debug(620, "unknown APDU tag 9F 84 %02x\n", tag[2]);
794                                break;
795                }
796        }
797
798        return 0;
799}
800
801//res function
802
803int caresaction(struct dvbdev* dvbnode, int sessionnr)
804{
805        struct casession* casession = NULL;
806
807        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
808        casession = dvbnode->caslot->casession;
809
810        debug(620, "caresaction nr %d, stat %d", sessionnr, casession[sessionnr].state);
811
812        switch(casession[sessionnr].state)
813        {
814                case CASESSIONSTART:
815                {
816                        debug(620, "state cares sessionstart");
817                        unsigned char tag[3] = {0x9F, 0x80, 0x10}; //profile enquiry
818                        sendAPDU(dvbnode, sessionnr, tag, NULL, 0);
819                        casession[sessionnr].state = CARESFIRSTENQUIRY;
820                        return 0;
821                }
822                case CARESFIRSTENQUIRY:
823                {
824                        debug(620, "state caresfirstenquiry");
825                        unsigned char tag[3] = {0x9F, 0x80, 0x12}; //profile change
826                        sendAPDU(dvbnode, sessionnr, tag, NULL, 0);
827                        casession[sessionnr].state = CARESCHANGE;
828                        return 0;
829                }
830                case CARESCHANGE:
831                {
832                        debug(620, "state careschange not ok");
833                        break;
834                }
835                case CARESENQUIRY:
836                {
837                        debug(620, "state caresenquiry");
838                        unsigned char tag[3] = {0x9F, 0x80, 0x11};
839                        unsigned char data[][4]=
840                        {
841                                {0x00, 0x01, 0x00, 0x41},
842                                {0x00, 0x02, 0x00, 0x41},
843                                {0x00, 0x03, 0x00, 0x41},
844                                //{0x00, 0x20, 0x00, 0x41}, //host control
845                                {0x00, 0x24, 0x00, 0x41},
846                                {0x00, 0x40, 0x00, 0x41}
847                                //{0x00, 0x10, 0x00, 0x41} //auth.
848                        };
849                        sendAPDU(dvbnode, sessionnr, tag, data, sizeof(data));
850                        casession[sessionnr].state = CASESSIONFINAL;
851                        return 0;
852                }
853                case CASESSIONFINAL:
854                        debug(620, "state caresfinal and action is not ok");
855                default:
856                        break;
857        }
858
859        return 0;
860}
861
862int caresAPDU(struct dvbdev* dvbnode, int sessionnr, unsigned char *tag, void *data, int len)
863{
864        struct casession* casession = NULL;
865
866        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
867        casession = dvbnode->caslot->casession;
868
869        debug(620, "res manager %02x %02x %02x", tag[0], tag[1], tag[2]);
870
871        if(debug_level == 620)
872        {
873                int i = 0;
874                printf("Res manager data (len %d): > ", len);
875                for(i = 0; i < len; i++)
876                        printf("%02x ", ((unsigned char*)data)[i]);
877                printf("\n");
878        }
879
880        if(tag[0] == 0x9f && tag[1] == 0x80)
881        {
882                switch(tag[2])
883                {
884                        case 0x10:  // profile enquiry
885                                debug(620, "cam ask what can i");
886                                casession[sessionnr].state = CARESENQUIRY;
887                                return 1;
888                        case 0x11: // Tprofile
889                                if(debug_level == 620)
890                                {
891                                        printf("My cam can: > ");
892                                        if(!len)
893                                                printf("nothing\n");
894                                        else
895                                        {
896                                                int i = 0;
897                                                for (i = 0; i < len; i++)
898                                                        printf("%02x ", ((unsigned char*)data)[i]);
899                                        }
900                                }
901
902                                if(casession[sessionnr].state == CARESFIRSTENQUIRY)
903                                {
904                                        // profile change
905                                        return 1;
906                                }
907                                casession[sessionnr].state = CASESSIONFINAL;
908                                break;
909                        default:
910                                debug(620, "unknown APDU tag 9F 80 %02x\n", tag[2]);
911                }
912        }
913
914        return 0;
915}
916
917//app functions
918
919void caappmenu(struct dvbdev* dvbnode)
920{
921        //must be send to the app session
922        debug(620, "caappmenu");
923        unsigned char tag[3] = {0x9F, 0x80, 0x22};  //Tenter_menu
924        int sessionnr = 0;
925
926        sessionnr = getfreecasession(dvbnode, 1, 1);
927        if(sessionnr > -1)
928                sendAPDU(dvbnode, sessionnr, tag, NULL, 0);
929}
930
931int caappaction(struct dvbdev* dvbnode, int sessionnr)
932{
933        struct casession* casession = NULL;
934
935        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
936        casession = dvbnode->caslot->casession;
937
938        debug(620, "caappaction nr %d, stat %d", sessionnr, casession[sessionnr].state);
939
940        switch(casession[sessionnr].state)
941        {
942                case CASESSIONSTART:
943                {
944                        debug(620, "state app sessionstart");
945                        unsigned char tag[3] = {0x9F, 0x80, 0x20}; //app manager info
946
947                        sendAPDU(dvbnode, sessionnr, tag, NULL, 0);
948                        casession[sessionnr].state = CASESSIONFINAL;
949                        return 1;
950                }
951                case CASESSIONFINAL:
952                {
953                        debug(620, "state app sessionfinal");
954                        return 0;
955                }
956                default:
957                        return 0;
958        }
959}
960
961int caappAPDU(struct dvbdev* dvbnode, int sessionnr, unsigned char *tag, void *data, int len)
962{
963        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
964
965        debug(620, "app manager %02x %02x %02x", tag[0], tag[1], tag[2]);
966
967        if(debug_level == 620)
968        {
969                int i = 0;
970                printf("App manager data (len %d): > ", len);
971                for(i = 0; i < len; i++)
972                        printf("%02x ", ((unsigned char*)data)[i]);
973                printf("\n");
974        }
975
976        if(tag[0] == 0x9f && tag[1] == 0x80)
977        {
978                switch (tag[2])
979                {
980                        case 0x21:
981                        {
982                                int dl;
983                                debug(620, "app manager info:");
984                                debug(620, "len: %d", len);
985                                debug(620, "type: %d", ((unsigned char*)data)[0]);
986                                debug(620, "manufacturer: %02x %02x", ((unsigned char*)data)[2], ((unsigned char*)data)[1]);
987                                debug(620, "code: %02x %02x", ((unsigned char*)data)[4],((unsigned char*)data)[3]);
988
989                                dl = ((unsigned char*)data)[5];
990                                if(dl + 6 > len)
991                                {
992                                        debug(620, "invalid length (%d vs %d)", dl + 6, len);
993                                        dl = len - 6;
994                                }
995
996                                char str[dl + 1];
997                                memcpy(str, data + 6, dl);
998                                str[dl] = '\0';
999
1000                                if(debug_level == 620)
1001                                {
1002                                        int i = 0;
1003                                        printf("Menu string (len %d): > ", dl);
1004                                        for(i = 0; i < dl; ++i)
1005                                                printf("%c", ((unsigned char*)data)[i + 6]);
1006                                        printf("\n");
1007                                }
1008
1009                                free(dvbnode->caslot->name);
1010                                dvbnode->caslot->name = strstrip(ostrcat(str, NULL, 0, 1));
1011                                debug(620, "set name %s on slot %d", dvbnode->caslot->name, dvbnode->devnr);
1012                                break;
1013                        }
1014                        default:
1015                        {
1016                                debug(620, "unknown APDU tag 9F 80 %02x\n", tag[2]);
1017                                break;
1018                        }
1019                }
1020        }
1021
1022        return 0;
1023}
1024
1025//session functions
1026
1027//inuse: 1 is only that the session is in use
1028//inuse: >1 the session is used for decrypt
1029int getfreecasession(struct dvbdev* dvbnode, int type, int value)
1030{
1031        int i;
1032
1033        if(dvbnode != NULL && dvbnode->caslot != NULL)
1034        {
1035                for(i = 0; i < MAXCASESSION; i++)
1036                {
1037                        if(type == 0 && dvbnode->caslot->casession[i].resmanager == 1 && dvbnode->caslot->casession[i].inuse == 1) //resmanager
1038                        {
1039                                dvbnode->caslot->casession[i].inuse = value;
1040                                return i;
1041                        }
1042                        if(type == 1 && dvbnode->caslot->casession[i].appmanager == 1 && dvbnode->caslot->casession[i].inuse == 1) //appmanager
1043                        {
1044                                dvbnode->caslot->casession[i].inuse = value;
1045                                return i;
1046                        }
1047                        if(type == 2 && dvbnode->caslot->casession[i].camanager == 1 && dvbnode->caslot->casession[i].inuse == 1) //camanager
1048                        {
1049                                dvbnode->caslot->casession[i].inuse = value;
1050                                return i;
1051                        }
1052                        if(type == 3 && dvbnode->caslot->casession[i].datetimemanager == 1 && dvbnode->caslot->casession[i].inuse == 1) //datetimemanager
1053                        {
1054                                dvbnode->caslot->casession[i].inuse = value;
1055                                return i;
1056                        }
1057                        if(type == 4 && dvbnode->caslot->casession[i].mmimanager == 1 && dvbnode->caslot->casession[i].inuse == 1) //mmimemanager
1058                        {
1059                                dvbnode->caslot->casession[i].inuse = value;
1060                                return i;
1061                        }
1062                }
1063        }
1064        return -1;
1065}
1066
1067void casessiondel(struct dvbdev* dvbnode, int sessionnr)
1068{
1069        if(dvbnode != NULL && dvbnode->caslot != NULL)
1070        {
1071                free(dvbnode->caslot->casession[sessionnr].mmititle);
1072                free(dvbnode->caslot->casession[sessionnr].mmisubtitle);
1073                free(dvbnode->caslot->casession[sessionnr].mmitext);
1074                free(dvbnode->caslot->casession[sessionnr].mmibottom);
1075                memset(&dvbnode->caslot->casession[sessionnr], 0, sizeof(struct casession));
1076        }
1077}
1078
1079void casessionfree(struct dvbdev* dvbnode)
1080{
1081        int i = 0;
1082
1083        for(i = 0; i < MAXCASESSION; i++)
1084                casessiondel(dvbnode, i);
1085}
1086
1087int casessionpoll(struct dvbdev* dvbnode)
1088{
1089        int sessionnr = 0;
1090        struct casession* casession = NULL;
1091
1092        if(dvbnode == NULL || dvbnode->caslot == NULL) return 0;
1093        casession = dvbnode->caslot->casession;
1094
1095        for(sessionnr = 1; sessionnr < MAXCASESSION; ++sessionnr)
1096        {
1097                if(casession[sessionnr].inuse > 0)
1098                {
1099                        if(casession[sessionnr].state == CASESSIONDEL)
1100                        {
1101                                unsigned char data[1] = {0x00};
1102                                sendSPDU(dvbnode, 0x96, data, 1, sessionnr, NULL, 0);
1103                                casessiondel(dvbnode, sessionnr);
1104                                return 1;
1105                        }
1106                        else if(casession[sessionnr].action == 1)
1107                        {
1108                                if(casession[sessionnr].resmanager == 1)
1109                                        casession[sessionnr].action = caresaction(dvbnode, sessionnr);
1110                                else if(casession[sessionnr].appmanager == 1)
1111                                        casession[sessionnr].action = caappaction(dvbnode, sessionnr);
1112                                else if(casession[sessionnr].camanager == 1)
1113                                        casession[sessionnr].action = cacaaction(dvbnode, sessionnr);
1114                                else if(casession[sessionnr].datetimemanager == 1)
1115                                        casession[sessionnr].action = cadatetimeaction(dvbnode, sessionnr);
1116                                else if(casession[sessionnr].mmimanager == 1)
1117                                        casession[sessionnr].action = cammiaction(dvbnode, sessionnr);
1118                                return 1;
1119                        }
1120                }
1121        }
1122        return 0;
1123}
1124
1125struct casession* casessioncreate(struct dvbdev* dvbnode, unsigned char* resid, unsigned char status, unsigned long newtag)
1126{
1127        unsigned long tag = 0;
1128        int sessionnr = 0;
1129        struct casession* casession = NULL;
1130
1131        if(dvbnode == NULL || dvbnode->caslot == NULL) return NULL;
1132        casession = dvbnode->caslot->casession;
1133
1134        for(sessionnr = 1; sessionnr < MAXCASESSION; ++sessionnr)
1135                if(casession[sessionnr].inuse == 0)
1136                        break;
1137
1138        if(sessionnr == MAXCASESSION)
1139        {
1140                status = 0xF3;
1141                debug(620, "no free session found nr = %d", sessionnr);
1142                return NULL;
1143        }
1144
1145        debug(620, "use sessionnr = %d", sessionnr);
1146        if(newtag == 0)
1147        {
1148                tag = resid[0] << 24;
1149                tag |= resid[1] << 16;
1150                tag |= resid[2] << 8;
1151                tag |= resid[3];
1152        }
1153        else
1154                tag = newtag;
1155
1156        switch(tag)
1157        {
1158                case 0x00010041:
1159                        casession[sessionnr].inuse = 1;
1160                        casession[sessionnr].resmanager = 1;
1161                        debug(620, "create session res manager");
1162                        break;
1163                case 0x00020041:
1164                        casession[sessionnr].inuse = 1;
1165                        casession[sessionnr].appmanager = 1;
1166                        debug(620, "create session app manager");
1167                        break;
1168                case 0x00030041:
1169                        casession[sessionnr].inuse = 1;
1170                        casession[sessionnr].camanager = 1;
1171                        debug(620, "create session ca manager");
1172                        break;
1173                case 0x00240041:
1174                        casession[sessionnr].inuse = 1;
1175                        casession[sessionnr].datetimemanager = 1;
1176                        debug(620, "create session datetime manager");
1177                        break;
1178                case 0x00400041:
1179                        casession[sessionnr].inuse = 1;
1180                        casession[sessionnr].mmimanager = 1;
1181                        debug(620, "create session mmi manager");
1182                        break;
1183                case 0x00100041:
1184                        debug(620, "create session auth manager");
1185                case 0x00200041:
1186                default:
1187                        status = 0xF0;
1188                        if(resid != NULL)
1189                                debug(620, "unknown resource type %02x %02x %02x %02x\n", resid[0], resid[1], resid[2], resid[3]);
1190                        return NULL;
1191        }
1192
1193        debug(620, "new session nr: %d", sessionnr);
1194        casession[sessionnr].sessionnr = sessionnr;
1195        casession[sessionnr].state = CASESSIONCREATE;
1196        status = 0;
1197
1198        if(newtag != 0)
1199        {
1200                unsigned char data[4];
1201                data[0] = (newtag >> 24) & 0xff;
1202                data[1] = (newtag >> 16) & 0xff;
1203                data[2] = (newtag >> 8) & 0xff;
1204                data[3] = newtag & 0xff;
1205                sendSPDU(dvbnode, 0x93, data, 4, sessionnr, NULL, 0);
1206        }
1207
1208        return &casession[sessionnr];
1209}
1210
1211void casessionreceive(struct dvbdev* dvbnode, unsigned char *buf, size_t len)
1212{
1213        unsigned char *pkt = buf;
1214        unsigned char tag = *pkt++;
1215        int llen = 0, hlen = 0;
1216        struct casession* casession = NULL;
1217        int sessionnr = 0;
1218
1219        if(dvbnode == NULL || dvbnode->caslot == NULL) return;
1220
1221        if(debug_level == 620)
1222        {
1223                printf("Session Data (len %d): > ", len);
1224                int i = 0;
1225                for(i = 0; i < len; i++)
1226                        printf("%02x ", buf[i]);
1227                printf("\n");
1228        }
1229
1230        llen = parselenfield(pkt, &hlen);
1231        pkt += llen;
1232
1233        if(tag == 0x91)
1234        {
1235                unsigned char status = 0;
1236
1237                casession = casessioncreate(dvbnode, pkt, status, 0);
1238
1239                //open session
1240                unsigned char data[6];
1241                data[0] = status;
1242                memcpy(data + 1, pkt, 4);
1243                if(casession != NULL)
1244                {
1245                        sendSPDU(dvbnode, 0x92, data, 5, casession->sessionnr, NULL, 0);
1246                        casession->state = CASESSIONSTART;
1247                        casession->action = 1;
1248                }
1249                else
1250                        sendSPDU(dvbnode, 0x92, data, 5, 0, NULL, 0);
1251        }
1252        else
1253        {
1254                sessionnr = pkt[hlen - 2] << 8;
1255                sessionnr |= pkt[hlen - 1] & 0xFF;
1256                debug(620, "tag = %x, hlen = %d, session = %d", tag, hlen, sessionnr);
1257
1258                if(sessionnr < 1 || sessionnr >= MAXCASESSION)
1259                {
1260                        debug(620, "illegal session number %d", sessionnr);
1261                        return;
1262                }
1263
1264                casession = &dvbnode->caslot->casession[sessionnr];
1265                if(casession->inuse == 0)
1266                {
1267                        debug(620, "data on closed session %d", sessionnr);
1268                        return;
1269                }
1270
1271                switch(tag)
1272                {
1273                        case 0x90:
1274                                break;
1275                        case 0x94:
1276                                debug(620, "recv create session response %02x", pkt[0]);
1277                                if(pkt[0] != 0)
1278                                        casessiondel(dvbnode, sessionnr);
1279                                else
1280                                {
1281                                        casession->state = CASESSIONSTART;
1282                                        casession->action = 1;
1283                                }
1284                                break;
1285                        case 0x95:
1286                                debug(620, "recv close session");
1287                                casession->state = CASESSIONDEL;
1288                                casession->action = 1;
1289                                break;
1290                        default:
1291                                debug(620, "not supported tag %02x", tag);
1292                                return;
1293                }
1294        }
1295
1296        hlen += llen + 1; // lengthfield and tag
1297
1298        pkt = buf + hlen;
1299        len -= hlen;
1300
1301        if(casession != NULL)
1302        {
1303                debug(620, "len %d", len);
1304                while(len > 0)
1305                {
1306                        int alen = 0;
1307                        unsigned char *tag = pkt;
1308                        pkt += 3; //tag
1309                        len -= 3;
1310                        hlen = parselenfield(pkt, &alen);
1311                        pkt += hlen;
1312                        len -= hlen;
1313                        debug(620, "len = %d, hlen = %d, alen = %d", len, hlen, alen);
1314
1315                        if(len - alen > 0 && len - alen < 3)
1316                                alen = len;
1317
1318                        debug(620, "got APDU tag = 0x%2x, len = %d", (int)tag, alen);
1319
1320                        if(casession->resmanager == 1)
1321                        {
1322                                if(caresAPDU(dvbnode, sessionnr, tag, pkt, alen))
1323                                        casession->action = 1;
1324                        }
1325                        else if(casession->appmanager == 1)
1326                        {
1327                                if(caappAPDU(dvbnode, sessionnr, tag, pkt, alen))
1328                                        casession->action = 1;
1329                        }
1330                        else if(casession->camanager == 1)
1331                        {
1332                                if(cacaAPDU(dvbnode, sessionnr, tag, pkt, alen))
1333                                        casession->action = 1;
1334                        }
1335                        else if(casession->datetimemanager == 1)
1336                        {
1337                                if(cadatetimeAPDU(dvbnode, sessionnr, tag, pkt, alen))
1338                                        casession->action = 1;
1339                        }
1340                        else if(casession->mmimanager == 1)
1341                        {
1342                                if(cammiAPDU(dvbnode, sessionnr, tag, pkt, alen))
1343                                        casession->action = 1;
1344                        }
1345                        pkt += alen;
1346                        len -= alen;
1347                }
1348
1349        }
1350
1351        if(len != 0)
1352                debug(620, "warning, TL-Data has invalid length");
1353}
1354
1355//slot function
1356
1357//send a transport connection create request
1358int cacreatetc(struct dvbdev* dvbnode)
1359{
1360        int ret = 0;
1361        unsigned char* buf = NULL;
1362
1363        if(dvbnode == NULL || dvbnode->caslot == NULL ) return 1;
1364
1365        buf = (unsigned char*) malloc(sizeof(char) * 5);
1366        if(buf == NULL)
1367        {
1368                err("no mem");
1369                return 1;
1370        }
1371
1372        buf[0] = dvbnode->devnr;
1373        buf[1] = dvbnode->caslot->connid;
1374        buf[2] = T_CREATE_T_C;
1375        buf[3] = 1;
1376        buf[4] = dvbnode->caslot->connid;
1377
1378        ret = cawrite(dvbnode, dvbnode->fd, buf, 5, 0, -1);
1379        free(buf); buf = NULL;
1380        dvbnode->caslot->poll = 0;
1381
1382        return ret;
1383}
1384
1385void caslotfree(struct dvbdev* dvbnode)
1386{
1387        if(dvbnode != NULL && dvbnode->caslot != NULL)
1388        {
1389                free(dvbnode->caslot->name);
1390                dvbnode->caslot->name = NULL;
1391                free(dvbnode->caslot->rbuf);
1392                dvbnode->caslot->rbuf = NULL;
1393                free(dvbnode->caslot->caids);
1394                dvbnode->caslot->caids = NULL;
1395                memset(dvbnode->caslot, 0, sizeof(struct caslot));
1396        }
1397        if(dvbnode != NULL) caservicedel(NULL, dvbnode->caslot);
1398}
1399
1400void processtpdu(struct dvbdev* dvbnode, unsigned char tpdutag, unsigned char* buf, int asnlen)
1401{
1402        struct caslot* canode = NULL;
1403
1404        if(dvbdev == NULL) return;
1405        canode = dvbnode->caslot;
1406
1407        switch(tpdutag)
1408        {
1409                case T_C_T_C_REPLY:
1410                        debug(620, "got ctc replay (slot %d, conn %d)", dvbnode->devnr, canode->connid);
1411
1412                        casend(dvbnode, NULL, 0);
1413
1414                        break;
1415                case T_DELETE_T_C:
1416                        debug(620, "got delete transport connection (slot %d, conn %d)", dvbnode->devnr, canode->connid);
1417
1418                        //send the D_T_C_REPLAY
1419                        unsigned char sendbuf[5];
1420
1421                        sendbuf[0] = dvbnode->devnr;
1422                        sendbuf[1] = canode->connid;
1423                        sendbuf[2] = T_D_T_C_REPLY;
1424                        sendbuf[3] = 1;
1425                        sendbuf[4] = canode->connid;
1426
1427                        cawrite(dvbnode, dvbnode->fd, sendbuf, 5, 0, -1);
1428                        casessionfree(dvbnode);
1429                        caslotfree(dvbnode);
1430
1431                        break;
1432                case T_D_T_C_REPLY:
1433
1434                        debug(620, "got delete transport connection replay (slot %d, conn %d)", dvbnode->devnr, canode->connid);
1435
1436                        casessionfree(dvbnode);
1437                        caslotfree(dvbnode);
1438                        break;
1439
1440                case T_REQUEST_T_C:
1441
1442                        debug(620, "got request transport connection (slot %d, conn %d)", dvbnode->devnr, canode->connid);
1443
1444                        break;
1445                case T_DATA_MORE:
1446                {
1447                        int newbuflen = canode->rlen + asnlen;
1448
1449                        debug(620, "got data more (slot %d, conn %d)", dvbnode->devnr, canode->connid);
1450
1451                        canode->rbuf = realloc(canode->rbuf, newbuflen);
1452                        if(canode->rbuf != NULL)
1453                        {
1454                                memcpy(canode->rbuf + canode->rlen, buf, asnlen);
1455                                canode->rlen = newbuflen;
1456                        }
1457
1458                        break;
1459                }
1460                case T_DATA_LAST:
1461                {
1462                        if(canode->rbuf == NULL)
1463                        {
1464                                debug(620, "got data last single package (slot %d, conn %d)", dvbnode->devnr, canode->connid);
1465
1466                                casessionreceive(dvbnode, buf, asnlen);
1467                                casessionpoll(dvbnode);
1468                        }
1469                        else
1470                        {
1471                                debug(620, "got data last chained package (slot %d, conn %d)", dvbnode->devnr, canode->connid);
1472                                int newbuflen = canode->rlen + asnlen;
1473
1474                                canode->rbuf = realloc(canode->rbuf, newbuflen);
1475                                if(canode->rbuf != NULL)
1476                                {
1477                                        memcpy(canode->rbuf + canode->rlen, buf, asnlen);
1478                                        canode->rlen = newbuflen;
1479                                        casessionreceive(dvbnode, canode->rbuf, canode->rlen);
1480                                        casessionpoll(dvbnode);
1481                                }
1482
1483                                free(canode->rbuf);
1484                                canode->rbuf = NULL;
1485                                canode->rlen = 0;
1486                        }
1487                        break;
1488                }
1489                case T_SB:
1490                {
1491                        //debug(620, "got sb (slot %d, conn %d, buf %02x)", dvbnode->devnr, canode->connid, buf[0]);
1492
1493                        if(buf[0] & 0x80)
1494                        {
1495                                debug(620, "data ready (slot %d)", dvbnode->devnr);
1496
1497                                //send the RCV and ask for the data
1498                                unsigned char sendbuf[5];
1499
1500                                sendbuf[0] = dvbnode->devnr;
1501                                sendbuf[1] = canode->connid;
1502                                sendbuf[2] = T_RCV;
1503                                sendbuf[3] = 1;
1504                                sendbuf[4] = canode->connid;
1505
1506                                cawrite(dvbnode, dvbnode->fd, sendbuf, 5, 0, -1);
1507                        }
1508                        break;
1509                }
1510                case 0x13: //MIPSEL
1511                {
1512                        debug(620, "got mipsel session data (slot %d, conn %d)", dvbnode->devnr, canode->connid);
1513                        casessionreceive(dvbnode, buf, asnlen);
1514                        casessionpoll(dvbnode);
1515                        break;
1516                }
1517                default:
1518                        debug(620, "unknown tpdu tag 0x%0x (slot %d, conn %d)", tpdutag, dvbnode->devnr, canode->connid);
1519        }
1520}
1521
1522void cacheck(struct stimerthread* self, struct dvbdev* dvbnode)
1523{
1524        int ret = 0, len = MINMALLOC;
1525        ca_slot_info_t info;
1526        struct caslot* canode = NULL;
1527        unsigned char* buf = NULL;
1528#ifdef SH4
1529        unsigned char* tmpbuf = NULL;
1530#endif
1531#ifdef SIMULATE
1532        unsigned char* tmpbuf = NULL;
1533#endif
1534        if(dvbnode == NULL) return;
1535        canode = dvbnode->caslot;
1536
1537        buf = calloc(1, MINMALLOC);
1538        if(buf == NULL)
1539        {
1540                err("no mem");
1541                return;
1542        }
1543
1544        switch(canode->status)
1545        {
1546                case 0: //idle
1547                case 100: //manuell reset
1548                {
1549                        if(canode->status == 0)
1550                                cawait(self, dvbnode, -1);
1551                        canode->status = 0;
1552                        debug(620, "status: no, slot %d", dvbnode->devnr);
1553                        if(dvbnode->caslot->status == 101) break; //titan end
1554
1555                        //reset the module an wait max 10 sek
1556                        careseting(self, dvbnode, 0);
1557
1558                        info.num = dvbnode->devnr;
1559                        if(cagetslotinfo(dvbnode, &info) == 0)
1560                        {
1561                                debug(620, "flags %d %d %d, slot %d", info.flags, CA_CI_MODULE_READY, info.flags & CA_CI_MODULE_READY, dvbnode->devnr);
1562
1563                                if(info.flags & CA_CI_MODULE_READY)
1564                                {
1565                                        debug(620, "cam (slot %d) status changed, cam now present", dvbnode->devnr);
1566                                        canode->connid = dvbnode->devnr + 1;
1567                                        if(cacreatetc(dvbnode) == 5)
1568                                        {
1569                                                casessionfree(dvbnode);
1570                                                caslotfree(dvbnode);
1571                                                canode->status = 1;
1572                                                canode->connid = dvbnode->devnr + 1;
1573                                                dvbnode->caslot->fastrun = getconfigint("camwait", NULL);
1574                                        }
1575                                        else
1576                                        {
1577                                                canode->connid = 0;
1578                                                sleep(1);
1579                                        }
1580                                }
1581                        }
1582                        else
1583                                sleep(1);
1584                }
1585                break;
1586                case 1: //active
1587                case 2: //active (ca and app ready)
1588                {
1589                        //debug(620, "status: wait, slot %d", dvbnode->devnr);
1590                        ret = caread(dvbnode, buf, &len);
1591                        if(dvbnode->caslot->status == 101) break; //titan end
1592                        if(ret == 0) //ready
1593                        {
1594                                //debug(620, "read, slot %d, ret %d", dvbnode->devnr, ret);
1595#ifdef MIPSEL
1596                                canode->poll = 1;
1597                                canode->connid = dvbnode->devnr + 1;
1598                                processtpdu(dvbnode, 0x13, buf, len);
1599#else
1600                                tmpbuf = buf;
1601                                int buflen = len - 2;
1602                                tmpbuf += 2; //remove leading slot and connection id
1603                                while(buflen > 0)
1604                                {
1605                                        unsigned char tpdutag = tmpbuf[0];
1606                                        unsigned short asnlen;
1607                                        int lenfieldlen;
1608
1609                                        canode->poll = 1;
1610                                        lenfieldlen = asn1decode(&asnlen, tmpbuf + 1, buflen - 1);
1611
1612                                        if(lenfieldlen < 0 || asnlen < 1 || asnlen > (buflen - (1 + lenfieldlen)))
1613                                        {
1614                                                err("received data with invalid asn from module on slot %d", dvbnode->devnr);
1615                                                break;
1616                                        }
1617
1618                                        canode->connid = tmpbuf[1 + lenfieldlen];
1619                                        tmpbuf += 1 + lenfieldlen + 1;
1620                                        buflen -= (1 + lenfieldlen + 1);
1621                                        asnlen--;
1622
1623                                        processtpdu(dvbnode, tpdutag, tmpbuf, asnlen);
1624
1625                                        //skip over the consumed data
1626                                        tmpbuf += asnlen;
1627                                        buflen -= asnlen;
1628                                }
1629#endif
1630                        }
1631                        else if(ret == 1 && canode->poll == 1) //write
1632                        {
1633#ifdef MIPSEL
1634                                int count = 0;
1635                                struct queue* qe = getqueue(dvbnode->devnr);
1636                                if(qe != NULL)
1637                                {
1638                                        while(qe != NULL && count < 10)
1639                                        {
1640                                                //debug(620, "write (queue), slot %d, ret %d", dvbnode->devnr, ret);
1641                                               
1642                                                int writeret = cawrite(dvbnode, dvbnode->fd, qe->data, qe->len, qe->flag, -1);
1643                                                if(writeret >= 0 && writeret == qe->len)
1644                                                {
1645                                                        delqueue(qe, 0);
1646                                                        qe = getqueue(dvbnode->devnr);
1647                                                }
1648                                                else
1649                                                        count++;
1650                                        }
1651                                }
1652                                else
1653                                {
1654                                        //debug(620, "write (poll), slot %d, ret %d", dvbnode->devnr, ret);
1655                                        casend(dvbnode, NULL, 0);
1656                                        if(canode->fastrun > 0) canode->fastrun--;
1657                                }
1658#else                   
1659                                struct queue* qe = getqueue(dvbnode->devnr);
1660                                if(qe != NULL)
1661                                {
1662                                        //debug(620, "write (queue), slot %d, ret %d", dvbnode->devnr, ret);
1663                                       
1664                                        int writeret = cawrite(dvbnode, dvbnode->fd, qe->data, qe->len, qe->flag, -1);
1665                                        if(writeret >= 0 && writeret == qe->len)
1666                                        {
1667                                                delqueue(qe, 0);
1668                                        }
1669                                }
1670                                else
1671                                {
1672                                        //debug(620, "write (poll), slot %d, ret %d", dvbnode->devnr, ret);
1673                                        casend(dvbnode, NULL, 0);
1674                                        if(canode->fastrun > 0) canode->fastrun--;
1675                                }
1676#endif
1677                        }
1678                        else if(ret == 1 && canode->poll == 0)
1679                        {
1680                                debug(620, "write but poll=0, slot %d, ret %d", dvbnode->devnr, ret);
1681                                if(canode->fastrun > 0) canode->fastrun--;
1682                        }
1683                        else if(ret == 2) //change
1684                        {
1685                                debug(620, "change, slot %d, ret %d", dvbnode->devnr, ret);
1686                                info.num = dvbnode->devnr;
1687
1688                                if(cagetslotinfo(dvbnode, &info) == 1 || !(info.flags & CA_CI_MODULE_READY))
1689                                {
1690                                        debug(620, "flags %d %d %d, slot %d", info.flags, CA_CI_MODULE_READY, info.flags & CA_CI_MODULE_READY, dvbnode->devnr);
1691                                        debug(620, "cam (slot %d) status changed, cam not present", dvbnode->devnr);
1692
1693                                        //reset routing
1694                                        debug(620, "reset routing tuner %d", dvbnode->devnr);
1695                                        switch(dvbnode->devnr)
1696                                        {
1697                                                case 0: setcisource(dvbnode->devnr, "A"); break;
1698                                                case 1: setcisource(dvbnode->devnr, "B"); break;
1699                                                case 2: setcisource(dvbnode->devnr, "C"); break;
1700                                                case 3: setcisource(dvbnode->devnr, "D"); break;
1701                                        }
1702
1703                                        casessionfree(dvbnode);
1704                                        caslotfree(dvbnode);
1705                                        canode->fastrun = 0;
1706
1707                                        sleep(1);
1708                                }
1709                        }
1710                        else if(ret == -2) //timeout
1711                        {
1712                                debug(620, "timeout slot %d, ret %d", dvbnode->devnr, ret);
1713                                if(canode->fastrun > 0) canode->fastrun--;
1714                                break;
1715                        }
1716                        else if(ret < 0) //error
1717                        {
1718                                debug(620, "error slot %d, ret %d", dvbnode->devnr, ret);
1719                                casessionfree(dvbnode);
1720                                caslotfree(dvbnode);
1721                                sleep(1);
1722                        }
1723                }
1724                break;
1725                default:
1726                {
1727                        debug(620, "unknown status");
1728                }
1729                break;
1730        }
1731
1732        //declear as ready, but not complete
1733        if(canode->caids != NULL && canode->status == 1 && canode->fastrun < 1)
1734        {
1735                if(getfreecasession(dvbnode, 1, 1) > -1 && getfreecasession(dvbnode, 2, 1) > -1)
1736                {
1737                        canode->status = 2;
1738                        //m_lock(&status.servicemutex, 2);
1739                        //sendcapmt(status.aktservice, 0, 2);
1740                        //m_unlock(&status.servicemutex, 2);
1741                }
1742        }
1743
1744        free(buf); buf = NULL;
1745}
1746
1747void cathread(struct stimerthread* self, struct dvbdev* dvbnode)
1748{
1749        if(dvbnode == NULL || dvbnode->caslot == NULL) return;
1750        debug(620, "CA thread start (slot %d)", dvbnode->devnr);
1751
1752        while(self != NULL && self->aktion != STOP && self->aktion != PAUSE)
1753        {
1754                if(dvbnode->caslot->status != 101)
1755                        cacheck(self, dvbnode);
1756                if(dvbnode->caslot->fastrun == 0)
1757                        sleep(1);
1758                else
1759                        usleep(100000);
1760        }
1761        debug(620, "CA thread end (slot %d)", dvbnode->devnr);
1762}
1763
1764void castart()
1765{
1766        struct dvbdev* dvbnode = dvbdev;
1767
1768        while(dvbnode != NULL)
1769        {
1770                if(dvbnode->type == CIDEV && dvbnode->fd > -1)
1771                {
1772                        if(debug_level == 620)
1773                        {
1774                                struct ca_caps caps;
1775                                ca_slot_info_t info;
1776
1777                                caps.slot_num = dvbnode->devnr;
1778                                if(cagetcaps(dvbnode, &caps) == 0)
1779                                        debug(620, "caps: slotsum:%d, type:%d, descrnr:%d, descrtype:%d", caps.slot_num, caps.slot_type, caps.descr_num, caps.descr_type);
1780
1781                                info.num = dvbnode->devnr;
1782                                if(cagetslotinfo(dvbnode, &info) == 0)
1783                                        debug(620, "info: slot:%d, type:%d, flag:%d", info.num, info.type, info.flags);
1784                        }
1785                        addtimer(&cathread, START, 1000, -1, (void*)dvbnode, NULL, NULL);
1786                }
1787                dvbnode = dvbnode->next;
1788        }
1789}
1790
1791int sendcapmttocam(struct dvbdev* dvbnode, struct service* node, unsigned char* buf, int len, int caservicenr, int cmdpos, int clear)
1792{
1793        int i = 0;
1794        char* tmpstr = NULL, *blacklist = NULL;
1795
1796        if(node == NULL && dvbnode == NULL) return 1;
1797
1798        if(dvbnode->type == CIDEV && dvbnode->fd > -1 && dvbnode->caslot != NULL && dvbnode->caslot->status == 2 && dvbnode->caslot->caids != NULL)
1799        {
1800                //check if crypt can onyl handle single service
1801                tmpstr = ostrcat("camtype_", oitoa(dvbnode->devnr), 0, 1);
1802                if(clear == 0 && getconfigint(tmpstr, NULL) == 0 && getcaservicebyslot(dvbnode->caslot, 1) > -1)
1803                {
1804                        debug(620, "cam is singel and is in use");
1805                        free(tmpstr); tmpstr = NULL;
1806                        return 1;
1807                }
1808                free(tmpstr); tmpstr = NULL;
1809               
1810                int foundcaid = 0;
1811               
1812    //check if channel used this slot
1813                if(node->channel != NULL)
1814                {
1815                        struct channelslot *channelslotnode = channelslot;
1816                        while(channelslotnode != NULL)
1817                        {
1818                                if(channelslotnode->transponderid == node->channel->transponderid && channelslotnode->serviceid == node->channel->serviceid)
1819                                {
1820          if(channelslotnode->slot == dvbnode->devnr)
1821          {
1822                                                debug(620, "channel support cam (channelslot=%d, slot=%d)", channelslotnode->slot, dvbnode->devnr);
1823                                                foundcaid = 1;
1824                                                break;
1825          }
1826          else
1827          {
1828                debug(620, "channel not support cam (channelslot=%d, slot=%d)", channelslotnode->slot, dvbnode->devnr);
1829                                                return 1;
1830                                        }
1831                                }                       
1832                                channelslotnode = channelslotnode->next;                       
1833                        }
1834                }
1835
1836                //check if cam can caid
1837                if(foundcaid == 0)
1838                {
1839                        tmpstr = ostrcat("camblacklist_", oitoa(dvbnode->devnr), 0, 1);
1840                        blacklist = getconfig(tmpstr, NULL);
1841                        free(tmpstr); tmpstr = NULL;
1842                        if(node->channel != NULL)
1843                        {
1844                                struct cadesc *nodecadesc = node->channel->cadesc;
1845                                while(nodecadesc != NULL)
1846                                {
1847                                        debug(620, "cam-ciads=%s", dvbnode->caslot->caids);
1848                                        debug(620, "videopid=%d, audiopid=%d, ac3pid=%d, capid=%d, caid=%d", node->channel->videopid, node->channel->audiopid, node->channel->ac3audiopid, nodecadesc->pid, nodecadesc->systemid);
1849                                        tmpstr = oitoa(nodecadesc->systemid);
1850                                        if(ostrstr(dvbnode->caslot->caids, tmpstr) != NULL)
1851                                        {
1852                                                //check if caid is in cams blacklist
1853                                                if(blacklist == NULL || ostrstr(blacklist, tmpstr) == NULL)
1854                                                {
1855                                                        foundcaid = 1;
1856                                                        break;
1857                                                }
1858                                                else
1859                                                        debug(620, "caid is in blacklist (%s -> %s)", tmpstr, blacklist);
1860                                        }
1861                                        free(tmpstr); tmpstr = NULL;
1862                        nodecadesc = nodecadesc->next;
1863                                }
1864                        }
1865                        free(tmpstr); tmpstr = NULL;
1866                }
1867
1868                if(foundcaid == 0)
1869                {
1870                        debug(620, "cam not supports caid");
1871                        return 1;
1872                }
1873
1874                //check if we can change input sources
1875                for(i = 0; i < MAXCASERVICE; i++)
1876                {
1877                        if(caservice[i].caslot != NULL && caservice[i].service != NULL && caservice[i].service->fedev != NULL && node->fedev != NULL)
1878                        {
1879                                if(caservice[i].caslot == dvbnode->caslot && caservice[i].service->fedev->devnr != node->fedev->devnr && (caservice[i].service->type == RECORDDIRECT || caservice[i].service->type == RECORDTIMER))
1880                                {
1881                                        debug(620, "can't change input sources");
1882                                        return 1;
1883                                }
1884                        }
1885                }
1886
1887                //got free camanager
1888                if(caservice[caservicenr].camanager == -1)
1889                {
1890                        caservice[caservicenr].camanager = getfreecasession(dvbnode, 2, 1);
1891                        debug(620, "use camanager %d", caservice[caservicenr].camanager);
1892                }
1893
1894                //check if cam can decrypt
1895                if(clear == 0 && caservice[caservicenr].camanager > -1 && getconfigint("checkcamdecrypt", NULL) == 1)
1896                {
1897                        if(buf != NULL && len >= cmdpos)
1898                        {
1899                                status.checkcamdecrypt = 100;
1900                                buf[cmdpos] = 0x03;
1901                                buf[cmdpos - 6] = 0x04; //WA for alphacrypt, only delete all ca-pmt
1902                                sendSPDU(dvbnode, 0x90, NULL, 0, caservice[caservicenr].camanager, buf, len);
1903                                buf[cmdpos] = 0x01;
1904                                buf[cmdpos - 6] = 0x03;
1905                                while(status.checkcamdecrypt > 0)
1906                                {
1907                                        status.checkcamdecrypt--;
1908                                        usleep(30000);
1909                                }
1910                if(status.checkcamdecrypt == -2)
1911                                {
1912                                        dvbnode->caslot->casession[caservice[caservicenr].camanager].inuse = 1;
1913                                        caservice[caservicenr].camanager = -1;
1914                                }
1915                        }
1916                }
1917
1918                //decrypt
1919                if(caservice[caservicenr].camanager > -1)
1920                {
1921                        //change ciX_input and inputX
1922                        if(clear == 0 && node->fedev != NULL)
1923                        {
1924                                char* ci = NULL;
1925                                debug(620, "set ci slot %d to tuner %d", dvbnode->devnr, node->fedev->devnr);
1926                                switch(node->fedev->devnr)
1927                                {
1928                                        case 0:
1929                                                setciinput(dvbnode->devnr, "A");
1930                                                ci = ostrcat("CI", oitoa(dvbnode->devnr), 0, 1);
1931                                                setcisource(node->fedev->devnr, ci);
1932                                                free(ci); ci = NULL;
1933                                                break;
1934                                        case 1:
1935                                                setciinput(dvbnode->devnr, "B");
1936                                                ci = ostrcat("CI", oitoa(dvbnode->devnr), 0, 1);
1937                                                setcisource(node->fedev->devnr, ci);
1938                                                free(ci); ci = NULL;
1939                                                break;
1940                                        case 2:
1941                                                setciinput(dvbnode->devnr, "C");
1942                                                ci = ostrcat("CI", oitoa(dvbnode->devnr), 0, 1);
1943                                                setcisource(node->fedev->devnr, ci);
1944                                                free(ci); ci = NULL;
1945                                                break;
1946                                        case 3:
1947                                                setciinput(dvbnode->devnr, "D");
1948                                                ci = ostrcat("CI", oitoa(dvbnode->devnr), 0, 1);
1949                                                setcisource(node->fedev->devnr, ci);
1950                                                free(ci); ci = NULL;
1951                                                break;
1952                                }
1953                        }
1954                        //send all saved capmt first
1955                        int first = 0;
1956                        for(i = 0; i < MAXCASERVICE; i++)
1957                        {
1958                                if(dvbnode->caslot == caservice[i].caslot && caservice[i].capmt != NULL && caservice[i].capmtlen > 0)
1959                                {
1960                                        if(i == 0)
1961                                                caservice[i].capmt[caservice[i].cmdpos - 6] = 0x01;
1962                                        else
1963                                                caservice[i].capmt[caservice[i].cmdpos - 6] = 0x00;
1964                                        first = 1;
1965                                        sendSPDU(dvbnode, 0x90, NULL, 0, caservice[i].camanager, caservice[i].capmt, caservice[i].capmtlen);
1966                                }
1967                        }
1968                        //send new capmt
1969                        if(first == 1) buf[cmdpos - 6] = 0x02;
1970                        sendSPDU(dvbnode, 0x90, NULL, 0, caservice[caservicenr].camanager, buf, len);
1971                        caservice[caservicenr].caslot = dvbnode->caslot;
1972                        //save new capmt
1973                        char* tmpbuf = malloc(len);
1974                        if(tmpbuf != NULL)
1975                        {
1976                                memcpy(tmpbuf, buf, len);
1977                                free(caservice[caservicenr].capmt);
1978                                caservice[caservicenr].capmt = tmpbuf;
1979                                caservice[caservicenr].capmtlen = len;
1980                                caservice[caservicenr].cmdpos = cmdpos;
1981                        }
1982                        debug(620, "found cam for decrypt (slot=%d)", dvbnode->devnr);
1983                        return 0;
1984                }
1985                else
1986                        debug(620, "no free camanager found");
1987        }
1988        return 1;
1989}
1990
1991#endif
Note: See TracBrowser for help on using the repository browser.