Add special 7-bit encoding and decoding functions for USSD coding

Handling 7-bit coding is a little different for USSD, as TS 03.38
states:

To avoid the situation where the receiving entity confuses 7 binary
zero pad bits as the @ character, the carriage return or <CR>
character shall be used for padding in this situation [...].

If <CR> is intended to be the last character and the message
(including the wanted <CR>) ends on an octet boundary, then another
<CR> must be added together with a padding bit 0. The receiving entity
will perform the carriage return function twice, but this will not
result in misoperation as the definition of <CR> [...] is identical to
the definition of <CR><CR>.

The receiving entity shall remove the final <CR> character where the
message ends on an octet boundary with <CR> as the last character.

Jacob has verified the fix with fakeBTS and the wireshark dissector.

Fixes: OW#947
Reviewed-by: Jacob Erlbeck <jerlbeck@sysmocom.de>
diff --git a/tests/ussd/ussd_test.c b/tests/ussd/ussd_test.c
index 55384f1..d41c141 100644
--- a/tests/ussd/ussd_test.c
+++ b/tests/ussd/ussd_test.c
@@ -22,6 +22,7 @@
 #include <osmocom/core/application.h>
 #include <osmocom/core/logging.h>
 #include <osmocom/gsm/gsm0480.h>
+#include <osmocom/gsm/gsm_utils.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -68,6 +69,20 @@
 
 struct log_info info = {};
 
+void gsm_7bit_ussd(char *text)
+{
+	uint8_t coded[256];
+	char decoded[256];
+	int y;
+
+	printf("original = %s\n", osmo_hexdump((uint8_t *)text, strlen(text)));
+	gsm_7bit_encode_ussd(coded, text, &y);
+	printf("encoded = %s\n", osmo_hexdump(coded, y));
+	gsm_7bit_decode_ussd(decoded, coded, y * 8 / 7);
+	y = strlen(decoded);
+	printf("decoded = %s\n\n", osmo_hexdump((uint8_t *)decoded, y));
+}
+
 int main(int argc, char **argv)
 {
 	struct ussd_request req;
@@ -93,5 +108,12 @@
 		printf("Result for %d is %d\n", rc, i);
 	}
 
+	printf("<CR> case test for 7 bit encode\n");
+	gsm_7bit_ussd("01234567");
+	gsm_7bit_ussd("0123456");
+	gsm_7bit_ussd("01234567\r");
+	gsm_7bit_ussd("0123456\r");
+	gsm_7bit_ussd("012345\r");
+
 	return 0;
 }