mirror of https://gerrit.osmocom.org/libosmocore
gprs_ns: Add code for SNS-SIZE and SNS-CONFIG encoding
Modern NS specifications contain a SNS (Sub Network Service) for negotiating IP/port/weight parameters of NS-over-IP links dynamically. This patch adds message encoding routines for SNS-CONFIG, SNS-SIZE and their respective acknowledgements. Related: OS#3372 Change-Id: I5c47e1c3c10deb89a7470ee2c03adfc174accc93
This commit is contained in:
parent
99273c7662
commit
17a642d8ff
|
@ -17,6 +17,15 @@ struct gprs_ns_hdr {
|
|||
uint8_t data[0]; /*!< variable-length payload */
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/*! Section 10.3.2c List of IP4 Elements */
|
||||
struct gprs_ns_ie_ip4_elem {
|
||||
uint32_t ip_addr;
|
||||
uint16_t udp_port;
|
||||
uint8_t sig_weight;
|
||||
uint8_t data_weight;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
extern const struct value_string gprs_ns_pdu_strings[];
|
||||
|
||||
/*! NS PDU Type (TS 08.16, Section 10.3.7, Table 14) */
|
||||
|
|
|
@ -6,7 +6,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
|
|||
AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN} -fno-strict-aliasing $(TALLOC_CFLAGS)
|
||||
|
||||
# FIXME: this should eventually go into a milenage/Makefile.am
|
||||
noinst_HEADERS = common_vty.h
|
||||
noinst_HEADERS = common_vty.h gb_internal.h
|
||||
|
||||
if ENABLE_GB
|
||||
lib_LTLIBRARIES = libosmogb.la
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/gsm/tlv.h>
|
||||
#include <osmocom/gprs/gprs_ns.h>
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
int gprs_ns_tx_sns_config_ack(struct gprs_nsvc *nsvc, uint8_t *cause);
|
||||
|
||||
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);
|
||||
|
||||
int gprs_ns_tx_sns_size_ack(struct gprs_nsvc *nsvc, uint8_t *cause);
|
180
src/gb/gprs_ns.c
180
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
|
||||
|
|
Loading…
Reference in New Issue