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