Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/*
2
 * ipconfig - configure parameters of an ip stack
3
 */
4
#include <u.h>
5
#include <libc.h>
6
#include <ip.h>
7
#include <bio.h>
8
#include <ndb.h>
9
#include "../dhcp.h"
10
#include "ipconfig.h"
11
 
12
#define DEBUG if(debug)warning
13
 
14
/* possible verbs */
15
enum
16
{
17
	/* commands */
18
	Vadd,
19
	Vremove,
20
	Vunbind,
21
	Vaddpref6,
22
	Vra6,
23
	/* media */
24
	Vether,
25
	Vgbe,
26
	Vppp,
27
	Vloopback,
28
	Vtorus,
29
	Vtree,
30
	Vpkt,
31
};
32
 
33
enum
34
{
35
	Taddr,
36
	Taddrs,
37
	Tstr,
38
	Tbyte,
39
	Tulong,
40
	Tvec,
41
};
42
 
43
typedef struct Option Option;
44
struct Option
45
{
46
	char	*name;
47
	int	type;
48
};
49
 
50
/*
51
 * I was too lazy to look up the types for each of these
52
 * options.  If someone feels like it, please mail me a
53
 * corrected array -- presotto
54
 */
55
Option option[256] =
56
{
57
[OBmask]		{ "ipmask",		Taddr },
58
[OBtimeoff]		{ "timeoff",		Tulong },
59
[OBrouter]		{ "ipgw",		Taddrs },
60
[OBtimeserver]		{ "time",		Taddrs },
61
[OBnameserver]		{ "name",		Taddrs },
62
[OBdnserver]		{ "dns",		Taddrs },
63
[OBlogserver]		{ "log",		Taddrs },
64
[OBcookieserver]	{ "cookie",		Taddrs },
65
[OBlprserver]		{ "lpr",		Taddrs },
66
[OBimpressserver]	{ "impress",		Taddrs },
67
[OBrlserver]		{ "rl",			Taddrs },
68
[OBhostname]		{ "sys",		Tstr },
69
[OBbflen]		{ "bflen",		Tulong },
70
[OBdumpfile]		{ "dumpfile",		Tstr },
71
[OBdomainname]		{ "dom",		Tstr },
72
[OBswapserver]		{ "swap",		Taddrs },
73
[OBrootpath]		{ "rootpath",		Tstr },
74
[OBextpath]		{ "extpath",		Tstr },
75
[OBipforward]		{ "ipforward",		Taddrs },
76
[OBnonlocal]		{ "nonlocal",		Taddrs },
77
[OBpolicyfilter]	{ "policyfilter",	Taddrs },
78
[OBmaxdatagram]		{ "maxdatagram",	Tulong },
79
[OBttl]			{ "ttl",		Tulong },
80
[OBpathtimeout]		{ "pathtimeout",	Taddrs },
81
[OBpathplateau]		{ "pathplateau",	Taddrs },
82
[OBmtu]			{ "mtu",		Tulong },
83
[OBsubnetslocal]	{ "subnetslocal",	Taddrs },
84
[OBbaddr]		{ "baddr",		Taddrs },
85
[OBdiscovermask]	{ "discovermask",	Taddrs },
86
[OBsupplymask]		{ "supplymask",		Taddrs },
87
[OBdiscoverrouter]	{ "discoverrouter",	Taddrs },
88
[OBrsserver]		{ "rs",			Taddrs },
89
[OBstaticroutes]	{ "staticroutes",	Taddrs },
90
[OBtrailerencap]	{ "trailerencap",	Taddrs },
91
[OBarptimeout]		{ "arptimeout",		Tulong },
92
[OBetherencap]		{ "etherencap",		Taddrs },
93
[OBtcpttl]		{ "tcpttl",		Tulong },
94
[OBtcpka]		{ "tcpka",		Tulong },
95
[OBtcpkag]		{ "tcpkag",		Tulong },
96
[OBnisdomain]		{ "nisdomain",		Tstr },
97
[OBniserver]		{ "ni",			Taddrs },
98
[OBntpserver]		{ "ntp",		Taddrs },
99
[OBnetbiosns]		{ "netbiosns",		Taddrs },
100
[OBnetbiosdds]		{ "netbiosdds",		Taddrs },
101
[OBnetbiostype]		{ "netbiostype",	Taddrs },
102
[OBnetbiosscope]	{ "netbiosscope",	Taddrs },
103
[OBxfontserver]		{ "xfont",		Taddrs },
104
[OBxdispmanager]	{ "xdispmanager",	Taddrs },
105
[OBnisplusdomain]	{ "nisplusdomain",	Tstr },
106
[OBnisplusserver]	{ "nisplus",		Taddrs },
107
[OBhomeagent]		{ "homeagent",		Taddrs },
108
[OBsmtpserver]		{ "smtp",		Taddrs },
109
[OBpop3server]		{ "pop3",		Taddrs },
110
[OBnntpserver]		{ "nntp",		Taddrs },
111
[OBwwwserver]		{ "www",		Taddrs },
112
[OBfingerserver]	{ "finger",		Taddrs },
113
[OBircserver]		{ "irc",		Taddrs },
114
[OBstserver]		{ "st",			Taddrs },
115
[OBstdaserver]		{ "stdar",		Taddrs },
116
 
117
[ODipaddr]		{ "ipaddr",		Taddr },
118
[ODlease]		{ "lease",		Tulong },
119
[ODoverload]		{ "overload",		Taddr },
120
[ODtype]		{ "type",		Tbyte },
121
[ODserverid]		{ "serverid",		Taddr },
122
[ODparams]		{ "params",		Tvec },
123
[ODmessage]		{ "message",		Tstr },
124
[ODmaxmsg]		{ "maxmsg",		Tulong },
125
[ODrenewaltime]		{ "renewaltime",	Tulong },
126
[ODrebindingtime]	{ "rebindingtime",	Tulong },
127
[ODvendorclass]		{ "vendorclass",	Tvec },
128
[ODclientid]		{ "clientid",		Tvec },
129
[ODtftpserver]		{ "tftp",		Taddr },
130
[ODbootfile]		{ "bootfile",		Tstr },
131
};
132
 
133
uchar defrequested[] = {
134
	OBmask, OBrouter, OBdnserver, OBhostname, OBdomainname, OBntpserver,
135
};
136
 
137
uchar	requested[256];
138
int	nrequested;
139
 
140
int	Oflag;
141
int	beprimary = -1;
142
Conf	conf;
143
int	debug;
144
int	dodhcp;
145
int	dolog;
146
int	dondbconfig = 0;
147
int	dupl_disc = 1;		/* flag: V6 duplicate neighbor discovery */
148
Ctl	*firstctl, **ctll;
149
Ipifc	*ifc;
150
int	ipv6auto = 0;
151
int	myifc = -1;
152
char	*ndboptions;
153
int	nip;
154
int	noconfig;
155
int	nodhcpwatch;
156
char 	optmagic[4] = { 0x63, 0x82, 0x53, 0x63 };
157
int	plan9 = 1;
158
int	sendhostname;
159
 
160
static char logfile[] = "ipconfig";
161
 
162
char *verbs[] = {
163
[Vadd]		"add",
164
[Vremove]	"remove",
165
[Vunbind]	"unbind",
166
[Vether]	"ether",
167
[Vgbe]		"gbe",
168
[Vppp]		"ppp",
169
[Vloopback]	"loopback",
170
[Vaddpref6]	"add6",
171
[Vra6]		"ra6",
172
[Vtorus]	"torus",
173
[Vtree]		"tree",
174
[Vpkt]		"pkt",
175
};
176
 
