/* $Id: mcl_lct_hdr.cpp,v 1.10 2003/10/29 16:02:08 roca Exp $ */ /* * Copyright (c) 1999-2003 INRIA - Universite Paris 6 - All rights reserved * (main author: Vincent Roca - vincent.roca@inrialpes.fr) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "mcl_includes.h" /* * private functions */ /* sending side */ static int lct_hdr_add_FTI_he (mclcb_t *mclcb, char *ptr, int hlen, hdr_infos_t *hdr_infos); static int lct_hdr_add_NONEWADU_he (mclcb_t *mclcb, char *ptr, int hlen, hdr_infos_t *hdr_infos); static int lct_hdr_add_FDT_he (mclcb_t *mclcb, char *ptr, int hlen, hdr_infos_t *hdr_infos); /* receiving side */ static int lct_hdr_parse_he (mclcb_t *mclcb, char *ptr, int hlen, hdr_infos_t *hdr_infos); /****** sending side **********************************************************/ /* * Initializes the LCT header (fixed header plus common fields) * Assumes that the memory block has been allocated by the caller * who MUST ensure that it will be large enough to hold all the * possible fields! * Returns the size of the LCT header (bytes), -1 if error. */ int lct_hdr_create (mclcb_t *mclcb, fixed_lct_hdr_t *lct_hdr, hdr_infos_t *hdr_infos) { int hlen; /* length of fixed+variable LCT hdr (bytes) */ TRACELVL(5, (mcl_stdout, "-> lct_hdr_create:\n")) /* * fixed size LCT header part */ lct_hdr->version= LCT_VERSION; lct_hdr->flag_c = 0; /* no CC extension */ lct_hdr->reserved = 0; lct_hdr->flag_h = 0; /* no half word format by default */ lct_hdr->flag_s = 0; /* no TSI field by default */ lct_hdr->flag_o = 0; /* no TOI field by default */ lct_hdr->flag_t = 0; /* no SCT field by default */ lct_hdr->flag_r = 0; /* no ERT field by default */ lct_hdr->flag_a = (hdr_infos->close > 0) ? 1 : 0; lct_hdr->flag_b = 0; /* no object close by default */ lct_hdr->codepoint = hdr_infos->fec_encoding_id; /* NB: the FPI field is added by ALC if required ! */ /* * hlen (total header len) is different from lct_hdr->hdr_len * (which only includes the header variable size part) */ hlen = sizeof(fixed_lct_hdr_t); /* includes 32bit CCI field */ ASSERT(!lct_hdr->flag_s); /* no additional CCI extension */ /* * additional fields */ if (hdr_infos->demux_label) { /* add transport session idf (previously called demux_label) */ lct_hdr->flag_s = 1; *(u_int32_t*)((char*)lct_hdr + hlen) = htonl(hdr_infos->demux_label); hlen += 4; } /* add a 32 bits TOI (tx object idf) */ lct_hdr->flag_o = 1; /* 32 bits */ *(u_int32_t*)((char*)lct_hdr + hlen) = htonl(hdr_infos->idf_adu); hlen += 4; /* * add header extensions if any */ if (hdr_infos->FTI_present) { /* add an FTI extension */ ASSERT(hdr_infos->adu_len > 0); hlen = lct_hdr_add_FTI_he(mclcb,(char*)lct_hdr, hlen, hdr_infos); if (hlen < 0) goto bad; } if (hdr_infos->FDT_present) { /* add an FDT extension */ hlen = lct_hdr_add_FDT_he(mclcb,(char*)lct_hdr, hlen, hdr_infos); if (hlen < 0) goto bad; } if (hdr_infos->NONEWADU_present) { ASSERT(hdr_infos->max_idf_adu >= mcl_iss); hlen = lct_hdr_add_NONEWADU_he(mclcb,(char*)lct_hdr, hlen, hdr_infos); if (hlen < 0) goto bad; } lct_hdr->hdr_len = hlen >> 2; /* in 32-bit words */ /* * and finally swap the first 16 bits of header in network endian */ *(u_int16_t*)lct_hdr = htons(*(u_int16_t*)lct_hdr); TRACELVL(5, (mcl_stdout, "<- lct_hdr_create: hlen=%d\n", hlen)) return hlen; bad: TRACELVL(5, (mcl_stdout, "<- lct_hdr_create: ERROR\n")) return -1; } /* * Add a FTI header extension, using the provided hdr_infos, depending * on the FEC Encoding ID. * * With FEC Encoding IDs 0 (NO FEC) and 128 (SMALL BLOCK, LARGE BLOCK * and EXPENDING): * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | HET = 64 | HEL | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Object Length (bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | FEC Instance ID | Encoding Symbol Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Source Block Length (k) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * * With FEC Encoding ID 140 (private ID (!), for our LDGM/LDPC codec): * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | HET = 64 | HEL | FEC Key | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Object Length (bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | FEC Instance ID | Encoding Symbol Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Source Block Length (k) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | FEC block length in symbols (n) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * NB: This FTI header extension is not RFC 3452 compliant but we need * the additional info with our LDGM/LDPC FEC codec. * The FEC key and the FEC block lenth fields are specific to * LDGM/LDPC codes who need this information to create the * appropriate parity check matrix (i.e. the same as the one * used by the source). * * Returns the new size of the header (bytes) with this * header extension, or -1 if error. */ static int lct_hdr_add_FTI_he (mclcb_t *mclcb, char *ptr, int hlen, hdr_infos_t *hdr_infos) { u_int32_t word1 = 0; u_int32_t word2 = 0; TRACELVL(5, (mcl_stdout, "-> lct_hdr_add_FTI_he:\n")) ASSERT(hdr_infos); ASSERT(hdr_infos->FTI_present); if (hdr_infos->fec_encoding_id == FEC_ENCODING_ID_NO_FEC || hdr_infos->fec_encoding_id == FEC_ENCODING_ID_SMALL_LARGE_EXP_FEC) { word1 = (EXT_FTI << 24) | (4 << 16); *(u_int32_t*)(ptr + hlen) = htonl(word1); hlen += 4; *(u_int32_t*)(ptr + hlen) = htonl(hdr_infos->adu_len); hlen += 4; word2 = (hdr_infos->fec_instance_id << 16) | (hdr_infos->symbol_len); *(u_int32_t*)(ptr + hlen) = htonl(word2); hlen += 4; *(u_int32_t*)(ptr + hlen) = htonl(hdr_infos->k); hlen += 4; } #ifdef LDPC_FEC else if (hdr_infos->fec_encoding_id == FEC_ENCODING_ID_LDPC_FEC) { /* private format */ word1 = (EXT_FTI << 24) | (5 << 16) | (u_int16_t)(hdr_infos->fec_key); *(u_int32_t*)(ptr + hlen) = htonl(word1); hlen += 4; *(u_int32_t*)(ptr + hlen) = htonl(hdr_infos->adu_len); hlen += 4; word2 = hdr_infos->fec_instance_id << 16 | (hdr_infos->symbol_len); *(u_int32_t*)(ptr + hlen) = htonl(word2); hlen += 4; *(u_int32_t*)(ptr + hlen) = htonl(hdr_infos->k); hlen += 4; *(u_int32_t*)(ptr + hlen) = htonl(hdr_infos->n); hlen += 4; } #endif TRACELVL(5, (mcl_stdout, "<- lct_hdr_add_FTI_he: hlen=%d\n", hlen)) return hlen; } /* * Add a header extension, using either the provided hdr_infos, * or by copying an externally supplied buffer containing the already * formatted extension header. * Updates the lct_hdr->hdr_len as required. * * not LCT compliant (extension): * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |L|HET=NONEWADU | HEL = 2 | 0 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | max object idf | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Returns the new size of the header (bytes) with this/these * extension header(s), or -1 if error. */ static int lct_hdr_add_NONEWADU_he (mclcb_t *mclcb, char *ptr, int hlen, hdr_infos_t *hdr_infos) { u_int32_t word1 = 0; TRACELVL(5, (mcl_stdout, "-> lct_hdr_add_NONEWADU_he:\n")) ASSERT(hdr_infos != NULL); ASSERT(hdr_infos->NONEWADU_present); ASSERT(hdr_infos->max_idf_adu >= mcl_iss); /* SIG_NONEWADU */ word1 = SIG_NONEWADU << 24 | (2 << 16); *(u_int32_t*)(ptr + hlen) = htonl(word1); hlen += 4; *(u_int32_t*)(ptr + hlen) = htonl(hdr_infos->max_idf_adu); hlen += 4; TRACELVL(5, (mcl_stdout, "<- lct_hdr_add_NONEWADU_he: max=%d\n", hdr_infos->max_idf_adu)) return hlen; } /* * Add FDT instance header EXT_FDT * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | HET=192 | FDT instance ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Returns the new size of the header (bytes) with this/these * extension header(s), or -1 if error. */ static int lct_hdr_add_FDT_he (mclcb_t *mclcb, char *ptr, int hlen, hdr_infos_t *hdr_infos) { u_int32_t word1 = 0; TRACELVL(5, (mcl_stdout, "-> lct_hdr_add_FDT_he:\n")) ASSERT(hdr_infos != NULL); ASSERT(hdr_infos->FDT_present); /* SIG_NONEWADU */ word1 = EXT_FDT << 24 | hdr_infos->FDT_instanceid; *(u_int32_t*)(ptr + hlen) = htonl(word1); hlen += 4; TRACELVL(5, (mcl_stdout, "<- lct_hdr_add_FDT_he: max=%d\n", hdr_infos->max_idf_adu)) return hlen; } /****** receiving side ********************************************************/ /* * Parses the LCT header of the received packet * Assumes that hdr_infos is already reset. * Returns the size of the LCT header (bytes), -1 if error. */ int lct_hdr_parse (mclcb_t *mclcb, fixed_lct_hdr_t *lct_hdr, hdr_infos_t *hdr_infos) { int hlen; /* length of fixed+variable LCT hdr (bytes) */ TRACELVL(5, (mcl_stdout, "-> lct_hdr_parse:\n")) /* * first of all swap the first 16 bits of header in host endian */ *(u_int16_t*)lct_hdr = ntohs(*(u_int16_t*)lct_hdr); /* sanity checks */ if ((lct_hdr->version != LCT_VERSION) || (lct_hdr->reserved != 0)) { PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, unknown version|non 0 reserved field\n")) goto bad_hdr; } /* check codepoint (in fact FEC Encoding ID) now */ if ((lct_hdr->codepoint != FEC_ENCODING_ID_NO_FEC) && (lct_hdr->codepoint != FEC_ENCODING_ID_SMALL_LARGE_EXP_FEC) #ifdef LDPC_FEC && (lct_hdr->codepoint != FEC_ENCODING_ID_LDPC_FEC) #endif ) { PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, unsupported codepoint/FEC encoding ID (%d)\n", lct_hdr->codepoint)) goto bad_hdr; } hdr_infos->fec_encoding_id = lct_hdr->codepoint; /* check header length */ if (lct_hdr->hdr_len < (2 + lct_hdr->flag_c + lct_hdr->flag_h + lct_hdr->flag_s + lct_hdr->flag_o + lct_hdr->flag_t + lct_hdr->flag_r)) { PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, hdr_len %d too short\n", lct_hdr->hdr_len)) goto bad_hdr; } /* * header flags */ //hdr_infos->payload_id_present = lct_hdr->flag_p;/* FPI added by ALC */ if (lct_hdr->flag_c != 0) { /* CC extension */ PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, CC of size > 32 bits not supported\n")) goto bad_hdr; } if (lct_hdr->flag_h) { /* half-word format */ PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, CC extension and half-word not supported\n")) goto bad_hdr; } if (lct_hdr->flag_t | lct_hdr->flag_r) { /* timing fields */ PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, SCT/ERT not supported\n")) goto bad_hdr; } hdr_infos->close = lct_hdr->flag_a; /* CLOSE session flag */ if (lct_hdr->flag_b) { /* CLOSE object flag */ PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, flag B (close object) not supported\n")) goto bad_hdr; } hlen = sizeof(fixed_lct_hdr_t); /* * additional fields */ if (lct_hdr->flag_s) { /* transport session idf (previously called demux_label) */ hdr_infos->demux_label = ntohl(*(u_int32_t*)((char*)lct_hdr + hlen)); hlen += 4; } else { hdr_infos->demux_label = 0; } if (lct_hdr->flag_o > 0) { /* TOI (Transport Object Idf) */ if (lct_hdr->flag_o == 1) { hdr_infos->idf_adu = ntohl(*(u_int32_t*)((char*)lct_hdr + hlen)); hlen += 4; } else { PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, TOI size != 32bits not supported\n")) goto bad_hdr; } } /* * parse extension headers if any */ if (hlen < (int)(lct_hdr->hdr_len << 2)) { hlen = lct_hdr_parse_he(mclcb,(char*)lct_hdr, hlen, hdr_infos); if (hlen < 0) goto bad_hdr; } if (hlen != (int)(lct_hdr->hdr_len << 2)) { PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, bad hdr_len (announced %d, actual %d)\n", lct_hdr->hdr_len, (hlen>>2) - 2)) goto bad_hdr; } TRACELVL(5, (mcl_stdout, "<- lct_hdr_parse: demux_label=%d\n", hdr_infos->demux_label)) return hlen; bad_hdr: PRINT_ERR((mcl_stderr, "lct_hdr_parse: ERROR, bad header, dropped\n")) TRACELVL(5, (mcl_stdout, "<- lct_hdr_parse: ERROR\n")) return -1; } /* * Returns the new size of the header (bytes) with the HE field(s), * or <0 if error */ static int lct_hdr_parse_he (mclcb_t *mclcb, char *ptr, int hlen, hdr_infos_t *hdr_infos) { fixed_lct_hdr_t *lct_hdr = (fixed_lct_hdr_t*)ptr; u_int32_t word1; /* first word of the HE */ u_int32_t word2; int can_ignore = 0; /* can be safely ignored bit */ int HET; int HEL; int eh_len; /* hdr extension length (32bit words) */ TRACELVL(5, (mcl_stdout, "-> lct_hdr_parse_he:\n")) /* * go through all HE */ for (eh_len = lct_hdr->hdr_len - (hlen >> 2); eh_len > 0; ) { /* at least one word long! */ word1 = ntohl(*(int*)(ptr + hlen)); hlen += 4; eh_len--; /*can_ignore = word1 >> 31;*/ can_ignore = 0; /* false for the present */ HET = (word1 & 0xFF000000) >> 24; HEL = (word1 & 0x00FF0000) >> 16; /* invalid if HET<64 */ TRACELVL(5, (mcl_stdout, " lct_hdr_parse_he: new HE, word=x%x, HET=%d, HEL=%d\n", word1, HET, HEL)) switch (HET) { case EXT_FDT: hdr_infos->FDT_instanceid= word1 & 0x00FFFFFF; hdr_infos->FDT_present = true; break; case EXT_FTI: /* * the FTI format depends on the FEC Encoding ID, * which has been checked before... */ /* assume the length (HEL) is ok, it will be checked * just bellow... */ hdr_infos->adu_len = ntohl(*(int*)(ptr + hlen)); hlen += 4; eh_len--; word2 = ntohl(*(int*)(ptr + hlen)); hdr_infos->fec_instance_id=(word2 & 0xFFFF0000)>> 16; switch (hdr_infos->fec_encoding_id) { case FEC_ENCODING_ID_NO_FEC: case FEC_ENCODING_ID_SMALL_LARGE_EXP_FEC: if (HEL != 4) { PRINT_ERR((mcl_stderr, "lct_hdr_parse_he: ERROR, bad HEL (%d) for FTI of Encoding ID %d\n", HEL, hdr_infos->fec_encoding_id)) goto bad; } hdr_infos->symbol_len=word2 & 0x0000FFFF; hlen += 4; eh_len--; hdr_infos->k = ntohl(*(int*)(ptr + hlen)); hlen += 4; eh_len--; break; #ifdef LDPC_FEC case FEC_ENCODING_ID_LDPC_FEC: if (HEL != 5) { PRINT_ERR((mcl_stderr, "lct_hdr_parse_he: ERROR, bad HEL (%d) for FTI of Encoding ID %d\n", HEL, hdr_infos->fec_encoding_id)) goto bad; } hdr_infos->fec_key = word1 & 0x0000FFFF; hdr_infos->symbol_len=word2 & 0x0000FFFF; hlen += 4; eh_len--; hdr_infos->k = ntohl(*(int*)(ptr + hlen)); hlen += 4; eh_len--; hdr_infos->n = ntohl(*(int*)(ptr + hlen)); hlen += 4; eh_len--; break; #endif default: PRINT_ERR((mcl_stderr, "lct_hdr_parse_he: ERROR, unsupported FEC enconding ID (%d) in FTI hdr ext\n", hdr_infos->fec_encoding_id)) goto bad; } hdr_infos->FTI_present = true; break; case SIG_NONEWADU: if (HEL != 2) { PRINT_ERR((mcl_stderr, "lct_hdr_parse_he: ERROR, bad NONEWADU hdr ext\n")) goto bad; } hdr_infos->max_idf_adu = ntohl(*(int*)(ptr + hlen)); hlen += 4; eh_len--; hdr_infos->NONEWADU_present = true; break; case EXT_NOP: /* ignore */ break; default: if (can_ignore) { /* first word already counted */ hlen += (HET < 128) ? (HEL << 2) - 4 : 0; eh_len -= (HET < 64) ? HEL - 1 : 0; PRINT_ERR((mcl_stderr, "lct_hdr_parse_HE: WARNING, unsupported HET %d (HEL=%d, word=x%x), ignored!\n", HET, HEL, word1)) break; } else { PRINT_ERR((mcl_stderr, "lct_hdr_parse_HE: ERROR, unsupported HET %d (HEL=%d, word=x%x)\n", HET, HEL, word1)) return -1; } } } TRACELVL(5, (mcl_stdout, "<- lct_hdr_parse_he:\n")) return hlen; bad: TRACELVL(5, (mcl_stdout, "<- lct_hdr_parse_he: ERROR\n")) return -1; }