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 <mbrown@fensystems.co.uk>
+ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ *
+ * 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 <gael_mace@users.sourceforge.net> & Alexandre Van
