72495a91ed1ea5249f5df635c32a3fb23106fb39
[vuplus_dvbapp] / lib / dvb_ci / dvbci_session.cpp
1 /* DVB CI Transport Connection */
2
3 #include <lib/dvb_ci/dvbci_session.h>
4 #include <lib/dvb_ci/dvbci_resmgr.h>
5 #include <lib/dvb_ci/dvbci_appmgr.h>
6 #include <lib/dvb_ci/dvbci_camgr.h>
7 #include <lib/dvb_ci/dvbci_datetimemgr.h>
8 #include <lib/dvb_ci/dvbci_mmi.h>
9
10 int eDVBCISession::buildLengthField(unsigned char *pkt, int len)
11 {
12         if (len < 127)
13         {
14                 *pkt++=len;
15                 return 1;
16         } else if (len < 256)
17         {
18                 *pkt++=0x81;
19                 *pkt++=len;
20                 return 2;
21         } else if (len < 65535)
22         {
23                 *pkt++=0x82;
24                 *pkt++=len>>8;
25                 *pkt++=len;
26                 return 3;
27         } else
28         {
29                 printf("too big length\n");
30                 exit(0);
31         }
32 }
33
34 int eDVBCISession::parseLengthField(const unsigned char *pkt, int &len)
35 {
36         len=0;
37         if (!(*pkt&0x80)) 
38         {
39                 len = *pkt;
40                 return 1;
41         }
42         for (int i=0; i<(pkt[0]&0x7F); ++i)
43         {
44                 len <<= 8;
45                 len |= pkt[i + 1];
46         }
47         return (pkt[0] & 0x7F) + 1;
48 }
49
50 void eDVBCISession::sendAPDU(const unsigned char *tag, const void *data, int len)
51 {
52         unsigned char pkt[len+3+4];
53         int l;
54         memcpy(pkt, tag, 3);
55         l=buildLengthField(pkt+3, len);
56         if (data)
57                 memcpy(pkt+3+l, data, len);
58         sendSPDU(0x90, 0, 0, pkt, len+3+l);
59 }
60
61 void eDVBCISession::sendSPDU(unsigned char tag, const void *data, int len, const void *apdu, int alen)
62 {
63         sendSPDU(slot, tag, data, len, session_nb, apdu, alen);
64 }
65
66 void eDVBCISession::sendSPDU(eDVBCISlot *slot, unsigned char tag, const void *data, int len, unsigned short session_nb, const void *apdu,int alen)
67 {
68         unsigned char pkt[4096];
69         unsigned char *ptr=pkt;
70         *ptr++=tag;
71         ptr+=buildLengthField(ptr, len+2);
72         if (data)
73                 memcpy(ptr, data, len);
74         ptr+=len;
75         *ptr++=session_nb>>8;
76         *ptr++=session_nb;
77
78         if (apdu)
79                 memcpy(ptr, apdu, alen);
80
81         ptr+=alen;
82         slot->write(pkt, ptr - pkt);
83 }
84
85 void eDVBCISession::sendOpenSessionResponse(eDVBCISlot *slot, unsigned char session_status, const unsigned char *resource_identifier, unsigned short session_nb)
86 {
87         char pkt[6];
88         pkt[0]=session_status;
89         printf("sendOpenSessionResponse\n");
90         memcpy(pkt + 1, resource_identifier, 4);
91         sendSPDU(slot, 0x92, pkt, 5, session_nb);
92 }
93
94 void eDVBCISession::recvCreateSessionResponse(const unsigned char *data)
95 {
96         status = data[0];
97         state = stateStarted;
98         action = 1;
99         printf("create Session Response, status %x\n", status);
100 }
101
102 void eDVBCISession::recvCloseSessionRequest(const unsigned char *data)
103 {
104         state = stateInDeletion;
105         action = 1;
106         printf("close Session Request\n");
107 }
108
109 eDVBCISession *eDVBCISession::createSession(eDVBCISlot *slot, const unsigned char *resource_identifier, unsigned char &status)
110 {
111         eDVBCISession *session;
112         unsigned long tag;
113         unsigned short session_nb;
114         for (session_nb=1; session_nb < SLMS; ++session_nb)
115                 if (!sessions[session_nb-1])
116                         break;
117         if (session_nb == SLMS)
118         {
119                 status=0xF3;
120                 return 0;
121         }
122
123         tag = resource_identifier[0] << 24;
124         tag|= resource_identifier[1] << 16;
125         tag|= resource_identifier[2] << 8;
126         tag|= resource_identifier[3];
127
128         switch (tag)
129         {
130         case 0x00010041:
131                 session=new eDVBCIResourceManagerSession;
132                 printf("RESOURCE MANAGER\n");
133                 break;
134         case 0x00020041:
135                 session=slot->application_manager = new eDVBCIApplicationManagerSession;
136                 printf("APPLICATION MANAGER\n");
137                 break;
138         case 0x00030041:
139                 session=slot->ca_manager=new eDVBCICAManagerSession;
140                 printf("CA MANAGER\n");
141                 break;
142         case 0x00240041:
143                 session=new eDVBCIDateTimeSession;
144                 printf("DATE-TIME\n");
145                 break;
146         case 0x00400041:
147                 session=new eDVBCIMMISession;
148                 printf("MMI\n");
149                 break;
150         case 0x00100041:
151 //              session=new eDVBCIAuthSession;
152                 printf("AuthSession\n");
153                 break;
154         case 0x00200041:
155         default:
156                 printf("unknown resource type %02x %02x %02x %02x\n", resource_identifier[0], resource_identifier[1], resource_identifier[2],resource_identifier[3]);
157                 session=0;
158                 status=0xF0;
159         }
160
161         if (!session)
162         {
163                 printf("unknown session.. expect crash\n");
164                 return 0;
165         }
166         printf("new session_nb: %d\n", session_nb);
167         session->session_nb = session_nb;
168         if (session)
169         {
170                 printf("session ok, status %02x\n", session->status);
171                 status = session->getStatus();
172                 if (status)
173                 {
174                         delete session;
175                         session = 0;
176                 }
177                 sessions[session_nb - 1] = session;
178                 session->slot = slot;
179         }
180         session->state = stateInCreation;
181         return session;
182 }
183
184 void eDVBCISession::receiveData(eDVBCISlot *slot, const unsigned char *ptr, size_t len)
185 {
186         const unsigned char *pkt = (const unsigned char*)ptr;
187         unsigned char tag = *pkt++;
188         int llen, hlen;
189         
190         llen = parseLengthField(pkt, hlen);
191         pkt += llen;
192         
193         eDVBCISession *session = NULL;
194         
195         if(tag == 0x91)
196         {
197                 unsigned char status;
198                 session = createSession(slot, pkt, status);
199                 sendOpenSessionResponse(slot, status, pkt, session?session->session_nb:0);
200
201                 if (session)
202                 {
203                         session->state=stateStarted;
204                         session->action=1;
205                 }
206         }
207         else
208         {
209                 unsigned session_nb;
210                 session_nb=pkt[hlen-2]<<8;
211                 session_nb|=pkt[hlen-1]&0xFF;
212                 
213                 if ((!session_nb) || (session_nb >= SLMS))
214                 {
215                         printf("PROTOCOL: illegal session number %x\n", session_nb);
216                         return;
217                 }
218                 
219                 session=sessions[session_nb-1];
220                 if (!session)
221                 {
222                         printf("PROTOCOL: data on closed session %x\n", session_nb);
223                         return;
224                 }
225
226                 switch (tag)
227                 {
228                 case 0x90:
229                         break;
230                 case 0x94:
231                         session->recvCreateSessionResponse(pkt);
232                         break;
233                 case 0x95:
234                         printf("recvCloseSessionRequest\n");
235                         session->recvCloseSessionRequest(pkt);
236                         break;
237                 default:
238                         printf("INTERNAL: nyi, tag %02x.\n", tag);
239                         return;
240                 }
241         }
242         
243         hlen += llen + 1; // lengthfield and tag
244
245         pkt = ((const unsigned char*)ptr) + hlen;
246         len -= hlen;
247
248         if (session)
249                 while (len > 0)
250                 {
251                         int alen;
252                         const unsigned char *tag=pkt;
253                         pkt+=3; // tag
254                         len-=3;
255                         hlen=parseLengthField(pkt, alen);
256                         pkt+=hlen;
257                         len-=hlen;
258
259                         //if (eDVBCIModule::getInstance()->workarounds_active & eDVBCIModule::workaroundMagicAPDULength)
260                         //{
261                         //      if (((len-alen) > 0) && ((len - alen) < 3))
262                         //      {
263                         //              printf("WORKAROUND: applying work around MagicAPDULength\n");
264                         //              alen=len;
265                         //      }
266                         //}
267                         if (session->receivedAPDU(tag, pkt, alen))
268                                 session->action = 1;
269                         pkt+=alen;
270                         len-=alen;
271                 }
272                 
273         if (len)
274                 printf("PROTOCOL: warning, TL-Data has invalid length\n");
275 }