1 /* 2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "DHCPClient.h" 11 #include "NetServer.h" 12 13 #include <Message.h> 14 #include <MessageRunner.h> 15 16 #include <arpa/inet.h> 17 #include <errno.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include <syslog.h> 21 #include <sys/sockio.h> 22 #include <sys/time.h> 23 24 25 // See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options 26 27 #define DHCP_CLIENT_PORT 68 28 #define DHCP_SERVER_PORT 67 29 30 #define DEFAULT_TIMEOUT 2 // secs 31 #define MAX_TIMEOUT 15 // secs 32 33 enum message_opcode { 34 BOOT_REQUEST = 1, 35 BOOT_REPLY 36 }; 37 38 enum message_option { 39 OPTION_MAGIC = 0x63825363, 40 41 // generic options 42 OPTION_PAD = 0, 43 OPTION_END = 255, 44 OPTION_SUBNET_MASK = 1, 45 OPTION_TIME_OFFSET = 2, 46 OPTION_ROUTER_ADDRESS = 3, 47 OPTION_DOMAIN_NAME_SERVER = 6, 48 OPTION_HOST_NAME = 12, 49 OPTION_DOMAIN_NAME = 15, 50 OPTION_DATAGRAM_SIZE = 22, 51 OPTION_MTU = 26, 52 OPTION_BROADCAST_ADDRESS = 28, 53 OPTION_NETWORK_TIME_SERVERS = 42, 54 OPTION_NETBIOS_NAME_SERVER = 44, 55 OPTION_NETBIOS_SCOPE = 47, 56 57 // DHCP specific options 58 OPTION_REQUEST_IP_ADDRESS = 50, 59 OPTION_ADDRESS_LEASE_TIME = 51, 60 OPTION_OVERLOAD = 52, 61 OPTION_MESSAGE_TYPE = 53, 62 OPTION_SERVER_ADDRESS = 54, 63 OPTION_REQUEST_PARAMETERS = 55, 64 OPTION_ERROR_MESSAGE = 56, 65 OPTION_MESSAGE_SIZE = 57, 66 OPTION_RENEWAL_TIME = 58, 67 OPTION_REBINDING_TIME = 59, 68 OPTION_CLASS_IDENTIFIER = 60, 69 OPTION_CLIENT_IDENTIFIER = 61, 70 }; 71 72 enum message_type { 73 DHCP_NONE = 0, 74 DHCP_DISCOVER, 75 DHCP_OFFER, 76 DHCP_REQUEST, 77 DHCP_DECLINE, 78 DHCP_ACK, 79 DHCP_NACK, 80 DHCP_RELEASE, 81 DHCP_INFORM 82 }; 83 84 struct dhcp_option_cookie { 85 dhcp_option_cookie() 86 : 87 state(0), 88 file_has_options(false), 89 server_name_has_options(false) 90 { 91 } 92 93 const uint8* next; 94 uint8 state; 95 bool file_has_options; 96 bool server_name_has_options; 97 }; 98 99 struct dhcp_message { 100 dhcp_message(message_type type); 101 102 uint8 opcode; 103 uint8 hardware_type; 104 uint8 hardware_address_length; 105 uint8 hop_count; 106 uint32 transaction_id; 107 uint16 seconds_since_start; 108 uint16 flags; 109 in_addr_t client_address; 110 in_addr_t your_address; 111 in_addr_t server_address; 112 in_addr_t gateway_address; 113 uint8 mac_address[16]; 114 uint8 server_name[64]; 115 uint8 file[128]; 116 uint32 options_magic; 117 uint8 options[1260]; 118 119 size_t MinSize() const { return 576; } 120 size_t Size() const; 121 122 bool HasOptions() const; 123 bool NextOption(dhcp_option_cookie& cookie, message_option& option, 124 const uint8*& data, size_t& size) const; 125 message_type Type() const; 126 const uint8* LastOption() const; 127 128 uint8* PrepareMessage(uint8 type); 129 uint8* PutOption(uint8* options, message_option option); 130 uint8* PutOption(uint8* options, message_option option, uint8 data); 131 uint8* PutOption(uint8* options, message_option option, uint16 data); 132 uint8* PutOption(uint8* options, message_option option, uint32 data); 133 uint8* PutOption(uint8* options, message_option option, const uint8* data, 134 uint32 size); 135 uint8* FinishOptions(uint8 *); 136 } _PACKED; 137 138 #define DHCP_FLAG_BROADCAST 0x8000 139 140 #define ARP_HARDWARE_TYPE_ETHER 1 141 142 const uint32 kMsgLeaseTime = 'lstm'; 143 144 static const uint8 kRequiredParameters[] = { 145 OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS, 146 OPTION_DOMAIN_NAME_SERVER, OPTION_BROADCAST_ADDRESS 147 }; 148 149 150 dhcp_message::dhcp_message(message_type type) 151 { 152 memset(this, 0, sizeof(*this)); 153 options_magic = htonl(OPTION_MAGIC); 154 155 uint8* next = PrepareMessage(type); 156 FinishOptions(next); 157 } 158 159 160 bool 161 dhcp_message::HasOptions() const 162 { 163 return options_magic == htonl(OPTION_MAGIC); 164 } 165 166 167 bool 168 dhcp_message::NextOption(dhcp_option_cookie& cookie, 169 message_option& option, const uint8*& data, size_t& size) const 170 { 171 if (cookie.state == 0) { 172 if (!HasOptions()) 173 return false; 174 175 cookie.state++; 176 cookie.next = options; 177 } 178 179 uint32 bytesLeft = 0; 180 181 switch (cookie.state) { 182 case 1: 183 // options from "options" 184 bytesLeft = sizeof(options) + cookie.next - options; 185 break; 186 187 case 2: 188 // options from "file" 189 bytesLeft = sizeof(options) + cookie.next - options; 190 break; 191 192 case 3: 193 // options from "server_name" 194 bytesLeft = sizeof(options) + cookie.next - options; 195 break; 196 } 197 198 while (true) { 199 if (bytesLeft == 0) { 200 // TODO: suppport OPTION_OVERLOAD! 201 cookie.state = 4; 202 return false; 203 } 204 205 option = (message_option)cookie.next[0]; 206 if (option == OPTION_END) { 207 cookie.state = 4; 208 return false; 209 } else if (option == OPTION_PAD) { 210 bytesLeft--; 211 cookie.next++; 212 continue; 213 } 214 215 size = cookie.next[1]; 216 data = &cookie.next[2]; 217 cookie.next += 2 + size; 218 219 if (option == OPTION_OVERLOAD) { 220 cookie.file_has_options = data[0] & 1; 221 cookie.server_name_has_options = data[0] & 2; 222 continue; 223 } 224 225 return true; 226 } 227 } 228 229 230 message_type 231 dhcp_message::Type() const 232 { 233 dhcp_option_cookie cookie; 234 message_option option; 235 const uint8* data; 236 size_t size; 237 while (NextOption(cookie, option, data, size)) { 238 // iterate through all options 239 if (option == OPTION_MESSAGE_TYPE) 240 return (message_type)data[0]; 241 } 242 243 return DHCP_NONE; 244 } 245 246 247 const uint8* 248 dhcp_message::LastOption() const 249 { 250 dhcp_option_cookie cookie; 251 message_option option; 252 const uint8* data; 253 size_t size; 254 while (NextOption(cookie, option, data, size)) { 255 // iterate through all options 256 } 257 258 return cookie.next; 259 } 260 261 262 size_t 263 dhcp_message::Size() const 264 { 265 const uint8* last = LastOption(); 266 return sizeof(dhcp_message) - sizeof(options) + last + 1 - options; 267 } 268 269 270 uint8* 271 dhcp_message::PrepareMessage(uint8 type) 272 { 273 uint8 *next = options; 274 next = PutOption(next, OPTION_MESSAGE_TYPE, type); 275 next = PutOption(next, OPTION_MESSAGE_SIZE, 276 (uint16)htons(sizeof(dhcp_message))); 277 return next; 278 } 279 280 281 uint8* 282 dhcp_message::PutOption(uint8* options, message_option option) 283 { 284 options[0] = option; 285 return options + 1; 286 } 287 288 289 uint8* 290 dhcp_message::PutOption(uint8* options, message_option option, uint8 data) 291 { 292 return PutOption(options, option, &data, 1); 293 } 294 295 296 uint8* 297 dhcp_message::PutOption(uint8* options, message_option option, uint16 data) 298 { 299 return PutOption(options, option, (uint8*)&data, sizeof(data)); 300 } 301 302 303 uint8* 304 dhcp_message::PutOption(uint8* options, message_option option, uint32 data) 305 { 306 return PutOption(options, option, (uint8*)&data, sizeof(data)); 307 } 308 309 310 uint8* 311 dhcp_message::PutOption(uint8* options, message_option option, 312 const uint8* data, uint32 size) 313 { 314 options[0] = option; 315 options[1] = size; 316 memcpy(&options[2], data, size); 317 318 return options + 2 + size; 319 } 320 321 322 uint8* 323 dhcp_message::FinishOptions(uint8 *next) 324 { 325 return PutOption(next, OPTION_END); 326 } 327 328 329 // #pragma mark - 330 331 332 DHCPClient::DHCPClient(BMessenger target, const char* device) 333 : AutoconfigClient("dhcp", target, device), 334 fConfiguration(kMsgConfigureInterface), 335 fRunner(NULL), 336 fLeaseTime(0) 337 { 338 fStartTime = system_time(); 339 fTransactionID = (uint32)fStartTime; 340 341 fStatus = get_mac_address(device, fMAC); 342 if (fStatus < B_OK) 343 return; 344 345 memset(&fServer, 0, sizeof(struct sockaddr_in)); 346 fServer.sin_family = AF_INET; 347 fServer.sin_len = sizeof(struct sockaddr_in); 348 fServer.sin_port = htons(DHCP_SERVER_PORT); 349 350 openlog_thread("DHCP", 0, LOG_DAEMON); 351 } 352 353 354 DHCPClient::~DHCPClient() 355 { 356 if (fStatus != B_OK) 357 return; 358 359 delete fRunner; 360 361 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 362 if (socket < 0) 363 return; 364 365 // release lease 366 367 dhcp_message release(DHCP_RELEASE); 368 _PrepareMessage(release, BOUND); 369 370 _SendMessage(socket, release, fServer); 371 close(socket); 372 373 closelog_thread(); 374 } 375 376 377 status_t 378 DHCPClient::Initialize() 379 { 380 fStatus = _Negotiate(INIT); 381 syslog(LOG_DEBUG, "DHCP for %s, status: %s\n", Device(), strerror(fStatus)); 382 return fStatus; 383 } 384 385 386 status_t 387 DHCPClient::_Negotiate(dhcp_state state) 388 { 389 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 390 if (socket < 0) 391 return errno; 392 393 sockaddr_in local; 394 memset(&local, 0, sizeof(struct sockaddr_in)); 395 local.sin_family = AF_INET; 396 local.sin_len = sizeof(struct sockaddr_in); 397 local.sin_port = htons(DHCP_CLIENT_PORT); 398 local.sin_addr.s_addr = INADDR_ANY; 399 400 // Enable reusing the port . This is needed in case there is more 401 // than 1 interface that needs to be configured. Note that the only reason 402 // this works is because there is code below to bind to a specific 403 // interface. 404 int option = 1; 405 setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option)); 406 407 if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) { 408 close(socket); 409 return errno; 410 } 411 412 sockaddr_in broadcast; 413 memset(&broadcast, 0, sizeof(struct sockaddr_in)); 414 broadcast.sin_family = AF_INET; 415 broadcast.sin_len = sizeof(struct sockaddr_in); 416 broadcast.sin_port = htons(DHCP_SERVER_PORT); 417 broadcast.sin_addr.s_addr = INADDR_BROADCAST; 418 419 option = 1; 420 setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); 421 422 if (state == INIT) { 423 // The local interface does not have an address yet, bind the socket 424 // to the device directly. 425 int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); 426 if (linkSocket >= 0) { 427 // we need to know the index of the device to be able to bind to it 428 ifreq request; 429 prepare_request(request, Device()); 430 if (ioctl(linkSocket, SIOCGIFINDEX, &request, sizeof(struct ifreq)) 431 == 0) { 432 setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, 433 &request.ifr_index, sizeof(int)); 434 } 435 436 close(linkSocket); 437 } 438 } 439 440 bigtime_t previousLeaseTime = fLeaseTime; 441 fLeaseTime = 0; 442 fRenewalTime = 0; 443 fRebindingTime = 0; 444 445 status_t status = B_ERROR; 446 time_t timeout; 447 uint32 tries; 448 _ResetTimeout(socket, timeout, tries); 449 450 dhcp_message discover(DHCP_DISCOVER); 451 _PrepareMessage(discover, state); 452 453 dhcp_message request(DHCP_REQUEST); 454 _PrepareMessage(request, state); 455 456 // send discover/request message 457 status = _SendMessage(socket, state == INIT ? discover : request, 458 state != RENEWAL ? broadcast : fServer); 459 if (status < B_OK) { 460 close(socket); 461 return status; 462 } 463 464 // receive loop until we've got an offer and acknowledged it 465 466 while (state != ACKNOWLEDGED) { 467 char buffer[2048]; 468 ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer), 469 0, NULL, NULL); 470 if (bytesReceived < 0 && errno == B_TIMED_OUT) { 471 // depending on the state, we'll just try again 472 if (!_TimeoutShift(socket, timeout, tries)) { 473 close(socket); 474 return B_TIMED_OUT; 475 } 476 477 if (state == INIT) 478 status = _SendMessage(socket, discover, broadcast); 479 else { 480 status = _SendMessage(socket, request, state != RENEWAL 481 ? broadcast : fServer); 482 } 483 484 if (status < B_OK) 485 break; 486 } else if (bytesReceived < B_OK) 487 break; 488 489 dhcp_message *message = (dhcp_message *)buffer; 490 if (message->transaction_id != htonl(fTransactionID) 491 || !message->HasOptions() 492 || memcmp(message->mac_address, discover.mac_address, 493 discover.hardware_address_length)) { 494 // this message is not for us 495 continue; 496 } 497 498 switch (message->Type()) { 499 case DHCP_NONE: 500 default: 501 // ignore this message 502 break; 503 504 case DHCP_OFFER: 505 { 506 // first offer wins 507 if (state != INIT) 508 break; 509 510 // collect interface options 511 512 fAssignedAddress = message->your_address; 513 514 fConfiguration.MakeEmpty(); 515 fConfiguration.AddString("device", Device()); 516 fConfiguration.AddBool("auto", true); 517 518 BMessage address; 519 address.AddString("family", "inet"); 520 address.AddString("address", _ToString(fAssignedAddress)); 521 _ParseOptions(*message, address); 522 523 fConfiguration.AddMessage("address", &address); 524 525 // request configuration from the server 526 527 _ResetTimeout(socket, timeout, tries); 528 state = REQUESTING; 529 _PrepareMessage(request, state); 530 531 status = _SendMessage(socket, request, broadcast); 532 // we're sending a broadcast so that all potential offers 533 // get an answer 534 break; 535 } 536 537 case DHCP_ACK: 538 { 539 if (state != REQUESTING && state != REBINDING 540 && state != RENEWAL) 541 continue; 542 543 // TODO: we might want to configure the stuff, don't we? 544 BMessage address; 545 _ParseOptions(*message, address); 546 // TODO: currently, only lease time and DNS is updated this way 547 548 // our address request has been acknowledged 549 state = ACKNOWLEDGED; 550 551 // configure interface 552 BMessage reply; 553 Target().SendMessage(&fConfiguration, &reply); 554 555 if (reply.FindInt32("status", &fStatus) != B_OK) 556 status = B_OK; 557 break; 558 } 559 560 case DHCP_NACK: 561 if (state != REQUESTING) 562 continue; 563 564 // try again (maybe we should prefer other servers if this 565 // happens more than once) 566 status = _SendMessage(socket, discover, broadcast); 567 if (status == B_OK) 568 state = INIT; 569 break; 570 } 571 } 572 573 close(socket); 574 575 if (status == B_OK && fLeaseTime > 0) { 576 // notify early enough when the lease is 577 if (fRenewalTime == 0) 578 fRenewalTime = fLeaseTime * 2/3; 579 if (fRebindingTime == 0) 580 fRebindingTime = fLeaseTime * 5/6; 581 582 bigtime_t now = system_time(); 583 _RestartLease(fRenewalTime); 584 585 fLeaseTime += now; 586 fRenewalTime += now; 587 fRebindingTime += now; 588 // make lease times absolute 589 } else { 590 fLeaseTime = previousLeaseTime; 591 bigtime_t now = system_time(); 592 fRenewalTime = (fLeaseTime - now) * 2/3 + now; 593 fRebindingTime = (fLeaseTime - now) * 5/6 + now; 594 } 595 596 return status; 597 } 598 599 600 void 601 DHCPClient::_RestartLease(bigtime_t leaseTime) 602 { 603 if (leaseTime == 0) 604 return; 605 606 BMessage lease(kMsgLeaseTime); 607 fRunner = new BMessageRunner(this, &lease, leaseTime, 1); 608 } 609 610 611 void 612 DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address) 613 { 614 dhcp_option_cookie cookie; 615 message_option option; 616 const uint8* data; 617 size_t size; 618 while (message.NextOption(cookie, option, data, size)) { 619 // iterate through all options 620 switch (option) { 621 case OPTION_ROUTER_ADDRESS: 622 address.AddString("gateway", _ToString(data)); 623 break; 624 case OPTION_SUBNET_MASK: 625 address.AddString("mask", _ToString(data)); 626 break; 627 case OPTION_BROADCAST_ADDRESS: 628 address.AddString("broadcast", _ToString(data)); 629 break; 630 case OPTION_DOMAIN_NAME_SERVER: 631 { 632 // TODO: for now, we write it just out to /etc/resolv.conf 633 FILE* file = fopen("/etc/resolv.conf", "w"); 634 for (uint32 i = 0; i < size / 4; i++) { 635 syslog(LOG_INFO, "DNS: %s\n", 636 _ToString(&data[i * 4]).String()); 637 if (file != NULL) { 638 fprintf(file, "nameserver %s\n", 639 _ToString(&data[i * 4]).String()); 640 } 641 } 642 fclose(file); 643 break; 644 } 645 case OPTION_SERVER_ADDRESS: 646 fServer.sin_addr.s_addr = *(in_addr_t*)data; 647 break; 648 649 case OPTION_ADDRESS_LEASE_TIME: 650 syslog(LOG_INFO, "lease time of %lu seconds\n", 651 htonl(*(uint32*)data)); 652 fLeaseTime = htonl(*(uint32*)data) * 1000000LL; 653 break; 654 case OPTION_RENEWAL_TIME: 655 syslog(LOG_INFO, "renewal time of %lu seconds\n", 656 htonl(*(uint32*)data)); 657 fRenewalTime = htonl(*(uint32*)data) * 1000000LL; 658 break; 659 case OPTION_REBINDING_TIME: 660 syslog(LOG_INFO, "rebinding time of %lu seconds\n", 661 htonl(*(uint32*)data)); 662 fRebindingTime = htonl(*(uint32*)data) * 1000000LL; 663 break; 664 665 case OPTION_HOST_NAME: 666 { 667 char name[256]; 668 memcpy(name, data, size); 669 name[size] = '\0'; 670 syslog(LOG_INFO, "DHCP host name: \"%s\"\n", name); 671 break; 672 } 673 674 case OPTION_DOMAIN_NAME: 675 { 676 char name[256]; 677 memcpy(name, data, size); 678 name[size] = '\0'; 679 syslog(LOG_INFO, "DHCP domain name: \"%s\"\n", name); 680 break; 681 } 682 683 case OPTION_MESSAGE_TYPE: 684 break; 685 686 default: 687 syslog(LOG_INFO, "unknown option %lu\n", (uint32)option); 688 break; 689 } 690 } 691 } 692 693 694 void 695 DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state) 696 { 697 message.opcode = BOOT_REQUEST; 698 message.hardware_type = ARP_HARDWARE_TYPE_ETHER; 699 message.hardware_address_length = 6; 700 message.transaction_id = htonl(fTransactionID); 701 message.seconds_since_start = htons(min_c((system_time() - fStartTime) 702 / 1000000LL, 65535)); 703 memcpy(message.mac_address, fMAC, 6); 704 705 message_type type = message.Type(); 706 707 switch (type) { 708 case DHCP_REQUEST: 709 case DHCP_RELEASE: 710 { 711 // add server identifier option 712 uint8* next = message.PrepareMessage(type); 713 next = message.PutOption(next, OPTION_SERVER_ADDRESS, 714 (uint32)fServer.sin_addr.s_addr); 715 716 // In RENEWAL or REBINDING state, we must set the client_address field, and not 717 // use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages 718 if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING)) { 719 next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, 720 (uint32)fAssignedAddress); 721 next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 722 kRequiredParameters, sizeof(kRequiredParameters)); 723 } else 724 message.client_address = fAssignedAddress; 725 726 message.FinishOptions(next); 727 break; 728 } 729 730 case DHCP_DISCOVER: 731 { 732 uint8 *next = message.PrepareMessage(type); 733 next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 734 kRequiredParameters, sizeof(kRequiredParameters)); 735 message.FinishOptions(next); 736 break; 737 } 738 739 default: 740 // the default options are fine 741 break; 742 } 743 } 744 745 746 void 747 DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries) 748 { 749 timeout = DEFAULT_TIMEOUT; 750 tries = 0; 751 752 struct timeval value; 753 value.tv_sec = timeout; 754 value.tv_usec = 0; 755 setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 756 } 757 758 759 bool 760 DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries) 761 { 762 timeout += timeout; 763 if (timeout > MAX_TIMEOUT) { 764 timeout = DEFAULT_TIMEOUT; 765 766 if (++tries > 2) 767 return false; 768 } 769 syslog(LOG_DEBUG, "DHCP timeout shift: %lu secs (try %lu)\n", timeout, 770 tries); 771 772 struct timeval value; 773 value.tv_sec = timeout; 774 value.tv_usec = 0; 775 setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 776 777 return true; 778 } 779 780 781 BString 782 DHCPClient::_ToString(const uint8* data) const 783 { 784 BString target = inet_ntoa(*(in_addr*)data); 785 return target; 786 } 787 788 789 BString 790 DHCPClient::_ToString(in_addr_t address) const 791 { 792 BString target = inet_ntoa(*(in_addr*)&address); 793 return target; 794 } 795 796 797 status_t 798 DHCPClient::_SendMessage(int socket, dhcp_message& message, 799 sockaddr_in& address) const 800 { 801 ssize_t bytesSent = sendto(socket, &message, message.Size(), 802 address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0, 803 (struct sockaddr*)&address, sizeof(sockaddr_in)); 804 if (bytesSent < 0) 805 return errno; 806 807 return B_OK; 808 } 809 810 811 dhcp_state 812 DHCPClient::_CurrentState() const 813 { 814 bigtime_t now = system_time(); 815 816 if (now > fLeaseTime || fStatus < B_OK) 817 return INIT; 818 if (now >= fRebindingTime) 819 return REBINDING; 820 if (now >= fRenewalTime) 821 return RENEWAL; 822 823 return BOUND; 824 } 825 826 827 void 828 DHCPClient::MessageReceived(BMessage* message) 829 { 830 switch (message->what) { 831 case kMsgLeaseTime: 832 { 833 dhcp_state state = _CurrentState(); 834 835 bigtime_t next; 836 if (_Negotiate(state) == B_OK) { 837 switch (state) { 838 case RENEWAL: 839 next = fRebindingTime; 840 break; 841 case REBINDING: 842 default: 843 next = fRenewalTime; 844 break; 845 } 846 } else { 847 switch (state) { 848 case RENEWAL: 849 next = (fLeaseTime - fRebindingTime) / 4 + system_time(); 850 break; 851 case REBINDING: 852 default: 853 next = (fLeaseTime - fRenewalTime) / 4 + system_time(); 854 break; 855 } 856 } 857 858 _RestartLease(next - system_time()); 859 break; 860 } 861 862 default: 863 BHandler::MessageReceived(message); 864 break; 865 } 866 } 867