diff --git a/userspace/include/hal_exports.h b/userspace/include/hal_exports.h
index b7f0017d47013d4fa6f2283c0c4b8d507675736e..8d0708e5a2b54ffe9e350b2bb1fa0ea74da70be4 100644
--- a/userspace/include/hal_exports.h
+++ b/userspace/include/hal_exports.h
@@ -26,6 +26,7 @@
 #define HEXP_LOCK_CMD_START 1
 #define HEXP_LOCK_CMD_CHECK 2
 #define HEXP_LOCK_CMD_ENABLE_TRACKING 3
+#define HEXP_LOCK_CMD_RESET 4
 
 #define HEXP_LOCK_STATUS_LOCKED 0
 #define HEXP_LOCK_STATUS_BUSY 1
diff --git a/userspace/libwr/include/libwr/hal_shmem.h b/userspace/libwr/include/libwr/hal_shmem.h
index d96a97f94be1ab1604236fe43583cfe9ce1dec2f..273c66147f7e0a41674e6b8ecf3064681d1f1bac 100644
--- a/userspace/libwr/include/libwr/hal_shmem.h
+++ b/userspace/libwr/include/libwr/hal_shmem.h
@@ -11,6 +11,7 @@
 #define HAL_PORT_STATE_UP 2
 #define HAL_PORT_STATE_CALIBRATION 3
 #define HAL_PORT_STATE_LOCKING 4
+#define HAL_PORT_STATE_RESET 5
 
 /* Read temperature from SFPs */
 #define READ_SFP_DIAG_ENABLE 1
diff --git a/userspace/ppsi b/userspace/ppsi
index cb5934e8dac07c21572d335a5691ea714eeebf57..b2f4280d7386dd936e0b62712955d6e5e31d2e94 160000
--- a/userspace/ppsi
+++ b/userspace/ppsi
@@ -1 +1 @@
-Subproject commit cb5934e8dac07c21572d335a5691ea714eeebf57
+Subproject commit b2f4280d7386dd936e0b62712955d6e5e31d2e94
diff --git a/userspace/tools/Makefile b/userspace/tools/Makefile
index 4677ff11b08bf0482fbc3ecbafefd08ee04f509a..9721453dc4eebc4e14f6a0406fa10c03e7a37a37 100644
--- a/userspace/tools/Makefile
+++ b/userspace/tools/Makefile
@@ -10,6 +10,7 @@ TOOLS += wrs_status_led
 TOOLS += mkpasswd
 TOOLS += wrs_sfp_dump
 TOOLS += wrs_throttling
+TOOLS += utc_leap_test
 PPSI_CONFIG = ../ppsi/include/generated/autoconf.h
 
 WR_INSTALL_ROOT ?= /usr/lib/white-rabbit
