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