diff options
| author | Andreas Eversberg <jolly@eversberg.eu> | 2013-08-08 12:38:53 +0200 | 
|---|---|---|
| committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2013-08-08 14:27:13 +0200 | 
| commit | 9597555a362cd28c02e9bbfe4f55c4b90ecdfa34 (patch) | |
| tree | 819721bf3ee366ff6a333da64cb646519e1e0a2c /src | |
| parent | 6bfa7445fca074fdf94707681d93e92ec0993bbd (diff) | |
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>
Diffstat (limited to 'src')
| -rw-r--r-- | src/gsm/gsm0480.c | 10 | ||||
| -rw-r--r-- | src/gsm/gsm_utils.c | 31 | ||||
| -rw-r--r-- | src/gsm/libosmogsm.map | 2 | 
3 files changed, 38 insertions, 5 deletions
diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c index b9b3ed97..cc693feb 100644 --- a/src/gsm/gsm0480.c +++ b/src/gsm/gsm0480.c @@ -105,7 +105,7 @@ struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char *  	msgb_put_u8(msg, ASN1_OCTET_STRING_TAG);  	ussd_len_ptr = msgb_put(msg, 1);  	data = msgb_put(msg, 0); -	len = gsm_7bit_encode(data, text); +	gsm_7bit_encode_ussd(data, text, &len);  	msgb_put(msg, len);  	ussd_len_ptr[0] = len;  	/* USSD-String } */ @@ -172,7 +172,7 @@ struct msgb *gsm0480_create_notifySS(const char *text)  	msgb_put_u8(msg, 0x82);  	tmp_len = msgb_put(msg, 1);  	data = msgb_put(msg, 0); -	len = gsm_7bit_encode(data, text); +	gsm_7bit_encode_ussd(data, text, &len);  	tmp_len[0] = len;  	msgb_put(msg, len); @@ -401,8 +401,8 @@ static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length,  				/* Prevent a mobile-originated buffer-overrun! */  				if (num_chars > MAX_LEN_USSD_STRING)  					num_chars = MAX_LEN_USSD_STRING; -				gsm_7bit_decode(req->text, -						&(uss_req_data[7]), num_chars); +				gsm_7bit_decode_ussd(req->text, +					&(uss_req_data[7]), num_chars);  				rc = 1;  			}  		} @@ -423,7 +423,7 @@ struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const  	/* First put the payload text into the message */  	ptr8 = msgb_put(msg, 0); -	response_len = gsm_7bit_encode(ptr8, text); +	gsm_7bit_encode_ussd(ptr8, text, &response_len);  	msgb_put(msg, response_len);  	/* Then wrap it as an Octet String */ diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c index 54b965e2..3dd15375 100644 --- a/src/gsm/gsm_utils.c +++ b/src/gsm/gsm_utils.c @@ -172,6 +172,19 @@ 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);  } +int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length) +{ +	int i; + +	gsm_7bit_decode_hdr(text, user_data, length, 0); +	i = strlen(text); +	/* remove last <CR>, if it fits up to the end of last octet */ +	if (i && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r') +		text[--i] = '\0'; + +	return i; +} +  /* GSM 03.38 6.2.1 Prepare character packing */  int gsm_septet_encode(uint8_t *result, const char *data)  { @@ -254,6 +267,24 @@ int gsm_7bit_encode(uint8_t *result, const char *data)  	return gsm_7bit_encode_oct(result, data, &out);  } +int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets) +{ +	int y; + +	y = gsm_7bit_encode_oct(result, data, octets); +	/* if last octet contains only one bit, add <CR> */ +	if (((y * 7) & 7) == 1) +		result[(*octets) - 1] |= ('\r' << 1); +	/* if last character is <CR> and completely fills last octet, add +	 * another <CR>. */ +	if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r') { +		result[(*octets)++] = '\r'; +		y++; +	} + +	return y; +} +  int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets)  {  	int y = 0; diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 8a020dbd..1b985e10 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -132,8 +132,10 @@ gsm48_parse_ra;  gsm48_rr_att_tlvdef;  gsm_7bit_decode; +gsm_7bit_decode_ussd;  gsm_7bit_decode_hdr;  gsm_7bit_encode; +gsm_7bit_encode_ussd;  gsm_7bit_encode_oct;  gsm_arfcn2band;  | 
