original files of m241

This commit is contained in:
neelimap
2026-07-30 11:19:44 +05:30
parent 170c2b3f3a
commit afc7070c1f
12254 changed files with 7655111 additions and 0 deletions
@@ -0,0 +1,145 @@
/* constants_dep.h */
#ifndef CONSTANTS_DEP_H
#define CONSTANTS_DEP_H
/**
*\file
* \brief Plateform-dependent constants definition
*
* This header defines all includes and constants which are plateform-dependent
*
* ptpdv2 is only implemented for linux, NetBSD and FreeBSD
*/
/* platform dependent */
#ifdef VXWORKS_OS /* copied from below linux part with some modification*/
#include <net/ethernet.h>
#include <hostLib.h>
#include <net/if_types.h>
#include<netinet/in.h>
#include<net/if.h>
#include<net/if_arp.h>
#include <ifaddrs.h>
#define IFACE_NAME_LENGTH IF_NAMESIZE
#define NET_ADDRESS_LENGTH INET_ADDRSTRLEN
#define IFCONF_LENGTH 10
#endif /* VXWORKS_OS */
#ifdef HAVE_MACHINE_ENDIAN_H
# include <machine/endian.h>
#endif /* HAVE_MACHINE_ENDIAN_H */
#ifdef HAVE_ENDIAN_H
# include <endian.h>
#endif /* HAVE_ENDIAN_H */
#ifdef HAVE_SYS_ISA_DEFS_H
# include <sys/isa_defs.h>
#endif /* HAVE_SYS_ISA_DEFS_H */
# if BYTE_ORDER == LITTLE_ENDIAN || defined(_LITTLE_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN)
# define PTPD_LSBF
# elif BYTE_ORDER == BIG_ENDIAN || defined(_BIG_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN)
# define PTPD_MSBF
# endif
#define CLOCK_IDENTITY_LENGTH 8
#define ADJ_FREQ_MAX 500000
/* UDP/IPv4 dependent */
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001UL
#endif
#define SUBDOMAIN_ADDRESS_LENGTH 4
#define PORT_ADDRESS_LENGTH 2
#define PTP_UUID_LENGTH 6
#define CLOCK_IDENTITY_LENGTH 8
#define FLAG_FIELD_LENGTH 2
#define PACKET_SIZE 300 /* ptpdv1 value kept because of use of TLV...*/
#define PACKET_BEGIN_UDP (ETHER_HDR_LEN + sizeof(struct ip) + \
sizeof(struct udphdr))
#define PACKET_BEGIN_ETHER (ETHER_HDR_LEN)
#define PTP_EVENT_PORT 319
#define PTP_GENERAL_PORT 320
#define DEFAULT_PTP_DOMAIN_ADDRESS "224.0.1.129"
#define PEER_PTP_DOMAIN_ADDRESS "224.0.0.107"
/* 802.3 Support */
#define PTP_ETHER_DST "01:1b:19:00:00:00"
#define PTP_ETHER_TYPE 0x88f7
#define PTP_ETHER_PEER "01:80:c2:00:00:0E"
/* dummy clock driver designation in preparation for generic clock driver API */
#define DEFAULT_CLOCKDRIVER "kernelclock"
/* default lock file location and mode */
#define DEFAULT_LOCKMODE F_WRLCK
#define DEFAULT_LOCKDIR "/var/run"
#define DEFAULT_LOCKFILE_NAME PTPD_PROGNAME".lock"
/*define DEFAULT_LOCKFILE_PATH DEFAULT_LOCKDIR"/"DEFAULT_LOCKFILE_NAME */
#define DEFAULT_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
/* default drift file location */
#define DEFAULT_DRIFTFILE "/etc/"PTPD_PROGNAME"_"DEFAULT_CLOCKDRIVER".drift"
/* default status file location */
#define DEFAULT_STATUSFILE DEFAULT_LOCKDIR"/"PTPD_PROGNAME".status"
/* Highest log level (default) catches all */
#define LOG_ALL LOG_DEBUGV
/* drift recovery metod for use with -F */
enum {
DRIFT_RESET = 0,
DRIFT_KERNEL,
DRIFT_FILE
};
/* IP transmission mode */
enum {
IPMODE_MULTICAST = 0,
IPMODE_UNICAST,
IPMODE_HYBRID,
#if 0
IPMODE_UNICAST_SIGNALING
#endif
};
/* servo dT calculation mode */
enum {
DT_NONE,
DT_CONSTANT,
DT_MEASURED
};
#define MM_STARTING_BOUNDARY_HOPS 0x7fff
/* others */
/* bigger screen size constants */
#define SCREEN_BUFSZ 228
#define SCREEN_MAXSZ 180
/* default size for string buffers */
#define BUF_SIZE 1000
#define NANOSECONDS_MAX 999999999
/* limit operator messages to once every X seconds */
#define OPERATOR_MESSAGES_INTERVAL 300.0
#define MAXTIMESTR 32
#endif /*CONSTANTS_DEP_H_*/
@@ -0,0 +1,379 @@
/*-
* Copyright (c) 2016-2017 Wind River Systems, Inc,
* Copyright (c) 2013-2014 Wojciech Owczarek,
*
* 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.
*/
/*
modification history
--------------------
25jan17,xxy Add support for TSN Clocks and Timers (F6548)
19aug16,xxy Fix overflow in PTP servo.(V7NET-1086)
15aug16,xxy Add PTP features.(F6696)
*/
/**
* @file daemonconfig.c
* @date Sun May 27 00:45:32 2013
*
* @brief Code to handle configuration file and default settings
*
* Functions in this file deal with config file parsing, reloading,
* loading default parameters, parsing command-line options, printing
* help output, etc.
*
*/
#include "../ptpd.h"
/* Load all rtOpts defaults */
void
loadDefaultSettings( RunTimeOpts *rtOpts )
{
/* Wipe the memory first to avoid unconsistent behaviour - no need to set Boolean to FALSE, int to 0 etc. */
memset(rtOpts, 0, sizeof(RunTimeOpts));
rtOpts->ptp_profile = PTP_DEFAULT_PROFILE;
rtOpts->announceInterval = DEFAULT_ANNOUNCE_INTERVAL;
rtOpts->syncInterval = DEFAULT_SYNC_INTERVAL;
rtOpts->logMinPdelayReqInterval = DEFAULT_PDELAYREQ_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;
rtOpts->transport = UDP_IPV4;
/* timePropertiesDS */
rtOpts->timeProperties.currentUtcOffsetValid = DEFAULT_UTC_VALID;
rtOpts->timeProperties.currentUtcOffset = DEFAULT_UTC_OFFSET;
rtOpts->timeProperties.timeSource = INTERNAL_OSCILLATOR;
rtOpts->timeProperties.timeTraceable = FALSE;
rtOpts->timeProperties.frequencyTraceable = FALSE;
rtOpts->timeProperties.ptpTimescale = FALSE;
rtOpts->ip_mode = IPMODE_MULTICAST;
rtOpts->noAdjust = NO_ADJUST; /* false */
rtOpts->logStatistics = FALSE;
/* Deep display of all packets seen by the daemon */
rtOpts->displayPackets = FALSE;
/* rtOpts->unicastAddress */
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->offset_first_updated = FALSE; */
/*
* defaults for new options
*/
rtOpts->ignore_delayreq_interval_master = FALSE;
rtOpts->do_IGMP_refresh = TRUE;
rtOpts->announceReceiptTimeout = DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
rtOpts->debug_level = PTP_DEBUG_LEVEL_0;
rtOpts->ttl = 64;
rtOpts->delayMechanism = DEFAULT_DELAY_MECHANISM;
rtOpts->noResetClock = DEFAULT_NO_RESET_CLOCK;
rtOpts->stepOnce = FALSE;
rtOpts->stepForce = FALSE;
rtOpts->oneStepMode = FALSE;
rtOpts->clearCounters = FALSE;
rtOpts->statisticsLogInterval = 0;
rtOpts->initial_delayreq = DEFAULT_DELAYREQ_INTERVAL;
rtOpts->subsequent_delayreq = DEFAULT_DELAYREQ_INTERVAL; /* this will be updated if -g is given*/
rtOpts->autoDelayReqInterval = TRUE;
rtOpts->masterRefreshInterval = 60;
rtOpts->drift_recovery_method = DRIFT_KERNEL;
rtOpts->snmp_enabled = FALSE;
/* This will only be used if the "none" preset is configured */
rtOpts->slaveOnly = FALSE;
/* Otherwise default to slave only via the preset */
rtOpts->selectedPreset = PTP_PRESET_SLAVEONLY;
/* highest possible */
rtOpts->logLevel = LOG_ALL;
/* ADJ_FREQ_MAX by default */
rtOpts->servoMaxPpb = ADJ_FREQ_MAX ;
/* kP and kI are scaled to 10000 and are gains now - values same as originally */
rtOpts->servoKP = 0.7;
rtOpts->servoKI = 0.3;
rtOpts->servoDtMethod = DT_MEASURED;
/* when measuring dT, use a maximum of 5 sync intervals (would correspond to avg 20% discard rate) */
rtOpts->servoMaxdT = 5.0;
/* disabled by default */
rtOpts->announceTimeoutGracePeriod = 0;
rtOpts->alwaysRespectUtcOffset = FALSE;
rtOpts->preferUtcValid = FALSE;
rtOpts->requireUtcValid = FALSE;
/* Try 46 for expedited forwarding */
rtOpts->dscpValue = 0;
/* status file options */
rtOpts->statusFileUpdateInterval = 1;
/* panic mode options */
rtOpts->enablePanicMode = FALSE;
rtOpts->panicModeDuration = 2;
rtOpts->panicModeExitThreshold = 0;
/* full network reset after 5 times in listening */
rtOpts->maxListen = 5;
/* Log file settings */
rtOpts->statisticsLog.logID = "statistics";
rtOpts->statisticsLog.openMode = "a+";
rtOpts->statisticsLog.logFP = NULL;
rtOpts->statisticsLog.truncateOnReopen = FALSE;
rtOpts->statisticsLog.unlinkOnClose = FALSE;
rtOpts->statisticsLog.maxSize = 0;
rtOpts->recordLog.logID = "record";
rtOpts->recordLog.openMode = "a+";
rtOpts->recordLog.logFP = NULL;
rtOpts->recordLog.truncateOnReopen = FALSE;
rtOpts->recordLog.unlinkOnClose = FALSE;
rtOpts->recordLog.maxSize = 0;
rtOpts->eventLog.logID = "log";
rtOpts->eventLog.openMode = "a+";
rtOpts->eventLog.logFP = NULL;
rtOpts->eventLog.truncateOnReopen = FALSE;
rtOpts->eventLog.unlinkOnClose = FALSE;
rtOpts->eventLog.maxSize = 0;
rtOpts->statusLog.logID = "status";
rtOpts->statusLog.openMode = "w";
strncpy(rtOpts->statusLog.logPath, DEFAULT_STATUSFILE, PATH_MAX);
rtOpts->statusLog.logFP = NULL;
rtOpts->statusLog.truncateOnReopen = FALSE;
rtOpts->statusLog.unlinkOnClose = TRUE;
/* Management message support settings */
rtOpts->managementEnabled = TRUE;
rtOpts->managementSetEnable = FALSE;
/* IP ACL settings */
rtOpts->timingAclEnabled = FALSE;
rtOpts->managementAclEnabled = FALSE;
rtOpts->timingAclOrder = ACL_DENY_PERMIT;
rtOpts->managementAclOrder = ACL_DENY_PERMIT;
/* by default we don't check Sync message sequence continuity */
rtOpts->syncSequenceChecking = FALSE;
rtOpts->clockUpdateTimeout = 0;
}
/* The PtpEnginePreset structure for reference:
typedef struct {
char* presetName;
Boolean slaveOnly;
Boolean noAdjust;
UInteger8_option clockClass;
} PtpEnginePreset;
*/
PtpEnginePreset
getPtpPreset(int presetNumber, RunTimeOpts *rtOpts)
{
PtpEnginePreset ret;
memset(&ret, 0, sizeof(ret));
switch (presetNumber)
{
case PTP_PRESET_SLAVEONLY:
ret.presetName = "slaveonly";
ret.slaveOnly = TRUE;
ret.noAdjust = FALSE;
ret.clockClass.minValue = SLAVE_ONLY_CLOCK_CLASS;
ret.clockClass.maxValue = SLAVE_ONLY_CLOCK_CLASS;
ret.clockClass.defaultValue = SLAVE_ONLY_CLOCK_CLASS;
break;
case PTP_PRESET_MASTERSLAVE:
ret.presetName = "masterslave";
ret.slaveOnly = FALSE;
ret.noAdjust = FALSE;
ret.clockClass.minValue = 128;
ret.clockClass.maxValue = 254;
ret.clockClass.defaultValue = DEFAULT_CLOCK_CLASS;
break;
case PTP_PRESET_MASTERONLY:
ret.presetName = "masteronly";
ret.slaveOnly = FALSE;
ret.noAdjust = TRUE;
ret.clockClass.minValue = 0;
ret.clockClass.maxValue = 127;
ret.clockClass.defaultValue = DEFAULT_CLOCK_CLASS__APPLICATION_SPECIFIC_TIME_SOURCE;
break;
default:
ret.presetName = "none";
ret.slaveOnly = rtOpts->slaveOnly;
ret.noAdjust = rtOpts->noAdjust;
ret.clockClass.minValue = 0;
ret.clockClass.maxValue = 255;
ret.clockClass.defaultValue = rtOpts->clockQuality.clockClass;
}
return ret;
}
/*
* IT HAPPENS HERE
*
* Map all options from @dict dictionary to corresponding @rtopts fields,
* using existing @rtopts fields as defaults. Return a dictionary free
* of unknown options, with explicitly set defaults.
* NOTE: when adding options, also map them in checkSubsystemRestart to
* ensure correct config reload behaviour.
*/
void parseConfig (RunTimeOpts *rtOpts )
{
Boolean parseResult = TRUE;
PtpEnginePreset ptpPreset;
/* ==== Any additional logic should go here ===== */
rtOpts->ifaceName = rtOpts->primaryIfaceName;
/* Check timing packet ACLs */
if (rtOpts->timingAclEnabled)
{
int pResult, dResult;
if ((pResult = maskParser(rtOpts->timingAclPermitText, NULL)) == -1)
printf("Error while parsing timing permit access list: \"%s\"\n",
rtOpts->timingAclPermitText);
if ((dResult = maskParser(rtOpts->timingAclDenyText, NULL)) == -1)
printf("Error while parsing timing deny access list: \"%s\"\n",
rtOpts->timingAclDenyText);
/* -1 = ACL format error*/
if (pResult == -1 || dResult == -1)
{
parseResult = FALSE;
rtOpts->timingAclEnabled = FALSE;
}
/* 0 = no entries - we simply don't match */
if (pResult == 0 && dResult == 0)
{
rtOpts->timingAclEnabled = FALSE;
}
}
/* Check management message ACLs */
if (rtOpts->managementAclEnabled)
{
int pResult, dResult;
if ((pResult = maskParser(rtOpts->managementAclPermitText, NULL)) == -1)
printf("Error while parsing management permit access list: \"%s\"\n",
rtOpts->managementAclPermitText);
if ((dResult = maskParser(rtOpts->managementAclDenyText, NULL)) == -1)
printf("Error while parsing management deny access list: \"%s\"\n",
rtOpts->managementAclDenyText);
/* -1 = ACL format error*/
if (pResult == -1 || dResult == -1)
{
parseResult = FALSE;
rtOpts->managementAclEnabled = FALSE;
}
/* 0 = no entries - we simply don't match */
if (pResult == 0 && dResult == 0)
{
rtOpts->managementAclEnabled = FALSE;
}
}
/* Shift DSCP to accept the 6-bit value */
rtOpts->dscpValue = rtOpts->dscpValue << 2;
/*
* We're in hybrid mode and we haven't specified the delay request interval:
* use override with a default value
*/
if ((rtOpts->ip_mode == IPMODE_HYBRID))
{
rtOpts->ignore_delayreq_interval_master = TRUE;
}
/*
* We're in unicast slave-capable mode and we haven't specified the delay request interval:
* use override with a default value
*/
if ((rtOpts->ip_mode == IPMODE_UNICAST &&
rtOpts->clockQuality.clockClass > 127))
{
rtOpts->ignore_delayreq_interval_master = TRUE;
}
/* ==== END additional logic */
}
@@ -0,0 +1,63 @@
/**
* @file daemonconfig.h
*
* @brief definitions related to config file handling.
*
*
*/
#ifndef PTPD_DAEMONCONFIG_H_
#define PTPD_DAEMONCONFIG_H_
/* Config reload - component restart status flags */
/* No restart required - can continue with new config */
#define PTPD_RESTART_NONE 1 << 0
/* PTP port datasetw can be updated without restarting FSM */
#define PTPD_UPDATE_DATASETS 1 << 1
/* PTP FSM port re-initialisation required (PTP_INITIALIZING) */
#define PTPD_RESTART_PROTOCOL 1 << 2
/* Network config changed: PTP_INITIALIZING handles this so far */
#define PTPD_RESTART_NETWORK 1 << 3
/* Logging config changes: log files need closed / reopened */
#define PTPD_RESTART_LOGGING 1 << 4
/* Configuration changes need checking lock files */
#define PTPD_CHECK_LOCKS 1 << 5
/* CPU core has changed */
#define PTPD_CHANGE_CPUAFFINITY 1 << 6
/* Configuration changes require daemon restart */
#define PTPD_RESTART_DAEMON 1 << 7
#define PTPD_RESTART_ACLS 1 << 9
#define LOG2_HELP "(expressed as log 2 i.e. -1=0.5s, 0=1s, 1=2s etc.)"
/* Structure defining a PTP engine preset */
typedef struct {
char* presetName;
Boolean slaveOnly;
Boolean noAdjust;
UInteger8_option clockClass;
} PtpEnginePreset;
/* Preset definitions */
enum {
PTP_PRESET_NONE,
PTP_PRESET_SLAVEONLY,
PTP_PRESET_MASTERSLAVE,
PTP_PRESET_MASTERONLY,
PTP_PRESET_MAX
};
void loadDefaultSettings(RunTimeOpts*);
PtpEnginePreset getPtpPreset(int presetNumber, RunTimeOpts* rtOpts);
void parseConfig (RunTimeOpts*);
#endif /*PTPD_DAEMONCONFIG_H_*/
@@ -0,0 +1,233 @@
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#ifndef DATATYPES_DEP_H_
#define DATATYPES_DEP_H_
/**
*\file
* \brief Implementation specific datatype
*/
/*typedef enum {FALSE_VALUE=0, TRUE_VALUE} Boolean;*/
typedef uint32_t Boolean;
typedef char Octet;
typedef int8_t Integer8;
typedef int16_t Integer16;
typedef int32_t Integer32;
typedef uint8_t UInteger8;
typedef uint16_t UInteger16;
typedef uint32_t UInteger32;
typedef uint16_t Enumeration16;
typedef unsigned char Enumeration8;
typedef unsigned char Enumeration4;
typedef unsigned char Enumeration4Upper;
typedef unsigned char Enumeration4Lower;
typedef unsigned char UInteger4;
typedef unsigned char UInteger4Upper;
typedef unsigned char UInteger4Lower;
typedef unsigned char Nibble;
typedef unsigned char NibbleUpper;
typedef unsigned char NibbleLower;
/**
* \brief Implementation specific of UInteger48 type
*/
typedef struct {
uint32_t lsb;
uint16_t msb;
} UInteger48;
/**
* \brief Implementation specific of Integer64 type
*/
typedef struct {
uint32_t lsb;
int32_t msb;
} Integer64;
/**
* \brief Struct used to average the offset from master
*
* The FIR filtering of the offset from master input is a simple, two-sample average
*/
typedef struct {
Integer32 nsec_prev, y;
} offset_from_master_filter;
/**
* \brief Struct used to average the one way delay
*
* It is a variable cutoff/delay low-pass, infinite impulse response (IIR) filter.
*
* The one-way delay filter has the difference equation: s*y[n] - (s-1)*y[n-1] = x[n]/2 + x[n-1]/2, where increasing the stiffness (s) lowers the cutoff and increases the delay.
*/
typedef struct {
Integer32 nsec_prev, y;
Integer32 s_exp;
} one_way_delay_filter;
/**
* \brief Struct containing interface information and capabilities
*/
typedef struct {
unsigned int flags;
int addressFamily;
Boolean hasHwAddress;
Boolean hasAfAddress;
unsigned char hwAddress[14];
struct sockaddr afAddress;
} InterfaceInfo;
/**
* \brief Struct describing network transport data
*/
typedef struct {
Integer32 eventSock, generalSock;
Integer32 multicastAddr, peerMulticastAddr,unicastAddr;
/* Interface address and capability descriptor */
InterfaceInfo interfaceInfo;
char ethName[32];
int ethIndex;
void * ethCookie;
struct Ip_sockaddr_ll layer2addr;
/* used by IGMP refresh */
struct in_addr interfaceAddr;
/* Typically MAC address - outer 6 octers of ClockIdendity */
Octet interfaceID[ETHER_ADDR_LEN];
/* used for Hybrid mode */
Integer32 lastRecvAddr;
uint64_t sentPackets;
uint64_t receivedPackets;
Integer32 headerOffset;
/* used for tracking the last TTL set */
int ttlGeneral;
int ttlEvent;
Boolean joinedMulticast;
struct ether_addr etherDest;
struct ether_addr peerEtherDest;
Boolean txTimestampFailure;
Ipv4AccessList* timingAcl;
Ipv4AccessList* managementAcl;
} NetPath;
typedef struct {
char* logID;
char* openMode;
char logPath[PATH_MAX];
FILE* logFP;
Boolean logEnabled;
Boolean truncateOnReopen;
Boolean unlinkOnClose;
UInteger32 maxSize;
UInteger32 fileSize;
int maxFiles;
} LogFileHandler;
typedef struct{
UInteger8 minValue;
UInteger8 maxValue;
UInteger8 defaultValue;
} UInteger8_option;
typedef struct{
Integer32 minValue;
Integer32 maxValue;
Integer32 defaultValue;
} Integer32_option;
typedef struct{
UInteger32 minValue;
UInteger32 maxValue;
UInteger32 defaultValue;
} UInteger32_option;
typedef struct{
Integer16 minValue;
Integer16 maxValue;
Integer16 defaultValue;
} Integer16_option;
typedef struct{
UInteger16 minValue;
UInteger16 maxValue;
UInteger16 defaultValue;
} UInteger16_option;
#ifndef _WRS_CONFIG_ARCH_i86
#if (_BYTE_ORDER == _BIG_ENDIAN)
typedef union
{
double value;
struct
{
UInteger32 msw;
UInteger32 lsw;
} parts;
} ieee_double_shape_type;
#else
typedef union
{
double value;
struct
{
UInteger32 lsw;
UInteger32 msw;
} parts;
} ieee_double_shape_type;
#endif
/* Get two 32 bit ints from a double. */
#define EXTRACT_WORDS(ix0,ix1,d) \
do { \
ieee_double_shape_type ew_u; \
ew_u.value = (d); \
(ix0) = ew_u.parts.msw; \
(ix1) = ew_u.parts.lsw; \
} while (0)
/* Set a double from two 32 bit ints. */
#define INSERT_WORDS(d,ix0,ix1) \
do { \
ieee_double_shape_type iw_u; \
iw_u.parts.msw = (ix0); \
iw_u.parts.lsw = (ix1); \
(d) = iw_u.value; \
} while (0)
#endif
#endif /*DATATYPES_DEP_H_*/
@@ -0,0 +1,493 @@
/*-
* Copyright (c) 2013-2014 Wojciech Owczarek,
*
* 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 ipv4_acl.c
* @date Sun Oct 13 21:02:23 2013
*
* @brief Code to handle IPv4 access control lists
*
* Functions in this file parse, create and match IPv4 ACLs.
*
*/
#include "../ptpd.h"
#include "string.h"
/**
* strdup + free are used across code using strtok_r, so as to
* protect the original string, as strtok* modify it.
*/
/* count tokens in string delimited by delim */
static int countTokens(const char* text, const char* delim) {
int count=0;
char* stash = NULL;
char* text_;
char* text__;
if(text==NULL || delim==NULL)
return 0;
text_=strdup(text);
for(text__=text_,count=0;strtok_r(text__,delim, &stash) != NULL; text__=NULL) {
count++;
}
free(text_);
return count;
}
/* Parse a dotted-decimal string into an uint8_t array - return -1 on error */
static int ipToArray(const char* text, uint8_t dest[], int maxOctets, Boolean isMask)
{
char* text_;
char* text__;
char* subtoken;
char* stash = NULL;
char* endptr;
long octet;
int count = 0;
int result = 0;
memset(&dest[0], 0, maxOctets * sizeof(uint8_t));
text_=strdup(text);
for(text__=text_;;text__=NULL) {
if(count > maxOctets) {
result = -1;
goto end;
}
subtoken = strtok_r(text__,".",&stash);
if(subtoken == NULL)
goto end;
errno = 0;
octet=strtol(subtoken,&endptr,10);
if(errno!=0 || !IN_RANGE(octet,0,255)) {
result = -1;
goto end;
}
dest[count++] = (uint8_t)octet;
/* If we're parsing a mask and an octet is less than 0xFF, whole rest is zeros */
if(isMask && octet < 255)
goto end;
}
end:
free(text_);
return result;
}
/* Parse a single net mask into an AclEntry */
static int parseAclEntry(const char* line, AclEntry* acl) {
int result = 1;
char* stash;
char* text_;
char* token;
char* endptr;
long octet = 0;
uint8_t net_octets[4];
uint8_t mask_octets[4];
if(line == NULL || acl == NULL)
return -1;
if(countTokens(line,"/") == 0)
return -1;
text_=strdup(line);
token=strtok_r(text_,"/",&stash);
if((countTokens(token,".") > 4) ||
(countTokens(token,".") < 1) ||
(ipToArray(token,net_octets,4,0) < 0)) {
result=-1;
goto end;
}
acl->network = (net_octets[0] << 24) | (net_octets[1] << 16) | ( net_octets[2] << 8) | net_octets[3];
token=strtok_r(NULL,"/",&stash);
if(token == NULL) {
acl->netmask=32;
acl->bitmask=~0;
} else if(countTokens(token,".") == 1) {
errno = 0;
octet = strtol(token,&endptr,10);
if(errno != 0 || !IN_RANGE(octet,0,32)) {
result = -1;
goto end;
}
if(octet == 0)
acl->bitmask = 0;
else
acl->bitmask = ~0 << (32 - octet);
acl->netmask = (uint16_t)octet;
} else if((countTokens(token,".") > 4) ||
(ipToArray(token,mask_octets,4,1) < 0)) {
result=-1;
goto end;
} else {
acl->bitmask = (mask_octets[0] << 24) | (mask_octets[1] << 16) | ( mask_octets[2] << 8) | mask_octets[3];
uint32_t tmp = acl->bitmask;
int count = 0;
for(tmp = acl->bitmask;tmp<<count;count++);
acl->netmask=count;
}
end:
free(text_);
acl->network &= acl->bitmask;
return result;
}
/* qsort() compare function for sorting ACL entries */
static int
cmpAclEntry(const void *p1, const void *p2)
{
const AclEntry *left = p1;
const AclEntry *right = p2;
if(left->network > right->network)
return 1;
if(left->network < right->network)
return -1;
return 0;
}
/* Parse an ACL string into an aclEntry table and return number of entries. output can be NULL */
int
maskParser(const char* input, AclEntry* output)
{
char* token;
char* stash;
int found = 0;
char* text_;
char* text__;
AclEntry tmp;
memset(&tmp,0,sizeof(AclEntry));
if(strlen(input)==0) return 0;
text_=strdup(input);
for(text__=text_;;text__=NULL) {
token=strtok_r(text__,", ;\t",&stash);
if(token==NULL) break;
if(parseAclEntry(token,&tmp)<1) {
found = -1;
break;
}
if(output != NULL)
output[found]=tmp;
found++;
}
if((found>0) && (output != NULL))
qsort(output, found, sizeof(AclEntry), cmpAclEntry);
/* We got input but found nothing - error */
if (!found)
found = -1;
free(text_);
return found;
}
/* Create a maskTable from a text ACL */
static MaskTable*
createMaskTable(const char* input)
{
MaskTable* ret;
int masksFound = maskParser(input, NULL);
if(masksFound>=0) {
ret=(MaskTable*)calloc(1,sizeof(MaskTable));
if(ret == NULL)
return NULL;
ret->entries = (AclEntry*)calloc(masksFound, sizeof(AclEntry));
if(ret->entries == NULL)
{
free(ret);
return NULL;
}
ret->numEntries = maskParser(input,ret->entries);
return ret;
} else {
printf("Error while parsing access list: \"%s\"\n", input);
return NULL;
}
}
/* Print the contents of a single mask table */
static void
dumpMaskTable(MaskTable* table)
{
int i;
uint32_t network;
if(table == NULL)
return;
INFO("number of entries: %d\n",table->numEntries);
if(table->entries != NULL) {
for(i = 0; i < table->numEntries; i++) {
AclEntry this = table->entries[i];
#ifdef PTPD_MSBF
network = this.network;
#else
network = htonl(this.network);
#endif
INFO("%d.%d.%d.%d/%d\t(0x%.8x/0x%.8x), matches: %d\n",
*((uint8_t*)&network), *((uint8_t*)&network+1),
*((uint8_t*)&network+2), *((uint8_t*)&network+3), this.netmask,
this.network, this.bitmask, this.hitCount);
}
}
}
/* Free a MaskTable structure */
static void freeMaskTable(MaskTable** table)
{
if(*table == NULL)
return;
if((*table)->entries != NULL) {
free((*table)->entries);
(*table)->entries = NULL;
}
free(*table);
*table = NULL;
}
/* Destroy an Ipv4AccessList structure */
void
freeIpv4AccessList(Ipv4AccessList** acl)
{
if(*acl == NULL)
return;
freeMaskTable(&(*acl)->permitTable);
freeMaskTable(&(*acl)->denyTable);
free(*acl);
*acl = NULL;
}
/* Structure initialisation for Ipv4AccessList */
Ipv4AccessList*
createIpv4AccessList(const char* permitList, const char* denyList, int processingOrder)
{
Ipv4AccessList* ret;
ret = (Ipv4AccessList*)calloc(1,sizeof(Ipv4AccessList));
if(ret == NULL)
return NULL;
ret->permitTable = createMaskTable(permitList);
ret->denyTable = createMaskTable(denyList);
if(ret->permitTable == NULL || ret->denyTable == NULL) {
freeIpv4AccessList(&ret);
return NULL;
}
ret->processingOrder = processingOrder;
return ret;
}
/* Match an IP address against a MaskTable */
static int
matchAddress(const uint32_t addr, MaskTable* table)
{
int i;
if(table == NULL || table->entries == NULL || table->numEntries==0)
return -1;
for(i = 0; i < table->numEntries; i++) {
DBGV("addr: %08x, addr & mask: %08x, network: %08x\n",addr, table->entries[i].bitmask & addr, table->entries[i].network);
if((table->entries[i].bitmask & addr) == table->entries[i].network) {
table->entries[i].hitCount++;
return 1;
}
}
return 0;
}
/* Test an IP address against an ACL */
int
matchIpv4AccessList(Ipv4AccessList* acl, const uint32_t addr)
{
int ret;
int matchPermit = 0;
int matchDeny = 0;
/* Non-functional ACL permits everything */
if(acl == NULL)
return 1;
if(acl->permitTable != NULL)
matchPermit = matchAddress(addr,acl->permitTable) > 0;
if(acl->denyTable != NULL)
matchDeny = matchAddress(addr,acl->denyTable) > 0;
switch(acl->processingOrder) {
case ACL_PERMIT_DENY:
if(!matchPermit) {
ret = 0;
break;
}
if(matchDeny) {
ret = 0;
break;
}
ret = 1;
break;
default:
case ACL_DENY_PERMIT:
if (matchDeny && !matchPermit) {
ret = 0;
break;
}
else {
ret = 1;
break;
}
}
end:
if(ret)
acl->passedCounter++;
else
acl->droppedCounter++;
return ret;
}
/* Dump the contents and hit counters of an ACL */
void dumpIpv4AccessList(Ipv4AccessList* acl)
{
INFO("\n\n");
if(acl == NULL) {
INFO("(uninitialised ACL)\n");
return;
}
switch(acl->processingOrder) {
case ACL_DENY_PERMIT:
INFO("ACL order: deny,permit\n");
INFO("Passed packets: %d, dropped packets: %d\n",
acl->passedCounter, acl->droppedCounter);
INFO("--------\n");
INFO("Deny list:\n");
dumpMaskTable(acl->denyTable);
INFO("--------\n");
INFO("Permit list:\n");
dumpMaskTable(acl->permitTable);
break;
case ACL_PERMIT_DENY:
default:
INFO("ACL order: permit,deny\n");
INFO("Passed packets: %d, dropped packets: %d\n",
acl->passedCounter, acl->droppedCounter);
INFO("--------\n");
INFO("Permit list:\n");
dumpMaskTable(acl->permitTable);
INFO("--------\n");
INFO("Deny list:\n");
dumpMaskTable(acl->denyTable);
break;
}
INFO("\n\n");
}
/* Clear counters in a MaskTable */
static void
clearMaskTableCounters(MaskTable* table)
{
int i, count;
if(table==NULL || table->numEntries==0)
return;
count = table->numEntries;
for(i=0; i<count; i++) {
table->entries[i].hitCount = 0;
}
}
/* Clear ACL counter */
void clearIpv4AccessListCounters(Ipv4AccessList* acl) {
if(acl == NULL)
return;
acl->passedCounter=0;
acl->droppedCounter=0;
clearMaskTableCounters(acl->permitTable);
clearMaskTableCounters(acl->denyTable);
}
@@ -0,0 +1,52 @@
/**
* @file ipv4_acl.h
*
* @brief definitions related to IPv4 access control list handling
*
*/
#ifndef PTPD_IPV4_ACL_H_
#define PTPD_IPV4_ACL_H_
#define IN_RANGE(num, min,max) \
(num >= min && num <= max)
enum {
ACL_PERMIT_DENY,
ACL_DENY_PERMIT
};
typedef struct {
uint32_t network;
uint32_t bitmask;
uint16_t netmask;
uint32_t hitCount;
} AclEntry;
typedef struct {
int numEntries;
AclEntry* entries;
} MaskTable;
typedef struct {
MaskTable* permitTable;
MaskTable* denyTable;
int processingOrder;
uint32_t passedCounter;
uint32_t droppedCounter;
} Ipv4AccessList;
/* Parse string into AclEntry array */
int maskParser(const char* input, AclEntry* output);
/* Destroy an Ipv4AccessList structure */
void freeIpv4AccessList(Ipv4AccessList** acl);
/* Initialise an Ipv4AccessList structure */
Ipv4AccessList* createIpv4AccessList(const char* permitList, const char* denyList, int processingOrder);
/* Match on an IP address */
int matchIpv4AccessList(Ipv4AccessList* acl, const uint32_t addr);
/* Display the contents and hit counters of an access list */
void dumpIpv4AccessList(Ipv4AccessList* acl);
/* Clear counters */
void clearIpv4AccessListCounters(Ipv4AccessList* acl);
#endif /* PTPD_IPV4_ACL_H_ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,406 @@
/**
* @file ptpd_dep.h
*
* @brief External definitions for inclusion elsewhere.
*
*
*/
/*
modification history
--------------------
25jan17,xxy Add support for TSN Clocks and Timers (F6548)
01nov16,myt Add PTP features.(F7726)
15aug16,xxy Add PTP features.(F6696)
13jun16,xxy Add PTP one-step hardware Tx timeStamp
*/
#ifndef PTPD_DEP_H_
#define PTPD_DEP_H_
#ifdef RUNTIME_DEBUG
#undef PTPD_DBGV
#define PTPD_DBGV
#endif
/** \name System messages*/
/**\{*/
/* Syslog ordering. We define extra debug levels above LOG_DEBUG for internal use - but message() doesn't pass these to SysLog */
/* extended from <sys/syslog.h> */
#define LOG_DEBUG1 7
#define LOG_DEBUG2 8
#define LOG_DEBUG3 9
#define LOG_DEBUGV 9
#define EMERGENCY(x, ...) (void)printf( x, ##__VA_ARGS__)
#define ALERT(x, ...) (void)printf( x, ##__VA_ARGS__)
#define CRITICAL(x, ...) (void)printf( x, ##__VA_ARGS__)
#define ERROR_LOG(x, ...) (void)printf( x, ##__VA_ARGS__)
#define PERROR(x, ...) (void)printf( x " (strerror: %m)\n", ##__VA_ARGS__)
#define WARNING(x, ...) (void)printf( x, ##__VA_ARGS__)
#define NOTIFY(x, ...) (void)printf( x, ##__VA_ARGS__)
#define NOTICE(x, ...) (void)printf( x, ##__VA_ARGS__)
#define INFO(x, ...) (void)printf( x, ##__VA_ARGS__)
#include <assert.h>
#include <endCommon.h>
/*
list of per-module defines:
./dep/sys.c:#define PRINT_MAC_ADDRESSES
./dep/timer.c:#define US_TIMER_INTERVAL 125000
*/
#define USE_BINDTODEVICE
/* enable this line to show debug numbers in nanoseconds instead of microseconds
#define DEBUG_IN_NS */
#define DBG_UNIT_US (1000)
#define DBG_UNIT_NS (1)
#ifdef DEBUG_IN_NS
#define DBG_UNIT DBG_UNIT_NS
#else
#define DBG_UNIT DBG_UNIT_US
#endif
#ifdef PTPD_DBGV
#define DBGV(x, ...) printf( x, ##__VA_ARGS__)
#else
#define DBGV(x, ...)
#endif
/*
* new debug level DBG2:
* this is above DBG(), but below DBGV() (to avoid changing hundreds of lines)
*/
#ifdef PTPD_DBG2
#define DBG2(x, ...) printf( x, ##__VA_ARGS__)
#else
#define DBG2(x, ...)
#endif
#ifdef PTPD_DBG
#define DBG(x, ...) printf( x, ##__VA_ARGS__)
#else
#define DBG(x, ...)
#endif
/** \}*/
/** \name Endian corrections*/
/**\{*/
#if defined(PTPD_MSBF)
#define shift8(x,y) ( (x) << ((3-y)<<3) )
#define shift16(x,y) ( (x) << ((1-y)<<4) )
#elif defined(PTPD_LSBF)
#define shift8(x,y) ( (x) << ((y)<<3) )
#define shift16(x,y) ( (x) << ((y)<<4) )
#endif
#define flip16(x) htons(x)
#define flip32(x) htonl(x)
/* i don't know any target platforms that do not have htons and htonl,
but here are generic funtions just in case */
/*
#if defined(PTPD_MSBF)
#define flip16(x) (x)
#define flip32(x) (x)
#elif defined(PTPD_LSBF)
static inline Integer16 flip16(Integer16 x)
{
return (((x) >> 8) & 0x00ff) | (((x) << 8) & 0xff00);
}
static inline Integer32 flip32(x)
{
return (((x) >> 24) & 0x000000ff) | (((x) >> 8 ) & 0x0000ff00) |
(((x) << 8 ) & 0x00ff0000) | (((x) << 24) & 0xff000000);
}
#endif
*/
/** \}*/
/** \name Bit array manipulations*/
/**\{*/
#define getFlag(x,y) !!( *(UInteger8*)((x)+((y)<8?1:0)) & (1<<((y)<8?(y):(y)-8)) )
#define setFlag(x,y) ( *(UInteger8*)((x)+((y)<8?1:0)) |= 1<<((y)<8?(y):(y)-8) )
#define clearFlag(x,y) ( *(UInteger8*)((x)+((y)<8?1:0)) &= ~(1<<((y)<8?(y):(y)-8)) )
/** \}*/
/** \name msg.c
*-Pack and unpack PTP messages */
/**\{*/
void msgUnpackHeader(Octet * buf,MsgHeader*);
void msgUnpackAnnounce (Octet * buf,MsgAnnounce*);
void msgUnpackSync(Octet * buf,MsgSync*);
void msgUnpackFollowUp(Octet * buf,MsgFollowUp*);
void msgUnpackDelayReq(Octet * buf, MsgDelayReq * delayreq);
void msgUnpackDelayResp(Octet * buf,MsgDelayResp *);
void msgUnpackPDelayReq(Octet * buf,MsgPDelayReq*);
void msgUnpackPDelayResp(Octet * buf,MsgPDelayResp*);
void msgUnpackPDelayRespFollowUp(Octet * buf,MsgPDelayRespFollowUp*);
void msgUnpackManagement(Octet * buf,MsgManagement*, MsgHeader*, PtpClock *ptpClock);
void msgPackHeader(Octet * buf,PtpClock*);
void msgPackAnnounce(Octet * buf,PtpClock*,RunTimeOpts *);
void msgPackSync(Octet * buf,Timestamp*,PtpClock*,RunTimeOpts *);
void msgPackFollowUp(Octet * buf,Timestamp*,PtpClock*, const UInteger16,RunTimeOpts *);
void msgPackDelayReq(Octet * buf,Timestamp *,PtpClock *);
void msgPackDelayResp(Octet * buf,MsgHeader *,Timestamp *,PtpClock *,RunTimeOpts *);
void msgPackPDelayReq(Octet * buf,Timestamp*,PtpClock*,RunTimeOpts *);
void msgPackPDelayResp(Octet * buf,MsgHeader*,Timestamp*,PtpClock*);
void msgPackPDelayRespFollowUp(Octet * buf,MsgHeader*,Timestamp*,PtpClock*, const UInteger16);
void msgPackManagement(Octet * buf,MsgManagement*,PtpClock*);
void msgPackManagementRespAck(Octet *,MsgManagement*,PtpClock*);
void msgPackManagementTLV(Octet *,MsgManagement*, PtpClock*);
void msgPackManagementErrorStatusTLV(Octet *,MsgManagement*,PtpClock*);
void freeMMErrorStatusTLV(ManagementTLV*);
void freeMMTLV(ManagementTLV*);
void msgDump(PtpClock *ptpClock);
void msgDebugHeader(MsgHeader *header);
void msgDebugSync(MsgSync *sync);
void msgDebugAnnounce(MsgAnnounce *announce);
void msgDebugDelayReq(MsgDelayReq *req);
void msgDebugFollowUp(MsgFollowUp *follow);
void msgDebugDelayResp(MsgDelayResp *resp);
void msgDebugManagement(MsgManagement *manage);
void copyClockIdentity( ClockIdentity dest, ClockIdentity src);
void copyPortIdentity( PortIdentity * dest, PortIdentity * src);
void unpackMsgManagement(Octet *, MsgManagement*, PtpClock*);
void packMsgManagement(MsgManagement*, Octet *);
void unpackManagementTLV(Octet*, MsgManagement*, PtpClock*);
void packManagementTLV(ManagementTLV*, Octet*);
void freeManagementTLV(MsgManagement*);
void unpackMMClockDescription( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMClockDescription( MsgManagement*, Octet*);
void freeMMClockDescription( MMClockDescription*);
void unpackMMUserDescription( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMUserDescription( MsgManagement*, Octet*);
void freeMMUserDescription( MMUserDescription*);
void unpackMMErrorStatus( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMErrorStatus( MsgManagement*, Octet*);
void freeMMErrorStatus( MMErrorStatus*);
void unpackMMInitialize( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMInitialize( MsgManagement*, Octet*);
void unpackMMDefaultDataSet( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMDefaultDataSet( MsgManagement*, Octet*);
void unpackMMCurrentDataSet( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMCurrentDataSet( MsgManagement*, Octet*);
void unpackMMParentDataSet( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMParentDataSet( MsgManagement*, Octet*);
void unpackMMTimePropertiesDataSet( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMTimePropertiesDataSet( MsgManagement*, Octet*);
void unpackMMPortDataSet( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMPortDataSet( MsgManagement*, Octet*);
void unpackMMPriority1( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMPriority1( MsgManagement*, Octet*);
void unpackMMPriority2( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMPriority2( MsgManagement*, Octet*);
void unpackMMDomain( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMDomain( MsgManagement*, Octet*);
void unpackMMSlaveOnly( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMSlaveOnly( MsgManagement*, Octet* );
void unpackMMLogAnnounceInterval( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMLogAnnounceInterval( MsgManagement*, Octet*);
void unpackMMAnnounceReceiptTimeout( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMAnnounceReceiptTimeout( MsgManagement*, Octet*);
void unpackMMLogSyncInterval( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMLogSyncInterval( MsgManagement*, Octet*);
void unpackMMVersionNumber( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMVersionNumber( MsgManagement*, Octet*);
void unpackMMTime( Octet* buf, MsgManagement*, PtpClock * );
UInteger16 packMMTime( MsgManagement*, Octet*);
void unpackMMClockAccuracy( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMClockAccuracy( MsgManagement*, Octet*);
void unpackMMUtcProperties( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMUtcProperties( MsgManagement*, Octet*);
void unpackMMTraceabilityProperties( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMTraceabilityProperties( MsgManagement*, Octet*);
void unpackMMDelayMechanism( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMDelayMechanism( MsgManagement*, Octet*);
void unpackMMLogMinPdelayReqInterval( Octet* buf, MsgManagement*, PtpClock* );
UInteger16 packMMLogMinPdelayReqInterval( MsgManagement*, Octet*);
void unpackPortAddress( Octet* buf, PortAddress*, PtpClock*);
void packPortAddress( PortAddress*, Octet*);
void freePortAddress( PortAddress*);
void unpackPTPText( Octet* buf, PTPText*, PtpClock*);
void packPTPText( PTPText*, Octet*);
void freePTPText( PTPText*);
void unpackPhysicalAddress( Octet* buf, PhysicalAddress*, PtpClock*);
void packPhysicalAddress( PhysicalAddress*, Octet*);
void freePhysicalAddress( PhysicalAddress*);
void unpackClockIdentity( Octet* buf, ClockIdentity *c, PtpClock*);
void packClockIdentity( ClockIdentity *c, Octet* buf);
void freeClockIdentity( ClockIdentity *c);
void unpackClockQuality( Octet* buf, ClockQuality *c, PtpClock*);
void packClockQuality( ClockQuality *c, Octet* buf);
void freeClockQuality( ClockQuality *c);
void unpackTimeInterval( Octet* buf, TimeInterval *t, PtpClock*);
void packTimeInterval( TimeInterval *t, Octet* buf);
void freeTimeInterval( TimeInterval *t);
void unpackPortIdentity( Octet* buf, PortIdentity *p, PtpClock*);
void packPortIdentity( PortIdentity *p, Octet* buf);
void freePortIdentity( PortIdentity *p);
void unpackTimestamp( Octet* buf, Timestamp *t, PtpClock*);
void packTimestamp( Timestamp *t, Octet* buf);
void freeTimestamp( Timestamp *t);
UInteger16 msgPackManagementResponse(Octet * buf,MsgHeader*,MsgManagement*,PtpClock*);
/** \}*/
/** \name net.c (Unix API dependent)
* -Init network stuff, send and receive datas*/
/**\{*/
Boolean netInit(NetPath*,RunTimeOpts*,PtpClock*);
Boolean netShutdown(RunTimeOpts*,NetPath*);
int netSelect(RunTimeOpts *,TimeInternal*,NetPath*,fd_set*);
ssize_t netRecvEvent(Octet*,TimeInternal*,NetPath*,int);
ssize_t netRecvGeneral(Octet*,NetPath*);
ssize_t netSendEvent(Octet*,UInteger16,PtpClock*,RunTimeOpts*,Integer32,TimeInternal*);
ssize_t netSendGeneral(Octet*,UInteger16,NetPath*,RunTimeOpts*,Integer32 );
ssize_t netSendPeerGeneral(Octet*,UInteger16,NetPath*,RunTimeOpts*);
ssize_t netSendPeerEvent(Octet*,UInteger16,PtpClock*,RunTimeOpts*,TimeInternal*);
Boolean netRefreshIGMP(NetPath *, RunTimeOpts *, PtpClock *);
Boolean hostLookup(const char* hostname, Integer32* addr);
int netSetSysTime (void * ethCookie, struct timespec * ts);
int netGetSysTime (void * ethCookie, struct timespec * ts);
int netAdjustFreq (void * ethCookie, INT32 adj);
int netGetSysIntervalTime (void * ethCookie, IEEE1588_TIMER_SYNC * sync);
int netGetSysSyncDelayTime (void * ethCookie, long * delay);
int netSetSysIntervalTime (void * ethCookie, IEEE1588_TIMER_SYNC * sync);
int netSetSysTimeAdd (void *ethCookie, INT64 * counts);
int netEnableHwTimeStamp (void * ethCookie, UINT8 enable);
Boolean netGetHwTimeStampCap (void * ethCookie);
Boolean netGetHwOneStepCap (void * ethCookie);
/** \}*/
/** \name servo.c
* -Clock servo*/
/**\{*/
void initClock(RunTimeOpts*,PtpClock*);
void updatePeerDelay (one_way_delay_filter*, RunTimeOpts*,PtpClock*,TimeInternal*,Boolean);
void updateDelay (one_way_delay_filter*, RunTimeOpts*, PtpClock*,TimeInternal*);
void updateOffset(TimeInternal*,TimeInternal*,
offset_from_master_filter*,RunTimeOpts*,PtpClock*,TimeInternal*);
void updateClock(RunTimeOpts*,PtpClock*);
void servo_perform_clock_step(RunTimeOpts * rtOpts, PtpClock * ptpClock);
PtpClock * ptpdStartup(int slaveMaster, RunTimeOpts * rtOpts);
void ptpdShutdown(RunTimeOpts * rtOpts, PtpClock * ptpClock);
void enable_runtime_debug(void );
void disable_runtime_debug(void );
#define D_ON do { enable_runtime_debug(); } while (0);
#define D_OFF do { disable_runtime_debug( ); } while (0);
/** \}*/
/** \name sys.c (Unix API dependent)
* -Manage timing system API*/
/**\{*/
/* new debug methods to debug time variables */
char *time2st(const TimeInternal * p);
void DBG_time(const char *name, const TimeInternal p);
void logStatistics(RunTimeOpts *rtOpts, PtpClock *ptpClock);
void ShowStatistics(RunTimeOpts * rtOpts, PtpClock * ptpClock);
void displayStatus(const RunTimeOpts *rtOpts,PtpClock *ptpClock, const char *prefixMessage);
void displayPortIdentity(PortIdentity *port, const char *prefixMessage);
void getTime(RunTimeOpts * ,TimeInternal*);
void setTime(RunTimeOpts * ,TimeInternal*);
double getRand(void);
#ifndef HAVE_SYS_TIMEX_H
void adjTime(Integer32);
#else
void adjFreq_wrapper(RunTimeOpts * rtOpts, PtpClock * ptpClock, double adj);
Boolean adjFreq(RunTimeOpts *,double);
double getAdjFreq(void);
void informClockSource(PtpClock* ptpClock);
/* Observed drift save / recovery functions */
void restoreDrift(PtpClock * ptpClock, RunTimeOpts * rtOpts, Boolean quiet);
void saveDrift(PtpClock * ptpClock, RunTimeOpts * rtOpts, Boolean quiet);
/* Helper function to manage ntpadjtime / adjtimex flags */
void setTimexFlags(int flags, Boolean quiet);
void unsetTimexFlags(int flags, Boolean quiet);
int getTimexFlags(void);
Boolean checkTimexFlags(int flags);
#endif /* HAVE_SYS_TIMEX_H */
#ifndef _WRS_CONFIG_ARCH_i86
double trunc(double x);
double round(double x);
#endif
/** \}*/
/** \name timer.c (Unix API dependent)
* -Handle with timers*/
/**\{*/
void initTimer(void);
void timerUpdate(IntervalTimer*);
void timerStop(UInteger16,IntervalTimer*);
/* void timerStart(UInteger16,UInteger16,IntervalTimer*); */
/* R135 patch: we went back to floating point periods (for less than 1s )*/
void timerStart(UInteger16 index, float interval, IntervalTimer * itimer);
/* Version with randomized backoff */
void timerStart_random(UInteger16 index, float interval, IntervalTimer * itimer);
Boolean timerExpired(UInteger16,IntervalTimer*);
Boolean timerStopped(UInteger16,IntervalTimer*);
Boolean timerRunning(UInteger16,IntervalTimer*);
/** \}*/
void
reset_operator_messages(RunTimeOpts * rtOpts, PtpClock * ptpClock);
void setupPIservo(PIservo* servo, const RunTimeOpts* rtOpts);
void resetPIservo(PIservo* servo);
double runPIservo(RunTimeOpts * rtOpts, PIservo* servo, const Integer32 input);
#endif /*PTPD_DEP_H_*/
File diff suppressed because it is too large Load Diff
+732
View File
@@ -0,0 +1,732 @@
/*-
* Copyright (c) 2012 The IMS Company
* Vincent Bernat
*
* 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 snmp.c
* @author Vincent Bernat <bernat@luffy.cx>
* @date Sat Jun 23 23:08:05 2012
*
* @brief SNMP related functions
*/
#include "../ptpd.h"
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
// snmp_shutdown("example-demon");
/* Hard to get header... */
extern int header_generic(struct variable *, oid *, size_t *, int,
size_t *, WriteMethod **);
#define PTPBASE_SYSTEM_PROFILE 1
#define PTPBASE_DOMAIN_CLOCK_PORTS_TOTAL 2
#define PTPBASE_SYSTEM_DOMAIN_TOTALS 3
#define PTPBASE_CLOCK_CURRENT_DS_STEPS_REMOVED 4
#define PTPBASE_CLOCK_CURRENT_DS_OFFSET_FROM_MASTER 5
#define PTPBASE_CLOCK_CURRENT_DS_MEAN_PATH_DELAY 6
#define PTPBASE_CLOCK_PARENT_DS_PARENT_PORT_ID 7
#define PTPBASE_CLOCK_PARENT_DS_PARENT_STATS 8
#define PTPBASE_CLOCK_PARENT_DS_OFFSET 9
#define PTPBASE_CLOCK_PARENT_DS_CLOCK_PH_CH_RATE 10
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_IDENTITY 11
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO1 12
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO2 13
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_CLASS 14
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_ACCURACY 15
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_OFFSET 16
#define PTPBASE_CLOCK_DEFAULT_DS_TWO_STEP_FLAG 17
#define PTPBASE_CLOCK_DEFAULT_DS_CLOCK_IDENTITY 18
#define PTPBASE_CLOCK_DEFAULT_DS_PRIO1 19
#define PTPBASE_CLOCK_DEFAULT_DS_PRIO2 20
#define PTPBASE_CLOCK_DEFAULT_DS_SLAVE_ONLY 21
#define PTPBASE_CLOCK_DEFAULT_DS_QUALITY_CLASS 22
#define PTPBASE_CLOCK_DEFAULT_DS_QUALITY_ACCURACY 23
#define PTPBASE_CLOCK_DEFAULT_DS_QUALITY_OFFSET 24
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET_VALID 25
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET 26
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP59 27
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP61 28
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_TIME_TRACEABLE 29
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_FREQ_TRACEABLE 30
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_PTP_TIMESCALE 31
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_SOURCE 32
#define PTPBASE_CLOCK_PORT_NAME 33
#define PTPBASE_CLOCK_PORT_ROLE 34
#define PTPBASE_CLOCK_PORT_SYNC_ONE_STEP 35
#define PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS_TYPE 36
#define PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS 37
#define PTPBASE_CLOCK_PORT_NUM_ASSOCIATED_PORTS 38
#define PTPBASE_CLOCK_PORT_DS_PORT_NAME 39
#define PTPBASE_CLOCK_PORT_DS_PORT_IDENTITY 40
#define PTPBASE_CLOCK_PORT_DS_ANNOUNCEMENT_INTERVAL 41
#define PTPBASE_CLOCK_PORT_DS_ANNOUNCE_RCT_TIMEOUT 42
#define PTPBASE_CLOCK_PORT_DS_SYNC_INTERVAL 43
#define PTPBASE_CLOCK_PORT_DS_MIN_DELAY_REQ_INTERVAL 44
#define PTPBASE_CLOCK_PORT_DS_PEER_DELAY_REQ_INTERVAL 45
#define PTPBASE_CLOCK_PORT_DS_DELAY_MECH 46
#define PTPBASE_CLOCK_PORT_DS_PEER_MEAN_PATH_DELAY 47
#define PTPBASE_CLOCK_PORT_DS_GRANT_DURATION 48
#define PTPBASE_CLOCK_PORT_DS_PTP_VERSION 49
#define PTPBASE_CLOCK_PORT_RUNNING_NAME 50
#define PTPBASE_CLOCK_PORT_RUNNING_STATE 51
#define PTPBASE_CLOCK_PORT_RUNNING_ROLE 52
#define PTPBASE_CLOCK_PORT_RUNNING_INTERFACE_INDEX 53
#define PTPBASE_CLOCK_PORT_RUNNING_IPVERSION 54
#define PTPBASE_CLOCK_PORT_RUNNING_ENCAPSULATION_TYPE 55
#define PTPBASE_CLOCK_PORT_RUNNING_TX_MODE 56
#define PTPBASE_CLOCK_PORT_RUNNING_RX_MODE 57
#define PTPBASE_CLOCK_PORT_RUNNING_PACKETS_RECEIVED 58
#define PTPBASE_CLOCK_PORT_RUNNING_PACKETS_SENT 59
#define SNMP_PTP_ORDINARY_CLOCK 1
#define SNMP_PTP_CLOCK_INSTANCE 1 /* Only one instance */
#define SNMP_PTP_PORT_MASTER 1
#define SNMP_PTP_PORT_SLAVE 2
#define SNMP_IPv4 1
#define SNMP_PTP_TX_UNICAST 1
#define SNMP_PTP_TX_MULTICAST 2
#define SNMP_PTP_TX_MULTICAST_MIX 3
static oid ptp_oid[] = {1, 3, 6, 1, 4, 1, 39178, 100, 2};
static PtpClock *snmpPtpClock;
static RunTimeOpts *snmpRtOpts;
/* Helper functions to build header_*indexed_table() functions. Those
functions keep an internal state. They are not reentrant!
*/
/* {{{ */
struct snmpHeaderIndex {
struct variable *vp;
oid *name; /* Requested/returned OID */
size_t *length; /* Length of above OID */
int exact;
oid best[MAX_OID_LEN]; /* Best OID */
size_t best_len; /* Best OID length */
void *entity; /* Best entity */
};
static int
snmpHeaderInit(struct snmpHeaderIndex *idx,
struct variable *vp, oid *name, size_t *length,
int exact, size_t *var_len, WriteMethod **write_method)
{
/* If the requested OID name is less than OID prefix we
handle, adjust it to our prefix. */
if ((snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) {
memcpy(name, vp->name, sizeof(oid) * vp->namelen);
*length = vp->namelen;
}
/* Now, we can only handle OID matching our prefix. Those two
tests are not really necessary since NetSNMP won't give us
OID "above" our prefix. But this makes unit tests
easier. */
if (*length < vp->namelen) return 0;
if (memcmp(name, vp->name, vp->namelen * sizeof(oid))) return 0;
if(write_method != NULL) *write_method = 0;
*var_len = sizeof(long);
/* Initialize our header index structure */
idx->vp = vp;
idx->name = name;
idx->length = length;
idx->exact = exact;
idx->best_len = 0;
idx->entity = NULL;
return 1;
}
static void
snmpHeaderIndexAdd(struct snmpHeaderIndex *idx,
oid *index, size_t len, void *entity)
{
int result;
oid *target;
size_t target_len;
target = idx->name + idx->vp->namelen;
target_len = *idx->length - idx->vp->namelen;
if ((result = snmp_oid_compare(index, len, target, target_len)) < 0)
return; /* Too small. */
if (idx->exact) {
if (result == 0) {
memcpy(idx->best, index, sizeof(oid) * len);
idx->best_len = len;
idx->entity = entity;
return;
}
return;
}
if (result == 0)
return; /* Too small. */
if (idx->best_len == 0 ||
(snmp_oid_compare(index, len,
idx->best,
idx->best_len) < 0)) {
memcpy(idx->best, index, sizeof(oid) * len);
idx->best_len = len;
idx->entity = entity;
}
}
static void*
snmpHeaderIndexBest(struct snmpHeaderIndex *idx)
{
if (idx->entity == NULL)
return NULL;
if (idx->exact) {
if (snmp_oid_compare(idx->name + idx->vp->namelen,
*idx->length - idx->vp->namelen,
idx->best, idx->best_len) == 0)
return idx->entity;
return NULL;
}
memcpy(idx->name + idx->vp->namelen,
idx->best, sizeof(oid) * idx->best_len);
*idx->length = idx->vp->namelen + idx->best_len;
return idx->entity;
}
/* }}} */
#define SNMP_LOCAL_VARIABLES \
static unsigned long long_ret; \
static U64 counter64_ret; \
static uint32_t ipaddr; \
Integer64 bigint; \
struct snmpHeaderIndex idx; \
(void)long_ret; \
(void)counter64_ret; \
(void)ipaddr; \
(void)bigint; \
(void)idx
#define SNMP_INDEXED_TABLE \
if (!snmpHeaderInit(&idx, vp, name, \
length, exact, \
var_len, \
write_method)) \
return NULL
#define SNMP_ADD_INDEX(index, len, w) \
snmpHeaderIndexAdd(&idx, index, len, w)
#define SNMP_BEST_MATCH \
snmpHeaderIndexBest(&idx)
#define SNMP_OCTETSTR(V, L) \
( *var_len = L, \
(u_char *)V )
#define SNMP_COUNTER64(V) \
( counter64_ret.low = (V) & 0xffffffff, \
counter64_ret.high = (V) >> 32, \
*var_len = sizeof (counter64_ret), \
(u_char*)&counter64_ret )
#define SNMP_TIMEINTERNAL(V) \
( *var_len = sizeof(counter64_ret), \
internalTime_to_integer64(V, &bigint), \
counter64_ret.low = htonl(bigint.lsb), \
counter64_ret.high = htonl(bigint.msb), \
(u_char *)&counter64_ret )
#define SNMP_INTEGER(V) \
( long_ret = (V), \
*var_len = sizeof (long_ret), \
(u_char*)&long_ret )
#define SNMP_IPADDR(A) \
( ipaddr = A, \
*var_len = sizeof (ipaddr), \
(u_char*)&ipaddr )
#define SNMP_GAUGE SNMP_INTEGER
#define SNMP_UNSIGNED SNMP_INTEGER
#define SNMP_TRUE SNMP_INTEGER(1)
#define SNMP_FALSE SNMP_INTEGER(2)
#define SNMP_BOOLEAN(V) \
(V == TRUE)?SNMP_TRUE:SNMP_FALSE
#define SNMP_SIGNATURE struct variable *vp, \
oid *name, \
size_t *length, \
int exact, \
size_t *var_len, \
WriteMethod **write_method
/**
* Handle SNMP scalar values.
*/
static u_char*
snmpScalars(SNMP_SIGNATURE) {
SNMP_LOCAL_VARIABLES;
if (header_generic(vp, name, length, exact, var_len, write_method))
return NULL;
switch (vp->magic) {
case PTPBASE_SYSTEM_PROFILE:
return SNMP_INTEGER(1);
}
return NULL;
}
/**
* Handle ptpbaseSystemTable
*/
static u_char*
snmpSystemTable(SNMP_SIGNATURE) {
oid index[2];
SNMP_LOCAL_VARIABLES;
SNMP_INDEXED_TABLE;
/* We only have one index: one domain, one instance */
index[0] = snmpPtpClock->domainNumber;
index[1] = SNMP_PTP_CLOCK_INSTANCE;
SNMP_ADD_INDEX(index, 2, snmpPtpClock);
if (!SNMP_BEST_MATCH) return NULL;
switch (vp->magic) {
case PTPBASE_DOMAIN_CLOCK_PORTS_TOTAL:
return SNMP_GAUGE(snmpPtpClock->numberPorts);
}
return NULL;
}
/**
* Handle ptpbaseSystemDomainTable
*/
static u_char*
snmpSystemDomainTable(SNMP_SIGNATURE) {
oid index[1];
SNMP_LOCAL_VARIABLES;
SNMP_INDEXED_TABLE;
/* We only have one index: ordinary clock */
index[0] = SNMP_PTP_ORDINARY_CLOCK;
SNMP_ADD_INDEX(index, 1, snmpPtpClock);
if (!SNMP_BEST_MATCH) return NULL;
switch (vp->magic) {
case PTPBASE_SYSTEM_DOMAIN_TOTALS:
/* We only handle one domain... */
return SNMP_UNSIGNED(1);
}
return NULL;
}
/**
* Handle various ptpbaseClock*DSTable
*/
static u_char*
snmpClockDSTable(SNMP_SIGNATURE) {
oid index[3];
SNMP_LOCAL_VARIABLES;
SNMP_INDEXED_TABLE;
/* We only have one valid index */
index[0] = snmpPtpClock->domainNumber;
index[1] = SNMP_PTP_ORDINARY_CLOCK;
index[2] = SNMP_PTP_CLOCK_INSTANCE;
SNMP_ADD_INDEX(index, 3, snmpPtpClock);
if (!SNMP_BEST_MATCH) return NULL;
switch (vp->magic) {
/* ptpbaseClockCurrentDSTable */
case PTPBASE_CLOCK_CURRENT_DS_STEPS_REMOVED:
return SNMP_UNSIGNED(snmpPtpClock->stepsRemoved);
case PTPBASE_CLOCK_CURRENT_DS_OFFSET_FROM_MASTER:
return SNMP_TIMEINTERNAL(snmpPtpClock->offsetFromMaster);
case PTPBASE_CLOCK_CURRENT_DS_MEAN_PATH_DELAY:
return SNMP_TIMEINTERNAL(snmpPtpClock->meanPathDelay);
/* ptpbaseClockParentDSTable */
case PTPBASE_CLOCK_PARENT_DS_PARENT_PORT_ID:
return SNMP_OCTETSTR(&snmpPtpClock->parentPortIdentity,
sizeof(PortIdentity));
case PTPBASE_CLOCK_PARENT_DS_PARENT_STATS:
return SNMP_BOOLEAN(snmpPtpClock->parentStats);
case PTPBASE_CLOCK_PARENT_DS_OFFSET:
return SNMP_INTEGER(snmpPtpClock->observedParentOffsetScaledLogVariance);
case PTPBASE_CLOCK_PARENT_DS_CLOCK_PH_CH_RATE:
return SNMP_INTEGER(snmpPtpClock->observedParentClockPhaseChangeRate);
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_IDENTITY:
return SNMP_OCTETSTR(&snmpPtpClock->grandmasterIdentity,
sizeof(ClockIdentity));
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO1:
return SNMP_UNSIGNED(snmpPtpClock->grandmasterPriority1);
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO2:
return SNMP_UNSIGNED(snmpPtpClock->grandmasterPriority2);
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_CLASS:
return SNMP_UNSIGNED(snmpPtpClock->grandmasterClockQuality.clockClass);
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_ACCURACY:
return SNMP_INTEGER(snmpPtpClock->grandmasterClockQuality.clockAccuracy);
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_OFFSET:
return SNMP_INTEGER(snmpPtpClock->grandmasterClockQuality.offsetScaledLogVariance);
/* ptpbaseClockDefaultDSTable */
case PTPBASE_CLOCK_DEFAULT_DS_TWO_STEP_FLAG:
return SNMP_BOOLEAN(snmpPtpClock->twoStepFlag);
case PTPBASE_CLOCK_DEFAULT_DS_CLOCK_IDENTITY:
return SNMP_OCTETSTR(&snmpPtpClock->clockIdentity,
sizeof(ClockIdentity));
case PTPBASE_CLOCK_DEFAULT_DS_PRIO1:
return SNMP_UNSIGNED(snmpPtpClock->priority1);
case PTPBASE_CLOCK_DEFAULT_DS_PRIO2:
return SNMP_UNSIGNED(snmpPtpClock->priority2);
case PTPBASE_CLOCK_DEFAULT_DS_SLAVE_ONLY:
return SNMP_BOOLEAN(snmpPtpClock->slaveOnly);
case PTPBASE_CLOCK_DEFAULT_DS_QUALITY_CLASS:
return SNMP_UNSIGNED(snmpPtpClock->clockQuality.clockClass);
case PTPBASE_CLOCK_DEFAULT_DS_QUALITY_ACCURACY:
return SNMP_INTEGER(snmpPtpClock->clockQuality.clockAccuracy);
case PTPBASE_CLOCK_DEFAULT_DS_QUALITY_OFFSET:
return SNMP_INTEGER(snmpPtpClock->clockQuality.offsetScaledLogVariance);
/* ptpbaseClockTimePropertiesDSTable */
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET_VALID:
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.currentUtcOffsetValid);
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET:
return SNMP_INTEGER(snmpPtpClock->timePropertiesDS.currentUtcOffset);
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP59:
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.leap59);
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP61:
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.leap61);
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_TIME_TRACEABLE:
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.timeTraceable);
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_FREQ_TRACEABLE:
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.frequencyTraceable);
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_PTP_TIMESCALE:
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.ptpTimescale);
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_SOURCE:
return SNMP_INTEGER(snmpPtpClock->timePropertiesDS.timeSource);
}
return NULL;
}
/**
* Handle ptpbaseClockPort*Table
*/
static u_char*
snmpClockPortTable(SNMP_SIGNATURE) {
oid index[4];
SNMP_LOCAL_VARIABLES;
SNMP_INDEXED_TABLE;
/* We only have one valid index */
index[0] = snmpPtpClock->domainNumber;
index[1] = SNMP_PTP_ORDINARY_CLOCK;
index[2] = SNMP_PTP_CLOCK_INSTANCE;
index[3] = snmpPtpClock->portIdentity.portNumber;
SNMP_ADD_INDEX(index, 4, snmpPtpClock);
if (!SNMP_BEST_MATCH) return NULL;
switch (vp->magic) {
/* ptpbaseClockPortTable */
case PTPBASE_CLOCK_PORT_NAME:
case PTPBASE_CLOCK_PORT_DS_PORT_NAME:
case PTPBASE_CLOCK_PORT_RUNNING_NAME:
return SNMP_OCTETSTR(snmpPtpClock->user_description,
strlen(snmpPtpClock->user_description));
case PTPBASE_CLOCK_PORT_ROLE:
return SNMP_INTEGER((snmpPtpClock->portState == PTP_MASTER)?
SNMP_PTP_PORT_MASTER:SNMP_PTP_PORT_SLAVE);
case PTPBASE_CLOCK_PORT_SYNC_ONE_STEP:
return (snmpPtpClock->twoStepFlag == TRUE)?SNMP_FALSE:SNMP_TRUE;
case PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS_TYPE:
/* Only supports IPv4 */
return SNMP_INTEGER(SNMP_IPv4);
case PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS:
if (snmpPtpClock->netPath.unicastAddr)
return SNMP_IPADDR(snmpPtpClock->netPath.unicastAddr);
return SNMP_IPADDR(snmpPtpClock->netPath.multicastAddr);
case PTPBASE_CLOCK_PORT_NUM_ASSOCIATED_PORTS:
/* Either we are master and we use multicast and we
* consider we have a session or we are slave and we
* have only one master. */
return SNMP_INTEGER(1);
/* ptpbaseClockPortDSTable */
case PTPBASE_CLOCK_PORT_DS_PORT_IDENTITY:
return SNMP_OCTETSTR(&snmpPtpClock->portIdentity,
sizeof(PortIdentity));
case PTPBASE_CLOCK_PORT_DS_ANNOUNCEMENT_INTERVAL:
/* TODO: is it really logAnnounceInterval? */
return SNMP_INTEGER(snmpPtpClock->logAnnounceInterval);
case PTPBASE_CLOCK_PORT_DS_ANNOUNCE_RCT_TIMEOUT:
return SNMP_INTEGER(snmpPtpClock->announceReceiptTimeout);
case PTPBASE_CLOCK_PORT_DS_SYNC_INTERVAL:
/* TODO: is it really logSyncInterval? */
return SNMP_INTEGER(snmpPtpClock->logSyncInterval);
case PTPBASE_CLOCK_PORT_DS_MIN_DELAY_REQ_INTERVAL:
/* TODO: is it really logMinDelayReqInterval? */
return SNMP_INTEGER(snmpPtpClock->logMinDelayReqInterval);
case PTPBASE_CLOCK_PORT_DS_PEER_DELAY_REQ_INTERVAL:
/* TODO: is it really logMinPdelayReqInterval? */
return SNMP_INTEGER(snmpPtpClock->logMinPdelayReqInterval);
case PTPBASE_CLOCK_PORT_DS_DELAY_MECH:
return SNMP_INTEGER(snmpPtpClock->delayMechanism);
case PTPBASE_CLOCK_PORT_DS_PEER_MEAN_PATH_DELAY:
return SNMP_TIMEINTERNAL(snmpPtpClock->peerMeanPathDelay);
case PTPBASE_CLOCK_PORT_DS_GRANT_DURATION:
/* TODO: what is it? */
return SNMP_UNSIGNED(0);
case PTPBASE_CLOCK_PORT_DS_PTP_VERSION:
return SNMP_INTEGER(snmpPtpClock->versionNumber);
/* ptpbaseClockPortRunningTable */
case PTPBASE_CLOCK_PORT_RUNNING_STATE:
return SNMP_INTEGER(snmpPtpClock->portState);
case PTPBASE_CLOCK_PORT_RUNNING_ROLE:
return SNMP_INTEGER((snmpPtpClock->portState == PTP_MASTER)?
SNMP_PTP_PORT_MASTER:SNMP_PTP_PORT_SLAVE);
case PTPBASE_CLOCK_PORT_RUNNING_INTERFACE_INDEX:
/* TODO: maybe we can have it from the general configuration? */
return SNMP_INTEGER(0);
case PTPBASE_CLOCK_PORT_RUNNING_IPVERSION:
/* IPv4 only */
/* TODO: shouldn't we return SNMP_IPv4??? */
return SNMP_INTEGER(4);
case PTPBASE_CLOCK_PORT_RUNNING_ENCAPSULATION_TYPE:
/* None. Moreover, the format is not really described in the MIB... */
return SNMP_INTEGER(0);
case PTPBASE_CLOCK_PORT_RUNNING_TX_MODE:
case PTPBASE_CLOCK_PORT_RUNNING_RX_MODE:
if (snmpRtOpts->ip_mode == IPMODE_UNICAST)
return SNMP_INTEGER(SNMP_PTP_TX_UNICAST);
if (snmpRtOpts->ip_mode == IPMODE_HYBRID)
return SNMP_INTEGER(SNMP_PTP_TX_MULTICAST_MIX);
return SNMP_INTEGER(SNMP_PTP_TX_MULTICAST);
case PTPBASE_CLOCK_PORT_RUNNING_PACKETS_RECEIVED:
return SNMP_COUNTER64(snmpPtpClock->netPath.receivedPackets);
case PTPBASE_CLOCK_PORT_RUNNING_PACKETS_SENT:
return SNMP_COUNTER64(snmpPtpClock->netPath.sentPackets);
}
return NULL;
}
/**
* MIB definition
*/
static struct variable7 snmpVariables[] = {
/* ptpbaseSystemTable */
{ PTPBASE_DOMAIN_CLOCK_PORTS_TOTAL, ASN_GAUGE, HANDLER_CAN_RONLY,
snmpSystemTable, 5, {1, 1, 1, 1, 3}},
/* ptpbaseSystemDomainTable */
{ PTPBASE_SYSTEM_DOMAIN_TOTALS, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpSystemDomainTable, 5, {1, 1, 2, 1, 2}},
/* Scalars */
{ PTPBASE_SYSTEM_PROFILE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpScalars, 3, {1, 1, 3}},
/* ptpbaseClockCurrentDSTable */
{ PTPBASE_CLOCK_CURRENT_DS_STEPS_REMOVED, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 1, 1, 4}},
{ PTPBASE_CLOCK_CURRENT_DS_OFFSET_FROM_MASTER, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 1, 1, 5}},
{ PTPBASE_CLOCK_CURRENT_DS_MEAN_PATH_DELAY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 1, 1, 6}},
/* ptpbaseClockParentDSTable */
{ PTPBASE_CLOCK_PARENT_DS_PARENT_PORT_ID, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 4}},
{ PTPBASE_CLOCK_PARENT_DS_PARENT_STATS, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 5}},
{ PTPBASE_CLOCK_PARENT_DS_OFFSET, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 6}},
{ PTPBASE_CLOCK_PARENT_DS_CLOCK_PH_CH_RATE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 7}},
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_IDENTITY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 8}},
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO1, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 9}},
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO2, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 10}},
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_CLASS, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 11}},
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_ACCURACY, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 12}},
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_OFFSET, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 2, 1, 13}},
/* ptpbaseClockDefaultDSTable */
{ PTPBASE_CLOCK_DEFAULT_DS_TWO_STEP_FLAG, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 3, 1, 4}},
{ PTPBASE_CLOCK_DEFAULT_DS_CLOCK_IDENTITY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 3, 1, 5}},
{ PTPBASE_CLOCK_DEFAULT_DS_PRIO1, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 3, 1, 6}},
{ PTPBASE_CLOCK_DEFAULT_DS_PRIO2, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 3, 1, 7}},
{ PTPBASE_CLOCK_DEFAULT_DS_SLAVE_ONLY, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 3, 1, 8}},
{ PTPBASE_CLOCK_DEFAULT_DS_QUALITY_CLASS, ASN_UNSIGNED, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 3, 1, 9}},
{ PTPBASE_CLOCK_DEFAULT_DS_QUALITY_ACCURACY, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 3, 1, 10}},
{ PTPBASE_CLOCK_DEFAULT_DS_QUALITY_OFFSET, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 3, 1, 11}},
/* ptpbaseClockRunningTable: no data available for this table? */
/* ptpbaseClockTimePropertiesDSTable */
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET_VALID, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 5, 1, 4}},
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 5, 1, 5}},
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP59, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 5, 1, 6}},
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP61, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 5, 1, 7}},
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_TIME_TRACEABLE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 5, 1, 8}},
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_FREQ_TRACEABLE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 5, 1, 9}},
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_PTP_TIMESCALE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 5, 1, 10}},
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_SOURCE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockDSTable, 5, {1, 2, 5, 1, 11}},
/* ptpbaseClockPortTable */
{ PTPBASE_CLOCK_PORT_NAME, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 7, 1, 5}},
{ PTPBASE_CLOCK_PORT_ROLE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 7, 1, 6}},
{ PTPBASE_CLOCK_PORT_SYNC_ONE_STEP, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 7, 1, 7}},
{ PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS_TYPE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 7, 1, 8}},
{ PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 7, 1, 9}},
{ PTPBASE_CLOCK_PORT_NUM_ASSOCIATED_PORTS, ASN_GAUGE, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 7, 1, 10}},
/* ptpbaseClockPortDSTable */
{ PTPBASE_CLOCK_PORT_DS_PORT_NAME, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 5}},
{ PTPBASE_CLOCK_PORT_DS_PORT_IDENTITY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 6}},
{ PTPBASE_CLOCK_PORT_DS_ANNOUNCEMENT_INTERVAL, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 7}},
{ PTPBASE_CLOCK_PORT_DS_ANNOUNCE_RCT_TIMEOUT, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 8}},
{ PTPBASE_CLOCK_PORT_DS_SYNC_INTERVAL, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 9}},
{ PTPBASE_CLOCK_PORT_DS_MIN_DELAY_REQ_INTERVAL, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 10}},
{ PTPBASE_CLOCK_PORT_DS_PEER_DELAY_REQ_INTERVAL, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 11}},
{ PTPBASE_CLOCK_PORT_DS_DELAY_MECH, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 12}},
{ PTPBASE_CLOCK_PORT_DS_PEER_MEAN_PATH_DELAY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 13}},
/* { PTPBASE_CLOCK_PORT_DS_GRANT_DURATION, ASN_UNSIGNED, HANDLER_CAN_RONLY, */
/* snmpClockPortTable, 5, {1, 2, 8, 1, 14}}, */
{ PTPBASE_CLOCK_PORT_DS_PTP_VERSION, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 8, 1, 15}},
/* ptpbaseClockPortRunningTable */
{ PTPBASE_CLOCK_PORT_RUNNING_NAME, ASN_OCTET_STR, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 9, 1, 5}},
{ PTPBASE_CLOCK_PORT_RUNNING_STATE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 9, 1, 6}},
{ PTPBASE_CLOCK_PORT_RUNNING_ROLE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 9, 1, 7}},
/* { PTPBASE_CLOCK_PORT_RUNNING_INTERFACE_INDEX, ASN_INTEGER, HANDLER_CAN_RONLY, */
/* snmpClockPortTable, 5, {1, 2, 9, 1, 8}}, */
{ PTPBASE_CLOCK_PORT_RUNNING_IPVERSION, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 9, 1, 9}},
/* { PTPBASE_CLOCK_PORT_RUNNING_ENCAPSULATION_TYPE, ASN_INTEGER, HANDLER_CAN_RONLY, */
/* snmpClockPortTable, 5, {1, 2, 9, 1, 10}}, */
{ PTPBASE_CLOCK_PORT_RUNNING_TX_MODE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 9, 1, 11}},
{ PTPBASE_CLOCK_PORT_RUNNING_RX_MODE, ASN_INTEGER, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 9, 1, 12}},
{ PTPBASE_CLOCK_PORT_RUNNING_PACKETS_RECEIVED, ASN_COUNTER64, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 9, 1, 13}},
{ PTPBASE_CLOCK_PORT_RUNNING_PACKETS_SENT, ASN_COUNTER64, HANDLER_CAN_RONLY,
snmpClockPortTable, 5, {1, 2, 9, 1, 14}},
};
/**
* Log messages from NetSNMP subsystem.
*/
static int
snmpLogCallback(int major, int minor,
void *serverarg, void *clientarg)
{
struct snmp_log_message *slm = (struct snmp_log_message *)serverarg;
char *msg = strdup (slm->msg);
if (msg) msg[strlen(msg)-1] = '\0';
switch (slm->priority)
{
case LOG_EMERG: EMERGENCY("snmp[emerg]: %s\n", msg?msg:slm->msg); break;
case LOG_ALERT: ALERT ("snmp[alert]: %s\n", msg?msg:slm->msg); break;
case LOG_CRIT: CRITICAL ("snmp[crit]: %s\n", msg?msg:slm->msg); break;
case LOG_ERR: ERROR ("snmp[err]: %s\n", msg?msg:slm->msg); break;
case LOG_WARNING: WARNING ("snmp[warning]: %s\n", msg?msg:slm->msg); break;
case LOG_NOTICE: NOTICE ("snmp[notice]: %s\n", msg?msg:slm->msg); break;
case LOG_INFO: INFO ("snmp[info]: %s\n", msg?msg:slm->msg); break;
case LOG_DEBUG: DBGV ("snmp[debug]: %s\n", msg?msg:slm->msg); break;
}
free(msg);
return SNMP_ERR_NOERROR;
}
/**
* Initialisation of SNMP subsystem.
*/
void
snmpInit(RunTimeOpts *rtOpts, PtpClock *ptpClock) {
netsnmp_enable_subagent();
snmp_disable_log();
snmp_enable_calllog();
snmp_register_callback(SNMP_CALLBACK_LIBRARY,
SNMP_CALLBACK_LOGGING,
snmpLogCallback,
NULL);
init_agent("ptpAgent");
REGISTER_MIB("ptpMib", snmpVariables, variable7, ptp_oid);
init_snmp("ptpAgent");
/* Currently, ptpd only handle one clock. We put it in a
* global variable for the need of our subsystem. */
snmpPtpClock = ptpClock;
snmpRtOpts = rtOpts;
}
/**
* Clean up and shut down the SNMP subagent
*/
void
snmpShutdown() {
unregister_mib(ptp_oid, sizeof(ptp_oid) / sizeof(oid));
snmp_shutdown("ptpMib");
SOCK_CLEANUP;
}
@@ -0,0 +1,219 @@
/*-
* Copyright (c) 2016 Wind River Systems, Inc,
* Copyright (c) 2014 Wojciech Owczarek,
* Copyright (c) 2012-2013 George V. Neville-Neil,
* Wojciech Owczarek
* Copyright (c) 2011-2012 George V. Neville-Neil,
* Steven Kreuzer,
* Martin Burnicki,
* Jan Breuer,
* Gael Mace,
* Alexandre Van Kempen,
* Inaqui Delgado,
* Rick Ratzel,
* National Instruments.
* Copyright (c) 2009-2010 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.
*/
/*
modification history
--------------------
15aug16,xxy Add PTP features.(F6696)
02feb16,h_l Init version.
*/
/**
* @file startup.c
* @date Wed Jun 23 09:33:27 2010
*
* @brief Code to handle daemon startup, including command line args
*
* The function in this file are called when the daemon starts up
* and include the getopt() command line argument parsing.
*/
#include "../ptpd.h"
void
ptpdShutdown(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
(void)netShutdown(rtOpts, &ptpClock->netPath);
free(ptpClock->foreign);
/* free management messages, they can have dynamic memory allocated */
if (ptpClock->msgTmpHeader.messageType == MANAGEMENT)
{
freeManagementTLV(&ptpClock->msgTmp.manage);
}
freeManagementTLV(&ptpClock->outgoingManageTmp);
/* Not running statistics code - write observed drift to driftfile if enabled, inform user */
if (ptpClock->slaveOnly && !ptpClock->servo.runningMaxOutput)
{
saveDrift(ptpClock, rtOpts, FALSE);
}
free(ptpClock);
ptpClock = NULL;
}
PtpClock *
ptpdStartup(int slaveMaster, RunTimeOpts *rtOpts)
{
PtpClock *ptpClock;
if (slaveMaster == PTP_DEVICE_SLAVE)
{
rtOpts->slaveOnly = 1;
rtOpts->selectedPreset = PTP_PRESET_SLAVEONLY;
rtOpts->clockQuality.clockClass = SLAVE_ONLY_CLOCK_CLASS;
}
else if (slaveMaster == PTP_DEVICE_MASTER)
{
rtOpts->selectedPreset = PTP_PRESET_MASTERONLY;
rtOpts->clockQuality.clockClass = DEFAULT_CLOCK_CLASS__APPLICATION_SPECIFIC_TIME_SOURCE;
}
else
{
rtOpts->selectedPreset = PTP_PRESET_MASTERSLAVE;
rtOpts->clockQuality.clockClass = DEFAULT_CLOCK_CLASS;
}
/**
* This is where the final checking of the candidate settings container happens.
* A dictionary is returned with only the known options, explicitly set to defaults
* if not present. NULL is returned on any config error - parameters missing, out of range,
* etc. The getopt loop in loadCommandLineOptions() only sets keys verified here.
*/
parseConfig(rtOpts);
configcheck:
/* Allocate memory after we're done with other checks but before going into daemon */
ptpClock = (PtpClock *) calloc(1, sizeof(PtpClock));
if (!ptpClock)
{
PERROR("Error: Failed to allocate memory for protocol engine data");
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");
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);
/* Init user_description */
memset(ptpClock->user_description, 0, sizeof(ptpClock->user_description));
memcpy(ptpClock->user_description, &USER_DESCRIPTION, sizeof(USER_DESCRIPTION));
/* Init outgoing management message */
ptpClock->outgoingManageTmp.tlv = NULL;
NOTICE(USER_DESCRIPTION" started successfully on %s using \"%s\" preset \n",
rtOpts->ifaceName,
(getPtpPreset(rtOpts->selectedPreset, rtOpts)).presetName
);
ptpClock->resetStatisticsLog = TRUE;
ptpClock->netPath.generalSock = -1;
ptpClock->netPath.eventSock = -1;
if (rtOpts->transport == IEEE_802_3)
{
memset (&ptpClock->netPath.layer2addr, 0, sizeof(ptpClock->netPath.layer2addr));
ptpClock->netPath.layer2addr.sll_family = AF_PACKET;
ptpClock->netPath.layer2addr.sll_ifindex = if_nametoindex (rtOpts->primaryIfaceName);
ptpClock->netPath.layer2addr.sll_halen = ETHER_ADDR_LEN;
if (rtOpts->ptp_profile == PTP_802_1AS_PROFILE)
{
ptpClock->netPath.layer2addr.sll_addr[0] = 0x01;
ptpClock->netPath.layer2addr.sll_addr[1] = 0x80;
ptpClock->netPath.layer2addr.sll_addr[2] = 0xc2;
ptpClock->netPath.layer2addr.sll_addr[3] = 0x00;
ptpClock->netPath.layer2addr.sll_addr[4] = 0x00;
ptpClock->netPath.layer2addr.sll_addr[5] = 0x0e;
}
else
{
ptpClock->netPath.layer2addr.sll_addr[0] = 0x01;
ptpClock->netPath.layer2addr.sll_addr[1] = 0x1b;
ptpClock->netPath.layer2addr.sll_addr[2] = 0x19;
ptpClock->netPath.layer2addr.sll_addr[3] = 0x00;
ptpClock->netPath.layer2addr.sll_addr[4] = 0x00;
ptpClock->netPath.layer2addr.sll_addr[5] = 0x00;
}
}
return ptpClock;
}
@@ -0,0 +1,702 @@
/**
* @file statistics.c
* @authors Wojciech Owczarek
* @date Sun Jul 7 13:28:10 2013
* This souece file contains the implementations of functions maintaining and
* computing statistical information.
*/
#include "../ptpd.h"
static int cmpInt32 (const void *vA, const void *vB) {
int32_t a = *(int32_t*)vA;
int32_t b = *(int32_t*)vB;
return ((a < b) ? -1 : (a > b) ? 1 : 0);
}
static int cmpDouble (const void *vA, const void *vB) {
double a = *(double*)vA;
double b = *(double*)vB;
return ((a < b) ? -1 : (a > b) ? 1 : 0);
}
void
resetIntPermanentMean(IntPermanentMean* container) {
container->mean = 0;
container->count = 0;
}
int32_t
feedIntPermanentMean(IntPermanentMean* container, int32_t sample)
{
container->mean += ( sample - container-> mean ) / ++container->count;
return container->mean;
}
void
resetIntPermanentStdDev(IntPermanentStdDev* container) {
resetIntPermanentMean(&container->meanContainer);
container->squareSum = 0;
container->stdDev = 0;
}
int32_t
feedIntPermanentStdDev(IntPermanentStdDev* container, int32_t sample)
{
container->squareSum += ( sample - container->meanContainer.mean) *
( sample - feedIntPermanentMean(&container->meanContainer, sample ));
if(container->meanContainer.count > 1) {
container->stdDev = sqrt( container->squareSum /
(container->meanContainer.count - 1) );
} else {
container->stdDev = 0;
}
return container->stdDev;
}
void
resetDoublePermanentMean(DoublePermanentMean* container)
{
if(container == NULL)
return;
container->mean = 0.0;
container->count = 0;
}
double
feedDoublePermanentMean(DoublePermanentMean* container, double sample)
{
container->mean += ( sample - container-> mean ) / ++container->count;
return container->mean;
}
void
resetDoublePermanentStdDev(DoublePermanentStdDev* container)
{
if(container == NULL)
return;
resetDoublePermanentMean(&container->meanContainer);
container->squareSum = 0.0;
container->stdDev = 0.0;
}
double
feedDoublePermanentStdDev(DoublePermanentStdDev* container, double sample)
{
container->squareSum += ( sample - container->meanContainer.mean) *
( sample - feedDoublePermanentMean(&container->meanContainer, sample )) ;
if(container->meanContainer.count > 1) {
container->stdDev = sqrt(container->squareSum /
((container->meanContainer.count+0.0) - 1.0)) ;
} else {
container->stdDev = 0;
}
return container->stdDev;
}
/* Moving statistics - up to last n samples */
IntMovingMean*
createIntMovingMean(int capacity)
{
IntMovingMean* container;
if ( !(container = calloc (1, sizeof(IntMovingMean))) ) {
return NULL;
}
container->capacity = (capacity > STATCONTAINER_MAX_SAMPLES ) ?
STATCONTAINER_MAX_SAMPLES : capacity;
if ( !(container->samples = calloc (container->capacity, sizeof(int32_t))) ) {
free(container);
return NULL;
}
return container;
}
void
freeIntMovingMean(IntMovingMean** container)
{
free((*container)->samples);
free(*container);
*container = NULL;
}
void
resetIntMovingMean(IntMovingMean* container)
{
if(container == NULL)
return;
container->sum = 0;
container->mean = 0;
container->count = 0;
memset(container->samples, 0, sizeof(&container->samples));
}
int32_t
feedIntMovingMean(IntMovingMean* container, int32_t sample)
{
if(container == NULL) return 0;
/* sample buffer is full */
if ( container->count == container->capacity ) {
/* keep the sum current - drop the oldest value */
container->sum -= container->samples[0];
/* shift the sample buffer left, dropping the oldest sample */
memcpy(container->samples, container->samples + 1,
sizeof(int32_t) * (container->capacity - 1) );
/* counter will be incremented further, so we decrement it here */
container->count--;
container->full = TRUE;
}
container->samples[container->count++] = sample;
container->sum += sample;
container->mean = container->sum / container->count;
return container->mean;
}
IntMovingStdDev* createIntMovingStdDev(int capacity)
{
IntMovingStdDev* container;
if ( !(container = calloc (1, sizeof(IntMovingStdDev))) ) {
return NULL;
}
if((container->meanContainer = createIntMovingMean(capacity))
== NULL) {
free(container);
return NULL;
}
return container;
}
void
freeIntMovingStdDev(IntMovingStdDev** container)
{
freeIntMovingMean(&((*container)->meanContainer));
free(*container);
*container = NULL;
}
void
resetIntMovingStdDev(IntMovingStdDev* container)
{
if(container == NULL)
return;
resetIntMovingMean(container->meanContainer);
container->squareSum = 0;
container->stdDev = 0;
}
int32_t
feedIntMovingStdDev(IntMovingStdDev* container, int32_t sample)
{
int i = 0;
if(container == NULL)
return 0;
feedIntMovingMean(container->meanContainer, sample);
if (container->meanContainer->count < 2) {
container->stdDev = 0;
} else {
container->squareSum = 0;
for(i = 0; i < container->meanContainer->count; i++) {
container->squareSum += ( container->meanContainer->samples[i] - container->meanContainer->mean ) *
( container->meanContainer->samples[i] - container->meanContainer->mean );
}
container->stdDev = sqrt ( container->squareSum /
(container->meanContainer->count - 1 ));
}
return container->stdDev;
}
DoubleMovingMean*
createDoubleMovingMean(int capacity)
{
DoubleMovingMean* container;
if ( !(container = calloc (1, sizeof(DoubleMovingMean))) ) {
return NULL;
}
container->capacity = (capacity > STATCONTAINER_MAX_SAMPLES ) ?
STATCONTAINER_MAX_SAMPLES : capacity;
if ( !(container->samples = calloc(container->capacity, sizeof(double))) ) {
free(container);
return NULL;
}
return container;
}
void
freeDoubleMovingMean(DoubleMovingMean** container)
{
if(*container == NULL) {
return;
}
free((*container)->samples);
free(*container);
*container = NULL;
}
void
resetDoubleMovingMean(DoubleMovingMean* container)
{
if(container == NULL)
return;
container->sum = 0;
container->mean = 0;
container->count = 0;
memset(container->samples, 0, sizeof(&container->samples));
}
double
feedDoubleMovingMean(DoubleMovingMean* container, double sample)
{
if(container == NULL)
return 0;
/* sample buffer is full */
if ( container->count == container->capacity ) {
/* keep the sum current - drop the oldest value */
container->sum -= container->samples[0];
/* shift the sample buffer left, dropping the oldest sample */
memcpy(container->samples, container->samples + 1,
sizeof(double) * (container->capacity - 1) );
/* counter will be incremented further, so we decrement it here */
container->count--;
container->full = TRUE;
}
container->samples[container->count++] = sample;
container->sum += sample;
container->mean = container->sum / container->count;
return container->mean;
}
DoubleMovingStdDev* createDoubleMovingStdDev(int capacity)
{
DoubleMovingStdDev* container;
if ( !(container = calloc (1, sizeof(DoubleMovingStdDev))) ) {
return NULL;
}
if((container->meanContainer = createDoubleMovingMean(capacity))
== NULL) {
free(container);
return NULL;
}
return container;
}
void
freeDoubleMovingStdDev(DoubleMovingStdDev** container)
{
freeDoubleMovingMean(&((*container)->meanContainer));
free(*container);
*container = NULL;
}
void
resetDoubleMovingStdDev(DoubleMovingStdDev* container)
{
if(container == NULL)
return;
resetDoubleMovingMean(container->meanContainer);
container->squareSum = 0.0;
container->stdDev = 0.0;
}
double
feedDoubleMovingStdDev(DoubleMovingStdDev* container, double sample)
{
int i = 0;
if(container == NULL)
return 0.0;
feedDoubleMovingMean(container->meanContainer, sample);
if (container->meanContainer->count < 2) {
container->stdDev = 0.0;
} else {
container->squareSum = 0.0;
for(i = 0; i < container->meanContainer->count; i++) {
container->squareSum += ( container->meanContainer->samples[i] - container->meanContainer->mean ) *
( container->meanContainer->samples[i] - container->meanContainer->mean );
}
container->stdDev = sqrt ( container->squareSum /
(container->meanContainer->count - 1));
}
return container->stdDev;
}
IntMovingMedian* createIntMovingMedian(int capacity)
{
IntMovingMedian* container;
if ( !(container = calloc (1, sizeof(IntMovingMedian))) ) {
return NULL;
}
if((container->meanContainer = createIntMovingMean(capacity))
== NULL) {
free(container);
return NULL;
}
return container;
}
void
freeIntMovingMedian(IntMovingMedian** container)
{
freeIntMovingMean(&((*container)->meanContainer));
free(*container);
*container = NULL;
}
void
resetIntMovingMedian(IntMovingMedian* container)
{
if(container == NULL)
return;
resetIntMovingMean(container->meanContainer);
container->median = 0;
}
int32_t
feedIntMovingMedian(IntMovingMedian* container, int32_t sample)
{
if(container == NULL)
return 0;
feedIntMovingMean(container->meanContainer, sample);
int count = container->meanContainer->count;
int32_t sortedSamples[count];
Boolean odd = ((count %2 ) == 1);
memcpy(sortedSamples, container->meanContainer->samples, count * sizeof(sample));
qsort(sortedSamples, count, sizeof(sample), cmpInt32);
if(odd) {
container->median = sortedSamples[(count / 2)];
} else {
container->median = (sortedSamples[(count / 2) - 1] + sortedSamples[(count / 2)]) / 2;
}
return container->median;
}
DoubleMovingMedian* createDoubleMovingMedian(int capacity)
{
DoubleMovingMedian* container;
if ( !(container = calloc (1, sizeof(DoubleMovingMedian))) ) {
return NULL;
}
if((container->meanContainer = createDoubleMovingMean(capacity))
== NULL) {
free(container);
return NULL;
}
return container;
}
void
freeDoubleMovingMedian(DoubleMovingMedian** container)
{
freeDoubleMovingMean(&((*container)->meanContainer));
free(*container);
*container = NULL;
}
void
resetDoubleMovingMedian(DoubleMovingMedian* container)
{
if(container == NULL)
return;
resetDoubleMovingMean(container->meanContainer);
container->median = 0;
}
double
feedDoubleMovingMedian(DoubleMovingMedian* container, double sample)
{
if(container == NULL)
return 0;
feedDoubleMovingMean(container->meanContainer, sample);
int count = container->meanContainer->count;
double sortedSamples[count];
Boolean odd = ((count %2 ) == 1);
memcpy(sortedSamples, container->meanContainer->samples, count * sizeof(sample));
qsort(sortedSamples, count, sizeof(sample), cmpDouble);
if(odd) {
container->median = sortedSamples[(count / 2)];
} else {
container->median = (sortedSamples[(count / 2) -1] + sortedSamples[(count / 2)]) / 2;
}
DBGV("Median sample %.09f median %.09f\n", sample, container->median);
return container->median;
}
double getpeircesCriterion(int numObservations, int numDoubtful) {
static const double peircesTable[60][9] = {
/* 1 - 10 samples */
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
{1.196, -1, -1, -1, -1, -1, -1, -1, -1},
{1.383, 1.078, -1, -1, -1, -1, -1, -1, -1},
{1.509, 1.2, -1, -1, -1, -1, -1, -1, -1},
{1.61, 1.299, 1.099, -1, -1, -1, -1, -1, -1},
{1.693, 1.382, 1.187, 1.022, -1, -1, -1, -1, -1},
{1.763, 1.453, 1.261, 1.109, -1, -1, -1, -1, -1},
{1.824, 1.515, 1.324, 1.178, 1.045, -1, -1, -1, -1},
{1.878, 1.57, 1.38, 1.237, 1.114, -1, -1, -1, -1},
/* 11 - 20 samples */
{1.925, 1.619, 1.43, 1.289, 1.172, 1.059, -1, -1, -1},
{1.969, 1.663, 1.475, 1.336, 1.221, 1.118, 1.009, -1, -1},
{2.007, 1.704, 1.516, 1.379, 1.266, 1.167, 1.07, -1, -1},
{2.043, 1.741, 1.554, 1.417, 1.307, 1.21, 1.12, 1.026, -1},
{2.076, 1.775, 1.589, 1.453, 1.344, 1.249, 1.164, 1.078, -1},
{2.106, 1.807, 1.622, 1.486, 1.378, 1.285, 1.202, 1.122, 1.039},
{2.134, 1.836, 1.652, 1.517, 1.409, 1.318, 1.237, 1.161, 1.084},
{2.161, 1.864, 1.68, 1.546, 1.438, 1.348, 1.268, 1.195, 1.123},
{2.185, 1.89, 1.707, 1.573, 1.466, 1.377, 1.298, 1.226, 1.158},
{2.209, 1.914, 1.732, 1.599, 1.492, 1.404, 1.326, 1.255, 1.19},
/* 21 - 30 samples */
{2.23, 1.938, 1.756, 1.623, 1.517, 1.429, 1.352, 1.282, 1.218},
{2.251, 1.96, 1.779, 1.646, 1.54, 1.452, 1.376, 1.308, 1.245},
{2.271, 1.981, 1.8, 1.668, 1.563, 1.475, 1.399, 1.332, 1.27},
{2.29, 2, 1.821, 1.689, 1.584, 1.497, 1.421, 1.354, 1.293},
{2.307, 2.019, 1.84, 1.709, 1.604, 1.517, 1.442, 1.375, 1.315},
{2.324, 2.037, 1.859, 1.728, 1.624, 1.537, 1.462, 1.396, 1.336},
{2.341, 2.055, 1.877, 1.746, 1.642, 1.556, 1.481, 1.415, 1.356},
{2.356, 2.071, 1.894, 1.764, 1.66, 1.574, 1.5, 1.434, 1.375},
{2.371, 2.088, 1.911, 1.781, 1.677, 1.591, 1.517, 1.452, 1.393},
/* 31 - 40 samples */
{2.385, 2.103, 1.927, 1.797, 1.694, 1.608, 1.534, 1.469, 1.411},
{2.399, 2.118, 1.942, 1.812, 1.71, 1.624, 1.55, 1.486, 1.428},
{2.412, 2.132, 1.957, 1.828, 1.725, 1.64, 1.567, 1.502, 1.444},
{2.425, 2.146, 1.971, 1.842, 1.74, 1.655, 1.582, 1.517, 1.459},
{2.438, 2.159, 1.985, 1.856, 1.754, 1.669, 1.597, 1.532, 1.475},
{2.45, 2.172, 1.998, 1.87, 1.768, 1.683, 1.611, 1.547, 1.489},
{2.461, 2.184, 2.011, 1.883, 1.782, 1.697, 1.624, 1.561, 1.504},
{2.472, 2.196, 2.024, 1.896, 1.795, 1.711, 1.638, 1.574, 1.517},
{2.483, 2.208, 2.036, 1.909, 1.807, 1.723, 1.651, 1.587, 1.531},
/* 41 - 50 samples */
{2.494, 2.219, 2.047, 1.921, 1.82, 1.736, 1.664, 1.6, 1.544},
{2.504, 2.23, 2.059, 1.932, 1.832, 1.748, 1.676, 1.613, 1.556},
{2.514, 2.241, 2.07, 1.944, 1.843, 1.76, 1.688, 1.625, 1.568},
{2.524, 2.251, 2.081, 1.955, 1.855, 1.771, 1.699, 1.636, 1.58},
{2.533, 2.261, 2.092, 1.966, 1.866, 1.783, 1.711, 1.648, 1.592},
{2.542, 2.271, 2.102, 1.976, 1.876, 1.794, 1.722, 1.659, 1.603},
{2.551, 2.281, 2.112, 1.987, 1.887, 1.804, 1.733, 1.67, 1.614},
{2.56, 2.29, 2.122, 1.997, 1.897, 1.815, 1.743, 1.681, 1.625},
{2.568, 2.299, 2.131, 2.006, 1.907, 1.825, 1.754, 1.691, 1.636},
{2.577, 2.308, 2.14, 2.016, 1.917, 1.835, 1.764, 1.701, 1.646},
/* 51 - 60 * samples */
{2.585, 2.317, 2.149, 2.026, 1.927, 1.844, 1.773, 1.711, 1.656},
{2.592, 2.326, 2.158, 2.035, 1.936, 1.854, 1.783, 1.721, 1.666},
{2.6, 2.334, 2.167, 2.044, 1.945, 1.863, 1.792, 1.73, 1.675},
{2.608, 2.342, 2.175, 2.052, 1.954, 1.872, 1.802, 1.74, 1.685},
{2.615, 2.35, 2.184, 2.061, 1.963, 1.881, 1.811, 1.749, 1.694},
{2.622, 2.358, 2.192, 2.069, 1.972, 1.89, 1.82, 1.758, 1.703},
{2.629, 2.365, 2.2, 2.077, 1.98, 1.898, 1.828, 1.767, 1.711},
{2.636, 2.373, 2.207, 2.085, 1.988, 1.907, 1.837, 1.775, 1.72},
{2.643, 2.38, 2.215, 2.093, 1.996, 1.915, 1.845, 1.784, 1.729},
{2.65, 2.387, 2.223, 2.101, 2.004, 1.923, 1.853, 1.792, 1.737},
{2.656, 2.394, 2.23, 2.109, 2.012, 1.931, 1.861, 1.8, 1.745},
{2.663, 2.401, 2.237, 2.116, 2.019, 1.939, 1.869, 1.808, 1.753},
};
if ( numObservations < 1 || numObservations > 60)
return -1.0;
if ( numDoubtful < 1 || numDoubtful > 9)
return -1.0;
return(peircesTable[numObservations - 1][numDoubtful - 1]);
}
Boolean isIntPeircesOutlier(IntMovingStdDev *container, int32_t sample, double threshold) {
double maxDev;
/* Sanity check - race condition was seen when enabling and disabling filters repeatedly */
if(container == NULL || container->meanContainer == NULL)
return FALSE;
maxDev = container->stdDev * getpeircesCriterion(container->meanContainer->count, 1) * threshold;
/*
* Two cases:
* - Too early - we got a -1 from Peirce's table,
* - safeguard: std dev is zero and filter is blocking
* everything, hus, we let the sample through
*/
if (maxDev <= 0.0 ) return FALSE;
if(fabs((double)(sample - container->meanContainer->mean)) > maxDev) {
DBGV("Peirce %s outlier: val: %d, cnt: %d, mxd: %.09f (%.03f * dev * %.03f), dev: %.09f, mea: %.09f, dif: %.09f\n", container->identifier,
sample, container->meanContainer->count, maxDev, getpeircesCriterion(container->meanContainer->count, 1), threshold,
container->stdDev,
container->meanContainer->mean, fabs(sample - container->meanContainer->mean));
return TRUE;
}
return FALSE;
}
Boolean isDoublePeircesOutlier(DoubleMovingStdDev *container, double sample, double threshold) {
double maxDev;
/* Sanity check - race condition was seen when enabling and disabling filters repeatedly */
if(container == NULL || container->meanContainer == NULL)
return FALSE;
maxDev = container->stdDev * getpeircesCriterion(container->meanContainer->count, 1) * threshold;
/*
* Two cases:
* - Too early - we got a -1 from Peirce's table,
* - safeguard: std dev is zero and filter is blocking
* everything, hus, we let the sample through
*/
if (maxDev <= 0.0 ) {
return FALSE;
}
if(fabs((double)(sample - container->meanContainer->mean)) > maxDev) {
DBGV("Peirce %s outlier: val: %.09f, cnt: %d, mxd: %.09f (%.03f * dev * %.03f), dev: %.09f, mea: %.09f, dif: %.09f\n", container->identifier,
sample, container->meanContainer->count, maxDev, getpeircesCriterion(container->meanContainer->count, 1), threshold,
container->stdDev,
container->meanContainer->mean, fabs(sample - container->meanContainer->mean));
return TRUE;
}
return FALSE;
}
void
clearPtpEngineSlaveStats(PtpEngineSlaveStats* stats)
{
memset(stats, 0, sizeof(*stats));
}
void
resetPtpEngineSlaveStats(PtpEngineSlaveStats* stats) {
resetDoublePermanentStdDev(&stats->ofmStats);
resetDoublePermanentStdDev(&stats->owdStats);
}
@@ -0,0 +1,179 @@
/**
* @file statistics.h
* @authors Wojciech Owczarek
* @date Sun Jul 7 13:28:10 2013
*
* This header file contains the definitions of structures and functions
* implementing standard statistical measures - means and standard deviations,
* both complete (from t0 to tnow) and moving (from t0+n*windowsize to t0+(n+1)*windowsize)
*/
#ifndef STATISTICS_H_
#define STATISTICS_H_
#define STATCONTAINER_MAX_SAMPLES 60
/* "Permanent" i.e. non-moving statistics containers - useful for long term measurement */
typedef struct {
int32_t mean;
int32_t count;
} IntPermanentMean;
typedef struct {
double mean;
double count;
} DoublePermanentMean;
typedef struct {
IntPermanentMean meanContainer;
int32_t squareSum;
int32_t stdDev;
} IntPermanentStdDev;
typedef struct {
DoublePermanentMean meanContainer;
double squareSum;
double stdDev;
} DoublePermanentStdDev;
void resetIntPermanentMean(IntPermanentMean* container);
int32_t feedIntPermanentMean(IntPermanentMean* container, int32_t sample);
void resetIntPermanentStdDev(IntPermanentStdDev* container);
int32_t feedIntPermanentStdDev(IntPermanentStdDev* container, int32_t sample);
void resetDoublePermanentMean(DoublePermanentMean* container);
double feedDoublePermanentMean(DoublePermanentMean* container, double sample);
void resetDoublePermanentStdDev(DoublePermanentStdDev* container);
double feedDoublePermanentStdDev(DoublePermanentStdDev* container, double sample);
/* Moving statistics - up to last n samples */
typedef struct {
int32_t mean;
int32_t sum;
int32_t* samples;
Boolean full;
int count;
int capacity;
} IntMovingMean;
typedef struct {
double mean;
double sum;
double* samples;
Boolean full;
int count;
int capacity;
} DoubleMovingMean;
typedef struct {
IntMovingMean* meanContainer;
int32_t squareSum;
int32_t stdDev;
char* identifier[10];
} IntMovingStdDev;
typedef struct {
DoubleMovingMean* meanContainer;
double squareSum;
double stdDev;
char identifier[10];
} DoubleMovingStdDev;
typedef struct {
IntMovingMean* meanContainer;
int32_t median;
int32_t* sortedSamples;
char* identifier[10];
} IntMovingMedian;
typedef struct {
DoubleMovingMean* meanContainer;
double median;
double* sortedSamples;
char* identifier[10];
} DoubleMovingMedian;
IntMovingMean* createIntMovingMean(int capacity);
void freeIntMovingMean(IntMovingMean** container);
void resetIntMovingMean(IntMovingMean* container);
int32_t feedIntMovingMean(IntMovingMean* container, int32_t sample);
IntMovingStdDev* createIntMovingStdDev(int capacity);
void freeIntMovingStdDev(IntMovingStdDev** container);
void resetIntMovingStdDev(IntMovingStdDev* container);
int32_t feedIntMovingStdDev(IntMovingStdDev* container, int32_t sample);
DoubleMovingMean* createDoubleMovingMean(int capacity);
void freeDoubleMovingMean(DoubleMovingMean** container);
void resetDoubleMovingMean(DoubleMovingMean* container);
double feedDoubleMovingMean(DoubleMovingMean* container, double sample);
DoubleMovingStdDev* createDoubleMovingStdDev(int capacity);
void freeDoubleMovingStdDev(DoubleMovingStdDev** container);
void resetDoubleMovingStdDev(DoubleMovingStdDev* container);
double feedDoubleMovingStdDev(DoubleMovingStdDev* container, double sample);
IntMovingMedian* createIntMovingMedian(int capacity);
void freeIntMovingMedian(IntMovingMedian** container);
void resetIntMovingMedian(IntMovingMedian* container);
int32_t feedIntMovingMedian(IntMovingMedian* container, int32_t sample);
DoubleMovingMedian* createDoubleMovingMedian(int capacity);
void freeDoubleMovingMedian(DoubleMovingMedian** container);
void resetDoubleMovingMedian(DoubleMovingMedian* container);
double feedDoubleMovingMedian(DoubleMovingMedian* container, double sample);
void intStatsTest(int32_t sample);
void doubleStatsTest(double sample);
double getPeircesCriterion(int numObservations, int numDoubtful);
Boolean isIntPeircesOutlier(IntMovingStdDev *container, int32_t sample, double threshold);
Boolean isDoublePeircesOutlier(DoubleMovingStdDev *container, double sample, double threshold);
/**
* \struct PtpEngineSlaveStats
* \brief Ptpd clock statistics per port
*/
typedef struct
{
Boolean statsCalculated;
double ofmMean;
double ofmStdDev;
double owdMean;
double owdStdDev;
Boolean owdIsStable;
double owdStabilityThreshold;
int owdStabilityPeriod;
DoublePermanentStdDev ofmStats;
DoublePermanentStdDev owdStats;
} PtpEngineSlaveStats;
void clearPtpEngineSlaveStats(PtpEngineSlaveStats* stats);
void resetPtpEngineSlaveStats(PtpEngineSlaveStats* stats);
#endif /*STATISTICS_H_*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,291 @@
/*-
* Copyright (c) 2016 Wind River Systems, Inc,
* Copyright (c) 2011-2012 George V. Neville-Neil,
* Steven Kreuzer,
* Martin Burnicki,
* Jan Breuer,
* Gael Mace,
* Alexandre Van Kempen,
* Inaqui Delgado,
* Rick Ratzel,
* National Instruments.
* Copyright (c) 2009-2010 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.
*/
/*
modification history
--------------------
02feb16,h_l Init version.
*/
/**
* @file timer.c
* @date Wed Jun 23 09:41:26 2010
*
* @brief The timers which run the state machine.
*
* Timers in the PTP daemon are run off of the signal system.
*/
#include "../ptpd.h"
#define US_TIMER_INTERVAL (62500)
volatile unsigned int elapsed;
static timer_t ptpd_timerid;
/*
* original code calls sigalarm every fixed 1ms. This highly pollutes the debug_log, and causes more interrupted instructions
* This was later modified to have a fixed granularity of 1s.
*
* Currently this has a configured granularity, and timerStart() guarantees that clocks expire ASAP when the granularity is too small.
* Timers must now be explicitelly canceled with timerStop (instead of timerStart(0.0))
*/
void
catch_alarm(int sig)
{
elapsed++;
/* be sure to NOT call DBG in asynchronous handlers! */
}
void
initTimer(void)
{
struct itimerval itimer;
DBG("initTimer\n");
signal(SIGALRM, SIG_IGN);
elapsed = 0;
itimer.it_value.tv_sec = itimer.it_interval.tv_sec = 0;
itimer.it_value.tv_usec = itimer.it_interval.tv_usec = US_TIMER_INTERVAL;
signal(SIGALRM, catch_alarm);
#ifdef VXWORKS_OS
/*timer_create (CLOCK_REALTIME, NULL, &ptpd_timerid);
timer_settime(ptpd_timerid, 0, &itimer, NULL);*/
#else
setitimer(ITIMER_REAL, &itimer, 0);
#endif
}
void
timerUpdate(IntervalTimer * itimer)
{
int i, delta;
/*
* latch how many ticks we got since we were last called
* remember that catch_alarm() is totally asynchronous to this timerUpdate()
*/
#if 0
delta = elapsed;
elapsed = 0;
if (delta <= 0)
return;
#endif
/*
* if time actually passed, then decrease every timer left
* the one(s) that went to zero or negative are:
* a) rearmed at the original time (ignoring the time that may have passed ahead)
* b) have their expiration latched until timerExpired() is called
*/
for (i = 0; i < TIMER_ARRAY_SIZE; ++i) {
if ((itimer[i].interval) > 0 && ((itimer[i].left) <= tickGet()) ) {
#ifdef VXWORKS_OS
itimer[i].left = itimer[i].interval + tickGet();
#else
itimer[i].left = itimer[i].interval;
#endif
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 );
}
}
}
void
timerStop(UInteger16 index, IntervalTimer * itimer)
{
if (index >= TIMER_ARRAY_SIZE)
return;
itimer[index].interval = 0;
DBG2("timerStop: Stopping timer %d. (New interval: %d; New left: %d)\n", index, itimer[index].left , itimer[index].interval);
}
void
timerStart(UInteger16 index, float interval, IntervalTimer * itimer)
{
if (index >= TIMER_ARRAY_SIZE)
return;
itimer[index].expire = FALSE;
/*
* US_TIMER_INTERVAL defines the minimum interval between sigalarms.
* timerStart has a float parameter for the interval, which is casted to integer.
* very small amounts are forced to expire ASAP by setting the interval to 1
*/
#ifdef VXWORKS_OS
itimer[index].left = tickGet() + (UInteger32)(interval * sysClkRateGet()) ;
#else
itimer[index].left = (int)((interval * 1E6) / US_TIMER_INTERVAL);
#endif
if(itimer[index].left == 0){
/*
* the interval is too small, raise it to 1 to make sure it expires ASAP
* Timer cancelation is done explicitelly with stopTimer()
*/
itimer[index].left = 1;
static int operator_warned_interval_too_small = 0;
if(!operator_warned_interval_too_small){
operator_warned_interval_too_small = 1;
/*
* using random uniform timers it is pratically guarantted that we hit the possible minimum timer.
* This is because of the current timer model based on periodic sigalarm, irrespective if the next
* event is close or far away in time.
*
* A solution would be to recode this whole module with a calendar queue, while keeping the same API:
* E.g.: http://www.isi.edu/nsnam/ns/doc/node35.html
*
* Having events that expire immediatly (ie, delayreq invocations using random timers) can lead to
* messages appearing in unexpected ordering, so the protocol implementation must check more conditions
* and not assume a certain ususal ordering
*/
DBG("Timer would be issued immediatly. Please raise dep/timer.c:US_TIMER_INTERVAL to hold %.2fs\n",
interval
);
}
}
#ifdef VXWORKS_OS
itimer[index].interval = (UInteger32)(interval * sysClkRateGet());
if(itimer[index].interval == 0)
{
itimer[index].interval = 1;
}
#else
itimer[index].interval = itimer[index].left;
#endif
#if 0
printf("timerStart: Set timer index %d to internal %f New left: %d; new interval: %d\n", index, interval, itimer[index].left , itimer[index].interval);
#endif
}
/*
* This function arms the timer with a uniform range, as requested by page 105 of the standard (for sending delayReqs.)
* actual time will be U(0, interval * 2.0);
*
* 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 ;
DBG2(" timerStart_random: requested %.2f, got %.2f\n", interval, new_value);
timerStart(index, new_value, itimer);
}
Boolean
timerExpired(UInteger16 index, IntervalTimer * itimer)
{
timerUpdate(itimer);
if (index >= TIMER_ARRAY_SIZE)
return FALSE;
if (!itimer[index].expire)
return FALSE;
itimer[index].expire = FALSE;
#if 0
DBG2("timerExpired: Timer %d expired, taking actions. current interval: %d; current left: %d\n", index, itimer[index].left , itimer[index].interval);
#else
/*
logMsg("timerExpired: Timer %d expired, taking actions. current left: %d; current interval: %d\n", index, itimer[index].left , itimer[index].interval,0,0,0);
*/
#endif
return TRUE;
}
Boolean
timerStopped(UInteger16 index, IntervalTimer * itimer)
{
timerUpdate(itimer);
if (index >= TIMER_ARRAY_SIZE)
return FALSE;
if (itimer[index].interval == 0) {
return TRUE;
}
return FALSE;
}
Boolean
timerRunning(UInteger16 index, IntervalTimer * itimer)
{
timerUpdate(itimer);
if (index >= TIMER_ARRAY_SIZE)
return FALSE;
if ((itimer[index].interval != 0) &&
(itimer[index].expire == FALSE)) {
return TRUE;
}
return FALSE;
}