diff --git a/userspace/tools/utc_leap_test.c b/userspace/tools/utc_leap_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..bc7f1b739a22401e4a51d108d00f8a3e46d63d44
--- /dev/null
+++ b/userspace/tools/utc_leap_test.c
@@ -0,0 +1,279 @@
+/* This is just a subset of wr_date, user to test on the host */
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+
+#ifndef MOD_TAI
+#define MOD_TAI 0x80
+#endif
+
+int opt_verbose = 1;
+char *prgname;
+
+static void unix_time_clear_utc_flags(void)
+{
+	struct timex t;
+	
+	/*
+	 * We have to call adjtime twice here, as kernels
+	 * prior to 6b1859dba01c7 (included in 3.5 and
+	 * -stable), had an issue with the state machine
+	 * and wouldn't clear the STA_INS/DEL flag directly.
+	 */
+	t.modes = ADJ_STATUS;
+	t.status = STA_PLL;
+	adjtimex(&t);
+
+	/* Clear maxerror, as it can cause UNSYNC to be set */
+	t.modes = ADJ_MAXERROR;
+	t.maxerror = 0;
+	adjtimex(&t);
+
+	/* Clear the status */
+	t.modes = ADJ_STATUS;
+	t.status = 0;
+	adjtimex(&t);	
+		
+}
+
+static int unix_time_get_utc_time(int *hours, int *minutes, int *seconds)
+{
+	int ret;
+	struct timex t;
+	time_t now;
+	struct tm *date;
+	
+	/* Get the UTC time */
+	memset(&t, 0, sizeof(t));
+	ret = adjtimex(&t);
+	if (ret >= 0) {
+		now = t.time.tv_sec;
+		/* use gmtime for correct leap handling */
+		date = gmtime(&now);
+		*hours = date->tm_hour;
+		*minutes = date->tm_min;
+		*seconds = date->tm_sec;
+		return 0;
+	} else {
+		*hours = 0;
+		*minutes = 0;
+		*seconds = 0;
+		return -1;
+	}
+	
+	return -1;
+}
+
+static int unix_time_get_utc_offset(int *offset, int *leap59, int *leap61)
+{
+	int ret;
+	struct timex t;
+	int hours, minutes, seconds;
+	
+	unix_time_get_utc_time(&hours, &minutes, &seconds);
+	
+	/*
+	 * Get the UTC/TAI difference
+	 */
+	memset(&t, 0, sizeof(t));
+	ret = adjtimex(&t);
+	if (ret >= 0) {
+		if (hours >= 12) {
+			if ((t.status & STA_INS) == STA_INS) {
+				*leap59 = 0;
+				*leap61 = 1;
+			} else if ((t.status & STA_DEL) == STA_DEL) {
+				*leap59 = 1;
+				*leap61 = 0;
+			} else {
+				*leap59 = 0;
+				*leap61 = 0;
+			}	
+		} else {
+			unix_time_clear_utc_flags();			
+			*leap59 = 0;
+			*leap61 = 0;
+		}
+		/*
+		 * Our WRS kernel has tai support, but our compiler does not.
+		 * We are 32-bit only, and we know for sure that tai is
+		 * exactly after stbcnt. It's a bad hack, but it works
+		 */
+		*offset = *((int *)(&t.stbcnt) + 1);
+		return 0;
+	} else {
+		*leap59 = 0;
+		*leap61 = 0;
+		*offset = 0;
+		return -1;
+	}		
+}
+
+static int unix_time_set_utc_offset(int offset, int leap59, int leap61) 
+{
+	struct timex t;
+    	int ret;
+	
+	unix_time_clear_utc_flags();
+	
+	/* get the current flags first */
+	memset(&t, 0, sizeof(t));
+	ret = adjtimex(&t);
+	
+	if (ret >= 0) {
+		if (leap59) {
+			t.modes = MOD_STATUS;
+			t.status |= STA_DEL;
+			t.status &= ~STA_INS;
+			printf("set leap59 flag\n");
+		} else if (leap61) {
+			t.modes = MOD_STATUS;
+			t.status |= STA_INS;
+			t.status &= ~STA_DEL;
+			printf("set leap61 flag\n");
+		} else {
+			t.modes = MOD_STATUS;
+			t.status &= ~STA_INS;
+			t.status &= ~STA_DEL;
+			printf("set no leap flags\n");
+		}
+
+	    if (adjtimex(&t) < 0) {
+		    printf("set UTC flags failed\n");
+		    return -1;
+	    }
+
+    } else
+		printf("get UTC flags failed\n");
+	
+	t.modes = MOD_TAI;
+	t.constant = offset;
+	if (adjtimex(&t) < 0) {
+		printf("set UTC offset failed\n");
+		return -1;
+	} else
+		printf("set UTC offset to: %i\n", offset);
+    
+	
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int i, j;
+	int offset, leap59, leap61;
+	int hours, minutes, seconds;
+	struct timespec tp;
+	
+	for (j=0; j<3; j++) {
+
+		/* Get the UTC time */
+		unix_time_get_utc_time(&hours, &minutes, &seconds);
+		unix_time_get_utc_offset(&offset, &leap59, &leap61);	
+		printf("current time %d:%d:%d, offset=%d, l59=%d, l61=%d\n", hours, minutes, seconds, offset, leap59, leap61);
+
+
+		/* Set time to 30. June 2017 23:59:50 */
+		tp.tv_sec = 1498867190;
+		tp.tv_nsec = 0;
+		clock_settime(CLOCK_REALTIME, &tp);
+
+
+		/* Get the UTC time */
+		unix_time_get_utc_time(&hours, &minutes, &seconds);
+		unix_time_get_utc_offset(&offset, &leap59, &leap61);	
+		printf("new current time %d:%d:%d, offset=%d, l59=%d, l61=%d\n", hours, minutes, seconds, offset, leap59, leap61);
+
+
+		if (j == 0) {
+			/* Set leap61 and UTC offset to 37 */
+			offset = 37;
+			leap59 = 0;
+			leap61 = 1;		
+			unix_time_set_utc_offset(offset, leap59, leap61);
+		} else if (j == 1) {
+			/* Set leap59 and UTC offset to 37 */
+			offset = 37;
+			leap59 = 1;
+			leap61 = 0;		
+			unix_time_set_utc_offset(offset, leap59, leap61);
+		} else {
+			/* Set no leaps and UTC offset to 37 */
+			offset = 37;
+			leap59 = 0;
+			leap61 = 0;		
+			unix_time_set_utc_offset(offset, leap59, leap61);
+		}			
+
+		if (j == 0) {
+			if ((hours == 23) && (minutes == 59) && (seconds == 50) && (offset == 37) && (leap59 == 0) && (leap61 == 1)) {
+				printf("pre leap61 handling correct\n");
+			} else {
+				printf("pre leap61 handling failed\n");
+				exit(1);
+			}				
+		} else if (j == 1) {
+			if ((hours == 23) && (minutes == 59) && (seconds == 50) && (offset == 37) && (leap59 == 1) && (leap61 == 0)) {
+				printf("pre leap59 handling correct\n");
+			} else {
+				printf("pre leap59 handling failed\n");
+				exit(2);
+			}
+		} else {
+			if ((hours == 23) && (minutes == 59) && (seconds == 50) && (offset == 37) && (leap59 == 0) && (leap61 == 0)) {
+				printf("pre no-leap handling correct\n");
+			} else {
+				printf("pre no-leap handling failed\n");
+				exit(3);
+			}
+		}	
+		
+		for (i=0; i< 20; i++) {
+			/* Get the UTC time */
+			unix_time_get_utc_offset(&offset, &leap59, &leap61);	
+			unix_time_get_utc_time(&hours, &minutes, &seconds);
+			printf("new current time after offset and leap %d:%d:%d, offset=%d, l59=%d, l61=%d\n", hours, minutes, seconds, offset, leap59, leap61);
+			sleep(1);
+		}
+		
+		unix_time_get_utc_offset(&offset, &leap59, &leap61);	
+		unix_time_get_utc_time(&hours, &minutes, &seconds);
+		
+		if (j == 0) {
+			if ((hours == 0) && (minutes == 0) && (seconds == 9) && (offset == 38) && (leap59 == 0) && (leap61 == 0)) {
+				printf("post leap61 handling correct\n\n");
+			} else {
+				printf("post leap61 handling failed\n\n");
+				exit(1);
+			}				
+		} else if (j == 1) {
+			if ((hours == 0) && (minutes == 0) && (seconds == 11) && (offset == 36) && (leap59 == 0) && (leap61 == 0)) {
+				printf("post leap59 handling correct\n\n");
+			} else {
+				printf("post leap59 handling failed\n\n");
+				exit(2);
+			}
+		} else {
+			if ((hours == 0) && (minutes == 0) && (seconds == 10) && (offset == 37) && (leap59 == 0) && (leap61 == 0)) {
+				printf("post no-leap handling correct\n\n");
+			} else {
+				printf("post no-leap handling failed\n\n");
+				exit(3);
+			}
+		}				
+	}
+
+	printf("all leap handling tests passed\n\n");
+	exit(0);	
+}
diff --git a/userspace/wrsw_hal/hal_exports.c b/userspace/wrsw_hal/hal_exports.c
index 0bfad7523ebffd2742d8d40f0e525a521ce1e909..ad07772856fd905b624abf0585b47ef5ee890260 100644
--- a/userspace/wrsw_hal/hal_exports.c
+++ b/userspace/wrsw_hal/hal_exports.c
@@ -65,6 +65,10 @@ int halexp_lock_cmd(const char *port_name, int command, int priority)
 		else
 			return HEXP_LOCK_STATUS_NONE;
 		break;
