summaryrefslogtreecommitdiffstats
path: root/src/gsm
diff options
context:
space:
mode:
authorDennis Wehrle <dennis.wehrle@rz.uni-freiburg.de>2011-07-24 20:14:13 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2011-07-24 20:14:13 +0200
commit291e61346bb55d0462c07bf078cab3bb7eec2241 (patch)
tree7ad60ee02aa3cd494b92d1c8362320d1cf4dfd47 /src/gsm
parentc0dbe0be056df7992800276cee01e106272ccd2b (diff)
sms: SMS where cropped (from VTY), concatenation of SMS where not possible
Additionally it wasn't possible to send concatenated sms from the vty. To send multiple sms, it is necessary to use padding bits and add a user_data_header. Therefore the gsm_7bit_encode function was splitted to gsm_7bit_encode and gsm_septets2octets. gsm_septets2octets: this is the old gsm_7bit_encode function + additional padding parameter Additionally the gsm_7bit_decode function was modified to take account for the user_data_header. With the new gsm_get_octet_len function you can get the octet length for a given septet length. I also added several sms tests.
Diffstat (limited to 'src/gsm')
-rw-r--r--src/gsm/gsm_utils.c118
1 files changed, 89 insertions, 29 deletions
diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c
index 5da713c2..6b9cadc4 100644
--- a/src/gsm/gsm_utils.c
+++ b/src/gsm/gsm_utils.c
@@ -73,28 +73,44 @@ static int gsm_septet_lookup(uint8_t ch)
return -1;
}
+/* Compute the number of octets from the number of septets, for instance: 47 septets needs 41,125 = 42 octets */
+uint8_t gsm_get_octet_len(const uint8_t sept_len){
+ int octet_len = (sept_len * 7) / 8;
+ if ((sept_len * 7) % 8 != 0)
+ octet_len++;
+
+ return octet_len;
+}
+
/* GSM 03.38 6.2.1 Character unpacking */
-int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length)
+int gsm_7bit_decode_hdr(char *text, const uint8_t *user_data, uint8_t septet_l, uint8_t ud_hdr_ind)
{
int i = 0;
- int l = 0;
- int septet_l = (length * 8) / 7;
+ int shift = 0;
+
uint8_t *rtext = calloc(septet_l, sizeof(uint8_t));
uint8_t tmp;
- /* FIXME: We need to account for user data headers here */
- i += l;
- for (; i < septet_l; i++){
+ /* skip the user data header */
+ if (ud_hdr_ind) {
+ /* get user data header length + 1 (for the 'user data header length'-field) */
+ shift = ((user_data[0] + 1) * 8) / 7;
+ if ((((user_data[0] + 1) * 8) % 7) != 0)
+ shift++;
+ septet_l = septet_l - shift;
+ }
+
+ for (i = 0; i < septet_l; i++) {
rtext[i] =
- ((user_data[(i * 7 + 7) >> 3] <<
- (7 - ((i * 7 + 7) & 7))) |
- (user_data[(i * 7) >> 3] >>
- ((i * 7) & 7))) & 0x7f;
+ ((user_data[((i + shift) * 7 + 7) >> 3] <<
+ (7 - (((i + shift) * 7 + 7) & 7))) |
+ (user_data[((i + shift) * 7) >> 3] >>
+ (((i + shift) * 7) & 7))) & 0x7f;
}
for(i = 0; i < septet_l; i++){
/* this is an extension character */
- if(rtext[i] == 0x1b && i + 1 < length){
+ if(rtext[i] == 0x1b && i + 1 < septet_l){
tmp = rtext[i+1];
*(text++) = gsm_7bit_alphabet[0x7f + tmp];
i++;
@@ -104,14 +120,21 @@ int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length)
*(text++) = gsm_septet_lookup(rtext[i]);
}
+ if (ud_hdr_ind)
+ i += shift;
*text = '\0';
free(rtext);
return i;
}
+int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
+{
+ return gsm_7bit_decode_hdr(text, user_data, septet_l, 0);
+}
+
/* GSM 03.38 6.2.1 Prepare character packing */
-static int gsm_septet_encode(uint8_t *result, const char *data)
+int gsm_septet_encode(uint8_t *result, const char *data)
{
int i, y = 0;
uint8_t ch;
@@ -139,38 +162,75 @@ static int gsm_septet_encode(uint8_t *result, const char *data)
return y;
}
-/* GSM 03.38 6.2.1 Character packing */
-int gsm_7bit_encode(uint8_t *result, const char *data)
-{
- int i,y,z = 0;
- /* prepare for the worst case, every character expanding to two bytes */
- uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
+/* 7bit to octet packing */
+int gsm_septets2octets(uint8_t *result, uint8_t *rdata, uint8_t septet_len, uint8_t padding){
+ int i = 0, z = 0;
uint8_t cb, nb;
int shift = 0;
+ uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t));
- y = gsm_septet_encode(rdata, data);
-
- for(i = 0; i < y; i++) {
- if(shift == 7 && i + 1 < y){
- shift = 0;
- continue;
+ if (padding) {
+ shift = 7 - padding;
+ /* the first zero is needed for padding */
+ memcpy(data + 1, rdata, septet_len);
+ septet_len++;
+ } else
+ memcpy(data, rdata, septet_len);
+
+ for(i = 0; i < septet_len; i++) {
+ if (shift == 7) {
+ /*
+ * special end case with the. This is necessary if the
+ * last septet fits into the previous octet. E.g. 48
+ * non-extension characters:
+ * ....ag ( a = 1100001, g = 1100111)
+ * result[40] = 100001 XX, result[41] = 1100111 1 */
+ if (i + 1 < septet_len) {
+ shift = 0;
+ continue;
+ } else if (i + 1 == septet_len)
+ break;
}
- cb = (rdata[i] & 0x7f) >> shift;
- if(i + 1 < y){
- nb = (rdata[i + 1] & 0x7f) << (7 - shift);
+ cb = (data[i] & 0x7f) >> shift;
+ if (i + 1 < septet_len) {
+ nb = (data[i + 1] & 0x7f) << (7 - shift);
cb = cb | nb;
}
result[z++] = cb;
-
shift++;
}
- free(rdata);
+ free(data);
+
return z;
}
+/* GSM 03.38 6.2.1 Character packing */
+int gsm_7bit_encode(uint8_t *result, const char *data)
+{
+ int y = 0, z = 0;
+ /* prepare for the worst case, every character expanding to two bytes */
+ uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
+ y = gsm_septet_encode(rdata, data);
+ z = gsm_septets2octets(result, rdata, y, 0);
+
+ free(rdata);
+
+ /*
+ * We don't care about the number of octets (z), because they are not
+ * unique. E.g.:
+ * 1.) 46 non-extension characters + 1 extension character
+ * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
+ * 2.) 47 non-extension characters
+ * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
+ * 3.) 48 non-extension characters
+ * => (48 * 7 bit) / 8 bit = 42 octects
+ */
+ return y;
+}
+
/* convert power class to dBm according to GSM TS 05.05 */
unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
{