diff options
Diffstat (limited to 'src/pdu_decode.c')
-rw-r--r-- | src/pdu_decode.c | 878 |
1 files changed, 439 insertions, 439 deletions
diff --git a/src/pdu_decode.c b/src/pdu_decode.c index 9c0ced5..9014162 100644 --- a/src/pdu_decode.c +++ b/src/pdu_decode.c @@ -37,134 +37,134 @@ #define DECODE_FAIL(cond, name, ret) \ do { \ - if (cond) { \ - log_error("decode failed at %s", name); \ - return ret; \ - } \ + if (cond) { \ + log_error("decode failed at %s", name); \ + return ret; \ + } \ } while (0) int pdu_decode_timestamp(const char *pdu_str, struct tm *tm) { - char buf[PDU_TIMESTAMP_SIZE + 3]; - char *cp; - int off_upper; - int off_lower; - int off; + char buf[PDU_TIMESTAMP_SIZE + 3]; + char *cp; + int off_upper; + int off_lower; + int off; - STRLEN_CHECK(pdu_str, PDU_TIMESTAMP_LEN, -1); + STRLEN_CHECK(pdu_str, PDU_TIMESTAMP_LEN, -1); - memset(tm, 0, sizeof(*tm)); - memset(buf, 0, sizeof(buf)); + memset(tm, 0, sizeof(*tm)); + memset(buf, 0, sizeof(buf)); - strncpy(buf, pdu_str, PDU_TIMESTAMP_LEN); - nibble_swap(buf, PDU_TIMESTAMP_LEN); - strunpad(buf, 'F'); + strncpy(buf, pdu_str, PDU_TIMESTAMP_LEN); + nibble_swap(buf, PDU_TIMESTAMP_LEN); + strunpad(buf, 'F'); - off_upper = hex_nibble_scan(buf + GMT_OFFSET_IDX, 1); - off_lower = hex_nibble_scan(buf + GMT_OFFSET_IDX + 1, 1); + off_upper = hex_nibble_scan(buf + GMT_OFFSET_IDX, 1); + off_lower = hex_nibble_scan(buf + GMT_OFFSET_IDX + 1, 1); - if (off_upper & BIT(3)) { - off_upper &= ~BIT(3); - buf[GMT_OFFSET_IDX] = '-'; - } else { - buf[GMT_OFFSET_IDX] = '+'; - } + if (off_upper & BIT(3)) { + off_upper &= ~BIT(3); + buf[GMT_OFFSET_IDX] = '-'; + } else { + buf[GMT_OFFSET_IDX] = '+'; + } - off = (off_upper * 10 + off_lower) * 15; + off = (off_upper * 10 + off_lower) * 15; - snprintf(buf + GMT_OFFSET_IDX + 1, 5, "%02d%02d", off / 60, off % 60); + snprintf(buf + GMT_OFFSET_IDX + 1, 5, "%02d%02d", off / 60, off % 60); - cp = (char *) strptime(buf, "%y%m%d%H%M%S%z", tm); - if (!cp || *cp) { - log_error("timestamp could not be converted to tm"); - return -1; - } + cp = (char *) strptime(buf, "%y%m%d%H%M%S%z", tm); + if (!cp || *cp) { + log_error("timestamp could not be converted to tm"); + return -1; + } - return PDU_TIMESTAMP_LEN; + return PDU_TIMESTAMP_LEN; } int pdu_decode_cdma_timestamp(const char *pdu_str, struct tm *tm) { - char buf[PDU_CDMA_TIMESTAMP_LEN + 1]; - char *cp; + char buf[PDU_CDMA_TIMESTAMP_LEN + 1]; + char *cp; - STRLEN_CHECK(pdu_str, PDU_CDMA_TIMESTAMP_LEN, -1); + STRLEN_CHECK(pdu_str, PDU_CDMA_TIMESTAMP_LEN, -1); - memset(tm, 0, sizeof(*tm)); - memset(buf, 0, sizeof(buf)); + memset(tm, 0, sizeof(*tm)); + memset(buf, 0, sizeof(buf)); - strncpy(buf, pdu_str, PDU_CDMA_TIMESTAMP_LEN); + strncpy(buf, pdu_str, PDU_CDMA_TIMESTAMP_LEN); - cp = (char *) strptime(buf, "%y%m%d%H%M%S", tm); - if (!cp || *cp) { - log_error("timestamp could not be converted to tm"); - return -1; - } + cp = (char *) strptime(buf, "%y%m%d%H%M%S", tm); + if (!cp || *cp) { + log_error("timestamp could not be converted to tm"); + return -1; + } - return PDU_CDMA_TIMESTAMP_LEN; + return PDU_CDMA_TIMESTAMP_LEN; } int pdu_decode_addr(const char *pdu_str, struct pdu_addr *addr, int smsc) { - const char *begin = pdu_str; - int addr_len; - int tmp; - - memset(addr, 0, sizeof(*addr)); - - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "addr-len", -1); - pdu_str += HEX_BYTE_LEN; - addr->len = tmp; - - addr_len = addr->len; - if (smsc) { - if (!addr_len) { - goto done; - } - addr_len = addr_len * HEX_BYTE_LEN - HEX_BYTE_LEN; - } else { - if (addr_len & 1) { - addr_len++; - } - } - - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "addr-type", -1); - pdu_str += HEX_BYTE_LEN; - addr->type = tmp; - - if (addr_len < 0 || addr_len >= sizeof(addr->addr)) { - log_error("invalid length: 0x%02X", addr_len); - return -1; - } - - log_debug("addr-len [transformed]: 0x%02X", addr_len); - log_debug("addr-type: 0x%02X", addr->type); - - STRLEN_CHECK(pdu_str, addr_len, -1); - - strncpy(addr->addr, pdu_str, addr_len); - - nibble_swap(addr->addr, addr_len); - strunpad(addr->addr, 'F'); - if(addr->type == 0x91) {//91 indicates international format of the phone number - memmove(&addr->addr[1],addr->addr,addr_len); - addr->addr[0]='+'; - }; - pdu_str += addr_len; + const char *begin = pdu_str; + int addr_len; + int tmp; + + memset(addr, 0, sizeof(*addr)); + + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "addr-len", -1); + pdu_str += HEX_BYTE_LEN; + addr->len = tmp; + + addr_len = addr->len; + if (smsc) { + if (!addr_len) { + goto done; + } + addr_len = addr_len * HEX_BYTE_LEN - HEX_BYTE_LEN; + } else { + if (addr_len & 1) { + addr_len++; + } + } + + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "addr-type", -1); + pdu_str += HEX_BYTE_LEN; + addr->type = tmp; + + if (addr_len < 0 || addr_len >= sizeof(addr->addr)) { + log_error("invalid length: 0x%02X", addr_len); + return -1; + } + + log_debug("addr-len [transformed]: 0x%02X", addr_len); + log_debug("addr-type: 0x%02X", addr->type); + + STRLEN_CHECK(pdu_str, addr_len, -1); + + strncpy(addr->addr, pdu_str, addr_len); + + nibble_swap(addr->addr, addr_len); + strunpad(addr->addr, 'F'); + if (addr->type == 0x91) {//91 indicates international format of the phone number + memmove(&addr->addr[1],addr->addr,addr_len); + addr->addr[0]='+'; + }; + pdu_str += addr_len; done: - log_debug("addr: %s", addr->addr); - log_debug("addr-len: 0x%02X", addr->len); + log_debug("addr: %s", addr->addr); + log_debug("addr-len: 0x%02X", addr->len); - return pdu_str - begin; + return pdu_str - begin; } @@ -178,400 +178,400 @@ shiftl(buf[octet_idx(n) - 1], cycledown(n, 8)) & 0x7F int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octets) { - const char *begin = pdu_str; - int tmp; - uint8_t octets[PDU_OCTETS_MAX + 1]; - int user_data_start_index = 0; - int i; - - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "user-data-len", -1); - pdu_str += HEX_BYTE_LEN; - pdu->user_data_len = tmp; - - if (pdu->data_coding.general.unused) { - log_error("data coding group 0x%02X not implemented", - pdu->data_coding.data_coding & 0xF0); - return -1; - } - - - if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT || - pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT2 ) - { - log_debug("data coding alphabet is default (7-bit)"); - } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI) { - log_debug("data coding alphabet is default (7-bit) multi-part"); - } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { - log_debug("data coding alphabet is CDMA default (7-bit)"); - } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_EIGHT) { - log_debug("data coding alphabet is eight"); - } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_EIGHT) { - log_debug("data coding alphabet is CDMA eight"); - } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_TE) { - log_debug("data coding alphabet is TE specific 7-bit"); - } else { - log_debug("data coding alphabet 0x%02X not implemented", - pdu->data_coding.general.alphabet); - return -1; - } - - // ----------------------------------------------------------------------------- - // VERIFY DATA LENGTH AND GET NUMBER OF OCTETS (ACTUAL DATA BYTES IN PDU STRING) - // ----------------------------------------------------------------------------- - if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) || - (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT2) || - (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI)|| - (pdu->data_coding.general.alphabet == PDU_ALPHABET_TE)) { - if (pdu->user_data_len > PDU_UD_7BIT_MAX) { - log_warning("pdu contains invalid user-data-len: 0x%02X", - pdu->user_data_len); - pdu->user_data_len = PDU_UD_7BIT_MAX; - } - - //GSM 7-bit data (septets) length is encoded in PDU as number of septets - // (which is same as user_data_len), but octets is needed for decoding loop - *nr_octets = octets_from_septets(pdu->user_data_len); - - // CDMA 7-BIT ENCODING - } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { - if (is_vzw_lte()) { - // LE910-SVG stores data length as # of septets - log_debug("counting PDU length byte as number of septets (LE910-SVG/LE910-SV1/LE910-NA1/VZW)"); - *nr_octets = octets_from_septets(pdu->user_data_len); - } - else { - // Other CDMA radios store data length as # of octets - // NOTE: CE910 send PDU needs # of septets but receive PDU is in # of octets - log_debug("counting PDU length byte as number of octets"); - *nr_octets = pdu->user_data_len; - pdu->user_data_len = septets_from_octets(pdu->user_data_len); - } - - - if (pdu->user_data_len > PDU_UD_7BIT_MAX) { - log_warning("pdu contains invalid user-data-len: 0x%02X", pdu->user_data_len); - pdu->user_data_len = PDU_UD_7BIT_MAX; - } - - // GSM & CDMA 8-BIT ENCODING - } else if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_EIGHT) || - (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_EIGHT)) { - if (pdu->user_data_len > PDU_UD_8BIT_MAX) { - log_warning("pdu contains invalid user-data-len: 0x%02X", - pdu->user_data_len); - pdu->user_data_len = PDU_UD_8BIT_MAX; - } - - //Original data is octets (all 8 bits could contain data) - //Therefore, octets = user_data_len - *nr_octets = pdu->user_data_len; - } - - STRLEN_CHECK(pdu_str, *nr_octets * 2, -1); - - log_debug("nr_octets: 0x%02X (encoded data length)", *nr_octets); - log_debug("user-data-len: 0x%02X (decoded data length)", pdu->user_data_len); - - //Copy user data from pdu string into octets - for (i = 0; i < *nr_octets; i++) { - octets[i] = hex_byte_decode(pdu_str); - pdu_str += HEX_BYTE_LEN; - } - - - // --------------------------------------------------------- - // DECODE USER DATA (IF NEEDED) AND COPY INTO pdu->user_data - // --------------------------------------------------------- - // GSM 7-BIT & LVW2 7-BIT MULTI-PART - if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) || - (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT2) || - (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI)|| - (pdu->data_coding.general.alphabet == PDU_ALPHABET_TE)) { - // Keep UDH for concatenated SMS ONLY. - // Otherwise it is impossible to process correctly concatenated SMS. - i = 0; - if (pdu->type.user_data_header || - // For LVW3, LNA3 and LVW2 - Save header ONLY when it's actually a multi-part message. - // Multi-part messages should use Teleservice ID 4101 (0x1005) in LVW2 7-BIT MULTI-PART format. - // See 3GPP2 X.S0004-550-E for details on Teleservice ID. - (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI - && pdu->teleservice_id == PDU_TELE_ID_CDMA_WEMT)) { - for (i = 0; i <= octets[0]; ++i) { - pdu->user_data[i] = octets[i]; - } - i = octets[0] + 1; // Set message text start after UDH. - // Process octets padding for 7-bit encoding. - if (0 != (i * 8) % 7) { - pdu->user_data[i] = 0; // set padding data to 0; - i++; - } - } - - user_data_start_index = i; - for (; i < pdu->user_data_len; i++) { - pdu->user_data[i] = decode_septet_from_octet(octets, i); - log_debug("DECODE: i: %d octet: 0x%02X --> data: 0x%02X", i, octets[i], pdu->user_data[i]); - } - pdu->user_data[i] = '\0'; - - // CDMA 7-BIT - } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { - // Keep UDH for concatenated SMS. - // Otherwise it is impossible to process correctly concatenated SMS. - i = 0; - if (pdu->type.user_data_header) { - for (i = 0; i <= octets[0]; ++i) { - pdu->user_data[i] = octets[i]; - } - i = octets[0] + 1; // Set message text start after UDH. - // Process octets padding for 7-bit encoding. - if (0 != (i * 8) % 7) { - pdu->user_data[i] = 0; // set padding data to 0; - i++; - } - } - - for (; i < pdu->user_data_len; i++) { - pdu->user_data[i] = decode_cdma_septet_from_octet(octets, i); - log_debug("DECODE: i: %d octet: 0x%02X --> data: 0x%02X", i, octets[i], pdu->user_data[i]); - } - - //Remove padded byte for data length of 7 characters if not LE910-SVG - if (!is_vzw_lte() && (pdu->user_data[i-1] == 0)) { - log_debug("Removing padded char"); - i--; - pdu->user_data_len--; - } - pdu->user_data[i] = '\0'; - - // ALL 8-BIT ENCODING - } else { - for (i = 0; i < pdu->user_data_len; i++) { - pdu->user_data[i] = octets[i]; - } - pdu->user_data[i] = '\0'; - } - - - // --------------------------------------------------------------------- - // FOR GSM 7-BIT ENCODING ONLY, DECODE FROM GSM ALPHABET TO IRA ALPHABET - // (includes LVW2 multi-part) - // --------------------------------------------------------------------- - if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) || - (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT2) || - (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI)) { - int read = user_data_start_index; - int store = user_data_start_index; - - log_debug("Converting from GSM character set to IRA"); - for (; read < pdu->user_data_len; read++) { - if (pdu->user_data[read] == 0x1B) { - //Character from the extended set using the escape char (27) - read++; - log_debug("GSM before: 0x1B%02X | IRA after: 0x%02X", pdu->user_data[read], strExtendedTable[pdu->user_data[read]]); - pdu->user_data[store] = strExtendedTable[pdu->user_data[read]]; - } - else { - log_debug("GSM before: 0x%02X | IRA after: 0x%02X", pdu->user_data[read], strGSMTable[pdu->user_data[read]]); - pdu->user_data[store] = strGSMTable[pdu->user_data[read]]; - } - store++; - } - //Update lengths - pdu->user_data_len -= read - store; - pdu_str -= (read - store) * HEX_BYTE_LEN; - } - - return pdu_str - begin; + const char *begin = pdu_str; + int tmp; + uint8_t octets[PDU_OCTETS_MAX + 1]; + int user_data_start_index = 0; + int i; + + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "user-data-len", -1); + pdu_str += HEX_BYTE_LEN; + pdu->user_data_len = tmp; + + if (pdu->data_coding.general.unused) { + log_error("data coding group 0x%02X not implemented", + pdu->data_coding.data_coding & 0xF0); + return -1; + } + + + if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT || + pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT2 ) + { + log_debug("data coding alphabet is default (7-bit)"); + } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI) { + log_debug("data coding alphabet is default (7-bit) multi-part"); + } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { + log_debug("data coding alphabet is CDMA default (7-bit)"); + } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_EIGHT) { + log_debug("data coding alphabet is eight"); + } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_EIGHT) { + log_debug("data coding alphabet is CDMA eight"); + } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_TE) { + log_debug("data coding alphabet is TE specific 7-bit"); + } else { + log_debug("data coding alphabet 0x%02X not implemented", + pdu->data_coding.general.alphabet); + return -1; + } + + // ----------------------------------------------------------------------------- + // VERIFY DATA LENGTH AND GET NUMBER OF OCTETS (ACTUAL DATA BYTES IN PDU STRING) + // ----------------------------------------------------------------------------- + if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT2) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI)|| + (pdu->data_coding.general.alphabet == PDU_ALPHABET_TE)) { + if (pdu->user_data_len > PDU_UD_7BIT_MAX) { + log_warning("pdu contains invalid user-data-len: 0x%02X", + pdu->user_data_len); + pdu->user_data_len = PDU_UD_7BIT_MAX; + } + + //GSM 7-bit data (septets) length is encoded in PDU as number of septets + // (which is same as user_data_len), but octets is needed for decoding loop + *nr_octets = octets_from_septets(pdu->user_data_len); + + // CDMA 7-BIT ENCODING + } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { + if (is_telit_lte_vzw_3gpp2_format()) { + // LE910-SVG stores data length as # of septets + log_debug("counting PDU length byte as number of septets (LE910-SVG/LE910-SV1/LE910-NA1/VZW)"); + *nr_octets = octets_from_septets(pdu->user_data_len); + } + else { + // Other CDMA radios store data length as # of octets + // NOTE: CE910 send PDU needs # of septets but receive PDU is in # of octets + log_debug("counting PDU length byte as number of octets"); + *nr_octets = pdu->user_data_len; + pdu->user_data_len = septets_from_octets(pdu->user_data_len); + } + + + if (pdu->user_data_len > PDU_UD_7BIT_MAX) { + log_warning("pdu contains invalid user-data-len: 0x%02X", pdu->user_data_len); + pdu->user_data_len = PDU_UD_7BIT_MAX; + } + + // GSM & CDMA 8-BIT ENCODING + } else if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_EIGHT) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_EIGHT)) { + if (pdu->user_data_len > PDU_UD_8BIT_MAX) { + log_warning("pdu contains invalid user-data-len: 0x%02X", + pdu->user_data_len); + pdu->user_data_len = PDU_UD_8BIT_MAX; + } + + //Original data is octets (all 8 bits could contain data) + //Therefore, octets = user_data_len + *nr_octets = pdu->user_data_len; + } + + STRLEN_CHECK(pdu_str, *nr_octets * 2, -1); + + log_debug("nr_octets: 0x%02X (encoded data length)", *nr_octets); + log_debug("user-data-len: 0x%02X (decoded data length)", pdu->user_data_len); + + //Copy user data from pdu string into octets + for (i = 0; i < *nr_octets; i++) { + octets[i] = hex_byte_decode(pdu_str); + pdu_str += HEX_BYTE_LEN; + } + + + // --------------------------------------------------------- + // DECODE USER DATA (IF NEEDED) AND COPY INTO pdu->user_data + // --------------------------------------------------------- + // GSM 7-BIT & LVW2 7-BIT MULTI-PART + if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT2) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI)|| + (pdu->data_coding.general.alphabet == PDU_ALPHABET_TE)) { + // Keep UDH for concatenated SMS ONLY. + // Otherwise it is impossible to process correctly concatenated SMS. + i = 0; + if (pdu->type.user_data_header || + // For LVW3, LNA3 and LVW2 - Save header ONLY when it's actually a multi-part message. + // Multi-part messages should use Teleservice ID 4101 (0x1005) in LVW2 7-BIT MULTI-PART format. + // See 3GPP2 X.S0004-550-E for details on Teleservice ID. + (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI + && pdu->teleservice_id == PDU_TELE_ID_CDMA_WEMT)) { + for (i = 0; i <= octets[0]; ++i) { + pdu->user_data[i] = octets[i]; + } + i = octets[0] + 1; // Set message text start after UDH. + // Process octets padding for 7-bit encoding. + if (0 != (i * 8) % 7) { + pdu->user_data[i] = 0; // set padding data to 0; + i++; + } + } + + user_data_start_index = i; + for (; i < pdu->user_data_len; i++) { + pdu->user_data[i] = decode_septet_from_octet(octets, i); + log_debug("DECODE: i: %d octet: 0x%02X --> data: 0x%02X", i, octets[i], pdu->user_data[i]); + } + pdu->user_data[i] = '\0'; + + // CDMA 7-BIT + } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { + // Keep UDH for concatenated SMS. + // Otherwise it is impossible to process correctly concatenated SMS. + i = 0; + if (pdu->type.user_data_header) { + for (i = 0; i <= octets[0]; ++i) { + pdu->user_data[i] = octets[i]; + } + i = octets[0] + 1; // Set message text start after UDH. + // Process octets padding for 7-bit encoding. + if (0 != (i * 8) % 7) { + pdu->user_data[i] = 0; // set padding data to 0; + i++; + } + } + + for (; i < pdu->user_data_len; i++) { + pdu->user_data[i] = decode_cdma_septet_from_octet(octets, i); + log_debug("DECODE: i: %d octet: 0x%02X --> data: 0x%02X", i, octets[i], pdu->user_data[i]); + } + + //Remove padded byte for data length of 7 characters if not LE910-SVG + if (!is_telit_lte_vzw_3gpp2_format() && (pdu->user_data[i-1] == 0)) { + log_debug("Removing padded char"); + i--; + pdu->user_data_len--; + } + pdu->user_data[i] = '\0'; + + // ALL 8-BIT ENCODING + } else { + for (i = 0; i < pdu->user_data_len; i++) { + pdu->user_data[i] = octets[i]; + } + pdu->user_data[i] = '\0'; + } + + + // --------------------------------------------------------------------- + // FOR GSM 7-BIT ENCODING ONLY, DECODE FROM GSM ALPHABET TO IRA ALPHABET + // (includes LVW2 multi-part) + // --------------------------------------------------------------------- + if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT2) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI)) { + int read = user_data_start_index; + int store = user_data_start_index; + + log_debug("Converting from GSM character set to IRA"); + for (; read < pdu->user_data_len; read++) { + if (pdu->user_data[read] == 0x1B) { + //Character from the extended set using the escape char (27) + read++; + log_debug("GSM before: 0x1B%02X | IRA after: 0x%02X", pdu->user_data[read], strExtendedTable[pdu->user_data[read]]); + pdu->user_data[store] = strExtendedTable[pdu->user_data[read]]; + } + else { + log_debug("GSM before: 0x%02X | IRA after: 0x%02X", pdu->user_data[read], strGSMTable[pdu->user_data[read]]); + pdu->user_data[store] = strGSMTable[pdu->user_data[read]]; + } + store++; + } + //Update lengths + pdu->user_data_len -= read - store; + pdu_str -= (read - store) * HEX_BYTE_LEN; + } + + return pdu_str - begin; } int pdu_decode(const char *pdu_str, struct pdu_info *pdu) { - const char *begin = pdu_str; - const char *msg_begin; - int tmp; - int nr_octets; + const char *begin = pdu_str; + const char *msg_begin; + int tmp; + int nr_octets; - memset(pdu, 0, sizeof(*pdu)); + memset(pdu, 0, sizeof(*pdu)); - tmp = pdu_decode_addr(pdu_str, &pdu->smsc_addr, 1); - DECODE_FAIL(tmp < 0, "smsc-addr", -1); - pdu_str += tmp; + tmp = pdu_decode_addr(pdu_str, &pdu->smsc_addr, 1); + DECODE_FAIL(tmp < 0, "smsc-addr", -1); + pdu_str += tmp; - msg_begin = pdu_str; + msg_begin = pdu_str; - log_debug("smsc-addr: %s", pdu->smsc_addr.addr); - log_debug("smsc-addr-type: 0x%02X", pdu->smsc_addr.type); - log_debug("smsc-addr-len: 0x%02X", pdu->smsc_addr.len); + log_debug("smsc-addr: %s", pdu->smsc_addr.addr); + log_debug("smsc-addr-type: 0x%02X", pdu->smsc_addr.type); + log_debug("smsc-addr-len: 0x%02X", pdu->smsc_addr.len); - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "type", -1); - pdu_str += HEX_BYTE_LEN; - pdu->type.type = tmp; + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "type", -1); + pdu_str += HEX_BYTE_LEN; + pdu->type.type = tmp; - log_debug("type: 0x%02X", pdu->type.type); + log_debug("type: 0x%02X", pdu->type.type); - if (pdu->type.msg_type == PDU_MTI_SUBMIT || - pdu->type.msg_type == PDU_MTI_REPORT) { - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + if (pdu->type.msg_type == PDU_MTI_SUBMIT || + pdu->type.msg_type == PDU_MTI_REPORT) { + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "msg-reference", -1); - pdu_str += HEX_BYTE_LEN; - pdu->msg_reference = tmp; + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "msg-reference", -1); + pdu_str += HEX_BYTE_LEN; + pdu->msg_reference = tmp; - log_debug("msg-reference: 0x%02X", pdu->msg_reference); - } + log_debug("msg-reference: 0x%02X", pdu->msg_reference); + } - tmp = pdu_decode_addr(pdu_str, &pdu->addr, 0); - DECODE_FAIL(tmp < 0, "addr", -1); - pdu_str += tmp; + tmp = pdu_decode_addr(pdu_str, &pdu->addr, 0); + DECODE_FAIL(tmp < 0, "addr", -1); + pdu_str += tmp; - log_debug("addr: %s", pdu->addr.addr); - log_debug("addr-type: 0x%02X", pdu->addr.type); - log_debug("addr-len: 0x%02X", pdu->addr.len); + log_debug("addr: %s", pdu->addr.addr); + log_debug("addr-type: 0x%02X", pdu->addr.type); + log_debug("addr-len: 0x%02X", pdu->addr.len); - switch (pdu->type.msg_type) { - case PDU_MTI_REPORT: - tmp = pdu_decode_timestamp(pdu_str, &pdu->timestamp); - DECODE_FAIL(tmp < 0, "report-timestamp", -1); - pdu_str += tmp; + switch (pdu->type.msg_type) { + case PDU_MTI_REPORT: + tmp = pdu_decode_timestamp(pdu_str, &pdu->timestamp); + DECODE_FAIL(tmp < 0, "report-timestamp", -1); + pdu_str += tmp; - break; - case PDU_MTI_DELIVER: - case PDU_MTI_SUBMIT: - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + break; + case PDU_MTI_DELIVER: + case PDU_MTI_SUBMIT: + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "protocol-id", -1); - pdu_str += HEX_BYTE_LEN; - pdu->protocol_id = tmp; + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "protocol-id", -1); + pdu_str += HEX_BYTE_LEN; + pdu->protocol_id = tmp; - log_debug("protocol-id: 0x%02X", pdu->protocol_id); + log_debug("protocol-id: 0x%02X", pdu->protocol_id); - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "data-coding-scheme", -1); - pdu_str += HEX_BYTE_LEN; - pdu->data_coding.data_coding = tmp; + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "data-coding-scheme", -1); + pdu_str += HEX_BYTE_LEN; + pdu->data_coding.data_coding = tmp; - log_debug("data-coding-scheme: 0x%02X", pdu->data_coding.data_coding); + log_debug("data-coding-scheme: 0x%02X", pdu->data_coding.data_coding); - if (pdu->type.msg_type == PDU_MTI_SUBMIT) { - log_debug("validity-period-format: 0x%02X", - pdu->type.validity_period_format); - switch (pdu->type.validity_period_format) { - case PDU_VPF_RELATIVE: - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + if (pdu->type.msg_type == PDU_MTI_SUBMIT) { + log_debug("validity-period-format: 0x%02X", + pdu->type.validity_period_format); + switch (pdu->type.validity_period_format) { + case PDU_VPF_RELATIVE: + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "validity-period", -1); - pdu_str += HEX_BYTE_LEN; - pdu->validity_period = tmp; + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "validity-period", -1); + pdu_str += HEX_BYTE_LEN; + pdu->validity_period = tmp; - log_debug("validity-period: 0x%02X", pdu->validity_period); + log_debug("validity-period: 0x%02X", pdu->validity_period); - break; + break; - case PDU_VPF_ENHANCED: - log_warning("PDU_VPF_ENHANCED? Falling through to absolute"); - case PDU_VPF_ABSOUTE: - tmp = pdu_decode_timestamp(pdu_str, &pdu->timestamp); - DECODE_FAIL(tmp < 0, "validity-period-timestamp", -1); - pdu_str += tmp; + case PDU_VPF_ENHANCED: + log_warning("PDU_VPF_ENHANCED? Falling through to absolute"); + case PDU_VPF_ABSOUTE: + tmp = pdu_decode_timestamp(pdu_str, &pdu->timestamp); + DECODE_FAIL(tmp < 0, "validity-period-timestamp", -1); + pdu_str += tmp; - return -1; + return -1; - case PDU_VPF_NOT_PRESENT: - default: - break; - } - } else if (pdu->type.msg_type == PDU_MTI_DELIVER) { - tmp = pdu_decode_timestamp(pdu_str, &pdu->timestamp); - DECODE_FAIL(tmp < 0, "delivery-timestamp", -1); - pdu_str += tmp; - } + case PDU_VPF_NOT_PRESENT: + default: + break; + } + } else if (pdu->type.msg_type == PDU_MTI_DELIVER) { + tmp = pdu_decode_timestamp(pdu_str, &pdu->timestamp); + DECODE_FAIL(tmp < 0, "delivery-timestamp", -1); + pdu_str += tmp; + } - tmp = pdu_decode_user_data(pdu_str, pdu, &nr_octets); - DECODE_FAIL(tmp < 0, "user-data", -1); - pdu_str += tmp; - } + tmp = pdu_decode_user_data(pdu_str, pdu, &nr_octets); + DECODE_FAIL(tmp < 0, "user-data", -1); + pdu_str += tmp; + } - pdu->msg_len = (pdu_str - msg_begin) / 2; + pdu->msg_len = (pdu_str - msg_begin) / 2; - log_debug("msg_len: %d", pdu->msg_len); + log_debug("msg_len: %d", pdu->msg_len); - return pdu_str - begin; + return pdu_str - begin; } int pdu_decode_cdma(const char *pdu_str, struct pdu_info *pdu) { - const char *begin = pdu_str; - const char *msg_begin; - int tmp; - int nr_octets; + const char *begin = pdu_str; + const char *msg_begin; + int tmp; + int nr_octets; - memset(pdu, 0, sizeof(*pdu)); + memset(pdu, 0, sizeof(*pdu)); - //Destination address - tmp = pdu_decode_addr(pdu_str, &pdu->addr, 1); - DECODE_FAIL(tmp < 0, "addr", -1); - pdu_str += tmp; + //Destination address + tmp = pdu_decode_addr(pdu_str, &pdu->addr, 1); + DECODE_FAIL(tmp < 0, "addr", -1); + pdu_str += tmp; - msg_begin = pdu_str; + msg_begin = pdu_str; - STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); + STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); - //Timestamp - tmp = pdu_decode_cdma_timestamp(pdu_str, &pdu->timestamp); - DECODE_FAIL(tmp < 0, "timestamp", -1); - pdu_str += tmp; + //Timestamp + tmp = pdu_decode_cdma_timestamp(pdu_str, &pdu->timestamp); + DECODE_FAIL(tmp < 0, "timestamp", -1); + pdu_str += tmp; - //Teleservice ID - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "tele-id-1", -1); - pdu_str += HEX_BYTE_LEN; - log_debug("tele-id-1: 0x%02X", tmp); + //Teleservice ID + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "tele-id-1", -1); + pdu_str += HEX_BYTE_LEN; + log_debug("tele-id-1: 0x%02X", tmp); - pdu->teleservice_id = 0; - pdu->teleservice_id |= (tmp << 8); // save upper byte of the Teleservice ID + pdu->teleservice_id = 0; + pdu->teleservice_id |= (tmp << 8); // save upper byte of the Teleservice ID - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "tele-id-2", -1); - pdu_str += HEX_BYTE_LEN; - log_debug("tele-id-2: 0x%02X", tmp); + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "tele-id-2", -1); + pdu_str += HEX_BYTE_LEN; + log_debug("tele-id-2: 0x%02X", tmp); - pdu->teleservice_id |= (tmp); // save lower byte of the Teleservice ID - log_debug("tele-id: 0x%04X", pdu->teleservice_id); + pdu->teleservice_id |= (tmp); // save lower byte of the Teleservice ID + log_debug("tele-id: 0x%04X", pdu->teleservice_id); - //Priority - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "priority", -1); - pdu_str += HEX_BYTE_LEN; - log_debug("priority: 0x%02X", tmp); + //Priority + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "priority", -1); + pdu_str += HEX_BYTE_LEN; + log_debug("priority: 0x%02X", tmp); - //Data coding scheme - tmp = hex_byte_decode(pdu_str); - DECODE_FAIL(tmp < 0, "data-coding-scheme", -1); - pdu_str += HEX_BYTE_LEN; - pdu->data_coding.data_coding = tmp; - log_debug("data-coding-scheme: 0x%02X", pdu->data_coding.data_coding); + //Data coding scheme + tmp = hex_byte_decode(pdu_str); + DECODE_FAIL(tmp < 0, "data-coding-scheme", -1); + pdu_str += HEX_BYTE_LEN; + pdu->data_coding.data_coding = tmp; + log_debug("data-coding-scheme: 0x%02X", pdu->data_coding.data_coding); - //User Data - tmp = pdu_decode_user_data(pdu_str, pdu, &nr_octets); - DECODE_FAIL(tmp < 0, "user-data", -1); - pdu_str += tmp; + //User Data + tmp = pdu_decode_user_data(pdu_str, pdu, &nr_octets); + DECODE_FAIL(tmp < 0, "user-data", -1); + pdu_str += tmp; - pdu->msg_len = 6 + nr_octets; + pdu->msg_len = 6 + nr_octets; - log_debug("msg_len: %d", pdu->msg_len); + log_debug("msg_len: %d", pdu->msg_len); - return pdu_str - begin; + return pdu_str - begin; } |