aboutsummaryrefslogtreecommitdiffstats
path: root/src/gsm/gsm0480.c
diff options
context:
space:
mode:
authorTobias Engel <tobias@ccc.de>2012-03-08 13:31:52 +0100
committerHarald Welte <laforge@gnumonks.org>2015-01-01 14:19:17 +0100
commit419684e30c2fe12d3e3441cfa9fea21f1c4de959 (patch)
tree042c219b08278e9a691fdab86a47ff42ad16220c /src/gsm/gsm0480.c
parentc13cf8bbd3a0650993b43e1cea071c02d0f00d8f (diff)
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.
Diffstat (limited to 'src/gsm/gsm0480.c')
-rw-r--r--src/gsm/gsm0480.c126
1 files changed, 101 insertions, 25 deletions
diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c
index dbacefc4..952604b9 100644
--- a/src/gsm/gsm0480.c
+++ b/src/gsm/gsm0480.c
@@ -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;