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