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