summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-12-29 20:56:08 +0100
committerHarald Welte <laforge@gnumonks.org>2010-12-30 14:35:15 +0100
commit2c1a26adb55d6c0f7e2203b186873ba73fb03425 (patch)
treeb2a63c2bfda5e80f850cf27d278c5ec53ef420d9
parent2a21901d9292dbdbd8714b8f3a9f80604fcde5a5 (diff)
ussd: Prepare being able to send custom L3 messages to the phone. WIP: custom l3 message....
-rw-r--r--openbsc/include/openbsc/gsm_data.h4
-rw-r--r--openbsc/include/openbsc/ussd.h11
-rw-r--r--openbsc/src/gsm_04_08.c2
-rw-r--r--openbsc/src/ussd.c151
-rw-r--r--openbsc/src/vty_interface_layer3.c42
5 files changed, 209 insertions, 1 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index fc02f58de..23aca119d 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -254,6 +254,10 @@ struct gsm_subscriber_connection {
int silent_call;
int put_channel;
+ int ussd_sequence;
+ int ussd_cur_seq;
+ const char *ussd_number;
+
/* bsc structures */
struct osmo_bsc_sccp_con *sccp_con;
diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h
index 6f80d23d8..819666bc5 100644
--- a/openbsc/include/openbsc/ussd.h
+++ b/openbsc/include/openbsc/ussd.h
@@ -5,6 +5,17 @@
#include <osmocore/msgb.h>
+struct vty;
+
int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg);
+/* reply with custom L3 messages */
+int ussd_parse_mapping(const char *number, const uint8_t *msg, int len);
+int ussd_clear_mapping(const char *number);
+int ussd_dump_mapping(struct vty *vty);
+
+
+int ussd_call_reroute(struct gsm_subscriber_connection *conn, struct msgb *msg);
+int ussd_call_rx(struct gsm_subscriber_connection *conn, struct msgb *msg);
+
#endif
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index a5bccf6b7..0780e2ea8 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -3216,6 +3216,8 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg)
if (silent_call_reroute(conn, msg))
return silent_call_rx(conn, msg);
+ if (ussd_call_reroute(conn, msg))
+ return ussd_call_rx(conn, msg);
switch (pdisc) {
case GSM48_PDISC_CC:
diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c
index c9eac13f0..97370c1b0 100644
--- a/openbsc/src/ussd.c
+++ b/openbsc/src/ussd.c
@@ -1,7 +1,7 @@
/* Network-specific handling of mobile-originated USSDs. */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2008, 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009 by Mike Haben <michael.haben@btinternet.com>
*
* All Rights Reserved
@@ -35,11 +35,28 @@
#include <openbsc/debug.h>
#include <openbsc/osmo_msc.h>
+
+#include <osmocore/talloc.h>
+
+#include <osmocom/vty/vty.h>
+
+struct ussd_mapping {
+ struct llist_head entry;
+ const char *ussd_number;
+
+ uint8_t **l3_frames;
+ uint8_t *l3_sizes;
+ int frame_sizes;
+};
+
+LLIST_HEAD(mapping_list);
+
/* 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(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req);
+static int ussd_send_custom(struct gsm_subscriber_connection *, struct msgb *, struct ussd_request *);
/* Entrypoint - handler function common to all mobile-originated USSDs */
@@ -58,6 +75,9 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
if (strstr(USSD_TEXT_OWN_NUMBER, req.text) != NULL) {
DEBUGP(DMM, "USSD: Own number requested\n");
rc = send_own_number(conn, msg, &req);
+ } else if (ussd_send_custom(conn, msg, &req)) {
+ LOGP(DMM, LOGL_NOTICE, "Sending custom L3 message for USSD.\n");
+ rc = 1;
} else {
DEBUGP(DMM, "Unhandled USSD %s\n", req.text);
rc = gsm0480_send_ussd_reject(conn, msg, &req);
@@ -78,3 +98,132 @@ static int send_own_number(struct gsm_subscriber_connection *conn, const struct
snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
return gsm0480_send_ussd_response(conn, msg, response_string, req);
}
+
+
+static int ussd_send_custom(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, struct ussd_request *req)
+{
+ struct msgb *out;
+ uint8_t* data;
+ struct ussd_mapping *map;
+
+ llist_for_each_entry(map, &mapping_list, entry) {
+ if (strstr(map->ussd_number, req->text) == NULL)
+ continue;
+
+ /* if we have more than one msg */
+ if (map->frame_sizes > 1) {
+ conn->ussd_sequence = 1;
+ conn->ussd_number = map->ussd_number;
+ }
+
+ out = gsm48_msgb_alloc();
+ if (!out)
+ return -1;
+
+
+ out->lchan = msg->lchan;
+ data = msgb_put(out, map->l3_sizes[0]);
+ memcpy(data, map->l3_frames[0], map->l3_sizes[0]);
+ gsm0808_submit_dtap(conn, out, 0, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+extern struct gsm_network *bsc_gsmnet;
+int ussd_parse_mapping(const char *number, const uint8_t *msg, int len)
+{
+ struct ussd_mapping *map;
+
+ llist_for_each_entry(map, &mapping_list, entry) {
+ if (strcmp(map->ussd_number, number) != 0)
+ continue;
+
+ LOGP(DINP, LOGL_ERROR, "NOT IMPLTELEMEND\n");
+#if 0
+ map->l3_frames = talloc_realloc(map, map->l3_sizes, uint8_t,
+ map->l3_sizes = talloc_realloc;
+
+ map->l3_frames[map->frame_sizes] = talloc_array(map, uint8_t, len);
+ memcpy(map->l3_frames[map->frame_sizes], msg, len);
+
+ map->l3_sizes[map->frame_sizes] = len;
+ map->frame_sizes += 1;
+#endif
+ return 0;
+ }
+
+
+ map = talloc_zero(bsc_gsmnet, struct ussd_mapping);
+ if (!map)
+ return -1;
+
+ llist_add(&map->entry, &mapping_list);
+ map->ussd_number = talloc_strdup(map, number);
+ map->l3_frames = talloc_array(map, uint8_t*, 1);
+ map->l3_sizes = talloc_array(map, uint8_t, 1);
+
+ map->l3_frames[0] = talloc_array(map, uint8_t, len);
+ memcpy(map->l3_frames[0], msg, len);
+ map->l3_sizes[0] = len;
+ map->frame_sizes += 1;
+
+ return 0;
+}
+
+int ussd_clear_mapping(const char *number)
+{
+ struct ussd_mapping *map;
+
+ llist_for_each_entry(map, &mapping_list, entry) {
+ if (strcmp(map->ussd_number, number) == 0) {
+ llist_del(&map->entry);
+ talloc_free(map);
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+
+int ussd_call_reroute(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+ struct ussd_mapping *map;
+
+ if (!conn->ussd_sequence)
+ return 0;
+
+ /* check if the rule is still there, compare number */
+ llist_for_each_entry(map, &mapping_list, entry) {
+ if (conn->ussd_number == map->ussd_number) {
+ return 1;
+ }
+ }
+
+ return -0;
+}
+
+int ussd_dump_mapping(struct vty *vty)
+{
+ int i = 0;
+ struct ussd_mapping *map;
+
+ llist_for_each_entry(map, &mapping_list, entry) {
+ vty_out(vty, "USSD Nr: %s nr_frames: %d%s",
+ map->ussd_number, map->frame_sizes, VTY_NEWLINE);
+ for (i = 0; i < map->frame_sizes; ++i)
+ vty_out(vty, " %d: '%s'%s",
+ i, hexdump(map->l3_frames[i], map->l3_sizes[i]), VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+int ussd_call_rx(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+ LOGP(DINP, LOGL_ERROR, "NOT IMPLTELEMEND\n");
+ return -1;
+}
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
index 25b9c16f8..218e3ce58 100644
--- a/openbsc/src/vty_interface_layer3.c
+++ b/openbsc/src/vty_interface_layer3.c
@@ -762,6 +762,44 @@ DEFUN(smsqueue_fail,
return CMD_SUCCESS;
}
+DEFUN(ussd_add,
+ ussd_add_cmd,
+ "ussd add NR HEX",
+ "USSD Custom Messages\n" "Add\n" "USSD query\n" "Hex String\n")
+{
+ uint8_t data[256];
+ int len;
+
+ len = hexparse(argv[1], data, 255);
+ if (len < 0) {
+ vty_out(vty, "Can not parse the string.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ussd_parse_mapping(argv[0], data, len);
+ return CMD_SUCCESS;
+}
+
+DEFUN(ussd_clear,
+ ussd_clear_cmd,
+ "ussd clear NR",
+ "USSD Custom Messages\n" "Clear\n" "USSD query\n")
+{
+ ussd_clear_mapping(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(ussd_dump,
+ ussd_dump_cmd,
+ "ussd dump",
+ "USSD Custom Messages\n" "Dump\n")
+{
+ ussd_dump_mapping(vty);
+ return CMD_SUCCESS;
+}
+
+
+
int bsc_vty_init_extra(void)
{
register_signal_handler(SS_SCALL, scall_cbfn, NULL);
@@ -793,5 +831,9 @@ int bsc_vty_init_extra(void)
install_element(ENABLE_NODE, &smsqueue_clear_cmd);
install_element(ENABLE_NODE, &smsqueue_fail_cmd);
+ install_element(ENABLE_NODE, &ussd_add_cmd);
+ install_element(ENABLE_NODE, &ussd_clear_cmd);
+ install_element(ENABLE_NODE, &ussd_dump_cmd);
+
return 0;
}