diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gsm/gsm0480.c | 126 | ||||
-rw-r--r-- | src/gsm/libosmogsm.map | 1 |
2 files changed, 102 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; diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 02c88840..b7c5158b 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -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; |