diff options
Diffstat (limited to 'src/gb/gprs_ns2_message.c')
-rw-r--r-- | src/gb/gprs_ns2_message.c | 395 |
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); } - - |