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