summaryrefslogtreecommitdiffstats
path: root/src/gsm/gsm0480.c
diff options
context:
space:
mode:
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;