laforge has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/libosmocore/+/21610 )


Change subject: bssgp2: Encoding + Decoding functions for BVC and MS flow 
control
......................................................................

bssgp2: Encoding + Decoding functions for BVC and MS flow control

Change-Id: I9c89bb1c03550930c07aad7ff8f67129ee7a6320
Related: OS#4891
---
M include/osmocom/gprs/gprs_bssgp2.h
M include/osmocom/gprs/protocol/gsm_08_18.h
M src/gb/gprs_bssgp2.c
M src/gb/libosmogb.map
4 files changed, 259 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/10/21610/1

diff --git a/include/osmocom/gprs/gprs_bssgp2.h 
b/include/osmocom/gprs/gprs_bssgp2.h
index 0ab3619..bf814cb 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 @@
                                      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 0ce28f5..466b0c5 100644
--- a/include/osmocom/gprs/protocol/gsm_08_18.h
+++ b/include/osmocom/gprs/protocol/gsm_08_18.h
@@ -341,3 +341,11 @@
 #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 ec2199a..70d5bba 100644
--- a/src/gb/gprs_bssgp2.c
+++ b/src/gb/gprs_bssgp2.c
@@ -219,3 +219,209 @@

        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 e605d27..f8ad901 100644
--- a/src/gb/libosmogb.map
+++ b/src/gb/libosmogb.map
@@ -47,12 +47,18 @@

 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;

--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/21610
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I9c89bb1c03550930c07aad7ff8f67129ee7a6320
Gerrit-Change-Number: 21610
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <lafo...@osmocom.org>
Gerrit-MessageType: newchange

Reply via email to