Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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