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 if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) { 401 close(socket); 402 return errno; 403 } 404 405 sockaddr_in broadcast; 406 memset(&broadcast, 0, sizeof(struct sockaddr_in)); 407 broadcast.sin_family = AF_INET; 408 broadcast.sin_len = sizeof(struct sockaddr_in); 409 broadcast.sin_port = htons(DHCP_SERVER_PORT); 410 broadcast.sin_addr.s_addr = INADDR_BROADCAST; 411 412 int option = 1; 413 setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); 414 415 if (state == INIT) { 416 // The local interface does not have an address yet, bind the socket 417 // to the device directly. 418 int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); 419 if (linkSocket >= 0) { 420 // we need to know the index of the device to be able to bind to it 421 ifreq request; 422 prepare_request(request, Device()); 423 if (ioctl(linkSocket, SIOCGIFINDEX, &request, sizeof(struct ifreq)) 424 == 0) { 425 setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, 426 &request.ifr_index, sizeof(int)); 427 } 428 429 close(linkSocket); 430 } 431 } 432 433 bigtime_t previousLeaseTime = fLeaseTime; 434 fLeaseTime = 0; 435 fRenewalTime = 0; 436 fRebindingTime = 0; 437 438 status_t status = B_ERROR; 439 time_t timeout; 440 uint32 tries; 441 _ResetTimeout(socket, timeout, tries); 442 443 dhcp_message discover(DHCP_DISCOVER); 444 _PrepareMessage(discover, state); 445 446 dhcp_message request(DHCP_REQUEST); 447 _PrepareMessage(request, state); 448 449 // send discover/request message 450 status = _SendMessage(socket, state == INIT ? discover : request, 451 state != RENEWAL ? broadcast : fServer); 452 if (status < B_OK) { 453 close(socket); 454 return status; 455 } 456 457 // receive loop until we've got an offer and acknowledged it 458 459 while (state != ACKNOWLEDGED) { 460 char buffer[2048]; 461 ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer), 462 0, NULL, NULL); 463 if (bytesReceived < 0 && errno == B_TIMED_OUT) { 464 // depending on the state, we'll just try again 465 if (!_TimeoutShift(socket, timeout, tries)) { 466 close(socket); 467 return B_TIMED_OUT; 468 } 469 470 if (state == INIT) 471 status = _SendMessage(socket, discover, broadcast); 472 else { 473 status = _SendMessage(socket, request, state != RENEWAL 474 ? broadcast : fServer); 475 } 476 477 if (status < B_OK) 478 break; 479 } else if (bytesReceived < B_OK) 480 break; 481 482 dhcp_message *message = (dhcp_message *)buffer; 483 if (message->transaction_id != htonl(fTransactionID) 484 || !message->HasOptions() 485 || memcmp(message->mac_address, discover.mac_address, 486 discover.hardware_address_length)) { 487 // this message is not for us 488 continue; 489 } 490 491 switch (message->Type()) { 492 case DHCP_NONE: 493 default: 494 // ignore this message 495 break; 496 497 case DHCP_OFFER: 498 { 499 // first offer wins 500 if (state != INIT) 501 break; 502 503 // collect interface options 504 505 fAssignedAddress = message->your_address; 506 507 fConfiguration.MakeEmpty(); 508 fConfiguration.AddString("device", Device()); 509 fConfiguration.AddBool("auto", true); 510 511 BMessage address; 512 address.AddString("family", "inet"); 513 address.AddString("address", _ToString(fAssignedAddress)); 514 _ParseOptions(*message, address); 515 516 fConfiguration.AddMessage("address", &address); 517 518 // request configuration from the server 519 520 _ResetTimeout(socket, timeout, tries); 521 state = REQUESTING; 522 _PrepareMessage(request, state); 523 524 status = _SendMessage(socket, request, broadcast); 525 // we're sending a broadcast so that all potential offers 526 // get an answer 527 break; 528 } 529 530 case DHCP_ACK: 531 { 532 if (state != REQUESTING && state != REBINDING 533 && state != RENEWAL) 534 continue; 535 536 // TODO: we might want to configure the stuff, don't we? 537 BMessage address; 538 _ParseOptions(*message, address); 539 // TODO: currently, only lease time and DNS is updated this way 540 541 // our address request has been acknowledged 542 state = ACKNOWLEDGED; 543 544 // configure interface 545 BMessage reply; 546 Target().SendMessage(&fConfiguration, &reply); 547 548 if (reply.FindInt32("status", &fStatus) != B_OK) 549 status = B_OK; 550 break; 551 } 552 553 case DHCP_NACK: 554 if (state != REQUESTING) 555 continue; 556 557 // try again (maybe we should prefer other servers if this 558 // happens more than once) 559 status = _SendMessage(socket, discover, broadcast); 560 if (status == B_OK) 561 state = INIT; 562 break; 563 } 564 } 565 566 close(socket); 567 568 if (status == B_OK && fLeaseTime > 0) { 569 // notify early enough when the lease is 570 if (fRenewalTime == 0) 571 fRenewalTime = fLeaseTime * 2/3; 572 if (fRebindingTime == 0) 573 fRebindingTime = fLeaseTime * 5/6; 574 575 bigtime_t now = system_time(); 576 _RestartLease(fRenewalTime); 577 578 fLeaseTime += now; 579 fRenewalTime += now; 580 fRebindingTime += now; 581 // make lease times absolute 582 } else { 583 fLeaseTime = previousLeaseTime; 584 bigtime_t now = system_time(); 585 fRenewalTime = (fLeaseTime - now) * 2/3 + now; 586 fRebindingTime = (fLeaseTime - now) * 5/6 + now; 587 } 588 589 return status; 590 } 591 592 593 void 594 DHCPClient::_RestartLease(bigtime_t leaseTime) 595 { 596 if (leaseTime == 0) 597 return; 598 599 BMessage lease(kMsgLeaseTime); 600 fRunner = new BMessageRunner(this, &lease, leaseTime, 1); 601 } 602 603 604 void 605 DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address) 606 { 607 dhcp_option_cookie cookie; 608 message_option option; 609 const uint8* data; 610 size_t size; 611 while (message.NextOption(cookie, option, data, size)) { 612 // iterate through all options 613 switch (option) { 614 case OPTION_ROUTER_ADDRESS: 615 address.AddString("gateway", _ToString(data)); 616 break; 617 case OPTION_SUBNET_MASK: 618 address.AddString("mask", _ToString(data)); 619 break; 620 case OPTION_BROADCAST_ADDRESS: 621 address.AddString("broadcast", _ToString(data)); 622 break; 623 case OPTION_DOMAIN_NAME_SERVER: 624 { 625 // TODO: for now, we write it just out to /etc/resolv.conf 626 FILE* file = fopen("/etc/resolv.conf", "w"); 627 for (uint32 i = 0; i < size / 4; i++) { 628 syslog(LOG_INFO, "DNS: %s\n", 629 _ToString(&data[i * 4]).String()); 630 if (file != NULL) { 631 fprintf(file, "nameserver %s\n", 632 _ToString(&data[i * 4]).String()); 633 } 634 } 635 fclose(file); 636 break; 637 } 638 case OPTION_SERVER_ADDRESS: 639 fServer.sin_addr.s_addr = *(in_addr_t*)data; 640 break; 641 642 case OPTION_ADDRESS_LEASE_TIME: 643 syslog(LOG_INFO, "lease time of %lu seconds\n", 644 htonl(*(uint32*)data)); 645 fLeaseTime = htonl(*(uint32*)data) * 1000000LL; 646 break; 647 case OPTION_RENEWAL_TIME: 648 syslog(LOG_INFO, "renewal time of %lu seconds\n", 649 htonl(*(uint32*)data)); 650 fRenewalTime = htonl(*(uint32*)data) * 1000000LL; 651 break; 652 case OPTION_REBINDING_TIME: 653 syslog(LOG_INFO, "rebinding time of %lu seconds\n", 654 htonl(*(uint32*)data)); 655 fRebindingTime = htonl(*(uint32*)data) * 1000000LL; 656 break; 657 658 case OPTION_HOST_NAME: 659 { 660 char name[256]; 661 memcpy(name, data, size); 662 name[size] = '\0'; 663 syslog(LOG_INFO, "DHCP host name: \"%s\"\n", name); 664 break; 665 } 666 667 case OPTION_DOMAIN_NAME: 668 { 669 char name[256]; 670 memcpy(name, data, size); 671 name[size] = '\0'; 672 syslog(LOG_INFO, "DHCP domain name: \"%s\"\n", name); 673 break; 674 } 675 676 case OPTION_MESSAGE_TYPE: 677 break; 678 679 default: 680 syslog(LOG_INFO, "unknown option %lu\n", (uint32)option); 681 break; 682 } 683 } 684 } 685 686 687 void 688 DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state) 689 { 690 message.opcode = BOOT_REQUEST; 691 message.hardware_type = ARP_HARDWARE_TYPE_ETHER; 692 message.hardware_address_length = 6; 693 message.transaction_id = htonl(fTransactionID); 694 message.seconds_since_start = htons(min_c((system_time() - fStartTime) 695 / 1000000LL, 65535)); 696 memcpy(message.mac_address, fMAC, 6); 697 698 message_type type = message.Type(); 699 700 switch (type) { 701 case DHCP_REQUEST: 702 case DHCP_RELEASE: 703 { 704 // add server identifier option 705 uint8* next = message.PrepareMessage(type); 706 next = message.PutOption(next, OPTION_SERVER_ADDRESS, 707 (uint32)fServer.sin_addr.s_addr); 708 709 // In RENEWAL or REBINDING state, we must set the client_address field, and not 710 // use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages 711 if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING)) { 712 next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, 713 (uint32)fAssignedAddress); 714 next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 715 kRequiredParameters, sizeof(kRequiredParameters)); 716 } else 717 message.client_address = fAssignedAddress; 718 719 message.FinishOptions(next); 720 break; 721 } 722 723 case DHCP_DISCOVER: 724 { 725 uint8 *next = message.PrepareMessage(type); 726 next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 727 kRequiredParameters, sizeof(kRequiredParameters)); 728 message.FinishOptions(next); 729 break; 730 } 731 732 default: 733 // the default options are fine 734 break; 735 } 736 } 737 738 739 void 740 DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries) 741 { 742 timeout = DEFAULT_TIMEOUT; 743 tries = 0; 744 745 struct timeval value; 746 value.tv_sec = timeout; 747 value.tv_usec = 0; 748 setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 749 } 750 751 752 bool 753 DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries) 754 { 755 timeout += timeout; 756 if (timeout > MAX_TIMEOUT) { 757 timeout = DEFAULT_TIMEOUT; 758 759 if (++tries > 2) 760 return false; 761 } 762 syslog(LOG_DEBUG, "DHCP timeout shift: %lu secs (try %lu)\n", timeout, 763 tries); 764 765 struct timeval value; 766 value.tv_sec = timeout; 767 value.tv_usec = 0; 768 setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 769 770 return true; 771 } 772 773 774 BString 775 DHCPClient::_ToString(const uint8* data) const 776 { 777 BString target = inet_ntoa(*(in_addr*)data); 778 return target; 779 } 780 781 782 BString 783 DHCPClient::_ToString(in_addr_t address) const 784 { 785 BString target = inet_ntoa(*(in_addr*)&address); 786 return target; 787 } 788 789 790 status_t 791 DHCPClient::_SendMessage(int socket, dhcp_message& message, 792 sockaddr_in& address) const 793 { 794 ssize_t bytesSent = sendto(socket, &message, message.Size(), 795 address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0, 796 (struct sockaddr*)&address, sizeof(sockaddr_in)); 797 if (bytesSent < 0) 798 return errno; 799 800 return B_OK; 801 } 802 803 804 dhcp_state 805 DHCPClient::_CurrentState() const 806 { 807 bigtime_t now = system_time(); 808 809 if (now > fLeaseTime || fStatus < B_OK) 810 return INIT; 811 if (now >= fRebindingTime) 812 return REBINDING; 813 if (now >= fRenewalTime) 814 return RENEWAL; 815 816 return BOUND; 817 } 818 819 820 void 821 DHCPClient::MessageReceived(BMessage* message) 822 { 823 switch (message->what) { 824 case kMsgLeaseTime: 825 { 826 dhcp_state state = _CurrentState(); 827 828 bigtime_t next; 829 if (_Negotiate(state) == B_OK) { 830 switch (state) { 831 case RENEWAL: 832 next = fRebindingTime; 833 break; 834 case REBINDING: 835 default: 836 next = fRenewalTime; 837 break; 838 } 839 } else { 840 switch (state) { 841 case RENEWAL: 842 next = (fLeaseTime - fRebindingTime) / 4 + system_time(); 843 break; 844 case REBINDING: 845 default: 846 next = (fLeaseTime - fRenewalTime) / 4 + system_time(); 847 break; 848 } 849 } 850 851 _RestartLease(next - system_time()); 852 break; 853 } 854 855 default: 856 BHandler::MessageReceived(message); 857 break; 858 } 859 } 860 861