[pim] Hooks for ssmpingd support
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 26e27e7..4ed1e89 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -268,6 +268,7 @@
   { MTYPE_PIM_NEIGHBOR,          "PIM interface neighbor"         },
   { MTYPE_PIM_IFCHANNEL,         "PIM interface (S,G) state"      },
   { MTYPE_PIM_UPSTREAM,          "PIM upstream (S,G) state"       },
+  { MTYPE_PIM_SSMPINGD,          "PIM sspimgd socket"             },
   { -1, NULL },
 };
 
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 692c2fc..a4073f5 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -2137,6 +2137,47 @@
   return CMD_SUCCESS;
 }
 
+static void show_ssmpingd(struct vty *vty)
+{
+  struct listnode      *node;
+  struct ssmpingd_sock *ss;
+  time_t                now;
+
+  vty_out(vty, "Source          Socket Uptime  Requests%s",
+	  VTY_NEWLINE);
+
+  if (!qpim_ssmpingd_list)
+    return;
+
+  now = pim_time_monotonic_sec();
+
+  for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) {
+    char source_str[100];
+    char ss_uptime[10];
+
+    pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
+    pim_time_uptime(ss_uptime, sizeof(ss_uptime), now - ss->creation);
+
+    vty_out(vty, "%-15s %6d %8s %8lld%s",
+	    source_str,
+	    ss->sock_fd,
+	    ss_uptime,
+	    ss->requests,
+	    VTY_NEWLINE);
+  }
+}
+
+DEFUN (show_ip_ssmpingd,
+       show_ip_ssmpingd_cmd,
+       "show ip ssmpingd",
+       SHOW_STR
+       IP_STR
+       SHOW_SSMPINGD_STR)
+{
+  show_ssmpingd(vty);
+  return CMD_SUCCESS;
+}
+
 static void mroute_add_all()
 {
   struct listnode    *node;
@@ -2205,7 +2246,7 @@
        ip_ssmpingd_cmd,
        "ip ssmpingd [A.B.C.D]",
        IP_STR
-       SSMPINGD_STR
+       CONF_SSMPINGD_STR
        "Source address\n")
 {
   int result;
@@ -2234,7 +2275,7 @@
        "no ip ssmpingd [A.B.C.D]",
        NO_STR
        IP_STR
-       SSMPINGD_STR
+       CONF_SSMPINGD_STR
        "Source address\n")
 {
   int result;
@@ -3132,6 +3173,36 @@
        DEBUG_PIM_STR
        DEBUG_PIM_TRACE_STR)
 
+DEFUN (debug_ssmpingd,
+       debug_ssmpingd_cmd,
+       "debug ssmpingd",
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_SSMPINGD_STR)
+{
+  PIM_DO_DEBUG_SSMPINGD;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ssmpingd,
+       no_debug_ssmpingd_cmd,
+       "no debug ssmpingd",
+       NO_STR
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_SSMPINGD_STR)
+{
+  PIM_DONT_DEBUG_SSMPINGD;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ssmpingd,
+       undebug_ssmpingd_cmd,
+       "undebug ssmpingd",
+       UNDEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_SSMPINGD_STR)
+
 DEFUN (debug_pim_zebra,
        debug_pim_zebra_cmd,
        "debug pim zebra",
@@ -3897,6 +3968,7 @@
   install_element (VIEW_NODE, &show_ip_mroute_cmd);
   install_element (VIEW_NODE, &show_ip_mroute_count_cmd);
   install_element (VIEW_NODE, &show_ip_route_cmd);
+  install_element (VIEW_NODE, &show_ip_ssmpingd_cmd);
   install_element (VIEW_NODE, &show_debugging_cmd);
 
   install_element (ENABLE_NODE, &clear_ip_interfaces_cmd);
@@ -3965,6 +4037,9 @@
   install_element (ENABLE_NODE, &debug_pim_trace_cmd);
   install_element (ENABLE_NODE, &no_debug_pim_trace_cmd);
   install_element (ENABLE_NODE, &undebug_pim_trace_cmd);
+  install_element (ENABLE_NODE, &debug_ssmpingd_cmd);
+  install_element (ENABLE_NODE, &no_debug_ssmpingd_cmd);
+  install_element (ENABLE_NODE, &undebug_ssmpingd_cmd);
   install_element (ENABLE_NODE, &debug_pim_zebra_cmd);
   install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd);
   install_element (ENABLE_NODE, &undebug_pim_zebra_cmd);
