xref: /plan9/sys/src/cmd/ip/dhcpd/dhcpd.c (revision decede3daff5663ad9461ecbdee99636df315e35)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <bio.h>
5 #include <ndb.h>
6 #include "dat.h"
7 
8 /*
9  *	ala rfc2131
10  */
11 
12 typedef struct Req Req;
13 struct Req
14 {
15 	int	fd;			/* for reply */
16 	Bootp	*bp;
17 	Udphdr	*up;
18 	uchar	*e;			/* end of received message */
19 	uchar	*p;			/* options pointer */
20 	uchar	*max;			/* max end of reply */
21 
22 	/* expanded to v6 */
23 	uchar	ciaddr[IPaddrlen];
24 	uchar	giaddr[IPaddrlen];
25 
26 	/* parsed options */
27 	int	p9request;		/* flag: this is a bootp with plan9 options */
28 	int	genrequest;		/* flag: this is a bootp with generic options */
29 	int	dhcptype;		/* dhcp message type */
30 	int	leasetime;		/* dhcp lease */
31 	uchar	ip[IPaddrlen];		/* requested address */
32 	uchar	server[IPaddrlen];	/* server address */
33 	char	msg[ERRMAX];		/* error message */
34 	char	vci[32];		/* vendor class id */
35 	char	*id;			/* client id */
36 	uchar	requested[32];		/* requested params */
37 	uchar	vendorclass[32];
38 	char	cputype[32-3];
39 
40 	Info	gii;			/* about target network */
41 	Info	ii;			/* about target system */
42 	int	staticbinding;
43 
44 	uchar buf[2*1024];		/* message buffer */
45 };
46 
47 #define TFTP "/lib/tftpd"
48 
49 char	*blog = "ipboot";
50 char	mysysname[64];
51 Ipifc	*ipifcs;
52 int	debug;
53 int	nobootp;
54 long	now;
55 int	slowstat, slowdyn;
56 char	net[256];
57 
58 int	pptponly;	/* only answer request that came from the pptp server */
59 int	mute, mutestat;
60 int	minlease = MinLease;
61 int	staticlease = StaticLease;
62 
63 ulong	start;
64 
65 /* option magic */
66 char plan9opt[4] = { 'p', '9', ' ', ' ' };
67 char genericopt[4] = { 0x63, 0x82, 0x53, 0x63 };
68 
69 /* well known addresses */
70 uchar zeros[Maxhwlen];
71 
72 /* option debug buffer */
73 char optbuf[1024];
74 char *op;
75 char *oe = optbuf + sizeof(optbuf);
76 
77 char *optname[256] =
78 {
79 [OBend]			"end",
80 [OBpad]			"pad",
81 [OBmask]		"mask",
82 [OBtimeoff]		"timeoff",
83 [OBrouter]		"router",
84 [OBtimeserver]		"time",
85 [OBnameserver]		"name",
86 [OBdnserver]		"dns",
87 [OBlogserver]		"log",
88 [OBcookieserver]	"cookie",
89 [OBlprserver]		"lpr",
90 [OBimpressserver]	"impress",
91 [OBrlserver]		"rl",
92 [OBhostname]		"host",
93 [OBbflen]		"bflen",
94 [OBdumpfile]		"dumpfile",
95 [OBdomainname]		"dom",
96 [OBswapserver]		"swap",
97 [OBrootpath]		"rootpath",
98 [OBextpath]		"extpath",
99 [OBipforward]		"ipforward",
100 [OBnonlocal]		"nonlocal",
101 [OBpolicyfilter]	"policyfilter",
102 [OBmaxdatagram]		"maxdatagram",
103 [OBttl]			"ttl",
104 [OBpathtimeout]		"pathtimeout",
105 [OBpathplateau]		"pathplateau",
106 [OBmtu]			"mtu",
107 [OBsubnetslocal]	"subnetslocal",
108 [OBbaddr]		"baddr",
109 [OBdiscovermask]	"discovermask",
110 [OBsupplymask]		"supplymask",
111 [OBdiscoverrouter]	"discoverrouter",
112 [OBrsserver]		"rsserver",
113 [OBstaticroutes]	"staticroutes",
114 [OBtrailerencap]	"trailerencap",
115 [OBarptimeout]		"arptimeout",
116 [OBetherencap]		"etherencap",
117 [OBtcpttl]		"tcpttl",
118 [OBtcpka]		"tcpka",
119 [OBtcpkag]		"tcpkag",
120 [OBnisdomain]		"nisdomain",
121 [OBniserver]		"niserver",
122 [OBntpserver]		"ntpserver",
123 [OBvendorinfo]		"vendorinfo",
124 [OBnetbiosns]		"NBns",
125 [OBnetbiosdds]		"NBdds",
126 [OBnetbiostype]		"NBtype",
127 [OBnetbiosscope]	"NBscope",
128 [OBxfontserver]		"xfont",
129 [OBxdispmanager]	"xdisp",
130 [OBnisplusdomain]	"NPdomain",
131 [OBnisplusserver]	"NP",
132 [OBhomeagent]		"homeagent",
133 [OBsmtpserver]		"smtp",
134 [OBpop3server]		"pop3",
135 [OBnntpserver]		"nntp",
136 [OBwwwserver]		"www",
137 [OBfingerserver]	"finger",
138 [OBircserver]		"ircserver",
139 [OBstserver]		"stserver",
140 [OBstdaserver]		"stdaserver",
141 
142 /* dhcp options */
143 [ODipaddr]		"ip",
144 [ODlease]		"leas",
145 [ODoverload]		"overload",
146 [ODtype]		"typ",
147 [ODserverid]		"sid",
148 [ODparams]		"params",
149 [ODmessage]		"message",
150 [ODmaxmsg]		"maxmsg",
151 [ODrenewaltime]		"renewaltime",
152 [ODrebindingtime]	"rebindingtime",
153 [ODvendorclass]		"vendorclass",
154 [ODclientid]		"cid",
155 [ODtftpserver]		"tftpserver",
156 [ODbootfile]		"bf",
157 };
158 
159 void	addropt(Req*, int, uchar*);
160 void	addrsopt(Req*, int, uchar**, int);
161 void	arpenter(uchar*, uchar*);
162 void	bootp(Req*);
163 void	byteopt(Req*, int, uchar);
164 void	dhcp(Req*);
165 void	fatal(int, char*, ...);
166 void	hexopt(Req*, int, char*);
167 void	logdhcp(Req*);
168 void	logdhcpout(Req *, char *);
169 void	longopt(Req*, int, long);
170 void	maskopt(Req*, int, uchar*);
171 void	miscoptions(Req*, uchar*);
172 int	openlisten(char *net);
173 void	parseoptions(Req*);
174 void	proto(Req*, int);
175 void	rcvdecline(Req*);
176 void	rcvdiscover(Req*);
177 void	rcvinform(Req*);
178 void	rcvrelease(Req*);
179 void	rcvrequest(Req*);
180 int	readlast(int, uchar*, int);
181 char*	readsysname(void);
182 void	remrequested(Req*, int);
183 void	sendack(Req*, uchar*, int, int);
184 void	sendnak(Req*, char*);
185 void	sendoffer(Req*, uchar*, int);
186 void	stringopt(Req*, int, char*);
187 void	termopt(Req*);
188 int	validip(uchar*);
189 void	vectoropt(Req*, int, uchar*, int);
190 void	warning(int, char*, ...);
191 
192 void
193 timestamp(char *tag)
194 {
195 	ulong t;
196 
197 	t = nsec()/1000;
198 	syslog(0, blog, "%s %lud", tag, t - start);
199 }
200 
201 void
202 usage(void)
203 {
204 	fprint(2, "usage: dhcp [-dmnprsSZ] [-f directory] [-M minlease] "
205 		"[-x netmtpt] [-Z staticlease] addr n [addr n] ...\n");
206 	exits("usage");
207 }
208 
209 void
210 main(int argc, char **argv)
211 {
212 	int i, n, fd;
213 	uchar ip[IPaddrlen];
214 	Req r;
215 
216 	setnetmtpt(net, sizeof net, nil);
217 
218 	fmtinstall('E', eipfmt);
219 	fmtinstall('I', eipfmt);
220 	fmtinstall('V', eipfmt);
221 	fmtinstall('M', eipfmt);
222 	ARGBEGIN {
223 	case 'd':
224 		debug = 1;
225 		break;
226 	case 'f':
227 		ndbfile = EARGF(usage());
228 		break;
229 	case 'm':
230 		mute = 1;
231 		break;
232 	case 'M':
233 		minlease = atoi(EARGF(usage()));
234 		if(minlease <= 0)
235 			minlease = MinLease;
236 		break;
237 	case 'n':
238 		nobootp = 1;
239 		break;
240 	case 'p':
241 		pptponly = 1;
242 		break;
243 	case 'r':
244 		mutestat = 1;
245 		break;
246 	case 's':
247 		slowstat = 1;
248 		break;
249 	case 'S':
250 		slowdyn = 1;
251 		break;
252 	case 'x':
253 		setnetmtpt(net, sizeof net, EARGF(usage()));
254 		break;
255 	case 'Z':
256 		staticlease = atoi(EARGF(usage()));
257 		if(staticlease <= 0)
258 			staticlease = StaticLease;
259 		break;
260 	default:
261 		usage();
262 		break;
263 	} ARGEND;
264 
265 	while(argc > 1){
266 		parseip(ip, argv[0]);
267 		if(!validip(ip))
268 			usage();
269 		n = atoi(argv[1]);
270 		if(n <= 0)
271 			usage();
272 		initbinding(ip, n);
273 		argc -= 2;
274 		argv += 2;
275 	}
276 
277 	/* for debugging */
278 	for(i = 0; i < 256; i++)
279 		if(optname[i] == 0)
280 			optname[i] = smprint("%d", i);
281 
282 	/* what is my name? */
283 	strcpy(mysysname, readsysname());
284 
285 	/* put process in background */
286 	if(!debug) switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
287 	case -1:
288 		fatal(1, "fork");
289 	case 0:
290 		break;
291 	default:
292 		exits(0);
293 	}
294 
295 	chdir(TFTP);
296 	fd = openlisten(net);
297 
298 	for(;;){
299 		memset(&r, 0, sizeof(r));
300 		r.fd = fd;
301 		n = readlast(r.fd, r.buf, sizeof(r.buf));
302 		if(n < Udphdrsize)
303 			fatal(1, "error reading requests");
304 		start = nsec()/1000;
305 		op = optbuf;
306 		*op = 0;
307 		proto(&r, n);
308 		if(r.id != nil)
309 			free(r.id);
310 	}
311 }
312 
313 void
314 proto(Req *rp, int n)
315 {
316 	uchar relip[IPaddrlen];
317 	char buf[64];
318 
319 	now = time(0);
320 
321 	rp->e = rp->buf + n;
322 	rp->bp = (Bootp*)rp->buf;
323 	rp->up = (Udphdr*)rp->buf;
324 	if (ipcmp(rp->up->laddr, IPv4bcast) == 0)
325 		ipmove(rp->up->laddr, rp->up->ifcaddr);
326 	rp->max = rp->buf + Udphdrsize + MINSUPPORTED - IPUDPHDRSIZE;
327 	rp->p = rp->bp->optdata;
328 	v4tov6(rp->giaddr, rp->bp->giaddr);
329 	v4tov6(rp->ciaddr, rp->bp->ciaddr);
330 
331 	if(pptponly && rp->bp->htype != 0)
332 		return;
333 
334 	ipifcs = readipifc(net, ipifcs, -1);
335 	if(validip(rp->giaddr))
336 		ipmove(relip, rp->giaddr);
337 	else if(validip(rp->up->raddr))
338 		ipmove(relip, rp->up->raddr);
339 	else
340 		ipmove(relip, rp->up->laddr);
341 	if(rp->e < (uchar*)rp->bp->sname){
342 		warning(0, "packet too short");
343 		return;
344 	}
345 	if(rp->bp->op != Bootrequest){
346 		warning(0, "not bootrequest");
347 		return;
348 	}
349 
350 	if(rp->e >= rp->bp->optdata){
351 		if(memcmp(rp->bp->optmagic, plan9opt, sizeof(rp->bp->optmagic)) == 0)
352 			rp->p9request = 1;
353 		if(memcmp(rp->bp->optmagic, genericopt, sizeof(rp->bp->optmagic)) == 0) {
354 			rp->genrequest = 1;
355 			parseoptions(rp);
356 		}
357 	}
358 	rp->p = rp->bp->optdata;
359 
360 	/*  If no id is specified, make one from the hardware address
361 	 *  of the target.  We assume all zeros is not a hardware address
362 	 *  which could be a mistake.
363 	 */
364 	if(rp->id == nil){
365 		if(rp->bp->hlen > Maxhwlen){
366 			warning(0, "hlen %d", rp->bp->hlen);
367 			return;
368 		}
369 		if(memcmp(zeros, rp->bp->chaddr, rp->bp->hlen) == 0){
370 			warning(0, "no chaddr");
371 			return;
372 		}
373 		sprint(buf, "hwa%2.2ux_", rp->bp->htype);
374 		rp->id = tohex(buf, rp->bp->chaddr, rp->bp->hlen);
375 	}
376 
377 	/* info about gateway */
378 	if(lookupip(relip, &rp->gii, 1) < 0){
379 		warning(0, "lookupip failed");
380 		return;
381 	}
382 
383 	/* info about target system */
384 	if(lookup(rp->bp, &rp->ii, &rp->gii) == 0)
385 		if(rp->ii.indb && rp->ii.dhcpgroup[0] == 0)
386 			rp->staticbinding = 1;
387 
388 	if(rp->dhcptype)
389 		dhcp(rp);
390 	else
391 		bootp(rp);
392 timestamp("done");
393 }
394 
395 static void
396 slowdelay(Req *rp)
397 {
398 	if(slowstat && rp->staticbinding || slowdyn && !rp->staticbinding)
399 		sleep(2000);
400 }
401 
402 void
403 dhcp(Req *rp)
404 {
405 	logdhcp(rp);
406 
407 	switch(rp->dhcptype){
408 	case Discover:
409 		slowdelay(rp);
410 		rcvdiscover(rp);
411 		break;
412 	case Request:
413 		rcvrequest(rp);
414 		break;
415 	case Decline:
416 		rcvdecline(rp);
417 		break;
418 	case Release:
419 		rcvrelease(rp);
420 		break;
421 	case Inform:
422 		rcvinform(rp);
423 		break;
424 	}
425 }
426 
427 void
428 rcvdiscover(Req *rp)
429 {
430 	Binding *b, *nb;
431 
432 	if(rp->staticbinding){
433 		sendoffer(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease));
434 		return;
435 	}
436 
437 	/*
438 	 *  first look for an outstanding offer
439 	 */
440 	b = idtooffer(rp->id, &rp->gii);
441 
442 	/*
443 	 * rfc2131 says:
444 	 *   If an address is available, the new address
445 	 *   SHOULD be chosen as follows:
446 	 *
447 	 *      o The client's current address as recorded in the client's current
448 	 *        binding, ELSE
449 	 *
450 	 *      o The client's previous address as recorded in the client's (now
451 	 *        expired or released) binding, if that address is in the server's
452 	 *        pool of available addresses and not already allocated, ELSE
453 	 *
454 	 *      o The address requested in the 'Requested IP Address' option, if that
455 	 *        address is valid and not already allocated, ELSE
456 	 *
457 	 *      o A new address allocated from the server's pool of available
458 	 *        addresses; the address is selected based on the subnet from which
459 	 *        the message was received (if 'giaddr' is 0) or on the address of
460 	 *        the relay agent that forwarded the message ('giaddr' when not 0).
461 	 */
462 	if(b == nil){
463 		b = idtobinding(rp->id, &rp->gii, 1);
464 		if(b && b->boundto && strcmp(b->boundto, rp->id) != 0)
465 		if(validip(rp->ip) && samenet(rp->ip, &rp->gii)){
466 			nb = iptobinding(rp->ip, 0);
467 			if(nb && nb->lease < now)
468 				b = nb;
469 		}
470 	}
471 	if(b == nil){
472 		warning(0, "!Discover(%s via %I): no binding %I",
473 			rp->id, rp->gii.ipaddr, rp->ip);
474 		return;
475 	}
476 	mkoffer(b, rp->id, rp->leasetime);
477 	sendoffer(rp, b->ip, b->offer);
478 }
479 
480 void
481 rcvrequest(Req *rp)
482 {
483 	Binding *b;
484 
485 	if(validip(rp->server)){
486 		/* this is a reply to an offer - SELECTING */
487 
488 		/* check for hard assignment */
489 		if(rp->staticbinding){
490 			if(forme(rp->server))
491 				sendack(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease), 1);
492 			else
493 				warning(0, "!Request(%s via %I): for server %I not me",
494 					rp->id, rp->gii.ipaddr, rp->server);
495 			return;
496 		}
497 
498 		b = idtooffer(rp->id, &rp->gii);
499 
500 		/* if we don't have an offer, nak */
501 		if(b == nil){
502 			warning(0, "!Request(%s via %I): no offer",
503 				rp->id, rp->gii.ipaddr);
504 			if(forme(rp->server))
505 				sendnak(rp, "no offer for you");
506 			return;
507 		}
508 
509 		/* if not for me, retract offer */
510 		if(!forme(rp->server)){
511 			b->expoffer = 0;
512 			warning(0, "!Request(%s via %I): for server %I not me",
513 				rp->id, rp->gii.ipaddr, rp->server);
514 			return;
515 		}
516 
517 		/*
518 		 *  if the client is confused about what we offered, nak.
519 		 *  client really shouldn't be specifying this when selecting
520 		 */
521 		if(validip(rp->ip) && ipcmp(rp->ip, b->ip) != 0){
522 			warning(0, "!Request(%s via %I): requests %I, not %I",
523 				rp->id, rp->gii.ipaddr, rp->ip, b->ip);
524 			sendnak(rp, "bad ip address option");
525 			return;
526 		}
527 		if(commitbinding(b) < 0){
528 			warning(0, "!Request(%s via %I): can't commit %I",
529 				rp->id, rp->gii.ipaddr, b->ip);
530 			sendnak(rp, "can't commit binding");
531 			return;
532 		}
533 		sendack(rp, b->ip, b->offer, 1);
534 	} else if(validip(rp->ip)){
535 		/*
536 		 *  checking address/net - INIT-REBOOT
537 		 *
538 		 *  This is a rebooting client that remembers its old
539 		 *  address.
540 		 */
541 		/* check for hard assignment */
542 		if(rp->staticbinding){
543 			if(memcmp(rp->ip, rp->ii.ipaddr, IPaddrlen) != 0){
544 				warning(0, "!Request(%s via %I): %I not valid for %E",
545 					rp->id, rp->gii.ipaddr, rp->ip, rp->bp->chaddr);
546 				sendnak(rp, "not valid");
547 			}
548 			sendack(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease), 1);
549 			return;
550 		}
551 
552 		/* make sure the network makes sense */
553 		if(!samenet(rp->ip, &rp->gii)){
554 			warning(0, "!Request(%s via %I): bad forward of %I",
555 				rp->id, rp->gii.ipaddr, rp->ip);
556 			sendnak(rp, "wrong network");
557 			return;
558 		}
559 		b = iptobinding(rp->ip, 0);
560 		if(b == nil){
561 			warning(0, "!Request(%s via %I): no binding for %I for",
562 				rp->id, rp->gii.ipaddr, rp->ip);
563 			return;
564 		}
565 		if(memcmp(rp->ip, b->ip, IPaddrlen) != 0 || now > b->lease){
566 			warning(0, "!Request(%s via %I): %I not valid",
567 				rp->id, rp->gii.ipaddr, rp->ip);
568 			sendnak(rp, "not valid");
569 			return;
570 		}
571 		b->offer = b->lease - now;
572 		sendack(rp, b->ip, b->offer, 1);
573 	} else if(validip(rp->ciaddr)){
574 		/*
575 		 *  checking address - RENEWING or REBINDING
576 		 *
577 		 *  these states are indistinguishable in our action.  The only
578 		 *  difference is how close to lease expiration the client is.
579 		 *  If it is really close, it broadcasts the request hoping that
580 		 *  some server will answer.
581 		 */
582 
583 		/* check for hard assignment */
584 		if(rp->staticbinding){
585 			if(ipcmp(rp->ciaddr, rp->ii.ipaddr) != 0){
586 				warning(0, "!Request(%s via %I): %I not valid",
587 					rp->id, rp->gii.ipaddr, rp->ciaddr);
588 				sendnak(rp, "not valid");
589 			}
590 			sendack(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease), 1);
591 			return;
592 		}
593 
594 		/* make sure the network makes sense */
595 		if(!samenet(rp->ciaddr, &rp->gii)){
596 			warning(0, "!Request(%s via %I): bad forward of %I",
597 				rp->id, rp->gii.ipaddr, rp->ip);
598 			sendnak(rp, "wrong network");
599 			return;
600 		}
601 		b = iptobinding(rp->ciaddr, 0);
602 		if(b == nil){
603 			warning(0, "!Request(%s via %I): no binding for %I",
604 				rp->id, rp->gii.ipaddr, rp->ciaddr);
605 			return;
606 		}
607 		if(ipcmp(rp->ciaddr, b->ip) != 0){
608 			warning(0, "!Request(%I via %s): %I not valid",
609 				rp->id, rp->gii.ipaddr, rp->ciaddr);
610 			sendnak(rp, "invalid ip address");
611 			return;
612 		}
613 		mkoffer(b, rp->id, rp->leasetime);
614 		if(commitbinding(b) < 0){
615 			warning(0, "!Request(%s via %I): can't commit %I",
616 				rp->id, rp->gii.ipaddr, b->ip);
617 			sendnak(rp, "can't commit binding");
618 			return;
619 		}
620 		sendack(rp, b->ip, b->offer, 1);
621 	}
622 }
623 
624 void
625 rcvdecline(Req *rp)
626 {
627 	Binding *b;
628 	char buf[64];
629 
630 	if(rp->staticbinding)
631 		return;
632 
633 	b = idtooffer(rp->id, &rp->gii);
634 	if(b == nil){
635 		warning(0, "!Decline(%s via %I): no binding",
636 			rp->id, rp->gii.ipaddr);
637 		return;
638 	}
639 
640 	/* mark ip address as in use */
641 	snprint(buf, sizeof(buf), "declined by %s", rp->id);
642 	mkoffer(b, buf, 0x7fffffff);
643 	commitbinding(b);
644 }
645 
646 void
647 rcvrelease(Req *rp)
648 {
649 	Binding *b;
650 
651 	if(rp->staticbinding)
652 		return;
653 
654 	b = idtobinding(rp->id, &rp->gii, 0);
655 	if(b == nil){
656 		warning(0, "!Release(%s via %I): no binding",
657 			rp->id, rp->gii.ipaddr);
658 		return;
659 	}
660 	if(strcmp(rp->id, b->boundto) != 0){
661 		warning(0, "!Release(%s via %I): invalid release of %I",
662 			rp->id, rp->gii.ipaddr, rp->ip);
663 		return;
664 	}
665 	warning(0, "Release(%s via %I): releasing %I", b->boundto, rp->gii.ipaddr, b->ip);
666 	if(releasebinding(b, rp->id) < 0)
667 		warning(0, "release: couldn't release");
668 }
669 
670 void
671 rcvinform(Req *rp)
672 {
673 	Binding *b;
674 
675 	if(rp->staticbinding){
676 		sendack(rp, rp->ii.ipaddr, 0, 0);
677 		return;
678 	}
679 
680 	b = iptobinding(rp->ciaddr, 0);
681 	if(b == nil){
682 		warning(0, "!Inform(%s via %I): no binding for %I",
683 			rp->id, rp->gii.ipaddr, rp->ip);
684 		return;
685 	}
686 	sendack(rp, b->ip, 0, 0);
687 }
688 
689 int
690 setsiaddr(uchar *siaddr, uchar *saddr, uchar *laddr)
691 {
692 	if(ipcmp(saddr, IPnoaddr) != 0){
693 		v6tov4(siaddr, saddr);
694 		return 0;
695 	} else {
696 		v6tov4(siaddr, laddr);
697 		return 1;
698 	}
699 }
700 
701 int
702 ismuted(Req *rp)
703 {
704 	return mute || (mutestat && rp->staticbinding);
705 }
706 
707 void
708 sendoffer(Req *rp, uchar *ip, int offer)
709 {
710 	int n;
711 	ushort flags;
712 	Bootp *bp;
713 	Udphdr *up;
714 
715 	bp = rp->bp;
716 	up = rp->up;
717 
718 	/*
719 	 *  set destination
720 	 */
721 	flags = nhgets(bp->flags);
722 	if(validip(rp->giaddr)){
723 		ipmove(up->raddr, rp->giaddr);
724 		hnputs(up->rport, 67);
725 	} else if(flags & Fbroadcast){
726 		ipmove(up->raddr, IPv4bcast);
727 		hnputs(up->rport, 68);
728 	} else {
729 		ipmove(up->raddr, ip);
730 		if(bp->htype == 1)
731 			arpenter(up->raddr, bp->chaddr);
732 		hnputs(up->rport, 68);
733 	}
734 
735 	/*
736 	 *  fill in standard bootp part
737 	 */
738 	bp->op = Bootreply;
739 	bp->hops = 0;
740 	hnputs(bp->secs, 0);
741 	memset(bp->ciaddr, 0, sizeof(bp->ciaddr));
742 	v6tov4(bp->giaddr, rp->giaddr);
743 	v6tov4(bp->yiaddr, ip);
744 	setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr);
745 	strncpy(bp->sname, mysysname, sizeof(bp->sname));
746 	strncpy(bp->file, rp->ii.bootf, sizeof(bp->file));
747 
748 	/*
749 	 *  set options
750 	 */
751 	byteopt(rp, ODtype, Offer);
752 	longopt(rp, ODlease, offer);
753 	addropt(rp, ODserverid, up->laddr);
754 	miscoptions(rp, ip);
755 	termopt(rp);
756 
757 	logdhcpout(rp, "Offer");
758 
759 	/*
760 	 *  send
761 	 */
762 	n = rp->p - rp->buf;
763 	if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
764 		warning(0, "offer: write failed: %r");
765 }
766 
767 void
768 sendack(Req *rp, uchar *ip, int offer, int sendlease)
769 {
770 	int n;
771 	ushort flags;
772 	Bootp *bp;
773 	Udphdr *up;
774 
775 	bp = rp->bp;
776 	up = rp->up;
777 
778 	/*
779 	 *  set destination
780 	 */
781 	flags = nhgets(bp->flags);
782 	if(validip(rp->giaddr)){
783 		ipmove(up->raddr, rp->giaddr);
784 		hnputs(up->rport, 67);
785 	} else if(flags & Fbroadcast){
786 		ipmove(up->raddr, IPv4bcast);
787 		hnputs(up->rport, 68);
788 	} else {
789 		ipmove(up->raddr, ip);
790 		if(bp->htype == 1)
791 			arpenter(up->raddr, bp->chaddr);
792 		hnputs(up->rport, 68);
793 	}
794 
795 	/*
796 	 *  fill in standard bootp part
797 	 */
798 	bp->op = Bootreply;
799 	bp->hops = 0;
800 	hnputs(bp->secs, 0);
801 	v6tov4(bp->giaddr, rp->giaddr);
802 	v6tov4(bp->yiaddr, ip);
803 	setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr);
804 	strncpy(bp->sname, mysysname, sizeof(bp->sname));
805 	strncpy(bp->file, rp->ii.bootf, sizeof(bp->file));
806 
807 	/*
808 	 *  set options
809 	 */
810 	byteopt(rp, ODtype, Ack);
811 	if(sendlease){
812 		longopt(rp, ODlease, offer);
813 	}
814 	addropt(rp, ODserverid, up->laddr);
815 	miscoptions(rp, ip);
816 	termopt(rp);
817 
818 	logdhcpout(rp, "Ack");
819 
820 	/*
821 	 *  send
822 	 */
823 	n = rp->p - rp->buf;
824 	if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
825 		warning(0, "ack: write failed: %r");
826 }
827 
828 void
829 sendnak(Req *rp, char *msg)
830 {
831 	int n;
832 	Bootp *bp;
833 	Udphdr *up;
834 
835 	bp = rp->bp;
836 	up = rp->up;
837 
838 	/*
839 	 *  set destination (always broadcast)
840 	 */
841 	if(validip(rp->giaddr)){
842 		ipmove(up->raddr, rp->giaddr);
843 		hnputs(up->rport, 67);
844 	} else {
845 		ipmove(up->raddr, IPv4bcast);
846 		hnputs(up->rport, 68);
847 	}
848 
849 	/*
850 	 *  fill in standard bootp part
851 	 */
852 	bp->op = Bootreply;
853 	bp->hops = 0;
854 	hnputs(bp->secs, 0);
855 	v6tov4(bp->giaddr, rp->giaddr);
856 	memset(bp->ciaddr, 0, sizeof(bp->ciaddr));
857 	memset(bp->yiaddr, 0, sizeof(bp->yiaddr));
858 	memset(bp->siaddr, 0, sizeof(bp->siaddr));
859 
860 	/*
861 	 *  set options
862 	 */
863 	byteopt(rp, ODtype, Nak);
864 	addropt(rp, ODserverid, up->laddr);
865 	if(msg)
866 		stringopt(rp, ODmessage, msg);
867 	if(strncmp(rp->id, "id", 2) == 0)
868 		hexopt(rp, ODclientid, rp->id+2);
869 	termopt(rp);
870 
871 	logdhcpout(rp, "Nak");
872 
873 	/*
874 	 *  send nak
875 	 */
876 	n = rp->p - rp->buf;
877 	if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
878 		warning(0, "nak: write failed: %r");
879 }
880 
881 void
882 bootp(Req *rp)
883 {
884 	int n;
885 	Bootp *bp;
886 	Udphdr *up;
887 	ushort flags;
888 	Iplifc *lifc;
889 	Info *iip;
890 
891 	warning(0, "bootp %s %I->%I from %s via %I, file %s",
892 		rp->genrequest? "generic": (rp->p9request? "p9": ""),
893 		rp->up->raddr, rp->up->laddr,
894 		rp->id, rp->gii.ipaddr,
895 		rp->bp->file);
896 
897 	if(nobootp)
898 		return;
899 
900 	bp = rp->bp;
901 	up = rp->up;
902 	iip = &rp->ii;
903 
904 	if(rp->staticbinding == 0){
905 		warning(0, "bootp from unknown %s via %I", rp->id, rp->gii.ipaddr);
906 		return;
907 	}
908 
909 	/* ignore if not for us */
910 	if(*bp->sname){
911 		if(strcmp(bp->sname, mysysname) != 0){
912 			bp->sname[20] = 0;
913 			warning(0, "bootp for server %s", bp->sname);
914 			return;
915 		}
916 	} else
917 		slowdelay(rp);
918 
919 	/* ignore if we don't know what file to load */
920 	if(*bp->file == 0){
921 		if(rp->genrequest && *iip->bootf2)	/* if not plan 9 and we have an alternate file... */
922 			strncpy(bp->file, iip->bootf2, sizeof(bp->file));
923 		else if(*iip->bootf)
924 			strncpy(bp->file, iip->bootf, sizeof(bp->file));
925 		else if(*bp->sname)		/* if we were asked, respond no matter what */
926 			bp->file[0] = '\0';
927 		else {
928 			warning(0, "no bootfile for %I", iip->ipaddr);
929 			return;
930 		}
931 	}
932 
933 	/* ignore if the file is unreadable */
934 	if((!rp->genrequest) && bp->file[0] && access(bp->file, 4) < 0){
935 		warning(0, "inaccessible bootfile1 %s", bp->file);
936 		return;
937 	}
938 
939 	bp->op = Bootreply;
940 	v6tov4(bp->yiaddr, iip->ipaddr);
941 	if(rp->p9request){
942 		warning(0, "p9bootp: %I", iip->ipaddr);
943 		memmove(bp->optmagic, plan9opt, 4);
944 		if(iip->gwip == 0)
945 			v4tov6(iip->gwip, bp->giaddr);
946 		rp->p += sprint((char*)rp->p, "%V %I %I %I", iip->ipmask+IPv4off, iip->fsip,
947 				iip->auip, iip->gwip);
948 		sprint(optbuf, "%s", (char*)(bp->optmagic));
949 	} else if(rp->genrequest){
950 		warning(0, "genericbootp: %I", iip->ipaddr);
951 		memmove(bp->optmagic, genericopt, 4);
952 		miscoptions(rp, iip->ipaddr);
953 		termopt(rp);
954 	} else if(iip->vendor[0] != 0) {
955 		warning(0, "bootp vendor field: %s", iip->vendor);
956 		memset(rp->p, 0, 128-4);
957 		rp->p += sprint((char*)bp->optmagic, "%s", iip->vendor);
958 	} else {
959 		memset(rp->p, 0, 128-4);
960 		rp->p += 128-4;
961 	}
962 
963 	/*
964 	 *  set destination
965 	 */
966 	flags = nhgets(bp->flags);
967 	if(validip(rp->giaddr)){
968 		ipmove(up->raddr, rp->giaddr);
969 		hnputs(up->rport, 67);
970 	} else if(flags & Fbroadcast){
971 		ipmove(up->raddr, IPv4bcast);
972 		hnputs(up->rport, 68);
973 	} else {
974 		v4tov6(up->raddr, bp->yiaddr);
975 		if(bp->htype == 1)
976 			arpenter(up->raddr, bp->chaddr);
977 		hnputs(up->rport, 68);
978 	}
979 
980 	/*
981 	 *  select best local address if destination is directly connected
982 	 */
983 	lifc = findlifc(up->raddr);
984 	if(lifc)
985 		ipmove(up->laddr, lifc->ip);
986 
987 	/*
988 	 *  our identity
989 	 */
990 	strncpy(bp->sname, mysysname, sizeof(bp->sname));
991 
992 	/*
993 	 *  set tftp server
994 	 */
995 	setsiaddr(bp->siaddr, iip->tftp, up->laddr);
996 	if(rp->genrequest && *iip->bootf2)
997 		setsiaddr(bp->siaddr, iip->tftp2, up->laddr);
998 
999 	/*
1000 	 * RFC 1048 says that we must pad vendor field with
1001 	 * zeros until we have a 64 byte field.
1002 	 */
1003 	n = rp->p - rp->bp->optdata;
1004 	if(n < 64-4) {
1005 		memset(rp->p, 0, (64-4)-n);
1006 		rp->p += (64-4)-n;
1007 	}
1008 
1009 	/*
1010 	 *  send
1011 	 */
1012 	n = rp->p - rp->buf;
1013 	if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
1014 		warning(0, "bootp: write failed: %r");
1015 
1016 	warning(0, "bootp via %I: file %s xid(%ux)flag(%ux)ci(%V)gi(%V)yi(%V)si(%V) %s",
1017 			up->raddr, bp->file, nhgetl(bp->xid), nhgets(bp->flags),
1018 			bp->ciaddr, bp->giaddr, bp->yiaddr, bp->siaddr,
1019 			optbuf);
1020 }
1021 
1022 void
1023 parseoptions(Req *rp)
1024 {
1025 	int n, c, code;
1026 	uchar *o, *p;
1027 
1028 	p = rp->p;
1029 
1030 	while(p < rp->e){
1031 		code = *p++;
1032 		if(code == 255)
1033 			break;
1034 		if(code == 0)
1035 			continue;
1036 
1037 		/* ignore anything that's too long */
1038 		n = *p++;
1039 		o = p;
1040 		p += n;
1041 		if(p > rp->e)
1042 			return;
1043 
1044 		switch(code){
1045 		case ODipaddr:	/* requested ip address */
1046 			if(n == IPv4addrlen)
1047 				v4tov6(rp->ip, o);
1048 			break;
1049 		case ODlease:	/* requested lease time */
1050 			rp->leasetime = nhgetl(o);
1051 			if(rp->leasetime > MaxLease || rp->leasetime < 0)
1052 				rp->leasetime = MaxLease;
1053 			break;
1054 		case ODtype:
1055 			c = *o;
1056 			if(c < 10 && c > 0)
1057 				rp->dhcptype = c;
1058 			break;
1059 		case ODserverid:
1060 			if(n == IPv4addrlen)
1061 				v4tov6(rp->server, o);
1062 			break;
1063 		case ODmessage:
1064 			if(n > sizeof rp->msg-1)
1065 				n = sizeof rp->msg-1;
1066 			memmove(rp->msg, o, n);
1067 			rp->msg[n] = 0;
1068 			break;
1069 		case ODmaxmsg:
1070 			c = nhgets(o);
1071 			c -= 28;
1072 			c += Udphdrsize;
1073 			if(c > 0)
1074 				rp->max = rp->buf + c;
1075 			break;
1076 		case ODclientid:
1077 			if(n <= 1)
1078 				break;
1079 			rp->id = toid( o, n);
1080 			break;
1081 		case ODparams:
1082 			if(n > sizeof(rp->requested))
1083 				n = sizeof(rp->requested);
1084 			memmove(rp->requested, o, n);
1085 			break;
1086 		case ODvendorclass:
1087 			if(n >= sizeof(rp->vendorclass))
1088 				n = sizeof(rp->vendorclass)-1;
1089 			memmove(rp->vendorclass, o, n);
1090 			rp->vendorclass[n] = 0;
1091 			if(strncmp((char*)rp->vendorclass, "p9-", 3) == 0)
1092 				strcpy(rp->cputype, (char*)rp->vendorclass+3);
1093 			break;
1094 		case OBend:
1095 			return;
1096 		}
1097 	}
1098 }
1099 
1100 void
1101 remrequested(Req *rp, int opt)
1102 {
1103 	uchar *p;
1104 
1105 	p = memchr(rp->requested, opt, sizeof(rp->requested));
1106 	if(p != nil)
1107 		*p = OBpad;
1108 }
1109 
1110 void
1111 miscoptions(Req *rp, uchar *ip)
1112 {
1113 	char *p;
1114 	int i, j;
1115 	uchar *addrs[2];
1116 	uchar x[2*IPaddrlen];
1117 	uchar vopts[64];
1118 	uchar *op, *omax;
1119 	char *attr[100], **a;
1120 	int na;
1121 	Ndbtuple *t;
1122 
1123 	addrs[0] = x;
1124 	addrs[1] = x+IPaddrlen;
1125 
1126 	/* always supply these */
1127 	maskopt(rp, OBmask, rp->gii.ipmask);
1128 	if(validip(rp->gii.gwip)){
1129 		remrequested(rp, OBrouter);
1130 		addropt(rp, OBrouter, rp->gii.gwip);
1131 	} else if(validip(rp->giaddr)){
1132 		remrequested(rp, OBrouter);
1133 		addropt(rp, OBrouter, rp->giaddr);
1134 	}
1135 
1136 	/*
1137 	 * OBhostname for the HP4000M switches
1138 	 * (this causes NT to log infinite errors - tough shit)
1139 	 */
1140 	if(*rp->ii.domain){
1141 		remrequested(rp, OBhostname);
1142 		stringopt(rp, OBhostname, rp->ii.domain);
1143 	}
1144 	if(*rp->ii.rootpath)
1145 		stringopt(rp, OBrootpath, rp->ii.rootpath);
1146 
1147 	/* figure out what we need to lookup */
1148 	na = 0;
1149 	a = attr;
1150 	if(*rp->ii.domain == 0)
1151 		a[na++] = "dom";
1152 	for(i = 0; i < sizeof(rp->requested); i++)
1153 		switch(rp->requested[i]){
1154 		case OBrouter:
1155 			a[na++] = "@ipgw";
1156 			break;
1157 		case OBdnserver:
1158 			a[na++] = "@dns";
1159 			break;
1160 		case OBnetbiosns:
1161 			a[na++] = "@wins";
1162 			break;
1163 		case OBsmtpserver:
1164 			a[na++] = "@smtp";
1165 			break;
1166 		case OBpop3server:
1167 			a[na++] = "@pop3";
1168 			break;
1169 		case OBwwwserver:
1170 			a[na++] = "@www";
1171 			break;
1172 		case OBntpserver:
1173 			a[na++] = "@ntp";
1174 			break;
1175 		case OBtimeserver:
1176 			a[na++] = "@time";
1177 			break;
1178 		}
1179 	if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
1180 	|| strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
1181 		a[na++] = "@fs";
1182 		a[na++] = "@auth";
1183 	}
1184 	t = lookupinfo(ip, a, na);
1185 
1186 	/* lookup anything we might be missing */
1187 	if(*rp->ii.domain == 0)
1188 		lookupname(rp->ii.domain, t);
1189 
1190 	/* add any requested ones that we know about */
1191 	for(i = 0; i < sizeof(rp->requested); i++)
1192 		switch(rp->requested[i]){
1193 		case OBrouter:
1194 			j = lookupserver("ipgw", addrs, t);
1195 			addrsopt(rp, OBrouter, addrs, j);
1196 			break;
1197 		case OBdnserver:
1198 			j = lookupserver("dns", addrs, t);
1199 			addrsopt(rp, OBdnserver, addrs, j);
1200 			break;
1201 		case OBhostname:
1202 			if(*rp->ii.domain)
1203 				stringopt(rp, OBhostname, rp->ii.domain);
1204 			break;
1205 		case OBdomainname:
1206 			p = strchr(rp->ii.domain, '.');
1207 			if(p)
1208 				stringopt(rp, OBdomainname, p+1);
1209 			break;
1210 		case OBnetbiosns:
1211 			j = lookupserver("wins", addrs, t);
1212 			addrsopt(rp, OBnetbiosns, addrs, j);
1213 			break;
1214 		case OBnetbiostype:
1215 			/* p-node: peer to peer WINS queries */
1216 			byteopt(rp, OBnetbiostype, 0x2);
1217 			break;
1218 		case OBsmtpserver:
1219 			j = lookupserver("smtp", addrs, t);
1220 			addrsopt(rp, OBsmtpserver, addrs, j);
1221 			break;
1222 		case OBpop3server:
1223 			j = lookupserver("pop3", addrs, t);
1224 			addrsopt(rp, OBpop3server, addrs, j);
1225 			break;
1226 		case OBwwwserver:
1227 			j = lookupserver("www", addrs, t);
1228 			addrsopt(rp, OBwwwserver, addrs, j);
1229 			break;
1230 		case OBntpserver:
1231 			j = lookupserver("ntp", addrs, t);
1232 			addrsopt(rp, OBntpserver, addrs, j);
1233 			break;
1234 		case OBtimeserver:
1235 			j = lookupserver("time", addrs, t);
1236 			addrsopt(rp, OBtimeserver, addrs, j);
1237 			break;
1238 		case OBttl:
1239 			byteopt(rp, OBttl, 255);
1240 			break;
1241 		}
1242 
1243 	/* add plan9 specific options */
1244 	if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
1245 	|| strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
1246 	/* point to temporary area */
1247 		op = rp->p;
1248 		omax = rp->max;
1249 		rp->p = vopts;
1250 		rp->max = vopts + sizeof(vopts) - 1;
1251 
1252 		j = lookupserver("fs", addrs, t);
1253 		addrsopt(rp, OP9fs, addrs, j);
1254 		j = lookupserver("auth", addrs, t);
1255 		addrsopt(rp, OP9auth, addrs, j);
1256 
1257 	/* point back */
1258 		j = rp->p - vopts;
1259 		rp->p = op;
1260 		rp->max = omax;
1261 		vectoropt(rp, OBvendorinfo, vopts, j);
1262 	}
1263 
1264 	ndbfree(t);
1265 }
1266 
1267 int
1268 openlisten(char *net)
1269 {
1270 	int fd, cfd;
1271 	char data[128], devdir[40];
1272 
1273 	sprint(data, "%s/udp!*!bootp", net);
1274 	cfd = announce(data, devdir);
1275 	if(cfd < 0)
1276 		fatal(1, "can't announce");
1277 	if(fprint(cfd, "headers") < 0)
1278 		fatal(1, "can't set header mode");
1279 
1280 	sprint(data, "%s/data", devdir);
1281 	fd = open(data, ORDWR);
1282 	if(fd < 0)
1283 		fatal(1, "open udp data");
1284 	return fd;
1285 }
1286 
1287 void
1288 fatal(int syserr, char *fmt, ...)
1289 {
1290 	char buf[ERRMAX];
1291 	va_list arg;
1292 
1293 	va_start(arg, fmt);
1294 	vseprint(buf, buf+sizeof(buf), fmt, arg);
1295 	va_end(arg);
1296 	if(syserr)
1297 		syslog(1, blog, "%s: %r", buf);
1298 	else
1299 		syslog(1, blog, "%s", buf);
1300 	exits(buf);
1301 }
1302 
1303 extern void
1304 warning(int syserr, char *fmt, ...)
1305 {
1306 	char buf[256];
1307 	va_list arg;
1308 
1309 	va_start(arg, fmt);
1310 	vseprint(buf, buf+sizeof(buf), fmt, arg);
1311 	va_end(arg);
1312 	if(syserr){
1313 		syslog(0, blog, "%s: %r", buf);
1314 		if(debug)
1315 			fprint(2, "%s: %r\n", buf);
1316 	} else {
1317 		syslog(0, blog, "%s", buf);
1318 		if(debug)
1319 			fprint(2, "%s\n", buf);
1320 	}
1321 }
1322 
1323 char*
1324 readsysname(void)
1325 {
1326 	static char name[128];
1327 	char *p;
1328 	int n, fd;
1329 
1330 	fd = open("/dev/sysname", OREAD);
1331 	if(fd >= 0){
1332 		n = read(fd, name, sizeof(name)-1);
1333 		close(fd);
1334 		if(n > 0){
1335 			name[n] = 0;
1336 			return name;
1337 		}
1338 	}
1339 	p = getenv("sysname");
1340 	if(p == nil || *p == 0)
1341 		return "unknown";
1342 	return p;
1343 }
1344 
1345 extern int
1346 validip(uchar *ip)
1347 {
1348 	if(ipcmp(ip, IPnoaddr) == 0)
1349 		return 0;
1350 	if(ipcmp(ip, v4prefix) == 0)
1351 		return 0;
1352 	return 1;
1353 }
1354 
1355 void
1356 longopt(Req *rp, int t, long v)
1357 {
1358 	if(rp->p + 6 > rp->max)
1359 		return;
1360 	*rp->p++ = t;
1361 	*rp->p++ = 4;
1362 	hnputl(rp->p, v);
1363 	rp->p += 4;
1364 
1365 	op = seprint(op, oe, "%s(%ld)", optname[t], v);
1366 }
1367 
1368 void
1369 addropt(Req *rp, int t, uchar *ip)
1370 {
1371 	if(rp->p + 6 > rp->max)
1372 		return;
1373 	*rp->p++ = t;
1374 	*rp->p++ = 4;
1375 	memmove(rp->p, ip+IPv4off, 4);
1376 	rp->p += 4;
1377 
1378 	op = seprint(op, oe, "%s(%I)", optname[t], ip);
1379 }
1380 
1381 void
1382 maskopt(Req *rp, int t, uchar *ip)
1383 {
1384 	if(rp->p + 6 > rp->max)
1385 		return;
1386 	*rp->p++ = t;
1387 	*rp->p++ = 4;
1388 	memmove(rp->p, ip+IPv4off, 4);
1389 	rp->p += 4;
1390 
1391 	op = seprint(op, oe, "%s(%M)", optname[t], ip);
1392 }
1393 
1394 void
1395 addrsopt(Req *rp, int t, uchar **ip, int i)
1396 {
1397 	if(i <= 0)
1398 		return;
1399 	if(rp->p + 2 + 4*i > rp->max)
1400 		return;
1401 	*rp->p++ = t;
1402 	*rp->p++ = 4*i;
1403 	op = seprint(op, oe, "%s(", optname[t]);
1404 	while(i-- > 0){
1405 		v6tov4(rp->p, *ip);
1406 		rp->p += 4;
1407 		op = seprint(op, oe, "%I", *ip);
1408 		ip++;
1409 		if(i > 0)
1410 			op = seprint(op, oe, " ");
1411 	}
1412 	op = seprint(op, oe, ")");
1413 }
1414 
1415 void
1416 byteopt(Req *rp, int t, uchar v)
1417 {
1418 	if(rp->p + 3 > rp->max)
1419 		return;
1420 	*rp->p++ = t;
1421 	*rp->p++ = 1;
1422 	*rp->p++ = v;
1423 
1424 	op = seprint(op, oe, "%s(%d)", optname[t], v);
1425 }
1426 
1427 void
1428 termopt(Req *rp)
1429 {
1430 	if(rp->p + 1 > rp->max)
1431 		return;
1432 	*rp->p++ = OBend;
1433 }
1434 
1435 void
1436 stringopt(Req *rp, int t, char *str)
1437 {
1438 	int n;
1439 
1440 	n = strlen(str);
1441 	if(n > 255)
1442 		n = 255;
1443 	if(rp->p+n+2 > rp->max)
1444 		return;
1445 	*rp->p++ = t;
1446 	*rp->p++ = n;
1447 	memmove(rp->p, str, n);
1448 	rp->p += n;
1449 
1450 	op = seprint(op, oe, "%s(%s)", optname[t], str);
1451 }
1452 
1453 void
1454 vectoropt(Req *rp, int t, uchar *v, int n)
1455 {
1456 	int i;
1457 
1458 	if(n > 255)
1459 		n = 255;
1460 	if(rp->p+n+2 > rp->max)
1461 		return;
1462 	*rp->p++ = t;
1463 	*rp->p++ = n;
1464 	memmove(rp->p, v, n);
1465 	rp->p += n;
1466 
1467 	op = seprint(op, oe, "%s(", optname[t]);
1468 	if(n > 0)
1469 		op = seprint(op, oe, "%ud", 0);
1470 	for(i = 1; i < n; i++)
1471 		op = seprint(op, oe, " %ud", v[i]);
1472 }
1473 
1474 int
1475 fromhex(int x)
1476 {
1477 	if(x >= '0' && x <= '9')
1478 		return x - '0';
1479 	return x - 'a';
1480 }
1481 
1482 void
1483 hexopt(Req *rp, int t, char *str)
1484 {
1485 	int n;
1486 
1487 	n = strlen(str);
1488 	n /= 2;
1489 	if(n > 255)
1490 		n = 255;
1491 	if(rp->p+n+2 > rp->max)
1492 		return;
1493 	*rp->p++ = t;
1494 	*rp->p++ = n;
1495 	while(n-- > 0){
1496 		*rp->p++ = (fromhex(str[0])<<4)|fromhex(str[1]);
1497 		str += 2;
1498 	}
1499 
1500 	op = seprint(op, oe, "%s(%s)", optname[t], str);
1501 }
1502 
1503 void
1504 arpenter(uchar *ip, uchar *ether)
1505 {
1506 	int f;
1507 	char buf[256];
1508 
1509 	/* brazil */
1510 	sprint(buf, "%s/arp", net);
1511 	f = open(buf, OWRITE);
1512 	if(f < 0){
1513 		syslog(debug, blog, "open %s: %r", buf);
1514 		return;
1515 	}
1516 	fprint(f, "add ether %I %E", ip, ether);
1517 	close(f);
1518 }
1519 
1520 char *dhcpmsgname[] =
1521 {
1522 	[Discover]	"Discover",
1523 	[Offer]		"Offer",
1524 	[Request]	"Request",
1525 	[Decline]	"Decline",
1526 	[Ack]		"Ack",
1527 	[Nak]		"Nak",
1528 	[Release]	"Release",
1529 	[Inform]	"Inform",
1530 };
1531 
1532 void
1533 logdhcp(Req *rp)
1534 {
1535 	char buf[4096];
1536 	char *p, *e;
1537 	int i;
1538 
1539 	p = buf;
1540 	e = buf + sizeof(buf);
1541 	if(rp->dhcptype > 0 && rp->dhcptype <= Inform)
1542 		p = seprint(p, e, "%s(", dhcpmsgname[rp->dhcptype]);
1543 	else
1544 		p = seprint(p, e, "%d(", rp->dhcptype);
1545 	p = seprint(p, e, "%I->%I) xid(%ux)flag(%ux)", rp->up->raddr, rp->up->laddr,
1546 		nhgetl(rp->bp->xid), nhgets(rp->bp->flags));
1547 	if(rp->bp->htype == 1)
1548 		p = seprint(p, e, "ea(%E)", rp->bp->chaddr);
1549 	if(validip(rp->ciaddr))
1550 		p = seprint(p, e, "ci(%I)", rp->ciaddr);
1551 	if(validip(rp->giaddr))
1552 		p = seprint(p, e, "gi(%I)", rp->giaddr);
1553 	if(validip(rp->ip))
1554 		p = seprint(p, e, "ip(%I)", rp->ip);
1555 	if(rp->id != nil)
1556 		p = seprint(p, e, "id(%s)", rp->id);
1557 	if(rp->leasetime)
1558 		p = seprint(p, e, "leas(%d)", rp->leasetime);
1559 	if(validip(rp->server))
1560 		p = seprint(p, e, "sid(%I)", rp->server);
1561 	p = seprint(p, e, "need(");
1562 	for(i = 0; i < sizeof(rp->requested); i++)
1563 		if(rp->requested[i] != 0)
1564 			p = seprint(p, e, "%s ", optname[rp->requested[i]]);
1565 	p = seprint(p, e, ")");
1566 
1567 	USED(p);
1568 	syslog(0, blog, "%s", buf);
1569 }
1570 
1571 void
1572 logdhcpout(Req *rp, char *type)
1573 {
1574 	syslog(0, blog, "%s(%I-%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s",
1575 		type, rp->up->laddr, rp->up->raddr, rp->id,
1576 		rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf);
1577 }
1578 
1579 /*
1580  *  if we get behind, it's useless to try answering since the sender
1581  *  will probably have retransmitted with a differnt sequence number.
1582  *  So dump all the last message in the queue.
1583  */
1584 void ding(void*, char *msg)
1585 {
1586 	if(strstr(msg, "alarm"))
1587 		noted(NCONT);
1588 	else
1589 		noted(NDFLT);
1590 }
1591 
1592 int
1593 readlast(int fd, uchar *buf, int len)
1594 {
1595 	int lastn, n;
1596 
1597 	notify(ding);
1598 
1599 	lastn = 0;
1600 	for(;;){
1601 		alarm(20);
1602 		n = read(fd, buf, len);
1603 		alarm(0);
1604 		if(n < 0){
1605 			if(lastn > 0)
1606 				return lastn;
1607 			break;
1608 		}
1609 		lastn = n;
1610 	}
1611 	return read(fd, buf, len);
1612 }
1613