Supplementary Services (de)activation, interrogation added

These patches enhance the Supplementary Service (SS) processing from
only being able to handle USSD to other SS, specifically activation,
deactivation and interrogation of those SS. Registration is not yet
implemented.

include/osmocom/gsm/protocol/gsm_09_02.h has been added with needed
values for SS.

Modified by Harald Welte to keep the old ussd-only functiosn for API/ABI
stability.
This commit is contained in:
Tobias Engel 2012-03-08 13:31:52 +01:00 committed by Harald Welte
parent c13cf8bbd3
commit 419684e30c
6 changed files with 262 additions and 33 deletions

View File

@ -77,6 +77,7 @@ nobase_include_HEADERS = \
osmocom/gsm/protocol/gsm_04_80.h \
osmocom/gsm/protocol/gsm_08_08.h \
osmocom/gsm/protocol/gsm_08_58.h \
osmocom/gsm/protocol/gsm_09_02.h \
osmocom/gsm/protocol/gsm_12_21.h \
osmocom/gsm/protocol/gsm_44_318.h \
osmocom/gsm/protocol/ipaccess.h \

View File

@ -1,19 +1,33 @@
#pragma once
#include <osmocom/core/defs.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/protocol/gsm_04_80.h>
#define MAX_LEN_USSD_STRING 31
/* deprecated */
struct ussd_request {
char text[MAX_LEN_USSD_STRING + 1];
uint8_t transaction_id;
uint8_t invoke_id;
};
/* deprecated */
int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len,
struct ussd_request *request);
struct ussd_request *request) OSMO_DEPRECATED("Use gsm0480_decode_ss_request() instead");
struct ss_request {
uint8_t opcode;
uint8_t ss_code;
uint8_t ussd_text[MAX_LEN_USSD_STRING + 1];
uint8_t transaction_id;
uint8_t invoke_id;
};
int gsm0480_decode_ss_request(const struct gsm48_hdr *hdr, uint16_t len,
struct ss_request *request);
struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const char *text);
struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char *text);

View File