@@ -3993,6 +4068,9 @@
   install_element (CONFIG_NODE, &debug_pim_trace_cmd);
   install_element (CONFIG_NODE, &no_debug_pim_trace_cmd);
   install_element (CONFIG_NODE, &undebug_pim_trace_cmd);
+  install_element (CONFIG_NODE, &debug_ssmpingd_cmd);
+  install_element (CONFIG_NODE, &no_debug_ssmpingd_cmd);
+  install_element (CONFIG_NODE, &undebug_ssmpingd_cmd);
   install_element (CONFIG_NODE, &debug_pim_zebra_cmd);
   install_element (CONFIG_NODE, &no_debug_pim_zebra_cmd);
   install_element (CONFIG_NODE, &undebug_pim_zebra_cmd);
diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h
index f3b2f96..800bfcb 100644
--- a/pimd/pim_cmd.h
+++ b/pimd/pim_cmd.h
@@ -27,7 +27,8 @@
 #define IGMP_STR                               "IGMP information\n"
 #define IGMP_GROUP_STR                         "IGMP groups information\n"
 #define IGMP_SOURCE_STR                        "IGMP sources information\n"
-#define SSMPINGD_STR                           "Enable ssmpingd operation\n"
+#define CONF_SSMPINGD_STR                      "Enable ssmpingd operation\n"
+#define SHOW_SSMPINGD_STR                      "ssmpingd operation\n"
 #define IFACE_PIM_STR                          "Enable PIM SSM operation\n"
 #define IFACE_IGMP_STR                         "Enable IGMP operation\n"
 #define IFACE_IGMP_QUERY_INTERVAL_STR          "IGMP host query interval\n"
@@ -42,6 +43,7 @@
 #define DEBUG_PIM_PACKETS_STR                       "PIM protocol packets\n"
 #define DEBUG_PIM_TRACE_STR                         "PIM internal daemon activity\n"
 #define DEBUG_PIM_ZEBRA_STR                         "ZEBRA protocol activity\n"
+#define DEBUG_SSMPINGD_STR                          "ssmpingd activity\n"
 #define CLEAR_IP_IGMP_STR                           "IGMP clear commands\n"
 #define CLEAR_IP_PIM_STR                            "PIM clear commands\n"
 #define MROUTE_STR                                  "IP multicast routing table\n"
diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c
index e4b16aa..4eb5c8d 100644
--- a/pimd/pim_ssmpingd.c
+++ b/pimd/pim_ssmpingd.c
@@ -20,26 +20,328 @@
   $QuaggaId: $Format:%an, %ai, %h$ $
 */
 
+#include <zebra.h>
+
+#include "if.h"
+#include "log.h"
+#include "memory.h"
+
 #include "pim_ssmpingd.h"
 #include "pim_time.h"
+#include "pim_sock.h"
+#include "pim_str.h"
 #include "pimd.h"
 
