diff options
Diffstat (limited to 'src/pdu_decode.c')
-rw-r--r-- | src/pdu_decode.c | 156 |
1 files changed, 148 insertions, 8 deletions
diff --git a/src/pdu_decode.c b/src/pdu_decode.c index cbc2009..2b9e44c 100644 --- a/src/pdu_decode.c +++ b/src/pdu_decode.c @@ -30,6 +30,7 @@ #include <ctype.h> #include "config.h" +#include "global.h" #include "log.h" #include "utils.h" #include "pdu_decode.h" @@ -82,6 +83,31 @@ int pdu_decode_timestamp(const char *pdu_str, struct tm *tm) 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; + int off_upper; + int off_lower; + int off; + + STRLEN_CHECK(pdu_str, PDU_CDMA_TIMESTAMP_LEN, -1); + + memset(tm, 0, sizeof(*tm)); + memset(buf, 0, sizeof(buf)); + + 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; + } + + return PDU_CDMA_TIMESTAMP_LEN; +} + int pdu_decode_addr(const char *pdu_str, struct pdu_addr *addr, int smsc) { const char *begin = pdu_str; @@ -141,17 +167,21 @@ done: } #define octet_idx(n) octet_align(n) +#define octet_cdma_idx(n) ((n+1) * 7 / 8) #define decode_septet(buf, n) \ shiftl(bit_maskr(cycledown(n, 8)) & buf[octet_idx(n)], cycleup(n, 8)) | \ shiftr(bit_maskl(cycleup(n, 8), 8) & buf[octet_idx(n - 1)], cycledown(n - 1, 8)) -int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu) +#define decode_septet_cdma(buf, n) \ +shiftr(buf[octet_cdma_idx(n)], cycleup(n, 8) + 1) | \ +shiftl(buf[octet_cdma_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 nr_octets; int i; STRLEN_CHECK(pdu_str, HEX_BYTE_LEN, -1); @@ -176,7 +206,30 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu) pdu->user_data_len = PDU_UD_7BIT_MAX; } - nr_octets = octet_align(pdu->user_data_len); + *nr_octets = octet_align(pdu->user_data_len); + } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { + log_debug("data coding alphabet is cdma default"); + + if (!strcmp(Global.core.model, "LE910-SVG")) { + 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; + } + } + else { + 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; + } + } + + if (!strcmp(Global.core.model, "LE910-SVG")) { + *nr_octets = octet_align(pdu->user_data_len); + } + else { + *nr_octets = pdu->user_data_len; + pdu->user_data_len = octet_align_cdma(pdu->user_data_len); + } } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_EIGHT) { log_debug("data coding alphabet is eight"); @@ -186,19 +239,19 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu) pdu->user_data_len = PDU_UD_8BIT_MAX; } - nr_octets = pdu->user_data_len; + *nr_octets = pdu->user_data_len; } else { log_debug("data coding alphabet 0x%02X not implemented", pdu->data_coding.general.alphabet); return -1; } - STRLEN_CHECK(pdu_str, nr_octets * 2, -1); + STRLEN_CHECK(pdu_str, *nr_octets * 2, -1); log_debug("user-data-len: 0x%02X", pdu->user_data_len); - log_debug("nr_octets: 0x%02X", nr_octets); + log_debug("nr_octets: 0x%02X", *nr_octets); - for (i = 0; i < nr_octets; i++) { + for (i = 0; i < *nr_octets; i++) { octets[i] = hex_byte_decode(pdu_str); pdu_str += HEX_BYTE_LEN; } @@ -222,6 +275,32 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu) pdu->user_data[i] = decode_septet(octets, i); } pdu->user_data[i] = '\0'; + } 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_septet_cdma(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 (strcmp(Global.core.model, "LE910-SVG") && pdu->user_data[i-1] == 0) { + log_debug("Removing padded char"); + i--; + pdu->user_data_len--; + } + pdu->user_data[i] = '\0'; } else { for (i = 0; i < pdu->user_data_len; i++) { pdu->user_data[i] = octets[i]; @@ -237,6 +316,7 @@ 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; memset(pdu, 0, sizeof(*pdu)); @@ -341,7 +421,7 @@ int pdu_decode(const char *pdu_str, struct pdu_info *pdu) pdu_str += tmp; } - tmp = pdu_decode_user_data(pdu_str, pdu); + tmp = pdu_decode_user_data(pdu_str, pdu, &nr_octets); DECODE_FAIL(tmp < 0, "user-data", -1); pdu_str += tmp; } @@ -352,3 +432,63 @@ int pdu_decode(const char *pdu_str, struct pdu_info *pdu) 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; + + 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; + + msg_begin = pdu_str; + + 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; + + //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); + + 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); + + //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); + + //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; + + log_debug("msg_len: %d", pdu->msg_len); + + return pdu_str - begin; +} |