components/ptp/patches/00-sol_sf_patch_over_community_edition.patch
author Prakash Jalan <Prakash.Jalan@oracle.com>
Wed, 04 Dec 2013 16:17:21 -0800
changeset 1580 dece556dd5e7
child 2214 c98efe8be94e
permissions -rw-r--r--
PSARC/2013/284 PTP (Precision Time Protocol) 2.2.0 15820662 SUNBT7203023 PTP support in Solaris

Includes the changes from third party vendor Solarflare to make
ptpd use hardware assistance provided by some of their NICs.
   This patch also include changes developed in-house to support
Solaris in general and Solaris on sparc platform. Solarflare
related changes will not be fed back upstream. Solaris related
changes will be contributed back upstream.

diff -r 3f1e7d35d0ab -r 821e8eadeaff COPYRIGHT
--- a/COPYRIGHT	Tue May 14 17:07:59 2013 -0700
+++ b/COPYRIGHT	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,6 @@
 /*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2012 George V. Neville-Neil, 
  *                         Steven Kreuzer, 
  *                         Martin Burnicki, 
diff -r 3f1e7d35d0ab -r 821e8eadeaff Makefile
--- a/Makefile	Tue May 14 17:07:59 2013 -0700
+++ b/Makefile	Sun Oct 27 22:49:29 2013 -0700
@@ -2,16 +2,12 @@
 
 VERSION = ptpd-2.2.0
 
-release:
-	(cd src; make clean)
-	mkdir $(VERSION)
-	(cd $(VERSION); \
-	ln -s ../src .; \
-	ln -s ../doc .; \
-	ln -s ../tools .; \
-	ln -s ../COPYRIGHT .; \
-	ln -s ../ChangeLog .; \
-	ln -s ../Makefile .; \
-	ln -s ../README .; \
-	ln -s ../RELEASE_NOTES .)
-	tar cvzf $(VERSION).tar.gz -L --exclude .o --exclude Doxygen --exclude .svn --exclude .dep --exclude core $(VERSION)
+build:
+	(cd src; gmake clean; gmake)
+
+install:
+	mkdir -p $(DESTDIR)/usr/lib/inet
+	ginstall -D -p -m 755 src/ptpd $(DESTDIR)/usr/lib/inet/ptpd
+	mkdir -p $(DESTDIR)/usr/share/man/man1m/
+	ginstall -D -p -m 444 src/ptpd2.8 $(DESTDIR)/usr/share/man/man1m/ptpd.1m
+	
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/Makefile
--- a/src/Makefile	Tue May 14 17:07:59 2013 -0700
+++ b/src/Makefile	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,4 @@
-# Makefile for ptpd2
+# Makefile for ptpd
 
 #
 # Compile time defines:
@@ -13,6 +13,7 @@
 #  -DPTPD_DBGV    adds all debug messages
 #
 #   -DPTPD_NO_DAEMON             forces option -c
+#  -DBSD_INTERFACE_FUNCTIONS: for OpenBSD
 #
 #   -PTP_EXPERIMENTAL            Allows non-standard compliant experimental options:
 #                                   -U: Hybrid mode
@@ -27,29 +28,35 @@
 RM = rm -f
 
 # start with CFLAGS += ..., so additional CFLAGs can be specified e.g. on the make command line
-CFLAGS += -Wall -g
-
+CFLAGS = -Wall -g -D_ISOC99_SOURCE -D_BSD_SOURCE -std=gnu99 -m64
+CPPFLAGS += -D_XOPEN_SOURCE=600 -D__EXTENSIONS__ -D_XPG4_2
 CFLAGS += -DRUNTIME_DEBUG
 #CFLAGS += -DPTPD_DBG
 #CFLAGS += -DPTPD_DBG2
 #CFLAGS += -DPTPD_DBGV
+#CFLAGS += -DPTPD_DUMP
 
 #CFLAGS += -DPTPD_NO_DAEMON
+#CFLAGS += -DBSD_INTERFACE_FUNCTIONS
 #CFLAGS += -DDBG_SIGUSR2_CHANGE_DOMAIN
-CFLAGS += -DDBG_SIGUSR2_CHANGE_DEBUG
+#CFLAGS += -DDBG_SIGRTMIN_LEAP_SECOND
+#CFLAGS += -DDBG_SIGUSR2_CHANGE_DEBUG
+#CFLAGS += -DPTPD_FULL_OPTIONS
 
-CFLAGS += -DPTP_EXPERIMENTAL
+#CFLAGS += -DPTP_EXPERIMENTAL
 
 LDFLAGS+= -lm -lrt
+LDFLAGS += -lnsl -lsocket -m64
 
-PROG = ptpd2
+PROG = ptpd
 SRCS = ptpd.c arith.c bmc.c protocol.c display.c\
-	dep/msg.c dep/net.c dep/servo.c dep/startup.c dep/sys.c dep/timer.c
+	dep/msg.c dep/net.c dep/servo.c dep/startup.c dep/sys.c dep/timer.c dep/time.c
 
 OBJS = $(SRCS:.c=.o)
 
 HDRS = ptpd.h constants.h datatypes.h \
-	dep/ptpd_dep.h dep/constants_dep.h dep/datatypes_dep.h
+	dep/ptpd_dep.h dep/constants_dep.h dep/datatypes_dep.h \
+        dep/sfxge_ioctl.h
 
 CSCOPE = cscope
 GTAGS = gtags
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/arith.c
--- a/src/arith.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/arith.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,5 +1,7 @@
 /*-
- * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer,
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
  *
@@ -36,9 +38,12 @@
  * 
  */
 
+#include <math.h>
 #include "ptpd.h"
 
 
+double round (double __x);
+
 void 
 integer64_to_internalTime(Integer64 bigint, TimeInternal * internal)
 {
@@ -245,7 +250,7 @@
 }
 
 
-
+#if 0
 int check_timestamp_is_fresh2(TimeInternal * timeA, TimeInternal * timeB)
 {
 	int ret;
@@ -264,7 +269,7 @@
 	return check_timestamp_is_fresh2(timeA, &timeB);
 }
 
-
+#endif
 int
 isTimeInternalNegative(const TimeInternal * p)
 {
@@ -272,4 +277,52 @@
 }
 
 
+int64_t
+internalTime_to_scalar(TimeInternal *internal)
+{
+	return ((int64_t)internal->seconds * 1000000000LL)
+		+ (int64_t)internal->nanoseconds;
+}
 
+float
+secondsToMidnight(void) 
+{
+	TimeInternal now;
+ 
+	timerNow(&now);
+ 
+	// TODO should be 86400 - (now.seconds % 86400)
+	Integer32 stmI = (now.seconds - (now.seconds % 86400) + 86400) - 
+		now.seconds;
+ 
+	return (stmI + 0.0 - now.nanoseconds / 1E9);
+}
+ 
+
+float
+getPauseBeforeMidnight(Integer8 announceInterval) 
+{
+	return ((secondsToMidnight() <= getPauseAfterMidnight(announceInterval)) ?
+		secondsToMidnight() : getPauseAfterMidnight(announceInterval));
+}
+
+
+float
+getPauseAfterMidnight(Integer8 announceInterval) 
+{
+	return((LEAP_SECOND_PAUSE_PERIOD > 2 * pow(2,announceInterval)) ?
+	       LEAP_SECOND_PAUSE_PERIOD + 0.0  : 2 * pow(2,announceInterval) + 
+	       0.0);
+}
+
+
+int
+log2IntegerSaturateAtZero(LongDouble number)
+{
+    if (number <= 0) return 0;
+
+    number = log(number)/log(2);
+
+    return round(number);
+}
+
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/bmc.c
--- a/src/bmc.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/bmc.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,5 @@
 /*-
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
@@ -77,7 +78,7 @@
 
 	ptpClock->domainNumber = rtOpts->domainNumber;
 	ptpClock->slaveOnly = rtOpts->slaveOnly;
-	if(rtOpts->slaveOnly)
+	if(rtOpts->master_slave_mode == PTP_MODE_SLAVE)
 		rtOpts->clockQuality.clockClass = 255;
 
 /* Port configuration data set */
@@ -91,16 +92,17 @@
 	ptpClock->portIdentity.portNumber = NUMBER_PORTS;
 
 	/* select the initial rate of delayreqs until we receive the first announce message */
-	ptpClock->logMinDelayReqInterval = rtOpts->initial_delayreq;
+	ptpClock->minDelayReqInterval = rtOpts->initial_delayreq;
+	ptpClock->logMinDelayReqInterval = log2IntegerSaturateAtZero(rtOpts->initial_delayreq);
 
 	clearTime(&ptpClock->peerMeanPathDelay);
 
-	ptpClock->logAnnounceInterval = rtOpts->announceInterval;
+	ptpClock->logAnnounceInterval = log2IntegerSaturateAtZero(rtOpts->announceInterval);
 	ptpClock->announceReceiptTimeout = rtOpts->announceReceiptTimeout;
-	ptpClock->logSyncInterval = rtOpts->syncInterval;
+	ptpClock->logSyncInterval = log2IntegerSaturateAtZero(rtOpts->syncInterval);
 	ptpClock->delayMechanism = rtOpts->delayMechanism;
-	ptpClock->logMinPdelayReqInterval = DEFAULT_PDELAYREQ_INTERVAL;
-	ptpClock->versionNumber = VERSION_PTP;
+	ptpClock->logMinPdelayReqInterval = DEFAULT_LOG_PDELAYREQ_INTERVAL;
+	ptpClock->versionNumber = VERSION_PTP_PROTOCOL;
 
  	/*
 	 *  Initialize random number generator using same method as ptpv1:
@@ -145,9 +147,10 @@
 	ptpClock->timeSource = INTERNAL_OSCILLATOR;
 
 	/* UTC vs TAI timescales */
-	ptpClock->currentUtcOffsetValid = DEFAULT_UTC_VALID;
+	ptpClock->currentUtcOffsetValid = rtOpts->currentUtcOffsetValid;
 	ptpClock->currentUtcOffset = rtOpts->currentUtcOffset;
 	
+	/* TODO Should we clear the leap second flags? Unprogram leap second in kernel? */
 }
 
 
@@ -156,8 +159,10 @@
 {
 	/* make sure we revert to ARB timescale in Passive mode*/
 	if(ptpClock->portState == PTP_PASSIVE){
-		ptpClock->currentUtcOffsetValid = DEFAULT_UTC_VALID;
+		ptpClock->currentUtcOffsetValid = rtOpts->currentUtcOffsetValid;
 		ptpClock->currentUtcOffset = rtOpts->currentUtcOffset;
+
+		/* TODO Should we clear the leap second flags? Unprogram leap second in kernel? */
 	}
 	
 }
@@ -166,6 +171,16 @@
 /*Local clock is synchronized to Ebest Table 16 (9.3.5) of the spec*/
 void s1(MsgHeader *header,MsgAnnounce *announce,PtpClock *ptpClock, RunTimeOpts *rtOpts)
 {
+
+	Boolean previousLeap59 = FALSE, previousLeap61 = FALSE;
+	Integer16 previousUtcOffset = 0;
+
+	if (ptpClock->portState == PTP_SLAVE) {
+		previousLeap59 = ptpClock->leap59;
+		previousLeap61 = ptpClock->leap61;
+		previousUtcOffset = ptpClock->currentUtcOffset;
+	}
+
 	/* Current DS */
 	ptpClock->stepsRemoved = announce->stepsRemoved + 1;
 
@@ -193,12 +208,95 @@
 	/* set PTP_PASSIVE-specific state */
 	p1(ptpClock, rtOpts);
 
-	ptpClock->leap59 = ((header->flagField[1] & PTP_LI_61) == PTP_LI_59);
-	ptpClock->leap61 = ((header->flagField[1] & PTP_LI_61) == PTP_LI_61);
 	ptpClock->timeTraceable = ((header->flagField[1] & TIME_TRACEABLE) == TIME_TRACEABLE);
 	ptpClock->frequencyTraceable = ((header->flagField[1] & FREQUENCY_TRACEABLE) == FREQUENCY_TRACEABLE);
 	ptpClock->ptpTimescale = ((header->flagField[1] & PTP_TIMESCALE) == PTP_TIMESCALE);
 	ptpClock->timeSource = announce->timeSource;
+
+	
+	/* Leap second handling */
+
+        if (ptpClock->portState == PTP_SLAVE) {
+		/* We must not take leap second updates while a leap second
+		 * is in progress. This shouldn't happen but we should not
+		 * rely on the master behaving. We'll take the update when
+		 * the first announce arrives after the leap second has
+		 * completed.
+		 */
+		if (!ptpClock->leapSecondInProgress) {
+			ptpClock->leap59 = ((header->flagField[1] & PTP_LI_59) == PTP_LI_59);
+			ptpClock->leap61 = ((header->flagField[1] & PTP_LI_61) == PTP_LI_61);
+			
+			if(ptpClock->leap59 && ptpClock->leap61) {
+				ERROR("Both Leap59 and Leap61 flags set!\n");
+				toState(PTP_FAULTY, rtOpts, ptpClock);
+				return;
+			}
+
+			if ((previousLeap59 != ptpClock->leap59) || 
+		            (previousLeap61 != ptpClock->leap61)) {
+				/* Either a leap second has been set. Start
+				 * by cancelling any leap seconds already
+				 * programmed. */
+				ptpClock->leapSecondPending = FALSE;
+				timerStop(LEAP_SECOND_PENDING_TIMER, ptpClock->itimer);
+				timerStop(LEAP_SECOND_NOW_TIMER, ptpClock->itimer);
+#if !defined(__APPLE__)
+				unsetTimexFlags(STA_INS | STA_DEL,TRUE);
+#endif /* apple */
+				/* If one of the leap seconds is set, program
+				 * the kernel to make the change. Set a timer
+				 * to expire just before the leap second will
+				 * occur. */
+				if (ptpClock->leap59 || ptpClock->leap61) {
+#if !defined(__APPLE__)
+					if (rtOpts->noResetClock ||
+					    rtOpts->resetClockStartupOnly) {
+						WARNING("=== Leap second pending! "
+							"One second will be %s "
+							"at midnight\n",
+							ptpClock->leap61 ?
+							"added" : "deleted");
+					} else {
+						WARNING("=== Leap second pending! "
+							"Setting kernel to %s "
+							"one second at midnight\n",
+							ptpClock->leap61 ?
+							"add" : "delete");
+					
+						setTimexFlags(ptpClock->leap61 ?
+							      STA_INS : STA_DEL,
+							      FALSE);
+					}
+#else
+					WARNING("=== Leap second pending! "
+						"No kernel leap second "
+						"API support - expect a "
+						"clock jump at midnight!\n");
+#endif /* apple */
+					ptpClock->leapSecondPending = TRUE;
+					timerStart(LEAP_SECOND_PENDING_TIMER,
+						   secondsToMidnight() - 
+						   getPauseBeforeMidnight(ptpClock->logAnnounceInterval),
+						   ptpClock->itimer);
+				} else {
+					WARNING("=== Leap second event "
+						"aborted by GM!\n");
+				}
+			}
+		}
+
+		if((previousUtcOffset != ptpClock->currentUtcOffset) && 
+		   !ptpClock->leapSecondPending && 
+		   !ptpClock->leapSecondInProgress ) {
+			WARNING("=== UTC offset changed from %d to %d with "
+				"no leap second pending!\n",
+				previousUtcOffset, ptpClock->currentUtcOffset);
+		} else if( previousUtcOffset != ptpClock->currentUtcOffset) {
+			WARNING("=== UTC offset changed from %d to %d\n",
+				previousUtcOffset,ptpClock->currentUtcOffset);
+		}
+	}
 }
 
 
@@ -342,9 +440,7 @@
 		 RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	Integer8 comp;
-	
-	
-	if (rtOpts->slaveOnly)	{
+	if (rtOpts->master_slave_mode == PTP_MODE_SLAVE) {
 		s1(header,announce,ptpClock, rtOpts);
 		return PTP_SLAVE;
 	}
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/constants.h
--- a/src/constants.h	Tue May 14 17:07:59 2013 -0700
+++ b/src/constants.h	Sun Oct 27 22:49:29 2013 -0700
@@ -1,3 +1,33 @@
+/*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
+ *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
+ * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 #ifndef CONSTANTS_H_
 #define CONSTANTS_H_
 
@@ -9,7 +39,8 @@
 * and enumeration defined in the spec
  */
 
- #define MANUFACTURER_ID \
+#define PTP_VERSION_STRING "ptpdv2_2_0_0"
+#define MANUFACTURER_ID \
   "MaceG VanKempen;2.0.0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 
 
@@ -17,21 +48,26 @@
 #define DEFAULT_INBOUND_LATENCY      	0       /* in nsec */
 #define DEFAULT_OUTBOUND_LATENCY     	0       /* in nsec */
 #define DEFAULT_NO_RESET_CLOCK       	FALSE
+#define DEFAULT_RESET_CLOCK_STARTUP_ONLY FALSE
+#define DEFAULT_NO_ADJUST_CLOCK      FALSE
 #define DEFAULT_DOMAIN_NUMBER        	0
-#define DEFAULT_DELAY_MECHANISM      	E2E     // TODO
+#define DEFAULT_DELAY_MECHANISM      	E2E
 #define DEFAULT_AP                   	10
 #define DEFAULT_AI                   	1000
 #define DEFAULT_DELAY_S              	6
-#define DEFAULT_ANNOUNCE_INTERVAL    	1      /* 0 in 802.1AS */
+#define DEFAULT_ANNOUNCE_INTERVAL    	2.0    /* 0 in 802.1AS */
+#define LEAP_SECOND_PAUSE_PERIOD        2      /* how long before/after leap */
+                                               /* second event we pause offset */
+                                               /* calculation */
 
 /* Master mode operates in ARB (UTC) timescale, without TAI+leap seconds */
 #define DEFAULT_UTC_OFFSET           	0
 #define DEFAULT_UTC_VALID            	FALSE
-#define DEFAULT_PDELAYREQ_INTERVAL   	1      /* -4 in 802.1AS */
+#define DEFAULT_LOG_PDELAYREQ_INTERVAL  1      /* -4 in 802.1AS */
 
-#define DEFAULT_DELAYREQ_INTERVAL    	0      /* new value from page 237 of the standard */
+#define DEFAULT_DELAYREQ_INTERVAL    	1.0    /* new value from page 237 of the standard */
 
-#define DEFAULT_SYNC_INTERVAL        	0      /* -7 in 802.1AS */  /* from page 237 of the standard */
+#define DEFAULT_SYNC_INTERVAL        	1.0    /* -7 in 802.1AS */  /* from page 237 of the standard */
 /* number of announces we need to lose until a time out occurs. Thus it is 12 seconds */
 #define DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT 6     /* 3 by default */
 
@@ -49,7 +85,7 @@
 section 7.6.2.4, page 55:
 248     Default. This clockClass shall be used if none of the other clockClass definitions apply.
 13      Shall designate a clock that is synchronized to an application-specific source of time. The timescale distributed
-        shall be ARB. A clockClass 13 clock shall not be a slave to another clock in the domain. 
+        shall be ARB. A clockClass 13 clock shall not be a slave to another clock in the domain.
 */
 #define DEFAULT_CLOCK_CLASS		248
 #define DEFAULT_CLOCK_CLASS__APPLICATION_SPECIFIC_TIME_SOURCE	13
@@ -63,22 +99,34 @@
 */
 #define DEFAULT_CLOCK_ACCURACY		0xFE
 
-#define DEFAULT_PRIORITY1		128        
-#define DEFAULT_PRIORITY2		128        /* page 238, default priority is the midpoint, to allow easy control of the BMC algorithm */
+#define DEFAULT_PRIORITY1		248
+#define DEFAULT_PRIORITY2		248
 
 
-/* page 238:  τ, see 7.6.3.2: The default initialization value shall be 1.0 s.  */
-#define DEFAULT_CLOCK_VARIANCE 	        28768 /* To be determined in 802.1AS. */
-                                             
+#define DEFAULT_CLOCK_VARIANCE 	       -4000 /* To be determined in 802.1AS. */
+                                             /* We use the same value as in */
+                                             /* ptpdv1. */
+
 
 
 #define DEFAULT_MAX_FOREIGN_RECORDS  	5
 #define DEFAULT_PARENTS_STATS			FALSE
 
+/* Default time mode for master and slave modes */
+#define DEFAULT_MASTER_TIME_MODE        TIME_SYSTEM
+#define DEFAULT_SLAVE_TIME_MODE         TIME_SYSTEM
+
+/* For time both, default system time update interval */
+#define DEFAULT_SYSTEM_TIME_UPDATE_INTERVAL 1.0
+
+/* We don't allow the time to be set to before 1/1/1971 because this almost */
+/* certainly means something has gone very wrong */
+#define UTC_TIME_VALID_MINIMUM          (31536000)
+
 /* features, only change to refelect changes in implementation */
 #define NUMBER_PORTS      	1
-#define VERSION_PTP       	2
-#define TWO_STEP_FLAG    	TRUE
+#define VERSION_PTP_PROTOCOL	2
+#define TWO_STEP_FLAG    	0x02
 #define BOUNDARY_CLOCK    	FALSE
 #define SLAVE_ONLY		FALSE
 #define NO_ADJUST		FALSE
@@ -107,7 +155,7 @@
  * \brief Domain Number (Table 2 in the spec)*/
 
 enum {
-	DFLT_DOMAIN_NUMBER = 0, ALT1_DOMAIN_NUMBER, ALT2_DOMAIN_NUMBER, ALT3_DOMAIN_NUMBER
+  DFLT_DOMAIN_NUMBER = 0, ALT1_DOMAIN_NUMBER, ALT2_DOMAIN_NUMBER, ALT3_DOMAIN_NUMBER
 };
 
 /**
@@ -148,9 +196,13 @@
 
   /* non-spec timers */
   OPERATOR_MESSAGES_TIMER,  /* used to limit the operator messages */
-  TIMER_ARRAY_SIZE
+  LEAP_SECOND_PENDING_TIMER, /**<\brief timer used for handling leap second operations */
+  LEAP_SECOND_NOW_TIMER, /**<\brief Timer used to time moment of leap second */
+  TIMER_ARRAY_SIZE  /* this one is non-spec */
 };
 
+extern char *PTP_timer_dbg_string[];
+
 /**
  * \brief PTP states
  */
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/datatypes.h
--- a/src/datatypes.h	Tue May 14 17:07:59 2013 -0700
+++ b/src/datatypes.h	Sun Oct 27 22:49:29 2013 -0700
@@ -1,7 +1,37 @@
+/*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
+ *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
+ * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 #ifndef DATATYPES_H_
 #define DATATYPES_H_
 
-#include <stdio.h> 
+#include <stdio.h>
 
 /*Struct defined in spec*/
 
@@ -12,233 +42,241 @@
 *
 * This header file defines structures defined by the spec,
 * main program data structure, and all messages structures
- */
+*/
 
 
 /**
 * \brief The TimeInterval type represents time intervals
- */
+*/
 typedef struct {
-	Integer64 scaledNanoseconds;
+  Integer64 scaledNanoseconds;
 } TimeInterval;
 
 /**
 * \brief The Timestamp type represents a positive time with respect to the epoch
- */
+*/
 typedef struct  {
-	UInteger48 secondsField;
-	UInteger32 nanosecondsField;
+  UInteger48 secondsField;
+  UInteger32 nanosecondsField;
 } Timestamp;
 
 /**
 * \brief The ClockIdentity type identifies a clock
- */
+*/
 typedef Octet ClockIdentity[CLOCK_IDENTITY_LENGTH];
 
 /**
 * \brief The PortIdentity identifies a PTP port.
- */
+*/
 typedef struct {
-	ClockIdentity clockIdentity;
-	UInteger16 portNumber;
+  ClockIdentity clockIdentity;
+  UInteger16 portNumber;
 } PortIdentity;
 
 /**
 * \brief The PortAdress type represents the protocol address of a PTP port
- */
+*/
 typedef struct {
-	Enumeration16 networkProtocol;
-	UInteger16 adressLength;
-	Octet* adressField;
+  Enumeration16 networkProtocol;
+  UInteger16 adressLength;
+  Octet* adressField;
 } PortAdress;
 
 /**
 * \brief The ClockQuality represents the quality of a clock
- */
+*/
 typedef struct {
-	UInteger8 clockClass;
-	Enumeration8 clockAccuracy;
-	UInteger16 offsetScaledLogVariance;
+  UInteger8 clockClass;
+  Enumeration8 clockAccuracy;
+  UInteger16 offsetScaledLogVariance;
 } ClockQuality;
 
 /**
 * \brief The TLV type represents TLV extension fields
- */
+*/
 typedef struct {
-	Enumeration16 tlvType;
-	UInteger16 lengthField;
-	Octet* valueField;
+  Enumeration16 tlvType;
+  UInteger16 lengthField;
+  Octet* valueField;
 } TLV;
 
 /**
 * \brief The PTPText data type is used to represent textual material in PTP messages
- */
+*/
 typedef struct {
-	UInteger8 lengthField;
-	Octet* textField;
+  UInteger8 lengthField;
+  Octet* textField;
 } PTPText;
 
 /**
 * \brief The FaultRecord type is used to construct fault logs
- */
+*/
 typedef struct {
-	UInteger16 faultRecordLength;
-	Timestamp faultTime;
-	Enumeration8 severityCode;
-	PTPText faultName;
-	PTPText faultValue;
-	PTPText faultDescription;
+  UInteger16 faultRecordLength;
+  Timestamp faultTime;
+  Enumeration8 severityCode;
+  PTPText faultName;
+  PTPText faultValue;
+  PTPText faultDescription;
 } FaultRecord;
 
 
 /**
 * \brief The common header for all PTP messages (Table 18 of the spec)
- */
+*/
 /* Message header */
 typedef struct {
-	Nibble transportSpecific;
-	Enumeration4 messageType;
-	UInteger4 versionPTP;
-	UInteger16 messageLength;
-	UInteger8 domainNumber;
-	Octet flagField[2];
-	Integer64 correctionfield;
-	PortIdentity sourcePortIdentity;
-	UInteger16 sequenceId;
-	UInteger8 controlField;
-	Integer8 logMessageInterval;
+  Nibble transportSpecific;
+  Enumeration4 messageType;
+  UInteger4 versionPTP;
+  UInteger16 messageLength;
+  UInteger8 domainNumber;
+  Octet flagField[2];
+  Integer64 correctionfield;
+  PortIdentity sourcePortIdentity;
+  UInteger16 sequenceId;
+  UInteger8 controlField;
+  Integer8 logMessageInterval;
 } MsgHeader;
 
 
 /**
 * \brief Announce message fields (Table 25 of the spec)
- */
+*/
 /*Announce Message */
 typedef struct {
-	Timestamp originTimestamp;
-	Integer16 currentUtcOffset;
-	UInteger8 grandmasterPriority1;
-	ClockQuality grandmasterClockQuality;
-	UInteger8 grandmasterPriority2;
-	ClockIdentity grandmasterIdentity;
-	UInteger16 stepsRemoved;
-	Enumeration8 timeSource;
+  Timestamp originTimestamp;
+  Integer16 currentUtcOffset;
+  UInteger8 grandmasterPriority1;
+  ClockQuality grandmasterClockQuality;
+  UInteger8 grandmasterPriority2;
+  ClockIdentity grandmasterIdentity;
+  UInteger16 stepsRemoved;
+  Enumeration8 timeSource;
 }MsgAnnounce;
 
 
 /**
 * \brief Sync message fields (Table 26 of the spec)
- */
+*/
 /*Sync Message */
 typedef struct {
-	Timestamp originTimestamp;
+  Timestamp originTimestamp;
 }MsgSync;
 
 /**
 * \brief DelayReq message fields (Table 26 of the spec)
- */
+*/
 /*DelayReq Message */
 typedef struct {
-	Timestamp originTimestamp;
+  Timestamp originTimestamp;
 }MsgDelayReq;
 
 /**
 * \brief DelayResp message fields (Table 30 of the spec)
- */
+*/
 /*delayResp Message*/
 typedef struct {
-	Timestamp receiveTimestamp;
-	PortIdentity requestingPortIdentity;
+  Timestamp receiveTimestamp;
+  PortIdentity requestingPortIdentity;
 }MsgDelayResp;
 
 /**
 * \brief FollowUp message fields (Table 27 of the spec)
- */
+*/
 /*Follow-up Message*/
 typedef struct {
-	Timestamp preciseOriginTimestamp;
+  Timestamp preciseOriginTimestamp;
 }MsgFollowUp;
 
 /**
 * \brief PDelayReq message fields (Table 29 of the spec)
- */
+*/
 /*PdelayReq Message*/
 typedef struct {
-	Timestamp originTimestamp;
+  Timestamp originTimestamp;
 }MsgPDelayReq;
 
 /**
 * \brief PDelayResp message fields (Table 30 of the spec)
- */
+*/
 /*PdelayResp Message*/
 typedef struct {
-	Timestamp requestReceiptTimestamp;
-	PortIdentity requestingPortIdentity;
+  Timestamp requestReceiptTimestamp;
+  PortIdentity requestingPortIdentity;
 }MsgPDelayResp;
 
 /**
 * \brief PDelayRespFollowUp message fields (Table 31 of the spec)
- */
+*/
 /*PdelayRespFollowUp Message*/
 typedef struct {
-	Timestamp responseOriginTimestamp;
-	PortIdentity requestingPortIdentity;
+  Timestamp responseOriginTimestamp;
+  PortIdentity requestingPortIdentity;
 }MsgPDelayRespFollowUp;
 
 /**
 * \brief Signaling message fields (Table 33 of the spec)
- */
+*/
 /*Signaling Message*/
 typedef struct {
-	PortIdentity targetPortIdentity;
-	char* tlv;
+  PortIdentity targetPortIdentity;
+  char* tlv;
 }MsgSignaling;
 
 /**
 * \brief Management message fields (Table 37 of the spec)
- */
+*/
 /*management Message*/
 typedef struct {
-	PortIdentity targetPortIdentity;
-	UInteger8 startingBoundaryHops;
-	UInteger8 boundaryHops;
-	Enumeration4 actionField;
-	char* tlv;
+  PortIdentity targetPortIdentity;
+  UInteger8 startingBoundaryHops;
+  UInteger8 boundaryHops;
+  Enumeration4 actionField;
+  char* tlv;
 }MsgManagement;
 
 
 
 /**
-* \brief Time structure to handle Linux time information
- */
-typedef struct {
-	Integer32 seconds;
-	Integer32 nanoseconds;
-} TimeInternal;
-
-/**
 * \brief Structure used as a timer
- */
+*/
 typedef struct {
-	Integer32 interval;
-	Integer32 left;
-	Boolean expire;
+  Integer32  interval;
+  Integer32  left;
+  Boolean expire;
 } IntervalTimer;
 
 
 /**
 * \brief ForeignMasterRecord is used to manage foreign masters
+*/
+typedef struct
+{
+  PortIdentity foreignMasterPortIdentity;
+  UInteger16 foreignMasterAnnounceMessages;
+
+  //This one is not in the spec
+  MsgAnnounce  announce;
+  MsgHeader    header;
+} ForeignMasterRecord;
+
+/** 
+ * \brief Structure used to collect statistics
  */
 typedef struct
 {
-	PortIdentity foreignMasterPortIdentity;
-	UInteger16 foreignMasterAnnounceMessages;
+  UInteger32  ts_sync_failures;
+} Statistics;
 
-	//This one is not in the spec
-	MsgAnnounce  announce;
-	MsgHeader    header;
-} ForeignMasterRecord;
-
+/**
+*  \brief Timestamp method in use
+*/
+typedef enum {
+  TS_METHOD_SYSTEM,
+  TS_METHOD_SO_TIMESTAMPING,
+  TS_METHOD_DRIVER_IOCTL
+} TsMethod;
 
 /**
  * \struct PtpClock
@@ -246,241 +284,329 @@
  */
 /* main program data structure */
 typedef struct {
-	/* Default data set */
+  /* Default data set */
 
-	/*Static members*/
-	Boolean twoStepFlag;
-	ClockIdentity clockIdentity;
-	UInteger16 numberPorts;
+  /*Static members*/
+  Boolean twoStepFlag;
+  ClockIdentity clockIdentity;
+  UInteger16 numberPorts;
 
-	/*Dynamic members*/
-	ClockQuality clockQuality;
+  /*Dynamic members*/
+  ClockQuality clockQuality;
 
-	/*Configurable members*/
-	UInteger8 priority1;
-	UInteger8 priority2;
-	UInteger8 domainNumber;
-	Boolean slaveOnly;
+  /*Configurable members*/
+  UInteger8 priority1;
+  UInteger8 priority2;
+  UInteger8 domainNumber;
+  Boolean slaveOnly;
 
 
-	/* Current data set */
+  /* Current data set */
 
-	/*Dynamic members*/
-	UInteger16 stepsRemoved;
-	TimeInternal offsetFromMaster;
-	TimeInternal meanPathDelay;
+  /*Dynamic members*/
+  UInteger16 stepsRemoved;
+  TimeInternal offsetFromMaster;
+  TimeInternal meanPathDelay;
 
 
-	/* Parent data set */
+  /* Parent data set */
 
-	/*Dynamic members*/
-	PortIdentity parentPortIdentity;
-	Boolean parentStats;
-	UInteger16 observedParentOffsetScaledLogVariance;
-	Integer32 observedParentClockPhaseChangeRate;
-	ClockIdentity grandmasterIdentity;
-	ClockQuality grandmasterClockQuality;
-	UInteger8 grandmasterPriority1;
-	UInteger8 grandmasterPriority2;
+  /*Dynamic members*/
+  PortIdentity parentPortIdentity;
+  Boolean parentStats;
+  UInteger16 observedParentOffsetScaledLogVariance;
+  Integer32 observedParentClockPhaseChangeRate;
+  ClockIdentity grandmasterIdentity;
+  ClockQuality grandmasterClockQuality;
+  UInteger8 grandmasterPriority1;
+  UInteger8 grandmasterPriority2;
 
-	/* Global time properties data set */
+  /* Global time properties data set */
 
-	/*Dynamic members*/
-	Integer16 currentUtcOffset;
-	Boolean currentUtcOffsetValid;
-	Boolean leap59;
-	Boolean leap61;
-	Boolean timeTraceable;
-	Boolean frequencyTraceable;
-	Boolean ptpTimescale;
-	Enumeration8 timeSource;
+  /*Dynamic members*/
+  Integer16 currentUtcOffset;
+  Boolean currentUtcOffsetValid;
+  Boolean leap59;
+  Boolean leap61;
+  Boolean timeTraceable;
+  Boolean frequencyTraceable;
+  Boolean ptpTimescale;
+  Boolean leapSecondInProgress;
+  Boolean leapSecondPending;
+  Enumeration8 timeSource;
 
-	/* Port configuration data set */
+  /* Port configuration data set */
 
-	/*Static members*/
-	PortIdentity portIdentity;
+  /*Static members*/
+  PortIdentity portIdentity;
 
-	/*Dynamic members*/
-	Enumeration8 portState;
-	Integer8 logMinDelayReqInterval;
-	TimeInternal peerMeanPathDelay;
- 
-	/*Configurable members*/
-	Integer8 logAnnounceInterval;
-	UInteger8 announceReceiptTimeout;
-	Integer8 logSyncInterval;
-	Enumeration8 delayMechanism;
-	Integer8 logMinPdelayReqInterval;
-	UInteger4 versionNumber;
+  /*Dynamic members*/
+  Enumeration8 portState;
+  LongDouble minDelayReqInterval;
+  Integer8 logMinDelayReqInterval;
+  TimeInternal peerMeanPathDelay;
 
+  /*Configurable members*/
+  Integer8 logAnnounceInterval;
+  UInteger8 announceReceiptTimeout;
+  Integer8 logSyncInterval;
+  Enumeration8 delayMechanism;
+  Integer8 logMinPdelayReqInterval;
+  UInteger4 versionNumber;
 
-	/* Foreign master data set */
-	ForeignMasterRecord *foreign;
 
-	/* Other things we need for the protocol */
-	UInteger16 number_foreign_records;
-	Integer16  max_foreign_records;
-	Integer16  foreign_record_i;
-	Integer16  foreign_record_best;
-	UInteger32 random_seed;
-	Boolean  record_update;    /* should we run bmc() after receiving an announce message? */
+  /* Foreign master data set */
+  ForeignMasterRecord *foreign;
 
+  /* Other things we need for the protocol */
+  UInteger16 number_foreign_records;
+  Integer16  max_foreign_records;
+  Integer16  foreign_record_i;
+  Integer16  foreign_record_best;
+  UInteger32 random_seed;
+  Boolean  record_update;    /* should we run bmc() after receiving an announce message? */
 
-	MsgHeader msgTmpHeader;
 
-	union {
-		MsgSync  sync;
-		MsgFollowUp  follow;
-		MsgDelayReq  req;
-		MsgDelayResp resp;
-		MsgPDelayReq  preq;
-		MsgPDelayResp  presp;
-		MsgPDelayRespFollowUp  prespfollow;
-		MsgManagement  manage;
-		MsgAnnounce  announce;
-		MsgSignaling signaling;
-	} msgTmp;
+  MsgHeader msgTmpHeader;
 
+  union {
+    MsgSync  sync;
+    MsgFollowUp  follow;
+    MsgDelayReq  req;
+    MsgDelayResp resp;
+    MsgPDelayReq  preq;
+    MsgPDelayResp  presp;
+    MsgPDelayRespFollowUp  prespfollow;
+    MsgManagement  manage;
+    MsgAnnounce  announce;
+    MsgSignaling signaling;
+  } msgTmp;
 
-	Octet msgObuf[PACKET_SIZE];
-	Octet msgIbuf[PACKET_SIZE];
 
-/*
-	20110630: These variables were deprecated in favor of the ones that appear in the stats log (delayMS and delaySM)
-	
-	TimeInternal  master_to_slave_delay;
-	TimeInternal  slave_to_master_delay;
+  Octet msgObuf[PACKET_SIZE];
+  Octet msgIbuf[PACKET_SIZE];
 
-	*/
-	Integer32 	observed_drift;
+  TimeInternal  master_to_slave_delay;
+  TimeInternal  slave_to_master_delay;
+  LongDouble    observed_drift;
+  LongDouble    frequency_adjustment;
 
-	TimeInternal  pdelay_req_receive_time;
-	TimeInternal  pdelay_req_send_time;
-	TimeInternal  pdelay_resp_receive_time;
-	TimeInternal  pdelay_resp_send_time;
-	TimeInternal  sync_receive_time;
-	TimeInternal  delay_req_send_time;
-	TimeInternal  delay_req_receive_time;
-	MsgHeader		PdelayReqHeader;
-	MsgHeader		delayReqHeader;
-	TimeInternal	pdelayMS;
-	TimeInternal	pdelaySM;
-	TimeInternal  delayMS;
-	TimeInternal	delaySM;
-	TimeInternal  lastSyncCorrectionField;
-	TimeInternal  lastPdelayRespCorrectionField;
+  TimeInternal  pdelay_req_receive_time;
+  TimeInternal  pdelay_req_send_time;
+  TimeInternal  pdelay_resp_receive_time;
+  TimeInternal  pdelay_resp_send_time;
+  TimeInternal  sync_receive_time;
+  TimeInternal  delay_req_send_time;
+  TimeInternal  delay_req_receive_time;
+  MsgHeader		PdelayReqHeader;
+  MsgHeader		delayReqHeader;
+  TimeInternal	pdelayMS;
+  TimeInternal	pdelaySM;
+  TimeInternal  delayMS;
+  TimeInternal	delaySM;
+  TimeInternal  lastSyncCorrectionField;
+  TimeInternal  lastPdelayRespCorrectionField;
 
+  /**
+  * TRUE when the clock is used to synchronize NIC and system time and
+  * the process is the PTP_MASTER. The offset and adjustment calculation
+  * is always "master (= NIC) to slave (= system time)" and PTP_SLAVEs
+  * update their system time, but the master needs to invert the
+  * clock adjustment and control NIC time instead. This way
+  * the master's system time is propagated to slaves.
+  */
+  Boolean nic_instead_of_system;
 
+  /**
+  * Specifies the method for retrieving timestamps. Depending on the kernel
+  * version and operating mode, timestamping is done by either system
+  * timestamps made by the kernel,
+  * queue, the socket error queue or via proprietary ioctl operations.
+  */
+  TsMethod tsMethod;
 
-	Boolean  sentPDelayReq;
-	UInteger16  sentPDelayReqSequenceId;
-	UInteger16  sentDelayReqSequenceId;
-	UInteger16  sentSyncSequenceId;
-	UInteger16  sentAnnounceSequenceId;
-	UInteger16  recvPDelayReqSequenceId;
-	UInteger16  recvSyncSequenceId;
-	UInteger16  recvPDelayRespSequenceId;
-	Boolean  waitingForFollow;
-	Boolean  waitingForDelayResp;
-	
+  /**
+  * a prefix to be inserted before messages about the clock:
+  * may be empty, but not NULL
+  *
+  * used to distinguish multiple active clock servos per process
+  */
+  const char *name;
 
-	offset_from_master_filter  ofm_filt;
-	one_way_delay_filter  owd_filt;
+  Boolean  sentPDelayReq;
+  UInteger16  sentPDelayReqSequenceId;
+  UInteger16  sentDelayReqSequenceId;
+  UInteger16  sentSyncSequenceId;
+  UInteger16  sentAnnounceSequenceId;
+  UInteger16  recvPDelayReqSequenceId;
+  UInteger16  recvSyncSequenceId;
+  UInteger16  recvPDelayRespSequenceId;
+  Boolean  waitingForFollow;
+  Boolean  waitingForDelayResp;
 
-	Boolean message_activity;
 
-	IntervalTimer  itimer[TIMER_ARRAY_SIZE];
+  offset_from_master_filter  ofm_filt;
+  one_way_delay_filter  owd_filt;
 
-	NetPath netPath;
+  Boolean message_activity;
 
-	/*Usefull to init network stuff*/
-	UInteger8 port_communication_technology;
-	Octet port_uuid_field[PTP_UUID_LENGTH];
+  IntervalTimer  itimer[TIMER_ARRAY_SIZE];
 
-	int reset_count;
-	int current_init_clock;
-	int can_step_clock;
-	int warned_operator_slow_slewing;
-	int warned_operator_fast_slewing;
+  NetPath netPath;
 
-	char char_last_msg;                             /* representation of last message processed by servo */
-	Boolean last_packet_was_sync;                   /* used to limit logging of Sync messages */
-	
-	int waiting_for_first_sync;                     /* we'll only start the delayReq timer after the first sync */
-	int waiting_for_first_delayresp;                /* Just for information purposes */
-	Boolean startup_in_progress;
-	
-#ifdef PTP_EXPERIMENTAL
-	Integer32 MasterAddr;                           // used for hybrid mode, when receiving announces
-	Integer32 LastSlaveAddr;                        // used for hybrid mode, when receiving delayreqs
-#endif
+  /*Usefull to init network stuff*/
+  UInteger8 port_communication_technology;
+  Octet port_uuid_field[PTP_UUID_LENGTH];
 
+  int reset_count;
+  int warned_operator_slow_slewing;
+  int warned_operator_fast_slewing;
+
+  char char_last_msg;  					/* representation of last message processed by servo */
+  Boolean last_packet_was_sync;                   /* used to limit logging of Sync messages */
+
+  int waiting_for_first_sync;				/* we'll only start the delayReq timer after the first sync */
+  int waiting_for_first_delayresp;		/* Just for information purposes */
+
+  Boolean offset_first_updated;
+  Boolean clock_first_updated;
+
+  Statistics statistics;
+  
 } PtpClock;
 
 /**
- * \struct RunTimeOpts
- * \brief Program options set at run-time
- */
+* \enum Time mode enumeration
+* \brief Time mode for PTP clock
+*/
+typedef enum {
+  /**
+  * Use and control system time
+  */
+  TIME_SYSTEM,
+  /**
+  * Use and control network interface time using Solarflare IOCTLs and
+  * net_tstamp.h API.
+  */
+  TIME_NIC,
+  /**
+  * A combination of PTP between NICs plus a local synchronization
+  * between NIC and system time:
+  *
+  * - NIC time is controlled via PTP packets, main time seen
+  *   by PTPd is the NIC time
+  * - system_to_nic and nic_to_system delays are provided by
+  *   device driver on request
+  * - time.c adapts NIC time to system time on master and system time
+  *   to NIC time on slaves by feeding these offsets into another
+  *   instance of the clock servo (as in TIME_SYSTEM)
+  *
+  * The command line options only apply to one clock sync and
+  * the defaults are used for the other:
+  * - NIC time: default values for clock control (adjust and reset)
+  *   and servo (coefficients), configurable PTP
+  * - system time: configurable clock control and servo, PTP options do
+  *   not apply
+  */
+  TIME_BOTH,
+  /**
+  * Time used and controlled by PTP is the system time with hardware
+  * packet time stamping via Linux net_tstamp.h API or using driver
+  * proprietary IOCTLs.
+  */
+  TIME_SYSTEM_LINUX_HW,
+  /**
+  * Time used and controlled by PTP is the system time with software
+  * packet time stamping via standard Linux net_tstamp.h API.
+  */
+  TIME_SYSTEM_LINUX_SW,
+
+  TIME_MAX
+} TimeMode;
+
+/**
+* \enum Master slave mode enumeration
+* \brief Master/slave mode for PTP clock
+*/
+typedef enum {
+  PTP_MODE_NULL,
+  PTP_MODE_MASTER_NO_NTP,
+  PTP_MODE_MASTER_WITH_NTP,
+  PTP_MODE_SLAVE
+} MasterSlaveMode;
+
+/**
+* \struct RunTimeOpts
+* \brief Program options set at run-time
+*/
 /* program options set at run-time */
 typedef struct {
-	Integer8 announceInterval;
-	Integer8 announceReceiptTimeout;
-	
-	Integer8 syncInterval;
-	ClockQuality clockQuality;
-	UInteger8 priority1;
-	UInteger8 priority2;
-	UInteger8 domainNumber;
+  LongDouble announceInterval;
+  Integer8 announceReceiptTimeout;
+
+  LongDouble syncInterval;
+  ClockQuality clockQuality;
+  UInteger8 priority1;
+  UInteger8 priority2;
+  UInteger8 domainNumber;
 #ifdef PTP_EXPERIMENTAL
 	UInteger8 mcast_group_Number;
 #endif
 
 	Boolean	slaveOnly;
-	Integer16 currentUtcOffset;
-	Octet ifaceName[IFACE_NAME_LENGTH];
-	Boolean	noResetClock;
-	Integer32 maxReset; /* Maximum number of nanoseconds to reset */
-	Integer32 maxDelay; /* Maximum number of nanoseconds of delay */
-	Boolean	noAdjust;
-	Boolean	displayStats;
-	Boolean	csvStats;
-	Boolean displayPackets;
-	Octet unicastAddress[MAXHOSTNAMELEN];
-	Integer32 ap, ai;
-	Integer16 s;
-	TimeInternal inboundLatency, outboundLatency;
-	Integer16 max_foreign_records;
-	Boolean ethernet_mode;
-	Enumeration8 delayMechanism;
-	Boolean	offset_first_updated;
-	char file[PATH_MAX];
-	int logFd;
-	Boolean useSysLog;
-	int ttl;
-	char recordFile[PATH_MAX];
-	FILE *recordFP;
+  Integer16 currentUtcOffset;
+  Boolean currentUtcOffsetValid;
+  Octet ifaceName[IFACE_NAME_LENGTH];
+  Boolean	noResetClock;
+  Boolean resetClockStartupOnly;
+  Integer32 maxReset; /* Maximum number of nanoseconds to reset */
+  TimeInternal maxDelay; /* Maximum number of nanoseconds of delay */
+  Boolean	noAdjust;
+  Boolean	displayStats;
+  Boolean verboseStats;
+  Boolean	csvStats;
+  Boolean displayPackets;
+  Octet unicastAddress[MAXHOSTNAMELEN];
+  Integer32 ap, ai;
+  Integer16 s;
+  TimeInternal inboundLatency, outboundLatency;
+  Integer16 max_foreign_records;
+  Boolean ethernet_mode;
+  Enumeration8 delayMechanism;
+//  Boolean	offset_first_updated;
+  char file[PATH_MAX];
+  int logFd;
+  Boolean useSysLog;
+#ifndef __sun
+  int ttl;
+#else 
+  uchar_t ttl;
+#endif
+  char recordFile[PATH_MAX];
+  FILE *recordFP;
 
-	int log_seconds_between_message;
+  int log_seconds_between_message;
 
-	Boolean ignore_daemon_lock;
-	Boolean do_IGMP_refresh;
-	int nonDaemon;
-	Boolean do_log_to_file;
-	Boolean do_record_quality_file;
-	
-	int initial_delayreq;
-	int subsequent_delayreq;
+  Boolean ignore_daemon_lock;
+  Boolean do_IGMP_refresh;
+  int nonDaemon;
+  Boolean do_log_to_file;
+  Boolean do_record_quality_file;
+
+  LongDouble initial_delayreq;
+  int subsequent_delayreq;
 	Boolean ignore_delayreq_interval_master;
-	Boolean syslog_startup_messages_also_to_stdout;
-	
+  Boolean syslog_startup_messages_also_to_stdout;
+
 #ifdef PTP_EXPERIMENTAL
 	int do_hybrid_mode;
 #endif
-	int do_unicast_mode;
-
-#ifdef RUNTIME_DEBUG
-	int debug_level;
-#endif
+  TimeMode time_mode;
+  MasterSlaveMode master_slave_mode;
+  LongDouble system_time_update_interval;
+  int do_unicast_mode;
+  
+  int debug_level;
 
 } RunTimeOpts;
 
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/constants_dep.h
--- a/src/dep/constants_dep.h	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/constants_dep.h	Sun Oct 27 22:49:29 2013 -0700
@@ -1,3 +1,33 @@
+/*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
+ *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
+ * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
 /* constants_dep.h */
 
@@ -16,7 +46,7 @@
 /* platform dependent */
 
 #if !defined(linux) && !defined(__NetBSD__) && !defined(__FreeBSD__) && \
-  !defined(__APPLE__)
+  !defined(__APPLE__) && !defined(__sun)
 #error Not ported to this architecture, please update.
 #endif
 
@@ -38,7 +68,7 @@
 #endif /* linux */
 
 
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__)
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__sun)
 # include <sys/types.h>
 # include <sys/socket.h>
 # include <netinet/in.h>
@@ -48,6 +78,9 @@
 # if defined(__FreeBSD__) || defined(__APPLE__)
 #  include <net/ethernet.h>
 #  include <sys/uio.h>
+# elif defined(__sun)
+#  include <sys/ethernet.h>
+#  include <sys/uio.h>
 # else
 #  include <net/if_ether.h>
 # endif
@@ -55,25 +88,35 @@
 # define IFACE_NAME_LENGTH         IF_NAMESIZE
 # define NET_ADDRESS_LENGTH        INET_ADDRSTRLEN
 
-# define IFCONF_LENGTH 10
+# define IFCONF_LENGTH 20
 
 # define adjtimex ntp_adjtime
 
+#if !defined(__sun)
 # include <machine/endian.h>
 # if BYTE_ORDER == LITTLE_ENDIAN
 #   define PTPD_LSBF
 # elif BYTE_ORDER == BIG_ENDIAN
 #   define PTPD_MSBF
 # endif
+#else
+# if defined(__sparc__)
+#   define PTPD_MSBF
+# else
+#   define PTPD_LSBF
+# endif
+#endif
 #endif
 
+#define SFC_FIRMWARE_VERSION_NUMBER_MIN 6039
+
 #define CLOCK_IDENTITY_LENGTH 8
-#define ADJ_FREQ_MAX  512000
+/* The system clock can handle frequency adjustments up to 100,000,000ppb */
+#define ADJ_FREQ_MAX_SYSTEM  100000000.0
+/* Our NIC can only handle frequency adjustments up to 1,000,000ppb */
+#define ADJ_FREQ_MAX_NIC  1000000.0
 
 /* UDP/IPv4 dependent */
-#ifndef INADDR_LOOPBACK
-#define INADDR_LOOPBACK 0x7f000001UL
-#endif
 
 #define SUBDOMAIN_ADDRESS_LENGTH  4
 #define PORT_ADDRESS_LENGTH       2
@@ -110,6 +153,8 @@
 
 #define NANOSECONDS_MAX 999999999
 
+/* our own errno for failure to retrieve timestamp */
+#define ENOTIMESTAMP  1000
 
 // limit operator messages to once every X seconds
 #define OPERATOR_MESSAGES_INTERVAL 300.0
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/datatypes_dep.h
--- a/src/dep/datatypes_dep.h	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/datatypes_dep.h	Sun Oct 27 22:49:29 2013 -0700
@@ -1,12 +1,44 @@
+/*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
+ *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
+ * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 #ifndef DATATYPES_DEP_H_
 #define DATATYPES_DEP_H_
 
+#include <sys/ioctl.h>
+#include <net/if.h>
+
 /**
 *\file
 * \brief Implementation specific datatype
 
  */
-/* FIXME: shouldn't uint32_t and friends be used here? */
 typedef enum {FALSE=0, TRUE} Boolean;
 typedef char Octet;
 typedef signed char Integer8;
@@ -20,12 +52,13 @@
 typedef unsigned char Enumeration4;
 typedef unsigned char UInteger4;
 typedef unsigned char Nibble;
+typedef long double LongDouble;
 
 /**
 * \brief Implementation specific of UInteger48 type
  */
 typedef struct {
-	unsigned int lsb;     /* FIXME: shouldn't uint32_t and uint16_t be used here? */
+	unsigned int lsb;
 	unsigned short msb;
 } UInteger48;
 
@@ -33,7 +66,7 @@
 * \brief Implementation specific of Integer64 type
  */
 typedef struct {
-	unsigned int lsb;     /* FIXME: shouldn't uint32_t and int32_t be used here? */
+	unsigned int lsb;
 	int msb;
 } Integer64;
 
@@ -58,20 +91,48 @@
   Integer32  s_exp;
 } one_way_delay_filter;
 
+
+#define TX_STACK_SIZE 1
+
+/**
+* \brief Time structure to handle Linux time information
+ */
+typedef struct TimeInternal {
+  Integer32 seconds;
+  Integer32 nanoseconds;
+} TimeInternal;
+
+
+struct tx_item {
+  int len;
+  TimeInternal ts;
+  unsigned char buf[PACKET_SIZE];
+};
+
 /**
 * \brief Struct used to store network datas
  */
 typedef struct {
   Integer32 eventSock, generalSock, multicastAddr, peerMulticastAddr,unicastAddr;
 
+#if defined(linux) 
+  /** for further ioctl() calls on eventSock */
+  struct ifreq eventSockIFR;
+#elif defined(__sun)
+  Integer32 devFd;
+  struct lifreq eventSockIFR;
+  void	*ioctl_req;
+#endif
+
+
+  /* @ioctl_timestamping Added support for hw based timestamping */
+  struct {
+    struct tx_item data[TX_STACK_SIZE];
+    int count;
+  } tx_stack;
+
   /* used by IGMP refresh */
   struct in_addr interfaceAddr;
-
-#ifdef PTP_EXPERIMENTAL
-  /* used for Hybrid mode */
-  Integer32 lastRecvAddr;
-#endif
-
 } NetPath;
 
 #endif /*DATATYPES_DEP_H_*/
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/msg.c
--- a/src/dep/msg.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/msg.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,5 @@
 /*-
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
@@ -39,10 +40,6 @@
 
 #include "../ptpd.h"
 
-#ifdef PTP_EXPERIMENTAL
-extern RunTimeOpts rtOpts; 
-#endif
-
 /*Unpack Header from IN buffer to msgTmpHeader field */
 void 
 msgUnpackHeader(Octet * buf, MsgHeader * header)
@@ -73,23 +70,34 @@
 
 /*Pack header message into OUT buffer of ptpClock*/
 void 
-msgPackHeader(Octet * buf, PtpClock * ptpClock)
+msgPackHeader(Octet * buf, PtpClock * ptpClock, unsigned int messageType)
 {
-	Nibble transport = 0x80;
+	const UInteger8 transportSpecific = 0x00;
+  UInteger8 octet0 = transportSpecific | (UInteger8)messageType;
+  
+	/* (spec annex D) */
+	*(UInteger8 *) (buf + 0) = octet0;
+	*(UInteger4 *) (buf + 1) = ptpClock->versionNumber;
+	*(UInteger8 *) (buf + 2) = 0; /* messageLength */
+	*(UInteger8 *) (buf + 3) = 0; /* messageLength */
+	*(UInteger8 *) (buf + 4) = ptpClock->domainNumber;
+	*(UInteger8 *) (buf + 5) = 0;
 
-	/* (spec annex D) */
-	*(UInteger8 *) (buf + 0) = transport;
-	*(UInteger4 *) (buf + 1) = ptpClock->versionNumber;
-	*(UInteger8 *) (buf + 4) = ptpClock->domainNumber;
+	if (((messageType == SYNC) || (messageType == PDELAY_RESP)) &&
+		(ptpClock->twoStepFlag)) {
+		*(UInteger8 *) (buf + 6) = PTP_TWO_STEP;
+	} else {
+		*(UInteger8 *) (buf + 6) = 0;
+	}
+	*(UInteger8 *) (buf + 7) = 0;
 
-	/* TODO: this bit should have been active only for sync and PdelayResp */
-	if (ptpClock->twoStepFlag)
-		*(UInteger8 *) (buf + 6) = PTP_TWO_STEP;
-
-	memset((buf + 8), 0, 8);
+	memset((buf + 8), 0, 12);
 	memcpy((buf + 20), ptpClock->portIdentity.clockIdentity, 
 	       CLOCK_IDENTITY_LENGTH);
 	*(UInteger16 *) (buf + 28) = flip16(ptpClock->portIdentity.portNumber);
+	*(UInteger8 *) (buf + 30) = 0; /* sequenceId */
+	*(UInteger8 *) (buf + 31) = 0; /* sequenceId */
+	*(UInteger8 *) (buf + 32) = 0; /* controlField */
 	*(UInteger8 *) (buf + 33) = 0x7F;
 	/* Default value(spec Table 24) */
 }
@@ -100,13 +108,9 @@
 void 
 msgPackSync(Octet * buf, Timestamp * originTimestamp, PtpClock * ptpClock)
 {
-	msgPackHeader(buf, ptpClock);
+	msgPackHeader(buf, ptpClock, SYNC);
 	
 	/* changes in header */
-	*(char *)(buf + 0) = *(char *)(buf + 0) & 0xF0;
-	/* RAZ messageType */
-	*(char *)(buf + 0) = *(char *)(buf + 0) | 0x00;
-	/* Table 19 */
 	*(UInteger16 *) (buf + 2) = flip16(SYNC_LENGTH);
 	*(UInteger16 *) (buf + 30) = flip16(ptpClock->sentSyncSequenceId);
 	*(UInteger8 *) (buf + 32) = 0x00;
@@ -142,15 +146,26 @@
 void 
 msgPackAnnounce(Octet * buf, PtpClock * ptpClock)
 {
-	msgPackHeader(buf, ptpClock);
+	UInteger16 tmp;
 
+	msgPackHeader(buf, ptpClock, ANNOUNCE);
+
+	if (ptpClock->leap59) {
+		*(UInteger8 *) (buf + 7) |= 0x02;
+	}
+	if (ptpClock->leap61) {
+		*(UInteger8 *) (buf + 7) |= 0x01;
+	}
+	
+	if (ptpClock->currentUtcOffsetValid)
+		*(UInteger8 *) (buf + 7) |= 0x04;
 	
 	/* changes in header */
-	*(char *)(buf + 0) = *(char *)(buf + 0) & 0xF0;
-	/* RAZ messageType */
-	*(char *)(buf + 0) = *(char *)(buf + 0) | 0x0B;
 	/* Table 19 */
-	*(UInteger16 *) (buf + 2) = flip16(ANNOUNCE_LENGTH);
+	/* *(UInteger16 *) (buf + 2) = flip16(ANNOUNCE_LENGTH);
+	 */
+	tmp = flip16(ANNOUNCE_LENGTH);
+	memcpy((buf + 2), &tmp, sizeof(UInteger16));
 	*(UInteger16 *) (buf + 30) = flip16(ptpClock->sentAnnounceSequenceId);
 	*(UInteger8 *) (buf + 32) = 0x05;
 	/* Table 23 */
@@ -166,7 +181,10 @@
 		flip16(ptpClock->clockQuality.offsetScaledLogVariance);
 	*(UInteger8 *) (buf + 52) = ptpClock->grandmasterPriority2;
 	memcpy((buf + 53), ptpClock->grandmasterIdentity, CLOCK_IDENTITY_LENGTH);
-	*(UInteger16 *) (buf + 61) = flip16(ptpClock->stepsRemoved);
+/*	*(UInteger16 *) (buf + 61) = flip16(ptpClock->stepsRemoved);
+ */
+	tmp = flip16(ptpClock->stepsRemoved);
+	memcpy((buf+61), &tmp, sizeof(UInteger16));
 	*(Enumeration8 *) (buf + 63) = ptpClock->timeSource;
 }
 
@@ -174,6 +192,8 @@
 void 
 msgUnpackAnnounce(Octet * buf, MsgAnnounce * announce)
 {
+	UInteger16 tmp;
+
 	announce->originTimestamp.secondsField.msb = 
 		flip16(*(UInteger16 *) (buf + 34));
 	announce->originTimestamp.secondsField.lsb = 
@@ -191,7 +211,10 @@
 	announce->grandmasterPriority2 = *(UInteger8 *) (buf + 52);
 	memcpy(announce->grandmasterIdentity, (buf + 53), 
 	       CLOCK_IDENTITY_LENGTH);
-	announce->stepsRemoved = flip16(*(UInteger16 *) (buf + 61));
+	memcpy(&tmp, (buf+61), sizeof(UInteger16));
+	announce->stepsRemoved = flip16(tmp);
+	/*announce->stepsRemoved = flip16(*(UInteger16 *) (buf + 61));
+	 */
 	announce->timeSource = *(Enumeration8 *) (buf + 63);
 	
 #ifdef PTPD_DBG
@@ -203,12 +226,9 @@
 void 
 msgPackFollowUp(Octet * buf, Timestamp * preciseOriginTimestamp, PtpClock * ptpClock)
 {
-	msgPackHeader(buf, ptpClock);
+	msgPackHeader(buf, ptpClock, FOLLOW_UP);
 	
 	/* changes in header */
-	*(char *)(buf + 0) = *(char *)(buf + 0) & 0xF0;
-	/* RAZ messageType */
-	*(char *)(buf + 0) = *(char *)(buf + 0) | 0x08;
 	/* Table 19 */
 	*(UInteger16 *) (buf + 2) = flip16(FOLLOW_UP_LENGTH);
 	*(UInteger16 *) (buf + 30) = flip16(ptpClock->sentSyncSequenceId - 1);
@@ -248,13 +268,10 @@
 void 
 msgPackPDelayReq(Octet * buf, Timestamp * originTimestamp, PtpClock * ptpClock)
 {
-	msgPackHeader(buf, ptpClock);
+	msgPackHeader(buf, ptpClock, PDELAY_REQ);
 
 	
 	/* changes in header */
-	*(char *)(buf + 0) = *(char *)(buf + 0) & 0xF0;
-	/* RAZ messageType */
-	*(char *)(buf + 0) = *(char *)(buf + 0) | 0x02;
 	/* Table 19 */
 	*(UInteger16 *) (buf + 2) = flip16(PDELAY_REQ_LENGTH);
 	*(UInteger16 *) (buf + 30) = flip16(ptpClock->sentPDelayReqSequenceId);
@@ -277,12 +294,9 @@
 void 
 msgPackDelayReq(Octet * buf, Timestamp * originTimestamp, PtpClock * ptpClock)
 {
-	msgPackHeader(buf, ptpClock);
+	msgPackHeader(buf, ptpClock, DELAY_REQ);
 	
 	/* changes in header */
-	*(char *)(buf + 0) = *(char *)(buf + 0) & 0xF0;
-	/* RAZ messageType */
-	*(char *)(buf + 0) = *(char *)(buf + 0) | 0x01;
 	/* Table 19 */
 	*(UInteger16 *) (buf + 2) = flip16(DELAY_REQ_LENGTH);
 
@@ -308,21 +322,12 @@
 void 
 msgPackDelayResp(Octet * buf, MsgHeader * header, Timestamp * receiveTimestamp, PtpClock * ptpClock)
 {
-	msgPackHeader(buf, ptpClock);
+	msgPackHeader(buf, ptpClock, DELAY_RESP);
 	
 	/* changes in header */
-	*(char *)(buf + 0) = *(char *)(buf + 0) & 0xF0;
-	/* RAZ messageType */
-	*(char *)(buf + 0) = *(char *)(buf + 0) | 0x09;
 	/* Table 19 */
 	*(UInteger16 *) (buf + 2) = flip16(DELAY_RESP_LENGTH);
 	*(UInteger8 *) (buf + 4) = header->domainNumber;
-
-#ifdef PTP_EXPERIMENTAL
-	if(rtOpts.do_hybrid_mode)    
-		*(char *)(buf + 6) |= PTP_UNICAST;
-#endif
-
 	memset((buf + 8), 0, 8);
 
 	/* Copy correctionField of PdelayReqMessage */
@@ -355,12 +360,9 @@
 void 
 msgPackPDelayResp(Octet * buf, MsgHeader * header, Timestamp * requestReceiptTimestamp, PtpClock * ptpClock)
 {
-	msgPackHeader(buf, ptpClock);
+	msgPackHeader(buf, ptpClock, PDELAY_RESP);
 	
 	/* changes in header */
-	*(char *)(buf + 0) = *(char *)(buf + 0) & 0xF0;
-	/* RAZ messageType */
-	*(char *)(buf + 0) = *(char *)(buf + 0) | 0x03;
 	/* Table 19 */
 	*(UInteger16 *) (buf + 2) = flip16(PDELAY_RESP_LENGTH);
 	*(UInteger8 *) (buf + 4) = header->domainNumber;
@@ -465,12 +467,9 @@
 void 
 msgPackPDelayRespFollowUp(Octet * buf, MsgHeader * header, Timestamp * responseOriginTimestamp, PtpClock * ptpClock)
 {
-	msgPackHeader(buf, ptpClock);
+	msgPackHeader(buf, ptpClock, PDELAY_RESP_FOLLOW_UP);
 	
 	/* changes in header */
-	*(char *)(buf + 0) = *(char *)(buf + 0) & 0xF0;
-	/* RAZ messageType */
-	*(char *)(buf + 0) = *(char *)(buf + 0) | 0x0A;
 	/* Table 19 */
 	*(UInteger16 *) (buf + 2) = flip16(PDELAY_RESP_FOLLOW_UP_LENGTH);
 	*(UInteger16 *) (buf + 30) = flip16(ptpClock->PdelayReqHeader.sequenceId);
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/net.c
--- a/src/dep/net.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/net.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,6 @@
 /*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen,
  *                         Jan Breuer
@@ -37,6 +39,14 @@
  *
  */
 
+#ifdef __sun
+#include <net/if_arp.h>
+#include <signal.h>
+#include "sfxge_ioctl.h"
+#include <string.h>
+extern void catch_alarm(int sig);
+#endif /* __sun */
+
 #include "../ptpd.h"
 
 /* choose kernel-level nanoseconds or microseconds resolution on the client-side */
@@ -44,6 +54,27 @@
 #error kernel-level timestamps not detected
 #endif
 
+/* Function that wraps up call to send message */
+static int sendMessage(int sockfd, const void *buf, size_t length,
+                       const struct sockaddr *addr, socklen_t addrLen,
+                       const char *messageType)
+{
+  int rc = sendto(sockfd, buf, length, 0, addr, addrLen);
+
+  if (rc < 0) {
+    DBG("error sending %s message, errno %d\n", messageType, errno);
+    return errno;
+  }
+  
+  if (rc != length) {
+    DBG("error sending %s message, sent %d bytes, expected %d\n",
+        messageType, rc, length);
+    return EIO;
+  }
+  
+  return 0;
+}
+
 /**
  * shutdown the IPv4 multicast for specific address
  *
@@ -149,12 +180,11 @@
 	return TRUE;
 }
 
-
 /*Test if network layer is OK for PTP*/
 UInteger8 
 lookupCommunicationTechnology(UInteger8 communicationTechnology)
 {
-#if defined(linux)
+#if defined(linux) || defined(__sun)
 	switch (communicationTechnology) {
 	case ARPHRD_ETHER:
 	case ARPHRD_EETHER:
@@ -164,170 +194,456 @@
 	default:
 		break;
 	}
-#endif  /* defined(linux) */
+#endif  /* defined(linux) || defined (__sun)*/
 
 	return PTP_DEFAULT;
 }
 
+#if defined(__sun)
+/* Find the local network interfacei; For solaris use lifreq */
+UInteger32 
+findIface(Octet * ifaceName, UInteger8 * communicationTechnology,
+    Octet * uuid, NetPath * netPath)
+{
+
+ /* depends on linux specific ioctls (see 'netdevice' man page) */
+ int i, flags;
+ struct lifconf data;
+ struct lifreq device[IFCONF_LENGTH];
+ struct sockaddr_dl *sdl;
+
+
+  /* an interface specified */
+    if (ifaceName[0] != '\0') {
+    i = 0;
+    memcpy(device[i].lifr_name, ifaceName, IFACE_NAME_LENGTH);
+    sdl = (struct sockaddr_dl *)&device[i].lifr_addr;
+
+    if (ioctl(netPath->eventSock, SIOCGLIFHWADDR, &device[i]) < 0)
+      DBGV("failed to get hardware address\n");
+    else if ((*communicationTechnology = sdl->sdl_type) != 0x4)
+      DBGV("unsupported communication technology (%d)\n", *communicationTechnology);
+    else {
+      memcpy(uuid, sdl->sdl_data, PTP_UUID_LENGTH);
+      clockIdentity_display(uuid);
+      }
+
+  } else {
+    /* no iface specified */
+    /* get list of network interfaces */
+
+	data.lifc_family = AF_INET;
+	data.lifc_len = sizeof(device);
+	data.lifc_req = device;
+
+	memset(data.lifc_buf, 0, data.lifc_len);
+
+	flags = IFF_UP | IFF_RUNNING | IFF_MULTICAST;
+
+    if (ioctl(netPath->eventSock, SIOCGLIFCONF, &data) < 0) {
+      PERROR("failed query network interfaces");
+      return 0;
+    }
+    if (data.lifc_len >= sizeof(device))
+      DBG("device list may exceed allocated space\n");
+
+    /* search through interfaces */
+    for (i = 0; i < data.lifc_len / sizeof(device[0]); ++i) {
+
+    sdl = (struct sockaddr_dl *)&device[i].lifr_addr;
+
+      DBGV("%d %s %s\n", i, device[i].lifr_name,
+          inet_ntoa(((struct sockaddr_in *)
+          &device[i].lifr_addr)->sin_addr));
+
+      if (ioctl(netPath->eventSock, SIOCGLIFFLAGS, 
+		&device[i]) < 0)
+        DBGV("failed to get device flags\n");
+      else if ((device[i].lifr_flags & flags) != flags)
+        DBGV("does not meet requirements"
+            "(%08x, %08x)\n", device[i].lifr_flags,
+            flags);
+      else if (ioctl(netPath->eventSock, SIOCGLIFHWADDR, &device[i]) < 0)
+        DBGV("failed to get hardware address\n");
+      else if ((*communicationTechnology = sdl->sdl_type) != 0x4)
+        DBGV("unsupported communication technology (%d)\n", *communicationTechnology);
+      else {
+        DBGV("found interface (%s)\n", device[i].lifr_name);
+        memcpy(uuid, sdl->sdl_data, PTP_UUID_LENGTH);
+        clockIdentity_display(uuid);
+        memcpy(ifaceName, device[i].lifr_name, IFACE_NAME_LENGTH);
+        break;
+      }
+    }
+  }
+
+  if (ifaceName[0] == '\0') {
+    ERROR("failed to find a usable interface\n");
+    return 0;
+  }
+  if (ioctl(netPath->eventSock, SIOCGLIFADDR, &device[i]) < 0) {
+    PERROR("failed to get ip address");
+    return 0;
+  }
+
+  /* @ioctl_timestamping Added support for IOCTL based timestamping for older kernels */
+  netPath->eventSockIFR = device[i];
+  return ((struct sockaddr_in *)&device[i].lifr_addr)->sin_addr.s_addr;
+}
+
+#else /* __sun */
 
  /* Find the local network interface */
 UInteger32 
 findIface(Octet * ifaceName, UInteger8 * communicationTechnology,
     Octet * uuid, NetPath * netPath)
 {
-#if defined(linux)
+#if defined(linux) || defined(__sun)
 
-	/* depends on linux specific ioctls (see 'netdevice' man page) */
-	int i, flags;
-	struct ifconf data;
-	struct ifreq device[IFCONF_LENGTH];
+        /* depends on linux specific ioctls (see 'netdevice' man page) */
+        int i, flags;
+        struct ifconf data;
+        struct ifreq device[IFCONF_LENGTH];
 
-	data.ifc_len = sizeof(device);
-	data.ifc_req = device;
+        data.ifc_len = sizeof(device);
+        data.ifc_req = device;
 
-	memset(data.ifc_buf, 0, data.ifc_len);
+  memset(data.ifc_buf, 0, data.ifc_len);
 
-	flags = IFF_UP | IFF_RUNNING | IFF_MULTICAST;
+  flags = IFF_UP | IFF_RUNNING | IFF_MULTICAST;
 
-	/* look for an interface if none specified */
-	if (ifaceName[0] != '\0') {
-		i = 0;
-		memcpy(device[i].ifr_name, ifaceName, IFACE_NAME_LENGTH);
+  /* an interface specified */
+  if (ifaceName[0] != '\0') {
+    i = 0;
+    memcpy(device[i].ifr_name, ifaceName, IFACE_NAME_LENGTH);
 
-		if (ioctl(netPath->eventSock, SIOCGIFHWADDR, &device[i]) < 0)
-			DBGV("failed to get hardware address\n");
-		else if ((*communicationTechnology = 
-			  lookupCommunicationTechnology(
-				  device[i].ifr_hwaddr.sa_family)) 
-			 == PTP_DEFAULT)
-			DBGV("unsupported communication technology (%d)\n", 
-			     *communicationTechnology);
-		else
-			memcpy(uuid, device[i].ifr_hwaddr.sa_data, 
-			       PTP_UUID_LENGTH);
-	} else {
-		/* no iface specified */
-		/* get list of network interfaces */
-		if (ioctl(netPath->eventSock, SIOCGIFCONF, &data) < 0) {
-			PERROR("failed query network interfaces");
-			return 0;
-		}
-		if (data.ifc_len >= sizeof(device))
-			DBG("device list may exceed allocated space\n");
+    if (ioctl(netPath->eventSock, SIOCGIFHWADDR, &device[i]) < 0)
+      DBGV("failed to get hardware address\n");
+    else if ((*communicationTechnology =
+        lookupCommunicationTechnology(
+          device[i].ifr_hwaddr.sa_family)) == PTP_DEFAULT)
+      DBGV("unsupported communication technology1 (%d)\n",
+          *communicationTechnology);
+    else
+      memcpy(uuid, device[i].ifr_hwaddr.sa_data, PTP_UUID_LENGTH);
 
-		/* search through interfaces */
-		for (i = 0; i < data.ifc_len / sizeof(device[0]); ++i) {
-			DBGV("%d %s %s\n", i, device[i].ifr_name, 
-			     inet_ntoa(((struct sockaddr_in *)
-					&device[i].ifr_addr)->sin_addr));
+  } else {
+    /* no iface specified */
+    /* get list of network interfaces */
+    if (ioctl(netPath->eventSock, SIOCGIFCONF, &data) < 0) {
+      PERROR("failed query network interfaces");
+      return 0;
+    }
+    if (data.ifc_len >= sizeof(device))
+      DBG("device list may exceed allocated space\n");
 
-			if (ioctl(netPath->eventSock, SIOCGIFFLAGS, 
-				  &device[i]) < 0)
-				DBGV("failed to get device flags\n");
-			else if ((device[i].ifr_flags & flags) != flags)
-				DBGV("does not meet requirements"
-				     "(%08x, %08x)\n", device[i].ifr_flags, 
-				     flags);
-			else if (ioctl(netPath->eventSock, SIOCGIFHWADDR, 
-				       &device[i]) < 0)
-				DBGV("failed to get hardware address\n");
-			else if ((*communicationTechnology = 
-				  lookupCommunicationTechnology(
-					  device[i].ifr_hwaddr.sa_family)) 
-				 == PTP_DEFAULT)
-				DBGV("unsupported communication technology"
-				     "(%d)\n", *communicationTechnology);
-			else {
-				DBGV("found interface (%s)\n", 
-				     device[i].ifr_name);
-				memcpy(uuid, device[i].ifr_hwaddr.sa_data, 
-				       PTP_UUID_LENGTH);
-				memcpy(ifaceName, device[i].ifr_name, 
-				       IFACE_NAME_LENGTH);
-				break;
-			}
-		}
-	}
+    /* search through interfaces */
+    for (i = 0; i < data.ifc_len / sizeof(device[0]); ++i) {
+      DBGV("%d %s %s\n", i, device[i].ifr_name,
+          inet_ntoa(((struct sockaddr_in *)
+          &device[i].ifr_addr)->sin_addr));
 
-	if (ifaceName[0] == '\0') {
-		ERROR("failed to find a usable interface\n");
-		return 0;
-	}
-	if (ioctl(netPath->eventSock, SIOCGIFADDR, &device[i]) < 0) {
-		PERROR("failed to get ip address");
-		return 0;
-	}
-	return ((struct sockaddr_in *)&device[i].ifr_addr)->sin_addr.s_addr;
+      if (ioctl(netPath->eventSock, SIOCGIFFLAGS, 
+		&device[i]) < 0)
+        DBGV("failed to get device flags\n");
+      else if ((device[i].ifr_flags & flags) != flags)
+        DBGV("does not meet requirements"
+            "(%08x, %08x)\n", device[i].ifr_flags,
+            flags);
+      else if (ioctl(netPath->eventSock, SIOCGIFHWADDR,
+              &device[i]) < 0)
+        DBGV("failed to get hardware address\n");
+      else if ((*communicationTechnology =
+          lookupCommunicationTechnology(
+            device[i].ifr_hwaddr.sa_family)) == PTP_DEFAULT)
+        DBGV("unsupported communication technology2"
+            "(%d)\n", *communicationTechnology);
+      else {
+        DBGV("found interface (%s)\n", 
+		device[i].ifr_name);
+        memcpy(uuid, device[i].ifr_hwaddr.sa_data, PTP_UUID_LENGTH);
+        memcpy(ifaceName, device[i].ifr_name, IFACE_NAME_LENGTH);
+        break;
+      }
+    }
+  }
+
+  if (ifaceName[0] == '\0') {
+    ERROR("failed to find a usable interface\n");
+    return 0;
+  }
+  if (ioctl(netPath->eventSock, SIOCGIFADDR, &device[i]) < 0) {
+    PERROR("failed to get ip address");
+    return 0;
+  }
+
+  /* @ioctl_timestamping Added support for IOCTL based timestamping for older kernels */
+  netPath->eventSockIFR = device[i];
+  return ((struct sockaddr_in *)&device[i].ifr_addr)->sin_addr.s_addr;
 
 #else /* usually *BSD */
 
-	struct ifaddrs *if_list, *ifv4, *ifh;
+  struct ifaddrs *if_list, *ifv4, *ifh;
 
-	if (getifaddrs(&if_list) < 0) {
-		PERROR("getifaddrs() failed");
-		return FALSE;
-	}
-	/* find an IPv4, multicast, UP interface, right name(if supplied) */
-	for (ifv4 = if_list; ifv4 != NULL; ifv4 = ifv4->ifa_next) {
-		if ((ifv4->ifa_flags & IFF_UP) == 0)
-			continue;
-		if ((ifv4->ifa_flags & IFF_RUNNING) == 0)
-			continue;
-		if ((ifv4->ifa_flags & IFF_LOOPBACK))
-			continue;
-		if ((ifv4->ifa_flags & IFF_MULTICAST) == 0)
-			continue;
-                /* must have IPv4 address */
-		if (ifv4->ifa_addr->sa_family != AF_INET)
-			continue;
-		if (ifaceName[0] && strncmp(ifv4->ifa_name, ifaceName, 
-					    IF_NAMESIZE) != 0)
-			continue;
-		break;
-	}
+  if (getifaddrs(&if_list) < 0) {
+    PERROR("getifaddrs() failed");
+    return FALSE;
+  }
+  /* find an IPv4, multicast, UP interface, right name(if supplied) */
+  for (ifv4 = if_list; ifv4 != NULL; ifv4 = ifv4->ifa_next) {
+    if ((ifv4->ifa_flags & IFF_UP) == 0)
+      continue;
+    if ((ifv4->ifa_flags & IFF_RUNNING) == 0)
+      continue;
+    if ((ifv4->ifa_flags & IFF_LOOPBACK))
+      continue;
+    if ((ifv4->ifa_flags & IFF_MULTICAST) == 0)
+      continue;
+    /* must have IPv4 address */
+    if (ifv4->ifa_addr->sa_family != AF_INET)
+      continue;
+    if (ifaceName[0] && strncmp(ifv4->ifa_name, ifaceName, 
+			    IF_NAMESIZE) != 0)
+      continue;
+    break;
+  }
 
-	if (ifv4 == NULL) {
-		if (ifaceName[0]) {
-			ERROR("interface \"%s\" does not exist,"
-			      "or is not appropriate\n", ifaceName);
-			return FALSE;
-		}
-		ERROR("no suitable interfaces found!");
-		return FALSE;
-	}
-	/* find the AF_LINK info associated with the chosen interface */
-	for (ifh = if_list; ifh != NULL; ifh = ifh->ifa_next) {
-		if (ifh->ifa_addr->sa_family != AF_LINK)
-			continue;
-		if (strncmp(ifv4->ifa_name, ifh->ifa_name, IF_NAMESIZE) == 0)
-			break;
-	}
+  if (ifv4 == NULL) {
+    if (ifaceName[0]) {
+      ERROR("interface \"%s\" does not exist,"
+            "or is not appropriate\n", ifaceName);
+      return FALSE;
+    }
+    ERROR("no suitable interfaces found!");
+    return FALSE;
+  }
+  /* find the AF_LINK info associated with the chosen interface */
+  for (ifh = if_list; ifh != NULL; ifh = ifh->ifa_next) {
+#ifndef __sun
+    if (ifh->ifa_addr->sa_family != AF_LINK)
+      continue;
+#endif
+    if (strncmp(ifv4->ifa_name, ifh->ifa_name, IF_NAMESIZE) == 0)
+      break;
+  }
 
-	if (ifh == NULL) {
-		ERROR("could not get hardware address for interface \"%s\"\n", 
-		      ifv4->ifa_name);
-		return FALSE;
-	}
-	/* check that the interface TYPE is OK */
-	if (((struct sockaddr_dl *)ifh->ifa_addr)->sdl_type != IFT_ETHER) {
-		ERROR("\"%s\" is not an ethernet interface!\n", ifh->ifa_name);
-		return FALSE;
-	}
-	DBG("==> %s %s %s\n", ifv4->ifa_name,
-	    inet_ntoa(((struct sockaddr_in *)ifv4->ifa_addr)->sin_addr),
-	    ether_ntoa((struct ether_addr *)
-		       LLADDR((struct sockaddr_dl *)ifh->ifa_addr))
-	    );
+  if (ifh == NULL) {
+    ERROR("could not get hardware address for interface \"%s\"\n",
+          ifv4->ifa_name);
+    return FALSE;
+  }
+  /* check that the interface TYPE is OK */
+  if (((struct sockaddr_dl *)ifh->ifa_addr)->sdl_type != IFT_ETHER) {
+    ERROR("\"%s\" is not an ethernet interface!\n", ifh->ifa_name);
+    return FALSE;
+  }
+  DBG("==> %s %s %s\n", ifv4->ifa_name,
+      inet_ntoa(((struct sockaddr_in *)ifv4->ifa_addr)->sin_addr),
+      ether_ntoa((struct ether_addr *)
+	      LLADDR((struct sockaddr_dl *)ifh->ifa_addr))
+      );
 
-	*communicationTechnology = PTP_ETHER;
-	memcpy(ifaceName, ifh->ifa_name, IFACE_NAME_LENGTH);
-	memcpy(uuid, LLADDR((struct sockaddr_dl *)ifh->ifa_addr), 
-	       PTP_UUID_LENGTH);
+  *communicationTechnology = PTP_ETHER;
+  memcpy(ifaceName, ifh->ifa_name, IFACE_NAME_LENGTH);
+  memcpy(uuid, LLADDR((struct sockaddr_dl *)ifh->ifa_addr), 
+	PTP_UUID_LENGTH);
 
-	return ((struct sockaddr_in *)ifv4->ifa_addr)->sin_addr.s_addr;
+  return ((struct sockaddr_in *)ifv4->ifa_addr)->sin_addr.s_addr;
 
 #endif
 }
+#endif /* __sun */
+
+/* @pdelay_req TODO timestamp is not being collected when PDELAY_REQ messages are */
+/* sent. Collect the timestamp and throw it away for now */
+static int txTimestamp(PtpClock *ptpClock, char *pdu, int pdulen, TimeMode timeMode, Boolean keep)
+{
+  TimeInternal ts;
+  int haveTs = 0;
+  int matchedPkt = 0;
+  NetPath *netPath = &ptpClock->netPath;
+
+  DUMP("PDU", pdu, pdulen);
+
+  switch (ptpClock->tsMethod) {
+    case TS_METHOD_SYSTEM:
+      /* Time stamp will appear on the multicast loopback. */
+      return 0;
+      break;
+
+    case TS_METHOD_DRIVER_IOCTL:
+      /* fast path: get send time stamp directly */
+      haveTs = getSendTime(&ts, timeMode, netPath);
+      if(haveTs) {
+        DBGV("got send time stamp in first attempt\n");
+      } else {
+        /*
+         * need to wait for it: need to check system time, counting
+         * the number of nanoSleep()s is too inaccurate because it
+         * each call sleeps much longer than requested
+         */
+        TimeInternal start, now;
+        timerNow(&start);
+        while(TRUE) {
+          TimeInternal delayAfterPacketSend;
+          delayAfterPacketSend.seconds = 0;
+          delayAfterPacketSend.nanoseconds = 1000;
+          nanoSleep(&delayAfterPacketSend);
+          haveTs = getSendTime(&ts, timeMode, netPath);
+          timerNow(&now);
+          subTime(&now, &now, &start);
+          /* 0.1 seconds is the maximum we wait... */
+          if(haveTs || now.seconds >= 1 || now.nanoseconds >= 100000000) {
+            DBGV("%s send time stamp after %d.%09ds\n",
+                 haveTs ? "got" : "failed to get",
+                 now.seconds, now.nanoseconds);
+            break;
+          }
+        }
+      }
+
+      if(haveTs) {
+        /* TODO can we match the packet in this case? */
+        matchedPkt = 1;
+      }
+      break;
+
+#ifndef  __sun /* Do not compile if __sun as we don't support non-ioctl method yet */
+    case TS_METHOD_SO_TIMESTAMPING:
+    {
+      struct cmsghdr *cmsg;
+      struct iovec vec[1];
+      struct msghdr msg;
+      struct sock_extended_err *err;
+      struct timespec *tmp;
+
+      int cnt, level, type;
+      char control[512];
+      unsigned char buf[PACKET_SIZE];
+      const char *ts_text;
+      
+      vec[0].iov_base = buf;
+      vec[0].iov_len = sizeof(buf);
+      memset(&msg, 0, sizeof(msg));
+      msg.msg_iov = vec;
+      msg.msg_iovlen = 1;
+      msg.msg_control = control;
+      msg.msg_controllen = sizeof(control);
+
+      /*
+       * need to wait for it: need to check system time, counting
+       * the number of nanoSleep()s is too inaccurate because it
+       * each call sleeps much longer than requested
+       */
+      TimeInternal start, now;
+      timerNow(&start);
+      while((cnt = recvmsg(netPath->eventSock, &msg, MSG_ERRQUEUE)) < 0) {
+        if ((errno == EAGAIN) || (errno == EINTR)) {
+          TimeInternal delay;
+          delay.seconds = 0;
+          delay.nanoseconds = 1000;
+          nanoSleep(&delay);
+          timerNow(&now);
+          subTime(&now, &now, &start);
+          /* 0.1 second is the maximum we wait... */
+          if(now.seconds >= 1 || now.nanoseconds >= 100000000) {
+            DBGV("Failed to get send time stamp after %d.%09ds\n",
+                 now.seconds, now.nanoseconds);
+            return -1;
+          }
+        } else {
+          ERROR("recvmsg failed: %s\n", strerror(errno));
+          return -1;
+        }
+      }
+
+      if (cnt < pdulen) {
+        ERROR("recvmsg returned only %d of %d bytes\n", cnt, pdulen);
+        return -1;
+      }
+
+      DUMP("cmsg all", buf, cnt);
+
+      for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+
+        level = cmsg->cmsg_level;
+        type  = cmsg->cmsg_type;
+
+        DUMP("cmsg", cmsg, cmsg->cmsg_len);
+
+        if (SOL_SOCKET == level && SO_TIMESTAMPING == type) {
+          if (cmsg->cmsg_len < sizeof(*tmp)*3) {
+            ERROR("received short so_timestamping\n");
+            return -1;
+          }
+          /* array of three time stamps: software, HW, raw HW */
+          tmp = (struct timespec*)CMSG_DATA(cmsg);
+
+          switch (timeMode) {
+            case TIME_SYSTEM_LINUX_SW:
+              /* Desired timestamp is first in array */
+              ts_text = "SW SYS";
+              break;
+            case TIME_SYSTEM_LINUX_HW:
+              /* Desired timestamp is second in array */
+              ts_text = "HW SYS";
+              tmp++;
+            break;
+            case TIME_NIC:
+            case TIME_BOTH:
+              /* Desired timestamp is third in array */
+              ts_text = "HW RAW";
+              tmp += 2;
+              break;
+            default:
+              ERROR("Invalid case in switch %d\n", timeMode);
+              break;
+          }
+
+          if (tmp->tv_sec && tmp->tv_nsec) {
+            DBG("%s Tx TIMESTAMP: %d.%09d\n", ts_text, tmp->tv_sec, tmp->tv_nsec);
+            ts.seconds = tmp->tv_sec;
+            ts.nanoseconds = tmp->tv_nsec;
+            haveTs = 1;
+          }
+        } else if (IPPROTO_IP == level && IP_RECVERR == type) {
+          err = (struct sock_extended_err*)CMSG_DATA(cmsg);
+          if (err->ee_errno == ENOMSG &&
+              err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING &&
+              !memcmp(pdu, buf + cnt - pdulen, pdulen)) {
+            matchedPkt = 1;
+          }
+        }
+      }
+    }
+      break;
+#endif /* ifndef __sun */
+
+    default:
+      ERROR("!!! txTimestamp() Unexpected time mode %d\n", timeMode);
+      return 0;
+      break;
+    }
+
+  if (!haveTs || !matchedPkt) {
+    return -1;
+  }
+
+  if (keep) {
+    /* Push packet onto stack. */
+    int index = netPath->tx_stack.count;
+    if (TX_STACK_SIZE == index) {
+      ERROR("out of stack space\n");
+      return -1;
+    }
+    memcpy(netPath->tx_stack.data[index].buf, pdu, pdulen);
+    netPath->tx_stack.data[index].len = pdulen;
+    netPath->tx_stack.data[index].ts = ts;
+    netPath->tx_stack.count++;
+  }
+
+  return 0;
+}
 
 /**
  * Init the multcast for specific IPv4 address
@@ -390,7 +706,7 @@
 
 
 	/* Init Peer multicast IP address */
-	memcpy(addrStr, PEER_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH);
+	strncpy(addrStr, PEER_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH);
 
 	if (!inet_aton(addrStr, &netAddr)) {
 		ERROR("failed to encode multi-cast address: %s\n", addrStr);
@@ -413,9 +729,9 @@
  * @return TRUE if successful
  */
 Boolean 
-netInitTimestamping(NetPath * netPath)
+netInitTimestamping(NetPath * netPath, Boolean useSystemTimeStamps)
 {
-	int val = 1;
+	int val = useSystemTimeStamps;
 	Boolean result = TRUE;
 	
 #if defined(SO_TIMESTAMPNS) /* Linux, Apple */
@@ -457,70 +773,76 @@
 
 /**
  * start all of the UDP stuff 
- * must specify 'subdomainName', and optionally 'ifaceName', 
+ * must specify 'subdomainName', and optionally 'ifaceName',
  * if not then pass ifaceName == "" 
- * on socket options, see the 'socket(7)' and 'ip' man pages 
+ * on socket options, see the 'socket(7)' and 'ip' man pages
  *
  * @param netPath 
- * @param rtOpts 
+ * @param rtOpts
  * @param ptpClock 
- * 
+ *
  * @return TRUE if successful
  */
-Boolean 
+Boolean
 netInit(NetPath * netPath, RunTimeOpts * rtOpts, PtpClock * ptpClock)
 {
-	int temp;
-	struct in_addr interfaceAddr, netAddr;
-	struct sockaddr_in addr;
+  int temp;
+#ifdef __sun
+  uchar_t temp_char;
+  char devpath[MAXLINKNAMELEN];
+#endif
 
-	DBG("netInit\n");
+  struct in_addr interfaceAddr, netAddr;
+  struct sockaddr_in addr;
+  Boolean useSystemTimeStamps = (rtOpts->time_mode == TIME_SYSTEM);
 
-	/* open sockets */
-	if ((netPath->eventSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0
-	    || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM, 
-					      IPPROTO_UDP)) < 0) {
-		PERROR("failed to initalize sockets");
-		return FALSE;
-	}
-	/* find a network interface */
-	if (!(interfaceAddr.s_addr = 
-	      findIface(rtOpts->ifaceName, 
-			&ptpClock->port_communication_technology,
-			ptpClock->port_uuid_field, netPath)))
-		return FALSE;
+  DBG("netInit\n");
 
-	/* save interface address for IGMP refresh */
-	netPath->interfaceAddr = interfaceAddr;
-	
-	DBG("Local IP address used : %s \n", inet_ntoa(interfaceAddr));
+  /* open sockets */
+  if ((netPath->eventSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0
+      || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM,
+		      IPPROTO_UDP)) < 0) {
+    PERROR("failed to initalize sockets");
+    return FALSE;
+  }
+  /* find a network interface */
+  if (!(interfaceAddr.s_addr =
+        findIface(rtOpts->ifaceName,
+      &ptpClock->port_communication_technology,
+      ptpClock->port_uuid_field, netPath)))
+    return FALSE;
 
-	temp = 1;			/* allow address reuse */
-	if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR, 
-		       &temp, sizeof(int)) < 0
-	    || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR, 
-			  &temp, sizeof(int)) < 0) {
-		DBG("failed to set socket reuse\n");
-	}
-	/* bind sockets */
-	/*
-	 * need INADDR_ANY to allow receipt of multi-cast and uni-cast
-	 * messages
-	 */
-	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = htonl(INADDR_ANY);
-	addr.sin_port = htons(PTP_EVENT_PORT);
-	if (bind(netPath->eventSock, (struct sockaddr *)&addr, 
-		 sizeof(struct sockaddr_in)) < 0) {
-		PERROR("failed to bind event socket");
-		return FALSE;
-	}
-	addr.sin_port = htons(PTP_GENERAL_PORT);
-	if (bind(netPath->generalSock, (struct sockaddr *)&addr, 
-		 sizeof(struct sockaddr_in)) < 0) {
-		PERROR("failed to bind general socket");
-		return FALSE;
-	}
+  /* save interface address for IGMP refresh */
+  netPath->interfaceAddr = interfaceAddr;
+
+  DBG("Local IP address used : %s \n", inet_ntoa(interfaceAddr));
+
+  temp = 1;			/* allow address reuse */
+  if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR,
+			  &temp, sizeof(int)) < 0
+      || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR, 
+	      &temp, sizeof(int)) < 0) {
+    DBG("failed to set socket reuse\n");
+  }
+  /* bind sockets */
+  /*
+  * need INADDR_ANY to allow receipt of multi-cast and uni-cast
+  * messages
+  */
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  addr.sin_port = htons(PTP_EVENT_PORT);
+  if (bind(netPath->eventSock, (struct sockaddr *)&addr,
+    sizeof(struct sockaddr_in)) < 0) {
+    PERROR("failed to bind event socket");
+    return FALSE;
+  }
+  addr.sin_port = htons(PTP_GENERAL_PORT);
+  if (bind(netPath->generalSock, (struct sockaddr *)&addr,
+    sizeof(struct sockaddr_in)) < 0) {
+    PERROR("failed to bind general socket");
+    return FALSE;
+  }
 
 
 
@@ -545,111 +867,256 @@
 		PERROR("failed to call SO_BINDTODEVICE on the interface");
 		return FALSE;
 	}
+#endif  /* linux */
+#endif  /* USE_BINDTODEVICE */
+
+
+  /* send a uni-cast address if specified (useful for testing) */
+  if (rtOpts->unicastAddress[0]) {
+    /* Attempt a DNS lookup first. */
+    struct hostent *host;
+#ifdef __sun
+    host = gethostbyname(rtOpts->unicastAddress);
+#else
+    host = gethostbyname2(rtOpts->unicastAddress, AF_INET);
 #endif
-#endif
-
-
-	/* send a uni-cast address if specified (useful for testing) */
-	if (rtOpts->unicastAddress[0]) {
-		/* Attempt a DNS lookup first. */
-		struct hostent *host;
-		host = gethostbyname2(rtOpts->unicastAddress, AF_INET);
-                if (host != NULL) {
-			if (host->h_length != 4) {
-				PERROR("unicast host resolved to non ipv4"
-				       "address");
-				return FALSE;
-			}
-			netPath->unicastAddr = 
-				*(uint32_t *)host->h_addr_list[0];
-		} else {
-			/* Maybe it's a dotted quad. */
-			if (!inet_aton(rtOpts->unicastAddress, &netAddr)) {
-				ERROR("failed to encode uni-cast address: %s\n",
-				      rtOpts->unicastAddress);
-				return FALSE;
-				netPath->unicastAddr = netAddr.s_addr;
-			}
-                }
-	} else {
-                netPath->unicastAddr = 0;
-	}
+    if (host != NULL) {
+      if (host->h_length != 4) {
+        PERROR("unicast host resolved to non ipv4"
+              "address");
+        return FALSE;
+      }
+      netPath->unicastAddr =
+	      *(uint32_t *)host->h_addr_list[0];
+    } else {
+      /* Maybe it's a dotted quad. */
+      if (!inet_aton(rtOpts->unicastAddress, &netAddr)) {
+        ERROR("failed to encode uni-cast address: %s\n",
+              rtOpts->unicastAddress);
+        return FALSE;
+        netPath->unicastAddr = netAddr.s_addr;
+      }
+    }
+  } else {
+    netPath->unicastAddr = 0;
+  }
 
 	/* init UDP Multicast on both Default and Pear addresses */
 	if (!netInitMulticast(netPath, rtOpts)) {
 		return FALSE;
 	}
 
-	/* set socket time-to-live to 1 */
+  /* set socket time-to-live to 1 */
 
-	if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_TTL, 
-		       &rtOpts->ttl, sizeof(int)) < 0
-	    || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_TTL, 
-			  &rtOpts->ttl, sizeof(int)) < 0) {
-		PERROR("failed to set the multi-cast time-to-live");
-		return FALSE;
-	}
+  if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_TTL,
+          &rtOpts->ttl, sizeof(rtOpts->ttl)) < 0
+      || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_TTL,
+        &rtOpts->ttl, sizeof(rtOpts->ttl)) < 0) {
+    PERROR("failed to set the multi-cast time-to-live");
+    return FALSE;
+  }
 
-	/* enable loopback */
-	temp = 1;
+#ifndef __sun
+  /* enable loopback */
+  temp = useSystemTimeStamps;
 
 	DBG("Going to set IP_MULTICAST_LOOP with %d \n", temp);
 
-	if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_LOOP, 
-		       &temp, sizeof(int)) < 0
-	    || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_LOOP, 
-			  &temp, sizeof(int)) < 0) {
-		PERROR("failed to enable multi-cast loopback");
-		return FALSE;
-	}
+  if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_LOOP,
+          &temp, sizeof(int)) < 0
+      || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_LOOP,
+        &temp, sizeof(int)) < 0) {
+    PERROR("failed to enable multi-cast loopback");
+    return FALSE;
+  }
+#else
+  /* enable loopback */
+  /* On Solaris, the IP_MULTICAST_LOOP takes uchar_t as data */
+  temp_char = useSystemTimeStamps;
+	
+  DBG("Going to set IP_MULTICAST_LOOP with %d \n", temp);
+
+  if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_LOOP,
+          &temp_char, sizeof(temp_char)) < 0
+      || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_LOOP,
+        &temp_char, sizeof(temp_char)) < 0) {
+    PERROR("failed to enable multi-cast loopback");
+    return FALSE;
+  }
+#endif
+
+#ifdef __sun
+  /* Open a socket for hw assist IOCTLs only if we need it */
+  if (rtOpts->time_mode == TIME_BOTH || rtOpts->time_mode == TIME_NIC) {
+       /*
+        * On Solaris, we cannot use netPath->eventSock to send ioctl to 
+        * NIC driver as eventSock is a datagram socket. In the plumbed
+        * network stack, ip module act as a driver which means ip will
+        * not pass unknown ioctl down. So, we create a new fd to be
+        * used for ioctls to NIC.
+        */
+       snprintf(devpath, sizeof(devpath), "/dev/net/%s", rtOpts->ifaceName); 
+       if ((netPath->devFd = open(devpath, O_RDWR)) < 0) {
+               PERROR("failed to open device %s\n", devpath);
+               return FALSE;
+       } else {
+               DBG("open()ed %s\n", devpath);
+       }
+  }
+
+#endif
 
 	/* make timestamps available through recvmsg() */
-	if (!netInitTimestamping(netPath)) {
+	if (!netInitTimestamping(netPath, useSystemTimeStamps)) {
 		ERROR("failed to enable receive time stamps");
 		return FALSE;
 	}
 
-	return TRUE;
+  return TRUE;
 }
 
 /*Check if data have been received*/
-int 
+int
 netSelect(TimeInternal * timeout, NetPath * netPath)
 {
-	int ret, nfds;
-	fd_set readfds;
-	struct timeval tv, *tv_ptr;
+  int ret, nfds;
+  fd_set readfds;
+  struct timespec tv;
+  const struct timespec *tv_ptr;
+  sigset_t ignore_sigs;
 
-	if (timeout < 0)
-		return FALSE;
+  if (netPath->tx_stack.count)
+    return TRUE;
 
-	FD_ZERO(&readfds);
-	FD_SET(netPath->eventSock, &readfds);
-	FD_SET(netPath->generalSock, &readfds);
+  FD_ZERO(&readfds);
+  FD_SET(netPath->eventSock, &readfds);
+  FD_SET(netPath->generalSock, &readfds);
 
-	if (timeout) {
-		tv.tv_sec = timeout->seconds;
-		tv.tv_usec = timeout->nanoseconds / 1000;
-		tv_ptr = &tv;
-	} else
-		tv_ptr = 0;
+  if (timeout) {
+    tv.tv_sec = timeout->seconds;
+    tv.tv_nsec = timeout->nanoseconds;
+    tv_ptr = &tv;
+  } else
+    tv_ptr = 0;
 
-	if (netPath->eventSock > netPath->generalSock)
-		nfds = netPath->eventSock;
-	else
-		nfds = netPath->generalSock;
+  if (netPath->eventSock > netPath->generalSock)
+    nfds = netPath->eventSock;
+  else
+    nfds = netPath->generalSock;
 
-	ret = select(nfds + 1, &readfds, 0, 0, tv_ptr) > 0;
+  ret = pselect(nfds + 1, &readfds, 0, 0, tv_ptr, &ignore_sigs) > 0;
 
-	if (ret < 0) {
-		if (errno == EAGAIN || errno == EINTR)
-			return 0;
-	}
-	return ret;
+  if (ret < 0) {
+    if (errno == EAGAIN || errno == EINTR)
+      return 0;
+  }
+  return ret;
 }
 
+#ifdef linux
+/* Used to get receive timestamps when in the SYSTEM  LINUX_HW or LINUX_SW time modes */
+static int do_rx_timestamping(struct msghdr *msg, TimeInternal *time, RunTimeOpts *rtOpts)
+{
+    struct cmsghdr *cm;
+    struct timeval *tv;
+    Boolean have_time = FALSE;
 
+    /* @ioctl_timestamping As v1 code, added bool to break out of loop on discovery for ts. */
+    for (cm = CMSG_FIRSTHDR(msg); !have_time && cm != NULL; cm = CMSG_NXTHDR(msg, cm)) {
 
+        struct timespec *stamp;
+
+        DUMP("CM", cm, cm->cmsg_len);
+
+        if (cm->cmsg_level != SOL_SOCKET)
+            continue;
+
+        switch (cm->cmsg_type) {
+
+        case SCM_TIMESTAMP:
+            tv = (struct timeval *)CMSG_DATA(cm);
+            if(cm->cmsg_len < sizeof(*tv))
+            {
+                ERROR("received short SCM_TIMESTAMP (%d/%d)\n",
+                      cm->cmsg_len, sizeof(*tv));
+                return -1;
+            }
+
+            time->seconds = tv->tv_sec;
+            time->nanoseconds = tv->tv_usec*1000;
+            have_time = TRUE;
+            break;
+
+#ifdef SO_TIMESTAMPNS
+        case SCM_TIMESTAMPNS:
+            stamp = (struct timespec *)CMSG_DATA(cm);
+            if(cm->cmsg_len < sizeof(*stamp))
+            {
+                ERROR("received short SCM_TIMESTAMPNS (%d/%d)\n",
+                      cm->cmsg_len, sizeof(*stamp));
+                return -1;
+            }
+            time->seconds = stamp->tv_sec;
+            time->nanoseconds = stamp->tv_nsec;
+            have_time = TRUE;
+            break;
+#endif
+
+        case SO_TIMESTAMPING:
+        {
+            const char *ts_text;
+
+            /* array of three time stamps: software, HW, raw HW */
+            stamp = (struct timespec*)CMSG_DATA(cm);
+
+            if (cm->cmsg_len < sizeof(*stamp)*3) {
+                ERROR("received short SO_TIMESTAMPING (%d/%d)\n",
+                cm->cmsg_len, (int)sizeof(*stamp)*3);
+                return -1;
+            }
+
+            switch (rtOpts->time_mode) {
+                case TIME_SYSTEM_LINUX_SW:
+                    /* Desired timestamp is first in array */
+                    ts_text = "SW SYS";
+                    break;
+                case TIME_SYSTEM_LINUX_HW:
+                    /* Desired timestamp is second in array */
+                    ts_text = "HW SYS";
+                    stamp++;
+                    break;
+                case TIME_NIC:
+                case TIME_BOTH:
+                    /* Desired timestamp is third in array */
+                    ts_text = "HW RAW";
+                    stamp += 2;
+                    break;
+                default:
+                    ERROR("Invalid case in switch %d\n", rtOpts->time_mode);
+                    break;
+            }
+
+            if (stamp->tv_sec && stamp->tv_nsec) {
+                DBG2("%s Rx TIMESTAMP %d.%09d\n", ts_text, stamp->tv_sec, stamp->tv_nsec);
+                time->seconds = stamp->tv_sec;
+                time->nanoseconds = stamp->tv_nsec;
+
+                have_time = TRUE;
+            }
+        }
+            break;
+        }
+    }
+
+    if (!have_time) {
+        DBG("no receive time stamp\n");
+        return -1;
+    }
+    DBG("kernel recv time stamp %us %dns\n", time->seconds, time->nanoseconds);
+
+    return 0;
+}
+#endif /* linux */
 
 /** 
  * store received data from network to "buf" , get and store the
@@ -668,16 +1135,17 @@
  */
 
 ssize_t 
-netRecvEvent(Octet * buf, TimeInternal * time, NetPath * netPath)
+netRecvEvent(Octet * buf, TimeInternal * time, PtpClock *ptpClock, RunTimeOpts *rtOpts, Boolean *loopedBackTx)
 {
 	ssize_t ret;
 	struct msghdr msg;
 	struct iovec vec[1];
 	struct sockaddr_in from_addr;
+	NetPath *netPath = &ptpClock->netPath;
 
 	union {
 		struct cmsghdr cm;
-		char	control[CMSG_SPACE(sizeof(struct timeval))];
+		char	control[512];
 	}     cmsg_un;
 
 	struct cmsghdr *cmsg;
@@ -690,10 +1158,25 @@
 #endif
 	
 #if defined(SO_TIMESTAMP)
-	struct timeval * tv;
+	struct timeval tv;
+	struct timeval * tv1;
 #endif
 	Boolean timestampValid = FALSE;
 
+  /* Pop packet from stack. */
+  if (netPath->tx_stack.count) {
+    int index = netPath->tx_stack.count - 1;
+    ret = netPath->tx_stack.data[index].len;
+    memcpy(buf, netPath->tx_stack.data[index].buf, ret);
+    time->seconds = netPath->tx_stack.data[index].ts.seconds;
+    time->nanoseconds = netPath->tx_stack.data[index].ts.nanoseconds;
+    netPath->tx_stack.count--;
+    DBGV("netRecvEvent: ts from stack %d bytes\n", ret);
+    *loopedBackTx = TRUE;
+    return ret;
+  }
+
+	*loopedBackTx = FALSE;
 
 	vec[0].iov_base = buf;
 	vec[0].iov_len = PACKET_SIZE;
@@ -735,10 +1218,19 @@
 	netPath->lastRecvAddr = from_addr.sin_addr.s_addr;
 #endif
 
+  /* If we are collecting timestamps using the driver IOCTL method, we
+   * need to wait until we've decoded the header before processing the
+   * timestamps. For other methods, call do_rx_timestamping().
+   */
+  if (ptpClock->tsMethod == TS_METHOD_DRIVER_IOCTL) {
+    return ret;
+  }
 
-
+#ifdef linux
+  return (do_rx_timestamping(&msg, time, rtOpts) == 0)? ret: 0;
+#else
 	if (msg.msg_controllen <= 0) {
-		ERROR("received short ancillary data (%ld/%ld)\n",
+		ERROR("netRecvEvent: received short ancillary data (%ld/%ld)\n",
 		    (long)msg.msg_controllen, (long)sizeof(cmsg_un.control));
 
 		return 0;
@@ -772,9 +1264,16 @@
 			
 #if defined(SO_TIMESTAMP)
 			if(cmsg->cmsg_type == SCM_TIMESTAMP) {
-				tv = (struct timeval *)CMSG_DATA(cmsg);
-				time->seconds = tv->tv_sec;
-				time->nanoseconds = tv->tv_usec * 1000;
+				tv1 = (struct timeval *)CMSG_DATA(cmsg);
+				/*
+				 * tv->sec is 8 byte field, 
+				 * tv may not be 8 byte aligned.
+				 * Use memcpy();
+				 *
+				 */
+				memcpy(&tv, tv1, sizeof(struct timeval));
+				time->seconds = tv.tv_sec;
+				time->nanoseconds = tv.tv_usec * 1000;
 				timestampValid = TRUE;
 				DBGV("kernel MICRO recv time stamp %us %dns\n",
 				     time->seconds, time->nanoseconds);
@@ -795,6 +1294,7 @@
 	}
 
 	return ret;
+#endif /* ifdef linux */
 }
 
 
@@ -811,13 +1311,34 @@
  * @return 
  */
 
+ssize_t
+netRecvGeneral_old(Octet * buf, TimeInternal * time, NetPath * netPath)
+{
+  ssize_t ret;
+  struct sockaddr_in from_addr;
+  socklen_t addr_len = sizeof(struct sockaddr_in);
+
+  ret = recvfrom(netPath->generalSock, buf, PACKET_SIZE, MSG_DONTWAIT,
+          (struct sockaddr *)&from_addr, &addr_len);
+  if (ret <= 0) {
+    if (errno == EAGAIN || errno == EINTR)
+      return 0;
+
+    return ret;
+  }
+
+  DBGV("netRecvGeneral: rxed %d bytes\n", ret);
+  return ret;
+}
+
 ssize_t 
-netRecvGeneral(Octet * buf, TimeInternal * time, NetPath * netPath)
+netRecvGeneral(Octet * buf, TimeInternal * time,  PtpClock *ptpClock, RunTimeOpts *rtOpts)
 {
 	ssize_t ret;
 	struct msghdr msg;
 	struct iovec vec[1];
 	struct sockaddr_in from_addr;
+	NetPath *netPath = &ptpClock->netPath;
 	
 	union {
 		struct cmsghdr cm;
@@ -825,7 +1346,7 @@
 	}     cmsg_un;
 	
 	struct cmsghdr *cmsg;
-	
+
 #if defined(SO_TIMESTAMPNS)
 	struct timespec * ts;
 #elif defined(SO_BINTIME)
@@ -834,7 +1355,8 @@
 #endif
 	
 #if defined(SO_TIMESTAMP)
-	struct timeval * tv;
+	struct timeval tv;
+	struct timeval * tv1;
 #endif
 	Boolean timestampValid = FALSE;
 	
@@ -880,11 +1402,18 @@
 #ifdef PTP_EXPERIMENTAL
 	netPath->lastRecvAddr = from_addr.sin_addr.s_addr;
 #endif
-	
+
+  /* If we are collecting timestamps using the driver IOCTL method, we
+   * need to wait until we've decoded the header before processing the
+   * timestamps. For other methods, call do_rx_timestamping().
+   */
+  if (ptpClock->tsMethod == TS_METHOD_DRIVER_IOCTL) {
+    return ret;
+  }
 	
 	
 	if (msg.msg_controllen <= 0) {
-		ERROR("received short ancillary data (%ld/%ld)\n",
+		ERROR("netRecvGeneral : received short ancillary data (%ld/%ld)\n",
 		      (long)msg.msg_controllen, (long)sizeof(cmsg_un.control));
 		
 		return 0;
@@ -918,9 +1447,10 @@
 			
 #if defined(SO_TIMESTAMP)
 			if(cmsg->cmsg_type == SCM_TIMESTAMP) {
-				tv = (struct timeval *)CMSG_DATA(cmsg);
-				time->seconds = tv->tv_sec;
-				time->nanoseconds = tv->tv_usec * 1000;
+				tv1 = (struct timeval *)CMSG_DATA(cmsg);
+				memcpy(&tv, tv1, sizeof (struct timeval));
+				time->seconds = tv.tv_sec;
+				time->nanoseconds = tv.tv_usec * 1000;
 				timestampValid = TRUE;
 				DBGV("kernel MICRO recv time stamp %us %dns\n",
 				     time->seconds, time->nanoseconds);
@@ -955,11 +1485,12 @@
 ///
 /// TODO: merge these 2 functions into one
 ///
-ssize_t 
-netSendEvent(Octet * buf, UInteger16 length, NetPath * netPath, Integer32 alt_dst)
+int
+netSendEvent(Octet * buf, UInteger16 length, PtpClock *ptpClock, RunTimeOpts *rtOpts, Integer32 alt_dst)
 {
-	ssize_t ret;
+	int ret;
 	struct sockaddr_in addr;
+	NetPath *netPath = &ptpClock->netPath;
 
 	addr.sin_family = AF_INET;
 	addr.sin_port = htons(PTP_EVENT_PORT);
@@ -971,75 +1502,71 @@
 			addr.sin_addr.s_addr = alt_dst;
 		}
 
-		ret = sendto(netPath->eventSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error sending uni-cast event message\n");
-		/* 
+		ret = sendMessage(netPath->eventSock, buf, length,
+                      (struct sockaddr *)&addr, sizeof(addr),
+                      "unicast event");
+		if (ret == 0) {
+		/*
 		 * Need to forcibly loop back the packet since
-		 * we are not using multicast. 
+		 * we are not using multicast.
 		 */
 		addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
-		ret = sendto(netPath->eventSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error looping back uni-cast event message\n");
-		
+		ret = sendMessage(netPath->eventSock, buf, length,
+                        (struct sockaddr *)&addr, sizeof(addr),
+                        "loopback unicast event");
+		}
 	} else {
 		addr.sin_addr.s_addr = netPath->multicastAddr;
+    
+		ret = sendMessage(netPath->eventSock, buf, length,
+                      (struct sockaddr *)&addr, sizeof(addr),
+                      "multicast event");
+	}
 
-		ret = sendto(netPath->eventSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error sending multi-cast event message\n");
+	if (ret == 0) {
+		if (txTimestamp(ptpClock, (char *)buf, length, rtOpts->time_mode, TRUE) != 0) {
+			ERROR("txTimestamp failed\n");
+			ret = ENOTIMESTAMP;
+		}
 	}
 
 	return ret;
 }
 
-ssize_t 
+int 
 netSendGeneral(Octet * buf, UInteger16 length, NetPath * netPath, Integer32 alt_dst)
 {
-	ssize_t ret;
+	int ret;
 	struct sockaddr_in addr;
 
 	addr.sin_family = AF_INET;
 	addr.sin_port = htons(PTP_GENERAL_PORT);
 
 	if(netPath->unicastAddr || alt_dst ){
-	if (netPath->unicastAddr) {
-		addr.sin_addr.s_addr = netPath->unicastAddr;
+		if (netPath->unicastAddr) {
+			addr.sin_addr.s_addr = netPath->unicastAddr;
 		} else {
 			addr.sin_addr.s_addr = alt_dst;
 		}
-
-
-		ret = sendto(netPath->generalSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error sending uni-cast general message\n");
+		ret = sendMessage(netPath->eventSock, buf, length,
+                      (struct sockaddr *)&addr, sizeof(addr),
+                      "unicast general");
 	} else {
 		addr.sin_addr.s_addr = netPath->multicastAddr;
+		ret = sendMessage(netPath->generalSock, buf, length,
+                      (struct sockaddr *)&addr, sizeof(addr),
+                      "multicast general");
+	}
 
-		ret = sendto(netPath->generalSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error sending multi-cast general message\n");
-	}
 	return ret;
 }
 
-ssize_t 
+int 
 netSendPeerGeneral(Octet * buf, UInteger16 length, NetPath * netPath)
 {
 
-	ssize_t ret;
+	int ret;
 	struct sockaddr_in addr;
 
 	addr.sin_family = AF_INET;
@@ -1048,64 +1575,52 @@
 	if (netPath->unicastAddr) {
 		addr.sin_addr.s_addr = netPath->unicastAddr;
 
-		ret = sendto(netPath->generalSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error sending uni-cast general message\n");
-
+		ret = sendMessage(netPath->eventSock, buf, length,
+                      (struct sockaddr *)&addr, sizeof(addr),
+                      "unicast general");
 	} else {
 		addr.sin_addr.s_addr = netPath->peerMulticastAddr;
 
-		ret = sendto(netPath->generalSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error sending multi-cast general message\n");
+		ret = sendMessage(netPath->generalSock, buf, length,
+                      (struct sockaddr *)&addr, sizeof(addr),
+                      "multicast general");
 	}
 	return ret;
 
 }
 
-ssize_t 
-netSendPeerEvent(Octet * buf, UInteger16 length, NetPath * netPath)
+int
+netSendPeerEvent(Octet * buf, UInteger16 length, PtpClock * ptpClock, RunTimeOpts * rtOpts)
 {
-	ssize_t ret;
+	int ret;
 	struct sockaddr_in addr;
+	NetPath *netPath = &ptpClock->netPath;
 
 	addr.sin_family = AF_INET;
 	addr.sin_port = htons(PTP_EVENT_PORT);
 
 	if (netPath->unicastAddr) {
 		addr.sin_addr.s_addr = netPath->unicastAddr;
-
-		ret = sendto(netPath->eventSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error sending uni-cast event message\n");
-
-		/* 
-		 * Need to forcibly loop back the packet since
-		 * we are not using multicast. 
-		 */
-		addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-		
-		ret = sendto(netPath->eventSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error looping back uni-cast event message\n");			
+		ret = sendMessage(netPath->eventSock, buf, length,
+                      (struct sockaddr *)&addr, sizeof(addr),
+                      "unicast event");
 	} else {
 		addr.sin_addr.s_addr = netPath->peerMulticastAddr;
+		ret = sendMessage(netPath->eventSock, buf, length,
+                      (struct sockaddr *)&addr, sizeof(addr),
+                      "multicast event");
+	}
 
-		ret = sendto(netPath->eventSock, buf, length, 0, 
-			     (struct sockaddr *)&addr, 
-			     sizeof(struct sockaddr_in));
-		if (ret <= 0)
-			DBG("error sending multi-cast event message\n");
-	}
-	return ret;
+  /* @pdelay_req TODO timestamp is not being collected when PDELAY_REQ messages */
+  /* are sent. Collect the timestamp and throw it away for now */
+  if (ret == 0) {
+    if (txTimestamp(ptpClock, buf, length, rtOpts->time_mode, FALSE) != 0) {
+      ERROR("txTimestamp failed\n");
+      ret = ENOTIMESTAMP;
+    }
+  }
+
+  return ret;
 }
 
 
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/ptpd_dep.h
--- a/src/dep/ptpd_dep.h	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/ptpd_dep.h	Sun Oct 27 22:49:29 2013 -0700
@@ -1,9 +1,39 @@
+/*-
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
+ *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
+ * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /**
  * @file   ptpd_dep.h
- * 
+ *
  * @brief  External definitions for inclusion elsewhere.
- * 
- * 
+ *
+ *
  */
 
 #ifndef PTPD_DEP_H_
@@ -43,12 +73,12 @@
 #define EMERGENCY(x, ...) message(LOG_EMERG, x, ##__VA_ARGS__)
 #define ALERT(x, ...)     message(LOG_ALERT, x, ##__VA_ARGS__)
 #define CRITICAL(x, ...)  message(LOG_CRIT, x, ##__VA_ARGS__)
-#define ERROR(x, ...)  message(LOG_ERR, x, ##__VA_ARGS__)
+#define ERROR(x, ...)     message(LOG_ERR, x, ##__VA_ARGS__)
 #define PERROR(x, ...)    message(LOG_ERR, x "      (strerror: %m)\n", ##__VA_ARGS__)
 #define WARNING(x, ...)   message(LOG_WARNING, x, ##__VA_ARGS__)
-#define NOTIFY(x, ...) message(LOG_NOTICE, x, ##__VA_ARGS__)
+#define NOTIFY(x, ...)    message(LOG_NOTICE, x, ##__VA_ARGS__)
 #define NOTICE(x, ...)    message(LOG_NOTICE, x, ##__VA_ARGS__)
-#define INFO(x, ...)   message(LOG_INFO, x, ##__VA_ARGS__)
+#define INFO(x, ...)      message(LOG_INFO, x, ##__VA_ARGS__)
 
 
 
@@ -90,7 +120,6 @@
 #undef PTPD_DBG2
 #define PTPD_DBG
 #define PTPD_DBG2
-
 #define DBGV(x, ...) message(LOG_DEBUGV, x, ##__VA_ARGS__)
 #else
 #define DBGV(x, ...)
@@ -116,6 +145,12 @@
 #define DBG(x, ...)
 #endif
 
+#ifdef PTPD_DUMP
+#define DUMP(text, addr, len) dump(text, addr, len)
+#else
+#define DUMP(text, addr, len)
+#endif
+
 /** \}*/
 
 /** \name Endian corrections*/
@@ -179,7 +214,7 @@
 void msgUnpackManagement(Octet * buf,MsgManagement*);
 UInteger8 msgUnloadManagement(Octet * buf,MsgManagement*,PtpClock*,RunTimeOpts*);
 void msgUnpackManagementPayload(Octet *buf, MsgManagement *manage);
-void msgPackHeader(Octet * buf,PtpClock*);
+void msgPackHeader(Octet * buf,PtpClock*,unsigned int);
 void msgPackAnnounce(Octet * buf,PtpClock*);
 void msgPackSync(Octet * buf,Timestamp*,PtpClock*);
 void msgPackFollowUp(Octet * buf,Timestamp*,PtpClock*);
@@ -211,13 +246,14 @@
 Boolean netInit(NetPath*,RunTimeOpts*,PtpClock*);
 Boolean netShutdown(NetPath*);
 int netSelect(TimeInternal*,NetPath*);
-ssize_t netRecvEvent(Octet*,TimeInternal*,NetPath*);
-ssize_t netRecvGeneral(Octet*,TimeInternal*,NetPath*);
-ssize_t netSendEvent(Octet*,UInteger16,NetPath*, Integer32 );
-ssize_t netSendGeneral(Octet*,UInteger16,NetPath*, Integer32 );
-ssize_t netSendPeerGeneral(Octet*,UInteger16,NetPath*);
-ssize_t netSendPeerEvent(Octet*,UInteger16,NetPath*);
+ssize_t netRecvEvent(Octet*,TimeInternal*,PtpClock*,RunTimeOpts*,Boolean*);
+ssize_t netRecvGeneral(Octet*,TimeInternal*,PtpClock *, RunTimeOpts *);
 
+/* These functions all return 0 for success or an errno in the case of failure */
+int netSendEvent(Octet*,UInteger16,PtpClock*,RunTimeOpts*,Integer32);
+int netSendGeneral(Octet*,UInteger16,NetPath*,Integer32);
+int netSendPeerGeneral(Octet*,UInteger16,NetPath*);
+int netSendPeerEvent(Octet*,UInteger16,PtpClock*,RunTimeOpts*);
 Boolean netRefreshIGMP(NetPath *, RunTimeOpts *, PtpClock *);
 
 
@@ -234,7 +270,7 @@
   offset_from_master_filter*,RunTimeOpts*,PtpClock*,TimeInternal*);
 void updateClock(RunTimeOpts*,PtpClock*);
 
-void servo_perform_clock_step(RunTimeOpts * rtOpts, PtpClock * ptpClock);
+void servo_perform_clock_step(RunTimeOpts * rtOpts, PtpClock * ptpClock, TimeInternal*);
 
 /** \}*/
 
@@ -267,19 +303,110 @@
 
 
 void message(int priority, const char *format, ...);
+void dump(const char *text, void *addr, int len);
 void displayStats(RunTimeOpts *rtOpts, PtpClock *ptpClock);
 Boolean nanoSleep(TimeInternal*);
-void getTime(TimeInternal*);
-void setTime(TimeInternal*);
 double getRand(void);
-Boolean adjFreq(Integer32);
 
 void recordSync(RunTimeOpts * rtOpts, UInteger16 sequenceId, TimeInternal * time);
+/** \}*/
+
+/** \name time.c (Unix API dependent)
+ * -Timing system API*/
+ /**\{*/
+Boolean initTime(RunTimeOpts*, PtpClock*);
+void shutdownTime(PtpClock*);
+void getTime(TimeInternal*, TimeMode, PtpClock*);
+void setTime(TimeInternal*, TimeMode, PtpClock*);
+void syncSystemWithNIC(RunTimeOpts *rtOpts, PtpClock *ptpClock);
+
+/**
+ * Adjusts the time, ideally by varying the clock rate.
+ *
+ * @param adj      frequency adjustment: a time source which supports that ignores the offset
+ */
+void adjTime(LongDouble adj, TimeMode timeMode, PtpClock*);
+
+/**
+ * Adjusts the time by shifting the clock.
+ *
+ * @param offset   this value must be substracted from clock (might be negative)
+ */
+void adjTimeOffset(TimeInternal *offset, TimeMode timeMode, PtpClock*);
+
+/**
+ * Adjusts the time by shifting the clock to insert a leap second
+ */
+void adjTimeInsertLeapSecond(TimeMode timeMode, RunTimeOpts*, PtpClock*);
+
+/**
+ * Adjusts the time by shifting the clock to delete a leap second
+ */
+void adjTimeDeleteLeapSecond(TimeMode timeMode, RunTimeOpts*, PtpClock*);
+
+/**
+ * Gets the time when the latest outgoing packet left the host.
+ *
+ * There is no way to identify the packet the time stamp belongs to,
+ * so this must be called after sending each packet until the time
+ * stamp for the packet is available. This can be some (hopefully
+ * small) time after the packet was passed to the IP stack.
+ *
+ * There is no mechanism either to determine packet loss and thus a
+ * time stamp which never becomes available.
+ *
+ * @todo Can such packet loss occur?
+ *
+ * Does not work with TIME_SYSTEM.
+ *
+ * @retval sendTimeStamp    set to the time when the packet left the host
+ * @return TRUE if the time stamp was available
+ */
+Boolean getSendTime(TimeInternal *sendTimeStamp, TimeMode, NetPath*);
+
+/**
+ * Gets the time when the packet identified by the given attributes
+ * was received by the host.
+ *
+ * Because the arrival of packets is out of the control of PTPd, the
+ * time stamping must support unique identification of which time
+ * stamp belongs to which packet.
+ *
+ * Due to packet loss in the receive queue, there can be time stamps
+ * without IP packets. getReceiveTime() automatically discards stale
+ * time stamps, including the ones that where returned by
+ * getReceiveTime(). This implies that there is not guarantee that
+ * calling getReceiveTime() more than once for the same packet
+ * will always return a result.
+ *
+ * Due to hardware limitations only one time stamp might be stored
+ * until queried by the NIC driver; this can lead to packets without
+ * time stamp. This needs to be handled by the caller of
+ * getReceiveTime(), for example by ignoring the packet.
+ *
+ * Does not work with TIME_SYSTEM.
+ *
+ * @retval recvTimeStamp    set to the time when the packet entered the host, if available
+ * @return TRUE if the time stamp was available
+ */
+Boolean getReceiveTime(TimeInternal *recvTimeStamp,
+                       ClockIdentity clockIdentity,
+                       UInteger16 sequenceId, TimeMode, NetPath*);
+
+long get_current_tickrate(void);
+
 
 #if defined(__APPLE__)
 void 	adjTime(Integer32);
 #endif /* __APPLE__ */
 
+#if !defined(__APPLE__)
+void setTimexFlags(int flags, Boolean quiet);
+void unsetTimexFlags(int flags, Boolean quiet);
+int getTimexFlags(void);
+Boolean checkTimexFlags(int flags);
+#endif /* apple */
+
 /** \}*/
 
 /** \name timer.c (Unix API dependent)
@@ -297,6 +424,9 @@
 void timerStart_random(UInteger16 index, float interval, IntervalTimer * itimer);
 
 Boolean timerExpired(UInteger16,IntervalTimer*);
+
+/** gets the current system time */
+void timerNow(TimeInternal*);
 /** \}*/
 
 
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/servo.c
--- a/src/dep/servo.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/servo.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,6 @@
 /*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
@@ -69,8 +71,8 @@
 #if !defined(__APPLE__)
 
 	if (!rtOpts->noAdjust)
-		adjFreq(0);
-	ptpClock->observed_drift = 0;
+		adjTime(0, rtOpts->time_mode, ptpClock);
+	ptpClock->observed_drift = 0.0;
 #endif /* apple */
 
 
@@ -85,10 +87,8 @@
 
 	ptpClock->ofm_filt.y           = 0;
 	ptpClock->ofm_filt.nsec_prev   = -1; /* AKB: -1 used for non-valid nsec time */
-	ptpClock->ofm_filt.nsec_prev   = 0;
-
 	ptpClock->owd_filt.s_exp       = 0;  /* clears one-way delay filter */
-	rtOpts->offset_first_updated   = FALSE;
+	ptpClock->offset_first_updated   = FALSE;
 
 	ptpClock->char_last_msg='I';
 
@@ -105,6 +105,10 @@
 void 
 updateDelay(one_way_delay_filter * owd_filt, RunTimeOpts * rtOpts, PtpClock * ptpClock, TimeInternal * correctionField)
 {
+	/* updates paused, leap second pending - do nothing */
+        if(ptpClock->leapSecondInProgress)
+		return;
+
 	/* todo: do all intermediate calculations on temp vars */
 	TimeInternal prev_meanPathDelay = ptpClock->meanPathDelay;
 
@@ -121,31 +125,41 @@
 	/* calc 'slave_to_master_delay' */
 	subTime(&slave_to_master_delay, &ptpClock->delay_req_receive_time, 
 		&ptpClock->delay_req_send_time);
-
+/*
 	if (slave_to_master_delay.nanoseconds < 0) {
-		INFO("updateDelay aborted, delay %d is negative",
+		INFO("updateDelay aborted, delay %d is negative\n",
 		     slave_to_master_delay.nanoseconds);
 		return;
 	}
+*/
 
-	if (rtOpts->maxDelay) { /* If maxDelay is 0 then it's OFF */
-		if (slave_to_master_delay.seconds && rtOpts->maxDelay) {
+	/* If maxDelay is 0 then it's OFF */
+	if ((rtOpts->maxDelay.seconds || rtOpts->maxDelay.nanoseconds) &&
+	    ptpClock->offset_first_updated) {
+		if (slave_to_master_delay.seconds) {
 			INFO("updateDelay aborted, delay greater than 1"
-			     " second.");
+			     " second.\n");
 			msgDump(ptpClock);
 				goto display;
 		}
-
-		if (slave_to_master_delay.nanoseconds > rtOpts->maxDelay) {
-			INFO("updateDelay aborted, delay %d greater than "
-			     "administratively set maximum %d\n",
-			     slave_to_master_delay.nanoseconds, 
-			     rtOpts->maxDelay);
+		/* Get scalar versions of the the slave to master delay and
+		 * max delay */
+		int64_t s_to_m_delay = internalTime_to_scalar(&slave_to_master_delay);
+		int64_t max_delay = internalTime_to_scalar(&rtOpts->maxDelay);
+		
+		if ((s_to_m_delay > max_delay) ||
+		    (s_to_m_delay < -max_delay)) {
+			INFO("updateDelay aborted, s->m delay %d.%09d greater than "
+			     "administratively set maximum %d.%09d\n",
+			     slave_to_master_delay.seconds,
+			     slave_to_master_delay.nanoseconds,
+			     rtOpts->maxDelay.seconds,
+			     rtOpts->maxDelay.nanoseconds);
 			msgDump(ptpClock);
 				goto display;
-			}
 		}
 	}
+	}
 
 
 	/*
@@ -153,7 +167,7 @@
 	 *   - update the global delaySM variable
 	 *   - calculate a new filtered MPD
 	 */
-	if (rtOpts->offset_first_updated) {
+	if (ptpClock->offset_first_updated) {
 		Integer16 s;
 
 		/*
@@ -313,6 +327,12 @@
 updateOffset(TimeInternal * send_time, TimeInternal * recv_time,
     offset_from_master_filter * ofm_filt, RunTimeOpts * rtOpts, PtpClock * ptpClock, TimeInternal * correctionField)
 {
+	DBGV("UTCOffset: %d, %d | leap 59: %d |  leap61: %d\n", 
+	     ptpClock->currentUtcOffsetValid, ptpClock->currentUtcOffset,
+	     ptpClock->leap59, ptpClock->leap61);
+        /* updates paused, leap second pending - do nothing */
+        if(ptpClock->leapSecondInProgress)
+		return;
 
 	DBGV("==> updateOffset\n");
 
@@ -322,19 +342,24 @@
 	/* calc 'master_to_slave_delay' */
 	subTime(&master_to_slave_delay, recv_time, send_time);
 
-	if (rtOpts->maxDelay) { /* If maxDelay is 0 then it's OFF */
-		if (master_to_slave_delay.seconds && rtOpts->maxDelay) {
-			INFO("updateOffset aborted, delay greater than 1"
-			     " second.");
-			msgDump(ptpClock);
-			return;
-		}
 
-		if (master_to_slave_delay.nanoseconds > rtOpts->maxDelay) {
-			INFO("updateOffset aborted, delay %d greater than "
-			     "administratively set maximum %d\n",
-			     master_to_slave_delay.nanoseconds, 
-			     rtOpts->maxDelay);
+	
+	/* If maxDelay is 0 then it's OFF */
+	if ((rtOpts->maxDelay.seconds || rtOpts->maxDelay.nanoseconds) &&
+	    ptpClock->offset_first_updated) {
+		/* Get scalar versions of the the slave to master delay and
+		 * max delay */
+		int64_t m_to_s_delay = internalTime_to_scalar(&master_to_slave_delay);
+		int64_t max_delay = internalTime_to_scalar(&rtOpts->maxDelay);
+		
+		if ((m_to_s_delay > max_delay) ||
+		    (m_to_s_delay < -max_delay)) {
+			INFO("updateDelay aborted, m->s delay %d.%09d greater than "
+			     "administratively set maximum %d.%09d\n",
+			     master_to_slave_delay.seconds,
+			     master_to_slave_delay.nanoseconds,
+			     rtOpts->maxDelay.seconds,
+			     rtOpts->maxDelay.nanoseconds);
 			msgDump(ptpClock);
 			return;
 		}
@@ -344,6 +369,13 @@
 	ptpClock->char_last_msg='S';
 	ptpClock->last_packet_was_sync = TRUE;
 
+	DBGV("send_time = %d.%09d\n",
+	     send_time->seconds, send_time->nanoseconds);
+	DBGV("recv_time = %d.%09d\n",
+             recv_time->seconds, recv_time->nanoseconds);
+	DBGV("master_to_slave_delay = %d.%09d\n",
+	     master_to_slave_delay.seconds, master_to_slave_delay.nanoseconds);
+
 	/*
 	 * The packet has passed basic checks, so we'll:
 	 *   - update the global delayMS variable
@@ -355,14 +387,21 @@
 	/* Take care about correctionField */
 	subTime(&ptpClock->delayMS,
 		&ptpClock->delayMS, correctionField);
+	DBGV("delayMS = %d.%09d\n",
+	     ptpClock->delayMS.seconds, ptpClock->delayMS.nanoseconds);
+	DBGV("correctionField = %d.%09d\n",
+	     correctionField->seconds, correctionField->nanoseconds);
+	DBGV("meanPathDelay = %d.%09d\n",
+	     ptpClock->meanPathDelay.seconds, ptpClock->meanPathDelay.nanoseconds);
 
 
+	DBGV("updateOffset: delayMechanism = %d\n", ptpClock->delayMechanism);
 	/* update 'offsetFromMaster' */
 	if (ptpClock->delayMechanism == P2P) {
 		subTime(&ptpClock->offsetFromMaster, 
 			&ptpClock->delayMS, 
 			&ptpClock->peerMeanPathDelay);
-	} else if (ptpClock->delayMechanism == E2E) {
+	} else {
 		/* (End to End mode) */
 		subTime(&ptpClock->offsetFromMaster, 
 			&ptpClock->delayMS, 
@@ -372,13 +411,16 @@
 	if (ptpClock->offsetFromMaster.seconds) {
 		/* cannot filter with secs, clear filter */
 		ofm_filt->nsec_prev = 0;
-		rtOpts->offset_first_updated = TRUE;
+		ptpClock->offset_first_updated = TRUE;
 		return;
 	}
 
 	/* filter 'offsetFromMaster' */
-	ofm_filt->y = ptpClock->offsetFromMaster.nanoseconds / 2 + 
-		ofm_filt->nsec_prev / 2;
+	/* The time is normalised so the nanoseconds will be less than 10^9. Improve
+	 * accuracy of calculation by doing division after addition. Add 1 to get correct
+	 * rounding.
+	 */
+	ofm_filt->y = (ptpClock->offsetFromMaster.nanoseconds + ofm_filt->nsec_prev + 1) / 2;
 	ofm_filt->nsec_prev = ptpClock->offsetFromMaster.nanoseconds;
 	ptpClock->offsetFromMaster.nanoseconds = ofm_filt->y;
 
@@ -388,41 +430,44 @@
 	 * Offset must have been computed at least one time before 
 	 * computing end to end delay
 	 */
-		rtOpts->offset_first_updated = TRUE;
+		ptpClock->offset_first_updated = TRUE;
 	}
 
 
 
-void servo_perform_clock_step(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+void servo_perform_clock_step(RunTimeOpts * rtOpts, PtpClock * ptpClock, TimeInternal *offset)
 {
 	if(rtOpts->noAdjust){
 		WARNING("     Clock step blocked because of option -t\n");
 		return;
 	}
 
-	TimeInternal timeTmp;
-	
-	getTime(&timeTmp);
-	subTime(&timeTmp, &timeTmp, &ptpClock->offsetFromMaster);
+	WARNING("performing hard frequency reset, by setting frequency to zero\n");
+	/* In our driver, stepping the time also has the effect of setting the frequency */
+	/* adjustment to zero. */
+	 adjTimeOffset(offset, rtOpts->time_mode, ptpClock);
+	ptpClock->observed_drift = 0.0;
 
-	WARNING("     Performing hard frequency reset, by setting frequency to zero\n");
-	adjFreq(0);
-	ptpClock->observed_drift = 0;
-
-	setTime(&timeTmp);
 	initClock(rtOpts, ptpClock);
-	toState(PTP_FAULTY, rtOpts, ptpClock);		/* make a full protocol reset */
 }
 
 
-void warn_operator_fast_slewing(RunTimeOpts * rtOpts, PtpClock * ptpClock, Integer32 adj)
+void warn_operator_fast_slewing(RunTimeOpts * rtOpts, PtpClock * ptpClock, LongDouble adj)
 {
-	if(ptpClock->warned_operator_fast_slewing == 0){
-		if ((adj >= ADJ_FREQ_MAX) || ((adj <= -ADJ_FREQ_MAX))){
+	LongDouble max_adj;
+	if ((rtOpts->time_mode == TIME_NIC) || (rtOpts->time_mode == TIME_BOTH))
+		max_adj = ADJ_FREQ_MAX_NIC;
+	else
+		max_adj = ADJ_FREQ_MAX_SYSTEM;
+	
+	if ((adj >= max_adj) || (adj <= -max_adj)) {
+		if(ptpClock->warned_operator_fast_slewing == 0) {
 			ptpClock->warned_operator_fast_slewing = 1;
 
 			NOTICE("Servo: Going to slew the clock with the maximum frequency adjustment\n");
 		}
+	} else {
+		ptpClock->warned_operator_fast_slewing = 0;
 	}
 
 }
@@ -436,9 +481,10 @@
 		/* rule of thumb: at tick rate 10000, slewing at the maximum speed took 0.5ms per second */
 		float estimated = (((abs(ptpClock->offsetFromMaster.seconds)) + 0.0) * 2.0 * 1000.0 / 3600.0);
 
-
-		ALERT("Servo: %d seconds offset detected, will take %.1f hours to slew\n",
+		// we don't want to arrive early 1s in an expiration opening, so all consoles get a message when the time is 1s off.
+		ALERT("Servo: %d.%09d seconds offset detected, will take %.1f hours to slew\n",
 			ptpClock->offsetFromMaster.seconds,
+			ptpClock->offsetFromMaster.nanoseconds,
 			estimated
 		);
 		
@@ -447,22 +493,25 @@
 
 
 /*
- * this is a wrapper around adjFreq to abstract extra operations
+ * this is a wrapper around adjTime to abstract extra operations
  */
-void adjFreq_wrapper(RunTimeOpts * rtOpts, PtpClock * ptpClock, Integer32 adj)
+void adjTime_wrapper(RunTimeOpts * rtOpts, PtpClock * ptpClock, LongDouble adj)
 {
 
 
    
 	if (rtOpts->noAdjust){
-		DBGV("adjFreq2: noAdjust on, returning\n");
+		DBGV("adjTime_wrapper: noAdjust on, returning\n");
 		return;
 	}
 
+	// go back to only sending delayreq after first sync
+	// otherwise we lose the first sync always
+	// test all combinations
 
 	// call original adjtime
-	DBG2("     adjFreq2: call adjfreq to %d us \n", adj / DBG_UNIT);
-	adjFreq(adj);
+	DBG2("     adjTime_wrapper: call adjTime to %d \n", adj);
+	adjTime(adj, rtOpts->time_mode, ptpClock);
 
 	warn_operator_fast_slewing(rtOpts, ptpClock, adj);
 
@@ -475,8 +524,11 @@
 void 
 updateClock(RunTimeOpts * rtOpts, PtpClock * ptpClock)
 {
-	Integer32 adj;
-	//TimeInternal timeTmp;
+    LongDouble adj;
+
+	/* updates paused, leap second pending - do nothing */
+        if(ptpClock->leapSecondInProgress)
+            return;
 
 	DBGV("==> updateClock\n");
 
@@ -514,26 +566,31 @@
 		/*
 		 * noAdjust     = cannot do any change to clock
 		 * noResetClock = if can change the clock, can we also step it?
+		 * resetClockOnlyOnce = can only step clock on first update
 		 */
 		if (!rtOpts->noAdjust) {
 			/* */
-			if (!rtOpts->noResetClock) {
+			if (!rtOpts->noResetClock &&
+			    (!rtOpts->resetClockStartupOnly || !ptpClock->clock_first_updated)) {
 
-				servo_perform_clock_step(rtOpts, ptpClock);
+				servo_perform_clock_step(rtOpts, ptpClock, &ptpClock->offsetFromMaster);
 			} else {
 				/*
 				 * potential problem:    "-1.1" is   a) -1:0.1 or b) -1:-0.1?
 				 * if this code is right it implies the second case
 				 */
 #if !defined(__APPLE__)
-				adj = ptpClock->offsetFromMaster.nanoseconds
-					> 0 ? ADJ_FREQ_MAX : -ADJ_FREQ_MAX;
-
-				// does this hurt when the clock gets close to zero again?
-				ptpClock->observed_drift = adj;
+				LongDouble max_adj;
+				if ((rtOpts->time_mode == TIME_NIC) || (rtOpts->time_mode == TIME_BOTH))
+					max_adj = ADJ_FREQ_MAX_NIC;
+				else
+					max_adj = ADJ_FREQ_MAX_SYSTEM;
+				
+				adj = (ptpClock->offsetFromMaster.nanoseconds > 0.0)?
+					max_adj : -max_adj;
 
 				warn_operator_slow_slewing(rtOpts, ptpClock);
-				adjFreq_wrapper(rtOpts, ptpClock, -adj);
+				adjTime_wrapper(rtOpts, ptpClock, -adj);
 
 				/* its not clear how the APPLE case works for large jumps */
 #endif /* __APPLE__ */
@@ -541,14 +598,18 @@
 			}
 		}
 	} else {
+		LongDouble max_adj;
 		/* these variables contain the actual ai and ap to be used below */
 		Integer32 ap = rtOpts->ap;
 		Integer32 ai = rtOpts->ai;
 
+		/* Clear the slow slewing warning so that it will be re-issued if
+		 * another large offset occurs */
+		ptpClock->warned_operator_slow_slewing = 0;
+	
 
 		
 
-		
 		/* the PI controller */
 		/* Offset from master is less than one second.  Use the the PI controller
 		 * to adjust the time
@@ -561,44 +622,48 @@
 			ai = 1;
 
 
+		/*
+		 *  optional new PI controller, with better accuracy with HW-timestamps:
+		 *  http://sourceforge.net/tracker/?func=detail&aid=2995791&group_id=139814&atid=744632
+		 */
 
 		
 		/* the accumulator for the I component */
 		// original PI servo
 		ptpClock->observed_drift += 
-			ptpClock->offsetFromMaster.nanoseconds / ai;
+			(LongDouble)ptpClock->offsetFromMaster.nanoseconds / (LongDouble)ai;
 
-		// ADJ_FREQ_MAX: 512 000
+		if ((rtOpts->time_mode == TIME_NIC) || (rtOpts->time_mode == TIME_BOTH))
+			max_adj = ADJ_FREQ_MAX_NIC;
+		else
+			max_adj = ADJ_FREQ_MAX_SYSTEM;
+		
+		/* clamp the accumulator to ADJ_FREQ_MAX for sanity */
+		if (ptpClock->observed_drift > max_adj)
+			ptpClock->observed_drift = max_adj;
+		else if (ptpClock->observed_drift < -max_adj)
+			ptpClock->observed_drift = -max_adj;
 
-		/* clamp the accumulator to ADJ_FREQ_MAX for sanity */
-		if (ptpClock->observed_drift > ADJ_FREQ_MAX)
-			ptpClock->observed_drift = ADJ_FREQ_MAX;
-		else if (ptpClock->observed_drift < -ADJ_FREQ_MAX)
-			ptpClock->observed_drift = -ADJ_FREQ_MAX;
-
-		adj = ptpClock->offsetFromMaster.nanoseconds / ap +
+		adj = (LongDouble)ptpClock->offsetFromMaster.nanoseconds / (LongDouble)ap +
 			ptpClock->observed_drift;
 
-		DBG("     Observed_drift with AI component: %d\n",
-			ptpClock->observed_drift  );
+		DBG("     Observed_drift with AI component: %Lf\n",
+			 ptpClock->observed_drift);
 
-		DBG("     After PI: Adj: %d   Drift: %d   OFM %d\n",
+		DBG("     After PI: Adj: %Lf   Drift: %Lf   OFM %d\n",
 			adj, ptpClock->observed_drift , ptpClock->offsetFromMaster.nanoseconds);
 
-
-		DBG2("     Observed_drift with AI component: %d\n",
-			ptpClock->observed_drift / DBG_UNIT );
-
-		DBG2("     After PI: Adj: %d   Drift: %d   OFM %d\n",
-			adj, ptpClock->observed_drift / DBG_UNIT, ptpClock->offsetFromMaster.nanoseconds / DBG_UNIT);
-
 #if defined(__APPLE__)
-			adjTime(ptpClock->offsetFromMaster.nanoseconds);
+			adjTime((LongDouble)ptpClock->offsetFromMaster.nanoseconds);
 #else
-		adjFreq_wrapper(rtOpts, ptpClock, -adj);
+		adjTime_wrapper(rtOpts, ptpClock, -adj);
 #endif /* __APPLE__ */
 	}
 
+	/* If we get here, the clock has been updated. Used to enable syncing of
+	 * second servo in time both mode.
+	 */
+	ptpClock->clock_first_updated = TRUE;
 
 
 display:
@@ -625,6 +690,6 @@
 	DBGV("offset from master:      %10ds %11dns\n",
 	    ptpClock->offsetFromMaster.seconds, 
 	    ptpClock->offsetFromMaster.nanoseconds);
-	DBGV("observed drift:          %10d\n", ptpClock->observed_drift);
+	DBGV("observed drift:          %Lf\n", ptpClock->observed_drift);
 }
 
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/sfxge_ioctl.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dep/sfxge_ioctl.h	Sun Oct 27 22:49:29 2013 -0700
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ */
+/****************************************************************************
+ * Driver for Solarflare network controllers
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * Copyright 2005-2006: Fen Systems Ltd.
+ * Copyright 2006-2010: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Initially developed by Michael Brown <[email protected]>
+ * Maintained by Solarflare Communications <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef SFXGE_IOCTL_H
+#define SFXGE_IOCTL_H
+
+#include <sys/sockio.h>
+#define __u8	uint8_t
+#define __u16   uint16_t
+#define __u32   uint32_t
+#define __u64   uint64_t
+#define __s8	int8_t
+#define __s16	int16_t
+#define __s32	int32_t
+#define __s64	int64_t
+
+#define SFXGE_IOC	('S' << 24 | 'F' << 16 | 'C' << 8)
+
+#define SFXGE_TS_INIT		(SFXGE_IOC | 0x12)
+#define SFXGE_TS_READ		(SFXGE_IOC | 0x13)
+#define SFXGE_TS_SETTIME	(SFXGE_IOC | 0x14)
+#define SFXGE_TS_ADJTIME	(SFXGE_IOC | 0x15)
+#define SFXGE_TS_SYNC		(SFXGE_IOC | 0x16)
+
+#define	SFXGE_DRV_VERSION1	1
+
+/* PTP support for NIC time disciplining ************************************/
+
+struct sfxge_timespec {
+	int64_t tv_sec;
+	int32_t	tv_nsec;
+};
+
+/* Initialise timestamping, like SIOCHWTSTAMP *******************************/
+
+enum {
+      	HWTSTAMP_TX_OFF,
+	HWTSTAMP_TX_ON,
+};
+
+enum {
+      	HWTSTAMP_FILTER_NONE,
+	HWTSTAMP_FILTER_ALL,
+	HWTSTAMP_FILTER_SOME,
+	HWTSTAMP_FILTER_PTP_V1_L4_EVENT,
+	HWTSTAMP_FILTER_PTP_V1_L4_SYNC,
+	HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ,
+	HWTSTAMP_FILTER_PTP_V2_L4_EVENT,
+	HWTSTAMP_FILTER_PTP_V2_L4_SYNC,
+	HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ,
+	HWTSTAMP_FILTER_PTP_V2_L2_EVENT,
+	HWTSTAMP_FILTER_PTP_V2_L2_SYNC,
+	HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ,
+	HWTSTAMP_FILTER_PTP_V2_EVENT,
+	HWTSTAMP_FILTER_PTP_V2_SYNC,
+	HWTSTAMP_FILTER_PTP_V2_DELAY_REQ,
+};
+
+struct sfxge_hwtstamp_config {
+	uint32_t drv_version;
+	uint32_t flags;
+	uint32_t tx_type;
+	uint32_t rx_filter;
+};
+
+/* Read any transmit or receive timestamps since the last call **************/
+
+struct sfxge_ts_read {
+	uint32_t tx_valid;
+	struct sfxge_timespec tx_ts;
+	struct sfxge_timespec tx_ts_hw;
+	uint32_t rx_valid;
+	struct sfxge_timespec rx_ts;
+	struct sfxge_timespec rx_ts_hw;
+	uint8_t uuid [6];
+	uint8_t seqid [2];
+};
+
+struct sfxge_ts_settime {
+        struct sfxge_timespec ts; /* In and out */
+        uint32_t iswrite;          /* 1 == write, 0 == read (only) */
+};
+
+struct sfxge_ts_adjtime {
+        int64_t adjustment;       /* Parts per billion, In and out */
+        uint32_t iswrite;          /* 1 == write, 0 == read (only) */
+};
+
+struct sfxge_ts_sync {
+        struct sfxge_timespec ts;
+};
+
+union sfxge_ioctl_data {
+	struct sfxge_hwtstamp_config ts_init;
+	struct sfxge_ts_read ts_read;
+	struct sfxge_ts_settime ts_settime;
+	struct sfxge_ts_adjtime ts_adjtime;
+	struct sfxge_ts_sync ts_sync;
+};
+
+struct sfxge_sock_ioctl {
+	uint32_t cmd;
+	uint16_t reserved;
+	union sfxge_ioctl_data u;
+};
+#endif /* SFXGE_IOCTL_H */
+
+
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/startup.c
--- a/src/dep/startup.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/startup.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,6 @@
 /*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
@@ -39,6 +41,8 @@
 
 #include "../ptpd.h"
 
+PtpClock *ptpClock;
+
 /*
  * valgrind 3.5.0 currently reports no errors (last check: 20110512)
  * valgrind 3.4.1 lacks an adjtimex handler
@@ -70,6 +74,10 @@
 volatile sig_atomic_t	 sighup_received  = 0;
 volatile sig_atomic_t	 sigusr1_received = 0;
 volatile sig_atomic_t	 sigusr2_received = 0;
+#ifdef DBG_SIGRTMIN_LEAP_SECOND
+volatile sig_atomic_t	 sigrtmin0_received = 0;
+volatile sig_atomic_t	 sigrtmin1_received = 0;
+#endif
 
 /*
  * Function to catch signals asynchronously.
@@ -79,31 +87,38 @@
  */
 void catch_signals(int sig)
 {
-	switch (sig) {
-	case SIGINT:
+  switch (sig) {
+  case SIGINT:
 		sigint_received = 1;
 		break;
-	case SIGTERM:
+  case SIGTERM:
 		sigterm_received = 1;
-		break;
-	case SIGHUP:
-		sighup_received = 1;
-		break;
-	case SIGUSR1:
-		sigusr1_received = 1;
-		break;
-	case SIGUSR2:
-		sigusr2_received = 1;
-		break;
-	default:
-		/*
-		 * TODO: should all other signals be catched, and handled as SIGINT?
-		 *
-		 * Reason: currently, all other signals are just uncatched, and the OS kills us.
-		 * The difference is that we could then close the open files properly.
-		 */
-		break;
-	}
+    break;
+  case SIGHUP:
+    sighup_received = 1;
+    break;
+  case SIGUSR1:
+    sigusr1_received = 1;
+    break;
+  case SIGUSR2:
+    sigusr2_received = 1;
+    break;
+  default:
+#ifdef DBG_SIGRTMIN_LEAP_SECOND
+    if (sig == SIGRTMIN + 0)
+      sigrtmin0_received = 1;
+    else if (sig == SIGRTMIN + 1)
+      sigrtmin1_received = 1;
+    else
+#endif
+      /*
+       * TODO: should all other signals be catched, and handled as SIGINT?
+       *
+       * Reason: currently, all other signals are just uncatched, and the OS kills us.
+       * The difference is that we could then close the open files properly.
+       */
+    break;
+  }
 }
 
 
@@ -119,12 +134,12 @@
 	exit(0);
 }
 
-/** 
+/**
  * Signal handler for HUP which tells us to swap the log file.
  * 
  * @param sig 
  */
-void 
+void
 do_signal_sighup(RunTimeOpts * rtOpts)
 {
 	if(rtOpts->do_record_quality_file)
@@ -135,7 +150,7 @@
 		if(!logToFile(rtOpts))
 			NOTIFY("SIGHUP logToFile failed\n");
 
-	NOTIFY("I've been SIGHUP'd\n");
+  NOTIFY("I've been SIGHUP'd\n");
 }
 
 
@@ -146,10 +161,10 @@
 void
 check_signals(RunTimeOpts * rtOpts, PtpClock * ptpClock)
 {
-	/*
-	 * note:
-	 * alarm signals are handled in a similar way in dep/timer.c
-	 */
+  /*
+  * note:
+  * alarm signals are handled in a similar way in dep/timer.c
+  */
 
 	if(sigint_received || sigterm_received){
 		do_signal_close(ptpClock);
@@ -158,42 +173,80 @@
 	if(sighup_received){
 		do_signal_sighup(rtOpts);
 	sighup_received=0;
+  }
+
+  if(sigusr1_received){
+    WARNING("SigUSR1 received, manually stepping clock to current known OFM\n");
+    /* If the time mode is time both then step the NIC clock and system clock.
+     * Do the time both clock first because this requires the clock to be stepped
+     * by the sum of the two servo's current offset and the offset is cleared by
+     * the clock step process */
+    if (rtOpts->time_mode == TIME_BOTH) {
+      TimeInternal offset;
+      extern PtpClock *G_timeBothClock;
+      extern RunTimeOpts *G_timeBothRtOpts;
+      addTime(&offset, &ptpClock->offsetFromMaster, &G_timeBothClock->offsetFromMaster);
+      servo_perform_clock_step(G_timeBothRtOpts, G_timeBothClock, &offset);
+    }
+    servo_perform_clock_step(rtOpts, ptpClock, &ptpClock->offsetFromMaster);
+  sigusr1_received = 0;
+  }
+
+
+#ifdef DBG_SIGUSR2_CHANGE_DOMAIN
+  if(sigusr2_received){
+    /* swap domain numbers */
+    static int prev_domain;
+    static int first_time = 1;
+    if(first_time){
+      first_time = 0;
+      prev_domain = ptpClock->domainNumber + 1;
+    }
+
+    int  temp = ptpClock->domainNumber;
+    ptpClock->domainNumber = prev_domain;
+    prev_domain = temp;
+
+
+    // propagate new choice as the run-time option
+    rtOpts->domainNumber = ptpClock->domainNumber;
+
+    WARNING("SigUSR2 received. PTP_Domain is now %d  (saved: %d)\n",
+      ptpClock->domainNumber,
+      prev_domain
+    );
+  sigusr2_received = 0;
+  }
+#endif
+
+
+#ifdef DBG_SIGRTMIN_LEAP_SECOND
+	if (sigrtmin0_received && (rtOpts->master_slave_mode != PTP_MODE_SLAVE)) {
+		ptpClock->leap61 = TRUE;
+		ptpClock->leap59 = FALSE;
+		timerStop(LEAP_SECOND_NOW_TIMER, ptpClock->itimer);
+		timerStart(LEAP_SECOND_NOW_TIMER,
+			   secondsToMidnight() + (float)ptpClock->currentUtcOffset,
+			   ptpClock->itimer);
+		
+		INFO("Signalling leap second 61 at end of current day\n");
+		sigrtmin0_received = 0;
 	}
 
-	if(sigusr1_received){
-		WARNING("SigUSR1 received, manually stepping clock to current known OFM\n");
-		servo_perform_clock_step(rtOpts, ptpClock);
-	sigusr1_received = 0;
-	}
+	if (sigrtmin1_received && (rtOpts->master_slave_mode != PTP_MODE_SLAVE)) {
+		ptpClock->leap59 = TRUE;
+		ptpClock->leap61 = FALSE;
+		
+		timerStop(LEAP_SECOND_NOW_TIMER, ptpClock->itimer);
+		timerStart(LEAP_SECOND_NOW_TIMER,
+			   secondsToMidnight() + (float)ptpClock->currentUtcOffset - 1.0,
+			   ptpClock->itimer);
 
-
-#ifdef DBG_SIGUSR2_CHANGE_DOMAIN
-	if(sigusr2_received){
-		/* swap domain numbers */
-		static int prev_domain;
-		static int first_time = 1;
-		if(first_time){
-			first_time = 0;
-			prev_domain = ptpClock->domainNumber + 1;
-		}
-
-		int  temp = ptpClock->domainNumber;
-		ptpClock->domainNumber = prev_domain;
-		prev_domain = temp;
-
-		
-		// propagate new choice as the run-time option
-		rtOpts->domainNumber = ptpClock->domainNumber;
-		
-		WARNING("SigUSR2 received. PTP_Domain is now %d  (saved: %d)\n",
-			ptpClock->domainNumber,
-			prev_domain
-		);
-		sigusr2_received = 0;
+		INFO("Signalling leap second 59 at end of current day\n");
+		sigrtmin1_received = 0;
 	}
 #endif
 
-		
 #ifdef DBG_SIGUSR2_CHANGE_DEBUG
 #ifdef RUNTIME_DEBUG
 	if(sigusr2_received){
@@ -242,8 +295,8 @@
 #include <sys/stat.h>
 #include <libgen.h>
 
-#define LOCKFILE "/var/run/kernel_clock"
-#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+#define LOCKFILE "/system/volatile/ptpd.pid"
+#define LOCKMODE (S_IRUSR|S_IWUSR)
 
 int global_lock_fd;
 
@@ -261,6 +314,31 @@
 	return(fcntl(fd, F_SETLK, &fl));
 }
 
+int
+get_owner_lockfile(int fd)
+{
+	struct flock fl;
+
+	fl.l_type = F_WRLCK;
+	fl.l_start = 0;
+	fl.l_whence = SEEK_SET;
+	fl.l_len = 0;
+	if (fcntl(fd, F_GETLK, &fl) == 0) {
+		return(fl.l_pid);
+	}
+	return 0;
+}
+
+int
+unlockfile(int fd) {
+	struct flock fl;
+
+	fl.l_type = F_UNLCK;
+	fl.l_start = 0;
+	fl.l_whence = SEEK_SET;
+	fl.l_len = 0;
+	return(fcntl(fd, F_SETLK, &fl));
+}
 
 /*
  * a discussion where the lock file should reside: http://rute.2038bug.com/node38.html.gz#SECTION003859000000000000000
@@ -268,33 +346,37 @@
 int
 daemon_already_running(void)
 {
-	char    buf[16];
+  char    buf[16];
+  int lpid;
 
 	INFO("  Info:    Going to check lock %s\n", LOCKFILE);
-	global_lock_fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
-	if (global_lock_fd < 0) {
-		syslog(LOG_ERR, "can't open %s: %s", LOCKFILE, strerror(errno));
-		PERROR("can't open %s: %s", LOCKFILE, strerror(errno));
-		exit(1);
-	}
-	if (lockfile(global_lock_fd) < 0) {
-		if (errno == EACCES || errno == EAGAIN) {
-			close(global_lock_fd);
-			return(1);
-		}
-		syslog(LOG_ERR, "can't lock %s: %s", LOCKFILE, strerror(errno));
-		PERROR("can't lock %s: %s", LOCKFILE, strerror(errno));
-		return(1);
-	}
-	ftruncate(global_lock_fd, 0);
-	sprintf(buf, "%ld\n", (long)getpid());
-	write(global_lock_fd, buf, strlen(buf)+1);
-	return(0);
+  global_lock_fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
+  if (global_lock_fd < 0) {
+    syslog(LOG_ERR, "can't open %s: %s", LOCKFILE, strerror(errno));
+    PERROR("can't open %s: %s", LOCKFILE, strerror(errno));
+    //ptpdShutdown(FALSE);
+    exit(1);
+  }
+  if (lockfile(global_lock_fd) < 0) {
+    if (errno == EACCES || errno == EAGAIN) {
+	lpid = get_owner_lockfile(global_lock_fd);
+	syslog(LOG_ERR, "%s locked by %d", LOCKFILE, lpid);
+	PERROR("%s locked by %d", LOCKFILE, lpid);
+      close(global_lock_fd);
+      return(1);
+    }
+    syslog(LOG_ERR, "can't lock %s: %s", LOCKFILE, strerror(errno));
+    PERROR("can't lock %s: %s", LOCKFILE, strerror(errno));
+    return(1);
+  }
+  ftruncate(global_lock_fd, 0);
+  sprintf(buf, "%ld\n", (long)getpid());
+  write(global_lock_fd, buf, strlen(buf)+1);
+  return(0);
 }
 
 
 
-
 int query_shell(char *command, char *answer, int answer_size);
 
 
@@ -310,14 +392,17 @@
 	char command[BUF_SIZE];
 	char answer[BUF_SIZE];
 	int matches;
+	int mypid;
 
-	snprintf(command, BUF_SIZE - 1, "pgrep -x %s | wc -l", name);
+	mypid = getpid();
+	snprintf(command, BUF_SIZE - 1, "pgrep -x %s | grep -v %d | wc -l", name, mypid);
 
 	if( query_shell(command, answer, BUF_SIZE) < 0){
 		return -1;
 	};
 	
 	sscanf(answer, "%d", &matches);
+
 	return (matches);
 }
 
@@ -333,32 +418,32 @@
  */
 int query_shell(char *command, char *answer, int answer_size)
 {
-	int status;
-	FILE *fp;
+  int status;
+  FILE *fp;
 
 	// clear previous answer
 	answer[0] = '\0';
 
 	fp = popen(command, "r");
-	if (fp == NULL){
+  if (fp == NULL){
 		PERROR("can't call  %s", command);
-		return -1;
-	};
+    return -1;
+  };
 
 	// get first line of popen
 	fgets(answer, answer_size - 1, fp);
 
 	DBG2("Query_shell: _%s_ -> _%s_\n", command, answer);
 
-	status = pclose(fp);
-	if (status == -1) {
-		PERROR("can't call pclose() ");
-		return -1;
-	} 
+  status = pclose(fp);
+  if (status == -1) {
+    PERROR("can't call pclose() ");
+    return -1;
+  }
 
-	/* from Man page:
-	     Use macros described under wait() to inspect `status' in order
-	     to determine success/failure of command executed by popen() */
+  /* from Man page:
+      Use macros described under wait() to inspect `status' in order
+      to determine success/failure of command executed by popen() */
 
 	return 0;
 }
@@ -375,38 +460,38 @@
 int
 check_parallel_daemons(char *name, int expected, int strict, RunTimeOpts * rtOpts)
 {
-	int matches = pgrep_matches(name);
+  int matches = pgrep_matches(name);
 
-	if(matches == expected){
-		if(!expected){
-			INFO(       "  Info:    No %s daemons detected in parallel (as expected)\n",
-				name );
-		} else {
-			INFO(       "  Info:    %d %s daemons detected in parallel (as expected)\n",
-				matches, name);
-		}
-		return 1;
+  if(matches == expected){
+	if(!expected){
+		INFO(       "  Info:    No %s daemons detected in parallel (as expected)\n",
+			name );
 	} else {
-		if(strict){
-			if(expected == 0){
-				ERROR(  "  Error:   %d %s daemon(s) detected in parallel, but we were not expecting any. Exiting.\n",
-				   matches, name);
-			} else {
-				ERROR(  "  Error:   %d %s daemon(s) detected in parallel, but we were expecting %d. Exiting.\n",
-				   matches, name, expected);
-			}
-			return 0;
-		} else {
-			if(!expected){
-				WARNING("  Warning: %d %s daemon(s) detected in parallel, but we were expected none. Continuing anyway.\n",
-				   matches, name);
-			} else {
-				WARNING("  Warning: %d %s daemon(s) detected in parallel, but we were expecting %d. Continuing anyway.\n",
-				   matches, name, expected);
-			}
-			return 1;
-		}
+		INFO(       "  Info:    %d %s daemons detected in parallel (as expected)\n",
+			matches, name);
 	}
+    return 1;
+  } else {
+    if(strict){
+	if(expected == 0){
+		ERROR(  "  Error:   %d %s daemon(s) detected in parallel, but we were not expecting any. Exiting.\n",
+		    matches, name);
+	} else {
+		ERROR(  "  Error:   %d %s daemon(s) detected in parallel, but we were expecting %d. Exiting.\n",
+          matches, name, expected);
+	}
+      return 0;
+    } else {
+	if(!expected){
+		WARNING("  Warning: %d %s daemon(s) detected in parallel, but we were expected none. Continuing anyway.\n",
+		   matches, name);
+	} else {
+		WARNING("  Warning: %d %s daemon(s) detected in parallel, but we were expecting %d. Continuing anyway.\n",
+            matches, name, expected);
+	}
+      return 1;
+    }
+  }
 }
 
 
@@ -417,28 +502,28 @@
 
 
 
-/** 
+/**
  * Log output to a file
  * 
  * 
  * @return True if success, False if failure
  */
-int 
+int
 logToFile(RunTimeOpts * rtOpts)
 {
 	if(rtOpts->logFd != -1)
 		close(rtOpts->logFd);
-	
 
-	/* We new append the file instead of replacing it. Also use mask 644 instead of 444 */
+
+  /* We new append the file instead of replacing it. Also use mask 644 instead of 444 */
 	if((rtOpts->logFd = open(rtOpts->file, O_CREAT | O_APPEND | O_RDWR, 0644 )) != -1) {
 		dup2(rtOpts->logFd, STDOUT_FILENO);
 		dup2(rtOpts->logFd, STDERR_FILENO);
-	}
+  }
 	return rtOpts->logFd != -1;
 }
 
-/** 
+/**
  * Record quality data for later correlation
  * 
  * 
@@ -451,63 +536,82 @@
 		fclose(rtOpts->recordFP);
 
 	if ((rtOpts->recordFP = fopen(rtOpts->recordFile, "w")) == NULL)
-		PERROR("could not open sync recording file");
-	else
+    PERROR("could not open sync recording file");
+  else
 		setlinebuf(rtOpts->recordFP);
 	return (rtOpts->recordFP != NULL);
 }
 
-void 
+void
 ptpdShutdown(PtpClock * ptpClock)
 {
-	netShutdown(&ptpClock->netPath);
+  shutdownTime(ptpClock);
+  netShutdown(&ptpClock->netPath);
 
-	
+
 	free(ptpClock->foreign);
 	free(ptpClock);
 
-	/* properly clean lockfile (eventough new deaemons can adquire the lock after we die) */
-	close(global_lock_fd);
-	unlink(LOCKFILE);
+#if 0
+  /* Don't call free if we are in the context of the signal handler */
+  if (!inSigHandler) {
+    free(ptpClock->foreign);
+    free(ptpClock);
+  }
+#endif
+
+  /* properly clean lockfile (even though new deaemons can acquire the lock after we die) */
+  close(global_lock_fd);
+  unlink(LOCKFILE);
 }
 
 void dump_command_line_parameters(int argc, char **argv)
 {
 	//
 	int i = 0;
-	char sbuf[1000];
-	char *st = sbuf;
-	int len = 0;
-	
-	*st = '\0';
-	for(i=0; i < argc; i++){
-		len += snprintf(sbuf + len,
-					     sizeof(sbuf) - len,
-					     "%s ", argv[i]);
+  char sbuf[1000];
+  char *st = sbuf;
+  int len = 0;
+
+  *st = '\0';
+  for(i=0; i < argc; i++){
+    if (len >= sizeof(sbuf)) {
+      ERROR("command line too long, %d\n", len);
+      return;
+    } else {
+      len += snprintf(sbuf + len,
+		      sizeof(sbuf) - len,
+		      "%s ", argv[i]);
+    }
+  }
+
+  INFO("\n");
+  INFO("Starting ptpd daemon with parameters:      %s\n", sbuf);
+}
+
+
+void
+display_short_help(char *msg, Boolean error)
+{
+	char *ermsg;
+	if (error) {
+		ermsg = "ERROR";
+	} else {
+		ermsg = "";
 	}
 
-	INFO("\n");
-	INFO("Starting ptpd2 daemon with parameters:      %s\n", sbuf);
-}
-
-
-void
-display_short_help(char *error)
-{
 	printf(
-			//"\n"
-			"ptpd2:\n"
-			"   -gGW          Protocol mode (slave/master with ntp/master without ntp)\n"
+			"ptpd:\n"
+			"   -gW          Protocol mode (slave/master)\n"
 			"   -b <dev>      Interface to use\n"
 			"\n"
 			"   -cC  -DVfS    Console / verbose console;     Dump stats / Interval / Output file / no Syslog\n"
 			"   -uU           Unicast/Hybrid mode\n"
 			"\n"
 			"\n"
-			"   -hHB           Summary / Complete help file / run-time debug level\n"
+			"   -?HB           Summary / Complete help file / run-time debug level\n"
 			"\n"
-			"ERROR: %s\n\n",
-			error
+			"%s %s\n\n", ermsg, msg
 		);
 }
 
@@ -517,166 +621,188 @@
 ptpdStartup(int argc, char **argv, Integer16 * ret, RunTimeOpts * rtOpts)
 {
 	PtpClock * ptpClock;
-	int c, noclose = 0;
-	int mode_selected = 0;		// 1: slave / 2: master, with ntp / 3: master without ntp
+  int c, noclose = 0;
+  int mode_selected = 0;		// 1: slave / 2: master, with ntp / 3: master without ntp
 
-	int ntp_daemons_expected = 0;
-	int ntp_daemons_strict = 1;
-	int ptp_daemons_expected = 0;
-	int ptp_daemons_strict = 1;
+  int ntp_daemons_expected = 0;
+  int ntp_daemons_strict = 1;
+  int ptp_daemons_expected = 0;
+  int ptp_daemons_strict = 1;
 
-	dump_command_line_parameters(argc, argv);
+  Boolean time_mode_specified = FALSE;
+  TimeMode default_time_mode;
+  Boolean use_hardware_assist = FALSE;
+  Boolean is_error;
 
-	const char *getopt_string = "HgGWb:cCf:ST:dDPR:xO:tM:a:w:u:Uehzl:o:i:I:n:N:y:m:v:r:s:p:q:Y:BjLV:";
+  dump_command_line_parameters(argc, argv);
+/*
+#ifdef PTPD_FULL_OPTIONS
+  const char *getopt_string = "HcSdDEPf:R:X:B:txjO:M:a:w:b:l:T:u:o:i:n:y:m:v:r:s:p:q:Y:LZgGWK";
+#else
+  const char *getopt_string = "HcSdDEPf:R:X:B:txjM:a:w:b:l:T:o:i:n:y:m:v:r:s:p:q:Y:LZgGWK";
+#endif
+*/
 
-	/* parse command line arguments */
-	while ((c = getopt(argc, argv, getopt_string)) != -1) {
-		switch (c) {
-		case '?':
-			printf("\n");
-			display_short_help("Please input correct parameters (use -H for complete help file)");
-			*ret = 1;
-			return 0;
-			break;
-			
-		case 'H':
-			printf(
-				"\nUsage:  ptpv2d [OPTION]\n\n"
-				"Ptpv2d runs on UDP/IP , E2E mode by default\n"
+   const char *getopt_string = "?HgGWb:cCf:ST:dDPR:xO:tM:a:w:u:ehzl:o:i:n:N:y:m:v:r:s:p:q:Y:BjLV:XZK";
+
+  /* parse command line arguments */
+  while ((c = getopt(argc, argv, getopt_string)) != -1) {
+    switch (c) {
+    case '?':
+      if (optopt == '?') {
+	      is_error = FALSE;
+	      *ret = 0;
+      } else {
+	      is_error = TRUE;
+	      *ret = 1;
+      }
+      printf("\n");
+      display_short_help("Please input correct parameters (use -H for complete help file)", is_error);
+      return 0;
+      break;
+
+    case 'H':
+      printf(
+				"\nUsage:  ptpd [OPTION]\n\n"
+				"ptpd runs on UDP/IP , E2E mode by default\n"
+        "\n"
+#define GETOPT_START_OF_OPTIONS
+	"-H                show detailed help page\n"
 				"\n"
-#define GETOPT_START_OF_OPTIONS
-				"-H                show detailed help page\n"
+        "Mode selection (one option is always required):\n"
+        "-g                run as slave only\n"
+        "-W                run as a Master _without_ NTP (reverts to client when inactive)\n"
+        "-b NAME           bind PTP to network interface NAME\n"
 				"\n"
-				"Mode selection (one option is always required):\n"
-				"-g                run as slave only\n"
-				"-G                run as a Master _with_ NTP  (implies -t -L)\n"
-				"-W                run as a Master _without_ NTP (reverts to client when inactive)\n"
-				"-b NAME           bind PTP to network interface NAME\n"
+	"Options:\n"
+	"-c                run in command line (non-daemon) mode (implies -D)\n"
+	"-C                verbose non-daemon mode: implies -c -S -D -V 0, disables -f\n"
+	"-f FILE           send output to FILE (implies -D)\n"
+        "-S                DON'T send messages to syslog\n"
 				"\n"
-				"Options:\n"
-				"-c                run in command line (non-daemon) mode (implies -D)\n"
-				"-C                verbose non-daemon mode: implies -c -S -D -V 0, disables -f\n"
-				"-f FILE           send output to FILE (implies -D)\n"
-				"-S                DON'T send messages to syslog\n"
+        "-T NUMBER         set multicast time to live\n"
+	"-d                display stats (per received packet, see also -V)\n"
+	"-D                display stats in .csv format (per received packet, see also -V)\n"
+	"-P                display each received packet in detail\n"
+	"-R FILE           record data about sync packets in a seperate file\n"
 				"\n"
-				"-T NUMBER         set multicast time to live\n"
-				"-d                display stats (per received packet, see also -V)\n"
-				"-D                display stats in .csv format (per received packet, see also -V)\n"
-				"-P                display each received packet in detail\n"
-				"-R FILE           record data about sync packets in a seperate file\n"
+	"-x                do not reset the clock if off by more than one second\n"
+	"-O NUMBER         do not reset the clock if offset is more than NUMBER nanoseconds\n"
+
+	"-t                do not make any changes to the system clock\n"
+	"-M NUMBER         do not accept delay values of more than NUMBER nanoseconds\n"
+	"-a 10,1000        specify clock servo Proportional and Integral attenuations\n"
+	"-w NUMBER         specify one way delay filter stiffness\n"
 				"\n"
-				"-x                do not reset the clock if off by more than one second\n"
-				"-O NUMBER         do not reset the clock if offset is more than NUMBER nanoseconds\n"
+	"-K                use PTP hardware in network interface. Exit if\n"
+	"                  PTP hardware is not usable or available.\n"
+	"-u ADDRESS        Unicast mode: send all messages in unicast to ADDRESS\n"
+	"-U                Hybrid  mode: send DELAY messages in unicast\n"
+	"                    This causes all delayReq messages to be sent in unicast to the\n"
+	"                    IP address of the Master (taken from the last announce received).\n"
+	"                    For masters, it replyes the delayResp to the IP address of the client\n"
+	"                    (from the corresponding delayReq message).\n"
+	"                    All other messages are send in multicast\n"
+				"\n"
+	"-e                run in ethernet mode (level2) \n"
+	"-h                run in End to End mode \n"
+	"-z                run in Peer-delay mode\n"
+	"-l NUMBER,NUMBER  specify inbound, outbound latency in nsec.\n"
+	"                    (Use this to compensate the time it takes to send and recv\n"
+	"                    messages via sockets)\n"
+			"\n"
+	"-o NUMBER         specify current UTC offset\n"
+	"-i NUMBER         specify PTP domain number (between 0-3)\n"
+	"-I NUMBER         specify Mcast group (between 0-3, emulates PTPv1 group selection)\n"
 
-				"-t                do not make any changes to the system clock\n"
-				"-M NUMBER         do not accept delay values of more than NUMBER nanoseconds\n"
-				"-a 10,1000        specify clock servo Proportional and Integral attenuations\n"
-				"-w NUMBER         specify one way delay filter stiffness\n"
 				"\n"
-				"-u ADDRESS        Unicast mode: send all messages in unicast to ADDRESS\n"
-				"-U                Hybrid  mode: send DELAY messages in unicast\n"
-				"                    This causes all delayReq messages to be sent in unicast to the\n"
-				"                    IP address of the Master (taken from the last announce received).\n"
-				"                    For masters, it replyes the delayResp to the IP address of the client\n"
-				"                    (from the corresponding delayReq message).\n"
-				"                    All other messages are send in multicast\n"
+	"-n NUMBER         specify announce interval in seconds\n"
+	"-N NUMBER         specify announce receipt TO (number of lost announces to timeout)\n"
+
+       	"-y NUMBER         specify sync interval in seconds\n"
+	"-m NUMBER         specify max number of foreign master records\n"
 				"\n"
-				"-e                run in ethernet mode (level2) \n"
-				"-h                run in End to End mode \n"
-				"-z                run in Peer-delay mode\n"
-				"-l NUMBER,NUMBER  specify inbound, outbound latency in nsec.\n"
-				"                    (Use this to compensate the time it takes to send and recv\n"
-				"                    messages via sockets)\n"
+        "-v NUMBER         Master mode: specify system clock Allen variance\n"
+        "-r NUMBER         Master mode: specify system clock accuracy\n"
+        "-s NUMBER         Master mode: specify system clock class\n"
+        "-p NUMBER         Master mode: specify priority1 attribute\n"
+        "-q NUMBER         Master mode: specify priority2 attribute\n"
+		"\n"
+		"\n"
+	"-Y 0[,0]          Initial and Master_Overide delayreq intervals\n"
+	"                     desc: the first 2^ number is the rate the slave sends delayReq\n"
+	"                     When the first answer is received, the master value is used (unless the\n"
+	"                     second number was also given)\n"
+		"\n"
+	"-B                Enable debug messages (if compiled-in). Multiple invocations to more debug\n"
+		"\n"
+	"Compatibility Options (to restore previous default behaviour):\n"
+	"-j                Do not refresh the IGMP Multicast menbership at each protol reset\n"
+	"-L                Allow multiple instances (ignore lock and other daemons)\n"
+	"-V 0              Seconds between log messages (0: all messages)\n"
 				"\n"
-				"-o NUMBER         specify current UTC offset\n"
-				"-i NUMBER         specify PTP domain number (between 0-3)\n"
-				"-I NUMBER         specify Mcast group (between 0-3, emulates PTPv1 group selection)\n"
-				
 				"\n"
-				"-n NUMBER         specify announce interval in 2^NUMBER sec\n"
-				"-N NUMBER         specify announce receipt TO (number of lost announces to timeout)\n"
-
-				"-y NUMBER         specify sync interval in 2^NUMBER sec\n"
-				"-m NUMBER         specify max number of foreign master records\n"
-				"\n"
-				"-v NUMBER         Master mode: specify system clock Allen variance\n"
-				"-r NUMBER         Master mode: specify system clock accuracy\n"
-				"-s NUMBER         Master mode: specify system clock class\n"
-				"-p NUMBER         Master mode: specify priority1 attribute\n"
-				"-q NUMBER         Master mode: specify priority2 attribute\n"
-				"\n"
-				"\n"
-				"-Y 0[,0]          Initial and Master_Overide delayreq intervals\n"
-				"                     desc: the first 2^ number is the rate the slave sends delayReq\n"
-				"                     When the first answer is received, the master value is used (unless the\n"
-				"                     second number was also given)\n"
-				"\n"
-				"-B                Enable debug messages (if compiled-in). Multiple invocations to more debug\n"
-				"\n"
-				"Compatibility Options (to restore previous default behaviour):\n"
-				"-j                Do not refresh the IGMP Multicast menbership at each protol reset\n"
-				"-L                Allow multiple instances (ignore lock and other daemons)\n"
-				"-V 0              Seconds between log messages (0: all messages)\n"
-				"\n"
-				"\n"
+	"-Z                ignore delayReq interval given by Master\n"
 
 
 #define GETOPT_END_OF_OPTIONS
 				"\n"
-				"Possible internal states:\n"
-				"  init:        INITIALIZING\n"
-				"  flt:         FAULTY\n"
-				"  lstn_init:   LISTENING (first time)\n"
-				"  lstn_reset:  LISTENING (non first time)\n"
-				"  pass:        INACTIVE Master\n"
-				"  uncl:        UNCALIBRATED\n"
-				"  slv:         SLAVE\n"
-				"  pmst:        PRE Master\n"
-				"  mst:         ACTIVE Master\n"
-				"  dsbl:        DISABLED\n"
-				"  ?:           UNKNOWN state\n"
+	"Possible internal states:\n"
+	"  init:        INITIALIZING\n"
+	"  flt:         FAULTY\n"
+	"  lstn_init:   LISTENING (first time)\n"
+	"  lstn_reset:  LISTENING (non first time)\n"
+	"  pass:        INACTIVE Master\n"
+	"  uncl:        UNCALIBRATED\n"
+	"  slv:         SLAVE\n"
+	"  pmst:        PRE Master\n"
+	"  mst:         ACTIVE Master\n"
+	"  dsbl:        DISABLED\n"
+	"  ?:           UNKNOWN state\n"
 
-				"\n"
+			"\n"
 
-				"Signals synchronous behaviour:\n"
-				"  SIGHUP         Re-open statistics log (specified with -f)\n"
-				"  SIGUSR1        Manually step clock to current OFM value (overides -x, but honors -t)\n"
-				"  SIGUSR2        swap domain between current and current + 1 (useful for testing)\n"
-				"  SIGUSR2        cycle run-time debug level (requires RUNTIME_DEBUG)\n"
-				"\n"
-				"  SIGINT|TERM    close file, remove lock file, and clean exit\n"
-				"  SIGKILL|STOP   force an unclean exit\n"
-				
-				"\n"
-				"BMC Algorithm defaults:\n"
-				"  Software:   P1(128) > Class(13|248) > Accuracy(\"unk\"/0xFE)   > Variance(61536) > P2(128)\n"
+        "Signals synchronous behaviour:\n"
+	"  SIGHUP         Re-open statistics log (specified with -f)\n"
+	"  SIGUSR1        Manually step clock to current OFM value (overides -x, but honors -t)\n"
+	"  SIGUSR2        swap domain between current and current + 1 (useful for testing)\n"
+	"  SIGUSR2        cycle run-time debug level (requires RUNTIME_DEBUG)\n"
+#ifdef DBG_SIGRTMIN_LEAP_SECOND
+	"  SIGRTMIN       Master: signal a leap second 61 at the end of the current UTC day\n"
+	"  SIGRTMIN+1     Master- signal a leap second 59 at the end of the current UTC day\n"
+#endif
+        "\n"
+        "  SIGINT|TERM    close file, remove lock file, and clean exit\n"
+        "  SIGKILL|STOP   force an unclean exit\n"
 
-											 
-				/*  "-k NUMBER,NUMBER  send a management message of key, record, then exit\n" implemented later.. */
-			    "\n"
-			    );
-			*ret = 1;
-			return 0;
-			break;
+        "\n"
+        "BMC Algorithm defaults:\n"
+        "  Software:   P1(248) > Class(13|248) > Accuracy(\"unk\"/0xFE)   > Variance(61536) > P2(0)\n\nptpd version %s\n",
 
-		case 'c':
-			rtOpts->nonDaemon = 1;
-			break;
+        PTP_VERSION_STRING
+        );
+      *ret = 0;
+      return 0;
+      break;
+
+    case 'c':
+      rtOpts->nonDaemon = 1;
+      break;
 			
-		case 'C':
-			rtOpts->nonDaemon = 2;
+    case 'C':
+	rtOpts->nonDaemon = 2;
 
-			rtOpts->useSysLog    = FALSE;
-			rtOpts->syslog_startup_messages_also_to_stdout = TRUE;
-			rtOpts->displayStats = TRUE;
-			rtOpts->csvStats     = TRUE;
-			rtOpts->log_seconds_between_message = 0;
-			rtOpts->do_log_to_file = FALSE;
-			break;
-			
-		case 'S':
-			rtOpts->useSysLog = FALSE;
-			break;
+	rtOpts->useSysLog    = FALSE;
+	rtOpts->syslog_startup_messages_also_to_stdout = TRUE;
+	rtOpts->displayStats = TRUE;
+	rtOpts->csvStats     = TRUE;
+	rtOpts->log_seconds_between_message = 0;
+	rtOpts->do_log_to_file = FALSE;
+	break;
+	
+    case 'S':
+      rtOpts->useSysLog = FALSE;
+      break;
 		case 'T':
 			rtOpts->ttl = atoi(optarg);
 			break;
@@ -697,74 +823,101 @@
 #endif
 			break;
 			
-		case 'd':
-			rtOpts->displayStats = TRUE;
-			break;
-		case 'D':
-			rtOpts->displayStats = TRUE;
-			rtOpts->csvStats = TRUE;
-			break;
-		case 'P':
-			rtOpts->displayPackets = TRUE;
-			break;
+    case 'd':
+      rtOpts->displayStats = TRUE;
+      break;
+    case 'D':
+      rtOpts->displayStats = TRUE;
+      rtOpts->verboseStats = TRUE;
+      rtOpts->csvStats = TRUE;
+      break;
+    case 'P':
+      rtOpts->displayPackets = TRUE;
+      break;
 
-		case 'R':
-			/* this option handling is now after the arguments processing (to show the help in case of -?) */
-			strncpy(rtOpts->recordFile, optarg, PATH_MAX);
-			rtOpts->do_record_quality_file = TRUE;
-			break;
+    case 'R':
+      /* this option handling is now after the arguments processing (to show the help in case of -?) */
+      strncpy(rtOpts->recordFile, optarg, PATH_MAX);
+      rtOpts->do_record_quality_file = TRUE;
+      break;
+    case 'X':
+      if(!strcasecmp(optarg, "nic"))
+      {
+        rtOpts->time_mode = TIME_NIC;
+      }
+      else if(!strcasecmp(optarg, "system"))
+      {
+        rtOpts->time_mode = TIME_SYSTEM;
+      }
+      else if(!strcasecmp(optarg, "both"))
+      {
+        rtOpts->time_mode = TIME_BOTH;
+      }
+      else if(!strcasecmp(optarg, "linux_hw"))
+      {
+        rtOpts->time_mode = TIME_SYSTEM_LINUX_HW;
+      }
+      else
+      {
+        ERROR("unsupported -z clock '%s'.\n", optarg);
+        *ret = 1;
+      }
+      /*
+      * Set a flag to control whether to indicate that we don't need
+      * to set the default time mode.
+      */
+      time_mode_specified = TRUE;
+      break;
+    case 'x':
+      rtOpts->noResetClock = TRUE;
+      break;
+    case 'O':
+      rtOpts->maxReset = atoi(optarg);
+      if (rtOpts->maxReset > 1000000000) {
+        ERROR("Use -x to prevent jumps of more"
+              " than one second.");
+        *ret = 1;
+        return (0);
+      }
+      break;
+    case 'M':
+    {
+      long double max_delay = strtod(optarg, NULL);
+      rtOpts->maxDelay.seconds = (Integer32)floor(max_delay);
+      rtOpts->maxDelay.nanoseconds =
+        (Integer32)round((max_delay - rtOpts->maxDelay.seconds) * 1000000000.0);
+      break;
+    }
+	break;
+    case 't':
+	rtOpts->noAdjust = TRUE;
+	break;
+    case 'a':
+      rtOpts->ap = strtol(optarg, &optarg, 0);
+      if (optarg[0])
+        rtOpts->ai = strtol(optarg + 1, 0, 0);
+      break;
+    case 'w':
+      rtOpts->s = strtol(optarg, &optarg, 0);
+      break;
+    case 'b':
+      memset(rtOpts->ifaceName, 0, IFACE_NAME_LENGTH);
+      strncpy(rtOpts->ifaceName, optarg, IFACE_NAME_LENGTH);
+      break;
 
+    case 'u':
+			rtOpts->do_unicast_mode = 1;
+      strncpy(rtOpts->unicastAddress, optarg,
+		      MAXHOSTNAMELEN);
 
-		case 'x':
-			rtOpts->noResetClock = TRUE;
-			break;
-		case 'O':
-			rtOpts->maxReset = atoi(optarg);
-			if (rtOpts->maxReset > 1000000000) {
-				ERROR("Use -x to prevent jumps of more"
-				       " than one second.");
-				*ret = 1;
-				return (0);
-			}
-			break;
-		case 'M':
-			rtOpts->maxDelay = atoi(optarg);
-			if (rtOpts->maxDelay > 1000000000) {
-				ERROR("Use -x to prevent jumps of more"
-				       " than one second.");
-				*ret = 1;
-				return (0);
-			}
-			break;
-		case 't':
-			rtOpts->noAdjust = TRUE;
-			break;
-		case 'a':
-			rtOpts->ap = strtol(optarg, &optarg, 0);
-			if (optarg[0])
-				rtOpts->ai = strtol(optarg + 1, 0, 0);
-			break;
-		case 'w':
-			rtOpts->s = strtol(optarg, &optarg, 0);
-			break;
-		case 'b':
-			memset(rtOpts->ifaceName, 0, IFACE_NAME_LENGTH);
-			strncpy(rtOpts->ifaceName, optarg, IFACE_NAME_LENGTH);
-			break;
+	/*
+	 * FIXME: some code still relies on checking if this variable is filled. Upgrade this to do_unicast_mode
+	 *
+	 * E.g.:  netSendEvent(Octet * buf, UInteger16 length, NetPath * netPath, Integer32 alt_dst)
+	 *  if(netPath->unicastAddr || alt_dst ) ...
+	 */
+      break;
 
-		case 'u':
-			rtOpts->do_unicast_mode = 1;
-			strncpy(rtOpts->unicastAddress, optarg, 
-				MAXHOSTNAMELEN);
-
-			/*
-			 * FIXME: some code still relies on checking if this variable is filled. Upgrade this to do_unicast_mode
-			 *
-			 * E.g.:  netSendEvent(Octet * buf, UInteger16 length, NetPath * netPath, Integer32 alt_dst)
-			 *  if(netPath->unicastAddr || alt_dst ){
-			 */
-			break;
-			 
 		case 'U':
 #ifdef PTP_EXPERIMENTAL
 			rtOpts->do_hybrid_mode = 1;
@@ -773,174 +926,244 @@
 #endif
 			break;
 
-			
-		case 'l':
-			rtOpts->inboundLatency.nanoseconds = 
-				strtol(optarg, &optarg, 0);
-			if (optarg[0])
-				rtOpts->outboundLatency.nanoseconds = 
-					strtol(optarg + 1, 0, 0);
-			break;
-		case 'o':
-			rtOpts->currentUtcOffset = strtol(optarg, &optarg, 0);
-			break;
-		case 'i':
-			rtOpts->domainNumber = strtol(optarg, &optarg, 0);
-			break;
 
-		case 'I':
+    case 'l':
+      rtOpts->inboundLatency.nanoseconds =
+	      strtol(optarg, &optarg, 0);
+      if (optarg[0])
+        rtOpts->outboundLatency.nanoseconds =
+		strtol(optarg + 1, 0, 0);
+      break;
+    case 'o':
+      rtOpts->currentUtcOffset = strtol(optarg, &optarg, 0);
+      rtOpts->currentUtcOffsetValid = TRUE;
+      break;
+    case 'i':
+      rtOpts->domainNumber = strtol(optarg, &optarg, 0);
+      if (rtOpts->domainNumber > 3) {
+	ERROR(" Please provide an integer between 0 to 3 with -i\n");
+	*ret = 1;
+	return (0);
+      }
+      break;
+
+	case 'I':
 #ifdef PTP_EXPERIMENTAL
-			rtOpts->mcast_group_Number = strtol(optarg, &optarg, 0);
+	rtOpts->mcast_group_Number = strtol(optarg, &optarg, 0);
+	if (rtOpts->mcast_group_Number > 3) {
+		ERROR(" Please provide an integer between 0 to 3 with -I\n");
+		*ret = 1;
+		return (0);
+      }
 #else
-			INFO("Multicast group selection not enabled. Please compile with PTP_EXPERIMENTAL\n");
+	INFO("Multicast group selection not enabled. Please compile with PTP_EXPERIMENTAL\n");
 #endif
-			break;
+	break;
+   
 
 
-			
-		case 'y':
-			rtOpts->syncInterval = strtol(optarg, 0, 0);
-			break;
-		case 'n':
-			rtOpts->announceInterval = strtol(optarg, 0, 0);
-			break;
+	case 'y':
+      rtOpts->syncInterval = strtod(optarg, 0);
+      break;
+    case 'n':
+      rtOpts->announceInterval = strtod(optarg, 0);
+      break;
 
 		case 'N':
 			rtOpts->announceReceiptTimeout = strtol(optarg, 0, 0);
 			break;
 			
-		case 'm':
-			rtOpts->max_foreign_records = strtol(optarg, 0, 0);
-			if (rtOpts->max_foreign_records < 1)
-				rtOpts->max_foreign_records = 1;
-			break;
-		case 'v':
-			rtOpts->clockQuality.offsetScaledLogVariance = 
-				strtol(optarg, 0, 0);
-			break;
-		case 'r':
-			rtOpts->clockQuality.clockAccuracy = 
-				strtol(optarg, 0, 0);
-			break;
-		case 's':
-			rtOpts->clockQuality.clockClass = strtol(optarg, 0, 0);
-			break;
-		case 'p':
-			rtOpts->priority1 = strtol(optarg, 0, 0);
-			break;
-		case 'q':
-			rtOpts->priority2 = strtol(optarg, 0, 0);
-			break;
-		case 'e':
-			rtOpts->ethernet_mode = TRUE;
-			ERROR("Not implemented yet !");
-			return 0;
-			break;
-		case 'h':
-			rtOpts->delayMechanism = E2E;
-			break;
+    case 'm':
+      rtOpts->max_foreign_records = strtol(optarg, 0, 0);
+      if (rtOpts->max_foreign_records < 1)
+        rtOpts->max_foreign_records = 1;
+      break;
+    case 'v':
+      rtOpts->clockQuality.offsetScaledLogVariance =
+        strtol(optarg, 0, 0);
+      break;
+    case 'r':
+      rtOpts->clockQuality.clockAccuracy =
+        strtol(optarg, 0, 0);
+      break;
+    case 's':
+      rtOpts->clockQuality.clockClass = strtol(optarg, 0, 0);
+      break;
+    case 'p':
+      rtOpts->priority1 = strtol(optarg, 0, 0);
+      break;
+    case 'q':
+      rtOpts->priority2 = strtol(optarg, 0, 0);
+      break;
+	case 'e':
+		rtOpts->ethernet_mode = TRUE;
+		ERROR("Not implemented yet !");
+		*ret = 3;
+		return 0;
+		break;
+	case 'h':
+		rtOpts->delayMechanism = E2E;
+		break;
 
-		case 'V':
-			rtOpts->log_seconds_between_message = strtol(optarg, &optarg, 0);
-			break;
+	case 'V':
+		rtOpts->log_seconds_between_message = strtol(optarg, &optarg, 0);
+		break;
 
-		case 'z':
-			rtOpts->delayMechanism = P2P;
-			break;
+	case 'Z':
+		rtOpts->ignore_delayreq_interval_master = TRUE;
+		break;
 
-		/* mode selection */
-		/* slave only */
-		case 'g':
-			mode_selected = 1;
-			rtOpts->slaveOnly = TRUE;
-			rtOpts->initial_delayreq = DEFAULT_DELAYREQ_INTERVAL;		// allow us to use faster rate at init
+	case 'z':
+		rtOpts->delayMechanism = P2P;
+		break;
 
-			/* we dont expect any parallel deamons, and we are strict about it  */
-			ntp_daemons_expected = 0;
-			ntp_daemons_strict = 1;
-			ptp_daemons_expected = 0;
-			ptp_daemons_strict = 1;
-			break;
-			
-		/* Master + NTP */
-		case 'G':
-			mode_selected = 2;
-			rtOpts->clockQuality.clockClass = DEFAULT_CLOCK_CLASS__APPLICATION_SPECIFIC_TIME_SOURCE;
-			rtOpts->slaveOnly = FALSE;
-			rtOpts->noAdjust = TRUE;
+    /* mode selection */
+    /* slave only */
+    case 'g':
+      switch (mode_selected) {
+	      case 2 :
+		      ERROR(" -G and -g cannot be specified together\n");
+		      *ret = 3;
+		      return 0;
+	      case 3:
+		      ERROR(" -W and -g cannot be specified together\n");
+		      *ret = 3;
+		      return 0;
+	      default:
+		      break;
+      }
+      mode_selected = 1;
+      rtOpts->slaveOnly = TRUE;
+      rtOpts->master_slave_mode = PTP_MODE_SLAVE;
+      rtOpts->initial_delayreq = DEFAULT_DELAYREQ_INTERVAL;		// allow us to use faster rate at init
 
-			/* we expect one ntpd daemon in parallel, but we are not strick about it */
-			ntp_daemons_expected = 1;
-			ntp_daemons_strict = 0;
-			ptp_daemons_expected = 0;
-			ptp_daemons_strict = 0;
-			break;
+      /* we dont expect any parallel deamons, and we are strict about it  */
+      ntp_daemons_expected = 0;
+      ntp_daemons_strict = 1;
+      ptp_daemons_expected = 0;
+      ptp_daemons_strict = 1;
 
-		/*
-		 *  master without NTP (Original Master behaviour):
-		 *    it falls back to slave mode when its inactive master;
-		 *    once it starts being active, it will drift for itself, so in actual terms it always requires NTP to work properly
-		 */
-		case 'W':
-			mode_selected = 3;
-			rtOpts->slaveOnly = FALSE;
-			rtOpts->noAdjust = FALSE;
+      default_time_mode = DEFAULT_SLAVE_TIME_MODE;
+      break;
 
-			/* we don't expect ntpd, but we can run with other ptpv1 deamons  */
-			ntp_daemons_expected = 0;
-			ntp_daemons_strict = 1;
-			ptp_daemons_expected = 0;
-			ptp_daemons_strict = 0;
-			break;
+    /* Master + NTP */
+    case 'G':
+      switch (mode_selected) {
+	      case 1 :
+		      ERROR(" -G and -g cannot be specified together\n");
+		      *ret = 3;
+		      return 0;
+	      case 3:
+		      ERROR(" -G and -W cannot be specified together\n");
+		      *ret = 3;
+		      return 0;
+	      default:
+		      break;
+      }
+      mode_selected = 2;
+      rtOpts->master_slave_mode = PTP_MODE_MASTER_WITH_NTP;
+      rtOpts->clockQuality.clockClass = DEFAULT_CLOCK_CLASS__APPLICATION_SPECIFIC_TIME_SOURCE;
+      rtOpts->slaveOnly = FALSE;
+      rtOpts->noAdjust = TRUE;
 
-			
-		case 'Y':
-			rtOpts->initial_delayreq = strtol(optarg, &optarg, 0);
-			rtOpts->subsequent_delayreq = rtOpts->initial_delayreq;
-			rtOpts->ignore_delayreq_interval_master = FALSE;
+      /* we expect one ntpd daemon in parallel, but we are not strick about it */
+      ntp_daemons_expected = 1;
+      ntp_daemons_strict = 0;
+      ptp_daemons_expected = 0;
+      ptp_daemons_strict = 0;
 
-			/* Use this to override the master-given DelayReq value */
-			if (optarg[0]){
-				rtOpts->subsequent_delayreq = strtol(optarg + 1, &optarg, 0);
-				rtOpts->ignore_delayreq_interval_master = TRUE;
-			}
-			break;
+      default_time_mode = DEFAULT_MASTER_TIME_MODE;
+      break;
 
-		case 'L':
-			/* enable running multiple ptpd2 daemons */
-			rtOpts->ignore_daemon_lock = TRUE;
-			break;
-		case 'j':
-			rtOpts->do_IGMP_refresh = FALSE;
-			break;
+    /*
+     *  master without NTP (Original Master behaviour):
+     *    it falls back to slave mode when its inactive master;
+     *    once it starts being active, it will drift for itself, so in actual terms it always requires NTP to work properly
+     */
+    case 'W':
+      switch (mode_selected) {
+	      case 1 :
+		      ERROR(" -W and -g cannot be specified together\n");
+		      *ret = 3;
+		      return 0;
+	      case 2:
+		      ERROR(" -G and -W cannot be specified together\n");
+		      *ret = 3;
+		      return 0;
+	      default:
+		      break;
+      }
+      rtOpts->master_slave_mode = PTP_MODE_MASTER_NO_NTP;
+      mode_selected = 3;
+      rtOpts->slaveOnly = FALSE;
+      rtOpts->noAdjust = FALSE;
+
+      /* we don't expect ntpd, but we can run with other ptpv1 deamons  */
+      ntp_daemons_expected = 0;
+      ntp_daemons_strict = 1;
+      ptp_daemons_expected = 0;
+      ptp_daemons_strict = 0;
+      default_time_mode = DEFAULT_MASTER_TIME_MODE;
+      break;
+
+      /* Use the NIC hardware; i.e. TIME_BOTH mode */
+    case 'K':
+/*
+#ifdef __sparc__
+	ERROR("HW assist (-K) is not supported on sparc\n");
+	*ret = 3;
+	return 0;
+#endif
+*/
+      use_hardware_assist = TRUE;
+      break;
+
 		
-			
+     case 'Y':
+	rtOpts->initial_delayreq = strtod(optarg, 0);
+	rtOpts->subsequent_delayreq = rtOpts->initial_delayreq;
+	rtOpts->ignore_delayreq_interval_master = FALSE;
 
-		default:
-			ERROR("Unknown parameter %c \n", c);
-			*ret = 1;
-			return 0;
-		}
+	/* Use this to override the master-given DelayReq value */
+	if (optarg[0]){
+		rtOpts->subsequent_delayreq = strtol(optarg + 1, &optarg, 0);
+		rtOpts->ignore_delayreq_interval_master = TRUE;
 	}
+      break;
 
+      case 'L':
+         /* enable running multiple ptpd2 daemons */
+	 rtOpts->ignore_daemon_lock = TRUE;
+	 break;
+      case 'j':
+	rtOpts->do_IGMP_refresh = FALSE;
+	break;
 
-	/*
-	 * we try to catch as many error conditions as possible, but before we call daemon().
-	 * the exception is the lock file, as we get a new pid when we call daemon(),
-	 * so this is checked twice: once to read, second to read/write
-	 */
-	if(geteuid() != 0)
-	{
-		display_short_help("Please run this daemon as root");
-			*ret = 1;
-			return 0;
-		}
+    default:
+      ERROR("Unknown parameter %c \n", c);
+      *ret = 1;
+      return 0;
+    }
+  }
 
-	if(!mode_selected){
-		display_short_help("Please select program mode");
-		*ret = 1;
-		return 0;
-	}
+
+  /*
+   * we try to catch as many error conditions as possible, but before we call daemon().
+   * the exception is the lock file, as we get a new pid when we call daemon(),
+   * so this is checked twice: once to read, second to read/write
+   */
+  if(geteuid() != 0)
+  {
+    display_short_help("Please run this daemon as root", TRUE);
+      *ret = 1;
+      return 0;
+  }
+
+  if(rtOpts->master_slave_mode == PTP_MODE_NULL) {
+    display_short_help("Please select program mode", TRUE);
+    *ret = 1;
+    return 0;
+  }
 
 #ifdef PTP_EXPERIMENTAL
 	if(rtOpts->do_unicast_mode && rtOpts->do_hybrid_mode){
@@ -950,42 +1173,47 @@
 	}
 #endif
 
+    /* If the time mode has not been specified then use the default time mode */
+    if (time_mode_specified == FALSE) {
+      if (use_hardware_assist) {
+	      default_time_mode = TIME_BOTH;
+      }
+      rtOpts->time_mode = default_time_mode;
+    }
 
+  ptpClock = (PtpClock *) calloc(1, sizeof(PtpClock));
+  if (!ptpClock) {
+    PERROR("failed to allocate memory for protocol engine data");
+    *ret = 2;
+    return 0;
+  } else {
+    DBG("allocated %d bytes for protocol engine data\n",
+        (int)sizeof(PtpClock));
+    ptpClock->foreign = (ForeignMasterRecord *)
+      calloc(rtOpts->max_foreign_records,
+            sizeof(ForeignMasterRecord));
+    if (!ptpClock->foreign) {
+      PERROR("failed to allocate memory for foreign "
+            "master data");
+      *ret = 2;
+      free(ptpClock);
+      return 0;
+    } else {
+      DBG("allocated %d bytes for foreign master data\n",
+          (int)(rtOpts->max_foreign_records *
+          sizeof(ForeignMasterRecord)));
+    }
+  }
 
+  /* Init to 0 net buffer */
+  memset(ptpClock->msgIbuf, 0, PACKET_SIZE);
+  memset(ptpClock->msgObuf, 0, PACKET_SIZE);
 
+  /* Initialise sockets to invalid */
+  ptpClock->netPath.eventSock = -1;
+  ptpClock->netPath.generalSock = -1;
 
 
-
-	ptpClock = (PtpClock *) calloc(1, sizeof(PtpClock));
-	if (!ptpClock) {
-		PERROR("failed to allocate memory for protocol engine data");
-		*ret = 2;
-		return 0;
-	} else {
-		DBG("allocated %d bytes for protocol engine data\n", 
-		    (int)sizeof(PtpClock));
-		ptpClock->foreign = (ForeignMasterRecord *)
-			calloc(rtOpts->max_foreign_records, 
-			       sizeof(ForeignMasterRecord));
-		if (!ptpClock->foreign) {
-			PERROR("failed to allocate memory for foreign "
-			       "master data");
-			*ret = 2;
-			free(ptpClock);
-			return 0;
-		} else {
-			DBG("allocated %d bytes for foreign master data\n", 
-			    (int)(rtOpts->max_foreign_records * 
-				  sizeof(ForeignMasterRecord)));
-		}
-	}
-
-	/* Init to 0 net buffer */
-	memset(ptpClock->msgIbuf, 0, PACKET_SIZE);
-	memset(ptpClock->msgObuf, 0, PACKET_SIZE);
-
-
- 
 	/*
 	 * This section discusses some of the complexities of doing proper Locking and Background Daemon programs.
 	 *
@@ -997,7 +1225,7 @@
 	 *
 	 *      The correct way is to lock the shared resource that needs write protection: the kernel clock itself.
 	 *   (http://mywiki.wooledge.org/ProcessManagement#How_do_I_make_sure_only_one_copy_of_my_script_can_run_at_a_time.3F)
-	 *   Thus, ptpd2 will lock the file /var/run/kernel_clock in daemon_already_running().
+	 *   Thus, ptpd2 will lock the file LOCKFILE in daemon_already_running().
 	 *      Unfortunately this is not followed by the other discipliners, so on top of locking we also try to find
 	 *   them by name (we spawn pgrep in check_parallel_daemons()).
 	 *      Another alternative would be to clone NTP's way of doing this: to bind to port 123, the NTP port. Although this
@@ -1024,10 +1252,13 @@
 	if(rtOpts->ignore_daemon_lock == 0){
 		/* check and create Lock */
 		if(daemon_already_running()){
-			ERROR("  Error:   Multiple ptpd2 instances detected (-L to ignore lock file %s)\n", LOCKFILE);
+			ERROR("  Error:   Multiple ptpd instances detected (-L to ignore lock file %s)\n", LOCKFILE);
 			*ret = 3;
+			free(ptpClock);
 			return 0;
 		}
+		/* unlock the file so that child process can lock it */
+		(void) unlockfile(global_lock_fd);
 	} else {
 		/* if we ignore the daemon lock, we also are not strict for parallel daemons (but we always syslog what is happening) */
 		ptp_daemons_strict=0;
@@ -1035,86 +1266,92 @@
 	}
 
 
-	if(check_parallel_daemons("ptpd", ptp_daemons_expected, ptp_daemons_strict, rtOpts) &&
-	   check_parallel_daemons("ntpd", ntp_daemons_expected, ntp_daemons_strict, rtOpts))
-	{
-		/* ok */
-	} else {
-		*ret = 3;
-		return 0;
-	}
+  if(check_parallel_daemons("ptpd", ptp_daemons_expected, ptp_daemons_strict, rtOpts) &&
+    check_parallel_daemons("ntpd", ntp_daemons_expected, ntp_daemons_strict, rtOpts))
+  {
+    /* ok */
+  } else {
+    *ret = 3;
+    free(ptpClock);
+    return 0;
+  }
 
 
+  /* Manage open files: stats and quality file */
+  if(rtOpts->do_record_quality_file){
+	if (recordToFile(rtOpts))
+      noclose = 1;
+    else
+      PERROR("could not open quality file");
+  }
 
+  if(rtOpts->do_log_to_file){
+		if(logToFile(rtOpts))
+      noclose = 1;
+    else
+      PERROR("could not open output file");
 
+    rtOpts->displayStats = TRUE;
+    rtOpts->verboseStats = TRUE;
+    rtOpts->csvStats = TRUE;
+  }
 
-	/* Manage open files: stats and quality file */
-	if(rtOpts->do_record_quality_file){
-		if (recordToFile(rtOpts))
-			noclose = 1;
-		else
-			PERROR("could not open quality file");
-	}
 
-	if(rtOpts->do_log_to_file){
-		if(logToFile(rtOpts))
-			noclose = 1;
-		else
-			PERROR("could not open output file");
 
-		rtOpts->displayStats = TRUE;
-		rtOpts->csvStats = TRUE;
-	}
-
-
-
-	/*  DAEMON */
+  /*  DAEMON */
 #ifdef PTPD_NO_DAEMON
-	if(rtOpts->nonDaemon == 0){
-		rtOpts->nonDaemon= 1;
-	}
+  if(rtOpts->nonDaemon == 0){
+    rtOpts->nonDaemon= 1;
+  }
 #endif
 
 
-	
-	if(rtOpts->nonDaemon == 0){
-		/* fork to daemon */
-		if (daemon(0, noclose) == -1) {
-			PERROR("failed to start as daemon");
-			*ret = 3;
-			return 0;
-		}
+
+  if(rtOpts->nonDaemon == 0){
+    /* fork to daemon */
+    if (daemon(0, noclose) == -1) {
+      PERROR("failed to start as daemon");
+      *ret = 3;
+      free(ptpClock);
+      return 0;
+    }
 		INFO("  Info:    Now running as a daemon\n");
-	}
+  }
 
 	/* if syslog is on, send all messages to syslog only  */
 	rtOpts->syslog_startup_messages_also_to_stdout = FALSE;   
 
 
-	/* Second lock check, to replace the contents with our own new PID. It seems that F_WRLCK is not inherited to the child, so we lock again */
-	if(rtOpts->ignore_daemon_lock == 0){
-		/* check and create Lock */
-		if(daemon_already_running()){
+  /* Second lock check, to replace the contents with our own new PID. It seems that F_WRLCK is not inherited to the child, so we lock again */
+  if(rtOpts->ignore_daemon_lock == 0){
+    /* check and create Lock */
+    if(daemon_already_running()){
 			ERROR("Multiple instances of this daemon detected (Use option -L to ignore lock file %s)\n", LOCKFILE);
-			*ret = 3;
-			return 0;
-		}
-	}
+      *ret = 3;
+      free(ptpClock);
+      return 0;
+    }
+  }
 
-	
-	/* use new synchronous signal handlers */
-	signal(SIGINT,  catch_signals);
-	signal(SIGTERM, catch_signals);
-	signal(SIGHUP,  catch_signals);
 
-	signal(SIGUSR1, catch_signals);
-	signal(SIGUSR2, catch_signals);
+  /* use new syncronous signal handlers */
+  signal(SIGINT,  catch_signals);
+  signal(SIGTERM, catch_signals);
+  signal(SIGHUP,  catch_signals);
 
-	*ret = 0;
+  signal(SIGUSR1, catch_signals);
+  signal(SIGUSR2, catch_signals);
+
+#ifdef DBG_SIGRTMIN_LEAP_SECOND
+  signal(SIGRTMIN,   catch_signals);
+  signal(SIGRTMIN+1, catch_signals);
+#endif
+
+  *ret = 0;
 
 	INFO("  Info:    Startup finished sucessfully\n");
 
-	return ptpClock;
+  return ptpClock;
 }
 
 
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/sys.c
--- a/src/dep/sys.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/sys.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,6 @@
 /*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2011      George V. Neville-Neil, Steven Kreuzer,
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen,
  *                         National Instruments.
@@ -39,6 +41,8 @@
  *
  */
 
+#include <inttypes.h>
+
 #include "../ptpd.h"
 
 #if defined(linux)
@@ -55,6 +59,9 @@
 /* only C99 has the round function built-in */
 double round (double __x);
 
+/* TODO Yuk */
+extern PtpClock *G_ptpClock;
+extern PtpClock* G_timeBothClock;
 
 /*
  returns a static char * for the representation of time, for debug purposes
@@ -111,9 +118,11 @@
 	/* always print either a space, or the leading "-". This makes the stat files columns-aligned */
 	len += snprintf(&s[len], max_len - len, "%c",
 		isTimeInternalNegative(p)? '-':' ');
+	if (len > max_len) len = max_len;
 
 	len += snprintf(&s[len], max_len - len, "%d.%09d",
 	    abs(p->seconds), abs(p->nanoseconds));
+	if (len > max_len) len = max_len;
 
 	return len;
 }
@@ -170,11 +179,14 @@
 	int len = 0;
 	int i;
 
-	if (info)
+	if (info) {
 		len += snprintf(&s[len], max_len - len, "%s", info);
+		if (len > max_len) len = max_len;
+	}
 
 	for (i = 0; ;) {
 		len += snprintf(&s[len], max_len - len, "%02x", (unsigned char) id[i]);
+		if (len > max_len) len = max_len;
 
 		if (++i >= CLOCK_IDENTITY_LENGTH)
 			break;
@@ -191,19 +203,23 @@
 	int len = 0;
 	int i;
 
-	if (info)
+	if (info) {
 		len += snprintf(&s[len], max_len - len, "%s", info);
+		if (len > max_len) len = max_len;
+	}
 
 	for (i = 0; ;) {
 		/* skip bytes 3 and 4 */
 		if(!((i==3) || (i==4))){
 			len += snprintf(&s[len], max_len - len, "%02x", (unsigned char) id[i]);
+			if (len > max_len) len = max_len;
 
 			if (++i >= CLOCK_IDENTITY_LENGTH)
 				break;
 
 			/* print a separator after each byte except the last one */
 			len += snprintf(&s[len], max_len - len, "%s", ":");
+			if (len > max_len) len = max_len;
 		} else {
 
 			i++;
@@ -226,7 +242,7 @@
 	static struct ether_addr prev_addr;
 	static char buf[BUF_SIZE];
 
-#if defined(linux) || defined(__NetBSD__)
+#if defined(linux) || defined(__NetBSD__) || defined(__sun)
 	if (memcmp(addr->ether_addr_octet, &prev_addr, 
 		  sizeof(struct ether_addr )) != 0) {
 		valid = 0;
@@ -270,7 +286,7 @@
 	for (i = 0, j = 0; i< CLOCK_IDENTITY_LENGTH ; i++ ){
 		/* skip bytes 3 and 4 */
 		if(!((i==3) || (i==4))){
-#if defined(linux) || defined(__NetBSD__)
+#if defined(linux) || defined(__NetBSD__) || defined(__sun)
 			e.ether_addr_octet[j] = (uint8_t) id[i];
 #else // e.g. defined(__FreeBSD__)
 			e.octet[j] = (uint8_t) id[i];
@@ -282,6 +298,7 @@
 	/* convert and print hostname */
 	ether_ntohost_cache(buf, &e);
 	len += snprintf(&s[len], max_len - len, "(%s)", buf);
+	if (len > max_len) len = max_len;
 
 	return len;
 }
@@ -292,18 +309,23 @@
 {
 	int len = 0;
 
-	if (info)
+	if (info) {
 		len += snprintf(&s[len], max_len - len, "%s", info);
+		if (len > max_len) len = max_len;
+	}
 
 #ifdef PRINT_MAC_ADDRESSES
 	len += snprint_ClockIdentity_mac(&s[len], max_len - len, id->clockIdentity, NULL);
 #else	
 	len += snprint_ClockIdentity(&s[len], max_len - len, id->clockIdentity, NULL);
 #endif
+	if (len > max_len) len = max_len;
 
 	len += snprint_ClockIdentity_ntohost(&s[len], max_len - len, id->clockIdentity, NULL);
+	if (len > max_len) len = max_len;
 
 	len += snprintf(&s[len], max_len - len, "/%02x", (unsigned) id->portNumber);
+	if (len > max_len) len = max_len;
 	return len;
 }
 
@@ -356,7 +378,6 @@
 		struct timeval now;
 
 		extern char *translatePortState(PtpClock *ptpClock);
-		extern PtpClock *G_ptpClock;
 
 		fprintf(stderr, "   (ptpd %-9s ",
 			priority == LOG_EMERG   ? "emergency)" :
@@ -387,7 +408,51 @@
 	va_end(ap);
 }
 
-void 
+/*
+* Dumps a data buffer
+* This either prints the message to syslog, or with timestamp+state to stderr 
+* (which has possibly been redirected to a file, using logtofile()/dup2()
+*/
+void
+dump(const char *text, void *addr, int len)
+{
+  uint8_t *address = (uint8_t *)addr;
+  extern RunTimeOpts rtOpts;
+  if(rtOpts.useSysLog) {
+    int i;
+    static Boolean logOpened;
+    if(!logOpened) {
+      openlog("ptpd2", 0, LOG_DAEMON);
+      logOpened = TRUE;
+    }
+
+    syslog(LOG_DEBUG, "%s: length %d, data...\n", text, len);
+    for (i = 0; i < len; i++) {
+      syslog(LOG_DEBUG, "0x%02x ", address[i]);
+      if ((i % 8) == 7) {
+        syslog(LOG_DEBUG, "\n");
+      }
+    }
+    if ((i % 8) != 0) {
+      syslog(LOG_DEBUG, "\n");
+    }
+
+  } else {
+    int i;
+    fprintf(stderr, "%s: length %d, data...\n", text, len);
+    for (i = 0; i < len; i++) {
+      fprintf(stderr, "0x%02x ", address[i]);
+      if ((i % 8) == 7) {
+        fprintf(stderr, "\n");
+      }
+    }
+    if ((i % 8) != 0) {
+      fprintf(stderr, "\n");
+    }
+  }
+}
+
+void
 displayStats(RunTimeOpts * rtOpts, PtpClock * ptpClock)
 {
 	static int start = 1;
@@ -402,6 +467,14 @@
 		return;
 	}
 
+  /* In non-verbose mode, don't print a separate line for the other ptp clock
+   * instance used for time both if we've in slave state. Conversely, if in 
+   * listening or master state we do want stats, even if this is non-verbose mode
+   */
+  if (!rtOpts->verboseStats && (ptpClock != G_ptpClock) &&
+	(G_ptpClock->portState == PTP_SLAVE)) {
+	return;
+  }
 
 	
 	if (start && rtOpts->csvStats) {
@@ -413,7 +486,7 @@
 	}
 	memset(sbuf, ' ', sizeof(sbuf));
 
-	getTime(&now);
+	getTime(&now, TIME_SYSTEM, ptpClock);
 
 
 	/*
@@ -440,110 +513,167 @@
 	strftime(time_str, MAXTIMESTR, "%Y-%m-%d %X", localtime(&time_s));
 	len += snprintf(sbuf + len, sizeof(sbuf) - len, "%s%s.%06d, %s",
 		       rtOpts->csvStats ? "" : "state: ",
-		       time_str, (int)now.nanoseconds/1000,
+			time_str, (int)now.nanoseconds/1000,
 		       translatePortState(ptpClock));
+	if (len > sizeof(sbuf)) len = sizeof(sbuf);
+
+	if (ptpClock->name != NULL) {
+		len += snprintf(sbuf + len, sizeof(sbuf) - len, "%s ", ptpClock->name);
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
+	}
+
+	if (rtOpts->verboseStats) {
+		len += snprintf(sbuf + len, sizeof(sbuf) - len, "%s, ",
+			translatePortState(ptpClock));
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
+	}
 
 	if (ptpClock->portState == PTP_SLAVE) {
-		len += snprint_PortIdentity(sbuf + len, sizeof(sbuf) - len,
-			 &ptpClock->parentPortIdentity, " ");
+		if (!rtOpts->verboseStats) {
+			int64_t offset = ((int64_t)ptpClock->offsetFromMaster.seconds * 1000000000)
+				+ (int64_t)ptpClock->offsetFromMaster.nanoseconds;
 
-		/* 
-		 * if grandmaster ID differs from parent port ID then
-		 * also print GM ID 
-		 */
-		if (memcmp(ptpClock->grandmasterIdentity, 
-			   ptpClock->parentPortIdentity.clockIdentity, 
-			   CLOCK_IDENTITY_LENGTH)) {
-			len += snprint_ClockIdentity(sbuf + len, 
-						     sizeof(sbuf) - len,
-						     ptpClock->grandmasterIdentity, 
-						     " GM:");
-		}
+			len += snprintf(sbuf + len, sizeof(sbuf) - len, "offset: %"PRIi64" ns", offset);
+			if (len > sizeof(sbuf)) len = sizeof(sbuf);
 
-		len += snprintf(sbuf + len, sizeof(sbuf) - len, ", ");
+			if (rtOpts->time_mode == TIME_BOTH) {
+				int64_t offset = ((int64_t)G_timeBothClock->offsetFromMaster.seconds * 1000000000)
+					+ (int64_t)G_timeBothClock->offsetFromMaster.nanoseconds;
 
-		if (!rtOpts->csvStats)
-			len += snprintf(sbuf + len, 
-					sizeof(sbuf) - len, "owd: ");
-        
+				len += snprintf(sbuf + len, sizeof(sbuf) - len, ", %s offset: %"PRIi64" ns",
+					(G_timeBothClock->name != NULL)? G_timeBothClock->name: "",
+					offset);
+				if (len > sizeof(sbuf)) len = sizeof(sbuf);
+			}
+		} else {
+			if (!rtOpts->csvStats) {
+				len += snprintf(sbuf + len, sizeof(sbuf) - len, "cid: ");
+				if (len > sizeof(sbuf)) len = sizeof(sbuf);
+			}
+			len += snprint_PortIdentity(sbuf + len, sizeof(sbuf) - len,
+				&ptpClock->parentPortIdentity, " ");
+			if (len > sizeof(sbuf)) len = sizeof(sbuf);
+
+      /*
+       * if grandmaster ID differs from parent port ID then
+       * also print GM ID
+       */
+      if (memcmp(ptpClock->grandmasterIdentity,
+                 ptpClock->parentPortIdentity.clockIdentity,
+                 CLOCK_IDENTITY_LENGTH)) {
+        len += snprint_ClockIdentity(sbuf + len, 
+					sizeof(sbuf) - len,
+                                     ptpClock->grandmasterIdentity, 
+				     " GM:");
+        if (len > sizeof(sbuf)) len = sizeof(sbuf);
+      }
+
+      len += snprintf(sbuf + len, sizeof(sbuf) - len, ", ");
+      if (len > sizeof(sbuf)) len = sizeof(sbuf);
+
+      if (!rtOpts->csvStats) {
+        len += snprintf(sbuf + len, 
+			sizeof(sbuf) - len, "owd: ");
+        if (len > sizeof(sbuf)) len = sizeof(sbuf);
+      }
+
 		if(rtOpts->delayMechanism == E2E) {
 			len += snprint_TimeInternal(sbuf + len, sizeof(sbuf) - len,
-						    &ptpClock->meanPathDelay);
+						&ptpClock->meanPathDelay);
 		} else {
 			len += snprint_TimeInternal(sbuf + len, sizeof(sbuf) - len,
 						    &ptpClock->peerMeanPathDelay);
 		}
 
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
 		len += snprintf(sbuf + len, sizeof(sbuf) - len, ", ");
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
 
-		if (!rtOpts->csvStats)
-			len += snprintf(sbuf + len, sizeof(sbuf) - len, 
+		if (!rtOpts->csvStats) {
+			len += snprintf(sbuf + len, sizeof(sbuf) - len,
 					"ofm: ");
+			if (len > sizeof(sbuf)) len = sizeof(sbuf);
+		}
 
 		len += snprint_TimeInternal(sbuf + len, sizeof(sbuf) - len,
-		    &ptpClock->offsetFromMaster);
+                                  &ptpClock->offsetFromMaster);
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
 
 
 
 		/* print MS and SM with sign */
 		len += snprintf(sbuf + len, sizeof(sbuf) - len, ", ");
-		if (!rtOpts->csvStats)
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
+		if (!rtOpts->csvStats) {
 			len += snprintf(sbuf + len, sizeof(sbuf) - len,
 			"stm: ");
-			
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
+		}
+
 		len += snprint_TimeInternal(sbuf + len, sizeof(sbuf) - len,
 				&(ptpClock->delaySM));
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
 
 		len += snprintf(sbuf + len, sizeof(sbuf) - len, ", ");
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
 
 
-		if (!rtOpts->csvStats)
+		if (!rtOpts->csvStats) {
 			len += snprintf(sbuf + len, sizeof(sbuf) - len,
 			"mts: ");
+			if (len > sizeof(sbuf)) len = sizeof(sbuf);
+		}
 
 		len += snprint_TimeInternal(sbuf + len, sizeof(sbuf) - len,
 				&(ptpClock->delayMS));
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
+
+
+		len += sprintf(sbuf + len, ", %s%Lf",
+                     rtOpts->csvStats ? "" : "drift: ",
+		     ptpClock->observed_drift);
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
 
 		
-		len += sprintf(sbuf + len, ", %s%d",
-		    rtOpts->csvStats ? "" : "drift: ", 
-			       ptpClock->observed_drift);
-
-
 
 
 		/* Last column has the type of last packet processed by the servo */
 		len += snprintf(sbuf + len, sizeof(sbuf) - len, ", ");
+		if (len > sizeof(sbuf)) len = sizeof(sbuf);
 
-		if (!rtOpts->csvStats)
-			len += snprintf(sbuf + len, sizeof(sbuf) - len,
-			"last_msg: ");
+      if (!rtOpts->csvStats) {
+        len += snprintf(sbuf + len, sizeof(sbuf) - len,
+	"last_msg: ");
+        if (len > sizeof(sbuf)) len = sizeof(sbuf);
+      }
 
-		len += snprintf(sbuf + len, sizeof(sbuf) - len,
-				"%c ", ptpClock->char_last_msg);
+      len += snprintf(sbuf + len, sizeof(sbuf) - len,
+		      "%c ", ptpClock->char_last_msg);
+      if (len > sizeof(sbuf)) len = sizeof(sbuf);
+    }
+  }
+  else {
+    if ((ptpClock->portState == PTP_MASTER) || (ptpClock->portState == PTP_PASSIVE)) {
 
-	}
-	else {
-		if ((ptpClock->portState == PTP_MASTER) || (ptpClock->portState == PTP_PASSIVE)) {
+      len += snprint_PortIdentity(sbuf + len, sizeof(sbuf) - len,
+                                  &ptpClock->parentPortIdentity, " ");
+      if (len > sizeof(sbuf)) len = sizeof(sbuf);
+    }
 
-			len += snprint_PortIdentity(sbuf + len, sizeof(sbuf) - len,
-				 &ptpClock->parentPortIdentity, " ");
-							 
-			//len += snprintf(sbuf + len, sizeof(sbuf) - len, ")");
-		}
 
-		
-		/* show the current reset number on the log */
-		if (ptpClock->portState == PTP_LISTENING) {
-			len += snprintf(sbuf + len,
-						     sizeof(sbuf) - len,
-						     " %d ", ptpClock->reset_count);
-		}
-	}
+    /* show the current reset number on the log */
+    if (ptpClock->portState == PTP_LISTENING) {
+      len += snprintf(sbuf + len,
+		      sizeof(sbuf) - len,
+                      " num_resets: %d ", ptpClock->reset_count);
+      if (len > sizeof(sbuf)) len = sizeof(sbuf);
+    }
+  }
 
-	
-	/* add final \n in normal status lines */
-	len += snprintf(sbuf + len, sizeof(sbuf) - len, "\n");
+
+  /* add final \n in normal status lines */
+  len += snprintf(sbuf + len, sizeof(sbuf) - len, "\n");
+  if (len > sizeof(sbuf)) len = sizeof(sbuf);
 
 #if 0   /* NOTE: Do we want this? */
 	if (rtOpts->nonDaemon) {
@@ -551,8 +681,8 @@
 		len += snprintf(sbuf + len, sizeof(sbuf) - len, "\n");
 	}
 #endif
-	write(1, sbuf, rtOpts->csvStats ? len : SCREEN_MAXSZ + 1);
-	
+	write(1, sbuf, len);
+
 }
 
 
@@ -581,6 +711,7 @@
 	return TRUE;
 }
 
+#if 0 /* Defined in dep/time.c - fetch time from hw */
 void 
 getTime(TimeInternal * time)
 {
@@ -600,21 +731,7 @@
 	time->nanoseconds = tp.tv_nsec;
 #endif /* linux || __APPLE__ */
 }
-
-void 
-setTime(TimeInternal * time)
-{
-	struct timeval tv;
- 
-	tv.tv_sec = time->seconds;
-	tv.tv_usec = time->nanoseconds / 1000;
-	WARNING("Going to step the system clock to %ds %dns\n",
-	       time->seconds, time->nanoseconds);
-	settimeofday(&tv, 0);
-	WARNING("Finished stepping the system clock to %ds %dns\n",
-	       time->seconds, time->nanoseconds);
-}
-
+#endif
 
 /* returns a double beween 0.0 and 1.0 */
 double 
@@ -627,44 +744,123 @@
 
 
 
-/*
- * TODO: this function should have been coded in a way to manipulate both the frequency and the tick,
- * to avoid having to call setTime() when the clock is very far away.
- * This would result in situations we would force the kernel clock to run the clock twice as slow,
- * in order to avoid stepping time backwards
- */
 #if !defined(__APPLE__)
-Boolean
-adjFreq(Integer32 adj)
+void
+setTimexFlags(int flags, Boolean quiet)
 {
-	struct timex t;
+	struct timex tmx;
+	int ret;
 
-	memset(&t, 0, sizeof(t));
-	if (adj > ADJ_FREQ_MAX){
-		adj = ADJ_FREQ_MAX;
-	} else if (adj < -ADJ_FREQ_MAX){
-		adj = -ADJ_FREQ_MAX;
+	memset(&tmx, 0, sizeof(tmx));
+
+	tmx.modes = MOD_STATUS;
+
+	tmx.status = getTimexFlags();
+	if(tmx.status == -1) 
+		return;
+	/* unset all read-only flags */
+	tmx.status &= ~STA_RONLY;
+	tmx.status |= flags;
+
+	ret = adjtimex(&tmx);
+
+	if (ret < 0)
+		PERROR("Could not set adjtimex flags: %s", strerror(errno));
+
+	if(!quiet && ret > 2) {
+		switch (ret) {
+		case TIME_OOP:
+			WARNING("Adjtimex: leap second already in progress\n");
+			break;
+		case TIME_WAIT:
+			WARNING("Adjtimex: leap second already occurred\n");
+			break;
+#if !defined(TIME_BAD)
+		case TIME_ERROR:
+#else
+		case TIME_BAD:
+#endif /* TIME_BAD */
+		default:
+			DBGV("unsetTimexFlags: adjtimex() returned TIME_BAD\n");
+			break;
+		}
+	}
+}
+
+void
+unsetTimexFlags(int flags, Boolean quiet) 
+{
+	struct timex tmx;
+	int ret;
+
+	memset(&tmx, 0, sizeof(tmx));
+
+	tmx.modes = MOD_STATUS;
+	tmx.status = getTimexFlags();
+	if(tmx.status == -1)
+		return;
+
+	/* unset all read-only flags */
+	tmx.status &= ~STA_RONLY;
+	tmx.status &= ~flags;
+
+	ret = adjtimex(&tmx);
+
+	if (ret < 0)
+		PERROR("Could not unset adjtimex flags: %s", strerror(errno));
+
+	if(!quiet && ret > 2) {
+		switch (ret) {
+		case TIME_OOP:
+			WARNING("Adjtimex: leap second already in progress\n");
+			break;
+		case TIME_WAIT:
+			WARNING("Adjtimex: leap second already occurred\n");
+			break;
+#if !defined(TIME_BAD)
+		case TIME_ERROR:
+#else
+		case TIME_BAD:
+#endif /* TIME_BAD */
+		default:
+			DBGV("unsetTimexFlags: adjtimex() returned TIME_BAD\n");
+			break;
+		}
+	}
+}
+
+int getTimexFlags(void)
+{
+	struct timex tmx;
+	int ret;
+
+	memset(&tmx, 0, sizeof(tmx));
+
+	tmx.modes = 0;
+	ret = adjtimex(&tmx);
+	if (ret < 0) {
+		PERROR("Could not read adjtimex flags: %s", strerror(errno));
+		return(-1);
+
 	}
 
-	t.modes = MOD_FREQUENCY;
-	t.freq = adj * ((1 << 16) / 1000);
+	return( tmx.status );
+}
 
-	/* do calculation in double precision, instead of Integer32 */
-	int t1 = t.freq;
-	int t2;
-	
-	float f = (adj + 0.0) * (((1 << 16) + 0.0) / 1000.0);  /* could be float f = adj * 65.536 */
-	t2 = t1;  // just to avoid compiler warning
-	t2 = (int)round(f);
-	t.freq = t2;
+Boolean
+checkTimexFlags(int flags) {
 
-	DBG2("        adj is %d;  t freq is %d       (float: %f Integer32: %d)\n", adj, t.freq,  f, t1);
-	
-	return !adjtimex(&t);
+    int tflags = getTimexFlags();
+    if (tflags == -1) 
+	    return FALSE;
+    return ((tflags & flags) == flags);
 }
 
 #else
 
+/* @ioctl_timestamping TODO This won't work - not sure whether we can easily support
+* apple and ioctl timestamping */
+
 void
 adjTime(Integer32 nanoseconds)
 {
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/time.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dep/time.c	Sun Oct 27 22:49:29 2013 -0700
@@ -0,0 +1,1208 @@
+/*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "../ptpd.h"
+#include <stdarg.h>
+#include <math.h>
+
+#ifdef __sun
+#include <unistd.h>
+#include <stropts.h>
+#endif
+
+
+#ifdef linux
+
+#include <asm/types.h>
+#include <linux/errqueue.h>
+
+/* SO_EE_ORIGIN_TIMESTAMPING is defined in linux/errqueue.h in recent kernels.
+ * Define it for compilation with older kernels.
+ */
+#ifndef SO_EE_ORIGIN_TIMESTAMPING
+#define SO_EE_ORIGIN_TIMESTAMPING 4
+#endif
+
+/* SO_TIMESTAMPING is defined in asm/socket.h in recent kernels.
+ * Define it for compilation with older kernels.
+ */
+#ifndef SO_TIMESTAMPING
+#define SO_TIMESTAMPING  37
+#define SCM_TIMESTAMPING SO_TIMESTAMPING
+#endif
+
+/* SIOCSHWTSTAMP is defined in linux/sockios.h in recent kernels.
+ * Define it for compilation with older kernels.
+ */
+#ifndef SIOCSHWTSTAMP
+#define SIOCSHWTSTAMP 0x89b0
+#endif
+
+#endif /*linux*/
+
+/* SO_TIMESTAMPING gets an integer bit field comprised of these values */
+enum {
+	SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
+	SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1),
+	SOF_TIMESTAMPING_RX_HARDWARE = (1<<2),
+	SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3),
+	SOF_TIMESTAMPING_SOFTWARE = (1<<4),
+	SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5),
+	SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6),
+	SOF_TIMESTAMPING_MASK =
+	(SOF_TIMESTAMPING_RAW_HARDWARE - 1) |
+	SOF_TIMESTAMPING_RAW_HARDWARE
+};
+
+#ifdef __sun
+#include "sfxge_ioctl.h"
+#else 
+#include "efx_ioctl.h"
+#endif
+
+/** global state for controlling system time when TIME_BOTH is selected */
+static PtpClock timeBothClock;
+PtpClock *G_timeBothClock = NULL;
+
+/** run time optsions for controlling system time when TIME_BOTH is selected */
+static  RunTimeOpts timeBothRtOpts;
+RunTimeOpts *G_timeBothRtOpts = NULL;
+
+/**
+ * Most recent send time stamp from NIC, 0/0 if none available right now.
+ * Reset by getSendTime().
+ */
+static TimeInternal lastSendTime;
+
+#ifndef RECV_ARRAY_SIZE
+/**
+ * Must be large enough to buffer all time stamps received from the NIC
+ * but not yet requested by the protocol processor. Because new information
+ * can only be added when the protocol asks for old one, this should not
+ * get very full.
+ */
+# define RECV_ARRAY_SIZE 10
+#endif
+
+/**
+ * An array of the latest RECV_ARRAY_SIZE packet receive information.
+ * Once it overflows the oldest ones are overwritten in a round-robin
+ * fashion.
+ */
+static struct {
+  TimeInternal recvTimeStamp;
+  UInteger16 sequenceId;
+  ClockIdentity clockId;
+} lastRecvTimes[RECV_ARRAY_SIZE];
+
+/**
+ * Oldest valid and next free entry in lastRecvTimes.
+ * Valid ones are [oldest, free[ if oldest <= free,
+ * otherwise [oldest, RECV_ARRAY_SIZE[ and [0, free[.
+ */
+static int oldestRecv, nextFreeRecv;
+
+int ptp_ioctl(NetPath *netPath, void *drv_ioctl)
+{
+#ifndef __sun
+	netPath.eventSockIFR.ifr_data = drv_ioctl;
+	return(ioctl(netPath->eventSock, SIOCEFX, &netPath->eventSockIFR));
+#else	/* __sun */
+	struct strioctl ioc;
+	struct sfxge_sock_ioctl *req = (struct sfxge_sock_ioctl *)drv_ioctl;
+	int len;
+
+	switch(req->cmd) {
+		case SFXGE_TS_INIT:
+			len = sizeof (struct sfxge_hwtstamp_config);
+			DBGV("SFXGE_TS_INIT issued\n");
+			break;
+		case SFXGE_TS_READ:
+			len = sizeof (struct sfxge_ts_read);
+			DBGV("SFXGE_TS_READ issued\n");
+			break;
+		case SFXGE_TS_ADJTIME:
+			len = sizeof (struct sfxge_ts_adjtime);
+			DBGV("SFXGE_TS_ADJTIME issued\n");
+			break;
+		case SFXGE_TS_SETTIME:
+			len = sizeof (struct sfxge_ts_settime);
+			DBGV("SFXGE_TS_SETTIME issued\n");
+			break;
+		case SFXGE_TS_SYNC:
+			len = sizeof (struct sfxge_ts_sync);
+			DBGV("SFXGE_TS_SYNC issued\n");
+			break;
+		default:
+			printf("Unknown ioctl number %x ... exiting\n", req->cmd);
+			exit (1);
+	}
+	(void) memset(&ioc, 0, sizeof (ioc));
+	ioc.ic_cmd = req->cmd;
+	ioc.ic_timout = 0;
+	ioc.ic_len = len;
+	ioc.ic_dp = (char *)&req->u;
+	return (ioctl(netPath->devFd, I_STR, (char *)&ioc));
+#endif	/* __sun */
+}
+/**
+ * if TIME_BOTH: measure NIC<->system time offsets and adapt system time
+ *
+ * This function is called whenever init.c gets control; to prevent to
+ * frequent changes it ignores invocations less than one second away from
+ * the previous one.
+ */
+void syncSystemWithNIC(RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+  TimeInternal delay;
+  static TimeInternal zero;
+#ifdef __sun
+  struct sfxge_sock_ioctl req;
+#else
+  struct efx_sock_ioctl req;
+#endif
+
+  if(rtOpts->time_mode != TIME_BOTH)
+    return;
+
+  /* Limit the number of times per second we synchronise with the NIC */
+  static TimeInternal lastsync;
+  TimeInternal now, t;
+  LongDouble offset;
+  timerNow(&now);
+  subTime(&t, &now, &lastsync);
+  offset = (LongDouble)t.seconds + ((LongDouble)t.nanoseconds / 1000000000);
+  if ((offset > 0) && (offset < rtOpts->system_time_update_interval))
+    return;
+
+  lastsync = now;
+
+  memset(&req, 0, sizeof(req));
+#if  defined(__sun)
+  req.cmd = SFXGE_TS_SYNC;
+#else
+  req.cmd = EFX_TS_SYNC;
+#endif
+  if (ptp_ioctl(&ptpClock->netPath, &req) < 0) {
+    ptpClock->statistics.ts_sync_failures++;
+    ERROR("failed to correlate SFC NIC and system clock %d times (if %s, error %s)\n",
+          ptpClock->statistics.ts_sync_failures,
+          ptpClock->netPath.eventSockIFR.lifr_name, strerror(errno));
+    return;
+  }
+
+  /* For master modes, set the name according to the port state */
+  switch (rtOpts->master_slave_mode) {
+    case PTP_MODE_MASTER_WITH_NTP:
+      if (ptpClock->portState == PTP_MASTER) {
+        ptpClock->name = "[nic->slave]";
+      } else if (ptpClock->portState == PTP_PASSIVE) {
+        ptpClock->name = "[master||nic]";
+      }
+      break;
+      
+    case PTP_MODE_MASTER_NO_NTP:
+      if (ptpClock->portState == PTP_MASTER) {
+        ptpClock->name = "[nic->slave]";
+      } else if (ptpClock->portState == PTP_SLAVE) {
+        ptpClock->name = "[master->nic]";
+      }
+      break;
+      
+    default:
+      /* Do nothing */
+      break;
+  }
+
+  /* Update the timeBothClock with leap seconds in progress from main servo 
+   * to make sure we don't try to update the system clock during the leap
+   * second.
+   */
+  timeBothClock.leapSecondInProgress = ptpClock->leapSecondInProgress;
+
+  // TODO Possibly the delay req time needs to be inverted or doubled
+  // We don't really support a measurement of the one way delay at present.
+
+  DBGV("sync value %lld.%09d\n", req.u.ts_sync.ts.tv_sec, req.u.ts_sync.ts.tv_nsec);
+  delay.seconds = req.u.ts_sync.ts.tv_sec;
+  delay.nanoseconds = req.u.ts_sync.ts.tv_nsec;
+  DBGV("system to NIC delay %ld.%09d\n", delay.seconds, delay.nanoseconds);
+
+  timeBothClock.delay_req_receive_time = delay;
+  timeBothClock.delay_req_send_time = zero;
+  /* Note- we don't use the correction factor- zero */
+  updateDelay(&timeBothClock.owd_filt, &timeBothRtOpts, &timeBothClock, &zero);
+
+  /* Note that the NIC to system delay and system to NIC delay are the same */
+  DBGV("NIC to system delay %ld.%09d\n", delay.seconds, delay.nanoseconds);
+  /* Note that we don't use the correction factor - zero */
+  updateOffset(&delay, &zero, &timeBothClock.ofm_filt, &timeBothRtOpts, &timeBothClock, &zero);
+
+  updateClock(&timeBothRtOpts, &timeBothClock);
+  DBGV("system time updated\n");
+}
+
+static Boolean selectNICTimeMode(TimeMode timeMode, PtpClock *ptpClock)
+{
+  NetPath *netPath = &ptpClock->netPath;
+
+  DBGV("time stamp rx/tx packets\n");
+
+#ifdef linux
+  /* Linux SW mode is an anomaly and we treat it differently to the other modes */
+  if (timeMode == TIME_SYSTEM_LINUX_SW) {
+    /* same as before, but without requiring support by the NIC */
+    int so_timestamping_flags = SOF_TIMESTAMPING_TX_SOFTWARE
+                              | SOF_TIMESTAMPING_RX_SOFTWARE
+                              | SOF_TIMESTAMPING_SOFTWARE;
+
+    if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMPING,
+                   &so_timestamping_flags, sizeof(so_timestamping_flags)) < 0) {
+      ERROR("SO_TIMESTAMPING: setsockopt error: %s", strerror(errno));
+      return FALSE;
+    }
+
+    NOTIFY("SO_TIMESTAMPING (software) enabled\n");
+    ptpClock->tsMethod = TS_METHOD_SO_TIMESTAMPING;
+    return TRUE;
+  }
+#endif
+
+  /* For the modes linux_hw, nic and both, try to enable SO_TIMESTAMPING. If
+   * that fails, attempt IOCTL based timestamping. Otherwise, fail.
+   */
+
+#ifndef __sun /* Do not attempt to compile for the time being if on __sun */
+
+  /* Attempt SO_TIMSTAMPING */
+  NOTIFY("trying SO_TIMESTAMPING...\n");
+
+  {
+  struct hwtstamp_config hwconfig;
+
+    int so_timestamping_flags = SOF_TIMESTAMPING_TX_HARDWARE
+                              | SOF_TIMESTAMPING_RX_HARDWARE
+                              | SOF_TIMESTAMPING_SYS_HARDWARE
+                              | SOF_TIMESTAMPING_RAW_HARDWARE;
+
+    netPath->eventSockIFR.ifr_data = (void *)&hwconfig;
+
+    memset(&hwconfig, 0, sizeof(&hwconfig));
+    hwconfig.tx_type = HWTSTAMP_TX_ON;
+    hwconfig.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+
+    if (ioctl(netPath->eventSock, SIOCSHWTSTAMP, &netPath->eventSockIFR) < 0) {
+      if (errno == ERANGE) {
+        /* hardware time stamping not supported */
+        NOTIFY("SO_TIMESTAMPING: SIOCSHWTSTAMP mode of operation not supported\n");
+      } else {
+        NOTIFY("SO_TIMESTAMPING: SIOCSHWTSTAMP %s\n", strerror(errno));
+      }
+    } else {
+      /* Now enable the SO_TIMESTAMPING option on the event socket */
+      if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMPING,
+                     &so_timestamping_flags, sizeof(so_timestamping_flags)) < 0) {
+        /* Enabling SO_TIMESTAMPING on the socket shouldn't fail if the driver
+         * operation succeeded.
+         */
+        NOTIFY("SO_TIMESTAMPING: setsockopt error: %s", strerror(errno));
+        /* TODO should we carry on? */
+      } else {
+        NOTIFY("SO_TIMESTAMPING enabled\n");
+        ptpClock->tsMethod = TS_METHOD_SO_TIMESTAMPING;
+        return TRUE;
+      }
+    }
+  }
+
+#endif /* ifndef __sun */
+
+  /* Attempt IOCTL timestamping */
+  NOTIFY("trying IOCTL timestamping...\n");
+
+  {
+#ifdef __sun
+  struct sfxge_sock_ioctl req;
+#else
+  struct efx_sock_ioctl req;
+#endif
+    req.u.ts_init.flags = 0;
+    req.u.ts_init.tx_type = HWTSTAMP_TX_ON;
+    req.u.ts_init.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+
+#ifdef __sun
+    req.cmd = SFXGE_TS_INIT;
+#else
+    req.cmd = EFX_TS_INIT;
+#endif
+
+    if(ptp_ioctl(netPath, &req) < 0) {
+      NOTIFY("could not activate SFC hardware rx/tx time stamping on %s, %s\n",
+              netPath->eventSockIFR.lifr_name, strerror(errno));
+    } else {
+      NOTIFY("SFC IOCTL timestamping enabled\n");
+      ptpClock->tsMethod = TS_METHOD_DRIVER_IOCTL;
+      return TRUE;
+    }
+  }
+
+  ERROR("failed to enable IOCTL hardware timestamping!\n");
+  return FALSE;
+}
+
+Boolean initTime(RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+  Boolean rc;
+  
+  switch(rtOpts->time_mode) {
+  case TIME_SYSTEM:
+    ptpClock->tsMethod = TS_METHOD_SYSTEM;
+    return TRUE;
+    break;
+  case TIME_BOTH:
+    /* Prepare clock servo for controlling system time.
+     * TODO We can adjust the secondary servo rate now so this is no longer really true...
+     * "For the system->nic secondary servo, we reset the S, AP and AI parameters
+     * because the servo rate is fixed at 1 second, where as the filter parameters
+     * for the primary may by adjusted to compensate for message frequency and
+     * accuracy of measurements."
+     * Generally if noAdjust is set on the primary, set it on the secondary. The exception is
+     * when a master with NTP. In this case, the secondary is used to sync the NIC clock from
+     * the system clock so enable adjustment.
+     * The four scenarios are as follows:
+     *    Master + NTP:     system --> nic --> slave        (-G option)
+     *    Slave + NTP:      system --> nic  X  master       (-G option)
+     *    Master no NTP:    system <-- nic --> slave        (-W option)
+     *    Slave no NTP:     system <-- nic <-- master       (-g option)
+     */
+    timeBothClock = *ptpClock;
+    timeBothRtOpts = *rtOpts;
+    timeBothRtOpts.s = DEFAULT_DELAY_S;
+    timeBothRtOpts.ap = DEFAULT_AP;
+    timeBothRtOpts.ai = DEFAULT_AI;
+    timeBothClock.portState = PTP_SLAVE;
+
+    switch (rtOpts->master_slave_mode) {
+      case PTP_MODE_MASTER_WITH_NTP:
+        ptpClock->name = "[nic->slave]";
+        timeBothClock.name = "[system->nic]";
+        timeBothRtOpts.time_mode = TIME_NIC;
+        timeBothClock.nic_instead_of_system = TRUE;
+        timeBothRtOpts.noAdjust = DEFAULT_NO_ADJUST_CLOCK;
+        break;
+        
+      case PTP_MODE_MASTER_NO_NTP:
+        ptpClock->name = "[nic->slave]";
+        timeBothClock.name = "[nic->system]";
+        timeBothRtOpts.time_mode = TIME_SYSTEM;
+        timeBothClock.nic_instead_of_system = FALSE;
+        break;
+        
+      case PTP_MODE_SLAVE:
+        ptpClock->name = "[master->nic]";
+        timeBothClock.name = "[nic->system]";
+        timeBothRtOpts.time_mode = TIME_SYSTEM;
+        timeBothClock.nic_instead_of_system = FALSE;
+        break;
+        
+      default:
+        ERROR("Invalid value in switch %d\n", rtOpts->master_slave_mode);
+        return FALSE;
+    }
+
+    initClock(&timeBothRtOpts, &timeBothClock);
+    G_timeBothClock = &timeBothClock;
+    G_timeBothRtOpts = &timeBothRtOpts;
+
+    rc = selectNICTimeMode(rtOpts->time_mode, ptpClock);
+    if (rc && ((rtOpts->master_slave_mode != PTP_MODE_SLAVE) || rtOpts->noResetClock)) {
+      /* If we are in one or the master modes, set the NIC time once using the
+       * current system time. After this, the NIC time will free-run but at least
+       * we won't be shortly after the epoch. Note that we use timerNow rather
+       * than getTime to get the system time because getTime will return the NIC
+       * time in this mode.
+       */
+      TimeInternal time;
+      timerNow(&time);
+      setTime(&time, rtOpts->time_mode, ptpClock);
+      NOTIFY("NIC time set to system time: %d.%d\n", time.seconds, time.nanoseconds);
+    }
+    return rc;
+    break;
+  case TIME_NIC:
+    rc = selectNICTimeMode(rtOpts->time_mode, ptpClock);
+    if (rc && ((rtOpts->master_slave_mode != PTP_MODE_SLAVE) || rtOpts->noResetClock)) {
+      /* If we are in one or the master modes, set the NIC time once using the
+       * current system time. After this, the NIC time will free-run but at least
+       * we won't be shortly after the epoch. Note that we use timerNow rather
+       * than getTime to get the system time because getTime will return the NIC
+       * time in this mode.
+       */
+      TimeInternal time;
+      timerNow(&time);
+      setTime(&time, rtOpts->time_mode, ptpClock);
+      NOTIFY("NIC time set to system time: %d.%d\n", time.seconds, time.nanoseconds);
+    }
+    return rc;
+    break;
+  case TIME_SYSTEM_LINUX_HW:
+  case TIME_SYSTEM_LINUX_SW:
+    return selectNICTimeMode(rtOpts->time_mode, ptpClock);
+    break;
+  default:
+    ERROR("unsupported selection of time source\n");
+    return FALSE;
+    break;
+  }
+}
+
+void shutdownTime(PtpClock *ptpClock)
+{
+  NetPath *netPath = &ptpClock->netPath;
+
+  switch (ptpClock->tsMethod) {
+
+#ifndef __sun  /* Do not compile for the time being if __sun */
+    case TS_METHOD_SO_TIMESTAMPING:
+    {
+      int so_timestamping_flags = 0;
+
+      struct hwtstamp_config hwconfig;
+      netPath->eventSockIFR.ifr_data = (void *)&hwconfig;
+      memset(&hwconfig, 0, sizeof(&hwconfig));
+
+      hwconfig.tx_type = HWTSTAMP_TX_OFF;
+      hwconfig.rx_filter = HWTSTAMP_FILTER_NONE;
+      (void)ioctl(netPath->eventSock, SIOCSHWTSTAMP, &netPath->eventSockIFR);
+
+      (void)setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMPING,
+                       &so_timestamping_flags, sizeof(so_timestamping_flags));
+    }
+      break;
+#endif /* ifndef __sun */
+
+    case TS_METHOD_DRIVER_IOCTL:
+    {
+#ifdef __sun
+      struct sfxge_sock_ioctl req;
+      req.cmd = SFXGE_TS_INIT;
+#else
+      struct efx_sock_ioctl req;
+      req.cmd = EFX_TS_INIT;
+#endif
+      req.u.ts_init.flags = 0;
+      req.u.ts_init.tx_type = HWTSTAMP_TX_OFF;
+      req.u.ts_init.rx_filter = HWTSTAMP_FILTER_NONE;
+      (void)ptp_ioctl(netPath, &req);
+    }
+      break;
+
+    default:
+      break;
+  }
+}
+
+void getTime(TimeInternal *time, TimeMode timeMode, PtpClock *ptpClock)
+{
+  switch(timeMode)
+  {
+  case TIME_SYSTEM_LINUX_HW:
+  case TIME_SYSTEM_LINUX_SW:
+  case TIME_SYSTEM: {
+
+#if defined(__APPLE__) /* TODO Does OSX really not support clock_gettime()? */
+    struct timeval tv;
+
+    gettimeofday(&tv, 0);
+    time->seconds = tv.tv_sec;
+    time->nanoseconds = tv.tv_usec*1000;
+#else
+    struct timespec tv;
+    int err = clock_gettime(CLOCK_REALTIME, &tv);
+    if (err != 0) {
+      ERROR("error getting time %d\n", err);
+      return;
+    }
+    time->seconds = tv.tv_sec;
+    time->nanoseconds = tv.tv_nsec;
+#endif
+    break;
+  }
+  case TIME_BOTH:
+  case TIME_NIC: {
+    NetPath *netPath = &ptpClock->netPath;
+#ifdef __sun
+    struct sfxge_sock_ioctl req;
+#else
+    struct efx_sock_ioctl req;
+#endif
+
+    memset(&req, 0, sizeof(req));
+
+#ifdef __sun
+    req.cmd = SFXGE_TS_SETTIME;
+#else
+    req.cmd = EFX_TS_SETTIME;
+#endif
+    req.u.ts_settime.iswrite = 0;
+    if (ptp_ioctl(netPath, &req) < 0) {
+      ERROR("could not read SFC hardware time on %s: %s\n",
+            netPath->eventSockIFR.lifr_name, strerror(errno));
+      return;
+    }
+    time->seconds = req.u.ts_settime.ts.tv_sec;
+    time->nanoseconds = req.u.ts_settime.ts.tv_nsec;
+    break;
+  }
+  default:
+    ERROR("unsupported selection of time source\n");
+    break;
+  }
+}
+
+void setTime(TimeInternal *time, TimeMode timeMode, PtpClock *ptpClock)
+{
+  switch(timeMode)
+  {
+  case TIME_SYSTEM_LINUX_HW:
+  case TIME_SYSTEM_LINUX_SW:
+  case TIME_SYSTEM: {
+    WARNING("going to step the system clock to %ds %dns\n",
+            time->seconds, time->nanoseconds);
+#if defined(__APPLE__) /* TODO Does OSX really not support clock_settime()? */
+    struct timeval tv;
+    tv.tv_sec = time->seconds;
+    tv.tv_usec = time->nanoseconds/1000;
+    settimeofday(&tv, 0);
+#else
+    struct timespec tv;
+    tv.tv_sec = time->seconds;
+    tv.tv_nsec = time->nanoseconds;
+    int err = clock_settime(CLOCK_REALTIME, &tv);
+    if (err != 0) {
+      ERROR("error setting time %d\n", err);
+      return;
+    }
+#endif
+    WARNING("finished stepping the system clock to %ds %dns\n",
+            time->seconds, time->nanoseconds);
+    break;
+  }
+  case TIME_BOTH:
+  case TIME_NIC: {
+    NetPath *netPath = &ptpClock->netPath;
+#ifdef __sun
+    struct sfxge_sock_ioctl req;
+#else
+    struct efx_sock_ioctl req;
+#endif
+
+    TimeInternal currentTime, offset;
+
+    memset(&req, 0, sizeof(req));
+
+    NOTIFY("resetting NIC clock to %ds %dns\n", time->seconds, time->nanoseconds);
+    getTime(&currentTime, timeMode, ptpClock);
+    subTime(&offset, time, &currentTime);
+
+    req.u.ts_settime.iswrite = 1;
+    req.u.ts_settime.ts.tv_sec = offset.seconds;
+    req.u.ts_settime.ts.tv_nsec = offset.nanoseconds;
+#ifdef __sun
+    req.cmd = SFXGE_TS_SETTIME;
+#else
+    req.cmd = EFX_TS_SETTIME;
+#endif
+
+    NOTIFY("adding NIC offset %ld.%09d (%ld/%p)\n",
+           req.u.ts_settime.ts.tv_sec, req.u.ts_settime.ts.tv_nsec,
+           sizeof(req), &req);
+    if (ptp_ioctl(netPath, &req) < 0) {
+      ERROR("could not set SFC hardware time on %s: %s\n",
+            netPath->eventSockIFR.lifr_name, strerror(errno));
+    }
+    else
+    {
+      DBGV("new NIC time %ld.%09d\n",
+           req.u.ts_settime.ts.tv_sec,
+           req.u.ts_settime.ts.tv_nsec);
+    }
+    break;
+  }
+  default:
+    ERROR("unsupported selection of time source\n");
+    break;
+  }
+}
+
+
+void adjTime(LongDouble adj, TimeMode timeMode, PtpClock *ptpClock)
+{
+  switch(timeMode)
+  {
+  case TIME_SYSTEM_LINUX_HW:
+  case TIME_SYSTEM_LINUX_SW:
+  case TIME_SYSTEM: {
+    struct timex t;
+    static Boolean maxAdjValid;
+    static LongDouble maxAdj;
+    static LongDouble minTick, maxTick;
+    static LongDouble userHZ;
+    static LongDouble tickRes; /* USER_HZ * 1000 [ppb] */
+    LongDouble tickAdj;
+    LongDouble freqAdj;
+    long maxError;
+    int res;
+
+    if (!maxAdjValid) {
+        userHZ = (LongDouble)sysconf(_SC_CLK_TCK);
+        t.modes = 0;
+#ifdef __sun
+#warning Solaris - struct timex: t.constant is arbitrarily assigned to 15
+    t.constant = 15; /* need to be >0 but <30 */
+#endif
+        adjtimex(&t);
+        maxAdj = (LongDouble)t.tolerance / (((1<<16)+0.0)/1000.0);
+        tickRes = userHZ * 1000.0;
+        /* limits from the adjtimex command man page; could be determined via binary search */
+        minTick = (900000.0 - 1000000.0) / userHZ;
+        maxTick = (1100000.0 - 1000000.0) / userHZ;
+        maxAdjValid = TRUE;
+    }
+
+    /*
+     * The Linux man page for the adjtimex() system call does not
+     * describe limits for frequency. The more recent man page for
+     * the adjtimex command on RH5 does and says that
+     * -tolerance <= frequency <= tolerance
+     * which was confirmed by trying out values just outside that interval.
+     *
+     * Note that this contradicts the comments for struct timex which say
+     * that freq and tolerance have different units (scaled ppm vs ppm).
+     *
+     * We follow the actual implementation on Linux 2.6.22 and do the
+     * range check after scaling.
+     */
+
+     /* LDE 17082011 Set max error to stop adjtimex reported bad time */
+     t.modes = MOD_FREQUENCY|MOD_CLKB|MOD_MAXERROR;
+
+    /*
+     * 1 t.tick = 1 e-6 s * USER_HZ 1/s = 1 USER_HZ * 1000 ppb
+     *
+     * Large values of adj can be turned into t.tick adjustments:
+     * tickAdj t.tick = adj ppb / ( USER_HZ * 1000 ppb )
+     *
+     * Round this so that the error is as small is possible,
+     * because we need to fit that into t.freq.
+     */
+    freqAdj = adj;
+    tickAdj = 0;
+    if(freqAdj > maxAdj)
+    {
+      tickAdj = round((adj - maxAdj) / tickRes);
+      if(tickAdj > maxTick)
+        tickAdj = maxTick;
+      freqAdj = adj - tickAdj * tickRes;
+    }
+    else if(freqAdj < -maxAdj)
+    {
+      tickAdj = -round((-adj - maxAdj) / tickRes);
+      if(tickAdj < minTick)
+        tickAdj = minTick;
+      freqAdj = adj - tickAdj * tickRes;
+    }
+    if(freqAdj > maxAdj)
+      freqAdj = maxAdj;
+    else if(freqAdj < -maxAdj)
+      freqAdj = -maxAdj;
+
+    t.freq = (long)round(freqAdj * (((1 << 16) + 0.0) / 1000.0));
+#ifdef __sun
+#warning Solaris - struct timex: no field named tick
+#warning Solaris - struct timex: t.constant is arbitrarily assigned to 15
+    t.constant = 15; /* need to be >0 but <30 */
+#else
+    t.tick = (long)round(tickAdj + (1000000.0 / userHZ));
+#endif
+    ptpClock->frequency_adjustment = tickAdj * tickRes + freqAdj;
+
+    /* LDE 17082011 Set the max error to the current offset from master */
+    /* Saturate the max error at 2000 seconds. This is close the max value that */
+    /* fit in the max error field. */
+    if (ptpClock->offsetFromMaster.seconds > 2000) {
+      maxError = 0xffffffff;
+    } else {
+      maxError = ptpClock->offsetFromMaster.seconds * 1000000;
+      if (ptpClock->offsetFromMaster.nanoseconds > 0) {
+        maxError += ptpClock->offsetFromMaster.nanoseconds/1000;
+      } else {
+        maxError -= ptpClock->offsetFromMaster.nanoseconds/1000;
+      }
+    }
+    t.maxerror = maxError;
+
+#ifndef __sun
+    DBG("requested adj %Lf ppb => adjust system frequency by %ld scaled ppm (%Lf ppb) + %ld us/tick "
+        "(%Lf ppb) = adj %Lf ppb (freq limit %Lf/%Lf ppm, tick limit %Lf/%Lf us*USER_HZ)\n",
+        adj,
+        t.freq, freqAdj,
+        (long)(t.tick - 1000000.0 / userHZ), tickAdj * tickRes,
+        ptpClock->frequency_adjustment,
+        -maxAdj, maxAdj,
+        minTick, maxTick);
+#endif
+    res = adjtimex(&t);
+    switch (res) {
+    case -1:
+        ERROR("adjtimex(freq = %d) failed: %s\n",
+              t.freq, strerror(errno));
+        break;
+    case TIME_OK:
+        DBG("  -> TIME_OK\n");
+        break;
+    case TIME_INS:
+        ERROR("adjtimex -> insert leap second?!\n");
+        break;
+    case TIME_DEL:
+        ERROR("adjtimex -> delete leap second?!\n");
+        break;
+    case TIME_OOP:
+        ERROR("adjtimex -> leap second in progress?!\n");
+        break;
+    case TIME_WAIT:
+        ERROR("adjtimex -> leap second has occurred?!\n");
+        break;
+    case TIME_BAD:
+        ERROR("adjtimex -> time bad\n");
+        /* Clear the unsynchronised flag - we are synchronised */
+        t.modes = MOD_STATUS;
+        t.status &= ~STA_UNSYNC;
+        (void)adjtimex(&t);
+        INFO("clearing system time unsynchronised flag\n");
+        break;
+    default:
+        ERROR("adjtimex -> unknown result %d\n", res);
+        break;
+    }
+    break;
+  }
+  case TIME_BOTH:
+  case TIME_NIC: {
+    /* adjust NIC frequency */
+    NetPath *netPath = &ptpClock->netPath;
+#ifdef __sun
+    struct sfxge_sock_ioctl req;
+#else
+    struct efx_sock_ioctl req;
+#endif
+
+    memset(&req, 0, sizeof(req));
+    if (ptpClock->nic_instead_of_system) {
+      req.u.ts_adjtime.adjustment = (long long)round(-adj);
+      ptpClock->frequency_adjustment = -adj;
+    } else {
+      req.u.ts_adjtime.adjustment = (long long)round(adj);
+      ptpClock->frequency_adjustment = adj;
+    }
+    req.u.ts_adjtime.iswrite = 1;
+#ifdef __sun
+    req.cmd = SFXGE_TS_ADJTIME;
+#else
+    req.cmd = EFX_TS_ADJTIME;
+#endif
+    DBGV("adjust NIC frequency by %lld (%Lf) ppb\n",
+          req.u.ts_adjtime.adjustment, ptpClock->frequency_adjustment);
+    if (ptp_ioctl(netPath, &req) < 0) {
+      ERROR("could not modify SFC hardware frequency on %s: %s\n",
+            netPath->eventSockIFR.lifr_name, strerror(errno));
+    }
+    break;
+  }
+  default:
+    ERROR("unsupported selection of time source\n");
+    break;
+  }
+}
+
+void adjTimeOffset(TimeInternal *offset, TimeMode timeMode, PtpClock *ptpClock)
+{
+  switch(timeMode)
+  {
+    case TIME_BOTH:
+    case TIME_NIC: {
+      NetPath *netPath = &ptpClock->netPath;
+#ifdef __sun
+      struct sfxge_sock_ioctl req;
+#else
+      struct efx_sock_ioctl req;
+#endif
+
+      memset(&req, 0, sizeof(req));
+      req.u.ts_settime.iswrite = 1;
+      req.u.ts_settime.ts.tv_sec = offset->seconds;
+      req.u.ts_settime.ts.tv_nsec = offset->nanoseconds;
+#ifdef __sun
+      req.cmd = SFXGE_TS_SETTIME;
+#else
+      req.cmd = EFX_TS_SETTIME;
+#endif
+
+      /* invert the sign: if offset is positive, we need to substract it and vice versa;
+       * when in nic_instead_of_system the logic is already inverted
+       */
+      // TODO check that time is normalised at this point / use arith fns for all time ops
+      if (!ptpClock->nic_instead_of_system) {
+        req.u.ts_settime.ts.tv_sec *= -1;
+        req.u.ts_settime.ts.tv_nsec *= -1;
+      }
+
+      DBGV("adjust NIC time by offset %ld.%09d\n",
+          (UInteger32)req.u.ts_settime.ts.tv_sec, req.u.ts_settime.ts.tv_nsec);
+      if (ptp_ioctl(netPath, &req) < 0) {
+        ERROR("could not modify SFC hardware time on %s: %s\n",
+              ptpClock->netPath.eventSockIFR.lifr_name,
+              strerror(errno));
+      }
+      break;
+    }
+
+    default: {
+      TimeInternal timeTmp;
+
+      DBG2("Adjusting system time by offset %ld.%09d\n", offset->seconds, offset->nanoseconds);
+
+      getTime(&timeTmp, timeMode, ptpClock);
+      DBGV("**** Time was %ld.%09d\n", timeTmp.seconds, timeTmp.nanoseconds);
+      subTime(&timeTmp, &timeTmp, offset);
+      /* We don't allow the time to be set to before 1/1/1971 because this almost */
+      /* certainly means something has gone very wrong */
+      if (timeTmp.seconds < UTC_TIME_VALID_MINIMUM) {
+        DBG("**** Refusing to set system time to %ld.%09d\n", timeTmp.seconds, timeTmp.nanoseconds);
+      } else {
+        setTime(&timeTmp, timeMode, ptpClock);
+        DBG("System time adjusted to %ld.%09d\n", timeTmp.seconds, timeTmp.nanoseconds);
+      }
+    }
+  }
+}
+
+void adjTimeInsertLeapSecond(TimeMode timeMode, RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+	if (rtOpts->noResetClock || rtOpts->resetClockStartupOnly)
+		return;
+	
+	switch(timeMode) {
+	case TIME_BOTH:
+	case TIME_NIC: 
+	case TIME_SYSTEM_LINUX_HW:
+	{
+		NetPath *netPath = &ptpClock->netPath;
+		LongDouble adj;
+#ifdef __sun
+		struct sfxge_sock_ioctl req;
+#else
+		struct efx_sock_ioctl req;
+#endif
+		memset(&req, 0, sizeof(req));
+#if defined(__sun)
+		req.cmd = SFXGE_TS_SETTIME;
+#else
+		req.cmd = EFX_TS_SETTIME;
+#endif 
+
+		req.u.ts_settime.iswrite = 1;
+		req.u.ts_settime.ts.tv_sec = -1;
+		req.u.ts_settime.ts.tv_nsec = 0;
+
+		DBGV("insert leap second in NIC time\n");
+		if (ptp_ioctl(netPath, &req) < 0) {
+			ERROR("could not modify SFC hardware time on %s: %s\n",
+			      ptpClock->netPath.eventSockIFR.lifr_name,
+			      strerror(errno));
+		}
+
+		/* Applying an offset resets the frequency adjustment to 0 (doh!)
+		 * If we are running in time mode both or nic, we need to set the
+		 * frequency adjustment back to the correct value immediately!
+		 */
+		if ((timeMode == TIME_BOTH) || (timeMode == TIME_NIC)) {
+			adj = (LongDouble)ptpClock->offsetFromMaster.nanoseconds / rtOpts->ap
+			    + ptpClock->observed_drift;
+
+			adjTime(-adj, timeMode, ptpClock);
+		}
+		break;
+	}
+
+	default:
+		INFO("No need to insert leap second for mode - handled by kernel\n");
+	}
+}
+
+void adjTimeDeleteLeapSecond(TimeMode timeMode, RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+
+	if (rtOpts->noResetClock || rtOpts->resetClockStartupOnly)
+		return;
+	
+	switch(timeMode) {
+	case TIME_BOTH:
+	case TIME_NIC:
+	case TIME_SYSTEM_LINUX_HW:
+	{
+		NetPath *netPath = &ptpClock->netPath;
+		LongDouble adj;
+
+#ifdef __sun
+		struct sfxge_sock_ioctl req;
+
+		memset(&req, 0, sizeof(req));
+		req.cmd = SFXGE_TS_SETTIME;
+#else
+		struct efx_sock_ioctl req;
+
+		memset(&req, 0, sizeof(req));
+		req.cmd = EFX_TS_SETTIME;
+#endif
+
+		req.u.ts_settime.iswrite = 1;
+		req.u.ts_settime.ts.tv_sec = 1;
+		req.u.ts_settime.ts.tv_nsec = 0;
+
+		DBGV("delete leap second from NIC time\n");
+		if (ptp_ioctl(netPath, &req) < 0) {
+			ERROR("could not modify SFC hardware time on %s: %s\n",
+			      ptpClock->netPath.eventSockIFR.lifr_name,
+			      strerror(errno));
+		}
+
+		/* Applying an offset resets the frequency adjustment to 0 (doh!)
+		 * If we are running in time mode both or nic, we need to set the
+		 * frequency adjustment back to the correct value immediately!
+		 */
+		if ((timeMode == TIME_BOTH) || (timeMode == TIME_NIC)) {
+			adj = (LongDouble)ptpClock->offsetFromMaster.nanoseconds / rtOpts->ap
+			    + ptpClock->observed_drift;
+
+			adjTime(-adj, timeMode, ptpClock);
+		}
+		break;
+	}
+
+	default:
+		INFO("No need to insert leap second for mode - handled by kernel\n");
+	}
+}
+
+
+static void getTimeStamps(TimeMode timeMode, NetPath *netPath)
+{
+#ifdef __sun
+  struct sfxge_sock_ioctl req;
+#else
+  struct efx_sock_ioctl req;
+#endif
+
+  Boolean rawTime = (timeMode == TIME_BOTH) || (timeMode == TIME_NIC);
+
+  /* Repeatedly call the IOCTL until we have all the timestamps */
+  do {
+    memset(&req, 0, sizeof(req));
+#ifdef __sun
+    req.cmd = SFXGE_TS_READ;
+#else
+    req.cmd = EFX_TS_READ;
+#endif
+    if(ptp_ioctl(netPath, &req) < 0) {
+      ERROR("could not read SFC hardware time stamps on %s: %s\n",
+            netPath->eventSockIFR.lifr_name, strerror(errno));
+      return;
+    }
+
+    DBGV("rx %s, tx %s\n",
+         req.u.ts_read.rx_valid ? "valid" : "invalid",
+         req.u.ts_read.tx_valid ? "valid" : "invalid");
+
+    if(req.u.ts_read.rx_valid)
+    {
+      int newIndex;
+
+      if(nextFreeRecv == RECV_ARRAY_SIZE)
+      {
+        newIndex = 0;
+        nextFreeRecv = 1;
+        oldestRecv = 2;
+      }
+      else
+      {
+        newIndex = nextFreeRecv;
+        nextFreeRecv++;
+        if(oldestRecv && nextFreeRecv == oldestRecv)
+          ++oldestRecv;
+      }
+
+      if(oldestRecv >= RECV_ARRAY_SIZE)
+        oldestRecv = 0;
+
+      DBGV("new entry %d, oldest %d, next free %d\n", newIndex, oldestRecv, nextFreeRecv);
+
+      if (rawTime) {
+        lastRecvTimes[newIndex].recvTimeStamp.seconds = req.u.ts_read.rx_ts_hw.tv_sec;
+        lastRecvTimes[newIndex].recvTimeStamp.nanoseconds = req.u.ts_read.rx_ts_hw.tv_nsec;
+      } else {
+        lastRecvTimes[newIndex].recvTimeStamp.seconds = req.u.ts_read.rx_ts.tv_sec;
+        lastRecvTimes[newIndex].recvTimeStamp.nanoseconds = req.u.ts_read.rx_ts.tv_nsec;
+      }
+      lastRecvTimes[newIndex].sequenceId = ((uint16_t)req.u.ts_read.seqid[0] << 8)
+                                         | (uint16_t)req.u.ts_read.seqid[1];
+
+      /* Section 18.3.7 IEEE1588. Version 1 UUIDs are mapped into octets 2-7 of the clock
+       * ID. We don't compare the first two octets.
+       */
+      lastRecvTimes[newIndex].clockId[0] = 0;
+      lastRecvTimes[newIndex].clockId[1] = 0;
+      memcpy(lastRecvTimes[newIndex].clockId + sizeof(lastRecvTimes[newIndex].clockId) - sizeof(req.u.ts_read.uuid),
+             req.u.ts_read.uuid,
+             sizeof(req.u.ts_read.uuid));
+
+      DBGV("rx %d: time %d.%09u, sequence %u, uuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+           newIndex,
+           lastRecvTimes[newIndex].recvTimeStamp.seconds,
+           lastRecvTimes[newIndex].recvTimeStamp.nanoseconds,
+           lastRecvTimes[newIndex].sequenceId,
+           req.u.ts_read.uuid[0], req.u.ts_read.uuid[1], req.u.ts_read.uuid[2],
+           req.u.ts_read.uuid[3], req.u.ts_read.uuid[4], req.u.ts_read.uuid[5]);
+    }
+
+    if(req.u.ts_read.tx_valid)
+    {
+      if (rawTime) {
+        lastSendTime.seconds = req.u.ts_read.tx_ts_hw.tv_sec;
+        lastSendTime.nanoseconds = req.u.ts_read.tx_ts_hw.tv_nsec;
+      } else {
+        lastSendTime.seconds = req.u.ts_read.tx_ts.tv_sec;
+        lastSendTime.nanoseconds = req.u.ts_read.tx_ts.tv_nsec;
+      }
+
+      DBGV("tx time %d.%09d (%d.%09d)\n",
+           lastSendTime.seconds, lastSendTime.nanoseconds,
+           req.u.ts_read.tx_ts.tv_sec, req.u.ts_read.tx_ts.tv_nsec);
+    }
+  } while (req.u.ts_read.tx_valid || req.u.ts_read.rx_valid);
+}
+
+Boolean getSendTime(TimeInternal *sendTimeStamp,
+                    TimeMode timeMode, NetPath *netPath)
+{
+  /* check for new time stamps */
+  getTimeStamps(timeMode, netPath);
+
+  if(lastSendTime.seconds || lastSendTime.nanoseconds)
+  {
+    *sendTimeStamp = lastSendTime;
+    lastSendTime.seconds = 0;
+    lastSendTime.nanoseconds = 0;
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+/**
+ * helper function for getReceiveTime() which searches for time stamp
+ * in lastRecvTimes[leftIndex, rightIndex[
+ */
+static Boolean getReceiveTimeFromArray(TimeInternal *recvTimeStamp,
+                                       ClockIdentity clockId,
+                                       UInteger16 sequenceId,
+                                       int leftIndex, int rightIndex)
+{
+  int i;
+
+  DBGV("left idx %d, right idx %d\n", leftIndex, rightIndex);
+
+  //DBGV("sequence id %d, clock id %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+  //     sequenceId,
+  //     clockId[0], clockId[1], clockId[2], clockId[3],
+  //     clockId[4], clockId[5], clockId[6], clockId[7]);
+
+  for(i = leftIndex; i < rightIndex; i++)
+  {
+    //DBGV("rx index %d: time %d.%09d, sequence %u, clock id %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+    //     i,
+    //     lastRecvTimes[i].recvTimeStamp.seconds,
+    //     lastRecvTimes[i].recvTimeStamp.nanoseconds,
+    //     lastRecvTimes[i].sequenceId,
+    //     lastRecvTimes[i].clockId[0], lastRecvTimes[i].clockId[1],
+    //     lastRecvTimes[i].clockId[2], lastRecvTimes[i].clockId[3],
+    //     lastRecvTimes[i].clockId[4], lastRecvTimes[i].clockId[5],
+    //     lastRecvTimes[i].clockId[6], lastRecvTimes[i].clockId[7]);
+
+    if(!memcmp(lastRecvTimes[i].clockId + 2, clockId + 2, 6) &&
+       lastRecvTimes[i].sequenceId == sequenceId)
+    {
+      DBGV("found rx index %d: time %d.%09d, sequence %u, clock id %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+           i,
+           lastRecvTimes[i].recvTimeStamp.seconds,
+           lastRecvTimes[i].recvTimeStamp.nanoseconds,
+           lastRecvTimes[i].sequenceId,
+           lastRecvTimes[i].clockId[0], lastRecvTimes[i].clockId[1],
+           lastRecvTimes[i].clockId[2], lastRecvTimes[i].clockId[3],
+           lastRecvTimes[i].clockId[4], lastRecvTimes[i].clockId[5],
+           lastRecvTimes[i].clockId[6], lastRecvTimes[i].clockId[7]);
+
+      *recvTimeStamp = lastRecvTimes[i].recvTimeStamp;
+      // invalidate entry to prevent accidental reuse (happened when slaves were
+      // restarted quickly while the master still had their old sequence IDs in the array)
+      memset(&lastRecvTimes[i], 0, sizeof(lastRecvTimes[i]));
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+Boolean getReceiveTime(TimeInternal *recvTimeStamp,
+                       ClockIdentity clockId,
+                       UInteger16 sequenceId,
+                       TimeMode timeMode,
+                       NetPath *netPath)
+{
+  /* check for new time stamps */
+  getTimeStamps(timeMode, netPath);
+
+  if(oldestRecv <= nextFreeRecv)
+    return getReceiveTimeFromArray(recvTimeStamp, clockId, sequenceId, oldestRecv, nextFreeRecv);
+  else
+  {
+    if(getReceiveTimeFromArray(recvTimeStamp, clockId, sequenceId, oldestRecv, RECV_ARRAY_SIZE))
+      return TRUE;
+    else
+      return getReceiveTimeFromArray(recvTimeStamp, clockId, sequenceId, 0, nextFreeRecv);
+  }
+}
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/dep/timer.c
--- a/src/dep/timer.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/dep/timer.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,5 +1,7 @@
 /*-
- * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer,
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
  *
@@ -39,6 +41,9 @@
 #include "../ptpd.h"
 
 #define US_TIMER_INTERVAL (62500)
+#ifdef __sun
+volatile hrtime_t timerInited;
+#endif
 volatile unsigned int elapsed;
 
 /*
@@ -54,15 +59,38 @@
 {
 	elapsed++;
 	/* be sure to NOT call DBG in asynchronous handlers! */
+
+#ifdef __sun
+	/*
+	 * Solaris removes the handler once signal is delivered. We
+	 * need to set the handler again.
+	 */
+	signal(SIGALRM, catch_alarm);
+#endif
 }
 
-void 
+/** Strings to help timer related debug messages. */
+char *PTP_timer_dbg_string[] =
+{"PDELAYREQ_INTERVAL_TIMER",
+  "DELAYREQ_INTERVAL_TIMER",
+  "SYNC_INTERVAL_TIMER",
+  "ANNOUNCE_RECEIPT_TIMER",
+  "ANNOUNCE_INTERVAL_TIMER",
+
+  /* non-spec timers */
+  "OPERATOR_MESSAGES_TIMER",
+  "LEAP_SECOND_PENDING_TIMER",
+  "LEAP_SECOND_NOW_TIMER"
+};
+
+void
 initTimer(void)
 {
-	struct itimerval itimer;
 
 	DBG("initTimer\n");
 
+#if !defined(__sun)
+	struct itimerval itimer;
 	signal(SIGALRM, SIG_IGN);
 
 	elapsed = 0;
@@ -71,6 +99,10 @@
 
 	signal(SIGALRM, catch_alarm);
 	setitimer(ITIMER_REAL, &itimer, 0);
+#else
+	timerInited = gethrtime();
+#endif
+
 }
 
 void 
@@ -83,8 +115,18 @@
 	 * latch how many ticks we got since we were last called
 	 * remember that catch_alarm() is totally asynchronous to this timerUpdate()
 	 */
+#ifdef __sun
+	/*
+	 * We want to have the number of 'ticks' (each equal to
+	 * US_TIMER_INTERVAL microseconds) since last call assigned to
+	 * 'delta'.
+	 */
+	delta = (gethrtime() - timerInited)/(US_TIMER_INTERVAL * 1000);
+	timerInited = gethrtime();
+#else
 	delta = elapsed;
 	elapsed = 0;
+#endif
 
 	if (delta <= 0)
 		return;
@@ -100,7 +142,8 @@
 		    <= 0) {
 			itimer[i].left = itimer[i].interval;
 			itimer[i].expire = TRUE;
-			DBG2("TimerUpdate:    Timer %u has now expired.   (Re-armed again with interval %d, left %d)\n", i, itimer[i].interval, itimer[i].left );
+			DBG2("TimerUpdate:    Timer %u(%s) has now expired.   (Re-armed again with interval %d, left %d)\n",
+			    i, PTP_timer_dbg_string[i], itimer[i].interval, itimer[i].left );
 		}
 	}
 
@@ -113,7 +156,8 @@
 		return;
 
 	itimer[index].interval = 0;
-	DBG2("timerStop:      Stopping timer %d.   (New interval: %d; New left: %d)\n", index, itimer[index].left , itimer[index].interval);
+	DBG2("timerStop:      Stopping timer %d(%s).   (New interval: %d; New left: %d)\n",\
+	    index, PTP_timer_dbg_string[index], itimer[index].left , itimer[index].interval);
 }
 
 void 
@@ -156,12 +200,13 @@
 			DBG("Timer would be issued immediatly. Please raise dep/timer.c:US_TIMER_INTERVAL to hold %.2fs\n",
 				interval
 			);
-			
+
 		}
 	}
 	itimer[index].interval = itimer[index].left;
 
-	DBG2("timerStart:     Set timer %d to %f.  New interval: %d; new left: %d\n", index, interval, itimer[index].left , itimer[index].interval);
+	DBG2("timerStart:     Set timer %d(%s) to %f.  New interval: %d; new left: %d\n",\
+	   index, PTP_timer_dbg_string[index], interval, itimer[index].left , itimer[index].interval);
 }
 
 
@@ -173,21 +218,22 @@
  * PTPv1 algorithm was:
  *    ptpClock->R = getRand(&ptpClock->random_seed) % (PTP_DELAY_REQ_INTERVAL - 2) + 2;
  *    R is the number of Syncs to be received, before sending a new request
- * 
- */ 
+ *
+ */
 void timerStart_random(UInteger16 index, float interval, IntervalTimer * itimer)
 {
 	float new_value;
 
 	new_value = getRand() * interval * 2.0;
-	DBG2(" timerStart_random: requested %.2f, got %.2f\n", interval, new_value);
-	
+	DBG2(" timerStart_random: index %d(%s) requested %.2f, got %.2f\n",
+	    index, PTP_timer_dbg_string[index], interval, new_value);
+
 	timerStart(index, new_value, itimer);
 }
 
 
 
-Boolean 
+Boolean
 timerExpired(UInteger16 index, IntervalTimer * itimer)
 {
 	timerUpdate(itimer);
@@ -201,7 +247,28 @@
 	itimer[index].expire = FALSE;
 
 
-	DBG2("timerExpired:   Timer %d expired, taking actions.   current interval: %d; current left: %d\n", index, itimer[index].left , itimer[index].interval);
+	DBG2("timerExpired:   Timer %d(%s) expired, taking actions.   current interval: %d; current left: %d\n",\
+	    index, PTP_timer_dbg_string[index],  itimer[index].left , itimer[index].interval);
 
 	return TRUE;
 }
+
+void timerNow(TimeInternal *time)
+{
+#if defined(__APPLE__)
+  struct timeval tv;
+
+  gettimeofday(&tv, 0);
+  time->seconds = tv.tv_sec;
+  time->nanoseconds = tv.tv_usec*1000;
+#else
+  struct timespec tv;
+  int err = clock_gettime(CLOCK_REALTIME, &tv);
+  if (err != 0) {
+    ERROR("error getting time %d\n", err);
+    return;
+  }
+  time->seconds = tv.tv_sec;
+  time->nanoseconds = tv.tv_nsec;
+#endif
+}
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/display.c
--- a/src/display.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/display.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,6 @@
 /*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
@@ -105,7 +107,7 @@
 netPath_display(NetPath * net)
 {
 	struct in_addr addr;
-
+	DBGV(">>>Network Info:\n");
 	DBGV("eventSock : %d \n", net->eventSock);
 	DBGV("generalSock : %d \n", net->generalSock);
 	addr.s_addr = net->multicastAddr;
@@ -114,6 +116,7 @@
 	DBGV("peerMulticastAddress : %s \n", inet_ntoa(addr));
 	addr.s_addr = net->unicastAddr;
 	DBGV("unicastAddress : %s \n", inet_ntoa(addr));
+	DBGV("<<<\n");
 }
 
 /**\brief Display a IntervalTimer Structure*/
@@ -201,27 +204,27 @@
 void 
 msgHeader_display(MsgHeader * header)
 {
-	DBGV("Message header : \n");
+	DBGV(">>>Message header : \n");
 	DBGV("\n");
-	DBGV("transportSpecific : %d\n", header->transportSpecific);
-	DBGV("messageType : %d\n", header->messageType);
-	DBGV("versionPTP : %d\n", header->versionPTP);
-	DBGV("messageLength : %d\n", header->messageLength);
-	DBGV("domainNumber : %d\n", header->domainNumber);
-	DBGV("FlagField %02hhx:%02hhx\n", header->flagField[0], header->flagField[1]);
+	DBGV("\ttransportSpecific : %d\n", header->transportSpecific);
+	DBGV("\tmessageType : %d\n", header->messageType);
+	DBGV("\tversionPTP : %d\n", header->versionPTP);
+	DBGV("\tmessageLength : %d\n", header->messageLength);
+	DBGV("\tdomainNumber : %d\n", header->domainNumber);
+	DBGV("\tFlagField %02hhx:%02hhx\n", header->flagField[0], header->flagField[1]);
 	integer64_display(&header->correctionfield);
 	portIdentity_display(&header->sourcePortIdentity);
-	DBGV("sequenceId : %d\n", header->sequenceId);
-	DBGV("controlField : %d\n", header->controlField);
-	DBGV("logMessageInterval : %d\n", header->logMessageInterval);
-	DBGV("\n");
+	DBGV("\tsequenceId : %d\n", header->sequenceId);
+	DBGV("\tcontrolField : %d\n", header->controlField);
+	DBGV("\tlogMessageInterval : %d\n", header->logMessageInterval);
+	DBGV("<<<\n");
 }
 
 /**\brief Display Announce message*/
 void 
 msgAnnounce_display(MsgAnnounce * announce)
 {
-	DBGV("Announce Message : \n");
+	DBGV(">>>Announce Message : \n");
 	DBGV("\n");
 	DBGV("originTimestamp : \n");
 	DBGV("secondField  : \n");
@@ -235,7 +238,7 @@
 	clockIdentity_display(announce->grandmasterIdentity);
 	DBGV("stepsRemoved : %d \n", announce->stepsRemoved);
 	DBGV("timeSource : %d \n", announce->timeSource);
-	DBGV("\n");
+	DBGV("<<<\n");
 }
 
 /**\brief Display Follow_UP message*/
@@ -292,8 +295,8 @@
 
 	DBGV("---Run time Options Display-- \n");
 	DBGV("\n");
-	DBGV("announceInterval : %d \n", rtOpts->announceInterval);
-	DBGV("syncInterval : %d \n", rtOpts->syncInterval);
+	DBGV("announceInterval : %Lf \n", rtOpts->announceInterval);
+	DBGV("syncInterval : %Lf \n", rtOpts->syncInterval);
 	clockQuality_display(&(rtOpts->clockQuality));
 	DBGV("priority1 : %d \n", rtOpts->priority1);
 	DBGV("priority2 : %d \n", rtOpts->priority2);
@@ -314,7 +317,7 @@
 	timeInternal_display(&(rtOpts->outboundLatency));
 	DBGV("max_foreign_records : %d \n", rtOpts->max_foreign_records);
 	DBGV("ethernet mode : %d \n", rtOpts->ethernet_mode);
-	DBGV("\n");
+	DBGV("--- ---\n");
 }
 
 
@@ -333,7 +336,7 @@
 	DBGV("priority2 : %d \n", ptpClock->priority2);
 	DBGV("domainNumber : %d \n", ptpClock->domainNumber);
 	DBGV("slaveOnly : %d \n", ptpClock->slaveOnly);
-	DBGV("\n");
+	DBGV("-------\n");
 }
 
 
@@ -350,7 +353,7 @@
 	timeInternal_display(&ptpClock->offsetFromMaster);
 	DBGV("Mean path delay : \n");
 	timeInternal_display(&ptpClock->meanPathDelay);
-	DBGV("\n");
+	DBGV("---------\n");
 }
 
 
@@ -371,7 +374,7 @@
 	clockQuality_display(&ptpClock->grandmasterClockQuality);
 	DBGV("grandmasterpriority1 : %d \n", ptpClock->grandmasterPriority1);
 	DBGV("grandmasterpriority2 : %d \n", ptpClock->grandmasterPriority2);
-	DBGV("\n");
+	DBGV("---------\n");
 }
 
 /**\brief Display Global data set of a PtpClock*/
@@ -390,7 +393,7 @@
 	DBGV("frequencyTraceable : %d \n", ptpClock->frequencyTraceable);
 	DBGV("ptpTimescale : %d \n", ptpClock->ptpTimescale);
 	DBGV("timeSource : %d \n", ptpClock->timeSource);
-	DBGV("\n");
+	DBGV("------\n");
 }
 
 /**\brief Display Port data set of a PtpClock*/
@@ -403,6 +406,7 @@
 
 	portIdentity_display(&ptpClock->portIdentity);
 	DBGV("port state : %d \n", ptpClock->portState);
+	DBGV("minDelayReqInterval : %Lf \n", ptpClock->minDelayReqInterval);
 	DBGV("logMinDelayReqInterval : %d \n", ptpClock->logMinDelayReqInterval);
 	DBGV("peerMeanPathDelay : \n");
 	timeInternal_display(&ptpClock->peerMeanPathDelay);
@@ -412,7 +416,7 @@
 	DBGV("delayMechanism : %d \n", ptpClock->delayMechanism);
 	DBGV("logMinPdelayReqInterval : %d \n", ptpClock->logMinPdelayReqInterval);
 	DBGV("versionNumber : %d \n", ptpClock->versionNumber);
-	DBGV("\n");
+	DBGV("--------\n");
 }
 
 /**\brief Display ForeignMaster data set of a PtpClock*/
@@ -444,7 +448,7 @@
 		DBGV("No Foreign masters recorded \n");
 	}
 
-	DBGV("\n");
+	DBGV("---- End of Ptp Clock Foreign Data Set ---\n");
 
 
 }
@@ -506,7 +510,7 @@
 	DBGV("y : %d \n", ptpClock->owd_filt.y);
 	DBGV("s_exp : %d \n", ptpClock->owd_filt.s_exp);
 	DBGV("\n");
-	DBGV("observed_drift : %d \n", ptpClock->observed_drift);
+	DBGV("observed_drift : %Lf \n", ptpClock->observed_drift);
 	DBGV("message activity %d \n", ptpClock->message_activity);
 	DBGV("\n");
 
@@ -519,7 +523,7 @@
 	netPath_display(&ptpClock->netPath);
 	DBGV("mCommunication technology %d \n", ptpClock->port_communication_technology);
 	clockUUID_display(ptpClock->port_uuid_field);
-	DBGV("\n");
+	DBGV("---------\n");
 }
 
 
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/protocol.c
--- a/src/protocol.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/protocol.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,6 @@
 /*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
@@ -30,10 +32,10 @@
 /**
  * @file   protocol.c
  * @date   Wed Jun 23 09:40:39 2010
- * 
+ *
  * @brief  The code that handles the IEEE-1588 protocol and state machine
- * 
- * 
+ *
+ *
  */
 
 #include "ptpd.h"
@@ -73,7 +75,7 @@
    checked for 'port_state'. the actions and events may or may not change
    'port_state' by calling toState(), but once they are done we loop around
    again and perform the actions required for the new 'port_state'. */
-void 
+void
 protocol(RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	DBG("event POWERUP\n");
@@ -105,75 +107,83 @@
 
 
 /* perform actions required when leaving 'port_state' and entering 'state' */
-void 
+void
 toState(UInteger8 state, RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	ptpClock->message_activity = TRUE;
-	
+
 	/* leaving state tasks */
 	switch (ptpClock->portState)
 	{
 	case PTP_MASTER:
-		timerStop(SYNC_INTERVAL_TIMER, ptpClock->itimer);  
+		timerStop(SYNC_INTERVAL_TIMER, ptpClock->itimer);
 		timerStop(ANNOUNCE_INTERVAL_TIMER, ptpClock->itimer);
-		timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer); 
+		timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer);
 		break;
-		
+
 	case PTP_SLAVE:
 		timerStop(ANNOUNCE_RECEIPT_TIMER, ptpClock->itimer);
-		
+
 		if (ptpClock->delayMechanism == E2E)
 			timerStop(DELAYREQ_INTERVAL_TIMER, ptpClock->itimer);
 		else if (ptpClock->delayMechanism == P2P)
 			timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer);
-		
-		initClock(rtOpts, ptpClock); 
+
+    /* bug 25796 - Don't reset the servo when entering or leaving the slave state.
+     * Instead we assume let the servo continue to work. If the time on a the next
+     * master is significantly different, this will cause a servo reset and a time
+     * correction. Otherwise we will converge as normal.
+     * initClock(rtOpts, ptpClock);
+     */
 		break;
-		
+
 	case PTP_PASSIVE:
 		timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer);
 		timerStop(ANNOUNCE_RECEIPT_TIMER, ptpClock->itimer);
 		break;
-		
+
 	case PTP_LISTENING:
 		timerStop(ANNOUNCE_RECEIPT_TIMER, ptpClock->itimer);
 		break;
-		
+
 	default:
 		break;
 	}
-	
+
 	/* entering state tasks */
 
 	/*
 	 * No need of PRE_MASTER state because of only ordinary clock
 	 * implementation.
 	 */
-	
+
 	switch (state)
 	{
 	case PTP_INITIALIZING:
 		DBG("state PTP_INITIALIZING\n");
+		INFO("state -> initialising\n");
 		ptpClock->portState = PTP_INITIALIZING;
 		break;
-		
+
 	case PTP_FAULTY:
 		DBG("state PTP_FAULTY\n");
+		INFO("state -> faulty\n");
 		ptpClock->portState = PTP_FAULTY;
 		break;
-		
+
 	case PTP_DISABLED:
 		DBG("state PTP_DISABLED\n");
+		INFO("state -> disabled\n");
 		ptpClock->portState = PTP_DISABLED;
 		break;
-		
+
 	case PTP_LISTENING:
 		/* in Listening mode, make sure we don't send anything. Instead we just expect/wait for announces (started below) */
 		timerStop(SYNC_INTERVAL_TIMER,      ptpClock->itimer);
 		timerStop(ANNOUNCE_INTERVAL_TIMER,  ptpClock->itimer);
 		timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer);
 		timerStop(DELAYREQ_INTERVAL_TIMER,  ptpClock->itimer);
-		
+
 		/*
 		 *  Count how many _unique_ timeouts happen to us.
 		 *  If we were already in Listen mode, then do not count this as a seperate reset, but stil do a new IGMP refresh
@@ -183,51 +193,52 @@
 		}
 
 		/* Revert to the original DelayReq interval, and ignore the one for the last master */
-		ptpClock->logMinDelayReqInterval = rtOpts->initial_delayreq;
+		ptpClock->minDelayReqInterval = rtOpts->initial_delayreq;
+		ptpClock->logMinDelayReqInterval = log2IntegerSaturateAtZero(rtOpts->initial_delayreq);
 
 		/* force a IGMP refresh per reset */
 		if (rtOpts->do_IGMP_refresh) {
 			netRefreshIGMP(&ptpClock->netPath, rtOpts, ptpClock);
 		}
-		
+
 
 		DBG("state PTP_LISTENING\n");
-		INFO("  now in state PTP_LISTENING\n");
-		timerStart(ANNOUNCE_RECEIPT_TIMER, 
+		INFO("state -> listening\n");
+		timerStart(ANNOUNCE_RECEIPT_TIMER,
 			   (ptpClock->announceReceiptTimeout) * 
-			   (pow(2,ptpClock->logAnnounceInterval)), 
+			   rtOpts->announceInterval,
 			   ptpClock->itimer);
 		ptpClock->portState = PTP_LISTENING;
 		break;
 
 	case PTP_MASTER:
 		DBG("state PTP_MASTER\n");
-		INFO("  now in state PTP_MASTER\n");
-		
+		INFO("state -> master\n");
+
 		timerStart(SYNC_INTERVAL_TIMER, 
-			   pow(2,ptpClock->logSyncInterval), ptpClock->itimer);
-		DBG("SYNC INTERVAL TIMER : %f \n",
-		    pow(2,ptpClock->logSyncInterval));
+				rtOpts->syncInterval, ptpClock->itimer);
+		DBG("SYNC INTERVAL TIMER : %Lf \n",
+				rtOpts->syncInterval);
 		timerStart(ANNOUNCE_INTERVAL_TIMER, 
-			   pow(2,ptpClock->logAnnounceInterval), 
-			   ptpClock->itimer);
-		timerStart(PDELAYREQ_INTERVAL_TIMER, 
-			   pow(2,ptpClock->logMinPdelayReqInterval), 
+				rtOpts->announceInterval, 
+				ptpClock->itimer);
+		timerStart(PDELAYREQ_INTERVAL_TIMER,
+			   pow(2,ptpClock->logMinPdelayReqInterval),
 			   ptpClock->itimer);
 		ptpClock->portState = PTP_MASTER;
 		break;
 
 	case PTP_PASSIVE:
 		DBG("state PTP_PASSIVE\n");
-		INFO("  now in state PTP_PASSIVE\n");
+		INFO("state -> passive\n");
 
-		
-		timerStart(PDELAYREQ_INTERVAL_TIMER, 
-			   pow(2,ptpClock->logMinPdelayReqInterval), 
+
+		timerStart(PDELAYREQ_INTERVAL_TIMER,
+			   pow(2,ptpClock->logMinPdelayReqInterval),
 			   ptpClock->itimer);
-		timerStart(ANNOUNCE_RECEIPT_TIMER, 
+		timerStart(ANNOUNCE_RECEIPT_TIMER,
 			   (ptpClock->announceReceiptTimeout) * 
-			   (pow(2,ptpClock->logAnnounceInterval)), 
+			   rtOpts->announceInterval,
 			   ptpClock->itimer);
 		ptpClock->portState = PTP_PASSIVE;
 		p1(ptpClock, rtOpts);
@@ -235,15 +246,21 @@
 
 	case PTP_UNCALIBRATED:
 		DBG("state PTP_UNCALIBRATED\n");
+		INFO("state -> uncalibrated\n");
 		ptpClock->portState = PTP_UNCALIBRATED;
 		break;
 
 	case PTP_SLAVE:
 		DBG("state PTP_SLAVE\n");
-		INFO("  now in state PTP_SLAVE\n");
-		
-		initClock(rtOpts, ptpClock);
-		
+		INFO("state -> slave\n");
+
+		/* bug 25796 - Don't reset the servo when entering or leaving the slave state.
+		 * Instead we assume let the servo continue to work. If the time on a the next
+		 * master is significantly different, this will cause a servo reset and a time
+		 * correction. Otherwise we will converge as normal.
+		 * initClock(rtOpts, ptpClock);
+		 */
+
 		ptpClock->waitingForFollow = FALSE;
 		ptpClock->waitingForDelayResp = FALSE;
 
@@ -252,16 +269,16 @@
 		clearTime(&ptpClock->pdelay_req_receive_time);
 		clearTime(&ptpClock->pdelay_resp_send_time);
 		clearTime(&ptpClock->pdelay_resp_receive_time);
-		
+
 		timerStart(OPERATOR_MESSAGES_TIMER,
 			   OPERATOR_MESSAGES_INTERVAL,
 			   ptpClock->itimer);
 		
 		timerStart(ANNOUNCE_RECEIPT_TIMER,
 			   (ptpClock->announceReceiptTimeout) * 
-			   (pow(2,ptpClock->logAnnounceInterval)), 
+			   rtOpts->announceInterval,
 			   ptpClock->itimer);
-		
+
 		/*
 		 * Previously, this state transition would start the delayreq timer immediately.
 		 * However, if this was faster than the first received sync, then the servo would drop the delayResp
@@ -271,6 +288,24 @@
 		ptpClock->waiting_for_first_delayresp = TRUE;
 
 		ptpClock->portState = PTP_SLAVE;
+
+#if !defined(__APPLE__)
+
+		/* 
+		 * leap second pending in kernel but no leap second 
+		 * info from GM - withdraw kernel leap second
+		 * if the flags have disappeared but we're past 
+		 * leap second event, do nothing - kernel flags 
+		 * will be unset in handleAnnounce()
+		 */
+		if((!ptpClock->leap59 && !ptpClock->leap61) &&
+		    !ptpClock->leapSecondInProgress &&
+		   (checkTimexFlags(STA_INS) || checkTimexFlags(STA_DEL))) {
+			WARNING("=== Leap second pending in kernel but not on "
+				"GM: aborting kernel leap second\n");
+			unsetTimexFlags(STA_INS | STA_DEL, TRUE);
+		}
+#endif /* apple */
 		break;
 
 	default:
@@ -283,11 +318,12 @@
 }
 
 
-Boolean 
+Boolean
 doInit(RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
+	NOTIFY("ptpd version: %s\n", PTP_VERSION_STRING);
 	DBG("manufacturerIdentity: %s\n", MANUFACTURER_ID);
-	
+
 	/* initialize networking */
 	netShutdown(&ptpClock->netPath);
 	if (!netInit(&ptpClock->netPath, rtOpts, ptpClock)) {
@@ -295,27 +331,36 @@
 		toState(PTP_FAULTY, rtOpts, ptpClock);
 		return FALSE;
 	}
-	
+
+	/* initialize other stuff, including HW if needed */
+	shutdownTime(ptpClock);
+	if(!initTime(rtOpts, ptpClock))
+	{
+	    ERROR("failed to initialize timing\n");
+	    toState(PTP_FAULTY, rtOpts, ptpClock);
+	    return FALSE;
+	}
+
 	/* initialize other stuff */
 	initData(rtOpts, ptpClock);
 	initTimer();
 	initClock(rtOpts, ptpClock);
 	m1(rtOpts, ptpClock );
-	msgPackHeader(ptpClock->msgObuf, ptpClock);
-	
+	msgPackHeader(ptpClock->msgObuf, ptpClock, SYNC);
+
 	toState(PTP_LISTENING, rtOpts, ptpClock);
-	
+
 	return TRUE;
 }
 
 /* handle actions and events for 'port_state' */
-void 
+void
 doState(RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	UInteger8 state;
-	
+
 	ptpClock->message_activity = FALSE;
-	
+
 	/* Process record_update (BMC algorithm) before everything else */
 	switch (ptpClock->portState)
 	{
@@ -335,11 +380,11 @@
 				toState(state, rtOpts, ptpClock);
 		}
 		break;
-		
+
 	default:
 		break;
 	}
-	
+
 	
 	switch (ptpClock->portState)
 	{
@@ -348,14 +393,26 @@
 		DBG("event FAULT_CLEARED\n");
 		toState(PTP_INITIALIZING, rtOpts, ptpClock);
 		return;
-		
+
 	case PTP_LISTENING:
 	case PTP_UNCALIBRATED:
 	case PTP_SLAVE:
 	// passive mode behaves like the SLAVE state, in order to wait for the announce timeout of the current active master
 	case PTP_PASSIVE:
+
+		/* If we are in time both mode sync the system and local NIC. This process will continue
+                 * even if we lose contact with the master. Note that we only do this if ptpd was
+		 * started in a master mode or the primary servo has updated the clock at least once.
+		 * bug 26688 This avoids the scenario during slave start up where we start syncing the
+		 * system time to the NIC time before the NIC is synced to the master.
+		 */
+		if ((rtOpts->time_mode == TIME_BOTH) &&
+		    ((rtOpts->master_slave_mode != PTP_MODE_SLAVE) || ptpClock->clock_first_updated)) {
+			syncSystemWithNIC(rtOpts, ptpClock);
+		}
+		
 		handle(rtOpts, ptpClock);
-		
+
 		/*
 		 * handle SLAVE timers:
 		 *   - No Announce message was received
@@ -367,7 +424,7 @@
 			ptpClock->number_foreign_records = 0;
 			ptpClock->foreign_record_i = 0;
 
-			if(!ptpClock->slaveOnly && 
+			if(rtOpts->master_slave_mode != PTP_MODE_SLAVE &&
 			   ptpClock->clockQuality.clockClass != 255) {
 				m1(rtOpts,ptpClock);
 				toState(PTP_MASTER, rtOpts, ptpClock);
@@ -380,7 +437,7 @@
 				toState(PTP_LISTENING, rtOpts, ptpClock);
 			}
 		}
-		
+
 		if (timerExpired(OPERATOR_MESSAGES_TIMER, ptpClock->itimer)) {
 			reset_operator_messages(rtOpts, ptpClock);
 		}
@@ -396,32 +453,113 @@
 			if (timerExpired(PDELAYREQ_INTERVAL_TIMER,
 					ptpClock->itimer)) {
 				DBGV("event PDELAYREQ_INTERVAL_TIMEOUT_EXPIRES\n");
-				issuePDelayReq(rtOpts,ptpClock);
+ 				issuePDelayReq(rtOpts,ptpClock);
 			}
 
 			/* FIXME: Path delay should also rearm its timer with the value received from the Master */
 		}
+
+		/* XXX wowczarek: handle leap second timers */
+		if (ptpClock->leap59 || ptpClock->leap61) 
+			DBGV("seconds to midnight: %f\n", secondsToMidnight());
+
+		if(timerExpired(LEAP_SECOND_PENDING_TIMER,ptpClock->itimer)) {
+			/* leap second period is over */
+			if(ptpClock->leapSecondInProgress) {
+				/* 
+				 * do not unpause offset calculation just
+				 * yet, just indicate and it will be
+				 * unpaused in handleAnnounce
+				 */
+				ptpClock->leapSecondPending = FALSE;
+				timerStop(LEAP_SECOND_PENDING_TIMER,ptpClock->itimer);
+			/* leap second period has just started */
+			} else if(ptpClock->leapSecondPending) {
+				WARNING("=== Leap second event imminent - pausing "
+					"offset updates\n");
+				ptpClock->leapSecondInProgress = TRUE;
+#if !defined(__APPLE__)
+				if (!rtOpts->noResetClock && !rtOpts->resetClockStartupOnly &&
+				    !checkTimexFlags(ptpClock->leap61 ? STA_INS : STA_DEL)) {
+					WARNING("=== Kernel leap second flags have "
+						"been unset - attempting to set "
+						"again");
+					setTimexFlags(ptpClock->leap61 ? 
+						      STA_INS : STA_DEL, FALSE);
+				}
+#endif /* apple */
+				timerStart(LEAP_SECOND_PENDING_TIMER,
+					getPauseBeforeMidnight(ptpClock->logAnnounceInterval) + 
+					getPauseAfterMidnight(ptpClock->logAnnounceInterval),
+					ptpClock->itimer);
+
+				if (ptpClock->leap61) {
+					timerStart(LEAP_SECOND_NOW_TIMER,
+						secondsToMidnight(),
+						ptpClock->itimer);
+				} else {
+					timerStart(LEAP_SECOND_NOW_TIMER,
+						secondsToMidnight() - 1.0,
+						ptpClock->itimer);
+				}
+			}
+		}
+
+		if(timerExpired(LEAP_SECOND_NOW_TIMER,ptpClock->itimer)) {
+			if (ptpClock->leap61) {
+				WARNING("=== Leap second added!\n");
+				adjTimeInsertLeapSecond(rtOpts->time_mode, rtOpts, ptpClock);
+			} else {
+				WARNING("=== Leap second deleted!\n");
+				adjTimeDeleteLeapSecond(rtOpts->time_mode, rtOpts, ptpClock);
+			}
+			timerStop(LEAP_SECOND_NOW_TIMER,ptpClock->itimer);
+		}
 		break;
 
 	case PTP_MASTER:
+
+		/* If we are in time both mode, sync the system and local NIC. This process will continue
+		 * irrespective of whether theere is communication with one or more slave nodes.
+		 */
+		if (rtOpts->time_mode == TIME_BOTH) {
+			syncSystemWithNIC(rtOpts, ptpClock);
+		}
+
 		/*
-		 * handle SLAVE timers:
+		 * handle MASTER timers:
 		 *   - Time to send new Sync
 		 *   - Time to send new Announce
 		 *   - Time to send new PathDelay
 		 *      (DelayResp has no timer - as these are sent and retransmitted by the slaves)
 		 */
-	
+
+#ifdef DBG_SIGRTMIN_LEAP_SECOND
+                if(timerExpired(LEAP_SECOND_NOW_TIMER, ptpClock->itimer)) {
+			/* If we are signalling a leap second, apply the adjustment
+			 * and cancel the signalling.
+			 */
+			if (ptpClock->leap61)
+				ptpClock->currentUtcOffset++;
+			if (ptpClock->leap59)
+				ptpClock->currentUtcOffset--;
+			INFO("Setting UTC offset to %d\n", ptpClock->currentUtcOffset);
+			ptpClock->leap61 = FALSE;
+			ptpClock->leap59 = FALSE;
+			timerStop(LEAP_SECOND_NOW_TIMER, ptpClock->itimer);
+		}
+#endif
+
 		if (timerExpired(SYNC_INTERVAL_TIMER, ptpClock->itimer)) {
 			DBGV("event SYNC_INTERVAL_TIMEOUT_EXPIRES\n");
 			issueSync(rtOpts, ptpClock);
 		}
-		
+
 		if (timerExpired(ANNOUNCE_INTERVAL_TIMER, ptpClock->itimer)) {
 			DBGV("event ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES\n");
 			issueAnnounce(rtOpts, ptpClock);
 		}
-		
+
 		if (ptpClock->delayMechanism == P2P) {
 			if (timerExpired(PDELAYREQ_INTERVAL_TIMER,
 					ptpClock->itimer)) {
@@ -429,19 +567,20 @@
 				issuePDelayReq(rtOpts,ptpClock);
 			}
 		}
-		
+
 		// TODO: why is handle() below expiretimer, while in slave is the opposite
 		handle(rtOpts, ptpClock);
-		
-		if (ptpClock->slaveOnly || ptpClock->clockQuality.clockClass == 255)
+
+		if (rtOpts->master_slave_mode == PTP_MODE_SLAVE ||
+		   ptpClock->clockQuality.clockClass == 255)
 			toState(PTP_LISTENING, rtOpts, ptpClock);
-		
+
 		break;
 
 	case PTP_DISABLED:
 		handle(rtOpts, ptpClock);
 		break;
-		
+
 	default:
 		DBG("(doState) do unrecognized state\n");
 		break;
@@ -456,57 +595,54 @@
 	int ret;
 	ssize_t length;
 	Boolean isFromSelf;
+	Boolean isEvent;
+	Boolean isLoopedBackTx = FALSE;
 	TimeInternal time = { 0, 0 };
 
 	if (!ptpClock->message_activity) {
-		ret = netSelect(0, &ptpClock->netPath);
-		if (ret < 0) {
-			PERROR("failed to poll sockets");
+		/* To support time both mode, we time-out after a  second to allow the
+		 * the system clock to be synced to the NIC clock. For other modes, this
+		 * should have no effect on the behaviour. */
+		TimeInternal timeout;
+		double integerPart, fractionalPart;
+		fractionalPart = modf(rtOpts->system_time_update_interval, &integerPart);
+		timeout.seconds = (Integer32)integerPart;
+		timeout.nanoseconds = (Integer32)(fractionalPart * 1000000000.0);
+
+		ret = netSelect(&timeout, &ptpClock->netPath);
+		if(ret < 0) {
+			PERROR("failed to poll sockets\n");
 			toState(PTP_FAULTY, rtOpts, ptpClock);
 			return;
 		} else if (!ret) {
-			/* DBGV("handle: nothing\n"); */
+			/* We timed out, return immediately. */
 			return;
 		}
 		/* else length > 0 */
 	}
 
-	DBGV("handle: something\n");
+	/*DBGV("handle: something\n");*/
 
-	/* TODO: this should be based on the select actual FDs (if(FD_ISSET(...)) */
-	length = netRecvEvent(ptpClock->msgIbuf, &time, &ptpClock->netPath);
-
-
+	isEvent = TRUE;
+	length = netRecvEvent(ptpClock->msgIbuf, &time, ptpClock,
+                          rtOpts,
+                          &isLoopedBackTx);
 	if (length < 0) {
-		PERROR("failed to receive on the event socket");
+		PERROR("failed to receive on the event socket\n");
 		toState(PTP_FAULTY, rtOpts, ptpClock);
 		return;
 	} else if (!length) {
+		isEvent = FALSE;
 		length = netRecvGeneral(ptpClock->msgIbuf, &time,
-					&ptpClock->netPath);
+					ptpClock, rtOpts);
 		if (length < 0) {
-			PERROR("failed to receive on the general socket");
+			PERROR("failed to receive on the general socket\n");
 			toState(PTP_FAULTY, rtOpts, ptpClock);
 			return;
 		} else if (!length)
 			return;
 	}
 
-	/*
-	 * make sure we use the TAI to UTC offset specified, if the master is sending the UTC_VALID bit
-	 *
-	 *
-	 * On the slave, all timestamps that we handle here have been collected by our local clock (loopback+kernel-level timestamp)
-	 * This includes delayReq just send, and delayResp, when it arrives.
-	 *
-	 * these are then adjusted to the same timebase of the Master (+34 leap seconds, as of 2011)
-	 *
-	 */
-	DBGV("__UTC_offset: %d %d \n", ptpClock->currentUtcOffsetValid, ptpClock->currentUtcOffset);
-	if (ptpClock->currentUtcOffsetValid) {
-		time.seconds += ptpClock->currentUtcOffset;
-	}
-
 	ptpClock->message_activity = TRUE;
 
 	if (length < HEADER_LENGTH) {
@@ -517,6 +653,30 @@
 
 	msgUnpackHeader(ptpClock->msgIbuf, &ptpClock->msgTmpHeader);
 
+	if(isEvent && !isLoopedBackTx && (ptpClock->tsMethod == TS_METHOD_DRIVER_IOCTL)) {
+		/* query hardware for matching receive time stamp */
+		if(!getReceiveTime(&time,
+                       ptpClock->msgTmpHeader.sourcePortIdentity.clockIdentity,
+                       ptpClock->msgTmpHeader.sequenceId, rtOpts->time_mode, &ptpClock->netPath)) {
+				/*
+				 * This doesn't apply to us as we can timestamp sync and delay requests:
+				 * "Incoming packets without hardware time stamp cannot be ignored outright because
+				 * a master might only be able to time stamp DelayReq packets; ignoring the Sync
+				 * packets from another, better clock would break the clock selection protocol.
+				 * Therefore set system time as fallback and decide below what to do."
+				 * Instead, ignore the packet outright!
+				 */
+				DBGV("*** message with no time stamp ***\n");
+				return;
+		}
+	}
+
+	/* make sure we use the TAI to UTC offset specified, if the master is sending the UTC_VALID bit */
+	DBG2("__UTC_offset: %d %d \n", ptpClock->currentUtcOffsetValid, ptpClock->currentUtcOffset);
+	if((rtOpts->master_slave_mode == PTP_MODE_SLAVE) && ptpClock->currentUtcOffsetValid){
+		time.seconds += ptpClock->currentUtcOffset;
+	}	
+
 	if (ptpClock->msgTmpHeader.versionPTP != ptpClock->versionNumber) {
 		DBG2("ignore version %d message\n", ptpClock->msgTmpHeader.versionPTP);
 		return;
@@ -527,13 +687,13 @@
 		return;
 	}
 
-	/*Spec 9.5.2.2*/	
+	/*Spec 9.5.2.2*/
 	isFromSelf = (ptpClock->portIdentity.portNumber == ptpClock->msgTmpHeader.sourcePortIdentity.portNumber
 		      && !memcmp(ptpClock->msgTmpHeader.sourcePortIdentity.clockIdentity, ptpClock->portIdentity.clockIdentity, CLOCK_IDENTITY_LENGTH));
 
 	/*
 	 * subtract the inbound latency adjustment if it is not a loop
-	 *  back and the time stamp seems reasonable 
+	 *  back and the time stamp seems reasonable
 	 */
 	if (!isFromSelf && time.seconds > 0)
 		subTime(&time, &time, &rtOpts->inboundLatency);
@@ -576,27 +736,27 @@
 	switch (ptpClock->msgTmpHeader.messageType)
 	{
 	case ANNOUNCE:
-		handleAnnounce(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
+		handleAnnounce(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
 			       length, isFromSelf, rtOpts, ptpClock);
 		break;
 	case SYNC:
-		handleSync(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
+		handleSync(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
 			   length, &time, isFromSelf, rtOpts, ptpClock);
 		break;
 	case FOLLOW_UP:
-		handleFollowUp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
+		handleFollowUp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
 			       length, isFromSelf, rtOpts, ptpClock);
 		break;
 	case DELAY_REQ:
-		handleDelayReq(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
+		handleDelayReq(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
 			       length, &time, isFromSelf, rtOpts, ptpClock);
 		break;
 	case PDELAY_REQ:
-		handlePDelayReq(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
+		handlePDelayReq(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
 				length, &time, isFromSelf, rtOpts, ptpClock);
-		break;  
+		break;
 	case DELAY_RESP:
-		handleDelayResp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
+		handleDelayResp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
 				length, isFromSelf, rtOpts, ptpClock);
 		break;
 	case PDELAY_RESP:
@@ -604,16 +764,16 @@
 				 &time, length, isFromSelf, rtOpts, ptpClock);
 		break;
 	case PDELAY_RESP_FOLLOW_UP:
-		handlePDelayRespFollowUp(&ptpClock->msgTmpHeader, 
-					 ptpClock->msgIbuf, length, 
+		handlePDelayRespFollowUp(&ptpClock->msgTmpHeader,
+					 ptpClock->msgIbuf, length,
 					 isFromSelf, rtOpts, ptpClock);
 		break;
 	case MANAGEMENT:
-		handleManagement(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
+		handleManagement(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
 				 length, isFromSelf, rtOpts, ptpClock);
 		break;
 	case SIGNALING:
-		handleSignaling(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
+		handleSignaling(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
 				length, isFromSelf, rtOpts, ptpClock);
 		break;
 	default:
@@ -627,11 +787,11 @@
 }
 
 /*spec 9.5.3*/
-void 
-handleAnnounce(MsgHeader *header, Octet *msgIbuf, ssize_t length, 
+void
+handleAnnounce(MsgHeader *header, Octet *msgIbuf, ssize_t length,
 	       Boolean isFromSelf, RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
-	Boolean isFromCurrentParent = FALSE; 
+	Boolean isFromCurrentParent = FALSE;
 
 	DBGV("HandleAnnounce : Announce message received : \n");
 
@@ -650,40 +810,63 @@
 	case PTP_DISABLED:
 		DBG("Handleannounce : disregard\n");
 		return;
-		
-	case PTP_UNCALIBRATED:	
+
+	case PTP_UNCALIBRATED:
 	case PTP_SLAVE:
 		if (isFromSelf) {
 			DBGV("HandleAnnounce : Ignore message from self \n");
 			return;
 		}
-		
+
 		/*
 		 * Valid announce message is received : BMC algorithm
-		 * will be executed 
+		 * will be executed
 		 */
 		ptpClock->record_update = TRUE;
 
 		isFromCurrentParent = !memcmp(
 			ptpClock->parentPortIdentity.clockIdentity,
 			header->sourcePortIdentity.clockIdentity,
-			CLOCK_IDENTITY_LENGTH)	&& 
-			(ptpClock->parentPortIdentity.portNumber == 
+			CLOCK_IDENTITY_LENGTH)	&&
+			(ptpClock->parentPortIdentity.portNumber ==
 			 header->sourcePortIdentity.portNumber);
-	
+
 		switch (isFromCurrentParent) {
 		case TRUE:
 	   		msgUnpackAnnounce(ptpClock->msgIbuf,
 					  &ptpClock->msgTmp.announce);
 
-			/* update datasets (file bmc.c) */
+			/* If the leap second period is over (pending == FALSE,
+			 * inProgress == TRUE), unpause offset calculation
+			 * (received first announce after leap second)
+			 * Note that we must be this before running the BMC
+			 * algorithm as this can set leapSecondPending again.
+			 */
+			if(ptpClock->leapSecondInProgress &&
+			   !ptpClock->leapSecondPending) {
+				WARNING("=== Leap second event over - "
+					"resuming offset updates\n");
+				ptpClock->leapSecondInProgress = FALSE;
+				ptpClock->leap59 = FALSE;
+				ptpClock->leap61 = FALSE;
+				unsetTimexFlags(STA_INS | STA_DEL, TRUE);
+			}
+			
+			/* call the BMC algorithm (file bmc.c) */
 	   		s1(header,&ptpClock->msgTmp.announce,ptpClock, rtOpts);
 
+
+			/* update current master in the fmr as well */
+			memcpy(&ptpClock->foreign[ptpClock->foreign_record_best].header,
+			       header,sizeof(MsgHeader));
+			memcpy(&ptpClock->foreign[ptpClock->foreign_record_best].announce,
+			       &ptpClock->msgTmp.announce,sizeof(MsgAnnounce));
+
 			DBG2("___ Announce: received Announce from current Master, so reset the Announce timer\n");
 	   		/*Reset Timer handling Announce receipt timeout*/
 	   		timerStart(ANNOUNCE_RECEIPT_TIMER,
 				   (ptpClock->announceReceiptTimeout) * 
-				   (pow(2,ptpClock->logAnnounceInterval)), 
+				   rtOpts->announceInterval,
 				   ptpClock->itimer);
 
 #ifdef PTP_EXPERIMENTAL
@@ -691,20 +874,20 @@
 			// todo: add this to bmc(), to cover the very first packet
 			ptpClock->MasterAddr = ptpClock->netPath.lastRecvAddr;
 #endif
-			break;
+	   		break;
 
 		case FALSE:
-			/*addForeign takes care of AnnounceUnpacking*/
+	   		/*addForeign takes care of AnnounceUnpacking*/
 			/* the actual decision to change masters is only done in  doState() / record_update == TRUE / bmc() */
-			
+
 			/* the original code always called: addforeign(new master) + timerstart(announce) */
 
 			addForeign(ptpClock->msgIbuf,header,ptpClock);
-			timerStart(ANNOUNCE_RECEIPT_TIMER,
+	   		timerStart(ANNOUNCE_RECEIPT_TIMER,
 				   (ptpClock->announceReceiptTimeout) * 
-				   (pow(2,ptpClock->logAnnounceInterval)), 
+				   rtOpts->announceInterval,
 				   ptpClock->itimer);
-			break;
+	   		break;
 
 		default:
 			DBG("HandleAnnounce : (isFromCurrentParent)"
@@ -718,7 +901,7 @@
 	 * Passive case: previously, this was handled in the default, just like the master case.
 	 * This the announce would call addForeign(), but NOT reset the timer, so after 12s it would expire and we would come alive periodically 
 	 *
-	 * This code is now merged with the slave case to reset the timer, and call addForeign() if it's a third master
+	 * This code is now merged with the slave case to reset the timer, and  call addForeign() if it's a third master
 	 *
 	 */
 	case PTP_PASSIVE:
@@ -756,7 +939,7 @@
 			/*Reset Timer handling Announce receipt timeout*/
 			timerStart(ANNOUNCE_RECEIPT_TIMER,
 				   (ptpClock->announceReceiptTimeout) *
-				   (pow(2,ptpClock->logAnnounceInterval)),
+				   rtOpts->announceInterval,
 				   ptpClock->itimer);
 		} else {
 			/*addForeign takes care of AnnounceUnpacking*/
@@ -769,27 +952,27 @@
 		}
 		break;
 
-		
+
 	case PTP_MASTER:
-	case PTP_LISTENING:           /* listening mode still causes timeouts in order to send IGMP refreshes */
+	case PTP_LISTENING:			/* listening mode still causes timeouts in order to send IGMP refreshes */
 	default :
-		if (isFromSelf) {
+		if (isFromSelf)	{
 			DBGV("HandleAnnounce : Ignore message from self \n");
 			return;
 		}
 
 		DBGV("Announce message from another foreign master\n");
 		addForeign(ptpClock->msgIbuf,header,ptpClock);
-		ptpClock->record_update = TRUE;    /* run BMC() as soon as possible */
+		ptpClock->record_update = TRUE;		/* run BMC() as soon as possible */
 		break;
 
 	} /* switch on (port_state) */
 }
 
 
-void 
-handleSync(MsgHeader *header, Octet *msgIbuf, ssize_t length, 
-	   TimeInternal *time, Boolean isFromSelf, 
+void
+handleSync(MsgHeader *header, Octet *msgIbuf, ssize_t length,
+	   TimeInternal *time, Boolean isFromSelf,
 	   RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	TimeInternal OriginTimestamp;
@@ -797,12 +980,12 @@
 
 	Boolean isFromCurrentParent = FALSE;
 	DBGV("Sync message received : \n");
-	
+
 	if (length < SYNC_LENGTH) {
 		ERROR("short Sync message\n");
 		toState(PTP_FAULTY, rtOpts, ptpClock);
 		return;
-	}	
+	}
 
 	switch (ptpClock->portState) {
 	case PTP_INITIALIZING:
@@ -810,8 +993,8 @@
 	case PTP_DISABLED:
 		DBGV("HandleSync : disregard\n");
 		return;
-		
-	case PTP_UNCALIBRATED:	
+
+	case PTP_UNCALIBRATED:
 	case PTP_SLAVE:
 		if (isFromSelf) {
 			DBGV("HandleSync: Ignore message from self \n");
@@ -820,27 +1003,27 @@
 		isFromCurrentParent =
 			!memcmp(ptpClock->parentPortIdentity.clockIdentity,
 				header->sourcePortIdentity.clockIdentity,
-				CLOCK_IDENTITY_LENGTH) && 
-			(ptpClock->parentPortIdentity.portNumber == 
+				CLOCK_IDENTITY_LENGTH) &&
+			(ptpClock->parentPortIdentity.portNumber ==
 			 header->sourcePortIdentity.portNumber);
-		
+
 		if (isFromCurrentParent) {
 			/* We only start our own delayReq timer after receiving the first sync */
 			if (ptpClock->waiting_for_first_sync) {
 				ptpClock->waiting_for_first_sync = FALSE;
 				NOTICE("Received first Sync from Master\n");
-				NOTICE("   going to arm DelayReq timer for the first time, with initial rate: %d\n",
-					ptpClock->logMinDelayReqInterval
+				NOTICE("   going to arm DelayReq timer for the first time, with initial rate: %Lf\n",
+					ptpClock->minDelayReqInterval
 				);
 
 				if (ptpClock->delayMechanism == E2E)
 					timerStart(DELAYREQ_INTERVAL_TIMER,
-						   pow(2,ptpClock->logMinDelayReqInterval),
-						   ptpClock->itimer);
+							ptpClock->minDelayReqInterval,
+							ptpClock->itimer);
 				else if (ptpClock->delayMechanism == P2P)
 					timerStart(PDELAYREQ_INTERVAL_TIMER,
-						   pow(2,ptpClock->logMinPdelayReqInterval),
-						   ptpClock->itimer);
+                               pow(2,ptpClock->logMinPdelayReqInterval),
+                               ptpClock->itimer);
 			}
 
 			ptpClock->sync_receive_time.seconds = time->seconds;
@@ -852,13 +1035,13 @@
 				DBG2("HandleSync: waiting for follow-up \n");
 
 				ptpClock->waitingForFollow = TRUE;
-				ptpClock->recvSyncSequenceId = 
+				ptpClock->recvSyncSequenceId =
 					header->sequenceId;
 				/*Save correctionField of Sync message*/
 				integer64_to_internalTime(
 					header->correctionfield,
 					&correctionField);
-				ptpClock->lastSyncCorrectionField.seconds = 
+				ptpClock->lastSyncCorrectionField.seconds =
 					correctionField.seconds;
 				ptpClock->lastSyncCorrectionField.nanoseconds =
 					correctionField.nanoseconds;
@@ -895,9 +1078,9 @@
 		} if (ptpClock->twoStepFlag) {
 			DBGV("HandleSync: going to send followup message\n ");
 
-			/*Add latency*/
-			addTime(time,time,&rtOpts->outboundLatency);
-			issueFollowup(time,rtOpts,ptpClock);
+      /*Add latency*/
+      addTime(time,time,&rtOpts->outboundLatency);
+      issueFollowup(time,rtOpts,ptpClock);
 			break;
 		} else {
 			DBGV("HandleSync: Sync message received from self\n ");
@@ -906,17 +1089,17 @@
 }
 
 
-void 
-handleFollowUp(MsgHeader *header, Octet *msgIbuf, ssize_t length, 
+void
+handleFollowUp(MsgHeader *header, Octet *msgIbuf, ssize_t length,
 	       Boolean isFromSelf, RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	DBGV("Handlefollowup : Follow up message received \n");
-	
+
 	TimeInternal preciseOriginTimestamp;
 	TimeInternal correctionField;
 	Boolean isFromCurrentParent = FALSE;
-	
-	if (length < FOLLOW_UP_LENGTH)
+
+	if(length < FOLLOW_UP_LENGTH)
 	{
 		ERROR("short Follow up message\n");
 		toState(PTP_FAULTY, rtOpts, ptpClock);
@@ -937,19 +1120,19 @@
 	case PTP_LISTENING:
 		DBGV("Handfollowup : disregard\n");
 		return;
-		
-	case PTP_UNCALIBRATED:	
+
+	case PTP_UNCALIBRATED:
 	case PTP_SLAVE:
-		isFromCurrentParent = 
+		isFromCurrentParent =
 			!memcmp(ptpClock->parentPortIdentity.clockIdentity,
 				header->sourcePortIdentity.clockIdentity,
-				CLOCK_IDENTITY_LENGTH) && 
-			(ptpClock->parentPortIdentity.portNumber == 
+				CLOCK_IDENTITY_LENGTH) &&
+			(ptpClock->parentPortIdentity.portNumber ==
 			 header->sourcePortIdentity.portNumber);
-	 	
+
 		if (isFromCurrentParent) {
 			if (ptpClock->waitingForFollow)	{
-				if ((ptpClock->recvSyncSequenceId == 
+				if ((ptpClock->recvSyncSequenceId ==
 				     header->sequenceId)) {
 					msgUnpackFollowUp(ptpClock->msgIbuf,
 							  &ptpClock->msgTmp.follow);
@@ -979,6 +1162,7 @@
 				     "message \n");
 		} else
 			DBG2("Ignored, Follow up message is not from current parent \n");
+	break;
 
 	case PTP_MASTER:
 	case PTP_PASSIVE:
@@ -994,13 +1178,13 @@
 
 
 void
-handleDelayReq(MsgHeader *header, Octet *msgIbuf, ssize_t length, 
+handleDelayReq(MsgHeader *header, Octet *msgIbuf, ssize_t length,
 	       TimeInternal *time, Boolean isFromSelf,
 	       RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	if (ptpClock->delayMechanism == E2E) {
 		DBGV("delayReq message received : \n");
-		
+
 		if (length < DELAY_REQ_LENGTH) {
 			ERROR("short DelayReq message\n");
 			toState(PTP_FAULTY, rtOpts, ptpClock);
@@ -1018,7 +1202,7 @@
 			return;
 
 		case PTP_SLAVE:
-			if (isFromSelf)	{
+			if (isFromSelf) {
 				DBG("==> Handle DelayReq (%d)\n",
 					 header->sequenceId);
 				
@@ -1062,14 +1246,14 @@
 			// remember IP address of this client for -U option
 			ptpClock->LastSlaveAddr = ptpClock->netPath.lastRecvAddr;
 #endif
-					
+			
 			issueDelayResp(time,&ptpClock->delayReqHeader,
-				       rtOpts,ptpClock);
+					rtOpts,ptpClock);
 			break;
 
 		default:
 			DBG("do unrecognized state2\n");
-			break;
+      break;
 		}
 	} else /* (Peer to Peer mode) */
 		ERROR("Delay messages are ignored in Peer to Peer mode\n");
@@ -1108,16 +1292,16 @@
 			if ((memcmp(ptpClock->parentPortIdentity.clockIdentity,
 				    header->sourcePortIdentity.clockIdentity,
 				    CLOCK_IDENTITY_LENGTH) == 0 ) &&
-			    (ptpClock->parentPortIdentity.portNumber == 
+			    (ptpClock->parentPortIdentity.portNumber ==
 			     header->sourcePortIdentity.portNumber))
 				isFromCurrentParent = TRUE;
-			
+
 			if ((memcmp(ptpClock->portIdentity.clockIdentity,
 				    ptpClock->msgTmp.resp.requestingPortIdentity.clockIdentity,
 				    CLOCK_IDENTITY_LENGTH) == 0) &&
-			    ((ptpClock->sentDelayReqSequenceId - 1)== 
+			    ((UInteger16)(ptpClock->sentDelayReqSequenceId - 1)==
 			     header->sequenceId) &&
-			    (ptpClock->portIdentity.portNumber == 
+			    (ptpClock->portIdentity.portNumber ==
 			     ptpClock->msgTmp.resp.requestingPortIdentity.portNumber)
 			    && isFromCurrentParent) {
 				DBG("==> Handle DelayResp (%d)\n",
@@ -1131,15 +1315,15 @@
 
 				toInternalTime(&requestReceiptTimestamp,
 					       &ptpClock->msgTmp.resp.receiveTimestamp);
-				ptpClock->delay_req_receive_time.seconds = 
+				ptpClock->delay_req_receive_time.seconds =
 					requestReceiptTimestamp.seconds;
-				ptpClock->delay_req_receive_time.nanoseconds = 
+				ptpClock->delay_req_receive_time.nanoseconds =
 					requestReceiptTimestamp.nanoseconds;
 
 				integer64_to_internalTime(
 					header->correctionfield,
 					&correctionField);
-				
+
 				/*
 					send_time = delay_req_send_time (received as CMSG in handleEvent)
 					recv_time = requestReceiptTimestamp (received inside delayResp)
@@ -1150,7 +1334,7 @@
 
 				if (ptpClock->waiting_for_first_delayresp) {
 					ptpClock->waiting_for_first_delayresp = FALSE;
-					NOTICE("  received first DelayResp from Master\n");
+					NOTICE(" received first DelayResp from Master\n");
 				}
 
 				if (rtOpts->ignore_delayreq_interval_master == 0) {
@@ -1160,18 +1344,19 @@
 
 					/* Accept new DelayReq value from the Master */
 					if (ptpClock->logMinDelayReqInterval != header->logMessageInterval) {
-						NOTICE("  received new DelayReq frequency %d from Master (was: %d)\n",
+						NOTICE(" received new DelayReq frequency %d from Master (was: %d)\n",
 							 header->logMessageInterval, ptpClock->logMinDelayReqInterval );
 					}
 
 					// collect new value indicated from the Master
 					ptpClock->logMinDelayReqInterval = header->logMessageInterval;
-					
+					ptpClock->minDelayReqInterval = pow(2, header->logMessageInterval);
+
 					/* FIXME: the actual rearming of this timer with the new value only happens later in doState()/issueDelayReq() */
 				} else {
-					if (ptpClock->logMinDelayReqInterval != rtOpts->subsequent_delayreq) {
+					if (ptpClock->minDelayReqInterval != rtOpts->subsequent_delayreq) {
 						NOTICE("  received new DelayReq frequency %d from command line (was: %d)\n",
-							rtOpts->subsequent_delayreq, ptpClock->logMinDelayReqInterval);
+							rtOpts->subsequent_delayreq, ptpClock->minDelayReqInterval);
 					}
 					ptpClock->logMinDelayReqInterval = rtOpts->subsequent_delayreq;
 				}
@@ -1187,9 +1372,9 @@
 }
 
 
-void 
-handlePDelayReq(MsgHeader *header, Octet *msgIbuf, ssize_t length, 
-		TimeInternal *time, Boolean isFromSelf, 
+void
+handlePDelayReq(MsgHeader *header, Octet *msgIbuf, ssize_t length,
+		TimeInternal *time, Boolean isFromSelf,
 		RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	if (ptpClock->delayMechanism == P2P) {
@@ -1201,7 +1386,7 @@
 			return;
 		}
 
-		switch (ptpClock->portState ) {
+		switch(ptpClock->portState ) {
 		case PTP_INITIALIZING:
 		case PTP_FAULTY:
 		case PTP_DISABLED:
@@ -1222,7 +1407,7 @@
 					time->seconds;
 				ptpClock->pdelay_req_send_time.nanoseconds = 
 					time->nanoseconds;
-			
+
 				/*Add latency*/
 				addTime(&ptpClock->pdelay_req_send_time,
 					&ptpClock->pdelay_req_send_time,
@@ -1230,33 +1415,33 @@
 				break;
 			} else {
 				msgUnpackHeader(ptpClock->msgIbuf,
-						&ptpClock->PdelayReqHeader);
-				issuePDelayResp(time, header, rtOpts, 
-						ptpClock);	
+					&ptpClock->PdelayReqHeader);
+				issuePDelayResp(time, header, rtOpts,
+					ptpClock);
 				break;
 			}
-		default:
-			DBG("do unrecognized state3\n");
-			break;
-		}
-	} else /* (End to End mode..) */
+    default:
+      DBG("do unrecognized state3\n");
+      break;
+    }
+  } else /* (End to End mode..) */
 		ERROR("Peer Delay messages are disregarded in End to End "
 		      "mode \n");
 }
 
 void
 handlePDelayResp(MsgHeader *header, Octet *msgIbuf, TimeInternal *time,
-		 ssize_t length, Boolean isFromSelf, 
+		 ssize_t length, Boolean isFromSelf,
 		 RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
 	if (ptpClock->delayMechanism == P2P) {
 		/* Boolean isFromCurrentParent = FALSE; NOTE: This is never used in this function */
 		TimeInternal requestReceiptTimestamp;
 		TimeInternal correctionField;
-	
+
 		DBGV("PdelayResp message received : \n");
 
-		if (length < PDELAY_RESP_LENGTH) {
+		if (length < PDELAY_RESP_LENGTH)	{
 			ERROR("short PDelayResp message\n");
 			toState(PTP_FAULTY, rtOpts, ptpClock);
 			return;
@@ -1276,25 +1461,29 @@
 			if (ptpClock->twoStepFlag && isFromSelf) {
 				addTime(time,time,&rtOpts->outboundLatency);
 				issuePDelayRespFollowUp(time,
-							&ptpClock->PdelayReqHeader,
-							rtOpts,ptpClock);
+						&ptpClock->PdelayReqHeader,
+						rtOpts,ptpClock);
 				break;
 			}
 			msgUnpackPDelayResp(ptpClock->msgIbuf,
 					    &ptpClock->msgTmp.presp);
-		
+
 #if 0  /* NOTE: This is never used in this function. Should it? */
 			isFromCurrentParent = !memcmp(ptpClock->parentPortIdentity.clockIdentity,
-						      header->sourcePortIdentity.clockIdentity,CLOCK_IDENTITY_LENGTH) && 
-				(ptpClock->parentPortIdentity.portNumber == 
+						      header->sourcePortIdentity.clockIdentity,CLOCK_IDENTITY_LENGTH) &&
+				(ptpClock->parentPortIdentity.portNumber ==
 				 header->sourcePortIdentity.portNumber);
-#endif	
-			if (!((ptpClock->sentPDelayReqSequenceId == 
-			       header->sequenceId) && 
+#endif  
+      /* TODO Not convinced that we will detect scenario where peer delay was transmitted but
+       * the retrieval of the timestamp failed. In theory, we should reject the response packet
+       * here because the sequence number doesn't match
+       */
+			if (!((ptpClock->sentPDelayReqSequenceId ==
+			       header->sequenceId) &&
 			      (!memcmp(ptpClock->portIdentity.clockIdentity,ptpClock->msgTmp.presp.requestingPortIdentity.clockIdentity,CLOCK_IDENTITY_LENGTH))
 				 && ( ptpClock->portIdentity.portNumber == ptpClock->msgTmp.presp.requestingPortIdentity.portNumber)))	{
 
-				/* Two Step Clock */
+                                /* Two Step Clock */
 				if ((header->flagField[0] & PTP_TWO_STEP) == PTP_TWO_STEP) {
 					/*Store t4 (Fig 35)*/
 					ptpClock->pdelay_resp_receive_time.seconds = time->seconds;
@@ -1304,7 +1493,7 @@
 						       &ptpClock->msgTmp.presp.requestReceiptTimestamp);
 					ptpClock->pdelay_req_receive_time.seconds = requestReceiptTimestamp.seconds;
 					ptpClock->pdelay_req_receive_time.nanoseconds = requestReceiptTimestamp.nanoseconds;
-					
+
 					integer64_to_internalTime(header->correctionfield,&correctionField);
 					ptpClock->lastPdelayRespCorrectionField.seconds = correctionField.seconds;
 					ptpClock->lastPdelayRespCorrectionField.nanoseconds = correctionField.nanoseconds;
@@ -1314,7 +1503,7 @@
 					/*Store t4 (Fig 35)*/
 					ptpClock->pdelay_resp_receive_time.seconds = time->seconds;
 					ptpClock->pdelay_resp_receive_time.nanoseconds = time->nanoseconds;
-					
+
 					integer64_to_internalTime(header->correctionfield,&correctionField);
 					updatePeerDelay (&ptpClock->owd_filt,rtOpts,ptpClock,&correctionField,FALSE);
 					break;
@@ -1337,23 +1526,23 @@
 	}
 }
 
-void 
-handlePDelayRespFollowUp(MsgHeader *header, Octet *msgIbuf, ssize_t length, 
-			 Boolean isFromSelf, RunTimeOpts *rtOpts, 
+void
+handlePDelayRespFollowUp(MsgHeader *header, Octet *msgIbuf, ssize_t length,
+			 Boolean isFromSelf, RunTimeOpts *rtOpts,
 			 PtpClock *ptpClock){
 
 	if (ptpClock->delayMechanism == P2P) {
 		TimeInternal responseOriginTimestamp;
 		TimeInternal correctionField;
-	
+
 		DBGV("PdelayRespfollowup message received : \n");
-	
+
 		if(length < PDELAY_RESP_FOLLOW_UP_LENGTH) {
 			ERROR("short PDelayRespfollowup message\n");
 			toState(PTP_FAULTY, rtOpts, ptpClock);
 			return;
-		}	
-	
+		}
+
 		switch(ptpClock->portState) {
 		case PTP_INITIALIZING:
 		case PTP_FAULTY:
@@ -1361,29 +1550,29 @@
 		case PTP_UNCALIBRATED:
 			DBGV("HandlePdelayResp : disregard\n");
 			return;
-		
+
 		case PTP_SLAVE:
 		case PTP_MASTER:
 			if ((header->sequenceId == 
-			    ptpClock->sentPDelayReqSequenceId-1) && (header->sequenceId == ptpClock->recvPDelayRespSequenceId)) {
+			      (UInteger16)(ptpClock->sentPDelayReqSequenceId-1)) && (header->sequenceId == ptpClock->recvPDelayRespSequenceId)) {
 				msgUnpackPDelayRespFollowUp(
-					ptpClock->msgIbuf,
-					&ptpClock->msgTmp.prespfollow);
+						ptpClock->msgIbuf,
+						&ptpClock->msgTmp.prespfollow);
 				toInternalTime(
-					&responseOriginTimestamp,
-					&ptpClock->msgTmp.prespfollow.responseOriginTimestamp);
-				ptpClock->pdelay_resp_send_time.seconds = 
-					responseOriginTimestamp.seconds;
-				ptpClock->pdelay_resp_send_time.nanoseconds = 
-					responseOriginTimestamp.nanoseconds;
+						&responseOriginTimestamp,
+						&ptpClock->msgTmp.prespfollow.responseOriginTimestamp);
+				 ptpClock->pdelay_resp_send_time.seconds = 
+					 responseOriginTimestamp.seconds;
+				 ptpClock->pdelay_resp_send_time.nanoseconds = 
+					 responseOriginTimestamp.nanoseconds;
 				integer64_to_internalTime(
-					ptpClock->msgTmpHeader.correctionfield,
-					&correctionField);
+						ptpClock->msgTmpHeader.correctionfield,
+						&correctionField);
 				addTime(&correctionField,&correctionField,
-					&ptpClock->lastPdelayRespCorrectionField);
+						&ptpClock->lastPdelayRespCorrectionField);
 				updatePeerDelay (&ptpClock->owd_filt,
-						 rtOpts, ptpClock,
-						 &correctionField,TRUE);
+						rtOpts, ptpClock,
+						&correctionField,TRUE);
 				break;
 			}
 		default:
@@ -1395,26 +1584,26 @@
 	}
 }
 
-void 
-handleManagement(MsgHeader *header, Octet *msgIbuf, ssize_t length, 
+void
+handleManagement(MsgHeader *header, Octet *msgIbuf, ssize_t length,
 		 Boolean isFromSelf, RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {}
 
-void 
-handleSignaling(MsgHeader *header, Octet *msgIbuf, ssize_t length, 
-		     Boolean isFromSelf, RunTimeOpts *rtOpts, 
+void
+handleSignaling(MsgHeader *header, Octet *msgIbuf, ssize_t length,
+		     Boolean isFromSelf, RunTimeOpts *rtOpts,
 		     PtpClock *ptpClock)
 {}
 
 
 /*Pack and send on general multicast ip adress an Announce message*/
-void 
+void
 issueAnnounce(RunTimeOpts *rtOpts,PtpClock *ptpClock)
 {
 	msgPackAnnounce(ptpClock->msgObuf,ptpClock);
 
-	if (!netSendGeneral(ptpClock->msgObuf,ANNOUNCE_LENGTH,
-			    &ptpClock->netPath, 0)) {
+	if (netSendGeneral(ptpClock->msgObuf,ANNOUNCE_LENGTH,
+			    &ptpClock->netPath, 0) != 0) {
 		toState(PTP_FAULTY,rtOpts,ptpClock);
 		DBGV("Announce message can't be sent -> FAULTY state \n");
 	} else {
@@ -1429,20 +1618,30 @@
 void
 issueSync(RunTimeOpts *rtOpts,PtpClock *ptpClock)
 {
-	Timestamp originTimestamp;
-	TimeInternal internalTime;
-	getTime(&internalTime);
-	fromInternalTime(&internalTime,&originTimestamp);
+  Timestamp originTimestamp;
+  TimeInternal internalTime;
+  int rc;
+  
+  getTime(&internalTime, rtOpts->time_mode, ptpClock); 
+  fromInternalTime(&internalTime,&originTimestamp);
 
-	msgPackSync(ptpClock->msgObuf,&originTimestamp,ptpClock);
+  msgPackSync(ptpClock->msgObuf,&originTimestamp,ptpClock);
 
-	if (!netSendEvent(ptpClock->msgObuf,SYNC_LENGTH,&ptpClock->netPath, 0)) {
-		toState(PTP_FAULTY,rtOpts,ptpClock);
-		DBGV("Sync message can't be sent -> FAULTY state \n");
-	} else {
-		DBGV("Sync MSG sent ! \n");
-		ptpClock->sentSyncSequenceId++;
-	}
+  rc = netSendEvent(ptpClock->msgObuf,SYNC_LENGTH,ptpClock,rtOpts, 0);
+  if (rc != 0) {
+    /* If we failed because we didn't retrieve the transmit timestamp this is 
+     * most likely because we've lost the network connection. PTPD will recover
+     * if the network connection is reestablished. In this case don't go into the
+     * faulty state as this does a complete re-initialisation.
+     */
+    if (rc != ENOTIMESTAMP) {
+      toState(PTP_FAULTY,rtOpts,ptpClock);
+      DBGV("Sync message can't be sent -> FAULTY state \n");
+    }
+  } else {
+    DBGV("Sync MSG sent ! \n");
+    ptpClock->sentSyncSequenceId++;
+  }
 }
 
 
@@ -1452,11 +1651,11 @@
 {
 	Timestamp preciseOriginTimestamp;
 	fromInternalTime(time,&preciseOriginTimestamp);
-	
+
 	msgPackFollowUp(ptpClock->msgObuf,&preciseOriginTimestamp,ptpClock);
-	
-	if (!netSendGeneral(ptpClock->msgObuf,FOLLOW_UP_LENGTH,
-			    &ptpClock->netPath, 0)) {
+
+	if (netSendGeneral(ptpClock->msgObuf,FOLLOW_UP_LENGTH,
+				&ptpClock->netPath, 0) != 0) {
 		toState(PTP_FAULTY,rtOpts,ptpClock);
 		DBGV("FollowUp message can't be sent -> FAULTY state \n");
 	} else {
@@ -1471,11 +1670,12 @@
 {
 	Timestamp originTimestamp;
 	TimeInternal internalTime;
+	int rc;
 
 	DBG("==> Issue DelayReq (%d)\n", ptpClock->sentDelayReqSequenceId );
 
 	/* call GTOD. This time is later replaced on handle_delayreq, to get the actual send timestamp from the OS */
-	getTime(&internalTime);
+	getTime(&internalTime, rtOpts->time_mode, ptpClock);
 	fromInternalTime(&internalTime,&originTimestamp);
 
 	// uses current sentDelayReqSequenceId
@@ -1488,61 +1688,89 @@
 	}
 #endif
 
-	if (!netSendEvent(ptpClock->msgObuf,DELAY_REQ_LENGTH,
-			  &ptpClock->netPath, dst)) {
-		toState(PTP_FAULTY,rtOpts,ptpClock);
-		DBGV("delayReq message can't be sent -> FAULTY state \n");
-	} else {
-		DBGV("DelayReq MSG sent ! \n");
-		ptpClock->sentDelayReqSequenceId++;
+	rc = netSendEvent(ptpClock->msgObuf, DELAY_REQ_LENGTH,
+			ptpClock,rtOpts, dst);
+  if (rc != 0) {
+    /* If we failed because we didn't retrieve the transmit timestamp this is 
+     * most likely because we've lost the network connection. PTPD will recover
+     * if the network connection is reestablished. In this case don't go into the
+     * faulty state as this does a complete re-initialisation.
+     */
+    if (rc != ENOTIMESTAMP) {
+      toState(PTP_FAULTY,rtOpts,ptpClock);
+      DBGV("delayReq message can't be sent -> FAULTY state \n");
+    }
+  } else {
+    DBGV("DelayReq MSG sent ! \n");
+    ptpClock->sentDelayReqSequenceId++;
 
 		/* From now on, we will only accept delayreq and delayresp of (sentDelayReqSequenceId - 1) */
 
-		/* Explicitelly re-arm timer for sending the next delayReq */
-		timerStart_random(DELAYREQ_INTERVAL_TIMER,
-		   pow(2,ptpClock->logMinDelayReqInterval),
-		   ptpClock->itimer);
-	}
+    /* Explicitelly re-arm timer for sending the next delayReq */
+    timerStart_random(DELAYREQ_INTERVAL_TIMER,
+		    ptpClock->minDelayReqInterval,
+                       ptpClock->itimer);
+  }
 }
 
 /*Pack and send on event multicast ip adress a PDelayReq message*/
 void
 issuePDelayReq(RunTimeOpts *rtOpts,PtpClock *ptpClock)
 {
-	Timestamp originTimestamp;
-	TimeInternal internalTime;
-	getTime(&internalTime);
-	fromInternalTime(&internalTime,&originTimestamp);
-	
-	msgPackPDelayReq(ptpClock->msgObuf,&originTimestamp,ptpClock);
+  Timestamp originTimestamp;
+  TimeInternal internalTime;
+  int rc;
+  
+  getTime(&internalTime, rtOpts->time_mode, ptpClock);
+  fromInternalTime(&internalTime,&originTimestamp);
 
-	if (!netSendPeerEvent(ptpClock->msgObuf,PDELAY_REQ_LENGTH,
-			      &ptpClock->netPath)) {
-		toState(PTP_FAULTY,rtOpts,ptpClock);
-		DBGV("PdelayReq message can't be sent -> FAULTY state \n");
-	} else {
-		DBGV("PDelayReq MSG sent ! \n");
-		ptpClock->sentPDelayReqSequenceId++;
-	}
+  msgPackPDelayReq(ptpClock->msgObuf,&originTimestamp,ptpClock);
+
+  rc = netSendPeerEvent(ptpClock->msgObuf,PDELAY_REQ_LENGTH,
+		  ptpClock, rtOpts);
+  if (rc != 0) {
+    /* If we failed because we didn't retrieve the transmit timestamp this is 
+     * most likely because we've lost the network connection. PTPD will recover
+     * if the network connection is reestablished. In this case don't go into the
+     * faulty state as this does a complete re-initialisation.
+     */
+    if (rc != ENOTIMESTAMP) {
+      toState(PTP_FAULTY,rtOpts,ptpClock);
+      DBGV("PdelayReq message can't be sent -> FAULTY state \n");
+    }
+  } else {
+    DBGV("PDelayReq MSG sent ! \n");
+    ptpClock->sentPDelayReqSequenceId++;
+  }
 }
 
 /*Pack and send on event multicast ip adress a PDelayResp message*/
 void
 issuePDelayResp(TimeInternal *time,MsgHeader *header,RunTimeOpts *rtOpts,
-		PtpClock *ptpClock)
+                PtpClock *ptpClock)
 {
-	Timestamp requestReceiptTimestamp;
-	fromInternalTime(time,&requestReceiptTimestamp);
-	msgPackPDelayResp(ptpClock->msgObuf,header,
-			  &requestReceiptTimestamp,ptpClock);
+  Timestamp requestReceiptTimestamp;
+  fromInternalTime(time,&requestReceiptTimestamp);
+  int rc;
+  
+  msgPackPDelayResp(ptpClock->msgObuf,header,
+		  &requestReceiptTimestamp,ptpClock);
 
-	if (!netSendPeerEvent(ptpClock->msgObuf,PDELAY_RESP_LENGTH,
-			      &ptpClock->netPath)) {
-		toState(PTP_FAULTY,rtOpts,ptpClock);
-		DBGV("PdelayResp message can't be sent -> FAULTY state \n");
-	} else {
-		DBGV("PDelayResp MSG sent ! \n");
-	}
+  rc = netSendPeerEvent(ptpClock->msgObuf,PDELAY_RESP_LENGTH,
+		  ptpClock, rtOpts);
+  if (rc != 0) {
+    /* If we failed because we didn't retrieve the transmit timestamp this is 
+     * most likely because we've lost the network connection. PTPD will recover
+     * if the network connection is reestablished. In this case don't go into the
+     * faulty state as this does a complete re-initialisation.
+     */
+    if (rc != ENOTIMESTAMP) {
+      toState(PTP_FAULTY,rtOpts,ptpClock);
+      DBGV("PdelayResp message can't be sent -> FAULTY state \n");
+    }
+  } else {
+    DBGV("PDelayResp MSG sent ! \n");
+  }
 }
 
 
@@ -1562,8 +1790,8 @@
 	}
 #endif
 
-	if (!netSendGeneral(ptpClock->msgObuf,PDELAY_RESP_LENGTH,
-			    &ptpClock->netPath, dst)) {
+	if (netSendGeneral(ptpClock->msgObuf,PDELAY_RESP_LENGTH,
+				&ptpClock->netPath, dst) != 0) {
 		toState(PTP_FAULTY,rtOpts,ptpClock);
 		DBGV("delayResp message can't be sent -> FAULTY state \n");
 	} else {
@@ -1574,73 +1802,73 @@
 
 void
 issuePDelayRespFollowUp(TimeInternal *time, MsgHeader *header,
-			     RunTimeOpts *rtOpts, PtpClock *ptpClock)
+                             RunTimeOpts *rtOpts, PtpClock *ptpClock)
 {
-	Timestamp responseOriginTimestamp;
-	fromInternalTime(time,&responseOriginTimestamp);
+  Timestamp responseOriginTimestamp;
+  fromInternalTime(time,&responseOriginTimestamp);
 
-	msgPackPDelayRespFollowUp(ptpClock->msgObuf,header,
-				  &responseOriginTimestamp,ptpClock);
+  msgPackPDelayRespFollowUp(ptpClock->msgObuf,header,
+		  &responseOriginTimestamp,ptpClock);
 
-	if (!netSendPeerGeneral(ptpClock->msgObuf,
-				PDELAY_RESP_FOLLOW_UP_LENGTH,
-				&ptpClock->netPath)) {
-		toState(PTP_FAULTY,rtOpts,ptpClock);
-		DBGV("PdelayRespFollowUp message can't be sent -> FAULTY state \n");
-	} else {
-		DBGV("PDelayRespFollowUp MSG sent ! \n");
-	}
+  if (netSendPeerGeneral(ptpClock->msgObuf,
+			  PDELAY_RESP_FOLLOW_UP_LENGTH,
+			  &ptpClock->netPath) != 0) {
+    toState(PTP_FAULTY,rtOpts,ptpClock);
+    DBGV("PdelayRespFollowUp message can't be sent -> FAULTY state \n");
+  } else {
+    DBGV("PDelayRespFollowUp MSG sent ! \n");
+  }
 }
 
-void 
+void
 issueManagement(MsgHeader *header,MsgManagement *manage,RunTimeOpts *rtOpts,
 		PtpClock *ptpClock)
 {}
 
-void 
+void
 addForeign(Octet *buf,MsgHeader *header,PtpClock *ptpClock)
 {
 	int i,j;
 	Boolean found = FALSE;
 
 	j = ptpClock->foreign_record_best;
-	
+
 	/*Check if Foreign master is already known*/
 	for (i=0;i<ptpClock->number_foreign_records;i++) {
 		if (!memcmp(header->sourcePortIdentity.clockIdentity,
 			    ptpClock->foreign[j].foreignMasterPortIdentity.clockIdentity,
-			    CLOCK_IDENTITY_LENGTH) && 
-		    (header->sourcePortIdentity.portNumber == 
+			    CLOCK_IDENTITY_LENGTH) &&
+		    (header->sourcePortIdentity.portNumber ==
 		     ptpClock->foreign[j].foreignMasterPortIdentity.portNumber))
 		{
 			/*Foreign Master is already in Foreignmaster data set*/
-			ptpClock->foreign[j].foreignMasterAnnounceMessages++; 
+			ptpClock->foreign[j].foreignMasterAnnounceMessages++;
 			found = TRUE;
 			DBGV("addForeign : AnnounceMessage incremented \n");
 			msgUnpackHeader(buf,&ptpClock->foreign[j].header);
 			msgUnpackAnnounce(buf,&ptpClock->foreign[j].announce);
 			break;
 		}
-	
+
 		j = (j+1)%ptpClock->number_foreign_records;
 	}
 
 	/*New Foreign Master*/
 	if (!found) {
-		if (ptpClock->number_foreign_records < 
+		if (ptpClock->number_foreign_records <
 		    ptpClock->max_foreign_records) {
 			ptpClock->number_foreign_records++;
 		}
 		j = ptpClock->foreign_record_i;
-		
+
 		/*Copy new foreign master data set from Announce message*/
 		memcpy(ptpClock->foreign[j].foreignMasterPortIdentity.clockIdentity,
 		       header->sourcePortIdentity.clockIdentity,
 		       CLOCK_IDENTITY_LENGTH);
-		ptpClock->foreign[j].foreignMasterPortIdentity.portNumber = 
+		ptpClock->foreign[j].foreignMasterPortIdentity.portNumber =
 			header->sourcePortIdentity.portNumber;
 		ptpClock->foreign[j].foreignMasterAnnounceMessages = 0;
-		
+
 		/*
 		 * header and announce field of each Foreign Master are
 		 * usefull to run Best Master Clock Algorithm
@@ -1648,9 +1876,9 @@
 		msgUnpackHeader(buf,&ptpClock->foreign[j].header);
 		msgUnpackAnnounce(buf,&ptpClock->foreign[j].announce);
 		DBGV("New foreign Master added \n");
-		
-		ptpClock->foreign_record_i = 
-			(ptpClock->foreign_record_i+1) % 
-			ptpClock->max_foreign_records;	
+
+		ptpClock->foreign_record_i =
+			(ptpClock->foreign_record_i+1) %
+			ptpClock->max_foreign_records;
 	}
 }
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/ptpd.c
--- a/src/ptpd.c	Tue May 14 17:07:59 2013 -0700
+++ b/src/ptpd.c	Sun Oct 27 22:49:29 2013 -0700
@@ -1,4 +1,6 @@
 /*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
  * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
  *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
  * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
@@ -57,48 +59,54 @@
 int
 main(int argc, char **argv)
 {
-	PtpClock *ptpClock;
-	Integer16 ret;
+    PtpClock *ptpClock;
+    Integer16 ret;
 
-	/* initialize run-time options to default values */
-	rtOpts.announceInterval = DEFAULT_ANNOUNCE_INTERVAL;
-	rtOpts.syncInterval = DEFAULT_SYNC_INTERVAL;
-	rtOpts.clockQuality.clockAccuracy = DEFAULT_CLOCK_ACCURACY;
-	rtOpts.clockQuality.clockClass = DEFAULT_CLOCK_CLASS;
-	rtOpts.clockQuality.offsetScaledLogVariance = DEFAULT_CLOCK_VARIANCE;
-	rtOpts.priority1 = DEFAULT_PRIORITY1;
-	rtOpts.priority2 = DEFAULT_PRIORITY2;
-	rtOpts.domainNumber = DEFAULT_DOMAIN_NUMBER;
+    /* initialize run-time options to default values */
+    rtOpts.announceInterval = DEFAULT_ANNOUNCE_INTERVAL;
+    rtOpts.syncInterval = DEFAULT_SYNC_INTERVAL;
+    rtOpts.clockQuality.clockAccuracy = DEFAULT_CLOCK_ACCURACY;
+    rtOpts.clockQuality.clockClass = DEFAULT_CLOCK_CLASS;
+    rtOpts.clockQuality.offsetScaledLogVariance = DEFAULT_CLOCK_VARIANCE;
+    rtOpts.priority1 = DEFAULT_PRIORITY1;
+    rtOpts.priority2 = DEFAULT_PRIORITY2;
+    rtOpts.domainNumber = DEFAULT_DOMAIN_NUMBER;
 #ifdef PTP_EXPERIMENTAL
 	rtOpts.mcast_group_Number = 0;
 	rtOpts.do_hybrid_mode = 0;
 #endif
 	
 	// rtOpts.slaveOnly = FALSE;
-	rtOpts.currentUtcOffset = DEFAULT_UTC_OFFSET;
-	rtOpts.ifaceName[0] = '\0';
-	rtOpts.do_unicast_mode = 0;
-
-	rtOpts.noAdjust = NO_ADJUST;  // false
-	// rtOpts.displayStats = FALSE;
-	// rtOpts.csvStats = FALSE;
-	/* Deep display of all packets seen by the daemon */
-	rtOpts.displayPackets = FALSE;
-	// rtOpts.unicastAddress
-	rtOpts.ap = DEFAULT_AP;
-	rtOpts.ai = DEFAULT_AI;
-	rtOpts.s = DEFAULT_DELAY_S;
-	rtOpts.inboundLatency.nanoseconds = DEFAULT_INBOUND_LATENCY;
-	rtOpts.outboundLatency.nanoseconds = DEFAULT_OUTBOUND_LATENCY;
-	rtOpts.max_foreign_records = DEFAULT_MAX_FOREIGN_RECORDS;
-	// rtOpts.ethernet_mode = FALSE;
-	// rtOpts.offset_first_updated = FALSE;
-	// rtOpts.file[0] = 0;
-	rtOpts.logFd = -1;
-	rtOpts.recordFP = NULL;
-	rtOpts.do_log_to_file = FALSE;
-	rtOpts.do_record_quality_file = FALSE;
-	rtOpts.nonDaemon = FALSE;
+    rtOpts.currentUtcOffset = DEFAULT_UTC_OFFSET;
+    rtOpts.currentUtcOffsetValid = DEFAULT_UTC_VALID;
+    rtOpts.ifaceName[0] = '\0';
+    rtOpts.do_unicast_mode = 0;
+    rtOpts.resetClockStartupOnly = DEFAULT_RESET_CLOCK_STARTUP_ONLY;
+    rtOpts.maxReset = 0;
+    rtOpts.maxDelay.seconds = 0;
+    rtOpts.maxDelay.nanoseconds = 0;
+    rtOpts.noAdjust = NO_ADJUST;	// false
+    // rtOpts.displayStats = FALSE;
+    rtOpts.verboseStats = FALSE;
+    // rtOpts.csvStats = FALSE;
+    /* Deep display of all packets seen by the daemon */
+    rtOpts.displayPackets = FALSE;
+    // rtOpts.unicastAddress
+    rtOpts.ap = DEFAULT_AP;
+    rtOpts.ai = DEFAULT_AI;
+    rtOpts.s = DEFAULT_DELAY_S;
+    rtOpts.inboundLatency.nanoseconds = DEFAULT_INBOUND_LATENCY;
+    rtOpts.outboundLatency.nanoseconds = DEFAULT_OUTBOUND_LATENCY;
+    rtOpts.max_foreign_records = DEFAULT_MAX_FOREIGN_RECORDS;
+    rtOpts.ethernet_mode = FALSE;
+    // rtOpts.offset_first_updated = FALSE;
+    // rtOpts.file[0] = 0;
+    rtOpts.logFd = -1;
+    rtOpts.recordFP = NULL;
+    rtOpts.ignore_daemon_lock = FALSE;
+    rtOpts.do_log_to_file = FALSE;
+    rtOpts.do_record_quality_file = FALSE;
+    rtOpts.nonDaemon = FALSE;
 
 	/*
 	 * defaults for new options
@@ -112,6 +120,9 @@
 #ifdef RUNTIME_DEBUG
 	rtOpts.debug_level = LOG_INFO;			/* by default debug messages as disabled, but INFO messages and below are printed */
 #endif
+	rtOpts.time_mode = DEFAULT_SLAVE_TIME_MODE;
+	rtOpts.master_slave_mode = PTP_MODE_NULL;
+	rtOpts.system_time_update_interval = DEFAULT_SYSTEM_TIME_UPDATE_INTERVAL;
 
 	rtOpts.ttl = 1;
 	rtOpts.delayMechanism   = DEFAULT_DELAY_MECHANISM;
@@ -121,20 +132,20 @@
 	rtOpts.initial_delayreq = DEFAULT_DELAYREQ_INTERVAL;
 	rtOpts.subsequent_delayreq = DEFAULT_DELAYREQ_INTERVAL;      // this will be updated if -g is given
 
-	/* Initialize run time options with command line arguments */
-	if (!(ptpClock = ptpdStartup(argc, argv, &ret, &rtOpts)))
-		return ret;
+    /* Initialize run time options with command line arguments */
+    if (!(ptpClock = ptpdStartup(argc, argv, &ret, &rtOpts)))
+        return ret;
 
-	/* global variable for message(), please see comment on top of this file */
-	G_ptpClock = ptpClock;
+    /* global variable for message(), please see comment on top of this file */
+    G_ptpClock = ptpClock;
 
-	/* do the protocol engine */
-	protocol(&rtOpts, ptpClock);
-	/* forever loop.. */
+    /* do the protocol engine */
+    protocol(&rtOpts, ptpClock);
+    /* forever loop.. */
 
-	ptpdShutdown(ptpClock);
+    ptpdShutdown(ptpClock);
 
 	NOTIFY("self shutdown, probably due to an error\n");
 
-	return 1;
+    return 1;
 }
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/ptpd.h
--- a/src/ptpd.h	Tue May 14 17:07:59 2013 -0700
+++ b/src/ptpd.h	Sun Oct 27 22:49:29 2013 -0700
@@ -1,16 +1,47 @@
+/*-
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2012 Solarflare Communications Inc
+ * Copyright (c) 2009-2011 George V. Neville-Neil, Steven Kreuzer, 
+ *                         Martin Burnicki, Gael Mace, Alexandre Van Kempen
+ * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /**
  * @file   ptpd.h
  * @mainpage Ptpd v2 Documentation
- * @authors Martin Burnicki, Alexandre van Kempen, Steven Kreuzer, 
+ * @authors Martin Burnicki, Alexandre van Kempen, Steven Kreuzer,
  *          George Neville-Neil
  * @version 2.0
  * @date   Fri Aug 27 10:22:19 2010
- * 
+ *
  * @section implementation Implementation
  * PTTdV2 is not a full implementation of 1588 - 2008 standard.
  * It is implemented only with use of Transparent Clock and Peer delay
  * mechanism, according to 802.1AS requierements.
- * 
+ *
  * This header file includes all others headers.
  * It defines functions which are not dependant of the operating system.
  */
@@ -31,7 +62,6 @@
 #include <limits.h>
 #include <netdb.h>
 #include <sys/time.h>
-#include <sys/resource.h>
 #ifndef __APPLE__
 #include <sys/timex.h>
 #endif
@@ -50,6 +80,11 @@
 #include "dep/datatypes_dep.h"
 #include "datatypes.h"
 #include "dep/ptpd_dep.h"
+#ifdef	__sun
+#define TIME_BAD TIME_ERROR
+#include <sys/time.h>
+#include <strings.h>
+#endif
 
 #define min(a,b)     (((a)<(b))?(a):(b))
 #define max(a,b)     (((a)>(b))?(a):(b))
@@ -61,10 +96,15 @@
 /* arith.c */
 
 /**
- * \brief Convert Integer64 into TimeInternal structure
+ * \brief Convert Integer64 with fractional ns into TimeInternal structure
  */
 void integer64_to_internalTime(Integer64,TimeInternal*);
 /**
+ * \brief Convert TimeInternal structure to linear 64 bit number
+ */
+int64_t internalTime_to_scalar(TimeInternal*);
+
+/**
  * \brief Convert TimeInternal into Timestamp structure (defined by the spec)
  */
 void fromInternalTime(TimeInternal*,Timestamp*);
@@ -74,12 +114,6 @@
  */
 void toInternalTime(TimeInternal*,Timestamp*);
 
-void ts_to_InternalTime(struct timespec *, TimeInternal *);
-void tv_to_InternalTime(struct timeval  *, TimeInternal *);
-
-
-
-
 /**
  * \brief Use to normalize a TimeInternal structure
  *
@@ -178,6 +212,7 @@
 
 void clearTime(TimeInternal *time);
 int isTimeInternalNegative(const TimeInternal * p);
+int log2IntegerSaturateAtZero(LongDouble number);
 
 char *dump_TimeInternal(const TimeInternal * p);
 char *dump_TimeInternal2(const char *st1, const TimeInternal * p1, const char *st2, const TimeInternal * p2);
@@ -193,6 +228,9 @@
 int is_Time_close(TimeInternal *x, TimeInternal *b, int nanos);
 int isTimeInternalNegative(const TimeInternal * p);
 
+float secondsToMidnight(void);
+float getPauseBeforeMidnight(Integer8 announceInterval);
+float getPauseAfterMidnight(Integer8 announceInterval);
 
 
 int check_timestamp_is_fresh2(TimeInternal * timeA, TimeInternal * timeB);
diff -r 3f1e7d35d0ab -r 821e8eadeaff src/ptpd2.8
--- a/src/ptpd2.8	Tue May 14 17:07:59 2013 -0700
+++ b/src/ptpd2.8	Sun Oct 27 22:49:29 2013 -0700
@@ -1,10 +1,13 @@
 .\" -*- nroff -*"
-.TH ptpd2 8 "January, 2012" "version 2.2.0" "Precision Time Protocol daemon"
+.\"
+.\" Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+.\"
+.TH ptpd "1M" "January, 2012" "version 2.2.0" "System Administration Commands"
 .SH NAME
-ptpd2 \- Precision Time Protocol daemon (1588-2008)
+ptpd \- Precision Time Protocol daemon (1588-2008)
 .SH SYNOPSIS
-.B ptpd2
-[?]
+.B /usr/lib/inet/ptpd
+[-?]
 [-B]
 [-c]
 [-C]
@@ -22,9 +25,8 @@
 [-a NUMBER,NUMBER]
 [-w NUMBER]
 [-b NAME]
+[-K]
 [-u ADDRESS]
-[-I group]
-[-U]
 [-e]
 [-h]
 [-l NUMBER,NUMBER]
@@ -41,15 +43,15 @@
 [-s NUMBER]
 [-p NUMBER]
 [-q NUMBER]
-[-G]
 [-W]
 [-Y NUMBER]
 [-L]
 [-j]
 .SH DESCRIPTION
-Implements the Precision Time Protocol (PTP) Version 2 as defined by the IEEE
-1588-2008 standard. PTP was developed to provide very precise time
-coordination of LAN connected computers.
+The ptpd program is a userland daemon that does very precise
+synchronization of system clocks of LAN connected systems.
+It implements the Precision Time Protocol (PTP)  Version  2
+as defined by the IEEE 1588-2008 standard.
 .PP
 PTPd is a complete implementation of the IEEE 1588 v2 specification for a
 standard (ordinary) clock. PTPd has been tested with and is known
@@ -59,6 +61,81 @@
 interoperable, and stable IEEE 1588 implementation.
 .PP
 For more information, see http://ptpd.sourceforge.net/
+.PP
+ptpd in Solaris works over any Ethernet based data link.
+It can also take advantage of PTP specific hardware found
+in certain NICs (Network Interface Card) for improved accuracy.
+.SH SERVICE MANAGEMENT
+The operation of ptpd is managed as a service by the service
+management facility, smf(5), under the service identifier:
+.TP
+.nf
+  svc:/network/ptp:default
+.fi
+.aj
+.PP
+Administrative actions on this service, such as  enabling,
+disabling,  or  requesting  restart,  can be performed using
+svcadm(1M). The service's status can be  queried  using  the
+svcs(1) command.  There are several options controlled by
+services properties which can be set by the system
+administrator. The available options can be listed by
+executing the following command:
+.PP
+.nf
+  svccfg -s svc:/network/ptp:default listprop config
+.fi
+.aj
+.PP
+Each of these properties can be set using this command:
+.PP
+.nf
+  svccfg -s svc:/network/ptp:default setprop <propname> = <value>
+.fi
+.aj
+
+
+See svcadm(1M) and svccfg(1M).
+
+Available options and their meaning are as follows:
+.TP
+.BR config/listen_ifname
+A string specifying the name of the link to which ptp daemon
+should bind to. By default, ptp daemon picks the first usable
+link with an IP address configured.
+.TP
+.BR config/node_type
+A string specifying the working mode of the ptpd. It can
+be either "slave" or "master". Default value is "slave".
+.TP
+.BR config/use_hw
+A boolean which when true, instructs ptpd to take advantage
+of the PTP hardware assist in the NIC. If set to true and
+NIC does not have PTP hardware assist, the ptpd will exit.
+Default is false. See EXAMPLES on how to recognize a NIC
+with PTP hardware assist.
+.TP
+.BR config/domain
+An integer specifying PTP domain as defined in the
+IEEE specification.  It can take values from 0 to 3
+both inclusive. Default value is 0.
+.TP
+.BR config/announce_interval
+An integer specifying the interval in seconds between
+successive PTP ANNOUNCE messages sent by PTP master.
+Default value is 2.
+.TP
+.BR config/sync_interval
+An integer specifying the interval between successive
+PTP SYNC messages sent by PTP master. Default value is 1.
+.TP
+.BR config/logfile
+A string specifying the location of the file  used  for
+log output. The default is /var/log/ptp.log
+.TP
+.BR  config/other_options
+A string specifying other command line options mentioned
+below to be passed to svc:/network/ptp:default at startup.
 .SH OPTIONS
 .TP
 .B \-?
@@ -115,15 +192,13 @@
 .B \-b NAME
 bind PTP to network interface NAME
 .TP
+.B \-K
+use PTP hardware in network interface. Exit if
+PTP hardware is not usable or available.
+.TP
 .B \-u ADDRESS
 also send uni-cast to ADDRESS
 .TP
-.B \-I
-multicast group for PTP_EXPERIMENTAL mode
-.TP
-.B \-U
-enable hybrid mode which uses both unicast and multicast, requires PTP_EXPERIMENTAL
-.TP
 .B \-e
 run in ethernet mode (currently unimplemented)
 .TP
@@ -172,20 +247,86 @@
 .B \-q NUMBER
 specify priority2 attribute
 .TP
-.B \-G
-run as master with connection to NTP
-.TP
 .B \-W
-run as master without NTP
+run as master only
 .TP
 .B \-Y NUMBER
 set an initial delay request value
 .TP
 .B \-L
-enable running multiple ptpd2 daemons
+enable running multiple ptpd daemons
 .TP
 .B \-j
 turn off IGMP refresh messages
+.SH EXAMPLES
+Example 1 Identify the presence of PTP hardware assist. If the
+ptp property is equal to 1, PTP hardware assist can
+be enabled for that NIC through the config/use_hw
+property.
+
+.nf
+#dladm show-linkprop -p ptp
+
+LINK   PROPERTY   PERM VALUE   EFFECTIVE  DEFAULT   POSSIBLE
+net1     ptp        r-    0        0          0          0,1
+net2     ptp        r-    0        0          0          0,1
+net0     ptp        r-    0        0          0          0,1
+net3     ptp        r-    0        0          0          0,1
+net7     ptp        r-    0        0          0          0,1
+net8     ptp        r-    1        1          0          0,1
+
+In the example above, the link net8 supports ptp in hardware.
+.fi
+
+Example 2 Starting the ptp service in slave mode.
+
+First bind ptp service to net8 -
+.nf
+#svccfg -s svc:/network/ptp:default \\
+    setprop config/listen_ifname=net8
+
+Then set the mode to "slave" -
+#svccfg -s svc:/network/ptp:default \\
+    setprop config/node_type=slave
+
+Enable the service -
+#svcadm enable svc:/network/ptp:default
+
+.fi
+Starting the service in slave mode will allow the ptp
+service to set system time to an external clock (PTP master)
+on the network connected to interface net8.
+.nf
+
+Example 3 Force ptp service to use PTP hardware in the NIC.
+
+First configure the service to use the PTP hardware -
+#svccfg -s svc:/network/ptp:default \\
+    setprop config/use_hw=yes
+
+.fi
+Then refresh the service, assuming it is enabled and online
+already -
+.nf
+#svcadm refresh svc:/network/ptp:default
+
+.fi
+.SH NOTES
+Be careful when logging is enabled. In default setting it can
+generate upto 40 MB of data in a window of 24 hours and many
+times more if enabled with -P option.
+.P
+Solaris does not allow creation of a vnic on a network
+interface which is providing hardware assistance to ptpd.
+Vice versa, ptpd cannot get hardware assistance from an
+interfac which has pre-existing vnic(s).
+
+.SH SEE ALSO
+svcs(1), svcadm(1M), attributes(5), smf(5)
+
+
+IEEE Standard 1588-2008, Precision Clock Synchronization
+Protocol for Networked Measurement and Control Systems, 2008
 
 .SH AUTHORS
 Gael Mace <[email protected]> & Alexandre Van