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