source: titan/titan/ca.h @ 15280

Last change on this file since 15280 was 15189, checked in by nit, 12 years ago

[titan] extend freemenulist

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