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: */ 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 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 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 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*/ 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* 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