xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_clockdev.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: ntp_clockdev.c,v 1.2 2024/08/18 20:47:17 christos Exp $	*/
2897be3a4Schristos 
3897be3a4Schristos /* ntp_clockdev.c - map clock instances to devices
4897be3a4Schristos  *
5897be3a4Schristos  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
6897be3a4Schristos  * The contents of 'html/copyright.html' apply.
7897be3a4Schristos  * ---------------------------------------------------------------------
8897be3a4Schristos  * The runtime support for the 'device' configuration statement.  Just a
9897be3a4Schristos  * simple list to map refclock source addresses to the device(s) to use
10897be3a4Schristos  * instead of the builtin names.
11897be3a4Schristos  * ---------------------------------------------------------------------
12897be3a4Schristos  */
13897be3a4Schristos 
14897be3a4Schristos #ifdef HAVE_CONFIG_H
15897be3a4Schristos # include <config.h>
16897be3a4Schristos #endif
17897be3a4Schristos 
18897be3a4Schristos #ifdef HAVE_NETINFO
19897be3a4Schristos # include <netinfo/ni.h>
20897be3a4Schristos #endif
21897be3a4Schristos 
22897be3a4Schristos #include <stdio.h>
23897be3a4Schristos #include <isc/net.h>
24897be3a4Schristos 
25897be3a4Schristos #include "ntp.h"
26897be3a4Schristos #include "ntpd.h"
27897be3a4Schristos #include "ntp_clockdev.h"
28897be3a4Schristos 
29897be3a4Schristos /* In the windows port 'refclock_open' is in 'libntp' (windows specific
30897be3a4Schristos  * 'termios.c' source) and calling a function located in NTPD from the
31897be3a4Schristos  * library is not something we should do.  Therefore 'termios.c' now
32897be3a4Schristos  * provides a hook to set a callback function used for the lookup, and
33897be3a4Schristos  * we have to populate that when we have indeed device name
34897be3a4Schristos  * redirections...
35897be3a4Schristos  */
36897be3a4Schristos #ifdef SYS_WINNT
37897be3a4Schristos extern const char * (*termios_device_lookup_func)(const sockaddr_u*, int);
38897be3a4Schristos #endif
39897be3a4Schristos 
40897be3a4Schristos /* What we remember for a device redirection */
41897be3a4Schristos typedef struct DeviceInfoS DeviceInfoT;
42897be3a4Schristos struct DeviceInfoS {
43897be3a4Schristos 	DeviceInfoT *next;	/* link to next record		*/
44897be3a4Schristos 	int	     ident;	/* type (byte1) and unit (byte0)*/
45897be3a4Schristos 	char	    *ttyName;	/* time data IO device		*/
46897be3a4Schristos 	char	    *ppsName;	/* PPS device			*/
47897be3a4Schristos };
48897be3a4Schristos 
49897be3a4Schristos /* Our list of device redirections: */
50897be3a4Schristos static DeviceInfoT * InfoList = NULL;
51897be3a4Schristos 
52897be3a4Schristos /* Free a single record: */
53897be3a4Schristos static void freeDeviceInfo(
54897be3a4Schristos 	DeviceInfoT *item
55897be3a4Schristos 	)
56897be3a4Schristos {
57897be3a4Schristos 	if (NULL != item) {
58897be3a4Schristos 		free(item->ttyName);
59897be3a4Schristos 		free(item->ppsName);
60897be3a4Schristos 		free(item);
61897be3a4Schristos 	}
62897be3a4Schristos }
63897be3a4Schristos 
64897be3a4Schristos /* Get clock ID from pseudo network address. Returns -1 on error. */
65897be3a4Schristos static int
66897be3a4Schristos getClockIdent(
67897be3a4Schristos 	const sockaddr_u *srcadr
68897be3a4Schristos 	)
69897be3a4Schristos {
70897be3a4Schristos 	int clkType, clkUnit;
71897be3a4Schristos 
72897be3a4Schristos 	/*
73897be3a4Schristos 	 * Check for valid address and running peer
74897be3a4Schristos 	 */
75897be3a4Schristos 	if (!ISREFCLOCKADR(srcadr))
76897be3a4Schristos 		return -1;
77897be3a4Schristos 
78897be3a4Schristos 	clkType = REFCLOCKTYPE(srcadr);
79897be3a4Schristos 	clkUnit = REFCLOCKUNIT(srcadr);
80897be3a4Schristos 	return (clkType << 8) + clkUnit;
81897be3a4Schristos }
82897be3a4Schristos 
83897be3a4Schristos /* Purge the complete redirection list. */
84897be3a4Schristos void
85897be3a4Schristos clockdev_clear(void)
86897be3a4Schristos {
87897be3a4Schristos 	DeviceInfoT * item;
88897be3a4Schristos 	while (NULL != (item = InfoList)) {
89897be3a4Schristos 		InfoList = item->next;
90897be3a4Schristos 		freeDeviceInfo(item);
91897be3a4Schristos 	}
92897be3a4Schristos }
93897be3a4Schristos 
94897be3a4Schristos /* Remove record(s) for a clock.
95897be3a4Schristos  * returns number of removed records (maybe zero) or -1 on error
96897be3a4Schristos  */
97897be3a4Schristos int
98897be3a4Schristos clockdev_remove(
99897be3a4Schristos 	const sockaddr_u *addr_sock
100897be3a4Schristos 	)
101897be3a4Schristos {
102897be3a4Schristos 	DeviceInfoT *item, **ppl;
103897be3a4Schristos 	int	     rcnt  = 0;
104897be3a4Schristos 	const int    ident = getClockIdent(addr_sock);
105897be3a4Schristos 
106897be3a4Schristos 	if (ident < 0)
107897be3a4Schristos 		return -1;
108897be3a4Schristos 
109897be3a4Schristos 	ppl = &InfoList;
110897be3a4Schristos 	while (NULL != (item = *ppl)) {
111897be3a4Schristos 		if (ident == item->ident) {
112897be3a4Schristos 			*ppl = item->next;
113897be3a4Schristos 			freeDeviceInfo(item);
114897be3a4Schristos 			++rcnt;
115897be3a4Schristos 		} else {
116897be3a4Schristos 			ppl = &item->next;
117897be3a4Schristos 		}
118897be3a4Schristos 	}
119897be3a4Schristos 	return rcnt;
120897be3a4Schristos }
121897be3a4Schristos 
122897be3a4Schristos /* Update or create a redirection record for a clock instace */
123897be3a4Schristos int /*error*/
124897be3a4Schristos clockdev_update(
125897be3a4Schristos 	const sockaddr_u *addr_sock,
126897be3a4Schristos 	const char	 *ttyName,
127897be3a4Schristos 	const char	 *ppsName
128897be3a4Schristos 	)
129897be3a4Schristos {
130897be3a4Schristos 	DeviceInfoT *item;
131897be3a4Schristos 	const int   ident = getClockIdent(addr_sock);
132897be3a4Schristos 	if (ident < 0)
133897be3a4Schristos 		return EINVAL;
134897be3a4Schristos 
135897be3a4Schristos 	/* make sure Windows can use device redirections, too: */
136897be3a4Schristos #   ifdef SYS_WINNT
137897be3a4Schristos 	termios_device_lookup_func = clockdev_lookup;
138897be3a4Schristos #   endif
139897be3a4Schristos 
140897be3a4Schristos 	/* try to update an existing record */
141897be3a4Schristos 	for (item = InfoList;  NULL != item;  item = item->next)
142897be3a4Schristos 		if (ident == item->ident) {
143897be3a4Schristos 			msyslog(LOG_INFO, "Update IO devices for %s: timedata='%s' ppsdata='%s'",
144897be3a4Schristos 				refnumtoa(addr_sock),
145897be3a4Schristos 				ttyName ? ttyName : "(null)",
146897be3a4Schristos 				ppsName ? ppsName : "(null)");
147897be3a4Schristos 			free(item->ttyName);
148897be3a4Schristos 			free(item->ppsName);
149897be3a4Schristos 			item->ttyName = ttyName ? estrdup(ttyName) : NULL;
150897be3a4Schristos 			item->ppsName = ppsName ? estrdup(ppsName) : NULL;
151897be3a4Schristos 			return 0;
152897be3a4Schristos 		}
153897be3a4Schristos 
154897be3a4Schristos 	/* seems we have to create a new entry... */
155897be3a4Schristos 	msyslog(LOG_INFO, "Add IO devices for %s: timedata='%s' ppsdata='%s'",
156897be3a4Schristos 		refnumtoa(addr_sock),
157897be3a4Schristos 		ttyName ? ttyName : "(null)",
158897be3a4Schristos 		ppsName ? ppsName : "(null)");
159897be3a4Schristos 
160897be3a4Schristos 	item = emalloc(sizeof(*item));
161897be3a4Schristos 	item->next    = InfoList;
162897be3a4Schristos 	item->ident   = ident;
163897be3a4Schristos 	item->ttyName = ttyName ? estrdup(ttyName) : NULL;
164897be3a4Schristos 	item->ppsName = ppsName ? estrdup(ppsName) : NULL;
165897be3a4Schristos 	InfoList = item;
166897be3a4Schristos 	return 0;
167897be3a4Schristos }
168897be3a4Schristos 
169897be3a4Schristos /* Lookup a redirection for a clock instance. Returns either the name
170897be3a4Schristos  * registered for the device or NULL if no redirection is found.
171897be3a4Schristos  */
172897be3a4Schristos const char*
173897be3a4Schristos clockdev_lookup(
174897be3a4Schristos 	const sockaddr_u *addr_sock,
175897be3a4Schristos 	int		  getPPS
176897be3a4Schristos 	)
177897be3a4Schristos {
178897be3a4Schristos 	const DeviceInfoT *item;
179897be3a4Schristos 	const int	  ident = getClockIdent(addr_sock);
180897be3a4Schristos 
181897be3a4Schristos 	if (ident < 0)
182897be3a4Schristos 		return NULL;
183897be3a4Schristos 
184897be3a4Schristos 	for (item = InfoList;  NULL != item;  item = item->next)
185897be3a4Schristos 		if (ident == item->ident)
186897be3a4Schristos 			return getPPS ? item->ppsName : item->ttyName;
187897be3a4Schristos 
188897be3a4Schristos 	return NULL;
189897be3a4Schristos }
190