+static void ssmpingd_read_on(struct ssmpingd_sock *ss);
+
 void pim_ssmpingd_init()
 {
+  zassert(!qpim_ssmpingd_list);
 }
 
 void pim_ssmpingd_destroy()
 {
-  if (qpim_ssmpingd_list)
+  if (qpim_ssmpingd_list) {
     list_free(qpim_ssmpingd_list);
+    qpim_ssmpingd_list = 0;
+  }
+}
+
+static struct ssmpingd_sock *ssmpingd_find(struct in_addr source_addr)
+{
+  struct listnode      *node;
+  struct ssmpingd_sock *ss;
+
+  if (!qpim_ssmpingd_list)
+    return 0;
+
+  for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss))
+    if (source_addr.s_addr == ss->source_addr.s_addr)
+      return ss;
+
+  return 0;
+}
+
+static void ssmpingd_free(struct ssmpingd_sock *ss)
+{
+  XFREE(MTYPE_PIM_SSMPINGD, ss);
+}
+
+static int ssmpingd_socket(struct in_addr addr, int mttl)
+{
+  int fd;
+
+  fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  if (fd < 0) {
+    zlog_err("%s: could not create socket: errno=%d: %s",
+	     __PRETTY_FUNCTION__, errno, safe_strerror(errno));
+    return -1;
+  }
+
+  /* Needed to obtain destination address from recvmsg() */
+  {
+#if defined(HAVE_IP_PKTINFO)
+    /* Linux IP_PKTINFO */
+    int opt = 1;
+    if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) {
+      zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
+		fd, errno, safe_strerror(errno));
+    }
+#elif defined(HAVE_IP_RECVDSTADDR)
+    /* BSD IP_RECVDSTADDR */
+    int opt = 1;
+    if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) {
+      zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
+		fd, errno, safe_strerror(errno));
+    }
+#else
+    zlog_err("%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
+	     __FILE__, __PRETTY_FUNCTION__);
+    close(fd);
+    return -1;
+#endif
+  }
+  
+  {
+    int reuse = 1;
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+		   (void *) &reuse, sizeof(reuse))) {
+      zlog_warn("%s: could not set Reuse Address Option on socket fd=%d: errno=%d: %s",
+		__PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
+      close(fd);
+      return -1;
+    }
+  }
+
+  if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
+		 (void *) &mttl, sizeof(mttl))) {
+    zlog_warn("%s: could not set multicast TTL=%d on socket fd=%d: errno=%d: %s",
+	      __PRETTY_FUNCTION__, mttl, fd, errno, safe_strerror(errno));
+    close(fd);
+    return -1;
+  }
+
+  if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+		 (void *) &addr, sizeof(addr))) {
+    zlog_warn("%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
+	      __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
+    close(fd);
+    return -1;
+  }
+
+  {
+    long flags;
+
+    flags = fcntl(fd, F_GETFL, 0);
+    if (flags < 0) {
+      zlog_warn("%s: could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
+		__PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
+      close(fd);
+      return -1;
+    }
+
+    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
+      zlog_warn("%s: could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
+		__PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
+      close(fd);
+      return -1;
+    }
+  }
+
+  return fd;
+}
+
+static void ssmpingd_delete(struct ssmpingd_sock *ss)
+{
+  zassert(ss);
+  zassert(qpim_ssmpingd_list);
+
+  THREAD_OFF(ss->t_sock_read);
+
+  if (close(ss->sock_fd)) {
+    int e = errno;
+    char source_str[100];
+    pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
+    zlog_warn("%s: failure closing ssmpingd sock_fd=%d for source %s: errno=%d: %s",
+	      __PRETTY_FUNCTION__,
+	      ss->sock_fd, source_str, e, safe_strerror(e));
+    /* warning only */
+  }
+
+  listnode_delete(qpim_ssmpingd_list, ss);
+  ssmpingd_free(ss);
+}
+
+static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
+{
+  struct interface *ifp;
+  struct sockaddr_in from;
+  struct sockaddr_in to;
+  socklen_t fromlen = sizeof(from);
+  socklen_t tolen = sizeof(to);
+  int ifindex = -1;
+  char buf[1000];
+  int len;
+
+  len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf),
+			      &from, &fromlen,
+			      &to, &tolen,
+			      &ifindex);
+  if (len < 0) {
+    char source_str[100];
+    pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
+    zlog_warn("%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s",
+	      __PRETTY_FUNCTION__, source_str, ss->sock_fd, errno, safe_strerror(errno));
+    return -1;
+  }
+
+  ifp = if_lookup_by_index(ifindex);
+
+  if (PIM_DEBUG_SSMPINGD) {
+    char source_str[100];
+    char from_str[100];
+    char to_str[100];
+    pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
+    pim_inet4_dump("<from?>", from.sin_addr, from_str, sizeof(from_str));
+    pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
+    zlog_debug("%s: ssmpingd on source %s: interface %s ifindex=%d received ssmping from %s to %s on fd=%d",
+	       __PRETTY_FUNCTION__,
+	       source_str,
+	       ifp ? ifp->name : "<iface?>",
+	       ifindex, from_str, to_str, ss->sock_fd);
+  }
+
+  return 0;
+}
+
+static int ssmpingd_sock_read(struct thread *t)
+{
+  struct ssmpingd_sock *ss;
+  int sock_fd;
+  int result;
+
+  zassert(t);
+
+  ss = THREAD_ARG(t);
+  zassert(ss);
+
+  sock_fd = THREAD_FD(t);
+  zassert(sock_fd == ss->sock_fd);
+
+  result = ssmpingd_read_msg(ss);
+
+  /* Keep reading */
+  ss->t_sock_read = 0;
+  ssmpingd_read_on(ss);
+
+  return result;
+}
+
+static void ssmpingd_read_on(struct ssmpingd_sock *ss)
+{
+  zassert(!ss->t_sock_read);
+  THREAD_READ_ON(master, ss->t_sock_read,
+		 ssmpingd_sock_read, ss, ss->sock_fd);
+}
+
+static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr)
+{
+  struct ssmpingd_sock *ss;
+  int sock_fd;
+
+  if (!qpim_ssmpingd_list) {
+    qpim_ssmpingd_list = list_new();
+    if (!qpim_ssmpingd_list) {
+      zlog_err("%s %s: failure: qpim_ssmpingd_list=list_new()",
+	       __FILE__, __PRETTY_FUNCTION__);
+      return 0;
+    }
+    qpim_ssmpingd_list->del = (void (*)(void *)) ssmpingd_free;
+  }
+
+  sock_fd = ssmpingd_socket(source_addr, 64 /* ttl */);
+  if (sock_fd < 0) {
+    char source_str[100];
+    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
+    zlog_warn("%s: ssmpingd_socket() failure for source %s",
+	      __PRETTY_FUNCTION__, source_str);
+    return 0;
+  }
+
+  ss = XMALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss));
+  if (!ss) {
+    char source_str[100];
+    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
+    zlog_err("%s: XMALLOC(%d) failure for ssmpingd source %s",
+	     __PRETTY_FUNCTION__,
+	     sizeof(*ss), source_str);
+    close(sock_fd);
+    return 0;
+  }
+
+  ss->sock_fd     = sock_fd;
+  ss->t_sock_read = 0;
+  ss->source_addr = source_addr;
+  ss->creation    = pim_time_monotonic_sec();
+  ss->requests    = 0;
+
+  listnode_add(qpim_ssmpingd_list, ss);
+
+  ssmpingd_read_on(ss);
+
+  return ss;
 }
 
 int pim_ssmpingd_start(struct in_addr source_addr)
 {
+  struct ssmpingd_sock *ss;
+
+  ss = ssmpingd_find(source_addr);
+  if (ss) {
+    /* silently ignore request to recreate entry */
+    return 0;
+  }
+
+  {
+    char source_str[100];
+    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
+    zlog_info("%s: starting ssmpingd for source %s",
+	      __PRETTY_FUNCTION__, source_str);
+  }
+
+  ss = ssmpingd_new(source_addr);
+  if (!ss) {
+    char source_str[100];
+    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
+    zlog_warn("%s: ssmpingd_new() failure for source %s",
+	      __PRETTY_FUNCTION__, source_str);
+    return -1;
+  }
+
   return 0;
 }
 
 int pim_ssmpingd_stop(struct in_addr source_addr)
 {
+  struct ssmpingd_sock *ss;
+
+  ss = ssmpingd_find(source_addr);
+  if (!ss) {
+    char source_str[100];
+    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
+    zlog_warn("%s: could not find ssmpingd for source %s",
+	      __PRETTY_FUNCTION__, source_str);
+    return -1;
+  }
+
+  {
+    char source_str[100];
+    pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
+    zlog_info("%s: stopping ssmpingd for source %s",
+	      __PRETTY_FUNCTION__, source_str);
+  }
+
+  ssmpingd_delete(ss);
+
   return 0;
 }
