From 99532b00e0ae517f266938f75dadcedc84146aaf Mon Sep 17 00:00:00 2001 From: Alexander Chemeris Date: Tue, 3 Mar 2020 18:15:15 +0300 Subject: WIP: gb: Standard-compliant Static Gb over IP The current implementation of the Gb over IP in Osmocom is derived from the ip.access implementation of it, which is a "weird combination of Gb over FR and Gb over IP" in that it runs over UDP/IP but uses procedures like NS-RESET and NS-BLOCK which are only specified for Gb over FR. This makes it impossible to use OsmoPCU and OsmoGbProxy with standard SGSNs like from Huawei in "Static IP-GB" mode (i.e. without SNS procedure). This patch is a hack to remove NS-RESET procedure and use NS-ALIVE to setup an NS link and keep it open. One could argue that SNS is a much better way and should be used instead of the old "static" config but in pratical installations you do ant to use osmo-gb-proxy to aggregate multiple links and it doesn't support SNS yet. So using this hack is the easiest way to get multiple OsmoPCU's to connect to a standrd-compliant SGSN. NOTE: This patch is a quick hack and lacks any unit-testing or configuration. Change-Id: I1b1b28913488a40e4fceb65e646c3d89e8a431a4 --- src/gb/gprs_ns.c | 55 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index ac39e4a6..1391f506 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -106,6 +106,8 @@ } \ } while (0) +static int gbip_dialect_ipaccess = 0; + static const struct tlv_definition ns_att_tlvdef = { .def = { [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, @@ -220,7 +222,7 @@ static inline void ns_set_state_with_log(struct gprs_nsvc *nsvc, uint32_t state, { uint32_t old_state = is_remote ? nsvc->remote_state : nsvc->state; - LOGPSRC(DNS, LOGL_DEBUG, file, line, "NSEI %d (NS-VCI=%u) setting %sstate [%s,%s,%s] -> [%s,%s,%s]\n", + LOGPSRC(DNS, LOGL_DEBUG, file, line, "NSEI=%d (NS-VCI=%u) setting %sstate [%s,%s,%s] -> [%s,%s,%s]\n", nsvc->nsei, nsvc->nsvci, is_remote ? "remote " : "", NS_DESC_A(old_state), NS_DESC_B(old_state), NS_DESC_R(old_state), NS_DESC_A(state), NS_DESC_B(state), NS_DESC_R(state)); @@ -326,8 +328,8 @@ struct gprs_nsvc *gprs_nsvc_create2(struct gprs_ns_inst *nsi, uint16_t nsvci, nsvc->nsvci = nsvci; nsvc->nsvci_is_valid = 1; /* before RESET procedure: BLOCKED and DEAD */ - if (nsi->bss_sns_fi) - ns_set_state(nsvc, 0); + if (nsi->bss_sns_fi || gbip_dialect_ipaccess) + ns_set_state(nsvc, 0); /* DEAD */ else ns_set_state(nsvc, NSE_S_BLOCKED); nsvc->nsi = nsi; @@ -792,7 +794,7 @@ static void gprs_ns_timer_cb(void *data) nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) { /* mark as dead (and blocked unless IP-SNS) */ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_DEAD]); - if (!nsvc->nsi->bss_sns_fi) { + if (gbip_dialect_ipaccess && !nsvc->nsi->bss_sns_fi) { ns_set_state(nsvc, NSE_S_BLOCKED); rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); } else @@ -803,7 +805,7 @@ static void gprs_ns_timer_cb(void *data) nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]); ns_osmo_signal_dispatch(nsvc, S_NS_ALIVE_EXP, 0); /* FIXME: should we send this signal in case of SNS? */ - if (!nsvc->nsi->bss_sns_fi) + if (gbip_dialect_ipaccess && !nsvc->nsi->bss_sns_fi) ns_osmo_signal_dispatch(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } @@ -1755,13 +1757,27 @@ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, * NS-ALIVE out of the blue, we might have been re-started * and should send a NS-RESET to make sure everything recovers * fine. */ + LOGP(DNS, LOGL_DEBUG, "NSEI=%u Rx ALIVE (NSVCI=%u) in state [%s,%s,%s]\n", + (*nsvc)->nsei, (*nsvc)->nsvci, NS_DESC_A((*nsvc)->state), NS_DESC_B((*nsvc)->state), NS_DESC_R((*nsvc)->state)); + if (!gbip_dialect_ipaccess && !((*nsvc)->state & NSE_S_ALIVE)) { + ns_set_remote_state(*nsvc, NSE_S_ALIVE); + ns_set_state(*nsvc, NSE_S_ALIVE); + ns_osmo_signal_dispatch(*nsvc, S_NS_UNBLOCK, 0); + } if ((*nsvc)->state == NSE_S_BLOCKED) rc = gprs_nsvc_reset((*nsvc), NS_CAUSE_PDU_INCOMP_PSTATE); else if (!((*nsvc)->state & NSE_S_RESET)) rc = gprs_ns_tx_alive_ack(*nsvc); break; case NS_PDUT_ALIVE_ACK: - ns_mark_alive(*nsvc); + LOGP(DNS, LOGL_DEBUG, "NSEI=%u Rx ALIVE ACK (NSVCI=%u) in state [%s,%s,%s]\n", + (*nsvc)->nsei, (*nsvc)->nsvci, NS_DESC_A((*nsvc)->state), NS_DESC_B((*nsvc)->state), NS_DESC_R((*nsvc)->state)); + if (!gbip_dialect_ipaccess && !((*nsvc)->state & NSE_S_ALIVE)) { + ns_set_remote_state(*nsvc, NSE_S_ALIVE); + ns_set_state(*nsvc, NSE_S_ALIVE); + ns_osmo_signal_dispatch(*nsvc, S_NS_UNBLOCK, 0); + } else + ns_mark_alive(*nsvc); if ((*nsvc)->timer_mode == NSVC_TIMER_TNS_ALIVE) osmo_stat_item_set((*nsvc)->statg->items[NS_STAT_ALIVE_DELAY], nsvc_timer_elapsed_ms(*nsvc)); @@ -2112,17 +2128,26 @@ int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) LOGP(DNS, LOGL_INFO, "NSEI=%u RESET procedure based on API request\n", nsvc->nsei); - /* Mark NS-VC locally as blocked and dead */ - ns_set_state(nsvc, NSE_S_BLOCKED | NSE_S_RESET); + if (gbip_dialect_ipaccess) { + /* Mark NS-VC locally as blocked and dead */ + ns_set_state(nsvc, NSE_S_BLOCKED | NSE_S_RESET); - /* Send NS-RESET PDU */ - rc = gprs_ns_tx_reset(nsvc, cause); - if (rc < 0) { - LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", - nsvc->nsei); + /* Send NS-RESET PDU */ + rc = gprs_ns_tx_reset(nsvc, cause); + if (rc < 0) { + LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", + nsvc->nsei); + } + /* Start Tns-reset */ + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); + } else { + /* Mark NS-VC as unblocked and dead */ + ns_set_state(nsvc, 0); /* DEAD */ + ns_set_remote_state(nsvc, 0); /* DEAD */ + rate_ctr_inc(&(nsvc)->ctrg->ctr[NS_CTR_DEAD]); + /* Initiate TEST proc.: Send ALIVE and start timer */ + gprs_nsvc_start_test(nsvc); } - /* Start Tns-reset */ - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); return rc; } -- cgit v1.2.3