From 057122e466f2420244502f9b069df8f51f8363fd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 6 Jun 2020 22:04:20 +0200 Subject: NS: Optionally disable NS-{RESET,BLOCK,UNBLOCK} when using UDP/IP 3GPP TS 48.016 is quite clear in that no NS-{RESET,BLOCK,UNBLOCK} procedures shall be used over an IP based transport. They are only for use in Frame Relay based transport. However, as libosmogb was first developed against ip.access nanoBTS, and their Gb implementation mandates those procedures, we unconditionally implemented those procedures back then. Let's give the user the option of disabling this behavior to become more spec compliant (and interoperate with more other vendors out there). Change-Id: Ic4eba1b4dcbeac00f5879db295e0a9f1a50f71d8 --- include/osmocom/gprs/gprs_ns.h | 2 ++ src/gb/gprs_ns.c | 17 +++++++++--- src/gb/gprs_ns_vty.c | 62 ++++++++++++++++++++++++++++-------------- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/include/osmocom/gprs/gprs_ns.h b/include/osmocom/gprs/gprs_ns.h index 02faa506..94d30368 100644 --- a/include/osmocom/gprs/gprs_ns.h +++ b/include/osmocom/gprs/gprs_ns.h @@ -97,6 +97,8 @@ struct gprs_ns_inst { uint32_t remote_ip; uint16_t remote_port; int dscp; + /*! IPA compatibility: NS-RESET/BLOCK/UNBLOCK even on IP-SNS */ + bool use_reset_block_unblock; } nsip; /*! NS-over-FR-over-GRE-over-IP specific bits */ struct { diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index 4e584adc..f1b36f44 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -327,7 +327,7 @@ 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) + if (nsi->bss_sns_fi || !nsi->nsip.use_reset_block_unblock) ns_set_state(nsvc, 0); else ns_set_state(nsvc, NSE_S_BLOCKED); @@ -793,7 +793,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 (!nsvc->nsi->bss_sns_fi && nsvc->nsi->nsip.use_reset_block_unblock) { ns_set_state(nsvc, NSE_S_BLOCKED); rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); } else @@ -804,7 +804,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 (!nsvc->nsi->bss_sns_fi && nsvc->nsi->nsip.use_reset_block_unblock) ns_osmo_signal_dispatch(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } @@ -1758,8 +1758,12 @@ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, * fine. */ if ((*nsvc)->state == NSE_S_BLOCKED) rc = gprs_nsvc_reset((*nsvc), NS_CAUSE_PDU_INCOMP_PSTATE); - else if (!((*nsvc)->state & NSE_S_RESET)) + else if (!((*nsvc)->state & NSE_S_RESET)) { + /* if we're not alive, we cannot transmit the ACK; set ALIVE */ + if (!((*nsvc)->state & NSE_S_ALIVE)) + ns_mark_alive(*nsvc); rc = gprs_ns_tx_alive_ack(*nsvc); + } break; case NS_PDUT_ALIVE_ACK: ns_mark_alive(*nsvc); @@ -1915,6 +1919,11 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb, void *ctx) llist_del(&nsi->unknown_nsvc->list); INIT_LLIST_HEAD(&nsi->unknown_nsvc->list); + /* By default we are in IPA compatible mode, that is we use NS-RESET, NS-BLOCK + * and NS-UNBLOCK procedures even for an IP/UDP based Gb interface, in violation + * of 3GPP TS 48.016. */ + nsi->nsip.use_reset_block_unblock = true; + return nsi; } diff --git a/src/gb/gprs_ns_vty.c b/src/gb/gprs_ns_vty.c index 9cffb71d..bd53f2f1 100644 --- a/src/gb/gprs_ns_vty.c +++ b/src/gb/gprs_ns_vty.c @@ -90,6 +90,32 @@ static int config_write_ns(struct vty *vty) vty_out(vty, "ns%s", VTY_NEWLINE); + /* global configuration must be written first, as some of it may be + * relevant when creating the NSE/NSVC later below */ + + if (vty_nsi->nsip.local_ip) { + ia.s_addr = osmo_htonl(vty_nsi->nsip.local_ip); + vty_out(vty, " encapsulation udp local-ip %s%s", + inet_ntoa(ia), VTY_NEWLINE); + } + if (vty_nsi->nsip.local_port) + vty_out(vty, " encapsulation udp local-port %u%s", + vty_nsi->nsip.local_port, VTY_NEWLINE); + if (vty_nsi->nsip.dscp) + vty_out(vty, " encapsulation udp dscp %d%s", + vty_nsi->nsip.dscp, VTY_NEWLINE); + + vty_out(vty, " encapsulation udp use-reset-block-unblock %s%s", + vty_nsi->nsip.use_reset_block_unblock ? "enabled" : "disabled", VTY_NEWLINE); + + vty_out(vty, " encapsulation framerelay-gre enabled %u%s", + vty_nsi->frgre.enabled ? 1 : 0, VTY_NEWLINE); + if (vty_nsi->frgre.local_ip) { + ia.s_addr = osmo_htonl(vty_nsi->frgre.local_ip); + vty_out(vty, " encapsulation framerelay-gre local-ip %s%s", + inet_ntoa(ia), VTY_NEWLINE); + } + llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) { if (!nsvc->persistent) continue; @@ -130,26 +156,6 @@ static int config_write_ns(struct vty *vty) get_value_string(gprs_ns_timer_strs, i), vty_nsi->timeout[i], VTY_NEWLINE); - if (vty_nsi->nsip.local_ip) { - ia.s_addr = osmo_htonl(vty_nsi->nsip.local_ip); - vty_out(vty, " encapsulation udp local-ip %s%s", - inet_ntoa(ia), VTY_NEWLINE); - } - if (vty_nsi->nsip.local_port) - vty_out(vty, " encapsulation udp local-port %u%s", - vty_nsi->nsip.local_port, VTY_NEWLINE); - if (vty_nsi->nsip.dscp) - vty_out(vty, " encapsulation udp dscp %d%s", - vty_nsi->nsip.dscp, VTY_NEWLINE); - - vty_out(vty, " encapsulation framerelay-gre enabled %u%s", - vty_nsi->frgre.enabled ? 1 : 0, VTY_NEWLINE); - if (vty_nsi->frgre.local_ip) { - ia.s_addr = osmo_htonl(vty_nsi->frgre.local_ip); - vty_out(vty, " encapsulation framerelay-gre local-ip %s%s", - inet_ntoa(ia), VTY_NEWLINE); - } - return CMD_SUCCESS; } @@ -500,6 +506,21 @@ DEFUN(cfg_nsip_dscp, cfg_nsip_dscp_cmd, return CMD_SUCCESS; } +DEFUN(cfg_nsip_res_block_unblock, cfg_nsip_res_block_unblock_cmd, + "encapsulation udp use-reset-block-unblock (enabled|disabled)", + ENCAPS_STR "NS over UDP Encapsulation\n" + "Use NS-{RESET,BLOCK,UNBLOCK} procedures in violation of 3GPP TS 48.016\n" + "Enable NS-{RESET,BLOCK,UNBLOCK}\n" + "Disable NS-{RESET,BLOCK,UNBLOCK}\n") +{ + if (!strcmp(argv[0], "enabled")) + vty_nsi->nsip.use_reset_block_unblock = true; + else + vty_nsi->nsip.use_reset_block_unblock = false; + + return CMD_SUCCESS; +} + DEFUN(cfg_frgre_local_ip, cfg_frgre_local_ip_cmd, "encapsulation framerelay-gre local-ip A.B.C.D", ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n" @@ -643,6 +664,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element(L_NS_NODE, &cfg_nsip_local_ip_cmd); install_element(L_NS_NODE, &cfg_nsip_local_port_cmd); install_element(L_NS_NODE, &cfg_nsip_dscp_cmd); + install_element(L_NS_NODE, &cfg_nsip_res_block_unblock_cmd); install_element(L_NS_NODE, &cfg_frgre_enable_cmd); install_element(L_NS_NODE, &cfg_frgre_local_ip_cmd); -- cgit v1.2.3