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