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 OUdphdr *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 < OUdphdrsize) 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 = (OUdphdr*)rp->buf; 318 rp->max = rp->buf + OUdphdrsize + 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 OUdphdr *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 OUdphdr *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 OUdphdr *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 OUdphdr *up; 867 ushort flags; 868 Iplifc *lifc; 869 Info *iip; 870 871 warning(0, "bootp %s %I->%I from %s via %I, file %s", 872 rp->genrequest ? "generic" : (rp->p9request ? "p9" : ""), 873 rp->up->raddr, rp->up->laddr, 874 rp->id, rp->gii.ipaddr, 875 rp->bp->file); 876 877 if(nobootp) 878 return; 879 880 bp = rp->bp; 881 up = rp->up; 882 iip = &rp->ii; 883 884 if(rp->staticbinding == 0){ 885 warning(0, "bootp from unknown %s via %I", rp->id, rp->gii.ipaddr); 886 return; 887 } 888 889 /* ignore if not for us */ 890 if(*bp->sname){ 891 if(strcmp(bp->sname, mysysname) != 0){ 892 bp->sname[20] = 0; 893 warning(0, "bootp for server %s", bp->sname); 894 return; 895 } 896 } else if(slow) 897 sleep(500); 898 899 /* ignore if we don't know what file to load */ 900 if(*bp->file == 0){ 901 if(rp->genrequest && *iip->bootf2) /* if not plan 9 and we have an alternate file... */ 902 strncpy(bp->file, iip->bootf2, sizeof(bp->file)); 903 else if(*iip->bootf) 904 strncpy(bp->file, iip->bootf, sizeof(bp->file)); 905 else if(*bp->sname) /* if we were asked, respond no matter what */ 906 bp->file[0] = '\0'; 907 else { 908 warning(0, "no bootfile for %I", iip->ipaddr); 909 return; 910 } 911 } 912 913 /* ignore if the file is unreadable */ 914 if((!rp->genrequest) && bp->file[0] && access(bp->file, 4) < 0){ 915 warning(0, "inaccessible bootfile1 %s", bp->file); 916 return; 917 } 918 919 bp->op = Bootreply; 920 v6tov4(bp->yiaddr, iip->ipaddr); 921 if(rp->p9request){ 922 warning(0, "p9bootp: %I", iip->ipaddr); 923 memmove(bp->optmagic, plan9opt, 4); 924 if(iip->gwip == 0) 925 v4tov6(iip->gwip, bp->giaddr); 926 rp->p += sprint((char*)rp->p, "%V %I %I %I", iip->ipmask+IPv4off, iip->fsip, 927 iip->auip, iip->gwip); 928 sprint(optbuf, "%s", (char*)(bp->optmagic)); 929 } else if(rp->genrequest){ 930 warning(0, "genericbootp: %I", iip->ipaddr); 931 memmove(bp->optmagic, genericopt, 4); 932 miscoptions(rp, iip->ipaddr); 933 termopt(rp); 934 } else if(iip->vendor[0] != 0) { 935 warning(0, "bootp vendor field: %s", iip->vendor); 936 memset(rp->p, 0, 128-4); 937 rp->p += sprint((char*)bp->optmagic, "%s", iip->vendor); 938 } else { 939 memset(rp->p, 0, 128-4); 940 rp->p += 128-4; 941 } 942 943 /* 944 * set destination 945 */ 946 flags = nhgets(bp->flags); 947 if(validip(rp->giaddr)){ 948 ipmove(up->raddr, rp->giaddr); 949 hnputs(up->rport, 67); 950 } else if(flags & Fbroadcast){ 951 ipmove(up->raddr, IPv4bcast); 952 hnputs(up->rport, 68); 953 } else { 954 v4tov6(up->raddr, bp->yiaddr); 955 if(bp->htype == 1) 956 arpenter(up->raddr, bp->chaddr); 957 hnputs(up->rport, 68); 958 } 959 960 /* 961 * select best local address if destination is directly connected 962 */ 963 lifc = findlifc(up->raddr); 964 if(lifc) 965 ipmove(up->laddr, lifc->ip); 966 967 /* 968 * our identity 969 */ 970 strncpy(bp->sname, mysysname, sizeof(bp->sname)); 971 972 /* 973 * set tftp server 974 */ 975 setsiaddr(bp->siaddr, iip->tftp, up->laddr); 976 if(rp->genrequest && *iip->bootf2) 977 setsiaddr(bp->siaddr, iip->tftp2, up->laddr); 978 979 /* 980 * RFC 1048 says that we must pad vendor field with 981 * zeros until we have a 64 byte field. 982 */ 983 n = rp->p - rp->bp->optdata; 984 if(n < 64-4) { 985 memset(rp->p, 0, (64-4)-n); 986 rp->p += (64-4)-n; 987 } 988 989 /* 990 * send 991 */ 992 n = rp->p - rp->buf; 993 if(!mute && write(rp->fd, rp->buf, n) != n) 994 warning(0, "bootp: write failed: %r"); 995 996 warning(0, "bootp via %I: file %s xid(%ux)flag(%ux)ci(%V)gi(%V)yi(%V)si(%V) %s", 997 up->raddr, bp->file, nhgetl(bp->xid), nhgets(bp->flags), 998 bp->ciaddr, bp->giaddr, bp->yiaddr, bp->siaddr, 999 optbuf); 1000 } 1001 1002 void 1003 parseoptions(Req *rp) 1004 { 1005 int n, c, code; 1006 uchar *o, *p; 1007 1008 p = rp->p; 1009 1010 while(p < rp->e){ 1011 code = *p++; 1012 if(code == 255) 1013 break; 1014 if(code == 0) 1015 continue; 1016 1017 /* ignore anything that's too long */ 1018 n = *p++; 1019 o = p; 1020 p += n; 1021 if(p > rp->e) 1022 return; 1023 1024 switch(code){ 1025 case ODipaddr: /* requested ip address */ 1026 if(n == IPv4addrlen) 1027 v4tov6(rp->ip, o); 1028 break; 1029 case ODlease: /* requested lease time */ 1030 rp->leasetime = nhgetl(o); 1031 if(rp->leasetime > MaxLease || rp->leasetime < 0) 1032 rp->leasetime = MaxLease; 1033 break; 1034 case ODtype: 1035 c = *o; 1036 if(c < 10 && c > 0) 1037 rp->dhcptype = c; 1038 break; 1039 case ODserverid: 1040 if(n == IPv4addrlen) 1041 v4tov6(rp->server, o); 1042 break; 1043 case ODmessage: 1044 if(n > sizeof rp->msg-1) 1045 n = sizeof rp->msg-1; 1046 memmove(rp->msg, o, n); 1047 rp->msg[n] = 0; 1048 break; 1049 case ODmaxmsg: 1050 c = nhgets(o); 1051 c -= 28; 1052 c += OUdphdrsize; 1053 if(c > 0) 1054 rp->max = rp->buf + c; 1055 break; 1056 case ODclientid: 1057 if(n <= 1) 1058 break; 1059 rp->id = toid( o, n); 1060 break; 1061 case ODparams: 1062 if(n > sizeof(rp->requested)) 1063 n = sizeof(rp->requested); 1064 memmove(rp->requested, o, n); 1065 break; 1066 case ODvendorclass: 1067 if(n >= sizeof(rp->vendorclass)) 1068 n = sizeof(rp->vendorclass)-1; 1069 memmove(rp->vendorclass, o, n); 1070 rp->vendorclass[n] = 0; 1071 if(strncmp((char*)rp->vendorclass, "p9-", 3) == 0) 1072 strcpy(rp->cputype, (char*)rp->vendorclass+3); 1073 break; 1074 case OBend: 1075 return; 1076 } 1077 } 1078 } 1079 1080 void 1081 remrequested(Req *rp, int opt) 1082 { 1083 uchar *p; 1084 1085 p = memchr(rp->requested, opt, sizeof(rp->requested)); 1086 if(p != nil) 1087 *p = OBpad; 1088 } 1089 1090 void 1091 miscoptions(Req *rp, uchar *ip) 1092 { 1093 char *p; 1094 int i, j; 1095 uchar *addrs[2]; 1096 uchar x[2*IPaddrlen]; 1097 uchar vopts[64]; 1098 uchar *op, *omax; 1099 char *attr[100], **a; 1100 int na; 1101 Ndbtuple *t; 1102 1103 addrs[0] = x; 1104 addrs[1] = x+IPaddrlen; 1105 1106 /* always supply these */ 1107 maskopt(rp, OBmask, rp->gii.ipmask); 1108 if(validip(rp->gii.gwip)){ 1109 remrequested(rp, OBrouter); 1110 addropt(rp, OBrouter, rp->gii.gwip); 1111 } else if(validip(rp->giaddr)){ 1112 remrequested(rp, OBrouter); 1113 addropt(rp, OBrouter, rp->giaddr); 1114 } 1115 1116 // OBhostname for the HP4000M switches 1117 // (this causes NT to log infinite errors - tough shit ) 1118 if(*rp->ii.domain){ 1119 remrequested(rp, OBhostname); 1120 stringopt(rp, OBhostname, rp->ii.domain); 1121 } 1122 if(*rp->ii.rootpath) 1123 stringopt(rp, OBrootpath, rp->ii.rootpath); 1124 1125 /* figure out what we need to lookup */ 1126 na = 0; 1127 a = attr; 1128 if(*rp->ii.domain == 0) 1129 a[na++] = "dom"; 1130 for(i = 0; i < sizeof(rp->requested); i++) 1131 switch(rp->requested[i]){ 1132 case OBrouter: 1133 a[na++] = "@ipgw"; 1134 break; 1135 case OBdnserver: 1136 a[na++] = "@dns"; 1137 break; 1138 case OBnetbiosns: 1139 a[na++] = "@wins"; 1140 break; 1141 case OBsmtpserver: 1142 a[na++] = "@smtp"; 1143 break; 1144 case OBpop3server: 1145 a[na++] = "@pop3"; 1146 break; 1147 case OBwwwserver: 1148 a[na++] = "@www"; 1149 break; 1150 case OBntpserver: 1151 a[na++] = "@ntp"; 1152 break; 1153 case OBtimeserver: 1154 a[na++] = "@time"; 1155 break; 1156 } 1157 if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0 1158 || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){ 1159 a[na++] = "@fs"; 1160 a[na++] = "@auth"; 1161 } 1162 t = lookupinfo(ip, a, na); 1163 1164 /* lookup anything we might be missing */ 1165 if(*rp->ii.domain == 0) 1166 lookupname(rp->ii.domain, t); 1167 1168 /* add any requested ones that we know about */ 1169 for(i = 0; i < sizeof(rp->requested); i++) 1170 switch(rp->requested[i]){ 1171 case OBrouter: 1172 j = lookupserver("ipgw", addrs, t); 1173 addrsopt(rp, OBrouter, addrs, j); 1174 break; 1175 case OBdnserver: 1176 j = lookupserver("dns", addrs, t); 1177 addrsopt(rp, OBdnserver, addrs, j); 1178 break; 1179 case OBhostname: 1180 if(*rp->ii.domain) 1181 stringopt(rp, OBhostname, rp->ii.domain); 1182 break; 1183 case OBdomainname: 1184 p = strchr(rp->ii.domain, '.'); 1185 if(p) 1186 stringopt(rp, OBdomainname, p+1); 1187 break; 1188 case OBnetbiosns: 1189 j = lookupserver("wins", addrs, t); 1190 addrsopt(rp, OBnetbiosns, addrs, j); 1191 break; 1192 case OBnetbiostype: 1193 /* p-node: peer to peer WINS queries */ 1194 byteopt(rp, OBnetbiostype, 0x2); 1195 break; 1196 case OBsmtpserver: 1197 j = lookupserver("smtp", addrs, t); 1198 addrsopt(rp, OBsmtpserver, addrs, j); 1199 break; 1200 case OBpop3server: 1201 j = lookupserver("pop3", addrs, t); 1202 addrsopt(rp, OBpop3server, addrs, j); 1203 break; 1204 case OBwwwserver: 1205 j = lookupserver("www", addrs, t); 1206 addrsopt(rp, OBwwwserver, addrs, j); 1207 break; 1208 case OBntpserver: 1209 j = lookupserver("ntp", addrs, t); 1210 addrsopt(rp, OBntpserver, addrs, j); 1211 break; 1212 case OBtimeserver: 1213 j = lookupserver("time", addrs, t); 1214 addrsopt(rp, OBtimeserver, addrs, j); 1215 break; 1216 case OBttl: 1217 byteopt(rp, OBttl, 255); 1218 break; 1219 } 1220 1221 // add plan9 specific options 1222 if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0 1223 || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){ 1224 // point to temporary area 1225 op = rp->p; 1226 omax = rp->max; 1227 rp->p = vopts; 1228 rp->max = vopts + sizeof(vopts) - 1; 1229 1230 j = lookupserver("fs", addrs, t); 1231 addrsopt(rp, OP9fs, addrs, j); 1232 j = lookupserver("auth", addrs, t); 1233 addrsopt(rp, OP9auth, addrs, j); 1234 1235 // point back 1236 j = rp->p - vopts; 1237 rp->p = op; 1238 rp->max = omax; 1239 vectoropt(rp, OBvendorinfo, vopts, j); 1240 } 1241 1242 ndbfree(t); 1243 } 1244 1245 int 1246 openlisten(char *net) 1247 { 1248 int fd, cfd; 1249 char data[128]; 1250 char devdir[40]; 1251 1252 sprint(data, "%s/udp!*!bootp", net); 1253 cfd = announce(data, devdir); 1254 if(cfd < 0) 1255 fatal(1, "can't announce"); 1256 if(fprint(cfd, "headers") < 0) 1257 fatal(1, "can't set header mode"); 1258 fprint(cfd, "oldheaders"); 1259 1260 sprint(data, "%s/data", devdir); 1261 1262 fd = open(data, ORDWR); 1263 if(fd < 0) 1264 fatal(1, "open udp data"); 1265 return fd; 1266 } 1267 1268 void 1269 fatal(int syserr, char *fmt, ...) 1270 { 1271 char buf[ERRMAX]; 1272 va_list arg; 1273 1274 va_start(arg, fmt); 1275 vseprint(buf, buf+sizeof(buf), fmt, arg); 1276 va_end(arg); 1277 if(syserr) 1278 syslog(1, blog, "%s: %r", buf); 1279 else 1280 syslog(1, blog, "%s", buf); 1281 exits(buf); 1282 } 1283 1284 extern void 1285 warning(int syserr, char *fmt, ...) 1286 { 1287 char buf[256]; 1288 va_list arg; 1289 1290 va_start(arg, fmt); 1291 vseprint(buf, buf+sizeof(buf), fmt, arg); 1292 va_end(arg); 1293 if(syserr){ 1294 syslog(0, blog, "%s: %r", buf); 1295 if(debug) 1296 fprint(2, "%s: %r\n", buf); 1297 } else { 1298 syslog(0, blog, "%s", buf); 1299 if(debug) 1300 fprint(2, "%s\n", buf); 1301 } 1302 } 1303 1304 char* 1305 readsysname(void) 1306 { 1307 static char name[128]; 1308 char *p; 1309 int n, fd; 1310 1311 fd = open("/dev/sysname", OREAD); 1312 if(fd >= 0){ 1313 n = read(fd, name, sizeof(name)-1); 1314 close(fd); 1315 if(n > 0){ 1316 name[n] = 0; 1317 return name; 1318 } 1319 } 1320 p = getenv("sysname"); 1321 if(p == nil || *p == 0) 1322 return "unknown"; 1323 return p; 1324 } 1325 1326 extern int 1327 validip(uchar *ip) 1328 { 1329 if(ipcmp(ip, IPnoaddr) == 0) 1330 return 0; 1331 if(ipcmp(ip, v4prefix) == 0) 1332 return 0; 1333 return 1; 1334 } 1335 1336 void 1337 longopt(Req *rp, int t, long v) 1338 { 1339 if(rp->p + 6 > rp->max) 1340 return; 1341 *rp->p++ = t; 1342 *rp->p++ = 4; 1343 hnputl(rp->p, v); 1344 rp->p += 4; 1345 1346 op = seprint(op, oe, "%s(%ld)", optname[t], v); 1347 } 1348 1349 void 1350 addropt(Req *rp, int t, uchar *ip) 1351 { 1352 if(rp->p + 6 > rp->max) 1353 return; 1354 *rp->p++ = t; 1355 *rp->p++ = 4; 1356 memmove(rp->p, ip+IPv4off, 4); 1357 rp->p += 4; 1358 1359 op = seprint(op, oe, "%s(%I)", optname[t], ip); 1360 } 1361 1362 void 1363 maskopt(Req *rp, int t, uchar *ip) 1364 { 1365 if(rp->p + 6 > rp->max) 1366 return; 1367 *rp->p++ = t; 1368 *rp->p++ = 4; 1369 memmove(rp->p, ip+IPv4off, 4); 1370 rp->p += 4; 1371 1372 op = seprint(op, oe, "%s(%M)", optname[t], ip); 1373 } 1374 1375 void 1376 addrsopt(Req *rp, int t, uchar **ip, int i) 1377 { 1378 if(i <= 0) 1379 return; 1380 if(rp->p + 2 + 4*i > rp->max) 1381 return; 1382 *rp->p++ = t; 1383 *rp->p++ = 4*i; 1384 op = seprint(op, oe, "%s(", optname[t]); 1385 while(i-- > 0){ 1386 v6tov4(rp->p, *ip); 1387 rp->p += 4; 1388 op = seprint(op, oe, "%I", *ip); 1389 ip++; 1390 if(i > 0) 1391 op = seprint(op, oe, " "); 1392 } 1393 op = seprint(op, oe, ")"); 1394 } 1395 1396 void 1397 byteopt(Req *rp, int t, uchar v) 1398 { 1399 if(rp->p + 3 > rp->max) 1400 return; 1401 *rp->p++ = t; 1402 *rp->p++ = 1; 1403 *rp->p++ = v; 1404 1405 op = seprint(op, oe, "%s(%d)", optname[t], v); 1406 } 1407 1408 void 1409 termopt(Req *rp) 1410 { 1411 if(rp->p + 1 > rp->max) 1412 return; 1413 *rp->p++ = OBend; 1414 } 1415 1416 void 1417 stringopt(Req *rp, int t, char *str) 1418 { 1419 int n; 1420 1421 n = strlen(str); 1422 if(n > 255) 1423 n = 255; 1424 if(rp->p+n+2 > rp->max) 1425 return; 1426 *rp->p++ = t; 1427 *rp->p++ = n; 1428 memmove(rp->p, str, n); 1429 rp->p += n; 1430 1431 op = seprint(op, oe, "%s(%s)", optname[t], str); 1432 } 1433 1434 void 1435 vectoropt(Req *rp, int t, uchar *v, int n) 1436 { 1437 int i; 1438 1439 if(n > 255) 1440 n = 255; 1441 if(rp->p+n+2 > rp->max) 1442 return; 1443 *rp->p++ = t; 1444 *rp->p++ = n; 1445 memmove(rp->p, v, n); 1446 rp->p += n; 1447 1448 op = seprint(op, oe, "%s(", optname[t]); 1449 if(n > 0) 1450 op = seprint(op, oe, "%ud", 0); 1451 for(i = 1; i < n; i++) 1452 op = seprint(op, oe, " %ud", v[i]); 1453 } 1454 1455 int 1456 fromhex(int x) 1457 { 1458 if(x >= '0' && x <= '9') 1459 return x - '0'; 1460 return x - 'a'; 1461 } 1462 1463 void 1464 hexopt(Req *rp, int t, char *str) 1465 { 1466 int n; 1467 1468 n = strlen(str); 1469 n /= 2; 1470 if(n > 255) 1471 n = 255; 1472 if(rp->p+n+2 > rp->max) 1473 return; 1474 *rp->p++ = t; 1475 *rp->p++ = n; 1476 while(n-- > 0){ 1477 *rp->p++ = (fromhex(str[0])<<4)|fromhex(str[1]); 1478 str += 2; 1479 } 1480 1481 op = seprint(op, oe, "%s(%s)", optname[t], str); 1482 } 1483 1484 void 1485 arpenter(uchar *ip, uchar *ether) 1486 { 1487 int f; 1488 char buf[256]; 1489 1490 /* brazil */ 1491 sprint(buf, "%s/arp", net); 1492 f = open(buf, OWRITE); 1493 if(f < 0){ 1494 syslog(debug, blog, "open %s: %r", buf); 1495 return; 1496 } 1497 fprint(f, "add ether %I %E", ip, ether); 1498 close(f); 1499 } 1500 1501 char *dhcpmsgname[] = 1502 { 1503 [Discover] "Discover", 1504 [Offer] "Offer", 1505 [Request] "Request", 1506 [Decline] "Decline", 1507 [Ack] "Ack", 1508 [Nak] "Nak", 1509 [Release] "Release", 1510 [Inform] "Inform", 1511 }; 1512 1513 void 1514 logdhcp(Req *rp) 1515 { 1516 char buf[4096]; 1517 char *p, *e; 1518 int i; 1519 1520 p = buf; 1521 e = buf + sizeof(buf); 1522 if(rp->dhcptype > 0 && rp->dhcptype <= Inform) 1523 p = seprint(p, e, "%s(", dhcpmsgname[rp->dhcptype]); 1524 else 1525 p = seprint(p, e, "%d(", rp->dhcptype); 1526 p = seprint(p, e, "%I->%I) xid(%ux)flag(%ux)", rp->up->raddr, rp->up->laddr, 1527 nhgetl(rp->bp->xid), nhgets(rp->bp->flags)); 1528 if(rp->bp->htype == 1) 1529 p = seprint(p, e, "ea(%E)", rp->bp->chaddr); 1530 if(validip(rp->ciaddr)) 1531 p = seprint(p, e, "ci(%I)", rp->ciaddr); 1532 if(validip(rp->giaddr)) 1533 p = seprint(p, e, "gi(%I)", rp->giaddr); 1534 if(validip(rp->ip)) 1535 p = seprint(p, e, "ip(%I)", rp->ip); 1536 if(rp->id != nil) 1537 p = seprint(p, e, "id(%s)", rp->id); 1538 if(rp->leasetime) 1539 p = seprint(p, e, "leas(%d)", rp->leasetime); 1540 if(validip(rp->server)) 1541 p = seprint(p, e, "sid(%I)", rp->server); 1542 p = seprint(p, e, "need("); 1543 for(i = 0; i < sizeof(rp->requested); i++) 1544 if(rp->requested[i] != 0) 1545 p = seprint(p, e, "%s ", optname[rp->requested[i]]); 1546 p = seprint(p, e, ")"); 1547 1548 USED(p); 1549 syslog(0, blog, "%s", buf); 1550 } 1551 1552 void 1553 logdhcpout(Req *rp, char *type) 1554 { 1555 syslog(0, blog, "%s(%I-%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s", 1556 type, rp->up->laddr, rp->up->raddr, rp->id, 1557 rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf); 1558 } 1559 1560 /* 1561 * if we get behind, it's useless to try answering since the sender 1562 * will probably have retransmitted with a differnt sequence number. 1563 * So dump all the last message in the queue. 1564 */ 1565 void ding(void*, char *msg) 1566 { 1567 if(strstr(msg, "alarm")) 1568 noted(NCONT); 1569 else 1570 noted(NDFLT); 1571 } 1572 1573 int 1574 readlast(int fd, uchar *buf, int len) 1575 { 1576 int lastn, n; 1577 1578 notify(ding); 1579 1580 lastn = 0; 1581 for(;;){ 1582 alarm(20); 1583 n = read(fd, buf, len); 1584 alarm(0); 1585 if(n < 0){ 1586 if(lastn > 0) 1587 return lastn; 1588 break; 1589 } 1590 lastn = n; 1591 } 1592 return read(fd, buf, len); 1593 } 1594