Plan 9 from Bell Labs’s /usr/web/sources/contrib/quanstro/root/sys/src/fs/ip/sntp.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "all.h"

#include "../ip/ip.h"

typedef struct Sntppkt {
	uchar	d[Easize];		/* ether header */
	uchar	s[Easize];
	uchar	type[2];

	uchar	vihl;			/* ip header */
	uchar	tos;
	uchar	length[2];
	uchar	id[2];
	uchar	frag[2];
	uchar	ttl;
	uchar	proto;
	uchar	cksum[2];
	uchar	src[Pasize];
	uchar	dst[Pasize];

	uchar	udpsrc[2];		/* Src port */
	uchar	udpdst[2];		/* Dst port */
	uchar	udplen[2];		/* Packet length */
	uchar	udpsum[2];		/* Checksum including header */
	uchar	mode;			/* li:2, vn:3, mode:3 */
	uchar	stratum;			/* level of local clock */
	char	poll;			/* log2(max interval between polls) */
	char	precision;		/* log2(clock precision) -6 => mains, -18 => us */
	uchar	rootdelay[4];		/* round trip delay to reference 16.16 fraction */
	uchar	dispersion[4];		/* max error to reference */
	uchar	clockid[4];		/* reference clock identifier */
	uchar	reftime[8];		/* local time when clock set */
	uchar	orgtime[8];		/* local time when client sent request */
	uchar	rcvtime[8];		/* time request arrived */
	uchar	xmttime[8];		/* time reply sent */
} Sntppkt;

enum {
	Sntpsize = 4 + 3 * 4 + 4 * 8,
	Version = 1,
	Stratum = 0,
	Poll = 0,
	LI = 0,
	Symmetric = 2,
	ClientMode = 3,
	ServerMode = 4,
	Epoch = 86400 * (365 * 70 + 17), /* 1900 to 1970 in seconds */
};

#define dprint(...)	if(cons.flags&sntp.flag)print(__VA_ARGS__);

static struct {
	Lock;
	int	flag;
	int	gotreply;
	int	kicked;
	int	active;
	Rendez	r;
	Rendez	doze;
} sntp;

static int
done(void*)
{
	return sntp.gotreply != 0;
}

static int
kicked(void*)
{
	return sntp.kicked != 0;
}

void
sntprecv(Msgbuf *mb, Ifc*)
{
	int v, li, m;
	Sntppkt *sh;
	Timet now, dt;
	Udppkt *uh;

	uh = (Udppkt*)mb->data;
	dprint("sntp: receive from %I\n", uh->src);
	if(memcmp(uh->src, sntpip, 4) != 0){
		dprint("sntp: wrong IP\n");
		goto overandout;
	}
	if(nhgets(uh->udplen) < Sntpsize){
		dprint("sntp: packet too small\n");
		goto overandout;
	}
	sh = (Sntppkt *)mb->data;
	v = (sh->mode >> 3) & 7;
	li = (sh->mode >> 6);
	m = sh->mode & 7;
	/*
	 * if reply from right place and contains time set gotreply
	 * and wakeup r
	 */
	dprint(	"sntp: LI %d version %d mode %d  stratum %d\n"
		"sntp: poll %d precision %d rootdelay %ld dispersion %ld\n",
		li, v, m, sh->stratum,
		sh->poll, sh->precision, nhgetl(sh->rootdelay), nhgetl(sh->dispersion));
	if(v == 0 || v > 3){
		dprint("sntp: unsupported version\n");
		goto overandout;
	}
	if(m >= 6 || m == ClientMode){
		dprint("sntp: wrong mode\n");
		goto overandout;
	}
	now = nhgetl(sh->xmttime) - Epoch;
	if(li == 3 || now == 0 || sh->stratum == 0){
		print("sntp: time server not synchronized\n");
		goto overandout;
	}
	if(dt = now-time()){
		settime(now);
		setrtc(now);
		if(dt < 0)
			dt = -dt;
		if(dt > 1 || (cons.flags&sntp.flag))
			print("sntp: %T [adjust %+ld]\n", now, (long)dt);
	}
	sntp.gotreply = 1;
	wakeup(&sntp.r);
overandout:
	mbfree(mb);
}

