#ifndef MPTCP_PM_NAME
 #define MPTCP_PM_NAME          "mptcp_pm"
 #endif
+#ifndef MPTCP_PM_EVENTS
+#define MPTCP_PM_EVENTS                "mptcp_pm_events"
+#endif
 
 static void syntax(char *argv[])
 {
        fprintf(stderr, "\tflush\n");
        fprintf(stderr, "\tdump\n");
        fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n");
+       fprintf(stderr, "\tevents\n");
        exit(0);
 }
 
        }
 }
 
+static int capture_events(int fd, int event_group)
+{
+       u_int8_t buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                       NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024];
+       struct genlmsghdr *ghdr;
+       struct rtattr *attrs;
+       struct nlmsghdr *nh;
+       int ret = 0;
+       int res_len;
+       int msg_len;
+       fd_set rfds;
+
+       if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+                      &event_group, sizeof(event_group)) < 0)
+               error(1, errno, "could not join the " MPTCP_PM_EVENTS " mcast group");
+
+       do {
+               FD_ZERO(&rfds);
+               FD_SET(fd, &rfds);
+               res_len = NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024;
+
+               ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
+
+               if (ret < 0)
+                       error(1, ret, "error in select() on NL socket");
+
+               res_len = recv(fd, buffer, res_len, 0);
+               if (res_len < 0)
+                       error(1, res_len, "error on recv() from NL socket");
+
+               nh = (struct nlmsghdr *)buffer;
+
+               for (; NLMSG_OK(nh, res_len); nh = NLMSG_NEXT(nh, res_len)) {
+                       if (nh->nlmsg_type == NLMSG_ERROR)
+                               error(1, NLMSG_ERROR, "received invalid NL message");
+
+                       ghdr = (struct genlmsghdr *)NLMSG_DATA(nh);
+
+                       if (ghdr->cmd == 0)
+                               continue;
+
+                       fprintf(stderr, "type:%d", ghdr->cmd);
+
+                       msg_len = nh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
+
+                       attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+                       while (RTA_OK(attrs, msg_len)) {
+                               if (attrs->rta_type == MPTCP_ATTR_TOKEN)
+                                       fprintf(stderr, ",token:%u", *(__u32 *)RTA_DATA(attrs));
+                               else if (attrs->rta_type == MPTCP_ATTR_FAMILY)
+                                       fprintf(stderr, ",family:%u", *(__u16 *)RTA_DATA(attrs));
+                               else if (attrs->rta_type == MPTCP_ATTR_LOC_ID)
+                                       fprintf(stderr, ",loc_id:%u", *(__u8 *)RTA_DATA(attrs));
+                               else if (attrs->rta_type == MPTCP_ATTR_REM_ID)
+                                       fprintf(stderr, ",rem_id:%u", *(__u8 *)RTA_DATA(attrs));
+                               else if (attrs->rta_type == MPTCP_ATTR_SADDR4) {
+                                       u_int32_t saddr4 = ntohl(*(__u32 *)RTA_DATA(attrs));
+
+                                       fprintf(stderr, ",saddr4:%u.%u.%u.%u", saddr4 >> 24,
+                                              (saddr4 >> 16) & 0xFF, (saddr4 >> 8) & 0xFF,
+                                              (saddr4 & 0xFF));
+                               } else if (attrs->rta_type == MPTCP_ATTR_SADDR6) {
+                                       char buf[INET6_ADDRSTRLEN];
+
+                                       if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf,
+                                                     sizeof(buf)) != NULL)
+                                               fprintf(stderr, ",saddr6:%s", buf);
+                               } else if (attrs->rta_type == MPTCP_ATTR_DADDR4) {
+                                       u_int32_t daddr4 = ntohl(*(__u32 *)RTA_DATA(attrs));
+
+                                       fprintf(stderr, ",daddr4:%u.%u.%u.%u", daddr4 >> 24,
+                                              (daddr4 >> 16) & 0xFF, (daddr4 >> 8) & 0xFF,
+                                              (daddr4 & 0xFF));
+                               } else if (attrs->rta_type == MPTCP_ATTR_DADDR6) {
+                                       char buf[INET6_ADDRSTRLEN];
+
+                                       if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf,
+                                                     sizeof(buf)) != NULL)
+                                               fprintf(stderr, ",daddr6:%s", buf);
+                               } else if (attrs->rta_type == MPTCP_ATTR_SPORT)
+                                       fprintf(stderr, ",sport:%u",
+                                               ntohs(*(__u16 *)RTA_DATA(attrs)));
+                               else if (attrs->rta_type == MPTCP_ATTR_DPORT)
+                                       fprintf(stderr, ",dport:%u",
+                                               ntohs(*(__u16 *)RTA_DATA(attrs)));
+                               else if (attrs->rta_type == MPTCP_ATTR_BACKUP)
+                                       fprintf(stderr, ",backup:%u", *(__u8 *)RTA_DATA(attrs));
+                               else if (attrs->rta_type == MPTCP_ATTR_ERROR)
+                                       fprintf(stderr, ",error:%u", *(__u8 *)RTA_DATA(attrs));
+                               else if (attrs->rta_type == MPTCP_ATTR_SERVER_SIDE)
+                                       fprintf(stderr, ",server_side:%u", *(__u8 *)RTA_DATA(attrs));
+
+                               attrs = RTA_NEXT(attrs, msg_len);
+                       }
+               }
+               fprintf(stderr, "\n");
+       } while (1);
+
+       return 0;
+}
+
 /* do a netlink command and, if max > 0, fetch the reply  */
 static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max)
 {
        return ret;
 }
 
