int openlisten(char *net) { int n, fd, cfd; char data[128], devdir[40]; // sprint(data, "%s/udp!*!bootpc", net); sprint(data, "%s/udp!*!68", net); for(n = 0; ; n++) { cfd = announce(data, devdir); if(cfd >= 0) break; /* might be another client - wait and try again */ fprint(2, "dhcpclient: can't announce %s: %r", data); sleep(1000); if(n > 10) myfatal("can't announce: giving up: %r"); } if(fprint(cfd, "headers") < 0) myfatal("can't set header mode: %r"); sprint(data, "%s/data", devdir); fd = open(data, ORDWR); if(fd < 0) myfatal("open %s: %r", data); close(cfd); return fd; }
void dhcpsend(int type) { int n; uint8_t *p; Bootp bp; Udphdr *up; memset(&bp, 0, sizeof bp); up = (Udphdr*)bp.udphdr; hnputs(up->rport, 67); bp.op = Bootrequest; hnputl(bp.xid, dhcp.xid); hnputs(bp.secs, time(0) - dhcp.starttime); hnputs(bp.flags, Fbroadcast); /* reply must be broadcast */ memmove(bp.optmagic, optmagic, 4); p = bp.optdata; p = optaddbyte(p, ODtype, type); p = optadd(p, ODclientid, dhcp.cid, strlen(dhcp.cid)); switch(type) { default: myfatal("dhcpsend: unknown message type: %d", type); case Discover: ipmove(up->raddr, IPv4bcast); /* broadcast */ break; case Request: if(dhcp.state == Sbound || dhcp.state == Srenewing) ipmove(up->raddr, dhcp.server); else ipmove(up->raddr, IPv4bcast); /* broadcast */ p = optaddulong(p, ODlease, dhcp.lease); if(dhcp.state == Sselecting || dhcp.state == Srequesting) { p = optaddaddr(p, ODipaddr, dhcp.client); /* mistake?? */ p = optaddaddr(p, ODserverid, dhcp.server); } else v6tov4(bp.ciaddr, dhcp.client); break; case Release: ipmove(up->raddr, dhcp.server); v6tov4(bp.ciaddr, dhcp.client); p = optaddaddr(p, ODipaddr, dhcp.client); p = optaddaddr(p, ODserverid, dhcp.server); break; } *p++ = OBend; n = p - (uint8_t*)&bp; if(write(dhcp.fd, &bp, n) != n) myfatal("dhcpsend: write failed: %r"); }
void timerthread(void* v) { for(;;) { sleep(1000); qlock(&dhcp.lk); if(--dhcp.timeout > 0) { qunlock(&dhcp.lk); continue; } switch(dhcp.state) { default: myfatal("timerthread: unknown state %d", dhcp.state); case Sinit: break; case Sselecting: dhcpsend(Discover); dhcp.timeout = 4; dhcp.resend++; if(dhcp.resend>5) myfatal("dhcp: giving up: selecting"); break; case Srequesting: dhcpsend(Request); dhcp.timeout = 4; dhcp.resend++; if(dhcp.resend>5) myfatal("dhcp: giving up: requesting"); break; case Srenewing: dhcpsend(Request); dhcp.timeout = 1; dhcp.resend++; if(dhcp.resend>3) { dhcp.state = Srebinding; dhcp.resend = 0; } break; case Srebinding: dhcpsend(Request); dhcp.timeout = 4; dhcp.resend++; if(dhcp.resend>5) myfatal("dhcp: giving up: rebinding"); break; case Sbound: break; } qunlock(&dhcp.lk); } }
void *myrealloc(void *ptr, int size) { assert(size >= 0 && ptr); void *p = realloc(ptr, size); if(!p) { myfatal("out of memory"); } return p; }
void *mymalloc(int size) { assert(size >= 0); void *p = malloc(size); if(!p) { myfatal("out of memory"); } return p; }
uint32_t thread(void(*f)(void*), void *a) { int pid; pid = rfork(RFNOWAIT|RFMEM|RFPROC); if(pid < 0) myfatal("rfork failed: %r"); if(pid != 0) return pid; (*f)(a); return 0; /* never reaches here */ }
void dhcprecv(void) { uint8_t buf[2000]; Bootp *bp; int n, type; uint32_t lease; uint8_t mask[IPaddrlen]; qunlock(&dhcp.lk); n = read(dhcp.fd, buf, sizeof(buf)); qlock(&dhcp.lk); if(n <= 0) myfatal("dhcprecv: bad read: %r"); bp = parse(buf, n); if(bp == 0) return; if(1) { fprint(2, "recved\n"); bootpdump(buf, n); } type = optgetbyte(bp, ODtype); switch(type) { default: fprint(2, "dhcprecv: unknown type: %d\n", type); break; case Offer: if(dhcp.state != Sselecting) break; lease = optgetulong(bp, ODlease); if(lease == 0) myfatal("bad lease"); if(!optgetaddr(bp, OBmask, mask)) memset(mask, 0xff, sizeof(mask)); v4tov6(dhcp.client, bp->yiaddr); if(!optgetaddr(bp, ODserverid, dhcp.server)) { fprint(2, "dhcprecv: Offer from server with invalid serverid\n"); break; } dhcp.lease = lease; ipmove(dhcp.mask, mask); memmove(dhcp.sname, bp->sname, sizeof(dhcp.sname)); dhcp.sname[sizeof(dhcp.sname)-1] = 0; dhcpsend(Request); dhcp.state = Srequesting; dhcp.resend = 0; dhcp.timeout = 4; break; case Ack: if(dhcp.state != Srequesting) if(dhcp.state != Srenewing) if(dhcp.state != Srebinding) break; lease = optgetulong(bp, ODlease); if(lease == 0) myfatal("bad lease"); if(!optgetaddr(bp, OBmask, mask)) memset(mask, 0xff, sizeof(mask)); v4tov6(dhcp.client, bp->yiaddr); dhcp.lease = lease; ipmove(dhcp.mask, mask); dhcp.state = Sbound; break; case Nak: myfatal("recved nak"); break; } }