source: titan/titan/ca.h @ 27536

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

ci modul add seperate cimenulist

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