177
void	adddefroute(char*, uchar*);
178
int	addoption(char*);
179
void	binddevice(void);
180
void	bootprequest(void);
181
void	controldevice(void);
182
void	dhcpquery(int, int);
183
void	dhcprecv(void);
184
void	dhcpsend(int);
185
int	dhcptimer(void);
186
void	dhcpwatch(int);
187
void	doadd(int);
188
void	doremove(void);
189
void	dounbind(void);
190
int	getndb(void);
191
void	getoptions(uchar*);
192
int	ip4cfg(void);
193
int	ip6cfg(int a);
194
void	lookforip(char*);
195
void	mkclientid(void);
196
void	ndbconfig(void);
197
int	nipifcs(char*);
198
int	openlisten(void);
199
uchar*	optaddaddr(uchar*, int, uchar*);
200
uchar*	optaddbyte(uchar*, int, int);
201
uchar*	optaddstr(uchar*, int, char*);
202
uchar*	optadd(uchar*, int, void*, int);
203
uchar*	optaddulong(uchar*, int, ulong);
204
uchar*	optaddvec(uchar*, int, uchar*, int);
205
int	optgetaddrs(uchar*, int, uchar*, int);
206
int	optgetp9addrs(uchar*, int, uchar*, int);
207
int	optgetaddr(uchar*, int, uchar*);
208
int	optgetbyte(uchar*, int);
209
int	optgetstr(uchar*, int, char*, int);
210
uchar*	optget(uchar*, int, int*);
211
ulong	optgetulong(uchar*, int);
212
int	optgetvec(uchar*, int, uchar*, int);
213
char*	optgetx(uchar*, uchar);
214
Bootp*	parsebootp(uchar*, int);
215
int	parseoptions(uchar *p, int n);
216
int	parseverb(char*);
217
void	pppbinddev(void);
218
void	putndb(void);
219
void	tweakservers(void);
220
void	usage(void);
221
int	validip(uchar*);
222
void	writendb(char*, int, int);
223
 
224
void
225
usage(void)
226
{
227
	fprint(2, "usage: %s [-6dDGnNOpPruX][-b baud][-c ctl]* [-g gw]"
228
		"[-h host][-m mtu]\n"
229
		"\t[-x mtpt][-o dhcpopt] type dev [verb] [laddr [mask "
230
		"[raddr [fs [auth]]]]]\n", argv0);
231
	exits("usage");
232
}
233
 
234
void
235
warning(char *fmt, ...)
236
{
237
	char buf[1024];
238
	va_list arg;
239
 
240
	va_start(arg, fmt);
241
	vseprint(buf, buf + sizeof buf, fmt, arg);
242
	va_end(arg);
243
	if (dolog)
244
		syslog(0, logfile, "%s", buf);
245
	else
246
		fprint(2, "%s: %s\n", argv0, buf);
247
}
248
 
249
static void
250
parsenorm(int argc, char **argv)
251
{
252
	switch(argc){
253
	case 5:
254
		 if (parseip(conf.auth, argv[4]) == -1)
255
			usage();
256
		/* fall through */
257
	case 4:
258
		 if (parseip(conf.fs, argv[3]) == -1)
259
			usage();
260
		/* fall through */
261
	case 3:
262
		 if (parseip(conf.raddr, argv[2]) == -1)
263
			usage();
264
		/* fall through */
265
	case 2:
266
		/*
267
		 * can't test for parseipmask()==-1 cuz 255.255.255.255
268
		 * looks like that.
269
		 */
270
		if (strcmp(argv[1], "0") != 0)
271
			parseipmask(conf.mask, argv[1]);
272
		/* fall through */
273
	case 1:
274
		 if (parseip(conf.laddr, argv[0]) == -1)
275
			usage();
276
		/* fall through */
277
	case 0:
278
		break;
279
	default:
280
		usage();
281
	}
282
}
283
 
284
static void
285
parse6pref(int argc, char **argv)
286
{
287
	switch(argc){
288
	case 6:
289
		conf.preflt = strtoul(argv[5], 0, 10);
290
		/* fall through */
291
	case 5:
292
		conf.validlt = strtoul(argv[4], 0, 10);
293
		/* fall through */
294
	case 4:
295
		conf.autoflag = (atoi(argv[3]) != 0);
296
		/* fall through */
297
	case 3:
298
		conf.onlink = (atoi(argv[2]) != 0);
299
		/* fall through */
300
	case 2:
301
		conf.prefixlen = atoi(argv[1]);
302
		/* fall through */
303
	case 1:
304
		if (parseip(conf.v6pref, argv[0]) == -1)
305
			sysfatal("bad address %s", argv[0]);
306
		break;
307
	}
308
	DEBUG("parse6pref: pref %I len %d", conf.v6pref, conf.prefixlen);
309
}
310
 
311
/* parse router advertisement (keyword, value) pairs */
312
static void
313
parse6ra(int argc, char **argv)
314
{
315
	int i, argsleft;
316
	char *kw, *val;
317
 
318
	if (argc % 2 != 0)
319
		usage();
320
 
321
	i = 0;
322
	for (argsleft = argc; argsleft > 1; argsleft -= 2) {
323
		kw =  argv[i];
324
		val = argv[i+1];
325
		if (strcmp(kw, "recvra") == 0)
326
			conf.recvra = (atoi(val) != 0);
327
		else if (strcmp(kw, "sendra") == 0)
328
			conf.sendra = (atoi(val) != 0);
329
		else if (strcmp(kw, "mflag") == 0)
330
			conf.mflag = (atoi(val) != 0);
331
		else if (strcmp(kw, "oflag") == 0)
332
			conf.oflag = (atoi(val) != 0);
333
		else if (strcmp(kw, "maxraint") == 0)
334
			conf.maxraint = atoi(val);
335
		else if (strcmp(kw, "minraint") == 0)
336
			conf.minraint = atoi(val);
337
		else if (strcmp(kw, "linkmtu") == 0)
338
			conf.linkmtu = atoi(val);
339
		else if (strcmp(kw, "reachtime") == 0)
340
			conf.reachtime = atoi(val);
341
		else if (strcmp(kw, "rxmitra") == 0)
342
			conf.rxmitra = atoi(val);
343
		else if (strcmp(kw, "ttl") == 0)
344
			conf.ttl = atoi(val);
345
		else if (strcmp(kw, "routerlt") == 0)
346
			conf.routerlt = atoi(val);
347
		else {
348
			warning("bad ra6 keyword %s", kw);
349
			usage();
350
		}
351
		i += 2;
352
	}
353
 
354
	/* consistency check */
355
	if (conf.maxraint < conf.minraint)
356
		sysfatal("maxraint %d < minraint %d",
357
			conf.maxraint, conf.minraint);
358
}
359
 
360
static void
361
init(void)
362
{
363
	srand(truerand());
364
	fmtinstall('E', eipfmt);
365
	fmtinstall('I', eipfmt);
366
	fmtinstall('M', eipfmt);
367
	fmtinstall('V', eipfmt);
368
 	nsec();			/* make sure time file is open before forking */
369
 
370
	setnetmtpt(conf.mpoint, sizeof conf.mpoint, nil);
371
	conf.cputype = getenv("cputype");
372
	if(conf.cputype == nil)
373
		conf.cputype = "386";
374
 
375
	ctll = &firstctl;
376
	v6paraminit(&conf);
377
 
378
	/* init set of requested dhcp parameters with the default */
379
	nrequested = sizeof defrequested;
380
	memcpy(requested, defrequested, nrequested);
381
}
382
 
383
static int
384
parseargs(int argc, char **argv)
385
{
386
	char *p;
387
	int action, verb;
388
 
389
	/* default to any host name we already have */
390
	if(*conf.hostname == 0){
391
		p = getenv("sysname");
392
		if(p == nil || *p == 0)
393
			p = sysname();
394
		if(p != nil)
395
			strncpy(conf.hostname, p, sizeof conf.hostname-1);
396
	}
397
 
398
	/* defaults */
399
	conf.type = "ether";
400
	conf.dev = "/net/ether0";
401
	action = Vadd;
402
 
403
	/* get optional medium and device */
404
	if (argc > 0){
405
		verb = parseverb(*argv);
406
		switch(verb){
407
		case Vether:
408
		case Vgbe:
409
		case Vppp:
410
		case Vloopback:
411
		case Vtorus:
412
		case Vtree:
413
		case Vpkt:
414
			conf.type = *argv++;
415
			argc--;
416
			if(argc > 0){
417
				conf.dev = *argv++;
418
				argc--;
419
			} else if(verb == Vppp)
420
				conf.dev = "/dev/eia0";
421
			break;
422
		}
423
	}
424
 
425
	/* get optional verb */
426
	if (argc > 0){
427
		verb = parseverb(*argv);
428
		switch(verb){
429
		case Vether:
430
		case Vgbe:
431
		case Vppp:
432
		case Vloopback:
433
		case Vtorus:
434
		case Vtree:
435
		case Vpkt:
436
			sysfatal("medium %s already specified", conf.type);
437
		case Vadd:
438
		case Vremove:
439
		case Vunbind:
440
		case Vaddpref6:
441
		case Vra6:
442
			argv++;
443
			argc--;
444
			action = verb;
445
			break;
446
		}
447
	}
448
 
449
	/* get verb-dependent arguments */
450
	switch (action) {
451
	case Vadd:
452
	case Vremove:
453
	case Vunbind:
454
		parsenorm(argc, argv);
455
		break;
456
	case Vaddpref6:
457
		parse6pref(argc, argv);
458
		break;
459
	case Vra6:
460
		parse6ra(argc, argv);
461
		break;
462
	}
463
	return action;
464
}
465
 
