rcv_l->bc_peer_is_up = true;
        rcv_l->state = LINK_ESTABLISHED;
        tipc_link_bc_ack_rcv(rcv_l, ack, xmitq);
+       trace_tipc_link_reset(rcv_l, TIPC_DUMP_ALL, "bclink removed!");
        tipc_link_reset(rcv_l);
        rcv_l->state = LINK_RESET;
        if (!snd_l->ackers) {
+               trace_tipc_link_reset(snd_l, TIPC_DUMP_ALL, "zero ackers!");
                tipc_link_reset(snd_l);
                snd_l->state = LINK_RESET;
                __skb_queue_purge(xmitq);
 
        l = *link;
        strcpy(l->name, tipc_bclink_name);
+       trace_tipc_link_reset(l, TIPC_DUMP_ALL, "bclink created!");
        tipc_link_reset(l);
        l->state = LINK_RESET;
        l->ackers = 0;
 int tipc_link_fsm_evt(struct tipc_link *l, int evt)
 {
        int rc = 0;
+       int old_state = l->state;
 
        switch (l->state) {
        case LINK_RESETTING:
        default:
                pr_err("Unknown FSM state %x in %s\n", l->state, l->name);
        }
+       trace_tipc_link_fsm(l->name, old_state, l->state, evt);
        return rc;
 illegal_evt:
        pr_err("Illegal FSM event %x in state %x on link %s\n",
               evt, l->state, l->name);
+       trace_tipc_link_fsm(l->name, old_state, l->state, evt);
        return rc;
 }
 
                l->stats.msg_length_profile[6]++;
 }
 
+/**
+ * tipc_link_too_silent - check if link is "too silent"
+ * @l: tipc link to be checked
+ *
+ * Returns true if the link 'silent_intv_cnt' is about to reach the
+ * 'abort_limit' value, otherwise false
+ */
+bool tipc_link_too_silent(struct tipc_link *l)
+{
+       return (l->silent_intv_cnt + 2 > l->abort_limit);
+}
+
 /* tipc_link_timeout - perform periodic task as instructed from node timeout
  */
 int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq)
        u16 bc_acked = l->bc_rcvlink->acked;
        struct tipc_mon_state *mstate = &l->mon_state;
 
+       trace_tipc_link_timeout(l, TIPC_DUMP_NONE, " ");
+       trace_tipc_link_too_silent(l, TIPC_DUMP_ALL, " ");
        switch (l->state) {
        case LINK_ESTABLISHED:
        case LINK_SYNCHING:
        TIPC_SKB_CB(skb)->chain_imp = msg_importance(hdr);
        skb_queue_tail(&l->wakeupq, skb);
        l->stats.link_congs++;
+       trace_tipc_link_conges(l, TIPC_DUMP_ALL, "wakeup scheduled!");
        return -ELINKCONG;
 }
 
        if (less(to, from))
                return 0;
 
+       trace_tipc_link_retrans(r, from, to, &l->transmq);
        /* Detect repeated retransmit failures on same packet */
        if (r->prev_from != from) {
                r->prev_from = from;
                r->stale_cnt = 0;
        } else if (++r->stale_cnt > 99 && time_after(jiffies, r->stale_limit)) {
                link_retransmit_failure(l, skb);
+               trace_tipc_list_dump(&l->transmq, true, "retrans failure!");
+               trace_tipc_link_dump(l, TIPC_DUMP_NONE, "retrans failure!");
+               trace_tipc_link_dump(r, TIPC_DUMP_NONE, "retrans failure!");
                if (link_is_bc_sndlink(l))
                        return TIPC_LINK_DOWN_EVT;
                return tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
                l->stats.sent_nacks++;
        skb->priority = TC_PRIO_CONTROL;
        __skb_queue_tail(xmitq, skb);
+       trace_tipc_proto_build(skb, false, l->name);
 }
 
 void tipc_link_create_dummy_tnl_msg(struct tipc_link *l,
        char *if_name;
        int rc = 0;
 
+       trace_tipc_proto_rcv(skb, false, l->name);
        if (tipc_link_is_blocked(l) || !xmitq)
                goto exit;
 
        hdr = buf_msg(skb);
        data = msg_data(hdr);
 
-       if (!tipc_link_validate_msg(l, hdr))
+       if (!tipc_link_validate_msg(l, hdr)) {
+               trace_tipc_skb_dump(skb, false, "PROTO invalid (1)!");
+               trace_tipc_link_dump(l, TIPC_DUMP_NONE, "PROTO invalid (1)!");
                goto exit;
+       }
 
        switch (mtyp) {
        case RESET_MSG:
        if (!more(acked, l->acked))
                return;
 
+       trace_tipc_link_bc_ack(l, l->acked, acked, &snd_l->transmq);
        /* Skip over packets peer has already acked */
        skb_queue_walk(&snd_l->transmq, skb) {
                if (more(buf_seqno(skb), l->acked))
 
                if (tipc_link_peer_is_down(l))
                        tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT);
                tipc_node_fsm_evt(n, SELF_LOST_CONTACT_EVT);
+               trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link down!");
                tipc_link_fsm_evt(l, LINK_RESET_EVT);
                tipc_link_reset(l);
                tipc_link_build_reset_msg(l, xmitq);
        tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT);
        n->sync_point = tipc_link_rcv_nxt(tnl) + (U16_MAX / 2 - 1);
        tipc_link_tnl_prepare(l, tnl, FAILOVER_MSG, xmitq);
+       trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link down -> failover!");
        tipc_link_reset(l);
        tipc_link_fsm_evt(l, LINK_RESET_EVT);
        tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT);
                        *respond = false;
                        goto exit;
                }
