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