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