void
sntpsend(void)
{
	uchar tmp[Pasize];
	ulong ip;
	ushort sum;
	Ifc *ifc;
	Msgbuf *mb;
	Sntppkt *s;

	/* find an interface on the same subnet as sntpip, if any */
	ip = nhgetl(sntpip);
	for(ifc = enets; ifc; ifc = ifc->next){
		if(isvalidip(ifc->ipa) &&
		   (nhgetl(ifc->ipa)&ifc->mask) == (ip&ifc->mask))
			break;
	}
	/* if none, find an interface with a default gateway */
	if(ifc == nil)
		for(ifc = enets; ifc; ifc = ifc->next)
			if(isvalidip(ifc->ipa) && isvalidip(ifc->netgate))
				break;
	if(ifc == nil){
		dprint("sntp: can't send to %I; no route\n", sntpip);
		return;
	}

	/* compose a UDP sntp request */
	dprint("sntp: sending to %I on ifc %I\n", sntpip, ifc->ipa);
	mb = mballoc(Ensize+Ipsize+Udpsize+Sntpsize, 0, Mbsntp);
	s = (Sntppkt*)mb->data;
	/* IP fields */	
	memmove(s->src, ifc->ipa, Pasize);
	memmove(s->dst, sntpip, Pasize);
	s->proto = Udpproto;
	s->ttl = 0;
	/* Udp fields */
	hnputs(s->udpsrc, SNTP_LOCAL);
	hnputs(s->udpdst, SNTP);
	hnputs(s->udplen, Sntpsize + Udpsize);
	/* Sntp fields */
	memset(mb->data + Ensize+Ipsize+Udpsize, 0, Sntpsize);
	s->mode = 010 | ClientMode;
	s->poll = 6;
	hnputl(s->orgtime, rtctime() + Epoch);	/* leave 0 fraction */
	/* Compute the UDP sum - form psuedo header */
	hnputs(s->cksum, Udpsize + Sntpsize);
	hnputs(s->udpsum, 0);
	sum = ptclcsum((uchar *)mb->data + Ensize + Ipsize - Udpphsize,
	    Udpsize + Udpphsize + Sntpsize);
	hnputs(s->udpsum, sum);
	/*
	  * now try to send it - cribbed from icmp.c
	  */
	memmove(tmp, s->dst, Pasize);
	if((nhgetl(ifc->ipa)&ifc->mask) != (nhgetl(s->dst)&ifc->mask)){
		dprint("sntp: route via %I\n", ifc->netgate);
		iproute(tmp, s->dst, ifc->netgate);
	}
	ipsend1(mb, ifc, tmp);
}

void
sntptask(void)
{
	int i;

	dprint("sntp: running\n");
	tsleep(&sntp.doze, kicked, 0, 2 * 60 * 1000);
	for(;;){
		sntp.kicked = 0;
		dprint("sntp: poll time\n");
		if(sntp.active && isvalidip(sntpip)){
			sntp.gotreply = 0;
			for (i = 0; i < 3; i++){
				sntpsend();
				tsleep(&sntp.r, done, 0, 1000);
				if(sntp.gotreply)
					break;
			}
			/* clock has been set */
		}
		tsleep(&sntp.doze, kicked, 0, 60 * 60 * 1000);
	}
}

void
cmd_sntp(int argc, char *argv[])
{
	int i;
	uchar tip[Pasize];

	if(argc <= 1){
		print("sntp kick -- check time now\n");
		print("sntp active -- toggle active status\n");
		print("sntp ip -- set sntp ip\n");
		return;
	}
	for(i=1; i<argc; i++){
		if(strcmp(argv[i], "kick") == 0){
		kick:	sntp.active = 1;
			sntp.kicked = 1;
			wakeup(&sntp.doze);
		}else if(strcmp(argv[i], "active") == 0)
			sntp.active ^= 1;
		else if(strcmp(argv[i], "ip") == 0){
			i++;
			if(!argv[i] || chartoip(tip, argv[i])){
				print("bad smtp address\n");
				continue;
			}
			memmove(sntpip, tip, sizeof sntpip);
			goto kick;
		}
	}
	print("active %d\nip %I\n", sntp.active, sntpip);
}

void
sntpinit(void)
{
	cmd_install("sntp", "subcommand -- sntp protocol", cmd_sntp);
	sntp.flag = flag_install("sntp", "-- verbose");
	sntp.active = 1;
	userinit(sntptask, 0, "sntp");
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.