diff options
Diffstat (limited to 'src/gb/gprs_ns.c')
-rw-r--r-- | src/gb/gprs_ns.c | 180 |
1 files changed, 178 insertions, 2 deletions
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index 976a1018..660dfece 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -1,8 +1,9 @@ /*! \file gprs_ns.c * GPRS Networks Service (NS) messages on the Gb interface. - * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05). */ + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) + * as well as its successor 3GPP TS 48.016 */ /* - * (C) 2009-2017 by Harald Welte <laforge@gnumonks.org> + * (C) 2009-2018 by Harald Welte <laforge@gnumonks.org> * (C) 2016-2017 sysmocom - s.f.m.c. GmbH * * All Rights Reserved @@ -86,6 +87,7 @@ #include <osmocom/gprs/gprs_ns_frgre.h> #include "common_vty.h" +#include "gb_internal.h" #define ns_set_state(ns_, st_) ns_set_state_with_log(ns_, st_, false, __FILE__, __LINE__) #define ns_set_remote_state(ns_, st_) ns_set_state_with_log(ns_, st_, true, __FILE__, __LINE__) @@ -99,6 +101,12 @@ static const struct tlv_definition ns_att_tlvdef = { [NS_IE_PDU] = { TLV_TYPE_TvLV, 0 }, [NS_IE_BVCI] = { TLV_TYPE_TvLV, 0 }, [NS_IE_NSEI] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_IPv4_LIST] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_IPv6_LIST] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_MAX_NR_NSVC] = { TLV_TYPE_FIXED, 2 }, + [NS_IE_IPv4_EP_NR] = { TLV_TYPE_FIXED, 2 }, + [NS_IE_IPv6_EP_NR] = { TLV_TYPE_FIXED, 2 }, + [NS_IE_RESET_FLAG] = { TLV_TYPE_TV, 0 }, }, }; @@ -750,6 +758,174 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) return gprs_ns_tx(nsvc, msg); } +/*! Encode + Transmit a SNS-ACK as per Section 9.3.1. + * \param[in] nsvc NS-VC through which to transmit the ACK + * \param[in] trans_id Transaction ID which to acknowledge + * \param[in] cause Pointer to cause value (NULL if no cause to be sent) + * \param[in] ip4_elems Array of IPv4 Elements + * \param[in] num_ip4_elems number of ip4_elems + * \returns 0 on success; negative in case of error */ +int gprs_ns_tx_sns_ack(struct gprs_nsvc *nsvc, uint8_t trans_id, uint8_t *cause, + const struct gprs_ns_ie_ip4_elem *ip4_elems, + unsigned int num_ip4_elems) +{ + struct msgb *msg = gprs_ns_msgb_alloc(); + struct gprs_ns_hdr *nsh; + uint16_t nsei; + + log_set_context(LOG_CTX_GB_NSVC, nsvc); + if (!msg) + return -ENOMEM; + + nsei = osmo_htons(nsvc->nsei); + + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; + + nsh->pdu_type = SNS_PDUT_ACK; + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); + msgb_v_put(msg, trans_id); + if (cause) + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause); + if (ip4_elems) { + /* List of IP4 Elements 10.3.2c */ + msgb_tvlv_put(msg, NS_IE_IPv4_LIST, + num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem), + (const uint8_t *)ip4_elems); + } + /* FIXME: List of IP6 elements 10.3.2d */ + return gprs_ns_tx(nsvc, msg); +} + +/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4. + * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG + * \param[in] end_flag Whether or not this is the last SNS-CONFIG + * \param[in] ip4_elems Array of IPv4 Elements + * \param[in] num_ip4_elems number of ip4_elems + * \returns 0 on success; negative in case of error */ +int gprs_ns_tx_sns_config(struct gprs_nsvc *nsvc, bool end_flag, + const struct gprs_ns_ie_ip4_elem *ip4_elems, + unsigned int num_ip4_elems) +{ + struct msgb *msg = gprs_ns_msgb_alloc(); + struct gprs_ns_hdr *nsh; + uint16_t nsei; + + log_set_context(LOG_CTX_GB_NSVC, nsvc); + if (!msg) + return -ENOMEM; + + nsei = osmo_htons(nsvc->nsei); + + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; + + nsh->pdu_type = SNS_PDUT_CONFIG; + + msgb_v_put(msg, end_flag ? 0x01 : 0x00); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); + + /* List of IP4 Elements 10.3.2c */ + msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem), + (const uint8_t *)ip4_elems); + /* FIXME: List of IP6 elements 10.3.2d */ + + return gprs_ns_tx(nsvc, msg); +} + +/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5. + * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG-ACK + * \param[in] cause Pointer to cause value (NULL if no cause to be sent) + * \returns 0 on success; negative in case of error */ +int gprs_ns_tx_sns_config_ack(struct gprs_nsvc *nsvc, uint8_t *cause) +{ + struct msgb *msg = gprs_ns_msgb_alloc(); + struct gprs_ns_hdr *nsh; + uint16_t nsei; + + log_set_context(LOG_CTX_GB_NSVC, nsvc); + if (!msg) + return -ENOMEM; + + nsei = osmo_htons(nsvc->nsei); + + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; + + nsh->pdu_type = SNS_PDUT_CONFIG_ACK; + + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); + if (cause) + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause); + + return gprs_ns_tx(nsvc, msg); +} + + +/*! Encode + transmit a SNS-SIZE as per Section 9.3.7. + * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE + * \param[in] reset_flag Whether or not to add a RESET flag + * \param[in] max_nr_nsvc Maximum number of NS-VCs + * \param[in] ip4_ep_nr Number of IPv4 endpoints (NULL if none) + * \param[in] ip6_ep_nr Number of IPv6 endpoints (NULL if none) + * \returns 0 on success; negative in case of error */ +int gprs_ns_tx_sns_size(struct gprs_nsvc *nsvc, bool reset_flag, uint16_t max_nr_nsvc, + uint16_t *ip4_ep_nr, uint16_t *ip6_ep_nr) +{ + struct msgb *msg = gprs_ns_msgb_alloc(); + struct gprs_ns_hdr *nsh; + uint16_t nsei; + + log_set_context(LOG_CTX_GB_NSVC, nsvc); + if (!msg) + return -ENOMEM; + + nsei = osmo_htons(nsvc->nsei); + + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; + + nsh->pdu_type = SNS_PDUT_SIZE; + + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); + msgb_tv_put(msg, NS_IE_RESET_FLAG, reset_flag ? 0x01 : 0x00); + msgb_tv16_put(msg, NS_IE_MAX_NR_NSVC, max_nr_nsvc); + if (ip4_ep_nr) + msgb_tv16_put(msg, NS_IE_IPv4_EP_NR, *ip4_ep_nr); + if (ip6_ep_nr) + msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, *ip6_ep_nr); + + return gprs_ns_tx(nsvc, msg); +} + +/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8. + * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE-ACK + * \param[in] cause Pointer to cause value (NULL if no cause to be sent) + * \returns 0 on success; negative in case of error */ +int gprs_ns_tx_sns_size_ack(struct gprs_nsvc *nsvc, uint8_t *cause) +{ + struct msgb *msg = gprs_ns_msgb_alloc(); + struct gprs_ns_hdr *nsh; + uint16_t nsei; + + log_set_context(LOG_CTX_GB_NSVC, nsvc); + if (!msg) + return -ENOMEM; + + nsei = osmo_htons(nsvc->nsei); + + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; + + nsh->pdu_type = SNS_PDUT_SIZE_ACK; + + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); + if (cause) + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause); + + return gprs_ns_tx(nsvc, msg); +} + /*! High-level function for transmitting a NS-UNITDATA messsage * \param[in] nsi NS-instance on which we shall transmit * \param[in] msg struct msgb to be trasnmitted |