source: titan/titan/ca.h @ 14611

Last change on this file since 14611 was 12697, checked in by nit, 12 years ago

[titan] update

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