diff --git a/pimd/pim_ssmpingd.h b/pimd/pim_ssmpingd.h
index 32563ae..4bef20b 100644
--- a/pimd/pim_ssmpingd.h
+++ b/pimd/pim_ssmpingd.h
@@ -32,7 +32,7 @@
 struct ssmpingd_sock {
   int            sock_fd;     /* socket */
   struct thread *t_sock_read; /* thread for reading socket */
-  struct in_addr source;      /* source address */
+  struct in_addr source_addr; /* source address */
   int64_t        creation;    /* timestamp of socket creation */
   int64_t        requests;    /* counter */
 };
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 7d69b5b..0b06d0e 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -30,6 +30,7 @@
 #include "pim_iface.h"
 #include "pim_cmd.h"
 #include "pim_str.h"
+#include "pim_ssmpingd.h"
 
 int pim_debug_config_write(struct vty *vty)
 {
@@ -66,6 +67,11 @@
     ++writes;
   }
 
+  if (PIM_DEBUG_SSMPINGD) {
+    vty_out(vty, "debug ssmpingd%s", VTY_NEWLINE);
+    ++writes;
+  }
+
   return writes;
 }
 
@@ -78,6 +84,19 @@
     ++writes;
   }
 
+  if (qpim_ssmpingd_list) {
+    struct listnode *node;
+    struct ssmpingd_sock *ss;
+    vty_out(vty, "!%s", VTY_NEWLINE);
+    ++writes;
+    for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) {
+      char source_str[100];
+      pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
+      vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE);
+      ++writes;
+    }
+  }
+
   return writes;
 }
 
