*/
 
 struct icmp_control {
-       void (*handler)(struct sk_buff *skb);
+       bool (*handler)(struct sk_buff *skb);
        short   error;          /* This ICMP is classed as an error message */
 };
 
  *     ICMP_PARAMETERPROB.
  */
 
-static void icmp_unreach(struct sk_buff *skb)
+static bool icmp_unreach(struct sk_buff *skb)
 {
        const struct iphdr *iph;
        struct icmphdr *icmph;
        icmp_socket_deliver(skb, info);
 
 out:
-       return;
+       return true;
 out_err:
        ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
-       goto out;
+       return false;
 }
 
 
  *     Handle ICMP_REDIRECT.
  */
 
-static void icmp_redirect(struct sk_buff *skb)
+static bool icmp_redirect(struct sk_buff *skb)
 {
        if (skb->len < sizeof(struct iphdr)) {
                ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS);
-               return;
+               return false;
        }
 
-       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-               return;
+       if (!pskb_may_pull(skb, sizeof(struct iphdr))) {
+               /* there aught to be a stat */
+               return false;
+       }
 
        icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway);
+       return true;
 }
 
 /*
  *     See also WRT handling of options once they are done and working.
  */
 
-static void icmp_echo(struct sk_buff *skb)
+static bool icmp_echo(struct sk_buff *skb)
 {
        struct net *net;
 
                icmp_param.head_len        = sizeof(struct icmphdr);
                icmp_reply(&icmp_param, skb);
        }
+       /* should there be an ICMP stat for ignored echos? */
+       return true;
 }
 
 /*
  *               MUST be accurate to a few minutes.
  *               MUST be updated at least at 15Hz.
  */
-static void icmp_timestamp(struct sk_buff *skb)
+static bool icmp_timestamp(struct sk_buff *skb)
 {
        struct timespec tv;
        struct icmp_bxm icmp_param;
        icmp_param.data_len        = 0;
        icmp_param.head_len        = sizeof(struct icmphdr) + 12;
        icmp_reply(&icmp_param, skb);
-out:
-       return;
+       return true;
+
 out_err:
        ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS);
-       goto out;
+       return false;
 }
 
-static void icmp_discard(struct sk_buff *skb)
+static bool icmp_discard(struct sk_buff *skb)
 {
+       /* pretend it was a success */
+       return true;
 }
 
 /*
        struct icmphdr *icmph;
        struct rtable *rt = skb_rtable(skb);
        struct net *net = dev_net(rt->dst.dev);
+       bool success;
 
        if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                struct sec_path *sp = skb_sec_path(skb);
                }
        }
 
-       icmp_pointers[icmph->type].handler(skb);
+       success = icmp_pointers[icmph->type].handler(skb);
+
+       if (success)  {
+               consume_skb(skb);
+               return 0;
+       }
 
 drop:
        kfree_skb(skb);
 
  *     All we need to do is get the socket.
  */
 
-void ping_rcv(struct sk_buff *skb)
+bool ping_rcv(struct sk_buff *skb)
 {
        struct sock *sk;
        struct net *net = dev_net(skb->dev);
                pr_debug("rcv on socket %p\n", sk);
                ping_queue_rcv_skb(sk, skb_get(skb));
                sock_put(sk);
-               return;
+               return true;
        }
        pr_debug("no socket, dropping\n");
 
-       /* We're called from icmp_rcv(). kfree_skb() is done there. */
+       return false;
 }
 EXPORT_SYMBOL_GPL(ping_rcv);
 
 
        const struct in6_addr *saddr, *daddr;
        struct icmp6hdr *hdr;
        u8 type;
+       bool success = false;
 
        if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                struct sec_path *sp = skb_sec_path(skb);
                break;
 
        case ICMPV6_ECHO_REPLY:
-               ping_rcv(skb);
+               success = ping_rcv(skb);
                break;
 
        case ICMPV6_PKT_TOOBIG:
                icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
        }
 
-       kfree_skb(skb);
+       /* until the v6 path can be better sorted assume failure and
+        * preserve the status quo behaviour for the rest of the paths to here
+        */
+       if (success)
+               consume_skb(skb);
+       else
+               kfree_skb(skb);
+
        return 0;
 
 csum_error: