diff --git a/encap.c b/encap.c index ca90aa2..1af7376 100644 --- a/encap.c +++ b/encap.c @@ -268,7 +268,7 @@ static int gtp1u_udp_encap_recv(struct gtp5g_dev *gtp, struct sk_buff *skb) // recalculation gtpv1 gtpv1 = (struct gtpv1_hdr *)(skb->data + sizeof(struct udphdr)); - pdr = pdr_find_by_gtp1u(gtp, skb, hdrlen, gtpv1->tid); + pdr = pdr_find_by_gtp1u(gtp, skb, hdrlen, gtpv1->tid, gtpv1->type); // pskb_may_pull() is called in pdr_find_by_gtp1u(), so gtpv1 may be invalidated here. // recalculation gtpv1 gtpv1 = (struct gtpv1_hdr *)(skb->data + sizeof(struct udphdr)); diff --git a/pdr.c b/pdr.c index 60fe786..9118624 100644 --- a/pdr.c +++ b/pdr.c @@ -3,6 +3,7 @@ #include "dev.h" #include "link.h" #include "pdr.h" +#include "gtp.h" #include "genl_pdr.h" #include "genl_far.h" #include "seid.h" @@ -238,7 +239,7 @@ static int sdf_filter_match(struct sdf_filter *sdf, struct sk_buff *skb, } struct pdr *pdr_find_by_gtp1u(struct gtp5g_dev *gtp, struct sk_buff *skb, - unsigned int hdrlen, u32 teid) + unsigned int hdrlen, u32 teid, u8 type) { #ifdef MATCH_IP struct iphdr *outer_iph; @@ -248,6 +249,7 @@ struct pdr *pdr_find_by_gtp1u(struct gtp5g_dev *gtp, struct sk_buff *skb, struct hlist_head *head; struct pdr *pdr; struct pdi *pdi; + int may_pull_len; if (!gtp) return NULL; @@ -255,7 +257,12 @@ struct pdr *pdr_find_by_gtp1u(struct gtp5g_dev *gtp, struct sk_buff *skb, if (ntohs(skb->protocol) != ETH_P_IP) return NULL; - if (!pskb_may_pull(skb, hdrlen)) + if (type == GTPV1_MSG_TYPE_TPDU) + may_pull_len = hdrlen + sizeof(struct iphdr); + else + may_pull_len = hdrlen; + + if (!pskb_may_pull(skb, may_pull_len)) return NULL; iph = (struct iphdr *)(skb->data + hdrlen); diff --git a/pdr.h b/pdr.h index 3725c85..33b8475 100644 --- a/pdr.h +++ b/pdr.h @@ -96,7 +96,7 @@ struct pdr { extern void pdr_context_delete(struct pdr *); extern struct pdr *find_pdr_by_id(struct gtp5g_dev *, u64, u16); extern struct pdr *pdr_find_by_gtp1u(struct gtp5g_dev *, struct sk_buff *, - unsigned int, u32); + unsigned int, u32, u8); extern struct pdr *pdr_find_by_ipv4(struct gtp5g_dev *, struct sk_buff *, unsigned int, __be32); extern int find_qer_id_in_pdr(struct pdr *, u32);