From 2b5eb8ddb02bce309f70c24604001b97d642835e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 28 Oct 2015 13:31:16 +0300 Subject: libmsc: use message type as an entry point and handle release complete message --- openbsc/include/openbsc/ussd.h | 3 + openbsc/src/libmsc/ussd.c | 171 +++++++++++++++++++++++++++++++++++------ 2 files changed, 152 insertions(+), 22 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h index a84f51fbd..eee0b9a0c 100644 --- a/openbsc/include/openbsc/ussd.h +++ b/openbsc/include/openbsc/ussd.h @@ -5,6 +5,9 @@ #include +#define USSD_MO 1 +#define USSD_MT 0 + int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg); diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c index c81f777c7..2bad560d5 100644 --- a/openbsc/src/libmsc/ussd.c +++ b/openbsc/src/libmsc/ussd.c @@ -45,11 +45,12 @@ struct gsm_ussd { uint8_t invoke_id; uint8_t transaction_id; - uint8_t current_transaction_id; + uint8_t mobile_originated; struct gsm_subscriber_connection *conn; }; +static unsigned s_ussd_open_sessions = 0; static uint64_t s_uniq_ussd_sessiod_id = 0; static LLIST_HEAD(s_active_ussd_sessions); @@ -59,7 +60,9 @@ static struct llist_head *get_active_ussd_sessions(void) } -static struct gsm_ussd* ussd_session_alloc(struct gsm_subscriber_connection* conn) +static struct gsm_ussd* ussd_session_alloc(struct gsm_subscriber_connection* conn, + uint8_t tid, + uint8_t mo) { struct gsm_network* net = conn->bts->network; struct gsm_ussd* m = talloc_zero(net, struct gsm_ussd); @@ -68,37 +71,41 @@ static struct gsm_ussd* ussd_session_alloc(struct gsm_subscriber_connection* con m->conn = conn; m->uniq_id = s_uniq_ussd_sessiod_id++; + m->transaction_id = tid; + m->mobile_originated = mo; + ++s_ussd_open_sessions; INIT_LLIST_HEAD(&m->ussqueue); llist_add_tail(&m->ussqueue, &s_active_ussd_sessions); - DEBUGP(DMM, "Alloc USSD session: %d\n", m->uniq_id); + DEBUGP(DMM, "Alloc USSD session: %d (open: %d)\n", m->uniq_id, s_ussd_open_sessions); return m; } static void ussd_session_free(struct gsm_ussd* s) { - DEBUGP(DMM, "Free USSD session: %d\n", s->uniq_id); + --s_ussd_open_sessions; + DEBUGP(DMM, "Free USSD session: %d (open: %d)\n", s->uniq_id, s_ussd_open_sessions); llist_del(&s->ussqueue); talloc_free(s); } -static struct gsm_ussd* get_by_uniq_id(uint8_t invoke_id) +static struct gsm_ussd* get_by_uniq_id(uint8_t uniq_id) { struct gsm_ussd* c; llist_for_each_entry(c, get_active_ussd_sessions(), ussqueue) { - if (c->uniq_id == invoke_id) { - DEBUGP(DMM, "uniq invoke_id %d has %s extention\n", - invoke_id, c->conn->subscr->extension); + if (c->uniq_id == uniq_id) { + DEBUGP(DMM, "uniq_id %d has %s extention\n", + uniq_id, c->conn->subscr->extension); return c; } } - DEBUGP(DMM, "uniq invoke_id %d hasn't been found\n", invoke_id); + DEBUGP(DMM, "uniq_id %d hasn't been found\n", uniq_id); return NULL; } -static struct gsm_ussd* get_by_id(struct gsm_subscriber_connection *conn, uint8_t invoke_id) +static struct gsm_ussd* get_by_iid(struct gsm_subscriber_connection *conn, uint8_t invoke_id) { struct gsm_ussd* c; llist_for_each_entry(c, get_active_ussd_sessions(), ussqueue) { @@ -113,14 +120,74 @@ static struct gsm_ussd* get_by_id(struct gsm_subscriber_connection *conn, uint8_ return NULL; } +static struct gsm_ussd* get_by_tid(struct gsm_subscriber_connection *conn, uint8_t transaction_id) +{ + struct gsm_ussd* c; + llist_for_each_entry(c, get_active_ussd_sessions(), ussqueue) { + if (c->conn == conn && c->transaction_id == transaction_id) { + DEBUGP(DMM, "transaction_id %d has %s extention\n", + transaction_id, c->conn->subscr->extension); + return c; + } + } + + DEBUGP(DMM, "transaction_id %d hasn't been found\n", transaction_id); + return NULL; +} + +// From SUP int on_ussd_response(const struct ss_request *req, const char *extention) { struct ussd_request ussd_req; - struct gsm_ussd* ussdq = get_by_uniq_id(req->invoke_id); + struct gsm_ussd* ussdq; memset(&ussd_req, 0, sizeof(ussd_req)); int rc; - uint8_t mtype; + switch (req->message_type) { + case GSM0480_MTYPE_REGISTER: + DEBUGP(DMM, "Network originated USSD messages isn't supported yet!\n"); + + //TODO Send to sup rejection + return 0; + + case GSM0480_MTYPE_FACILITY: + case GSM0480_MTYPE_RELEASE_COMPLETE: + // FIXME add uinq_id field + ussdq = get_by_uniq_id(req->invoke_id); + if (!ussdq) { + DEBUGP(DMM, "No session was found for uniq_id: %d!\n", + req->invoke_id); + // TODO SUP Reject + return 0; + } + break; + default: + DEBUGP(DMM, "Unknown message type 0x%02x\n", req->message_type); + // TODO SUP Reject + return 0; + } + + ussd_req.transaction_id = ussdq->transaction_id; + ussd_req.invoke_id = ussdq->invoke_id; + + if (req->component_type != GSM0480_CTYPE_REJECT) { + rc = gsm0480_send_ussd_response(ussdq->conn, + NULL, + (const char *)req->ussd_text, + &ussd_req, + req->opcode, + req->component_type, + req->message_type); + } else { + rc = gsm0480_send_ussd_reject(ussdq->conn, NULL, &ussd_req); + } + + if (req->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) { + ussd_session_free(ussdq); + msc_release_connection(ussdq->conn); + } + +#if 0 switch (req->opcode) { case GSM0480_OP_CODE_USS_NOTIFY: DEBUGP(DMM, "Network originated USSD Notify is not supported yet!\n"); @@ -149,7 +216,7 @@ int on_ussd_response(const struct ss_request *req, const char *extention) } mtype = GSM0480_MTYPE_FACILITY; - ussd_req.transaction_id = ussdq->current_transaction_id; + ussd_req.transaction_id = ussdq->transaction_id; break; default: // TODO SUP Reject @@ -175,12 +242,14 @@ int on_ussd_response(const struct ss_request *req, const char *extention) } return rc; + +#endif } /* Entrypoint - handler function common to all mobile-originated USSDs */ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) { - int rc; + int rc = 0; struct gsm48_hdr *gh; struct ss_request req; struct gsm_ussd* ussdq = NULL; @@ -193,16 +262,73 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) gh = msgb_l3(msg); rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req); - - //if (req.ussd_text[0] == 0xFF) - // req.ussd_text[0] = '\0'; - if (!rc) { DEBUGP(DMM, "Unhandled SS\n"); - goto failed; + ussdq = get_by_tid(conn, req.transaction_id); + if (ussdq) { + // TODO send notification to SUP + goto failed_transaction; + } + + goto transaction_not_found; } - ussdq = get_by_id(conn, req.invoke_id); + switch (req.message_type) { + case GSM0480_MTYPE_REGISTER: + ussdq = ussd_session_alloc(conn, req.transaction_id, USSD_MO); + if (!ussdq) { + DEBUGP(DMM, "Failed to create new session\n"); + goto transaction_not_found; + } + ussdq->invoke_id = req.invoke_id; + break; + case GSM0480_MTYPE_FACILITY: + ussdq = get_by_tid(conn, req.transaction_id); + if (!ussdq) { + ussdq = get_by_iid(conn, req.invoke_id); + if (!ussdq) { + DEBUGP(DMM, "no session found invoke_id=%d tid=%d\n", + req.invoke_id, req.transaction_id); + goto transaction_not_found; + } + } + break; + + case GSM0480_MTYPE_RELEASE_COMPLETE: + // FIXME handle parsing in libosmocore + ussdq = get_by_tid(conn, req.transaction_id); + if (!ussdq) { + DEBUGP(DMM, "RELEASE_COMPLETE to non-existing transaction!\n"); + goto release_conn; + } + + ussd_session_free(ussdq); + // TODO send notification to SUP + goto release_conn; + } + + req.invoke_id = ussdq->uniq_id; + rc = subscr_tx_uss_message(&req, conn->subscr); + if (rc) { + DEBUGP(DMM, "Unable tp send uss over sup reason: %d\n", rc); + goto failed_transaction; + } + return 0; + +failed_transaction: + ussd_session_free(ussdq); + +transaction_not_found: + ussd_req.invoke_id = req.invoke_id; + ussd_req.transaction_id = req.transaction_id; + gsm0480_send_ussd_reject(conn, msg, &ussd_req); + +release_conn: + msc_release_connection(conn); + return rc; + +#if 0 + ussdq = get_by_iid(conn, req.invoke_id); // TODO FIXME !!!! Replace by message_type switch (req.opcode) { @@ -258,7 +384,7 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) } return 0; - +#endif #if 0 struct ussd_request req; struct gsm48_hdr *gh; @@ -287,7 +413,7 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) //TODO: } #endif - +#if 0 failed: // TODO handle error on SUP end if (ussdq) { @@ -300,6 +426,7 @@ failed: /* check if we can release it */ msc_release_connection(conn); return rc; +#endif } #if 0 -- cgit v1.2.3