1fb81684fSAxel Dörfler /* 21a905a76SAxel Dörfler * Copyright 2006-2009, 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> 20293ed4feSAxel Dörfler #include <syslog.h> 2136bde12dSAxel Dörfler #include <sys/sockio.h> 22f9af6566SAxel Dörfler #include <sys/time.h> 23fb81684fSAxel Dörfler 24fb81684fSAxel Dörfler 25fb81684fSAxel Dörfler // See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options 26fb81684fSAxel Dörfler 27fb81684fSAxel Dörfler #define DHCP_CLIENT_PORT 68 28fb81684fSAxel Dörfler #define DHCP_SERVER_PORT 67 29fb81684fSAxel Dörfler 30f9af6566SAxel Dörfler #define DEFAULT_TIMEOUT 2 // secs 31f9af6566SAxel Dörfler #define MAX_TIMEOUT 15 // secs 32f9af6566SAxel Dörfler 33fb81684fSAxel Dörfler enum message_opcode { 34fb81684fSAxel Dörfler BOOT_REQUEST = 1, 35fb81684fSAxel Dörfler BOOT_REPLY 36fb81684fSAxel Dörfler }; 37fb81684fSAxel Dörfler 38fb81684fSAxel Dörfler enum message_option { 39fb81684fSAxel Dörfler OPTION_MAGIC = 0x63825363, 40fb81684fSAxel Dörfler 41fb81684fSAxel Dörfler // generic options 42fb81684fSAxel Dörfler OPTION_PAD = 0, 43f9af6566SAxel Dörfler OPTION_END = 255, 44f9af6566SAxel Dörfler OPTION_SUBNET_MASK = 1, 4565186fecSAxel Dörfler OPTION_TIME_OFFSET = 2, 46f9af6566SAxel Dörfler OPTION_ROUTER_ADDRESS = 3, 47f9af6566SAxel Dörfler OPTION_DOMAIN_NAME_SERVER = 6, 48f9af6566SAxel Dörfler OPTION_HOST_NAME = 12, 495782c5a3SAxel Dörfler OPTION_DOMAIN_NAME = 15, 50fb81684fSAxel Dörfler OPTION_DATAGRAM_SIZE = 22, 51fb81684fSAxel Dörfler OPTION_MTU = 26, 52fb81684fSAxel Dörfler OPTION_BROADCAST_ADDRESS = 28, 53fb81684fSAxel Dörfler OPTION_NETWORK_TIME_SERVERS = 42, 5465186fecSAxel Dörfler OPTION_NETBIOS_NAME_SERVER = 44, 5565186fecSAxel Dörfler OPTION_NETBIOS_SCOPE = 47, 56fb81684fSAxel Dörfler 57fb81684fSAxel Dörfler // DHCP specific options 58fb81684fSAxel Dörfler OPTION_REQUEST_IP_ADDRESS = 50, 59fb81684fSAxel Dörfler OPTION_ADDRESS_LEASE_TIME = 51, 60fb81684fSAxel Dörfler OPTION_OVERLOAD = 52, 61fb81684fSAxel Dörfler OPTION_MESSAGE_TYPE = 53, 62fb81684fSAxel Dörfler OPTION_SERVER_ADDRESS = 54, 63fb81684fSAxel Dörfler OPTION_REQUEST_PARAMETERS = 55, 64fb81684fSAxel Dörfler OPTION_ERROR_MESSAGE = 56, 65fb81684fSAxel Dörfler OPTION_MESSAGE_SIZE = 57, 66fb81684fSAxel Dörfler OPTION_RENEWAL_TIME = 58, 67fb81684fSAxel Dörfler OPTION_REBINDING_TIME = 59, 68fb81684fSAxel Dörfler OPTION_CLASS_IDENTIFIER = 60, 69fb81684fSAxel Dörfler OPTION_CLIENT_IDENTIFIER = 61, 70fb81684fSAxel Dörfler }; 71fb81684fSAxel Dörfler 72fb81684fSAxel Dörfler enum message_type { 73f9af6566SAxel Dörfler DHCP_NONE = 0, 74f9af6566SAxel Dörfler DHCP_DISCOVER, 75fb81684fSAxel Dörfler DHCP_OFFER, 76fb81684fSAxel Dörfler DHCP_REQUEST, 77fb81684fSAxel Dörfler DHCP_DECLINE, 78fb81684fSAxel Dörfler DHCP_ACK, 79f9af6566SAxel Dörfler DHCP_NACK, 80fb81684fSAxel Dörfler DHCP_RELEASE, 81fb81684fSAxel Dörfler DHCP_INFORM 82fb81684fSAxel Dörfler }; 83fb81684fSAxel Dörfler 84fb81684fSAxel Dörfler struct dhcp_option_cookie { 8515ab0bcfSAxel Dörfler dhcp_option_cookie() 8615ab0bcfSAxel Dörfler : 8715ab0bcfSAxel Dörfler state(0), 8815ab0bcfSAxel Dörfler file_has_options(false), 8915ab0bcfSAxel Dörfler server_name_has_options(false) 9015ab0bcfSAxel Dörfler { 9115ab0bcfSAxel Dörfler } 92fb81684fSAxel Dörfler 93fb81684fSAxel Dörfler const uint8* next; 94fb81684fSAxel Dörfler uint8 state; 95fb81684fSAxel Dörfler bool file_has_options; 96fb81684fSAxel Dörfler bool server_name_has_options; 97fb81684fSAxel Dörfler }; 98fb81684fSAxel Dörfler 99fb81684fSAxel Dörfler struct dhcp_message { 100fb81684fSAxel Dörfler dhcp_message(message_type type); 101fb81684fSAxel Dörfler 102fb81684fSAxel Dörfler uint8 opcode; 103fb81684fSAxel Dörfler uint8 hardware_type; 104fb81684fSAxel Dörfler uint8 hardware_address_length; 105fb81684fSAxel Dörfler uint8 hop_count; 106fb81684fSAxel Dörfler uint32 transaction_id; 10746ff5400SAxel Dörfler uint16 seconds_since_start; 108fb81684fSAxel Dörfler uint16 flags; 109fb81684fSAxel Dörfler in_addr_t client_address; 110fb81684fSAxel Dörfler in_addr_t your_address; 111fb81684fSAxel Dörfler in_addr_t server_address; 112fb81684fSAxel Dörfler in_addr_t gateway_address; 113fb81684fSAxel Dörfler uint8 mac_address[16]; 114fb81684fSAxel Dörfler uint8 server_name[64]; 115fb81684fSAxel Dörfler uint8 file[128]; 116fb81684fSAxel Dörfler uint32 options_magic; 117fb81684fSAxel Dörfler uint8 options[1260]; 118fb81684fSAxel Dörfler 119fb81684fSAxel Dörfler size_t MinSize() const { return 576; } 120fb81684fSAxel Dörfler size_t Size() const; 121fb81684fSAxel Dörfler 122fb81684fSAxel Dörfler bool HasOptions() const; 123fb81684fSAxel Dörfler bool NextOption(dhcp_option_cookie& cookie, message_option& option, 124fb81684fSAxel Dörfler const uint8*& data, size_t& size) const; 125f9af6566SAxel Dörfler message_type Type() const; 126fb81684fSAxel Dörfler const uint8* LastOption() const; 127fb81684fSAxel Dörfler 128a073ba1aSHugo Santos uint8* PrepareMessage(uint8 type); 129fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option); 130fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint8 data); 131fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint16 data); 132fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint32 data); 13315ab0bcfSAxel Dörfler uint8* PutOption(uint8* options, message_option option, const uint8* data, 13415ab0bcfSAxel Dörfler uint32 size); 135a073ba1aSHugo Santos uint8* FinishOptions(uint8 *); 136fb81684fSAxel Dörfler } _PACKED; 137fb81684fSAxel Dörfler 1380cf5e6acSAxel Dörfler #define DHCP_FLAG_BROADCAST 0x8000 139fb81684fSAxel Dörfler 140fb81684fSAxel Dörfler #define ARP_HARDWARE_TYPE_ETHER 1 141fb81684fSAxel Dörfler 1426cc7630fSAxel Dörfler const uint32 kMsgLeaseTime = 'lstm'; 1436cc7630fSAxel Dörfler 1445d4d5313SHugo Santos static const uint8 kRequiredParameters[] = { 14565186fecSAxel Dörfler OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS, 14665186fecSAxel Dörfler OPTION_DOMAIN_NAME_SERVER, OPTION_BROADCAST_ADDRESS 1475d4d5313SHugo Santos }; 1485d4d5313SHugo Santos 149fb81684fSAxel Dörfler 150fb81684fSAxel Dörfler dhcp_message::dhcp_message(message_type type) 151fb81684fSAxel Dörfler { 152fb81684fSAxel Dörfler memset(this, 0, sizeof(*this)); 153fb81684fSAxel Dörfler options_magic = htonl(OPTION_MAGIC); 154fb81684fSAxel Dörfler 155a073ba1aSHugo Santos uint8* next = PrepareMessage(type); 156a073ba1aSHugo Santos FinishOptions(next); 157fb81684fSAxel Dörfler } 158fb81684fSAxel Dörfler 159fb81684fSAxel Dörfler 160fb81684fSAxel Dörfler bool 161fb81684fSAxel Dörfler dhcp_message::HasOptions() const 162fb81684fSAxel Dörfler { 163fb81684fSAxel Dörfler return options_magic == htonl(OPTION_MAGIC); 164fb81684fSAxel Dörfler } 165fb81684fSAxel Dörfler 166fb81684fSAxel Dörfler 167fb81684fSAxel Dörfler bool 168fb81684fSAxel Dörfler dhcp_message::NextOption(dhcp_option_cookie& cookie, 169fb81684fSAxel Dörfler message_option& option, const uint8*& data, size_t& size) const 170fb81684fSAxel Dörfler { 171fb81684fSAxel Dörfler if (cookie.state == 0) { 172fb81684fSAxel Dörfler if (!HasOptions()) 173fb81684fSAxel Dörfler return false; 174fb81684fSAxel Dörfler 175fb81684fSAxel Dörfler cookie.state++; 176fb81684fSAxel Dörfler cookie.next = options; 177fb81684fSAxel Dörfler } 178fb81684fSAxel Dörfler 179fb81684fSAxel Dörfler uint32 bytesLeft = 0; 180fb81684fSAxel Dörfler 181fb81684fSAxel Dörfler switch (cookie.state) { 182fb81684fSAxel Dörfler case 1: 183fb81684fSAxel Dörfler // options from "options" 184fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 185fb81684fSAxel Dörfler break; 186fb81684fSAxel Dörfler 187fb81684fSAxel Dörfler case 2: 188fb81684fSAxel Dörfler // options from "file" 189fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 190fb81684fSAxel Dörfler break; 191fb81684fSAxel Dörfler 192fb81684fSAxel Dörfler case 3: 193fb81684fSAxel Dörfler // options from "server_name" 194fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 195fb81684fSAxel Dörfler break; 196fb81684fSAxel Dörfler } 197fb81684fSAxel Dörfler 198fb81684fSAxel Dörfler while (true) { 199fb81684fSAxel Dörfler if (bytesLeft == 0) { 200fb81684fSAxel Dörfler // TODO: suppport OPTION_OVERLOAD! 201fb81684fSAxel Dörfler cookie.state = 4; 202fb81684fSAxel Dörfler return false; 203fb81684fSAxel Dörfler } 204fb81684fSAxel Dörfler 205fb81684fSAxel Dörfler option = (message_option)cookie.next[0]; 206fb81684fSAxel Dörfler if (option == OPTION_END) { 207fb81684fSAxel Dörfler cookie.state = 4; 208fb81684fSAxel Dörfler return false; 209fb81684fSAxel Dörfler } else if (option == OPTION_PAD) { 210fb81684fSAxel Dörfler bytesLeft--; 211fb81684fSAxel Dörfler cookie.next++; 212fb81684fSAxel Dörfler continue; 213fb81684fSAxel Dörfler } 214fb81684fSAxel Dörfler 215fb81684fSAxel Dörfler size = cookie.next[1]; 216fb81684fSAxel Dörfler data = &cookie.next[2]; 217fb81684fSAxel Dörfler cookie.next += 2 + size; 218fb81684fSAxel Dörfler 219fb81684fSAxel Dörfler if (option == OPTION_OVERLOAD) { 220fb81684fSAxel Dörfler cookie.file_has_options = data[0] & 1; 221fb81684fSAxel Dörfler cookie.server_name_has_options = data[0] & 2; 222fb81684fSAxel Dörfler continue; 223fb81684fSAxel Dörfler } 224fb81684fSAxel Dörfler 225fb81684fSAxel Dörfler return true; 226fb81684fSAxel Dörfler } 227fb81684fSAxel Dörfler } 228fb81684fSAxel Dörfler 229fb81684fSAxel Dörfler 230f9af6566SAxel Dörfler message_type 231f9af6566SAxel Dörfler dhcp_message::Type() const 232f9af6566SAxel Dörfler { 233f9af6566SAxel Dörfler dhcp_option_cookie cookie; 234f9af6566SAxel Dörfler message_option option; 235f9af6566SAxel Dörfler const uint8* data; 236f9af6566SAxel Dörfler size_t size; 237f9af6566SAxel Dörfler while (NextOption(cookie, option, data, size)) { 238f9af6566SAxel Dörfler // iterate through all options 239f9af6566SAxel Dörfler if (option == OPTION_MESSAGE_TYPE) 240f9af6566SAxel Dörfler return (message_type)data[0]; 241f9af6566SAxel Dörfler } 242f9af6566SAxel Dörfler 243f9af6566SAxel Dörfler return DHCP_NONE; 244f9af6566SAxel Dörfler } 245f9af6566SAxel Dörfler 246f9af6566SAxel Dörfler 247fb81684fSAxel Dörfler const uint8* 248fb81684fSAxel Dörfler dhcp_message::LastOption() const 249fb81684fSAxel Dörfler { 250fb81684fSAxel Dörfler dhcp_option_cookie cookie; 251fb81684fSAxel Dörfler message_option option; 252fb81684fSAxel Dörfler const uint8* data; 253fb81684fSAxel Dörfler size_t size; 254fb81684fSAxel Dörfler while (NextOption(cookie, option, data, size)) { 255fb81684fSAxel Dörfler // iterate through all options 256fb81684fSAxel Dörfler } 257fb81684fSAxel Dörfler 258fb81684fSAxel Dörfler return cookie.next; 259fb81684fSAxel Dörfler } 260fb81684fSAxel Dörfler 261fb81684fSAxel Dörfler 262fb81684fSAxel Dörfler size_t 263fb81684fSAxel Dörfler dhcp_message::Size() const 264fb81684fSAxel Dörfler { 265fb81684fSAxel Dörfler const uint8* last = LastOption(); 266fb81684fSAxel Dörfler return sizeof(dhcp_message) - sizeof(options) + last + 1 - options; 267fb81684fSAxel Dörfler } 268fb81684fSAxel Dörfler 269fb81684fSAxel Dörfler 270fb81684fSAxel Dörfler uint8* 271a073ba1aSHugo Santos dhcp_message::PrepareMessage(uint8 type) 272a073ba1aSHugo Santos { 273a073ba1aSHugo Santos uint8 *next = options; 274a073ba1aSHugo Santos next = PutOption(next, OPTION_MESSAGE_TYPE, type); 27515ab0bcfSAxel Dörfler next = PutOption(next, OPTION_MESSAGE_SIZE, 27615ab0bcfSAxel Dörfler (uint16)htons(sizeof(dhcp_message))); 277a073ba1aSHugo Santos return next; 278a073ba1aSHugo Santos } 279a073ba1aSHugo Santos 28065186fecSAxel Dörfler 281a073ba1aSHugo Santos uint8* 282fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option) 283fb81684fSAxel Dörfler { 284fb81684fSAxel Dörfler options[0] = option; 285fb81684fSAxel Dörfler return options + 1; 286fb81684fSAxel Dörfler } 287fb81684fSAxel Dörfler 288fb81684fSAxel Dörfler 289fb81684fSAxel Dörfler uint8* 290fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8 data) 291fb81684fSAxel Dörfler { 292fb81684fSAxel Dörfler return PutOption(options, option, &data, 1); 293fb81684fSAxel Dörfler } 294fb81684fSAxel Dörfler 295fb81684fSAxel Dörfler 296fb81684fSAxel Dörfler uint8* 297fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint16 data) 298fb81684fSAxel Dörfler { 299fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 300fb81684fSAxel Dörfler } 301fb81684fSAxel Dörfler 302fb81684fSAxel Dörfler 303fb81684fSAxel Dörfler uint8* 304fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint32 data) 305fb81684fSAxel Dörfler { 306fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 307fb81684fSAxel Dörfler } 308fb81684fSAxel Dörfler 309fb81684fSAxel Dörfler 310fb81684fSAxel Dörfler uint8* 31115ab0bcfSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, 31215ab0bcfSAxel Dörfler const uint8* data, uint32 size) 313fb81684fSAxel Dörfler { 314fb81684fSAxel Dörfler options[0] = option; 315fb81684fSAxel Dörfler options[1] = size; 316fb81684fSAxel Dörfler memcpy(&options[2], data, size); 317fb81684fSAxel Dörfler 318fb81684fSAxel Dörfler return options + 2 + size; 319fb81684fSAxel Dörfler } 320fb81684fSAxel Dörfler 321fb81684fSAxel Dörfler 322a073ba1aSHugo Santos uint8* 323a073ba1aSHugo Santos dhcp_message::FinishOptions(uint8 *next) 324a073ba1aSHugo Santos { 325a073ba1aSHugo Santos return PutOption(next, OPTION_END); 326a073ba1aSHugo Santos } 327a073ba1aSHugo Santos 328a073ba1aSHugo Santos 329fb81684fSAxel Dörfler // #pragma mark - 330fb81684fSAxel Dörfler 331fb81684fSAxel Dörfler 332f9af6566SAxel Dörfler DHCPClient::DHCPClient(BMessenger target, const char* device) 333293ed4feSAxel Dörfler : AutoconfigClient("dhcp", target, device), 3346cc7630fSAxel Dörfler fConfiguration(kMsgConfigureInterface), 3356cc7630fSAxel Dörfler fRunner(NULL), 3366cc7630fSAxel Dörfler fLeaseTime(0) 337fb81684fSAxel Dörfler { 33846ff5400SAxel Dörfler fStartTime = system_time(); 33946ff5400SAxel Dörfler fTransactionID = (uint32)fStartTime; 340fb81684fSAxel Dörfler 3410ce7725eSAxel Dörfler fStatus = get_mac_address(device, fMAC); 342fb81684fSAxel Dörfler if (fStatus < B_OK) 343fb81684fSAxel Dörfler return; 344fb81684fSAxel Dörfler 3456cc7630fSAxel Dörfler memset(&fServer, 0, sizeof(struct sockaddr_in)); 3466cc7630fSAxel Dörfler fServer.sin_family = AF_INET; 3476cc7630fSAxel Dörfler fServer.sin_len = sizeof(struct sockaddr_in); 3486cc7630fSAxel Dörfler fServer.sin_port = htons(DHCP_SERVER_PORT); 349293ed4feSAxel Dörfler 350293ed4feSAxel Dörfler openlog_thread("DHCP", 0, LOG_DAEMON); 3516cc7630fSAxel Dörfler } 3526cc7630fSAxel Dörfler 3536cc7630fSAxel Dörfler 3546cc7630fSAxel Dörfler DHCPClient::~DHCPClient() 3556cc7630fSAxel Dörfler { 3566cc7630fSAxel Dörfler if (fStatus != B_OK) 3576cc7630fSAxel Dörfler return; 3586cc7630fSAxel Dörfler 3596cc7630fSAxel Dörfler delete fRunner; 3600ce7725eSAxel Dörfler 361fb81684fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 3626cc7630fSAxel Dörfler if (socket < 0) 363fb81684fSAxel Dörfler return; 3646cc7630fSAxel Dörfler 3656cc7630fSAxel Dörfler // release lease 3666cc7630fSAxel Dörfler 3676cc7630fSAxel Dörfler dhcp_message release(DHCP_RELEASE); 36846ff5400SAxel Dörfler _PrepareMessage(release, BOUND); 3696cc7630fSAxel Dörfler 3706cc7630fSAxel Dörfler _SendMessage(socket, release, fServer); 3716cc7630fSAxel Dörfler close(socket); 372293ed4feSAxel Dörfler 373293ed4feSAxel Dörfler closelog_thread(); 374fb81684fSAxel Dörfler } 375fb81684fSAxel Dörfler 3766cc7630fSAxel Dörfler 3776cc7630fSAxel Dörfler status_t 3786cc7630fSAxel Dörfler DHCPClient::Initialize() 3796cc7630fSAxel Dörfler { 3806cc7630fSAxel Dörfler fStatus = _Negotiate(INIT); 381293ed4feSAxel Dörfler syslog(LOG_DEBUG, "DHCP for %s, status: %s\n", Device(), strerror(fStatus)); 3826cc7630fSAxel Dörfler return fStatus; 3836cc7630fSAxel Dörfler } 3846cc7630fSAxel Dörfler 3856cc7630fSAxel Dörfler 3866cc7630fSAxel Dörfler status_t 3876cc7630fSAxel Dörfler DHCPClient::_Negotiate(dhcp_state state) 3886cc7630fSAxel Dörfler { 3896cc7630fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 3906cc7630fSAxel Dörfler if (socket < 0) 3916cc7630fSAxel Dörfler return errno; 3926cc7630fSAxel Dörfler 393fb81684fSAxel Dörfler sockaddr_in local; 394fb81684fSAxel Dörfler memset(&local, 0, sizeof(struct sockaddr_in)); 395fb81684fSAxel Dörfler local.sin_family = AF_INET; 396fb81684fSAxel Dörfler local.sin_len = sizeof(struct sockaddr_in); 397fb81684fSAxel Dörfler local.sin_port = htons(DHCP_CLIENT_PORT); 398fb81684fSAxel Dörfler local.sin_addr.s_addr = INADDR_ANY; 399fb81684fSAxel Dörfler 400*2b829b04SBruno G. Albuquerque // Enable reusing the port . This is needed in case there is more 401*2b829b04SBruno G. Albuquerque // than 1 interface that needs to be configured. Note that the only reason 402*2b829b04SBruno G. Albuquerque // this works is because there is code below to bind to a specific 403*2b829b04SBruno G. Albuquerque // interface. 404*2b829b04SBruno G. Albuquerque int option = 1; 405*2b829b04SBruno G. Albuquerque setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option)); 406*2b829b04SBruno G. Albuquerque 407fb81684fSAxel Dörfler if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) { 408fb81684fSAxel Dörfler close(socket); 4096cc7630fSAxel Dörfler return errno; 410fb81684fSAxel Dörfler } 411fb81684fSAxel Dörfler 412fb81684fSAxel Dörfler sockaddr_in broadcast; 413fb81684fSAxel Dörfler memset(&broadcast, 0, sizeof(struct sockaddr_in)); 414fb81684fSAxel Dörfler broadcast.sin_family = AF_INET; 415fb81684fSAxel Dörfler broadcast.sin_len = sizeof(struct sockaddr_in); 416fb81684fSAxel Dörfler broadcast.sin_port = htons(DHCP_SERVER_PORT); 417fb81684fSAxel Dörfler broadcast.sin_addr.s_addr = INADDR_BROADCAST; 418fb81684fSAxel Dörfler 419*2b829b04SBruno G. Albuquerque option = 1; 420fb81684fSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); 421fb81684fSAxel Dörfler 42236bde12dSAxel Dörfler if (state == INIT) { 42336bde12dSAxel Dörfler // The local interface does not have an address yet, bind the socket 42436bde12dSAxel Dörfler // to the device directly. 42536bde12dSAxel Dörfler int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); 42636bde12dSAxel Dörfler if (linkSocket >= 0) { 42736bde12dSAxel Dörfler // we need to know the index of the device to be able to bind to it 42836bde12dSAxel Dörfler ifreq request; 429293ed4feSAxel Dörfler prepare_request(request, Device()); 43036bde12dSAxel Dörfler if (ioctl(linkSocket, SIOCGIFINDEX, &request, sizeof(struct ifreq)) 43136bde12dSAxel Dörfler == 0) { 43236bde12dSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, 43336bde12dSAxel Dörfler &request.ifr_index, sizeof(int)); 43436bde12dSAxel Dörfler } 43536bde12dSAxel Dörfler 43636bde12dSAxel Dörfler close(linkSocket); 43736bde12dSAxel Dörfler } 43836bde12dSAxel Dörfler } 43936bde12dSAxel Dörfler 4406cc7630fSAxel Dörfler bigtime_t previousLeaseTime = fLeaseTime; 4416cc7630fSAxel Dörfler fLeaseTime = 0; 44246ff5400SAxel Dörfler fRenewalTime = 0; 44346ff5400SAxel Dörfler fRebindingTime = 0; 444fb81684fSAxel Dörfler 4456cc7630fSAxel Dörfler status_t status = B_ERROR; 4466cc7630fSAxel Dörfler time_t timeout; 4476cc7630fSAxel Dörfler uint32 tries; 4486cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 4496cc7630fSAxel Dörfler 4506cc7630fSAxel Dörfler dhcp_message discover(DHCP_DISCOVER); 45146ff5400SAxel Dörfler _PrepareMessage(discover, state); 4526cc7630fSAxel Dörfler 4536cc7630fSAxel Dörfler dhcp_message request(DHCP_REQUEST); 45446ff5400SAxel Dörfler _PrepareMessage(request, state); 4556cc7630fSAxel Dörfler 45646ff5400SAxel Dörfler // send discover/request message 4576cc7630fSAxel Dörfler status = _SendMessage(socket, state == INIT ? discover : request, 45846ff5400SAxel Dörfler state != RENEWAL ? broadcast : fServer); 4596cc7630fSAxel Dörfler if (status < B_OK) { 460fb81684fSAxel Dörfler close(socket); 4616cc7630fSAxel Dörfler return status; 4626cc7630fSAxel Dörfler } 463fb81684fSAxel Dörfler 464f9af6566SAxel Dörfler // receive loop until we've got an offer and acknowledged it 465f9af6566SAxel Dörfler 466f9af6566SAxel Dörfler while (state != ACKNOWLEDGED) { 467f9af6566SAxel Dörfler char buffer[2048]; 468f9af6566SAxel Dörfler ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer), 469f9af6566SAxel Dörfler 0, NULL, NULL); 4704b661a95SAxel Dörfler if (bytesReceived < 0 && errno == B_TIMED_OUT) { 471f9af6566SAxel Dörfler // depending on the state, we'll just try again 4726cc7630fSAxel Dörfler if (!_TimeoutShift(socket, timeout, tries)) { 4736cc7630fSAxel Dörfler close(socket); 4746cc7630fSAxel Dörfler return B_TIMED_OUT; 475f9af6566SAxel Dörfler } 476f9af6566SAxel Dörfler 477f9af6566SAxel Dörfler if (state == INIT) 4786cc7630fSAxel Dörfler status = _SendMessage(socket, discover, broadcast); 47915ab0bcfSAxel Dörfler else { 48046ff5400SAxel Dörfler status = _SendMessage(socket, request, state != RENEWAL 4816cc7630fSAxel Dörfler ? broadcast : fServer); 48215ab0bcfSAxel Dörfler } 483f9af6566SAxel Dörfler 4846cc7630fSAxel Dörfler if (status < B_OK) 485f9af6566SAxel Dörfler break; 486f9af6566SAxel Dörfler } else if (bytesReceived < B_OK) 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)); 5210ce7725eSAxel Dörfler _ParseOptions(*message, address); 522f9af6566SAxel Dörfler 52310cc12daSAxel Dörfler fConfiguration.AddMessage("address", &address); 524f9af6566SAxel Dörfler 52510cc12daSAxel Dörfler // request configuration from the server 526f9af6566SAxel Dörfler 5276cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 528f9af6566SAxel Dörfler state = REQUESTING; 52946ff5400SAxel Dörfler _PrepareMessage(request, state); 530f9af6566SAxel Dörfler 5316cc7630fSAxel Dörfler status = _SendMessage(socket, request, broadcast); 53215ab0bcfSAxel Dörfler // we're sending a broadcast so that all potential offers 53315ab0bcfSAxel Dörfler // get an answer 53410cc12daSAxel Dörfler break; 535f9af6566SAxel Dörfler } 536f9af6566SAxel Dörfler 537f9af6566SAxel Dörfler case DHCP_ACK: 53810cc12daSAxel Dörfler { 53915ab0bcfSAxel Dörfler if (state != REQUESTING && state != REBINDING 54015ab0bcfSAxel Dörfler && state != RENEWAL) 541f9af6566SAxel Dörfler continue; 542f9af6566SAxel Dörfler 5436cc7630fSAxel Dörfler // TODO: we might want to configure the stuff, don't we? 5446cc7630fSAxel Dörfler BMessage address; 5456cc7630fSAxel Dörfler _ParseOptions(*message, address); 5466cc7630fSAxel Dörfler // TODO: currently, only lease time and DNS is updated this way 5476cc7630fSAxel Dörfler 548f9af6566SAxel Dörfler // our address request has been acknowledged 549f9af6566SAxel Dörfler state = ACKNOWLEDGED; 55010cc12daSAxel Dörfler 55110cc12daSAxel Dörfler // configure interface 55210cc12daSAxel Dörfler BMessage reply; 553293ed4feSAxel Dörfler Target().SendMessage(&fConfiguration, &reply); 55410cc12daSAxel Dörfler 55510cc12daSAxel Dörfler if (reply.FindInt32("status", &fStatus) != B_OK) 5566cc7630fSAxel Dörfler status = B_OK; 557f9af6566SAxel Dörfler break; 55810cc12daSAxel Dörfler } 559f9af6566SAxel Dörfler 560f9af6566SAxel Dörfler case DHCP_NACK: 561f9af6566SAxel Dörfler if (state != REQUESTING) 562f9af6566SAxel Dörfler continue; 563f9af6566SAxel Dörfler 56415ab0bcfSAxel Dörfler // try again (maybe we should prefer other servers if this 56515ab0bcfSAxel Dörfler // happens more than once) 5666cc7630fSAxel Dörfler status = _SendMessage(socket, discover, broadcast); 5676cc7630fSAxel Dörfler if (status == B_OK) 568f9af6566SAxel Dörfler state = INIT; 569f9af6566SAxel Dörfler break; 570f9af6566SAxel Dörfler } 571f9af6566SAxel Dörfler } 572f9af6566SAxel Dörfler 573fb81684fSAxel Dörfler close(socket); 5746cc7630fSAxel Dörfler 5756cc7630fSAxel Dörfler if (status == B_OK && fLeaseTime > 0) { 5766cc7630fSAxel Dörfler // notify early enough when the lease is 57746ff5400SAxel Dörfler if (fRenewalTime == 0) 57846ff5400SAxel Dörfler fRenewalTime = fLeaseTime * 2/3; 57946ff5400SAxel Dörfler if (fRebindingTime == 0) 58046ff5400SAxel Dörfler fRebindingTime = fLeaseTime * 5/6; 58146ff5400SAxel Dörfler 582168cc3dfSRene Gollent bigtime_t now = system_time(); 58346ff5400SAxel Dörfler _RestartLease(fRenewalTime); 58446ff5400SAxel Dörfler 58546ff5400SAxel Dörfler fLeaseTime += now; 58646ff5400SAxel Dörfler fRenewalTime += now; 58746ff5400SAxel Dörfler fRebindingTime += now; 58846ff5400SAxel Dörfler // make lease times absolute 58946ff5400SAxel Dörfler } else { 5906cc7630fSAxel Dörfler fLeaseTime = previousLeaseTime; 59146ff5400SAxel Dörfler bigtime_t now = system_time(); 59246ff5400SAxel Dörfler fRenewalTime = (fLeaseTime - now) * 2/3 + now; 59346ff5400SAxel Dörfler fRebindingTime = (fLeaseTime - now) * 5/6 + now; 59446ff5400SAxel Dörfler } 5956cc7630fSAxel Dörfler 5966cc7630fSAxel Dörfler return status; 597fb81684fSAxel Dörfler } 598fb81684fSAxel Dörfler 599fb81684fSAxel Dörfler 6006cc7630fSAxel Dörfler void 6016cc7630fSAxel Dörfler DHCPClient::_RestartLease(bigtime_t leaseTime) 602fb81684fSAxel Dörfler { 6036cc7630fSAxel Dörfler if (leaseTime == 0) 604f9af6566SAxel Dörfler return; 605f9af6566SAxel Dörfler 6066cc7630fSAxel Dörfler BMessage lease(kMsgLeaseTime); 60746ff5400SAxel Dörfler fRunner = new BMessageRunner(this, &lease, leaseTime, 1); 608f9af6566SAxel Dörfler } 609f9af6566SAxel Dörfler 610f9af6566SAxel Dörfler 611f9af6566SAxel Dörfler void 6120ce7725eSAxel Dörfler DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address) 6130ce7725eSAxel Dörfler { 6140ce7725eSAxel Dörfler dhcp_option_cookie cookie; 6150ce7725eSAxel Dörfler message_option option; 6160ce7725eSAxel Dörfler const uint8* data; 6170ce7725eSAxel Dörfler size_t size; 6180ce7725eSAxel Dörfler while (message.NextOption(cookie, option, data, size)) { 6190ce7725eSAxel Dörfler // iterate through all options 6200ce7725eSAxel Dörfler switch (option) { 6210ce7725eSAxel Dörfler case OPTION_ROUTER_ADDRESS: 6220ce7725eSAxel Dörfler address.AddString("gateway", _ToString(data)); 6230ce7725eSAxel Dörfler break; 6240ce7725eSAxel Dörfler case OPTION_SUBNET_MASK: 6250ce7725eSAxel Dörfler address.AddString("mask", _ToString(data)); 6260ce7725eSAxel Dörfler break; 6275782c5a3SAxel Dörfler case OPTION_BROADCAST_ADDRESS: 6285782c5a3SAxel Dörfler address.AddString("broadcast", _ToString(data)); 6295782c5a3SAxel Dörfler break; 6300ce7725eSAxel Dörfler case OPTION_DOMAIN_NAME_SERVER: 631a552ec13SAxel Dörfler { 632a552ec13SAxel Dörfler // TODO: for now, we write it just out to /etc/resolv.conf 633a552ec13SAxel Dörfler FILE* file = fopen("/etc/resolv.conf", "w"); 6340ce7725eSAxel Dörfler for (uint32 i = 0; i < size / 4; i++) { 635293ed4feSAxel Dörfler syslog(LOG_INFO, "DNS: %s\n", 636293ed4feSAxel Dörfler _ToString(&data[i * 4]).String()); 63715ab0bcfSAxel Dörfler if (file != NULL) { 63815ab0bcfSAxel Dörfler fprintf(file, "nameserver %s\n", 63915ab0bcfSAxel Dörfler _ToString(&data[i * 4]).String()); 64015ab0bcfSAxel Dörfler } 6410ce7725eSAxel Dörfler } 642a552ec13SAxel Dörfler fclose(file); 6430ce7725eSAxel Dörfler break; 644a552ec13SAxel Dörfler } 6450ce7725eSAxel Dörfler case OPTION_SERVER_ADDRESS: 6460ce7725eSAxel Dörfler fServer.sin_addr.s_addr = *(in_addr_t*)data; 6470ce7725eSAxel Dörfler break; 64846ff5400SAxel Dörfler 6490ce7725eSAxel Dörfler case OPTION_ADDRESS_LEASE_TIME: 650293ed4feSAxel Dörfler syslog(LOG_INFO, "lease time of %lu seconds\n", 651293ed4feSAxel Dörfler htonl(*(uint32*)data)); 6526cc7630fSAxel Dörfler fLeaseTime = htonl(*(uint32*)data) * 1000000LL; 6530ce7725eSAxel Dörfler break; 6541a4e8e7bSAxel Dörfler case OPTION_RENEWAL_TIME: 655293ed4feSAxel Dörfler syslog(LOG_INFO, "renewal time of %lu seconds\n", 65646ff5400SAxel Dörfler htonl(*(uint32*)data)); 65746ff5400SAxel Dörfler fRenewalTime = htonl(*(uint32*)data) * 1000000LL; 65846ff5400SAxel Dörfler break; 6591a4e8e7bSAxel Dörfler case OPTION_REBINDING_TIME: 660293ed4feSAxel Dörfler syslog(LOG_INFO, "rebinding time of %lu seconds\n", 66146ff5400SAxel Dörfler htonl(*(uint32*)data)); 66246ff5400SAxel Dörfler fRebindingTime = htonl(*(uint32*)data) * 1000000LL; 6631a4e8e7bSAxel Dörfler break; 6641a4e8e7bSAxel Dörfler 6650ce7725eSAxel Dörfler case OPTION_HOST_NAME: 6665782c5a3SAxel Dörfler { 6670ce7725eSAxel Dörfler char name[256]; 6680ce7725eSAxel Dörfler memcpy(name, data, size); 6690ce7725eSAxel Dörfler name[size] = '\0'; 670293ed4feSAxel Dörfler syslog(LOG_INFO, "DHCP host name: \"%s\"\n", name); 6710ce7725eSAxel Dörfler break; 6725782c5a3SAxel Dörfler } 6735782c5a3SAxel Dörfler 6745782c5a3SAxel Dörfler case OPTION_DOMAIN_NAME: 6755782c5a3SAxel Dörfler { 6765782c5a3SAxel Dörfler char name[256]; 6775782c5a3SAxel Dörfler memcpy(name, data, size); 6785782c5a3SAxel Dörfler name[size] = '\0'; 679293ed4feSAxel Dörfler syslog(LOG_INFO, "DHCP domain name: \"%s\"\n", name); 6805782c5a3SAxel Dörfler break; 6815782c5a3SAxel Dörfler } 6820ce7725eSAxel Dörfler 6830ce7725eSAxel Dörfler case OPTION_MESSAGE_TYPE: 6840ce7725eSAxel Dörfler break; 6850ce7725eSAxel Dörfler 6860ce7725eSAxel Dörfler default: 687293ed4feSAxel Dörfler syslog(LOG_INFO, "unknown option %lu\n", (uint32)option); 6880ce7725eSAxel Dörfler break; 6890ce7725eSAxel Dörfler } 6900ce7725eSAxel Dörfler } 6910ce7725eSAxel Dörfler } 6920ce7725eSAxel Dörfler 6930ce7725eSAxel Dörfler 6940ce7725eSAxel Dörfler void 69546ff5400SAxel Dörfler DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state) 6960ce7725eSAxel Dörfler { 6970ce7725eSAxel Dörfler message.opcode = BOOT_REQUEST; 6980ce7725eSAxel Dörfler message.hardware_type = ARP_HARDWARE_TYPE_ETHER; 6990ce7725eSAxel Dörfler message.hardware_address_length = 6; 7000ce7725eSAxel Dörfler message.transaction_id = htonl(fTransactionID); 701bcc8dadaSAxel Dörfler message.seconds_since_start = htons(min_c((system_time() - fStartTime) 70215ab0bcfSAxel Dörfler / 1000000LL, 65535)); 7030ce7725eSAxel Dörfler memcpy(message.mac_address, fMAC, 6); 7040ce7725eSAxel Dörfler 70546ff5400SAxel Dörfler message_type type = message.Type(); 70646ff5400SAxel Dörfler 70746ff5400SAxel Dörfler switch (type) { 7080ce7725eSAxel Dörfler case DHCP_REQUEST: 7090ce7725eSAxel Dörfler case DHCP_RELEASE: 7100ce7725eSAxel Dörfler { 7110ce7725eSAxel Dörfler // add server identifier option 712a073ba1aSHugo Santos uint8* next = message.PrepareMessage(type); 7130ce7725eSAxel Dörfler next = message.PutOption(next, OPTION_SERVER_ADDRESS, 7140ce7725eSAxel Dörfler (uint32)fServer.sin_addr.s_addr); 71546ff5400SAxel Dörfler 71646ff5400SAxel Dörfler // In RENEWAL or REBINDING state, we must set the client_address field, and not 71746ff5400SAxel Dörfler // use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages 7185d4d5313SHugo Santos if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING)) { 71915ab0bcfSAxel Dörfler next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, 72015ab0bcfSAxel Dörfler (uint32)fAssignedAddress); 7215d4d5313SHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 7225d4d5313SHugo Santos kRequiredParameters, sizeof(kRequiredParameters)); 7235d4d5313SHugo Santos } else 72446ff5400SAxel Dörfler message.client_address = fAssignedAddress; 72546ff5400SAxel Dörfler 726a073ba1aSHugo Santos message.FinishOptions(next); 727a073ba1aSHugo Santos break; 728a073ba1aSHugo Santos } 729a073ba1aSHugo Santos 730a073ba1aSHugo Santos case DHCP_DISCOVER: 731a073ba1aSHugo Santos { 732a073ba1aSHugo Santos uint8 *next = message.PrepareMessage(type); 733a073ba1aSHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 734a073ba1aSHugo Santos kRequiredParameters, sizeof(kRequiredParameters)); 735a073ba1aSHugo Santos message.FinishOptions(next); 7360ce7725eSAxel Dörfler break; 7370ce7725eSAxel Dörfler } 7380ce7725eSAxel Dörfler 7390ce7725eSAxel Dörfler default: 7400ce7725eSAxel Dörfler // the default options are fine 7410ce7725eSAxel Dörfler break; 7420ce7725eSAxel Dörfler } 7430ce7725eSAxel Dörfler } 7440ce7725eSAxel Dörfler 7450ce7725eSAxel Dörfler 7460ce7725eSAxel Dörfler void 7476cc7630fSAxel Dörfler DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries) 748f9af6566SAxel Dörfler { 7496cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 7506cc7630fSAxel Dörfler tries = 0; 751f9af6566SAxel Dörfler 752f9af6566SAxel Dörfler struct timeval value; 7536cc7630fSAxel Dörfler value.tv_sec = timeout; 754f9af6566SAxel Dörfler value.tv_usec = 0; 755f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 756f9af6566SAxel Dörfler } 757f9af6566SAxel Dörfler 758f9af6566SAxel Dörfler 759f9af6566SAxel Dörfler bool 7606cc7630fSAxel Dörfler DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries) 761f9af6566SAxel Dörfler { 7626cc7630fSAxel Dörfler timeout += timeout; 7636cc7630fSAxel Dörfler if (timeout > MAX_TIMEOUT) { 7646cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 765f9af6566SAxel Dörfler 7666cc7630fSAxel Dörfler if (++tries > 2) 767f9af6566SAxel Dörfler return false; 768f9af6566SAxel Dörfler } 769293ed4feSAxel Dörfler syslog(LOG_DEBUG, "DHCP timeout shift: %lu secs (try %lu)\n", timeout, 770293ed4feSAxel Dörfler tries); 771f9af6566SAxel Dörfler 772f9af6566SAxel Dörfler struct timeval value; 7736cc7630fSAxel Dörfler value.tv_sec = timeout; 774f9af6566SAxel Dörfler value.tv_usec = 0; 775f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 776f9af6566SAxel Dörfler 777f9af6566SAxel Dörfler return true; 778f9af6566SAxel Dörfler } 779f9af6566SAxel Dörfler 780f9af6566SAxel Dörfler 781f9af6566SAxel Dörfler BString 782f9af6566SAxel Dörfler DHCPClient::_ToString(const uint8* data) const 783f9af6566SAxel Dörfler { 784f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)data); 785f9af6566SAxel Dörfler return target; 786f9af6566SAxel Dörfler } 787f9af6566SAxel Dörfler 788f9af6566SAxel Dörfler 789f9af6566SAxel Dörfler BString 790f9af6566SAxel Dörfler DHCPClient::_ToString(in_addr_t address) const 791f9af6566SAxel Dörfler { 792f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)&address); 793f9af6566SAxel Dörfler return target; 794f9af6566SAxel Dörfler } 795f9af6566SAxel Dörfler 796f9af6566SAxel Dörfler 797f9af6566SAxel Dörfler status_t 7981a905a76SAxel Dörfler DHCPClient::_SendMessage(int socket, dhcp_message& message, 7991a905a76SAxel Dörfler sockaddr_in& address) const 800f9af6566SAxel Dörfler { 801f9af6566SAxel Dörfler ssize_t bytesSent = sendto(socket, &message, message.Size(), 802f9af6566SAxel Dörfler address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0, 803f9af6566SAxel Dörfler (struct sockaddr*)&address, sizeof(sockaddr_in)); 804f9af6566SAxel Dörfler if (bytesSent < 0) 805f9af6566SAxel Dörfler return errno; 806f9af6566SAxel Dörfler 807f9af6566SAxel Dörfler return B_OK; 808fb81684fSAxel Dörfler } 809fb81684fSAxel Dörfler 810fb81684fSAxel Dörfler 81146ff5400SAxel Dörfler dhcp_state 81246ff5400SAxel Dörfler DHCPClient::_CurrentState() const 81346ff5400SAxel Dörfler { 81446ff5400SAxel Dörfler bigtime_t now = system_time(); 81546ff5400SAxel Dörfler 81646ff5400SAxel Dörfler if (now > fLeaseTime || fStatus < B_OK) 81746ff5400SAxel Dörfler return INIT; 81846ff5400SAxel Dörfler if (now >= fRebindingTime) 81946ff5400SAxel Dörfler return REBINDING; 82046ff5400SAxel Dörfler if (now >= fRenewalTime) 82146ff5400SAxel Dörfler return RENEWAL; 82246ff5400SAxel Dörfler 82346ff5400SAxel Dörfler return BOUND; 82446ff5400SAxel Dörfler } 82546ff5400SAxel Dörfler 82646ff5400SAxel Dörfler 827fb81684fSAxel Dörfler void 828fb81684fSAxel Dörfler DHCPClient::MessageReceived(BMessage* message) 829fb81684fSAxel Dörfler { 8306cc7630fSAxel Dörfler switch (message->what) { 8316cc7630fSAxel Dörfler case kMsgLeaseTime: 83246ff5400SAxel Dörfler { 83346ff5400SAxel Dörfler dhcp_state state = _CurrentState(); 83446ff5400SAxel Dörfler 83546ff5400SAxel Dörfler bigtime_t next; 83646ff5400SAxel Dörfler if (_Negotiate(state) == B_OK) { 83746ff5400SAxel Dörfler switch (state) { 83846ff5400SAxel Dörfler case RENEWAL: 83946ff5400SAxel Dörfler next = fRebindingTime; 8406cc7630fSAxel Dörfler break; 84146ff5400SAxel Dörfler case REBINDING: 84246ff5400SAxel Dörfler default: 84346ff5400SAxel Dörfler next = fRenewalTime; 84446ff5400SAxel Dörfler break; 84546ff5400SAxel Dörfler } 84646ff5400SAxel Dörfler } else { 84746ff5400SAxel Dörfler switch (state) { 84846ff5400SAxel Dörfler case RENEWAL: 84946ff5400SAxel Dörfler next = (fLeaseTime - fRebindingTime) / 4 + system_time(); 85046ff5400SAxel Dörfler break; 85146ff5400SAxel Dörfler case REBINDING: 85246ff5400SAxel Dörfler default: 85346ff5400SAxel Dörfler next = (fLeaseTime - fRenewalTime) / 4 + system_time(); 85446ff5400SAxel Dörfler break; 85546ff5400SAxel Dörfler } 85646ff5400SAxel Dörfler } 85746ff5400SAxel Dörfler 85846ff5400SAxel Dörfler _RestartLease(next - system_time()); 85946ff5400SAxel Dörfler break; 86046ff5400SAxel Dörfler } 8616cc7630fSAxel Dörfler 8626cc7630fSAxel Dörfler default: 863fb81684fSAxel Dörfler BHandler::MessageReceived(message); 8646cc7630fSAxel Dörfler break; 8656cc7630fSAxel Dörfler } 866fb81684fSAxel Dörfler } 867