libmsc/gsm_04_80.c: make the API abstract from ss_request struct

There is no need to pass a pointer to a ss_request struct when
calling the gsm0480_send_ussd_* functions, because they only
use both transaction ID and InvokeID from there, which may
be passed directly.

This change allows one to use this API without parsing the
whole GSM 04.80 message, or when parsing is failed. Moreover,
if InvokeID is not available, one can pass any incorrect,
(e.g. negative) value, so the universal NULL tag will be used.
Finally, setting a TI flag is also up to the caller.

Change-Id: I13d5abbfdcf8238ebaf0566c420f09cd9255b648
This commit is contained in:
Vadim Yanitskiy 2018-06-12 08:03:53 +07:00
parent 9aec25e464
commit 5df4e4ddde
3 changed files with 77 additions and 28 deletions

View File

@ -7,14 +7,14 @@
struct gsm_subscriber_connection;
int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
const char* response_text,
const struct ss_request *req);
uint8_t transaction_id, uint8_t invoke_id,
const char *response_text);
int gsm0480_send_ussd_return_error(struct gsm_subscriber_connection *conn,
const struct ss_request *req,
uint8_t transaction_id, uint8_t invoke_id,
uint8_t error_code);
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
const struct ss_request *req,
uint8_t error_tag, uint8_t error_code);
uint8_t transaction_id, int invoke_id,
uint8_t problem_tag, uint8_t problem_code);
int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level,
const char *text);

View File

@ -59,10 +59,28 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
return data;
}
static inline unsigned char *msgb_push_NULL(struct msgb *msgb)
{
uint8_t *data = msgb_push(msgb, 2);
/* Send response to a mobile-originated ProcessUnstructuredSS-Request */
data[0] = ASN1_NULL_TYPE_TAG;
data[1] = 0;
return data;
}
/*! Send a MT RELEASE COMPLETE message with USSD-response,
* wrapped into the ReturnResult component (see section 3.6.1).
*
* \param[in] conn Active subscriber connection
* \param[in] transaction_id Transaction ID with TI flag set
* \param[in] invoke_id InvokeID of the request
* \param[in] response_text The response text
* \return result of \ref msc_tx_dtap
*/
int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
const char *response_text, const struct ss_request *req)
uint8_t transaction_id, uint8_t invoke_id,
const char *response_text)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD RSP");
struct gsm48_hdr *gh;
@ -91,7 +109,7 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG);
/* Pre-pend the invoke ID */
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id);
/* Wrap this up as a Return Result component */
msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT);
@ -101,15 +119,24 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
/* And finally pre-pend the L3 header */
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id
| (1<<7); /* TI direction = 1 */
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->proto_discr |= transaction_id << 4;
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
return msc_tx_dtap(conn, msg);
}
/*! Send a MT RELEASE COMPLETE message with ReturnError component
* (see section 3.6.1) and given error code (see section 3.6.6).
*
* \param[in] conn Active subscriber connection
* \param[in] transaction_id Transaction ID with TI flag set
* \param[in] invoke_id InvokeID of the request
* \param[in] error_code Error code (section 4.5)
* \return result of \ref msc_tx_dtap
*/
int gsm0480_send_ussd_return_error(struct gsm_subscriber_connection *conn,
const struct ss_request *req, uint8_t error_code)
uint8_t transaction_id, uint8_t invoke_id, uint8_t error_code)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD ERR");
struct gsm48_hdr *gh;
@ -118,7 +145,7 @@ int gsm0480_send_ussd_return_error(struct gsm_subscriber_connection *conn,
msgb_push_TLV1(msg, GSM_0480_ERROR_CODE_TAG, error_code);
/* Before it insert the invoke ID */
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id);
/* Wrap this up as a Reject component */
msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_ERROR);
@ -128,25 +155,45 @@ int gsm0480_send_ussd_return_error(struct gsm_subscriber_connection *conn,
/* And finally pre-pend the L3 header */
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->proto_discr |= transaction_id << 4;
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
return msc_tx_dtap(conn, msg);
}
/*! Send a MT RELEASE COMPLETE message with Reject component
* (see section 3.6.1) and given error code (see section 3.6.7).
*
* \param[in] conn Active subscriber connection
* \param[in] transaction_id Transaction ID with TI flag set
* \param[in] invoke_id InvokeID of the request
* \param[in] problem_tag Problem code tag (table 3.13)
* \param[in] problem_code Problem code (tables 3.14-17)
* \return result of \ref msc_tx_dtap
*
* Note: if InvokeID is not available, e.g. when message parsing
* failed, any incorrect value can be passed (0x00 > x > 0xff), so
* the universal NULL-tag (see table 3.6) will be used instead.
*/
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
const struct ss_request *req,
uint8_t error_tag, uint8_t error_code)
uint8_t transaction_id, int invoke_id,
uint8_t problem_tag, uint8_t problem_code)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REJ");
struct gsm48_hdr *gh;
/* First insert the problem code */
msgb_push_TLV1(msg, error_tag, error_code);
msgb_push_TLV1(msg, problem_tag, problem_code);
/* Before it insert the invoke ID */
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
/**
* If the Invoke ID is not available, Universal Null
* (table 3.9) with length = 0 shall be used.
*/
if (invoke_id < 0 || invoke_id > 255)
msgb_push_NULL(msg);
else
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id);
/* Wrap this up as a Reject component */
msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT);
@ -156,8 +203,8 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
/* And finally pre-pend the L3 header */
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->proto_discr |= transaction_id << 4;
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
return msc_tx_dtap(conn, msg);

