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