Home | History | Annotate | Line # | Download | only in ntpd
      1 /*	$NetBSD: ntp_clockdev.c,v 1.2 2024/08/18 20:47:17 christos Exp $	*/
      2 
      3 /* ntp_clockdev.c - map clock instances to devices
      4  *
      5  * Written by Juergen Perlinger (perlinger (at) ntp.org) for the NTP project.
      6  * The contents of 'html/copyright.html' apply.
      7  * ---------------------------------------------------------------------
      8  * The runtime support for the 'device' configuration statement.  Just a
      9  * simple list to map refclock source addresses to the device(s) to use
     10  * instead of the builtin names.
     11  * ---------------------------------------------------------------------
     12  */
     13 
     14 #ifdef HAVE_CONFIG_H
     15 # include <config.h>
     16 #endif
     17 
     18 #ifdef HAVE_NETINFO
     19 # include <netinfo/ni.h>
     20 #endif
     21 
     22 #include <stdio.h>
     23 #include <isc/net.h>
     24 
     25 #include "ntp.h"
     26 #include "ntpd.h"
     27 #include "ntp_clockdev.h"
     28 
     29 /* In the windows port 'refclock_open' is in 'libntp' (windows specific
     30  * 'termios.c' source) and calling a function located in NTPD from the
     31  * library is not something we should do.  Therefore 'termios.c' now
     32  * provides a hook to set a callback function used for the lookup, and
     33  * we have to populate that when we have indeed device name
     34  * redirections...
     35  */
     36 #ifdef SYS_WINNT
     37 extern const char * (*termios_device_lookup_func)(const sockaddr_u*, int);
     38 #endif
     39 
     40 /* What we remember for a device redirection */
     41 typedef struct DeviceInfoS DeviceInfoT;
     42 struct DeviceInfoS {
     43 	DeviceInfoT *next;	/* link to next record		*/
     44 	int	     ident;	/* type (byte1) and unit (byte0)*/
     45 	char	    *ttyName;	/* time data IO device		*/
     46 	char	    *ppsName;	/* PPS device			*/
     47 };
     48 
     49 /* Our list of device redirections: */
     50 static DeviceInfoT * InfoList = NULL;
     51 
     52 /* Free a single record: */
     53 static void freeDeviceInfo(
     54 	DeviceInfoT *item
     55 	)
     56 {
     57 	if (NULL != item) {
     58 		free(item->ttyName);
     59 		free(item->ppsName);
     60 		free(item);
     61 	}
     62 }
     63 
     64 /* Get clock ID from pseudo network address. Returns -1 on error. */
     65 static int
     66 getClockIdent(
     67 	const sockaddr_u *srcadr
     68 	)
     69 {
     70 	int clkType, clkUnit;
     71 
     72 	/*
     73 	 * Check for valid address and running peer
     74 	 */
     75 	if (!ISREFCLOCKADR(srcadr))
     76 		return -1;
     77 
     78 	clkType = REFCLOCKTYPE(srcadr);
     79 	clkUnit = REFCLOCKUNIT(srcadr);
     80 	return (clkType << 8) + clkUnit;
     81 }
     82 
     83 /* Purge the complete redirection list. */
     84 void
     85 clockdev_clear(void)
     86 {
     87 	DeviceInfoT * item;
     88 	while (NULL != (item = InfoList)) {
     89 		InfoList = item->next;
     90 		freeDeviceInfo(item);
     91 	}
     92 }
     93 
     94 /* Remove record(s) for a clock.
     95  * returns number of removed records (maybe zero) or -1 on error
     96  */
     97 int
     98 clockdev_remove(
     99 	const sockaddr_u *addr_sock
    100 	)
    101 {
    102 	DeviceInfoT *item, **ppl;
    103 	int	     rcnt  = 0;
    104 	const int    ident = getClockIdent(addr_sock);
    105 
    106 	if (ident < 0)
    107 		return -1;
    108 
    109 	ppl = &InfoList;
    110 	while (NULL != (item = *ppl)) {
    111 		if (ident == item->ident) {
    112 			*ppl = item->next;
    113 			freeDeviceInfo(item);
    114 			++rcnt;
    115 		} else {
    116 			ppl = &item->next;
    117 		}
    118 	}
    119 	return rcnt;
    120 }
    121 
    122 /* Update or create a redirection record for a clock instace */
    123 int /*error*/
    124 clockdev_update(
    125 	const sockaddr_u *addr_sock,
    126 	const char	 *ttyName,
    127 	const char	 *ppsName
    128 	)
    129 {
    130 	DeviceInfoT *item;
    131 	const int   ident = getClockIdent(addr_sock);
    132 	if (ident < 0)
    133 		return EINVAL;
    134 
    135 	/* make sure Windows can use device redirections, too: */
    136 #   ifdef SYS_WINNT
    137 	termios_device_lookup_func = clockdev_lookup;
    138 #   endif
    139 
    140 	/* try to update an existing record */
    141 	for (item = InfoList;  NULL != item;  item = item->next)
    142 		if (ident == item->ident) {
    143 			msyslog(LOG_INFO, "Update IO devices for %s: timedata='%s' ppsdata='%s'",
    144 				refnumtoa(addr_sock),
    145 				ttyName ? ttyName : "(null)",
    146 				ppsName ? ppsName : "(null)");
    147 			free(item->ttyName);
    148 			free(item->ppsName);
    149 			item->ttyName = ttyName ? estrdup(ttyName) : NULL;
    150 			item->ppsName = ppsName ? estrdup(ppsName) : NULL;
    151 			return 0;
    152 		}
    153 
    154 	/* seems we have to create a new entry... */
    155 	msyslog(LOG_INFO, "Add IO devices for %s: timedata='%s' ppsdata='%s'",
    156 		refnumtoa(addr_sock),
    157 		ttyName ? ttyName : "(null)",
    158 		ppsName ? ppsName : "(null)");
    159 
    160 	item = emalloc(sizeof(*item));
    161 	item->next    = InfoList;
    162 	item->ident   = ident;
    163 	item->ttyName = ttyName ? estrdup(ttyName) : NULL;
    164 	item->ppsName = ppsName ? estrdup(ppsName) : NULL;
    165 	InfoList = item;
    166 	return 0;
    167 }
    168 
    169 /* Lookup a redirection for a clock instance. Returns either the name
    170  * registered for the device or NULL if no redirection is found.
    171  */
    172 const char*
    173 clockdev_lookup(
    174 	const sockaddr_u *addr_sock,
    175 	int		  getPPS
    176 	)
    177 {
    178 	const DeviceInfoT *item;
    179 	const int	  ident = getClockIdent(addr_sock);
    180 
    181 	if (ident < 0)
    182 		return NULL;
    183 
    184 	for (item = InfoList;  NULL != item;  item = item->next)
    185 		if (ident == item->ident)
    186 			return getPPS ? item->ppsName : item->ttyName;
    187 
    188 	return NULL;
    189 }
    190