@ -0,0 +1,137 @@
#ifndef PROTO_GSM_09_02_H
#define PROTO_GSM_09_02_H
/* GSM TS 09.02 definitions (MAP) */
/* Section 17.7.4 */
/* SS-Status */
#define GSM0902_SS_STATUS_Q_BIT 0x08
#define GSM0902_SS_STATUS_P_BIT 0x04
#define GSM0902_SS_STATUS_R_BIT 0x02
#define GSM0902_SS_STATUS_A_BIT 0x01
/* SS-Data */
#define GSM0902_SS_DATA_SS_STATUS_TAG 0x84
#define GSM0902_SS_DATA_NBR_USER 0x85
/* SS-Info */
#define GSM0902_SS_INFO_FORW_INFO_TAG 0xA0
#define GSM0902_SS_INFO_CALL_BARR_INFO_TAG 0xA1
#define GSM0902_SS_INFO_SS_DATA_TAG 0xA3
/* InterrogateSS-Res */
#define GSM0902_SS_INTERR_SS_RES_SS_STATUS_TAG 0x80
#define GSM0902_SS_INTERR_SS_RES_BSG_LIST_TAG 0x81
#define GSM0902_SS_INTERR_SS_RES_FORW_FEAT_LIST_TAG 0x82
#define GSM0902_SS_INTERR_SS_RES_GEN_SERV_INFO_TAG 0x83
/* Section 17.7.5 */
/* Supplementary service codes */
#define GSM0902_SS_CODE_ALL_SS 0x00
#define GSM0902_SS_CODE_ALL_LINE_IDENTIFICATION_SS 0x10
#define GSM0902_SS_CODE_CLIP 0x11
#define GSM0902_SS_CODE_CLIR 0x12
#define GSM0902_SS_CODE_COLP 0x13
#define GSM0902_SS_CODE_COLR 0x14
#define GSM0902_SS_CODE_MCI 0x15
#define GSM0902_SS_CODE_ALL_NAME_IDENTIFICATION_SS 0x18
#define GSM0902_SS_CODE_CNAP 0x19
#define GSM0902_SS_CODE_ALL_FORWARDING_SS 0x20
#define GSM0902_SS_CODE_CFU 0x21
#define GSM0902_SS_CODE_ALL_COND_FORWARDING_SS 0x28
#define GSM0902_SS_CODE_CFB 0x29
#define GSM0902_SS_CODE_CFNRY 0x2A
#define GSM0902_SS_CODE_CFNRC 0x2B
#define GSM0902_SS_CODE_CD 0x24
#define GSM0902_SS_CODE_ALL_CALL_OFFERING_SS 0x30
#define GSM0902_SS_CODE_ECT 0x31
#define GSM0902_SS_CODE_MAH 0x32
#define GSM0902_SS_CODE_ALL_CALL_COMPLETION_SS 0x40
#define GSM0902_SS_CODE_CW 0x41
#define GSM0902_SS_CODE_HOLD 0x42
#define GSM0902_SS_CODE_CCBS_A 0x43
#define GSM0902_SS_CODE_CCBS_B 0x44
#define GSM0902_SS_CODE_MC 0x45
#define GSM0902_SS_CODE_ALL_MULTI_PARTY_SS 0x50
#define GSM0902_SS_CODE_MULTI_PTY 0x51
#define GSM0902_SS_CODE_ALL_COMMUNITY_OF_INTEREST_SS 0x60
#define GSM0902_SS_CODE_CUG 0x61
#define GSM0902_SS_CODE_ALL_CHARGING_SS 0x70
#define GSM0902_SS_CODE_AOCI 0x71
#define GSM0902_SS_CODE_AOCC 0x72
#define GSM0902_SS_CODE_ALL_ADDITIONAL_INFO_TRANSFER_SS 0x80
#define GSM0902_SS_CODE_UUS1 0x81
#define GSM0902_SS_CODE_UUS2 0x82
#define GSM0902_SS_CODE_UUS3 0x83
#define GSM0902_SS_CODE_ALL_BARRING_SS 0x90
#define GSM0902_SS_CODE_BARRING_OF_OUTGOING_CALLS 0x91
#define GSM0902_SS_CODE_BAOC 0x92
#define GSM0902_SS_CODE_BOIC 0x93
#define GSM0902_SS_CODE_BOIC_EX_HC 0x94
#define GSM0902_SS_CODE_BARRING_OF_INCOMING_CALLS 0x99
#define GSM0902_SS_CODE_BAIC 0x9A
#define GSM0902_SS_CODE_BIC_ROAM 0x9B
#define GSM0902_SS_CODE_ALL_PLMN_SPECIFIC_SS 0xF0
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_1 0xF1
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_2 0xF2
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_3 0xF3
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_4 0xF4
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_5 0xF5
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_6 0xF6
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_7 0xF7
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_8 0xF8
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_9 0xF9
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_A 0xFA
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_B 0xFB
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_C 0xFC
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_D 0xFD
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_E 0xFE
#define GSM0902_SS_CODE_PLMN_SPECIFIC_SS_F 0xFF
#define GSM0902_SS_CODE_ALL_CALL_PRIORITY_SS 0xA0
#define GSM0902_SS_CODE_EMLPP 0xA1
#define GSM0902_SS_CODE_ALL_LCSPRIVACY_EXCEPTION 0xB0
#define GSM0902_SS_CODE_UNIVERSAL 0xB1
#define GSM0902_SS_CODE_CALL_SESSION_RELATED 0xB2
#define GSM0902_SS_CODE_CALL_SESSION_UNRELATED 0xB3
#define GSM0902_SS_CODE_PLMNOPERATOR 0xB4
#define GSM0902_SS_CODE_SERVICE_TYPE 0xB5
#define GSM0902_SS_CODE_ALL_MOLR_SS 0xC0
#define GSM0902_SS_CODE_BASIC_SELF_LOCATION 0xC1
#define GSM0902_SS_CODE_AUTONOMOUS_SELF_LOCATION 0xC2
#define GSM0902_SS_CODE_TRANSFER_TO_THIRD_PARTY 0xC3
/* Section 17.7.9 */
/* Teleservice codes */
#define GSM0902_TS_CODE_ALL_TELESERVICES 0x00
#define GSM0902_TS_CODE_ALL_SPEECH_TRANSMISSION_SERVICES 0x10
#define GSM0902_TS_CODE_TELEPHONY 0x11
#define GSM0902_TS_CODE_EMERGENCY_CALLS 0x12
#define GSM0902_TS_CODE_ALL_SHORT_MESSAGE_SERVICES 0x20
#define GSM0902_TS_CODE_SHORT_MESSAGE_MT_PP 0x21
#define GSM0902_TS_CODE_SHORT_MESSAGE_MO_PP 0x22
#define GSM0902_TS_CODE_ALL_FACSIMILE_TRANSMISSION_SERVICES 0x60
#define GSM0902_TS_CODE_FACSIMILE_GROUP3AND_ALTER_SPEECH 0x61
#define GSM0902_TS_CODE_AUTOMATIC_FACSIMILE_GROUP3 0x62
#define GSM0902_TS_CODE_FACSIMILE_GROUP4 0x63
#define GSM0902_TS_CODE_ALL_DATA_TELESERVICES 0x70
#define GSM0902_TS_CODE_ALL_TELESERVICES_EXEPT_SMS 0x80
#define GSM0902_TS_CODE_ALL_VOICE_GROUP_CALL_SERVICES 0x90
#define GSM0902_TS_CODE_VOICE_GROUP_CALL 0x91
#define GSM0902_TS_CODE_VOICE_BROADCAST_CALL 0x92
#define GSM0902_TS_CODE_ALL_PLMN_SPECIFIC_TS 0xD0
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_1 0xD1
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_2 0xD2
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_3 0xD3
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_4 0xD4
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_5 0xD5
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_6 0xD6
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_7 0xD7
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_8 0xD8
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_9 0xD9
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_A 0xDA
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_B 0xDB
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_C 0xDC
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_D 0xDD
#define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_E 0xDE
#endif /* PROTO_GSM_09_02_H */

