00001
00002
00003
00004
00005 #include <stdint.h>
00006
00007 #include "mythcontext.h"
00008
00009 #include "dsmccreceiver.h"
00010 #include "dsmccbiop.h"
00011 #include "dsmcccache.h"
00012 #include "dsmcc.h"
00013
00014 #define DSMCC_SYNC_BYTE 0x47
00015 #define DSMCC_TRANSPORT_ERROR 0x80
00016 #define DSMCC_START_INDICATOR 0x40
00017
00018 #define DSMCC_MESSAGE_DSI 0x1006
00019 #define DSMCC_MESSAGE_DII 0x1002
00020 #define DSMCC_MESSAGE_DDB 0x1003
00021
00022 #define DSMCC_SECTION_INDICATION 0x3B
00023 #define DSMCC_SECTION_DATA 0x3C
00024 #define DSMCC_SECTION_DESCR 0x3D
00025
00026 #define DSMCC_SECTION_OFFSET 0
00027 #define DSMCC_MSGHDR_OFFSET 8
00028 #define DSMCC_DATAHDR_OFFSET 8
00029 #define DSMCC_DSI_OFFSET 20
00030 #define DSMCC_DII_OFFSET 20
00031 #define DSMCC_DDB_OFFSET 20
00032 #define DSMCC_BIOP_OFFSET 24
00033
00034 static uint32_t crc32(const unsigned char *data, int len);
00035
00036 Dsmcc::Dsmcc()
00037 {
00038 carousels.setAutoDelete(true);
00039 m_startTag = 0;
00040 }
00041
00045 ObjCarousel *Dsmcc::GetCarouselById(unsigned int carouselId)
00046 {
00047 QPtrListIterator<ObjCarousel> it(carousels);
00048 ObjCarousel *car;
00049
00050 for (; (car = it.current()) != NULL; ++it)
00051 {
00052 if (car->m_id == carouselId)
00053 return car;
00054 }
00055 return NULL;
00056 }
00057
00066 ObjCarousel *Dsmcc::AddTap(unsigned short componentTag, unsigned carouselId)
00067 {
00068 ObjCarousel *car = GetCarouselById(carouselId);
00069
00070
00071
00072 if (car == NULL)
00073 {
00074 car = new ObjCarousel(this);
00075 carousels.append(car);
00076 car->m_id = carouselId;
00077 }
00078
00079
00080 QValueVector<unsigned short>::iterator it;
00081 for (it = car->m_Tags.begin(); it != car->m_Tags.end(); ++it)
00082 {
00083 if (*it == componentTag)
00084 break;
00085 }
00086
00087 if (it == car->m_Tags.end())
00088 {
00089 car->m_Tags.append(componentTag);
00090 VERBOSE(VB_DSMCC, QString("[dsmcc] Adding tap for stream "
00091 "tag %1 with carousel %2")
00092 .arg(componentTag).arg(carouselId));
00093 }
00094
00095 return car;
00096 }
00097
00098 bool Dsmcc::ProcessSectionHeader(DsmccSectionHeader *header,
00099 const unsigned char *data, int length)
00100 {
00101 int crc_offset = 0;
00102
00103 header->table_id = data[0];
00104 header->flags[0] = data[1];
00105 header->flags[1] = data[2];
00106
00107
00108
00109 if (((header->flags[0] & 0x80) == 0) || (header->flags[0] & 0x40) != 0)
00110 {
00111 VERBOSE(VB_DSMCC, "[dsmcc] Invalid section\n");
00112 return false;
00113 }
00114
00115
00116
00117 header->table_id_extension = (data[4] << 8) | data[5];
00118
00119 header->flags2 = data[6];
00120
00121 crc_offset = length - 4 - 1;
00122
00123
00124
00125 header->crc = ((data[crc_offset] << 24) | (data[crc_offset+1] << 16) |
00126 (data[crc_offset+2] << 8) | (data[crc_offset+3]));
00127
00128 return true;
00129 }
00130
00140 void Dsmcc::ProcessDownloadServerInitiate(const unsigned char *data,
00141 int length)
00142 {
00143 (void) length;
00144
00145 int off = 0, ret;
00146
00147
00148
00149
00150
00151 off = 22;
00152
00153
00154 off += 2;
00155
00156 BiopIor gatewayProfile;
00157 ret = gatewayProfile.Process(data+DSMCC_BIOP_OFFSET);
00158 if (ret > 0)
00159 {
00160 off += ret;
00161 }
00162 else
00163 {
00164 return;
00165 }
00166
00167 VERBOSE(VB_DSMCC, QString("[dsmcc] Gateway Module %1 on carousel %2")
00168 .arg(gatewayProfile.m_profile_body->GetReference()->m_nModuleId)
00169 .arg(gatewayProfile.m_profile_body->
00170 GetReference()->m_nCarouselId));
00171
00172
00173 ProfileBodyFull *full = (ProfileBodyFull*)gatewayProfile.m_profile_body;
00174
00175 VERBOSE(VB_DSMCC, QString("[dsmcc] DSI tap identifies "
00176 "tag %1 with carousel %2")
00177 .arg(full->dsm_conn.tap.assoc_tag)
00178 .arg(gatewayProfile.m_profile_body->
00179 GetReference()->m_nCarouselId));
00180
00181
00182 unsigned int carouselId =
00183 gatewayProfile.m_profile_body->GetReference()->m_nCarouselId;
00184
00185 ObjCarousel *car = AddTap(full->dsm_conn.tap.assoc_tag, carouselId);
00186
00187
00188
00189
00190
00191 unsigned short downloadTapsCount = data[off];
00192 off++;
00193 off += downloadTapsCount;
00194 unsigned short serviceContextListCount = data[off];
00195 off++;
00196 off += serviceContextListCount;
00197 unsigned short userInfoLength = (data[off] << 8) | data[off+1];
00198 off += 2;
00199 off += userInfoLength;
00200
00201
00202 car->filecache.SetGateway(
00203 *(gatewayProfile.m_profile_body->GetReference()));
00204 }
00205
00206 void Dsmcc::ProcessDownloadInfoIndication(const unsigned char *data,
00207 unsigned short streamTag)
00208 {
00209 DsmccDii dii;
00210 int off = 0;
00211
00212 dii.download_id = ((data[0] << 24) | (data[1] << 16) |
00213 (data[2] << 8) | (data[3]));
00214
00215 ObjCarousel *car = GetCarouselById(dii.download_id);
00216
00217 if (car == NULL)
00218 {
00219 VERBOSE(VB_DSMCC, QString("[dsmcc] Section Info for "
00220 "unknown carousel %1")
00221 .arg(dii.download_id));
00222
00223 return;
00224 }
00225
00226 off += 4;
00227 dii.block_size = data[off] << 8 | data[off+1];
00228 off += 2;
00229
00230 off += 6;
00231 dii.tc_download_scenario = ((data[off + 0] << 24) | (data[off + 1] << 16) |
00232 (data[off + 2] << 8) | (data[off + 3]));
00233 off += 4;
00234
00235
00236 off += 2;
00237 dii.number_modules = (data[off] << 8) | data[off + 1];
00238 off += 2;
00239 dii.modules = new DsmccModuleInfo[dii.number_modules];
00240
00241 for (uint i = 0; i < dii.number_modules; i++)
00242 {
00243 dii.modules[i].module_id = (data[off] << 8) | data[off + 1];
00244 off += 2;
00245 dii.modules[i].module_size =
00246 (data[off + 0] << 24) | (data[off + 1] << 16) |
00247 (data[off + 2] << 8) | (data[off + 3]);
00248 off += 4;
00249 dii.modules[i].module_version = data[off++];
00250 dii.modules[i].module_info_len = data[off++];
00251
00252 VERBOSE(VB_DSMCC, QString("[dsmcc] Module %1 -> "
00253 "Size = %2 Version = %3")
00254 .arg(dii.modules[i].module_id)
00255 .arg(dii.modules[i].module_size)
00256 .arg(dii.modules[i].module_version));
00257
00258 int ret = dii.modules[i].modinfo.Process(data + off);
00259
00260 if (ret > 0)
00261 {
00262 off += ret;
00263 }
00264 else
00265 {
00266 return;
00267 }
00268 }
00269
00270 dii.private_data_len = (data[off] << 8) | data[off + 1];
00271
00272 car->AddModuleInfo(&dii, this, streamTag);
00273 return;
00274 }
00275
00276
00277 void Dsmcc::ProcessSectionIndication(const unsigned char *data,
00278 int length, unsigned short streamTag)
00279 {
00280 DsmccSectionHeader section;
00281 if (!ProcessSectionHeader(§ion, data + DSMCC_SECTION_OFFSET, length))
00282 return;
00283
00284 const unsigned char *hdrData = data + DSMCC_MSGHDR_OFFSET;
00285
00286 unsigned char protocol = hdrData[0];
00287 if (protocol != 0x11)
00288 return;
00289
00290 unsigned char header_type = hdrData[1];
00291 if (header_type != 0x03)
00292 return;
00293
00294 unsigned short message_id = (hdrData[2] << 8) | hdrData[3];
00295
00296
00297
00298
00299
00300
00301
00302 unsigned short message_len = (hdrData[10] << 8) | hdrData[11];
00303 if (message_len > 4076)
00304 return;
00305
00306 if (message_id == DSMCC_MESSAGE_DSI)
00307 {
00308 VERBOSE(VB_DSMCC, "[dsmcc] Server Gateway");
00309
00310
00311
00312 if (streamTag == m_startTag)
00313 {
00314 ProcessDownloadServerInitiate(data + DSMCC_DSI_OFFSET,
00315 length - DSMCC_DSI_OFFSET);
00316 }
00317 else
00318 {
00319 VERBOSE(VB_DSMCC, QString("[dsmcc] Discarding DSI from tag %1")
00320 .arg(streamTag));
00321 }
00322
00323 }
00324 else if (message_id == DSMCC_MESSAGE_DII)
00325 {
00326 VERBOSE(VB_DSMCC, "[dsmcc] Module Info");
00327 ProcessDownloadInfoIndication(data + DSMCC_DII_OFFSET, streamTag);
00328 }
00329 else
00330 {
00331 VERBOSE(VB_DSMCC, "[dsmcc] Unknown section");
00332
00333 }
00334
00335 }
00336
00337
00338 void Dsmcc::ProcessSectionData(const unsigned char *data, int length)
00339 {
00340 DsmccSectionHeader section;
00341 if (!ProcessSectionHeader(§ion, data + DSMCC_SECTION_OFFSET, length))
00342 return;
00343
00344 const unsigned char *hdrData = data + DSMCC_DATAHDR_OFFSET;
00345
00346
00347
00348
00349 unsigned long download_id = ((hdrData[4] << 24) | (hdrData[5] << 16) |
00350 (hdrData[6] << 8) | (hdrData[7]));
00351
00352
00353 unsigned short message_len = (hdrData[10] << 8) | hdrData[11];
00354
00355 const unsigned char *blockData = data + DSMCC_DDB_OFFSET;
00356 DsmccDb ddb;
00357
00358 ddb.module_id = (blockData[0] << 8) | blockData[1];
00359 ddb.module_version = blockData[2];
00360
00361 ddb.block_number = (blockData[4] << 8) | blockData[5];
00362 ddb.len = message_len - 6;
00363
00364 VERBOSE(VB_DSMCC, QString("[dsmcc] Data Block ModID %1 Pos %2 Version %3")
00365 .arg(ddb.module_id).arg(ddb.block_number).arg(ddb.module_version));
00366
00367 ObjCarousel *car = GetCarouselById(download_id);
00368 if (car != NULL)
00369 car->AddModuleData(download_id, &ddb, blockData + 6);
00370
00371 return;
00372 }
00373
00374 void Dsmcc::ProcessSectionDesc(const unsigned char *data, int length)
00375 {
00376 DsmccSectionHeader section;
00377 ProcessSectionHeader(§ion, data + DSMCC_SECTION_OFFSET, length);
00378
00379
00380 }
00381
00382
00383 void Dsmcc::ProcessSection(const unsigned char *data, int length,
00384 int componentTag, unsigned carouselId,
00385 int dataBroadcastId)
00386 {
00387
00388 QPtrListIterator<ObjCarousel> it(carousels);
00389 ObjCarousel *car;
00390
00391 VERBOSE(VB_DSMCC, QString("[dsmcc] Read block size %1 from tag %2 "
00392 "carousel id %3 data broadcast Id %4")
00393 .arg(length).arg(componentTag)
00394 .arg(carouselId).arg(dataBroadcastId));
00395
00396 bool found = false;
00397 for (; (car = it.current()) != NULL; ++it)
00398 {
00399
00400 QValueVector<unsigned short>::iterator it;
00401 for (it = car->m_Tags.begin(); it != car->m_Tags.end(); ++it)
00402 {
00403 if (*it == componentTag)
00404 {
00405 found = true;
00406 break;
00407 }
00408 }
00409 if (found)
00410 break;
00411 }
00412 if (!found && dataBroadcastId == 0x0106)
00413 {
00414
00415
00416
00417 car = AddTap(componentTag, carouselId);
00418 m_startTag = componentTag;
00419 found = true;
00420 }
00421
00422 if (!found)
00423 {
00424 VERBOSE(VB_DSMCC, QString("[dsmcc] Dropping block from tag %1")
00425 .arg(componentTag));
00426
00427 return;
00428 }
00429
00430 unsigned short section_len = ((data[1] & 0xF) << 8) | (data[2]);
00431 section_len += 3;
00432
00433 unsigned long crc32_decode = crc32(data, section_len);
00434
00435 if (crc32_decode != 0)
00436 {
00437 VERBOSE(VB_DSMCC,
00438 QString("[dsmcc] Dropping corrupt section (Got %1)")
00439 .arg(crc32_decode));
00440 return;
00441 }
00442
00443 switch (data[0])
00444 {
00445 case DSMCC_SECTION_INDICATION:
00446 VERBOSE(VB_DSMCC, "[dsmcc] Server/Info Section");
00447 ProcessSectionIndication(data, length, componentTag);
00448 break;
00449 case DSMCC_SECTION_DATA:
00450 VERBOSE(VB_DSMCC, "[dsmcc] Data Section");
00451 ProcessSectionData(data, length);
00452 break;
00453 case DSMCC_SECTION_DESCR:
00454 VERBOSE(VB_DSMCC, "[dsmcc] Descriptor Section");
00455 ProcessSectionDesc(data, length);
00456 break;
00457 default:
00458 VERBOSE(VB_DSMCC, QString("[dsmcc] Unknown Section %1")
00459 .arg(data[0]));
00460 break;
00461 }
00462 }
00463
00464
00465 void Dsmcc::Reset()
00466 {
00467 VERBOSE(VB_DSMCC, "Resetting carousel");
00468 carousels.clear();
00469 }
00470
00471 int Dsmcc::GetDSMCCObject(QStringList &objectPath, QByteArray &result)
00472 {
00473 ObjCarousel *car;
00474 QPtrListIterator<ObjCarousel> it(carousels);
00475
00476 if (carousels.isEmpty())
00477 return 1;
00478
00479
00480 for (; (car = it.current()) != NULL; ++it)
00481 {
00482 int res = car->filecache.GetDSMObject(objectPath, result);
00483 if (res != -1)
00484 return res;
00485 }
00486
00487 return -1;
00488 }
00489
00490
00491
00492
00493 static unsigned long crc_table[256] =
00494 {
00495 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
00496 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
00497 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
00498 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
00499 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
00500 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
00501 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
00502 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
00503 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
00504 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
00505 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
00506 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
00507 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
00508 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
00509 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
00510 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
00511 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
00512 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
00513 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
00514 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
00515 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
00516 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
00517 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
00518 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
00519 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
00520 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
00521 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
00522 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
00523 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
00524 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
00525 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
00526 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
00527 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
00528 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
00529 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
00530 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
00531 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
00532 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
00533 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
00534 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
00535 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
00536 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
00537 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
00538 };
00539
00540 static uint32_t crc32(const unsigned char *data, int len)
00541 {
00542 register int i;
00543 uint32_t crc = 0xffffffff;
00544
00545 for (i = 0; i < len; i++)
00546 crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff];
00547
00548 return crc;
00549 }