@@ -61,6 +61,11 @@ enum gprs_ns_cs {
GPRS_NS_CS_ERROR, /*!< Failed to process message */
};
+enum gprs_ns_spec {
+ GPRS_NS_TS_08_16 = 0,
+ GPRS_NS_TS_48_016,
+};
+
struct gprs_nsvc;
/*! \brief Osmocom GPRS callback function type */
typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
@@ -120,10 +125,13 @@ struct gprs_nsvc {
enum nsvc_timer_mode timer_mode;
struct timeval timer_started;
int alive_retries;
+ enum gprs_ns_spec compliance;
unsigned int remote_end_is_sgsn:1;
unsigned int persistent:1;
unsigned int nsvci_is_valid:1;
+ unsigned int static_config:1;
+ unsigned int config_completed:1;
struct rate_ctr_group *ctrg;
struct osmo_stat_item_group *statg;
@@ -149,11 +149,28 @@ static const struct osmo_stat_item_group_desc nsvc_statg_desc = {
.class_id = OSMO_STATS_CLASS_PEER,
};
+static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode);
+
#define CHECK_TX_RC(rc, nsvc) \
if (rc < 0) \
LOGP(DNS, LOGL_ERROR, "TX failed (%d) to peer %s\n", \
rc, gprs_ns_ll_str(nsvc));
+static int enable_reset_block_proc(const struct gprs_nsvc *nsvc)
+{
+ return nsvc->compliance != GPRS_NS_TS_48_016 ||
+ !nsvc->static_config ||
+ nsvc->ll != GPRS_NS_LL_UDP;
+}
+
+static int continue_test_proc(const struct gprs_nsvc *nsvc)
+{
+ return nsvc->compliance == GPRS_NS_TS_48_016 &&
+ nsvc->static_config &&
+ nsvc->ll == GPRS_NS_LL_UDP &&
+ nsvc->remote_end_is_sgsn;
+}
+
struct msgb *gprs_ns_msgb_alloc(void)
{
struct msgb *msg = msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM,
@@ -588,16 +605,24 @@ static void gprs_ns_timer_cb(void *data)
nsvc->alive_retries++;
if (nsvc->alive_retries >
nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) {
- /* mark as dead and blocked */
- nsvc->state = NSE_S_BLOCKED;
- rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
- rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_DEAD]);
LOGP(DNS, LOGL_NOTICE,
"NSEI=%u Tns-alive expired more then "
"%u times, blocking NS-VC\n", nsvc->nsei,
nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]);
+ /* mark as dead */
+ nsvc->state = nsvc->state & ~NSE_S_ALIVE;
+ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_DEAD]);
ns_osmo_signal_dispatch(nsvc, S_NS_ALIVE_EXP, 0);
- ns_osmo_signal_dispatch(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED);
+
+ if (continue_test_proc(nsvc)) {
+ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST);
+ } else if (enable_reset_block_proc(nsvc)) {
+ /* mark as blocked */
+ nsvc->state = NSE_S_BLOCKED;
+ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
+ ns_osmo_signal_dispatch(nsvc, S_NS_BLOCK,
+ NS_CAUSE_NSVC_BLOCKED);
+ }
return;
}
/* Tns-test case: send NS-ALIVE PDU */
@@ -1109,6 +1134,14 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
return rc;
rc = 0;
+ } else if (nsvc->static_config && !nsvc->config_completed) {
+
+ if (!enable_reset_block_proc(nsvc)) {
+ nsvc->state = NSE_S_ALIVE;
+ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST);
+ }
+
+ nsvc->config_completed = 1;
}
if (nsvc)
@@ -1311,10 +1344,18 @@ 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. */
- if ((*nsvc)->state == NSE_S_BLOCKED)
+ 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)) {
rc = gprs_ns_tx_alive_ack(*nsvc);
+ if (!enable_reset_block_proc(*nsvc) &&
+ !((*nsvc)->state & NSE_S_ALIVE))
+ {
+ /* start the test procedure */
+ gprs_ns_tx_simple((*nsvc), NS_PDUT_ALIVE);
+ nsvc_start_timer((*nsvc), NSVC_TIMER_TNS_TEST);
+ }
+ }
break;
case NS_PDUT_ALIVE_ACK:
if ((*nsvc)->timer_mode == NSVC_TIMER_TNS_ALIVE)
@@ -1605,7 +1646,12 @@ struct gprs_nsvc *gprs_ns_nsip_connect(struct gprs_ns_inst *nsi,
nsvc->nsei = nsei;
nsvc->remote_end_is_sgsn = 1;
- gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
+ if (enable_reset_block_proc(nsvc)) {
+ gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
+ } else if (continue_test_proc(nsvc)) {
+ nsvc->state = NSE_S_ALIVE;
+ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST);
+ }
return nsvc;
}
@@ -91,6 +91,11 @@ static int config_write_ns(struct vty *vty)
vty_out(vty, " nse %u remote-role %s%s",
nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss",
VTY_NEWLINE);
+ vty_out(vty, " nse %u compliance %s%s",
+ nsvc->nsei,
+ nsvc->compliance == GPRS_NS_TS_08_16 ?
+ "ts08.16" : "ts48.016",
+ VTY_NEWLINE);
switch (nsvc->ll) {
case GPRS_NS_LL_UDP:
vty_out(vty, " nse %u encapsulation udp%s", nsvc->nsei,
@@ -257,6 +262,7 @@ DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd,
if (!nsvc) {
nsvc = gprs_nsvc_create(vty_nsi, nsvci);
nsvc->nsei = nsei;
+ nsvc->static_config = 1;
}
nsvc->nsvci = nsvci;
/* All NSVCs that are explicitly configured by VTY are
@@ -389,6 +395,30 @@ DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_nse_compliance, cfg_nse_compliance_cmd,
+ "nse <0-65535> compliance (ts08.16|ts48.016)",
+ NSE_CMD_STR
+ "Set protocol compliance\n"
+ "Use 3GPP TS 08.16\n"
+ "Use 3GPP TS 48.016\n")
+{
+ uint16_t nsei = atoi(argv[0]);
+ struct gprs_nsvc *nsvc;
+
+ nsvc = gprs_nsvc_by_nsei(vty_nsi, nsei);
+ if (!nsvc) {
+ vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strcmp(argv[1], "ts08.16"))
+ nsvc->compliance = GPRS_NS_TS_08_16;
+ else
+ nsvc->compliance = GPRS_NS_TS_48_016;
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_no_nse, cfg_no_nse_cmd,
"no nse <0-65535>",
"Delete Persistent NS Entity\n"
@@ -593,6 +623,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi)
install_element(L_NS_NODE, &cfg_nse_fr_dlci_cmd);
install_element(L_NS_NODE, &cfg_nse_encaps_cmd);
install_element(L_NS_NODE, &cfg_nse_remoterole_cmd);
+ install_element(L_NS_NODE, &cfg_nse_compliance_cmd);
install_element(L_NS_NODE, &cfg_no_nse_cmd);
install_element(L_NS_NODE, &cfg_ns_timer_cmd);
install_element(L_NS_NODE, &cfg_nsip_local_ip_cmd);