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