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