u8                      restart_count;
 };
 
+struct echo_info {
+       struct in_addr          ms_addr_ip4;
+       struct in_addr          peer_addr_ip4;
+       u8                      gtp_version;
+};
+
 static unsigned int gtp_net_id __read_mostly;
 
 struct gtp_net {
 
 static u32 gtp_h_initval;
 
+static struct genl_family gtp_genl_family;
+
+enum gtp_multicast_groups {
+       GTP_GENL_MCGRP,
+};
+
+static const struct genl_multicast_group gtp_genl_mcgrps[] = {
+       [GTP_GENL_MCGRP] = { .name = GTP_GENL_MCGRP_NAME },
+};
+
 static void pdp_context_delete(struct pdp_ctx *pctx);
 
 static inline u32 gtp0_hashfn(u64 tid)
  *   by the receiver
  * Returns true if the echo req was correct, false otherwise.
  */
-static bool gtp0_validate_echo_req(struct gtp0_header *gtp0)
+static bool gtp0_validate_echo_hdr(struct gtp0_header *gtp0)
 {
        return !(gtp0->tid || (gtp0->flags ^ 0x1e) ||
                gtp0->number != 0xff || gtp0->flow);
 }
 
+/* msg_type has to be GTP_ECHO_REQ or GTP_ECHO_RSP */
+static void gtp0_build_echo_msg(struct gtp0_header *hdr, __u8 msg_type)
+{
+       int len_pkt, len_hdr;
+
+       hdr->flags = 0x1e; /* v0, GTP-non-prime. */
+       hdr->type = msg_type;
+       /* GSM TS 09.60. 7.3 In all Path Management Flow Label and TID
+        * are not used and shall be set to 0.
+        */
+       hdr->flow = 0;
+       hdr->tid = 0;
+       hdr->number = 0xff;
+       hdr->spare[0] = 0xff;
+       hdr->spare[1] = 0xff;
+       hdr->spare[2] = 0xff;
+
+       len_pkt = sizeof(struct gtp0_packet);
+       len_hdr = sizeof(struct gtp0_header);
+
+       if (msg_type == GTP_ECHO_RSP)
+               hdr->length = htons(len_pkt - len_hdr);
+       else
+               hdr->length = 0;
+}
+
 static int gtp0_send_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
 {
        struct gtp0_packet *gtp_pkt;
 
        gtp0 = (struct gtp0_header *)(skb->data + sizeof(struct udphdr));
 
-       if (!gtp0_validate_echo_req(gtp0))
+       if (!gtp0_validate_echo_hdr(gtp0))
                return -1;
 
        seq = gtp0->seq;
        gtp_pkt = skb_push(skb, sizeof(struct gtp0_packet));
        memset(gtp_pkt, 0, sizeof(struct gtp0_packet));
 
-       gtp_pkt->gtp0_h.flags = 0x1e; /* v0, GTP-non-prime. */
-       gtp_pkt->gtp0_h.type = GTP_ECHO_RSP;
-       gtp_pkt->gtp0_h.length =
-               htons(sizeof(struct gtp0_packet) - sizeof(struct gtp0_header));
+       gtp0_build_echo_msg(>p_pkt->gtp0_h, GTP_ECHO_RSP);
 
        /* GSM TS 09.60. 7.3 The Sequence Number in a signalling response
         * message shall be copied from the signalling request message
         */
        gtp_pkt->gtp0_h.seq = seq;
 
-       /* GSM TS 09.60. 7.3 In all Path Management Flow Label and TID
-        * are not used and shall be set to 0.
-        */
-       gtp_pkt->gtp0_h.flow = 0;
-       gtp_pkt->gtp0_h.tid = 0;
-       gtp_pkt->gtp0_h.number = 0xff;
-       gtp_pkt->gtp0_h.spare[0] = 0xff;
-       gtp_pkt->gtp0_h.spare[1] = 0xff;
-       gtp_pkt->gtp0_h.spare[2] = 0xff;
-
        gtp_pkt->ie.tag = GTPIE_RECOVERY;
        gtp_pkt->ie.val = gtp->restart_count;
 
        return 0;
 }
 
+static int gtp_genl_fill_echo(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
+                             int flags, u32 type, struct echo_info echo)
+{
+       void *genlh;
+
+       genlh = genlmsg_put(skb, snd_portid, snd_seq, >p_genl_family, flags,
+                           type);
+       if (!genlh)
+               goto failure;
+
+       if (nla_put_u32(skb, GTPA_VERSION, echo.gtp_version) ||
+           nla_put_be32(skb, GTPA_PEER_ADDRESS, echo.peer_addr_ip4.s_addr) ||
+           nla_put_be32(skb, GTPA_MS_ADDRESS, echo.ms_addr_ip4.s_addr))
+               goto failure;
+
+       genlmsg_end(skb, genlh);
+       return 0;
+
+failure:
+       genlmsg_cancel(skb, genlh);
+       return -EMSGSIZE;
+}
+
+static int gtp0_handle_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
+{
+       struct gtp0_header *gtp0;
+       struct echo_info echo;
+       struct sk_buff *msg;
+       struct iphdr *iph;
+       int ret;
+
+       gtp0 = (struct gtp0_header *)(skb->data + sizeof(struct udphdr));
+
+       if (!gtp0_validate_echo_hdr(gtp0))
+               return -1;
+
+       iph = ip_hdr(skb);
+       echo.ms_addr_ip4.s_addr = iph->daddr;
+       echo.peer_addr_ip4.s_addr = iph->saddr;
+       echo.gtp_version = GTP_V0;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       if (!msg)
+               return -ENOMEM;
+
+       ret = gtp_genl_fill_echo(msg, 0, 0, 0, GTP_CMD_ECHOREQ, echo);
+       if (ret < 0) {
+               nlmsg_free(msg);
+               return ret;
+       }
+
+       return genlmsg_multicast_netns(>p_genl_family, dev_net(gtp->dev),
+                                      msg, 0, GTP_GENL_MCGRP, GFP_ATOMIC);
+}
+
 /* 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)
 {
        if (gtp0->type == GTP_ECHO_REQ && gtp->sk_created)
                return gtp0_send_echo_resp(gtp, skb);
 
+       if (gtp0->type == GTP_ECHO_RSP && gtp->sk_created)
+               return gtp0_handle_echo_resp(gtp, skb);
+
        if (gtp0->type != GTP_TPDU)
                return 1;
 
        return gtp_rx(pctx, skb, hdrlen, gtp->role);
 }
 
+/* msg_type has to be GTP_ECHO_REQ or GTP_ECHO_RSP */
+static void gtp1u_build_echo_msg(struct gtp1_header_long *hdr, __u8 msg_type)
+{
+       int len_pkt, len_hdr;
+
+       /* S flag must be set to 1 */
+       hdr->flags = 0x32; /* v1, GTP-non-prime. */
+       hdr->type = msg_type;
+       /* 3GPP TS 29.281 5.1 - TEID has to be set to 0 */
+       hdr->tid = 0;
+
+       /* seq, npdu and next should be counted to the length of the GTP packet
+        * that's why szie of gtp1_header should be subtracted,
+        * not size of gtp1_header_long.
+        */
+
+       len_hdr = sizeof(struct gtp1_header);
+
+       if (msg_type == GTP_ECHO_RSP) {
+               len_pkt = sizeof(struct gtp1u_packet);
+               hdr->length = htons(len_pkt - len_hdr);
+       } else {
+               /* GTP_ECHO_REQ does not carry GTP Information Element,
+                * the why gtp1_header_long is used here.
+                */
+               len_pkt = sizeof(struct gtp1_header_long);
+               hdr->length = htons(len_pkt - len_hdr);
+       }
+}
+
 static int gtp1u_send_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
 {
        struct gtp1_header_long *gtp1u;
        gtp_pkt = skb_push(skb, sizeof(struct gtp1u_packet));
        memset(gtp_pkt, 0, sizeof(struct gtp1u_packet));
 
-       /* S flag must be set to 1 */
-       gtp_pkt->gtp1u_h.flags = 0x32;
-       gtp_pkt->gtp1u_h.type = GTP_ECHO_RSP;
-       /* seq, npdu and next should be counted to the length of the GTP packet
-        * that's why szie of gtp1_header should be subtracted,
-        * not why szie of gtp1_header_long.
-        */
-       gtp_pkt->gtp1u_h.length =
-               htons(sizeof(struct gtp1u_packet) - sizeof(struct gtp1_header));
-       /* 3GPP TS 29.281 5.1 - TEID has to be set to 0 */
-       gtp_pkt->gtp1u_h.tid = 0;
+       gtp1u_build_echo_msg(>p_pkt->gtp1u_h, GTP_ECHO_RSP);
 
        /* 3GPP TS 29.281 7.7.2 - The Restart Counter value in the
         * Recovery information element shall not be used, i.e. it shall
        return 0;
 }
 
+static int gtp1u_handle_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
+{
+       struct gtp1_header_long *gtp1u;
+       struct echo_info echo;
+       struct sk_buff *msg;
+       struct iphdr *iph;
+       int ret;
+
+       gtp1u = (struct gtp1_header_long *)(skb->data + sizeof(struct udphdr));
+
+       /* 3GPP TS 29.281 5.1 - For the Echo Request, Echo Response,
+        * Error Indication and Supported Extension Headers Notification
+        * messages, the S flag shall be set to 1 and TEID shall be set to 0.
+        */
+       if (!(gtp1u->flags & GTP1_F_SEQ) || gtp1u->tid)
+               return -1;
+
+       iph = ip_hdr(skb);
+       echo.ms_addr_ip4.s_addr = iph->daddr;
+       echo.peer_addr_ip4.s_addr = iph->saddr;
+       echo.gtp_version = GTP_V1;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       if (!msg)
+               return -ENOMEM;
+
+       ret = gtp_genl_fill_echo(msg, 0, 0, 0, GTP_CMD_ECHOREQ, echo);
+       if (ret < 0) {
+               nlmsg_free(msg);
+               return ret;
+       }
+
+       return genlmsg_multicast_netns(>p_genl_family, dev_net(gtp->dev),
+                                      msg, 0, GTP_GENL_MCGRP, GFP_ATOMIC);
+}
+
 static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
        unsigned int hdrlen = sizeof(struct udphdr) +
        if (gtp1->type == GTP_ECHO_REQ && gtp->sk_created)
                return gtp1u_send_echo_resp(gtp, skb);
 
+       if (gtp1->type == GTP_ECHO_RSP && gtp->sk_created)
+               return gtp1u_handle_echo_resp(gtp, skb);
+
        if (gtp1->type != GTP_TPDU)
                return 1;
 
        return err;
 }
 