View File

@ -192,23 +192,29 @@ struct msgb *gsm0480_create_notifySS(const char *text)
}
/* Forward declarations */
static int parse_ussd(const struct gsm48_hdr *hdr,
uint16_t len, struct ussd_request *req);
static int parse_ussd_info_elements(const uint8_t *ussd_ie, uint16_t len,
struct ussd_request *req);
static int parse_ss(const struct gsm48_hdr *hdr,
uint16_t len, struct ss_request *req);
static int parse_ss_info_elements(const uint8_t *ussd_ie, uint16_t len,
struct ss_request *req);
static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
struct ussd_request *req);
struct ss_request *req);
static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
struct ussd_request *req);
struct ss_request *req);
static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length,
struct ussd_request *req);
struct ss_request *req);
static int parse_ss_for_bs_req(const uint8_t *ss_req_data,
uint16_t length,
struct ss_request *req);
/* Decode a mobile-originated USSD-request message */
int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len,
struct ussd_request *req)
{
struct ss_request ss;
int rc = 0;
memset(&ss, 0, sizeof(ss));
if (len < sizeof(*hdr) + 2) {
LOGP(0, LOGL_DEBUG, "USSD Request is too short.\n");
return 0;
@ -216,7 +222,19 @@ int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len,
if ((hdr->proto_discr & 0x0f) == GSM48_PDISC_NC_SS) {
req->transaction_id = hdr->proto_discr & 0x70;
rc = parse_ussd(hdr, len, req);
ss.transaction_id = req->transaction_id;
rc = parse_ss(hdr, len, &ss);
/* convert from ss_request to legacy ussd_request */
req->transaction_id = ss.transaction_id;
req->invoke_id = ss.invoke_id;
if (ss.ussd_text[0] == 0xFF)
req->text[0] = '\0';
else {
memcpy(req->text, ss.ussd_text, sizeof(req->text));
req->text[sizeof(req->text)-1] = '\0';
}
}
if (!rc)
@ -225,20 +243,42 @@ int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len,
return rc;
}
static int parse_ussd(const struct gsm48_hdr *hdr, uint16_t len, struct ussd_request *req)
/* Decode a mobile-originated SS request message */
int gsm0480_decode_ss_request(const struct gsm48_hdr *hdr, uint16_t len,
struct ss_request *req)
{
int rc = 0;
if (len < sizeof(*hdr) + 2) {
LOGP(0, LOGL_DEBUG, "SS Request is too short.\n");
return 0;
}
if ((hdr->proto_discr & 0x0f) == GSM48_PDISC_NC_SS) {
req->transaction_id = hdr->proto_discr & 0x70;
rc = parse_ss(hdr, len, req);
}
if (!rc)
LOGP(0, LOGL_DEBUG, "Error occurred while parsing received SS!\n");
return rc;
}
static int parse_ss(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request *req)
{
int rc = 1;
uint8_t msg_type = hdr->msg_type & 0xBF; /* message-type - section 3.4 */
switch (msg_type) {
case GSM0480_MTYPE_RELEASE_COMPLETE:
LOGP(0, LOGL_DEBUG, "USS Release Complete\n");
LOGP(0, LOGL_DEBUG, "SS Release Complete\n");
/* could also parse out the optional Cause/Facility data */
req->text[0] = '\0';
req->ussd_text[0] = 0xFF;
break;
case GSM0480_MTYPE_REGISTER:
case GSM0480_MTYPE_FACILITY:
rc &= parse_ussd_info_elements(&hdr->data[0], len - sizeof(*hdr), req);
rc &= parse_ss_info_elements(&hdr->data[0], len - sizeof(*hdr), req);
break;
default:
LOGP(0, LOGL_DEBUG, "Unknown GSM 04.80 message-type field 0x%02x\n",
@ -250,16 +290,16 @@ static int parse_ussd(const struct gsm48_hdr *hdr, uint16_t len, struct ussd_req
return rc;
}
static int parse_ussd_info_elements(const uint8_t *ussd_ie, uint16_t len,
struct ussd_request *req)
static int parse_ss_info_elements(const uint8_t *ss_ie, uint16_t len,
struct ss_request *req)
{
int rc = -1;
/* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */
uint8_t iei;
uint8_t iei_length;
iei = ussd_ie[0];
iei_length = ussd_ie[1];
iei = ss_ie[0];
iei_length = ss_ie[1];
/* If the data does not fit, report an error */
if (len - 2 < iei_length)
@ -269,7 +309,7 @@ static int parse_ussd_info_elements(const uint8_t *ussd_ie, uint16_t len,
case GSM48_IE_CAUSE:
break;
case GSM0480_IE_FACILITY:
rc = parse_facility_ie(ussd_ie+2, iei_length, req);
rc = parse_facility_ie(ss_ie + 2, iei_length, req);
break;
case GSM0480_IE_SS_VERSION:
break;
@ -284,7 +324,7 @@ static int parse_ussd_info_elements(const uint8_t *ussd_ie, uint16_t len,
}
static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
struct ussd_request *req)
struct ss_request *req)
{
int rc = 1;
uint8_t offset = 0;
@ -303,8 +343,8 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
switch (component_type) {
case GSM0480_CTYPE_INVOKE:
rc &= parse_ss_invoke(facility_ie+2,
component_length,
req);
component_length,
req);
break;
case GSM0480_CTYPE_RETURN_RESULT:
break;
@ -326,7 +366,7 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
/* Parse an Invoke component - see table 3.3 */
static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
struct ussd_request *req)
struct ss_request *req)
{
int rc = 1;
uint8_t offset;
@ -337,7 +377,7 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
/* mandatory part */
if (invoke_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) {
LOGP(0, LOGL_DEBUG, "Unexpected GSM 04.80 Component-ID tag "
"0x%02x (expecting Invoke ID tag)\n", invoke_data[0]);
"0x%02x (expecting Invoke ID tag)\n", invoke_data[0]);
}
offset = invoke_data[1] + 2;
@ -356,12 +396,20 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
if (offset + 2 > length)
return 0;
uint8_t operation_code = invoke_data[offset+2];
req->opcode = operation_code;
switch (operation_code) {
case GSM0480_OP_CODE_PROCESS_USS_REQ:
rc = parse_process_uss_req(invoke_data + offset + 3,
length - offset - 3,
req);
break;
case GSM0480_OP_CODE_ACTIVATE_SS:
case GSM0480_OP_CODE_DEACTIVATE_SS:
case GSM0480_OP_CODE_INTERROGATE_SS:
rc = parse_ss_for_bs_req(invoke_data + offset + 3,
length - offset - 3,
req);
break;
default:
LOGP(0, LOGL_DEBUG, "GSM 04.80 operation code 0x%02x "
"is not yet handled\n", operation_code);
@ -380,7 +428,7 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
/* Parse the parameters of a Process UnstructuredSS Request */
static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length,
struct ussd_request *req)
struct ss_request *req)
{
int rc = 0;
int num_chars;
@ -398,8 +446,12 @@ static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length,
if ((dcs == 0x0F) &&
(uss_req_data[5] == ASN1_OCTET_STRING_TAG)) {
num_chars = (uss_req_data[6] * 8) / 7;
gsm_7bit_decode_n_ussd(req->text, sizeof(req->text),
&(uss_req_data[7]), num_chars);
/* Prevent a mobile-originated buffer-overrun! */
if (num_chars > MAX_LEN_USSD_STRING)
num_chars = MAX_LEN_USSD_STRING;
gsm_7bit_decode_n_ussd((char *)req->ussd_text,
sizeof(req->ussd_text),
&(uss_req_data[7]), num_chars);
rc = 1;
}
}
@ -407,6 +459,30 @@ static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length,
return rc;
}
/* Parse the parameters of a Interrogate/Activate/DeactivateSS Request */
static int parse_ss_for_bs_req(const uint8_t *ss_req_data,
uint16_t length,
struct ss_request *req)
{
int rc = 0;
/* we need at least that much */
if (length < 5)
return 0;
if (ss_req_data[0] == GSM_0480_SEQUENCE_TAG) {
if ((ss_req_data[2] == ASN1_OCTET_STRING_TAG) &&
ss_req_data[3] == 1) {
req->ss_code = ss_req_data[4];
rc = 1;
}
}
return rc;
}
struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const char *text)
{
struct msgb *msg;

View File

@ -44,6 +44,7 @@ gsm0480_create_notifySS;
gsm0480_create_unstructuredSS_Notify;
gsm0480_create_ussd_resp;
gsm0480_decode_ussd_request;
gsm0480_decode_ss_request;
gsm0480_wrap_facility;
gsm0480_wrap_invoke;

View File

@ -38,13 +38,13 @@ static int parse_ussd(const uint8_t *_data, int len)
{
uint8_t *data;
int rc;
struct ussd_request req;
struct ss_request req;
struct gsm48_hdr *hdr;
data = malloc(len);
memcpy(data, _data, len);
hdr = (struct gsm48_hdr *) &data[0];
rc = gsm0480_decode_ussd_request(hdr, len, &req);
rc = gsm0480_decode_ss_request(hdr, len, &req);
free(data);
return rc;
@ -54,14 +54,14 @@ static int parse_mangle_ussd(const uint8_t *_data, int len)
{
uint8_t *data;
int rc;
struct ussd_request req;
struct ss_request req;
struct gsm48_hdr *hdr;
data = malloc(len);
memcpy(data, _data, len);
hdr = (struct gsm48_hdr *) &data[0];
hdr->data[1] = len - sizeof(*hdr) - 2;
rc = gsm0480_decode_ussd_request(hdr, len, &req);
rc = gsm0480_decode_ss_request(hdr, len, &req);
free(data);
return rc;
@ -113,15 +113,15 @@ static void test_7bit_ussd(const char *text, const char *encoded_hex, const char
int main(int argc, char **argv)
{
struct ussd_request req;
struct ss_request req;
const int size = sizeof(ussd_request);
int i;
struct msgb *msg;
osmo_init_logging(&info);
gsm0480_decode_ussd_request((struct gsm48_hdr *) ussd_request, size, &req);
printf("Tested if it still works. Text was: %s\n", req.text);
gsm0480_decode_ss_request((struct gsm48_hdr *) ussd_request, size, &req);
printf("Tested if it still works. Text was: %s\n", req.ussd_text);
printf("Testing parsing a USSD request and truncated versions\n");