466
void
467
main(int argc, char **argv)
468
{
469
	int retry, action;
470
	Ctl *cp;
471
 
472
	init();
473
	retry = 0;
474
	ARGBEGIN {
475
	case '6': 			/* IPv6 auto config */
476
		ipv6auto = 1;
477
		break;
478
	case 'b':
479
		conf.baud = EARGF(usage());
480
		break;
481
	case 'c':
482
		cp = malloc(sizeof *cp);
483
		if(cp == nil)
484
			sysfatal("%r");
485
		*ctll = cp;
486
		ctll = &cp->next;
487
		cp->next = nil;
488
		cp->ctl = EARGF(usage());
489
		break;
490
	case 'd':
491
		dodhcp = 1;
492
		break;
493
	case 'D':
494
		debug = 1;
495
		break;
496
	case 'g':
497
		if (parseip(conf.gaddr, EARGF(usage())) == -1)
498
			usage();
499
		break;
500
	case 'G':
501
		plan9 = 0;
502
		break;
503
	case 'h':
504
		snprint(conf.hostname, sizeof conf.hostname, "%s",
505
			EARGF(usage()));
506
		sendhostname = 1;
507
		break;
508
	case 'm':
509
		conf.mtu = atoi(EARGF(usage()));
510
		break;
511
	case 'n':
512
		noconfig = 1;
513
		break;
514
	case 'N':
515
		dondbconfig = 1;
516
		break;
517
	case 'o':
518
		if(addoption(EARGF(usage())) < 0)
519
			usage();
520
		break;
521
	case 'O':
522
		Oflag = 1;
523
		break;
524
	case 'p':
525
		beprimary = 1;
526
		break;
527
	case 'P':
528
		beprimary = 0;
529
		break;
530
	case 'r':
531
		retry = 1;
532
		break;
533
	case 'u':		/* IPv6: duplicate neighbour disc. off */
534
		dupl_disc = 0;
535
		break;
536
	case 'x':
537
		setnetmtpt(conf.mpoint, sizeof conf.mpoint, EARGF(usage()));
538
		break;
539
	case 'X':
540
		nodhcpwatch = 1;
541
		break;
542
	default:
543
		usage();
544
	} ARGEND;
545
	argv0 = "ipconfig";		/* boot invokes us as tcp? */
546
 
547
	action = parseargs(argc, argv);
548
	switch(action){
549
	case Vadd:
550
		doadd(retry);
551
		break;
552
	case Vremove:
553
		doremove();
554
		break;
555
	case Vunbind:
556
		dounbind();
557
		break;
558
	case Vaddpref6:
559
	case Vra6:
560
		doipv6(action);
561
		break;
562
	}
563
	exits(0);
564
}
565
 
566
int
567
havendb(char *net)
568
{
569
	Dir *d;
570
	char buf[128];
571
 
572
	snprint(buf, sizeof buf, "%s/ndb", net);
573
	if((d = dirstat(buf)) == nil)
574
		return 0;
575
	if(d->length == 0){
576
		free(d);
577
		return 0;
578
	}
579
	free(d);
580
	return 1;
581
}
582
 
583
void
584
doadd(int retry)
585
{
586
	int tries, ppp;
587
 
588
	ppp = strcmp(conf.type, "ppp") == 0;
589
 
590
	/* get number of preexisting interfaces */
591
	nip = nipifcs(conf.mpoint);
592
	if(beprimary == -1 && (nip == 0 || !havendb(conf.mpoint)))
593
		beprimary = 1;
594
 
595
	/* get ipifc into name space and condition device for ip */
596
	if(!noconfig){
597
		lookforip(conf.mpoint);
598
		controldevice();
599
		binddevice();
600
	}
601
 
602
	if (ipv6auto && !ppp) {
603
		if (ip6cfg(ipv6auto) < 0)
604
			sysfatal("can't automatically start IPv6 on %s",
605
				conf.dev);
606
//		return;
607
	} else if (validip(conf.laddr) && !isv4(conf.laddr)) {
608
		if (ip6cfg(0) < 0)
609
			sysfatal("can't start IPv6 on %s, address %I",
610
				conf.dev, conf.laddr);
611
//		return;
612
	}
613
 
614
	if(!validip(conf.laddr) && !ppp)
615
		if(dondbconfig)
616
			ndbconfig();
617
		else
618
			dodhcp = 1;
619
 
620
	/* run dhcp if we need something */
621
	if(dodhcp){
622
		mkclientid();
623
		for(tries = 0; tries < 30; tries++){
624
			dhcpquery(!noconfig, Sselecting);
625
			if(conf.state == Sbound)
626
				break;
627
			sleep(1000);
628
		}
629
	}
630
 
631
	if(!validip(conf.laddr))
632
		if(retry && dodhcp && !noconfig){
633
			warning("couldn't determine ip address, retrying");
634
			dhcpwatch(1);
635
			return;
636
		} else
637
			sysfatal("no success with DHCP");
638
 
639
	if(!noconfig)
640
		if(ip4cfg() < 0)
641
			sysfatal("can't start ip");
642
		else if(dodhcp && conf.lease != Lforever)
643
			dhcpwatch(0);
644
 
645
	/* leave everything we've learned somewhere other procs can find it */
646
	if(beprimary == 1){
647
		putndb();
648
		tweakservers();
649
	}
650
}
651
 
652
void
653
doremove(void)
654
{
655
	char file[128];
656
	int cfd;
657
	Ipifc *nifc;
658
	Iplifc *lifc;
659
 
660
	if(!validip(conf.laddr))
661
		sysfatal("remove requires an address");
662
	ifc = readipifc(conf.mpoint, ifc, -1);
663
	for(nifc = ifc; nifc != nil; nifc = nifc->next){
664
		if(strcmp(nifc->dev, conf.dev) != 0)
665
			continue;
666
		for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next){
667
			if(ipcmp(conf.laddr, lifc->ip) != 0)
668
				continue;
669
			if (validip(conf.mask) &&
670
			    ipcmp(conf.mask, lifc->mask) != 0)
671
				continue;
672
			if (validip(conf.raddr) &&
673
			    ipcmp(conf.raddr, lifc->net) != 0)
674
				continue;
675
 
676
			snprint(file, sizeof file, "%s/ipifc/%d/ctl",
677
				conf.mpoint, nifc->index);
678
			cfd = open(file, ORDWR);
679
			if(cfd < 0){
680
				warning("can't open %s: %r", conf.mpoint);
681
				continue;
682
			}
683
			if(fprint(cfd, "remove %I %M", lifc->ip, lifc->mask) < 0)
684
				warning("can't remove %I %M from %s: %r",
685
					lifc->ip, lifc->mask, file);
686
		}
687
	}
688
}
689
 
690
void
691
dounbind(void)
692
{
693
	Ipifc *nifc;
694
	char file[128];
695
	int cfd;
696
 
697
	ifc = readipifc(conf.mpoint, ifc, -1);
698
	for(nifc = ifc; nifc != nil; nifc = nifc->next){
699
		if(strcmp(nifc->dev, conf.dev) == 0){
700
			snprint(file, sizeof file, "%s/ipifc/%d/ctl",
701
				conf.mpoint, nifc->index);
702
			cfd = open(file, ORDWR);
703
			if(cfd < 0){
704
				warning("can't open %s: %r", conf.mpoint);
705
				break;
706
			}
707
			if(fprint(cfd, "unbind") < 0)
708
				warning("can't unbind from %s: %r", file);
709
			break;
710
		}
711
	}
712
}
713
 
714
/* set the default route */
715
void
716
adddefroute(char *mpoint, uchar *gaddr)
717
{
718
	char buf[256];
719
	int cfd;
720
 
721
	sprint(buf, "%s/iproute", mpoint);
722
	cfd = open(buf, ORDWR);
723
	if(cfd < 0)
724
		return;
725
 
726
	if(isv4(gaddr))
727
		fprint(cfd, "add 0 0 %I", gaddr);
728
	else
729
		fprint(cfd, "add :: /0 %I", gaddr);
730
	close(cfd);
731
}
732
 
