xref: /plan9/sys/src/cmd/ip/dhcpd/dhcpd.c (revision 588d0145e19f8596f2f4442d05dd8a9eda147983)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ip.h>
47dd7cddfSDavid du Colombier #include <bio.h>
57dd7cddfSDavid du Colombier #include <ndb.h>
67dd7cddfSDavid du Colombier #include "dat.h"
77dd7cddfSDavid du Colombier 
82ddf2468SDavid du Colombier /*
92ddf2468SDavid du Colombier  *	ala rfc2131
102ddf2468SDavid du Colombier  */
117dd7cddfSDavid du Colombier 
120a84db5eSDavid du Colombier enum {
130a84db5eSDavid du Colombier 	Maxloglen = 1024,
140a84db5eSDavid du Colombier };
150a84db5eSDavid du Colombier 
167dd7cddfSDavid du Colombier typedef struct Req Req;
177dd7cddfSDavid du Colombier struct Req
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier 	int	fd;			/* for reply */
207dd7cddfSDavid du Colombier 	Bootp	*bp;
21f27a9a5aSDavid du Colombier 	Udphdr	*up;
227dd7cddfSDavid du Colombier 	uchar	*e;			/* end of received message */
237dd7cddfSDavid du Colombier 	uchar	*p;			/* options pointer */
247dd7cddfSDavid du Colombier 	uchar	*max;			/* max end of reply */
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier 	/* expanded to v6 */
277dd7cddfSDavid du Colombier 	uchar	ciaddr[IPaddrlen];
287dd7cddfSDavid du Colombier 	uchar	giaddr[IPaddrlen];
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier 	/* parsed options */
312ddf2468SDavid du Colombier 	int	p9request;		/* flag: this is a bootp with plan9 options */
322ddf2468SDavid du Colombier 	int	genrequest;		/* flag: this is a bootp with generic options */
338ae63d3dSDavid du Colombier 	int	broadcast;		/* flag: request was broadcast */
347dd7cddfSDavid du Colombier 	int	dhcptype;		/* dhcp message type */
357dd7cddfSDavid du Colombier 	int	leasetime;		/* dhcp lease */
367dd7cddfSDavid du Colombier 	uchar	ip[IPaddrlen];		/* requested address */
377dd7cddfSDavid du Colombier 	uchar	server[IPaddrlen];	/* server address */
389a747e4fSDavid du Colombier 	char	msg[ERRMAX];		/* error message */
397dd7cddfSDavid du Colombier 	char	vci[32];		/* vendor class id */
407dd7cddfSDavid du Colombier 	char	*id;			/* client id */
417dd7cddfSDavid du Colombier 	uchar	requested[32];		/* requested params */
427dd7cddfSDavid du Colombier 	uchar	vendorclass[32];
437dd7cddfSDavid du Colombier 	char	cputype[32-3];
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier 	Info	gii;			/* about target network */
467dd7cddfSDavid du Colombier 	Info	ii;			/* about target system */
477dd7cddfSDavid du Colombier 	int	staticbinding;
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier 	uchar buf[2*1024];		/* message buffer */
507dd7cddfSDavid du Colombier };
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier #define TFTP "/lib/tftpd"
532ddf2468SDavid du Colombier 
547dd7cddfSDavid du Colombier char	*blog = "ipboot";
557dd7cddfSDavid du Colombier char	mysysname[64];
567dd7cddfSDavid du Colombier Ipifc	*ipifcs;
577dd7cddfSDavid du Colombier int	debug;
587dd7cddfSDavid du Colombier int	nobootp;
597dd7cddfSDavid du Colombier long	now;
60e183b1a6SDavid du Colombier int	slowstat, slowdyn;
619a747e4fSDavid du Colombier char	net[256];
627dd7cddfSDavid du Colombier 
632ddf2468SDavid du Colombier int	pptponly;	/* only answer request that came from the pptp server */
64e183b1a6SDavid du Colombier int	mute, mutestat;
657dd7cddfSDavid du Colombier int	minlease = MinLease;
662ddf2468SDavid du Colombier int	staticlease = StaticLease;
677dd7cddfSDavid du Colombier 
68e47b3901SDavid du Colombier uvlong	start;
693ff48bf5SDavid du Colombier 
700a84db5eSDavid du Colombier static int v6opts;
710a84db5eSDavid du Colombier 
727dd7cddfSDavid du Colombier /* option magic */
737dd7cddfSDavid du Colombier char plan9opt[4] = { 'p', '9', ' ', ' ' };
747dd7cddfSDavid du Colombier char genericopt[4] = { 0x63, 0x82, 0x53, 0x63 };
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier /* well known addresses */
777dd7cddfSDavid du Colombier uchar zeros[Maxhwlen];
787dd7cddfSDavid du Colombier 
793ff48bf5SDavid du Colombier /* option debug buffer */
803ff48bf5SDavid du Colombier char optbuf[1024];
813ff48bf5SDavid du Colombier char *op;
823ff48bf5SDavid du Colombier char *oe = optbuf + sizeof(optbuf);
833ff48bf5SDavid du Colombier 
843ff48bf5SDavid du Colombier char *optname[256] =
853ff48bf5SDavid du Colombier {
863ff48bf5SDavid du Colombier [OBend]			"end",
873ff48bf5SDavid du Colombier [OBpad]			"pad",
883ff48bf5SDavid du Colombier [OBmask]		"mask",
893ff48bf5SDavid du Colombier [OBtimeoff]		"timeoff",
903ff48bf5SDavid du Colombier [OBrouter]		"router",
913ff48bf5SDavid du Colombier [OBtimeserver]		"time",
923ff48bf5SDavid du Colombier [OBnameserver]		"name",
933ff48bf5SDavid du Colombier [OBdnserver]		"dns",
943ff48bf5SDavid du Colombier [OBlogserver]		"log",
953ff48bf5SDavid du Colombier [OBcookieserver]	"cookie",
963ff48bf5SDavid du Colombier [OBlprserver]		"lpr",
973ff48bf5SDavid du Colombier [OBimpressserver]	"impress",
983ff48bf5SDavid du Colombier [OBrlserver]		"rl",
993ff48bf5SDavid du Colombier [OBhostname]		"host",
1003ff48bf5SDavid du Colombier [OBbflen]		"bflen",
1013ff48bf5SDavid du Colombier [OBdumpfile]		"dumpfile",
1023ff48bf5SDavid du Colombier [OBdomainname]		"dom",
1033ff48bf5SDavid du Colombier [OBswapserver]		"swap",
1043ff48bf5SDavid du Colombier [OBrootpath]		"rootpath",
1053ff48bf5SDavid du Colombier [OBextpath]		"extpath",
1063ff48bf5SDavid du Colombier [OBipforward]		"ipforward",
1073ff48bf5SDavid du Colombier [OBnonlocal]		"nonlocal",
1083ff48bf5SDavid du Colombier [OBpolicyfilter]	"policyfilter",
1093ff48bf5SDavid du Colombier [OBmaxdatagram]		"maxdatagram",
1103ff48bf5SDavid du Colombier [OBttl]			"ttl",
1113ff48bf5SDavid du Colombier [OBpathtimeout]		"pathtimeout",
1123ff48bf5SDavid du Colombier [OBpathplateau]		"pathplateau",
1133ff48bf5SDavid du Colombier [OBmtu]			"mtu",
1143ff48bf5SDavid du Colombier [OBsubnetslocal]	"subnetslocal",
1153ff48bf5SDavid du Colombier [OBbaddr]		"baddr",
1163ff48bf5SDavid du Colombier [OBdiscovermask]	"discovermask",
1173ff48bf5SDavid du Colombier [OBsupplymask]		"supplymask",
1183ff48bf5SDavid du Colombier [OBdiscoverrouter]	"discoverrouter",
1193ff48bf5SDavid du Colombier [OBrsserver]		"rsserver",
1203ff48bf5SDavid du Colombier [OBstaticroutes]	"staticroutes",
1213ff48bf5SDavid du Colombier [OBtrailerencap]	"trailerencap",
1223ff48bf5SDavid du Colombier [OBarptimeout]		"arptimeout",
1233ff48bf5SDavid du Colombier [OBetherencap]		"etherencap",
1243ff48bf5SDavid du Colombier [OBtcpttl]		"tcpttl",
1253ff48bf5SDavid du Colombier [OBtcpka]		"tcpka",
1263ff48bf5SDavid du Colombier [OBtcpkag]		"tcpkag",
1273ff48bf5SDavid du Colombier [OBnisdomain]		"nisdomain",
1283ff48bf5SDavid du Colombier [OBniserver]		"niserver",
1293ff48bf5SDavid du Colombier [OBntpserver]		"ntpserver",
1303ff48bf5SDavid du Colombier [OBvendorinfo]		"vendorinfo",
1313ff48bf5SDavid du Colombier [OBnetbiosns]		"NBns",
1323ff48bf5SDavid du Colombier [OBnetbiosdds]		"NBdds",
1333ff48bf5SDavid du Colombier [OBnetbiostype]		"NBtype",
1343ff48bf5SDavid du Colombier [OBnetbiosscope]	"NBscope",
1353ff48bf5SDavid du Colombier [OBxfontserver]		"xfont",
1363ff48bf5SDavid du Colombier [OBxdispmanager]	"xdisp",
1373ff48bf5SDavid du Colombier [OBnisplusdomain]	"NPdomain",
1383ff48bf5SDavid du Colombier [OBnisplusserver]	"NP",
1393ff48bf5SDavid du Colombier [OBhomeagent]		"homeagent",
1403ff48bf5SDavid du Colombier [OBsmtpserver]		"smtp",
1413ff48bf5SDavid du Colombier [OBpop3server]		"pop3",
1423ff48bf5SDavid du Colombier [OBnntpserver]		"nntp",
1433ff48bf5SDavid du Colombier [OBwwwserver]		"www",
1443ff48bf5SDavid du Colombier [OBfingerserver]	"finger",
1453ff48bf5SDavid du Colombier [OBircserver]		"ircserver",
1463ff48bf5SDavid du Colombier [OBstserver]		"stserver",
1473ff48bf5SDavid du Colombier [OBstdaserver]		"stdaserver",
1483ff48bf5SDavid du Colombier 
1493ff48bf5SDavid du Colombier /* dhcp options */
1503ff48bf5SDavid du Colombier [ODipaddr]		"ip",
1513ff48bf5SDavid du Colombier [ODlease]		"leas",
1523ff48bf5SDavid du Colombier [ODoverload]		"overload",
1533ff48bf5SDavid du Colombier [ODtype]		"typ",
1543ff48bf5SDavid du Colombier [ODserverid]		"sid",
1553ff48bf5SDavid du Colombier [ODparams]		"params",
1563ff48bf5SDavid du Colombier [ODmessage]		"message",
1573ff48bf5SDavid du Colombier [ODmaxmsg]		"maxmsg",
1583ff48bf5SDavid du Colombier [ODrenewaltime]		"renewaltime",
1593ff48bf5SDavid du Colombier [ODrebindingtime]	"rebindingtime",
1603ff48bf5SDavid du Colombier [ODvendorclass]		"vendorclass",
1613ff48bf5SDavid du Colombier [ODclientid]		"cid",
1623ff48bf5SDavid du Colombier [ODtftpserver]		"tftpserver",
1633ff48bf5SDavid du Colombier [ODbootfile]		"bf",
1643ff48bf5SDavid du Colombier };
1653ff48bf5SDavid du Colombier 
1667dd7cddfSDavid du Colombier void	addropt(Req*, int, uchar*);
1677dd7cddfSDavid du Colombier void	addrsopt(Req*, int, uchar**, int);
1687dd7cddfSDavid du Colombier void	arpenter(uchar*, uchar*);
1697dd7cddfSDavid du Colombier void	bootp(Req*);
1707dd7cddfSDavid du Colombier void	byteopt(Req*, int, uchar);
1717dd7cddfSDavid du Colombier void	dhcp(Req*);
1727dd7cddfSDavid du Colombier void	fatal(int, char*, ...);
1737dd7cddfSDavid du Colombier void	hexopt(Req*, int, char*);
1742ddf2468SDavid du Colombier void	logdhcp(Req*);
1752ddf2468SDavid du Colombier void	logdhcpout(Req *, char *);
1767dd7cddfSDavid du Colombier void	longopt(Req*, int, long);
1773ff48bf5SDavid du Colombier void	maskopt(Req*, int, uchar*);
1787dd7cddfSDavid du Colombier void	miscoptions(Req*, uchar*);
1797dd7cddfSDavid du Colombier int	openlisten(char *net);
1800a84db5eSDavid du Colombier void	p9addrsopt(Req *rp, int t, uchar **ip, int i);
1817dd7cddfSDavid du Colombier void	parseoptions(Req*);
1827dd7cddfSDavid du Colombier void	proto(Req*, int);
1837dd7cddfSDavid du Colombier void	rcvdecline(Req*);
1847dd7cddfSDavid du Colombier void	rcvdiscover(Req*);
1857dd7cddfSDavid du Colombier void	rcvinform(Req*);
1867dd7cddfSDavid du Colombier void	rcvrelease(Req*);
1877dd7cddfSDavid du Colombier void	rcvrequest(Req*);
1882ddf2468SDavid du Colombier int	readlast(int, uchar*, int);
1897dd7cddfSDavid du Colombier char*	readsysname(void);
1907dd7cddfSDavid du Colombier void	remrequested(Req*, int);
1917dd7cddfSDavid du Colombier void	sendack(Req*, uchar*, int, int);
1927dd7cddfSDavid du Colombier void	sendnak(Req*, char*);
1937dd7cddfSDavid du Colombier void	sendoffer(Req*, uchar*, int);
1947dd7cddfSDavid du Colombier void	stringopt(Req*, int, char*);
1957dd7cddfSDavid du Colombier void	termopt(Req*);
1967dd7cddfSDavid du Colombier int	validip(uchar*);
1977dd7cddfSDavid du Colombier void	vectoropt(Req*, int, uchar*, int);
1987dd7cddfSDavid du Colombier void	warning(int, char*, ...);
1993ff48bf5SDavid du Colombier 
2003ff48bf5SDavid du Colombier void
timestamp(char * tag)2013ff48bf5SDavid du Colombier timestamp(char *tag)
2023ff48bf5SDavid du Colombier {
203e47b3901SDavid du Colombier 	uvlong t;
2043ff48bf5SDavid du Colombier 
2053ff48bf5SDavid du Colombier 	t = nsec()/1000;
206e47b3901SDavid du Colombier 	syslog(0, blog, "%s %lludµs", tag, t - start);
2073ff48bf5SDavid du Colombier }
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier void
usage(void)2107dd7cddfSDavid du Colombier usage(void)
2117dd7cddfSDavid du Colombier {
2122ddf2468SDavid du Colombier 	fprint(2, "usage: dhcp [-dmnprsSZ] [-f directory] [-M minlease] "
2132ddf2468SDavid du Colombier 		"[-x netmtpt] [-Z staticlease] addr n [addr n] ...\n");
2147dd7cddfSDavid du Colombier 	exits("usage");
2157dd7cddfSDavid du Colombier }
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier void
main(int argc,char ** argv)2187dd7cddfSDavid du Colombier main(int argc, char **argv)
2197dd7cddfSDavid du Colombier {
2203ff48bf5SDavid du Colombier 	int i, n, fd;
2217dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
2227dd7cddfSDavid du Colombier 	Req r;
2237dd7cddfSDavid du Colombier 
2242ddf2468SDavid du Colombier 	setnetmtpt(net, sizeof net, nil);
2257dd7cddfSDavid du Colombier 
2269a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2279a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2289a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
2299a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2307dd7cddfSDavid du Colombier 	ARGBEGIN {
2310a84db5eSDavid du Colombier 	case '6':
2320a84db5eSDavid du Colombier 		v6opts = 1;
2330a84db5eSDavid du Colombier 		break;
2347dd7cddfSDavid du Colombier 	case 'd':
2357dd7cddfSDavid du Colombier 		debug = 1;
2367dd7cddfSDavid du Colombier 		break;
2377dd7cddfSDavid du Colombier 	case 'f':
2382ddf2468SDavid du Colombier 		ndbfile = EARGF(usage());
2397dd7cddfSDavid du Colombier 		break;
2402ddf2468SDavid du Colombier 	case 'm':
2412ddf2468SDavid du Colombier 		mute = 1;
242e183b1a6SDavid du Colombier 		break;
2432ddf2468SDavid du Colombier 	case 'M':
2442ddf2468SDavid du Colombier 		minlease = atoi(EARGF(usage()));
2452ddf2468SDavid du Colombier 		if(minlease <= 0)
2462ddf2468SDavid du Colombier 			minlease = MinLease;
2477dd7cddfSDavid du Colombier 		break;
2487dd7cddfSDavid du Colombier 	case 'n':
2497dd7cddfSDavid du Colombier 		nobootp = 1;
2507dd7cddfSDavid du Colombier 		break;
2517dd7cddfSDavid du Colombier 	case 'p':
2527dd7cddfSDavid du Colombier 		pptponly = 1;
2537dd7cddfSDavid du Colombier 		break;
254e183b1a6SDavid du Colombier 	case 'r':
255e183b1a6SDavid du Colombier 		mutestat = 1;
256e183b1a6SDavid du Colombier 		break;
2572ddf2468SDavid du Colombier 	case 's':
2582ddf2468SDavid du Colombier 		slowstat = 1;
2597dd7cddfSDavid du Colombier 		break;
2602ddf2468SDavid du Colombier 	case 'S':
2612ddf2468SDavid du Colombier 		slowdyn = 1;
2622ddf2468SDavid du Colombier 		break;
2632ddf2468SDavid du Colombier 	case 'x':
2642ddf2468SDavid du Colombier 		setnetmtpt(net, sizeof net, EARGF(usage()));
2652ddf2468SDavid du Colombier 		break;
2662ddf2468SDavid du Colombier 	case 'Z':
2672ddf2468SDavid du Colombier 		staticlease = atoi(EARGF(usage()));
2682ddf2468SDavid du Colombier 		if(staticlease <= 0)
2692ddf2468SDavid du Colombier 			staticlease = StaticLease;
2702ddf2468SDavid du Colombier 		break;
2712ddf2468SDavid du Colombier 	default:
2727dd7cddfSDavid du Colombier 		usage();
2737dd7cddfSDavid du Colombier 		break;
2747dd7cddfSDavid du Colombier 	} ARGEND;
2757dd7cddfSDavid du Colombier 
2767dd7cddfSDavid du Colombier 	while(argc > 1){
2777dd7cddfSDavid du Colombier 		parseip(ip, argv[0]);
2787dd7cddfSDavid du Colombier 		if(!validip(ip))
2797dd7cddfSDavid du Colombier 			usage();
2807dd7cddfSDavid du Colombier 		n = atoi(argv[1]);
2817dd7cddfSDavid du Colombier 		if(n <= 0)
2827dd7cddfSDavid du Colombier 			usage();
2837dd7cddfSDavid du Colombier 		initbinding(ip, n);
2847dd7cddfSDavid du Colombier 		argc -= 2;
2857dd7cddfSDavid du Colombier 		argv += 2;
2867dd7cddfSDavid du Colombier 	}
2877dd7cddfSDavid du Colombier 
2883ff48bf5SDavid du Colombier 	/* for debugging */
2893ff48bf5SDavid du Colombier 	for(i = 0; i < 256; i++)
2903ff48bf5SDavid du Colombier 		if(optname[i] == 0)
2913ff48bf5SDavid du Colombier 			optname[i] = smprint("%d", i);
2923ff48bf5SDavid du Colombier 
2937dd7cddfSDavid du Colombier 	/* what is my name? */
2942ddf2468SDavid du Colombier 	strcpy(mysysname, readsysname());
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier 	/* put process in background */
2970a84db5eSDavid du Colombier 	if(!debug)
2980a84db5eSDavid du Colombier 	switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
2997dd7cddfSDavid du Colombier 	case -1:
3007dd7cddfSDavid du Colombier 		fatal(1, "fork");
3017dd7cddfSDavid du Colombier 	case 0:
3027dd7cddfSDavid du Colombier 		break;
3037dd7cddfSDavid du Colombier 	default:
3047dd7cddfSDavid du Colombier 		exits(0);
3057dd7cddfSDavid du Colombier 	}
3067dd7cddfSDavid du Colombier 
307ea58ad6fSDavid du Colombier 	if (chdir(TFTP) < 0)
308ea58ad6fSDavid du Colombier 		warning(1, "can't change directory to %s", TFTP);
3097dd7cddfSDavid du Colombier 	fd = openlisten(net);
3107dd7cddfSDavid du Colombier 
3117dd7cddfSDavid du Colombier 	for(;;){
3127dd7cddfSDavid du Colombier 		memset(&r, 0, sizeof(r));
3137dd7cddfSDavid du Colombier 		r.fd = fd;
3143ff48bf5SDavid du Colombier 		n = readlast(r.fd, r.buf, sizeof(r.buf));
315f27a9a5aSDavid du Colombier 		if(n < Udphdrsize)
3167dd7cddfSDavid du Colombier 			fatal(1, "error reading requests");
3173ff48bf5SDavid du Colombier 		start = nsec()/1000;
3183ff48bf5SDavid du Colombier 		op = optbuf;
3193ff48bf5SDavid du Colombier 		*op = 0;
3207dd7cddfSDavid du Colombier 		proto(&r, n);
3217dd7cddfSDavid du Colombier 		if(r.id != nil)
3227dd7cddfSDavid du Colombier 			free(r.id);
3237dd7cddfSDavid du Colombier 	}
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier void
proto(Req * rp,int n)3277dd7cddfSDavid du Colombier proto(Req *rp, int n)
3287dd7cddfSDavid du Colombier {
3297dd7cddfSDavid du Colombier 	uchar relip[IPaddrlen];
3307dd7cddfSDavid du Colombier 	char buf[64];
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	now = time(0);
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier 	rp->e = rp->buf + n;
3357dd7cddfSDavid du Colombier 	rp->bp = (Bootp*)rp->buf;
336f27a9a5aSDavid du Colombier 	rp->up = (Udphdr*)rp->buf;
3378ae63d3dSDavid du Colombier 	if (ipcmp(rp->up->laddr, IPv4bcast) == 0){
338decede3dSDavid du Colombier 		ipmove(rp->up->laddr, rp->up->ifcaddr);
3398ae63d3dSDavid du Colombier 		rp->broadcast = 1;
3408ae63d3dSDavid du Colombier 	}
341f27a9a5aSDavid du Colombier 	rp->max = rp->buf + Udphdrsize + MINSUPPORTED - IPUDPHDRSIZE;
3427dd7cddfSDavid du Colombier 	rp->p = rp->bp->optdata;
3437dd7cddfSDavid du Colombier 	v4tov6(rp->giaddr, rp->bp->giaddr);
3447dd7cddfSDavid du Colombier 	v4tov6(rp->ciaddr, rp->bp->ciaddr);
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier 	if(pptponly && rp->bp->htype != 0)
3477dd7cddfSDavid du Colombier 		return;
3487dd7cddfSDavid du Colombier 
3499a747e4fSDavid du Colombier 	ipifcs = readipifc(net, ipifcs, -1);
3507dd7cddfSDavid du Colombier 	if(validip(rp->giaddr))
3517dd7cddfSDavid du Colombier 		ipmove(relip, rp->giaddr);
3527dd7cddfSDavid du Colombier 	else if(validip(rp->up->raddr))
3537dd7cddfSDavid du Colombier 		ipmove(relip, rp->up->raddr);
3547dd7cddfSDavid du Colombier 	else
3557dd7cddfSDavid du Colombier 		ipmove(relip, rp->up->laddr);
3567dd7cddfSDavid du Colombier 	if(rp->e < (uchar*)rp->bp->sname){
3577dd7cddfSDavid du Colombier 		warning(0, "packet too short");
3587dd7cddfSDavid du Colombier 		return;
3597dd7cddfSDavid du Colombier 	}
3607dd7cddfSDavid du Colombier 	if(rp->bp->op != Bootrequest){
3617dd7cddfSDavid du Colombier 		warning(0, "not bootrequest");
3627dd7cddfSDavid du Colombier 		return;
3637dd7cddfSDavid du Colombier 	}
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier 	if(rp->e >= rp->bp->optdata){
3667dd7cddfSDavid du Colombier 		if(memcmp(rp->bp->optmagic, plan9opt, sizeof(rp->bp->optmagic)) == 0)
3677dd7cddfSDavid du Colombier 			rp->p9request = 1;
3687dd7cddfSDavid du Colombier 		if(memcmp(rp->bp->optmagic, genericopt, sizeof(rp->bp->optmagic)) == 0) {
3697dd7cddfSDavid du Colombier 			rp->genrequest = 1;
3707dd7cddfSDavid du Colombier 			parseoptions(rp);
3713ff48bf5SDavid du Colombier 		}
3723ff48bf5SDavid du Colombier 	}
3737dd7cddfSDavid du Colombier 	rp->p = rp->bp->optdata;
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier 	/*  If no id is specified, make one from the hardware address
3767dd7cddfSDavid du Colombier 	 *  of the target.  We assume all zeros is not a hardware address
3777dd7cddfSDavid du Colombier 	 *  which could be a mistake.
3787dd7cddfSDavid du Colombier 	 */
3797dd7cddfSDavid du Colombier 	if(rp->id == nil){
3807dd7cddfSDavid du Colombier 		if(rp->bp->hlen > Maxhwlen){
3817dd7cddfSDavid du Colombier 			warning(0, "hlen %d", rp->bp->hlen);
3827dd7cddfSDavid du Colombier 			return;
3837dd7cddfSDavid du Colombier 		}
3847dd7cddfSDavid du Colombier 		if(memcmp(zeros, rp->bp->chaddr, rp->bp->hlen) == 0){
3857dd7cddfSDavid du Colombier 			warning(0, "no chaddr");
3867dd7cddfSDavid du Colombier 			return;
3877dd7cddfSDavid du Colombier 		}
3887dd7cddfSDavid du Colombier 		sprint(buf, "hwa%2.2ux_", rp->bp->htype);
3897dd7cddfSDavid du Colombier 		rp->id = tohex(buf, rp->bp->chaddr, rp->bp->hlen);
3907dd7cddfSDavid du Colombier 	}
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 	/* info about gateway */
3933ff48bf5SDavid du Colombier 	if(lookupip(relip, &rp->gii, 1) < 0){
3947dd7cddfSDavid du Colombier 		warning(0, "lookupip failed");
3957dd7cddfSDavid du Colombier 		return;
3967dd7cddfSDavid du Colombier 	}
3977dd7cddfSDavid du Colombier 
3987dd7cddfSDavid du Colombier 	/* info about target system */
3997dd7cddfSDavid du Colombier 	if(lookup(rp->bp, &rp->ii, &rp->gii) == 0)
4007dd7cddfSDavid du Colombier 		if(rp->ii.indb && rp->ii.dhcpgroup[0] == 0)
4017dd7cddfSDavid du Colombier 			rp->staticbinding = 1;
4027dd7cddfSDavid du Colombier 
4037dd7cddfSDavid du Colombier 	if(rp->dhcptype)
4047dd7cddfSDavid du Colombier 		dhcp(rp);
4057dd7cddfSDavid du Colombier 	else
4067dd7cddfSDavid du Colombier 		bootp(rp);
4073ff48bf5SDavid du Colombier 	timestamp("done");
4087dd7cddfSDavid du Colombier }
4097dd7cddfSDavid du Colombier 
4108ae63d3dSDavid du Colombier /*
4118ae63d3dSDavid du Colombier  * since we are single-threaded, this causes us to effectively
412*588d0145SDavid du Colombier  * stop listening while we sleep.
4138ae63d3dSDavid du Colombier  */
414e183b1a6SDavid du Colombier static void
slowdelay(Req * rp)415e183b1a6SDavid du Colombier slowdelay(Req *rp)
416e183b1a6SDavid du Colombier {
417e183b1a6SDavid du Colombier 	if(slowstat && rp->staticbinding || slowdyn && !rp->staticbinding)
418*588d0145SDavid du Colombier 		sleep(1000);
419e183b1a6SDavid du Colombier }
420e183b1a6SDavid du Colombier 
4217dd7cddfSDavid du Colombier void
dhcp(Req * rp)4227dd7cddfSDavid du Colombier dhcp(Req *rp)
4237dd7cddfSDavid du Colombier {
4247dd7cddfSDavid du Colombier 	logdhcp(rp);
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 	switch(rp->dhcptype){
4277dd7cddfSDavid du Colombier 	case Discover:
428e183b1a6SDavid du Colombier 		slowdelay(rp);
4297dd7cddfSDavid du Colombier 		rcvdiscover(rp);
4307dd7cddfSDavid du Colombier 		break;
4317dd7cddfSDavid du Colombier 	case Request:
4327dd7cddfSDavid du Colombier 		rcvrequest(rp);
4337dd7cddfSDavid du Colombier 		break;
4347dd7cddfSDavid du Colombier 	case Decline:
4357dd7cddfSDavid du Colombier 		rcvdecline(rp);
4367dd7cddfSDavid du Colombier 		break;
4377dd7cddfSDavid du Colombier 	case Release:
4387dd7cddfSDavid du Colombier 		rcvrelease(rp);
4397dd7cddfSDavid du Colombier 		break;
4407dd7cddfSDavid du Colombier 	case Inform:
4417dd7cddfSDavid du Colombier 		rcvinform(rp);
4427dd7cddfSDavid du Colombier 		break;
4437dd7cddfSDavid du Colombier 	}
4447dd7cddfSDavid du Colombier }
4457dd7cddfSDavid du Colombier 
4467dd7cddfSDavid du Colombier void
rcvdiscover(Req * rp)4477dd7cddfSDavid du Colombier rcvdiscover(Req *rp)
4487dd7cddfSDavid du Colombier {
4497dd7cddfSDavid du Colombier 	Binding *b, *nb;
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 	if(rp->staticbinding){
4522ddf2468SDavid du Colombier 		sendoffer(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease));
4537dd7cddfSDavid du Colombier 		return;
4547dd7cddfSDavid du Colombier 	}
4557dd7cddfSDavid du Colombier 
4567dd7cddfSDavid du Colombier 	/*
4577dd7cddfSDavid du Colombier 	 *  first look for an outstanding offer
4587dd7cddfSDavid du Colombier 	 */
4597dd7cddfSDavid du Colombier 	b = idtooffer(rp->id, &rp->gii);
4607dd7cddfSDavid du Colombier 
4617dd7cddfSDavid du Colombier 	/*
4627dd7cddfSDavid du Colombier 	 * rfc2131 says:
4637dd7cddfSDavid du Colombier 	 *   If an address is available, the new address
4647dd7cddfSDavid du Colombier 	 *   SHOULD be chosen as follows:
4657dd7cddfSDavid du Colombier 	 *
4667dd7cddfSDavid du Colombier 	 *      o The client's current address as recorded in the client's current
4677dd7cddfSDavid du Colombier 	 *        binding, ELSE
4687dd7cddfSDavid du Colombier 	 *
4697dd7cddfSDavid du Colombier 	 *      o The client's previous address as recorded in the client's (now
4707dd7cddfSDavid du Colombier 	 *        expired or released) binding, if that address is in the server's
4717dd7cddfSDavid du Colombier 	 *        pool of available addresses and not already allocated, ELSE
4727dd7cddfSDavid du Colombier 	 *
4737dd7cddfSDavid du Colombier 	 *      o The address requested in the 'Requested IP Address' option, if that
4747dd7cddfSDavid du Colombier 	 *        address is valid and not already allocated, ELSE
4757dd7cddfSDavid du Colombier 	 *
4767dd7cddfSDavid du Colombier 	 *      o A new address allocated from the server's pool of available
4777dd7cddfSDavid du Colombier 	 *        addresses; the address is selected based on the subnet from which
4787dd7cddfSDavid du Colombier 	 *        the message was received (if 'giaddr' is 0) or on the address of
4797dd7cddfSDavid du Colombier 	 *        the relay agent that forwarded the message ('giaddr' when not 0).
4807dd7cddfSDavid du Colombier 	 */
4817dd7cddfSDavid du Colombier 	if(b == nil){
4827dd7cddfSDavid du Colombier 		b = idtobinding(rp->id, &rp->gii, 1);
4837dd7cddfSDavid du Colombier 		if(b && b->boundto && strcmp(b->boundto, rp->id) != 0)
4847dd7cddfSDavid du Colombier 		if(validip(rp->ip) && samenet(rp->ip, &rp->gii)){
4857dd7cddfSDavid du Colombier 			nb = iptobinding(rp->ip, 0);
4867dd7cddfSDavid du Colombier 			if(nb && nb->lease < now)
4877dd7cddfSDavid du Colombier 				b = nb;
4887dd7cddfSDavid du Colombier 		}
4897dd7cddfSDavid du Colombier 	}
4907dd7cddfSDavid du Colombier 	if(b == nil){
4913ff48bf5SDavid du Colombier 		warning(0, "!Discover(%s via %I): no binding %I",
4923ff48bf5SDavid du Colombier 			rp->id, rp->gii.ipaddr, rp->ip);
4937dd7cddfSDavid du Colombier 		return;
4947dd7cddfSDavid du Colombier 	}
4957dd7cddfSDavid du Colombier 	mkoffer(b, rp->id, rp->leasetime);
4967dd7cddfSDavid du Colombier 	sendoffer(rp, b->ip, b->offer);
4977dd7cddfSDavid du Colombier }
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier void
rcvrequest(Req * rp)5007dd7cddfSDavid du Colombier rcvrequest(Req *rp)
5017dd7cddfSDavid du Colombier {
5027dd7cddfSDavid du Colombier 	Binding *b;
5037dd7cddfSDavid du Colombier 
5047dd7cddfSDavid du Colombier 	if(validip(rp->server)){
5057dd7cddfSDavid du Colombier 		/* this is a reply to an offer - SELECTING */
5067dd7cddfSDavid du Colombier 
5077dd7cddfSDavid du Colombier 		/* check for hard assignment */
5087dd7cddfSDavid du Colombier 		if(rp->staticbinding){
5097dd7cddfSDavid du Colombier 			if(forme(rp->server))
5100a84db5eSDavid du Colombier 				sendack(rp, rp->ii.ipaddr,
5110a84db5eSDavid du Colombier 					(staticlease > minlease? staticlease:
5120a84db5eSDavid du Colombier 					minlease), 1);
5137dd7cddfSDavid du Colombier 			else
5143ff48bf5SDavid du Colombier 				warning(0, "!Request(%s via %I): for server %I not me",
5153ff48bf5SDavid du Colombier 					rp->id, rp->gii.ipaddr, rp->server);
5167dd7cddfSDavid du Colombier 			return;
5177dd7cddfSDavid du Colombier 		}
5187dd7cddfSDavid du Colombier 
5197dd7cddfSDavid du Colombier 		b = idtooffer(rp->id, &rp->gii);
5207dd7cddfSDavid du Colombier 
5217dd7cddfSDavid du Colombier 		/* if we don't have an offer, nak */
5227dd7cddfSDavid du Colombier 		if(b == nil){
5233ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): no offer",
5247dd7cddfSDavid du Colombier 				rp->id, rp->gii.ipaddr);
5257dd7cddfSDavid du Colombier 			if(forme(rp->server))
5267dd7cddfSDavid du Colombier 				sendnak(rp, "no offer for you");
5277dd7cddfSDavid du Colombier 			return;
5287dd7cddfSDavid du Colombier 		}
5297dd7cddfSDavid du Colombier 
5307dd7cddfSDavid du Colombier 		/* if not for me, retract offer */
5317dd7cddfSDavid du Colombier 		if(!forme(rp->server)){
5327dd7cddfSDavid du Colombier 			b->expoffer = 0;
5333ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): for server %I not me",
5343ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, rp->server);
5357dd7cddfSDavid du Colombier 			return;
5367dd7cddfSDavid du Colombier 		}
5377dd7cddfSDavid du Colombier 
5387dd7cddfSDavid du Colombier 		/*
5397dd7cddfSDavid du Colombier 		 *  if the client is confused about what we offered, nak.
5407dd7cddfSDavid du Colombier 		 *  client really shouldn't be specifying this when selecting
5417dd7cddfSDavid du Colombier 		 */
5427dd7cddfSDavid du Colombier 		if(validip(rp->ip) && ipcmp(rp->ip, b->ip) != 0){
5433ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): requests %I, not %I",
5447dd7cddfSDavid du Colombier 				rp->id, rp->gii.ipaddr, rp->ip, b->ip);
5457dd7cddfSDavid du Colombier 			sendnak(rp, "bad ip address option");
5467dd7cddfSDavid du Colombier 			return;
5477dd7cddfSDavid du Colombier 		}
5487dd7cddfSDavid du Colombier 		if(commitbinding(b) < 0){
5493ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): can't commit %I",
5503ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, b->ip);
5517dd7cddfSDavid du Colombier 			sendnak(rp, "can't commit binding");
5527dd7cddfSDavid du Colombier 			return;
5537dd7cddfSDavid du Colombier 		}
5547dd7cddfSDavid du Colombier 		sendack(rp, b->ip, b->offer, 1);
5557dd7cddfSDavid du Colombier 	} else if(validip(rp->ip)){
5567dd7cddfSDavid du Colombier 		/*
5577dd7cddfSDavid du Colombier 		 *  checking address/net - INIT-REBOOT
5587dd7cddfSDavid du Colombier 		 *
5593ff48bf5SDavid du Colombier 		 *  This is a rebooting client that remembers its old
5603ff48bf5SDavid du Colombier 		 *  address.
5617dd7cddfSDavid du Colombier 		 */
5627dd7cddfSDavid du Colombier 		/* check for hard assignment */
5637dd7cddfSDavid du Colombier 		if(rp->staticbinding){
5647dd7cddfSDavid du Colombier 			if(memcmp(rp->ip, rp->ii.ipaddr, IPaddrlen) != 0){
5653ff48bf5SDavid du Colombier 				warning(0, "!Request(%s via %I): %I not valid for %E",
5663ff48bf5SDavid du Colombier 					rp->id, rp->gii.ipaddr, rp->ip, rp->bp->chaddr);
5677dd7cddfSDavid du Colombier 				sendnak(rp, "not valid");
5687dd7cddfSDavid du Colombier 			}
5690a84db5eSDavid du Colombier 			sendack(rp, rp->ii.ipaddr, (staticlease > minlease?
5700a84db5eSDavid du Colombier 				staticlease: minlease), 1);
5717dd7cddfSDavid du Colombier 			return;
5727dd7cddfSDavid du Colombier 		}
5737dd7cddfSDavid du Colombier 
5747dd7cddfSDavid du Colombier 		/* make sure the network makes sense */
5757dd7cddfSDavid du Colombier 		if(!samenet(rp->ip, &rp->gii)){
5763ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): bad forward of %I",
5773ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, rp->ip);
5787dd7cddfSDavid du Colombier 			sendnak(rp, "wrong network");
5797dd7cddfSDavid du Colombier 			return;
5807dd7cddfSDavid du Colombier 		}
5817dd7cddfSDavid du Colombier 		b = iptobinding(rp->ip, 0);
5827dd7cddfSDavid du Colombier 		if(b == nil){
5830a84db5eSDavid du Colombier 			warning(0, "!Request(%s via %I): no binding for %I",
5843ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, rp->ip);
5857dd7cddfSDavid du Colombier 			return;
5867dd7cddfSDavid du Colombier 		}
5877dd7cddfSDavid du Colombier 		if(memcmp(rp->ip, b->ip, IPaddrlen) != 0 || now > b->lease){
5883ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): %I not valid",
5893ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, rp->ip);
5907dd7cddfSDavid du Colombier 			sendnak(rp, "not valid");
5917dd7cddfSDavid du Colombier 			return;
5927dd7cddfSDavid du Colombier 		}
5937dd7cddfSDavid du Colombier 		b->offer = b->lease - now;
5947dd7cddfSDavid du Colombier 		sendack(rp, b->ip, b->offer, 1);
5957dd7cddfSDavid du Colombier 	} else if(validip(rp->ciaddr)){
5963ff48bf5SDavid du Colombier 		/*
5973ff48bf5SDavid du Colombier 		 *  checking address - RENEWING or REBINDING
5983ff48bf5SDavid du Colombier 		 *
5993ff48bf5SDavid du Colombier 		 *  these states are indistinguishable in our action.  The only
6003ff48bf5SDavid du Colombier 		 *  difference is how close to lease expiration the client is.
6013ff48bf5SDavid du Colombier 		 *  If it is really close, it broadcasts the request hoping that
6023ff48bf5SDavid du Colombier 		 *  some server will answer.
6033ff48bf5SDavid du Colombier 		 */
6047dd7cddfSDavid du Colombier 
6057dd7cddfSDavid du Colombier 		/* check for hard assignment */
6067dd7cddfSDavid du Colombier 		if(rp->staticbinding){
6077dd7cddfSDavid du Colombier 			if(ipcmp(rp->ciaddr, rp->ii.ipaddr) != 0){
6083ff48bf5SDavid du Colombier 				warning(0, "!Request(%s via %I): %I not valid",
6093ff48bf5SDavid du Colombier 					rp->id, rp->gii.ipaddr, rp->ciaddr);
6107dd7cddfSDavid du Colombier 				sendnak(rp, "not valid");
6117dd7cddfSDavid du Colombier 			}
6120a84db5eSDavid du Colombier 			sendack(rp, rp->ii.ipaddr, (staticlease > minlease?
6130a84db5eSDavid du Colombier 				staticlease: minlease), 1);
6147dd7cddfSDavid du Colombier 			return;
6157dd7cddfSDavid du Colombier 		}
6167dd7cddfSDavid du Colombier 
6177dd7cddfSDavid du Colombier 		/* make sure the network makes sense */
6187dd7cddfSDavid du Colombier 		if(!samenet(rp->ciaddr, &rp->gii)){
6193ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): bad forward of %I",
6203ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, rp->ip);
6217dd7cddfSDavid du Colombier 			sendnak(rp, "wrong network");
6227dd7cddfSDavid du Colombier 			return;
6237dd7cddfSDavid du Colombier 		}
6247dd7cddfSDavid du Colombier 		b = iptobinding(rp->ciaddr, 0);
6257dd7cddfSDavid du Colombier 		if(b == nil){
6263ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): no binding for %I",
6273ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, rp->ciaddr);
6287dd7cddfSDavid du Colombier 			return;
6297dd7cddfSDavid du Colombier 		}
6307dd7cddfSDavid du Colombier 		if(ipcmp(rp->ciaddr, b->ip) != 0){
6313ff48bf5SDavid du Colombier 			warning(0, "!Request(%I via %s): %I not valid",
6323ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, rp->ciaddr);
6337dd7cddfSDavid du Colombier 			sendnak(rp, "invalid ip address");
6347dd7cddfSDavid du Colombier 			return;
6357dd7cddfSDavid du Colombier 		}
6367dd7cddfSDavid du Colombier 		mkoffer(b, rp->id, rp->leasetime);
6377dd7cddfSDavid du Colombier 		if(commitbinding(b) < 0){
6383ff48bf5SDavid du Colombier 			warning(0, "!Request(%s via %I): can't commit %I",
6393ff48bf5SDavid du Colombier 				rp->id, rp->gii.ipaddr, b->ip);
6407dd7cddfSDavid du Colombier 			sendnak(rp, "can't commit binding");
6417dd7cddfSDavid du Colombier 			return;
6427dd7cddfSDavid du Colombier 		}
6437dd7cddfSDavid du Colombier 		sendack(rp, b->ip, b->offer, 1);
6447dd7cddfSDavid du Colombier 	}
6457dd7cddfSDavid du Colombier }
6467dd7cddfSDavid du Colombier 
6477dd7cddfSDavid du Colombier void
rcvdecline(Req * rp)6487dd7cddfSDavid du Colombier rcvdecline(Req *rp)
6497dd7cddfSDavid du Colombier {
6507dd7cddfSDavid du Colombier 	Binding *b;
6517dd7cddfSDavid du Colombier 	char buf[64];
6527dd7cddfSDavid du Colombier 
6537dd7cddfSDavid du Colombier 	if(rp->staticbinding)
6547dd7cddfSDavid du Colombier 		return;
6557dd7cddfSDavid du Colombier 
6567dd7cddfSDavid du Colombier 	b = idtooffer(rp->id, &rp->gii);
6577dd7cddfSDavid du Colombier 	if(b == nil){
6583ff48bf5SDavid du Colombier 		warning(0, "!Decline(%s via %I): no binding",
6597dd7cddfSDavid du Colombier 			rp->id, rp->gii.ipaddr);
6607dd7cddfSDavid du Colombier 		return;
6617dd7cddfSDavid du Colombier 	}
6627dd7cddfSDavid du Colombier 
6637dd7cddfSDavid du Colombier 	/* mark ip address as in use */
6647dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "declined by %s", rp->id);
6657dd7cddfSDavid du Colombier 	mkoffer(b, buf, 0x7fffffff);
6667dd7cddfSDavid du Colombier 	commitbinding(b);
6677dd7cddfSDavid du Colombier }
6687dd7cddfSDavid du Colombier 
6697dd7cddfSDavid du Colombier void
rcvrelease(Req * rp)6707dd7cddfSDavid du Colombier rcvrelease(Req *rp)
6717dd7cddfSDavid du Colombier {
6727dd7cddfSDavid du Colombier 	Binding *b;
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier 	if(rp->staticbinding)
6757dd7cddfSDavid du Colombier 		return;
6767dd7cddfSDavid du Colombier 
6777dd7cddfSDavid du Colombier 	b = idtobinding(rp->id, &rp->gii, 0);
6787dd7cddfSDavid du Colombier 	if(b == nil){
6793ff48bf5SDavid du Colombier 		warning(0, "!Release(%s via %I): no binding",
6807dd7cddfSDavid du Colombier 			rp->id, rp->gii.ipaddr);
6817dd7cddfSDavid du Colombier 		return;
6827dd7cddfSDavid du Colombier 	}
6837dd7cddfSDavid du Colombier 	if(strcmp(rp->id, b->boundto) != 0){
6843ff48bf5SDavid du Colombier 		warning(0, "!Release(%s via %I): invalid release of %I",
6853ff48bf5SDavid du Colombier 			rp->id, rp->gii.ipaddr, rp->ip);
6867dd7cddfSDavid du Colombier 		return;
6877dd7cddfSDavid du Colombier 	}
6883ff48bf5SDavid du Colombier 	warning(0, "Release(%s via %I): releasing %I", b->boundto, rp->gii.ipaddr, b->ip);
6897dd7cddfSDavid du Colombier 	if(releasebinding(b, rp->id) < 0)
6907dd7cddfSDavid du Colombier 		warning(0, "release: couldn't release");
6917dd7cddfSDavid du Colombier }
6927dd7cddfSDavid du Colombier 
6937dd7cddfSDavid du Colombier void
rcvinform(Req * rp)6947dd7cddfSDavid du Colombier rcvinform(Req *rp)
6957dd7cddfSDavid du Colombier {
6967dd7cddfSDavid du Colombier 	Binding *b;
6977dd7cddfSDavid du Colombier 
6987dd7cddfSDavid du Colombier 	if(rp->staticbinding){
6997dd7cddfSDavid du Colombier 		sendack(rp, rp->ii.ipaddr, 0, 0);
7007dd7cddfSDavid du Colombier 		return;
7017dd7cddfSDavid du Colombier 	}
7027dd7cddfSDavid du Colombier 
7037dd7cddfSDavid du Colombier 	b = iptobinding(rp->ciaddr, 0);
7047dd7cddfSDavid du Colombier 	if(b == nil){
7053ff48bf5SDavid du Colombier 		warning(0, "!Inform(%s via %I): no binding for %I",
7063ff48bf5SDavid du Colombier 			rp->id, rp->gii.ipaddr, rp->ip);
7077dd7cddfSDavid du Colombier 		return;
7087dd7cddfSDavid du Colombier 	}
7097dd7cddfSDavid du Colombier 	sendack(rp, b->ip, 0, 0);
7107dd7cddfSDavid du Colombier }
7117dd7cddfSDavid du Colombier 
71259cc4ca5SDavid du Colombier int
setsiaddr(uchar * siaddr,uchar * saddr,uchar * laddr)7133ff48bf5SDavid du Colombier setsiaddr(uchar *siaddr, uchar *saddr, uchar *laddr)
71459cc4ca5SDavid du Colombier {
7153ff48bf5SDavid du Colombier 	if(ipcmp(saddr, IPnoaddr) != 0){
7163ff48bf5SDavid du Colombier 		v6tov4(siaddr, saddr);
71759cc4ca5SDavid du Colombier 		return 0;
71859cc4ca5SDavid du Colombier 	} else {
71959cc4ca5SDavid du Colombier 		v6tov4(siaddr, laddr);
72059cc4ca5SDavid du Colombier 		return 1;
72159cc4ca5SDavid du Colombier 	}
72259cc4ca5SDavid du Colombier }
72359cc4ca5SDavid du Colombier 
724e183b1a6SDavid du Colombier int
ismuted(Req * rp)725e183b1a6SDavid du Colombier ismuted(Req *rp)
726e183b1a6SDavid du Colombier {
727e183b1a6SDavid du Colombier 	return mute || (mutestat && rp->staticbinding);
728e183b1a6SDavid du Colombier }
729e183b1a6SDavid du Colombier 
7307dd7cddfSDavid du Colombier void
sendoffer(Req * rp,uchar * ip,int offer)7317dd7cddfSDavid du Colombier sendoffer(Req *rp, uchar *ip, int offer)
7327dd7cddfSDavid du Colombier {
7337dd7cddfSDavid du Colombier 	int n;
7347dd7cddfSDavid du Colombier 	ushort flags;
7357dd7cddfSDavid du Colombier 	Bootp *bp;
736f27a9a5aSDavid du Colombier 	Udphdr *up;
7377dd7cddfSDavid du Colombier 
7387dd7cddfSDavid du Colombier 	bp = rp->bp;
7397dd7cddfSDavid du Colombier 	up = rp->up;
7407dd7cddfSDavid du Colombier 
7417dd7cddfSDavid du Colombier 	/*
7427dd7cddfSDavid du Colombier 	 *  set destination
7437dd7cddfSDavid du Colombier 	 */
7447dd7cddfSDavid du Colombier 	flags = nhgets(bp->flags);
7457dd7cddfSDavid du Colombier 	if(validip(rp->giaddr)){
7467dd7cddfSDavid du Colombier 		ipmove(up->raddr, rp->giaddr);
7477dd7cddfSDavid du Colombier 		hnputs(up->rport, 67);
7487dd7cddfSDavid du Colombier 	} else if(flags & Fbroadcast){
7497dd7cddfSDavid du Colombier 		ipmove(up->raddr, IPv4bcast);
7507dd7cddfSDavid du Colombier 		hnputs(up->rport, 68);
7517dd7cddfSDavid du Colombier 	} else {
7527dd7cddfSDavid du Colombier 		ipmove(up->raddr, ip);
7537dd7cddfSDavid du Colombier 		if(bp->htype == 1)
7547dd7cddfSDavid du Colombier 			arpenter(up->raddr, bp->chaddr);
7557dd7cddfSDavid du Colombier 		hnputs(up->rport, 68);
7567dd7cddfSDavid du Colombier 	}
7577dd7cddfSDavid du Colombier 
7587dd7cddfSDavid du Colombier 	/*
7597dd7cddfSDavid du Colombier 	 *  fill in standard bootp part
7607dd7cddfSDavid du Colombier 	 */
7617dd7cddfSDavid du Colombier 	bp->op = Bootreply;
7627dd7cddfSDavid du Colombier 	bp->hops = 0;
7637dd7cddfSDavid du Colombier 	hnputs(bp->secs, 0);
7647dd7cddfSDavid du Colombier 	memset(bp->ciaddr, 0, sizeof(bp->ciaddr));
76580ee5cbfSDavid du Colombier 	v6tov4(bp->giaddr, rp->giaddr);
7667dd7cddfSDavid du Colombier 	v6tov4(bp->yiaddr, ip);
7673ff48bf5SDavid du Colombier 	setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr);
7687dd7cddfSDavid du Colombier 	strncpy(bp->sname, mysysname, sizeof(bp->sname));
7697dd7cddfSDavid du Colombier 	strncpy(bp->file, rp->ii.bootf, sizeof(bp->file));
7707dd7cddfSDavid du Colombier 
7717dd7cddfSDavid du Colombier 	/*
7727dd7cddfSDavid du Colombier 	 *  set options
7737dd7cddfSDavid du Colombier 	 */
7747dd7cddfSDavid du Colombier 	byteopt(rp, ODtype, Offer);
7757dd7cddfSDavid du Colombier 	longopt(rp, ODlease, offer);
7767dd7cddfSDavid du Colombier 	addropt(rp, ODserverid, up->laddr);
7777dd7cddfSDavid du Colombier 	miscoptions(rp, ip);
7787dd7cddfSDavid du Colombier 	termopt(rp);
7797dd7cddfSDavid du Colombier 
7803ff48bf5SDavid du Colombier 	logdhcpout(rp, "Offer");
7817dd7cddfSDavid du Colombier 
7827dd7cddfSDavid du Colombier 	/*
7837dd7cddfSDavid du Colombier 	 *  send
7847dd7cddfSDavid du Colombier 	 */
7857dd7cddfSDavid du Colombier 	n = rp->p - rp->buf;
786e183b1a6SDavid du Colombier 	if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
7877dd7cddfSDavid du Colombier 		warning(0, "offer: write failed: %r");
7887dd7cddfSDavid du Colombier }
7897dd7cddfSDavid du Colombier 
7907dd7cddfSDavid du Colombier void
sendack(Req * rp,uchar * ip,int offer,int sendlease)7917dd7cddfSDavid du Colombier sendack(Req *rp, uchar *ip, int offer, int sendlease)
7927dd7cddfSDavid du Colombier {
7937dd7cddfSDavid du Colombier 	int n;
7947dd7cddfSDavid du Colombier 	ushort flags;
7957dd7cddfSDavid du Colombier 	Bootp *bp;
796f27a9a5aSDavid du Colombier 	Udphdr *up;
7977dd7cddfSDavid du Colombier 
7987dd7cddfSDavid du Colombier 	bp = rp->bp;
7997dd7cddfSDavid du Colombier 	up = rp->up;
8007dd7cddfSDavid du Colombier 
8017dd7cddfSDavid du Colombier 	/*
8027dd7cddfSDavid du Colombier 	 *  set destination
8037dd7cddfSDavid du Colombier 	 */
8047dd7cddfSDavid du Colombier 	flags = nhgets(bp->flags);
8057dd7cddfSDavid du Colombier 	if(validip(rp->giaddr)){
8067dd7cddfSDavid du Colombier 		ipmove(up->raddr, rp->giaddr);
8077dd7cddfSDavid du Colombier 		hnputs(up->rport, 67);
8087dd7cddfSDavid du Colombier 	} else if(flags & Fbroadcast){
8097dd7cddfSDavid du Colombier 		ipmove(up->raddr, IPv4bcast);
8107dd7cddfSDavid du Colombier 		hnputs(up->rport, 68);
8117dd7cddfSDavid du Colombier 	} else {
8127dd7cddfSDavid du Colombier 		ipmove(up->raddr, ip);
8137dd7cddfSDavid du Colombier 		if(bp->htype == 1)
8147dd7cddfSDavid du Colombier 			arpenter(up->raddr, bp->chaddr);
8157dd7cddfSDavid du Colombier 		hnputs(up->rport, 68);
8167dd7cddfSDavid du Colombier 	}
8177dd7cddfSDavid du Colombier 
8187dd7cddfSDavid du Colombier 	/*
8197dd7cddfSDavid du Colombier 	 *  fill in standard bootp part
8207dd7cddfSDavid du Colombier 	 */
8217dd7cddfSDavid du Colombier 	bp->op = Bootreply;
8227dd7cddfSDavid du Colombier 	bp->hops = 0;
8237dd7cddfSDavid du Colombier 	hnputs(bp->secs, 0);
82480ee5cbfSDavid du Colombier 	v6tov4(bp->giaddr, rp->giaddr);
8257dd7cddfSDavid du Colombier 	v6tov4(bp->yiaddr, ip);
8263ff48bf5SDavid du Colombier 	setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr);
8277dd7cddfSDavid du Colombier 	strncpy(bp->sname, mysysname, sizeof(bp->sname));
8287dd7cddfSDavid du Colombier 	strncpy(bp->file, rp->ii.bootf, sizeof(bp->file));
8297dd7cddfSDavid du Colombier 
8307dd7cddfSDavid du Colombier 	/*
8317dd7cddfSDavid du Colombier 	 *  set options
8327dd7cddfSDavid du Colombier 	 */
8337dd7cddfSDavid du Colombier 	byteopt(rp, ODtype, Ack);
8343ff48bf5SDavid du Colombier 	if(sendlease){
8357dd7cddfSDavid du Colombier 		longopt(rp, ODlease, offer);
8363ff48bf5SDavid du Colombier 	}
8377dd7cddfSDavid du Colombier 	addropt(rp, ODserverid, up->laddr);
8387dd7cddfSDavid du Colombier 	miscoptions(rp, ip);
8397dd7cddfSDavid du Colombier 	termopt(rp);
8407dd7cddfSDavid du Colombier 
8413ff48bf5SDavid du Colombier 	logdhcpout(rp, "Ack");
8427dd7cddfSDavid du Colombier 
8437dd7cddfSDavid du Colombier 	/*
8447dd7cddfSDavid du Colombier 	 *  send
8457dd7cddfSDavid du Colombier 	 */
8467dd7cddfSDavid du Colombier 	n = rp->p - rp->buf;
847e183b1a6SDavid du Colombier 	if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
8487dd7cddfSDavid du Colombier 		warning(0, "ack: write failed: %r");
8497dd7cddfSDavid du Colombier }
8507dd7cddfSDavid du Colombier 
8517dd7cddfSDavid du Colombier void
sendnak(Req * rp,char * msg)8527dd7cddfSDavid du Colombier sendnak(Req *rp, char *msg)
8537dd7cddfSDavid du Colombier {
8547dd7cddfSDavid du Colombier 	int n;
8557dd7cddfSDavid du Colombier 	Bootp *bp;
856f27a9a5aSDavid du Colombier 	Udphdr *up;
8577dd7cddfSDavid du Colombier 
8587dd7cddfSDavid du Colombier 	bp = rp->bp;
8597dd7cddfSDavid du Colombier 	up = rp->up;
8607dd7cddfSDavid du Colombier 
8617dd7cddfSDavid du Colombier 	/*
8627dd7cddfSDavid du Colombier 	 *  set destination (always broadcast)
8637dd7cddfSDavid du Colombier 	 */
8647dd7cddfSDavid du Colombier 	if(validip(rp->giaddr)){
8657dd7cddfSDavid du Colombier 		ipmove(up->raddr, rp->giaddr);
8667dd7cddfSDavid du Colombier 		hnputs(up->rport, 67);
8677dd7cddfSDavid du Colombier 	} else {
8687dd7cddfSDavid du Colombier 		ipmove(up->raddr, IPv4bcast);
8697dd7cddfSDavid du Colombier 		hnputs(up->rport, 68);
8707dd7cddfSDavid du Colombier 	}
8717dd7cddfSDavid du Colombier 
8727dd7cddfSDavid du Colombier 	/*
8737dd7cddfSDavid du Colombier 	 *  fill in standard bootp part
8747dd7cddfSDavid du Colombier 	 */
8757dd7cddfSDavid du Colombier 	bp->op = Bootreply;
8767dd7cddfSDavid du Colombier 	bp->hops = 0;
8777dd7cddfSDavid du Colombier 	hnputs(bp->secs, 0);
87880ee5cbfSDavid du Colombier 	v6tov4(bp->giaddr, rp->giaddr);
8797dd7cddfSDavid du Colombier 	memset(bp->ciaddr, 0, sizeof(bp->ciaddr));
8807dd7cddfSDavid du Colombier 	memset(bp->yiaddr, 0, sizeof(bp->yiaddr));
8817dd7cddfSDavid du Colombier 	memset(bp->siaddr, 0, sizeof(bp->siaddr));
8827dd7cddfSDavid du Colombier 
8837dd7cddfSDavid du Colombier 	/*
8847dd7cddfSDavid du Colombier 	 *  set options
8857dd7cddfSDavid du Colombier 	 */
8867dd7cddfSDavid du Colombier 	byteopt(rp, ODtype, Nak);
8877dd7cddfSDavid du Colombier 	addropt(rp, ODserverid, up->laddr);
8887dd7cddfSDavid du Colombier 	if(msg)
8897dd7cddfSDavid du Colombier 		stringopt(rp, ODmessage, msg);
8907dd7cddfSDavid du Colombier 	if(strncmp(rp->id, "id", 2) == 0)
8917dd7cddfSDavid du Colombier 		hexopt(rp, ODclientid, rp->id+2);
8927dd7cddfSDavid du Colombier 	termopt(rp);
8937dd7cddfSDavid du Colombier 
8943ff48bf5SDavid du Colombier 	logdhcpout(rp, "Nak");
8953ff48bf5SDavid du Colombier 
8967dd7cddfSDavid du Colombier 	/*
8977dd7cddfSDavid du Colombier 	 *  send nak
8987dd7cddfSDavid du Colombier 	 */
8997dd7cddfSDavid du Colombier 	n = rp->p - rp->buf;
900e183b1a6SDavid du Colombier 	if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
9017dd7cddfSDavid du Colombier 		warning(0, "nak: write failed: %r");
9027dd7cddfSDavid du Colombier }
9037dd7cddfSDavid du Colombier 
9047dd7cddfSDavid du Colombier void
bootp(Req * rp)9057dd7cddfSDavid du Colombier bootp(Req *rp)
9067dd7cddfSDavid du Colombier {
9077dd7cddfSDavid du Colombier 	int n;
9087dd7cddfSDavid du Colombier 	Bootp *bp;
909f27a9a5aSDavid du Colombier 	Udphdr *up;
9107dd7cddfSDavid du Colombier 	ushort flags;
9119a747e4fSDavid du Colombier 	Iplifc *lifc;
9127dd7cddfSDavid du Colombier 	Info *iip;
9137dd7cddfSDavid du Colombier 
9148ae63d3dSDavid du Colombier 	warning(0, "bootp %s %I->%I from %s via %I, file %s %s",
9153ff48bf5SDavid du Colombier 		rp->genrequest? "generic": (rp->p9request? "p9": ""),
9167dd7cddfSDavid du Colombier 		rp->up->raddr, rp->up->laddr,
917da51d93aSDavid du Colombier 		rp->id, rp->gii.ipaddr,
9188ae63d3dSDavid du Colombier 		rp->bp->file, rp->broadcast? "broadcast": "unicast");
9197dd7cddfSDavid du Colombier 
9207dd7cddfSDavid du Colombier 	if(nobootp)
9217dd7cddfSDavid du Colombier 		return;
9227dd7cddfSDavid du Colombier 
9237dd7cddfSDavid du Colombier 	bp = rp->bp;
9247dd7cddfSDavid du Colombier 	up = rp->up;
9257dd7cddfSDavid du Colombier 	iip = &rp->ii;
9267dd7cddfSDavid du Colombier 
9277dd7cddfSDavid du Colombier 	if(rp->staticbinding == 0){
9287dd7cddfSDavid du Colombier 		warning(0, "bootp from unknown %s via %I", rp->id, rp->gii.ipaddr);
9297dd7cddfSDavid du Colombier 		return;
9307dd7cddfSDavid du Colombier 	}
9317dd7cddfSDavid du Colombier 
9327dd7cddfSDavid du Colombier 	/* ignore if not for us */
9337dd7cddfSDavid du Colombier 	if(*bp->sname){
9347dd7cddfSDavid du Colombier 		if(strcmp(bp->sname, mysysname) != 0){
9357dd7cddfSDavid du Colombier 			bp->sname[20] = 0;
9367dd7cddfSDavid du Colombier 			warning(0, "bootp for server %s", bp->sname);
9377dd7cddfSDavid du Colombier 			return;
9387dd7cddfSDavid du Colombier 		}
939e183b1a6SDavid du Colombier 	} else
940e183b1a6SDavid du Colombier 		slowdelay(rp);
9417dd7cddfSDavid du Colombier 
9427dd7cddfSDavid du Colombier 	/* ignore if we don't know what file to load */
9437dd7cddfSDavid du Colombier 	if(*bp->file == 0){
9440a84db5eSDavid du Colombier 		if(rp->genrequest && *iip->bootf2) /* if not plan 9 & have alternate file... */
9453ff48bf5SDavid du Colombier 			strncpy(bp->file, iip->bootf2, sizeof(bp->file));
9463ff48bf5SDavid du Colombier 		else if(*iip->bootf)
9477dd7cddfSDavid du Colombier 			strncpy(bp->file, iip->bootf, sizeof(bp->file));
9487dd7cddfSDavid du Colombier 		else if(*bp->sname) /* if we were asked, respond no matter what */
9497dd7cddfSDavid du Colombier 			bp->file[0] = '\0';
9507dd7cddfSDavid du Colombier 		else {
9517dd7cddfSDavid du Colombier 			warning(0, "no bootfile for %I", iip->ipaddr);
9527dd7cddfSDavid du Colombier 			return;
9537dd7cddfSDavid du Colombier 		}
9547dd7cddfSDavid du Colombier 	}
9557dd7cddfSDavid du Colombier 
9567dd7cddfSDavid du Colombier 	/* ignore if the file is unreadable */
9573ff48bf5SDavid du Colombier 	if((!rp->genrequest) && bp->file[0] && access(bp->file, 4) < 0){
9589a747e4fSDavid du Colombier 		warning(0, "inaccessible bootfile1 %s", bp->file);
9597dd7cddfSDavid du Colombier 		return;
9607dd7cddfSDavid du Colombier 	}
9617dd7cddfSDavid du Colombier 
9627dd7cddfSDavid du Colombier 	bp->op = Bootreply;
9637dd7cddfSDavid du Colombier 	v6tov4(bp->yiaddr, iip->ipaddr);
9647dd7cddfSDavid du Colombier 	if(rp->p9request){
9657dd7cddfSDavid du Colombier 		warning(0, "p9bootp: %I", iip->ipaddr);
9667dd7cddfSDavid du Colombier 		memmove(bp->optmagic, plan9opt, 4);
9677dd7cddfSDavid du Colombier 		if(iip->gwip == 0)
9687dd7cddfSDavid du Colombier 			v4tov6(iip->gwip, bp->giaddr);
9697dd7cddfSDavid du Colombier 		rp->p += sprint((char*)rp->p, "%V %I %I %I", iip->ipmask+IPv4off, iip->fsip,
9707dd7cddfSDavid du Colombier 				iip->auip, iip->gwip);
9713ff48bf5SDavid du Colombier 		sprint(optbuf, "%s", (char*)(bp->optmagic));
9727dd7cddfSDavid du Colombier 	} else if(rp->genrequest){
9737dd7cddfSDavid du Colombier 		warning(0, "genericbootp: %I", iip->ipaddr);
9747dd7cddfSDavid du Colombier 		memmove(bp->optmagic, genericopt, 4);
9757dd7cddfSDavid du Colombier 		miscoptions(rp, iip->ipaddr);
9767dd7cddfSDavid du Colombier 		termopt(rp);
9777dd7cddfSDavid du Colombier 	} else if(iip->vendor[0] != 0) {
9787dd7cddfSDavid du Colombier 		warning(0, "bootp vendor field: %s", iip->vendor);
9797dd7cddfSDavid du Colombier 		memset(rp->p, 0, 128-4);
9807dd7cddfSDavid du Colombier 		rp->p += sprint((char*)bp->optmagic, "%s", iip->vendor);
9817dd7cddfSDavid du Colombier 	} else {
9827dd7cddfSDavid du Colombier 		memset(rp->p, 0, 128-4);
9837dd7cddfSDavid du Colombier 		rp->p += 128-4;
9847dd7cddfSDavid du Colombier 	}
9857dd7cddfSDavid du Colombier 
9867dd7cddfSDavid du Colombier 	/*
9877dd7cddfSDavid du Colombier 	 *  set destination
9887dd7cddfSDavid du Colombier 	 */
9897dd7cddfSDavid du Colombier 	flags = nhgets(bp->flags);
9907dd7cddfSDavid du Colombier 	if(validip(rp->giaddr)){
9917dd7cddfSDavid du Colombier 		ipmove(up->raddr, rp->giaddr);
9927dd7cddfSDavid du Colombier 		hnputs(up->rport, 67);
9937dd7cddfSDavid du Colombier 	} else if(flags & Fbroadcast){
9947dd7cddfSDavid du Colombier 		ipmove(up->raddr, IPv4bcast);
9957dd7cddfSDavid du Colombier 		hnputs(up->rport, 68);
9967dd7cddfSDavid du Colombier 	} else {
9977dd7cddfSDavid du Colombier 		v4tov6(up->raddr, bp->yiaddr);
9987dd7cddfSDavid du Colombier 		if(bp->htype == 1)
9997dd7cddfSDavid du Colombier 			arpenter(up->raddr, bp->chaddr);
10007dd7cddfSDavid du Colombier 		hnputs(up->rport, 68);
10017dd7cddfSDavid du Colombier 	}
10027dd7cddfSDavid du Colombier 
10037dd7cddfSDavid du Colombier 	/*
10047dd7cddfSDavid du Colombier 	 *  select best local address if destination is directly connected
10057dd7cddfSDavid du Colombier 	 */
10069a747e4fSDavid du Colombier 	lifc = findlifc(up->raddr);
10079a747e4fSDavid du Colombier 	if(lifc)
10089a747e4fSDavid du Colombier 		ipmove(up->laddr, lifc->ip);
10097dd7cddfSDavid du Colombier 
10107dd7cddfSDavid du Colombier 	/*
10117dd7cddfSDavid du Colombier 	 *  our identity
10127dd7cddfSDavid du Colombier 	 */
10137dd7cddfSDavid du Colombier 	strncpy(bp->sname, mysysname, sizeof(bp->sname));
10143ff48bf5SDavid du Colombier 
10153ff48bf5SDavid du Colombier 	/*
10163ff48bf5SDavid du Colombier 	 *  set tftp server
10173ff48bf5SDavid du Colombier 	 */
10183ff48bf5SDavid du Colombier 	setsiaddr(bp->siaddr, iip->tftp, up->laddr);
10193ff48bf5SDavid du Colombier 	if(rp->genrequest && *iip->bootf2)
10203ff48bf5SDavid du Colombier 		setsiaddr(bp->siaddr, iip->tftp2, up->laddr);
102159cc4ca5SDavid du Colombier 
10227dd7cddfSDavid du Colombier 	/*
10237dd7cddfSDavid du Colombier 	 * RFC 1048 says that we must pad vendor field with
10247dd7cddfSDavid du Colombier 	 * zeros until we have a 64 byte field.
10257dd7cddfSDavid du Colombier 	 */
10267dd7cddfSDavid du Colombier 	n = rp->p - rp->bp->optdata;
10277dd7cddfSDavid du Colombier 	if(n < 64-4) {
10287dd7cddfSDavid du Colombier 		memset(rp->p, 0, (64-4)-n);
10297dd7cddfSDavid du Colombier 		rp->p += (64-4)-n;
10307dd7cddfSDavid du Colombier 	}
10317dd7cddfSDavid du Colombier 
10327dd7cddfSDavid du Colombier 	/*
10337dd7cddfSDavid du Colombier 	 *  send
10347dd7cddfSDavid du Colombier 	 */
10357dd7cddfSDavid du Colombier 	n = rp->p - rp->buf;
1036e183b1a6SDavid du Colombier 	if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
10377dd7cddfSDavid du Colombier 		warning(0, "bootp: write failed: %r");
10383ff48bf5SDavid du Colombier 
10393ff48bf5SDavid du Colombier 	warning(0, "bootp via %I: file %s xid(%ux)flag(%ux)ci(%V)gi(%V)yi(%V)si(%V) %s",
10403ff48bf5SDavid du Colombier 			up->raddr, bp->file, nhgetl(bp->xid), nhgets(bp->flags),
10413ff48bf5SDavid du Colombier 			bp->ciaddr, bp->giaddr, bp->yiaddr, bp->siaddr,
10423ff48bf5SDavid du Colombier 			optbuf);
10437dd7cddfSDavid du Colombier }
10447dd7cddfSDavid du Colombier 
10457dd7cddfSDavid du Colombier void
parseoptions(Req * rp)10467dd7cddfSDavid du Colombier parseoptions(Req *rp)
10477dd7cddfSDavid du Colombier {
10487dd7cddfSDavid du Colombier 	int n, c, code;
10497dd7cddfSDavid du Colombier 	uchar *o, *p;
10507dd7cddfSDavid du Colombier 
10517dd7cddfSDavid du Colombier 	p = rp->p;
10527dd7cddfSDavid du Colombier 
10537dd7cddfSDavid du Colombier 	while(p < rp->e){
10547dd7cddfSDavid du Colombier 		code = *p++;
10557dd7cddfSDavid du Colombier 		if(code == 255)
10567dd7cddfSDavid du Colombier 			break;
10577dd7cddfSDavid du Colombier 		if(code == 0)
10587dd7cddfSDavid du Colombier 			continue;
10597dd7cddfSDavid du Colombier 
10607dd7cddfSDavid du Colombier 		/* ignore anything that's too long */
10617dd7cddfSDavid du Colombier 		n = *p++;
10627dd7cddfSDavid du Colombier 		o = p;
10637dd7cddfSDavid du Colombier 		p += n;
10647dd7cddfSDavid du Colombier 		if(p > rp->e)
10657dd7cddfSDavid du Colombier 			return;
10667dd7cddfSDavid du Colombier 
10677dd7cddfSDavid du Colombier 		switch(code){
10687dd7cddfSDavid du Colombier 		case ODipaddr:	/* requested ip address */
10697dd7cddfSDavid du Colombier 			if(n == IPv4addrlen)
10707dd7cddfSDavid du Colombier 				v4tov6(rp->ip, o);
10717dd7cddfSDavid du Colombier 			break;
10727dd7cddfSDavid du Colombier 		case ODlease:	/* requested lease time */
10737dd7cddfSDavid du Colombier 			rp->leasetime = nhgetl(o);
107480ee5cbfSDavid du Colombier 			if(rp->leasetime > MaxLease || rp->leasetime < 0)
10757dd7cddfSDavid du Colombier 				rp->leasetime = MaxLease;
10767dd7cddfSDavid du Colombier 			break;
10777dd7cddfSDavid du Colombier 		case ODtype:
10787dd7cddfSDavid du Colombier 			c = *o;
10797dd7cddfSDavid du Colombier 			if(c < 10 && c > 0)
10807dd7cddfSDavid du Colombier 				rp->dhcptype = c;
10817dd7cddfSDavid du Colombier 			break;
10827dd7cddfSDavid du Colombier 		case ODserverid:
10837dd7cddfSDavid du Colombier 			if(n == IPv4addrlen)
10847dd7cddfSDavid du Colombier 				v4tov6(rp->server, o);
10857dd7cddfSDavid du Colombier 			break;
10867dd7cddfSDavid du Colombier 		case ODmessage:
10879a747e4fSDavid du Colombier 			if(n > sizeof rp->msg-1)
10889a747e4fSDavid du Colombier 				n = sizeof rp->msg-1;
10897dd7cddfSDavid du Colombier 			memmove(rp->msg, o, n);
10907dd7cddfSDavid du Colombier 			rp->msg[n] = 0;
10917dd7cddfSDavid du Colombier 			break;
10927dd7cddfSDavid du Colombier 		case ODmaxmsg:
10937dd7cddfSDavid du Colombier 			c = nhgets(o);
10947dd7cddfSDavid du Colombier 			c -= 28;
1095f27a9a5aSDavid du Colombier 			c += Udphdrsize;
10967dd7cddfSDavid du Colombier 			if(c > 0)
10977dd7cddfSDavid du Colombier 				rp->max = rp->buf + c;
10987dd7cddfSDavid du Colombier 			break;
10997dd7cddfSDavid du Colombier 		case ODclientid:
11007dd7cddfSDavid du Colombier 			if(n <= 1)
11017dd7cddfSDavid du Colombier 				break;
11027dd7cddfSDavid du Colombier 			rp->id = toid( o, n);
11037dd7cddfSDavid du Colombier 			break;
11047dd7cddfSDavid du Colombier 		case ODparams:
11057dd7cddfSDavid du Colombier 			if(n > sizeof(rp->requested))
11067dd7cddfSDavid du Colombier 				n = sizeof(rp->requested);
11077dd7cddfSDavid du Colombier 			memmove(rp->requested, o, n);
11087dd7cddfSDavid du Colombier 			break;
11097dd7cddfSDavid du Colombier 		case ODvendorclass:
11107dd7cddfSDavid du Colombier 			if(n >= sizeof(rp->vendorclass))
11117dd7cddfSDavid du Colombier 				n = sizeof(rp->vendorclass)-1;
11127dd7cddfSDavid du Colombier 			memmove(rp->vendorclass, o, n);
11137dd7cddfSDavid du Colombier 			rp->vendorclass[n] = 0;
11147dd7cddfSDavid du Colombier 			if(strncmp((char*)rp->vendorclass, "p9-", 3) == 0)
11157dd7cddfSDavid du Colombier 				strcpy(rp->cputype, (char*)rp->vendorclass+3);
11167dd7cddfSDavid du Colombier 			break;
11177dd7cddfSDavid du Colombier 		case OBend:
11187dd7cddfSDavid du Colombier 			return;
11197dd7cddfSDavid du Colombier 		}
11207dd7cddfSDavid du Colombier 	}
11217dd7cddfSDavid du Colombier }
11227dd7cddfSDavid du Colombier 
11237dd7cddfSDavid du Colombier void
remrequested(Req * rp,int opt)11247dd7cddfSDavid du Colombier remrequested(Req *rp, int opt)
11257dd7cddfSDavid du Colombier {
11267dd7cddfSDavid du Colombier 	uchar *p;
11277dd7cddfSDavid du Colombier 
11287dd7cddfSDavid du Colombier 	p = memchr(rp->requested, opt, sizeof(rp->requested));
11297dd7cddfSDavid du Colombier 	if(p != nil)
11307dd7cddfSDavid du Colombier 		*p = OBpad;
11317dd7cddfSDavid du Colombier }
11327dd7cddfSDavid du Colombier 
11337dd7cddfSDavid du Colombier void
miscoptions(Req * rp,uchar * ip)11347dd7cddfSDavid du Colombier miscoptions(Req *rp, uchar *ip)
11357dd7cddfSDavid du Colombier {
11360a84db5eSDavid du Colombier 	int i, j, na;
11370a84db5eSDavid du Colombier 	uchar x[2*IPaddrlen], vopts[Maxoptlen];
11387dd7cddfSDavid du Colombier 	uchar *op, *omax;
11390a84db5eSDavid du Colombier 	uchar *addrs[2];
11400a84db5eSDavid du Colombier 	char *p;
11413ff48bf5SDavid du Colombier 	char *attr[100], **a;
11423ff48bf5SDavid du Colombier 	Ndbtuple *t;
11437dd7cddfSDavid du Colombier 
11447dd7cddfSDavid du Colombier 	addrs[0] = x;
11457dd7cddfSDavid du Colombier 	addrs[1] = x+IPaddrlen;
11467dd7cddfSDavid du Colombier 
11477dd7cddfSDavid du Colombier 	/* always supply these */
11483ff48bf5SDavid du Colombier 	maskopt(rp, OBmask, rp->gii.ipmask);
11497dd7cddfSDavid du Colombier 	if(validip(rp->gii.gwip)){
11507dd7cddfSDavid du Colombier 		remrequested(rp, OBrouter);
11517dd7cddfSDavid du Colombier 		addropt(rp, OBrouter, rp->gii.gwip);
11527dd7cddfSDavid du Colombier 	} else if(validip(rp->giaddr)){
11537dd7cddfSDavid du Colombier 		remrequested(rp, OBrouter);
11547dd7cddfSDavid du Colombier 		addropt(rp, OBrouter, rp->giaddr);
11557dd7cddfSDavid du Colombier 	}
11567dd7cddfSDavid du Colombier 
11572ddf2468SDavid du Colombier 	/*
11582ddf2468SDavid du Colombier 	 * OBhostname for the HP4000M switches
11592ddf2468SDavid du Colombier 	 * (this causes NT to log infinite errors - tough shit)
11602ddf2468SDavid du Colombier 	 */
11619a747e4fSDavid du Colombier 	if(*rp->ii.domain){
11629a747e4fSDavid du Colombier 		remrequested(rp, OBhostname);
11639a747e4fSDavid du Colombier 		stringopt(rp, OBhostname, rp->ii.domain);
11649a747e4fSDavid du Colombier 	}
11653ff48bf5SDavid du Colombier 	if(*rp->ii.rootpath)
11669a747e4fSDavid du Colombier 		stringopt(rp, OBrootpath, rp->ii.rootpath);
11673ff48bf5SDavid du Colombier 
11683ff48bf5SDavid du Colombier 	/* figure out what we need to lookup */
11693ff48bf5SDavid du Colombier 	na = 0;
11703ff48bf5SDavid du Colombier 	a = attr;
11713ff48bf5SDavid du Colombier 	if(*rp->ii.domain == 0)
11723ff48bf5SDavid du Colombier 		a[na++] = "dom";
11733ff48bf5SDavid du Colombier 	for(i = 0; i < sizeof(rp->requested); i++)
11743ff48bf5SDavid du Colombier 		switch(rp->requested[i]){
11753ff48bf5SDavid du Colombier 		case OBrouter:
11763ff48bf5SDavid du Colombier 			a[na++] = "@ipgw";
11773ff48bf5SDavid du Colombier 			break;
11783ff48bf5SDavid du Colombier 		case OBdnserver:
11793ff48bf5SDavid du Colombier 			a[na++] = "@dns";
11803ff48bf5SDavid du Colombier 			break;
11813ff48bf5SDavid du Colombier 		case OBnetbiosns:
11823ff48bf5SDavid du Colombier 			a[na++] = "@wins";
11833ff48bf5SDavid du Colombier 			break;
11843ff48bf5SDavid du Colombier 		case OBsmtpserver:
11853ff48bf5SDavid du Colombier 			a[na++] = "@smtp";
11863ff48bf5SDavid du Colombier 			break;
11873ff48bf5SDavid du Colombier 		case OBpop3server:
11883ff48bf5SDavid du Colombier 			a[na++] = "@pop3";
11893ff48bf5SDavid du Colombier 			break;
11903ff48bf5SDavid du Colombier 		case OBwwwserver:
11913ff48bf5SDavid du Colombier 			a[na++] = "@www";
11923ff48bf5SDavid du Colombier 			break;
11933ff48bf5SDavid du Colombier 		case OBntpserver:
11943ff48bf5SDavid du Colombier 			a[na++] = "@ntp";
11953ff48bf5SDavid du Colombier 			break;
11963ff48bf5SDavid du Colombier 		case OBtimeserver:
11973ff48bf5SDavid du Colombier 			a[na++] = "@time";
11983ff48bf5SDavid du Colombier 			break;
11999a747e4fSDavid du Colombier 		}
12003ff48bf5SDavid du Colombier 	if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
12013ff48bf5SDavid du Colombier 	|| strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
12023ff48bf5SDavid du Colombier 		a[na++] = "@fs";
12033ff48bf5SDavid du Colombier 		a[na++] = "@auth";
12043ff48bf5SDavid du Colombier 	}
12053ff48bf5SDavid du Colombier 	t = lookupinfo(ip, a, na);
12069a747e4fSDavid du Colombier 
12077dd7cddfSDavid du Colombier 	/* lookup anything we might be missing */
12087dd7cddfSDavid du Colombier 	if(*rp->ii.domain == 0)
12093ff48bf5SDavid du Colombier 		lookupname(rp->ii.domain, t);
12107dd7cddfSDavid du Colombier 
12117dd7cddfSDavid du Colombier 	/* add any requested ones that we know about */
12127dd7cddfSDavid du Colombier 	for(i = 0; i < sizeof(rp->requested); i++)
12137dd7cddfSDavid du Colombier 		switch(rp->requested[i]){
12143ff48bf5SDavid du Colombier 		case OBrouter:
12153ff48bf5SDavid du Colombier 			j = lookupserver("ipgw", addrs, t);
12163ff48bf5SDavid du Colombier 			addrsopt(rp, OBrouter, addrs, j);
12173ff48bf5SDavid du Colombier 			break;
12187dd7cddfSDavid du Colombier 		case OBdnserver:
12193ff48bf5SDavid du Colombier 			j = lookupserver("dns", addrs, t);
12207dd7cddfSDavid du Colombier 			addrsopt(rp, OBdnserver, addrs, j);
12217dd7cddfSDavid du Colombier 			break;
12227dd7cddfSDavid du Colombier 		case OBhostname:
12237dd7cddfSDavid du Colombier 			if(*rp->ii.domain)
12247dd7cddfSDavid du Colombier 				stringopt(rp, OBhostname, rp->ii.domain);
12257dd7cddfSDavid du Colombier 			break;
12267dd7cddfSDavid du Colombier 		case OBdomainname:
12277dd7cddfSDavid du Colombier 			p = strchr(rp->ii.domain, '.');
12287dd7cddfSDavid du Colombier 			if(p)
12297dd7cddfSDavid du Colombier 				stringopt(rp, OBdomainname, p+1);
12307dd7cddfSDavid du Colombier 			break;
12317dd7cddfSDavid du Colombier 		case OBnetbiosns:
12323ff48bf5SDavid du Colombier 			j = lookupserver("wins", addrs, t);
12337dd7cddfSDavid du Colombier 			addrsopt(rp, OBnetbiosns, addrs, j);
12347dd7cddfSDavid du Colombier 			break;
12357dd7cddfSDavid du Colombier 		case OBnetbiostype:
12367dd7cddfSDavid du Colombier 			/* p-node: peer to peer WINS queries */
12377dd7cddfSDavid du Colombier 			byteopt(rp, OBnetbiostype, 0x2);
12387dd7cddfSDavid du Colombier 			break;
12397dd7cddfSDavid du Colombier 		case OBsmtpserver:
12403ff48bf5SDavid du Colombier 			j = lookupserver("smtp", addrs, t);
12417dd7cddfSDavid du Colombier 			addrsopt(rp, OBsmtpserver, addrs, j);
12427dd7cddfSDavid du Colombier 			break;
12437dd7cddfSDavid du Colombier 		case OBpop3server:
12443ff48bf5SDavid du Colombier 			j = lookupserver("pop3", addrs, t);
12457dd7cddfSDavid du Colombier 			addrsopt(rp, OBpop3server, addrs, j);
12467dd7cddfSDavid du Colombier 			break;
12477dd7cddfSDavid du Colombier 		case OBwwwserver:
12483ff48bf5SDavid du Colombier 			j = lookupserver("www", addrs, t);
12497dd7cddfSDavid du Colombier 			addrsopt(rp, OBwwwserver, addrs, j);
12507dd7cddfSDavid du Colombier 			break;
12517dd7cddfSDavid du Colombier 		case OBntpserver:
12523ff48bf5SDavid du Colombier 			j = lookupserver("ntp", addrs, t);
12537dd7cddfSDavid du Colombier 			addrsopt(rp, OBntpserver, addrs, j);
12547dd7cddfSDavid du Colombier 			break;
12557dd7cddfSDavid du Colombier 		case OBtimeserver:
12563ff48bf5SDavid du Colombier 			j = lookupserver("time", addrs, t);
12577dd7cddfSDavid du Colombier 			addrsopt(rp, OBtimeserver, addrs, j);
12587dd7cddfSDavid du Colombier 			break;
12597dd7cddfSDavid du Colombier 		case OBttl:
12607dd7cddfSDavid du Colombier 			byteopt(rp, OBttl, 255);
12617dd7cddfSDavid du Colombier 			break;
12627dd7cddfSDavid du Colombier 		}
12637dd7cddfSDavid du Colombier 
12642ddf2468SDavid du Colombier 	/* add plan9 specific options */
12657dd7cddfSDavid du Colombier 	if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
12667dd7cddfSDavid du Colombier 	|| strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
12672ddf2468SDavid du Colombier 		/* point to temporary area */
12687dd7cddfSDavid du Colombier 		op = rp->p;
12697dd7cddfSDavid du Colombier 		omax = rp->max;
12700a84db5eSDavid du Colombier 		/* stash encoded options in vopts */
12717dd7cddfSDavid du Colombier 		rp->p = vopts;
12727dd7cddfSDavid du Colombier 		rp->max = vopts + sizeof(vopts) - 1;
12737dd7cddfSDavid du Colombier 
12740a84db5eSDavid du Colombier 		/* emit old v4 addresses first to make sure that they fit */
12750a84db5eSDavid du Colombier 		addrsopt(rp, OP9fsv4, addrs, lookupserver("fs", addrs, t));
12760a84db5eSDavid du Colombier 		addrsopt(rp, OP9authv4, addrs, lookupserver("auth", addrs, t));
12777dd7cddfSDavid du Colombier 
12780a84db5eSDavid du Colombier 		p9addrsopt(rp, OP9fs, addrs, lookupserver("fs", addrs, t));
12790a84db5eSDavid du Colombier 		p9addrsopt(rp, OP9auth, addrs, lookupserver("auth", addrs, t));
12800a84db5eSDavid du Colombier 		p9addrsopt(rp, OP9ipaddr, addrs, lookupserver("ip", addrs, t));
12810a84db5eSDavid du Colombier 		p9addrsopt(rp, OP9ipmask, addrs, lookupserver("ipmask", addrs, t));
12820a84db5eSDavid du Colombier 		p9addrsopt(rp, OP9ipgw, addrs, lookupserver("ipgw", addrs, t));
12830a84db5eSDavid du Colombier 
12840a84db5eSDavid du Colombier 		/* point back to packet, encapsulate vopts into packet */
12857dd7cddfSDavid du Colombier 		j = rp->p - vopts;
12867dd7cddfSDavid du Colombier 		rp->p = op;
12877dd7cddfSDavid du Colombier 		rp->max = omax;
12887dd7cddfSDavid du Colombier 		vectoropt(rp, OBvendorinfo, vopts, j);
12897dd7cddfSDavid du Colombier 	}
12907dd7cddfSDavid du Colombier 
12913ff48bf5SDavid du Colombier 	ndbfree(t);
12927dd7cddfSDavid du Colombier }
12937dd7cddfSDavid du Colombier 
12947dd7cddfSDavid du Colombier int
openlisten(char * net)12957dd7cddfSDavid du Colombier openlisten(char *net)
12967dd7cddfSDavid du Colombier {
12977dd7cddfSDavid du Colombier 	int fd, cfd;
12982ddf2468SDavid du Colombier 	char data[128], devdir[40];
12997dd7cddfSDavid du Colombier 
13007dd7cddfSDavid du Colombier 	sprint(data, "%s/udp!*!bootp", net);
13017dd7cddfSDavid du Colombier 	cfd = announce(data, devdir);
13027dd7cddfSDavid du Colombier 	if(cfd < 0)
13037dd7cddfSDavid du Colombier 		fatal(1, "can't announce");
13047dd7cddfSDavid du Colombier 	if(fprint(cfd, "headers") < 0)
13057dd7cddfSDavid du Colombier 		fatal(1, "can't set header mode");
13067dd7cddfSDavid du Colombier 
13077dd7cddfSDavid du Colombier 	sprint(data, "%s/data", devdir);
13087dd7cddfSDavid du Colombier 	fd = open(data, ORDWR);
13097dd7cddfSDavid du Colombier 	if(fd < 0)
13107dd7cddfSDavid du Colombier 		fatal(1, "open udp data");
13117dd7cddfSDavid du Colombier 	return fd;
13127dd7cddfSDavid du Colombier }
13137dd7cddfSDavid du Colombier 
13147dd7cddfSDavid du Colombier void
fatal(int syserr,char * fmt,...)13157dd7cddfSDavid du Colombier fatal(int syserr, char *fmt, ...)
13167dd7cddfSDavid du Colombier {
13170a84db5eSDavid du Colombier 	char buf[Maxloglen];
13187dd7cddfSDavid du Colombier 	va_list arg;
13197dd7cddfSDavid du Colombier 
13207dd7cddfSDavid du Colombier 	va_start(arg, fmt);
13219a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, arg);
13227dd7cddfSDavid du Colombier 	va_end(arg);
13237dd7cddfSDavid du Colombier 	if(syserr)
13243ff48bf5SDavid du Colombier 		syslog(1, blog, "%s: %r", buf);
13257dd7cddfSDavid du Colombier 	else
13263ff48bf5SDavid du Colombier 		syslog(1, blog, "%s", buf);
13277dd7cddfSDavid du Colombier 	exits(buf);
13287dd7cddfSDavid du Colombier }
13297dd7cddfSDavid du Colombier 
13300a84db5eSDavid du Colombier void
warning(int syserr,char * fmt,...)13317dd7cddfSDavid du Colombier warning(int syserr, char *fmt, ...)
13327dd7cddfSDavid du Colombier {
13330a84db5eSDavid du Colombier 	char buf[Maxloglen];
13347dd7cddfSDavid du Colombier 	va_list arg;
13357dd7cddfSDavid du Colombier 
13367dd7cddfSDavid du Colombier 	va_start(arg, fmt);
13379a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, arg);
13387dd7cddfSDavid du Colombier 	va_end(arg);
13397dd7cddfSDavid du Colombier 	if(syserr){
13403ff48bf5SDavid du Colombier 		syslog(0, blog, "%s: %r", buf);
13417dd7cddfSDavid du Colombier 		if(debug)
13423ff48bf5SDavid du Colombier 			fprint(2, "%s: %r\n", buf);
13437dd7cddfSDavid du Colombier 	} else {
13443ff48bf5SDavid du Colombier 		syslog(0, blog, "%s", buf);
13457dd7cddfSDavid du Colombier 		if(debug)
13463ff48bf5SDavid du Colombier 			fprint(2, "%s\n", buf);
13477dd7cddfSDavid du Colombier 	}
13487dd7cddfSDavid du Colombier }
13497dd7cddfSDavid du Colombier 
13507dd7cddfSDavid du Colombier char*
readsysname(void)13517dd7cddfSDavid du Colombier readsysname(void)
13527dd7cddfSDavid du Colombier {
13539a747e4fSDavid du Colombier 	static char name[128];
13547dd7cddfSDavid du Colombier 	char *p;
13557dd7cddfSDavid du Colombier 	int n, fd;
13567dd7cddfSDavid du Colombier 
13577dd7cddfSDavid du Colombier 	fd = open("/dev/sysname", OREAD);
13587dd7cddfSDavid du Colombier 	if(fd >= 0){
13597dd7cddfSDavid du Colombier 		n = read(fd, name, sizeof(name)-1);
13607dd7cddfSDavid du Colombier 		close(fd);
13617dd7cddfSDavid du Colombier 		if(n > 0){
13627dd7cddfSDavid du Colombier 			name[n] = 0;
13637dd7cddfSDavid du Colombier 			return name;
13647dd7cddfSDavid du Colombier 		}
13657dd7cddfSDavid du Colombier 	}
13667dd7cddfSDavid du Colombier 	p = getenv("sysname");
13679a747e4fSDavid du Colombier 	if(p == nil || *p == 0)
13689a747e4fSDavid du Colombier 		return "unknown";
13697dd7cddfSDavid du Colombier 	return p;
13707dd7cddfSDavid du Colombier }
13717dd7cddfSDavid du Colombier 
13727dd7cddfSDavid du Colombier extern int
validip(uchar * ip)13737dd7cddfSDavid du Colombier validip(uchar *ip)
13747dd7cddfSDavid du Colombier {
13757dd7cddfSDavid du Colombier 	if(ipcmp(ip, IPnoaddr) == 0)
13767dd7cddfSDavid du Colombier 		return 0;
13777dd7cddfSDavid du Colombier 	if(ipcmp(ip, v4prefix) == 0)
13787dd7cddfSDavid du Colombier 		return 0;
13797dd7cddfSDavid du Colombier 	return 1;
13807dd7cddfSDavid du Colombier }
13817dd7cddfSDavid du Colombier 
13827dd7cddfSDavid du Colombier void
longopt(Req * rp,int t,long v)13837dd7cddfSDavid du Colombier longopt(Req *rp, int t, long v)
13847dd7cddfSDavid du Colombier {
13857dd7cddfSDavid du Colombier 	if(rp->p + 6 > rp->max)
13867dd7cddfSDavid du Colombier 		return;
13877dd7cddfSDavid du Colombier 	*rp->p++ = t;
13887dd7cddfSDavid du Colombier 	*rp->p++ = 4;
13897dd7cddfSDavid du Colombier 	hnputl(rp->p, v);
13907dd7cddfSDavid du Colombier 	rp->p += 4;
13913ff48bf5SDavid du Colombier 
13923ff48bf5SDavid du Colombier 	op = seprint(op, oe, "%s(%ld)", optname[t], v);
13937dd7cddfSDavid du Colombier }
13947dd7cddfSDavid du Colombier 
13957dd7cddfSDavid du Colombier void
addropt(Req * rp,int t,uchar * ip)13967dd7cddfSDavid du Colombier addropt(Req *rp, int t, uchar *ip)
13977dd7cddfSDavid du Colombier {
13987dd7cddfSDavid du Colombier 	if(rp->p + 6 > rp->max)
13997dd7cddfSDavid du Colombier 		return;
14000a84db5eSDavid du Colombier 	if (!isv4(ip)) {
14010a84db5eSDavid du Colombier 		if (debug)
14020a84db5eSDavid du Colombier 			warning(0, "not a v4 %s server: %I", optname[t], ip);
14030a84db5eSDavid du Colombier 		return;
14040a84db5eSDavid du Colombier 	}
14057dd7cddfSDavid du Colombier 	*rp->p++ = t;
14067dd7cddfSDavid du Colombier 	*rp->p++ = 4;
14077dd7cddfSDavid du Colombier 	memmove(rp->p, ip+IPv4off, 4);
14087dd7cddfSDavid du Colombier 	rp->p += 4;
14093ff48bf5SDavid du Colombier 
14103ff48bf5SDavid du Colombier 	op = seprint(op, oe, "%s(%I)", optname[t], ip);
14113ff48bf5SDavid du Colombier }
14123ff48bf5SDavid du Colombier 
14133ff48bf5SDavid du Colombier void
maskopt(Req * rp,int t,uchar * ip)14143ff48bf5SDavid du Colombier maskopt(Req *rp, int t, uchar *ip)
14153ff48bf5SDavid du Colombier {
14163ff48bf5SDavid du Colombier 	if(rp->p + 6 > rp->max)
14173ff48bf5SDavid du Colombier 		return;
14183ff48bf5SDavid du Colombier 	*rp->p++ = t;
14193ff48bf5SDavid du Colombier 	*rp->p++ = 4;
14203ff48bf5SDavid du Colombier 	memmove(rp->p, ip+IPv4off, 4);
14213ff48bf5SDavid du Colombier 	rp->p += 4;
14223ff48bf5SDavid du Colombier 
14233ff48bf5SDavid du Colombier 	op = seprint(op, oe, "%s(%M)", optname[t], ip);
14247dd7cddfSDavid du Colombier }
14257dd7cddfSDavid du Colombier 
14267dd7cddfSDavid du Colombier void
addrsopt(Req * rp,int t,uchar ** ip,int i)14277dd7cddfSDavid du Colombier addrsopt(Req *rp, int t, uchar **ip, int i)
14287dd7cddfSDavid du Colombier {
14290a84db5eSDavid du Colombier 	int v4s, n;
14300a84db5eSDavid du Colombier 
14317dd7cddfSDavid du Colombier 	if(i <= 0)
14327dd7cddfSDavid du Colombier 		return;
14337dd7cddfSDavid du Colombier 	if(rp->p + 2 + 4*i > rp->max)
14347dd7cddfSDavid du Colombier 		return;
14350a84db5eSDavid du Colombier 	v4s = 0;
14360a84db5eSDavid du Colombier 	for(n = i; n-- > 0; )
14370a84db5eSDavid du Colombier 		if (isv4(ip[n]))
14380a84db5eSDavid du Colombier 			v4s++;
14390a84db5eSDavid du Colombier 	if (v4s <= 0) {
14400a84db5eSDavid du Colombier 		if (debug)
14410a84db5eSDavid du Colombier 			warning(0, "no v4 %s servers", optname[t]);
14420a84db5eSDavid du Colombier 		return;
14430a84db5eSDavid du Colombier 	}
14447dd7cddfSDavid du Colombier 	*rp->p++ = t;
14450a84db5eSDavid du Colombier 	*rp->p++ = 4*v4s;
14463ff48bf5SDavid du Colombier 	op = seprint(op, oe, " %s(", optname[t]);
14477dd7cddfSDavid du Colombier 	while(i-- > 0){
14480a84db5eSDavid du Colombier 		if (!isv4(*ip)) {
14490a84db5eSDavid du Colombier 			op = seprint(op, oe, " skipping %I ", *ip);
14500a84db5eSDavid du Colombier 			continue;
14510a84db5eSDavid du Colombier 		}
14527dd7cddfSDavid du Colombier 		v6tov4(rp->p, *ip);
14537dd7cddfSDavid du Colombier 		rp->p += 4;
14543ff48bf5SDavid du Colombier 		op = seprint(op, oe, "%I", *ip);
14557dd7cddfSDavid du Colombier 		ip++;
14563ff48bf5SDavid du Colombier 		if(i > 0)
14573ff48bf5SDavid du Colombier 			op = seprint(op, oe, " ");
14587dd7cddfSDavid du Colombier 	}
14593ff48bf5SDavid du Colombier 	op = seprint(op, oe, ")");
14607dd7cddfSDavid du Colombier }
14617dd7cddfSDavid du Colombier 
14627dd7cddfSDavid du Colombier void
p9addrsopt(Req * rp,int t,uchar ** ip,int i)14630a84db5eSDavid du Colombier p9addrsopt(Req *rp, int t, uchar **ip, int i)
14640a84db5eSDavid du Colombier {
14650a84db5eSDavid du Colombier 	char *pkt, *payload;
14660a84db5eSDavid du Colombier 
14670a84db5eSDavid du Colombier 	if(i <= 0 || !v6opts)
14680a84db5eSDavid du Colombier 		return;
14690a84db5eSDavid du Colombier 	pkt = (char *)rp->p;
14700a84db5eSDavid du Colombier 	*pkt++ = t;			/* option */
14710a84db5eSDavid du Colombier 	pkt++;				/* fill in payload length below */
14720a84db5eSDavid du Colombier 	payload = pkt;
14730a84db5eSDavid du Colombier 	*pkt++ = i;			/* plan 9 address count */
14740a84db5eSDavid du Colombier 	op = seprint(op, oe, " %s(", optname[t]);
14750a84db5eSDavid du Colombier 	while(i-- > 0){
14760a84db5eSDavid du Colombier 		pkt = seprint(pkt, (char *)rp->max, "%I", *ip);
14770a84db5eSDavid du Colombier 		if ((uchar *)pkt+1 >= rp->max) {
14780a84db5eSDavid du Colombier 			op = seprint(op, oe, "<out of mem1>)");
14790a84db5eSDavid du Colombier 			return;
14800a84db5eSDavid du Colombier 		}
14810a84db5eSDavid du Colombier 		pkt++;			/* leave NUL as terminator */
14820a84db5eSDavid du Colombier 		op = seprint(op, oe, "%I", *ip);
14830a84db5eSDavid du Colombier 		ip++;
14840a84db5eSDavid du Colombier 		if(i > 0)
14850a84db5eSDavid du Colombier 			op = seprint(op, oe, " ");
14860a84db5eSDavid du Colombier 	}
14870a84db5eSDavid du Colombier 	if ((uchar *)pkt - rp->p > 0377) {
14880a84db5eSDavid du Colombier 		op = seprint(op, oe, "<out of mem2>)");
14890a84db5eSDavid du Colombier 		return;
14900a84db5eSDavid du Colombier 	}
14910a84db5eSDavid du Colombier 	op = seprint(op, oe, ")");
14920a84db5eSDavid du Colombier 	rp->p[1] = pkt - payload;	/* payload length */
14930a84db5eSDavid du Colombier 	rp->p = (uchar *)pkt;
14940a84db5eSDavid du Colombier }
14950a84db5eSDavid du Colombier 
14960a84db5eSDavid du Colombier void
byteopt(Req * rp,int t,uchar v)14977dd7cddfSDavid du Colombier byteopt(Req *rp, int t, uchar v)
14987dd7cddfSDavid du Colombier {
14997dd7cddfSDavid du Colombier 	if(rp->p + 3 > rp->max)
15007dd7cddfSDavid du Colombier 		return;
15017dd7cddfSDavid du Colombier 	*rp->p++ = t;
15027dd7cddfSDavid du Colombier 	*rp->p++ = 1;
15037dd7cddfSDavid du Colombier 	*rp->p++ = v;
15043ff48bf5SDavid du Colombier 
15053ff48bf5SDavid du Colombier 	op = seprint(op, oe, "%s(%d)", optname[t], v);
15067dd7cddfSDavid du Colombier }
15077dd7cddfSDavid du Colombier 
15087dd7cddfSDavid du Colombier void
termopt(Req * rp)15097dd7cddfSDavid du Colombier termopt(Req *rp)
15107dd7cddfSDavid du Colombier {
15117dd7cddfSDavid du Colombier 	if(rp->p + 1 > rp->max)
15127dd7cddfSDavid du Colombier 		return;
15137dd7cddfSDavid du Colombier 	*rp->p++ = OBend;
15147dd7cddfSDavid du Colombier }
15157dd7cddfSDavid du Colombier 
15167dd7cddfSDavid du Colombier void
stringopt(Req * rp,int t,char * str)15177dd7cddfSDavid du Colombier stringopt(Req *rp, int t, char *str)
15187dd7cddfSDavid du Colombier {
15197dd7cddfSDavid du Colombier 	int n;
15207dd7cddfSDavid du Colombier 
15217dd7cddfSDavid du Colombier 	n = strlen(str);
15227dd7cddfSDavid du Colombier 	if(n > 255)
15237dd7cddfSDavid du Colombier 		n = 255;
15247dd7cddfSDavid du Colombier 	if(rp->p+n+2 > rp->max)
15257dd7cddfSDavid du Colombier 		return;
15267dd7cddfSDavid du Colombier 	*rp->p++ = t;
15277dd7cddfSDavid du Colombier 	*rp->p++ = n;
15287dd7cddfSDavid du Colombier 	memmove(rp->p, str, n);
15297dd7cddfSDavid du Colombier 	rp->p += n;
15303ff48bf5SDavid du Colombier 
15313ff48bf5SDavid du Colombier 	op = seprint(op, oe, "%s(%s)", optname[t], str);
15327dd7cddfSDavid du Colombier }
15337dd7cddfSDavid du Colombier 
15347dd7cddfSDavid du Colombier void
vectoropt(Req * rp,int t,uchar * v,int n)15357dd7cddfSDavid du Colombier vectoropt(Req *rp, int t, uchar *v, int n)
15367dd7cddfSDavid du Colombier {
15373ff48bf5SDavid du Colombier 	int i;
15383ff48bf5SDavid du Colombier 
15390a84db5eSDavid du Colombier 	if(n > 255) {
15407dd7cddfSDavid du Colombier 		n = 255;
15410a84db5eSDavid du Colombier 		op = seprint(op, oe, "vectoropt len %d > 255 ", n);
15420a84db5eSDavid du Colombier 	}
15437dd7cddfSDavid du Colombier 	if(rp->p+n+2 > rp->max)
15447dd7cddfSDavid du Colombier 		return;
15457dd7cddfSDavid du Colombier 	*rp->p++ = t;
15467dd7cddfSDavid du Colombier 	*rp->p++ = n;
15477dd7cddfSDavid du Colombier 	memmove(rp->p, v, n);
15487dd7cddfSDavid du Colombier 	rp->p += n;
15493ff48bf5SDavid du Colombier 
15503ff48bf5SDavid du Colombier 	op = seprint(op, oe, "%s(", optname[t]);
15513ff48bf5SDavid du Colombier 	if(n > 0)
15520a84db5eSDavid du Colombier 		op = seprint(op, oe, "%ud", v[0]);
15533ff48bf5SDavid du Colombier 	for(i = 1; i < n; i++)
15543ff48bf5SDavid du Colombier 		op = seprint(op, oe, " %ud", v[i]);
15550a84db5eSDavid du Colombier 	op = seprint(op, oe, ")");
15567dd7cddfSDavid du Colombier }
15577dd7cddfSDavid du Colombier 
15587dd7cddfSDavid du Colombier int
fromhex(int x)15597dd7cddfSDavid du Colombier fromhex(int x)
15607dd7cddfSDavid du Colombier {
15617dd7cddfSDavid du Colombier 	if(x >= '0' && x <= '9')
15627dd7cddfSDavid du Colombier 		return x - '0';
15637dd7cddfSDavid du Colombier 	return x - 'a';
15647dd7cddfSDavid du Colombier }
15657dd7cddfSDavid du Colombier 
15667dd7cddfSDavid du Colombier void
hexopt(Req * rp,int t,char * str)15677dd7cddfSDavid du Colombier hexopt(Req *rp, int t, char *str)
15687dd7cddfSDavid du Colombier {
15697dd7cddfSDavid du Colombier 	int n;
15707dd7cddfSDavid du Colombier 
15717dd7cddfSDavid du Colombier 	n = strlen(str);
15727dd7cddfSDavid du Colombier 	n /= 2;
15737dd7cddfSDavid du Colombier 	if(n > 255)
15747dd7cddfSDavid du Colombier 		n = 255;
15757dd7cddfSDavid du Colombier 	if(rp->p+n+2 > rp->max)
15767dd7cddfSDavid du Colombier 		return;
15777dd7cddfSDavid du Colombier 	*rp->p++ = t;
15787dd7cddfSDavid du Colombier 	*rp->p++ = n;
15797dd7cddfSDavid du Colombier 	while(n-- > 0){
15807dd7cddfSDavid du Colombier 		*rp->p++ = (fromhex(str[0])<<4)|fromhex(str[1]);
15817dd7cddfSDavid du Colombier 		str += 2;
15827dd7cddfSDavid du Colombier 	}
15833ff48bf5SDavid du Colombier 
15843ff48bf5SDavid du Colombier 	op = seprint(op, oe, "%s(%s)", optname[t], str);
15857dd7cddfSDavid du Colombier }
15867dd7cddfSDavid du Colombier 
15877dd7cddfSDavid du Colombier void
arpenter(uchar * ip,uchar * ether)15887dd7cddfSDavid du Colombier arpenter(uchar *ip, uchar *ether)
15897dd7cddfSDavid du Colombier {
15907dd7cddfSDavid du Colombier 	int f;
15917dd7cddfSDavid du Colombier 	char buf[256];
15927dd7cddfSDavid du Colombier 
15937dd7cddfSDavid du Colombier 	sprint(buf, "%s/arp", net);
15947dd7cddfSDavid du Colombier 	f = open(buf, OWRITE);
15957dd7cddfSDavid du Colombier 	if(f < 0){
15967dd7cddfSDavid du Colombier 		syslog(debug, blog, "open %s: %r", buf);
15977dd7cddfSDavid du Colombier 		return;
15987dd7cddfSDavid du Colombier 	}
15997dd7cddfSDavid du Colombier 	fprint(f, "add ether %I %E", ip, ether);
16007dd7cddfSDavid du Colombier 	close(f);
16017dd7cddfSDavid du Colombier }
16027dd7cddfSDavid du Colombier 
16037dd7cddfSDavid du Colombier char *dhcpmsgname[] =
16047dd7cddfSDavid du Colombier {
16057dd7cddfSDavid du Colombier 	[Discover]	"Discover",
16067dd7cddfSDavid du Colombier 	[Offer]		"Offer",
16077dd7cddfSDavid du Colombier 	[Request]	"Request",
16087dd7cddfSDavid du Colombier 	[Decline]	"Decline",
16097dd7cddfSDavid du Colombier 	[Ack]		"Ack",
16107dd7cddfSDavid du Colombier 	[Nak]		"Nak",
16117dd7cddfSDavid du Colombier 	[Release]	"Release",
16127dd7cddfSDavid du Colombier 	[Inform]	"Inform",
16137dd7cddfSDavid du Colombier };
16147dd7cddfSDavid du Colombier 
16157dd7cddfSDavid du Colombier void
logdhcp(Req * rp)16167dd7cddfSDavid du Colombier logdhcp(Req *rp)
16177dd7cddfSDavid du Colombier {
16187dd7cddfSDavid du Colombier 	char buf[4096];
16197dd7cddfSDavid du Colombier 	char *p, *e;
16207dd7cddfSDavid du Colombier 	int i;
16217dd7cddfSDavid du Colombier 
16227dd7cddfSDavid du Colombier 	p = buf;
16237dd7cddfSDavid du Colombier 	e = buf + sizeof(buf);
16247dd7cddfSDavid du Colombier 	if(rp->dhcptype > 0 && rp->dhcptype <= Inform)
16253ff48bf5SDavid du Colombier 		p = seprint(p, e, "%s(", dhcpmsgname[rp->dhcptype]);
16267dd7cddfSDavid du Colombier 	else
16273ff48bf5SDavid du Colombier 		p = seprint(p, e, "%d(", rp->dhcptype);
16283ff48bf5SDavid du Colombier 	p = seprint(p, e, "%I->%I) xid(%ux)flag(%ux)", rp->up->raddr, rp->up->laddr,
16293ff48bf5SDavid du Colombier 		nhgetl(rp->bp->xid), nhgets(rp->bp->flags));
16307dd7cddfSDavid du Colombier 	if(rp->bp->htype == 1)
16313ff48bf5SDavid du Colombier 		p = seprint(p, e, "ea(%E)", rp->bp->chaddr);
16323ff48bf5SDavid du Colombier 	if(validip(rp->ciaddr))
16333ff48bf5SDavid du Colombier 		p = seprint(p, e, "ci(%I)", rp->ciaddr);
16343ff48bf5SDavid du Colombier 	if(validip(rp->giaddr))
16353ff48bf5SDavid du Colombier 		p = seprint(p, e, "gi(%I)", rp->giaddr);
16363ff48bf5SDavid du Colombier 	if(validip(rp->ip))
16373ff48bf5SDavid du Colombier 		p = seprint(p, e, "ip(%I)", rp->ip);
16383ff48bf5SDavid du Colombier 	if(rp->id != nil)
16393ff48bf5SDavid du Colombier 		p = seprint(p, e, "id(%s)", rp->id);
16403ff48bf5SDavid du Colombier 	if(rp->leasetime)
16413ff48bf5SDavid du Colombier 		p = seprint(p, e, "leas(%d)", rp->leasetime);
16423ff48bf5SDavid du Colombier 	if(validip(rp->server))
16433ff48bf5SDavid du Colombier 		p = seprint(p, e, "sid(%I)", rp->server);
16443ff48bf5SDavid du Colombier 	p = seprint(p, e, "need(");
16457dd7cddfSDavid du Colombier 	for(i = 0; i < sizeof(rp->requested); i++)
16467dd7cddfSDavid du Colombier 		if(rp->requested[i] != 0)
16473ff48bf5SDavid du Colombier 			p = seprint(p, e, "%s ", optname[rp->requested[i]]);
16487dd7cddfSDavid du Colombier 	p = seprint(p, e, ")");
16498ae63d3dSDavid du Colombier 	p = seprint(p, e, " %s", rp->broadcast? "broadcast": "unicast");
16507dd7cddfSDavid du Colombier 	USED(p);
16517dd7cddfSDavid du Colombier 	syslog(0, blog, "%s", buf);
16527dd7cddfSDavid du Colombier }
16533ff48bf5SDavid du Colombier 
16543ff48bf5SDavid du Colombier void
logdhcpout(Req * rp,char * type)16553ff48bf5SDavid du Colombier logdhcpout(Req *rp, char *type)
16563ff48bf5SDavid du Colombier {
16573ff48bf5SDavid du Colombier 	syslog(0, blog, "%s(%I-%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s",
16583ff48bf5SDavid du Colombier 		type, rp->up->laddr, rp->up->raddr, rp->id,
16593ff48bf5SDavid du Colombier 		rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf);
16603ff48bf5SDavid du Colombier }
16613ff48bf5SDavid du Colombier 
16623ff48bf5SDavid du Colombier /*
16633ff48bf5SDavid du Colombier  *  if we get behind, it's useless to try answering since the sender
16643ff48bf5SDavid du Colombier  *  will probably have retransmitted with a differnt sequence number.
16650a84db5eSDavid du Colombier  *  So dump all but the last message in the queue.
16663ff48bf5SDavid du Colombier  */
16670a84db5eSDavid du Colombier void
ding(void *,char * msg)16680a84db5eSDavid du Colombier ding(void*, char *msg)
16693ff48bf5SDavid du Colombier {
16703ff48bf5SDavid du Colombier 	if(strstr(msg, "alarm"))
16713ff48bf5SDavid du Colombier 		noted(NCONT);
16723ff48bf5SDavid du Colombier 	else
16733ff48bf5SDavid du Colombier 		noted(NDFLT);
16743ff48bf5SDavid du Colombier }
16753ff48bf5SDavid du Colombier 
16763ff48bf5SDavid du Colombier int
readlast(int fd,uchar * buf,int len)16773ff48bf5SDavid du Colombier readlast(int fd, uchar *buf, int len)
16783ff48bf5SDavid du Colombier {
16793ff48bf5SDavid du Colombier 	int lastn, n;
16803ff48bf5SDavid du Colombier 
16813ff48bf5SDavid du Colombier 	notify(ding);
16823ff48bf5SDavid du Colombier 
16833ff48bf5SDavid du Colombier 	lastn = 0;
16843ff48bf5SDavid du Colombier 	for(;;){
16853ff48bf5SDavid du Colombier 		alarm(20);
16863ff48bf5SDavid du Colombier 		n = read(fd, buf, len);
16873ff48bf5SDavid du Colombier 		alarm(0);
16883ff48bf5SDavid du Colombier 		if(n < 0){
16893ff48bf5SDavid du Colombier 			if(lastn > 0)
16903ff48bf5SDavid du Colombier 				return lastn;
16913ff48bf5SDavid du Colombier 			break;
16923ff48bf5SDavid du Colombier 		}
16933ff48bf5SDavid du Colombier 		lastn = n;
16943ff48bf5SDavid du Colombier 	}
16953ff48bf5SDavid du Colombier 	return read(fd, buf, len);
16963ff48bf5SDavid du Colombier }
1697