aboutsummaryrefslogtreecommitdiffstats
path: root/src/gb/gprs_ns2_message.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gb/gprs_ns2_message.c')
-rw-r--r--src/gb/gprs_ns2_message.c395
1 files changed, 265 insertions, 130 deletions
diff --git a/src/gb/gprs_ns2_message.c b/src/gb/gprs_ns2_message.c
index fac6108c..de63b7aa 100644
--- a/src/gb/gprs_ns2_message.c
+++ b/src/gb/gprs_ns2_message.c
@@ -43,30 +43,13 @@
do { \
if (!nsvc->nse->bss_sns_fi) \
break; \
- LOGP(DLNS, LOGL_DEBUG, "NSEI=%u Rx invalid packet %s with SNS\n", \
- nsvc->nse->nsei, reason); \
+ LOGNSVC(nsvc, LOGL_DEBUG, "invalid packet %s with SNS\n", reason); \
} while (0)
-enum ns_ctr {
- NS_CTR_PKTS_IN,
- NS_CTR_PKTS_OUT,
- NS_CTR_BYTES_IN,
- NS_CTR_BYTES_OUT,
- NS_CTR_BLOCKED,
- NS_CTR_DEAD,
- NS_CTR_REPLACED,
- NS_CTR_NSEI_CHG,
- NS_CTR_INV_VCI,
- NS_CTR_INV_NSEI,
- NS_CTR_LOST_ALIVE,
- NS_CTR_LOST_RESET,
-};
-
-
-
-static int gprs_ns2_validate_reset(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
+static int ns2_validate_reset(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
{
- if (!TLVP_PRESENT(tp, NS_IE_CAUSE) || !TLVP_PRESENT(tp, NS_IE_VCI) || !TLVP_PRESENT(tp, NS_IE_NSEI)) {
+ if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1) ||
+ !TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_NSEI, 2)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
@@ -74,9 +57,9 @@ static int gprs_ns2_validate_reset(struct gprs_ns2_vc *nsvc, struct msgb *msg, s
return 0;
}
-static int gprs_ns2_validate_reset_ack(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
+static int ns2_validate_reset_ack(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
{
- if (!TLVP_PRESENT(tp, NS_IE_VCI) || !TLVP_PRESENT(tp, NS_IE_NSEI)) {
+ if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_NSEI, 2)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
@@ -84,9 +67,9 @@ static int gprs_ns2_validate_reset_ack(struct gprs_ns2_vc *nsvc, struct msgb *ms
return 0;
}
-static int gprs_ns2_validate_block(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
+static int ns2_validate_block(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
{
- if (!TLVP_PRESENT(tp, NS_IE_VCI) || !TLVP_PRESENT(tp, NS_IE_CAUSE)) {
+ if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
@@ -94,9 +77,9 @@ static int gprs_ns2_validate_block(struct gprs_ns2_vc *nsvc, struct msgb *msg, s
return 0;
}
-static int gprs_ns2_validate_block_ack(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
+static int ns2_validate_block_ack(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
{
- if (!TLVP_PRESENT(tp, NS_IE_VCI)) {
+ if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
@@ -104,42 +87,46 @@ static int gprs_ns2_validate_block_ack(struct gprs_ns2_vc *nsvc, struct msgb *ms
return 0;
}
-static int gprs_ns2_validate_status(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
+static int ns2_validate_status(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
{
- if (!TLVP_PRESENT(tp, NS_IE_CAUSE)) {
+ if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
- uint8_t _cause = tlvp_val8(tp, NS_IE_VCI, 0);
-
+ uint8_t _cause = tlvp_val8(tp, NS_IE_CAUSE, 0);
switch (_cause) {
case NS_CAUSE_NSVC_BLOCKED:
case NS_CAUSE_NSVC_UNKNOWN:
- if (!TLVP_PRESENT(tp, NS_IE_CAUSE)) {
+ if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 1)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
+
+ if (nsvc->mode != GPRS_NS2_VC_MODE_BLOCKRESET) {
+ *cause = NS_CAUSE_PDU_INCOMP_PSTATE;
+ return -1;
+ }
break;
case NS_CAUSE_SEM_INCORR_PDU:
case NS_CAUSE_PDU_INCOMP_PSTATE:
case NS_CAUSE_PROTO_ERR_UNSPEC:
case NS_CAUSE_INVAL_ESSENT_IE:
case NS_CAUSE_MISSING_ESSENT_IE:
- if (!TLVP_PRESENT(tp, NS_IE_CAUSE)) {
+ if (!TLVP_PRES_LEN(tp, NS_IE_PDU, 1)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
break;
case NS_CAUSE_BVCI_UNKNOWN:
- if (!TLVP_PRESENT(tp, NS_IE_BVCI)) {
+ if (!TLVP_PRES_LEN(tp, NS_IE_BVCI, 2)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
break;
case NS_CAUSE_UNKN_IP_TEST_FAILED:
- if (!TLVP_PRESENT (tp, NS_IE_IPv4_LIST) && !TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
+ if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST) && !TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
*cause = NS_CAUSE_MISSING_ESSENT_IE;
return -1;
}
@@ -149,23 +136,23 @@ static int gprs_ns2_validate_status(struct gprs_ns2_vc *nsvc, struct msgb *msg,
return 0;
}
-int gprs_ns2_validate(struct gprs_ns2_vc *nsvc,
- uint8_t pdu_type,
- struct msgb *msg,
- struct tlv_parsed *tp,
- uint8_t *cause)
+int ns2_validate(struct gprs_ns2_vc *nsvc,
+ uint8_t pdu_type,
+ struct msgb *msg,
+ struct tlv_parsed *tp,
+ uint8_t *cause)
{
switch (pdu_type) {
case NS_PDUT_RESET:
- return gprs_ns2_validate_reset(nsvc, msg, tp, cause);
+ return ns2_validate_reset(nsvc, msg, tp, cause);
case NS_PDUT_RESET_ACK:
- return gprs_ns2_validate_reset_ack(nsvc, msg, tp, cause);
+ return ns2_validate_reset_ack(nsvc, msg, tp, cause);
case NS_PDUT_BLOCK:
- return gprs_ns2_validate_block(nsvc, msg, tp, cause);
+ return ns2_validate_block(nsvc, msg, tp, cause);
case NS_PDUT_BLOCK_ACK:
- return gprs_ns2_validate_block_ack(nsvc, msg, tp, cause);
+ return ns2_validate_block_ack(nsvc, msg, tp, cause);
case NS_PDUT_STATUS:
- return gprs_ns2_validate_status(nsvc, msg, tp, cause);
+ return ns2_validate_status(nsvc, msg, tp, cause);
/* following PDUs doesn't have any payloads */
case NS_PDUT_ALIVE:
@@ -182,13 +169,18 @@ int gprs_ns2_validate(struct gprs_ns2_vc *nsvc,
return 0;
}
+static int ns_vc_tx(struct gprs_ns2_vc *nsvc, struct msgb *msg)
+{
+ return nsvc->bind->send_vc(nsvc, msg);
+}
/* transmit functions */
static int ns2_tx_simple(struct gprs_ns2_vc *nsvc, uint8_t pdu_type)
{
- struct msgb *msg = gprs_ns2_msgb_alloc();
+ struct msgb *msg = ns2_msgb_alloc();
struct gprs_ns_hdr *nsh;
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
if (!msg)
@@ -196,77 +188,87 @@ static int ns2_tx_simple(struct gprs_ns2_vc *nsvc, uint8_t pdu_type)
msg->l2h = msgb_put(msg, sizeof(*nsh));
nsh = (struct gprs_ns_hdr *) msg->l2h;
-
nsh->pdu_type = pdu_type;
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
+ return ns_vc_tx(nsvc, msg);
}
/*! Transmit a NS-BLOCK on a given NS-VC.
* \param[in] vc NS-VC on which the NS-BLOCK is to be transmitted
* \param[in] cause Numeric NS Cause value
+ * \param[in] nsvci if given this NSVCI will be encoded. If NULL the nsvc->nsvci will be used.
* \returns 0 in case of success */
-int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause)
+int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause, uint16_t *nsvci)
{
struct msgb *msg;
struct gprs_ns_hdr *nsh;
- uint16_t nsvci = osmo_htons(nsvc->nsvci);
+ uint16_t encoded_nsvci;
+
+ if (nsvci)
+ encoded_nsvci = osmo_htons(*nsvci);
+ else
+ encoded_nsvci = osmo_htons(nsvc->nsvci);
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK");
- msg = gprs_ns2_msgb_alloc();
+ msg = ns2_msgb_alloc();
if (!msg)
return -ENOMEM;
- LOGP(DLNS, LOGL_INFO, "NSEI=%u Tx NS BLOCK (NSVCI=%u, cause=%s)\n",
- nsvc->nse->nsei, nsvc->nsvci, gprs_ns2_cause_str(cause));
-
- rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(nsvc->ctrg, NS_CTR_BLOCKED));
msg->l2h = msgb_put(msg, sizeof(*nsh));
nsh = (struct gprs_ns_hdr *) msg->l2h;
nsh->pdu_type = NS_PDUT_BLOCK;
msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
- msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
+ msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &encoded_nsvci);
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n", gprs_ns2_cause_str(cause));
+ return ns_vc_tx(nsvc, msg);
}
/*! Transmit a NS-BLOCK-ACK on a given NS-VC.
* \param[in] nsvc NS-VC on which the NS-BLOCK is to be transmitted
+ * \param[in] nsvci if given this NSVCI will be encoded. If NULL the nsvc->nsvci will be used.
* \returns 0 in case of success */
-int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc)
+int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc, uint16_t *nsvci)
{
struct msgb *msg;
struct gprs_ns_hdr *nsh;
- uint16_t nsvci = osmo_htons(nsvc->nsvci);
+ uint16_t encoded_nsvci;
+
+ if (nsvci)
+ encoded_nsvci = osmo_htons(*nsvci);
+ else
+ encoded_nsvci = osmo_htons(nsvc->nsvci);
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK ACK");
- msg = gprs_ns2_msgb_alloc();
+ msg = ns2_msgb_alloc();
if (!msg)
return -ENOMEM;
- LOGP(DLNS, LOGL_INFO, "NSEI=%u Tx NS BLOCK ACK (NSVCI=%u)\n", nsvc->nse->nsei, nsvc->nsvci);
-
- /* be conservative and mark it as blocked even now! */
msg->l2h = msgb_put(msg, sizeof(*nsh));
nsh = (struct gprs_ns_hdr *) msg->l2h;
nsh->pdu_type = NS_PDUT_BLOCK_ACK;
- msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
+ msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &encoded_nsvci);
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
+ return ns_vc_tx(nsvc, msg);
}
/*! Transmit a NS-RESET on a given NS-VC.
* \param[in] nsvc NS-VC used for transmission
- * \paam[in] cause Numeric NS cause value
+ * \param[in] cause Numeric NS cause value
* \returns 0 in case of success */
int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
{
@@ -275,17 +277,15 @@ int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
uint16_t nsvci = osmo_htons(nsvc->nsvci);
uint16_t nsei = osmo_htons(nsvc->nse->nsei);
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET");
- msg = gprs_ns2_msgb_alloc();
+ msg = ns2_msgb_alloc();
if (!msg)
return -ENOMEM;
- LOGP(DLNS, LOGL_INFO, "NSEI=%u Tx NS RESET (NSVCI=%u, cause=%s)\n",
- nsvc->nse->nsei, nsvc->nsvci, gprs_ns2_cause_str(cause));
-
msg->l2h = msgb_put(msg, sizeof(*nsh));
nsh = (struct gprs_ns_hdr *) msg->l2h;
nsh->pdu_type = NS_PDUT_RESET;
@@ -294,7 +294,8 @@ int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n", gprs_ns2_cause_str(cause));
+ return ns_vc_tx(nsvc, msg);
}
/*! Transmit a NS-RESET-ACK on a given NS-VC.
@@ -307,11 +308,12 @@ int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
uint16_t nsvci, nsei;
/* Section 9.2.6 */
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET ACK");
- msg = gprs_ns2_msgb_alloc();
+ msg = ns2_msgb_alloc();
if (!msg)
return -ENOMEM;
@@ -323,13 +325,11 @@ int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
nsh->pdu_type = NS_PDUT_RESET_ACK;
- LOGP(DLNS, LOGL_INFO, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n",
- nsvc->nse->nsei, nsvc->nsvci);
-
msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
+ return ns_vc_tx(nsvc, msg);
}
/*! Transmit a NS-UNBLOCK on a given NS-VC.
@@ -337,13 +337,11 @@ int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
* \returns 0 in case of success */
int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
{
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK");
- LOGP(DLNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n",
- nsvc->nse->nsei, nsvc->nsvci);
-
return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK);
}
@@ -353,13 +351,11 @@ int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
* \returns 0 in case of success */
int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc)
{
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK ACK");
- LOGP(DLNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n",
- nsvc->nse->nsei, nsvc->nsvci);
-
return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
}
@@ -368,9 +364,8 @@ int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc)
* \returns 0 in case of success */
int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
{
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
- LOGP(DLNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE (NSVCI=%u)\n",
- nsvc->nse->nsei, nsvc->nsvci);
return ns2_tx_simple(nsvc, NS_PDUT_ALIVE);
}
@@ -380,9 +375,8 @@ int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
* \returns 0 in case of success */
int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc)
{
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
- LOGP(DLNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE_ACK (NSVCI=%u)\n",
- nsvc->nse->nsei, nsvc->nsvci);
return ns2_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
}
@@ -399,12 +393,13 @@ int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
{
struct gprs_ns_hdr *nsh;
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
nsh = (struct gprs_ns_hdr *) msg->l2h;
if (!nsh) {
- LOGP(DLNS, LOGL_ERROR, "Not enough headroom for NS header\n");
+ LOGNSVC(nsvc, LOGL_ERROR, "Not enough headroom for NS header\n");
msgb_free(msg);
return -EIO;
}
@@ -414,7 +409,8 @@ int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
nsh->data[1] = bvci >> 8;
nsh->data[2] = bvci & 0xff;
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_DATA(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, "\n");
+ return ns_vc_tx(nsvc, msg);
}
/*! Transmit a NS-STATUS on a given NS-VC.
@@ -422,14 +418,17 @@ int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
* \param[in] cause Numeric NS cause value
* \param[in] bvci BVCI to be reset within NSVC
* \param[in] orig_msg message causing the STATUS
+ * \param[in] nsvci if given this NSVCI will be encoded. If NULL the nsvc->nsvci will be used.
* \returns 0 in case of success */
int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
- uint16_t bvci, struct msgb *orig_msg)
+ uint16_t bvci, struct msgb *orig_msg, uint16_t *nsvci)
{
- struct msgb *msg = gprs_ns2_msgb_alloc();
+ struct msgb *msg = ns2_msgb_alloc();
struct gprs_ns_hdr *nsh;
- uint16_t nsvci = osmo_htons(nsvc->nsvci);
+ uint16_t encoded_nsvci;
+ unsigned int orig_len, max_orig_len;
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
bvci = osmo_htons(bvci);
@@ -437,39 +436,162 @@ int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
if (!msg)
return -ENOMEM;
- LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n",
- nsvc->nse->nsei, nsvc->nsvci, gprs_ns2_cause_str(cause));
-
msg->l2h = msgb_put(msg, sizeof(*nsh));
nsh = (struct gprs_ns_hdr *) msg->l2h;
nsh->pdu_type = NS_PDUT_STATUS;
msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
- /* Section 9.2.7.1: Static conditions for NS-VCI */
- if (cause == NS_CAUSE_NSVC_BLOCKED ||
- cause == NS_CAUSE_NSVC_UNKNOWN)
- msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
-
- /* Section 9.2.7.2: Static conditions for NS PDU */
switch (cause) {
+ case NS_CAUSE_NSVC_BLOCKED:
+ case NS_CAUSE_NSVC_UNKNOWN:
+ /* Section 9.2.7.1: Static conditions for NS-VCI */
+ if (nsvci)
+ encoded_nsvci = osmo_htons(*nsvci);
+ else
+ encoded_nsvci = osmo_htons(nsvc->nsvci);
+ msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&encoded_nsvci);
+ break;
case NS_CAUSE_SEM_INCORR_PDU:
case NS_CAUSE_PDU_INCOMP_PSTATE:
case NS_CAUSE_PROTO_ERR_UNSPEC:
case NS_CAUSE_INVAL_ESSENT_IE:
case NS_CAUSE_MISSING_ESSENT_IE:
- msgb_tvlv_put(msg, NS_IE_PDU, msgb_l2len(orig_msg),
- orig_msg->l2h);
+ /* Section 9.2.7.2: Static conditions for NS PDU */
+ /* ensure the PDU doesn't exceed the MTU */
+ orig_len = msgb_l2len(orig_msg);
+ max_orig_len = msgb_length(msg) + TVLV_GROSS_LEN(orig_len);
+ if (max_orig_len > nsvc->bind->mtu)
+ orig_len -= max_orig_len - nsvc->bind->mtu;
+ msgb_tvlv_put(msg, NS_IE_PDU, orig_len, orig_msg->l2h);
break;
+ case NS_CAUSE_BVCI_UNKNOWN:
+ /* Section 9.2.7.3: Static conditions for BVCI */
+ msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
+ break;
+
default:
break;
}
- /* Section 9.2.7.3: Static conditions for BVCI */
- if (cause == NS_CAUSE_BVCI_UNKNOWN)
- msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
+ LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n", gprs_ns2_cause_str(cause));
+ return ns_vc_tx(nsvc, msg);
+}
- return nsvc->bind->send_vc(nsvc, msg);
+/*! Encode + Transmit a SNS-ADD/SNS-CHANGE-WEIGHT as per Section 9.3.2/9.3.3.
+ * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
+ * \param[in] pdu The PDU type to send out
+ * \param[in] trans_id The transaction id
+ * \param[in] ip4_elems Array of IPv4 Elements
+ * \param[in] num_ip4_elems number of ip4_elems
+ * \param[in] ip6_elems Array of IPv6 Elements
+ * \param[in] num_ip6_elems number of ip6_elems
+ * \returns 0 on success; negative in case of error */
+static int ns2_tx_sns_procedure(struct gprs_ns2_vc *nsvc,
+ enum ns_pdu_type pdu,
+ uint8_t trans_id,
+ const struct gprs_ns_ie_ip4_elem *ip4_elems,
+ unsigned int num_ip4_elems,
+ const struct gprs_ns_ie_ip6_elem *ip6_elems,
+ unsigned int num_ip6_elems)
+{
+ struct msgb *msg;
+ struct gprs_ns_hdr *nsh;
+ uint16_t nsei;
+
+ if (!nsvc)
+ return -EINVAL;
+
+ if (!ip4_elems && !ip6_elems)
+ return -EINVAL;
+
+ msg = ns2_msgb_alloc();
+
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
+ log_set_context(LOG_CTX_GB_NSVC, nsvc);
+ if (!msg)
+ return -ENOMEM;
+
+ if (!nsvc->nse->bss_sns_fi) {
+ LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+
+ nsei = osmo_htons(nsvc->nse->nsei);
+
+ msg->l2h = msgb_put(msg, sizeof(*nsh));
+ nsh = (struct gprs_ns_hdr *) msg->l2h;
+ nsh->pdu_type = pdu;
+ msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
+ msgb_v_put(msg, trans_id);
+
+ /* List of IP4 Elements 10.3.2c */
+ if (ip4_elems) {
+ msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
+ (const uint8_t *)ip4_elems);
+ } else if (ip6_elems) {
+ /* List of IP6 elements 10.3.2d */
+ msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
+ (const uint8_t *)ip6_elems);
+ }
+
+ return ns_vc_tx(nsvc, msg);
+}
+
+/*! Encode + Transmit a SNS-ADD as per Section 9.3.2.
+ * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
+ * \param[in] trans_id The transaction id
+ * \param[in] ip4_elems Array of IPv4 Elements
+ * \param[in] num_ip4_elems number of ip4_elems
+ * \param[in] ip6_elems Array of IPv6 Elements
+ * \param[in] num_ip6_elems number of ip6_elems
+ * \returns 0 on success; negative in case of error */
+int ns2_tx_sns_add(struct gprs_ns2_vc *nsvc,
+ uint8_t trans_id,
+ const struct gprs_ns_ie_ip4_elem *ip4_elems,
+ unsigned int num_ip4_elems,
+ const struct gprs_ns_ie_ip6_elem *ip6_elems,
+ unsigned int num_ip6_elems)
+{
+ return ns2_tx_sns_procedure(nsvc, SNS_PDUT_ADD, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
+}
+
+/*! Encode + Transmit a SNS-CHANGE-WEIGHT as per Section 9.3.3.
+ * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
+ * \param[in] trans_id The transaction id
+ * \param[in] ip4_elems Array of IPv4 Elements
+ * \param[in] num_ip4_elems number of ip4_elems
+ * \param[in] ip6_elems Array of IPv6 Elements
+ * \param[in] num_ip6_elems number of ip6_elems
+ * \returns 0 on success; negative in case of error */
+int ns2_tx_sns_change_weight(struct gprs_ns2_vc *nsvc,
+ uint8_t trans_id,
+ const struct gprs_ns_ie_ip4_elem *ip4_elems,
+ unsigned int num_ip4_elems,
+ const struct gprs_ns_ie_ip6_elem *ip6_elems,
+ unsigned int num_ip6_elems)
+{
+ return ns2_tx_sns_procedure(nsvc, SNS_PDUT_CHANGE_WEIGHT, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
+}
+
+/*! Encode + Transmit a SNS-DEL as per Section 9.3.6.
+ * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
+ * \param[in] trans_id The transaction id
+ * \param[in] ip4_elems Array of IPv4 Elements
+ * \param[in] num_ip4_elems number of ip4_elems
+ * \param[in] ip6_elems Array of IPv6 Elements
+ * \param[in] num_ip6_elems number of ip6_elems
+ * \returns 0 on success; negative in case of error */
+int ns2_tx_sns_del(struct gprs_ns2_vc *nsvc,
+ uint8_t trans_id,
+ const struct gprs_ns_ie_ip4_elem *ip4_elems,
+ unsigned int num_ip4_elems,
+ const struct gprs_ns_ie_ip6_elem *ip6_elems,
+ unsigned int num_ip6_elems)
+{
+ /* TODO: IP Address field */
+ return ns2_tx_sns_procedure(nsvc, SNS_PDUT_DELETE, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
}
@@ -486,26 +608,27 @@ int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
const struct gprs_ns_ie_ip6_elem *ip6_elems,
unsigned int num_ip6_elems)
{
- struct msgb *msg = gprs_ns2_msgb_alloc();
+ struct msgb *msg;
struct gprs_ns_hdr *nsh;
uint16_t nsei;
if (!nsvc)
return -1;
- msg = gprs_ns2_msgb_alloc();
+ msg = ns2_msgb_alloc();
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
if (!msg)
return -ENOMEM;
if (!nsvc->nse->bss_sns_fi) {
- LOGP(DLNS, LOGL_ERROR, "NSEI=%u Cannot transmit SNS on NSVC without SNS active\n",
- nsvc->nse->nsei);
+ LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
msgb_free(msg);
return -EIO;
}
+
nsei = osmo_htons(nsvc->nse->nsei);
msg->l2h = msgb_put(msg, sizeof(*nsh));
@@ -529,7 +652,10 @@ int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
(const uint8_t *)ip6_elems);
}
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
+ " (trans_id=%u, cause=%s, num_ip4=%u, num_ip6=%u)\n",
+ trans_id, cause ? gprs_ns2_cause_str(*cause) : "NULL", num_ip4_elems, num_ip6_elems);
+ return ns_vc_tx(nsvc, msg);
}
/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4.
@@ -551,15 +677,15 @@ int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
if (!nsvc)
return -1;
- msg = gprs_ns2_msgb_alloc();
+ msg = ns2_msgb_alloc();
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
if (!msg)
return -ENOMEM;
if (!nsvc->nse->bss_sns_fi) {
- LOGP(DLNS, LOGL_ERROR, "NSEI=%u Cannot transmit SNS on NSVC without SNS active\n",
- nsvc->nse->nsei);
+ LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
msgb_free(msg);
return -EIO;
}
@@ -584,7 +710,10 @@ int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
(const uint8_t *)ip6_elems);
}
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
+ " (end_flag=%u, num_ip4=%u, num_ip6=%u)\n",
+ end_flag, num_ip4_elems, num_ip6_elems);
+ return ns_vc_tx(nsvc, msg);
}
/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5.
@@ -600,14 +729,14 @@ int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
if (!nsvc)
return -1;
- msg = gprs_ns2_msgb_alloc();
+ msg = ns2_msgb_alloc();
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
if (!msg)
return -ENOMEM;
if (!nsvc->nse->bss_sns_fi) {
- LOGP(DLNS, LOGL_ERROR, "NSEI=%u Cannot transmit SNS on NSVC without SNS active\n",
- nsvc->nse->nsei);
+ LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
msgb_free(msg);
return -EIO;
}
@@ -623,7 +752,10 @@ int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
if (cause)
msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
- return nsvc->bind->send_vc(nsvc, msg);
+ LOGNSVC(nsvc, LOGL_INFO, "Tx SNS-CONFIG-ACK (cause=%s)\n",
+ cause ? gprs_ns2_cause_str(*cause) : "NULL");
+ LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
+ return ns_vc_tx(nsvc, msg);
}
@@ -637,22 +769,22 @@ int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
int ip4_ep_nr, int ip6_ep_nr)
{
- struct msgb *msg = gprs_ns2_msgb_alloc();
+ struct msgb *msg;
struct gprs_ns_hdr *nsh;
uint16_t nsei;
if (!nsvc)
return -1;
- msg = gprs_ns2_msgb_alloc();
+ msg = ns2_msgb_alloc();
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
if (!msg)
return -ENOMEM;
if (!nsvc->nse->bss_sns_fi) {
- LOGP(DLNS, LOGL_ERROR, "NSEI=%u Cannot transmit SNS on NSVC without SNS active\n",
- nsvc->nse->nsei);
+ LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
msgb_free(msg);
return -EIO;
}
@@ -672,7 +804,10 @@ int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_n
if (ip6_ep_nr >= 0)
msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, ip6_ep_nr);
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
+ " (reset=%u, max_nr_nsvc=%u, num_ip4=%d, num_ip6=%d)\n",
+ reset_flag, max_nr_nsvc, ip4_ep_nr, ip6_ep_nr);
+ return ns_vc_tx(nsvc, msg);
}
/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8.
@@ -681,17 +816,17 @@ int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_n
* \returns 0 on success; negative in case of error */
int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
{
- struct msgb *msg = gprs_ns2_msgb_alloc();
+ struct msgb *msg = ns2_msgb_alloc();
struct gprs_ns_hdr *nsh;
uint16_t nsei;
+ log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
log_set_context(LOG_CTX_GB_NSVC, nsvc);
if (!msg)
return -ENOMEM;
if (!nsvc->nse->bss_sns_fi) {
- LOGP(DLNS, LOGL_ERROR, "NSEI=%u Cannot transmit SNS on NSVC without SNS active\n",
- nsvc->nse->nsei);
+ LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
msgb_free(msg);
return -EIO;
}
@@ -707,7 +842,7 @@ int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
if (cause)
msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
- return nsvc->bind->send_vc(nsvc, msg);
+ LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n",
+ cause ? gprs_ns2_cause_str(*cause) : "NULL");
+ return ns_vc_tx(nsvc, msg);
}
-
-