Adds the functions gprs_ns_ll_copy() and gprs_ns_ll_clear(). Renames gprs_ns_format_peer() to gprs_ns_ll_str(). All of these functions uniformly access the link layer part within the NS-VC objects.
Sponsored-by: On-Waves ehf --- include/osmocom/gprs/gprs_ns.h | 8 +++++++- src/gb/gprs_ns.c | 42 +++++++++++++++++++++++++++++++++++----- src/gb/libosmogb.map | 4 +++- tests/gb/gprs_ns_test.c | 10 +++++----- 4 files changed, 52 insertions(+), 12 deletions(-)
diff --git a/include/osmocom/gprs/gprs_ns.h b/include/osmocom/gprs/gprs_ns.h index d16068b..7b0ec92 100644 --- a/include/osmocom/gprs/gprs_ns.h +++ b/include/osmocom/gprs/gprs_ns.h @@ -177,7 +177,13 @@ void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); int gprs_ns_vty_init(struct gprs_ns_inst *nsi);
/* Resturn peer info as string (NOTE: the buffer is allocated statically) */ -const char *gprs_ns_format_peer(struct gprs_nsvc *nsvc); +const char *gprs_ns_ll_str(struct gprs_nsvc *nsvc); + +/* Copy the link layer info from other into nsvc */ +void gprs_ns_ll_copy(struct gprs_nsvc *nsvc, struct gprs_nsvc *other); + +/* Clear the link layer info (will never match a real link then) */ +void gprs_ns_ll_clear(struct gprs_nsvc *nsvc);
#define NS_ALLOC_SIZE 2048 #define NS_ALLOC_HEADROOM 20 diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index 7801b29..61a96d7 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -802,7 +802,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, return rc; }
-const char *gprs_ns_format_peer(struct gprs_nsvc *nsvc) +const char *gprs_ns_ll_str(struct gprs_nsvc *nsvc) { static char buf[80]; snprintf(buf, sizeof(buf), "%s:%u", @@ -812,6 +812,38 @@ const char *gprs_ns_format_peer(struct gprs_nsvc *nsvc) return buf; }
+void gprs_ns_ll_copy(struct gprs_nsvc *nsvc, struct gprs_nsvc *other) +{ + nsvc->ll = other->ll; + + switch (nsvc->ll) { + case GPRS_NS_LL_UDP: + nsvc->ip = other->ip; + break; + case GPRS_NS_LL_FR_GRE: + nsvc->frgre = other->frgre; + break; + default: + break; + } +} + +void gprs_ns_ll_clear(struct gprs_nsvc *nsvc) +{ + switch (nsvc->ll) { + case GPRS_NS_LL_UDP: + nsvc->ip.bts_addr.sin_addr.s_addr = INADDR_ANY; + nsvc->ip.bts_addr.sin_port = 0; + break; + case GPRS_NS_LL_FR_GRE: + nsvc->frgre.bts_addr.sin_addr.s_addr = INADDR_ANY; + nsvc->frgre.bts_addr.sin_port = 0; + break; + default: + break; + } +} + /*! \brief Create/get NS-VC independently from underlying transport layer * \param nsi NS instance to which the data belongs * \param[in] msg message buffer containing newly-received data @@ -841,7 +873,7 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg, if (nsh->pdu_type == NS_PDUT_STATUS) { LOGP(DNS, LOGL_INFO, "Ignoring NS STATUS from %s " "for non-existing NS-VC\n", - gprs_ns_format_peer(fallback_nsvc)); + gprs_ns_ll_str(fallback_nsvc)); return GPRS_NS_CS_SKIPPED; }
@@ -851,7 +883,7 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg, log_set_context(GPRS_CTX_NSVC, fallback_nsvc); LOGP(DNS, LOGL_INFO, "Rejecting NS PDU type 0x%0x " "from %s for non-existing NS-VC\n", - nsh->pdu_type, gprs_ns_format_peer(fallback_nsvc)); + nsh->pdu_type, gprs_ns_ll_str(fallback_nsvc)); fallback_nsvc->nsvci = fallback_nsvc->nsei = 0xfffe; fallback_nsvc->state = NSE_S_ALIVE;
@@ -859,7 +891,7 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg, NS_CAUSE_PDU_INCOMP_PSTATE, 0, msg); if (rc < 0) { LOGP(DNS, LOGL_ERROR, "TX failed (%d) to peer %s\n", - rc, gprs_ns_format_peer(fallback_nsvc)); + rc, gprs_ns_ll_str(fallback_nsvc)); return rc; } return GPRS_NS_CS_REJECTED; @@ -887,7 +919,7 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg, *new_nsvc = gprs_nsvc_create(nsi, 0xffff); log_set_context(GPRS_CTX_NSVC, *new_nsvc); LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s\n", - gprs_ns_format_peer(fallback_nsvc)); + gprs_ns_ll_str(fallback_nsvc));
return GPRS_NS_CS_CREATED; } diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map index 0270db8..a21a7ac 100644 --- a/src/gb/libosmogb.map +++ b/src/gb/libosmogb.map @@ -54,7 +54,9 @@ gprs_ns_tx_reset; gprs_ns_tx_status; gprs_ns_tx_unblock; gprs_ns_vty_init; -gprs_ns_format_peer; +gprs_ns_ll_str; +gprs_ns_ll_copy; +gprs_ns_ll_clear;
gprs_nsvc_create; gprs_nsvc_delete; diff --git a/tests/gb/gprs_ns_test.c b/tests/gb/gprs_ns_test.c index c4fc228..1474fd4 100644 --- a/tests/gb/gprs_ns_test.c +++ b/tests/gb/gprs_ns_test.c @@ -134,31 +134,31 @@ static int test_signal(unsigned int subsys, unsigned int signal, case S_NS_RESET: printf("==> got signal NS_RESET, NS-VC 0x%04x/%s\n", nssd->nsvc->nsvci, - gprs_ns_format_peer(nssd->nsvc)); + gprs_ns_ll_str(nssd->nsvc)); break;
case S_NS_ALIVE_EXP: printf("==> got signal NS_ALIVE_EXP, NS-VC 0x%04x/%s\n", nssd->nsvc->nsvci, - gprs_ns_format_peer(nssd->nsvc)); + gprs_ns_ll_str(nssd->nsvc)); break;
case S_NS_BLOCK: printf("==> got signal NS_BLOCK, NS-VC 0x%04x/%s\n", nssd->nsvc->nsvci, - gprs_ns_format_peer(nssd->nsvc)); + gprs_ns_ll_str(nssd->nsvc)); break;
case S_NS_UNBLOCK: printf("==> got signal NS_UNBLOCK, NS-VC 0x%04x/%s\n", nssd->nsvc->nsvci, - gprs_ns_format_peer(nssd->nsvc)); + gprs_ns_ll_str(nssd->nsvc)); break;
default: printf("==> got signal %d, NS-VC 0x%04x/%s\n", signal, nssd->nsvc->nsvci, - gprs_ns_format_peer(nssd->nsvc)); + gprs_ns_ll_str(nssd->nsvc)); break; }
Under special circumstances (see below) receiving a NS-RESET leads to duplicated NS-VC entries.
This happens when the source port of a NS-VC changes to a new one that has already been used by another NS-VC.
This patch changes gprs_ns_rx_reset() to check for this case and to use the existing NS-VC object. The NS-VC object that was associated with the source address before is detached from this source but kept in the NS-VC list so that it can be reattached when a correspondent NS-RESET is received later on. Meanwhile it will have a cleared link layer address which will not match a real link info.
A new counter NS_CTR_REPLACED is incremented each time when the NS-VC object is replacing another one. A new signal S_NS_REPLACED is added which gets dispatched in this case, too.
Another new counter NS_CTR_NSEI_CHG is incremented each time when the NSEI of a NS-VC object (with fixed NSVCI) changes.
Ticket: OW#874 Sponsored-by: On-Waves ehf --- include/osmocom/gprs/gprs_ns.h | 3 + src/gb/gprs_ns.c | 226 +++++++++++++++++++++++++++------------- tests/gb/gprs_ns_test.c | 28 ++++- tests/gb/gprs_ns_test.ok | 10 +- 4 files changed, 190 insertions(+), 77 deletions(-)
diff --git a/include/osmocom/gprs/gprs_ns.h b/include/osmocom/gprs/gprs_ns.h index 7b0ec92..b28c58d 100644 --- a/include/osmocom/gprs/gprs_ns.h +++ b/include/osmocom/gprs/gprs_ns.h @@ -119,6 +119,7 @@ struct gprs_nsvc {
unsigned int remote_end_is_sgsn:1; unsigned int persistent:1; + unsigned int nsvci_is_valid:1;
struct rate_ctr_group *ctrg;
@@ -197,10 +198,12 @@ enum signal_ns { S_NS_BLOCK, S_NS_UNBLOCK, S_NS_ALIVE_EXP, /* Tns-alive expired more than N times */ + S_NS_REPLACED, /* nsvc object is replaced (sets old_nsvc) */ };
struct ns_signal_data { struct gprs_nsvc *nsvc; + struct gprs_nsvc *old_nsvc; uint8_t cause; };
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index 61a96d7..b403ca9 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -83,6 +83,9 @@
#include "common_vty.h"
+void gprs_ns_ll_copy(struct gprs_nsvc *nsvc, struct gprs_nsvc *other); +void gprs_ns_ll_clear(struct gprs_nsvc *nsvc); + static const struct tlv_definition ns_att_tlvdef = { .def = { [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, @@ -100,15 +103,19 @@ enum ns_ctr { NS_CTR_BYTES_OUT, NS_CTR_BLOCKED, NS_CTR_DEAD, + NS_CTR_REPLACED, + NS_CTR_NSEI_CHG, };
static const struct rate_ctr_desc nsvc_ctr_description[] = { - { "packets.in", "Packets at NS Level ( In)" }, - { "packets.out","Packets at NS Level (Out)" }, - { "bytes.in", "Bytes at NS Level ( In)" }, - { "bytes.out", "Bytes at NS Level (Out)" }, - { "blocked", "NS-VC Block count " }, - { "dead", "NS-VC gone dead count " }, + { "packets.in", "Packets at NS Level ( In)" }, + { "packets.out","Packets at NS Level (Out)" }, + { "bytes.in", "Bytes at NS Level ( In)" }, + { "bytes.out", "Bytes at NS Level (Out)" }, + { "blocked", "NS-VC Block count " }, + { "dead", "NS-VC gone dead count " }, + { "replaced", "NS-VC replaced other count" }, + { "nsei-chg", "NS-VC changed NSEI " }, };
static const struct rate_ctr_group_desc nsvc_ctrg_desc = { @@ -212,7 +219,7 @@ void gprs_nsvc_delete(struct gprs_nsvc *nsvc) static void ns_osmo_signal_dispatch(struct gprs_nsvc *nsvc, unsigned int signal, uint8_t cause) { - struct ns_signal_data nssd; + struct ns_signal_data nssd = {0};
nssd.nsvc = nsvc; nssd.cause = cause; @@ -220,6 +227,16 @@ static void ns_osmo_signal_dispatch(struct gprs_nsvc *nsvc, unsigned int signal, osmo_signal_dispatch(SS_L_NS, signal, &nssd); }
+static void ns_osmo_signal_dispatch_replaced(struct gprs_nsvc *nsvc, struct gprs_nsvc *old_nsvc) +{ + struct ns_signal_data nssd = {0}; + + nssd.nsvc = nsvc; + nssd.old_nsvc = old_nsvc; + + osmo_signal_dispatch(SS_L_NS, S_NS_REPLACED, &nssd); +} + /* Section 10.3.2, Table 13 */ static const struct value_string ns_cause_str[] = { { NS_CAUSE_TRANSIT_FAIL, "Transit network failure" }, @@ -658,19 +675,20 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) }
/* Section 7.3 */ -static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) +static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct tlv_parsed tp; - uint8_t *cause; - uint16_t *nsvci, *nsei; + uint8_t cause; + uint16_t nsvci, nsei; + struct gprs_nsvc *other_nsvc = NULL; int rc;
rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg) - sizeof(*nsh), 0, 0); if (rc < 0) { LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS RESET " - "Error during TLV Parse\n", nsvc->nsei); + "Error during TLV Parse\n", (*nsvc)->nsei); return rc; }
@@ -678,32 +696,84 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); - gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg); + gprs_ns_tx_status((*nsvc), NS_CAUSE_MISSING_ESSENT_IE, 0, msg); return -EINVAL; }
- cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); - nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); - nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); + cause = *(uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); + nsvci = ntohs(*(uint16_t *) TLVP_VAL(&tp, NS_IE_VCI)); + nsei = ntohs(*(uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI)); + + LOGP(DNS, LOGL_INFO, "NSVCI=%u%s Rx NS RESET (NSEI=%u, NSVCI=%u, cause=%s)\n", + (*nsvc)->nsvci, (*nsvc)->nsvci_is_valid ? "" : "(invalid)", + nsei, nsvci, gprs_ns_cause_str(cause)); + + if ((*nsvc)->nsvci_is_valid && (*nsvc)->nsvci != nsvci) { + /* NS-VCI has changed */ + other_nsvc = gprs_nsvc_by_nsvci((*nsvc)->nsi, nsvci); + + if (other_nsvc) { + /* The NS-VCI is already used by this NS-VC */ + + struct gprs_nsvc *tmp_nsvc; + char *old_peer; + + /* Exchange the NS-VC objects */ + tmp_nsvc = *nsvc; + *nsvc = other_nsvc; + other_nsvc = tmp_nsvc;
- LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", - nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); + /* Do logging */ + old_peer = talloc_strdup(other_nsvc, + gprs_ns_ll_str(other_nsvc)); + LOGP(DNS, LOGL_INFO, + "NS-VC changed link (NSVCI=%u) from %s to %s\n", + nsvci, old_peer, gprs_ns_ll_str(*nsvc)); + + talloc_free(old_peer); + + /* Do statistics */ + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_REPLACED]); + } + }
/* Mark NS-VC as blocked and alive */ - nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE; + + if (other_nsvc) { + /* Check NSEI */ + if ((*nsvc)->nsei != nsei) { + LOGP(DNS, LOGL_NOTICE, + "NS-VC changed NSEI (NSVCI=%u) from %u to %u\n", + nsvci, (*nsvc)->nsei, nsei); + + /* Override old NSEI */ + (*nsvc)->nsei = nsei; + + /* Do statistics */ + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_NSEI_CHG]); + }
- nsvc->nsei = ntohs(*nsei); - nsvc->nsvci = ntohs(*nsvci); + ns_osmo_signal_dispatch_replaced(*nsvc, other_nsvc); + + /* Update the ll info fields */ + gprs_ns_ll_copy(*nsvc, other_nsvc); + gprs_ns_ll_clear(other_nsvc); + } else { + (*nsvc)->nsei = nsei; + (*nsvc)->nsvci = nsvci; + (*nsvc)->nsvci_is_valid = 1; + }
/* inform interested parties about the fact that this NSVC * has received RESET */ - ns_osmo_signal_dispatch(nsvc, S_NS_RESET, *cause); + ns_osmo_signal_dispatch(*nsvc, S_NS_RESET, cause);
- rc = gprs_ns_tx_reset_ack(nsvc); + rc = gprs_ns_tx_reset_ack(*nsvc);
/* start the test procedure */ - gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); + gprs_ns_tx_simple((*nsvc), NS_PDUT_ALIVE); + nsvc_start_timer((*nsvc), NSVC_TIMER_TNS_TEST);
return rc; } @@ -748,7 +818,7 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg, struct gprs_nsvc **new_nsvc);
int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, - struct gprs_nsvc *nsvc); + struct gprs_nsvc **nsvc);
/*! \brief Receive incoming NS message from underlying transport layer * \param nsi NS instance to which the data belongs @@ -779,25 +849,14 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
rc = gprs_ns_vc_create(nsi, msg, fallback_nsvc, &nsvc);
- switch (rc) { - case GPRS_NS_CS_CREATED: - case GPRS_NS_CS_FOUND: - nsvc->ll = ll; - break; - case GPRS_NS_CS_SKIPPED: - case GPRS_NS_CS_REJECTED: - break; - default: + if (rc < 0) return rc; - }
rc = 0; }
- if (nsvc) { - nsvc->ip.bts_addr = *saddr; - rc = gprs_ns_process_msg(nsi, msg, nsvc); - } + if (nsvc) + rc = gprs_ns_process_msg(nsi, msg, &nsvc);
return rc; } @@ -848,6 +907,7 @@ void gprs_ns_ll_clear(struct gprs_nsvc *nsvc) * \param nsi NS instance to which the data belongs * \param[in] msg message buffer containing newly-received data * \param[in] fallback_nsvc is used to send error messages back to the peer + * and to initialise the ll info of a created NS-VC object * \param[out] new_nsvc contains a pointer to a NS-VC object if one has * been created or found * \returns < 0 in case of error, GPRS_NS_CS_SKIPPED if a message has been @@ -867,6 +927,7 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg,
struct tlv_parsed tp; uint16_t nsvci; + uint16_t nsei;
int rc;
@@ -912,43 +973,60 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg, return -EINVAL; } nsvci = ntohs(*(uint16_t *) TLVP_VAL(&tp, NS_IE_VCI)); + nsei = ntohs(*(uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI)); /* Check if we already know this NSVCI, the remote end might * simply have changed addresses, or it is a SGSN */ existing_nsvc = gprs_nsvc_by_nsvci(nsi, nsvci); if (!existing_nsvc) { *new_nsvc = gprs_nsvc_create(nsi, 0xffff); log_set_context(GPRS_CTX_NSVC, *new_nsvc); + gprs_ns_ll_copy(*new_nsvc, fallback_nsvc); LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s\n", gprs_ns_ll_str(fallback_nsvc));
return GPRS_NS_CS_CREATED; }
+ /* Check NSEI */ + if (existing_nsvc->nsei != nsei) { + LOGP(DNS, LOGL_NOTICE, + "NS-VC changed NSEI (NSVCI=%u) from %u to %u\n", + nsvci, existing_nsvc->nsei, nsei); + + /* Override old NSEI */ + existing_nsvc->nsei = nsei; + + /* Do statistics */ + rate_ctr_inc(&existing_nsvc->ctrg->ctr[NS_CTR_NSEI_CHG]); + } + *new_nsvc = existing_nsvc; + gprs_ns_ll_copy(*new_nsvc, fallback_nsvc); return GPRS_NS_CS_FOUND; }
/*! \brief Process NS message independently from underlying transport layer * \param nsi NS instance to which the data belongs * \param[in] msg message buffer containing newly-received data - * \param[in] nsvc refers to the virtual connection + * \param[inout] nsvc refers to the virtual connection, may be modified when + * processing a NS_RESET * \returns 0 in case of success, < 0 in case of error * * This contains the main NS automaton. */ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, - struct gprs_nsvc *nsvc) + struct gprs_nsvc **nsvc) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; int rc = 0;
- msgb_nsei(msg) = nsvc->nsei; + msgb_nsei(msg) = (*nsvc)->nsei;
- log_set_context(GPRS_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, (*nsvc));
/* Increment number of Incoming bytes */ - rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]); - rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg)); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_PKTS_IN]); + rate_ctr_add(&(*nsvc)->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg));
switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -956,69 +1034,69 @@ 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) - rc = gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE); + if ((*nsvc)->state == NSE_S_BLOCKED) + rc = gprs_ns_tx_reset((*nsvc), NS_CAUSE_PDU_INCOMP_PSTATE); else - rc = gprs_ns_tx_alive_ack(nsvc); + rc = gprs_ns_tx_alive_ack(*nsvc); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive and start Tns-test */ - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); - if (nsvc->remote_end_is_sgsn) { + nsvc_start_timer((*nsvc), NSVC_TIMER_TNS_TEST); + if ((*nsvc)->remote_end_is_sgsn) { /* FIXME: this should be one level higher */ - if (nsvc->state & NSE_S_BLOCKED) - rc = gprs_ns_tx_unblock(nsvc); + if ((*nsvc)->state & NSE_S_BLOCKED) + rc = gprs_ns_tx_unblock(*nsvc); } break; case NS_PDUT_UNITDATA: /* actual user data */ - rc = gprs_ns_rx_unitdata(nsvc, msg); + rc = gprs_ns_rx_unitdata((*nsvc), msg); break; case NS_PDUT_STATUS: - rc = gprs_ns_rx_status(nsvc, msg); + rc = gprs_ns_rx_status((*nsvc), msg); break; case NS_PDUT_RESET: rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", (*nsvc)->nsei); /* mark NS-VC as blocked + active */ - nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; - nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; - rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); - if (nsvc->persistent || nsvc->remote_end_is_sgsn) { + (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE; + (*nsvc)->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_BLOCKED]); + if ((*nsvc)->persistent || (*nsvc)->remote_end_is_sgsn) { /* stop RESET timer */ - osmo_timer_del(&nsvc->timer); + osmo_timer_del(&(*nsvc)->timer); } /* Initiate TEST proc.: Send ALIVE and start timer */ - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); + rc = gprs_ns_tx_simple((*nsvc), NS_PDUT_ALIVE); + nsvc_start_timer((*nsvc), NSVC_TIMER_TNS_TEST); break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ - LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); - nsvc->state &= ~NSE_S_BLOCKED; - ns_osmo_signal_dispatch(nsvc, S_NS_UNBLOCK, 0); - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK\n", (*nsvc)->nsei); + (*nsvc)->state &= ~NSE_S_BLOCKED; + ns_osmo_signal_dispatch((*nsvc), S_NS_UNBLOCK, 0); + rc = gprs_ns_tx_simple((*nsvc), NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK ACK\n", (*nsvc)->nsei); /* mark NS-VC as unblocked + active */ - nsvc->state = NSE_S_ALIVE; - nsvc->remote_state = NSE_S_ALIVE; - ns_osmo_signal_dispatch(nsvc, S_NS_UNBLOCK, 0); + (*nsvc)->state = NSE_S_ALIVE; + (*nsvc)->remote_state = NSE_S_ALIVE; + ns_osmo_signal_dispatch((*nsvc), S_NS_UNBLOCK, 0); break; case NS_PDUT_BLOCK: - rc = gprs_ns_rx_block(nsvc, msg); + rc = gprs_ns_rx_block((*nsvc), msg); break; case NS_PDUT_BLOCK_ACK: - LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS BLOCK ACK\n", (*nsvc)->nsei); /* mark remote NS-VC as blocked + active */ - nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + (*nsvc)->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", - nsvc->nsei, nsh->pdu_type); + (*nsvc)->nsei, nsh->pdu_type); rc = -EINVAL; break; } diff --git a/tests/gb/gprs_ns_test.c b/tests/gb/gprs_ns_test.c index 1474fd4..d7b769d 100644 --- a/tests/gb/gprs_ns_test.c +++ b/tests/gb/gprs_ns_test.c @@ -21,6 +21,7 @@ #include <osmocom/core/logging.h> #include <osmocom/core/talloc.h> #include <osmocom/core/signal.h> +#include <osmocom/core/rate_ctr.h> #include <osmocom/gprs/gprs_msgb.h> #include <osmocom/gprs/gprs_ns.h> #include <osmocom/gprs/gprs_bssgp.h> @@ -113,7 +114,7 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, if (!real_sendto) real_sendto = dlsym(RTLD_NEXT, "sendto");
- if (sockfd != 0xdead && ((struct sockaddr_in *)dest_addr)->sin_addr.s_addr != htonl(0x01020304)) + if (((struct sockaddr_in *)dest_addr)->sin_addr.s_addr != htonl(0x01020304)) return real_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
printf("RESPONSE, msg length %d\n%s\n\n", len, osmo_hexdump(buf, len)); @@ -121,6 +122,21 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, return len; }
+static void dump_rate_ctr_group(FILE *stream, const char *prefix, + struct rate_ctr_group *ctrg) +{ + unsigned int i; + + for (i = 0; i < ctrg->desc->num_ctr; i++) { + struct rate_ctr *ctr = &ctrg->ctr[i]; + if (ctr->current && !strchr(ctrg->desc->ctr_desc[i].name, '.')) + fprintf(stream, " %s%s: %llu%s", + prefix, ctrg->desc->ctr_desc[i].description, + (long long)ctr->current, + "\n"); + }; +} + /* Signal handler for signals from NS layer */ static int test_signal(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) @@ -155,6 +171,15 @@ static int test_signal(unsigned int subsys, unsigned int signal, gprs_ns_ll_str(nssd->nsvc)); break;
+ case S_NS_REPLACED: + printf("==> got signal NS_REPLACED: 0x%04x/%s", + nssd->nsvc->nsvci, + gprs_ns_ll_str(nssd->nsvc)); + printf(" -> 0x%04x/%s\n", + nssd->old_nsvc->nsvci, + gprs_ns_ll_str(nssd->old_nsvc)); + break; + default: printf("==> got signal %d, NS-VC 0x%04x/%s\n", signal, nssd->nsvc->nsvci, @@ -203,6 +228,7 @@ static void gprs_dump_nsi(struct gprs_ns_inst *nsi) nsvc->nsvci, nsvc->nsei, ntohl(peer->sin_addr.s_addr), ntohs(peer->sin_port) ); + dump_rate_ctr_group(stdout, " ", nsvc->ctrg); } printf("\n"); } diff --git a/tests/gb/gprs_ns_test.ok b/tests/gb/gprs_ns_test.ok index 01b1bc9..7be84ef 100644 --- a/tests/gb/gprs_ns_test.ok +++ b/tests/gb/gprs_ns_test.ok @@ -91,12 +91,14 @@ result (RESET) = 9 Current NS-VCIs: VCI 0x3344, NSEI 0x1122, peer 0x01020304:3333 VCI 0x1122, NSEI 0x3344, peer 0x01020304:4444 + NS-VC changed NSEI : 1
--- Peer port 3333, RESET, VCI is changed back ---
PROCESSING RESET from 0x01020304:3333 02 00 81 01 01 82 11 22 04 82 11 22
+==> got signal NS_REPLACED: 0x1122/1.2.3.4:4444 -> 0x3344/1.2.3.4:3333 ==> got signal NS_RESET, NS-VC 0x1122/1.2.3.4:3333 RESPONSE, msg length 9 03 01 82 11 22 04 82 11 22 @@ -107,8 +109,10 @@ RESPONSE, msg length 1 result (RESET) = 9
Current NS-VCIs: + VCI 0x3344, NSEI 0x1122, peer 0x00000000:0 VCI 0x1122, NSEI 0x1122, peer 0x01020304:3333 - VCI 0x1122, NSEI 0x3344, peer 0x01020304:4444 + NS-VC replaced other count: 1 + NS-VC changed NSEI : 2
--- Peer port 4444, RESET, NSEI is changed back ---
@@ -125,8 +129,10 @@ RESPONSE, msg length 1 result (RESET) = 9
Current NS-VCIs: - VCI 0x1122, NSEI 0x1122, peer 0x01020304:3333 + VCI 0x3344, NSEI 0x1122, peer 0x00000000:0 VCI 0x1122, NSEI 0x1122, peer 0x01020304:4444 + NS-VC replaced other count: 1 + NS-VC changed NSEI : 2
===== NS protocol test END