1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include <bio.h> 5 #include <ndb.h> 6 #include "dat.h" 7 8 // 9 // ala rfc2131 10 // 11 12 typedef struct Req Req; 13 struct Req 14 { 15 int fd; /* for reply */ 16 Bootp *bp; 17 Udphdr *up; 18 uchar *e; /* end of received message */ 19 uchar *p; /* options pointer */ 20 uchar *max; /* max end of reply */ 21 22 /* expanded to v6 */ 23 uchar ciaddr[IPaddrlen]; 24 uchar giaddr[IPaddrlen]; 25 26 /* parsed options */ 27 int p9request; /* true if this is a bootp with plan9 options */ 28 int genrequest; /* true if this is a bootp with generic options */ 29 int dhcptype; /* dhcp message type */ 30 int leasetime; /* dhcp lease */ 31 uchar ip[IPaddrlen]; /* requested address */ 32 uchar server[IPaddrlen]; /* server address */ 33 char msg[ERRMAX]; /* error message */ 34 char vci[32]; /* vendor class id */ 35 char *id; /* client id */ 36 uchar requested[32]; /* requested params */ 37 uchar vendorclass[32]; 38 char cputype[32-3]; 39 40 Info gii; /* about target network */ 41 Info ii; /* about target system */ 42 int staticbinding; 43 44 uchar buf[2*1024]; /* message buffer */ 45 }; 46 47 #define TFTP "/lib/tftpd" 48 char *blog = "ipboot"; 49 char mysysname[64]; 50 Ipifc *ipifcs; 51 int debug; 52 int nobootp; 53 long now; 54 int slow; 55 char net[256]; 56 57 int pptponly; // only answer request that came from the pptp server 58 int mute; 59 int minlease = MinLease; 60 61 ulong start; 62 63 /* option magic */ 64 char plan9opt[4] = { 'p', '9', ' ', ' ' }; 65 char genericopt[4] = { 0x63, 0x82, 0x53, 0x63 }; 66 67 /* well known addresses */ 68 uchar zeros[Maxhwlen]; 69 70 /* option debug buffer */ 71 char optbuf[1024]; 72 char *op; 73 char *oe = optbuf + sizeof(optbuf); 74 75 char *optname[256] = 76 { 77 [OBend] "end", 78 [OBpad] "pad", 79 [OBmask] "mask", 80 [OBtimeoff] "timeoff", 81 [OBrouter] "router", 82 [OBtimeserver] "time", 83 [OBnameserver] "name", 84 [OBdnserver] "dns", 85 [OBlogserver] "log", 86 [OBcookieserver] "cookie", 87 [OBlprserver] "lpr", 88 [OBimpressserver] "impress", 89 [OBrlserver] "rl", 90 [OBhostname] "host", 91 [OBbflen] "bflen", 92 [OBdumpfile] "dumpfile", 93 [OBdomainname] "dom", 94 [OBswapserver] "swap", 95 [OBrootpath] "rootpath", 96 [OBextpath] "extpath", 97 [OBipforward] "ipforward", 98 [OBnonlocal] "nonlocal", 99 [OBpolicyfilter] "policyfilter", 100 [OBmaxdatagram] "maxdatagram", 101 [OBttl] "ttl", 102 [OBpathtimeout] "pathtimeout", 103 [OBpathplateau] "pathplateau", 104 [OBmtu] "mtu", 105 [OBsubnetslocal] "subnetslocal", 106 [OBbaddr] "baddr", 107 [OBdiscovermask] "discovermask", 108 [OBsupplymask] "supplymask", 109 [OBdiscoverrouter] "discoverrouter", 110 [OBrsserver] "rsserver", 111 [OBstaticroutes] "staticroutes", 112 [OBtrailerencap] "trailerencap", 113 [OBarptimeout] "arptimeout", 114 [OBetherencap] "etherencap", 115 [OBtcpttl] "tcpttl", 116 [OBtcpka] "tcpka", 117 [OBtcpkag] "tcpkag", 118 [OBnisdomain] "nisdomain", 119 [OBniserver] "niserver", 120 [OBntpserver] "ntpserver", 121 [OBvendorinfo] "vendorinfo", 122 [OBnetbiosns] "NBns", 123 [OBnetbiosdds] "NBdds", 124 [OBnetbiostype] "NBtype", 125 [OBnetbiosscope] "NBscope", 126 [OBxfontserver] "xfont", 127 [OBxdispmanager] "xdisp", 128 [OBnisplusdomain] "NPdomain", 129 [OBnisplusserver] "NP", 130 [OBhomeagent] "homeagent", 131 [OBsmtpserver] "smtp", 132 [OBpop3server] "pop3", 133 [OBnntpserver] "nntp", 134 [OBwwwserver] "www", 135 [OBfingerserver] "finger", 136 [OBircserver] "ircserver", 137 [OBstserver] "stserver", 138 [OBstdaserver] "stdaserver", 139 140 /* dhcp options */ 141 [ODipaddr] "ip", 142 [ODlease] "leas", 143 [ODoverload] "overload", 144 [ODtype] "typ", 145 [ODserverid] "sid", 146 [ODparams] "params", 147 [ODmessage] "message", 148 [ODmaxmsg] "maxmsg", 149 [ODrenewaltime] "renewaltime", 150 [ODrebindingtime] "rebindingtime", 151 [ODvendorclass] "vendorclass", 152 [ODclientid] "cid", 153 [ODtftpserver] "tftpserver", 154 [ODbootfile] "bf", 155 }; 156 157 void addropt(Req*, int, uchar*); 158 void addrsopt(Req*, int, uchar**, int); 159 void arpenter(uchar*, uchar*); 160 void bootp(Req*); 161 void byteopt(Req*, int, uchar); 162 void dhcp(Req*); 163 void fatal(int, char*, ...); 164 void hexopt(Req*, int, char*); 165 void longopt(Req*, int, long); 166 void maskopt(Req*, int, uchar*); 167 void miscoptions(Req*, uchar*); 168 int openlisten(char *net); 169 void parseoptions(Req*); 170 void proto(Req*, int); 171 void rcvdecline(Req*); 172 void rcvdiscover(Req*); 173 void rcvinform(Req*); 174 void rcvrelease(Req*); 175 void rcvrequest(Req*); 176 char* readsysname(void); 177 void remrequested(Req*, int); 178 void sendack(Req*, uchar*, int, int); 179 void sendnak(Req*, char*); 180 void sendoffer(Req*, uchar*, int); 181 void stringopt(Req*, int, char*); 182 void termopt(Req*); 183 int validip(uchar*); 184 void vectoropt(Req*, int, uchar*, int); 185 void warning(int, char*, ...); 186 void logdhcp(Req*); 187 void logdhcpout(Req *, char *); 188 int readlast(int, uchar*, int); 189 190 void 191 timestamp(char *tag) 192 { 193 ulong t; 194 195 t = nsec()/1000; 196 syslog(0, blog, "%s %lud", tag, t - start); 197 } 198 199 void 200 usage(void) 201 { 202 fprint(2, "usage: dhcp [-dmsnp] [-f directory] [-x netmtpt] [-M minlease] addr n [addr n ...]\n"); 203 exits("usage"); 204 } 205 206 void 207 main(int argc, char **argv) 208 { 209 int i, n, fd; 210 char *p; 211 uchar ip[IPaddrlen]; 212 Req r; 213 214 setnetmtpt(net, sizeof(net), nil); 215 216 fmtinstall('E', eipfmt); 217 fmtinstall('I', eipfmt); 218 fmtinstall('V', eipfmt); 219 fmtinstall('M', eipfmt); 220 ARGBEGIN { 221 case 'm': 222 mute = 1; 223 break; 224 case 'd': 225 debug = 1; 226 break; 227 case 'f': 228 p = ARGF(); 229 if(p == nil) 230 usage(); 231 ndbfile = p; 232 break; 233 case 's': 234 slow = 1; 235 break; 236 case 'n': 237 nobootp = 1; 238 break; 239 case 'p': 240 pptponly = 1; 241 break; 242 case 'x': 243 p = ARGF(); 244 if(p == nil) 245 usage(); 246 setnetmtpt(net, sizeof(net), p); 247 break; 248 case 'M': 249 p = ARGF(); 250 if(p == nil) 251 usage(); 252 minlease = atoi(p); 253 if(minlease <= 0) 254 minlease = MinLease; 255 break; 256 } ARGEND; 257 258 while(argc > 1){ 259 parseip(ip, argv[0]); 260 if(!validip(ip)) 261 usage(); 262 n = atoi(argv[1]); 263 if(n <= 0) 264 usage(); 265 initbinding(ip, n); 266 argc -= 2; 267 argv += 2; 268 } 269 270 /* for debugging */ 271 for(i = 0; i < 256; i++) 272 if(optname[i] == 0) 273 optname[i] = smprint("%d", i); 274 275 /* what is my name? */ 276 p = readsysname(); 277 strcpy(mysysname, p); 278 279 /* put process in background */ 280 if(!debug) switch(rfork(RFNOTEG|RFPROC|RFFDG)) { 281 case -1: 282 fatal(1, "fork"); 283 case 0: 284 break; 285 default: 286 exits(0); 287 } 288 289 chdir(TFTP); 290 fd = openlisten(net); 291 292 for(;;){ 293 memset(&r, 0, sizeof(r)); 294 r.fd = fd; 295 n = readlast(r.fd, r.buf, sizeof(r.buf)); 296 if(n < Udphdrsize) 297 fatal(1, "error reading requests"); 298 start = nsec()/1000; 299 op = optbuf; 300 *op = 0; 301 proto(&r, n); 302 if(r.id != nil) 303 free(r.id); 304 } 305 } 306 307 void 308 proto(Req *rp, int n) 309 { 310 uchar relip[IPaddrlen]; 311 char buf[64]; 312 313 now = time(0); 314 315 rp->e = rp->buf + n; 316 rp->bp = (Bootp*)rp->buf; 317 rp->up = (Udphdr*)rp->buf; 318 rp->max = rp->buf + Udphdrsize + MINSUPPORTED - IPUDPHDRSIZE; 319 rp->p = rp->bp->optdata; 320 v4tov6(rp->giaddr, rp->bp->giaddr); 321 v4tov6(rp->ciaddr, rp->bp->ciaddr); 322 323 if(pptponly && rp->bp->htype != 0) 324 return; 325 326 ipifcs = readipifc(net, ipifcs, -1); 327 if(validip(rp->giaddr)) 328 ipmove(relip, rp->giaddr); 329 else if(validip(rp->up->raddr)) 330 ipmove(relip, rp->up->raddr); 331 else 332 ipmove(relip, rp->up->laddr); 333 if(rp->e < (uchar*)rp->bp->sname){ 334 warning(0, "packet too short"); 335 return; 336 } 337 if(rp->bp->op != Bootrequest){ 338 warning(0, "not bootrequest"); 339 return; 340 } 341 342 if(rp->e >= rp->bp->optdata){ 343 if(memcmp(rp->bp->optmagic, plan9opt, sizeof(rp->bp->optmagic)) == 0) 344 rp->p9request = 1; 345 if(memcmp(rp->bp->optmagic, genericopt, sizeof(rp->bp->optmagic)) == 0) { 346 rp->genrequest = 1; 347 parseoptions(rp); 348 } 349 } 350 rp->p = rp->bp->optdata; 351 352 /* If no id is specified, make one from the hardware address 353 * of the target. We assume all zeros is not a hardware address 354 * which could be a mistake. 355 */ 356 if(rp->id == nil){ 357 if(rp->bp->hlen > Maxhwlen){ 358 warning(0, "hlen %d", rp->bp->hlen); 359 return; 360 } 361 if(memcmp(zeros, rp->bp->chaddr, rp->bp->hlen) == 0){ 362 warning(0, "no chaddr"); 363 return; 364 } 365 sprint(buf, "hwa%2.2ux_", rp->bp->htype); 366 rp->id = tohex(buf, rp->bp->chaddr, rp->bp->hlen); 367 } 368 369 /* info about gateway */ 370 if(lookupip(relip, &rp->gii, 1) < 0){ 371 warning(0, "lookupip failed"); 372 return; 373 } 374 375 /* info about target system */ 376 if(lookup(rp->bp, &rp->ii, &rp->gii) == 0) 377 if(rp->ii.indb && rp->ii.dhcpgroup[0] == 0) 378 rp->staticbinding = 1; 379 380 if(rp->dhcptype) 381 dhcp(rp); 382 else 383 bootp(rp); 384 timestamp("done"); 385 } 386 387 void 388 dhcp(Req *rp) 389 { 390 logdhcp(rp); 391 392 switch(rp->dhcptype){ 393 case Discover: 394 if(slow) 395 sleep(500); 396 rcvdiscover(rp); 397 break; 398 case Request: 399 rcvrequest(rp); 400 break; 401 case Decline: 402 rcvdecline(rp); 403 break; 404 case Release: 405 rcvrelease(rp); 406 break; 407 case Inform: 408 rcvinform(rp); 409 break; 410 } 411 } 412 413 void 414 rcvdiscover(Req *rp) 415 { 416 Binding *b, *nb; 417 418 if(rp->staticbinding){ 419 sendoffer(rp, rp->ii.ipaddr, StaticLease); 420 return; 421 } 422 423 /* 424 * first look for an outstanding offer 425 */ 426 b = idtooffer(rp->id, &rp->gii); 427 428 /* 429 * rfc2131 says: 430 * If an address is available, the new address 431 * SHOULD be chosen as follows: 432 * 433 * o The client's current address as recorded in the client's current 434 * binding, ELSE 435 * 436 * o The client's previous address as recorded in the client's (now 437 * expired or released) binding, if that address is in the server's 438 * pool of available addresses and not already allocated, ELSE 439 * 440 * o The address requested in the 'Requested IP Address' option, if that 441 * address is valid and not already allocated, ELSE 442 * 443 * o A new address allocated from the server's pool of available 444 * addresses; the address is selected based on the subnet from which 445 * the message was received (if 'giaddr' is 0) or on the address of 446 * the relay agent that forwarded the message ('giaddr' when not 0). 447 */ 448 if(b == nil){ 449 b = idtobinding(rp->id, &rp->gii, 1); 450 if(b && b->boundto && strcmp(b->boundto, rp->id) != 0) 451 if(validip(rp->ip) && samenet(rp->ip, &rp->gii)){ 452 nb = iptobinding(rp->ip, 0); 453 if(nb && nb->lease < now) 454 b = nb; 455 } 456 } 457 if(b == nil){ 458 warning(0, "!Discover(%s via %I): no binding %I", 459 rp->id, rp->gii.ipaddr, rp->ip); 460 return; 461 } 462 mkoffer(b, rp->id, rp->leasetime); 463 sendoffer(rp, b->ip, b->offer); 464 } 465 466 void 467 rcvrequest(Req *rp) 468 { 469 Binding *b; 470 471 if(validip(rp->server)){ 472 /* this is a reply to an offer - SELECTING */ 473 474 /* check for hard assignment */ 475 if(rp->staticbinding){ 476 if(forme(rp->server)) 477 sendack(rp, rp->ii.ipaddr, StaticLease, 1); 478 else 479 warning(0, "!Request(%s via %I): for server %I not me", 480 rp->id, rp->gii.ipaddr, rp->server); 481 return; 482 } 483 484 b = idtooffer(rp->id, &rp->gii); 485 486 /* if we don't have an offer, nak */ 487 if(b == nil){ 488 warning(0, "!Request(%s via %I): no offer", 489 rp->id, rp->gii.ipaddr); 490 if(forme(rp->server)) 491 sendnak(rp, "no offer for you"); 492 return; 493 } 494 495 /* if not for me, retract offer */ 496 if(!forme(rp->server)){ 497 b->expoffer = 0; 498 warning(0, "!Request(%s via %I): for server %I not me", 499 rp->id, rp->gii.ipaddr, rp->server); 500 return; 501 } 502 503 /* 504 * if the client is confused about what we offered, nak. 505 * client really shouldn't be specifying this when selecting 506 */ 507 if(validip(rp->ip) && ipcmp(rp->ip, b->ip) != 0){ 508 warning(0, "!Request(%s via %I): requests %I, not %I", 509 rp->id, rp->gii.ipaddr, rp->ip, b->ip); 510 sendnak(rp, "bad ip address option"); 511 return; 512 } 513 if(commitbinding(b) < 0){ 514 warning(0, "!Request(%s via %I): can't commit %I", 515 rp->id, rp->gii.ipaddr, b->ip); 516 sendnak(rp, "can't commit binding"); 517 return; 518 } 519 sendack(rp, b->ip, b->offer, 1); 520 } else if(validip(rp->ip)){ 521 /* 522 * checking address/net - INIT-REBOOT 523 * 524 * This is a rebooting client that remembers its old 525 * address. 526 */ 527 /* check for hard assignment */ 528 if(rp->staticbinding){ 529 if(memcmp(rp->ip, rp->ii.ipaddr, IPaddrlen) != 0){ 530 warning(0, "!Request(%s via %I): %I not valid for %E", 531 rp->id, rp->gii.ipaddr, rp->ip, rp->bp->chaddr); 532 sendnak(rp, "not valid"); 533 } 534 sendack(rp, rp->ii.ipaddr, StaticLease, 1); 535 return; 536 } 537 538 /* make sure the network makes sense */ 539 if(!samenet(rp->ip, &rp->gii)){ 540 warning(0, "!Request(%s via %I): bad forward of %I", 541 rp->id, rp->gii.ipaddr, rp->ip); 542 sendnak(rp, "wrong network"); 543 return; 544 } 545 b = iptobinding(rp->ip, 0); 546 if(b == nil){ 547 warning(0, "!Request(%s via %I): no binding for %I for", 548 rp->id, rp->gii.ipaddr, rp->ip); 549 return; 550 } 551 if(memcmp(rp->ip, b->ip, IPaddrlen) != 0 || now > b->lease){ 552 warning(0, "!Request(%s via %I): %I not valid", 553 rp->id, rp->gii.ipaddr, rp->ip); 554 sendnak(rp, "not valid"); 555 return; 556 } 557 b->offer = b->lease - now; 558 sendack(rp, b->ip, b->offer, 1); 559 } else if(validip(rp->ciaddr)){ 560 /* 561 * checking address - RENEWING or REBINDING 562 * 563 * these states are indistinguishable in our action. The only 564 * difference is how close to lease expiration the client is. 565 * If it is really close, it broadcasts the request hoping that 566 * some server will answer. 567 */ 568 569 /* check for hard assignment */ 570 if(rp->staticbinding){ 571 if(ipcmp(rp->ciaddr, rp->ii.ipaddr) != 0){ 572 warning(0, "!Request(%s via %I): %I not valid", 573 rp->id, rp->gii.ipaddr, rp->ciaddr); 574 sendnak(rp, "not valid"); 575 } 576 sendack(rp, rp->ii.ipaddr, StaticLease, 1); 577 return; 578 } 579 580 /* make sure the network makes sense */ 581 if(!samenet(rp->ciaddr, &rp->gii)){ 582 warning(0, "!Request(%s via %I): bad forward of %I", 583 rp->id, rp->gii.ipaddr, rp->ip); 584 sendnak(rp, "wrong network"); 585 return; 586 } 587 b = iptobinding(rp->ciaddr, 0); 588 if(b == nil){ 589 warning(0, "!Request(%s via %I): no binding for %I", 590 rp->id, rp->gii.ipaddr, rp->ciaddr); 591 return; 592 } 593 if(ipcmp(rp->ciaddr, b->ip) != 0){ 594 warning(0, "!Request(%I via %s): %I not valid", 595 rp->id, rp->gii.ipaddr, rp->ciaddr); 596 sendnak(rp, "invalid ip address"); 597 return; 598 } 599 mkoffer(b, rp->id, rp->leasetime); 600 if(commitbinding(b) < 0){ 601 warning(0, "!Request(%s via %I): can't commit %I", 602 rp->id, rp->gii.ipaddr, b->ip); 603 sendnak(rp, "can't commit binding"); 604 return; 605 } 606 sendack(rp, b->ip, b->offer, 1); 607 } 608 } 609 610 void 611 rcvdecline(Req *rp) 612 { 613 Binding *b; 614 char buf[64]; 615 616 if(rp->staticbinding) 617 return; 618 619 b = idtooffer(rp->id, &rp->gii); 620 if(b == nil){ 621 warning(0, "!Decline(%s via %I): no binding", 622 rp->id, rp->gii.ipaddr); 623 return; 624 } 625 626 /* mark ip address as in use */ 627 snprint(buf, sizeof(buf), "declined by %s", rp->id); 628 mkoffer(b, buf, 0x7fffffff); 629 commitbinding(b); 630 } 631 632 void 633 rcvrelease(Req *rp) 634 { 635 Binding *b; 636 637 if(rp->staticbinding) 638 return; 639 640 b = idtobinding(rp->id, &rp->gii, 0); 641 if(b == nil){ 642 warning(0, "!Release(%s via %I): no binding", 643 rp->id, rp->gii.ipaddr); 644 return; 645 } 646 if(strcmp(rp->id, b->boundto) != 0){ 647 warning(0, "!Release(%s via %I): invalid release of %I", 648 rp->id, rp->gii.ipaddr, rp->ip); 649 return; 650 } 651 warning(0, "Release(%s via %I): releasing %I", b->boundto, rp->gii.ipaddr, b->ip); 652 if(releasebinding(b, rp->id) < 0) 653 warning(0, "release: couldn't release"); 654 } 655 656 void 657 rcvinform(Req *rp) 658 { 659 Binding *b; 660 661 if(rp->staticbinding){ 662 sendack(rp, rp->ii.ipaddr, 0, 0); 663 return; 664 } 665 666 b = iptobinding(rp->ciaddr, 0); 667 if(b == nil){ 668 warning(0, "!Inform(%s via %I): no binding for %I", 669 rp->id, rp->gii.ipaddr, rp->ip); 670 return; 671 } 672 sendack(rp, b->ip, 0, 0); 673 } 674 675 int 676 setsiaddr(uchar *siaddr, uchar *saddr, uchar *laddr) 677 { 678 if(ipcmp(saddr, IPnoaddr) != 0){ 679 v6tov4(siaddr, saddr); 680 return 0; 681 } else { 682 v6tov4(siaddr, laddr); 683 return 1; 684 } 685 } 686 687 void 688 sendoffer(Req *rp, uchar *ip, int offer) 689 { 690 int n; 691 ushort flags; 692 Bootp *bp; 693 Udphdr *up; 694 695 bp = rp->bp; 696 up = rp->up; 697 698 /* 699 * set destination 700 */ 701 flags = nhgets(bp->flags); 702 if(validip(rp->giaddr)){ 703 ipmove(up->raddr, rp->giaddr); 704 hnputs(up->rport, 67); 705 } else if(flags & Fbroadcast){ 706 ipmove(up->raddr, IPv4bcast); 707 hnputs(up->rport, 68); 708 } else { 709 ipmove(up->raddr, ip); 710 if(bp->htype == 1) 711 arpenter(up->raddr, bp->chaddr); 712 hnputs(up->rport, 68); 713 } 714 715 /* 716 * fill in standard bootp part 717 */ 718 bp->op = Bootreply; 719 bp->hops = 0; 720 hnputs(bp->secs, 0); 721 memset(bp->ciaddr, 0, sizeof(bp->ciaddr)); 722 v6tov4(bp->giaddr, rp->giaddr); 723 v6tov4(bp->yiaddr, ip); 724 setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr); 725 strncpy(bp->sname, mysysname, sizeof(bp->sname)); 726 strncpy(bp->file, rp->ii.bootf, sizeof(bp->file)); 727 728 /* 729 * set options 730 */ 731 byteopt(rp, ODtype, Offer); 732 longopt(rp, ODlease, offer); 733 addropt(rp, ODserverid, up->laddr); 734 miscoptions(rp, ip); 735 termopt(rp); 736 737 logdhcpout(rp, "Offer"); 738 739 /* 740 * send 741 */ 742 n = rp->p - rp->buf; 743 if(!mute && write(rp->fd, rp->buf, n) != n) 744 warning(0, "offer: write failed: %r"); 745 } 746 747 void 748 sendack(Req *rp, uchar *ip, int offer, int sendlease) 749 { 750 int n; 751 ushort flags; 752 Bootp *bp; 753 Udphdr *up; 754 755 bp = rp->bp; 756 up = rp->up; 757 758 /* 759 * set destination 760 */ 761 flags = nhgets(bp->flags); 762 if(validip(rp->giaddr)){ 763 ipmove(up->raddr, rp->giaddr); 764 hnputs(up->rport, 67); 765 } else if(flags & Fbroadcast){ 766 ipmove(up->raddr, IPv4bcast); 767 hnputs(up->rport, 68); 768 } else { 769 ipmove(up->raddr, ip); 770 if(bp->htype == 1) 771 arpenter(up->raddr, bp->chaddr); 772 hnputs(up->rport, 68); 773 } 774 775 /* 776 * fill in standard bootp part 777 */ 778 bp->op = Bootreply; 779 bp->hops = 0; 780 hnputs(bp->secs, 0); 781 v6tov4(bp->giaddr, rp->giaddr); 782 v6tov4(bp->yiaddr, ip); 783 setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr); 784 strncpy(bp->sname, mysysname, sizeof(bp->sname)); 785 strncpy(bp->file, rp->ii.bootf, sizeof(bp->file)); 786 787 /* 788 * set options 789 */ 790 byteopt(rp, ODtype, Ack); 791 if(sendlease){ 792 longopt(rp, ODlease, offer); 793 } 794 addropt(rp, ODserverid, up->laddr); 795 miscoptions(rp, ip); 796 termopt(rp); 797 798 logdhcpout(rp, "Ack"); 799 800 /* 801 * send 802 */ 803 n = rp->p - rp->buf; 804 if(!mute && write(rp->fd, rp->buf, n) != n) 805 warning(0, "ack: write failed: %r"); 806 } 807 808 void 809 sendnak(Req *rp, char *msg) 810 { 811 int n; 812 Bootp *bp; 813 Udphdr *up; 814 815 bp = rp->bp; 816 up = rp->up; 817 818 /* 819 * set destination (always broadcast) 820 */ 821 if(validip(rp->giaddr)){ 822 ipmove(up->raddr, rp->giaddr); 823 hnputs(up->rport, 67); 824 } else { 825 ipmove(up->raddr, IPv4bcast); 826 hnputs(up->rport, 68); 827 } 828 829 /* 830 * fill in standard bootp part 831 */ 832 bp->op = Bootreply; 833 bp->hops = 0; 834 hnputs(bp->secs, 0); 835 v6tov4(bp->giaddr, rp->giaddr); 836 memset(bp->ciaddr, 0, sizeof(bp->ciaddr)); 837 memset(bp->yiaddr, 0, sizeof(bp->yiaddr)); 838 memset(bp->siaddr, 0, sizeof(bp->siaddr)); 839 840 /* 841 * set options 842 */ 843 byteopt(rp, ODtype, Nak); 844 addropt(rp, ODserverid, up->laddr); 845 if(msg) 846 stringopt(rp, ODmessage, msg); 847 if(strncmp(rp->id, "id", 2) == 0) 848 hexopt(rp, ODclientid, rp->id+2); 849 termopt(rp); 850 851 logdhcpout(rp, "Nak"); 852 853 /* 854 * send nak 855 */ 856 n = rp->p - rp->buf; 857 if(!mute && write(rp->fd, rp->buf, n) != n) 858 warning(0, "nak: write failed: %r"); 859 } 860 861 void 862 bootp(Req *rp) 863 { 864 int n; 865 Bootp *bp; 866 Udphdr *up; 867 ushort flags; 868 Iplifc *lifc; 869 Info *iip; 870 871 warning(0, "bootp %s %I->%I from %s via %I", 872 rp->genrequest ? "generic" : (rp->p9request ? "p9" : ""), 873 rp->up->raddr, rp->up->laddr, 874 rp->id, rp->gii.ipaddr); 875 876 if(nobootp) 877 return; 878 879 bp = rp->bp; 880 up = rp->up; 881 iip = &rp->ii; 882 883 if(rp->staticbinding == 0){ 884 warning(0, "bootp from unknown %s via %I", rp->id, rp->gii.ipaddr); 885 return; 886 } 887 888 /* ignore if not for us */ 889 if(*bp->sname){ 890 if(strcmp(bp->sname, mysysname) != 0){ 891 bp->sname[20] = 0; 892 warning(0, "bootp for server %s", bp->sname); 893 return; 894 } 895 } else if(slow) 896 sleep(500); 897 898 /* ignore if we don't know what file to load */ 899 if(*bp->file == 0){ 900 if(rp->genrequest && *iip->bootf2) /* if not plan 9 and we have an alternate file... */ 901 strncpy(bp->file, iip->bootf2, sizeof(bp->file)); 902 else if(*iip->bootf) 903 strncpy(bp->file, iip->bootf, sizeof(bp->file)); 904 else if(*bp->sname) /* if we were asked, respond no matter what */ 905 bp->file[0] = '\0'; 906 else { 907 warning(0, "no bootfile for %I", iip->ipaddr); 908 return; 909 } 910 } 911 912 /* ignore if the file is unreadable */ 913 if((!rp->genrequest) && bp->file[0] && access(bp->file, 4) < 0){ 914 warning(0, "inaccessible bootfile1 %s", bp->file); 915 return; 916 } 917 918 bp->op = Bootreply; 919 v6tov4(bp->yiaddr, iip->ipaddr); 920 if(rp->p9request){ 921 warning(0, "p9bootp: %I", iip->ipaddr); 922 memmove(bp->optmagic, plan9opt, 4); 923 if(iip->gwip == 0) 924 v4tov6(iip->gwip, bp->giaddr); 925 rp->p += sprint((char*)rp->p, "%V %I %I %I", iip->ipmask+IPv4off, iip->fsip, 926 iip->auip, iip->gwip); 927 sprint(optbuf, "%s", (char*)(bp->optmagic)); 928 } else if(rp->genrequest){ 929 warning(0, "genericbootp: %I", iip->ipaddr); 930 memmove(bp->optmagic, genericopt, 4); 931 miscoptions(rp, iip->ipaddr); 932 termopt(rp); 933 } else if(iip->vendor[0] != 0) { 934 warning(0, "bootp vendor field: %s", iip->vendor); 935 memset(rp->p, 0, 128-4); 936 rp->p += sprint((char*)bp->optmagic, "%s", iip->vendor); 937 } else { 938 memset(rp->p, 0, 128-4); 939 rp->p += 128-4; 940 } 941 942 /* 943 * set destination 944 */ 945 flags = nhgets(bp->flags); 946 if(validip(rp->giaddr)){ 947 ipmove(up->raddr, rp->giaddr); 948 hnputs(up->rport, 67); 949 } else if(flags & Fbroadcast){ 950 ipmove(up->raddr, IPv4bcast); 951 hnputs(up->rport, 68); 952 } else { 953 v4tov6(up->raddr, bp->yiaddr); 954 if(bp->htype == 1) 955 arpenter(up->raddr, bp->chaddr); 956 hnputs(up->rport, 68); 957 } 958 959 /* 960 * select best local address if destination is directly connected 961 */ 962 lifc = findlifc(up->raddr); 963 if(lifc) 964 ipmove(up->laddr, lifc->ip); 965 966 /* 967 * our identity 968 */ 969 strncpy(bp->sname, mysysname, sizeof(bp->sname)); 970 971 /* 972 * set tftp server 973 */ 974 setsiaddr(bp->siaddr, iip->tftp, up->laddr); 975 if(rp->genrequest && *iip->bootf2) 976 setsiaddr(bp->siaddr, iip->tftp2, up->laddr); 977 978 /* 979 * RFC 1048 says that we must pad vendor field with 980 * zeros until we have a 64 byte field. 981 */ 982 n = rp->p - rp->bp->optdata; 983 if(n < 64-4) { 984 memset(rp->p, 0, (64-4)-n); 985 rp->p += (64-4)-n; 986 } 987 988 /* 989 * send 990 */ 991 n = rp->p - rp->buf; 992 if(!mute && write(rp->fd, rp->buf, n) != n) 993 warning(0, "bootp: write failed: %r"); 994 995 warning(0, "bootp via %I: file %s xid(%ux)flag(%ux)ci(%V)gi(%V)yi(%V)si(%V) %s", 996 up->raddr, bp->file, nhgetl(bp->xid), nhgets(bp->flags), 997 bp->ciaddr, bp->giaddr, bp->yiaddr, bp->siaddr, 998 optbuf); 999 } 1000 1001 void 1002 parseoptions(Req *rp) 1003 { 1004 int n, c, code; 1005 uchar *o, *p; 1006 1007 p = rp->p; 1008 1009 while(p < rp->e){ 1010 code = *p++; 1011 if(code == 255) 1012 break; 1013 if(code == 0) 1014 continue; 1015 1016 /* ignore anything that's too long */ 1017 n = *p++; 1018 o = p; 1019 p += n; 1020 if(p > rp->e) 1021 return; 1022 1023 switch(code){ 1024 case ODipaddr: /* requested ip address */ 1025 if(n == IPv4addrlen) 1026 v4tov6(rp->ip, o); 1027 break; 1028 case ODlease: /* requested lease time */ 1029 rp->leasetime = nhgetl(o); 1030 if(rp->leasetime > MaxLease || rp->leasetime < 0) 1031 rp->leasetime = MaxLease; 1032 break; 1033 case ODtype: 1034 c = *o; 1035 if(c < 10 && c > 0) 1036 rp->dhcptype = c; 1037 break; 1038 case ODserverid: 1039 if(n == IPv4addrlen) 1040 v4tov6(rp->server, o); 1041 break; 1042 case ODmessage: 1043 if(n > sizeof rp->msg-1) 1044 n = sizeof rp->msg-1; 1045 memmove(rp->msg, o, n); 1046 rp->msg[n] = 0; 1047 break; 1048 case ODmaxmsg: 1049 c = nhgets(o); 1050 c -= 28; 1051 c += Udphdrsize; 1052 if(c > 0) 1053 rp->max = rp->buf + c; 1054 break; 1055 case ODclientid: 1056 if(n <= 1) 1057 break; 1058 rp->id = toid( o, n); 1059 break; 1060 case ODparams: 1061 if(n > sizeof(rp->requested)) 1062 n = sizeof(rp->requested); 1063 memmove(rp->requested, o, n); 1064 break; 1065 case ODvendorclass: 1066 if(n >= sizeof(rp->vendorclass)) 1067 n = sizeof(rp->vendorclass)-1; 1068 memmove(rp->vendorclass, o, n); 1069 rp->vendorclass[n] = 0; 1070 if(strncmp((char*)rp->vendorclass, "p9-", 3) == 0) 1071 strcpy(rp->cputype, (char*)rp->vendorclass+3); 1072 break; 1073 case OBend: 1074 return; 1075 } 1076 } 1077 } 1078 1079 void 1080 remrequested(Req *rp, int opt) 1081 { 1082 uchar *p; 1083 1084 p = memchr(rp->requested, opt, sizeof(rp->requested)); 1085 if(p != nil) 1086 *p = OBpad; 1087 } 1088 1089 void 1090 miscoptions(Req *rp, uchar *ip) 1091 { 1092 char *p; 1093 int i, j; 1094 uchar *addrs[2]; 1095 uchar x[2*IPaddrlen]; 1096 uchar vopts[64]; 1097 uchar *op, *omax; 1098 char *attr[100], **a; 1099 int na; 1100 Ndbtuple *t; 1101 1102 addrs[0] = x; 1103 addrs[1] = x+IPaddrlen; 1104 1105 /* always supply these */ 1106 maskopt(rp, OBmask, rp->gii.ipmask); 1107 if(validip(rp->gii.gwip)){ 1108 remrequested(rp, OBrouter); 1109 addropt(rp, OBrouter, rp->gii.gwip); 1110 } else if(validip(rp->giaddr)){ 1111 remrequested(rp, OBrouter); 1112 addropt(rp, OBrouter, rp->giaddr); 1113 } 1114 1115 // OBhostname for the HP4000M switches 1116 // (this causes NT to log infinite errors - tough shit ) 1117 if(*rp->ii.domain){ 1118 remrequested(rp, OBhostname); 1119 stringopt(rp, OBhostname, rp->ii.domain); 1120 } 1121 if(*rp->ii.rootpath) 1122 stringopt(rp, OBrootpath, rp->ii.rootpath); 1123 1124 /* figure out what we need to lookup */ 1125 na = 0; 1126 a = attr; 1127 if(*rp->ii.domain == 0) 1128 a[na++] = "dom"; 1129 for(i = 0; i < sizeof(rp->requested); i++) 1130 switch(rp->requested[i]){ 1131 case OBrouter: 1132 a[na++] = "@ipgw"; 1133 break; 1134 case OBdnserver: 1135 a[na++] = "@dns"; 1136 break; 1137 case OBnetbiosns: 1138 a[na++] = "@wins"; 1139 break; 1140 case OBsmtpserver: 1141 a[na++] = "@smtp"; 1142 break; 1143 case OBpop3server: 1144 a[na++] = "@pop3"; 1145 break; 1146 case OBwwwserver: 1147 a[na++] = "@www"; 1148 break; 1149 case OBntpserver: 1150 a[na++] = "@ntp"; 1151 break; 1152 case OBtimeserver: 1153 a[na++] = "@time"; 1154 break; 1155 } 1156 if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0 1157 || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){ 1158 a[na++] = "@fs"; 1159 a[na++] = "@auth"; 1160 } 1161 t = lookupinfo(ip, a, na); 1162 1163 /* lookup anything we might be missing */ 1164 if(*rp->ii.domain == 0) 1165 lookupname(rp->ii.domain, t); 1166 1167 /* add any requested ones that we know about */ 1168 for(i = 0; i < sizeof(rp->requested); i++) 1169 switch(rp->requested[i]){ 1170 case OBrouter: 1171 j = lookupserver("ipgw", addrs, t); 1172 addrsopt(rp, OBrouter, addrs, j); 1173 break; 1174 case OBdnserver: 1175 j = lookupserver("dns", addrs, t); 1176 addrsopt(rp, OBdnserver, addrs, j); 1177 break; 1178 case OBhostname: 1179 if(*rp->ii.domain) 1180 stringopt(rp, OBhostname, rp->ii.domain); 1181 break; 1182 case OBdomainname: 1183 p = strchr(rp->ii.domain, '.'); 1184 if(p) 1185 stringopt(rp, OBdomainname, p+1); 1186 break; 1187 case OBnetbiosns: 1188 j = lookupserver("wins", addrs, t); 1189 addrsopt(rp, OBnetbiosns, addrs, j); 1190 break; 1191 case OBnetbiostype: 1192 /* p-node: peer to peer WINS queries */ 1193 byteopt(rp, OBnetbiostype, 0x2); 1194 break; 1195 case OBsmtpserver: 1196 j = lookupserver("smtp", addrs, t); 1197 addrsopt(rp, OBsmtpserver, addrs, j); 1198 break; 1199 case OBpop3server: 1200 j = lookupserver("pop3", addrs, t); 1201 addrsopt(rp, OBpop3server, addrs, j); 1202 break; 1203 case OBwwwserver: 1204 j = lookupserver("www", addrs, t); 1205 addrsopt(rp, OBwwwserver, addrs, j); 1206 break; 1207 case OBntpserver: 1208 j = lookupserver("ntp", addrs, t); 1209 addrsopt(rp, OBntpserver, addrs, j); 1210 break; 1211 case OBtimeserver: 1212 j = lookupserver("time", addrs, t); 1213 addrsopt(rp, OBtimeserver, addrs, j); 1214 break; 1215 case OBttl: 1216 byteopt(rp, OBttl, 255); 1217 break; 1218 } 1219 1220 // add plan9 specific options 1221 if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0 1222 || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){ 1223 // point to temporary area 1224 op = rp->p; 1225 omax = rp->max; 1226 rp->p = vopts; 1227 rp->max = vopts + sizeof(vopts) - 1; 1228 1229 j = lookupserver("fs", addrs, t); 1230 addrsopt(rp, OP9fs, addrs, j); 1231 j = lookupserver("auth", addrs, t); 1232 addrsopt(rp, OP9auth, addrs, j); 1233 1234 // point back 1235 j = rp->p - vopts; 1236 rp->p = op; 1237 rp->max = omax; 1238 vectoropt(rp, OBvendorinfo, vopts, j); 1239 } 1240 1241 ndbfree(t); 1242 } 1243 1244 int 1245 openlisten(char *net) 1246 { 1247 int fd, cfd; 1248 char data[128]; 1249 char devdir[40]; 1250 1251 sprint(data, "%s/udp!*!bootp", net); 1252 cfd = announce(data, devdir); 1253 if(cfd < 0) 1254 fatal(1, "can't announce"); 1255 if(fprint(cfd, "headers") < 0) 1256 fatal(1, "can't set header mode"); 1257 1258 sprint(data, "%s/data", devdir); 1259 1260 fd = open(data, ORDWR); 1261 if(fd < 0) 1262 fatal(1, "open udp data"); 1263 return fd; 1264 } 1265 1266 void 1267 fatal(int syserr, char *fmt, ...) 1268 { 1269 char buf[ERRMAX]; 1270 va_list arg; 1271 1272 va_start(arg, fmt); 1273 vseprint(buf, buf+sizeof(buf), fmt, arg); 1274 va_end(arg); 1275 if(syserr) 1276 syslog(1, blog, "%s: %r", buf); 1277 else 1278 syslog(1, blog, "%s", buf); 1279 exits(buf); 1280 } 1281 1282 extern void 1283 warning(int syserr, char *fmt, ...) 1284 { 1285 char buf[256]; 1286 va_list arg; 1287 1288 va_start(arg, fmt); 1289 vseprint(buf, buf+sizeof(buf), fmt, arg); 1290 va_end(arg); 1291 if(syserr){ 1292 syslog(0, blog, "%s: %r", buf); 1293 if(debug) 1294 fprint(2, "%s: %r\n", buf); 1295 } else { 1296 syslog(0, blog, "%s", buf); 1297 if(debug) 1298 fprint(2, "%s\n", buf); 1299 } 1300 } 1301 1302 char* 1303 readsysname(void) 1304 { 1305 static char name[128]; 1306 char *p; 1307 int n, fd; 1308 1309 fd = open("/dev/sysname", OREAD); 1310 if(fd >= 0){ 1311 n = read(fd, name, sizeof(name)-1); 1312 close(fd); 1313 if(n > 0){ 1314 name[n] = 0; 1315 return name; 1316 } 1317 } 1318 p = getenv("sysname"); 1319 if(p == nil || *p == 0) 1320 return "unknown"; 1321 return p; 1322 } 1323 1324 extern int 1325 validip(uchar *ip) 1326 { 1327 if(ipcmp(ip, IPnoaddr) == 0) 1328 return 0; 1329 if(ipcmp(ip, v4prefix) == 0) 1330 return 0; 1331 return 1; 1332 } 1333 1334 void 1335 longopt(Req *rp, int t, long v) 1336 { 1337 if(rp->p + 6 > rp->max) 1338 return; 1339 *rp->p++ = t; 1340 *rp->p++ = 4; 1341 hnputl(rp->p, v); 1342 rp->p += 4; 1343 1344 op = seprint(op, oe, "%s(%ld)", optname[t], v); 1345 } 1346 1347 void 1348 addropt(Req *rp, int t, uchar *ip) 1349 { 1350 if(rp->p + 6 > rp->max) 1351 return; 1352 *rp->p++ = t; 1353 *rp->p++ = 4; 1354 memmove(rp->p, ip+IPv4off, 4); 1355 rp->p += 4; 1356 1357 op = seprint(op, oe, "%s(%I)", optname[t], ip); 1358 } 1359 1360 void 1361 maskopt(Req *rp, int t, uchar *ip) 1362 { 1363 if(rp->p + 6 > rp->max) 1364 return; 1365 *rp->p++ = t; 1366 *rp->p++ = 4; 1367 memmove(rp->p, ip+IPv4off, 4); 1368 rp->p += 4; 1369 1370 op = seprint(op, oe, "%s(%M)", optname[t], ip); 1371 } 1372 1373 void 1374 addrsopt(Req *rp, int t, uchar **ip, int i) 1375 { 1376 if(i <= 0) 1377 return; 1378 if(rp->p + 2 + 4*i > rp->max) 1379 return; 1380 *rp->p++ = t; 1381 *rp->p++ = 4*i; 1382 op = seprint(op, oe, "%s(", optname[t]); 1383 while(i-- > 0){ 1384 v6tov4(rp->p, *ip); 1385 rp->p += 4; 1386 op = seprint(op, oe, "%I", *ip); 1387 ip++; 1388 if(i > 0) 1389 op = seprint(op, oe, " "); 1390 } 1391 op = seprint(op, oe, ")"); 1392 } 1393 1394 void 1395 byteopt(Req *rp, int t, uchar v) 1396 { 1397 if(rp->p + 3 > rp->max) 1398 return; 1399 *rp->p++ = t; 1400 *rp->p++ = 1; 1401 *rp->p++ = v; 1402 1403 op = seprint(op, oe, "%s(%d)", optname[t], v); 1404 } 1405 1406 void 1407 termopt(Req *rp) 1408 { 1409 if(rp->p + 1 > rp->max) 1410 return; 1411 *rp->p++ = OBend; 1412 } 1413 1414 void 1415 stringopt(Req *rp, int t, char *str) 1416 { 1417 int n; 1418 1419 n = strlen(str); 1420 if(n > 255) 1421 n = 255; 1422 if(rp->p+n+2 > rp->max) 1423 return; 1424 *rp->p++ = t; 1425 *rp->p++ = n; 1426 memmove(rp->p, str, n); 1427 rp->p += n; 1428 1429 op = seprint(op, oe, "%s(%s)", optname[t], str); 1430 } 1431 1432 void 1433 vectoropt(Req *rp, int t, uchar *v, int n) 1434 { 1435 int i; 1436 1437 if(n > 255) 1438 n = 255; 1439 if(rp->p+n+2 > rp->max) 1440 return; 1441 *rp->p++ = t; 1442 *rp->p++ = n; 1443 memmove(rp->p, v, n); 1444 rp->p += n; 1445 1446 op = seprint(op, oe, "%s(", optname[t]); 1447 if(n > 0) 1448 op = seprint(op, oe, "%ud", 0); 1449 for(i = 1; i < n; i++) 1450 op = seprint(op, oe, " %ud", v[i]); 1451 } 1452 1453 int 1454 fromhex(int x) 1455 { 1456 if(x >= '0' && x <= '9') 1457 return x - '0'; 1458 return x - 'a'; 1459 } 1460 1461 void 1462 hexopt(Req *rp, int t, char *str) 1463 { 1464 int n; 1465 1466 n = strlen(str); 1467 n /= 2; 1468 if(n > 255) 1469 n = 255; 1470 if(rp->p+n+2 > rp->max) 1471 return; 1472 *rp->p++ = t; 1473 *rp->p++ = n; 1474 while(n-- > 0){ 1475 *rp->p++ = (fromhex(str[0])<<4)|fromhex(str[1]); 1476 str += 2; 1477 } 1478 1479 op = seprint(op, oe, "%s(%s)", optname[t], str); 1480 } 1481 1482 void 1483 arpenter(uchar *ip, uchar *ether) 1484 { 1485 int f; 1486 char buf[256]; 1487 1488 /* brazil */ 1489 sprint(buf, "%s/arp", net); 1490 f = open(buf, OWRITE); 1491 if(f < 0){ 1492 syslog(debug, blog, "open %s: %r", buf); 1493 return; 1494 } 1495 fprint(f, "add ether %I %E", ip, ether); 1496 close(f); 1497 } 1498 1499 char *dhcpmsgname[] = 1500 { 1501 [Discover] "Discover", 1502 [Offer] "Offer", 1503 [Request] "Request", 1504 [Decline] "Decline", 1505 [Ack] "Ack", 1506 [Nak] "Nak", 1507 [Release] "Release", 1508 [Inform] "Inform", 1509 }; 1510 1511 void 1512 logdhcp(Req *rp) 1513 { 1514 char buf[4096]; 1515 char *p, *e; 1516 int i; 1517 1518 p = buf; 1519 e = buf + sizeof(buf); 1520 if(rp->dhcptype > 0 && rp->dhcptype <= Inform) 1521 p = seprint(p, e, "%s(", dhcpmsgname[rp->dhcptype]); 1522 else 1523 p = seprint(p, e, "%d(", rp->dhcptype); 1524 p = seprint(p, e, "%I->%I) xid(%ux)flag(%ux)", rp->up->raddr, rp->up->laddr, 1525 nhgetl(rp->bp->xid), nhgets(rp->bp->flags)); 1526 if(rp->bp->htype == 1) 1527 p = seprint(p, e, "ea(%E)", rp->bp->chaddr); 1528 if(validip(rp->ciaddr)) 1529 p = seprint(p, e, "ci(%I)", rp->ciaddr); 1530 if(validip(rp->giaddr)) 1531 p = seprint(p, e, "gi(%I)", rp->giaddr); 1532 if(validip(rp->ip)) 1533 p = seprint(p, e, "ip(%I)", rp->ip); 1534 if(rp->id != nil) 1535 p = seprint(p, e, "id(%s)", rp->id); 1536 if(rp->leasetime) 1537 p = seprint(p, e, "leas(%d)", rp->leasetime); 1538 if(validip(rp->server)) 1539 p = seprint(p, e, "sid(%I)", rp->server); 1540 p = seprint(p, e, "need("); 1541 for(i = 0; i < sizeof(rp->requested); i++) 1542 if(rp->requested[i] != 0) 1543 p = seprint(p, e, "%s ", optname[rp->requested[i]]); 1544 p = seprint(p, e, ")"); 1545 1546 USED(p); 1547 syslog(0, blog, "%s", buf); 1548 } 1549 1550 void 1551 logdhcpout(Req *rp, char *type) 1552 { 1553 syslog(0, blog, "%s(%I-%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s", 1554 type, rp->up->laddr, rp->up->raddr, rp->id, 1555 rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf); 1556 } 1557 1558 /* 1559 * if we get behind, it's useless to try answering since the sender 1560 * will probably have retransmitted with a differnt sequence number. 1561 * So dump all the last message in the queue. 1562 */ 1563 void ding(void*, char *msg) 1564 { 1565 if(strstr(msg, "alarm")) 1566 noted(NCONT); 1567 else 1568 noted(NDFLT); 1569 } 1570 1571 int 1572 readlast(int fd, uchar *buf, int len) 1573 { 1574 int lastn, n; 1575 1576 notify(ding); 1577 1578 lastn = 0; 1579 for(;;){ 1580 alarm(20); 1581 n = read(fd, buf, len); 1582 alarm(0); 1583 if(n < 0){ 1584 if(lastn > 0) 1585 return lastn; 1586 break; 1587 } 1588 lastn = n; 1589 } 1590 return read(fd, buf, len); 1591 } 1592