530 lines
16 KiB
C
530 lines
16 KiB
C
/**
|
|
* @file ptpd.h
|
|
* @mainpage Ptpd v2 Documentation
|
|
* @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.
|
|
*/
|
|
/*
|
|
modification history
|
|
--------------------
|
|
17oct23,rjq Fix Y2038 issue.
|
|
15aug16,xxy Add PTP features.(F6696)
|
|
06jun16,xxy Fix unstable error.(VXW7-3677)
|
|
02feb16,h_l Init version.
|
|
*/
|
|
|
|
#ifndef PTPD_H_
|
|
#define PTPD_H_
|
|
|
|
#define VXWORKS_OS
|
|
|
|
#ifdef VXWORKS_OS
|
|
#define HAVE_SYS_TIMEX_H
|
|
|
|
#define _POSIX_TIMERS 200112L
|
|
|
|
#define PACKAGE_VERSION "2.3.1"
|
|
#define usleep(x) taskDelay(sysClkRateGet() * x / 1000000)
|
|
|
|
#endif /*endif VXWORKS_OS*/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <ipptp_config.h>
|
|
#endif /* HAVE_CONFIG_H */
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_STRINGS_H
|
|
#include <strings.h>
|
|
#endif /* HAVE_STRINGS_H */
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
#include <limits.h>
|
|
#include <netdb.h>
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#ifdef HAVE_SYS_TIMEX_H
|
|
#ifndef VXWORKS_OS
|
|
#include <sys/timex.h>
|
|
#else
|
|
/*below parts copied from include/uapi/linux/timx.h*/
|
|
struct timex {
|
|
int modes; /* mode selector */
|
|
long offset; /* time offset (usec) */
|
|
int freq; /* frequency offset (scaled ppm) */
|
|
long maxerror;/* maximum error (usec) */
|
|
long esterror;/* estimated error (usec) */
|
|
int status; /* clock command/status */
|
|
long constant;/* pll time constant */
|
|
long precision;/* clock precision (usec) (read only) */
|
|
long tolerance;/* clock frequency tolerance (ppm)
|
|
* (read only)
|
|
*/
|
|
struct timeval time; /* (read only, except for ADJ_SETOFFSET) */
|
|
unsigned int tick; /* (modified) usecs between clock ticks */
|
|
|
|
|
|
int tai; /* TAI offset (ro) */
|
|
|
|
};
|
|
|
|
/*
|
|
* Mode codes (timex.mode)
|
|
*/
|
|
#define ADJ_OFFSET 0x0001 /* time offset */
|
|
#define ADJ_FREQUENCY 0x0002 /* frequency offset */
|
|
#define ADJ_MAXERROR 0x0004 /* maximum time error */
|
|
#define ADJ_ESTERROR 0x0008 /* estimated time error */
|
|
#define ADJ_STATUS 0x0010 /* clock status */
|
|
#define ADJ_TIMECONST 0x0020 /* pll time constant */
|
|
#define ADJ_TAI 0x0080 /* set TAI offset */
|
|
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
|
|
#define ADJ_MICRO 0x1000 /* select microsecond resolution */
|
|
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
|
|
#define ADJ_TICK 0x4000 /* tick value */
|
|
|
|
|
|
/* NTP userland likes the MOD_ prefix better */
|
|
#define MOD_OFFSET ADJ_OFFSET
|
|
#define MOD_FREQUENCY ADJ_FREQUENCY
|
|
#define MOD_MAXERROR ADJ_MAXERROR
|
|
#define MOD_ESTERROR ADJ_ESTERROR
|
|
#define MOD_STATUS ADJ_STATUS
|
|
#define MOD_TIMECONST ADJ_TIMECONST
|
|
#define MOD_TAI ADJ_TAI
|
|
#define MOD_MICRO ADJ_MICRO
|
|
#define MOD_NANO ADJ_NANO
|
|
|
|
|
|
/*
|
|
* Status codes (timex.status)
|
|
*/
|
|
#define STA_PLL 0x0001 /* enable PLL updates (rw) */
|
|
#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */
|
|
#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */
|
|
#define STA_FLL 0x0008 /* select frequency-lock mode (rw) */
|
|
|
|
#define STA_INS 0x0010 /* insert leap (rw) */
|
|
#define STA_DEL 0x0020 /* delete leap (rw) */
|
|
#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */
|
|
#define STA_FREQHOLD 0x0080 /* hold frequency (rw) */
|
|
|
|
#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */
|
|
#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */
|
|
#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */
|
|
#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
|
|
|
|
#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
|
|
#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */
|
|
#define STA_MODE 0x4000 /* mode (0 = PLL, 1 = FLL) (ro) */
|
|
#define STA_CLK 0x8000 /* clock source (0 = A, 1 = B) (ro) */
|
|
|
|
/* read-only bits */
|
|
#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
|
|
STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK)
|
|
|
|
/*
|
|
* Clock states (time_state)
|
|
*/
|
|
#define TIME_OK 0 /* clock synchronized, no leap second */
|
|
#define TIME_INS 1 /* insert leap second */
|
|
#define TIME_DEL 2 /* delete leap second */
|
|
#define TIME_OOP 3 /* leap second in progress */
|
|
#define TIME_WAIT 4 /* leap second has occurred */
|
|
#define TIME_ERROR 5 /* clock not synchronized */
|
|
#define TIME_BAD TIME_ERROR /* bw compat */
|
|
|
|
#endif
|
|
#endif
|
|
#include <sys/socket.h>
|
|
|
|
#include <ipcom_netif.h>
|
|
|
|
#ifdef VXWORKS_OS
|
|
#include <selectLib.h>
|
|
#else
|
|
#include <sys/select.h>
|
|
|
|
#endif
|
|
|
|
#include <sys/ioctl.h>
|
|
#ifndef VXWORKS_OS
|
|
#include <sys/param.h>
|
|
#endif
|
|
#include <arpa/inet.h>
|
|
#include <stdarg.h>
|
|
#include <syslog.h>
|
|
#include <limits.h>
|
|
#ifdef VXWORKS_OS
|
|
|
|
struct option
|
|
{
|
|
#if defined (__STDC__) && __STDC__
|
|
const char *name;
|
|
#else
|
|
char *name;
|
|
#endif
|
|
/* has_arg can't be an enum because some compilers complain about
|
|
type mismatches in all the code that assumes it is an int. */
|
|
int has_arg;
|
|
int *flag;
|
|
int val;
|
|
};
|
|
|
|
/* Names for the values of the `has_arg' field of `struct option'. */
|
|
|
|
#define no_argument 0
|
|
#define required_argument 1
|
|
#define optional_argument 2
|
|
#else
|
|
#include <getopt.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#ifndef VXWORKS_OS
|
|
#include <glob.h>
|
|
#endif
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#ifdef HAVE_UTMPX_H
|
|
#include <utmpx.h>
|
|
#else
|
|
#ifdef HAVE_UTMP_H
|
|
#include <utmp.h>
|
|
#endif /* HAVE_UTMP_H */
|
|
#endif /* HAVE_UTMPX_H */
|
|
|
|
#ifdef HAVE_NET_ETHERNET_H
|
|
#include <net/ethernet.h>
|
|
#endif /* HAVE_NET_ETHERNET_H */
|
|
|
|
#include <netinet/in.h>
|
|
#ifdef HAVE_NETINET_IN_SYSTM_H
|
|
#include <netinet/in_systm.h>
|
|
#endif
|
|
#include <netinet/ip.h>
|
|
#include <netinet/udp.h>
|
|
#ifdef HAVE_NETINET_ETHER_H
|
|
#include <netinet/ether.h>
|
|
#endif /* HAVE_NETINET_ETHER_H */
|
|
|
|
#ifdef HAVE_NET_IF_ARP_H
|
|
#include <net/if_arp.h>
|
|
#endif /* HAVE_NET_IF_ARP_H*/
|
|
|
|
#ifdef HAVE_NET_IF_H
|
|
#include <net/if.h>
|
|
#endif /* HAVE_NET_IF_H*/
|
|
|
|
#ifdef HAVE_NETINET_IF_ETHER_H
|
|
#include <netinet/if_ether.h>
|
|
#endif /* HAVE_NETINET_IF_ETHER_H */
|
|
|
|
/* This macro is to remove sudden jitter which would cause PTP unstable */
|
|
#define huge_jitter_counts_max 3
|
|
|
|
#ifdef HAVE_SYS_CPUSET_H
|
|
#include <sys/cpuset.h>
|
|
#endif /* HAVE_SYS_CPUSET_H */
|
|
|
|
#include "constants.h"
|
|
#include "limits.h"
|
|
|
|
#include "dep/ipv4_acl.h"
|
|
|
|
#include "dep/constants_dep.h"
|
|
#include "dep/datatypes_dep.h"
|
|
|
|
|
|
#include "datatypes.h"
|
|
|
|
|
|
#include "dep/ptpd_dep.h"
|
|
#include "dep/daemonconfig.h"
|
|
|
|
int64_t llabs(int64_t i);
|
|
|
|
/* NOTE: this macro can be refactored into a function */
|
|
#define XMALLOC(ptr,size) \
|
|
if(!((ptr)=malloc(size))) { \
|
|
PERROR("failed to allocate memory"); \
|
|
return; \
|
|
}
|
|
|
|
#define IS_SET(data, bitpos) \
|
|
((data & ( 0x1 << bitpos )) == (0x1 << bitpos))
|
|
|
|
#define SET_FIELD(data, bitpos) \
|
|
data << bitpos
|
|
/*
|
|
#define min(a,b) (((a)<(b))?(a):(b))
|
|
#define max(a,b) (((a)>(b))?(a):(b))
|
|
|
|
*/
|
|
/** \name arith.c
|
|
* -Timing management and arithmetic*/
|
|
/**\{*/
|
|
/* arith.c */
|
|
|
|
/**
|
|
* \brief Convert Integer64 into TimeInternal structure
|
|
*/
|
|
void integer64_to_internalTime(Integer64,TimeInternal*);
|
|
/**
|
|
* \brief Convert TimeInternal structure to Integer64
|
|
*/
|
|
void internalTime_to_integer64(TimeInternal, Integer64*);
|
|
/**
|
|
* \brief Convert TimeInternal into Timestamp structure (defined by the spec)
|
|
*/
|
|
void fromInternalTime(const TimeInternal*,Timestamp*);
|
|
|
|
/**
|
|
* \brief Convert Timestamp to TimeInternal structure (defined by the spec)
|
|
*/
|
|
void toInternalTime(TimeInternal*, const Timestamp*);
|
|
|
|
void ts_to_InternalTime(const struct timespec *, TimeInternal *);
|
|
void tv_to_InternalTime(const struct timeval *, TimeInternal *);
|
|
|
|
|
|
|
|
|
|
/**
|
|
* \brief Use to normalize a TimeInternal structure
|
|
*
|
|
* The nanosecondsField member must always be less than 10⁹
|
|
* This function is used after adding or substracting TimeInternal
|
|
*/
|
|
void normalizeTime(TimeInternal*);
|
|
|
|
/**
|
|
* \brief Add two InternalTime structure and normalize
|
|
*/
|
|
void addTime(TimeInternal*,const TimeInternal*,const TimeInternal*);
|
|
|
|
/**
|
|
* \brief Substract two InternalTime structure and normalize
|
|
*/
|
|
void subTime(TimeInternal*,const TimeInternal*,const TimeInternal*);
|
|
/** \}*/
|
|
|
|
/**
|
|
* \brief Divied an InternalTime by 2
|
|
*/
|
|
void div2Time(TimeInternal *);
|
|
|
|
/** \name bmc.c
|
|
* -Best Master Clock Algorithm functions*/
|
|
/**\{*/
|
|
/* bmc.c */
|
|
/**
|
|
* \brief Compare data set of foreign masters and local data set
|
|
* \return The recommended state for the port
|
|
*/
|
|
UInteger8 bmc(ForeignMasterRecord*, const RunTimeOpts*,PtpClock*);
|
|
|
|
/**
|
|
* \brief When recommended state is Master, copy local data into parent and grandmaster dataset
|
|
*/
|
|
void m1(const RunTimeOpts *, PtpClock*);
|
|
|
|
/**
|
|
* \brief When recommended state is Slave, copy dataset of master into parent and grandmaster dataset
|
|
*/
|
|
void s1(MsgHeader*,MsgAnnounce*,PtpClock*, const RunTimeOpts *);
|
|
|
|
|
|
void p1(PtpClock *ptpClock, const RunTimeOpts *rtOpts);
|
|
|
|
/**
|
|
* \brief Initialize datas
|
|
*/
|
|
void initData(RunTimeOpts*,PtpClock*);
|
|
/** \}*/
|
|
|
|
|
|
/** \name protocol.c
|
|
* -Execute the protocol engine*/
|
|
/**\{*/
|
|
/**
|
|
* \brief Protocol engine
|
|
*/
|
|
/* protocol.c */
|
|
void protocol(RunTimeOpts*,PtpClock*);
|
|
/** \}*/
|
|
|
|
/** \name management.c
|
|
* -Management message support*/
|
|
/**\{*/
|
|
/* management.c */
|
|
/**
|
|
* \brief Management message support
|
|
*/
|
|
void handleMMNullManagement(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMClockDescription(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMSlaveOnly(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMUserDescription(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMSaveInNonVolatileStorage(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMResetNonVolatileStorage(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMInitialize(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMDefaultDataSet(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMCurrentDataSet(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMParentDataSet(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMTimePropertiesDataSet(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMPortDataSet(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMPriority1(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMPriority2(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMDomain(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMLogAnnounceInterval(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMAnnounceReceiptTimeout(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMLogSyncInterval(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMVersionNumber(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMEnablePort(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMDisablePort(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMTime(MsgManagement*, MsgManagement*, PtpClock*, RunTimeOpts*);
|
|
void handleMMClockAccuracy(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMUtcProperties(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMTraceabilityProperties(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMDelayMechanism(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMLogMinPdelayReqInterval(MsgManagement*, MsgManagement*, PtpClock*);
|
|
void handleMMErrorStatus(MsgManagement*);
|
|
void handleErrorManagementMessage(MsgManagement *incoming, MsgManagement *outgoing,
|
|
PtpClock *ptpClock, Enumeration16 mgmtId,
|
|
Enumeration16 errorId);
|
|
/** \}*/
|
|
|
|
/*
|
|
* \brief Packing and Unpacking macros
|
|
*/
|
|
#define DECLARE_PACK( type ) void pack##type( void*, void* );
|
|
|
|
DECLARE_PACK( NibbleUpper )
|
|
DECLARE_PACK( Enumeration4Lower )
|
|
DECLARE_PACK( UInteger4Lower )
|
|
DECLARE_PACK( UInteger16 )
|
|
DECLARE_PACK( UInteger8 )
|
|
DECLARE_PACK( Octet )
|
|
DECLARE_PACK( Integer8 )
|
|
DECLARE_PACK( UInteger48 )
|
|
DECLARE_PACK( Integer64 )
|
|
|
|
#define DECLARE_UNPACK( type ) void unpack##type( void*, void*, PtpClock *ptpClock );
|
|
|
|
DECLARE_UNPACK( Boolean )
|
|
DECLARE_UNPACK( Enumeration4Lower )
|
|
DECLARE_UNPACK( Octet )
|
|
DECLARE_UNPACK( UInteger48 )
|
|
DECLARE_UNPACK( Integer64 )
|
|
|
|
/*Diplay functions usefull to debug */
|
|
void displayRunTimeOpts(const RunTimeOpts*);
|
|
void displayDefault (const PtpClock*);
|
|
void displayCurrent (const PtpClock*);
|
|
void displayParent (const PtpClock*);
|
|
void displayGlobal (const PtpClock*);
|
|
void displayPort (const PtpClock*);
|
|
void displayForeignMaster (const PtpClock*);
|
|
void displayOthers (const PtpClock*);
|
|
void displayBuffer (const PtpClock*);
|
|
void displayPtpClock (const PtpClock*);
|
|
void timeInternal_display(const TimeInternal*);
|
|
void clockIdentity_display(const ClockIdentity);
|
|
void netPath_display(const NetPath*);
|
|
void intervalTimer_display(const IntervalTimer*);
|
|
void integer64_display (const Integer64*);
|
|
void timeInterval_display(const TimeInterval*);
|
|
void portIdentity_display(const PortIdentity*);
|
|
void clockQuality_display (const ClockQuality*);
|
|
void PTPText_display(const PTPText*, const PtpClock*);
|
|
void unicast_display(const Octet*);
|
|
const char *portState_getName(Enumeration8 portState);
|
|
void timestamp_display(const Timestamp * timestamp);
|
|
|
|
void displayCounters(const PtpClock*);
|
|
void displayStatistics(const PtpClock*);
|
|
void clearCounters(PtpClock *);
|
|
|
|
void msgHeader_display(const MsgHeader*);
|
|
void msgAnnounce_display(const MsgAnnounce*);
|
|
void msgSync_display(const MsgSync *sync);
|
|
void msgFollowUp_display(const MsgFollowUp*);
|
|
void msgPDelayReq_display(const MsgPDelayReq*);
|
|
void msgDelayReq_display(const MsgDelayReq * req);
|
|
void msgDelayResp_display(const MsgDelayResp * resp);
|
|
void msgPDelayResp_display(const MsgPDelayResp * presp);
|
|
void msgPDelayRespFollowUp_display(const MsgPDelayRespFollowUp * prespfollow);
|
|
void msgManagement_display(const MsgManagement * manage);
|
|
|
|
|
|
void mMSlaveOnly_display(const MMSlaveOnly*, const PtpClock*);
|
|
void mMClockDescription_display(const MMClockDescription*, const PtpClock*);
|
|
void mMUserDescription_display(const MMUserDescription*, const PtpClock*);
|
|
void mMInitialize_display(const MMInitialize*, const PtpClock*);
|
|
void mMDefaultDataSet_display(const MMDefaultDataSet*, const PtpClock*);
|
|
void mMCurrentDataSet_display(const MMCurrentDataSet*, const PtpClock*);
|
|
void mMParentDataSet_display(const MMParentDataSet*, const PtpClock*);
|
|
void mMTimePropertiesDataSet_display(const MMTimePropertiesDataSet*, const PtpClock*);
|
|
void mMPortDataSet_display(const MMPortDataSet*, const PtpClock*);
|
|
void mMPriority1_display(const MMPriority1*, const PtpClock*);
|
|
void mMPriority2_display(const MMPriority2*, const PtpClock*);
|
|
void mMDomain_display(const MMDomain*, const PtpClock*);
|
|
void mMLogAnnounceInterval_display(const MMLogAnnounceInterval*, const PtpClock*);
|
|
void mMAnnounceReceiptTimeout_display(const MMAnnounceReceiptTimeout*, const PtpClock*);
|
|
void mMLogSyncInterval_display(const MMLogSyncInterval*, const PtpClock*);
|
|
void mMVersionNumber_display(const MMVersionNumber*, const PtpClock*);
|
|
void mMTime_display(const MMTime*, const PtpClock*);
|
|
void mMClockAccuracy_display(const MMClockAccuracy*, const PtpClock*);
|
|
void mMUtcProperties_display(const MMUtcProperties*, const PtpClock*);
|
|
void mMTraceabilityProperties_display(const MMTraceabilityProperties*, const PtpClock*);
|
|
void mMDelayMechanism_display(const MMDelayMechanism*, const PtpClock*);
|
|
void mMLogMinPdelayReqInterval_display(const MMLogMinPdelayReqInterval*, const PtpClock*);
|
|
void mMErrorStatus_display(const MMErrorStatus*, const PtpClock*);
|
|
|
|
void clearTime(TimeInternal *time);
|
|
|
|
char *dump_TimeInternal(const TimeInternal * p);
|
|
char *dump_TimeInternal2(const char *st1, const TimeInternal * p1, const char *st2, const TimeInternal * p2);
|
|
|
|
|
|
|
|
int snprint_TimeInternal(char *s, int max_len, const TimeInternal * p);
|
|
|
|
|
|
void nano_to_Time(TimeInternal *time, int nano);
|
|
int gtTime(const TimeInternal *x, const TimeInternal *b);
|
|
void absTime(TimeInternal *time);
|
|
int is_Time_close(const TimeInternal *x, const TimeInternal *b, int nanos);
|
|
int isTimeInternalNegative(const TimeInternal * p);
|
|
double timeInternalToDouble(const TimeInternal * p);
|
|
TimeInternal doubleToTimeInternal(const double d);
|
|
|
|
|
|
void toState(UInteger8,RunTimeOpts*,PtpClock*);
|
|
|
|
/* helper functions for leap second handling */
|
|
float secondsToMidnight(RunTimeOpts*);
|
|
float getPauseAfterMidnight(Integer8 announceInterval);
|
|
|
|
Boolean respectUtcOffset(RunTimeOpts * rtOpts, PtpClock * ptpClock);
|
|
|
|
void ptpdBondarySyncTime(int threadNum);
|
|
|
|
#endif /*PTPD_H_*/
|