diff --git a/include/net/mrp.h b/include/net/mrp.h
index 4fbf02a..0f7558b 100644
--- a/include/net/mrp.h
+++ b/include/net/mrp.h
@@ -112,6 +112,7 @@ struct mrp_applicant {
 	struct mrp_application	*app;
 	struct net_device	*dev;
 	struct timer_list	join_timer;
+	struct timer_list	periodic_timer;
 
 	spinlock_t		lock;
 	struct sk_buff_head	queue;
diff --git a/net/802/mrp.c b/net/802/mrp.c
index 1eb05d8..8f1fa4f 100644
--- a/net/802/mrp.c
+++ b/net/802/mrp.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
 /*
  *	IEEE 802.1Q Multiple Registration Protocol (MRP)
  *
@@ -24,6 +26,12 @@
 static unsigned int mrp_join_time __read_mostly = 200;
 module_param(mrp_join_time, uint, 0644);
 MODULE_PARM_DESC(mrp_join_time, "Join time in ms (default 200ms)");
+
+static unsigned int mrp_periodic_time __read_mostly = 1000;
+module_param(mrp_periodic_time, uint, 0644);
+MODULE_PARM_DESC(mrp_periodic_time, "Periodic time in ms (default 1s)");
+
+
 MODULE_LICENSE("GPL");
 
 static const u8
@@ -210,6 +218,52 @@ mrp_tx_action_table[MRP_APPLICANT_MAX + 1] = {
 	[MRP_APPLICANT_QP] = MRP_TX_ACTION_S_IN_OPTIONAL,
 };
 
+
+// debug
+static char *
+mrp_event_str(enum mrp_event event) {
+    char *s = "unknown";
+    switch(event) {
+    case MRP_EVENT_NEW:        s = "NEW"; break;
+    case MRP_EVENT_JOIN:       s = "JOIN"; break;
+    case MRP_EVENT_LV:	       s = "LV"; break;
+    case MRP_EVENT_TX:	       s = "TX"; break;
+    case MRP_EVENT_R_NEW:      s = "R_NEW"; break;
+    case MRP_EVENT_R_JOIN_IN:  s = "R_JOIN_IN"; break;
+    case MRP_EVENT_R_IN:       s = "R_IN"; break;
+    case MRP_EVENT_R_JOIN_MT:  s = "R_JOIN_MT"; break;
+    case MRP_EVENT_R_MT:       s = "R_MT"; break;
+    case MRP_EVENT_R_LV:       s = "R_LV"; break;
+    case MRP_EVENT_R_LA:       s = "R_LA"; break;
+    case MRP_EVENT_REDECLARE:  s = "REDECLARE"; break;
+    case MRP_EVENT_PERIODIC:   s = "PERIODIC"; break;
+    case __MRP_EVENT_MAX:      break;
+    }
+    return s;
+}
+
+// debug
+static char *
+mrp_applicant_state_str(enum mrp_applicant_state state) {
+    char *s = "unknown";
+    switch(state) {
+    case MRP_APPLICANT_INVALID:  s = "INVALID"; break;
+    case MRP_APPLICANT_VO:       s = "VO"; break;
+    case MRP_APPLICANT_VP:       s = "VP"; break;
+    case MRP_APPLICANT_VN:       s = "VN"; break;
+    case MRP_APPLICANT_AN:       s = "AN"; break;
+    case MRP_APPLICANT_AA:       s = "AA"; break;
+    case MRP_APPLICANT_QA:       s = "QA"; break;
+    case MRP_APPLICANT_LA:       s = "LA"; break;
+    case MRP_APPLICANT_AO:       s = "AO"; break;
+    case MRP_APPLICANT_QO:       s = "QO"; break;
+    case MRP_APPLICANT_AP:       s = "AP"; break;
+    case MRP_APPLICANT_QP:       s = "QP"; break;
+    case __MRP_APPLICANT_MAX:    break;
+    }
+    return s;
+}
+
 static void mrp_attrvalue_inc(void *value, u8 len)
 {
 	u8 *v = (u8 *)value;
@@ -345,8 +399,15 @@ static void mrp_queue_xmit(struct mrp_applicant *app)
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&app->queue)))
-		dev_queue_xmit(skb);
+	while ((skb = skb_dequeue(&app->queue))) {
+	    int xmit_err = dev_queue_xmit(skb);
+	    pr_debug("dev=%s len=%d dev_queue_xmit=%d carrier_ok=%d dormant=%d\n"
+		     ,skb->dev->name, (int)skb->len
+		     ,(int)xmit_err
+		     ,(int)netif_carrier_ok(skb->dev)
+		     ,(int)netif_dormant(skb->dev)
+		     );
+	}
 }
 
 static int mrp_pdu_append_msg_hdr(struct mrp_applicant *app,
@@ -474,6 +535,13 @@ static void mrp_attr_event(struct mrp_applicant *app,
 		return;
 	}
 
+	pr_debug("attr_type=%d event=%s attr->state=%s new state=%s\n"
+		 ,(int)attr->type
+		 ,mrp_event_str(event)
+		 ,mrp_applicant_state_str(attr->state)
+		 ,mrp_applicant_state_str(state));
+
+
 	if (event == MRP_EVENT_TX) {
 		/* When appending the attribute fails, don't update its state
 		 * in order to retry at the next TX event.
@@ -521,6 +589,8 @@ int mrp_request_join(const struct net_device *dev,
 		port->applicants[appl->type]);
 	struct mrp_attr *attr;
 
+	pr_debug("dev->name=%s attr_type=%d\n", dev->name, (int)type);
+
 	if (sizeof(struct mrp_skb_cb) + len >
 	    FIELD_SIZEOF(struct sk_buff, cb))
 		return -ENOMEM;
@@ -546,6 +616,8 @@ void mrp_request_leave(const struct net_device *dev,
 		port->applicants[appl->type]);
 	struct mrp_attr *attr;
 
+	pr_debug("dev->name=%s attr_type=%d\n", dev->name, (int)type);
+
 	if (sizeof(struct mrp_skb_cb) + len >
 	    FIELD_SIZEOF(struct sk_buff, cb))
 		return;
@@ -595,6 +667,52 @@ static void mrp_join_timer(unsigned long data)
 	mrp_join_timer_arm(app);
 }
 
+static void mrp_periodic_timer_arm(struct mrp_applicant *app)
+{
+	unsigned long delay;
+
+	delay = (u64)msecs_to_jiffies(mrp_periodic_time);
+	mod_timer(&app->periodic_timer, jiffies + delay);
+}
+
+
+/*
+
+from [802.1Q-2011]
+http://standards.ieee.org/findstds/standard/802.1Q-2011.html
+
+
+10.7.4.4 periodictimer
+
+The Periodic Transmission timer, periodictimer, controls the frequency
+with which the PeriodicTransmission state machine generates periodic!
+events. The timer is required on a per-Port basis. The Periodic
+Transmission timer is set to one second when it is started.
+
+10.7.5.10 periodic!
+
+This event indicates to the Applicant state machine that the timer
+used to stimulate periodic transmission has expired.
+
+10.7.5.23 periodictimer!
+
+For an instance of the PeriodicTransmission state machine, the
+periodictimer! event is deemed to have occurred when the periodictimer
+associated with that state machine expires.
+
+*/
+static void mrp_periodic_timer(unsigned long data)
+{
+	struct mrp_applicant *app = (struct mrp_applicant *)data;
+
+	spin_lock(&app->lock);
+	mrp_mad_event(app, MRP_EVENT_PERIODIC);
+	mrp_pdu_queue(app);
+	spin_unlock(&app->lock);
+
+	mrp_periodic_timer_arm(app);
+}
+
 static int mrp_pdu_parse_end_mark(struct sk_buff *skb, int *offset)
 {
 	__be16 endmark;
@@ -791,10 +909,13 @@ out:
 	return 0;
 }
 
+
 static int mrp_init_port(struct net_device *dev)
 {
 	struct mrp_port *port;
 
+	pr_debug("dev->name=%s\n", dev->name);
+
 	port = kzalloc(sizeof(*port), GFP_KERNEL);
 	if (!port)
 		return -ENOMEM;
@@ -807,6 +928,8 @@ static void mrp_release_port(struct net_device *dev)
 	struct mrp_port *port = rtnl_dereference(dev->mrp_port);
 	unsigned int i;
 
+	pr_debug("dev->name=%s\n", dev->name);
+
 	for (i = 0; i <= MRP_APPLICATION_MAX; i++) {
 		if (rtnl_dereference(port->applicants[i]))
 			return;
@@ -820,6 +943,8 @@ int mrp_init_applicant(struct net_device *dev, struct
mrp_application *appl)
 	struct mrp_applicant *app;
 	int err;
 
+	pr_debug("dev->name=%s\n", dev->name);
+
 	ASSERT_RTNL();
 
