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