WIP: basic VTY configuration for routing SMS over GSUP
Change-Id: I4dc6ae1dd59928c5ae20205f4d893df106e6b38d
This commit is contained in:
parent
5e73dcb3ab
commit
d90586f93a
|
@ -6,6 +6,7 @@ noinst_HEADERS = \
|
|||
gsup_server.h \
|
||||
hlr.h \
|
||||
hlr_ussd.h \
|
||||
hlr_sms.h \
|
||||
hlr_vty.h \
|
||||
hlr_vty_subscr.h \
|
||||
logging.h \
|
||||
|
|
|
@ -45,13 +45,16 @@ struct hlr {
|
|||
char *gsup_bind_addr;
|
||||
|
||||
struct llist_head euse_list;
|
||||
struct hlr_euse *euse_default;
|
||||
struct llist_head iuse_list;
|
||||
|
||||
/* NCSS (call independent) session guard timeout value */
|
||||
int ncss_guard_timeout;
|
||||
|
||||
struct llist_head ussd_routes;
|
||||
struct llist_head sms_routes;
|
||||
|
||||
struct hlr_euse *ussd_euse_default;
|
||||
struct hlr_euse *sms_euse_default;
|
||||
|
||||
struct llist_head ss_sessions;
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
|
||||
#include "gsup_server.h"
|
||||
|
||||
enum hlr_sms_route_type {
|
||||
HLR_SMS_RT_SMSC_ADDR,
|
||||
HLR_SMS_RT_SENDER_MSISDN,
|
||||
HLR_SMS_RT_SENDER_IMSI,
|
||||
};
|
||||
|
||||
struct hlr_sms_route {
|
||||
struct llist_head list;
|
||||
enum hlr_sms_route_type type;
|
||||
char *match_pattern;
|
||||
const struct hlr_euse *euse;
|
||||
};
|
||||
|
||||
struct hlr_sms_route *sms_route_find(struct hlr *hlr,
|
||||
enum hlr_sms_route_type type,
|
||||
const char *pattern);
|
||||
struct hlr_sms_route *sms_route_alloc(struct hlr *hlr,
|
||||
enum hlr_sms_route_type type,
|
||||
const char *pattern,
|
||||
const struct hlr_euse *euse);
|
||||
void sms_route_del(struct hlr_sms_route *rt);
|
|
@ -50,6 +50,7 @@ osmo_hlr_SOURCES = \
|
|||
hlr_vty_subscr.c \
|
||||
gsup_send.c \
|
||||
hlr_ussd.c \
|
||||
hlr_sms.c \
|
||||
$(NULL)
|
||||
|
||||
osmo_hlr_LDADD = \
|
||||
|
|
|
@ -844,6 +844,7 @@ int main(int argc, char **argv)
|
|||
INIT_LLIST_HEAD(&g_hlr->iuse_list);
|
||||
INIT_LLIST_HEAD(&g_hlr->ss_sessions);
|
||||
INIT_LLIST_HEAD(&g_hlr->ussd_routes);
|
||||
INIT_LLIST_HEAD(&g_hlr->sms_routes);
|
||||
g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);
|
||||
|
||||
/* Init default (call independent) SS session guard timeout value */
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* OsmoHLR SMS routing implementation */
|
||||
|
||||
/* (C) 2019 by Vadim Yanitskiy <axilirator@gmail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/hlr_sms.h>
|
||||
#include <osmocom/hlr/hlr_ussd.h>
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
#include <osmocom/hlr/gsup_router.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
|
||||
struct hlr_sms_route *sms_route_find(struct hlr *hlr,
|
||||
enum hlr_sms_route_type type,
|
||||
const char *pattern)
|
||||
{
|
||||
struct hlr_sms_route *rt;
|
||||
|
||||
llist_for_each_entry(rt, &hlr->sms_routes, list) {
|
||||
if (rt->type != type)
|
||||
continue;
|
||||
if (!strcmp(rt->match_pattern, pattern))
|
||||
return rt;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct hlr_sms_route *sms_route_alloc(struct hlr *hlr,
|
||||
enum hlr_sms_route_type type,
|
||||
const char *pattern,
|
||||
const struct hlr_euse *euse)
|
||||
{
|
||||
struct hlr_sms_route *rt;
|
||||
|
||||
if (sms_route_find(hlr, type, pattern))
|
||||
return NULL;
|
||||
|
||||
rt = talloc(hlr, struct hlr_sms_route);
|
||||
OSMO_ASSERT(rt != NULL);
|
||||
|
||||
rt->match_pattern = talloc_strdup(rt, pattern);
|
||||
rt->type = type;
|
||||
rt->euse = euse;
|
||||
|
||||
llist_add_tail(&rt->list, &hlr->sms_routes);
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
void sms_route_del(struct hlr_sms_route *rt)
|
||||
{
|
||||
llist_del(&rt->list);
|
||||
talloc_free(rt);
|
||||
}
|
|
@ -569,9 +569,9 @@ int rx_proc_ss_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *
|
|||
ss->u.iuse = rt->u.iuse;
|
||||
}
|
||||
} else {
|
||||
if (hlr->euse_default) {
|
||||
if (hlr->ussd_euse_default) {
|
||||
ss->is_external = true;
|
||||
ss->u.euse = hlr->euse_default;
|
||||
ss->u.euse = hlr->ussd_euse_default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
226
src/hlr_vty.c
226
src/hlr_vty.c
|
@ -38,6 +38,7 @@
|
|||
#include <osmocom/hlr/hlr_vty.h>
|
||||
#include <osmocom/hlr/hlr_vty_subscr.h>
|
||||
#include <osmocom/hlr/hlr_ussd.h>
|
||||
#include <osmocom/hlr/hlr_sms.h>
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
|
||||
struct cmd_node hlr_node = {
|
||||
|
@ -159,8 +160,8 @@ DEFUN(cfg_hlr_gsup_bind_ip,
|
|||
"Respond with subscribers' own MSISDN\n" \
|
||||
"Respond with subscribers' own IMSI\n"
|
||||
|
||||
#define EXT_STR "External USSD Handler\n" \
|
||||
"Name of External USSD Handler (IPA CCM ID)\n"
|
||||
#define EXT_STR "External USSD/SMS Handler\n" \
|
||||
"Name of External USSD/SMS Handler (IPA CCM ID)\n"
|
||||
|
||||
DEFUN(cfg_ussd_route_pfx_int, cfg_ussd_route_pfx_int_cmd,
|
||||
"ussd route prefix PREFIX internal " INT_CHOICE,
|
||||
|
@ -223,11 +224,11 @@ DEFUN(cfg_ussd_defaultroute, cfg_ussd_defaultroute_cmd,
|
|||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (g_hlr->euse_default != euse) {
|
||||
vty_out(vty, "Switching default route from %s to %s%s",
|
||||
g_hlr->euse_default ? g_hlr->euse_default->name : "<none>",
|
||||
if (g_hlr->ussd_euse_default != euse) {
|
||||
vty_out(vty, "Switching default USSD route from '%s' to '%s'%s",
|
||||
g_hlr->ussd_euse_default ? g_hlr->ussd_euse_default->name : "<none>",
|
||||
euse->name, VTY_NEWLINE);
|
||||
g_hlr->euse_default = euse;
|
||||
g_hlr->ussd_euse_default = euse;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
@ -237,7 +238,164 @@ DEFUN(cfg_ussd_no_defaultroute, cfg_ussd_no_defaultroute_cmd,
|
|||
"no ussd default-route",
|
||||
NO_STR USSD_STR "Remove the default-route for all USSD to unknown destinations\n")
|
||||
{
|
||||
g_hlr->euse_default = NULL;
|
||||
g_hlr->ussd_euse_default = NULL;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SMS forwarding entity
|
||||
***********************************************************************/
|
||||
|
||||
#define SMS_STR "SMS Routing Configuration\n"
|
||||
|
||||
DEFUN(cfg_sms_route_smsc_addr, cfg_sms_route_smsc_addr_cmd,
|
||||
"sms route smsc-address ADDRESS external EUSE",
|
||||
SMS_STR "Add a new route\n" "Match by address of SMS Center\n"
|
||||
"Address of SMS Center\n" EXT_STR)
|
||||
{
|
||||
const struct hlr_sms_route *rt;
|
||||
const struct hlr_euse *euse;
|
||||
|
||||
rt = sms_route_find(g_hlr, HLR_SMS_RT_SMSC_ADDR, argv[0]);
|
||||
if (rt) {
|
||||
vty_out(vty, "%% Cannot add duplicate route for smsc-address '%s'%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
euse = euse_find(g_hlr, argv[1]);
|
||||
if (!euse) {
|
||||
vty_out(vty, "%% Cannot find EUSE '%s'%s", argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
rt = sms_route_alloc(g_hlr, HLR_SMS_RT_SMSC_ADDR, argv[0], euse);
|
||||
if (!rt) {
|
||||
vty_out(vty, "%% Failed to add a new route for smsc-address '%s'%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_sms_no_route_smsc_addr, cfg_sms_no_route_smsc_addr_cmd,
|
||||
"no sms route smsc-address ADDRESS",
|
||||
SMS_STR "Delete a route\n" "Match by address of SMS Center\n"
|
||||
"Address of SMS Center\n")
|
||||
{
|
||||
struct hlr_sms_route *rt;
|
||||
|
||||
rt = sms_route_find(g_hlr, HLR_SMS_RT_SMSC_ADDR, argv[0]);
|
||||
if (!rt) {
|
||||
vty_out(vty, "%% Cannot find route for smsc-address '%s'%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
sms_route_del(rt);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_sms_route_sender, cfg_sms_route_sender_cmd,
|
||||
"sms route sender (msisdn|imsi) IDENT external EUSE",
|
||||
SMS_STR "Add a new route\n" "Match by sender of SMS message\n"
|
||||
"Identify subscriber by IMSI\n"
|
||||
"Identify subscriber by MSISDN (phone number)\n" EXT_STR)
|
||||
{
|
||||
const struct hlr_sms_route *rt;
|
||||
enum hlr_sms_route_type type;
|
||||
const struct hlr_euse *euse;
|
||||
|
||||
if (argv[0][0] == 'm')
|
||||
type = HLR_SMS_RT_SENDER_MSISDN;
|
||||
else if (argv[0][0] == 'i')
|
||||
type = HLR_SMS_RT_SENDER_IMSI;
|
||||
else /* Shall not happen */
|
||||
OSMO_ASSERT(0);
|
||||
|
||||
rt = sms_route_find(g_hlr, type, argv[1]);
|
||||
if (rt) {
|
||||
vty_out(vty, "%% Cannot add duplicate route for %s '%s'%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
euse = euse_find(g_hlr, argv[2]);
|
||||
if (!euse) {
|
||||
vty_out(vty, "%% Cannot find EUSE '%s'%s", argv[2], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
rt = sms_route_alloc(g_hlr, type, argv[1], euse);
|
||||
if (!rt) {
|
||||
vty_out(vty, "%% Failed to add a new route for %s '%s'%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_sms_no_route_sender, cfg_sms_no_route_sender_cmd,
|
||||
"no sms route sender (msisdn|imsi) IDENT",
|
||||
SMS_STR "Delete a route\n" "Match by sender of SMS message\n"
|
||||
"Identify subscriber by IMSI\n"
|
||||
"Identify subscriber by MSISDN (phone number)\n")
|
||||
{
|
||||
struct hlr_sms_route *rt;
|
||||
enum hlr_sms_route_type type;
|
||||
|
||||
if (argv[0][0] == 'm')
|
||||
type = HLR_SMS_RT_SENDER_MSISDN;
|
||||
else if (argv[0][0] == 'i')
|
||||
type = HLR_SMS_RT_SENDER_IMSI;
|
||||
else /* Shall not happen */
|
||||
OSMO_ASSERT(0);
|
||||
|
||||
rt = sms_route_find(g_hlr, type, argv[1]);
|
||||
if (!rt) {
|
||||
vty_out(vty, "%% Cannot find route for %s '%s'%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
sms_route_del(rt);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_sms_defaultroute, cfg_sms_defaultroute_cmd,
|
||||
"sms default-route external EUSE",
|
||||
SMS_STR "Configure default-route for all "
|
||||
"SMS to unknown destinations\n" EXT_STR)
|
||||
{
|
||||
struct hlr_euse *euse;
|
||||
|
||||
euse = euse_find(g_hlr, argv[0]);
|
||||
if (!euse) {
|
||||
vty_out(vty, "%% Cannot find EUSE %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (g_hlr->sms_euse_default != euse) {
|
||||
vty_out(vty, "Switching default SMS route from '%s' to '%s'%s",
|
||||
g_hlr->sms_euse_default ? g_hlr->sms_euse_default->name : "<none>",
|
||||
euse->name, VTY_NEWLINE);
|
||||
g_hlr->sms_euse_default = euse;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_sms_no_defaultroute, cfg_sms_no_defaultroute_cmd,
|
||||
"no sms default-route",
|
||||
NO_STR SMS_STR "Remove the default-route "
|
||||
"for all SMS to unknown destinations\n")
|
||||
{
|
||||
g_hlr->sms_euse_default = NULL;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -288,7 +446,7 @@ DEFUN(cfg_no_euse, cfg_no_euse_cmd,
|
|||
vty_out(vty, "%% Cannot remove non-existant EUSE %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (g_hlr->euse_default == euse) {
|
||||
if (g_hlr->ussd_euse_default == euse || g_hlr->sms_euse_default == euse) {
|
||||
vty_out(vty, "%% Cannot remove EUSE %s, it is the default route%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
@ -301,23 +459,53 @@ static void dump_one_euse(struct vty *vty, struct hlr_euse *euse)
|
|||
vty_out(vty, " euse %s%s", euse->name, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static const char *sms_route_type_to_str(enum hlr_sms_route_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case HLR_SMS_RT_SMSC_ADDR:
|
||||
return "smsc-address";
|
||||
case HLR_SMS_RT_SENDER_MSISDN:
|
||||
return "sender msisdn";
|
||||
case HLR_SMS_RT_SENDER_IMSI:
|
||||
return "sender imsi";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int config_write_euse(struct vty *vty)
|
||||
{
|
||||
struct hlr_ussd_route *ussd_rt;
|
||||
struct hlr_sms_route *sms_rt;
|
||||
struct hlr_euse *euse;
|
||||
struct hlr_ussd_route *rt;
|
||||
|
||||
llist_for_each_entry(euse, &g_hlr->euse_list, list)
|
||||
dump_one_euse(vty, euse);
|
||||
|
||||
llist_for_each_entry(rt, &g_hlr->ussd_routes, list) {
|
||||
vty_out(vty, " ussd route prefix %s %s %s%s", rt->prefix,
|
||||
rt->is_external ? "external" : "internal",
|
||||
rt->is_external ? rt->u.euse->name : rt->u.iuse->name,
|
||||
llist_for_each_entry(ussd_rt, &g_hlr->ussd_routes, list) {
|
||||
vty_out(vty, " ussd route prefix %s %s %s%s", ussd_rt->prefix,
|
||||
ussd_rt->is_external ? "external" : "internal",
|
||||
ussd_rt->is_external ? ussd_rt->u.euse->name : ussd_rt->u.iuse->name,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (g_hlr->euse_default)
|
||||
vty_out(vty, " ussd default-route external %s%s", g_hlr->euse_default->name, VTY_NEWLINE);
|
||||
llist_for_each_entry(sms_rt, &g_hlr->sms_routes, list) {
|
||||
vty_out(vty, " sms route %s %s external %s%s",
|
||||
sms_route_type_to_str(sms_rt->type),
|
||||
sms_rt->match_pattern,
|
||||
sms_rt->euse->name,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (g_hlr->ussd_euse_default) {
|
||||
vty_out(vty, " ussd default-route external %s%s",
|
||||
g_hlr->ussd_euse_default->name, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (g_hlr->sms_euse_default) {
|
||||
vty_out(vty, " sms default-route external %s%s",
|
||||
g_hlr->sms_euse_default->name, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (g_hlr->ncss_guard_timeout != NCSS_GUARD_TIMEOUT_DEFAULT)
|
||||
vty_out(vty, " ncss-guard-timeout %i%s",
|
||||
|
@ -453,6 +641,14 @@ void hlr_vty_init(void)
|
|||
install_element(HLR_NODE, &cfg_ussd_no_route_pfx_cmd);
|
||||
install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
|
||||
install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
|
||||
|
||||
install_element(HLR_NODE, &cfg_sms_route_smsc_addr_cmd);
|
||||
install_element(HLR_NODE, &cfg_sms_no_route_smsc_addr_cmd);
|
||||
install_element(HLR_NODE, &cfg_sms_route_sender_cmd);
|
||||
install_element(HLR_NODE, &cfg_sms_no_route_sender_cmd);
|
||||
install_element(HLR_NODE, &cfg_sms_defaultroute_cmd);
|
||||
install_element(HLR_NODE, &cfg_sms_no_defaultroute_cmd);
|
||||
|
||||
install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
|
||||
install_element(HLR_NODE, &cfg_store_imei_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_store_imei_cmd);
|
||||
|
|
|
@ -107,6 +107,8 @@ OsmoHLR(config-hlr)# list
|
|||
database PATH
|
||||
euse NAME
|
||||
no euse NAME
|
||||
sms route smsc-address ADDRESS external EUSE
|
||||
sms route sender (msisdn|imsi) IDENT external EUSE
|
||||
ussd route prefix PREFIX internal (own-msisdn|own-imsi)
|
||||
ussd route prefix PREFIX external EUSE
|
||||
no ussd route prefix PREFIX
|
||||
|
|
Loading…
Reference in New Issue