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