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