+               trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link created!");
                tipc_link_reset(l);
                tipc_link_fsm_evt(l, LINK_RESET_EVT);
                if (n->state == NODE_FAILINGOVER)
                }
        }
 
-       if (!tipc_link_validate_msg(l, hdr))
+       if (!tipc_link_validate_msg(l, hdr)) {
+               trace_tipc_skb_dump(skb, false, "PROTO invalid (2)!");
+               trace_tipc_link_dump(l, TIPC_DUMP_NONE, "PROTO invalid (2)!");
                return false;
+       }
 
        /* Check and update node accesibility if applicable */
        if (state == SELF_UP_PEER_COMING) {
 
 };
 #endif
 
+/* Link & Node FSM states: */
+#define state_sym(val)                                                   \
+       __print_symbolic(val,                                             \
+                       {(0xe),         "ESTABLISHED"                   },\
+                       {(0xe << 4),    "ESTABLISHING"                  },\
+                       {(0x1 << 8),    "RESET"                         },\
+                       {(0x2 << 12),   "RESETTING"                     },\
+                       {(0xd << 16),   "PEER_RESET"                    },\
+                       {(0xf << 20),   "FAILINGOVER"                   },\
+                       {(0xc << 24),   "SYNCHING"                      },\
+                       {(0xdd),        "SELF_DOWN_PEER_DOWN"           },\
+                       {(0xaa),        "SELF_UP_PEER_UP"               },\
+                       {(0xd1),        "SELF_DOWN_PEER_LEAVING"        },\
+                       {(0xac),        "SELF_UP_PEER_COMING"           },\
+                       {(0xca),        "SELF_COMING_PEER_UP"           },\
+                       {(0x1d),        "SELF_LEAVING_PEER_DOWN"        },\
+                       {(0xf0),        "FAILINGOVER"                   },\
+                       {(0xcc),        "SYNCHING"                      })
+
+/* Link & Node FSM events: */
+#define evt_sym(val)                                                     \
+       __print_symbolic(val,                                             \
+                       {(0xec1ab1e),   "ESTABLISH_EVT"                 },\
+                       {(0x9eed0e),    "PEER_RESET_EVT"                },\
+                       {(0xfa110e),    "FAILURE_EVT"                   },\
+                       {(0x10ca1d0e),  "RESET_EVT"                     },\
+                       {(0xfa110bee),  "FAILOVER_BEGIN_EVT"            },\
+                       {(0xfa110ede),  "FAILOVER_END_EVT"              },\
+                       {(0xc1ccbee),   "SYNCH_BEGIN_EVT"               },\
+                       {(0xc1ccede),   "SYNCH_END_EVT"                 },\
+                       {(0xece),       "SELF_ESTABL_CONTACT_EVT"       },\
+                       {(0x1ce),       "SELF_LOST_CONTACT_EVT"         },\
+                       {(0x9ece),      "PEER_ESTABL_CONTACT_EVT"       },\
+                       {(0x91ce),      "PEER_LOST_CONTACT_EVT"         },\
+                       {(0xfbe),       "FAILOVER_BEGIN_EVT"            },\
+                       {(0xfee),       "FAILOVER_END_EVT"              },\
+                       {(0xcbe),       "SYNCH_BEGIN_EVT"               },\
+                       {(0xcee),       "SYNCH_END_EVT"                 })
+
 int tipc_skb_dump(struct sk_buff *skb, bool more, char *buf);
 int tipc_list_dump(struct sk_buff_head *list, bool more, char *buf);
 int tipc_sk_dump(struct sock *sk, u16 dqueues, char *buf);
        TP_PROTO(struct sk_buff *skb, bool more, const char *header), \
        TP_ARGS(skb, more, header))
 DEFINE_SKB_EVENT(tipc_skb_dump);
