xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_clockdev.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
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@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