View File

@ -46,7 +46,7 @@ const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
/* A network-specific handler function */
static int send_own_number(struct gsm_subscriber_connection *conn,
const struct ss_request *req)
uint8_t tid, uint8_t invoke_id)
{
char *own_number = conn->vsub->msisdn;
char response_string[GSM_EXTENSION_LENGTH + 20];
@ -56,7 +56,7 @@ static int send_own_number(struct gsm_subscriber_connection *conn,
/* Need trailing CR as EOT character */
snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
return gsm0480_send_ussd_response(conn, response_string, req);
return gsm0480_send_ussd_response(conn, tid, invoke_id, response_string);
}
/* Entry point for call independent MO SS messages */
@ -121,7 +121,8 @@ int gsm0911_rcv_nc_ss(struct gsm_subscriber_connection *conn, struct msgb *msg)
if (!rc) {
LOGP(DMM, LOGL_ERROR, "SS/USSD message parsing error, "
"rejecting request...\n");
gsm0480_send_ussd_reject(conn, &req, GSM_0480_PROBLEM_CODE_TAG_GENERAL,
gsm0480_send_ussd_reject(conn, tid, -1,
GSM_0480_PROBLEM_CODE_TAG_GENERAL,
GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
/* The GSM 04.80 API uses inverted codes (0 means error) */
return -EPROTO;
@ -131,8 +132,8 @@ int gsm0911_rcv_nc_ss(struct gsm_subscriber_connection *conn, struct msgb *msg)
if (req.ussd_text[0] == '\0' || req.ussd_text[0] == 0xFF) {
if (req.ss_code > 0) {
/* Assume interrogateSS or modification of it and reject */
return gsm0480_send_ussd_return_error(conn, &req,
GSM0480_ERR_CODE_ILLEGAL_SS_OPERATION);
return gsm0480_send_ussd_return_error(conn, tid,
req.invoke_id, GSM0480_ERR_CODE_ILLEGAL_SS_OPERATION);
}
/* Still assuming a Release-Complete and returning */
return 0;
@ -141,10 +142,11 @@ int gsm0911_rcv_nc_ss(struct gsm_subscriber_connection *conn, struct msgb *msg)
msc_subscr_conn_communicating(conn);
if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.ussd_text)) {
DEBUGP(DMM, "USSD: Own number requested\n");
rc = send_own_number(conn, &req);
rc = send_own_number(conn, tid, req.invoke_id);
} else {
DEBUGP(DMM, "Unhandled USSD %s\n", req.ussd_text);
rc = gsm0480_send_ussd_return_error(conn, &req,
rc = gsm0480_send_ussd_return_error(conn,
tid, req.invoke_id,
GSM0480_ERR_CODE_UNEXPECTED_DATA_VALUE);
}