diff options
author | Holger Hans Peter Freyther <zecke@selfish.org> | 2010-12-29 20:56:08 +0100 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2010-12-30 14:35:15 +0100 |
commit | 2c1a26adb55d6c0f7e2203b186873ba73fb03425 (patch) | |
tree | b2a63c2bfda5e80f850cf27d278c5ec53ef420d9 /openbsc/src | |
parent | 2a21901d9292dbdbd8714b8f3a9f80604fcde5a5 (diff) |
ussd: Prepare being able to send custom L3 messages to the phone. WIP: custom l3 message....
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/gsm_04_08.c | 2 | ||||
-rw-r--r-- | openbsc/src/ussd.c | 151 | ||||
-rw-r--r-- | openbsc/src/vty_interface_layer3.c | 42 |
3 files changed, 194 insertions, 1 deletions
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; } |