-static struct genl_family gtp_genl_family;
-
-enum gtp_multicast_groups {
-       GTP_GENL_MCGRP,
-};
-
-static const struct genl_multicast_group gtp_genl_mcgrps[] = {
-       [GTP_GENL_MCGRP] = { .name = GTP_GENL_MCGRP_NAME },
-};
-
 static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
                              int flags, u32 type, struct pdp_ctx *pctx)
 {
        return skb->len;
 }
 
+static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
+{
+       struct sk_buff *skb_to_send;
+       __be32 src_ip, dst_ip;
+       unsigned int version;
+       struct gtp_dev *gtp;
+       struct flowi4 fl4;
+       struct rtable *rt;
+       struct sock *sk;
+       __be16 port;
+       int len;
+
+       if (!info->attrs[GTPA_VERSION] ||
+           !info->attrs[GTPA_LINK] ||
+           !info->attrs[GTPA_PEER_ADDRESS] ||
+           !info->attrs[GTPA_MS_ADDRESS])
+               return -EINVAL;
+
+       version = nla_get_u32(info->attrs[GTPA_VERSION]);
+       dst_ip = nla_get_be32(info->attrs[GTPA_PEER_ADDRESS]);
+       src_ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
+
+       gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
+       if (!gtp)
+               return -ENODEV;
+
+       if (!gtp->sk_created)
+               return -EOPNOTSUPP;
+       if (!(gtp->dev->flags & IFF_UP))
+               return -ENETDOWN;
+
+       if (version == GTP_V0) {
+               struct gtp0_header *gtp0_h;
+
+               len = LL_RESERVED_SPACE(gtp->dev) + sizeof(struct gtp0_header) +
+                       sizeof(struct iphdr) + sizeof(struct udphdr);
+
+               skb_to_send = netdev_alloc_skb_ip_align(gtp->dev, len);
+               if (!skb_to_send)
+                       return -ENOMEM;
+
+               sk = gtp->sk0;
+               port = htons(GTP0_PORT);
+
+               gtp0_h = skb_push(skb_to_send, sizeof(struct gtp0_header));
+               memset(gtp0_h, 0, sizeof(struct gtp0_header));
+               gtp0_build_echo_msg(gtp0_h, GTP_ECHO_REQ);
+       } else if (version == GTP_V1) {
+               struct gtp1_header_long *gtp1u_h;
+
+               len = LL_RESERVED_SPACE(gtp->dev) +
+                       sizeof(struct gtp1_header_long) +
+                       sizeof(struct iphdr) + sizeof(struct udphdr);
+
+               skb_to_send = netdev_alloc_skb_ip_align(gtp->dev, len);
+               if (!skb_to_send)
+                       return -ENOMEM;
+
+               sk = gtp->sk1u;
+               port = htons(GTP1U_PORT);
+
+               gtp1u_h = skb_push(skb_to_send,
+                                  sizeof(struct gtp1_header_long));
+               memset(gtp1u_h, 0, sizeof(struct gtp1_header_long));
+               gtp1u_build_echo_msg(gtp1u_h, GTP_ECHO_REQ);
+       } else {
+               return -ENODEV;
+       }
+
+       rt = ip4_route_output_gtp(&fl4, sk, dst_ip, src_ip);
+       if (IS_ERR(rt)) {
+               netdev_dbg(gtp->dev, "no route for echo request to %pI4\n",
+                          &dst_ip);
+                          kfree_skb(skb_to_send);
+               return -ENODEV;
+       }
+
+       udp_tunnel_xmit_skb(rt, sk, skb_to_send,
+                           fl4.saddr, fl4.daddr,
+                           fl4.flowi4_tos,
+                           ip4_dst_hoplimit(&rt->dst),
+                           0,
+                           port, port,
+                           !net_eq(sock_net(sk),
+                                   dev_net(gtp->dev)),
+                           false);
+       return 0;
+}
+
 static const struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {
        [GTPA_LINK]             = { .type = NLA_U32, },
        [GTPA_VERSION]          = { .type = NLA_U32, },
                .dumpit = gtp_genl_dump_pdp,
                .flags = GENL_ADMIN_PERM,
        },
+       {
+               .cmd = GTP_CMD_ECHOREQ,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = gtp_genl_send_echo_req,
+               .flags = GENL_ADMIN_PERM,
+       },
 };
 
 static struct genl_family gtp_genl_family __ro_after_init = {