733
/* create a client id */
734
void
735
mkclientid(void)
736
{
737
	if(strcmp(conf.type, "ether") == 0 || strcmp(conf.type, "gbe") == 0)
738
		if(myetheraddr(conf.hwa, conf.dev) == 0){
739
			conf.hwalen = 6;
740
			conf.hwatype = 1;
741
			conf.cid[0] = conf.hwatype;
742
			memmove(&conf.cid[1], conf.hwa, conf.hwalen);
743
			conf.cidlen = conf.hwalen+1;
744
		} else {
745
			conf.hwatype = -1;
746
			snprint((char*)conf.cid, sizeof conf.cid,
747
				"plan9_%ld.%d", lrand(), getpid());
748
			conf.cidlen = strlen((char*)conf.cid);
749
		}
750
}
751
 
752
/* bind ip into the namespace */
753
void
754
lookforip(char *net)
755
{
756
	char proto[64];
757
 
758
	snprint(proto, sizeof proto, "%s/ipifc", net);
759
	if(access(proto, 0) == 0)
760
		return;
761
	sysfatal("no ip stack bound onto %s", net);
762
}
763
 
764
/* send some ctls to a device */
765
void
766
controldevice(void)
767
{
768
	char ctlfile[256];
769
	int fd;
770
	Ctl *cp;
771
 
772
	if (firstctl == nil ||
773
	    strcmp(conf.type, "ether") != 0 && strcmp(conf.type, "gbe") != 0)
774
		return;
775
 
776
	snprint(ctlfile, sizeof ctlfile, "%s/clone", conf.dev);
777
	fd = open(ctlfile, ORDWR);
778
	if(fd < 0)
779
		sysfatal("can't open %s", ctlfile);
780
 
781
	for(cp = firstctl; cp != nil; cp = cp->next){
782
		if(write(fd, cp->ctl, strlen(cp->ctl)) < 0)
783
			sysfatal("ctl message %s: %r", cp->ctl);
784
		seek(fd, 0, 0);
785
	}
786
//	close(fd);		/* or does it need to be left hanging? */
787
}
788
 
789
/* bind an ip stack to a device, leave the control channel open */
790
void
791
binddevice(void)
792
{
793
	char buf[256];
794
 
795
	if(strcmp(conf.type, "ppp") == 0)
796
		pppbinddev();
797
	else if(myifc < 0){
798
		/* get a new ip interface */
799
		snprint(buf, sizeof buf, "%s/ipifc/clone", conf.mpoint);
800
		conf.cfd = open(buf, ORDWR);
801
		if(conf.cfd < 0)
802
			sysfatal("opening %s/ipifc/clone: %r", conf.mpoint);
803
 
804
		/* specify medium as ethernet, bind the interface to it */
805
		if(fprint(conf.cfd, "bind %s %s", conf.type, conf.dev) < 0)
806
			sysfatal("%s: bind %s %s: %r", buf, conf.type, conf.dev);
807
	} else {
808
		/* open the old interface */
809
		snprint(buf, sizeof buf, "%s/ipifc/%d/ctl", conf.mpoint, myifc);
810
		conf.cfd = open(buf, ORDWR);
811
		if(conf.cfd < 0)
812
			sysfatal("open %s: %r", buf);
813
	}
814
 
815
}
816
 
817
/* add a logical interface to the ip stack */
818
int
819
ip4cfg(void)
820
{
821
	char buf[256];
822
	int n;
823
 
824
	if(!validip(conf.laddr))
825
		return -1;
826
 
827
	n = sprint(buf, "add");
828
	n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
829
 
830
	if(!validip(conf.mask))
831
		ipmove(conf.mask, defmask(conf.laddr));
832
	n += snprint(buf+n, sizeof buf-n, " %I", conf.mask);
833
 
834
	if(validip(conf.raddr)){
835
		n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
836
		if(conf.mtu != 0)
837
			n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
838
	}
839
 
840
	if(write(conf.cfd, buf, n) < 0){
841
		warning("write(%s): %r", buf);
842
		return -1;
843
	}
844
 
845
	if(beprimary==1 && validip(conf.gaddr))
846
		adddefroute(conf.mpoint, conf.gaddr);
847
 
848
	return 0;
849
}
850
 
851
/* remove a logical interface to the ip stack */
852
void
853
ipunconfig(void)
854
{
855
	char buf[256];
856
	int n;
857
 
858
	if(!validip(conf.laddr))
859
		return;
860
	DEBUG("couldn't renew IP lease, releasing %I", conf.laddr);
861
	n = sprint(buf, "remove");
862
	n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
863
 
864
	if(!validip(conf.mask))
865
		ipmove(conf.mask, defmask(conf.laddr));
866
	n += snprint(buf+n, sizeof buf-n, " %I", conf.mask);
867
 
868
	write(conf.cfd, buf, n);
869
 
870
	ipmove(conf.laddr, IPnoaddr);
871
	ipmove(conf.raddr, IPnoaddr);
872
	ipmove(conf.mask, IPnoaddr);
873
 
874
	/* forget configuration info */
875
	if(beprimary==1)
876
		writendb("", 0, 0);
877
}
878
 
879
void
880
ding(void*, char *msg)
881
{
882
	if(strstr(msg, "alarm"))
883
		noted(NCONT);
884
	noted(NDFLT);
885
}
886
 
887
void
888
dhcpquery(int needconfig, int startstate)
889
{
890
	if(needconfig)
891
		fprint(conf.cfd, "add %I %I", IPnoaddr, IPnoaddr);
892
 
893
	conf.fd = openlisten();
894
	if(conf.fd < 0){
895
		conf.state = Sinit;
896
		return;
897
	}
898
	notify(ding);
899
 
900
	/* try dhcp for 10 seconds */
901
	conf.xid = lrand();
902
	conf.starttime = time(0);
903
	conf.state = startstate;
904
	switch(startstate){
905
	case Sselecting:
906
		conf.offered = 0;
907
		dhcpsend(Discover);
908
		break;
909
	case Srenewing:
910
		dhcpsend(Request);
911
		break;
912
	default:
913
		sysfatal("internal error 0");
914
	}
915
	conf.resend = 0;
916
	conf.timeout = time(0) + 4;
917
 
918
	while(conf.state != Sbound){
919
		dhcprecv();
920
		if(dhcptimer() < 0)
921
			break;
922
		if(time(0) - conf.starttime > 10)
923
			break;
924
	}
925
	close(conf.fd);
926
 
927
	if(needconfig)
928
		fprint(conf.cfd, "remove %I %I", IPnoaddr, IPnoaddr);
929
 
930
}
931
 
932
enum {
933
	/*
934
	 * was an hour, needs to be less for the ARM/GS1 until the timer
935
	 * code has been cleaned up (pb).
936
	 */
937
	Maxsleep = 450,
938
};
939
 
940
void
941
dhcpwatch(int needconfig)
942
{
943
	int secs, s;
944
	ulong t;
945
 
946
	if(nodhcpwatch)
947
		return;
948
 
949
	switch(rfork(RFPROC|RFFDG|RFNOWAIT|RFNOTEG)){
950
	default:
951
		return;
952
	case 0:
953
		break;
954
	}
955
 
956
	dolog = 1;			/* log, don't print */
957
	procsetname("dhcpwatch");
958
	/* keep trying to renew the lease */
959
	for(;;){
960
		if(conf.lease == 0)
961
			secs = 5;
962
		else
963
			secs = conf.lease >> 1;
964
 
965
		/* avoid overflows */
966
		for(s = secs; s > 0; s -= t){
967
			if(s > Maxsleep)
968
				t = Maxsleep;
969
			else
970
				t = s;
971
			sleep(t*1000);
972
		}
973
 
974
		if(conf.lease > 0){
975
			/*
976
			 * during boot, the starttime can be bogus so avoid
977
			 * spurious ipunconfig's
978
			 */
979
			t = time(0) - conf.starttime;
980
			if(t > (3*secs)/2)
981
				t = secs;
982
			if(t >= conf.lease){
983
				conf.lease = 0;
984
				if(!noconfig){
985
					ipunconfig();
986
					needconfig = 1;
987
				}
988
			} else
989
				conf.lease -= t;
990
		}
991
		dhcpquery(needconfig, needconfig? Sselecting: Srenewing);
992
 
993
		if(needconfig && conf.state == Sbound){
994
			if(ip4cfg() < 0)
995
				sysfatal("can't start ip: %r");
996
			needconfig = 0;
997
			/*
998
			 * leave everything we've learned somewhere that
999
			 * other procs can find it.
1000
			 */
1001
			if(beprimary==1){
1002
				putndb();
1003
				tweakservers();
1004
			}
1005
		}
1006
	}
1007
}
1008
 
