1fb81684fSAxel Dörfler /* 236bde12dSAxel Dörfler * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. 3fb81684fSAxel Dörfler * Distributed under the terms of the MIT License. 4fb81684fSAxel Dörfler * 5fb81684fSAxel Dörfler * Authors: 6fb81684fSAxel Dörfler * Axel Dörfler, axeld@pinc-software.de 7fb81684fSAxel Dörfler */ 8fb81684fSAxel Dörfler 9fb81684fSAxel Dörfler 10fb81684fSAxel Dörfler #include "DHCPClient.h" 11fb81684fSAxel Dörfler #include "NetServer.h" 12fb81684fSAxel Dörfler 13f9af6566SAxel Dörfler #include <Message.h> 146cc7630fSAxel Dörfler #include <MessageRunner.h> 15f9af6566SAxel Dörfler 16f9af6566SAxel Dörfler #include <arpa/inet.h> 17fb81684fSAxel Dörfler #include <errno.h> 18fb81684fSAxel Dörfler #include <stdio.h> 19fb81684fSAxel Dörfler #include <string.h> 2036bde12dSAxel Dörfler #include <sys/sockio.h> 21f9af6566SAxel Dörfler #include <sys/time.h> 22fb81684fSAxel Dörfler 23fb81684fSAxel Dörfler 24fb81684fSAxel Dörfler // See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options 25fb81684fSAxel Dörfler 26fb81684fSAxel Dörfler #define DHCP_CLIENT_PORT 68 27fb81684fSAxel Dörfler #define DHCP_SERVER_PORT 67 28fb81684fSAxel Dörfler 29f9af6566SAxel Dörfler #define DEFAULT_TIMEOUT 2 // secs 30f9af6566SAxel Dörfler #define MAX_TIMEOUT 15 // secs 31f9af6566SAxel Dörfler 32fb81684fSAxel Dörfler enum message_opcode { 33fb81684fSAxel Dörfler BOOT_REQUEST = 1, 34fb81684fSAxel Dörfler BOOT_REPLY 35fb81684fSAxel Dörfler }; 36fb81684fSAxel Dörfler 37fb81684fSAxel Dörfler enum message_option { 38fb81684fSAxel Dörfler OPTION_MAGIC = 0x63825363, 39fb81684fSAxel Dörfler 40fb81684fSAxel Dörfler // generic options 41fb81684fSAxel Dörfler OPTION_PAD = 0, 42f9af6566SAxel Dörfler OPTION_END = 255, 43f9af6566SAxel Dörfler OPTION_SUBNET_MASK = 1, 4465186fecSAxel Dörfler OPTION_TIME_OFFSET = 2, 45f9af6566SAxel Dörfler OPTION_ROUTER_ADDRESS = 3, 46f9af6566SAxel Dörfler OPTION_DOMAIN_NAME_SERVER = 6, 47f9af6566SAxel Dörfler OPTION_HOST_NAME = 12, 485782c5a3SAxel Dörfler OPTION_DOMAIN_NAME = 15, 49fb81684fSAxel Dörfler OPTION_DATAGRAM_SIZE = 22, 50fb81684fSAxel Dörfler OPTION_MTU = 26, 51fb81684fSAxel Dörfler OPTION_BROADCAST_ADDRESS = 28, 52fb81684fSAxel Dörfler OPTION_NETWORK_TIME_SERVERS = 42, 5365186fecSAxel Dörfler OPTION_NETBIOS_NAME_SERVER = 44, 5465186fecSAxel Dörfler OPTION_NETBIOS_SCOPE = 47, 55fb81684fSAxel Dörfler 56fb81684fSAxel Dörfler // DHCP specific options 57fb81684fSAxel Dörfler OPTION_REQUEST_IP_ADDRESS = 50, 58fb81684fSAxel Dörfler OPTION_ADDRESS_LEASE_TIME = 51, 59fb81684fSAxel Dörfler OPTION_OVERLOAD = 52, 60fb81684fSAxel Dörfler OPTION_MESSAGE_TYPE = 53, 61fb81684fSAxel Dörfler OPTION_SERVER_ADDRESS = 54, 62fb81684fSAxel Dörfler OPTION_REQUEST_PARAMETERS = 55, 63fb81684fSAxel Dörfler OPTION_ERROR_MESSAGE = 56, 64fb81684fSAxel Dörfler OPTION_MESSAGE_SIZE = 57, 65fb81684fSAxel Dörfler OPTION_RENEWAL_TIME = 58, 66fb81684fSAxel Dörfler OPTION_REBINDING_TIME = 59, 67fb81684fSAxel Dörfler OPTION_CLASS_IDENTIFIER = 60, 68fb81684fSAxel Dörfler OPTION_CLIENT_IDENTIFIER = 61, 69fb81684fSAxel Dörfler }; 70fb81684fSAxel Dörfler 71fb81684fSAxel Dörfler enum message_type { 72f9af6566SAxel Dörfler DHCP_NONE = 0, 73f9af6566SAxel Dörfler DHCP_DISCOVER, 74fb81684fSAxel Dörfler DHCP_OFFER, 75fb81684fSAxel Dörfler DHCP_REQUEST, 76fb81684fSAxel Dörfler DHCP_DECLINE, 77fb81684fSAxel Dörfler DHCP_ACK, 78f9af6566SAxel Dörfler DHCP_NACK, 79fb81684fSAxel Dörfler DHCP_RELEASE, 80fb81684fSAxel Dörfler DHCP_INFORM 81fb81684fSAxel Dörfler }; 82fb81684fSAxel Dörfler 83fb81684fSAxel Dörfler struct dhcp_option_cookie { 8415ab0bcfSAxel Dörfler dhcp_option_cookie() 8515ab0bcfSAxel Dörfler : 8615ab0bcfSAxel Dörfler state(0), 8715ab0bcfSAxel Dörfler file_has_options(false), 8815ab0bcfSAxel Dörfler server_name_has_options(false) 8915ab0bcfSAxel Dörfler { 9015ab0bcfSAxel Dörfler } 91fb81684fSAxel Dörfler 92fb81684fSAxel Dörfler const uint8* next; 93fb81684fSAxel Dörfler uint8 state; 94fb81684fSAxel Dörfler bool file_has_options; 95fb81684fSAxel Dörfler bool server_name_has_options; 96fb81684fSAxel Dörfler }; 97fb81684fSAxel Dörfler 98fb81684fSAxel Dörfler struct dhcp_message { 99fb81684fSAxel Dörfler dhcp_message(message_type type); 100fb81684fSAxel Dörfler 101fb81684fSAxel Dörfler uint8 opcode; 102fb81684fSAxel Dörfler uint8 hardware_type; 103fb81684fSAxel Dörfler uint8 hardware_address_length; 104fb81684fSAxel Dörfler uint8 hop_count; 105fb81684fSAxel Dörfler uint32 transaction_id; 10646ff5400SAxel Dörfler uint16 seconds_since_start; 107fb81684fSAxel Dörfler uint16 flags; 108fb81684fSAxel Dörfler in_addr_t client_address; 109fb81684fSAxel Dörfler in_addr_t your_address; 110fb81684fSAxel Dörfler in_addr_t server_address; 111fb81684fSAxel Dörfler in_addr_t gateway_address; 112fb81684fSAxel Dörfler uint8 mac_address[16]; 113fb81684fSAxel Dörfler uint8 server_name[64]; 114fb81684fSAxel Dörfler uint8 file[128]; 115fb81684fSAxel Dörfler uint32 options_magic; 116fb81684fSAxel Dörfler uint8 options[1260]; 117fb81684fSAxel Dörfler 118fb81684fSAxel Dörfler size_t MinSize() const { return 576; } 119fb81684fSAxel Dörfler size_t Size() const; 120fb81684fSAxel Dörfler 121fb81684fSAxel Dörfler bool HasOptions() const; 122fb81684fSAxel Dörfler bool NextOption(dhcp_option_cookie& cookie, message_option& option, 123fb81684fSAxel Dörfler const uint8*& data, size_t& size) const; 124f9af6566SAxel Dörfler message_type Type() const; 125fb81684fSAxel Dörfler const uint8* LastOption() const; 126fb81684fSAxel Dörfler 127a073ba1aSHugo Santos uint8* PrepareMessage(uint8 type); 128fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option); 129fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint8 data); 130fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint16 data); 131fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint32 data); 13215ab0bcfSAxel Dörfler uint8* PutOption(uint8* options, message_option option, const uint8* data, 13315ab0bcfSAxel Dörfler uint32 size); 134a073ba1aSHugo Santos uint8* FinishOptions(uint8 *); 135fb81684fSAxel Dörfler } _PACKED; 136fb81684fSAxel Dörfler 1370cf5e6acSAxel Dörfler #define DHCP_FLAG_BROADCAST 0x8000 138fb81684fSAxel Dörfler 139fb81684fSAxel Dörfler #define ARP_HARDWARE_TYPE_ETHER 1 140fb81684fSAxel Dörfler 1416cc7630fSAxel Dörfler const uint32 kMsgLeaseTime = 'lstm'; 1426cc7630fSAxel Dörfler 1435d4d5313SHugo Santos static const uint8 kRequiredParameters[] = { 14465186fecSAxel Dörfler OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS, 14565186fecSAxel Dörfler OPTION_DOMAIN_NAME_SERVER, OPTION_BROADCAST_ADDRESS 1465d4d5313SHugo Santos }; 1475d4d5313SHugo Santos 148fb81684fSAxel Dörfler 149fb81684fSAxel Dörfler dhcp_message::dhcp_message(message_type type) 150fb81684fSAxel Dörfler { 151fb81684fSAxel Dörfler memset(this, 0, sizeof(*this)); 152fb81684fSAxel Dörfler options_magic = htonl(OPTION_MAGIC); 153fb81684fSAxel Dörfler 154a073ba1aSHugo Santos uint8* next = PrepareMessage(type); 155a073ba1aSHugo Santos FinishOptions(next); 156fb81684fSAxel Dörfler } 157fb81684fSAxel Dörfler 158fb81684fSAxel Dörfler 159fb81684fSAxel Dörfler bool 160fb81684fSAxel Dörfler dhcp_message::HasOptions() const 161fb81684fSAxel Dörfler { 162fb81684fSAxel Dörfler return options_magic == htonl(OPTION_MAGIC); 163fb81684fSAxel Dörfler } 164fb81684fSAxel Dörfler 165fb81684fSAxel Dörfler 166fb81684fSAxel Dörfler bool 167fb81684fSAxel Dörfler dhcp_message::NextOption(dhcp_option_cookie& cookie, 168fb81684fSAxel Dörfler message_option& option, const uint8*& data, size_t& size) const 169fb81684fSAxel Dörfler { 170fb81684fSAxel Dörfler if (cookie.state == 0) { 171fb81684fSAxel Dörfler if (!HasOptions()) 172fb81684fSAxel Dörfler return false; 173fb81684fSAxel Dörfler 174fb81684fSAxel Dörfler cookie.state++; 175fb81684fSAxel Dörfler cookie.next = options; 176fb81684fSAxel Dörfler } 177fb81684fSAxel Dörfler 178fb81684fSAxel Dörfler uint32 bytesLeft = 0; 179fb81684fSAxel Dörfler 180fb81684fSAxel Dörfler switch (cookie.state) { 181fb81684fSAxel Dörfler case 1: 182fb81684fSAxel Dörfler // options from "options" 183fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 184fb81684fSAxel Dörfler break; 185fb81684fSAxel Dörfler 186fb81684fSAxel Dörfler case 2: 187fb81684fSAxel Dörfler // options from "file" 188fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 189fb81684fSAxel Dörfler break; 190fb81684fSAxel Dörfler 191fb81684fSAxel Dörfler case 3: 192fb81684fSAxel Dörfler // options from "server_name" 193fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 194fb81684fSAxel Dörfler break; 195fb81684fSAxel Dörfler } 196fb81684fSAxel Dörfler 197fb81684fSAxel Dörfler while (true) { 198fb81684fSAxel Dörfler if (bytesLeft == 0) { 199fb81684fSAxel Dörfler // TODO: suppport OPTION_OVERLOAD! 200fb81684fSAxel Dörfler cookie.state = 4; 201fb81684fSAxel Dörfler return false; 202fb81684fSAxel Dörfler } 203fb81684fSAxel Dörfler 204fb81684fSAxel Dörfler option = (message_option)cookie.next[0]; 205fb81684fSAxel Dörfler if (option == OPTION_END) { 206fb81684fSAxel Dörfler cookie.state = 4; 207fb81684fSAxel Dörfler return false; 208fb81684fSAxel Dörfler } else if (option == OPTION_PAD) { 209fb81684fSAxel Dörfler bytesLeft--; 210fb81684fSAxel Dörfler cookie.next++; 211fb81684fSAxel Dörfler continue; 212fb81684fSAxel Dörfler } 213fb81684fSAxel Dörfler 214fb81684fSAxel Dörfler size = cookie.next[1]; 215fb81684fSAxel Dörfler data = &cookie.next[2]; 216fb81684fSAxel Dörfler cookie.next += 2 + size; 217fb81684fSAxel Dörfler 218fb81684fSAxel Dörfler if (option == OPTION_OVERLOAD) { 219fb81684fSAxel Dörfler cookie.file_has_options = data[0] & 1; 220fb81684fSAxel Dörfler cookie.server_name_has_options = data[0] & 2; 221fb81684fSAxel Dörfler continue; 222fb81684fSAxel Dörfler } 223fb81684fSAxel Dörfler 224fb81684fSAxel Dörfler return true; 225fb81684fSAxel Dörfler } 226fb81684fSAxel Dörfler } 227fb81684fSAxel Dörfler 228fb81684fSAxel Dörfler 229f9af6566SAxel Dörfler message_type 230f9af6566SAxel Dörfler dhcp_message::Type() const 231f9af6566SAxel Dörfler { 232f9af6566SAxel Dörfler dhcp_option_cookie cookie; 233f9af6566SAxel Dörfler message_option option; 234f9af6566SAxel Dörfler const uint8* data; 235f9af6566SAxel Dörfler size_t size; 236f9af6566SAxel Dörfler while (NextOption(cookie, option, data, size)) { 237f9af6566SAxel Dörfler // iterate through all options 238f9af6566SAxel Dörfler if (option == OPTION_MESSAGE_TYPE) 239f9af6566SAxel Dörfler return (message_type)data[0]; 240f9af6566SAxel Dörfler } 241f9af6566SAxel Dörfler 242f9af6566SAxel Dörfler return DHCP_NONE; 243f9af6566SAxel Dörfler } 244f9af6566SAxel Dörfler 245f9af6566SAxel Dörfler 246fb81684fSAxel Dörfler const uint8* 247fb81684fSAxel Dörfler dhcp_message::LastOption() const 248fb81684fSAxel Dörfler { 249fb81684fSAxel Dörfler dhcp_option_cookie cookie; 250fb81684fSAxel Dörfler message_option option; 251fb81684fSAxel Dörfler const uint8* data; 252fb81684fSAxel Dörfler size_t size; 253fb81684fSAxel Dörfler while (NextOption(cookie, option, data, size)) { 254fb81684fSAxel Dörfler // iterate through all options 255fb81684fSAxel Dörfler } 256fb81684fSAxel Dörfler 257fb81684fSAxel Dörfler return cookie.next; 258fb81684fSAxel Dörfler } 259fb81684fSAxel Dörfler 260fb81684fSAxel Dörfler 261fb81684fSAxel Dörfler size_t 262fb81684fSAxel Dörfler dhcp_message::Size() const 263fb81684fSAxel Dörfler { 264fb81684fSAxel Dörfler const uint8* last = LastOption(); 265fb81684fSAxel Dörfler return sizeof(dhcp_message) - sizeof(options) + last + 1 - options; 266fb81684fSAxel Dörfler } 267fb81684fSAxel Dörfler 268fb81684fSAxel Dörfler 269fb81684fSAxel Dörfler uint8* 270a073ba1aSHugo Santos dhcp_message::PrepareMessage(uint8 type) 271a073ba1aSHugo Santos { 272a073ba1aSHugo Santos uint8 *next = options; 273a073ba1aSHugo Santos next = PutOption(next, OPTION_MESSAGE_TYPE, type); 27415ab0bcfSAxel Dörfler next = PutOption(next, OPTION_MESSAGE_SIZE, 27515ab0bcfSAxel Dörfler (uint16)htons(sizeof(dhcp_message))); 276a073ba1aSHugo Santos return next; 277a073ba1aSHugo Santos } 278a073ba1aSHugo Santos 27965186fecSAxel Dörfler 280a073ba1aSHugo Santos uint8* 281fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option) 282fb81684fSAxel Dörfler { 283fb81684fSAxel Dörfler options[0] = option; 284fb81684fSAxel Dörfler return options + 1; 285fb81684fSAxel Dörfler } 286fb81684fSAxel Dörfler 287fb81684fSAxel Dörfler 288fb81684fSAxel Dörfler uint8* 289fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8 data) 290fb81684fSAxel Dörfler { 291fb81684fSAxel Dörfler return PutOption(options, option, &data, 1); 292fb81684fSAxel Dörfler } 293fb81684fSAxel Dörfler 294fb81684fSAxel Dörfler 295fb81684fSAxel Dörfler uint8* 296fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint16 data) 297fb81684fSAxel Dörfler { 298fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 299fb81684fSAxel Dörfler } 300fb81684fSAxel Dörfler 301fb81684fSAxel Dörfler 302fb81684fSAxel Dörfler uint8* 303fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint32 data) 304fb81684fSAxel Dörfler { 305fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 306fb81684fSAxel Dörfler } 307fb81684fSAxel Dörfler 308fb81684fSAxel Dörfler 309fb81684fSAxel Dörfler uint8* 31015ab0bcfSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, 31115ab0bcfSAxel Dörfler const uint8* data, uint32 size) 312fb81684fSAxel Dörfler { 313fb81684fSAxel Dörfler options[0] = option; 314fb81684fSAxel Dörfler options[1] = size; 315fb81684fSAxel Dörfler memcpy(&options[2], data, size); 316fb81684fSAxel Dörfler 317fb81684fSAxel Dörfler return options + 2 + size; 318fb81684fSAxel Dörfler } 319fb81684fSAxel Dörfler 320fb81684fSAxel Dörfler 321a073ba1aSHugo Santos uint8* 322a073ba1aSHugo Santos dhcp_message::FinishOptions(uint8 *next) 323a073ba1aSHugo Santos { 324a073ba1aSHugo Santos return PutOption(next, OPTION_END); 325a073ba1aSHugo Santos } 326a073ba1aSHugo Santos 327a073ba1aSHugo Santos 328fb81684fSAxel Dörfler // #pragma mark - 329fb81684fSAxel Dörfler 330fb81684fSAxel Dörfler 331f9af6566SAxel Dörfler DHCPClient::DHCPClient(BMessenger target, const char* device) 332fb81684fSAxel Dörfler : BHandler("dhcp"), 3336cc7630fSAxel Dörfler fTarget(target), 33410cc12daSAxel Dörfler fDevice(device), 3356cc7630fSAxel Dörfler fConfiguration(kMsgConfigureInterface), 3366cc7630fSAxel Dörfler fRunner(NULL), 3376cc7630fSAxel Dörfler fLeaseTime(0) 338fb81684fSAxel Dörfler { 33946ff5400SAxel Dörfler fStartTime = system_time(); 34046ff5400SAxel Dörfler fTransactionID = (uint32)fStartTime; 341fb81684fSAxel Dörfler 3420ce7725eSAxel Dörfler fStatus = get_mac_address(device, fMAC); 343fb81684fSAxel Dörfler if (fStatus < B_OK) 344fb81684fSAxel Dörfler return; 345fb81684fSAxel Dörfler 3466cc7630fSAxel Dörfler memset(&fServer, 0, sizeof(struct sockaddr_in)); 3476cc7630fSAxel Dörfler fServer.sin_family = AF_INET; 3486cc7630fSAxel Dörfler fServer.sin_len = sizeof(struct sockaddr_in); 3496cc7630fSAxel Dörfler fServer.sin_port = htons(DHCP_SERVER_PORT); 3506cc7630fSAxel Dörfler } 3516cc7630fSAxel Dörfler 3526cc7630fSAxel Dörfler 3536cc7630fSAxel Dörfler DHCPClient::~DHCPClient() 3546cc7630fSAxel Dörfler { 3556cc7630fSAxel Dörfler if (fStatus != B_OK) 3566cc7630fSAxel Dörfler return; 3576cc7630fSAxel Dörfler 3586cc7630fSAxel Dörfler delete fRunner; 3590ce7725eSAxel Dörfler 360fb81684fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 3616cc7630fSAxel Dörfler if (socket < 0) 362fb81684fSAxel Dörfler return; 3636cc7630fSAxel Dörfler 3646cc7630fSAxel Dörfler // release lease 3656cc7630fSAxel Dörfler 3666cc7630fSAxel Dörfler dhcp_message release(DHCP_RELEASE); 36746ff5400SAxel Dörfler _PrepareMessage(release, BOUND); 3686cc7630fSAxel Dörfler 3696cc7630fSAxel Dörfler _SendMessage(socket, release, fServer); 3706cc7630fSAxel Dörfler close(socket); 371fb81684fSAxel Dörfler } 372fb81684fSAxel Dörfler 3736cc7630fSAxel Dörfler 3746cc7630fSAxel Dörfler status_t 3756cc7630fSAxel Dörfler DHCPClient::Initialize() 3766cc7630fSAxel Dörfler { 3776cc7630fSAxel Dörfler fStatus = _Negotiate(INIT); 3786cc7630fSAxel Dörfler printf("DHCP for %s, status: %s\n", fDevice.String(), strerror(fStatus)); 3796cc7630fSAxel Dörfler return fStatus; 3806cc7630fSAxel Dörfler } 3816cc7630fSAxel Dörfler 3826cc7630fSAxel Dörfler 3836cc7630fSAxel Dörfler status_t 3846cc7630fSAxel Dörfler DHCPClient::_Negotiate(dhcp_state state) 3856cc7630fSAxel Dörfler { 3866cc7630fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 3876cc7630fSAxel Dörfler if (socket < 0) 3886cc7630fSAxel Dörfler return errno; 3896cc7630fSAxel Dörfler 390fb81684fSAxel Dörfler sockaddr_in local; 391fb81684fSAxel Dörfler memset(&local, 0, sizeof(struct sockaddr_in)); 392fb81684fSAxel Dörfler local.sin_family = AF_INET; 393fb81684fSAxel Dörfler local.sin_len = sizeof(struct sockaddr_in); 394fb81684fSAxel Dörfler local.sin_port = htons(DHCP_CLIENT_PORT); 395fb81684fSAxel Dörfler local.sin_addr.s_addr = INADDR_ANY; 396fb81684fSAxel Dörfler 397fb81684fSAxel Dörfler if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) { 398fb81684fSAxel Dörfler close(socket); 3996cc7630fSAxel Dörfler return errno; 400fb81684fSAxel Dörfler } 401fb81684fSAxel Dörfler 402fb81684fSAxel Dörfler sockaddr_in broadcast; 403fb81684fSAxel Dörfler memset(&broadcast, 0, sizeof(struct sockaddr_in)); 404fb81684fSAxel Dörfler broadcast.sin_family = AF_INET; 405fb81684fSAxel Dörfler broadcast.sin_len = sizeof(struct sockaddr_in); 406fb81684fSAxel Dörfler broadcast.sin_port = htons(DHCP_SERVER_PORT); 407fb81684fSAxel Dörfler broadcast.sin_addr.s_addr = INADDR_BROADCAST; 408fb81684fSAxel Dörfler 409fb81684fSAxel Dörfler int option = 1; 410fb81684fSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); 411fb81684fSAxel Dörfler 41236bde12dSAxel Dörfler if (state == INIT) { 41336bde12dSAxel Dörfler // The local interface does not have an address yet, bind the socket 41436bde12dSAxel Dörfler // to the device directly. 41536bde12dSAxel Dörfler int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); 41636bde12dSAxel Dörfler if (linkSocket >= 0) { 41736bde12dSAxel Dörfler // we need to know the index of the device to be able to bind to it 41836bde12dSAxel Dörfler ifreq request; 41936bde12dSAxel Dörfler prepare_request(request, fDevice.String()); 42036bde12dSAxel Dörfler if (ioctl(linkSocket, SIOCGIFINDEX, &request, sizeof(struct ifreq)) 42136bde12dSAxel Dörfler == 0) { 42236bde12dSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, 42336bde12dSAxel Dörfler &request.ifr_index, sizeof(int)); 42436bde12dSAxel Dörfler } 42536bde12dSAxel Dörfler 42636bde12dSAxel Dörfler close(linkSocket); 42736bde12dSAxel Dörfler } 42836bde12dSAxel Dörfler } 42936bde12dSAxel Dörfler 4306cc7630fSAxel Dörfler bigtime_t previousLeaseTime = fLeaseTime; 4316cc7630fSAxel Dörfler fLeaseTime = 0; 43246ff5400SAxel Dörfler fRenewalTime = 0; 43346ff5400SAxel Dörfler fRebindingTime = 0; 434fb81684fSAxel Dörfler 4356cc7630fSAxel Dörfler status_t status = B_ERROR; 4366cc7630fSAxel Dörfler time_t timeout; 4376cc7630fSAxel Dörfler uint32 tries; 4386cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 4396cc7630fSAxel Dörfler 4406cc7630fSAxel Dörfler dhcp_message discover(DHCP_DISCOVER); 44146ff5400SAxel Dörfler _PrepareMessage(discover, state); 4426cc7630fSAxel Dörfler 4436cc7630fSAxel Dörfler dhcp_message request(DHCP_REQUEST); 44446ff5400SAxel Dörfler _PrepareMessage(request, state); 4456cc7630fSAxel Dörfler 44646ff5400SAxel Dörfler // send discover/request message 4476cc7630fSAxel Dörfler status = _SendMessage(socket, state == INIT ? discover : request, 44846ff5400SAxel Dörfler state != RENEWAL ? broadcast : fServer); 4496cc7630fSAxel Dörfler if (status < B_OK) { 450fb81684fSAxel Dörfler close(socket); 4516cc7630fSAxel Dörfler return status; 4526cc7630fSAxel Dörfler } 453fb81684fSAxel Dörfler 454f9af6566SAxel Dörfler // receive loop until we've got an offer and acknowledged it 455f9af6566SAxel Dörfler 456f9af6566SAxel Dörfler while (state != ACKNOWLEDGED) { 457f9af6566SAxel Dörfler char buffer[2048]; 458f9af6566SAxel Dörfler ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer), 459f9af6566SAxel Dörfler 0, NULL, NULL); 4604b661a95SAxel Dörfler if (bytesReceived < 0 && errno == B_TIMED_OUT) { 461f9af6566SAxel Dörfler // depending on the state, we'll just try again 4626cc7630fSAxel Dörfler if (!_TimeoutShift(socket, timeout, tries)) { 4636cc7630fSAxel Dörfler close(socket); 4646cc7630fSAxel Dörfler return B_TIMED_OUT; 465f9af6566SAxel Dörfler } 466f9af6566SAxel Dörfler 467f9af6566SAxel Dörfler if (state == INIT) 4686cc7630fSAxel Dörfler status = _SendMessage(socket, discover, broadcast); 46915ab0bcfSAxel Dörfler else { 47046ff5400SAxel Dörfler status = _SendMessage(socket, request, state != RENEWAL 4716cc7630fSAxel Dörfler ? broadcast : fServer); 47215ab0bcfSAxel Dörfler } 473f9af6566SAxel Dörfler 4746cc7630fSAxel Dörfler if (status < B_OK) 475f9af6566SAxel Dörfler break; 476f9af6566SAxel Dörfler } else if (bytesReceived < B_OK) 477f9af6566SAxel Dörfler break; 478f9af6566SAxel Dörfler 479f9af6566SAxel Dörfler dhcp_message *message = (dhcp_message *)buffer; 480f9af6566SAxel Dörfler if (message->transaction_id != htonl(fTransactionID) 481f9af6566SAxel Dörfler || !message->HasOptions() 482f9af6566SAxel Dörfler || memcmp(message->mac_address, discover.mac_address, 483f9af6566SAxel Dörfler discover.hardware_address_length)) { 484f9af6566SAxel Dörfler // this message is not for us 485f9af6566SAxel Dörfler continue; 486f9af6566SAxel Dörfler } 487f9af6566SAxel Dörfler 488f9af6566SAxel Dörfler switch (message->Type()) { 489f9af6566SAxel Dörfler case DHCP_NONE: 490f9af6566SAxel Dörfler default: 491f9af6566SAxel Dörfler // ignore this message 492f9af6566SAxel Dörfler break; 493f9af6566SAxel Dörfler 494f9af6566SAxel Dörfler case DHCP_OFFER: 495f9af6566SAxel Dörfler { 496f9af6566SAxel Dörfler // first offer wins 497f9af6566SAxel Dörfler if (state != INIT) 498f9af6566SAxel Dörfler break; 499f9af6566SAxel Dörfler 500f9af6566SAxel Dörfler // collect interface options 501f9af6566SAxel Dörfler 502f9af6566SAxel Dörfler fAssignedAddress = message->your_address; 503f9af6566SAxel Dörfler 50410cc12daSAxel Dörfler fConfiguration.MakeEmpty(); 50510cc12daSAxel Dörfler fConfiguration.AddString("device", fDevice.String()); 506f01106c3SAxel Dörfler fConfiguration.AddBool("auto", true); 507f9af6566SAxel Dörfler 508f9af6566SAxel Dörfler BMessage address; 509f9af6566SAxel Dörfler address.AddString("family", "inet"); 510f9af6566SAxel Dörfler address.AddString("address", _ToString(fAssignedAddress)); 5110ce7725eSAxel Dörfler _ParseOptions(*message, address); 512f9af6566SAxel Dörfler 51310cc12daSAxel Dörfler fConfiguration.AddMessage("address", &address); 514f9af6566SAxel Dörfler 51510cc12daSAxel Dörfler // request configuration from the server 516f9af6566SAxel Dörfler 5176cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 518f9af6566SAxel Dörfler state = REQUESTING; 51946ff5400SAxel Dörfler _PrepareMessage(request, state); 520f9af6566SAxel Dörfler 5216cc7630fSAxel Dörfler status = _SendMessage(socket, request, broadcast); 52215ab0bcfSAxel Dörfler // we're sending a broadcast so that all potential offers 52315ab0bcfSAxel Dörfler // get an answer 52410cc12daSAxel Dörfler break; 525f9af6566SAxel Dörfler } 526f9af6566SAxel Dörfler 527f9af6566SAxel Dörfler case DHCP_ACK: 52810cc12daSAxel Dörfler { 52915ab0bcfSAxel Dörfler if (state != REQUESTING && state != REBINDING 53015ab0bcfSAxel Dörfler && state != RENEWAL) 531f9af6566SAxel Dörfler continue; 532f9af6566SAxel Dörfler 5336cc7630fSAxel Dörfler // TODO: we might want to configure the stuff, don't we? 5346cc7630fSAxel Dörfler BMessage address; 5356cc7630fSAxel Dörfler _ParseOptions(*message, address); 5366cc7630fSAxel Dörfler // TODO: currently, only lease time and DNS is updated this way 5376cc7630fSAxel Dörfler 538f9af6566SAxel Dörfler // our address request has been acknowledged 539f9af6566SAxel Dörfler state = ACKNOWLEDGED; 54010cc12daSAxel Dörfler 54110cc12daSAxel Dörfler // configure interface 54210cc12daSAxel Dörfler BMessage reply; 5436cc7630fSAxel Dörfler fTarget.SendMessage(&fConfiguration, &reply); 54410cc12daSAxel Dörfler 54510cc12daSAxel Dörfler if (reply.FindInt32("status", &fStatus) != B_OK) 5466cc7630fSAxel Dörfler status = B_OK; 547f9af6566SAxel Dörfler break; 54810cc12daSAxel Dörfler } 549f9af6566SAxel Dörfler 550f9af6566SAxel Dörfler case DHCP_NACK: 551f9af6566SAxel Dörfler if (state != REQUESTING) 552f9af6566SAxel Dörfler continue; 553f9af6566SAxel Dörfler 55415ab0bcfSAxel Dörfler // try again (maybe we should prefer other servers if this 55515ab0bcfSAxel Dörfler // happens more than once) 5566cc7630fSAxel Dörfler status = _SendMessage(socket, discover, broadcast); 5576cc7630fSAxel Dörfler if (status == B_OK) 558f9af6566SAxel Dörfler state = INIT; 559f9af6566SAxel Dörfler break; 560f9af6566SAxel Dörfler } 561f9af6566SAxel Dörfler } 562f9af6566SAxel Dörfler 563fb81684fSAxel Dörfler close(socket); 5646cc7630fSAxel Dörfler 5656cc7630fSAxel Dörfler if (status == B_OK && fLeaseTime > 0) { 5666cc7630fSAxel Dörfler // notify early enough when the lease is 56746ff5400SAxel Dörfler if (fRenewalTime == 0) 56846ff5400SAxel Dörfler fRenewalTime = fLeaseTime * 2/3; 56946ff5400SAxel Dörfler if (fRebindingTime == 0) 57046ff5400SAxel Dörfler fRebindingTime = fLeaseTime * 5/6; 57146ff5400SAxel Dörfler 57246ff5400SAxel Dörfler _RestartLease(fRenewalTime); 57346ff5400SAxel Dörfler 57446ff5400SAxel Dörfler bigtime_t now = system_time(); 57546ff5400SAxel Dörfler fLeaseTime += now; 57646ff5400SAxel Dörfler fRenewalTime += now; 57746ff5400SAxel Dörfler fRebindingTime += now; 57846ff5400SAxel Dörfler // make lease times absolute 57946ff5400SAxel Dörfler } else { 5806cc7630fSAxel Dörfler fLeaseTime = previousLeaseTime; 58146ff5400SAxel Dörfler bigtime_t now = system_time(); 58246ff5400SAxel Dörfler fRenewalTime = (fLeaseTime - now) * 2/3 + now; 58346ff5400SAxel Dörfler fRebindingTime = (fLeaseTime - now) * 5/6 + now; 58446ff5400SAxel Dörfler } 5856cc7630fSAxel Dörfler 5866cc7630fSAxel Dörfler return status; 587fb81684fSAxel Dörfler } 588fb81684fSAxel Dörfler 589fb81684fSAxel Dörfler 5906cc7630fSAxel Dörfler void 5916cc7630fSAxel Dörfler DHCPClient::_RestartLease(bigtime_t leaseTime) 592fb81684fSAxel Dörfler { 5936cc7630fSAxel Dörfler if (leaseTime == 0) 594f9af6566SAxel Dörfler return; 595f9af6566SAxel Dörfler 5966cc7630fSAxel Dörfler BMessage lease(kMsgLeaseTime); 59746ff5400SAxel Dörfler fRunner = new BMessageRunner(this, &lease, leaseTime, 1); 598f9af6566SAxel Dörfler } 599f9af6566SAxel Dörfler 600f9af6566SAxel Dörfler 601f9af6566SAxel Dörfler void 6020ce7725eSAxel Dörfler DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address) 6030ce7725eSAxel Dörfler { 6040ce7725eSAxel Dörfler dhcp_option_cookie cookie; 6050ce7725eSAxel Dörfler message_option option; 6060ce7725eSAxel Dörfler const uint8* data; 6070ce7725eSAxel Dörfler size_t size; 6080ce7725eSAxel Dörfler while (message.NextOption(cookie, option, data, size)) { 6090ce7725eSAxel Dörfler // iterate through all options 6100ce7725eSAxel Dörfler switch (option) { 6110ce7725eSAxel Dörfler case OPTION_ROUTER_ADDRESS: 6120ce7725eSAxel Dörfler address.AddString("gateway", _ToString(data)); 6130ce7725eSAxel Dörfler break; 6140ce7725eSAxel Dörfler case OPTION_SUBNET_MASK: 6150ce7725eSAxel Dörfler address.AddString("mask", _ToString(data)); 6160ce7725eSAxel Dörfler break; 6175782c5a3SAxel Dörfler case OPTION_BROADCAST_ADDRESS: 6185782c5a3SAxel Dörfler address.AddString("broadcast", _ToString(data)); 6195782c5a3SAxel Dörfler break; 6200ce7725eSAxel Dörfler case OPTION_DOMAIN_NAME_SERVER: 621a552ec13SAxel Dörfler { 622a552ec13SAxel Dörfler // TODO: for now, we write it just out to /etc/resolv.conf 623a552ec13SAxel Dörfler FILE* file = fopen("/etc/resolv.conf", "w"); 6240ce7725eSAxel Dörfler for (uint32 i = 0; i < size / 4; i++) { 6250ce7725eSAxel Dörfler printf("DNS: %s\n", _ToString(&data[i*4]).String()); 62615ab0bcfSAxel Dörfler if (file != NULL) { 62715ab0bcfSAxel Dörfler fprintf(file, "nameserver %s\n", 62815ab0bcfSAxel Dörfler _ToString(&data[i*4]).String()); 62915ab0bcfSAxel Dörfler } 6300ce7725eSAxel Dörfler } 631a552ec13SAxel Dörfler fclose(file); 6320ce7725eSAxel Dörfler break; 633a552ec13SAxel Dörfler } 6340ce7725eSAxel Dörfler case OPTION_SERVER_ADDRESS: 6350ce7725eSAxel Dörfler fServer.sin_addr.s_addr = *(in_addr_t*)data; 6360ce7725eSAxel Dörfler break; 63746ff5400SAxel Dörfler 6380ce7725eSAxel Dörfler case OPTION_ADDRESS_LEASE_TIME: 6390ce7725eSAxel Dörfler printf("lease time of %lu seconds\n", htonl(*(uint32*)data)); 6406cc7630fSAxel Dörfler fLeaseTime = htonl(*(uint32*)data) * 1000000LL; 6410ce7725eSAxel Dörfler break; 6421a4e8e7bSAxel Dörfler case OPTION_RENEWAL_TIME: 64346ff5400SAxel Dörfler printf("renewal time of %lu seconds\n", 64446ff5400SAxel Dörfler htonl(*(uint32*)data)); 64546ff5400SAxel Dörfler fRenewalTime = htonl(*(uint32*)data) * 1000000LL; 64646ff5400SAxel Dörfler break; 6471a4e8e7bSAxel Dörfler case OPTION_REBINDING_TIME: 64846ff5400SAxel Dörfler printf("rebinding time of %lu seconds\n", 64946ff5400SAxel Dörfler htonl(*(uint32*)data)); 65046ff5400SAxel Dörfler fRebindingTime = htonl(*(uint32*)data) * 1000000LL; 6511a4e8e7bSAxel Dörfler break; 6521a4e8e7bSAxel Dörfler 6530ce7725eSAxel Dörfler case OPTION_HOST_NAME: 6545782c5a3SAxel Dörfler { 6550ce7725eSAxel Dörfler char name[256]; 6560ce7725eSAxel Dörfler memcpy(name, data, size); 6570ce7725eSAxel Dörfler name[size] = '\0'; 6580ce7725eSAxel Dörfler printf("DHCP host name: \"%s\"\n", name); 6590ce7725eSAxel Dörfler break; 6605782c5a3SAxel Dörfler } 6615782c5a3SAxel Dörfler 6625782c5a3SAxel Dörfler case OPTION_DOMAIN_NAME: 6635782c5a3SAxel Dörfler { 6645782c5a3SAxel Dörfler char name[256]; 6655782c5a3SAxel Dörfler memcpy(name, data, size); 6665782c5a3SAxel Dörfler name[size] = '\0'; 6675782c5a3SAxel Dörfler printf("DHCP domain name: \"%s\"\n", name); 6685782c5a3SAxel Dörfler break; 6695782c5a3SAxel Dörfler } 6700ce7725eSAxel Dörfler 6710ce7725eSAxel Dörfler case OPTION_MESSAGE_TYPE: 6720ce7725eSAxel Dörfler break; 6730ce7725eSAxel Dörfler 6740ce7725eSAxel Dörfler default: 6750ce7725eSAxel Dörfler printf("unknown option %lu\n", (uint32)option); 6760ce7725eSAxel Dörfler break; 6770ce7725eSAxel Dörfler } 6780ce7725eSAxel Dörfler } 6790ce7725eSAxel Dörfler } 6800ce7725eSAxel Dörfler 6810ce7725eSAxel Dörfler 6820ce7725eSAxel Dörfler void 68346ff5400SAxel Dörfler DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state) 6840ce7725eSAxel Dörfler { 6850ce7725eSAxel Dörfler message.opcode = BOOT_REQUEST; 6860ce7725eSAxel Dörfler message.hardware_type = ARP_HARDWARE_TYPE_ETHER; 6870ce7725eSAxel Dörfler message.hardware_address_length = 6; 6880ce7725eSAxel Dörfler message.transaction_id = htonl(fTransactionID); 689*bcc8dadaSAxel Dörfler message.seconds_since_start = htons(min_c((system_time() - fStartTime) 69015ab0bcfSAxel Dörfler / 1000000LL, 65535)); 6910ce7725eSAxel Dörfler memcpy(message.mac_address, fMAC, 6); 6920ce7725eSAxel Dörfler 69346ff5400SAxel Dörfler message_type type = message.Type(); 69446ff5400SAxel Dörfler 69546ff5400SAxel Dörfler switch (type) { 6960ce7725eSAxel Dörfler case DHCP_REQUEST: 6970ce7725eSAxel Dörfler case DHCP_RELEASE: 6980ce7725eSAxel Dörfler { 6990ce7725eSAxel Dörfler // add server identifier option 700a073ba1aSHugo Santos uint8* next = message.PrepareMessage(type); 7010ce7725eSAxel Dörfler next = message.PutOption(next, OPTION_SERVER_ADDRESS, 7020ce7725eSAxel Dörfler (uint32)fServer.sin_addr.s_addr); 70346ff5400SAxel Dörfler 70446ff5400SAxel Dörfler // In RENEWAL or REBINDING state, we must set the client_address field, and not 70546ff5400SAxel Dörfler // use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages 7065d4d5313SHugo Santos if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING)) { 70715ab0bcfSAxel Dörfler next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, 70815ab0bcfSAxel Dörfler (uint32)fAssignedAddress); 7095d4d5313SHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 7105d4d5313SHugo Santos kRequiredParameters, sizeof(kRequiredParameters)); 7115d4d5313SHugo Santos } else 71246ff5400SAxel Dörfler message.client_address = fAssignedAddress; 71346ff5400SAxel Dörfler 714a073ba1aSHugo Santos message.FinishOptions(next); 715a073ba1aSHugo Santos break; 716a073ba1aSHugo Santos } 717a073ba1aSHugo Santos 718a073ba1aSHugo Santos case DHCP_DISCOVER: 719a073ba1aSHugo Santos { 720a073ba1aSHugo Santos uint8 *next = message.PrepareMessage(type); 721a073ba1aSHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 722a073ba1aSHugo Santos kRequiredParameters, sizeof(kRequiredParameters)); 723a073ba1aSHugo Santos message.FinishOptions(next); 7240ce7725eSAxel Dörfler break; 7250ce7725eSAxel Dörfler } 7260ce7725eSAxel Dörfler 7270ce7725eSAxel Dörfler default: 7280ce7725eSAxel Dörfler // the default options are fine 7290ce7725eSAxel Dörfler break; 7300ce7725eSAxel Dörfler } 7310ce7725eSAxel Dörfler } 7320ce7725eSAxel Dörfler 7330ce7725eSAxel Dörfler 7340ce7725eSAxel Dörfler void 7356cc7630fSAxel Dörfler DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries) 736f9af6566SAxel Dörfler { 7376cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 7386cc7630fSAxel Dörfler tries = 0; 739f9af6566SAxel Dörfler 740f9af6566SAxel Dörfler struct timeval value; 7416cc7630fSAxel Dörfler value.tv_sec = timeout; 742f9af6566SAxel Dörfler value.tv_usec = 0; 743f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 744f9af6566SAxel Dörfler } 745f9af6566SAxel Dörfler 746f9af6566SAxel Dörfler 747f9af6566SAxel Dörfler bool 7486cc7630fSAxel Dörfler DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries) 749f9af6566SAxel Dörfler { 7506cc7630fSAxel Dörfler timeout += timeout; 7516cc7630fSAxel Dörfler if (timeout > MAX_TIMEOUT) { 7526cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 753f9af6566SAxel Dörfler 7546cc7630fSAxel Dörfler if (++tries > 2) 755f9af6566SAxel Dörfler return false; 756f9af6566SAxel Dörfler } 7576cc7630fSAxel Dörfler printf("DHCP timeout shift: %lu secs (try %lu)\n", timeout, tries); 758f9af6566SAxel Dörfler 759f9af6566SAxel Dörfler struct timeval value; 7606cc7630fSAxel Dörfler value.tv_sec = timeout; 761f9af6566SAxel Dörfler value.tv_usec = 0; 762f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 763f9af6566SAxel Dörfler 764f9af6566SAxel Dörfler return true; 765f9af6566SAxel Dörfler } 766f9af6566SAxel Dörfler 767f9af6566SAxel Dörfler 768f9af6566SAxel Dörfler BString 769f9af6566SAxel Dörfler DHCPClient::_ToString(const uint8* data) const 770f9af6566SAxel Dörfler { 771f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)data); 772f9af6566SAxel Dörfler return target; 773f9af6566SAxel Dörfler } 774f9af6566SAxel Dörfler 775f9af6566SAxel Dörfler 776f9af6566SAxel Dörfler BString 777f9af6566SAxel Dörfler DHCPClient::_ToString(in_addr_t address) const 778f9af6566SAxel Dörfler { 779f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)&address); 780f9af6566SAxel Dörfler return target; 781f9af6566SAxel Dörfler } 782f9af6566SAxel Dörfler 783f9af6566SAxel Dörfler 784f9af6566SAxel Dörfler status_t 785f9af6566SAxel Dörfler DHCPClient::_SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const 786f9af6566SAxel Dörfler { 787f9af6566SAxel Dörfler ssize_t bytesSent = sendto(socket, &message, message.Size(), 788f9af6566SAxel Dörfler address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0, 789f9af6566SAxel Dörfler (struct sockaddr*)&address, sizeof(sockaddr_in)); 790f9af6566SAxel Dörfler if (bytesSent < 0) 791f9af6566SAxel Dörfler return errno; 792f9af6566SAxel Dörfler 793f9af6566SAxel Dörfler return B_OK; 794fb81684fSAxel Dörfler } 795fb81684fSAxel Dörfler 796fb81684fSAxel Dörfler 79746ff5400SAxel Dörfler dhcp_state 79846ff5400SAxel Dörfler DHCPClient::_CurrentState() const 79946ff5400SAxel Dörfler { 80046ff5400SAxel Dörfler bigtime_t now = system_time(); 80146ff5400SAxel Dörfler 80246ff5400SAxel Dörfler if (now > fLeaseTime || fStatus < B_OK) 80346ff5400SAxel Dörfler return INIT; 80446ff5400SAxel Dörfler if (now >= fRebindingTime) 80546ff5400SAxel Dörfler return REBINDING; 80646ff5400SAxel Dörfler if (now >= fRenewalTime) 80746ff5400SAxel Dörfler return RENEWAL; 80846ff5400SAxel Dörfler 80946ff5400SAxel Dörfler return BOUND; 81046ff5400SAxel Dörfler } 81146ff5400SAxel Dörfler 81246ff5400SAxel Dörfler 813fb81684fSAxel Dörfler void 814fb81684fSAxel Dörfler DHCPClient::MessageReceived(BMessage* message) 815fb81684fSAxel Dörfler { 8166cc7630fSAxel Dörfler switch (message->what) { 8176cc7630fSAxel Dörfler case kMsgLeaseTime: 81846ff5400SAxel Dörfler { 81946ff5400SAxel Dörfler dhcp_state state = _CurrentState(); 82046ff5400SAxel Dörfler 82146ff5400SAxel Dörfler bigtime_t next; 82246ff5400SAxel Dörfler if (_Negotiate(state) == B_OK) { 82346ff5400SAxel Dörfler switch (state) { 82446ff5400SAxel Dörfler case RENEWAL: 82546ff5400SAxel Dörfler next = fRebindingTime; 8266cc7630fSAxel Dörfler break; 82746ff5400SAxel Dörfler case REBINDING: 82846ff5400SAxel Dörfler default: 82946ff5400SAxel Dörfler next = fRenewalTime; 83046ff5400SAxel Dörfler break; 83146ff5400SAxel Dörfler } 83246ff5400SAxel Dörfler } else { 83346ff5400SAxel Dörfler switch (state) { 83446ff5400SAxel Dörfler case RENEWAL: 83546ff5400SAxel Dörfler next = (fLeaseTime - fRebindingTime) / 4 + system_time(); 83646ff5400SAxel Dörfler break; 83746ff5400SAxel Dörfler case REBINDING: 83846ff5400SAxel Dörfler default: 83946ff5400SAxel Dörfler next = (fLeaseTime - fRenewalTime) / 4 + system_time(); 84046ff5400SAxel Dörfler break; 84146ff5400SAxel Dörfler } 84246ff5400SAxel Dörfler } 84346ff5400SAxel Dörfler 84446ff5400SAxel Dörfler _RestartLease(next - system_time()); 84546ff5400SAxel Dörfler break; 84646ff5400SAxel Dörfler } 8476cc7630fSAxel Dörfler 8486cc7630fSAxel Dörfler default: 849fb81684fSAxel Dörfler BHandler::MessageReceived(message); 8506cc7630fSAxel Dörfler break; 8516cc7630fSAxel Dörfler } 852fb81684fSAxel Dörfler } 853fb81684fSAxel Dörfler 854