+			
+	case HEXP_LOCK_CMD_RESET:
+		return hal_port_reset(port_name);
+		
 	}
 
 	return -100;		/* fixme: add real error code */
diff --git a/userspace/wrsw_hal/hal_ports.c b/userspace/wrsw_hal/hal_ports.c
index b4460aba0be8ad3d39f4d7eb9e23a00bb99f4e6a..989b0daf3b7e1ec8f03129916bdc117b6fbed6d1 100644
--- a/userspace/wrsw_hal/hal_ports.c
+++ b/userspace/wrsw_hal/hal_ports.c
@@ -423,6 +423,7 @@ static void hal_port_fsm(struct hal_port_state * p)
 
 		/* Default state - wait until the link goes up */
 	case HAL_PORT_STATE_LINK_DOWN:
+	case HAL_PORT_STATE_RESET:
 		{
 			if (link_up) {
 				p->calib.tx_calibrated = 1;
@@ -760,6 +761,39 @@ int hal_port_check_lock(const char *port_name)
 		(hs->flags & RTS_REF_LOCKED));
 }
 
+int hal_port_reset(const char *port_name)
+{
+	struct hal_port_state *p = hal_lookup_port(ports,
+						  hal_port_nports, port_name);
+
+	if (!p)
+		return -1;
+
+	if (p->state != HAL_PORT_STATE_LINK_DOWN
+	    && p->state != HAL_PORT_STATE_DISABLED) {
+		if (p->locked) {
+			pr_info("Switching RTS to use local reference\n");
+			if (hal_get_timing_mode()
+			    != HAL_TIMING_MODE_GRAND_MASTER)
+				rts_set_mode(RTS_MODE_GM_FREERUNNING);
+		}
+
+		/* turn off synced LED */
+		set_led_synced(p->hw_index, 0);
+
+		/* turn off link/wrmode LEDs */
+		set_led_wrmode(p->hw_index, SFP_LED_WRMODE_OFF);
+		hal_port_reset_state(p);
+		p->state = HAL_PORT_STATE_RESET;
+
+		rts_enable_ptracker(p->hw_index, 0);
+		pr_info("%s: link down\n", p->name);
+
+		return 1;
+	}
+	return 0;
+}
+
 /* to avoid i2c transfers to set the link LEDs, cache their state */
 static void set_led_wrmode(int p_index, int val)
 {
diff --git a/userspace/wrsw_hal/wrsw_hal.h b/userspace/wrsw_hal/wrsw_hal.h
index b9a84c7ec2f63545a884255cb2f78fdd535b1d79..dbd60cd5df9aa91c44a6ee0aaa580e557158e1a7 100644
--- a/userspace/wrsw_hal/wrsw_hal.h
+++ b/userspace/wrsw_hal/wrsw_hal.h
@@ -27,9 +27,10 @@ int hal_update_wripc(int ms_timeout);
 
 int hal_add_cleanup_callback(hal_cleanup_callback_t cb);
 
-int hal_port_start_lock(const char  *port_name, int priority);
-int hal_port_check_lock(const char  *port_name);
-int hal_port_enable_tracking(const char  *port_name);
+int hal_port_start_lock(const char *port_name, int priority);
+int hal_port_check_lock(const char *port_name);
+int hal_port_reset(const char *port_name);
+int hal_port_enable_tracking(const char *port_name);
 
 int hal_init_timing_mode(void);
 int hal_init_timing(char *filename);