1009
int
1010
dhcptimer(void)
1011
{
1012
	ulong now;
1013
 
1014
	now = time(0);
1015
	if(now < conf.timeout)
1016
		return 0;
1017
 
1018
	switch(conf.state) {
1019
	default:
1020
		sysfatal("dhcptimer: unknown state %d", conf.state);
1021
	case Sinit:
1022
	case Sbound:
1023
		break;
1024
	case Sselecting:
1025
	case Srequesting:
1026
	case Srebinding:
1027
		dhcpsend(conf.state == Sselecting? Discover: Request);
1028
		conf.timeout = now + 4;
1029
		if(++conf.resend > 5) {
1030
			conf.state = Sinit;
1031
			return -1;
1032
		}
1033
		break;
1034
	case Srenewing:
1035
		dhcpsend(Request);
1036
		conf.timeout = now + 1;
1037
		if(++conf.resend > 3) {
1038
			conf.state = Srebinding;
1039
			conf.resend = 0;
1040
		}
1041
		break;
1042
	}
1043
	return 0;
1044
}
1045
 
1046
void
1047
dhcpsend(int type)
1048
{
1049
	Bootp bp;
1050
	uchar *p;
1051
	int n;
1052
	uchar vendor[64];
1053
	Udphdr *up = (Udphdr*)bp.udphdr;
1054
 
1055
	memset(&bp, 0, sizeof bp);
1056
 
1057
	hnputs(up->rport, 67);
1058
	bp.op = Bootrequest;
1059
	hnputl(bp.xid, conf.xid);
1060
	hnputs(bp.secs, time(0)-conf.starttime);
1061
	hnputs(bp.flags, 0);
1062
	memmove(bp.optmagic, optmagic, 4);
1063
	if(conf.hwatype >= 0 && conf.hwalen < sizeof bp.chaddr){
1064
		memmove(bp.chaddr, conf.hwa, conf.hwalen);
1065
		bp.hlen = conf.hwalen;
1066
		bp.htype = conf.hwatype;
1067
	}
1068
	p = bp.optdata;
1069
	p = optaddbyte(p, ODtype, type);
1070
	p = optadd(p, ODclientid, conf.cid, conf.cidlen);
1071
	switch(type) {
1072
	default:
1073
		sysfatal("dhcpsend: unknown message type: %d", type);
1074
	case Discover:
1075
		ipmove(up->raddr, IPv4bcast);	/* broadcast */
1076
		if(*conf.hostname && sendhostname)
1077
			p = optaddstr(p, OBhostname, conf.hostname);
1078
		if(plan9){
1079
			n = snprint((char*)vendor, sizeof vendor,
1080
				"plan9_%s", conf.cputype);
1081
			p = optaddvec(p, ODvendorclass, vendor, n);
1082
		}
1083
		p = optaddvec(p, ODparams, requested, nrequested);
1084
		if(validip(conf.laddr))
1085
			p = optaddaddr(p, ODipaddr, conf.laddr);
1086
		break;
1087
	case Request:
1088
		switch(conf.state){
1089
		case Srenewing:
1090
			ipmove(up->raddr, conf.server);
1091
			v6tov4(bp.ciaddr, conf.laddr);
1092
			break;
1093
		case Srebinding:
1094
			ipmove(up->raddr, IPv4bcast);	/* broadcast */
1095
			v6tov4(bp.ciaddr, conf.laddr);
1096
			break;
1097
		case Srequesting:
1098
			ipmove(up->raddr, IPv4bcast);	/* broadcast */
1099
			p = optaddaddr(p, ODipaddr, conf.laddr);
1100
			p = optaddaddr(p, ODserverid, conf.server);
1101
			break;
1102
		}
1103
		p = optaddulong(p, ODlease, conf.offered);
1104
		if(plan9){
1105
			n = snprint((char*)vendor, sizeof vendor,
1106
				"plan9_%s", conf.cputype);
1107
			p = optaddvec(p, ODvendorclass, vendor, n);
1108
		}
1109
		p = optaddvec(p, ODparams, requested, nrequested);
1110
		if(*conf.hostname && sendhostname)
1111
			p = optaddstr(p, OBhostname, conf.hostname);
1112
		break;
1113
	case Release:
1114
		ipmove(up->raddr, conf.server);
1115
		v6tov4(bp.ciaddr, conf.laddr);
1116
		p = optaddaddr(p, ODipaddr, conf.laddr);
1117
		p = optaddaddr(p, ODserverid, conf.server);
1118
		break;
1119
	}
1120
 
1121
	*p++ = OBend;
1122
 
1123
	n = p - (uchar*)&bp;
1124
	USED(n);
1125
 
1126
	/*
1127
	 *  We use a maximum size DHCP packet to survive the
1128
	 *  All_Aboard NAT package from Internet Share.  It
1129
	 *  always replies to DHCP requests with a packet of the
1130
	 *  same size, so if the request is too short the reply
1131
	 *  is truncated.
1132
	 */
1133
	if(write(conf.fd, &bp, sizeof bp) != sizeof bp)
1134
		warning("dhcpsend: write failed: %r");
1135
}
1136
 
