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