mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
				synced 2025-11-04 06:03:28 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			master
			...
			fixeria/sm
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4c80a7fb31 | ||
| 
						 | 
					d90586f93a | ||
| 
						 | 
					5e73dcb3ab | 
@@ -6,6 +6,7 @@ noinst_HEADERS = \
 | 
				
			|||||||
	gsup_server.h \
 | 
						gsup_server.h \
 | 
				
			||||||
	hlr.h \
 | 
						hlr.h \
 | 
				
			||||||
	hlr_ussd.h \
 | 
						hlr_ussd.h \
 | 
				
			||||||
 | 
						hlr_sms.h \
 | 
				
			||||||
	hlr_vty.h \
 | 
						hlr_vty.h \
 | 
				
			||||||
	hlr_vty_subscr.h \
 | 
						hlr_vty_subscr.h \
 | 
				
			||||||
	logging.h \
 | 
						logging.h \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,13 +45,16 @@ struct hlr {
 | 
				
			|||||||
	char *gsup_bind_addr;
 | 
						char *gsup_bind_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct llist_head euse_list;
 | 
						struct llist_head euse_list;
 | 
				
			||||||
	struct hlr_euse *euse_default;
 | 
					 | 
				
			||||||
	struct llist_head iuse_list;
 | 
						struct llist_head iuse_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* NCSS (call independent) session guard timeout value */
 | 
						/* NCSS (call independent) session guard timeout value */
 | 
				
			||||||
	int ncss_guard_timeout;
 | 
						int ncss_guard_timeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct llist_head ussd_routes;
 | 
						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;
 | 
						struct llist_head ss_sessions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								include/osmocom/hlr/hlr_sms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								include/osmocom/hlr/hlr_sms.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int forward_mo_sms(struct osmo_gsup_conn *conn,
 | 
				
			||||||
 | 
							   const struct osmo_gsup_message *gsup,
 | 
				
			||||||
 | 
							   struct msgb *msg);
 | 
				
			||||||
 | 
					int forward_sm_res_or_err(struct osmo_gsup_conn *conn,
 | 
				
			||||||
 | 
								  const struct osmo_gsup_message *gsup,
 | 
				
			||||||
 | 
								  struct msgb *msg);
 | 
				
			||||||
 | 
					int forward_mt_sms(struct osmo_gsup_conn *conn,
 | 
				
			||||||
 | 
							   const struct osmo_gsup_message *gsup,
 | 
				
			||||||
 | 
							   struct msgb *msg);
 | 
				
			||||||
@@ -50,6 +50,7 @@ osmo_hlr_SOURCES = \
 | 
				
			|||||||
	hlr_vty_subscr.c \
 | 
						hlr_vty_subscr.c \
 | 
				
			||||||
	gsup_send.c \
 | 
						gsup_send.c \
 | 
				
			||||||
	hlr_ussd.c \
 | 
						hlr_ussd.c \
 | 
				
			||||||
 | 
						hlr_sms.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo_hlr_LDADD = \
 | 
					osmo_hlr_LDADD = \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								src/hlr.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								src/hlr.c
									
									
									
									
									
								
							@@ -47,6 +47,7 @@
 | 
				
			|||||||
#include <osmocom/hlr/luop.h>
 | 
					#include <osmocom/hlr/luop.h>
 | 
				
			||||||
#include <osmocom/hlr/hlr_vty.h>
 | 
					#include <osmocom/hlr/hlr_vty.h>
 | 
				
			||||||
#include <osmocom/hlr/hlr_ussd.h>
 | 
					#include <osmocom/hlr/hlr_ussd.h>
 | 
				
			||||||
 | 
					#include <osmocom/hlr/hlr_sms.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct hlr *g_hlr;
 | 
					struct hlr *g_hlr;
 | 
				
			||||||
static void *hlr_ctx = NULL;
 | 
					static void *hlr_ctx = NULL;
 | 
				
			||||||
@@ -663,6 +664,28 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
 | 
				
			|||||||
	case OSMO_GSUP_MSGT_PROC_SS_ERROR:
 | 
						case OSMO_GSUP_MSGT_PROC_SS_ERROR:
 | 
				
			||||||
		rx_proc_ss_error(conn, &gsup);
 | 
							rx_proc_ss_error(conn, &gsup);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Short Message from MSC/VLR towards SMSC */
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_MO_FORWARD_SM_REQUEST:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_READY_FOR_SM_REQUEST:
 | 
				
			||||||
 | 
							forward_mo_sms(conn, &gsup, msg);
 | 
				
			||||||
 | 
							return 0; /* Do not free msgb */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Short Message from SMSC towards MSC/VLR */
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_MT_FORWARD_SM_REQUEST:
 | 
				
			||||||
 | 
							forward_mt_sms(conn, &gsup, msg);
 | 
				
			||||||
 | 
							return 0; /* Do not free msgb */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Short Message delivery status, to be forwarded 'as-is' */
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_MO_FORWARD_SM_RESULT:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_MT_FORWARD_SM_RESULT:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_MO_FORWARD_SM_ERROR:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_MT_FORWARD_SM_ERROR:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_READY_FOR_SM_RESULT:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_READY_FOR_SM_ERROR:
 | 
				
			||||||
 | 
							forward_sm_res_or_err(conn, &gsup, msg);
 | 
				
			||||||
 | 
							return 0; /* Do not free msgb */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
 | 
						case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
 | 
				
			||||||
	case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:
 | 
						case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:
 | 
				
			||||||
	case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:
 | 
						case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:
 | 
				
			||||||
@@ -844,6 +867,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	INIT_LLIST_HEAD(&g_hlr->iuse_list);
 | 
						INIT_LLIST_HEAD(&g_hlr->iuse_list);
 | 
				
			||||||
	INIT_LLIST_HEAD(&g_hlr->ss_sessions);
 | 
						INIT_LLIST_HEAD(&g_hlr->ss_sessions);
 | 
				
			||||||
	INIT_LLIST_HEAD(&g_hlr->ussd_routes);
 | 
						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);
 | 
						g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Init default (call independent) SS session guard timeout value */
 | 
						/* Init default (call independent) SS session guard timeout value */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										398
									
								
								src/hlr_sms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								src/hlr_sms.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,398 @@
 | 
				
			|||||||
 | 
					/* 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/core/utils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/gsm/protocol/gsm_04_11.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm48_ie.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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Common helper for preparing to be encoded GSUP message */
 | 
				
			||||||
 | 
					static void gsup_prepare_sm_error(struct osmo_gsup_message *msg,
 | 
				
			||||||
 | 
									  const struct osmo_gsup_message *src_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Init a mew GSUP message */
 | 
				
			||||||
 | 
						*msg = (struct osmo_gsup_message) {
 | 
				
			||||||
 | 
							.message_type = OSMO_GSUP_TO_MSGT_ERROR(src_msg->message_type),
 | 
				
			||||||
 | 
							.message_class = OSMO_GSUP_MESSAGE_CLASS_SMS,
 | 
				
			||||||
 | 
							.sm_rp_mr = src_msg->sm_rp_mr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Swap optional source and destination addresses */
 | 
				
			||||||
 | 
							.destination_name_len = src_msg->source_name_len,
 | 
				
			||||||
 | 
							.destination_name = src_msg->source_name,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Fill in subscriber's IMSI */
 | 
				
			||||||
 | 
						OSMO_STRLCPY_ARRAY(msg->imsi, src_msg->imsi);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int gsup_conn_enc_send(struct osmo_gsup_conn *conn,
 | 
				
			||||||
 | 
								      struct osmo_gsup_message *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *gsup_msgb;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_msgb = msgb_alloc_headroom(512, 64, __func__);
 | 
				
			||||||
 | 
						if (!gsup_msgb) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "Failed to allocate a GSUP message\n");
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_gsup_encode(gsup_msgb, msg);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "Failed to encode GSUP message '%s' (rc=%d)\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(msg->message_type), rc);
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_gsup_conn_send(conn, gsup_msgb);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "Failed to send GSUP message '%s' (rc=%d)\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(msg->message_type), rc);
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Short Message delivery status, to be forwarded 'as-is' */
 | 
				
			||||||
 | 
					int forward_sm_res_or_err(struct osmo_gsup_conn *conn,
 | 
				
			||||||
 | 
								  const struct osmo_gsup_message *gsup,
 | 
				
			||||||
 | 
								  struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hlr_subscriber subscr;
 | 
				
			||||||
 | 
						char src_name_buf[32];
 | 
				
			||||||
 | 
						char dst_name_buf[32];
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = db_subscr_get_by_imsi(g_hlr->dbc, gsup->imsi, &subscr);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Rx '%s' for unknown subscriber IMSI-%s\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi);
 | 
				
			||||||
 | 
							/* TODO: send some error back? */
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure destination name is present */
 | 
				
			||||||
 | 
						if (gsup->destination_name == NULL || !gsup->destination_name_len) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Rx '%s' (IMSI-%s) without destination name\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi);
 | 
				
			||||||
 | 
							/* TODO: send some error back? */
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure source name is present */
 | 
				
			||||||
 | 
						if (gsup->source_name == NULL || !gsup->source_name_len) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Rx '%s' (IMSI-%s) without source name\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi);
 | 
				
			||||||
 | 
							/* TODO: send some error back? */
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLSMS, LOGL_INFO, "Forward '%s' (IMSI-%s) from %s to %s\n",
 | 
				
			||||||
 | 
						     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi,
 | 
				
			||||||
 | 
						     osmo_quote_str_buf2(src_name_buf, sizeof(src_name_buf),
 | 
				
			||||||
 | 
									 (const char *) gsup->source_name,
 | 
				
			||||||
 | 
									 gsup->source_name_len),
 | 
				
			||||||
 | 
						     osmo_quote_str_buf2(dst_name_buf, sizeof(dst_name_buf),
 | 
				
			||||||
 | 
									 (const char *) gsup->destination_name,
 | 
				
			||||||
 | 
									 gsup->destination_name_len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_gsup_addr_send(conn->server, gsup->destination_name,
 | 
				
			||||||
 | 
									 gsup->destination_name_len, msg);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Failed to forward '%s' (IMSI-%s)\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi);
 | 
				
			||||||
 | 
							/* osmo_gsup_addr_send() free()d msg */
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct hlr_euse *find_euse(const struct hlr_subscriber *subscr,
 | 
				
			||||||
 | 
										const char *smsc_addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hlr_sms_route *rt;
 | 
				
			||||||
 | 
						const char *pattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Iterate over all known routes */
 | 
				
			||||||
 | 
						llist_for_each_entry(rt, &g_hlr->sms_routes, list) {
 | 
				
			||||||
 | 
							switch (rt->type) {
 | 
				
			||||||
 | 
							case HLR_SMS_RT_SMSC_ADDR:
 | 
				
			||||||
 | 
								pattern = smsc_addr;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case HLR_SMS_RT_SENDER_MSISDN:
 | 
				
			||||||
 | 
								pattern = subscr->msisdn;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case HLR_SMS_RT_SENDER_IMSI:
 | 
				
			||||||
 | 
								pattern = subscr->imsi;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								/* Shall not happen, make Coverity happy */
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (strcmp(rt->match_pattern, pattern) == 0)
 | 
				
			||||||
 | 
								return rt->euse;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Fall-back to default route if nothing will be found */
 | 
				
			||||||
 | 
						return g_hlr->sms_euse_default;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct osmo_gsup_conn *find_conn(struct osmo_gsup_server *srv,
 | 
				
			||||||
 | 
										      const struct hlr_euse *euse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char euse_addr[128];
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = snprintf(euse_addr, sizeof(euse_addr), "EUSE-%s", euse->name);
 | 
				
			||||||
 | 
						return gsup_route_find(srv, (uint8_t *) euse_addr, rc + 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Short Message from MSC/VLR towards SMSC */
 | 
				
			||||||
 | 
					int forward_mo_sms(struct osmo_gsup_conn *conn,
 | 
				
			||||||
 | 
							   const struct osmo_gsup_message *gsup,
 | 
				
			||||||
 | 
							   struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char smsc_addr[GSM23003_MSISDN_MAX_DIGITS + 1];
 | 
				
			||||||
 | 
						struct osmo_gsup_message rsp_msg;
 | 
				
			||||||
 | 
						struct hlr_subscriber subscr;
 | 
				
			||||||
 | 
						uint8_t ext, ton, npi;
 | 
				
			||||||
 | 
						uint8_t sm_rp_cause;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = db_subscr_get_by_imsi(g_hlr->dbc, gsup->imsi, &subscr);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Rx '%s' for unknown subscriber IMSI-%s\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							rsp_msg.cause = GMM_CAUSE_IMSI_UNKNOWN;
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure SM-RP-DA (SMSC address) is present */
 | 
				
			||||||
 | 
						if (gsup->sm_rp_da == NULL || !gsup->sm_rp_da_len) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Rx '%s' (IMSI-%s) without mandatory SM-RP-DA\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							rsp_msg.cause = GMM_CAUSE_INV_MAND_INFO;
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gsup->sm_rp_da_type != OSMO_GSUP_SMS_SM_RP_ODA_SMSC_ADDR) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Rx '%s' (IMSI-%s) with unexpected SM-RP-DA 0x%02x\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi,
 | 
				
			||||||
 | 
							     gsup->sm_rp_da_type);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							rsp_msg.cause = GMM_CAUSE_INV_MAND_INFO;
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Parse ToN (Type of Number) / NPI (Numbering Plan Indicator) */
 | 
				
			||||||
 | 
						ext = (gsup->sm_rp_da[0] >> 7) ^ 0x01; /* NOTE: inversed */
 | 
				
			||||||
 | 
						ton = (gsup->sm_rp_da[0] >> 4) & 0x07;
 | 
				
			||||||
 | 
						npi = gsup->sm_rp_da[0] & 0x0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We only support International ISDN/telephone format */
 | 
				
			||||||
 | 
						if (ext || ton != 0x01 || npi != 0x01) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Rx '%s' (IMSI-%s) with unsupported SMSC address format: "
 | 
				
			||||||
 | 
										 "ToN=0x%02x, NPI=0x%02x\n, extension=%s\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi,
 | 
				
			||||||
 | 
							     ton, npi, ext ? "yes" : "no");
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							rsp_msg.cause = GMM_CAUSE_SEM_INCORR_MSG;
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Decode SMSC address from SM-RP-DA */
 | 
				
			||||||
 | 
						rc = osmo_bcd2str(smsc_addr, sizeof(smsc_addr), gsup->sm_rp_da + 1,
 | 
				
			||||||
 | 
								  2, (gsup->sm_rp_da_len - 1) * 2, true);
 | 
				
			||||||
 | 
						if (rc < 0 || rc >= sizeof(smsc_addr)) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Failed to decode SMSC address from '%s' (IMSI-%s): rc=%d\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi, rc);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							rsp_msg.cause = GMM_CAUSE_SEM_INCORR_MSG;
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Attempt to find a EUSE */
 | 
				
			||||||
 | 
						const struct hlr_euse *euse = find_euse(&subscr, smsc_addr);
 | 
				
			||||||
 | 
						if (euse == NULL) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Failed to find a route for '%s' (IMSI-%s, MR-0x%02x)\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi, *gsup->sm_rp_mr);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							sm_rp_cause = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
 | 
				
			||||||
 | 
							rsp_msg.sm_rp_cause = &sm_rp_cause;
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const struct osmo_gsup_conn *euse_conn = find_conn(conn->server, euse);
 | 
				
			||||||
 | 
						if (euse_conn == NULL) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "EUSE '%s' is not connected!\n", euse->name);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							sm_rp_cause = GSM411_RP_CAUSE_MO_TEMP_FAIL;
 | 
				
			||||||
 | 
							rsp_msg.sm_rp_cause = &sm_rp_cause;
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLSMS, LOGL_INFO, "Forwarding '%s' (IMSI-%s, MR-0x%02x) to SMSC '%s'\n",
 | 
				
			||||||
 | 
						     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi,
 | 
				
			||||||
 | 
						     *gsup->sm_rp_mr, euse->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* HACK: make sure source name is present, fill in if needed */
 | 
				
			||||||
 | 
						if (gsup->source_name == NULL || !gsup->source_name_len) {
 | 
				
			||||||
 | 
							/* FIXME: distinguish between MSC/VLR and SGSN */
 | 
				
			||||||
 | 
							msgb_tlv_put(msg, OSMO_GSUP_SOURCE_NAME_IE,
 | 
				
			||||||
 | 
								     strlen(subscr.vlr_number) + 1,
 | 
				
			||||||
 | 
								     (uint8_t *) subscr.vlr_number);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Ensure the buffer has enough headroom to put IPA headers */
 | 
				
			||||||
 | 
						msgb_pull_to_l2(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Finally forward the original message */
 | 
				
			||||||
 | 
						rc = osmo_gsup_conn_send((struct osmo_gsup_conn *) euse_conn, msg);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "Failed to send GSUP message '%s' (rc=%d)\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), rc);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							sm_rp_cause = GSM411_RP_CAUSE_MO_TEMP_FAIL;
 | 
				
			||||||
 | 
							rsp_msg.sm_rp_cause = &sm_rp_cause;
 | 
				
			||||||
 | 
							msg = NULL; /* free()d by osmo_gsup_conn_send() */
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit_error:
 | 
				
			||||||
 | 
						gsup_conn_enc_send(conn, &rsp_msg);
 | 
				
			||||||
 | 
						if (msg != NULL)
 | 
				
			||||||
 | 
							talloc_free(msg);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Short Message from SMSC towards MSC/VLR */
 | 
				
			||||||
 | 
					int forward_mt_sms(struct osmo_gsup_conn *conn,
 | 
				
			||||||
 | 
							   const struct osmo_gsup_message *gsup,
 | 
				
			||||||
 | 
							   struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_gsup_message rsp_msg;
 | 
				
			||||||
 | 
						struct hlr_subscriber subscr;
 | 
				
			||||||
 | 
						uint8_t sm_rp_cause;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = db_subscr_get_by_imsi(g_hlr->dbc, gsup->imsi, &subscr);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_NOTICE, "Rx '%s' for unknown subscriber IMSI-%s\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							rsp_msg.cause = GMM_CAUSE_IMSI_UNKNOWN;
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						LOGP(DLSMS, LOGL_INFO, "Forwarding '%s' (IMSI-%s, MR-0x%02x) to MSC/VLR '%s'\n",
 | 
				
			||||||
 | 
						     osmo_gsup_message_type_name(gsup->message_type), gsup->imsi,
 | 
				
			||||||
 | 
						     *gsup->sm_rp_mr, FIXME!);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Finally forward the original message */
 | 
				
			||||||
 | 
						rc = osmo_gsup_conn_send(subscr_conn, msg);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "Failed to send GSUP message '%s' (rc=%d)\n",
 | 
				
			||||||
 | 
							     osmo_gsup_message_type_name(gsup->message_type), rc);
 | 
				
			||||||
 | 
							gsup_prepare_sm_error(&rsp_msg, gsup);
 | 
				
			||||||
 | 
							sm_rp_cause = GSM411_RP_CAUSE_MO_TEMP_FAIL;
 | 
				
			||||||
 | 
							rsp_msg.sm_rp_cause = &sm_rp_cause;
 | 
				
			||||||
 | 
							msg = NULL; /* free()d by osmo_gsup_conn_send() */
 | 
				
			||||||
 | 
							goto exit_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit_error:
 | 
				
			||||||
 | 
						gsup_conn_enc_send(conn, &rsp_msg);
 | 
				
			||||||
 | 
						if (msg != NULL)
 | 
				
			||||||
 | 
							talloc_free(msg);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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;
 | 
											ss->u.iuse = rt->u.iuse;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					if (hlr->euse_default) {
 | 
										if (hlr->ussd_euse_default) {
 | 
				
			||||||
						ss->is_external = true;
 | 
											ss->is_external = true;
 | 
				
			||||||
						ss->u.euse = hlr->euse_default;
 | 
											ss->u.euse = hlr->ussd_euse_default;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										228
									
								
								src/hlr_vty.c
									
									
									
									
									
								
							
							
						
						
									
										228
									
								
								src/hlr_vty.c
									
									
									
									
									
								
							@@ -38,6 +38,7 @@
 | 
				
			|||||||
#include <osmocom/hlr/hlr_vty.h>
 | 
					#include <osmocom/hlr/hlr_vty.h>
 | 
				
			||||||
#include <osmocom/hlr/hlr_vty_subscr.h>
 | 
					#include <osmocom/hlr/hlr_vty_subscr.h>
 | 
				
			||||||
#include <osmocom/hlr/hlr_ussd.h>
 | 
					#include <osmocom/hlr/hlr_ussd.h>
 | 
				
			||||||
 | 
					#include <osmocom/hlr/hlr_sms.h>
 | 
				
			||||||
#include <osmocom/hlr/gsup_server.h>
 | 
					#include <osmocom/hlr/gsup_server.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_node hlr_node = {
 | 
					struct cmd_node hlr_node = {
 | 
				
			||||||
@@ -150,8 +151,6 @@ DEFUN(cfg_hlr_gsup_bind_ip,
 | 
				
			|||||||
 * USSD Entity
 | 
					 * USSD Entity
 | 
				
			||||||
 ***********************************************************************/
 | 
					 ***********************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/hlr/hlr_ussd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define USSD_STR "USSD Configuration\n"
 | 
					#define USSD_STR "USSD Configuration\n"
 | 
				
			||||||
#define UROUTE_STR "Routing Configuration\n"
 | 
					#define UROUTE_STR "Routing Configuration\n"
 | 
				
			||||||
#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
 | 
					#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
 | 
				
			||||||
@@ -161,8 +160,8 @@ DEFUN(cfg_hlr_gsup_bind_ip,
 | 
				
			|||||||
		"Respond with subscribers' own MSISDN\n" \
 | 
							"Respond with subscribers' own MSISDN\n" \
 | 
				
			||||||
		"Respond with subscribers' own IMSI\n"
 | 
							"Respond with subscribers' own IMSI\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define EXT_STR "External USSD Handler\n" \
 | 
					#define EXT_STR "External USSD/SMS Handler\n" \
 | 
				
			||||||
		"Name of External USSD Handler (IPA CCM ID)\n"
 | 
							"Name of External USSD/SMS Handler (IPA CCM ID)\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_ussd_route_pfx_int, cfg_ussd_route_pfx_int_cmd,
 | 
					DEFUN(cfg_ussd_route_pfx_int, cfg_ussd_route_pfx_int_cmd,
 | 
				
			||||||
	"ussd route prefix PREFIX internal " INT_CHOICE,
 | 
						"ussd route prefix PREFIX internal " INT_CHOICE,
 | 
				
			||||||
@@ -225,11 +224,11 @@ DEFUN(cfg_ussd_defaultroute, cfg_ussd_defaultroute_cmd,
 | 
				
			|||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_hlr->euse_default != euse) {
 | 
						if (g_hlr->ussd_euse_default != euse) {
 | 
				
			||||||
		vty_out(vty, "Switching default route from %s to %s%s",
 | 
							vty_out(vty, "Switching default USSD route from '%s' to '%s'%s",
 | 
				
			||||||
			g_hlr->euse_default ? g_hlr->euse_default->name : "<none>",
 | 
								g_hlr->ussd_euse_default ? g_hlr->ussd_euse_default->name : "<none>",
 | 
				
			||||||
			euse->name, VTY_NEWLINE);
 | 
								euse->name, VTY_NEWLINE);
 | 
				
			||||||
		g_hlr->euse_default = euse;
 | 
							g_hlr->ussd_euse_default = euse;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -239,7 +238,164 @@ DEFUN(cfg_ussd_no_defaultroute, cfg_ussd_no_defaultroute_cmd,
 | 
				
			|||||||
	"no ussd default-route",
 | 
						"no ussd default-route",
 | 
				
			||||||
	NO_STR USSD_STR "Remove the default-route for all USSD to unknown destinations\n")
 | 
						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;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -290,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);
 | 
							vty_out(vty, "%% Cannot remove non-existant EUSE %s%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							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);
 | 
							vty_out(vty, "%% Cannot remove EUSE %s, it is the default route%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -303,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);
 | 
						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)
 | 
					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_euse *euse;
 | 
				
			||||||
	struct hlr_ussd_route *rt;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(euse, &g_hlr->euse_list, list)
 | 
						llist_for_each_entry(euse, &g_hlr->euse_list, list)
 | 
				
			||||||
		dump_one_euse(vty, euse);
 | 
							dump_one_euse(vty, euse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(rt, &g_hlr->ussd_routes, list) {
 | 
						llist_for_each_entry(ussd_rt, &g_hlr->ussd_routes, list) {
 | 
				
			||||||
		vty_out(vty, " ussd route prefix %s %s %s%s", rt->prefix,
 | 
							vty_out(vty, " ussd route prefix %s %s %s%s", ussd_rt->prefix,
 | 
				
			||||||
			rt->is_external ? "external" : "internal",
 | 
								ussd_rt->is_external ? "external" : "internal",
 | 
				
			||||||
			rt->is_external ? rt->u.euse->name : rt->u.iuse->name,
 | 
								ussd_rt->is_external ? ussd_rt->u.euse->name : ussd_rt->u.iuse->name,
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_hlr->euse_default)
 | 
						llist_for_each_entry(sms_rt, &g_hlr->sms_routes, list) {
 | 
				
			||||||
		vty_out(vty, " ussd default-route external %s%s", g_hlr->euse_default->name, VTY_NEWLINE);
 | 
							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)
 | 
						if (g_hlr->ncss_guard_timeout != NCSS_GUARD_TIMEOUT_DEFAULT)
 | 
				
			||||||
		vty_out(vty, " ncss-guard-timeout %i%s",
 | 
							vty_out(vty, " ncss-guard-timeout %i%s",
 | 
				
			||||||
@@ -455,6 +641,14 @@ void hlr_vty_init(void)
 | 
				
			|||||||
	install_element(HLR_NODE, &cfg_ussd_no_route_pfx_cmd);
 | 
						install_element(HLR_NODE, &cfg_ussd_no_route_pfx_cmd);
 | 
				
			||||||
	install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
 | 
						install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
 | 
				
			||||||
	install_element(HLR_NODE, &cfg_ussd_no_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_ncss_guard_timeout_cmd);
 | 
				
			||||||
	install_element(HLR_NODE, &cfg_store_imei_cmd);
 | 
						install_element(HLR_NODE, &cfg_store_imei_cmd);
 | 
				
			||||||
	install_element(HLR_NODE, &cfg_no_store_imei_cmd);
 | 
						install_element(HLR_NODE, &cfg_no_store_imei_cmd);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,6 +107,8 @@ OsmoHLR(config-hlr)# list
 | 
				
			|||||||
  database PATH
 | 
					  database PATH
 | 
				
			||||||
  euse NAME
 | 
					  euse NAME
 | 
				
			||||||
  no 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 internal (own-msisdn|own-imsi)
 | 
				
			||||||
  ussd route prefix PREFIX external EUSE
 | 
					  ussd route prefix PREFIX external EUSE
 | 
				
			||||||
  no ussd route prefix PREFIX
 | 
					  no ussd route prefix PREFIX
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user