source: titan/titan/ca.h @ 27981

Last change on this file since 27981 was 27740, checked in by obi, 10 years ago

update menulistbox with detail text

File size: 48.0 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, *tmpbuf = NULL;
1528
1529        if(dvbnode == NULL) return;
1530        canode = dvbnode->caslot;
1531
1532        buf = calloc(1, MINMALLOC);
1533        if(buf == NULL)
1534        {
1535                err("no mem");
1536                return;
1537        }
1538
1539        switch(canode->status)
1540        {
1541                case 0: //idle
1542                case 100: //manuell reset
1543                {
1544                        if(canode->status == 0)
1545                                cawait(self, dvbnode, -1);
1546                        canode->status = 0;
1547                        debug(620, "status: no, slot %d", dvbnode->devnr);
1548                        if(dvbnode->caslot->status == 101) break; //titan end
1549
1550                        //reset the module an wait max 10 sek
1551                        careseting(self, dvbnode, 0);
1552
1553                        info.num = dvbnode->devnr;
1554                        if(cagetslotinfo(dvbnode, &info) == 0)
1555                        {
1556                                debug(620, "flags %d %d %d, slot %d", info.flags, CA_CI_MODULE_READY, info.flags & CA_CI_MODULE_READY, dvbnode->devnr);
1557
1558                                if(info.flags & CA_CI_MODULE_READY)
1559                                {
1560                                        debug(620, "cam (slot %d) status changed, cam now present", dvbnode->devnr);
1561                                        canode->connid = dvbnode->devnr + 1;
1562                                        if(cacreatetc(dvbnode) == 5)
1563                                        {
1564                                                casessionfree(dvbnode);
1565                                                caslotfree(dvbnode);
1566                                                canode->status = 1;
1567                                                canode->connid = dvbnode->devnr + 1;
1568                                                dvbnode->caslot->fastrun = getconfigint("camwait", NULL);
1569                                        }
1570                                        else
1571                                        {
1572                                                canode->connid = 0;
1573                                                sleep(1);
1574                                        }
1575                                }
1576                        }
1577                        else
1578                                sleep(1);
1579                }
1580                break;
1581                case 1: //active
1582                case 2: //active (ca and app ready)
1583                {
1584                        //debug(620, "status: wait, slot %d", dvbnode->devnr);
1585                        ret = caread(dvbnode, buf, &len);
1586                        if(dvbnode->caslot->status == 101) break; //titan end
1587                        if(ret == 0) //ready
1588                        {
1589                                //debug(620, "read, slot %d, ret %d", dvbnode->devnr, ret);
1590#ifdef MIPSEL
1591                                canode->poll = 1;
1592                                canode->connid = dvbnode->devnr + 1;
1593                                processtpdu(dvbnode, 0x13, buf, len);
1594#else
1595                                tmpbuf = buf;
1596                                int buflen = len - 2;
1597                                tmpbuf += 2; //remove leading slot and connection id
1598                                while(buflen > 0)
1599                                {
1600                                        unsigned char tpdutag = tmpbuf[0];
1601                                        unsigned short asnlen;
1602                                        int lenfieldlen;
1603
1604                                        canode->poll = 1;
1605                                        lenfieldlen = asn1decode(&asnlen, tmpbuf + 1, buflen - 1);
1606
1607                                        if(lenfieldlen < 0 || asnlen < 1 || asnlen > (buflen - (1 + lenfieldlen)))
1608                                        {
1609                                                err("received data with invalid asn from module on slot %d", dvbnode->devnr);
1610                                                break;
1611                                        }
1612
1613                                        canode->connid = tmpbuf[1 + lenfieldlen];
1614                                        tmpbuf += 1 + lenfieldlen + 1;
1615                                        buflen -= (1 + lenfieldlen + 1);
1616                                        asnlen--;
1617
1618                                        processtpdu(dvbnode, tpdutag, tmpbuf, asnlen);
1619
1620                                        //skip over the consumed data
1621                                        tmpbuf += asnlen;
1622                                        buflen -= asnlen;
1623                                }
1624#endif
1625                        }
1626                        else if(ret == 1 && canode->poll == 1) //write
1627                        {
1628#ifdef MIPSEL
1629                                int count = 0;
1630                                struct queue* qe = getqueue(dvbnode->devnr);
1631                                if(qe != NULL)
1632                                {
1633                                        while(qe != NULL && count < 10)
1634                                        {
1635                                                //debug(620, "write (queue), slot %d, ret %d", dvbnode->devnr, ret);
1636                                               
1637                                                int writeret = cawrite(dvbnode, dvbnode->fd, qe->data, qe->len, qe->flag, -1);
1638                                                if(writeret >= 0 && writeret == qe->len)
1639                                                {
1640                                                        delqueue(qe, 0);
1641                                                        qe = getqueue(dvbnode->devnr);
1642                                                }
1643                                                else
1644                                                        count++;
1645                                        }
1646                                }
1647                                else
1648                                {
1649                                        //debug(620, "write (poll), slot %d, ret %d", dvbnode->devnr, ret);
1650                                        casend(dvbnode, NULL, 0);
1651                                        if(canode->fastrun > 0) canode->fastrun--;
1652                                }
1653#else                   
1654                                struct queue* qe = getqueue(dvbnode->devnr);
1655                                if(qe != NULL)
1656                                {
1657                                        //debug(620, "write (queue), slot %d, ret %d", dvbnode->devnr, ret);
1658                                       
1659                                        int writeret = cawrite(dvbnode, dvbnode->fd, qe->data, qe->len, qe->flag, -1);
1660                                        if(writeret >= 0 && writeret == qe->len)
1661                                        {
1662                                                delqueue(qe, 0);
1663                                        }
1664                                }
1665                                else
1666                                {
1667                                        //debug(620, "write (poll), slot %d, ret %d", dvbnode->devnr, ret);
1668                                        casend(dvbnode, NULL, 0);
1669                                        if(canode->fastrun > 0) canode->fastrun--;
1670                                }
1671#endif
1672                        }
1673                        else if(ret == 1 && canode->poll == 0)
1674                        {
1675                                debug(620, "write but poll=0, slot %d, ret %d", dvbnode->devnr, ret);
1676                                if(canode->fastrun > 0) canode->fastrun--;
1677                        }
1678                        else if(ret == 2) //change
1679                        {
1680                                debug(620, "change, slot %d, ret %d", dvbnode->devnr, ret);
1681                                info.num = dvbnode->devnr;
1682
1683                                if(cagetslotinfo(dvbnode, &info) == 1 || !(info.flags & CA_CI_MODULE_READY))
1684                                {
1685                                        debug(620, "flags %d %d %d, slot %d", info.flags, CA_CI_MODULE_READY, info.flags & CA_CI_MODULE_READY, dvbnode->devnr);
1686                                        debug(620, "cam (slot %d) status changed, cam not present", dvbnode->devnr);
1687
1688                                        //reset routing
1689                                        debug(620, "reset routing tuner %d", dvbnode->devnr);
1690                                        switch(dvbnode->devnr)
1691                                        {
1692                                                case 0: setcisource(dvbnode->devnr, "A"); break;
1693                                                case 1: setcisource(dvbnode->devnr, "B"); break;
1694                                                case 2: setcisource(dvbnode->devnr, "C"); break;
1695                                                case 3: setcisource(dvbnode->devnr, "D"); break;
1696                                        }
1697
1698                                        casessionfree(dvbnode);
1699                                        caslotfree(dvbnode);
1700                                        canode->fastrun = 0;
1701
1702                                        sleep(1);
1703                                }
1704                        }
1705                        else if(ret == -2) //timeout
1706                        {
1707                                debug(620, "timeout slot %d, ret %d", dvbnode->devnr, ret);
1708                                if(canode->fastrun > 0) canode->fastrun--;
1709                                break;
1710                        }
1711                        else if(ret < 0) //error
1712                        {
1713                                debug(620, "error slot %d, ret %d", dvbnode->devnr, ret);
1714                                casessionfree(dvbnode);
1715                                caslotfree(dvbnode);
1716                                sleep(1);
1717                        }
1718                }
1719                break;
1720                default:
1721                {
1722                        debug(620, "unknown status");
1723                }
1724                break;
1725        }
1726
1727        //declear as ready, but not complete
1728        if(canode->caids != NULL && canode->status == 1 && canode->fastrun < 1)
1729        {
1730                if(getfreecasession(dvbnode, 1, 1) > -1 && getfreecasession(dvbnode, 2, 1) > -1)
1731                {
1732                        canode->status = 2;
1733                        //m_lock(&status.servicemutex, 2);
1734                        //sendcapmt(status.aktservice, 0, 2);
1735                        //m_unlock(&status.servicemutex, 2);
1736                }
1737        }
1738
1739        free(buf); buf = NULL;
1740}
1741
1742void cathread(struct stimerthread* self, struct dvbdev* dvbnode)
1743{
1744        if(dvbnode == NULL || dvbnode->caslot == NULL) return;
1745        debug(620, "CA thread start (slot %d)", dvbnode->devnr);
1746
1747        while(self != NULL && self->aktion != STOP && self->aktion != PAUSE)
1748        {
1749                if(dvbnode->caslot->status != 101)
1750                        cacheck(self, dvbnode);
1751                if(dvbnode->caslot->fastrun == 0)
1752                        sleep(1);
1753                else
1754                        usleep(100000);
1755        }
1756        debug(620, "CA thread end (slot %d)", dvbnode->devnr);
1757}
1758
1759void castart()
1760{
1761        struct dvbdev* dvbnode = dvbdev;
1762
1763        while(dvbnode != NULL)
1764        {
1765                if(dvbnode->type == CIDEV && dvbnode->fd > -1)
1766                {
1767                        if(debug_level == 620)
1768                        {
1769                                struct ca_caps caps;
1770                                ca_slot_info_t info;
1771
1772                                caps.slot_num = dvbnode->devnr;
1773                                if(cagetcaps(dvbnode, &caps) == 0)
1774                                        debug(620, "caps: slotsum:%d, type:%d, descrnr:%d, descrtype:%d", caps.slot_num, caps.slot_type, caps.descr_num, caps.descr_type);
1775
1776                                info.num = dvbnode->devnr;
1777                                if(cagetslotinfo(dvbnode, &info) == 0)
1778                                        debug(620, "info: slot:%d, type:%d, flag:%d", info.num, info.type, info.flags);
1779                        }
1780                        addtimer(&cathread, START, 1000, -1, (void*)dvbnode, NULL, NULL);
1781                }
1782                dvbnode = dvbnode->next;
1783        }
1784}
1785
1786int sendcapmttocam(struct dvbdev* dvbnode, struct service* node, unsigned char* buf, int len, int caservicenr, int cmdpos, int clear)
1787{
1788        int i = 0;
1789        char* tmpstr = NULL, *blacklist = NULL;
1790
1791        if(node == NULL && dvbnode == NULL) return 1;
1792
1793        if(dvbnode->type == CIDEV && dvbnode->fd > -1 && dvbnode->caslot != NULL && dvbnode->caslot->status == 2 && dvbnode->caslot->caids != NULL)
1794        {
1795                //check if crypt can onyl handle single service
1796                tmpstr = ostrcat("camtype_", oitoa(dvbnode->devnr), 0, 1);
1797                if(clear == 0 && getconfigint(tmpstr, NULL) == 0 && getcaservicebyslot(dvbnode->caslot, 1) > -1)
1798                {
1799                        debug(620, "cam is singel and is in use");
1800                        free(tmpstr); tmpstr = NULL;
1801                        return 1;
1802                }
1803                free(tmpstr); tmpstr = NULL;
1804               
1805                int foundcaid = 0;
1806               
1807    //check if channel used this slot
1808                if(node->channel != NULL)
1809                {
1810                        struct channelslot *channelslotnode = channelslot;
1811                        while(channelslotnode != NULL)
1812                        {
1813                                if(channelslotnode->transponderid == node->channel->transponderid && channelslotnode->serviceid == node->channel->serviceid)
1814                                {
1815          if(channelslotnode->slot == dvbnode->devnr)
1816          {
1817                                                debug(620, "channel support cam (channelslot=%d, slot=%d)", channelslotnode->slot, dvbnode->devnr);
1818                                                foundcaid = 1;
1819                                                break;
1820          }
1821          else
1822          {
1823                debug(620, "channel not support cam (channelslot=%d, slot=%d)", channelslotnode->slot, dvbnode->devnr);
1824                                                return 1;
1825                                        }
1826                                }                       
1827                                channelslotnode = channelslotnode->next;                       
1828                        }
1829                }
1830
1831                //check if cam can caid
1832                if(foundcaid == 0)
1833                {
1834                        tmpstr = ostrcat("camblacklist_", oitoa(dvbnode->devnr), 0, 1);
1835                        blacklist = getconfig(tmpstr, NULL);
1836                        free(tmpstr); tmpstr = NULL;
1837                        if(node->channel != NULL)
1838                        {
1839                                struct cadesc *nodecadesc = node->channel->cadesc;
1840                                while(nodecadesc != NULL)
1841                                {
1842                                        debug(620, "cam-ciads=%s", dvbnode->caslot->caids);
1843                                        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);
1844                                        tmpstr = oitoa(nodecadesc->systemid);
1845                                        if(ostrstr(dvbnode->caslot->caids, tmpstr) != NULL)
1846                                        {
1847                                                //check if caid is in cams blacklist
1848                                                if(blacklist == NULL || ostrstr(blacklist, tmpstr) == NULL)
1849                                                {
1850                                                        foundcaid = 1;
1851                                                        break;
1852                                                }
1853                                                else
1854                                                        debug(620, "caid is in blacklist (%s -> %s)", tmpstr, blacklist);
1855                                        }
1856                                        free(tmpstr); tmpstr = NULL;
1857                        nodecadesc = nodecadesc->next;
1858                                }
1859                        }
1860                        free(tmpstr); tmpstr = NULL;
1861                }
1862
1863                if(foundcaid == 0)
1864                {
1865                        debug(620, "cam not supports caid");
1866                        return 1;
1867                }
1868
1869                //check if we can change input sources
1870                for(i = 0; i < MAXCASERVICE; i++)
1871                {
1872                        if(caservice[i].caslot != NULL && caservice[i].service != NULL && caservice[i].service->fedev != NULL && node->fedev != NULL)
1873                        {
1874                                if(caservice[i].caslot == dvbnode->caslot && caservice[i].service->fedev->devnr != node->fedev->devnr && (caservice[i].service->type == RECORDDIRECT || caservice[i].service->type == RECORDTIMER))
1875                                {
1876                                        debug(620, "can't change input sources");
1877                                        return 1;
1878                                }
1879                        }
1880                }
1881
1882                //got free camanager
1883                if(caservice[caservicenr].camanager == -1)
1884                {
1885                        caservice[caservicenr].camanager = getfreecasession(dvbnode, 2, 1);
1886                        debug(620, "use camanager %d", caservice[caservicenr].camanager);
1887                }
1888
1889                //check if cam can decrypt
1890                if(clear == 0 && caservice[caservicenr].camanager > -1 && getconfigint("checkcamdecrypt", NULL) == 1)
1891                {
1892                        if(buf != NULL && len >= cmdpos)
1893                        {
1894                                status.checkcamdecrypt = 100;
1895                                buf[cmdpos] = 0x03;
1896                                buf[cmdpos - 6] = 0x04; //WA for alphacrypt, only delete all ca-pmt
1897                                sendSPDU(dvbnode, 0x90, NULL, 0, caservice[caservicenr].camanager, buf, len);
1898                                buf[cmdpos] = 0x01;
1899                                buf[cmdpos - 6] = 0x03;
1900                                while(status.checkcamdecrypt > 0)
1901                                {
1902                                        status.checkcamdecrypt--;
1903                                        usleep(30000);
1904                                }
1905                if(status.checkcamdecrypt == -2)
1906                                {
1907                                        dvbnode->caslot->casession[caservice[caservicenr].camanager].inuse = 1;
1908                                        caservice[caservicenr].camanager = -1;
1909                                }
1910                        }
1911                }
1912
1913                //decrypt
1914                if(caservice[caservicenr].camanager > -1)
1915                {
1916                        //change ciX_input and inputX
1917                        if(clear == 0 && node->fedev != NULL)
1918                        {
1919                                char* ci = NULL;
1920                                debug(620, "set ci slot %d to tuner %d", dvbnode->devnr, node->fedev->devnr);
1921                                switch(node->fedev->devnr)
1922                                {
1923                                        case 0:
1924                                                setciinput(dvbnode->devnr, "A");
1925                                                ci = ostrcat("CI", oitoa(dvbnode->devnr), 0, 1);
1926                                                setcisource(node->fedev->devnr, ci);
1927                                                free(ci); ci = NULL;
1928                                                break;
1929                                        case 1:
1930                                                setciinput(dvbnode->devnr, "B");
1931                                                ci = ostrcat("CI", oitoa(dvbnode->devnr), 0, 1);
1932                                                setcisource(node->fedev->devnr, ci);
1933                                                free(ci); ci = NULL;
1934                                                break;
1935                                        case 2:
1936                                                setciinput(dvbnode->devnr, "C");
1937                                                ci = ostrcat("CI", oitoa(dvbnode->devnr), 0, 1);
1938                                                setcisource(node->fedev->devnr, ci);
1939                                                free(ci); ci = NULL;
1940                                                break;
1941                                        case 3:
1942                                                setciinput(dvbnode->devnr, "D");
1943                                                ci = ostrcat("CI", oitoa(dvbnode->devnr), 0, 1);
1944                                                setcisource(node->fedev->devnr, ci);
1945                                                free(ci); ci = NULL;
1946                                                break;
1947                                }
1948                        }
1949                        //send all saved capmt first
1950                        int first = 0;
1951                        for(i = 0; i < MAXCASERVICE; i++)
1952                        {
1953                                if(dvbnode->caslot == caservice[i].caslot && caservice[i].capmt != NULL && caservice[i].capmtlen > 0)
1954                                {
1955                                        if(i == 0)
1956                                                caservice[i].capmt[caservice[i].cmdpos - 6] = 0x01;
1957                                        else
1958                                                caservice[i].capmt[caservice[i].cmdpos - 6] = 0x00;
1959                                        first = 1;
1960                                        sendSPDU(dvbnode, 0x90, NULL, 0, caservice[i].camanager, caservice[i].capmt, caservice[i].capmtlen);
1961                                }
1962                        }
1963                        //send new capmt
1964                        if(first == 1) buf[cmdpos - 6] = 0x02;
1965                        sendSPDU(dvbnode, 0x90, NULL, 0, caservice[caservicenr].camanager, buf, len);
1966                        caservice[caservicenr].caslot = dvbnode->caslot;
1967                        //save new capmt
1968                        char* tmpbuf = malloc(len);
1969                        if(tmpbuf != NULL)
1970                        {
1971                                memcpy(tmpbuf, buf, len);
1972                                free(caservice[caservicenr].capmt);
1973                                caservice[caservicenr].capmt = tmpbuf;
1974                                caservice[caservicenr].capmtlen = len;
1975                                caservice[caservicenr].cmdpos = cmdpos;
1976                        }
1977                        debug(620, "found cam for decrypt (slot=%d)", dvbnode->devnr);
1978                        return 0;
1979                }
1980                else
1981                        debug(620, "no free camanager found");
1982        }
1983        return 1;
1984}
1985
1986#endif
Note: See TracBrowser for help on using the repository browser.