+DEFINE_SKB_EVENT(tipc_proto_build);
+DEFINE_SKB_EVENT(tipc_proto_rcv);
 
 DECLARE_EVENT_CLASS(tipc_list_class,
 
        TP_PROTO(struct tipc_link *l, u16 dqueues, const char *header), \
        TP_ARGS(l, dqueues, header))
 DEFINE_LINK_EVENT(tipc_link_dump);
+DEFINE_LINK_EVENT(tipc_link_conges);
+DEFINE_LINK_EVENT(tipc_link_timeout);
+DEFINE_LINK_EVENT(tipc_link_reset);
+
+#define DEFINE_LINK_EVENT_COND(name, cond) \
+DEFINE_EVENT_CONDITION(tipc_link_class, name, \
+       TP_PROTO(struct tipc_link *l, u16 dqueues, const char *header), \
+       TP_ARGS(l, dqueues, header), \
+       TP_CONDITION(cond))
+DEFINE_LINK_EVENT_COND(tipc_link_too_silent, tipc_link_too_silent(l));
+
+DECLARE_EVENT_CLASS(tipc_link_transmq_class,
+
+       TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq),
+
+       TP_ARGS(r, f, t, tq),
+
+       TP_STRUCT__entry(
+               __array(char, name, TIPC_MAX_LINK_NAME)
+               __field(u16, from)
+               __field(u16, to)
+               __field(u32, len)
+               __field(u16, fseqno)
+               __field(u16, lseqno)
+       ),
+
+       TP_fast_assign(
+               tipc_link_name_ext(r, __entry->name);
+               __entry->from = f;
+               __entry->to = t;
+               __entry->len = skb_queue_len(tq);
+               __entry->fseqno = msg_seqno(buf_msg(skb_peek(tq)));
+               __entry->lseqno = msg_seqno(buf_msg(skb_peek_tail(tq)));
+       ),
+
+       TP_printk("<%s> retrans req: [%u-%u] transmq: %u [%u-%u]\n",
+                 __entry->name, __entry->from, __entry->to,
+                 __entry->len, __entry->fseqno, __entry->lseqno)
+);
+
+DEFINE_EVENT(tipc_link_transmq_class, tipc_link_retrans,
+       TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq),
+       TP_ARGS(r, f, t, tq)
+);
+
+DEFINE_EVENT_PRINT(tipc_link_transmq_class, tipc_link_bc_ack,
+       TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq),
+       TP_ARGS(r, f, t, tq),
+       TP_printk("<%s> acked: [%u-%u] transmq: %u [%u-%u]\n",
+                 __entry->name, __entry->from, __entry->to,
+                 __entry->len, __entry->fseqno, __entry->lseqno)
+);
 
 DECLARE_EVENT_CLASS(tipc_node_class,
 
        TP_ARGS(n, more, header))
 DEFINE_NODE_EVENT(tipc_node_dump);
 
+DECLARE_EVENT_CLASS(tipc_fsm_class,
+
+       TP_PROTO(const char *name, u32 os, u32 ns, int evt),
+
+       TP_ARGS(name, os, ns, evt),
+
+       TP_STRUCT__entry(
+               __string(name, name)
+               __field(u32, os)
+               __field(u32, ns)
+               __field(u32, evt)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, name);
+               __entry->os = os;
+               __entry->ns = ns;
+               __entry->evt = evt;
+       ),
+
+       TP_printk("<%s> %s--(%s)->%s\n", __get_str(name),
+                 state_sym(__entry->os), evt_sym(__entry->evt),
+                 state_sym(__entry->ns))
+);
+
+#define DEFINE_FSM_EVENT(fsm_name) \
+DEFINE_EVENT(tipc_fsm_class, fsm_name, \
+       TP_PROTO(const char *name, u32 os, u32 ns, int evt), \
+       TP_ARGS(name, os, ns, evt))
+DEFINE_FSM_EVENT(tipc_link_fsm);
+
 #endif /* _TIPC_TRACE_H */
 
 /* This part must be outside protection */