1137
void
1138
dhcprecv(void)
1139
{
1140
	int i, n, type;
1141
	ulong lease;
1142
	char err[ERRMAX];
1143
	uchar buf[8000], vopts[256], taddr[IPaddrlen];
1144
	Bootp *bp;
1145
 
1146
	memset(buf, 0, sizeof buf);
1147
	alarm(1000);
1148
	n = read(conf.fd, buf, sizeof buf);
1149
	alarm(0);
1150
 
1151
	if(n < 0){
1152
		rerrstr(err, sizeof err);
1153
		if(strstr(err, "interrupt") == nil)
1154
			warning("dhcprecv: bad read: %s", err);
1155
		else
1156
			DEBUG("dhcprecv: read timed out");
1157
		return;
1158
	}
1159
	if(n == 0){
1160
		warning("dhcprecv: zero-length packet read");
1161
		return;
1162
	}
1163
 
1164
	bp = parsebootp(buf, n);
1165
	if(bp == 0) {
1166
		DEBUG("parsebootp failed: dropping packet");
1167
		return;
1168
	}
1169
 
1170
	type = optgetbyte(bp->optdata, ODtype);
1171
	switch(type) {
1172
	default:
1173
		warning("dhcprecv: unknown type: %d", type);
1174
		break;
1175
	case Offer:
1176
		DEBUG("got offer from %V ", bp->siaddr);
1177
		if(conf.state != Sselecting){
1178
//			DEBUG("");
1179
			break;
1180
		}
1181
		lease = optgetulong(bp->optdata, ODlease);
1182
		if(lease == 0){
1183
			/*
1184
			 * The All_Aboard NAT package from Internet Share
1185
			 * doesn't give a lease time, so we have to assume one.
1186
			 */
1187
			warning("Offer with %lud lease, using %d", lease, MinLease);
1188
			lease = MinLease;
1189
		}
1190
		DEBUG("lease=%lud ", lease);
1191
		if(!optgetaddr(bp->optdata, ODserverid, conf.server)) {
1192
			warning("Offer from server with invalid serverid");
1193
			break;
1194
		}
1195
 
1196
		v4tov6(conf.laddr, bp->yiaddr);
1197
		memmove(conf.sname, bp->sname, sizeof conf.sname);
1198
		conf.sname[sizeof conf.sname-1] = 0;
1199
		DEBUG("server=%I sname=%s", conf.server, conf.sname);
1200
		conf.offered = lease;
1201
		conf.state = Srequesting;
1202
		dhcpsend(Request);
1203
		conf.resend = 0;
1204
		conf.timeout = time(0) + 4;
1205
		break;
1206
	case Ack:
1207
		DEBUG("got ack from %V ", bp->siaddr);
1208
		if (conf.state != Srequesting && conf.state != Srenewing &&
1209
		    conf.state != Srebinding)
1210
			break;
1211
 
1212
		/* ignore a bad lease */
1213
		lease = optgetulong(bp->optdata, ODlease);
1214
		if(lease == 0){
1215
			/*
1216
			 * The All_Aboard NAT package from Internet Share
1217
			 * doesn't give a lease time, so we have to assume one.
1218
			 */
1219
			warning("Ack with %lud lease, using %d", lease, MinLease);
1220
			lease = MinLease;
1221
		}
1222
		DEBUG("lease=%lud ", lease);
1223
 
1224
		/* address and mask */
1225
		if(!validip(conf.laddr) || !Oflag)
1226
			v4tov6(conf.laddr, bp->yiaddr);
1227
		if(!validip(conf.mask) || !Oflag){
1228
			if(!optgetaddr(bp->optdata, OBmask, conf.mask))
1229
				ipmove(conf.mask, IPnoaddr);
1230
		}
1231
		DEBUG("ipaddr=%I ipmask=%M ", conf.laddr, conf.mask);
1232
 
1233
		/*
1234
		 * get a router address either from the router option
1235
		 * or from the router that forwarded the dhcp packet
1236
		 */
1237
		if(validip(conf.gaddr) && Oflag) {
1238
			DEBUG("ipgw=%I ", conf.gaddr);
1239
		} else if(optgetaddr(bp->optdata, OBrouter, conf.gaddr)){
1240
			DEBUG("ipgw=%I ", conf.gaddr);
1241
		} else if(memcmp(bp->giaddr, IPnoaddr+IPv4off, IPv4addrlen)!=0){
1242
			v4tov6(conf.gaddr, bp->giaddr);
1243
			DEBUG("giaddr=%I ", conf.gaddr);
1244
		}
1245
 
1246
		/* get dns servers */
1247
		memset(conf.dns, 0, sizeof conf.dns);
1248
		n = optgetaddrs(bp->optdata, OBdnserver, conf.dns,
1249
			sizeof conf.dns/IPaddrlen);
1250
		for(i = 0; i < n; i++)
1251
			DEBUG("dns=%I ", conf.dns + i*IPaddrlen);
1252
 
1253
		/* get ntp servers */
1254
		memset(conf.ntp, 0, sizeof conf.ntp);
1255
		n = optgetaddrs(bp->optdata, OBntpserver, conf.ntp,
1256
			sizeof conf.ntp/IPaddrlen);
1257
		for(i = 0; i < n; i++)
1258
			DEBUG("ntp=%I ", conf.ntp + i*IPaddrlen);
1259
 
1260
		/* get names */
1261
		optgetstr(bp->optdata, OBhostname,
1262
			conf.hostname, sizeof conf.hostname);
1263
		optgetstr(bp->optdata, OBdomainname,
1264
			conf.domainname, sizeof conf.domainname);
1265
 
1266
		/* get anything else we asked for */
1267
		getoptions(bp->optdata);
1268
 
1269
		/* get plan9-specific options */
1270
		n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof vopts-1);
1271
		if(n > 0 && parseoptions(vopts, n) == 0){
1272
			if(validip(conf.fs) && Oflag)
1273
				n = 1;
1274
			else {
1275
				n = optgetp9addrs(vopts, OP9fs, conf.fs, 2);
1276
				if (n == 0)
1277
					n = optgetaddrs(vopts, OP9fsv4,
1278
						conf.fs, 2);
1279
			}
1280
			for(i = 0; i < n; i++)
1281
				DEBUG("fs=%I ", conf.fs + i*IPaddrlen);
1282
 
1283
			if(validip(conf.auth) && Oflag)
1284
				n = 1;
1285
			else {
1286
				n = optgetp9addrs(vopts, OP9auth, conf.auth, 2);
1287
				if (n == 0)
1288
					n = optgetaddrs(vopts, OP9authv4,
1289
						conf.auth, 2);
1290
			}
1291
			for(i = 0; i < n; i++)
1292
				DEBUG("auth=%I ", conf.auth + i*IPaddrlen);
1293
 
1294
			n = optgetp9addrs(vopts, OP9ipaddr, taddr, 1);
1295
			if (n > 0)
1296
				memmove(conf.laddr, taddr, IPaddrlen);
1297
			n = optgetp9addrs(vopts, OP9ipmask, taddr, 1);
1298
			if (n > 0)
1299
				memmove(conf.mask, taddr, IPaddrlen);
1300
			n = optgetp9addrs(vopts, OP9ipgw, taddr, 1);
1301
			if (n > 0)
1302
				memmove(conf.gaddr, taddr, IPaddrlen);
1303
			DEBUG("new ipaddr=%I new ipmask=%M new ipgw=%I",
1304
				conf.laddr, conf.mask, conf.gaddr);
1305
		}
1306
		conf.lease = lease;
1307
		conf.state = Sbound;
1308
		DEBUG("server=%I sname=%s", conf.server, conf.sname);
1309
		break;
1310
	case Nak:
1311
		conf.state = Sinit;
1312
		warning("recved dhcpnak on %s", conf.mpoint);
1313
		break;
1314
	}
1315
}
1316
 
1317
/* return pseudo-random integer in range low...(hi-1) */
1318
ulong
1319
randint(ulong low, ulong hi)
1320
{
1321
	if (hi < low)
1322
		return low;
1323
	return low + nrand(hi - low);
1324
}
1325
 
1326
long
1327
jitter(void)		/* compute small pseudo-random delay in ms */
1328
{
1329
	return randint(0, 10*1000);
1330
}
1331
 
1332
int
1333
openlisten(void)
1334
{
1335
	int n, fd, cfd;
1336
	char data[128], devdir[40];
1337
 
1338
	if (validip(conf.laddr) &&
1339
	    (conf.state == Srenewing || conf.state == Srebinding))
1340
		sprint(data, "%s/udp!%I!68", conf.mpoint, conf.laddr);
1341
	else
1342
		sprint(data, "%s/udp!*!68", conf.mpoint);
1343
	for (n = 0; (cfd = announce(data, devdir)) < 0; n++) {
1344
		if(!noconfig)
1345
			sysfatal("can't announce for dhcp: %r");
1346
 
1347
		/* might be another client - wait and try again */
1348
		warning("can't announce %s: %r", data);
1349
		sleep(jitter());
1350
		if(n > 10)
1351
			return -1;
1352
	}
1353
 
1354
	if(fprint(cfd, "headers") < 0)
1355
		sysfatal("can't set header mode: %r");
1356
 
1357
	sprint(data, "%s/data", devdir);
1358
	fd = open(data, ORDWR);
1359
	if(fd < 0)
1360
		sysfatal("open %s: %r", data);
1361
	close(cfd);
1362
	return fd;
1363
}
1364
 
1365
uchar*
1366
optadd(uchar *p, int op, void *d, int n)
1367
{
1368
	p[0] = op;
1369
	p[1] = n;
1370
	memmove(p+2, d, n);
1371
	return p+n+2;
1372
}
1373
 
1374
uchar*
1375
optaddbyte(uchar *p, int op, int b)
1376
{
1377
	p[0] = op;
1378
	p[1] = 1;
1379
	p[2] = b;
1380
	return p+3;
1381
}
1382
 
1383
uchar*
1384
optaddulong(uchar *p, int op, ulong x)
1385
{
1386
	p[0] = op;
1387
	p[1] = 4;
1388
	hnputl(p+2, x);
1389
	return p+6;
1390
}
1391
 
1392
uchar *
1393
optaddaddr(uchar *p, int op, uchar *ip)
1394
{
1395
	p[0] = op;
1396
	p[1] = 4;
1397
	v6tov4(p+2, ip);
1398
	return p+6;
1399
}
1400
 
1401
/* add dhcp option op with value v of length n to dhcp option array p */
1402
uchar *
1403
optaddvec(uchar *p, int op, uchar *v, int n)
1404
{
1405
	p[0] = op;
1406
	p[1] = n;
1407
	memmove(p+2, v, n);
1408
	return p+2+n;
1409
}
1410
 
1411
uchar *
1412
optaddstr(uchar *p, int op, char *v)
1413
{
1414
	int n;
1415
 
1416
	n = strlen(v)+1;	/* microsoft leaves on the NUL, so we do too */
1417
	p[0] = op;
1418
	p[1] = n;
1419
	memmove(p+2, v, n);
1420
	return p+2+n;
1421
}
1422
 
1423
/*
1424
 * parse p, looking for option `op'.  if non-nil, np points to minimum length.
1425
 * return nil if option is too small, else ptr to opt, and
1426
 * store actual length via np if non-nil.
1427
 */
1428
uchar*
1429
optget(uchar *p, int op, int *np)
1430
{
1431
	int len, code;
1432
 
1433
	while ((code = *p++) != OBend) {
1434
		if(code == OBpad)
1435
			continue;
1436
		len = *p++;
1437
		if(code != op) {
1438
			p += len;
1439
			continue;
1440
		}
1441
		if(np != nil){
1442
			if(*np > len) {
1443
				return 0;
1444
			}
1445
			*np = len;
1446
		}
1447
		return p;
1448
	}
1449
	return 0;
1450
}
1451
 
1452
int
1453
optgetbyte(uchar *p, int op)
1454
{
1455
	int len;
1456
 
1457
	len = 1;
1458
	p = optget(p, op, &len);
1459
	if(p == nil)
1460
		return 0;
1461
	return *p;
1462
}
1463
 
