/* DVB CI Transport Connection */ #include #include #include #include #include #include eDVBCISession *eDVBCISession::sessions[SLMS]; int eDVBCISession::buildLengthField(unsigned char *pkt, int len) { if (len < 127) { *pkt++=len; return 1; } else if (len < 256) { *pkt++=0x81; *pkt++=len; return 2; } else if (len < 65535) { *pkt++=0x82; *pkt++=len>>8; *pkt++=len; return 3; } else { printf("too big length\n"); exit(0); } } int eDVBCISession::parseLengthField(const unsigned char *pkt, int &len) { len=0; if (!(*pkt&0x80)) { len = *pkt; return 1; } for (int i=0; i<(pkt[0]&0x7F); ++i) { len <<= 8; len |= pkt[i + 1]; } return (pkt[0] & 0x7F) + 1; } void eDVBCISession::sendAPDU(const unsigned char *tag, const void *data, int len) { unsigned char pkt[len+3+4]; int l; memcpy(pkt, tag, 3); l=buildLengthField(pkt+3, len); if (data) memcpy(pkt+3+l, data, len); sendSPDU(0x90, 0, 0, pkt, len+3+l); } void eDVBCISession::sendSPDU(unsigned char tag, const void *data, int len, const void *apdu, int alen) { sendSPDU(slot, tag, data, len, session_nb, apdu, alen); } void eDVBCISession::sendSPDU(eDVBCISlot *slot, unsigned char tag, const void *data, int len, unsigned short session_nb, const void *apdu,int alen) { unsigned char pkt[4096]; unsigned char *ptr=pkt; *ptr++=tag; ptr+=buildLengthField(ptr, len+2); if (data) memcpy(ptr, data, len); ptr+=len; *ptr++=session_nb>>8; *ptr++=session_nb; if (apdu) memcpy(ptr, apdu, alen); ptr+=alen; slot->send(pkt, ptr - pkt); } void eDVBCISession::sendOpenSessionResponse(eDVBCISlot *slot, unsigned char session_status, const unsigned char *resource_identifier, unsigned short session_nb) { char pkt[6]; pkt[0]=session_status; printf("sendOpenSessionResponse\n"); memcpy(pkt + 1, resource_identifier, 4); sendSPDU(slot, 0x92, pkt, 5, session_nb); } void eDVBCISession::recvCreateSessionResponse(const unsigned char *data) { status = data[0]; state = stateStarted; action = 1; printf("create Session Response, status %x\n", status); } void eDVBCISession::recvCloseSessionRequest(const unsigned char *data) { state = stateInDeletion; action = 1; printf("close Session Request\n"); } eDVBCISession *eDVBCISession::createSession(eDVBCISlot *slot, const unsigned char *resource_identifier, unsigned char &status) { eDVBCISession *session; unsigned long tag; unsigned short session_nb; for (session_nb=1; session_nb < SLMS; ++session_nb) if (!sessions[session_nb-1]) break; if (session_nb == SLMS) { status=0xF3; return 0; } tag = resource_identifier[0] << 24; tag|= resource_identifier[1] << 16; tag|= resource_identifier[2] << 8; tag|= resource_identifier[3]; switch (tag) { case 0x00010041: session=new eDVBCIResourceManagerSession; printf("RESOURCE MANAGER\n"); printf("session: %p\n",session); break; case 0x00020041: session=slot->application_manager = new eDVBCIApplicationManagerSession(slot); printf("APPLICATION MANAGER\n"); break; case 0x00030041: session=slot->ca_manager=new eDVBCICAManagerSession; printf("CA MANAGER\n"); break; case 0x00240041: session=new eDVBCIDateTimeSession; printf("DATE-TIME\n"); break; case 0x00400041: session = new eDVBCIMMISession(slot); printf("MMI - create session\n"); break; case 0x00100041: // session=new eDVBCIAuthSession; printf("AuthSession\n"); break; case 0x00200041: default: printf("unknown resource type %02x %02x %02x %02x\n", resource_identifier[0], resource_identifier[1], resource_identifier[2],resource_identifier[3]); session=0; status=0xF0; } if (!session) { printf("unknown session.. expect crash\n"); return 0; } printf("new session_nb: %d\n", session_nb); session->session_nb = session_nb; if (session) { sessions[session_nb - 1] = session; session->slot = slot; status = 0; } session->state = stateInCreation; return session; } void eDVBCISession::handleClose() { unsigned char data[1]={0x00}; sendSPDU(0x96, data, 1, 0, 0); } int eDVBCISession::pollAll() { for (int session_nb=1; session_nb < SLMS; ++session_nb) if (sessions[session_nb-1]) { int r; if (sessions[session_nb-1]->state == stateInDeletion) { sessions[session_nb-1]->handleClose(); delete sessions[session_nb-1]; sessions[session_nb-1]=0; r=1; } else r=sessions[session_nb-1]->poll(); if (r) return 1; } return 0; } void eDVBCISession::receiveData(eDVBCISlot *slot, const unsigned char *ptr, size_t len) { const unsigned char *pkt = (const unsigned char*)ptr; unsigned char tag = *pkt++; int llen, hlen; printf("slot: %p\n",slot); int i; for(i=0;isession_nb:0); if (session) { session->state=stateStarted; session->action=1; } } else { unsigned session_nb; session_nb=pkt[hlen-2]<<8; session_nb|=pkt[hlen-1]&0xFF; if ((!session_nb) || (session_nb >= SLMS)) { printf("PROTOCOL: illegal session number %x\n", session_nb); return; } session=sessions[session_nb-1]; if (!session) { printf("PROTOCOL: data on closed session %x\n", session_nb); return; } switch (tag) { case 0x90: break; case 0x94: session->recvCreateSessionResponse(pkt); break; case 0x95: printf("recvCloseSessionRequest\n"); session->recvCloseSessionRequest(pkt); break; default: printf("INTERNAL: nyi, tag %02x.\n", tag); return; } } hlen += llen + 1; // lengthfield and tag pkt = ((const unsigned char*)ptr) + hlen; len -= hlen; if (session) while (len > 0) { int alen; const unsigned char *tag=pkt; pkt+=3; // tag len-=3; hlen=parseLengthField(pkt, alen); pkt+=hlen; len-=hlen; //if (eDVBCIModule::getInstance()->workarounds_active & eDVBCIModule::workaroundMagicAPDULength) { if (((len-alen) > 0) && ((len - alen) < 3)) { printf("WORKAROUND: applying work around MagicAPDULength\n"); alen=len; } } if (session->receivedAPDU(tag, pkt, alen)) session->action = 1; pkt+=alen; len-=alen; } if (len) printf("PROTOCOL: warning, TL-Data has invalid length\n"); } eDVBCISession::~eDVBCISession() { }