154359Sroberto/* 2280849Scy * refclock_shm - clock driver for utc via shared memory 354359Sroberto * - under construction - 454359Sroberto * To add new modes: Extend or union the shmTime-struct. Do not 554359Sroberto * extend/shrink size, because otherwise existing implementations 654359Sroberto * will specify wrong size of shared memory-segment 754359Sroberto * PB 18.3.97 854359Sroberto */ 954359Sroberto 1054359Sroberto#ifdef HAVE_CONFIG_H 1154359Sroberto# include <config.h> 1254359Sroberto#endif 1354359Sroberto 14280849Scy#include "ntp_types.h" 15280849Scy 1654359Sroberto#if defined(REFCLOCK) && defined(CLOCK_SHM) 1754359Sroberto 1854359Sroberto#include "ntpd.h" 19280849Scy#undef fileno 2054359Sroberto#include "ntp_io.h" 21280849Scy#undef fileno 2254359Sroberto#include "ntp_refclock.h" 23280849Scy#undef fileno 24280849Scy#include "timespecops.h" 25280849Scy#undef fileno 2654359Sroberto#include "ntp_stdlib.h" 27285169Scy#include "ntp_assert.h" 2854359Sroberto 29280849Scy#undef fileno 3082498Sroberto#include <ctype.h> 31280849Scy#undef fileno 3282498Sroberto 3354359Sroberto#ifndef SYS_WINNT 3482498Sroberto# include <sys/ipc.h> 3582498Sroberto# include <sys/shm.h> 3682498Sroberto# include <assert.h> 3782498Sroberto# include <unistd.h> 3882498Sroberto# include <stdio.h> 3954359Sroberto#endif 4054359Sroberto 41285169Scy#ifdef HAVE_STDATOMIC_H 42285169Scy# include <stdatomic.h> 43285169Scy#endif /* HAVE_STDATOMIC_H */ 44285169Scy 4554359Sroberto/* 4654359Sroberto * This driver supports a reference clock attached thru shared memory 47280849Scy */ 4854359Sroberto 4954359Sroberto/* 5054359Sroberto * SHM interface definitions 5154359Sroberto */ 5254359Sroberto#define PRECISION (-1) /* precision assumed (0.5 s) */ 5354359Sroberto#define REFID "SHM" /* reference ID */ 5454359Sroberto#define DESCRIPTION "SHM/Shared memory interface" 5554359Sroberto 5654359Sroberto#define NSAMPLES 3 /* stages of median filter */ 5754359Sroberto 5854359Sroberto/* 59280849Scy * Mode flags 60280849Scy */ 61280849Scy#define SHM_MODE_PRIVATE 0x0001 62280849Scy 63280849Scy/* 6454359Sroberto * Function prototypes 6554359Sroberto */ 66280849Scystatic int shm_start (int unit, struct peer *peer); 67280849Scystatic void shm_shutdown (int unit, struct peer *peer); 68280849Scystatic void shm_poll (int unit, struct peer *peer); 69280849Scystatic void shm_timer (int unit, struct peer *peer); 70280849Scystatic void shm_clockstats (int unit, struct peer *peer); 71280849Scystatic void shm_control (int unit, const struct refclockstat * in_st, 72280849Scy struct refclockstat * out_st, struct peer *peer); 7354359Sroberto 7454359Sroberto/* 7554359Sroberto * Transfer vector 7654359Sroberto */ 7754359Srobertostruct refclock refclock_shm = { 7854359Sroberto shm_start, /* start up driver */ 7954359Sroberto shm_shutdown, /* shut down driver */ 80280849Scy shm_poll, /* transmit poll message */ 81280849Scy shm_control, /* control settings */ 82280849Scy noentry, /* not used: init */ 83280849Scy noentry, /* not used: buginfo */ 84280849Scy shm_timer, /* once per second */ 8554359Sroberto}; 86280849Scy 8754359Srobertostruct shmTime { 88280849Scy int mode; /* 0 - if valid is set: 89280849Scy * use values, 9054359Sroberto * clear valid 91280849Scy * 1 - if valid is set: 9254359Sroberto * if count before and after read of values is equal, 93280849Scy * use values 9454359Sroberto * clear valid 9554359Sroberto */ 96280849Scy volatile int count; 97280849Scy time_t clockTimeStampSec; 98280849Scy int clockTimeStampUSec; 99280849Scy time_t receiveTimeStampSec; 100280849Scy int receiveTimeStampUSec; 101280849Scy int leap; 102280849Scy int precision; 103280849Scy int nsamples; 104280849Scy volatile int valid; 105280849Scy unsigned clockTimeStampNSec; /* Unsigned ns timestamps */ 106280849Scy unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */ 107280849Scy int dummy[8]; 10854359Sroberto}; 109132451Sroberto 110280849Scystruct shmunit { 111280849Scy struct shmTime *shm; /* pointer to shared memory segment */ 112280849Scy int forall; /* access for all UIDs? */ 113132451Sroberto 114280849Scy /* debugging/monitoring counters - reset when printed */ 115280849Scy int ticks; /* number of attempts to read data*/ 116280849Scy int good; /* number of valid samples */ 117280849Scy int notready; /* number of peeks without data ready */ 118280849Scy int bad; /* number of invalid samples */ 119280849Scy int clash; /* number of access clashes while reading */ 120280849Scy 121280849Scy time_t max_delta; /* difference limit */ 122280849Scy time_t max_delay; /* age/stale limit */ 123280849Scy}; 124280849Scy 125285169Scy 126280849Scystatic struct shmTime* 127280849ScygetShmTime( 128280849Scy int unit, 129280849Scy int/*BOOL*/ forall 130280849Scy ) 131280849Scy{ 132280849Scy struct shmTime *p = NULL; 133280849Scy 13454359Sroberto#ifndef SYS_WINNT 13554359Sroberto 136280849Scy int shmid; 137280849Scy 138280849Scy /* 0x4e545030 is NTP0. 139280849Scy * Big units will give non-ascii but that's OK 140280849Scy * as long as everybody does it the same way. 141280849Scy */ 142280849Scy shmid=shmget(0x4e545030 + unit, sizeof (struct shmTime), 143280849Scy IPC_CREAT | (forall ? 0666 : 0600)); 144280849Scy if (shmid == -1) { /* error */ 145280849Scy msyslog(LOG_ERR, "SHM shmget (unit %d): %m", unit); 146280849Scy return NULL; 14754359Sroberto } 148280849Scy p = (struct shmTime *)shmat (shmid, 0, 0); 149280849Scy if (p == (struct shmTime *)-1) { /* error */ 150280849Scy msyslog(LOG_ERR, "SHM shmat (unit %d): %m", unit); 151280849Scy return NULL; 15254359Sroberto } 153285169Scy 154280849Scy return p; 15554359Sroberto#else 156280849Scy 157280849Scy static const char * nspref[2] = { "Local", "Global" }; 158280849Scy char buf[20]; 159280849Scy LPSECURITY_ATTRIBUTES psec = 0; 160280849Scy HANDLE shmid = 0; 16154359Sroberto SECURITY_DESCRIPTOR sd; 16254359Sroberto SECURITY_ATTRIBUTES sa; 163280849Scy unsigned int numch; 164280849Scy 165280849Scy numch = snprintf(buf, sizeof(buf), "%s\\NTP%d", 166280849Scy nspref[forall != 0], (unit & 0xFF)); 167280849Scy if (numch >= sizeof(buf)) { 168280849Scy msyslog(LOG_ERR, "SHM name too long (unit %d)", unit); 169280849Scy return NULL; 170280849Scy } 171280849Scy if (forall) { /* world access */ 17254359Sroberto if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { 173280849Scy msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m", unit); 174280849Scy return NULL; 17554359Sroberto } 176280849Scy if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) { 177280849Scy msyslog(LOG_ERR, "SHM SetSecurityDescriptorDacl (unit %d): %m", unit); 178280849Scy return NULL; 17954359Sroberto } 180280849Scy sa.nLength = sizeof(SECURITY_ATTRIBUTES); 181280849Scy sa.lpSecurityDescriptor = &sd; 182280849Scy sa.bInheritHandle = FALSE; 183280849Scy psec = &sa; 18454359Sroberto } 185280849Scy shmid = CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, 186280849Scy 0, sizeof (struct shmTime), buf); 187280849Scy if (shmid == NULL) { /*error*/ 188280849Scy char buf[1000]; 18954359Sroberto FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 19054359Sroberto 0, GetLastError (), 0, buf, sizeof (buf), 0); 191280849Scy msyslog(LOG_ERR, "SHM CreateFileMapping (unit %d): %s", unit, buf); 192280849Scy return NULL; 19354359Sroberto } 194280849Scy p = (struct shmTime *)MapViewOfFile(shmid, FILE_MAP_WRITE, 0, 0, 195280849Scy sizeof (struct shmTime)); 196280849Scy if (p == NULL) { /*error*/ 197280849Scy char buf[1000]; 198280849Scy FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 199280849Scy 0, GetLastError (), 0, buf, sizeof (buf), 0); 200280849Scy msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s", unit, buf); 201280849Scy return NULL; 20254359Sroberto } 203280849Scy 204285169Scy return p; 20554359Sroberto#endif 206280849Scy 207285169Scy /* NOTREACHED */ 208285169Scy ENSURE(!"getShmTime(): Not reached."); 20954359Sroberto} 210285169Scy 211285169Scy 21254359Sroberto/* 21354359Sroberto * shm_start - attach to shared memory 21454359Sroberto */ 21554359Srobertostatic int 21654359Srobertoshm_start( 21754359Sroberto int unit, 21854359Sroberto struct peer *peer 21954359Sroberto ) 22054359Sroberto{ 221280849Scy struct refclockproc * const pp = peer->procptr; 222280849Scy struct shmunit * const up = emalloc_zero(sizeof(*up)); 223280849Scy 22454359Sroberto pp->io.clock_recv = noentry; 225280849Scy pp->io.srcclock = peer; 22654359Sroberto pp->io.datalen = 0; 22754359Sroberto pp->io.fd = -1; 22854359Sroberto 229280849Scy up->forall = (unit >= 2) && !(peer->ttl & SHM_MODE_PRIVATE); 230280849Scy 231280849Scy up->shm = getShmTime(unit, up->forall); 232280849Scy 23354359Sroberto /* 23454359Sroberto * Initialize miscellaneous peer variables 23554359Sroberto */ 23654359Sroberto memcpy((char *)&pp->refid, REFID, 4); 237280849Scy if (up->shm != 0) { 238280849Scy pp->unitptr = up; 239280849Scy up->shm->precision = PRECISION; 240280849Scy peer->precision = up->shm->precision; 241280849Scy up->shm->valid = 0; 242280849Scy up->shm->nsamples = NSAMPLES; 24354359Sroberto pp->clockdesc = DESCRIPTION; 244280849Scy /* items to be changed later in 'shm_control()': */ 245280849Scy up->max_delay = 5; 246280849Scy up->max_delta = 4*3600; 247280849Scy return 1; 248280849Scy } else { 249280849Scy free(up); 250280849Scy pp->unitptr = NULL; 25154359Sroberto return 0; 25254359Sroberto } 25354359Sroberto} 25454359Sroberto 25554359Sroberto 25654359Sroberto/* 257280849Scy * shm_control - configure flag1/time2 params 258280849Scy * 259280849Scy * These are not yet available during 'shm_start', so we have to do any 260280849Scy * pre-computations we want to avoid during regular poll/timer callbacks 261280849Scy * in this callback. 262280849Scy */ 263280849Scystatic void 264280849Scyshm_control( 265280849Scy int unit, 266280849Scy const struct refclockstat * in_st, 267280849Scy struct refclockstat * out_st, 268280849Scy struct peer * peer 269280849Scy ) 270280849Scy{ 271280849Scy struct refclockproc * const pp = peer->procptr; 272280849Scy struct shmunit * const up = pp->unitptr; 273280849Scy 274280849Scy UNUSED_ARG(unit); 275280849Scy UNUSED_ARG(in_st); 276280849Scy UNUSED_ARG(out_st); 277280849Scy if (NULL == up) 278280849Scy return; 279280849Scy if (pp->sloppyclockflag & CLK_FLAG1) 280280849Scy up->max_delta = 0; 281280849Scy else if (pp->fudgetime2 < 1. || pp->fudgetime2 > 86400.) 282280849Scy up->max_delta = 4*3600; 283280849Scy else 284280849Scy up->max_delta = (time_t)floor(pp->fudgetime2 + 0.5); 285280849Scy} 286280849Scy 287280849Scy 288280849Scy/* 28954359Sroberto * shm_shutdown - shut down the clock 29054359Sroberto */ 29154359Srobertostatic void 29254359Srobertoshm_shutdown( 29354359Sroberto int unit, 29454359Sroberto struct peer *peer 29554359Sroberto ) 29654359Sroberto{ 297280849Scy struct refclockproc * const pp = peer->procptr; 298280849Scy struct shmunit * const up = pp->unitptr; 29954359Sroberto 300280849Scy UNUSED_ARG(unit); 301280849Scy if (NULL == up) 302280849Scy return; 30354359Sroberto#ifndef SYS_WINNT 304280849Scy 305280849Scy /* HMS: shmdt() wants char* or const void * */ 306280849Scy (void)shmdt((char *)up->shm); 307280849Scy 30854359Sroberto#else 309280849Scy 310280849Scy UnmapViewOfFile(up->shm); 311280849Scy 31254359Sroberto#endif 313280849Scy free(up); 31454359Sroberto} 31554359Sroberto 31654359Sroberto 31754359Sroberto/* 31854359Sroberto * shm_poll - called by the transmit procedure 31954359Sroberto */ 32054359Srobertostatic void 32154359Srobertoshm_poll( 32254359Sroberto int unit, 32354359Sroberto struct peer *peer 32454359Sroberto ) 32554359Sroberto{ 326280849Scy struct refclockproc * const pp = peer->procptr; 327280849Scy struct shmunit * const up = pp->unitptr; 328280849Scy int major_error; 32954359Sroberto 330280849Scy pp->polls++; 331280849Scy 332280849Scy /* get dominant reason if we have no samples at all */ 333280849Scy major_error = max(up->notready, up->bad); 334280849Scy major_error = max(major_error, up->clash); 335280849Scy 336280849Scy /* 337280849Scy * Process median filter samples. If none received, see what 338280849Scy * happened, tell the core and keep going. 339280849Scy */ 340280849Scy if (pp->coderecv != pp->codeproc) { 341280849Scy /* have some samples, everything OK */ 342280849Scy pp->lastref = pp->lastrec; 343338530Sdelphij refclock_report(peer, CEVNT_NOMINAL); 344280849Scy refclock_receive(peer); 345280849Scy } else if (NULL == up->shm) { /* is this possible at all? */ 346280849Scy /* we're out of business without SHM access */ 347280849Scy refclock_report(peer, CEVNT_FAULT); 348280849Scy } else if (major_error == up->clash) { 349280849Scy /* too many collisions is like a bad signal */ 350280849Scy refclock_report(peer, CEVNT_PROP); 351280849Scy } else if (major_error == up->bad) { 352280849Scy /* too much stale/bad/garbled data */ 353280849Scy refclock_report(peer, CEVNT_BADREPLY); 354280849Scy } else { 355280849Scy /* in any other case assume it's just a timeout */ 356280849Scy refclock_report(peer, CEVNT_TIMEOUT); 357280849Scy } 358280849Scy /* shm_clockstats() clears the tallies, so it must be last... */ 359280849Scy shm_clockstats(unit, peer); 360280849Scy} 361280849Scy 362285169Scy 363285169Scyenum segstat_t { 364285169Scy OK, NO_SEGMENT, NOT_READY, BAD_MODE, CLASH 365285169Scy}; 366285169Scy 367285169Scystruct shm_stat_t { 368285169Scy int status; 369285169Scy int mode; 370285169Scy struct timespec tvc, tvr, tvt; 371285169Scy int precision; 372285169Scy int leap; 373285169Scy}; 374285169Scy 375285169Scystatic inline void memory_barrier(void) 376285169Scy{ 377285169Scy#ifdef HAVE_ATOMIC_THREAD_FENCE 378285169Scy atomic_thread_fence(memory_order_seq_cst); 379285169Scy#endif /* HAVE_ATOMIC_THREAD_FENCE */ 380285169Scy} 381285169Scy 382285169Scystatic enum segstat_t shm_query(volatile struct shmTime *shm_in, struct shm_stat_t *shm_stat) 383285169Scy/* try to grab a sample from the specified SHM segment */ 384285169Scy{ 385293423Sdelphij struct shmTime shmcopy; 386293423Sdelphij volatile struct shmTime *shm = shm_in; 387285169Scy volatile int cnt; 388285169Scy 389285169Scy unsigned int cns_new, rns_new; 390285169Scy 391285169Scy /* 392285169Scy * This is the main routine. It snatches the time from the shm 393285169Scy * board and tacks on a local timestamp. 394285169Scy */ 395285169Scy if (shm == NULL) { 396285169Scy shm_stat->status = NO_SEGMENT; 397285169Scy return NO_SEGMENT; 398285169Scy } 399285169Scy 400285169Scy /*@-type@*//* splint is confused about struct timespec */ 401285169Scy shm_stat->tvc.tv_sec = shm_stat->tvc.tv_nsec = 0; 402285169Scy { 403285169Scy time_t now; 404285169Scy 405285169Scy time(&now); 406285169Scy shm_stat->tvc.tv_sec = now; 407285169Scy } 408285169Scy 409285169Scy /* relying on word access to be atomic here */ 410285169Scy if (shm->valid == 0) { 411285169Scy shm_stat->status = NOT_READY; 412285169Scy return NOT_READY; 413285169Scy } 414285169Scy 415285169Scy cnt = shm->count; 416285169Scy 417285169Scy /* 418285169Scy * This is proof against concurrency issues if either 419285169Scy * (a) the memory_barrier() call works on this host, or 420285169Scy * (b) memset compiles to an uninterruptible single-instruction bitblt. 421285169Scy */ 422285169Scy memory_barrier(); 423293423Sdelphij memcpy(&shmcopy, (void*)(uintptr_t)shm, sizeof(struct shmTime)); 424285169Scy shm->valid = 0; 425285169Scy memory_barrier(); 426285169Scy 427285169Scy /* 428285169Scy * Clash detection in case neither (a) nor (b) was true. 429285169Scy * Not supported in mode 0, and word access to the count field 430285169Scy * must be atomic for this to work. 431285169Scy */ 432285169Scy if (shmcopy.mode > 0 && cnt != shm->count) { 433285169Scy shm_stat->status = CLASH; 434285169Scy return shm_stat->status; 435285169Scy } 436285169Scy 437285169Scy shm_stat->status = OK; 438285169Scy shm_stat->mode = shmcopy.mode; 439285169Scy 440285169Scy switch (shmcopy.mode) { 441285169Scy case 0: 442285169Scy shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec; 443285169Scy shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000; 444285169Scy rns_new = shmcopy.receiveTimeStampNSec; 445285169Scy shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec; 446285169Scy shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000; 447285169Scy cns_new = shmcopy.clockTimeStampNSec; 448285169Scy 449285169Scy /* Since the following comparisons are between unsigned 450285169Scy ** variables they are always well defined, and any 451285169Scy ** (signed) underflow will turn into very large unsigned 452285169Scy ** values, well above the 1000 cutoff. 453285169Scy ** 454285169Scy ** Note: The usecs *must* be a *truncated* 455285169Scy ** representation of the nsecs. This code will fail for 456285169Scy ** *rounded* usecs, and the logic to deal with 457285169Scy ** wrap-arounds in the presence of rounded values is 458285169Scy ** much more convoluted. 459285169Scy */ 460285169Scy if ( ((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000) 461285169Scy && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) { 462285169Scy shm_stat->tvt.tv_nsec = cns_new; 463285169Scy shm_stat->tvr.tv_nsec = rns_new; 464285169Scy } 465285169Scy /* At this point shm_stat->tvr and shm_stat->tvt contain valid ns-level 466285169Scy ** timestamps, possibly generated by extending the old 467285169Scy ** us-level timestamps 468285169Scy */ 469285169Scy break; 470285169Scy 471285169Scy case 1: 472285169Scy 473285169Scy shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec; 474285169Scy shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000; 475285169Scy rns_new = shmcopy.receiveTimeStampNSec; 476285169Scy shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec; 477285169Scy shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000; 478285169Scy cns_new = shmcopy.clockTimeStampNSec; 479285169Scy 480285169Scy /* See the case above for an explanation of the 481285169Scy ** following test. 482285169Scy */ 483285169Scy if ( ((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000) 484285169Scy && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) { 485285169Scy shm_stat->tvt.tv_nsec = cns_new; 486285169Scy shm_stat->tvr.tv_nsec = rns_new; 487285169Scy } 488285169Scy /* At this point shm_stat->tvr and shm_stat->tvt contains valid ns-level 489285169Scy ** timestamps, possibly generated by extending the old 490285169Scy ** us-level timestamps 491285169Scy */ 492285169Scy break; 493285169Scy 494285169Scy default: 495285169Scy shm_stat->status = BAD_MODE; 496285169Scy break; 497285169Scy } 498285169Scy /*@-type@*/ 499285169Scy 500285169Scy /* 501285169Scy * leap field is not a leap offset but a leap notification code. 502285169Scy * The values are magic numbers used by NTP and set by GPSD, if at all, in 503285169Scy * the subframe code. 504285169Scy */ 505285169Scy shm_stat->leap = shmcopy.leap; 506285169Scy shm_stat->precision = shmcopy.precision; 507285169Scy 508285169Scy return shm_stat->status; 509285169Scy} 510285169Scy 511280849Scy/* 512285169Scy * shm_timer - called once every second. 513280849Scy * 514285169Scy * This tries to grab a sample from the SHM segment, filtering bad ones 515280849Scy */ 516280849Scystatic void 517280849Scyshm_timer( 518280849Scy int unit, 519280849Scy struct peer *peer 520280849Scy ) 521280849Scy{ 522280849Scy struct refclockproc * const pp = peer->procptr; 523280849Scy struct shmunit * const up = pp->unitptr; 524280849Scy 525280849Scy volatile struct shmTime *shm; 526280849Scy 527280849Scy l_fp tsrcv; 528280849Scy l_fp tsref; 529285169Scy int c; 530280849Scy 531280849Scy /* for formatting 'a_lastcode': */ 532280849Scy struct calendar cd; 533285169Scy time_t tt; 534280849Scy vint64 ts; 535280849Scy 536285169Scy enum segstat_t status; 537285169Scy struct shm_stat_t shm_stat; 538285169Scy 539280849Scy up->ticks++; 540280849Scy if ((shm = up->shm) == NULL) { 541280849Scy /* try to map again - this may succeed if meanwhile some- 542280849Scy body has ipcrm'ed the old (unaccessible) shared mem segment */ 543280849Scy shm = up->shm = getShmTime(unit, up->forall); 544280849Scy if (shm == NULL) { 545280849Scy DPRINTF(1, ("%s: no SHM segment\n", 546280849Scy refnumtoa(&peer->srcadr))); 547280849Scy return; 548280849Scy } 54954359Sroberto } 550280849Scy 551285169Scy /* query the segment, atomically */ 552285169Scy status = shm_query(shm, &shm_stat); 553280849Scy 554285169Scy switch (status) { 555285169Scy case OK: 556285169Scy DPRINTF(2, ("%s: SHM type %d sample\n", 557285169Scy refnumtoa(&peer->srcadr), shm_stat.mode)); 558285169Scy break; 559285169Scy case NO_SEGMENT: 560285169Scy /* should never happen, but is harmless */ 561285169Scy return; 562285169Scy case NOT_READY: 563285169Scy DPRINTF(1, ("%s: SHM not ready\n",refnumtoa(&peer->srcadr))); 564285169Scy up->notready++; 565285169Scy return; 566285169Scy case BAD_MODE: 567285169Scy DPRINTF(1, ("%s: SHM type blooper, mode=%d\n", 568285169Scy refnumtoa(&peer->srcadr), shm->mode)); 569285169Scy up->bad++; 570285169Scy msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d", 571285169Scy shm->mode); 572285169Scy return; 573285169Scy case CLASH: 574285169Scy DPRINTF(1, ("%s: type 1 access clash\n", 575285169Scy refnumtoa(&peer->srcadr))); 576285169Scy msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); 577285169Scy up->clash++; 578285169Scy return; 579280849Scy default: 580285169Scy DPRINTF(1, ("%s: internal error, unknown SHM fetch status\n", 581285169Scy refnumtoa(&peer->srcadr))); 582285169Scy msyslog (LOG_NOTICE, "internal error, unknown SHM fetch status"); 583285169Scy up->bad++; 584285169Scy return; 58554359Sroberto } 586280849Scy 587285169Scy 588280849Scy /* format the last time code in human-readable form into 589280849Scy * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible 590280849Scy * tv_sec". I can't find a base for this claim, but we can work 591280849Scy * around that potential problem. BTW, simply casting a pointer 592280849Scy * is a receipe for disaster on some architectures. 593280849Scy */ 594285169Scy tt = (time_t)shm_stat.tvt.tv_sec; 595280849Scy ts = time_to_vint64(&tt); 596280849Scy ntpcal_time_to_date(&cd, &ts); 597280849Scy 598280849Scy /* add ntpq -c cv timecode in ISO 8601 format */ 599280849Scy c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 600280849Scy "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ", 601280849Scy cd.year, cd.month, cd.monthday, 602280849Scy cd.hour, cd.minute, cd.second, 603285169Scy (long)shm_stat.tvt.tv_nsec); 604294554Sdelphij pp->lencode = (c > 0 && (size_t)c < sizeof(pp->a_lastcode)) ? c : 0; 605280849Scy 606280849Scy /* check 1: age control of local time stamp */ 607285169Scy tt = shm_stat.tvc.tv_sec - shm_stat.tvr.tv_sec; 608280849Scy if (tt < 0 || tt > up->max_delay) { 609280849Scy DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n", 610280849Scy refnumtoa(&peer->srcadr), (long long)tt)); 611280849Scy up->bad++; 612280849Scy msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds", 613280849Scy (long long)tt); 61454359Sroberto return; 61554359Sroberto } 616280849Scy 617280849Scy /* check 2: delta check */ 618285169Scy tt = shm_stat.tvr.tv_sec - shm_stat.tvt.tv_sec - (shm_stat.tvr.tv_nsec < shm_stat.tvt.tv_nsec); 619280849Scy if (tt < 0) 620280849Scy tt = -tt; 621280849Scy if (up->max_delta > 0 && tt > up->max_delta) { 622280849Scy DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n", 623280849Scy refnumtoa(&peer->srcadr), (long long)tt)); 624280849Scy up->bad++; 625280849Scy msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n", 626280849Scy (long long)tt); 627280849Scy return; 628280849Scy } 629280849Scy 630280849Scy /* if we really made it to this point... we're winners! */ 631280849Scy DPRINTF(2, ("%s: SHM feeding data\n", 632280849Scy refnumtoa(&peer->srcadr))); 633285169Scy tsrcv = tspec_stamp_to_lfp(shm_stat.tvr); 634285169Scy tsref = tspec_stamp_to_lfp(shm_stat.tvt); 635285169Scy pp->leap = shm_stat.leap; 636285169Scy peer->precision = shm_stat.precision; 637280849Scy refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1); 638280849Scy up->good++; 63954359Sroberto} 64054359Sroberto 641280849Scy/* 642280849Scy * shm_clockstats - dump and reset counters 643280849Scy */ 644280849Scystatic void shm_clockstats( 645280849Scy int unit, 646280849Scy struct peer *peer 647280849Scy ) 648280849Scy{ 649280849Scy struct refclockproc * const pp = peer->procptr; 650280849Scy struct shmunit * const up = pp->unitptr; 651280849Scy 652280849Scy UNUSED_ARG(unit); 653280849Scy if (pp->sloppyclockflag & CLK_FLAG4) { 654280849Scy mprintf_clock_stats( 655280849Scy &peer->srcadr, "%3d %3d %3d %3d %3d", 656280849Scy up->ticks, up->good, up->notready, 657280849Scy up->bad, up->clash); 658280849Scy } 659280849Scy up->ticks = up->good = up->notready = up->bad = up->clash = 0; 660280849Scy} 661280849Scy 66254359Sroberto#else 663280849ScyNONEMPTY_TRANSLATION_UNIT 66454359Sroberto#endif /* REFCLOCK */ 665