summaryrefslogtreecommitdiffstats
path: root/src/gb
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2019-03-16 14:38:19 +0100
committerHarald Welte <laforge@gnumonks.org>2019-03-16 18:34:52 +0100
commit94c9b449cfbafb610c1679cf733394f2df58f178 (patch)
treecf67870de3940d12bd3a5c13c63b9a1c022f5f2f /src/gb
parent1e072cca4ed8fd827e6992db82186102c79903f0 (diff)
gprs_ns: Don't use initial IP/port for anything but SNS
Section 6.2.1 of 3GPP TS 48.016 states: > A pre-configured endpoint shall not be used for NSE data or signalling > traffic (with the exception of Size and Configuration procedures) unless > it is configured by the SGSN using the auto-configuration procedures. However, in the current SNS implementation, the initial IP/Port over which we perform the SNS-SIZE + SNS-CONFIG are treated as one of the normal NS-VCs. Specifically, we also perform the NS-ALIVE procedure on it, which is clearly wrong. Let's explicitly create the "initial" NS-VC with data and signalling weight of 0, and ensure we never start the alive timer or send any non-SNS PDUs on this connection as long as SNS was not used to change either of the two weights to non-zero. While at it, also safeguard against processing any incoming non-SNS messages on such a all-zero-weight connection. Change-Id: I16a91a07e5914d123b2ea2f8413b94e7cd518628 Closes: OS#3844
Diffstat (limited to 'src/gb')
-rw-r--r--src/gb/gprs_ns.c57
1 files changed, 55 insertions, 2 deletions
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c
index 93c219c6..8c3b0fa2 100644
--- a/src/gb/gprs_ns.c
+++ b/src/gb/gprs_ns.c
@@ -195,6 +195,14 @@ const struct value_string gprs_ns_signal_ns_names[] = {
LOGP(DNS, LOGL_ERROR, "TX failed (%d) to peer %s\n", \
rc, gprs_ns_ll_str(nsvc));
+static bool nsvc_is_not_used(const struct gprs_nsvc *nsvc)
+{
+ if (nsvc->data_weight == 0 && nsvc->sig_weight == 0)
+ return true;
+ else
+ return false;
+}
+
struct msgb *gprs_ns_msgb_alloc(void)
{
struct msgb *msg = msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM,
@@ -444,12 +452,40 @@ const char *gprs_ns_cause_str(enum ns_cause cause)
static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg);
extern int grps_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg);
+static bool ns_is_sns(uint8_t pdu_type)
+{
+ switch (pdu_type) {
+ case SNS_PDUT_CONFIG:
+ case SNS_PDUT_ACK:
+ case SNS_PDUT_ADD:
+ case SNS_PDUT_CHANGE_WEIGHT:
+ case SNS_PDUT_DELETE:
+ case SNS_PDUT_CONFIG_ACK:
+ case SNS_PDUT_SIZE:
+ case SNS_PDUT_SIZE_ACK:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg)
{
+ struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
int ret;
log_set_context(LOG_CTX_GB_NSVC, nsvc);
+ /* A pre-configured endpoint shall not be used for NSE data or signalling
+ * traffic (with the exception of Size and Configuration procedures) unless it
+ * is configured by the SGSN using the auto-configuration procedures. */
+ if (nsvc_is_not_used(nsvc) && !ns_is_sns(nsh->pdu_type) && nsh->pdu_type != NS_PDUT_STATUS) {
+ LOGP(DNS, LOGL_NOTICE, "Not transmitting %s on unused/pre-configured endpoint\n",
+ get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
/* Increment number of Uplink bytes */
rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]);
rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], msgb_l2len(msg));
@@ -1690,6 +1726,13 @@ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg,
rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_PKTS_IN]);
rate_ctr_add(&(*nsvc)->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg));
+ if (nsvc_is_not_used(*nsvc) && !ns_is_sns(nsh->pdu_type) && nsh->pdu_type != NS_PDUT_STATUS) {
+ LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx %s on unused/pre-configured endpoint, discarding\n",
+ (*nsvc)->nsei, get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
+ gprs_ns_tx_status(*nsvc, NS_CAUSE_PROTO_ERR_UNSPEC, 0, msg);
+ return 0;
+ }
+
switch (nsh->pdu_type) {
case NS_PDUT_ALIVE:
/* If we're dead and blocked and suddenly receive a
@@ -2116,8 +2159,14 @@ struct gprs_nsvc *gprs_ns_nsip_connect_sns(struct gprs_ns_inst *nsi,
* require some massive code and API changes compared to existing libosmogb,
* so let's keep the old logic. */
nsvc = gprs_nsvc_by_rem_addr(nsi, dest);
- if (!nsvc)
- nsvc = gprs_nsvc_create(nsi, nsvci);
+ if (!nsvc) {
+ /* create NSVC with 0 data + signalling weight. This is illegal in SNS
+ * and can hence only be created locally and serves as indication that
+ * this NS-VC shall not be used for anything except SNS _unless_ it is
+ * modified via SNS-{CONFIG,CHANGEWEIGHT,ADD} to become part of the
+ * active NS-VCs */
+ nsvc = gprs_nsvc_create2(nsi, nsvci, 0, 0);
+ }
nsvc->ip.bts_addr = *dest;
nsvc->nsei = nsei;
nsvc->remote_end_is_sgsn = 1;
@@ -2161,6 +2210,10 @@ char *gprs_nsvc_state_append(char *s, struct gprs_nsvc *nsvc)
/*! Start the ALIVE timer procedure in all NS-VCs part of this NS Instance */
void gprs_nsvc_start_test(struct gprs_nsvc *nsvc)
{
+ /* skip the initial NS-VC unless it has explicitly been configured
+ * via SNS-CONFIG from the SGSN */
+ if (nsvc_is_not_used(nsvc))
+ return;
gprs_ns_tx_alive(nsvc);
nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST);
}