summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-06-02 12:42:37 +0200
committerHarald Welte <laforge@gnumonks.org>2010-06-02 12:42:37 +0200
commitd3dbe75844f07c3605ea00840a9f88242f990a16 (patch)
treeb2e47db9e2528675d40992276369ae8e50b69aba
parente300d0021c50326ead433f60ce5bb62dc6949984 (diff)
USSD: Incomplete attempt to implement non-call SS interrogatelaforge/supp_srv
-rw-r--r--openbsc/include/openbsc/gsm_04_80.h72
-rw-r--r--openbsc/src/gsm_04_80.c69
-rw-r--r--openbsc/src/ussd.c72
3 files changed, 189 insertions, 24 deletions
diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h
index b5ab1c6..03a46fa 100644
--- a/openbsc/include/openbsc/gsm_04_80.h
+++ b/openbsc/include/openbsc/gsm_04_80.h
@@ -4,12 +4,78 @@
#include <osmocore/msgb.h>
#include <osmocore/protocol/gsm_04_80.h>
+/* 29.002 V8.9.0 / 17.7.5 */
+enum gsm0902_map_ss_code {
+ /* line identification */
+ MAP_SS_CODE_CLIP = 0x11, /* calling line id present */
+ MAP_SS_CODE_CLIR = 0x12, /* calling line id restrict */
+ MAP_SS_CODE_COLP = 0x13, /* connected line id present */
+ MAP_SS_CODE_COLR = 0x14, /* onnected line id restrict */
+ MAP_SS_CODE_MCI = 0x15, /* malicious call id */
+
+ /* name identification */
+ MAP_SS_CODE_CNAP = 0x19, /* calling name presentation */
+
+ /* forwarding */
+ MAP_SS_CODE_CFU = 0x21, /* call forw unconditional */
+ MAP_SS_CODE_CFB = 0x29, /* call forw subscr busy */
+ MAP_SS_CODE_CFNRY = 0x2a, /* call forw no reply */
+ MAP_SS_CODE_CFNRC = 0x2b, /* call forw not reachable */
+ MAP_SS_CODE_CD = 0x24, /* call deflection */
+
+ /* call offering */
+ MAP_SS_CODE_ECT = 0x31, /* explicit call transfer */
+ MAP_SS_CODE_MAH = 0x32, /* mobile access hunting */
+
+ /* call completion SS */
+ MAP_SS_CODE_CW = 0x41, /* call waiting */
+ MAP_SS_CODE_HOLD = 0x42, /* call hold */
+ MAP_SS_CODE_CCBS_A = 0x43,
+ MAP_SS_CODE_CCBS_B = 0x44,
+ MAP_SS_CODE_MC = 0x45, /* multicall */
+
+ MAP_SS_CODE_MPTY = 0x51, /* multiparty */
+
+ MAP_SS_CODE_CUG = 0x61, /* closed user group */
+
+ MAP_SS_CODE_AOCI = 0x71, /* advice of charge info */
+ MAP_SS_CODE_AOCC = 0x72, /* advice of charge charging */
+
+ MAP_SS_CODE_UUS1 = 0x81,
+ MAP_SS_CODE_UUS2 = 0x82,
+ MAP_SS_CODE_UUS3 = 0x83,
+
+ /* barring */
+ MAP_SS_CODE_BOOC = 0x91,
+ MAP_SS_CODE_BAOC = 0x92, /* barr all outgoing calls */
+ MAP_SS_CODE_BOIC = 0x93, /* barr outgoing intl calls */
+ MAP_SS_CODE_BAIC = 0x9a, /* barr all incoming calls */
+ MAP_SS_CODE_BICROAM = 0x9b, /* barr incoming calls in roaming */
+};
+
+/* SS-Status + 23.011 Section 2.1.2.1 Table 2.1 */
+#define SS_STATUS_Q_BIT 0x08 /* quiescent */
+#define SS_STATUS_P_BIT 0x04 /* provisioned */
+#define SS_STATUS_R_BIT 0x02 /* registered */
+#define SS_STATUS_A_BIT 0x01 /* active */
+
+
#define MAX_LEN_USSD_STRING 31
struct ussd_request {
+ uint8_t opcode;
+
+ uint8_t transaction_id;
+ uint8_t invoke_id;
+
+ union {
+ struct {
char text[MAX_LEN_USSD_STRING + 1];
- u_int8_t transaction_id;
- u_int8_t invoke_id;
+ } unstructured;
+ struct {
+ uint8_t ss_code;
+ } interrogate;
+ };
};
int gsm0480_decode_ussd_request(const struct msgb *msg,
@@ -18,5 +84,7 @@ int gsm0480_send_ussd_response(const struct msgb *in_msg, const char* response_t
const struct ussd_request *req);
int gsm0480_send_ussd_reject(const struct msgb *msg,
const struct ussd_request *request);
+int gsm0480_send_ss_interr_resp(const struct msgb *in_msg, uint8_t status,
+ const struct ussd_request *req);
#endif
diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c
index ef10b17..efb798e 100644
--- a/openbsc/src/gsm_04_80.c
+++ b/openbsc/src/gsm_04_80.c
@@ -47,6 +47,8 @@ static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length,
struct ussd_request *req);
static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length,
struct ussd_request *req);
+static int parse_process_ss_interr_req(uint8_t *uss_req_data, uint8_t length,
+ struct ussd_request *req);
static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, u_int8_t tag)
{
@@ -95,7 +97,7 @@ static int parse_ussd(u_int8_t *ussd, struct ussd_request *req)
case GSM0480_MTYPE_RELEASE_COMPLETE:
DEBUGP(DMM, "USS Release Complete\n");
/* could also parse out the optional Cause/Facility data */
- req->text[0] = 0xFF;
+ req->unstructured.text[0] = 0xFF;
break;
case GSM0480_MTYPE_REGISTER:
case GSM0480_MTYPE_FACILITY:
@@ -194,12 +196,17 @@ static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length,
/* mandatory part */
if (invoke_data[offset] == GSM0480_OPERATION_CODE) {
u_int8_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_INTERROGATE_SS:
+ rc = parse_process_ss_interr_req(invoke_data + offset + 3,
+ length - offset - 3, req);
+ break;
default:
fprintf(stderr, "GSM 04.80 operation code 0x%02x "
"is not yet handled\n", operation_code);
@@ -233,10 +240,10 @@ static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length,
/* Prevent a mobile-originated buffer-overrun! */
if (num_chars > MAX_LEN_USSD_STRING)
num_chars = MAX_LEN_USSD_STRING;
- gsm_7bit_decode(req->text,
+ gsm_7bit_decode(req->unstructured.text,
&(uss_req_data[7]), num_chars);
/* append null-terminator */
- req->text[num_chars+1] = 0;
+ req->unstructured.text[num_chars+1] = 0;
rc = 1;
}
}
@@ -244,6 +251,62 @@ static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length,
return rc;
}
+static int parse_process_ss_interr_req(uint8_t *uss_req_data, uint8_t length,
+ struct ussd_request *req)
+{
+ int rc = -EIO;
+
+ if (uss_req_data[0] != GSM_0480_SEQUENCE_TAG)
+ goto err;
+
+ if (uss_req_data[2] != ASN1_OCTET_STRING_TAG)
+ goto err;
+
+ req->interrogate.ss_code = uss_req_data[4];
+
+ return rc;
+err:
+ return -EIO;
+}
+
+/* Send response to a mobile-originated InterrogateSS-Request */
+int gsm0480_send_ss_interr_resp(const struct msgb *in_msg, uint8_t status,
+ const struct ussd_request *req)
+{
+ struct msgb *msg = gsm48_msgb_alloc();
+ struct gsm48_hdr *gh;
+
+ msg->lchan = in_msg->lchan;
+
+ /* Pre-pend the ss-Status */
+ msgb_push_TLV1(msg, 0, status);
+
+ /* Pre-pend the operation code */
+ msgb_push_TLV1(msg, GSM0480_OPERATION_CODE,
+ GSM0480_OP_CODE_INTERROGATE_SS);
+
+ /* Wrap the operation code and IA5 string as a sequence */
+ 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);
+
+ /* Wrap this up as a Return Result component */
+ msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT);
+
+ /* Wrap the component in a Facility message */
+ msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
+
+ /* 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->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
+
+ return gsm48_sendmsg(msg, NULL);
+}
+
+
/* Send response to a mobile-originated ProcessUnstructuredSS-Request */
int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_text,
const struct ussd_request *req)
diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c
index 5476919..58f51c8 100644
--- a/openbsc/src/ussd.c
+++ b/openbsc/src/ussd.c
@@ -37,9 +37,51 @@
/* Declarations of USSD strings to be recognised */
const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
-/* Forward declarations of network-specific handler functions */
-static int send_own_number(const struct msgb *msg, const struct ussd_request *req);
+/* A network-specific handler function */
+static int send_own_number(const struct msgb *msg, const struct ussd_request *req)
+{
+ char *own_number = msg->lchan->conn.subscr->extension;
+ char response_string[GSM_EXTENSION_LENGTH + 20];
+ /* Need trailing CR as EOT character */
+ snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
+ return gsm0480_send_ussd_response(msg, response_string, req);
+}
+
+static int handle_rcv_uss_req(struct msgb *msg, struct ussd_request *req)
+{
+ if (req->unstructured.text[0] == 0xFF) /* Release-Complete */
+ return 0;
+
+ if (strstr(USSD_TEXT_OWN_NUMBER, req->unstructured.text) != NULL) {
+ LOGP(DMM, LOGL_INFO, "USSD: Own number requested\n");
+ return send_own_number(msg, req);
+ } else {
+ LOGP(DMM, LOGL_NOTICE, "Unhandled USSD %s\n", req->unstructured.text);
+ return gsm0480_send_ussd_reject(msg, req);
+ }
+}
+
+static int handle_rcv_interrogate(struct msgb *msg, struct ussd_request *req)
+{
+ uint8_t ss_status;
+
+ switch (req->interrogate.ss_code) {
+ case MAP_SS_CODE_CLIP:
+ case MAP_SS_CODE_COLP:
+ ss_status = SS_STATUS_P_BIT | SS_STATUS_R_BIT | SS_STATUS_A_BIT;
+ break;
+ case MAP_SS_CODE_CLIR:
+ case MAP_SS_CODE_COLR:
+ ss_status = SS_STATUS_P_BIT | SS_STATUS_R_BIT;
+ break;
+ default:
+ ss_status = 0;
+ break;
+ }
+
+ return gsm0480_send_ss_interr_resp(msg, ss_status, req);
+}
/* Entrypoint - handler function common to all mobile-originated USSDs */
int handle_rcv_ussd(struct msgb *msg)
@@ -47,25 +89,17 @@ int handle_rcv_ussd(struct msgb *msg)
struct ussd_request req;
gsm0480_decode_ussd_request(msg, &req);
- if (req.text[0] == 0xFF) /* Release-Complete */
- return 0;
- if (strstr(USSD_TEXT_OWN_NUMBER, req.text) != NULL) {
- DEBUGP(DMM, "USSD: Own number requested\n");
- return send_own_number(msg, &req);
- } else {
- DEBUGP(DMM, "Unhandled USSD %s\n", req.text);
- return gsm0480_send_ussd_reject(msg, &req);
+ switch (req.opcode) {
+ case GSM0480_OP_CODE_INTERROGATE_SS:
+ return handle_rcv_interrogate(msg, &req);
+ case GSM0480_OP_CODE_USS_REQUEST:
+ return handle_rcv_uss_req(msg, &req);
+ default:
+ LOGP(DMM, LOGL_NOTICE, "Unknown SS opcode 0x%02x\n", req.opcode);
+ break;
}
+ return 0;
}
-/* A network-specific handler function */
-static int send_own_number(const struct msgb *msg, const struct ussd_request *req)
-{
- char *own_number = msg->lchan->conn.subscr->extension;
- char response_string[GSM_EXTENSION_LENGTH + 20];
- /* Need trailing CR as EOT character */
- snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
- return gsm0480_send_ussd_response(msg, response_string, req);
-}