1fb81684fSAxel Dörfler /* 237a68cb1SAxel Dörfler * Copyright 2006-2010, 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 70f87f52fSStephan Aßmus * Vegard Wærp, vegarwa@online.no 8fb81684fSAxel Dörfler */ 9fb81684fSAxel Dörfler 10fb81684fSAxel Dörfler 11fb81684fSAxel Dörfler #include "DHCPClient.h" 12fb81684fSAxel Dörfler #include "NetServer.h" 13fb81684fSAxel Dörfler 14f9af6566SAxel Dörfler #include <Message.h> 156cc7630fSAxel Dörfler #include <MessageRunner.h> 16f9af6566SAxel Dörfler 17f9af6566SAxel Dörfler #include <arpa/inet.h> 18fb81684fSAxel Dörfler #include <errno.h> 19fb81684fSAxel Dörfler #include <stdio.h> 20fb81684fSAxel Dörfler #include <string.h> 21293ed4feSAxel Dörfler #include <syslog.h> 2236bde12dSAxel Dörfler #include <sys/sockio.h> 23f9af6566SAxel Dörfler #include <sys/time.h> 24fb81684fSAxel Dörfler 25fb81684fSAxel Dörfler 26fb81684fSAxel Dörfler // See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options 27fb81684fSAxel Dörfler 28fb81684fSAxel Dörfler #define DHCP_CLIENT_PORT 68 29fb81684fSAxel Dörfler #define DHCP_SERVER_PORT 67 30fb81684fSAxel Dörfler 31f9af6566SAxel Dörfler #define DEFAULT_TIMEOUT 2 // secs 32f9af6566SAxel Dörfler #define MAX_TIMEOUT 15 // secs 33f9af6566SAxel Dörfler 34fb81684fSAxel Dörfler enum message_opcode { 35fb81684fSAxel Dörfler BOOT_REQUEST = 1, 36fb81684fSAxel Dörfler BOOT_REPLY 37fb81684fSAxel Dörfler }; 38fb81684fSAxel Dörfler 39fb81684fSAxel Dörfler enum message_option { 40fb81684fSAxel Dörfler OPTION_MAGIC = 0x63825363, 41fb81684fSAxel Dörfler 42fb81684fSAxel Dörfler // generic options 43fb81684fSAxel Dörfler OPTION_PAD = 0, 44f9af6566SAxel Dörfler OPTION_END = 255, 45f9af6566SAxel Dörfler OPTION_SUBNET_MASK = 1, 4665186fecSAxel Dörfler OPTION_TIME_OFFSET = 2, 47f9af6566SAxel Dörfler OPTION_ROUTER_ADDRESS = 3, 48f9af6566SAxel Dörfler OPTION_DOMAIN_NAME_SERVER = 6, 49f9af6566SAxel Dörfler OPTION_HOST_NAME = 12, 505782c5a3SAxel Dörfler OPTION_DOMAIN_NAME = 15, 51fb81684fSAxel Dörfler OPTION_DATAGRAM_SIZE = 22, 52fb81684fSAxel Dörfler OPTION_MTU = 26, 53fb81684fSAxel Dörfler OPTION_BROADCAST_ADDRESS = 28, 54fb81684fSAxel Dörfler OPTION_NETWORK_TIME_SERVERS = 42, 5565186fecSAxel Dörfler OPTION_NETBIOS_NAME_SERVER = 44, 5665186fecSAxel Dörfler OPTION_NETBIOS_SCOPE = 47, 57fb81684fSAxel Dörfler 58fb81684fSAxel Dörfler // DHCP specific options 59fb81684fSAxel Dörfler OPTION_REQUEST_IP_ADDRESS = 50, 60fb81684fSAxel Dörfler OPTION_ADDRESS_LEASE_TIME = 51, 61fb81684fSAxel Dörfler OPTION_OVERLOAD = 52, 62fb81684fSAxel Dörfler OPTION_MESSAGE_TYPE = 53, 63fb81684fSAxel Dörfler OPTION_SERVER_ADDRESS = 54, 64fb81684fSAxel Dörfler OPTION_REQUEST_PARAMETERS = 55, 65fb81684fSAxel Dörfler OPTION_ERROR_MESSAGE = 56, 66fb81684fSAxel Dörfler OPTION_MESSAGE_SIZE = 57, 67fb81684fSAxel Dörfler OPTION_RENEWAL_TIME = 58, 68fb81684fSAxel Dörfler OPTION_REBINDING_TIME = 59, 69fb81684fSAxel Dörfler OPTION_CLASS_IDENTIFIER = 60, 70fb81684fSAxel Dörfler OPTION_CLIENT_IDENTIFIER = 61, 71fb81684fSAxel Dörfler }; 72fb81684fSAxel Dörfler 73fb81684fSAxel Dörfler enum message_type { 74f9af6566SAxel Dörfler DHCP_NONE = 0, 75f9af6566SAxel Dörfler DHCP_DISCOVER, 76fb81684fSAxel Dörfler DHCP_OFFER, 77fb81684fSAxel Dörfler DHCP_REQUEST, 78fb81684fSAxel Dörfler DHCP_DECLINE, 79fb81684fSAxel Dörfler DHCP_ACK, 80f9af6566SAxel Dörfler DHCP_NACK, 81fb81684fSAxel Dörfler DHCP_RELEASE, 82fb81684fSAxel Dörfler DHCP_INFORM 83fb81684fSAxel Dörfler }; 84fb81684fSAxel Dörfler 85fb81684fSAxel Dörfler struct dhcp_option_cookie { 8615ab0bcfSAxel Dörfler dhcp_option_cookie() 8715ab0bcfSAxel Dörfler : 8815ab0bcfSAxel Dörfler state(0), 8915ab0bcfSAxel Dörfler file_has_options(false), 9015ab0bcfSAxel Dörfler server_name_has_options(false) 9115ab0bcfSAxel Dörfler { 9215ab0bcfSAxel Dörfler } 93fb81684fSAxel Dörfler 94fb81684fSAxel Dörfler const uint8* next; 95fb81684fSAxel Dörfler uint8 state; 96fb81684fSAxel Dörfler bool file_has_options; 97fb81684fSAxel Dörfler bool server_name_has_options; 98fb81684fSAxel Dörfler }; 99fb81684fSAxel Dörfler 100fb81684fSAxel Dörfler struct dhcp_message { 101fb81684fSAxel Dörfler dhcp_message(message_type type); 102fb81684fSAxel Dörfler 103fb81684fSAxel Dörfler uint8 opcode; 104fb81684fSAxel Dörfler uint8 hardware_type; 105fb81684fSAxel Dörfler uint8 hardware_address_length; 106fb81684fSAxel Dörfler uint8 hop_count; 107fb81684fSAxel Dörfler uint32 transaction_id; 10846ff5400SAxel Dörfler uint16 seconds_since_start; 109fb81684fSAxel Dörfler uint16 flags; 110fb81684fSAxel Dörfler in_addr_t client_address; 111fb81684fSAxel Dörfler in_addr_t your_address; 112fb81684fSAxel Dörfler in_addr_t server_address; 113fb81684fSAxel Dörfler in_addr_t gateway_address; 114fb81684fSAxel Dörfler uint8 mac_address[16]; 115fb81684fSAxel Dörfler uint8 server_name[64]; 116fb81684fSAxel Dörfler uint8 file[128]; 117fb81684fSAxel Dörfler uint32 options_magic; 118fb81684fSAxel Dörfler uint8 options[1260]; 119fb81684fSAxel Dörfler 120fb81684fSAxel Dörfler size_t MinSize() const { return 576; } 121fb81684fSAxel Dörfler size_t Size() const; 122fb81684fSAxel Dörfler 123fb81684fSAxel Dörfler bool HasOptions() const; 124fb81684fSAxel Dörfler bool NextOption(dhcp_option_cookie& cookie, message_option& option, 125fb81684fSAxel Dörfler const uint8*& data, size_t& size) const; 126f9af6566SAxel Dörfler message_type Type() const; 127fb81684fSAxel Dörfler const uint8* LastOption() const; 128fb81684fSAxel Dörfler 129a073ba1aSHugo Santos uint8* PrepareMessage(uint8 type); 130fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option); 131fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint8 data); 132fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint16 data); 133fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint32 data); 13415ab0bcfSAxel Dörfler uint8* PutOption(uint8* options, message_option option, const uint8* data, 13515ab0bcfSAxel Dörfler uint32 size); 13637a68cb1SAxel Dörfler uint8* FinishOptions(uint8* options); 137fb81684fSAxel Dörfler } _PACKED; 138fb81684fSAxel Dörfler 1390cf5e6acSAxel Dörfler #define DHCP_FLAG_BROADCAST 0x8000 140fb81684fSAxel Dörfler 141fb81684fSAxel Dörfler #define ARP_HARDWARE_TYPE_ETHER 1 142fb81684fSAxel Dörfler 1436cc7630fSAxel Dörfler const uint32 kMsgLeaseTime = 'lstm'; 1446cc7630fSAxel Dörfler 14537a68cb1SAxel Dörfler static const uint8 kRequestParameters[] = { 14665186fecSAxel Dörfler OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS, 147bfd479b3SAxel Dörfler OPTION_DOMAIN_NAME_SERVER, OPTION_BROADCAST_ADDRESS, 148bfd479b3SAxel Dörfler OPTION_DOMAIN_NAME 1495d4d5313SHugo Santos }; 1505d4d5313SHugo Santos 151fb81684fSAxel Dörfler 152fb81684fSAxel Dörfler dhcp_message::dhcp_message(message_type type) 153fb81684fSAxel Dörfler { 154fb81684fSAxel Dörfler memset(this, 0, sizeof(*this)); 155fb81684fSAxel Dörfler options_magic = htonl(OPTION_MAGIC); 156fb81684fSAxel Dörfler 157a073ba1aSHugo Santos uint8* next = PrepareMessage(type); 158a073ba1aSHugo Santos FinishOptions(next); 159fb81684fSAxel Dörfler } 160fb81684fSAxel Dörfler 161fb81684fSAxel Dörfler 162fb81684fSAxel Dörfler bool 163fb81684fSAxel Dörfler dhcp_message::HasOptions() const 164fb81684fSAxel Dörfler { 165fb81684fSAxel Dörfler return options_magic == htonl(OPTION_MAGIC); 166fb81684fSAxel Dörfler } 167fb81684fSAxel Dörfler 168fb81684fSAxel Dörfler 169fb81684fSAxel Dörfler bool 170fb81684fSAxel Dörfler dhcp_message::NextOption(dhcp_option_cookie& cookie, 171fb81684fSAxel Dörfler message_option& option, const uint8*& data, size_t& size) const 172fb81684fSAxel Dörfler { 173fb81684fSAxel Dörfler if (cookie.state == 0) { 174fb81684fSAxel Dörfler if (!HasOptions()) 175fb81684fSAxel Dörfler return false; 176fb81684fSAxel Dörfler 177fb81684fSAxel Dörfler cookie.state++; 178fb81684fSAxel Dörfler cookie.next = options; 179fb81684fSAxel Dörfler } 180fb81684fSAxel Dörfler 181fb81684fSAxel Dörfler uint32 bytesLeft = 0; 182fb81684fSAxel Dörfler 183fb81684fSAxel Dörfler switch (cookie.state) { 184fb81684fSAxel Dörfler case 1: 185fb81684fSAxel Dörfler // options from "options" 186fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 187fb81684fSAxel Dörfler break; 188fb81684fSAxel Dörfler 189fb81684fSAxel Dörfler case 2: 190fb81684fSAxel Dörfler // options from "file" 191fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 192fb81684fSAxel Dörfler break; 193fb81684fSAxel Dörfler 194fb81684fSAxel Dörfler case 3: 195fb81684fSAxel Dörfler // options from "server_name" 196fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 197fb81684fSAxel Dörfler break; 198fb81684fSAxel Dörfler } 199fb81684fSAxel Dörfler 200fb81684fSAxel Dörfler while (true) { 201fb81684fSAxel Dörfler if (bytesLeft == 0) { 202fb81684fSAxel Dörfler // TODO: suppport OPTION_OVERLOAD! 203fb81684fSAxel Dörfler cookie.state = 4; 204fb81684fSAxel Dörfler return false; 205fb81684fSAxel Dörfler } 206fb81684fSAxel Dörfler 207fb81684fSAxel Dörfler option = (message_option)cookie.next[0]; 208fb81684fSAxel Dörfler if (option == OPTION_END) { 209fb81684fSAxel Dörfler cookie.state = 4; 210fb81684fSAxel Dörfler return false; 211fb81684fSAxel Dörfler } else if (option == OPTION_PAD) { 212fb81684fSAxel Dörfler bytesLeft--; 213fb81684fSAxel Dörfler cookie.next++; 214fb81684fSAxel Dörfler continue; 215fb81684fSAxel Dörfler } 216fb81684fSAxel Dörfler 217fb81684fSAxel Dörfler size = cookie.next[1]; 218fb81684fSAxel Dörfler data = &cookie.next[2]; 219fb81684fSAxel Dörfler cookie.next += 2 + size; 220fb81684fSAxel Dörfler 221fb81684fSAxel Dörfler if (option == OPTION_OVERLOAD) { 222fb81684fSAxel Dörfler cookie.file_has_options = data[0] & 1; 223fb81684fSAxel Dörfler cookie.server_name_has_options = data[0] & 2; 224fb81684fSAxel Dörfler continue; 225fb81684fSAxel Dörfler } 226fb81684fSAxel Dörfler 227fb81684fSAxel Dörfler return true; 228fb81684fSAxel Dörfler } 229fb81684fSAxel Dörfler } 230fb81684fSAxel Dörfler 231fb81684fSAxel Dörfler 232f9af6566SAxel Dörfler message_type 233f9af6566SAxel Dörfler dhcp_message::Type() const 234f9af6566SAxel Dörfler { 235f9af6566SAxel Dörfler dhcp_option_cookie cookie; 236f9af6566SAxel Dörfler message_option option; 237f9af6566SAxel Dörfler const uint8* data; 238f9af6566SAxel Dörfler size_t size; 239f9af6566SAxel Dörfler while (NextOption(cookie, option, data, size)) { 240f9af6566SAxel Dörfler // iterate through all options 241f9af6566SAxel Dörfler if (option == OPTION_MESSAGE_TYPE) 242f9af6566SAxel Dörfler return (message_type)data[0]; 243f9af6566SAxel Dörfler } 244f9af6566SAxel Dörfler 245f9af6566SAxel Dörfler return DHCP_NONE; 246f9af6566SAxel Dörfler } 247f9af6566SAxel Dörfler 248f9af6566SAxel Dörfler 249fb81684fSAxel Dörfler const uint8* 250fb81684fSAxel Dörfler dhcp_message::LastOption() const 251fb81684fSAxel Dörfler { 252fb81684fSAxel Dörfler dhcp_option_cookie cookie; 253fb81684fSAxel Dörfler message_option option; 254fb81684fSAxel Dörfler const uint8* data; 255fb81684fSAxel Dörfler size_t size; 256fb81684fSAxel Dörfler while (NextOption(cookie, option, data, size)) { 257fb81684fSAxel Dörfler // iterate through all options 258fb81684fSAxel Dörfler } 259fb81684fSAxel Dörfler 260fb81684fSAxel Dörfler return cookie.next; 261fb81684fSAxel Dörfler } 262fb81684fSAxel Dörfler 263fb81684fSAxel Dörfler 264fb81684fSAxel Dörfler size_t 265fb81684fSAxel Dörfler dhcp_message::Size() const 266fb81684fSAxel Dörfler { 267fb81684fSAxel Dörfler const uint8* last = LastOption(); 268fb81684fSAxel Dörfler return sizeof(dhcp_message) - sizeof(options) + last + 1 - options; 269fb81684fSAxel Dörfler } 270fb81684fSAxel Dörfler 271fb81684fSAxel Dörfler 272fb81684fSAxel Dörfler uint8* 273a073ba1aSHugo Santos dhcp_message::PrepareMessage(uint8 type) 274a073ba1aSHugo Santos { 275a073ba1aSHugo Santos uint8* next = options; 276a073ba1aSHugo Santos next = PutOption(next, OPTION_MESSAGE_TYPE, type); 27715ab0bcfSAxel Dörfler next = PutOption(next, OPTION_MESSAGE_SIZE, 27815ab0bcfSAxel Dörfler (uint16)htons(sizeof(dhcp_message))); 279a073ba1aSHugo Santos return next; 280a073ba1aSHugo Santos } 281a073ba1aSHugo Santos 28265186fecSAxel Dörfler 283a073ba1aSHugo Santos uint8* 284fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option) 285fb81684fSAxel Dörfler { 286fb81684fSAxel Dörfler options[0] = option; 287fb81684fSAxel Dörfler return options + 1; 288fb81684fSAxel Dörfler } 289fb81684fSAxel Dörfler 290fb81684fSAxel Dörfler 291fb81684fSAxel Dörfler uint8* 292fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8 data) 293fb81684fSAxel Dörfler { 294fb81684fSAxel Dörfler return PutOption(options, option, &data, 1); 295fb81684fSAxel Dörfler } 296fb81684fSAxel Dörfler 297fb81684fSAxel Dörfler 298fb81684fSAxel Dörfler uint8* 299fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint16 data) 300fb81684fSAxel Dörfler { 301fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 302fb81684fSAxel Dörfler } 303fb81684fSAxel Dörfler 304fb81684fSAxel Dörfler 305fb81684fSAxel Dörfler uint8* 306fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint32 data) 307fb81684fSAxel Dörfler { 308fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 309fb81684fSAxel Dörfler } 310fb81684fSAxel Dörfler 311fb81684fSAxel Dörfler 312fb81684fSAxel Dörfler uint8* 31315ab0bcfSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, 31415ab0bcfSAxel Dörfler const uint8* data, uint32 size) 315fb81684fSAxel Dörfler { 316fb81684fSAxel Dörfler options[0] = option; 317fb81684fSAxel Dörfler options[1] = size; 318fb81684fSAxel Dörfler memcpy(&options[2], data, size); 319fb81684fSAxel Dörfler 320fb81684fSAxel Dörfler return options + 2 + size; 321fb81684fSAxel Dörfler } 322fb81684fSAxel Dörfler 323fb81684fSAxel Dörfler 324a073ba1aSHugo Santos uint8* 32537a68cb1SAxel Dörfler dhcp_message::FinishOptions(uint8* options) 326a073ba1aSHugo Santos { 32737a68cb1SAxel Dörfler return PutOption(options, OPTION_END); 328a073ba1aSHugo Santos } 329a073ba1aSHugo Santos 330a073ba1aSHugo Santos 331fb81684fSAxel Dörfler // #pragma mark - 332fb81684fSAxel Dörfler 333fb81684fSAxel Dörfler 334f9af6566SAxel Dörfler DHCPClient::DHCPClient(BMessenger target, const char* device) 335293ed4feSAxel Dörfler : AutoconfigClient("dhcp", target, device), 3366cc7630fSAxel Dörfler fConfiguration(kMsgConfigureInterface), 337*16e8f13aSAxel Dörfler fResolverConfiguration(kMsgConfigureResolver), 3386cc7630fSAxel Dörfler fRunner(NULL), 339c1264353SStephan Aßmus fLeaseTime(0) 340fb81684fSAxel Dörfler { 34146ff5400SAxel Dörfler fStartTime = system_time(); 34246ff5400SAxel Dörfler fTransactionID = (uint32)fStartTime; 343fb81684fSAxel Dörfler 3440ce7725eSAxel Dörfler fStatus = get_mac_address(device, fMAC); 345fb81684fSAxel Dörfler if (fStatus < B_OK) 346fb81684fSAxel Dörfler return; 347fb81684fSAxel Dörfler 3486cc7630fSAxel Dörfler memset(&fServer, 0, sizeof(struct sockaddr_in)); 3496cc7630fSAxel Dörfler fServer.sin_family = AF_INET; 3506cc7630fSAxel Dörfler fServer.sin_len = sizeof(struct sockaddr_in); 3516cc7630fSAxel Dörfler fServer.sin_port = htons(DHCP_SERVER_PORT); 352293ed4feSAxel Dörfler 353293ed4feSAxel Dörfler openlog_thread("DHCP", 0, LOG_DAEMON); 3546cc7630fSAxel Dörfler } 3556cc7630fSAxel Dörfler 3566cc7630fSAxel Dörfler 3576cc7630fSAxel Dörfler DHCPClient::~DHCPClient() 3586cc7630fSAxel Dörfler { 3596cc7630fSAxel Dörfler if (fStatus != B_OK) 3606cc7630fSAxel Dörfler return; 3616cc7630fSAxel Dörfler 3626cc7630fSAxel Dörfler delete fRunner; 3630ce7725eSAxel Dörfler 364fb81684fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 3656cc7630fSAxel Dörfler if (socket < 0) 366fb81684fSAxel Dörfler return; 3676cc7630fSAxel Dörfler 3686cc7630fSAxel Dörfler // release lease 3696cc7630fSAxel Dörfler 3706cc7630fSAxel Dörfler dhcp_message release(DHCP_RELEASE); 37146ff5400SAxel Dörfler _PrepareMessage(release, BOUND); 3726cc7630fSAxel Dörfler 3736cc7630fSAxel Dörfler _SendMessage(socket, release, fServer); 3746cc7630fSAxel Dörfler close(socket); 375293ed4feSAxel Dörfler 376293ed4feSAxel Dörfler closelog_thread(); 377fb81684fSAxel Dörfler } 378fb81684fSAxel Dörfler 3796cc7630fSAxel Dörfler 3806cc7630fSAxel Dörfler status_t 3816cc7630fSAxel Dörfler DHCPClient::Initialize() 3826cc7630fSAxel Dörfler { 3836cc7630fSAxel Dörfler fStatus = _Negotiate(INIT); 384293ed4feSAxel Dörfler syslog(LOG_DEBUG, "DHCP for %s, status: %s\n", Device(), strerror(fStatus)); 3856cc7630fSAxel Dörfler return fStatus; 3866cc7630fSAxel Dörfler } 3876cc7630fSAxel Dörfler 3886cc7630fSAxel Dörfler 3896cc7630fSAxel Dörfler status_t 3906cc7630fSAxel Dörfler DHCPClient::_Negotiate(dhcp_state state) 3916cc7630fSAxel Dörfler { 3926cc7630fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 3936cc7630fSAxel Dörfler if (socket < 0) 3946cc7630fSAxel Dörfler return errno; 3956cc7630fSAxel Dörfler 396fb81684fSAxel Dörfler sockaddr_in local; 397fb81684fSAxel Dörfler memset(&local, 0, sizeof(struct sockaddr_in)); 398fb81684fSAxel Dörfler local.sin_family = AF_INET; 399fb81684fSAxel Dörfler local.sin_len = sizeof(struct sockaddr_in); 400fb81684fSAxel Dörfler local.sin_port = htons(DHCP_CLIENT_PORT); 401fb81684fSAxel Dörfler local.sin_addr.s_addr = INADDR_ANY; 402fb81684fSAxel Dörfler 4032b829b04SBruno G. Albuquerque // Enable reusing the port . This is needed in case there is more 4042b829b04SBruno G. Albuquerque // than 1 interface that needs to be configured. Note that the only reason 4052b829b04SBruno G. Albuquerque // this works is because there is code below to bind to a specific 4062b829b04SBruno G. Albuquerque // interface. 4072b829b04SBruno G. Albuquerque int option = 1; 4082b829b04SBruno G. Albuquerque setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option)); 4092b829b04SBruno G. Albuquerque 410fb81684fSAxel Dörfler if (bind(socket, (struct sockaddr*)&local, sizeof(local)) < 0) { 411fb81684fSAxel Dörfler close(socket); 4126cc7630fSAxel Dörfler return errno; 413fb81684fSAxel Dörfler } 414fb81684fSAxel Dörfler 415fb81684fSAxel Dörfler sockaddr_in broadcast; 416fb81684fSAxel Dörfler memset(&broadcast, 0, sizeof(struct sockaddr_in)); 417fb81684fSAxel Dörfler broadcast.sin_family = AF_INET; 418fb81684fSAxel Dörfler broadcast.sin_len = sizeof(struct sockaddr_in); 419fb81684fSAxel Dörfler broadcast.sin_port = htons(DHCP_SERVER_PORT); 420fb81684fSAxel Dörfler broadcast.sin_addr.s_addr = INADDR_BROADCAST; 421fb81684fSAxel Dörfler 4222b829b04SBruno G. Albuquerque option = 1; 423fb81684fSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); 424fb81684fSAxel Dörfler 42536bde12dSAxel Dörfler if (state == INIT) { 42636bde12dSAxel Dörfler // The local interface does not have an address yet, bind the socket 42736bde12dSAxel Dörfler // to the device directly. 42836bde12dSAxel Dörfler int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); 42936bde12dSAxel Dörfler if (linkSocket >= 0) { 43036bde12dSAxel Dörfler // we need to know the index of the device to be able to bind to it 43136bde12dSAxel Dörfler ifreq request; 432293ed4feSAxel Dörfler prepare_request(request, Device()); 43336bde12dSAxel Dörfler if (ioctl(linkSocket, SIOCGIFINDEX, &request, sizeof(struct ifreq)) 43436bde12dSAxel Dörfler == 0) { 43536bde12dSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, 43636bde12dSAxel Dörfler &request.ifr_index, sizeof(int)); 43736bde12dSAxel Dörfler } 43836bde12dSAxel Dörfler 43936bde12dSAxel Dörfler close(linkSocket); 44036bde12dSAxel Dörfler } 44136bde12dSAxel Dörfler } 44236bde12dSAxel Dörfler 4436cc7630fSAxel Dörfler bigtime_t previousLeaseTime = fLeaseTime; 4446cc7630fSAxel Dörfler fLeaseTime = 0; 44546ff5400SAxel Dörfler fRenewalTime = 0; 44646ff5400SAxel Dörfler fRebindingTime = 0; 447fb81684fSAxel Dörfler 4486cc7630fSAxel Dörfler status_t status = B_ERROR; 4496cc7630fSAxel Dörfler time_t timeout; 4506cc7630fSAxel Dörfler uint32 tries; 4516cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 4526cc7630fSAxel Dörfler 4536cc7630fSAxel Dörfler dhcp_message discover(DHCP_DISCOVER); 45446ff5400SAxel Dörfler _PrepareMessage(discover, state); 4556cc7630fSAxel Dörfler 4566cc7630fSAxel Dörfler dhcp_message request(DHCP_REQUEST); 45746ff5400SAxel Dörfler _PrepareMessage(request, state); 4586cc7630fSAxel Dörfler 45946ff5400SAxel Dörfler // send discover/request message 460593a0d2dSAxel Dörfler _SendMessage(socket, state == INIT ? discover : request, 46146ff5400SAxel Dörfler state != RENEWAL ? broadcast : fServer); 462593a0d2dSAxel Dörfler // no need to check the status; in case of an error we'll just send 463593a0d2dSAxel Dörfler // the message again 464fb81684fSAxel Dörfler 465f9af6566SAxel Dörfler // receive loop until we've got an offer and acknowledged it 466f9af6566SAxel Dörfler 467f9af6566SAxel Dörfler while (state != ACKNOWLEDGED) { 468f9af6566SAxel Dörfler char buffer[2048]; 469f9af6566SAxel Dörfler ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer), 470f9af6566SAxel Dörfler 0, NULL, NULL); 4714b661a95SAxel Dörfler if (bytesReceived < 0 && errno == B_TIMED_OUT) { 472f9af6566SAxel Dörfler // depending on the state, we'll just try again 4736cc7630fSAxel Dörfler if (!_TimeoutShift(socket, timeout, tries)) { 4746cc7630fSAxel Dörfler close(socket); 4756cc7630fSAxel Dörfler return B_TIMED_OUT; 476f9af6566SAxel Dörfler } 477f9af6566SAxel Dörfler 478f9af6566SAxel Dörfler if (state == INIT) 479593a0d2dSAxel Dörfler _SendMessage(socket, discover, broadcast); 48015ab0bcfSAxel Dörfler else { 481593a0d2dSAxel Dörfler _SendMessage(socket, request, 482593a0d2dSAxel Dörfler state != RENEWAL ? broadcast : fServer); 48315ab0bcfSAxel Dörfler } 484f9af6566SAxel Dörfler 485d77fe260SAxel Dörfler continue; 486593a0d2dSAxel Dörfler } else if (bytesReceived < 0) 487f9af6566SAxel Dörfler break; 488f9af6566SAxel Dörfler 489f9af6566SAxel Dörfler dhcp_message* message = (dhcp_message*)buffer; 490f9af6566SAxel Dörfler if (message->transaction_id != htonl(fTransactionID) 491f9af6566SAxel Dörfler || !message->HasOptions() 492f9af6566SAxel Dörfler || memcmp(message->mac_address, discover.mac_address, 493f9af6566SAxel Dörfler discover.hardware_address_length)) { 494f9af6566SAxel Dörfler // this message is not for us 495f9af6566SAxel Dörfler continue; 496f9af6566SAxel Dörfler } 497f9af6566SAxel Dörfler 498f9af6566SAxel Dörfler switch (message->Type()) { 499f9af6566SAxel Dörfler case DHCP_NONE: 500f9af6566SAxel Dörfler default: 501f9af6566SAxel Dörfler // ignore this message 502f9af6566SAxel Dörfler break; 503f9af6566SAxel Dörfler 504f9af6566SAxel Dörfler case DHCP_OFFER: 505f9af6566SAxel Dörfler { 506f9af6566SAxel Dörfler // first offer wins 507f9af6566SAxel Dörfler if (state != INIT) 508f9af6566SAxel Dörfler break; 509f9af6566SAxel Dörfler 510f9af6566SAxel Dörfler // collect interface options 511f9af6566SAxel Dörfler 512f9af6566SAxel Dörfler fAssignedAddress = message->your_address; 513f9af6566SAxel Dörfler 51410cc12daSAxel Dörfler fConfiguration.MakeEmpty(); 515293ed4feSAxel Dörfler fConfiguration.AddString("device", Device()); 516f01106c3SAxel Dörfler fConfiguration.AddBool("auto", true); 517f9af6566SAxel Dörfler 518f9af6566SAxel Dörfler BMessage address; 519f9af6566SAxel Dörfler address.AddString("family", "inet"); 520f9af6566SAxel Dörfler address.AddString("address", _ToString(fAssignedAddress)); 521*16e8f13aSAxel Dörfler fResolverConfiguration.MakeEmpty(); 522*16e8f13aSAxel Dörfler _ParseOptions(*message, address, fResolverConfiguration); 523f9af6566SAxel Dörfler 52410cc12daSAxel Dörfler fConfiguration.AddMessage("address", &address); 525f9af6566SAxel Dörfler 52610cc12daSAxel Dörfler // request configuration from the server 527f9af6566SAxel Dörfler 5286cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 529f9af6566SAxel Dörfler state = REQUESTING; 53046ff5400SAxel Dörfler _PrepareMessage(request, state); 531f9af6566SAxel Dörfler 5326cc7630fSAxel Dörfler status = _SendMessage(socket, request, broadcast); 53315ab0bcfSAxel Dörfler // we're sending a broadcast so that all potential offers 53415ab0bcfSAxel Dörfler // get an answer 53510cc12daSAxel Dörfler break; 536f9af6566SAxel Dörfler } 537f9af6566SAxel Dörfler 538f9af6566SAxel Dörfler case DHCP_ACK: 53910cc12daSAxel Dörfler { 54015ab0bcfSAxel Dörfler if (state != REQUESTING && state != REBINDING 54115ab0bcfSAxel Dörfler && state != RENEWAL) 542f9af6566SAxel Dörfler continue; 543f9af6566SAxel Dörfler 5446cc7630fSAxel Dörfler // TODO: we might want to configure the stuff, don't we? 5456cc7630fSAxel Dörfler BMessage address; 546*16e8f13aSAxel Dörfler fResolverConfiguration.MakeEmpty(); 547*16e8f13aSAxel Dörfler _ParseOptions(*message, address, fResolverConfiguration); 5486cc7630fSAxel Dörfler // TODO: currently, only lease time and DNS is updated this way 5496cc7630fSAxel Dörfler 550f9af6566SAxel Dörfler // our address request has been acknowledged 551f9af6566SAxel Dörfler state = ACKNOWLEDGED; 55210cc12daSAxel Dörfler 55310cc12daSAxel Dörfler // configure interface 55410cc12daSAxel Dörfler BMessage reply; 555d23fdd96SOliver Tappe status = Target().SendMessage(&fConfiguration, &reply); 556d23fdd96SOliver Tappe if (status == B_OK) 557d23fdd96SOliver Tappe status = reply.FindInt32("status", &fStatus); 558*16e8f13aSAxel Dörfler 559*16e8f13aSAxel Dörfler // configure resolver 560*16e8f13aSAxel Dörfler reply.MakeEmpty(); 561*16e8f13aSAxel Dörfler status = Target().SendMessage(&fResolverConfiguration, &reply); 562*16e8f13aSAxel Dörfler if (status == B_OK) 563*16e8f13aSAxel Dörfler status = reply.FindInt32("status", &fStatus); 564f9af6566SAxel Dörfler break; 56510cc12daSAxel Dörfler } 566f9af6566SAxel Dörfler 567f9af6566SAxel Dörfler case DHCP_NACK: 568f9af6566SAxel Dörfler if (state != REQUESTING) 569f9af6566SAxel Dörfler continue; 570f9af6566SAxel Dörfler 57115ab0bcfSAxel Dörfler // try again (maybe we should prefer other servers if this 57215ab0bcfSAxel Dörfler // happens more than once) 5736cc7630fSAxel Dörfler status = _SendMessage(socket, discover, broadcast); 5746cc7630fSAxel Dörfler if (status == B_OK) 575f9af6566SAxel Dörfler state = INIT; 576f9af6566SAxel Dörfler break; 577f9af6566SAxel Dörfler } 578f9af6566SAxel Dörfler } 579f9af6566SAxel Dörfler 580fb81684fSAxel Dörfler close(socket); 5816cc7630fSAxel Dörfler 5826cc7630fSAxel Dörfler if (status == B_OK && fLeaseTime > 0) { 5836cc7630fSAxel Dörfler // notify early enough when the lease is 58446ff5400SAxel Dörfler if (fRenewalTime == 0) 58546ff5400SAxel Dörfler fRenewalTime = fLeaseTime * 2/3; 58646ff5400SAxel Dörfler if (fRebindingTime == 0) 58746ff5400SAxel Dörfler fRebindingTime = fLeaseTime * 5/6; 58846ff5400SAxel Dörfler 589168cc3dfSRene Gollent bigtime_t now = system_time(); 59046ff5400SAxel Dörfler _RestartLease(fRenewalTime); 59146ff5400SAxel Dörfler 59246ff5400SAxel Dörfler fLeaseTime += now; 59346ff5400SAxel Dörfler fRenewalTime += now; 59446ff5400SAxel Dörfler fRebindingTime += now; 59546ff5400SAxel Dörfler // make lease times absolute 59646ff5400SAxel Dörfler } else { 5976cc7630fSAxel Dörfler fLeaseTime = previousLeaseTime; 59846ff5400SAxel Dörfler bigtime_t now = system_time(); 59946ff5400SAxel Dörfler fRenewalTime = (fLeaseTime - now) * 2/3 + now; 60046ff5400SAxel Dörfler fRebindingTime = (fLeaseTime - now) * 5/6 + now; 60146ff5400SAxel Dörfler } 6026cc7630fSAxel Dörfler 6036cc7630fSAxel Dörfler return status; 604fb81684fSAxel Dörfler } 605fb81684fSAxel Dörfler 606fb81684fSAxel Dörfler 6076cc7630fSAxel Dörfler void 6086cc7630fSAxel Dörfler DHCPClient::_RestartLease(bigtime_t leaseTime) 609fb81684fSAxel Dörfler { 6106cc7630fSAxel Dörfler if (leaseTime == 0) 611f9af6566SAxel Dörfler return; 612f9af6566SAxel Dörfler 6136cc7630fSAxel Dörfler BMessage lease(kMsgLeaseTime); 61446ff5400SAxel Dörfler fRunner = new BMessageRunner(this, &lease, leaseTime, 1); 615f9af6566SAxel Dörfler } 616f9af6566SAxel Dörfler 617f9af6566SAxel Dörfler 618f9af6566SAxel Dörfler void 619*16e8f13aSAxel Dörfler DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address, 620*16e8f13aSAxel Dörfler BMessage& resolverConfiguration) 6210ce7725eSAxel Dörfler { 6220ce7725eSAxel Dörfler dhcp_option_cookie cookie; 6230ce7725eSAxel Dörfler message_option option; 6240ce7725eSAxel Dörfler const uint8* data; 6250ce7725eSAxel Dörfler size_t size; 6260ce7725eSAxel Dörfler while (message.NextOption(cookie, option, data, size)) { 6270ce7725eSAxel Dörfler // iterate through all options 6280ce7725eSAxel Dörfler switch (option) { 6290ce7725eSAxel Dörfler case OPTION_ROUTER_ADDRESS: 6300ce7725eSAxel Dörfler address.AddString("gateway", _ToString(data)); 6310ce7725eSAxel Dörfler break; 6320ce7725eSAxel Dörfler case OPTION_SUBNET_MASK: 6330ce7725eSAxel Dörfler address.AddString("mask", _ToString(data)); 6340ce7725eSAxel Dörfler break; 6355782c5a3SAxel Dörfler case OPTION_BROADCAST_ADDRESS: 6365782c5a3SAxel Dörfler address.AddString("broadcast", _ToString(data)); 6375782c5a3SAxel Dörfler break; 6380ce7725eSAxel Dörfler case OPTION_DOMAIN_NAME_SERVER: 639a552ec13SAxel Dörfler { 6400ce7725eSAxel Dörfler for (uint32 i = 0; i < size / 4; i++) { 641293ed4feSAxel Dörfler syslog(LOG_INFO, "DNS: %s\n", 642293ed4feSAxel Dörfler _ToString(&data[i * 4]).String()); 643*16e8f13aSAxel Dörfler resolverConfiguration.AddString("nameserver", 64415ab0bcfSAxel Dörfler _ToString(&data[i * 4]).String()); 64515ab0bcfSAxel Dörfler } 646*16e8f13aSAxel Dörfler resolverConfiguration.AddInt32("nameserver_count", 647*16e8f13aSAxel Dörfler size / 4); 6480ce7725eSAxel Dörfler break; 649a552ec13SAxel Dörfler } 6500ce7725eSAxel Dörfler case OPTION_SERVER_ADDRESS: 6510ce7725eSAxel Dörfler fServer.sin_addr.s_addr = *(in_addr_t*)data; 6520ce7725eSAxel Dörfler break; 65346ff5400SAxel Dörfler 6540ce7725eSAxel Dörfler case OPTION_ADDRESS_LEASE_TIME: 655293ed4feSAxel Dörfler syslog(LOG_INFO, "lease time of %lu seconds\n", 656293ed4feSAxel Dörfler htonl(*(uint32*)data)); 6576cc7630fSAxel Dörfler fLeaseTime = htonl(*(uint32*)data) * 1000000LL; 6580ce7725eSAxel Dörfler break; 6591a4e8e7bSAxel Dörfler case OPTION_RENEWAL_TIME: 660293ed4feSAxel Dörfler syslog(LOG_INFO, "renewal time of %lu seconds\n", 66146ff5400SAxel Dörfler htonl(*(uint32*)data)); 66246ff5400SAxel Dörfler fRenewalTime = htonl(*(uint32*)data) * 1000000LL; 66346ff5400SAxel Dörfler break; 6641a4e8e7bSAxel Dörfler case OPTION_REBINDING_TIME: 665293ed4feSAxel Dörfler syslog(LOG_INFO, "rebinding time of %lu seconds\n", 66646ff5400SAxel Dörfler htonl(*(uint32*)data)); 66746ff5400SAxel Dörfler fRebindingTime = htonl(*(uint32*)data) * 1000000LL; 6681a4e8e7bSAxel Dörfler break; 6691a4e8e7bSAxel Dörfler 6700ce7725eSAxel Dörfler case OPTION_HOST_NAME: 671*16e8f13aSAxel Dörfler syslog(LOG_INFO, "DHCP host name: \"%.*s\"\n", (int)size, 672*16e8f13aSAxel Dörfler (const char*)data); 6730ce7725eSAxel Dörfler break; 6745782c5a3SAxel Dörfler 6755782c5a3SAxel Dörfler case OPTION_DOMAIN_NAME: 6765782c5a3SAxel Dörfler { 677*16e8f13aSAxel Dörfler char domain[256]; 678*16e8f13aSAxel Dörfler strlcpy(domain, (const char*)data, 679*16e8f13aSAxel Dörfler min_c(size + 1, sizeof(domain))); 6800f87f52fSStephan Aßmus 681*16e8f13aSAxel Dörfler syslog(LOG_INFO, "DHCP domain name: \"%s\"\n", domain); 6820f87f52fSStephan Aßmus 683*16e8f13aSAxel Dörfler resolverConfiguration.AddString("domain", domain); 6845782c5a3SAxel Dörfler break; 6855782c5a3SAxel Dörfler } 6860ce7725eSAxel Dörfler 6870ce7725eSAxel Dörfler case OPTION_MESSAGE_TYPE: 6880ce7725eSAxel Dörfler break; 6890ce7725eSAxel Dörfler 6900ce7725eSAxel Dörfler default: 691293ed4feSAxel Dörfler syslog(LOG_INFO, "unknown option %lu\n", (uint32)option); 6920ce7725eSAxel Dörfler break; 6930ce7725eSAxel Dörfler } 6940ce7725eSAxel Dörfler } 6950ce7725eSAxel Dörfler } 6960ce7725eSAxel Dörfler 6970ce7725eSAxel Dörfler 6980ce7725eSAxel Dörfler void 69946ff5400SAxel Dörfler DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state) 7000ce7725eSAxel Dörfler { 7010ce7725eSAxel Dörfler message.opcode = BOOT_REQUEST; 7020ce7725eSAxel Dörfler message.hardware_type = ARP_HARDWARE_TYPE_ETHER; 7030ce7725eSAxel Dörfler message.hardware_address_length = 6; 7040ce7725eSAxel Dörfler message.transaction_id = htonl(fTransactionID); 705bcc8dadaSAxel Dörfler message.seconds_since_start = htons(min_c((system_time() - fStartTime) 70615ab0bcfSAxel Dörfler / 1000000LL, 65535)); 7070ce7725eSAxel Dörfler memcpy(message.mac_address, fMAC, 6); 7080ce7725eSAxel Dörfler 70946ff5400SAxel Dörfler message_type type = message.Type(); 71046ff5400SAxel Dörfler 71146ff5400SAxel Dörfler switch (type) { 7120ce7725eSAxel Dörfler case DHCP_REQUEST: 7130ce7725eSAxel Dörfler case DHCP_RELEASE: 7140ce7725eSAxel Dörfler { 7150ce7725eSAxel Dörfler // add server identifier option 716a073ba1aSHugo Santos uint8* next = message.PrepareMessage(type); 7170ce7725eSAxel Dörfler next = message.PutOption(next, OPTION_SERVER_ADDRESS, 7180ce7725eSAxel Dörfler (uint32)fServer.sin_addr.s_addr); 71946ff5400SAxel Dörfler 72046ff5400SAxel Dörfler // In RENEWAL or REBINDING state, we must set the client_address field, and not 72146ff5400SAxel Dörfler // use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages 7225d4d5313SHugo Santos if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING)) { 72315ab0bcfSAxel Dörfler next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, 72415ab0bcfSAxel Dörfler (uint32)fAssignedAddress); 7255d4d5313SHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 72637a68cb1SAxel Dörfler kRequestParameters, sizeof(kRequestParameters)); 7275d4d5313SHugo Santos } else 72846ff5400SAxel Dörfler message.client_address = fAssignedAddress; 72946ff5400SAxel Dörfler 730a073ba1aSHugo Santos message.FinishOptions(next); 731a073ba1aSHugo Santos break; 732a073ba1aSHugo Santos } 733a073ba1aSHugo Santos 734a073ba1aSHugo Santos case DHCP_DISCOVER: 735a073ba1aSHugo Santos { 736a073ba1aSHugo Santos uint8* next = message.PrepareMessage(type); 737a073ba1aSHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 73837a68cb1SAxel Dörfler kRequestParameters, sizeof(kRequestParameters)); 739a073ba1aSHugo Santos message.FinishOptions(next); 7400ce7725eSAxel Dörfler break; 7410ce7725eSAxel Dörfler } 7420ce7725eSAxel Dörfler 7430ce7725eSAxel Dörfler default: 7440ce7725eSAxel Dörfler // the default options are fine 7450ce7725eSAxel Dörfler break; 7460ce7725eSAxel Dörfler } 7470ce7725eSAxel Dörfler } 7480ce7725eSAxel Dörfler 7490ce7725eSAxel Dörfler 7500ce7725eSAxel Dörfler void 7516cc7630fSAxel Dörfler DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries) 752f9af6566SAxel Dörfler { 7536cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 7546cc7630fSAxel Dörfler tries = 0; 755f9af6566SAxel Dörfler 756f9af6566SAxel Dörfler struct timeval value; 7576cc7630fSAxel Dörfler value.tv_sec = timeout; 758f9af6566SAxel Dörfler value.tv_usec = 0; 759f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 760f9af6566SAxel Dörfler } 761f9af6566SAxel Dörfler 762f9af6566SAxel Dörfler 763f9af6566SAxel Dörfler bool 7646cc7630fSAxel Dörfler DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries) 765f9af6566SAxel Dörfler { 7666cc7630fSAxel Dörfler timeout += timeout; 7676cc7630fSAxel Dörfler if (timeout > MAX_TIMEOUT) { 7686cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 769f9af6566SAxel Dörfler 7706cc7630fSAxel Dörfler if (++tries > 2) 771f9af6566SAxel Dörfler return false; 772f9af6566SAxel Dörfler } 773293ed4feSAxel Dörfler syslog(LOG_DEBUG, "DHCP timeout shift: %lu secs (try %lu)\n", timeout, 774293ed4feSAxel Dörfler tries); 775f9af6566SAxel Dörfler 776f9af6566SAxel Dörfler struct timeval value; 7776cc7630fSAxel Dörfler value.tv_sec = timeout; 778f9af6566SAxel Dörfler value.tv_usec = 0; 779f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 780f9af6566SAxel Dörfler 781f9af6566SAxel Dörfler return true; 782f9af6566SAxel Dörfler } 783f9af6566SAxel Dörfler 784f9af6566SAxel Dörfler 785f9af6566SAxel Dörfler BString 786f9af6566SAxel Dörfler DHCPClient::_ToString(const uint8* data) const 787f9af6566SAxel Dörfler { 788f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)data); 789f9af6566SAxel Dörfler return target; 790f9af6566SAxel Dörfler } 791f9af6566SAxel Dörfler 792f9af6566SAxel Dörfler 793f9af6566SAxel Dörfler BString 794f9af6566SAxel Dörfler DHCPClient::_ToString(in_addr_t address) const 795f9af6566SAxel Dörfler { 796f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)&address); 797f9af6566SAxel Dörfler return target; 798f9af6566SAxel Dörfler } 799f9af6566SAxel Dörfler 800f9af6566SAxel Dörfler 801f9af6566SAxel Dörfler status_t 8021a905a76SAxel Dörfler DHCPClient::_SendMessage(int socket, dhcp_message& message, 8031a905a76SAxel Dörfler sockaddr_in& address) const 804f9af6566SAxel Dörfler { 805f9af6566SAxel Dörfler ssize_t bytesSent = sendto(socket, &message, message.Size(), 806f9af6566SAxel Dörfler address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0, 807f9af6566SAxel Dörfler (struct sockaddr*)&address, sizeof(sockaddr_in)); 808f9af6566SAxel Dörfler if (bytesSent < 0) 809f9af6566SAxel Dörfler return errno; 810f9af6566SAxel Dörfler 811f9af6566SAxel Dörfler return B_OK; 812fb81684fSAxel Dörfler } 813fb81684fSAxel Dörfler 814fb81684fSAxel Dörfler 81546ff5400SAxel Dörfler dhcp_state 81646ff5400SAxel Dörfler DHCPClient::_CurrentState() const 81746ff5400SAxel Dörfler { 81846ff5400SAxel Dörfler bigtime_t now = system_time(); 81946ff5400SAxel Dörfler 82046ff5400SAxel Dörfler if (now > fLeaseTime || fStatus < B_OK) 82146ff5400SAxel Dörfler return INIT; 82246ff5400SAxel Dörfler if (now >= fRebindingTime) 82346ff5400SAxel Dörfler return REBINDING; 82446ff5400SAxel Dörfler if (now >= fRenewalTime) 82546ff5400SAxel Dörfler return RENEWAL; 82646ff5400SAxel Dörfler 82746ff5400SAxel Dörfler return BOUND; 82846ff5400SAxel Dörfler } 82946ff5400SAxel Dörfler 83046ff5400SAxel Dörfler 831fb81684fSAxel Dörfler void 832fb81684fSAxel Dörfler DHCPClient::MessageReceived(BMessage* message) 833fb81684fSAxel Dörfler { 8346cc7630fSAxel Dörfler switch (message->what) { 8356cc7630fSAxel Dörfler case kMsgLeaseTime: 83646ff5400SAxel Dörfler { 83746ff5400SAxel Dörfler dhcp_state state = _CurrentState(); 83846ff5400SAxel Dörfler 83946ff5400SAxel Dörfler bigtime_t next; 84046ff5400SAxel Dörfler if (_Negotiate(state) == B_OK) { 84146ff5400SAxel Dörfler switch (state) { 84246ff5400SAxel Dörfler case RENEWAL: 84346ff5400SAxel Dörfler next = fRebindingTime; 8446cc7630fSAxel Dörfler break; 84546ff5400SAxel Dörfler case REBINDING: 84646ff5400SAxel Dörfler default: 84746ff5400SAxel Dörfler next = fRenewalTime; 84846ff5400SAxel Dörfler break; 84946ff5400SAxel Dörfler } 85046ff5400SAxel Dörfler } else { 85146ff5400SAxel Dörfler switch (state) { 85246ff5400SAxel Dörfler case RENEWAL: 85346ff5400SAxel Dörfler next = (fLeaseTime - fRebindingTime) / 4 + system_time(); 85446ff5400SAxel Dörfler break; 85546ff5400SAxel Dörfler case REBINDING: 85646ff5400SAxel Dörfler default: 85746ff5400SAxel Dörfler next = (fLeaseTime - fRenewalTime) / 4 + system_time(); 85846ff5400SAxel Dörfler break; 85946ff5400SAxel Dörfler } 86046ff5400SAxel Dörfler } 86146ff5400SAxel Dörfler 86246ff5400SAxel Dörfler _RestartLease(next - system_time()); 86346ff5400SAxel Dörfler break; 86446ff5400SAxel Dörfler } 8656cc7630fSAxel Dörfler 8666cc7630fSAxel Dörfler default: 867fb81684fSAxel Dörfler BHandler::MessageReceived(message); 8686cc7630fSAxel Dörfler break; 8696cc7630fSAxel Dörfler } 870fb81684fSAxel Dörfler } 871