/* ntp_clockdev.c - map clock instances to devices * * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. * The contents of 'html/copyright.html' apply. * --------------------------------------------------------------------- * The runtime support for the 'device' configuration statement. Just a * simple list to map refclock source addresses to the device(s) to use * instead of the builtin names. * --------------------------------------------------------------------- */ #ifdef HAVE_CONFIG_H # include #endif #ifdef HAVE_NETINFO # include #endif #include #include #include "ntp.h" #include "ntpd.h" #include "ntp_clockdev.h" /* In the windows port 'refclock_open' is in 'libntp' (windows specific * 'termios.c' source) and calling a function located in NTPD from the * library is not something we should do. Therefore 'termios.c' now * provides a hook to set a callback function used for the lookup, and * we have to populate that when we have indeed device name * redirections... */ #ifdef SYS_WINNT extern const char * (*termios_device_lookup_func)(const sockaddr_u*, int); #endif /* What we remember for a device redirection */ typedef struct DeviceInfoS DeviceInfoT; struct DeviceInfoS { DeviceInfoT *next; /* link to next record */ int ident; /* type (byte1) and unit (byte0)*/ char *ttyName; /* time data IO device */ char *ppsName; /* PPS device */ }; /* Our list of device redirections: */ static DeviceInfoT * InfoList = NULL; /* Free a single record: */ static void freeDeviceInfo( DeviceInfoT *item ) { if (NULL != item) { free(item->ttyName); free(item->ppsName); free(item); } } /* Get clock ID from pseudo network address. Returns -1 on error. */ static int getClockIdent( const sockaddr_u *srcadr ) { int clkType, clkUnit; /* * Check for valid address and running peer */ if (!ISREFCLOCKADR(srcadr)) return -1; clkType = REFCLOCKTYPE(srcadr); clkUnit = REFCLOCKUNIT(srcadr); return (clkType << 8) + clkUnit; } /* Purge the complete redirection list. */ void clockdev_clear(void) { DeviceInfoT * item; while (NULL != (item = InfoList)) { InfoList = item->next; freeDeviceInfo(item); } } /* Remove record(s) for a clock. * returns number of removed records (maybe zero) or -1 on error */ int clockdev_remove( const sockaddr_u *addr_sock ) { DeviceInfoT *item, **ppl; int rcnt = 0; const int ident = getClockIdent(addr_sock); if (ident < 0) return -1; ppl = &InfoList; while (NULL != (item = *ppl)) { if (ident == item->ident) { *ppl = item->next; freeDeviceInfo(item); ++rcnt; } else { ppl = &item->next; } } return rcnt; } /* Update or create a redirection record for a clock instace */ int /*error*/ clockdev_update( const sockaddr_u *addr_sock, const char *ttyName, const char *ppsName ) { DeviceInfoT *item; const int ident = getClockIdent(addr_sock); if (ident < 0) return EINVAL; /* make sure Windows can use device redirections, too: */ # ifdef SYS_WINNT termios_device_lookup_func = clockdev_lookup; # endif /* try to update an existing record */ for (item = InfoList; NULL != item; item = item->next) if (ident == item->ident) { msyslog(LOG_INFO, "Update IO devices for %s: timedata='%s' ppsdata='%s'", refnumtoa(addr_sock), ttyName ? ttyName : "(null)", ppsName ? ppsName : "(null)"); free(item->ttyName); free(item->ppsName); item->ttyName = ttyName ? estrdup(ttyName) : NULL; item->ppsName = ppsName ? estrdup(ppsName) : NULL; return 0; } /* seems we have to create a new entry... */ msyslog(LOG_INFO, "Add IO devices for %s: timedata='%s' ppsdata='%s'", refnumtoa(addr_sock), ttyName ? ttyName : "(null)", ppsName ? ppsName : "(null)"); item = emalloc(sizeof(*item)); item->next = InfoList; item->ident = ident; item->ttyName = ttyName ? estrdup(ttyName) : NULL; item->ppsName = ppsName ? estrdup(ppsName) : NULL; InfoList = item; return 0; } /* Lookup a redirection for a clock instance. Returns either the name * registered for the device or NULL if no redirection is found. */ const char* clockdev_lookup( const sockaddr_u *addr_sock, int getPPS ) { const DeviceInfoT *item; const int ident = getClockIdent(addr_sock); if (ident < 0) return NULL; for (item = InfoList; NULL != item; item = item->next) if (ident == item->ident) return getPPS ? item->ppsName : item->ttyName; return NULL; }