-static int genl_parse_getfamily(struct nlmsghdr *nlh)
+static int genl_parse_getfamily(struct nlmsghdr *nlh, int *pm_family,
+                               int *events_mcast_grp)
 {
        struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
        int len = nlh->nlmsg_len;
        struct rtattr *attrs;
+       struct rtattr *grps;
+       struct rtattr *grp;
+       int got_events_grp;
+       int got_family;
+       int grps_len;
+       int grp_len;
 
        if (nlh->nlmsg_type != GENL_ID_CTRL)
                error(1, errno, "Not a controller message, len=%d type=0x%x\n",
                error(1, errno, "Unknown controller command %d\n", ghdr->cmd);
 
        attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+       got_family = 0;
+       got_events_grp = 0;
+
        while (RTA_OK(attrs, len)) {
-               if (attrs->rta_type == CTRL_ATTR_FAMILY_ID)
-                       return *(__u16 *)RTA_DATA(attrs);
+               if (attrs->rta_type == CTRL_ATTR_FAMILY_ID) {
+                       *pm_family = *(__u16 *)RTA_DATA(attrs);
+                       got_family = 1;
+               } else if (attrs->rta_type == CTRL_ATTR_MCAST_GROUPS) {
+                       grps = RTA_DATA(attrs);
+                       grps_len = RTA_PAYLOAD(attrs);
+
+                       while (RTA_OK(grps, grps_len)) {
+                               grp = RTA_DATA(grps);
+                               grp_len = RTA_PAYLOAD(grps);
+                               got_events_grp = 0;
+
+                               while (RTA_OK(grp, grp_len)) {
+                                       if (grp->rta_type == CTRL_ATTR_MCAST_GRP_ID)
+                                               *events_mcast_grp = *(__u32 *)RTA_DATA(grp);
+                                       else if (grp->rta_type == CTRL_ATTR_MCAST_GRP_NAME &&
+                                                !strcmp(RTA_DATA(grp), MPTCP_PM_EVENTS))
+                                               got_events_grp = 1;
+
+                                       grp = RTA_NEXT(grp, grp_len);
+                               }
+
+                               if (got_events_grp)
+                                       break;
+
+                               grps = RTA_NEXT(grps, grps_len);
+                       }
+               }
+
+               if (got_family && got_events_grp)
+                       return 0;
+
                attrs = RTA_NEXT(attrs, len);
        }
 
        return -1;
 }
 
-static int resolve_mptcp_pm_netlink(int fd)
+static int resolve_mptcp_pm_netlink(int fd, int *pm_family, int *events_mcast_grp)
 {
        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
        off += NLMSG_ALIGN(rta->rta_len);
 
        do_nl_req(fd, nh, off, sizeof(data));
-       return genl_parse_getfamily((void *)data);
+       return genl_parse_getfamily((void *)data, pm_family, events_mcast_grp);
 }
 
 int dsf(int fd, int pm_family, int argc, char *argv[])
 
 int main(int argc, char *argv[])
 {
-       int fd, pm_family;
+       int events_mcast_grp;
+       int pm_family;
+       int fd;
 
        if (argc < 2)
                syntax(argv);
        if (fd == -1)
                error(1, errno, "socket netlink");
 
-       pm_family = resolve_mptcp_pm_netlink(fd);
+       resolve_mptcp_pm_netlink(fd, &pm_family, &events_mcast_grp);
 
        if (!strcmp(argv[1], "add"))
                return add_addr(fd, pm_family, argc, argv);
                return get_set_limits(fd, pm_family, argc, argv);
        else if (!strcmp(argv[1], "set"))
                return set_flags(fd, pm_family, argc, argv);
+       else if (!strcmp(argv[1], "events"))
+               return capture_events(fd, events_mcast_grp);
 
        fprintf(stderr, "unknown sub-command: %s", argv[1]);
        syntax(argv);