17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ip.h>
47dd7cddfSDavid du Colombier #include "dhcp.h"
57dd7cddfSDavid du Colombier
67dd7cddfSDavid du Colombier void bootpdump(uchar *p, int n);
77dd7cddfSDavid du Colombier void dhcpinit(void);
8*f27a9a5aSDavid du Colombier void dhcprecv(void);
9*f27a9a5aSDavid du Colombier void dhcpsend(int);
10*f27a9a5aSDavid du Colombier void myfatal(char *fmt, ...);
11*f27a9a5aSDavid du Colombier int openlisten(char*);
127dd7cddfSDavid du Colombier uchar *optaddaddr(uchar*, int, uchar*);
13*f27a9a5aSDavid du Colombier uchar *optaddbyte(uchar*, int, int);
14*f27a9a5aSDavid du Colombier uchar *optadd(uchar*, int, void*, int);
15*f27a9a5aSDavid du Colombier uchar *optaddulong(uchar*, int, ulong);
167dd7cddfSDavid du Colombier uchar *optget(Bootp*, int, int);
17*f27a9a5aSDavid du Colombier int optgetaddr(Bootp*, int, uchar*);
187dd7cddfSDavid du Colombier int optgetbyte(Bootp*, int);
197dd7cddfSDavid du Colombier ulong optgetulong(Bootp*, int);
207dd7cddfSDavid du Colombier Bootp *parse(uchar*, int);
21*f27a9a5aSDavid du Colombier void stdinthread(void*);
227dd7cddfSDavid du Colombier ulong thread(void(*f)(void*), void *a);
23*f27a9a5aSDavid du Colombier void timerthread(void*);
24*f27a9a5aSDavid du Colombier void usage(void);
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier struct {
277dd7cddfSDavid du Colombier QLock lk;
287dd7cddfSDavid du Colombier int state;
297dd7cddfSDavid du Colombier int fd;
307dd7cddfSDavid du Colombier ulong xid;
317dd7cddfSDavid du Colombier ulong starttime;
327dd7cddfSDavid du Colombier char cid[100];
337dd7cddfSDavid du Colombier char sname[64];
347dd7cddfSDavid du Colombier uchar server[IPaddrlen]; /* server IP address */
357dd7cddfSDavid du Colombier uchar client[IPaddrlen]; /* client IP address */
367dd7cddfSDavid du Colombier uchar mask[IPaddrlen]; /* client mask */
377dd7cddfSDavid du Colombier ulong lease; /* lease time */
387dd7cddfSDavid du Colombier ulong resend; /* number of resends for current state */
397dd7cddfSDavid du Colombier ulong timeout; /* time to timeout - seconds */
407dd7cddfSDavid du Colombier } dhcp;
417dd7cddfSDavid du Colombier
429a747e4fSDavid du Colombier char net[64];
437dd7cddfSDavid du Colombier
447dd7cddfSDavid du Colombier char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 };
457dd7cddfSDavid du Colombier
467dd7cddfSDavid du Colombier void
main(int argc,char * argv[])477dd7cddfSDavid du Colombier main(int argc, char *argv[])
487dd7cddfSDavid du Colombier {
497dd7cddfSDavid du Colombier char *p;
507dd7cddfSDavid du Colombier
517dd7cddfSDavid du Colombier setnetmtpt(net, sizeof(net), nil);
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier ARGBEGIN{
547dd7cddfSDavid du Colombier case 'x':
557dd7cddfSDavid du Colombier p = ARGF();
567dd7cddfSDavid du Colombier if(p == nil)
577dd7cddfSDavid du Colombier usage();
587dd7cddfSDavid du Colombier setnetmtpt(net, sizeof(net), p);
597dd7cddfSDavid du Colombier }ARGEND;
607dd7cddfSDavid du Colombier
619a747e4fSDavid du Colombier fmtinstall('E', eipfmt);
629a747e4fSDavid du Colombier fmtinstall('I', eipfmt);
639a747e4fSDavid du Colombier fmtinstall('V', eipfmt);
647dd7cddfSDavid du Colombier
657dd7cddfSDavid du Colombier dhcpinit();
667dd7cddfSDavid du Colombier
677dd7cddfSDavid du Colombier rfork(RFNOTEG|RFREND);
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier thread(timerthread, 0);
707dd7cddfSDavid du Colombier thread(stdinthread, 0);
717dd7cddfSDavid du Colombier
727dd7cddfSDavid du Colombier qlock(&dhcp.lk);
737dd7cddfSDavid du Colombier dhcp.starttime = time(0);
747dd7cddfSDavid du Colombier dhcp.fd = openlisten(net);
757dd7cddfSDavid du Colombier dhcpsend(Discover);
767dd7cddfSDavid du Colombier dhcp.state = Sselecting;
777dd7cddfSDavid du Colombier dhcp.resend = 0;
787dd7cddfSDavid du Colombier dhcp.timeout = 4;
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier while(dhcp.state != Sbound)
817dd7cddfSDavid du Colombier dhcprecv();
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier /* allows other clients on this machine */
847dd7cddfSDavid du Colombier close(dhcp.fd);
857dd7cddfSDavid du Colombier dhcp.fd = -1;
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier print("ip=%I\n", dhcp.client);
887dd7cddfSDavid du Colombier print("mask=%I\n", dhcp.mask);
897dd7cddfSDavid du Colombier print("end\n");
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier /* keep lease alive */
927dd7cddfSDavid du Colombier for(;;) {
937dd7cddfSDavid du Colombier //fprint(2, "got lease for %d\n", dhcp.lease);
947dd7cddfSDavid du Colombier qunlock(&dhcp.lk);
95*f27a9a5aSDavid du Colombier sleep(dhcp.lease*500); /* wait half of lease time */
967dd7cddfSDavid du Colombier qlock(&dhcp.lk);
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier //fprint(2, "try renue\n", dhcp.lease);
997dd7cddfSDavid du Colombier dhcp.starttime = time(0);
1007dd7cddfSDavid du Colombier dhcp.fd = openlisten(net);
1017dd7cddfSDavid du Colombier dhcp.xid = time(0)*getpid();
1027dd7cddfSDavid du Colombier dhcpsend(Request);
1037dd7cddfSDavid du Colombier dhcp.state = Srenewing;
1047dd7cddfSDavid du Colombier dhcp.resend = 0;
1057dd7cddfSDavid du Colombier dhcp.timeout = 1;
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier while(dhcp.state != Sbound)
1087dd7cddfSDavid du Colombier dhcprecv();
1097dd7cddfSDavid du Colombier
1107dd7cddfSDavid du Colombier /* allows other clients on this machine */
1117dd7cddfSDavid du Colombier close(dhcp.fd);
1127dd7cddfSDavid du Colombier dhcp.fd = -1;
1137dd7cddfSDavid du Colombier }
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier void
usage(void)1177dd7cddfSDavid du Colombier usage(void)
1187dd7cddfSDavid du Colombier {
1197dd7cddfSDavid du Colombier fprint(2, "usage: %s [-x netextension]\n", argv0);
1207dd7cddfSDavid du Colombier exits("usage");
1217dd7cddfSDavid du Colombier }
1227dd7cddfSDavid du Colombier
1237dd7cddfSDavid du Colombier void
timerthread(void *)1247dd7cddfSDavid du Colombier timerthread(void*)
1257dd7cddfSDavid du Colombier {
1267dd7cddfSDavid du Colombier for(;;) {
1277dd7cddfSDavid du Colombier sleep(1000);
1287dd7cddfSDavid du Colombier qlock(&dhcp.lk);
1297dd7cddfSDavid du Colombier if(--dhcp.timeout > 0) {
1307dd7cddfSDavid du Colombier qunlock(&dhcp.lk);
1317dd7cddfSDavid du Colombier continue;
1327dd7cddfSDavid du Colombier }
1337dd7cddfSDavid du Colombier
1347dd7cddfSDavid du Colombier switch(dhcp.state) {
1357dd7cddfSDavid du Colombier default:
1367dd7cddfSDavid du Colombier myfatal("timerthread: unknown state %d", dhcp.state);
1377dd7cddfSDavid du Colombier case Sinit:
1387dd7cddfSDavid du Colombier break;
1397dd7cddfSDavid du Colombier case Sselecting:
1407dd7cddfSDavid du Colombier dhcpsend(Discover);
1417dd7cddfSDavid du Colombier dhcp.timeout = 4;
1427dd7cddfSDavid du Colombier dhcp.resend++;
1437dd7cddfSDavid du Colombier if(dhcp.resend>5)
1447dd7cddfSDavid du Colombier myfatal("dhcp: giving up: selecting");
1457dd7cddfSDavid du Colombier break;
1467dd7cddfSDavid du Colombier case Srequesting:
1477dd7cddfSDavid du Colombier dhcpsend(Request);
1487dd7cddfSDavid du Colombier dhcp.timeout = 4;
1497dd7cddfSDavid du Colombier dhcp.resend++;
1507dd7cddfSDavid du Colombier if(dhcp.resend>5)
1517dd7cddfSDavid du Colombier myfatal("dhcp: giving up: requesting");
1527dd7cddfSDavid du Colombier break;
1537dd7cddfSDavid du Colombier case Srenewing:
1547dd7cddfSDavid du Colombier dhcpsend(Request);
1557dd7cddfSDavid du Colombier dhcp.timeout = 1;
1567dd7cddfSDavid du Colombier dhcp.resend++;
1577dd7cddfSDavid du Colombier if(dhcp.resend>3) {
1587dd7cddfSDavid du Colombier dhcp.state = Srebinding;
1597dd7cddfSDavid du Colombier dhcp.resend = 0;
1607dd7cddfSDavid du Colombier }
1617dd7cddfSDavid du Colombier break;
1627dd7cddfSDavid du Colombier case Srebinding:
1637dd7cddfSDavid du Colombier dhcpsend(Request);
1647dd7cddfSDavid du Colombier dhcp.timeout = 4;
1657dd7cddfSDavid du Colombier dhcp.resend++;
1667dd7cddfSDavid du Colombier if(dhcp.resend>5)
1677dd7cddfSDavid du Colombier myfatal("dhcp: giving up: rebinding");
1687dd7cddfSDavid du Colombier break;
1697dd7cddfSDavid du Colombier case Sbound:
1707dd7cddfSDavid du Colombier break;
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier qunlock(&dhcp.lk);
1737dd7cddfSDavid du Colombier }
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier void
stdinthread(void *)1777dd7cddfSDavid du Colombier stdinthread(void*)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier uchar buf[100];
1807dd7cddfSDavid du Colombier int n;
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier for(;;) {
1837dd7cddfSDavid du Colombier n = read(0, buf, sizeof(buf));
1847dd7cddfSDavid du Colombier if(n <= 0)
1857dd7cddfSDavid du Colombier break;
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier /* shutdown cleanly */
1887dd7cddfSDavid du Colombier qlock(&dhcp.lk);
1897dd7cddfSDavid du Colombier if(dhcp.client) {
1907dd7cddfSDavid du Colombier if(dhcp.fd < 0)
1917dd7cddfSDavid du Colombier dhcp.fd = openlisten(net);
1927dd7cddfSDavid du Colombier dhcpsend(Release);
1937dd7cddfSDavid du Colombier }
1947dd7cddfSDavid du Colombier qunlock(&dhcp.lk);
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier postnote(PNGROUP, getpid(), "die");
1977dd7cddfSDavid du Colombier exits(0);
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier
2007dd7cddfSDavid du Colombier void
dhcpinit(void)2017dd7cddfSDavid du Colombier dhcpinit(void)
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier int fd;
2047dd7cddfSDavid du Colombier
2057dd7cddfSDavid du Colombier dhcp.state = Sinit;
2067dd7cddfSDavid du Colombier dhcp.timeout = 4;
2077dd7cddfSDavid du Colombier
2087dd7cddfSDavid du Colombier fd = open("/dev/random", 0);
2097dd7cddfSDavid du Colombier if(fd >= 0) {
2107dd7cddfSDavid du Colombier read(fd, &dhcp.xid, sizeof(dhcp.xid));
2117dd7cddfSDavid du Colombier close(fd);
2127dd7cddfSDavid du Colombier } else
2137dd7cddfSDavid du Colombier dhcp.xid = time(0)*getpid();
2147dd7cddfSDavid du Colombier srand(dhcp.xid);
2157dd7cddfSDavid du Colombier
2167dd7cddfSDavid du Colombier sprint(dhcp.cid, "%s.%d", getenv("sysname"), getpid());
2177dd7cddfSDavid du Colombier }
2187dd7cddfSDavid du Colombier
2197dd7cddfSDavid du Colombier void
dhcpsend(int type)2207dd7cddfSDavid du Colombier dhcpsend(int type)
2217dd7cddfSDavid du Colombier {
2227dd7cddfSDavid du Colombier int n;
223*f27a9a5aSDavid du Colombier uchar *p;
224*f27a9a5aSDavid du Colombier Bootp bp;
225*f27a9a5aSDavid du Colombier Udphdr *up;
2267dd7cddfSDavid du Colombier
227*f27a9a5aSDavid du Colombier memset(&bp, 0, sizeof bp);
228*f27a9a5aSDavid du Colombier up = (Udphdr*)bp.udphdr;
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier hnputs(up->rport, 67);
2317dd7cddfSDavid du Colombier bp.op = Bootrequest;
2327dd7cddfSDavid du Colombier hnputl(bp.xid, dhcp.xid);
2337dd7cddfSDavid du Colombier hnputs(bp.secs, time(0) - dhcp.starttime);
234*f27a9a5aSDavid du Colombier hnputs(bp.flags, Fbroadcast); /* reply must be broadcast */
2357dd7cddfSDavid du Colombier memmove(bp.optmagic, optmagic, 4);
2367dd7cddfSDavid du Colombier p = bp.optdata;
2377dd7cddfSDavid du Colombier p = optaddbyte(p, ODtype, type);
2387dd7cddfSDavid du Colombier p = optadd(p, ODclientid, dhcp.cid, strlen(dhcp.cid));
2397dd7cddfSDavid du Colombier switch(type) {
2407dd7cddfSDavid du Colombier default:
2417dd7cddfSDavid du Colombier myfatal("dhcpsend: unknown message type: %d", type);
2427dd7cddfSDavid du Colombier case Discover:
243*f27a9a5aSDavid du Colombier ipmove(up->raddr, IPv4bcast); /* broadcast */
2447dd7cddfSDavid du Colombier break;
2457dd7cddfSDavid du Colombier case Request:
2467dd7cddfSDavid du Colombier if(dhcp.state == Sbound || dhcp.state == Srenewing)
2477dd7cddfSDavid du Colombier ipmove(up->raddr, dhcp.server);
2487dd7cddfSDavid du Colombier else
249*f27a9a5aSDavid du Colombier ipmove(up->raddr, IPv4bcast); /* broadcast */
2507dd7cddfSDavid du Colombier p = optaddulong(p, ODlease, dhcp.lease);
2517dd7cddfSDavid du Colombier if(dhcp.state == Sselecting || dhcp.state == Srequesting) {
252*f27a9a5aSDavid du Colombier p = optaddaddr(p, ODipaddr, dhcp.client); /* mistake?? */
2537dd7cddfSDavid du Colombier p = optaddaddr(p, ODserverid, dhcp.server);
2547dd7cddfSDavid du Colombier } else
2557dd7cddfSDavid du Colombier v6tov4(bp.ciaddr, dhcp.client);
2567dd7cddfSDavid du Colombier break;
2577dd7cddfSDavid du Colombier case Release:
2587dd7cddfSDavid du Colombier ipmove(up->raddr, dhcp.server);
2597dd7cddfSDavid du Colombier v6tov4(bp.ciaddr, dhcp.client);
2607dd7cddfSDavid du Colombier p = optaddaddr(p, ODipaddr, dhcp.client);
2617dd7cddfSDavid du Colombier p = optaddaddr(p, ODserverid, dhcp.server);
2627dd7cddfSDavid du Colombier break;
2637dd7cddfSDavid du Colombier }
2647dd7cddfSDavid du Colombier
2657dd7cddfSDavid du Colombier *p++ = OBend;
2667dd7cddfSDavid du Colombier
2677dd7cddfSDavid du Colombier n = p - (uchar*)&bp;
2687dd7cddfSDavid du Colombier
2697dd7cddfSDavid du Colombier if(write(dhcp.fd, &bp, n) != n)
2707dd7cddfSDavid du Colombier myfatal("dhcpsend: write failed: %r");
2717dd7cddfSDavid du Colombier }
2727dd7cddfSDavid du Colombier
2737dd7cddfSDavid du Colombier void
dhcprecv(void)2747dd7cddfSDavid du Colombier dhcprecv(void)
2757dd7cddfSDavid du Colombier {
2767dd7cddfSDavid du Colombier uchar buf[2000];
2777dd7cddfSDavid du Colombier Bootp *bp;
2787dd7cddfSDavid du Colombier int n, type;
2797dd7cddfSDavid du Colombier ulong lease;
2807dd7cddfSDavid du Colombier uchar mask[IPaddrlen];
2817dd7cddfSDavid du Colombier
2827dd7cddfSDavid du Colombier qunlock(&dhcp.lk);
2837dd7cddfSDavid du Colombier n = read(dhcp.fd, buf, sizeof(buf));
2847dd7cddfSDavid du Colombier qlock(&dhcp.lk);
2857dd7cddfSDavid du Colombier
2867dd7cddfSDavid du Colombier if(n <= 0)
2877dd7cddfSDavid du Colombier myfatal("dhcprecv: bad read: %r");
2887dd7cddfSDavid du Colombier
2897dd7cddfSDavid du Colombier bp = parse(buf, n);
2907dd7cddfSDavid du Colombier if(bp == 0)
2917dd7cddfSDavid du Colombier return;
2927dd7cddfSDavid du Colombier
293*f27a9a5aSDavid du Colombier if(1) {
2947dd7cddfSDavid du Colombier fprint(2, "recved\n");
2957dd7cddfSDavid du Colombier bootpdump(buf, n);
2967dd7cddfSDavid du Colombier }
2977dd7cddfSDavid du Colombier
2987dd7cddfSDavid du Colombier type = optgetbyte(bp, ODtype);
2997dd7cddfSDavid du Colombier switch(type) {
3007dd7cddfSDavid du Colombier default:
3017dd7cddfSDavid du Colombier fprint(2, "dhcprecv: unknown type: %d\n", type);
3027dd7cddfSDavid du Colombier break;
3037dd7cddfSDavid du Colombier case Offer:
3047dd7cddfSDavid du Colombier if(dhcp.state != Sselecting)
3057dd7cddfSDavid du Colombier break;
3067dd7cddfSDavid du Colombier lease = optgetulong(bp, ODlease);
3077dd7cddfSDavid du Colombier if(lease == 0)
3087dd7cddfSDavid du Colombier myfatal("bad lease");
3097dd7cddfSDavid du Colombier if(!optgetaddr(bp, OBmask, mask))
3107dd7cddfSDavid du Colombier memset(mask, 0xff, sizeof(mask));
3117dd7cddfSDavid du Colombier v4tov6(dhcp.client, bp->yiaddr);
3127dd7cddfSDavid du Colombier if(!optgetaddr(bp, ODserverid, dhcp.server)) {
3137dd7cddfSDavid du Colombier fprint(2, "dhcprecv: Offer from server with invalid serverid\n");
3147dd7cddfSDavid du Colombier break;
3157dd7cddfSDavid du Colombier }
3167dd7cddfSDavid du Colombier
3177dd7cddfSDavid du Colombier dhcp.lease = lease;
3187dd7cddfSDavid du Colombier ipmove(dhcp.mask, mask);
3197dd7cddfSDavid du Colombier memmove(dhcp.sname, bp->sname, sizeof(dhcp.sname));
3207dd7cddfSDavid du Colombier dhcp.sname[sizeof(dhcp.sname)-1] = 0;
3217dd7cddfSDavid du Colombier
3227dd7cddfSDavid du Colombier dhcpsend(Request);
3237dd7cddfSDavid du Colombier dhcp.state = Srequesting;
3247dd7cddfSDavid du Colombier dhcp.resend = 0;
3257dd7cddfSDavid du Colombier dhcp.timeout = 4;
3267dd7cddfSDavid du Colombier break;
3277dd7cddfSDavid du Colombier case Ack:
3287dd7cddfSDavid du Colombier if(dhcp.state != Srequesting)
3297dd7cddfSDavid du Colombier if(dhcp.state != Srenewing)
3307dd7cddfSDavid du Colombier if(dhcp.state != Srebinding)
3317dd7cddfSDavid du Colombier break;
3327dd7cddfSDavid du Colombier lease = optgetulong(bp, ODlease);
3337dd7cddfSDavid du Colombier if(lease == 0)
3347dd7cddfSDavid du Colombier myfatal("bad lease");
3357dd7cddfSDavid du Colombier if(!optgetaddr(bp, OBmask, mask))
3367dd7cddfSDavid du Colombier memset(mask, 0xff, sizeof(mask));
3377dd7cddfSDavid du Colombier v4tov6(dhcp.client, bp->yiaddr);
3387dd7cddfSDavid du Colombier dhcp.lease = lease;
3397dd7cddfSDavid du Colombier ipmove(dhcp.mask, mask);
3407dd7cddfSDavid du Colombier dhcp.state = Sbound;
3417dd7cddfSDavid du Colombier break;
3427dd7cddfSDavid du Colombier case Nak:
3437dd7cddfSDavid du Colombier myfatal("recved nak");
3447dd7cddfSDavid du Colombier break;
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier }
3487dd7cddfSDavid du Colombier
3497dd7cddfSDavid du Colombier int
openlisten(char * net)3507dd7cddfSDavid du Colombier openlisten(char *net)
3517dd7cddfSDavid du Colombier {
352*f27a9a5aSDavid du Colombier int n, fd, cfd;
353*f27a9a5aSDavid du Colombier char data[128], devdir[40];
3547dd7cddfSDavid du Colombier
3557dd7cddfSDavid du Colombier // sprint(data, "%s/udp!*!bootpc", net);
3567dd7cddfSDavid du Colombier sprint(data, "%s/udp!*!68", net);
3577dd7cddfSDavid du Colombier for(n = 0; ; n++) {
3587dd7cddfSDavid du Colombier cfd = announce(data, devdir);
3597dd7cddfSDavid du Colombier if(cfd >= 0)
3607dd7cddfSDavid du Colombier break;
3617dd7cddfSDavid du Colombier /* might be another client - wait and try again */
362*f27a9a5aSDavid du Colombier fprint(2, "dhcpclient: can't announce %s: %r", data);
3637dd7cddfSDavid du Colombier sleep(1000);
3647dd7cddfSDavid du Colombier if(n > 10)
3657dd7cddfSDavid du Colombier myfatal("can't announce: giving up: %r");
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier if(fprint(cfd, "headers") < 0)
3697dd7cddfSDavid du Colombier myfatal("can't set header mode: %r");
3707dd7cddfSDavid du Colombier
3717dd7cddfSDavid du Colombier sprint(data, "%s/data", devdir);
3727dd7cddfSDavid du Colombier fd = open(data, ORDWR);
3737dd7cddfSDavid du Colombier if(fd < 0)
374*f27a9a5aSDavid du Colombier myfatal("open %s: %r", data);
3757dd7cddfSDavid du Colombier close(cfd);
3767dd7cddfSDavid du Colombier return fd;
3777dd7cddfSDavid du Colombier }
3787dd7cddfSDavid du Colombier
3797dd7cddfSDavid du Colombier uchar*
optadd(uchar * p,int op,void * d,int n)3807dd7cddfSDavid du Colombier optadd(uchar *p, int op, void *d, int n)
3817dd7cddfSDavid du Colombier {
3827dd7cddfSDavid du Colombier p[0] = op;
3837dd7cddfSDavid du Colombier p[1] = n;
3847dd7cddfSDavid du Colombier memmove(p+2, d, n);
3857dd7cddfSDavid du Colombier return p+n+2;
3867dd7cddfSDavid du Colombier }
3877dd7cddfSDavid du Colombier
3887dd7cddfSDavid du Colombier uchar*
optaddbyte(uchar * p,int op,int b)3897dd7cddfSDavid du Colombier optaddbyte(uchar *p, int op, int b)
3907dd7cddfSDavid du Colombier {
3917dd7cddfSDavid du Colombier p[0] = op;
3927dd7cddfSDavid du Colombier p[1] = 1;
3937dd7cddfSDavid du Colombier p[2] = b;
3947dd7cddfSDavid du Colombier return p+3;
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier
3977dd7cddfSDavid du Colombier uchar*
optaddulong(uchar * p,int op,ulong x)3987dd7cddfSDavid du Colombier optaddulong(uchar *p, int op, ulong x)
3997dd7cddfSDavid du Colombier {
4007dd7cddfSDavid du Colombier p[0] = op;
4017dd7cddfSDavid du Colombier p[1] = 4;
4027dd7cddfSDavid du Colombier hnputl(p+2, x);
4037dd7cddfSDavid du Colombier return p+6;
4047dd7cddfSDavid du Colombier }
4057dd7cddfSDavid du Colombier
4067dd7cddfSDavid du Colombier uchar *
optaddaddr(uchar * p,int op,uchar * ip)4077dd7cddfSDavid du Colombier optaddaddr(uchar *p, int op, uchar *ip)
4087dd7cddfSDavid du Colombier {
4097dd7cddfSDavid du Colombier p[0] = op;
4107dd7cddfSDavid du Colombier p[1] = 4;
4117dd7cddfSDavid du Colombier v6tov4(p+2, ip);
4127dd7cddfSDavid du Colombier return p+6;
4137dd7cddfSDavid du Colombier }
4147dd7cddfSDavid du Colombier
4157dd7cddfSDavid du Colombier uchar*
optget(Bootp * bp,int op,int n)4167dd7cddfSDavid du Colombier optget(Bootp *bp, int op, int n)
4177dd7cddfSDavid du Colombier {
4187dd7cddfSDavid du Colombier int len, code;
4197dd7cddfSDavid du Colombier uchar *p;
4207dd7cddfSDavid du Colombier
4217dd7cddfSDavid du Colombier p = bp->optdata;
4227dd7cddfSDavid du Colombier for(;;) {
4237dd7cddfSDavid du Colombier code = *p++;
4247dd7cddfSDavid du Colombier if(code == OBpad)
4257dd7cddfSDavid du Colombier continue;
4267dd7cddfSDavid du Colombier if(code == OBend)
4277dd7cddfSDavid du Colombier return 0;
4287dd7cddfSDavid du Colombier len = *p++;
4297dd7cddfSDavid du Colombier if(code != op) {
4307dd7cddfSDavid du Colombier p += len;
4317dd7cddfSDavid du Colombier continue;
4327dd7cddfSDavid du Colombier }
4337dd7cddfSDavid du Colombier if(n && n != len)
4347dd7cddfSDavid du Colombier return 0;
4357dd7cddfSDavid du Colombier return p;
4367dd7cddfSDavid du Colombier }
4377dd7cddfSDavid du Colombier }
4387dd7cddfSDavid du Colombier
4397dd7cddfSDavid du Colombier
4407dd7cddfSDavid du Colombier int
optgetbyte(Bootp * bp,int op)4417dd7cddfSDavid du Colombier optgetbyte(Bootp *bp, int op)
4427dd7cddfSDavid du Colombier {
4437dd7cddfSDavid du Colombier uchar *p;
4447dd7cddfSDavid du Colombier
4457dd7cddfSDavid du Colombier p = optget(bp, op, 1);
4467dd7cddfSDavid du Colombier if(p == 0)
4477dd7cddfSDavid du Colombier return 0;
4487dd7cddfSDavid du Colombier return *p;
4497dd7cddfSDavid du Colombier }
4507dd7cddfSDavid du Colombier
4517dd7cddfSDavid du Colombier ulong
optgetulong(Bootp * bp,int op)4527dd7cddfSDavid du Colombier optgetulong(Bootp *bp, int op)
4537dd7cddfSDavid du Colombier {
4547dd7cddfSDavid du Colombier uchar *p;
4557dd7cddfSDavid du Colombier
4567dd7cddfSDavid du Colombier p = optget(bp, op, 4);
4577dd7cddfSDavid du Colombier if(p == 0)
4587dd7cddfSDavid du Colombier return 0;
4597dd7cddfSDavid du Colombier return nhgetl(p);
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier int
optgetaddr(Bootp * bp,int op,uchar * ip)4637dd7cddfSDavid du Colombier optgetaddr(Bootp *bp, int op, uchar *ip)
4647dd7cddfSDavid du Colombier {
4657dd7cddfSDavid du Colombier uchar *p;
4667dd7cddfSDavid du Colombier
4677dd7cddfSDavid du Colombier p = optget(bp, op, 4);
4687dd7cddfSDavid du Colombier if(p == 0)
4697dd7cddfSDavid du Colombier return 0;
4707dd7cddfSDavid du Colombier v4tov6(ip, p);
4717dd7cddfSDavid du Colombier return 1;
4727dd7cddfSDavid du Colombier }
4737dd7cddfSDavid du Colombier
4747dd7cddfSDavid du Colombier /* make sure packet looks ok */
4757dd7cddfSDavid du Colombier Bootp *
parse(uchar * p,int n)4767dd7cddfSDavid du Colombier parse(uchar *p, int n)
4777dd7cddfSDavid du Colombier {
4787dd7cddfSDavid du Colombier int len, code;
4797dd7cddfSDavid du Colombier Bootp *bp;
4807dd7cddfSDavid du Colombier
4817dd7cddfSDavid du Colombier bp = (Bootp*)p;
4827dd7cddfSDavid du Colombier if(n < bp->optmagic - p) {
4837dd7cddfSDavid du Colombier fprint(2, "dhcpclient: parse: short bootp packet");
4847dd7cddfSDavid du Colombier return 0;
4857dd7cddfSDavid du Colombier }
4867dd7cddfSDavid du Colombier
4877dd7cddfSDavid du Colombier if(dhcp.xid != nhgetl(bp->xid)) {
488*f27a9a5aSDavid du Colombier fprint(2, "dhcpclient: parse: bad xid: got %ux expected %lux\n",
489*f27a9a5aSDavid du Colombier nhgetl(bp->xid), dhcp.xid);
4907dd7cddfSDavid du Colombier return 0;
4917dd7cddfSDavid du Colombier }
4927dd7cddfSDavid du Colombier
4937dd7cddfSDavid du Colombier if(bp->op != Bootreply) {
4947dd7cddfSDavid du Colombier fprint(2, "dhcpclient: parse: bad op\n");
4957dd7cddfSDavid du Colombier return 0;
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier
4987dd7cddfSDavid du Colombier n -= bp->optmagic - p;
4997dd7cddfSDavid du Colombier p = bp->optmagic;
5007dd7cddfSDavid du Colombier
5017dd7cddfSDavid du Colombier if(n < 4) {
5027dd7cddfSDavid du Colombier fprint(2, "dhcpclient: parse: not option data");
5037dd7cddfSDavid du Colombier return 0;
5047dd7cddfSDavid du Colombier }
5057dd7cddfSDavid du Colombier if(memcmp(optmagic, p, 4) != 0) {
506*f27a9a5aSDavid du Colombier fprint(2, "dhcpclient: parse: bad opt magic %ux %ux %ux %ux\n",
507*f27a9a5aSDavid du Colombier p[0], p[1], p[2], p[3]);
5087dd7cddfSDavid du Colombier return 0;
5097dd7cddfSDavid du Colombier }
5107dd7cddfSDavid du Colombier p += 4;
5117dd7cddfSDavid du Colombier n -= 4;
5127dd7cddfSDavid du Colombier while(n>0) {
5137dd7cddfSDavid du Colombier code = *p++;
5147dd7cddfSDavid du Colombier n--;
5157dd7cddfSDavid du Colombier if(code == OBpad)
5167dd7cddfSDavid du Colombier continue;
5177dd7cddfSDavid du Colombier if(code == OBend)
5187dd7cddfSDavid du Colombier return bp;
5197dd7cddfSDavid du Colombier if(n == 0) {
5207dd7cddfSDavid du Colombier fprint(2, "dhcpclient: parse: bad option: %d", code);
5217dd7cddfSDavid du Colombier return 0;
5227dd7cddfSDavid du Colombier }
5237dd7cddfSDavid du Colombier len = *p++;
5247dd7cddfSDavid du Colombier n--;
5257dd7cddfSDavid du Colombier if(len > n) {
5267dd7cddfSDavid du Colombier fprint(2, "dhcpclient: parse: bad option: %d", code);
5277dd7cddfSDavid du Colombier return 0;
5287dd7cddfSDavid du Colombier }
5297dd7cddfSDavid du Colombier p += len;
5307dd7cddfSDavid du Colombier n -= len;
5317dd7cddfSDavid du Colombier }
5327dd7cddfSDavid du Colombier
5337dd7cddfSDavid du Colombier /* fix up nonstandard packets */
5347dd7cddfSDavid du Colombier /* assume there is space */
5357dd7cddfSDavid du Colombier *p = OBend;
5367dd7cddfSDavid du Colombier
5377dd7cddfSDavid du Colombier return bp;
5387dd7cddfSDavid du Colombier }
5397dd7cddfSDavid du Colombier
5407dd7cddfSDavid du Colombier void
bootpdump(uchar * p,int n)5417dd7cddfSDavid du Colombier bootpdump(uchar *p, int n)
5427dd7cddfSDavid du Colombier {
5437dd7cddfSDavid du Colombier int len, i, code;
544*f27a9a5aSDavid du Colombier Bootp *bp;
545*f27a9a5aSDavid du Colombier Udphdr *up;
5467dd7cddfSDavid du Colombier
5477dd7cddfSDavid du Colombier bp = (Bootp*)p;
548*f27a9a5aSDavid du Colombier up = (Udphdr*)bp->udphdr;
5497dd7cddfSDavid du Colombier
5507dd7cddfSDavid du Colombier if(n < bp->optmagic - p) {
5517dd7cddfSDavid du Colombier fprint(2, "dhcpclient: short bootp packet");
5527dd7cddfSDavid du Colombier return;
5537dd7cddfSDavid du Colombier }
5547dd7cddfSDavid du Colombier
555*f27a9a5aSDavid du Colombier fprint(2, "laddr=%I lport=%d raddr=%I rport=%d\n", up->laddr,
556*f27a9a5aSDavid du Colombier nhgets(up->lport), up->raddr, nhgets(up->rport));
557*f27a9a5aSDavid du Colombier fprint(2, "op=%d htype=%d hlen=%d hops=%d\n", bp->op, bp->htype,
558*f27a9a5aSDavid du Colombier bp->hlen, bp->hops);
559*f27a9a5aSDavid du Colombier fprint(2, "xid=%ux secs=%d flags=%ux\n", nhgetl(bp->xid),
560*f27a9a5aSDavid du Colombier nhgets(bp->secs), nhgets(bp->flags));
5617dd7cddfSDavid du Colombier fprint(2, "ciaddr=%V yiaddr=%V siaddr=%V giaddr=%V\n",
5627dd7cddfSDavid du Colombier bp->ciaddr, bp->yiaddr, bp->siaddr, bp->giaddr);
5637dd7cddfSDavid du Colombier fprint(2, "chaddr=");
5647dd7cddfSDavid du Colombier for(i=0; i<16; i++)
5657dd7cddfSDavid du Colombier fprint(2, "%ux ", bp->chaddr[i]);
5667dd7cddfSDavid du Colombier fprint(2, "\n");
5677dd7cddfSDavid du Colombier fprint(2, "sname=%s\n", bp->sname);
5687dd7cddfSDavid du Colombier fprint(2, "file = %s\n", bp->file);
5697dd7cddfSDavid du Colombier
5707dd7cddfSDavid du Colombier n -= bp->optmagic - p;
5717dd7cddfSDavid du Colombier p = bp->optmagic;
5727dd7cddfSDavid du Colombier
5737dd7cddfSDavid du Colombier if(n < 4)
5747dd7cddfSDavid du Colombier return;
5757dd7cddfSDavid du Colombier if(memcmp(optmagic, p, 4) != 0)
576*f27a9a5aSDavid du Colombier fprint(2, "dhcpclient: bad opt magic %ux %ux %ux %ux\n",
577*f27a9a5aSDavid du Colombier p[0], p[1], p[2], p[3]);
5787dd7cddfSDavid du Colombier p += 4;
5797dd7cddfSDavid du Colombier n -= 4;
5807dd7cddfSDavid du Colombier
5817dd7cddfSDavid du Colombier while(n>0) {
5827dd7cddfSDavid du Colombier code = *p++;
5837dd7cddfSDavid du Colombier n--;
5847dd7cddfSDavid du Colombier if(code == OBpad)
5857dd7cddfSDavid du Colombier continue;
5867dd7cddfSDavid du Colombier if(code == OBend)
5877dd7cddfSDavid du Colombier break;
5887dd7cddfSDavid du Colombier if(n == 0) {
5897dd7cddfSDavid du Colombier fprint(2, " bad option: %d", code);
5907dd7cddfSDavid du Colombier return;
5917dd7cddfSDavid du Colombier }
5927dd7cddfSDavid du Colombier len = *p++;
5937dd7cddfSDavid du Colombier n--;
5947dd7cddfSDavid du Colombier if(len > n) {
5957dd7cddfSDavid du Colombier fprint(2, " bad option: %d", code);
5967dd7cddfSDavid du Colombier return;
5977dd7cddfSDavid du Colombier }
5987dd7cddfSDavid du Colombier switch(code) {
5997dd7cddfSDavid du Colombier default:
6007dd7cddfSDavid du Colombier fprint(2, "unknown option %d\n", code);
6017dd7cddfSDavid du Colombier for(i = 0; i<len; i++)
6027dd7cddfSDavid du Colombier fprint(2, "%ux ", p[i]);
6037dd7cddfSDavid du Colombier case ODtype:
6047dd7cddfSDavid du Colombier fprint(2, "DHCP type %d\n", p[0]);
6057dd7cddfSDavid du Colombier break;
6067dd7cddfSDavid du Colombier case ODclientid:
6077dd7cddfSDavid du Colombier fprint(2, "client id=");
6087dd7cddfSDavid du Colombier for(i = 0; i<len; i++)
6097dd7cddfSDavid du Colombier fprint(2, "%ux ", p[i]);
6107dd7cddfSDavid du Colombier fprint(2, "\n");
6117dd7cddfSDavid du Colombier break;
6127dd7cddfSDavid du Colombier case ODlease:
6137dd7cddfSDavid du Colombier fprint(2, "lease=%d\n", nhgetl(p));
6147dd7cddfSDavid du Colombier break;
6157dd7cddfSDavid du Colombier case ODserverid:
6167dd7cddfSDavid du Colombier fprint(2, "server id=%V\n", p);
6177dd7cddfSDavid du Colombier break;
6187dd7cddfSDavid du Colombier case OBmask:
6197dd7cddfSDavid du Colombier fprint(2, "mask=%V\n", p);
6207dd7cddfSDavid du Colombier break;
6217dd7cddfSDavid du Colombier case OBrouter:
6227dd7cddfSDavid du Colombier fprint(2, "router=%V\n", p);
6237dd7cddfSDavid du Colombier break;
6247dd7cddfSDavid du Colombier }
6257dd7cddfSDavid du Colombier p += len;
6267dd7cddfSDavid du Colombier n -= len;
6277dd7cddfSDavid du Colombier }
6287dd7cddfSDavid du Colombier }
6297dd7cddfSDavid du Colombier
6307dd7cddfSDavid du Colombier ulong
thread(void (* f)(void *),void * a)6317dd7cddfSDavid du Colombier thread(void(*f)(void*), void *a)
6327dd7cddfSDavid du Colombier {
6337dd7cddfSDavid du Colombier int pid;
634*f27a9a5aSDavid du Colombier
6357dd7cddfSDavid du Colombier pid = rfork(RFNOWAIT|RFMEM|RFPROC);
6367dd7cddfSDavid du Colombier if(pid < 0)
6377dd7cddfSDavid du Colombier myfatal("rfork failed: %r");
6387dd7cddfSDavid du Colombier if(pid != 0)
6397dd7cddfSDavid du Colombier return pid;
6407dd7cddfSDavid du Colombier (*f)(a);
641*f27a9a5aSDavid du Colombier return 0; /* never reaches here */
6427dd7cddfSDavid du Colombier }
6437dd7cddfSDavid du Colombier
6447dd7cddfSDavid du Colombier void
myfatal(char * fmt,...)6457dd7cddfSDavid du Colombier myfatal(char *fmt, ...)
6467dd7cddfSDavid du Colombier {
6477dd7cddfSDavid du Colombier char buf[1024];
6487dd7cddfSDavid du Colombier va_list arg;
6497dd7cddfSDavid du Colombier
6507dd7cddfSDavid du Colombier va_start(arg, fmt);
6519a747e4fSDavid du Colombier vseprint(buf, buf+sizeof(buf), fmt, arg);
6527dd7cddfSDavid du Colombier va_end(arg);
6537dd7cddfSDavid du Colombier fprint(2, "%s: %s\n", argv0, buf);
6547dd7cddfSDavid du Colombier postnote(PNGROUP, getpid(), "die");
6557dd7cddfSDavid du Colombier exits(buf);
6567dd7cddfSDavid du Colombier }
657