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