6 void bootpdump(uchar *p, int n);
10 void myfatal(char *fmt, ...);
11 int openlisten(char*);
12 uchar *optaddaddr(uchar*, int, uchar*);
13 uchar *optaddbyte(uchar*, int, int);
14 uchar *optadd(uchar*, int, void*, int);
15 uchar *optaddulong(uchar*, int, ulong);
16 uchar *optget(Bootp*, int, int);
17 int optgetaddr(Bootp*, int, uchar*);
18 int optgetbyte(Bootp*, int);
19 ulong optgetulong(Bootp*, int);
20 Bootp *parse(uchar*, int);
21 void stdinthread(void*);
22 ulong thread(void(*f)(void*), void *a);
23 void timerthread(void*);
34 uchar server[IPaddrlen]; /* server IP address */
35 uchar client[IPaddrlen]; /* client IP address */
36 uchar mask[IPaddrlen]; /* client mask */
37 ulong lease; /* lease time */
38 ulong resend; /* number of resends for current state */
39 ulong timeout; /* time to timeout - seconds */
44 char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 };
47 main(int argc, char *argv[])
51 setnetmtpt(net, sizeof(net), nil);
58 setnetmtpt(net, sizeof(net), p);
61 fmtinstall('E', eipfmt);
62 fmtinstall('I', eipfmt);
63 fmtinstall('V', eipfmt);
67 rfork(RFNOTEG|RFREND);
69 thread(timerthread, 0);
70 thread(stdinthread, 0);
73 dhcp.starttime = time(0);
74 dhcp.fd = openlisten(net);
76 dhcp.state = Sselecting;
80 while(dhcp.state != Sbound)
83 /* allows other clients on this machine */
87 print("ip=%I\n", dhcp.client);
88 print("mask=%I\n", dhcp.mask);
91 /* keep lease alive */
93 //fprint(2, "got lease for %d\n", dhcp.lease);
95 sleep(dhcp.lease*500); /* wait half of lease time */
98 //fprint(2, "try renue\n", dhcp.lease);
99 dhcp.starttime = time(0);
100 dhcp.fd = openlisten(net);
101 dhcp.xid = time(0)*getpid();
103 dhcp.state = Srenewing;
107 while(dhcp.state != Sbound)
110 /* allows other clients on this machine */
119 fprint(2, "usage: %s [-x netextension]\n", argv0);
129 if(--dhcp.timeout > 0) {
136 myfatal("timerthread: unknown state %d", dhcp.state);
144 myfatal("dhcp: giving up: selecting");
151 myfatal("dhcp: giving up: requesting");
158 dhcp.state = Srebinding;
167 myfatal("dhcp: giving up: rebinding");
183 n = read(0, buf, sizeof(buf));
187 /* shutdown cleanly */
191 dhcp.fd = openlisten(net);
196 postnote(PNGROUP, getpid(), "die");
208 fd = open("/dev/random", 0);
210 read(fd, &dhcp.xid, sizeof(dhcp.xid));
213 dhcp.xid = time(0)*getpid();
216 sprint(dhcp.cid, "%s.%d", getenv("sysname"), getpid());
227 memset(&bp, 0, sizeof bp);
228 up = (Udphdr*)bp.udphdr;
230 hnputs(up->rport, 67);
232 hnputl(bp.xid, dhcp.xid);
233 hnputs(bp.secs, time(0) - dhcp.starttime);
234 hnputs(bp.flags, Fbroadcast); /* reply must be broadcast */
235 memmove(bp.optmagic, optmagic, 4);
237 p = optaddbyte(p, ODtype, type);
238 p = optadd(p, ODclientid, dhcp.cid, strlen(dhcp.cid));
241 myfatal("dhcpsend: unknown message type: %d", type);
243 ipmove(up->raddr, IPv4bcast); /* broadcast */
246 if(dhcp.state == Sbound || dhcp.state == Srenewing)
247 ipmove(up->raddr, dhcp.server);
249 ipmove(up->raddr, IPv4bcast); /* broadcast */
250 p = optaddulong(p, ODlease, dhcp.lease);
251 if(dhcp.state == Sselecting || dhcp.state == Srequesting) {
252 p = optaddaddr(p, ODipaddr, dhcp.client); /* mistake?? */
253 p = optaddaddr(p, ODserverid, dhcp.server);
255 v6tov4(bp.ciaddr, dhcp.client);
258 ipmove(up->raddr, dhcp.server);
259 v6tov4(bp.ciaddr, dhcp.client);
260 p = optaddaddr(p, ODipaddr, dhcp.client);
261 p = optaddaddr(p, ODserverid, dhcp.server);
269 if(write(dhcp.fd, &bp, n) != n)
270 myfatal("dhcpsend: write failed: %r");
280 uchar mask[IPaddrlen];
283 n = read(dhcp.fd, buf, sizeof(buf));
287 myfatal("dhcprecv: bad read: %r");
294 fprint(2, "recved\n");
298 type = optgetbyte(bp, ODtype);
301 fprint(2, "dhcprecv: unknown type: %d\n", type);
304 if(dhcp.state != Sselecting)
306 lease = optgetulong(bp, ODlease);
308 myfatal("bad lease");
309 if(!optgetaddr(bp, OBmask, mask))
310 memset(mask, 0xff, sizeof(mask));
311 v4tov6(dhcp.client, bp->yiaddr);
312 if(!optgetaddr(bp, ODserverid, dhcp.server)) {
313 fprint(2, "dhcprecv: Offer from server with invalid serverid\n");
318 ipmove(dhcp.mask, mask);
319 memmove(dhcp.sname, bp->sname, sizeof(dhcp.sname));
320 dhcp.sname[sizeof(dhcp.sname)-1] = 0;
323 dhcp.state = Srequesting;
328 if(dhcp.state != Srequesting)
329 if(dhcp.state != Srenewing)
330 if(dhcp.state != Srebinding)
332 lease = optgetulong(bp, ODlease);
334 myfatal("bad lease");
335 if(!optgetaddr(bp, OBmask, mask))
336 memset(mask, 0xff, sizeof(mask));
337 v4tov6(dhcp.client, bp->yiaddr);
339 ipmove(dhcp.mask, mask);
343 myfatal("recved nak");
350 openlisten(char *net)
353 char data[128], devdir[40];
355 // sprint(data, "%s/udp!*!bootpc", net);
356 sprint(data, "%s/udp!*!68", net);
358 cfd = announce(data, devdir);
361 /* might be another client - wait and try again */
362 fprint(2, "dhcpclient: can't announce %s: %r", data);
365 myfatal("can't announce: giving up: %r");
368 if(fprint(cfd, "headers") < 0)
369 myfatal("can't set header mode: %r");
371 sprint(data, "%s/data", devdir);
372 fd = open(data, ORDWR);
374 myfatal("open %s: %r", data);
380 optadd(uchar *p, int op, void *d, int n)
389 optaddbyte(uchar *p, int op, int b)
398 optaddulong(uchar *p, int op, ulong x)
407 optaddaddr(uchar *p, int op, uchar *ip)
416 optget(Bootp *bp, int op, int n)
441 optgetbyte(Bootp *bp, int op)
445 p = optget(bp, op, 1);
452 optgetulong(Bootp *bp, int op)
456 p = optget(bp, op, 4);
463 optgetaddr(Bootp *bp, int op, uchar *ip)
467 p = optget(bp, op, 4);
474 /* make sure packet looks ok */
476 parse(uchar *p, int n)
482 if(n < bp->optmagic - p) {
483 fprint(2, "dhcpclient: parse: short bootp packet");
487 if(dhcp.xid != nhgetl(bp->xid)) {
488 fprint(2, "dhcpclient: parse: bad xid: got %ux expected %lux\n",
489 nhgetl(bp->xid), dhcp.xid);
493 if(bp->op != Bootreply) {
494 fprint(2, "dhcpclient: parse: bad op\n");
498 n -= bp->optmagic - p;
502 fprint(2, "dhcpclient: parse: not option data");
505 if(memcmp(optmagic, p, 4) != 0) {
506 fprint(2, "dhcpclient: parse: bad opt magic %ux %ux %ux %ux\n",
507 p[0], p[1], p[2], p[3]);
520 fprint(2, "dhcpclient: parse: bad option: %d", code);
526 fprint(2, "dhcpclient: parse: bad option: %d", code);
533 /* fix up nonstandard packets */
534 /* assume there is space */
541 bootpdump(uchar *p, int n)
548 up = (Udphdr*)bp->udphdr;
550 if(n < bp->optmagic - p) {
551 fprint(2, "dhcpclient: short bootp packet");
555 fprint(2, "laddr=%I lport=%d raddr=%I rport=%d\n", up->laddr,
556 nhgets(up->lport), up->raddr, nhgets(up->rport));
557 fprint(2, "op=%d htype=%d hlen=%d hops=%d\n", bp->op, bp->htype,
559 fprint(2, "xid=%ux secs=%d flags=%ux\n", nhgetl(bp->xid),
560 nhgets(bp->secs), nhgets(bp->flags));
561 fprint(2, "ciaddr=%V yiaddr=%V siaddr=%V giaddr=%V\n",
562 bp->ciaddr, bp->yiaddr, bp->siaddr, bp->giaddr);
563 fprint(2, "chaddr=");
565 fprint(2, "%ux ", bp->chaddr[i]);
567 fprint(2, "sname=%s\n", bp->sname);
568 fprint(2, "file = %s\n", bp->file);
570 n -= bp->optmagic - p;
575 if(memcmp(optmagic, p, 4) != 0)
576 fprint(2, "dhcpclient: bad opt magic %ux %ux %ux %ux\n",
577 p[0], p[1], p[2], p[3]);
589 fprint(2, " bad option: %d", code);
595 fprint(2, " bad option: %d", code);
600 fprint(2, "unknown option %d\n", code);
601 for(i = 0; i<len; i++)
602 fprint(2, "%ux ", p[i]);
604 fprint(2, "DHCP type %d\n", p[0]);
607 fprint(2, "client id=");
608 for(i = 0; i<len; i++)
609 fprint(2, "%ux ", p[i]);
613 fprint(2, "lease=%d\n", nhgetl(p));
616 fprint(2, "server id=%V\n", p);
619 fprint(2, "mask=%V\n", p);
622 fprint(2, "router=%V\n", p);
631 thread(void(*f)(void*), void *a)
635 pid = rfork(RFNOWAIT|RFMEM|RFPROC);
637 myfatal("rfork failed: %r");
641 return 0; /* never reaches here */
645 myfatal(char *fmt, ...)
651 vseprint(buf, buf+sizeof(buf), fmt, arg);
653 fprint(2, "%s: %s\n", argv0, buf);
654 postnote(PNGROUP, getpid(), "die");