1464
ulong
1465
optgetulong(uchar *p, int op)
1466
{
1467
	int len;
1468
 
1469
	len = 4;
1470
	p = optget(p, op, &len);
1471
	if(p == nil)
1472
		return 0;
1473
	return nhgetl(p);
1474
}
1475
 
1476
int
1477
optgetaddr(uchar *p, int op, uchar *ip)
1478
{
1479
	int len;
1480
 
1481
	len = 4;
1482
	p = optget(p, op, &len);
1483
	if(p == nil)
1484
		return 0;
1485
	v4tov6(ip, p);
1486
	return 1;
1487
}
1488
 
1489
/* expect at most n addresses; ip[] only has room for that many */
1490
int
1491
optgetaddrs(uchar *p, int op, uchar *ip, int n)
1492
{
1493
	int len, i;
1494
 
1495
	len = 4;
1496
	p = optget(p, op, &len);
1497
	if(p == nil)
1498
		return 0;
1499
	len /= IPv4addrlen;
1500
	if(len > n)
1501
		len = n;
1502
	for(i = 0; i < len; i++)
1503
		v4tov6(&ip[i*IPaddrlen], &p[i*IPv4addrlen]);
1504
	return i;
1505
}
1506
 
1507
/* expect at most n addresses; ip[] only has room for that many */
1508
int
1509
optgetp9addrs(uchar *ap, int op, uchar *ip, int n)
1510
{
1511
	int len, i, slen, addrs;
1512
	char *p;
1513
 
1514
	len = 1;			/* minimum bytes needed */
1515
	p = (char *)optget(ap, op, &len);
1516
	if(p == nil)
1517
		return 0;
1518
	addrs = *p++;			/* first byte is address count */
1519
	for (i = 0; i < n  && i < addrs && len > 0; i++) {
1520
		slen = strlen(p) + 1;
1521
		if (parseip(&ip[i*IPaddrlen], p) == -1)
1522
			fprint(2, "%s: bad address %s\n", argv0, p);
1523
		DEBUG("got plan 9 option %d addr %I (%s)",
1524
			op, &ip[i*IPaddrlen], p);
1525
		p += slen;
1526
		len -= slen;
1527
	}
1528
	return addrs;
1529
}
1530
 
1531
int
1532
optgetvec(uchar *p, int op, uchar *v, int n)
1533
{
1534
	int len;
1535
 
1536
	len = 1;
1537
	p = optget(p, op, &len);
1538
	if(p == nil)
1539
		return 0;
1540
	if(len > n)
1541
		len = n;
1542
	memmove(v, p, len);
1543
	return len;
1544
}
1545
 
1546
int
1547
optgetstr(uchar *p, int op, char *s, int n)
1548
{
1549
	int len;
1550
 
1551
	len = 1;
1552
	p = optget(p, op, &len);
1553
	if(p == nil)
1554
		return 0;
1555
	if(len >= n)
1556
		len = n-1;
1557
	memmove(s, p, len);
1558
	s[len] = 0;
1559
	return len;
1560
}
1561
 
1562
/*
1563
 * sanity check options area
1564
 * 	- options don't overflow packet
1565
 * 	- options end with an OBend
1566
 */
1567
int
1568
parseoptions(uchar *p, int n)
1569
{
1570
	int code, len, nin = n;
1571
 
1572
	while (n > 0) {
1573
		code = *p++;
1574
		n--;
1575
		if(code == OBend)
1576
			return 0;
1577
		if(code == OBpad)
1578
			continue;
1579
		if(n == 0) {
1580
			warning("parseoptions: bad option: 0x%ux: truncated: "
1581
				"opt length = %d", code, nin);
1582
			return -1;
1583
		}
1584
 
1585
		len = *p++;
1586
		n--;
1587
		DEBUG("parseoptions: %s(%d) len %d, bytes left %d",
1588
			option[code].name, code, len, n);
1589
		if(len > n) {
1590
			warning("parseoptions: bad option: 0x%ux: %d > %d: "
1591
				"opt length = %d", code, len, n, nin);
1592
			return -1;
1593
		}
1594
		p += len;
1595
		n -= len;
1596
	}
1597
 
1598
	/* make sure packet ends with an OBend after all the optget code */
1599
	*p = OBend;
1600
	return 0;
1601
}
1602
 
1603
/*
1604
 * sanity check received packet:
1605
 * 	- magic is dhcp magic
1606
 * 	- options don't overflow packet
1607
 */
1608
Bootp *
1609
parsebootp(uchar *p, int n)
1610
{
1611
	Bootp *bp;
1612
 
1613
	bp = (Bootp*)p;
1614
	if(n < bp->optmagic - p) {
1615
		warning("parsebootp: short bootp packet; with options, "
1616
			"need %d bytes, got %d", bp->optmagic - p, n);
1617
		return nil;
1618
	}
1619
 
1620
	if(conf.xid != nhgetl(bp->xid))		/* not meant for us */
1621
		return nil;
1622
 
1623
	if(bp->op != Bootreply) {
1624
		warning("parsebootp: bad op %d", bp->op);
1625
		return nil;
1626
	}
1627
 
1628
	n -= bp->optmagic - p;
1629
	p = bp->optmagic;
1630
 
1631
	if(n < 4) {
1632
		warning("parsebootp: no option data");
1633
		return nil;
1634
	}
1635
	if(memcmp(optmagic, p, 4) != 0) {
1636
		warning("parsebootp: bad opt magic %ux %ux %ux %ux",
1637
			p[0], p[1], p[2], p[3]);
1638
		return nil;
1639
	}
1640
	p += 4;
1641
	n -= 4;
1642
	DEBUG("parsebootp: new packet");
1643
	if(parseoptions(p, n) < 0)
1644
		return nil;
1645
	return bp;
1646
}
1647
 
1648
/* write out an ndb entry */
1649
void
1650
writendb(char *s, int n, int append)
1651
{
1652
	char file[64];
1653
	int fd;
1654
 
1655
	snprint(file, sizeof file, "%s/ndb", conf.mpoint);
1656
	if(append){
1657
		fd = open(file, OWRITE);
1658
		seek(fd, 0, 2);
1659
	} else
1660
		fd = open(file, OWRITE|OTRUNC);
1661
	write(fd, s, n);
1662
	close(fd);
1663
}
1664
 
1665
/* put server addresses into the ndb entry */
1666
char*
1667
putaddrs(char *p, char *e, char *attr, uchar *a, int len)
1668
{
1669
	int i;
1670
 
1671
	for(i = 0; i < len && validip(a); i += IPaddrlen, a += IPaddrlen)
1672
		p = seprint(p, e, "%s=%I\n", attr, a);
1673
	return p;
1674
}
1675
 
1676
/* make an ndb entry and put it into /net/ndb for the servers to see */
1677
void
1678
putndb(void)
1679
{
1680
	int append;
1681
	char buf[1024];
1682
	char *p, *e, *np;
1683
 
1684
	p = buf;
1685
	e = buf + sizeof buf;
1686
	if(getndb() == 0)
1687
		append = 1;
1688
	else {
1689
		append = 0;
1690
		p = seprint(p, e, "ip=%I ipmask=%M ipgw=%I\n",
1691
			conf.laddr, conf.mask, conf.gaddr);
1692
	}
1693
	if(np = strchr(conf.hostname, '.')){
1694
		if(*conf.domainname == 0)
1695
			strcpy(conf.domainname, np+1);
1696
		*np = 0;
1697
	}
1698
	if(*conf.hostname)
1699
		p = seprint(p, e, "\tsys=%s\n", conf.hostname);
1700
	if(*conf.domainname)
1701
		p = seprint(p, e, "\tdom=%s.%s\n",
1702
			conf.hostname, conf.domainname);
1703
	if(validip(conf.fs))
1704
		p = putaddrs(p, e, "\tfs", conf.fs, sizeof conf.fs);
1705
	if(validip(conf.auth))
1706
		p = putaddrs(p, e, "\tauth", conf.auth, sizeof conf.auth);
1707
	if(validip(conf.dns))
1708
		p = putaddrs(p, e, "\tdns", conf.dns, sizeof conf.dns);
1709
	if(validip(conf.ntp))
1710
		p = putaddrs(p, e, "\tntp", conf.ntp, sizeof conf.ntp);
1711
	if(ndboptions)
1712
		p = seprint(p, e, "%s\n", ndboptions);
1713
	if(p > buf)
1714
		writendb(buf, p-buf, append);
1715
}
1716
 
