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: */
freeDeviceInfo(DeviceInfoT * item)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
getClockIdent(const sockaddr_u * srcadr)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
clockdev_clear(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
clockdev_remove(const sockaddr_u * addr_sock)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*/
clockdev_update(const sockaddr_u * addr_sock,const char * ttyName,const char * ppsName)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*
clockdev_lookup(const sockaddr_u * addr_sock,int getPPS)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