Hi Holger

On 19.03.2011 01:54, Holger Hans Peter Freyther wrote:
On 03/18/2011 11:01 PM, Dennis Wehrle wrote:
Hello

Hi Dennis,

thank you very much for your patch. There are some formal issues with the
patch and it would be nice if you could resolve them.

sure ;-)


* In general we don't keep commented out code around, please remove it.
* We avoid the // comments.

Can you explain why? (just for my interest)

* When introducing a new function that has known static linkage please
   use a namespace, e.g. not get_octlet_length but at least
   gsm_get_octet_length or put in 7bit as well.

Besides that your patch looks nice, but I do have two concerns. Your 160 char
limit assumes the default GSM alphabet? In the future we might be able to
encode and decode from different (e.g. chinese/unicode) alphabet. The same
concern is for the new code in db.c that handles things specially. It would be
nice if all of this could be hidden in libosmocore or such.

I have moved the septet length lookup to the gsm_utils.c. This function looks for characters defined at the "GSM 7bit default alphabet extension table" (GSM 03.38 6.2.1.1) which needs two septets. These characters are: ^ | € { } [ ] ~ \

cheers
        holger


Best Regards
Dennis
diff --git a/include/osmocore/gsm_utils.h b/include/osmocore/gsm_utils.h
index 0aadd2e..a47ce7b 100644
--- a/include/osmocore/gsm_utils.h
+++ b/include/osmocore/gsm_utils.h
@@ -59,6 +59,9 @@ enum gsm_band gsm_band_parse(const char *mhz);
 int gsm_7bit_decode(char *decoded, const uint8_t *user_data, uint8_t length);
 int gsm_7bit_encode(uint8_t *result, const char *data);
 
+uint8_t gsm_get_octet_len(const uint8_t sept_len);
+uint8_t gsm_get_septet_len(const char *text);
+
 int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm);
 int ms_pwr_dbm(enum gsm_band band, uint8_t lvl);
 
diff --git a/src/gsm_utils.c b/src/gsm_utils.c
index 31e3cd6..faac7cf 100644
--- a/src/gsm_utils.c
+++ b/src/gsm_utils.c
@@ -73,17 +73,52 @@ static int gsm_septet_lookup(uint8_t ch)
 	return -1;
 }
 
+/* Warning, user_data_len indicates the amount of septets (characters), we need amount of octets occupied */
+/* compute the number of octets: */
+/* #octets = (#septets * 7 bit) / 8 bit */
+/* e.g. 47 non-extension characters needs 329 bits / 8 bit = 41,125 octets => we need 42 octets for 47 characters */
+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;
+}
+
+
+/* Get number of septets. Each extension character has to be count twice, because they need 2 septets*/
+uint8_t gsm_get_septet_len(const char *text){
+	uint8_t septet_len = strlen(text);
+	int i;
+	for(i = 0; i < strlen(text); i++){
+		switch(text[i]){
+		case 0x0c:
+		case 0x5e:
+		case 0x7b:
+		case 0x7d:
+		case 0x5c:
+		case 0x5b:
+		case 0x7e:
+		case 0x5d:
+		case 0x7c:
+			septet_len++;
+		default:
+			continue;
+		}
+	}
+	return septet_len;
+}
+
 /* GSM 03.38 6.2.1 Character unpacking */
 int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length)
 {
 	int i = 0;
-	int l = 0;
-	int septet_l = (length * 8) / 7;
+
+	int septet_l = length;
 	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++){
 		rtext[i] =
 			((user_data[(i * 7 + 7) >> 3] <<
@@ -155,6 +190,12 @@ int gsm_7bit_encode(uint8_t *result, const char *data)
 			shift = 0;
 			continue;
 		}
+		/* special end case. 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(shift == 7 && i + 1 == y)
+			break;
 
 		cb = (rdata[i] & 0x7f) >> shift;
 		if(i + 1 < y){
@@ -168,7 +209,12 @@ int gsm_7bit_encode(uint8_t *result, const char *data)
 	}
 
 	free(rdata);
-	return z;
+
+	/* we don't care about the number of octets, 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;
 }
 
 /* determine power control level for given dBm value, as indicated
diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
index 95a7d36..cf72332 100644
--- a/openbsc/src/libmsc/db.c
+++ b/openbsc/src/libmsc/db.c
@@ -996,8 +996,10 @@ int db_sms_store(struct gsm_sms *sms)
 
 	dbi_conn_quote_string_copy(conn, (char *)sms->text, &q_text);
 	dbi_conn_quote_string_copy(conn, (char *)sms->dest_addr, &q_daddr);
-	dbi_conn_quote_binary_copy(conn, sms->user_data, sms->user_data_len,
-				   &q_udata);
+
+	int octet_len = gsm_get_octet_len(sms->user_data_len);
+	dbi_conn_quote_binary_copy(conn, sms->user_data, octet_len, &q_udata);
+
 	/* FIXME: correct validity period */
 	result = dbi_conn_queryf(conn,
 		"INSERT INTO SMS "
@@ -1057,17 +1059,21 @@ static struct gsm_sms *sms_from_result(struct gsm_network *net, dbi_result resul
 		sms->dest_addr[sizeof(sms->dest_addr)-1] = '\0';
 	}
 
-	sms->user_data_len = dbi_result_get_field_length(result, "user_data");
-	user_data = dbi_result_get_binary(result, "user_data");
-	if (sms->user_data_len > sizeof(sms->user_data))
-		sms->user_data_len = (u_int8_t) sizeof(sms->user_data);
-	memcpy(sms->user_data, user_data, sms->user_data_len);
-
 	text = dbi_result_get_string(result, "text");
 	if (text) {
 		strncpy(sms->text, text, sizeof(sms->text));
 		sms->text[sizeof(sms->text)-1] = '\0';
 	}
+
+	/* user_data_len contains the number of septets, therefore use the "text"-field to get user_data_len. */
+	/* But each extension character has to be count twice, because they need 2 septets. */
+	sms->user_data_len = gsm_get_septet_len(text);
+
+	user_data = dbi_result_get_binary(result, "user_data");
+	if (sms->user_data_len > sizeof(sms->user_data))
+		sms->user_data_len = (u_int8_t) sizeof(sms->user_data);
+	memcpy(sms->user_data, user_data, sms->user_data_len);
+
 	return sms;
 }
 
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index 812e758..891571f 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -526,9 +526,7 @@ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
 	/* generate TP-UD */
 	switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
 	case DCS_7BIT_DEFAULT:
-		octet_len = sms->user_data_len*7/8;
-		if (sms->user_data_len*7%8 != 0)
-			octet_len++;
+		octet_len = gsm_get_octet_len(sms->user_data_len);
 		/* Warning, user_data_len indicates the amount of septets
 		 * (characters), we need amount of octets occupied */
 		smsp = msgb_put(msg, octet_len);
diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c
index 494c319..90227c7 100644
--- a/openbsc/src/libmsc/gsm_04_80.c
+++ b/openbsc/src/libmsc/gsm_04_80.c
@@ -73,7 +73,9 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
 	/* First put the payload text into the message */
 	ptr8 = msgb_put(msg, 0);
 	response_len = gsm_7bit_encode(ptr8, response_text);
-	msgb_put(msg, response_len);
+
+	int octet_len = gsm_get_octet_len(response_len);
+	msgb_put(msg, octet_len);
 
 	/* Then wrap it as an Octet String */
 	msgb_wrap_with_TL(msg, ASN1_OCTET_STRING_TAG);

Reply via email to