1717
/* get an ndb entry someone else wrote */
1718
int
1719
getndb(void)
1720
{
1721
	char buf[1024];
1722
	int fd, n;
1723
	char *p;
1724
 
1725
	snprint(buf, sizeof buf, "%s/ndb", conf.mpoint);
1726
	fd = open(buf, OREAD);
1727
	n = read(fd, buf, sizeof buf-1);
1728
	close(fd);
1729
	if(n <= 0)
1730
		return -1;
1731
	buf[n] = 0;
1732
	p = strstr(buf, "ip=");
1733
	if(p == nil)
1734
		return -1;
1735
	if (parseip(conf.laddr, p+3) == -1)
1736
		fprint(2, "%s: bad address %s\n", argv0, p+3);
1737
	return 0;
1738
}
1739
 
1740
/* tell a server to refresh */
1741
void
1742
tweakserver(char *server)
1743
{
1744
	int fd;
1745
	char file[64];
1746
 
1747
	snprint(file, sizeof file, "%s/%s", conf.mpoint, server);
1748
	fd = open(file, ORDWR);
1749
	if(fd < 0)
1750
		return;
1751
	fprint(fd, "refresh");
1752
	close(fd);
1753
}
1754
 
1755
/* tell all servers to refresh their information */
1756
void
1757
tweakservers(void)
1758
{
1759
	tweakserver("dns");
1760
	tweakserver("cs");
1761
}
1762
 
1763
/* return number of networks */
1764
int
1765
nipifcs(char *net)
1766
{
1767
	int n;
1768
	Ipifc *nifc;
1769
	Iplifc *lifc;
1770
 
1771
	n = 0;
1772
	ifc = readipifc(net, ifc, -1);
1773
	for(nifc = ifc; nifc != nil; nifc = nifc->next){
1774
		/*
1775
		 * ignore loopback devices when trying to
1776
		 * figure out if we're the primary interface.
1777
		 */
1778
		if(strcmp(nifc->dev, "/dev/null") != 0)
1779
			for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next)
1780
				if(validip(lifc->ip)){
1781
					n++;
1782
					break;
1783
				}
1784
		if(strcmp(nifc->dev, conf.dev) == 0)
1785
			myifc = nifc->index;
1786
	}
1787
	return n;
1788
}
1789
 
1790
/* return true if this is a valid v4 address */
1791
int
1792
validip(uchar *addr)
1793
{
1794
	return ipcmp(addr, IPnoaddr) != 0 && ipcmp(addr, v4prefix) != 0;
1795
}
1796
 
1797
/* look for an action */
1798
int
1799
parseverb(char *name)
1800
{
1801
	int i;
1802
 
1803
	for(i = 0; i < nelem(verbs); i++)
1804
		if(verbs[i] != nil && strcmp(name, verbs[i]) == 0)
1805
			return i;
1806
	return -1;
1807
}
1808
 
1809
/* get everything out of ndb */
1810
void
1811
ndbconfig(void)
1812
{
1813
	int nattr, nauth = 0, ndns = 0, nfs = 0, ok;
1814
	char etheraddr[32];
1815
	char *attrs[10];
1816
	Ndb *db;
1817
	Ndbtuple *t, *nt;
1818
 
1819
	db = ndbopen(0);
1820
	if(db == nil)
1821
		sysfatal("can't open ndb: %r");
1822
	if (strcmp(conf.type, "ether") != 0 && strcmp(conf.type, "gbe") != 0 ||
1823
	    myetheraddr(conf.hwa, conf.dev) != 0)
1824
		sysfatal("can't read hardware address");
1825
	sprint(etheraddr, "%E", conf.hwa);
1826
	nattr = 0;
1827
	attrs[nattr++] = "ip";
1828
	attrs[nattr++] = "ipmask";
1829
	attrs[nattr++] = "ipgw";
1830
	/* the @ triggers resolution to an IP address; see ndb(2) */
1831
	attrs[nattr++] = "@dns";
1832
	attrs[nattr++] = "@ntp";
1833
	attrs[nattr++] = "@fs";
1834
	attrs[nattr++] = "@auth";
1835
	attrs[nattr] = nil;
1836
	t = ndbipinfo(db, "ether", etheraddr, attrs, nattr);
1837
	for(nt = t; nt != nil; nt = nt->entry) {
1838
		ok = 1;
1839
		if(strcmp(nt->attr, "ip") == 0)
1840
			ok = parseip(conf.laddr, nt->val);
1841
		else if(strcmp(nt->attr, "ipmask") == 0)
1842
			parseipmask(conf.mask, nt->val);  /* could be -1 */
1843
		else if(strcmp(nt->attr, "ipgw") == 0)
1844
			ok = parseip(conf.gaddr, nt->val);
1845
		else if(ndns < 2 && strcmp(nt->attr, "dns") == 0)
1846
			ok = parseip(conf.dns+IPaddrlen*ndns, nt->val);
1847
		else if(strcmp(nt->attr, "ntp") == 0)
1848
			ok = parseip(conf.ntp, nt->val);
1849
		else if(nfs < 2 && strcmp(nt->attr, "fs") == 0)
1850
			ok = parseip(conf.fs+IPaddrlen*nfs, nt->val);
1851
		else if(nauth < 2 && strcmp(nt->attr, "auth") == 0)
1852
			ok = parseip(conf.auth+IPaddrlen*nauth, nt->val);
1853
		if (!ok)
1854
			fprint(2, "%s: bad %s address in ndb: %s\n", argv0,
1855
				nt->attr, nt->val);
1856
	}
1857
	ndbfree(t);
1858
	if(!validip(conf.laddr))
1859
		sysfatal("address not found in ndb");
1860
}
1861
 
1862
int
1863
addoption(char *opt)
1864
{
1865
	int i;
1866
	Option *o;
1867
 
1868
	if(opt == nil)
1869
		return -1;
1870
	for(o = option; o < &option[nelem(option)]; o++)
1871
		if(o->name && strcmp(opt, o->name) == 0){
1872
			i = o - option;
1873
			if(memchr(requested, i, nrequested) == 0 &&
1874
			    nrequested < nelem(requested))
1875
				requested[nrequested++] = i;
1876
			return 0;
1877
		}
1878
	return -1;
1879
}
1880
 
1881
char*
1882
optgetx(uchar *p, uchar opt)
1883
{
1884
	int i, n;
1885
	ulong x;
1886
	char *s, *ns;
1887
	char str[256];
1888
	uchar ip[IPaddrlen], ips[16*IPaddrlen], vec[256];
1889
	Option *o;
1890
 
1891
	o = &option[opt];
1892
	if(o->name == nil)
1893
		return nil;
1894
 
1895
	s = nil;
1896
	switch(o->type){
1897
	case Taddr:
1898
		if(optgetaddr(p, opt, ip))
1899
			s = smprint("%s=%I", o->name, ip);
1900
		break;
1901
	case Taddrs:
1902
		n = optgetaddrs(p, opt, ips, 16);
1903
		if(n > 0)
1904
			s = smprint("%s=%I", o->name, ips);
1905
		for(i = 1; i < n; i++){
1906
			ns = smprint("%s %s=%I", s, o->name, &ips[i*IPaddrlen]);
1907
			free(s);
1908
			s = ns;
1909
		}
1910
		break;
1911
	case Tulong:
1912
		x = optgetulong(p, opt);
1913
		if(x != 0)
1914
			s = smprint("%s=%lud", o->name, x);
1915
		break;
1916
	case Tbyte:
1917
		x = optgetbyte(p, opt);
1918
		if(x != 0)
1919
			s = smprint("%s=%lud", o->name, x);
1920
		break;
1921
	case Tstr:
1922
		if(optgetstr(p, opt, str, sizeof str))
1923
			s = smprint("%s=%s", o->name, str);
1924
		break;
1925
	case Tvec:
1926
		n = optgetvec(p, opt, vec, sizeof vec);
1927
		if(n > 0)
1928
			/* what's %H?  it's not installed */
1929
			s = smprint("%s=%.*H", o->name, n, vec);
1930
		break;
1931
	}
1932
	return s;
1933
}
1934
 
1935
void
1936
getoptions(uchar *p)
1937
{
1938
	int i;
1939
	char *s, *t;
1940
 
1941
	for(i = nelem(defrequested); i < nrequested; i++){
1942
		s = optgetx(p, requested[i]);
1943
		if(s != nil)
1944
			DEBUG("%s ", s);
1945
		if(ndboptions == nil)
1946
			ndboptions = smprint("\t%s", s);
1947
		else{
1948
			t = ndboptions;
1949
			ndboptions = smprint("\t%s%s", s, ndboptions);
1950
			free(t);
1951
		}
1952
		free(s);
1953
	}
1954
}