diff --git a/include/qer.h b/include/qer.h index 428c11f..bbb832b 100644 --- a/include/qer.h +++ b/include/qer.h @@ -8,6 +8,13 @@ #include "dev.h" #include "pdr.h" +// TS 29.244 8.2.7 Gate Status +// 0 OPEN, 1 CLOSED +// 2, 3 For future use. Shall not be sent. +// If received, shall be interpreted as the value "1" +#define QER_UL_GATE_CLOSE (0x1 << 2) +#define QER_DL_GATE_CLOSE (0x1 << 0) + struct qer { struct hlist_node hlist_id; u64 seid; diff --git a/src/genl/genl_qer.c b/src/genl/genl_qer.c index d041eb8..a8129c0 100644 --- a/src/genl/genl_qer.c +++ b/src/genl/genl_qer.c @@ -7,6 +7,7 @@ #include "genl_qer.h" #include "qer.h" #include "hash.h" +#include "log.h" #include #include @@ -309,8 +310,10 @@ static int qer_fill(struct qer *qer, struct gtp5g_dev *gtp, struct genl_info *in else qer->seid = 0; - if (info->attrs[GTP5G_QER_GATE]) + if (info->attrs[GTP5G_QER_GATE]) { qer->ul_dl_gate = nla_get_u8(info->attrs[GTP5G_QER_GATE]); + GTP5G_INF(NULL, "QER Gate Status (%x)", qer->ul_dl_gate); + } /* MBR */ if (info->attrs[GTP5G_QER_MBR] && diff --git a/src/gtpu/encap.c b/src/gtpu/encap.c index bad4bc2..15d0dd0 100644 --- a/src/gtpu/encap.c +++ b/src/gtpu/encap.c @@ -698,7 +698,7 @@ static int gtp5g_rx(struct pdr *pdr, struct sk_buff *skb, { int rt = -1; struct far *far = rcu_dereference(pdr->far); - // struct qer *qer = rcu_dereference(pdr->qer); + struct qer __rcu *qer_with_rate = rcu_dereference(pdr->qer_with_rate); if (!far) { GTP5G_ERR(pdr->dev, "FAR not exists for PDR(%u)\n", pdr->id); @@ -716,6 +716,10 @@ static int gtp5g_rx(struct pdr *pdr, struct sk_buff *skb, rt = gtp5g_drop_skb_encap(skb, pdr->dev, pdr); break; case FAR_ACTION_FORW: + if (qer_with_rate->ul_dl_gate & QER_UL_GATE_CLOSE) { + GTP5G_TRC(pdr->dev, "QER UL gate is closed, drop the packet"); + return PKT_DROPPED; + } rt = gtp5g_fwd_skb_encap(skb, pdr->dev, hdrlen, pdr, far); break; case FAR_ACTION_BUFF: @@ -991,6 +995,7 @@ int gtp5g_handle_skb_ipv4(struct sk_buff *skb, struct net_device *dev, struct far *far; //struct gtp5g_qer *qer; struct iphdr *iph; + struct qer __rcu *qer_with_rate = NULL; /* Read the IP destination address and resolve the PDR. * Prepend PDR header with TEI/TID from PDR. @@ -1014,6 +1019,7 @@ int gtp5g_handle_skb_ipv4(struct sk_buff *skb, struct net_device *dev, // __func__, __LINE__, qer->id, qer->qfi); //} + qer_with_rate = rcu_dereference(pdr->qer_with_rate); far = rcu_dereference(pdr->far); if (far) { // One and only one of the DROP, FORW and BUFF flags shall be set to 1. @@ -1023,6 +1029,10 @@ int gtp5g_handle_skb_ipv4(struct sk_buff *skb, struct net_device *dev, case FAR_ACTION_DROP: return gtp5g_drop_skb_ipv4(skb, dev, pdr); case FAR_ACTION_FORW: + if (qer_with_rate->ul_dl_gate & QER_DL_GATE_CLOSE) { + GTP5G_TRC(pdr->dev, "QER DL gate is closed, drop the packet"); + return PKT_DROPPED; + } return gtp5g_fwd_skb_ipv4(skb, dev, pktinfo, pdr, far); case FAR_ACTION_BUFF: return gtp5g_buf_skb_ipv4(skb, dev, pdr, far);