aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/gprs/gprs_bssgp2.h39
-rw-r--r--include/osmocom/gprs/protocol/gsm_08_18.h8
-rw-r--r--src/gb/gprs_bssgp2.c206
-rw-r--r--src/gb/libosmogb.map6
4 files changed, 259 insertions, 0 deletions
diff --git a/include/osmocom/gprs/gprs_bssgp2.h b/include/osmocom/gprs/gprs_bssgp2.h
index 0ab36191..bf814cb7 100644
--- a/include/osmocom/gprs/gprs_bssgp2.h
+++ b/include/osmocom/gprs/gprs_bssgp2.h
@@ -4,10 +4,41 @@
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/gprs/gprs_ns2.h>
+struct bssgp2_flow_ctrl;
struct gprs_ns2_inst;
struct gprs_ra_id;
struct msgb;
+struct bssgp2_flow_ctrl {
+ uint8_t tag;
+ /* maximum bucket size (Bmax) in bytes */
+ uint64_t bucket_size_max;
+ /*! bucket leak rate in _bytes_ per second */
+ uint64_t bucket_leak_rate;
+ /* percentage how full the given bucket is */
+ uint8_t bucket_full_ratio;
+ bool bucket_full_ratio_present;
+ union {
+ /*! FC-BVC specifi members */
+ struct {
+ /*! default maximum bucket size per MS in bytes */
+ uint64_t bmax_default_ms;
+ /*! default bucket leak rate (R) for MS flow control bucket */
+ uint64_t r_default_ms;
+
+ /*! average milliseconds of queueing delay for a BVC */
+ uint32_t measurement;
+ bool measurement_present;
+ } bvc;
+ /*! FC-MS specifi members */
+ struct {
+ /*! TLLI of the MS */
+ uint32_t tlli;
+ } ms;
+ } u;
+};
+
+
int bssgp2_nsi_tx_ptp(struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci,
struct msgb *msg, uint32_t lsp);
@@ -29,3 +60,11 @@ struct msgb *bssgp2_enc_bvc_reset_ack(uint16_t bvci, const struct gprs_ra_id *ra
const uint8_t *feat_bm, const uint8_t *ext_feat_bm);
struct msgb *bssgp2_enc_status(uint8_t cause, const uint16_t *bvci, const struct msgb *orig_msg);
+
+
+int bssgp2_dec_fc_bvc(struct bssgp2_flow_ctrl *fc, const struct tlv_parsed *tp);
+struct msgb *bssgp2_enc_fc_bvc(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran);
+struct msgb *bssgp2_enc_fc_bvc_ack(uint8_t tag);
+int bssgp2_dec_fc_ms(struct bssgp2_flow_ctrl *fc, struct tlv_parsed *tp);
+struct msgb *bssgp2_enc_fc_ms(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran);
+struct msgb *bssgp2_enc_fc_ms_ack(uint32_t tlli, uint8_t tag);
diff --git a/include/osmocom/gprs/protocol/gsm_08_18.h b/include/osmocom/gprs/protocol/gsm_08_18.h
index 0ce28f55..466b0c51 100644
--- a/include/osmocom/gprs/protocol/gsm_08_18.h
+++ b/include/osmocom/gprs/protocol/gsm_08_18.h
@@ -341,3 +341,11 @@ enum gprs_bssgp_cause {
#define BSSGP_XFEAT_DCN 0x20 /* Dedicated CN */
#define BSSGP_XFEAT_eDRX 0x40 /* eDRX */
#define BSSGP_XFEAT_MSAD 0x80 /* MS-assisted Dedicated CN selection */
+
+/* Flow Control Granularity (Section 11.3.102) */
+enum bssgp_fc_granularity {
+ BSSGP_FC_GRAN_100 = 0,
+ BSSGP_FC_GRAN_1000 = 1,
+ BSSGP_FC_GRAN_10000 = 2,
+ BSSGP_FC_GRAN_100000 = 3,
+};
diff --git a/src/gb/gprs_bssgp2.c b/src/gb/gprs_bssgp2.c
index e741fb46..a54a8d93 100644
--- a/src/gb/gprs_bssgp2.c
+++ b/src/gb/gprs_bssgp2.c
@@ -238,3 +238,209 @@ struct msgb *bssgp2_enc_status(uint8_t cause, const uint16_t *bvci, const struct
return msg;
}
+
+static const unsigned int bssgp_fc_gran_tbl[] = {
+ [BSSGP_FC_GRAN_100] = 100,
+ [BSSGP_FC_GRAN_1000] = 1000,
+ [BSSGP_FC_GRAN_10000] = 10000,
+ [BSSGP_FC_GRAN_100000] = 100000,
+};
+
+/*! Decode a FLOW-CONTROL-BVC PDU as per TS 48.018 Section 10.4.4.
+ * \param[out] fc caller-allocated memory for parsed output
+ * \param[in] tp pre-parsed TLVs; caller must ensure mandatory IE presence/length
+ * \returns 0 on success; negative in case of error */
+int bssgp2_dec_fc_bvc(struct bssgp2_flow_ctrl *fc, const struct tlv_parsed *tp)
+{
+ unsigned int granularity = 100;
+
+ /* optional "Flow Control Granularity IE" (11.3.102); applies to
+ * bucket_size_max, bucket_leak_rate and PFC FC params IE */
+ if (TLVP_PRESENT(tp, BSSGP_IE_FLOW_CTRL_GRANULARITY)) {
+ uint8_t gran = *TLVP_VAL(tp, BSSGP_IE_FLOW_CTRL_GRANULARITY);
+ granularity = bssgp_fc_gran_tbl[gran & 3];
+ }
+
+ /* mandatory IEs */
+ fc->tag = *TLVP_VAL(tp, BSSGP_IE_TAG);
+ fc->bucket_size_max = granularity * tlvp_val16be(tp, BSSGP_IE_BVC_BUCKET_SIZE);
+ fc->bucket_leak_rate = (granularity * tlvp_val16be(tp, BSSGP_IE_BUCKET_LEAK_RATE)) / 8;
+ fc->u.bvc.bmax_default_ms = granularity * tlvp_val16be(tp, BSSGP_IE_BMAX_DEFAULT_MS);
+ fc->u.bvc.r_default_ms = (granularity * tlvp_val16be(tp, BSSGP_IE_R_DEFAULT_MS)) / 8;
+
+ /* optional / conditional */
+ if (TLVP_PRESENT(tp, BSSGP_IE_BUCKET_FULL_RATIO)) {
+ fc->bucket_full_ratio_present = true;
+ fc->bucket_full_ratio = *TLVP_VAL(tp, BSSGP_IE_BUCKET_FULL_RATIO);
+ } else {
+ fc->bucket_full_ratio_present = false;
+ }
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_BVC_MEASUREMENT)) {
+ uint16_t val = tlvp_val16be(tp, BSSGP_IE_BVC_MEASUREMENT);
+ fc->u.bvc.measurement_present = true;
+ /* convert from centi-seconds to milli-seconds */
+ if (val == 0xffff)
+ fc->u.bvc.measurement = 0xffffffff;
+ else
+ fc->u.bvc.measurement = val * 10;
+ } else {
+ fc->u.bvc.measurement_present = false;
+ }
+
+ return 0;
+
+}
+
+/*! Encode a FLOW-CONTROL-BVC PDU as per TS 48.018 Section 10.4.4.
+ * \param[in] fc structure describing to-be-encoded FC parameters
+ * \param[in] gran if non-NULL: Encode using specified unit granularity
+ * \returns encoded PDU or NULL in case of error */
+struct msgb *bssgp2_enc_fc_bvc(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ struct bssgp_normal_hdr *bgph;
+ unsigned int granularity = 100;
+
+ if (gran)
+ granularity = bssgp_fc_gran_tbl[*gran & 3];
+
+ if (!msg)
+ return NULL;
+
+ bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+ bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC;
+
+ msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &fc->tag);
+ msgb_tvlv_put_16be(msg, BSSGP_IE_BVC_BUCKET_SIZE, fc->bucket_size_max / granularity);
+ msgb_tvlv_put_16be(msg, BSSGP_IE_BUCKET_LEAK_RATE, fc->bucket_leak_rate * 8 / granularity);
+ msgb_tvlv_put_16be(msg, BSSGP_IE_BMAX_DEFAULT_MS, fc->u.bvc.bmax_default_ms / granularity);
+ msgb_tvlv_put_16be(msg, BSSGP_IE_R_DEFAULT_MS, fc->u.bvc.r_default_ms * 8 / granularity);
+
+ if (fc->bucket_full_ratio_present)
+ msgb_tvlv_put(msg, BSSGP_IE_BUCKET_FULL_RATIO, 1, &fc->bucket_full_ratio);
+
+ if (fc->u.bvc.measurement_present) {
+ uint16_t val;
+ /* convert from ms to cs */
+ if (fc->u.bvc.measurement == 0xffffffff)
+ val = 0xffff;
+ else
+ val = fc->u.bvc.measurement / 10;
+ msgb_tvlv_put_16be(msg, BSSGP_IE_BVC_MEASUREMENT, val);
+ }
+
+ if (gran) {
+ uint8_t val = *gran & 3;
+ msgb_tvlv_put(msg, BSSGP_IE_FLOW_CTRL_GRANULARITY, 1, &val);
+ }
+
+ return msg;
+}
+
+/*! Encode a FLOW-CONTROL-BVC-ACK PDU as per TS 48.018 Section 10.4.4.
+ * \param[in] tag the tag IE value to encode
+ * \returns encoded PDU or NULL in case of error */
+struct msgb *bssgp2_enc_fc_bvc_ack(uint8_t tag)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ struct bssgp_normal_hdr *bgph;
+
+ if (!msg)
+ return NULL;
+
+ bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+ bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;
+
+ msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);
+
+ return msg;
+}
+
+/*! Decode a FLOW-CONTROL-MS PDU as per TS 48.018 Section 10.4.6.
+ * \param[out] fc caller-allocated memory for parsed output
+ * \param[in] tp pre-parsed TLVs; caller must ensure mandatory IE presence/length
+ * \returns 0 on success; negative in case of error */
+int bssgp2_dec_fc_ms(struct bssgp2_flow_ctrl *fc, struct tlv_parsed *tp)
+{
+ unsigned int granularity = 100;
+
+ /* optional "Flow Control Granularity IE" (11.3.102); applies to
+ * bucket_size_max, bucket_leak_rate and PFC FC params IE */
+ if (TLVP_PRESENT(tp, BSSGP_IE_FLOW_CTRL_GRANULARITY)) {
+ uint8_t gran = *TLVP_VAL(tp, BSSGP_IE_FLOW_CTRL_GRANULARITY);
+ granularity = bssgp_fc_gran_tbl[gran & 3];
+ }
+
+ /* mandatory IEs */
+ fc->u.ms.tlli = tlvp_val32be(tp, BSSGP_IE_TLLI);
+ fc->tag = *TLVP_VAL(tp, BSSGP_IE_TAG);
+ fc->bucket_size_max = granularity * tlvp_val16be(tp, BSSGP_IE_MS_BUCKET_SIZE);
+ fc->bucket_leak_rate = (granularity * tlvp_val16be(tp, BSSGP_IE_BUCKET_LEAK_RATE)) / 8;
+
+ /* optional / conditional */
+ if (TLVP_PRESENT(tp, BSSGP_IE_BUCKET_FULL_RATIO)) {
+ fc->bucket_full_ratio_present = true;
+ fc->bucket_full_ratio = *TLVP_VAL(tp, BSSGP_IE_BUCKET_FULL_RATIO);
+ } else {
+ fc->bucket_full_ratio_present = false;
+ }
+
+ return 0;
+}
+
+/*! Encode a FLOW-CONTROL-MS PDU as per TS 48.018 Section 10.4.6.
+ * \param[in] fc structure describing to-be-encoded FC parameters
+ * \param[in] gran if non-NULL: Encode using specified unit granularity
+ * \returns encoded PDU or NULL in case of error */
+struct msgb *bssgp2_enc_fc_ms(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ struct bssgp_normal_hdr *bgph;
+ unsigned int granularity = 100;
+
+ if (gran)
+ granularity = bssgp_fc_gran_tbl[*gran & 3];
+
+ if (!msg)
+ return NULL;
+
+ bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+ bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_MS;
+
+ msgb_tvlv_put_32be(msg, BSSGP_IE_TLLI, fc->u.ms.tlli);
+ msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &fc->tag);
+ msgb_tvlv_put_16be(msg, BSSGP_IE_MS_BUCKET_SIZE, fc->bucket_size_max / granularity);
+ msgb_tvlv_put_16be(msg, BSSGP_IE_BUCKET_LEAK_RATE, fc->bucket_leak_rate * 8 / granularity);
+
+ if (fc->bucket_full_ratio_present)
+ msgb_tvlv_put(msg, BSSGP_IE_BUCKET_FULL_RATIO, 1, &fc->bucket_full_ratio);
+
+ if (gran) {
+ uint8_t val = *gran & 3;
+ msgb_tvlv_put(msg, BSSGP_IE_FLOW_CTRL_GRANULARITY, 1, &val);
+ }
+
+ return msg;
+}
+
+/*! Encode a FLOW-CONTROL-BVC-ACK PDU as per TS 48.018 Section 10.4.7.
+ * \param[in] tlli the TLLI IE value to encode
+ * \param[in] tag the tag IE value to encode
+ * \returns encoded PDU or NULL in case of error */
+struct msgb *bssgp2_enc_fc_ms_ack(uint32_t tlli, uint8_t tag)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ struct bssgp_normal_hdr *bgph;
+
+ if (!msg)
+ return NULL;
+
+ bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+ bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;
+
+ msgb_tvlv_put_32be(msg, BSSGP_IE_TLLI, tlli);
+ msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);
+
+ return msg;
+}
diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map
index e605d27d..f8ad901c 100644
--- a/src/gb/libosmogb.map
+++ b/src/gb/libosmogb.map
@@ -47,12 +47,18 @@ bssgp_nsi;
bssgp2_nsi_tx_ptp;
bssgp2_nsi_tx_sig;
+bssgp2_dec_fc_bvc;
+bssgp2_dec_fc_ms;
bssgp2_enc_bvc_block;
bssgp2_enc_bvc_block_ack;
bssgp2_enc_bvc_unblock;
bssgp2_enc_bvc_unblock_ack;
bssgp2_enc_bvc_reset;
bssgp2_enc_bvc_reset_ack;
+bssgp2_enc_fc_bvc;
+bssgp2_enc_fc_bvc_ack;
+bssgp2_enc_fc_ms;
+bssgp2_enc_fc_ms_ack;
bssgp2_enc_status;
bssgp_bvc_fsm_alloc_sig_bss;