@@ -91,7 +110,7 @@
 
     /* IF name */
     vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE);
-    writes++;
+    ++writes;
 
     if (ifp->info) {
       struct pim_interface *pim_ifp = ifp->info;
@@ -99,13 +118,13 @@
       /* IF ip pim ssm */
       if (PIM_IF_TEST_PIM(pim_ifp->options)) {
 	vty_out(vty, " ip pim ssm%s", VTY_NEWLINE);
-	writes++;
+	++writes;
       }
 
       /* IF ip igmp */
       if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
 	vty_out(vty, " ip igmp%s", VTY_NEWLINE);
-	writes++;
+	++writes;
       }
 
       /* IF ip igmp query-interval */
@@ -113,14 +132,14 @@
 	      PIM_CMD_IP_IGMP_QUERY_INTERVAL,
 	      pim_ifp->igmp_default_query_interval,
 	      VTY_NEWLINE);
-      writes++;
+      ++writes;
 
       /* IF ip igmp query-max-response-time */
       vty_out(vty, " %s %d%s",
 	      PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC,
 	      pim_ifp->igmp_query_max_response_time_dsec,
 	      VTY_NEWLINE);
-      writes++;
+      ++writes;
 
       /* IF ip igmp join */
       if (pim_ifp->igmp_join_list) {
@@ -134,11 +153,12 @@
 	  vty_out(vty, " ip igmp join %s %s%s",
 		  group_str, source_str,
 		  VTY_NEWLINE);
-	  writes++;
+	  ++writes;
 	}
       }
     }
     vty_out(vty, "!%s", VTY_NEWLINE);
+    ++writes;
   }
 
   return writes;
diff --git a/pimd/pimd.h b/pimd/pimd.h
index bdf83b4..a2dc643 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -60,6 +60,7 @@
 #define PIM_MASK_IGMP_PACKETS (1 << 4)
 #define PIM_MASK_IGMP_TRACE   (1 << 5)
 #define PIM_MASK_ZEBRA        (1 << 6)
+#define PIM_MASK_SSMPINGD     (1 << 7)
 
 const char *const PIM_ALL_SYSTEMS;
 const char *const PIM_ALL_ROUTERS;
@@ -98,6 +99,7 @@
 #define PIM_DEBUG_IGMP_PACKETS (qpim_debugs & PIM_MASK_IGMP_PACKETS)
 #define PIM_DEBUG_IGMP_TRACE   (qpim_debugs & PIM_MASK_IGMP_TRACE)
 #define PIM_DEBUG_ZEBRA        (qpim_debugs & PIM_MASK_ZEBRA)
+#define PIM_DEBUG_SSMPINGD     (qpim_debugs & PIM_MASK_SSMPINGD)
 
 #define PIM_DEBUG_EVENTS       (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS))
 #define PIM_DEBUG_PACKETS      (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS))
@@ -110,6 +112,7 @@
 #define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS)
 #define PIM_DO_DEBUG_IGMP_TRACE   (qpim_debugs |= PIM_MASK_IGMP_TRACE)
 #define PIM_DO_DEBUG_ZEBRA        (qpim_debugs |= PIM_MASK_ZEBRA)
+#define PIM_DO_DEBUG_SSMPINGD     (qpim_debugs |= PIM_MASK_SSMPINGD)
 
 #define PIM_DONT_DEBUG_PIM_EVENTS   (qpim_debugs &= ~PIM_MASK_PIM_EVENTS)
 #define PIM_DONT_DEBUG_PIM_PACKETS  (qpim_debugs &= ~PIM_MASK_PIM_PACKETS)
@@ -118,6 +121,7 @@
 #define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS)
 #define PIM_DONT_DEBUG_IGMP_TRACE   (qpim_debugs &= ~PIM_MASK_IGMP_TRACE)
 #define PIM_DONT_DEBUG_ZEBRA        (qpim_debugs &= ~PIM_MASK_ZEBRA)
+#define PIM_DONT_DEBUG_SSMPINGD     (qpim_debugs &= ~PIM_MASK_SSMPINGD)
 
 void pim_init(void);
 void pim_terminate(void);