diff options
author | Pablo Neira Ayuso <pablo@gnumonks.org> | 2014-02-20 12:17:00 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@gnumonks.org> | 2014-02-20 12:48:40 +0100 |
commit | d123a0c0f57348422832c915b82a15d79b2a0c5b (patch) | |
tree | 9bfc7f0c0453ebed44122b4b8c811edeacbca523 | |
parent | d7cdbddebdd5620d6b2d3b94380e693f3d6671a0 (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.c | 48 |
1 files changed, 26 insertions, 22 deletions
@@ -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 |