diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 74018ebcaf3af018efdeb032b26450bae38b2bc0..0c6707a0d9d36502ba6780268b4845b7c36eaf01 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -58,6 +58,8 @@ struct pdp_ctx { struct in_addr ms_addr_ip4; struct in_addr sgsn_addr_ip4; + struct net_device *dev; + atomic_t tx_seq; struct rcu_head rcu_head; }; @@ -175,6 +177,40 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx, return false; } +static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen, + bool xnet) +{ + struct pcpu_sw_netstats *stats; + + if (!gtp_check_src_ms(skb, pctx, hdrlen)) { + netdev_dbg(pctx->dev, "No PDP ctx for this MS\n"); + return 1; + } + + /* Get rid of the GTP + UDP headers. */ + if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet)) + return -1; + + netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n"); + + /* Now that the UDP and the GTP header have been removed, set up the + * new network header. This is required by the upper layer to + * calculate the transport header. + */ + skb_reset_network_header(skb); + + skb->dev = pctx->dev; + + stats = this_cpu_ptr(pctx->dev->tstats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); + + netif_rx(skb); + return 0; +} + /* 1 means pass up to the stack, -1 means drop and 0 means decapsulated. */ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, bool xnet) @@ -201,13 +237,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, return 1; } - if (!gtp_check_src_ms(skb, pctx, hdrlen)) { - netdev_dbg(gtp->dev, "No PDP ctx for this MS\n"); - return 1; - } - - /* Get rid of the GTP + UDP headers. */ - return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet); + return gtp_rx(pctx, skb, hdrlen, xnet); } static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, @@ -250,13 +280,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, return 1; } - if (!gtp_check_src_ms(skb, pctx, hdrlen)) { - netdev_dbg(gtp->dev, "No PDP ctx for this MS\n"); - return 1; - } - - /* Get rid of the GTP + UDP headers. */ - return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet); + return gtp_rx(pctx, skb, hdrlen, xnet); } static void gtp_encap_destroy(struct sock *sk) @@ -290,10 +314,9 @@ static void gtp_encap_disable(struct gtp_dev *gtp) */ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) { - struct pcpu_sw_netstats *stats; struct gtp_dev *gtp; + int ret = 0; bool xnet; - int ret; gtp = rcu_dereference_sk_user_data(sk); if (!gtp) @@ -319,33 +342,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) switch (ret) { case 1: netdev_dbg(gtp->dev, "pass up to the process\n"); - return 1; + break; case 0: - netdev_dbg(gtp->dev, "forwarding packet from GGSN to uplink\n"); break; case -1: netdev_dbg(gtp->dev, "GTP packet has been dropped\n"); kfree_skb(skb); - return 0; + ret = 0; + break; } - /* Now that the UDP and the GTP header have been removed, set up the - * new network header. This is required by the upper layer to - * calculate the transport header. - */ - skb_reset_network_header(skb); - - skb->dev = gtp->dev; - - stats = this_cpu_ptr(gtp->dev->tstats); - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += skb->len; - u64_stats_update_end(&stats->syncp); - - netif_rx(skb); - - return 0; + return ret; } static int gtp_dev_init(struct net_device *dev) @@ -951,6 +958,7 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) if (pctx == NULL) return -ENOMEM; + pctx->dev = gtp->dev; ipv4_pdp_fill(pctx, info); atomic_set(&pctx->tx_seq, 0);