neels has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-hnbgw/+/28230 )
Change subject: add option to send SCCP CR without payload
......................................................................
add option to send SCCP CR without payload
It is reported that a third-party SGSN is rejecting SCCP CR when the
SCCP message part exceeds a certain length. The solution is to first
send an SCCP CR without payload, and send the payload in a DT later.
Add config option
hnbgw
sccp cr max-payload-len <0-999999>
If the RANAP payload surpasses the given length, osmo-hnbgw will first
send an SCCP CR without payload, cache the RANAP payload, and put that
in an SCCP DT once the SCCP CC is received.
The original idea was to limit the size of the entire SCCP part of the
message, but I'm currently not sure how to determine that without
copying much of the osmo_sccp code. I figured using a limit on the RANAP
payload is sufficient. To avoid the error with above third-party SGSN,
the easy solution is to set max-payload-len to 0, so that we always get
a separate SCCP CR without payload.
Related: SYS#5968
Related: I827e081eaacfb8e76684ed1560603e6c8f896c38 (osmo-ttcn3-hacks)
Change-Id: If0c5c0a76e5230bf22871f527dcb2dbdf34d7328
---
M include/osmocom/hnbgw/context_map.h
M include/osmocom/hnbgw/hnbgw.h
M include/osmocom/hnbgw/hnbgw_rua.h
M src/osmo-hnbgw/context_map.c
M src/osmo-hnbgw/hnbgw.c
M src/osmo-hnbgw/hnbgw_cn.c
M src/osmo-hnbgw/hnbgw_rua.c
M src/osmo-hnbgw/hnbgw_vty.c
8 files changed, 122 insertions(+), 14 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-hnbgw refs/changes/30/28230/1
diff --git a/include/osmocom/hnbgw/context_map.h b/include/osmocom/hnbgw/context_map.h
index 6910fe8..baa9166 100644
--- a/include/osmocom/hnbgw/context_map.h
+++ b/include/osmocom/hnbgw/context_map.h
@@ -2,6 +2,9 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/rua/RUA_CN-DomainIndicator.h>
+
+struct msgb;
enum hnbgw_context_map_state {
MAP_S_NULL,
@@ -33,6 +36,10 @@
bool is_ps;
/* SCCP User SAP connection ID */
uint32_t scu_conn_id;
+ /* Pending data to be sent: when we send an "empty" SCCP CR first, the initial
RANAP message will be sent in a
+ * separate DT once the CR is confirmed. This caches the initial RANAP message. */
+ struct msgb *cached_msg;
+ RUA_CN_DomainIndicator_t cached_domain_indicator;
enum hnbgw_context_map_state state;
@@ -49,6 +56,8 @@
struct hnbgw_context_map *
context_map_by_cn(struct hnbgw_cnlink *cn, uint32_t scu_conn_id);
+int context_map_send_cached_msg(struct hnbgw_context_map *map);
+
void context_map_deactivate(struct hnbgw_context_map *map);
int context_map_init(struct hnb_gw *gw);
diff --git a/include/osmocom/hnbgw/hnbgw.h b/include/osmocom/hnbgw/hnbgw.h
index 9a46301..76c5b84 100644
--- a/include/osmocom/hnbgw/hnbgw.h
+++ b/include/osmocom/hnbgw/hnbgw.h
@@ -134,6 +134,7 @@
bool hnbap_allow_tmsi;
/*! print hnb-id (true) or MCC-MNC-LAC-RAC-SAC (false) in logs */
bool log_prefix_hnb_id;
+ unsigned int max_sccp_cr_payload_len;
struct mgcp_client_conf *mgcp_client;
} config;
/*! SCTP listen socket for incoming connections */
@@ -175,3 +176,5 @@
void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx);
int hnbgw_vty_go_parent(struct vty *vty);
+
+bool hnbgw_requires_empty_sccp_cr(struct hnb_gw *gw, unsigned int ranap_msg_len);
diff --git a/include/osmocom/hnbgw/hnbgw_rua.h b/include/osmocom/hnbgw/hnbgw_rua.h
index 4b65115..fa33d6b 100644
--- a/include/osmocom/hnbgw/hnbgw_rua.h
+++ b/include/osmocom/hnbgw/hnbgw_rua.h
@@ -2,6 +2,7 @@
#include <osmocom/hnbgw/hnbgw.h>
#include <osmocom/rua/RUA_Cause.h>
+#include <osmocom/rua/RUA_CN-DomainIndicator.h>
int hnbgw_rua_rx(struct hnb_context *hnb, struct msgb *msg);
int hnbgw_rua_init(void);
@@ -11,3 +12,9 @@
const uint8_t *data, unsigned int len);
int rua_tx_disc(struct hnb_context *hnb, int is_ps, uint32_t context_id,
const RUA_Cause_t *cause, const uint8_t *data, unsigned int len);
+
+int rua_to_scu(struct hnb_context *hnb,
+ RUA_CN_DomainIndicator_t cN_DomainIndicator,
+ enum osmo_scu_prim_type type,
+ uint32_t context_id, uint32_t cause,
+ const uint8_t *data, unsigned int len);
diff --git a/src/osmo-hnbgw/context_map.c b/src/osmo-hnbgw/context_map.c
index 18f71ce..505c0c7 100644
--- a/src/osmo-hnbgw/context_map.c
+++ b/src/osmo-hnbgw/context_map.c
@@ -25,6 +25,7 @@
#include <osmocom/core/timer.h>
#include <osmocom/hnbgw/hnbgw.h>
+#include <osmocom/hnbgw/hnbgw_rua.h>
#include <osmocom/hnbgw/context_map.h>
#include <osmocom/hnbgw/mgw_fsm.h>
@@ -130,6 +131,18 @@
return NULL;
}
+int context_map_send_cached_msg(struct hnbgw_context_map *map)
+{
+ int rc;
+ if (!map || !map->cached_msg)
+ return 0;
+ rc = rua_to_scu(map->hnb_ctx, map->cached_domain_indicator, OSMO_SCU_PRIM_N_DATA,
+ map->rua_ctx_id, 0, msgb_data(map->cached_msg),
msgb_length(map->cached_msg));
+ msgb_free(map->cached_msg);
+ map->cached_msg = NULL;
+ return rc;
+}
+
void context_map_deactivate(struct hnbgw_context_map *map)
{
/* set the state to reserved. We still show up in the list and
diff --git a/src/osmo-hnbgw/hnbgw.c b/src/osmo-hnbgw/hnbgw.c
index 96c7ad1..04ca34c 100644
--- a/src/osmo-hnbgw/hnbgw.c
+++ b/src/osmo-hnbgw/hnbgw.c
@@ -88,6 +88,10 @@
gw->config.iuh_local_port = IUH_DEFAULT_SCTP_PORT;
gw->config.log_prefix_hnb_id = true;
+ /* No limit by default, always include the initial RANAP message in the SCCP CR towards
the CN.
+ * 999999 is the maximum value in hnbgw_vty.c */
+ gw->config.max_sccp_cr_payload_len = 999999;
+
gw->next_ue_ctx_id = 23;
INIT_LLIST_HEAD(&gw->hnb_list);
INIT_LLIST_HEAD(&gw->ue_list);
@@ -343,6 +347,11 @@
talloc_free(ctx);
}
+bool hnbgw_requires_empty_sccp_cr(struct hnb_gw *gw, unsigned int ranap_msg_len)
+{
+ return ranap_msg_len > gw->config.max_sccp_cr_payload_len;
+}
+
/*! call-back when the listen FD has something to read */
static int accept_cb(struct osmo_stream_srv_link *srv, int fd)
{
diff --git a/src/osmo-hnbgw/hnbgw_cn.c b/src/osmo-hnbgw/hnbgw_cn.c
index 9c06497..9c95ed5 100644
--- a/src/osmo-hnbgw/hnbgw_cn.c
+++ b/src/osmo-hnbgw/hnbgw_cn.c
@@ -339,6 +339,10 @@
/* Nothing needs to happen for RUA, RUA towards the HNB doesn't seem to know any
confirmations to its CONNECT
* operation. */
+ /* If our initial SCCP CR was sent without data payload, then the initial RANAP message
is cached and waiting to
+ * be sent as soon as the SCCP connection is confirmed. See if that is the case, send
cached data. */
+ context_map_send_cached_msg(context_map_by_cn(cnlink, param->conn_id));
+
return 0;
}
diff --git a/src/osmo-hnbgw/hnbgw_rua.c b/src/osmo-hnbgw/hnbgw_rua.c
index 1943ac0..c25eeb5 100644
--- a/src/osmo-hnbgw/hnbgw_rua.c
+++ b/src/osmo-hnbgw/hnbgw_rua.c
@@ -177,11 +177,11 @@
/* forward a RUA message to the SCCP User API to SCCP */
-static int rua_to_scu(struct hnb_context *hnb,
- RUA_CN_DomainIndicator_t cN_DomainIndicator,
- enum osmo_scu_prim_type type,
- uint32_t context_id, uint32_t cause,
- const uint8_t *data, unsigned int len)
+int rua_to_scu(struct hnb_context *hnb,
+ RUA_CN_DomainIndicator_t cN_DomainIndicator,
+ enum osmo_scu_prim_type type,
+ uint32_t context_id, uint32_t cause,
+ const uint8_t *data, unsigned int len)
{
struct msgb *msg;
struct osmo_scu_prim *prim;
@@ -225,9 +225,9 @@
default:
map = context_map_alloc_by_hnb(hnb, context_id, is_ps, cn);
OSMO_ASSERT(map);
- LOGHNB(hnb, DRUA, LOGL_DEBUG, "rua_to_scu() %s to %s, rua_ctx_id %u scu_conn_id
%u\n",
+ LOGHNB(hnb, DRUA, LOGL_DEBUG, "rua_to_scu() %s to %s, rua_ctx_id %u scu_conn_id %u
data-len %u\n",
cn_domain_indicator_to_str(cN_DomainIndicator),
osmo_sccp_addr_dump(remote_addr),
- map->rua_ctx_id, map->scu_conn_id);
+ map->rua_ctx_id, map->scu_conn_id, len);
}
/* add primitive header */
@@ -271,7 +271,7 @@
}
/* Intercept RAB Assignment Response, inform MGW FSM. */
- if (map && !map->is_ps && !release_context_map) {
+ if (data && len && map && !map->is_ps &&
!release_context_map) {
message = talloc_zero(map, ranap_message);
rc = ranap_cn_rx_co_decode(map, message, msgb_l2(prim->oph.msg),
msgb_l2len(prim->oph.msg));
@@ -363,21 +363,69 @@
struct hnb_context *hnb = msg->dst;
uint32_t context_id;
int rc;
+ const uint8_t *data;
+ unsigned int data_len;
rc = rua_decode_connecties(&ies, in);
if (rc < 0)
return rc;
context_id = asn1bitstr_to_u24(&ies.context_ID);
+ data = ies.ranaP_Message.buf;
+ data_len = ies.ranaP_Message.size;
- LOGHNB(hnb, DRUA, LOGL_DEBUG, "RUA %s Connect.req(ctx=0x%x, %s)\n",
- cn_domain_indicator_to_str(ies.cN_DomainIndicator), context_id,
- ies.establishment_Cause == RUA_Establishment_Cause_emergency_call ?
"emergency" : "normal");
+ LOGHNB(hnb, DRUA, LOGL_DEBUG, "RUA %s Connect.req(ctx=0x%x, %s,
RANAP.size=%u)\n",
+ cn_domain_indicator_to_str(ies.cN_DomainIndicator), context_id,
+ ies.establishment_Cause == RUA_Establishment_Cause_emergency_call ?
"emergency" : "normal",
+ data_len);
+
+ if (hnbgw_requires_empty_sccp_cr(hnb->gw, data_len)) {
+ /* Do not include data in the SCCP CR, to avoid hitting a message size limit at the
remote end that may
+ * lead to rejection. */
+ bool is_ps;
+ struct osmo_sccp_addr *remote_addr;
+ struct hnbgw_context_map *map;
+
+ switch (ies.cN_DomainIndicator) {
+ case RUA_CN_DomainIndicator_cs_domain:
+ remote_addr = &hnb->gw->sccp.iucs_remote_addr;
+ is_ps = false;
+ break;
+ case RUA_CN_DomainIndicator_ps_domain:
+ remote_addr = &hnb->gw->sccp.iups_remote_addr;
+ is_ps = true;
+ break;
+ default:
+ LOGHNB(hnb, DRUA, LOGL_ERROR, "Unsupported Domain %ld\n",
ies.cN_DomainIndicator);
+ rua_free_connecties(&ies);
+ return -1;
+ }
+
+ if (!hnb->gw->sccp.cnlink) {
+ LOGHNB(hnb, DRUA, LOGL_NOTICE, "CN=NULL, discarding message\n");
+ rua_free_connecties(&ies);
+ return 0;
+ }
+
+ map = context_map_alloc_by_hnb(hnb, context_id, is_ps, hnb->gw->sccp.cnlink);
+ OSMO_ASSERT(map);
+ LOGHNB(hnb, DRUA, LOGL_DEBUG, "rua_rx_init_connect() %s to %s, rua_ctx_id %u
scu_conn_id %u;"
+ " Sending SCCP CR without payload, caching %u octets\n",
+ cn_domain_indicator_to_str(ies.cN_DomainIndicator),
osmo_sccp_addr_dump(remote_addr),
+ map->rua_ctx_id, map->scu_conn_id, data_len);
+
+ map->cached_domain_indicator = ies.cN_DomainIndicator;
+ map->cached_msg = msgb_alloc_c(map, data_len, "map.cached_msg");
+ OSMO_ASSERT(map->cached_msg);
+ memcpy(msgb_put(map->cached_msg, data_len), data, data_len);
+
+ /* Data is cached for after CR is confirmed, send SCCP CR but omit payload. */
+ data = NULL;
+ data_len = 0;
+ }
rc = rua_to_scu(hnb, ies.cN_DomainIndicator, OSMO_SCU_PRIM_N_CONNECT,
- context_id, 0, ies.ranaP_Message.buf,
- ies.ranaP_Message.size);
-
+ context_id, 0, data, data_len);
rua_free_connecties(&ies);
return rc;
diff --git a/src/osmo-hnbgw/hnbgw_vty.c b/src/osmo-hnbgw/hnbgw_vty.c
index d064b7d..c263ab3 100644
--- a/src/osmo-hnbgw/hnbgw_vty.c
+++ b/src/osmo-hnbgw/hnbgw_vty.c
@@ -330,6 +330,18 @@
return CMD_SUCCESS;
}
+DEFUN(cfg_hnbgw_max_sccp_cr_payload_len, cfg_hnbgw_max_sccp_cr_payload_len_cmd,
+ "sccp cr max-payload-len <0-999999>",
+ "Configure SCCP behavior\n"
+ "Configure SCCP Connection Request\n"
+ "Set an upper bound for payload data length included directly in the CR. If an
initial RUA message has a"
+ " RANAP payload larger than this value (octets), send an SCCP CR without data,
followed by an SCCP DT."
+ " This may be necessary if the remote component has a size limit on valid SCCP
CR messages.\n")
+{
+ g_hnb_gw->config.max_sccp_cr_payload_len = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_hnbgw_iucs_remote_addr,
cfg_hnbgw_iucs_remote_addr_cmd,
"remote-addr NAME",
@@ -355,6 +367,8 @@
vty_out(vty, "hnbgw%s", VTY_NEWLINE);
vty_out(vty, " log-prefix %s%s", g_hnb_gw->config.log_prefix_hnb_id ?
"hnb-id" : "umts-cell-id",
VTY_NEWLINE);
+ if (g_hnb_gw->config.max_sccp_cr_payload_len != 999999)
+ vty_out(vty, " sccp cr max-payload-len %u%s",
g_hnb_gw->config.max_sccp_cr_payload_len, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -421,6 +435,7 @@
install_element(HNBGW_NODE, &cfg_hnbgw_rnc_id_cmd);
install_element(HNBGW_NODE, &cfg_hnbgw_log_prefix_cmd);
+ install_element(HNBGW_NODE, &cfg_hnbgw_max_sccp_cr_payload_len_cmd);
install_element(HNBGW_NODE, &cfg_hnbgw_iuh_cmd);
install_node(&iuh_node, config_write_hnbgw_iuh);
--
To view, visit
https://gerrit.osmocom.org/c/osmo-hnbgw/+/28230
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: If0c5c0a76e5230bf22871f527dcb2dbdf34d7328
Gerrit-Change-Number: 28230
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange