From: Taehee Yoo <[email protected]>

[ Upstream commit 6b01b1d9b2d38dc84ac398bfe9f00baff06a31e5 ]

GTP RX packet path lookups pdp context with TID. If duplicate TID pdp
contexts are existing in the list, it couldn't select correct pdp context.
So, TID value  should be unique.
GTP TX packet path lookups pdp context with ms_addr. If duplicate ms_addr pdp
contexts are existing in the list, it couldn't select correct pdp context.
So, ms_addr value should be unique.

Fixes: 459aa660eb1d ("gtp: add initial driver for datapath of GPRS Tunneling 
Protocol (GTP-U)")
Signed-off-by: Taehee Yoo <[email protected]>
Signed-off-by: Jakub Kicinski <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
---
 drivers/net/gtp.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index d178d5bad7e4..7ca96ba00f20 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -931,24 +931,31 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
        }
 }
 
-static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
-                       struct genl_info *info)
+static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
+                      struct genl_info *info)
 {
+       struct pdp_ctx *pctx, *pctx_tid = NULL;
        struct net_device *dev = gtp->dev;
        u32 hash_ms, hash_tid = 0;
-       struct pdp_ctx *pctx;
+       unsigned int version;
        bool found = false;
        __be32 ms_addr;
 
        ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
        hash_ms = ipv4_hashfn(ms_addr) % gtp->hash_size;
+       version = nla_get_u32(info->attrs[GTPA_VERSION]);
 
-       hlist_for_each_entry_rcu(pctx, &gtp->addr_hash[hash_ms], hlist_addr) {
-               if (pctx->ms_addr_ip4.s_addr == ms_addr) {
-                       found = true;
-                       break;
-               }
-       }
+       pctx = ipv4_pdp_find(gtp, ms_addr);
+       if (pctx)
+               found = true;
+       if (version == GTP_V0)
+               pctx_tid = gtp0_pdp_find(gtp,
+                                        nla_get_u64(info->attrs[GTPA_TID]));
+       else if (version == GTP_V1)
+               pctx_tid = gtp1_pdp_find(gtp,
+                                        nla_get_u32(info->attrs[GTPA_I_TEI]));
+       if (pctx_tid)
+               found = true;
 
        if (found) {
                if (info->nlhdr->nlmsg_flags & NLM_F_EXCL)
@@ -956,6 +963,11 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock 
*sk,
                if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE)
                        return -EOPNOTSUPP;
 
+               if (pctx && pctx_tid)
+                       return -EEXIST;
+               if (!pctx)
+                       pctx = pctx_tid;
+
                ipv4_pdp_fill(pctx, info);
 
                if (pctx->gtp_version == GTP_V0)
@@ -1079,7 +1091,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
                goto out_unlock;
        }
 
-       err = ipv4_pdp_add(gtp, sk, info);
+       err = gtp_pdp_add(gtp, sk, info);
 
 out_unlock:
        rcu_read_unlock();
-- 
2.20.1

Reply via email to