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