summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@gnumonks.org>2014-02-20 12:17:00 +0100
committerPablo Neira Ayuso <pablo@gnumonks.org>2014-02-20 12:48:40 +0100
commitd123a0c0f57348422832c915b82a15d79b2a0c5b (patch)
tree9bfc7f0c0453ebed44122b4b8c811edeacbca523
parentd7cdbddebdd5620d6b2d3b94380e693f3d6671a0 (diff)
gtp: fix handling of messages in the encap input path
* pass up to the stack if we don't know what to do. * drop packet if not well-formed or not found in our PDP ctx database.
-rw-r--r--gtp.c48
1 files changed, 26 insertions, 22 deletions
diff --git a/gtp.c b/gtp.c
index 7c14828..6a1feee 100644
--- a/gtp.c
+++ b/gtp.c
@@ -217,10 +217,12 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx)
return ret;
}
+/* 1 means pass up to the stack, -1 means drop and 0 means decapsulated */
static int gtp0_udp_encap_recv(struct gtp_instance *gti, struct sk_buff *skb)
{
struct gtp0_header *gtp0;
struct pdp_ctx *pctx;
+ int ret = 0;
u64 tid;
pr_info("gtp0 udp received\n");
@@ -229,33 +231,31 @@ static int gtp0_udp_encap_recv(struct gtp_instance *gti, struct sk_buff *skb)
/* check for GTP Version 0 */
if ((gtp0->flags >> 5) != GTP_V0)
- goto out;
+ return 1;
/* check if it is T-PDU. if not -> userspace */
if (gtp0->type != GTP_TPDU)
- goto out;
+ return 1;
/* look-up the PDP context for the Tunnel ID */
tid = be64_to_cpu(gtp0->tid);
rcu_read_lock();
pctx = gtp0_pdp_find(gti, tid);
- if (!pctx)
+ if (!pctx) {
+ ret = -1;
goto out_rcu;
+ }
/* get rid of the GTP header */
__skb_pull(skb, sizeof(*gtp0));
if (!gtp_check_src_ms(skb, pctx))
- goto out_rcu;
-
- rcu_read_unlock();
- return 0;
+ ret = -1;
out_rcu:
rcu_read_unlock();
-out:
- return -1;
+ return ret;
}
static u8 gtp1u_header_len[] = {
@@ -274,35 +274,38 @@ static int gtp1u_udp_encap_recv(struct gtp_instance *gti, struct sk_buff *skb)
struct gtp1_header *gtp1;
struct pdp_ctx *pctx;
unsigned int gtp1_hdrlen = sizeof(*gtp1);
+ int ret = 0;
pr_info("gtp1 udp received\n");
/* check for sufficient header size */
if (!pskb_may_pull(skb, sizeof(*gtp1)))
- goto out;
+ return -1;
gtp1 = (struct gtp1_header *)skb->data;
/* check for GTP Version 1 */
if ((gtp1->flags >> 5) != GTP_V1)
- goto out;
+ return 1;
/* check if it is T-PDU. */
if (gtp1->type != GTP_TPDU)
- goto out;
+ return 1;
/* look-up table for faster length computing */
gtp1_hdrlen = gtp1u_header_len[gtp1->flags & GTP1_F_MASK];
/* check for sufficient header size */
if (gtp1_hdrlen && !pskb_may_pull(skb, gtp1_hdrlen))
- goto out_rcu;
+ return -1;
/* look-up the PDP context for the Tunnel ID */
rcu_read_lock();
pctx = gtp1_pdp_find(gti, ntohl(gtp1->tid));
- if (!pctx)
+ if (!pctx) {
+ ret = -1;
goto out_rcu;
+ }
/* get rid of the GTP header */
__skb_pull(skb, sizeof(*gtp1) + gtp1_hdrlen);
@@ -310,15 +313,11 @@ static int gtp1u_udp_encap_recv(struct gtp_instance *gti, struct sk_buff *skb)
/* FIXME: actually take care of extension header chain */
if (!gtp_check_src_ms(skb, pctx))
- goto out_rcu;
-
- rcu_read_unlock();
- return 0;
+ ret = -1;
out_rcu:
rcu_read_unlock();
-out:
- return -1;
+ return ret;
}
/* UDP encapsulation receive handler. See net/ipv4/udp.c.
@@ -355,9 +354,14 @@ static int gtp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
ret = -1; /* shouldn't happen */
}
- /* Not a valid GTP packet, drop it. */
- if (unlikely(ret < 0))
+ switch (ret) {
+ case 1: /* pass up to the stack */
+ goto user_put;
+ case 0:
+ break;
+ case -1:
goto drop;
+ }
/* Now that the UDP and the GTP header have been removed, set up the
* new network header. This is required by the upper later to