ntp_control.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 1996 by Sun Microsystems, Inc.
* All Rights Reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ntp_control.c - respond to control messages and send async traps
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_control.h"
#include "ntp_stdlib.h"
/*
* Structure to hold request procedure information
*/
#define NOAUTH 0
#define AUTH 1
#define NO_REQUEST (-1)
#define LOG_INTERVAL_SECS 60
#define LOG_MSGS_PER_INTERVAL 5
struct ctl_proc {
short control_code; /* defined request code */
void (*handler) /* routine to handle request */
P((struct recvbuf *, int));
};
/*
* Only one flag. Authentication required or not.
*/
#define NOAUTH 0
#define AUTH 1
/*
* Request processing routines
*/
static void ctl_error P((int));
static void ctl_flushpkt P((int));
static void ctl_putdata P((const char *, int, int));
static void ctl_putstr P((const char *, const char *, int));
static void ctl_putlfp P((const char *, l_fp *));
static void ctl_putufp P((const char *, u_fp));
static void ctl_putuint P((const char *, u_long));
static void ctl_puthex P((const char *, u_long));
static void ctl_putint P((const char *, long));
static void ctl_putadr P((const char *, u_int32));
static void ctl_putid P((const char *, char *));
static void ctl_putarray P((const char *, s_fp *, int));
static void ctl_putsys P((int));
static void ctl_putpeer P((int, struct peer *));
#ifdef REFCLOCK
static void ctl_putclock P((int, struct refclockstat *, int));
#endif /* REFCLOCK */
static void control_unspec P((struct recvbuf *, int));
static void read_status P((struct recvbuf *, int));
static void read_variables P((struct recvbuf *, int));
static void write_variables P((struct recvbuf *, int));
static void read_clock_status P((struct recvbuf *, int));
static void write_clock_status P((struct recvbuf *, int));
static void unset_trap P((struct recvbuf *, int));
static struct ctl_proc control_codes[] = {
{ NO_REQUEST, 0 }
};
/*
* System variable values. The array can be indexed by
* the variable index to find the textual name.
*/
{ 0, EOV, "" }
};
/*
* System variables we print by default (in fuzzball order, more-or-less)
*/
static u_char def_sys_var[] = {
0
};
/*
* Peer variable list
*/
{ 0, EOV, "" }
};
/*
* Peer variables we print by default
*/
static u_char def_peer_var[] = {
0
};
#ifdef REFCLOCK
/*
* Clock variable list
*/
{ 0, EOV, "" }
};
/*
* Clock variables printed by default
*/
static u_char def_clock_var[] = {
CC_TYPE, /* won't be output if device= known */
0
};
#endif
/*
* System and processor definitions. These will change for the gizmo board.
*/
#ifndef HAVE_UNAME
# ifndef STR_SYSTEM
# define STR_SYSTEM "UNIX"
# endif
# ifndef STR_PROCESSOR
# define STR_PROCESSOR "unknown"
# endif
static char str_system[] = STR_SYSTEM;
static char str_processor[] = STR_PROCESSOR;
#else
static struct utsname utsnamebuf;
#endif /* HAVE_UNAME */
/*
* Trap structures. We only allow a few of these, and send
* a copy of each async message to each live one. Traps time
* out after an hour, it is up to the trap receipient to
* keep resetting it to avoid being timed out.
*/
/* ntp_request.c */
int num_ctl_traps;
/*
* Type bits, for ctlsettrap() call.
*/
#define TRAP_TYPE_CONFIG 0 /* used by configuration code */
/*
* List relating reference clock types to control message time sources.
* Index by the reference clock type.
* This list will only be used iff the reference clock driver doesn't
* set peer->sstclktype to something different than CTL_SST_TS_UNSPEC.
*/
static u_char clocktypes[] = {
CTL_SST_TS_NTP, /* REFCLK_NONE (0) */
CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */
CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK (2) */
CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */
CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */
CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */
CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) */
CTL_SST_TS_HF, /* REFCLK_CHU (7) */
CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */
CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */
CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */
CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */
CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */
CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */
CTL_SST_TS_LF, /* REFCLK_MSF_EES (14) */
CTL_SST_TS_UHF, /* REFCLK_TRUETIME (15) */
CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */
CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */
CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */
CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */
CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */
CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */
CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */
CTL_SST_TS_TELEPHONE, /* REFCLK_PTB_ACTS (23) */
CTL_SST_TS_TELEPHONE, /* REFCLK_USNO (24) */
CTL_SST_TS_UHF, /* REFCLK_TRUETIME (25) */
CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */
CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */
CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */
CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */
CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */
CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */
};
/*
* Keyid used for authenticating write requests.
*/
/*
* We keep track of the last error reported by the system internally
*/
static u_char ctl_sys_last_event;
static u_char ctl_sys_num_events;
/*
* Statistic counters to keep track of requests and responses.
*/
/*
* Imported from the I/O module
*/
extern struct interface *any_interface;
/*
* Imported from the main routines
*/
extern int debug;
/*
* Imported from the timer module
*/
extern u_long current_time;
extern struct peer *assoc_hash[];
extern int pps_control; /* flag for 1-pps signal present */
/*
* Importations from the protocol module
*/
extern u_char sys_stratum;
extern s_char sys_precision;
extern s_fp sys_rootdelay;
extern u_fp sys_rootdispersion;
extern l_fp sys_reftime;
extern l_fp sys_refskew;
/*
* Imported from the loop filter module
*/
extern l_fp last_offset;
extern s_fp drift_comp;
extern int pll_control;
/*
* Imported from the leap module
*/
extern u_char leap_indicator;
extern u_char leap_warning;
/*
* Response packet used by these routines. Also some state information
* so that we can handle packet formatting within a common set of
* subroutines. Note we try to enter data in place whenever possible,
* but the need to set the more bit correctly means we occasionally
* use the extra buffer and copy.
*/
static struct ntp_control rpkt;
static u_char res_version;
static u_char res_opcode;
static u_short res_associd;
static int res_offset;
static int datalinelen;
static int datanotbinflag;
static struct sockaddr_in *rmt_addr;
static u_char res_authenticate;
static u_char res_authokay;
#define MAXDATALINELEN (72)
/*
* Pointers for saving state when decoding request packets
*/
static char *reqpt;
static char *reqend;
/*
* init_control - initialize request data
*/
void
{
int i;
#ifdef HAVE_UNAME
uname(&utsnamebuf);
#endif /* HAVE_UNAME */
ctl_auth_keyid = 0;
ctl_sys_num_events = 0;
num_ctl_traps = 0;
for (i = 0; i < CTL_MAXTRAPS; i++)
}
/*
* ctl_error - send an error response for the current request
*/
static void
int errcode;
{
#ifdef DEBUG
if (debug >= 4)
#endif
/*
* fill in the fields. We assume rpkt.sequence and rpkt.associd
* have already been filled in.
*/
/*
* send packet and bump counters
*/
if (res_authenticate) {
int maclen;
maclen =
CTL_HEADER_LEN + maclen);
} else {
}
numctlerrors++;
}
/*
* process_control - process an incoming control message
*/
void
int restrict_mask;
{
register struct ntp_control *pkt;
register int req_count;
register int req_data;
int properlen;
int maclen;
#ifdef DEBUG
if (debug)
printf("in process_control()\n");
#endif
/*
* Save the addresses for error responses
*/
numctlreq++;
/*
* If the length is less than required for the header, or
* it is a response or a fragment, ignore this.
*/
#ifdef DEBUG
if (debug)
printf("invalid format in control packet\n");
#endif
return;
}
#ifdef DEBUG
if (debug)
printf("unknown version %d in control packet\n",
#endif
return;
}
/*
* Pull enough data from the packet to make intelligent responses
*/
res_offset = 0;
res_async = 0;
res_authenticate = 0;
res_keyid = 0;
res_authokay = 0;
datanotbinflag = 0;
datalinelen = 0;
/*
* We're set up now. Make sure we've got at least
* enough incoming data space to match the count.
*/
return;
}
#ifdef DEBUG
#endif
/* round up proper len to a 8 octet boundary */
&& maclen <= MAX_MAC_LEN) {
res_authenticate = 1;
#ifdef DEBUG
if (debug >= 3)
"recv_len %d, properlen %d, wants auth with keyid %ld, MAC length=%d\n",
#endif
if (!authhavekey(res_keyid)) {
#ifdef DEBUG
if (debug >= 2)
#endif
#ifdef DEBUG
if (debug >= 3)
printf("authenticated okay\n");
#endif
res_authokay = 1;
} else {
#ifdef DEBUG
if (debug >= 3)
printf("authentication failed\n");
#endif
res_keyid = 0;
}
}
/*
* Set up translate pointers
*/
/*
* Look for the opcode processor
*/
#ifdef DEBUG
if (debug >= 2)
printf("opcode %d, found command handler\n",
#endif
|| res_keyid != ctl_auth_keyid)) {
return;
}
return;
}
}
/*
* Can't find this one, return an error.
*/
numctlbadop++;
return;
}
/*
* ctlpeerstatus - return a status word for this peer
*/
{
if (pps_control)
}
}
status |= CTL_PST_CONFIG;
}
status |= CTL_PST_REACH;
peer->last_event);
}
/*
* ctlclkstatus - return a status word for this clock
*/
static u_short
struct refclockstat *clock;
{
}
/*
* ctlsysstatus - return the system status word
*/
{
if (sys_peer != 0) {
if (pps_control)
clock |= CTL_SST_TS_PPS;
} else {
if (pps_control)
clock |= CTL_SST_TS_PPS;
}
}
}
/*
* ctl_flushpkt - write out the current packet and prepare
* another if necessary.
*/
static void
int more;
{
int dlen;
int sendlen;
if (!more && datanotbinflag) {
/*
* Big hack, output a trailing \r\n
*/
*datapt++ = '\r';
*datapt++ = '\n';
}
/*
* Pad to a multiple of 32 bits
*/
while (sendlen & 0x3) {
*datapt++ = '\0';
sendlen++;
}
/*
* Fill in the packet with the current info
*/
if (res_async) {
register int i;
for (i = 0; i < CTL_MAXTRAPS; i++) {
ctl_trap[i].tr_localaddr,
-4,
if (!more)
ctl_trap[i].tr_sequence++;
numasyncmsgs++;
}
}
} else {
if (res_authenticate) {
int maclen;
/*
* If we are going to authenticate, then there is
* an additional requirement that the MAC begin on
* a 64 bit boundary.
*/
while (totlen & 7) {
*datapt++ = '\0';
totlen++;
}
maclen =
} else {
sendlen);
}
if (more)
numctlfrags++;
else
}
/*
* Set us up for another go around.
*/
res_offset += dlen;
}
/*
* ctl_putdata - write data into the packet, fragmenting and
* starting another if this one is full.
*/
static void
const char *dp;
int dlen;
int bin; /* set to 1 when data is binary */
{
int overhead;
overhead = 0;
if (!bin) {
datanotbinflag = 1;
overhead = 3;
*datapt++ = ',';
datalinelen++;
*datapt++ = '\r';
*datapt++ = '\n';
datalinelen = 0;
} else {
*datapt++ = ' ';
datalinelen++;
}
}
}
/*
* Save room for trailing junk
*/
/*
* Not enough room in this one, flush it out.
*/
}
datalinelen += dlen;
}
/*
* ctl_putstr - write a tagged string into the response packet
*/
static void
const char *tag;
const char *data;
int len;
{
register char *cp;
register const char *cq;
char buffer[400];
while (*cq != '\0')
if (len > 0) {
*cp++ = '=';
*cp++ = '"';
*cp++ = '"';
}
}
/*
* ctl_putlfp - write a tagged, signed l_fp into the response packet
*/
static void
const char *tag;
{
register const char *cq;
register char *cp;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
while (*cq != '\0')
}
/*
* ctl_putfp - write a tagged s_fp number into the response
*/
static void
const char *tag;
{
register char *cp;
register const char *cq;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
while (*cq != '\0')
}
/*
* ctl_putufp - write a tagged u_fp number into the response
*/
static void
const char *tag;
{
register char *cp;
register const char *cq;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
while (*cq != '\0')
}
/*
* ctl_putuint - write a tagged unsigned integer into the response
*/
static void
const char *tag;
{
register char *cp;
register const char *cq;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
while (*cp != '\0')
cp++;
}
/*
* ctl_puthex - write a tagged unsigned integer, in hex, into the response
*/
static void
const char *tag;
{
register char *cp;
register const char *cq;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
while (*cp != '\0')
cp++;
}
/*
* ctl_putint - write a tagged signed integer into the response
*/
static void
const char *tag;
long ival;
{
register char *cp;
register const char *cq;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
while (*cp != '\0')
cp++;
}
/*
* ctl_putts - write a tagged timestamp, in hex, into the response
*/
static void
const char *tag;
{
register char *cp;
register const char *cq;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
while (*cp != '\0')
cp++;
}
/*
* ctl_putadr - write a dotted quad IP address into the response
*/
static void
const char *tag;
{
register char *cp;
register const char *cq;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
while (*cq != '\0')
}
/*
* ctl_putid - write a tagged clock ID into the response
*/
static void
const char *tag;
char *id;
{
register char *cp;
register const char *cq;
char buffer[200];
while (*cq != '\0')
*cp++ = '=';
}
/*
* ctl_putarray - write a tagged eight element s_fp array into the response
*/
static void
const char *tag;
int start;
{
register char *cp;
register const char *cq;
char buffer[200];
int i, ind;
int len;
while (*cq != '\0')
*cp++ = '=';
/*
* Hack. We know the tag is either filtdelay, filtoffset,
* or filterror. Space over the shorter words one space.
*/
*cp++ = ' ';
i = start;
ind = 0;
do {
if (i == 0)
i = NTP_SHIFT;
i--;
if (ind) {
*cp++ = ' ';
} else {
ind = 1;
}
while (len < 7) {
*cp++ = ' ';
len++;
}
while (*cq != '\0')
} while(i != start);
}
/*
* ctl_putsys - output a system variable
*/
static void
int varid;
{
switch (varid) {
case CS_LEAP:
break;
case CS_STRATUM:
break;
case CS_PRECISION:
break;
case CS_ROOTDELAY:
break;
case CS_ROOTDISPERSION:
break;
case CS_REFID:
if (sys_stratum > 1)
else
break;
case CS_REFTIME:
break;
case CS_POLL:
break;
case CS_PEERID:
else
break;
case CS_OFFSET:
break;
case CS_DRIFT:
break;
case CS_COMPLIANCE:
break;
case CS_CLOCK:
get_systime(&tmp);
break;
case CS_LEAPIND:
break;
case CS_LEAPWARNING:
break;
case CS_PROCESSOR:
#ifndef HAVE_UNAME
sizeof(str_processor) - 1);
#else
#endif /* HAVE_UNAME */
break;
case CS_SYSTEM:
#ifndef HAVE_UNAME
sizeof(str_system) - 1);
#else
#endif /* HAVE_UNAME */
break;
case CS_KEYID:
break;
case CS_REFSKEW:
break;
case CS_VARLIST:
{
char buf[CTL_MAX_DATA_LEN];
register int i;
register struct ctl_var *k;
s = buf;
if (s > be)
break; /* really long var name 8-( - Killer */
strcat(s, "=\"");
s += strlen(s);
t = s;
{
continue;
if (s+i+1 >= be)
break;
if (s != t)
*s++ = ',';
s += i;
}
{
continue;
if (!ss)
continue;
ss++;
if (s+i+1 >= be)
break;
if (s != t)
*s++ = ',';
s += i;
}
if (s+2 >= be)
break;
*s++ = '"';
*s = '\0';
}
break;
}
}
/*
* ctl_putpeer - output a peer variable
*/
static void
int varid;
{
switch (varid) {
case CP_CONFIG:
break;
case CP_AUTHENABLE:
break;
case CP_AUTHENTIC:
break;
case CP_SRCADR:
break;
case CP_SRCPORT:
break;
case CP_DSTADR:
peer->cast_flags ?
8 : 12);
break;
case CP_DSTPORT:
break;
case CP_LEAP:
break;
case CP_HMODE:
break;
case CP_STRATUM:
break;
case CP_PPOLL:
break;
case CP_HPOLL:
break;
case CP_PRECISION:
break;
case CP_ROOTDELAY:
break;
case CP_ROOTDISPERSION:
break;
case CP_REFID:
else
else
break;
case CP_REFTIME:
break;
case CP_ORG:
break;
case CP_REC:
break;
case CP_XMT:
break;
case CP_REACH:
break;
case CP_FLASH:
break;
case CP_VALID:
break;
case CP_TIMER:
break;
case CP_DELAY:
break;
case CP_OFFSET:
break;
case CP_DISPERSION:
break;
case CP_KEYID:
break;
case CP_FILTDELAY:
break;
case CP_FILTOFFSET:
break;
case CP_FILTERROR:
break;
case CP_PMODE:
break;
case CP_RECEIVED:
break;
case CP_SENT:
break;
case CP_VARLIST:
{
char buf[CTL_MAX_DATA_LEN];
register char *s, *t, *be;
register int i;
register struct ctl_var *k;
s = buf;
if (s > be)
break; /* really long var name 8-( - Killer */
strcat(s, "=\"");
s += strlen(s);
t = s;
{
continue;
if (s+i+1 >= be)
break;
if (s != t)
*s++ = ',';
s += i;
}
if (s+2 >= be)
break;
*s++ = '"';
*s = '\0';
}
break;
}
}
#ifdef REFCLOCK
/*
* ctl_putclock - output clock variables
*/
static void
int varid;
struct refclockstat *clock;
int mustput;
{
switch(varid) {
case CC_TYPE:
}
break;
case CC_TIMECODE:
break;
case CC_POLL:
break;
case CC_NOREPLY:
break;
case CC_BADFORMAT:
break;
case CC_BADDATA:
break;
case CC_FUDGETIME1:
&clock->fudgetime1);
break;
case CC_FUDGETIME2:
&clock->fudgetime2);
break;
case CC_FUDGEVAL1:
break;
case CC_FUDGEVAL2:
else
break;
case CC_FLAGS:
break;
case CC_DEVICE:
if (mustput)
} else {
}
break;
case CC_VARLIST:
{
char buf[CTL_MAX_DATA_LEN];
register int i;
register struct ctl_var *k;
s = buf;
if (s > be)
break; /* really long var name 8-( - Killer */
strcat(s, "=\"");
s += strlen(s);
t = s;
{
continue;
if (s+i+1 >= be)
break;
if (s != t)
*s++ = ',';
s += i;
}
{
continue;
if (!ss)
continue;
ss++;
if (s+i+1 >= be)
break;
if (s != t)
*s++ = ',';
s += i;
*s = '\0';
}
if (s+2 >= be)
break;
*s++ = '"';
*s = '\0';
}
break;
}
}
#endif
/*
* ctl_getitem - get the next data item from the incoming packet
*/
static struct ctl_var *
char **data;
{
register struct ctl_var *v;
static char buf[128];
/*
* Delete leading commas and white space
*/
reqpt++;
}
return 0;
return &eol;
/*
* Look for a first character match on the tag. If we find
* one, see if it is a full match.
*/
v = var_list;
cp++;
tp++;
}
cp++;
buf[0] = '\0';
cp++;
return v;
}
if (*cp == '=') {
cp++;
cp++;
else {
return 0;
}
cp++;
*tp = '\0';
*(--tp) = '\0';
return v;
}
}
}
v++;
}
return v;
}
/*
* Log that somebody might be trying to exploit a buffer overflow.
*
* Limit login to LOG_MSGS_PER_INTERVAL times per LOG_INTERVAL_SECS seconds.
*
*/
static void
{
static time_t last_log_sec = 0;
static int log_count = 0;
char from_s[16];
log_count = 0;
}
if (log_count < LOG_MSGS_PER_INTERVAL) {
log_count++;
"Failed possible attack attempt from "
"%s to local %s\n",
}
}
/*
* control_unspec - response to an unspecified op-code
*/
/*ARGSUSED*/
static void
int restrict_mask;
{
/*
* What is an appropriate response to an unspecified op-code?
* I return no errors and no data, unless a specified assocation
* doesn't exist.
*/
if (res_associd != 0) {
return;
}
} else {
}
ctl_flushpkt(0);
}
/*
* read_status - return either a list of associd's, or a particular
* peer's status.
*/
/*ARGSUSED*/
static void
int restrict_mask;
{
register int i;
#ifdef DEBUG
if (debug >= 2)
#endif
/*
* Two choices here. If the specified association ID is
* zero we return all known assocation ID's. Otherwise
* we return a bunch of stuff about the particular peer.
*/
if (res_associd == 0) {
register int n;
n = 0;
for (i = 0; i < HASH_SIZE; i++) {
if (n == CTL_MAX_DATA_LEN/sizeof(u_short)) {
ctl_putdata((char *)ass_stat,
n * sizeof(u_short), 1);
n = 0;
}
}
}
if (n != 0)
ctl_flushpkt(0);
} else {
if (peer == 0) {
} else {
if (res_authokay)
peer->num_events = 0;
/*
* For now, output everything we know about the peer.
* May be more selective later.
*/
ctl_flushpkt(0);
}
}
}
/*
* read_variables - return the variables the caller asks for
*/
/*ARGSUSED*/
static void
int restrict_mask;
{
register struct ctl_var *v;
register int i;
char *valuep;
if (res_associd == 0) {
/*
* Wants system variables. Figure out which he wants
* and give them to him.
*/
if (res_authokay)
ctl_sys_num_events = 0;
gotvar = 0;
return;
}
gotvar = 1;
continue;
} else {
break; /* shouldn't happen ! */
}
}
gotvar = 1;
}
if (gotvar) {
for (i = 1; i <= CS_MAXCODE; i++)
if (wants[i])
ctl_putsys(i);
} else {
ctl_putsys((int)*cs);
}
} else {
/*
* Wants info for a particular peer. See if we know
* the guy.
*/
if (peer == 0) {
return;
}
if (res_authokay)
peer->num_events = 0;
gotvar = 0;
return;
}
gotvar = 1;
}
if (gotvar) {
for (i = 1; i <= CP_MAXCODE; i++)
if (wants[i])
ctl_putpeer(i, peer);
} else {
}
}
ctl_flushpkt(0);
}
/*
* write_variables - write into variables. We only allow leap bit writing
* this way.
*/
/*ARGSUSED*/
static void
int restrict_mask;
{
register struct ctl_var *v;
register int ext_var;
char *valuep;
long val;
/*
* If he's trying to write into a peer tell him no way
*/
if (res_associd != 0) {
return;
}
/*
* Set status
*/
/*
* Set flags to not-in-sync so we can tell when we get something.
*/
leapind = ~0;
leapwarn = ~0;
/*
* Look through the variables. Dump out at the first sign of trouble.
*/
ext_var = 0;
return;
}
ext_var = 1;
} else {
break;
}
}
return;
}
return;
}
return;
}
if (ext_var) {
char *t, *tt = s;
t = v->text;
while (*t && *t != '=')
*tt++ = *t++;
*tt++ = '=';
free(s);
} else {
/*
* This one seems sane. Save it.
*/
switch(v->code) {
case CS_LEAP:
case CS_LEAPIND:
break;
case CS_LEAPWARNING:
break;
default:
return;
}
}
}
/*
* If we got anything, do it.
*/
return;
}
}
ctl_flushpkt(0);
}
/*
* read_clock_status - return clock radio status
*/
/*ARGSUSED*/
static void
int restrict_mask;
{
#ifndef REFCLOCK
/*
* If no refclock support, no data to return
*/
#else
register struct ctl_var *v;
register int i;
char *valuep;
int gotvar;
struct refclockstat clock;
if (res_associd == 0) {
/*
* Find a clock for this jerk. If the system peer
* is a clock use it, else search the hash tables
* for one.
*/
} else {
peer = 0;
break;
}
}
if (peer == 0) {
return;
}
}
} else {
return;
}
}
/*
* If we got here we have a peer which is a clock. Get his status.
*/
/*
* Look for variables in the packet.
*/
gotvar = 0;
return;
}
gotvar = 1;
continue;
} else {
break; /* shouldn't happen ! */
}
}
gotvar = 1;
}
if (gotvar) {
for (i = 1; i <= CC_MAXCODE; i++)
if (wants[i])
} else {
}
ctl_flushpkt(0);
#endif
}
/*
* write_clock_status - we don't do this
*/
/*ARGSUSED*/
static void
int restrict_mask;
{
}
/*
* Trap support from here on down. We send async trap messages when the
* upper levels report trouble. Traps can by set either by control
* messages or by configuration.
*/
/*
* set_trap - set a trap in response to a control message
*/
static void
int restrict_mask;
{
int traptype;
/*
* See if this guy is allowed
*/
if (restrict_mask & RES_NOTRAP) {
return;
}
/*
* Determine his allowed trap type.
*/
if (restrict_mask & RES_LPTRAP)
/*
* Call ctlsettrap() to do the work. Return
* an error if it can't assign the trap.
*/
(int)res_version))
ctl_flushpkt(0);
}
/*
* unset_trap - unset a trap in response to a control message
*/
static void
int restrict_mask;
{
int traptype;
/*
* We don't prevent anyone from removing his own
* trap unless the trap is configured. Note we also
* must be aware of the possibility that restriction
* flags were changed since this guy last set his trap.
* Set the trap type based on this.
*/
if (restrict_mask & RES_LPTRAP)
/*
* Call ctlclrtrap() to clear this out.
*/
ctl_flushpkt(0);
}
/*
* ctlsettrap - called to set a trap
*/
int
struct sockaddr_in *raddr;
int traptype;
int version;
{
/*
* See if we can find this trap. If so, we only need update
* the flags and the time.
*/
switch (traptype) {
case TRAP_TYPE_CONFIG:
break;
case TRAP_TYPE_PRIO:
return 1; /* don't change anything */
break;
case TRAP_TYPE_NONPRIO:
return 1; /* don't change anything */
break;
}
return 1;
}
/*
* First we heard of this guy. Try to find a trap structure
* for him to use, clearing out lesser priority guys if we
* have to. Clear out anyone who's expired while we're at it.
*/
}
switch (traptype) {
case TRAP_TYPE_CONFIG:
break;
}
break;
break;
}
break;
case TRAP_TYPE_PRIO:
&& tptouse->tr_origtime
< tp->tr_origtime))
}
break;
case TRAP_TYPE_NONPRIO:
break;
}
}
}
/*
* If we don't have room for him return an error.
*/
return 0;
/*
* Set up this structure for him.
*/
if (traptype == TRAP_TYPE_CONFIG)
else if (traptype == TRAP_TYPE_NONPRIO)
return 1;
}
/*
* ctlclrtrap - called to clr a trap
*/
int
struct sockaddr_in *raddr;
int traptype;
{
return 0;
&& traptype != TRAP_TYPE_CONFIG)
return 0;
return 1;
}
/*
* ctlfindtrap - find a trap given the remote and local addresses
*/
static struct ctl_trap *
struct sockaddr_in *raddr;
{
return tp;
}
}
/*
* report_event - report an event to the trappers
*/
void
int err;
{
register int i;
/*
* Record error code in proper spots, but have mercy on the
* log file.
*/
if (!(err & PEER_EVENT)) {
#ifdef DEBUG
if (debug)
printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n",
#endif
}
} else if (peer != 0) {
char *src;
#ifdef REFCLOCK
else
#endif
peer->num_events++;
#ifdef DEBUG
if (debug)
printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n",
#endif
} else {
#ifdef DEBUG
#endif
return;
}
/*
* If no trappers, return.
*/
if (num_ctl_traps <= 0)
return;
/*
* Set up the outgoing packet variables
*/
res_offset = 0;
res_async = 1;
res_authenticate = 0;
if (!(err & PEER_EVENT)) {
/*
* For now, put everything we know about system
* variables. Maybe more selective later
*/
for (i = 1; i <= CS_MAXCODE; i++)
ctl_putsys(i);
#ifdef REFCLOCK
/*
* for clock exception events:
* add clock variables to reflect info on exception
*/
if (err == EVNT_CLOCKEXCPT) {
struct refclockstat clock;
(struct refclockstat *)0, &clock);
for (i = 1; i <= CC_MAXCODE; i++)
ctl_putclock(i, &clock, 0);
}
#endif /*REFCLOCK*/
} else {
/*
* Dump it all. Later, maybe less.
*/
for (i = 1; i <= CP_MAXCODE; i++)
ctl_putpeer(i, peer);
#ifdef REFCLOCK
/*
* for clock exception events:
* add clock variables to reflect info on exception
*/
if (err == EVNT_PEERCLOCK) {
struct refclockstat clock;
(struct refclockstat *)0,
&clock);
ctl_puthex("refclockstatus",
ctlclkstatus(&clock));
for (i = 1; i <= CC_MAXCODE; i++)
ctl_putclock(i, &clock, 0);
}
#endif /*REFCLOCK*/
}
/*
* We're done, return.
*/
ctl_flushpkt(0);
}
/*
* ctl_clr_stats - clear stat counters
*/
void
{
numctlreq = 0;
numctlbadpkts = 0;
numctlresponses = 0;
numctlfrags = 0;
numctlerrors = 0;
numctlfrags = 0;
numctltooshort = 0;
numctlinputresp = 0;
numctlinputfrag = 0;
numctlinputerr = 0;
numctlbadoffset = 0;
numctlbadversion = 0;
numctldatatooshort = 0;
numctlbadop = 0;
numasyncmsgs = 0;
}
static u_long
count_var(k)
struct ctl_var *k;
{
register u_long c;
c = 0;
c++;
return c;
}
char *
int def;
{
register u_long c;
register struct ctl_var *k;
k = *kv;
if (k)
{
free((char *)k);
}
}
void
char *data;
int def;
{
register struct ctl_var *k;
register char *s, *t;
return;
if ((k = *kv))
{
{
s = data;
t = k->text;
if (t)
{
while (*t != '=' && *s - *t == 0)
{
s++;
t++;
}
if (*s == *t && ((*t == '=') || !*t))
{
return;
}
}
else
{
return;
}
k++;
}
}
}
void
char *data;
int def;
{
}
void
{
struct ctl_var *k;
if (kv)
{
}
}