diff options
-rw-r--r-- | src/pdu.h | 21 | ||||
-rw-r--r-- | src/pdu_decode.c | 96 | ||||
-rw-r--r-- | src/pdu_encode.c | 41 |
3 files changed, 100 insertions, 58 deletions
@@ -49,12 +49,13 @@ enum { PDU_VPF_ABSOUTE = 3, }; +//PDU data formats (how the data was represented before encoding) enum { - PDU_ALPHABET_DEFAULT = 0, //7-bit - PDU_ALPHABET_CDMA_DEFAULT = 2, //7-bit - PDU_ALPHABET_EIGHT = 4, - PDU_ALPHABET_CDMA_EIGHT = 8, - PDU_ALPHABET_DEFAULT_MULTI = 9, + PDU_ALPHABET_DEFAULT = 0, //GSM 7-bit, (supposedly CDMA 8-bit but haven't seen it) + PDU_ALPHABET_CDMA_DEFAULT = 2, //no GSM, CDMA 7-bit + PDU_ALPHABET_EIGHT = 4, //GSM 8-bit, CDMA 16-bit unicode + PDU_ALPHABET_CDMA_EIGHT = 8, //GSM 16-bit, CDMA 8-bit (what CDMA radios are actually using) + PDU_ALPHABET_DEFAULT_MULTI = 9,//no GSM, LVW2 7-bit, multi-part }; struct pdu_info { @@ -117,10 +118,14 @@ int pdu_user_data_read(int fd, struct pdu_info *pdu); #define cycleup(n, mod) ((n) % (mod)) #define cycledown(n, mod) ((mod - 1) - ((n) % (mod))) -#define octet_align(n) ((((n) * 7) + ((-(n) * 7) & 7)) / 8) +//Returns the number of octets the given septets (normal ascii) can be encoded to +#define octets_from_septets(n) ((((n) * 7) + ((-(n) * 7) & 7)) / 8) -#define septet_idx(n) ((n) * 8 / 7) -#define octet_align_cdma(n) septet_idx(n) +//Returns the number of septets the given octets will decode to +#define septets_from_octets(n) ((n) * 8 / 7) + +#define octet_idx(n) octets_from_septets(n) +#define septet_idx(n) septets_from_octets(n) #define STRLEN_CHECK(str, len, ret) \ diff --git a/src/pdu_decode.c b/src/pdu_decode.c index 459916c..27822f3 100644 --- a/src/pdu_decode.c +++ b/src/pdu_decode.c @@ -163,16 +163,14 @@ done: return pdu_str - begin; } -#define octet_idx(n) octet_align(n) -#define octet_cdma_idx(n) ((n+1) * 7 / 8) -#define decode_septet(buf, n) \ +#define decode_septet_from_octet(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)) -#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 +#define decode_cdma_septet_from_octet(buf, n) \ +shiftr(buf[octet_idx(n)], cycleup(n, 8) + 1) | \ +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) { @@ -195,19 +193,19 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe return -1; } - if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) { - log_debug("data coding alphabet is default"); - 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; - } - - *nr_octets = octet_align(pdu->user_data_len); - } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI) { - //GSM style 8 bit conversion but with UDH multi-part header (LE910-SVG) - log_debug("data coding alphabet is nine"); + // ----------------------------------------------------------------------------- + // 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_DEFAULT_MULTI)) { + if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT_MULTI) { + //GSM style 7-bit encoding but with UDH multi-part header (LE910-SVG) + log_debug("data coding alphabet is nine"); + } else { + //GSM 7-bit encoding + log_debug("data coding alphabet is default"); + } if (pdu->user_data_len > PDU_UD_7BIT_MAX) { log_warning("pdu contains invalid user-data-len: 0x%02X", @@ -215,31 +213,30 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe pdu->user_data_len = PDU_UD_7BIT_MAX; } - *nr_octets = octet_align(pdu->user_data_len); + //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) { log_debug("data coding alphabet is cdma default"); - // Encoding 02 is 7 bit for LE910-SVG but 8 bit for other CDMA radios + // LE910-SVG stores data length as # of septets 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; - } + *nr_octets = octets_from_septets(pdu->user_data_len); } + // Other CDMA radios store data length as # of octets 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; - } + *nr_octets = pdu->user_data_len; + pdu->user_data_len = septets_from_octets(pdu->user_data_len); } - 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); + 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)) { log_debug("data coding alphabet is eight"); @@ -250,7 +247,11 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe 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; + + // UNSUPPORTED } else { log_debug("data coding alphabet 0x%02X not implemented", pdu->data_coding.general.alphabet); @@ -259,14 +260,20 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe 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 (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_DEFAULT_MULTI)) { // Keep UDH for concatenated SMS. @@ -284,12 +291,15 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe i++; } } + user_data_start_index = i; for (; i < pdu->user_data_len; i++) { - pdu->user_data[i] = decode_septet(octets, 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. @@ -305,10 +315,12 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe i++; } } + for (; i < pdu->user_data_len; i++) { - pdu->user_data[i] = decode_septet_cdma(octets, 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 (strcmp(Global.core.model, "LE910-SVG") && (pdu->user_data[i-1] == 0)) { log_debug("Removing padded char"); @@ -316,6 +328,8 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe 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]; @@ -323,7 +337,11 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe pdu->user_data[i] = '\0'; } - //Only for GSM 7-bit character set + + // --------------------------------------------------------------------- + // 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_DEFAULT_MULTI)) { int read = user_data_start_index; diff --git a/src/pdu_encode.c b/src/pdu_encode.c index ce62ee8..4d43eac 100644 --- a/src/pdu_encode.c +++ b/src/pdu_encode.c @@ -183,7 +183,9 @@ int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu, int *n } - //Convert to GSM character set, Only for 7-bit character set + // --------------------------------------------------------------------- + // FOR GSM 7-BIT ENCODING ONLY, ENCODE FROM IRA ALPHABET TO GSM ALPHABET + // --------------------------------------------------------------------- if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) { int read = 0; int store = 0; @@ -226,28 +228,36 @@ int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu, int *n } + // ------------------------------ + // ENCODE USER DATA INTO PDU DATA + // ------------------------------ + // GSM 7-BIT ENCODING if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) { if (pdu->user_data_len > PDU_UD_7BIT_MAX) { log_error("string exceeds 7-bit data max length"); return -1; } - *nr_octets = octet_align(pdu->user_data_len); + *nr_octets = octets_from_septets(pdu->user_data_len); for (i = 0; i < *nr_octets; i++) { octets[i] = encode_octet(pdu->user_data, i); + log_debug("ENCODE: i: %d data: 0x%02X --> octet: 0x%02X", i, pdu->user_data[i], octets[i]); } + + // CDMA 7-BIT ENCODING } else if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { if (pdu->user_data_len > PDU_UD_7BIT_MAX) { log_error("string exceeds 7-bit data max length"); return -1; } - //CDMA ENCODING - *nr_octets = octet_align(pdu->user_data_len); - pdu->user_data_len = *nr_octets; + *nr_octets = octets_from_septets(pdu->user_data_len); for (i = 0; i < *nr_octets; i++) { octets[i] = encode_cdma_octet(pdu->user_data, i); + log_debug("ENCODE: i: %d data: 0x%02X --> octet: 0x%02X", i, pdu->user_data[i], octets[i]); } + + // ALL 8-BIT ENCODING } else { if (pdu->user_data_len > PDU_UD_8BIT_MAX) { log_error("string exceeds 8-bit data max length"); @@ -265,10 +275,19 @@ int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu, int *n return -1; } - tmp = hex_byte_encode(pdu_str, len, pdu->user_data_len); - ENCODE_FAIL(tmp != HEX_BYTE_LEN, "user-data-len", -1); - pdu_str += tmp; - len -= tmp; + if (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT) { + // user_data_len is stored as number of encoded octets + // (but GSM is stored as originial # of septets) + log_debug("putting nr_octets into PDU as data length (CDMA)"); + tmp = hex_byte_encode(pdu_str, len, *nr_octets); + } + else { + log_debug("putting user_data_len into PDU as data length"); + tmp = hex_byte_encode(pdu_str, len, pdu->user_data_len); + } + ENCODE_FAIL(tmp != HEX_BYTE_LEN, "user-data-len", -1); + pdu_str += tmp; + len -= tmp; for (i = 0; i < *nr_octets; i++) { hex_byte_encode(pdu_str, len, octets[i]); @@ -277,8 +296,8 @@ int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu, int *n len -= *nr_octets * 2; pdu_str[i] = '\0'; - log_debug("user-data-len: 0x%02X", pdu->user_data_len); - log_debug("nr_octets: 0x%02X", *nr_octets); + log_debug("user-data-len: 0x%02X (before encoding)", pdu->user_data_len); + log_debug("nr_octets: 0x%02X (after encoding)", *nr_octets); return pdu_str - begin; } |