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 13f9af6566SAxel Dörfler #include <Message.h> 146cc7630fSAxel Dörfler #include <MessageRunner.h> 15af074561SAxel Dörfler #include <NetworkDevice.h> 16af074561SAxel Dörfler #include <NetworkInterface.h> 17f9af6566SAxel Dörfler 18f9af6566SAxel Dörfler #include <arpa/inet.h> 19fb81684fSAxel Dörfler #include <errno.h> 20fb81684fSAxel Dörfler #include <stdio.h> 21fb81684fSAxel Dörfler #include <string.h> 22293ed4feSAxel Dörfler #include <syslog.h> 2336bde12dSAxel Dörfler #include <sys/sockio.h> 24f9af6566SAxel Dörfler #include <sys/time.h> 25fb81684fSAxel Dörfler 264ac66051SAxel Dörfler #include <Debug.h> 274ac66051SAxel Dörfler #include <Message.h> 284ac66051SAxel Dörfler #include <MessageRunner.h> 294ac66051SAxel Dörfler 304ac66051SAxel Dörfler #include "NetServer.h" 314ac66051SAxel Dörfler 32fb81684fSAxel Dörfler 33fb81684fSAxel Dörfler // See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options 34fb81684fSAxel Dörfler 35fb81684fSAxel Dörfler #define DHCP_CLIENT_PORT 68 36fb81684fSAxel Dörfler #define DHCP_SERVER_PORT 67 37fb81684fSAxel Dörfler 38f9af6566SAxel Dörfler #define DEFAULT_TIMEOUT 2 // secs 39f9af6566SAxel Dörfler #define MAX_TIMEOUT 15 // secs 40f9af6566SAxel Dörfler 41fb81684fSAxel Dörfler enum message_opcode { 42fb81684fSAxel Dörfler BOOT_REQUEST = 1, 43fb81684fSAxel Dörfler BOOT_REPLY 44fb81684fSAxel Dörfler }; 45fb81684fSAxel Dörfler 46fb81684fSAxel Dörfler enum message_option { 47fb81684fSAxel Dörfler OPTION_MAGIC = 0x63825363, 48fb81684fSAxel Dörfler 49fb81684fSAxel Dörfler // generic options 50fb81684fSAxel Dörfler OPTION_PAD = 0, 51f9af6566SAxel Dörfler OPTION_END = 255, 52f9af6566SAxel Dörfler OPTION_SUBNET_MASK = 1, 5365186fecSAxel Dörfler OPTION_TIME_OFFSET = 2, 54f9af6566SAxel Dörfler OPTION_ROUTER_ADDRESS = 3, 55f9af6566SAxel Dörfler OPTION_DOMAIN_NAME_SERVER = 6, 56f9af6566SAxel Dörfler OPTION_HOST_NAME = 12, 575782c5a3SAxel Dörfler OPTION_DOMAIN_NAME = 15, 58fb81684fSAxel Dörfler OPTION_DATAGRAM_SIZE = 22, 59fb81684fSAxel Dörfler OPTION_MTU = 26, 60fb81684fSAxel Dörfler OPTION_BROADCAST_ADDRESS = 28, 61fb81684fSAxel Dörfler OPTION_NETWORK_TIME_SERVERS = 42, 6265186fecSAxel Dörfler OPTION_NETBIOS_NAME_SERVER = 44, 6365186fecSAxel Dörfler OPTION_NETBIOS_SCOPE = 47, 64fb81684fSAxel Dörfler 65fb81684fSAxel Dörfler // DHCP specific options 66fb81684fSAxel Dörfler OPTION_REQUEST_IP_ADDRESS = 50, 67fb81684fSAxel Dörfler OPTION_ADDRESS_LEASE_TIME = 51, 68fb81684fSAxel Dörfler OPTION_OVERLOAD = 52, 69fb81684fSAxel Dörfler OPTION_MESSAGE_TYPE = 53, 70fb81684fSAxel Dörfler OPTION_SERVER_ADDRESS = 54, 71fb81684fSAxel Dörfler OPTION_REQUEST_PARAMETERS = 55, 72fb81684fSAxel Dörfler OPTION_ERROR_MESSAGE = 56, 73fb81684fSAxel Dörfler OPTION_MESSAGE_SIZE = 57, 74fb81684fSAxel Dörfler OPTION_RENEWAL_TIME = 58, 75fb81684fSAxel Dörfler OPTION_REBINDING_TIME = 59, 76fb81684fSAxel Dörfler OPTION_CLASS_IDENTIFIER = 60, 77fb81684fSAxel Dörfler OPTION_CLIENT_IDENTIFIER = 61, 78fb81684fSAxel Dörfler }; 79fb81684fSAxel Dörfler 80fb81684fSAxel Dörfler enum message_type { 81f9af6566SAxel Dörfler DHCP_NONE = 0, 82f9af6566SAxel Dörfler DHCP_DISCOVER, 83fb81684fSAxel Dörfler DHCP_OFFER, 84fb81684fSAxel Dörfler DHCP_REQUEST, 85fb81684fSAxel Dörfler DHCP_DECLINE, 86fb81684fSAxel Dörfler DHCP_ACK, 87f9af6566SAxel Dörfler DHCP_NACK, 88fb81684fSAxel Dörfler DHCP_RELEASE, 89fb81684fSAxel Dörfler DHCP_INFORM 90fb81684fSAxel Dörfler }; 91fb81684fSAxel Dörfler 92fb81684fSAxel Dörfler struct dhcp_option_cookie { 9315ab0bcfSAxel Dörfler dhcp_option_cookie() 9415ab0bcfSAxel Dörfler : 9515ab0bcfSAxel Dörfler state(0), 9615ab0bcfSAxel Dörfler file_has_options(false), 9715ab0bcfSAxel Dörfler server_name_has_options(false) 9815ab0bcfSAxel Dörfler { 9915ab0bcfSAxel Dörfler } 100fb81684fSAxel Dörfler 101fb81684fSAxel Dörfler const uint8* next; 102fb81684fSAxel Dörfler uint8 state; 103fb81684fSAxel Dörfler bool file_has_options; 104fb81684fSAxel Dörfler bool server_name_has_options; 105fb81684fSAxel Dörfler }; 106fb81684fSAxel Dörfler 107fb81684fSAxel Dörfler struct dhcp_message { 108fb81684fSAxel Dörfler dhcp_message(message_type type); 109fb81684fSAxel Dörfler 110fb81684fSAxel Dörfler uint8 opcode; 111fb81684fSAxel Dörfler uint8 hardware_type; 112fb81684fSAxel Dörfler uint8 hardware_address_length; 113fb81684fSAxel Dörfler uint8 hop_count; 114fb81684fSAxel Dörfler uint32 transaction_id; 11546ff5400SAxel Dörfler uint16 seconds_since_start; 116fb81684fSAxel Dörfler uint16 flags; 117fb81684fSAxel Dörfler in_addr_t client_address; 118fb81684fSAxel Dörfler in_addr_t your_address; 119fb81684fSAxel Dörfler in_addr_t server_address; 120fb81684fSAxel Dörfler in_addr_t gateway_address; 121fb81684fSAxel Dörfler uint8 mac_address[16]; 122fb81684fSAxel Dörfler uint8 server_name[64]; 123fb81684fSAxel Dörfler uint8 file[128]; 124fb81684fSAxel Dörfler uint32 options_magic; 125fb81684fSAxel Dörfler uint8 options[1260]; 126fb81684fSAxel Dörfler 127fb81684fSAxel Dörfler size_t MinSize() const { return 576; } 128fb81684fSAxel Dörfler size_t Size() const; 129fb81684fSAxel Dörfler 130fb81684fSAxel Dörfler bool HasOptions() const; 131fb81684fSAxel Dörfler bool NextOption(dhcp_option_cookie& cookie, message_option& option, 132fb81684fSAxel Dörfler const uint8*& data, size_t& size) const; 133f9af6566SAxel Dörfler message_type Type() const; 134fb81684fSAxel Dörfler const uint8* LastOption() const; 135fb81684fSAxel Dörfler 136a073ba1aSHugo Santos uint8* PrepareMessage(uint8 type); 137fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option); 138fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint8 data); 139fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint16 data); 140fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint32 data); 14115ab0bcfSAxel Dörfler uint8* PutOption(uint8* options, message_option option, const uint8* data, 14215ab0bcfSAxel Dörfler uint32 size); 14337a68cb1SAxel Dörfler uint8* FinishOptions(uint8* options); 1444ac66051SAxel Dörfler 1454ac66051SAxel Dörfler static const char* TypeToString(message_type type); 146fb81684fSAxel Dörfler } _PACKED; 147fb81684fSAxel Dörfler 1480cf5e6acSAxel Dörfler #define DHCP_FLAG_BROADCAST 0x8000 149fb81684fSAxel Dörfler 150fb81684fSAxel Dörfler #define ARP_HARDWARE_TYPE_ETHER 1 151fb81684fSAxel Dörfler 1526cc7630fSAxel Dörfler const uint32 kMsgLeaseTime = 'lstm'; 1536cc7630fSAxel Dörfler 15437a68cb1SAxel Dörfler static const uint8 kRequestParameters[] = { 15565186fecSAxel Dörfler OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS, 156bfd479b3SAxel Dörfler OPTION_DOMAIN_NAME_SERVER, OPTION_BROADCAST_ADDRESS, 157bfd479b3SAxel Dörfler OPTION_DOMAIN_NAME 1585d4d5313SHugo Santos }; 1595d4d5313SHugo Santos 160fb81684fSAxel Dörfler 161fb81684fSAxel Dörfler dhcp_message::dhcp_message(message_type type) 162fb81684fSAxel Dörfler { 163fb4527d2SPhilippe Houdoin // ASSERT(this == offsetof(this, opcode)); 164fb81684fSAxel Dörfler memset(this, 0, sizeof(*this)); 165fb81684fSAxel Dörfler options_magic = htonl(OPTION_MAGIC); 166fb81684fSAxel Dörfler 167a073ba1aSHugo Santos uint8* next = PrepareMessage(type); 168a073ba1aSHugo Santos FinishOptions(next); 169fb81684fSAxel Dörfler } 170fb81684fSAxel Dörfler 171fb81684fSAxel Dörfler 172fb81684fSAxel Dörfler bool 173fb81684fSAxel Dörfler dhcp_message::HasOptions() const 174fb81684fSAxel Dörfler { 175fb81684fSAxel Dörfler return options_magic == htonl(OPTION_MAGIC); 176fb81684fSAxel Dörfler } 177fb81684fSAxel Dörfler 178fb81684fSAxel Dörfler 179fb81684fSAxel Dörfler bool 180fb81684fSAxel Dörfler dhcp_message::NextOption(dhcp_option_cookie& cookie, 181fb81684fSAxel Dörfler message_option& option, const uint8*& data, size_t& size) const 182fb81684fSAxel Dörfler { 183fb81684fSAxel Dörfler if (!HasOptions()) 184fb81684fSAxel Dörfler return false; 185fb81684fSAxel Dörfler 186fb4527d2SPhilippe Houdoin if (cookie.state == 0) { 187fb81684fSAxel Dörfler cookie.state++; 188fb81684fSAxel Dörfler cookie.next = options; 189fb81684fSAxel Dörfler } 190fb81684fSAxel Dörfler 191fb81684fSAxel Dörfler uint32 bytesLeft = 0; 192fb81684fSAxel Dörfler 193fb81684fSAxel Dörfler switch (cookie.state) { 194fb81684fSAxel Dörfler case 1: 195*ce36f054SPhilippe Houdoin // options from "options" 196fb4527d2SPhilippe Houdoin bytesLeft = sizeof(options) - (cookie.next - options); 197fb81684fSAxel Dörfler break; 198fb81684fSAxel Dörfler 199fb81684fSAxel Dörfler case 2: 200fb81684fSAxel Dörfler // options from "file" 201fb4527d2SPhilippe Houdoin bytesLeft = sizeof(file) - (cookie.next - file); 202fb81684fSAxel Dörfler break; 203fb81684fSAxel Dörfler 204fb81684fSAxel Dörfler case 3: 205fb81684fSAxel Dörfler // options from "server_name" 206fb4527d2SPhilippe Houdoin bytesLeft = sizeof(server_name) - (cookie.next - server_name); 207fb81684fSAxel Dörfler break; 208fb81684fSAxel Dörfler } 209fb81684fSAxel Dörfler 210fb81684fSAxel Dörfler while (true) { 211fb81684fSAxel Dörfler if (bytesLeft == 0) { 212fb4527d2SPhilippe Houdoin cookie.state++; 213fb4527d2SPhilippe Houdoin 214*ce36f054SPhilippe Houdoin // handle option overload in file and/or server_name fields. 215fb4527d2SPhilippe Houdoin switch (cookie.state) { 216fb4527d2SPhilippe Houdoin case 2: 217fb4527d2SPhilippe Houdoin // options from "file" 218fb4527d2SPhilippe Houdoin if (cookie.file_has_options) { 219fb4527d2SPhilippe Houdoin bytesLeft = sizeof(file); 220fb4527d2SPhilippe Houdoin cookie.next = file; 221fb4527d2SPhilippe Houdoin } 222fb4527d2SPhilippe Houdoin break; 223fb4527d2SPhilippe Houdoin 224fb4527d2SPhilippe Houdoin case 3: 225fb4527d2SPhilippe Houdoin // options from "server_name" 226fb4527d2SPhilippe Houdoin if (cookie.server_name_has_options) { 227fb4527d2SPhilippe Houdoin bytesLeft = sizeof(server_name); 228fb4527d2SPhilippe Houdoin cookie.next = server_name; 229fb4527d2SPhilippe Houdoin } 230fb4527d2SPhilippe Houdoin break; 231fb4527d2SPhilippe Houdoin 232fb4527d2SPhilippe Houdoin case 4: 233*ce36f054SPhilippe Houdoin // no more place to look for options 234fb81684fSAxel Dörfler return false; 235fb81684fSAxel Dörfler } 236fb81684fSAxel Dörfler 237fb4527d2SPhilippe Houdoin if (bytesLeft == 0) { 238fb4527d2SPhilippe Houdoin // no options for this state, try next one 239fb4527d2SPhilippe Houdoin continue; 240fb4527d2SPhilippe Houdoin } 241fb4527d2SPhilippe Houdoin } 242fb4527d2SPhilippe Houdoin 243fb81684fSAxel Dörfler option = (message_option)cookie.next[0]; 244fb81684fSAxel Dörfler if (option == OPTION_END) { 245fb4527d2SPhilippe Houdoin bytesLeft = 0; 246fb4527d2SPhilippe Houdoin continue; 247fb81684fSAxel Dörfler } else if (option == OPTION_PAD) { 248fb81684fSAxel Dörfler bytesLeft--; 249fb81684fSAxel Dörfler cookie.next++; 250fb81684fSAxel Dörfler continue; 251fb81684fSAxel Dörfler } 252fb81684fSAxel Dörfler 253fb81684fSAxel Dörfler size = cookie.next[1]; 254fb81684fSAxel Dörfler data = &cookie.next[2]; 255fb81684fSAxel Dörfler cookie.next += 2 + size; 256fb4527d2SPhilippe Houdoin bytesLeft -= 2 + size; 257fb81684fSAxel Dörfler 258fb81684fSAxel Dörfler if (option == OPTION_OVERLOAD) { 259fb81684fSAxel Dörfler cookie.file_has_options = data[0] & 1; 260fb81684fSAxel Dörfler cookie.server_name_has_options = data[0] & 2; 261fb81684fSAxel Dörfler continue; 262fb81684fSAxel Dörfler } 263fb81684fSAxel Dörfler 264fb81684fSAxel Dörfler return true; 265fb81684fSAxel Dörfler } 266fb81684fSAxel Dörfler } 267fb81684fSAxel Dörfler 268fb81684fSAxel Dörfler 269f9af6566SAxel Dörfler message_type 270f9af6566SAxel Dörfler dhcp_message::Type() const 271f9af6566SAxel Dörfler { 272f9af6566SAxel Dörfler dhcp_option_cookie cookie; 273f9af6566SAxel Dörfler message_option option; 274f9af6566SAxel Dörfler const uint8* data; 275f9af6566SAxel Dörfler size_t size; 276f9af6566SAxel Dörfler while (NextOption(cookie, option, data, size)) { 277f9af6566SAxel Dörfler // iterate through all options 278f9af6566SAxel Dörfler if (option == OPTION_MESSAGE_TYPE) 279f9af6566SAxel Dörfler return (message_type)data[0]; 280f9af6566SAxel Dörfler } 281f9af6566SAxel Dörfler 282f9af6566SAxel Dörfler return DHCP_NONE; 283f9af6566SAxel Dörfler } 284f9af6566SAxel Dörfler 285f9af6566SAxel Dörfler 286fb81684fSAxel Dörfler const uint8* 287fb81684fSAxel Dörfler dhcp_message::LastOption() const 288fb81684fSAxel Dörfler { 289fb81684fSAxel Dörfler dhcp_option_cookie cookie; 290fb81684fSAxel Dörfler message_option option; 291fb81684fSAxel Dörfler const uint8* data; 292fb81684fSAxel Dörfler size_t size; 293fb81684fSAxel Dörfler while (NextOption(cookie, option, data, size)) { 294fb81684fSAxel Dörfler // iterate through all options 295fb81684fSAxel Dörfler } 296fb81684fSAxel Dörfler 297fb81684fSAxel Dörfler return cookie.next; 298fb81684fSAxel Dörfler } 299fb81684fSAxel Dörfler 300fb81684fSAxel Dörfler 301fb81684fSAxel Dörfler size_t 302fb81684fSAxel Dörfler dhcp_message::Size() const 303fb81684fSAxel Dörfler { 304fb81684fSAxel Dörfler const uint8* last = LastOption(); 305fb81684fSAxel Dörfler return sizeof(dhcp_message) - sizeof(options) + last + 1 - options; 306fb81684fSAxel Dörfler } 307fb81684fSAxel Dörfler 308fb81684fSAxel Dörfler 309fb81684fSAxel Dörfler uint8* 310a073ba1aSHugo Santos dhcp_message::PrepareMessage(uint8 type) 311a073ba1aSHugo Santos { 312a073ba1aSHugo Santos uint8* next = options; 313a073ba1aSHugo Santos next = PutOption(next, OPTION_MESSAGE_TYPE, type); 31415ab0bcfSAxel Dörfler next = PutOption(next, OPTION_MESSAGE_SIZE, 31515ab0bcfSAxel Dörfler (uint16)htons(sizeof(dhcp_message))); 316a073ba1aSHugo Santos return next; 317a073ba1aSHugo Santos } 318a073ba1aSHugo Santos 31965186fecSAxel Dörfler 320a073ba1aSHugo Santos uint8* 321fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option) 322fb81684fSAxel Dörfler { 323fb81684fSAxel Dörfler options[0] = option; 324fb81684fSAxel Dörfler return options + 1; 325fb81684fSAxel Dörfler } 326fb81684fSAxel Dörfler 327fb81684fSAxel Dörfler 328fb81684fSAxel Dörfler uint8* 329fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8 data) 330fb81684fSAxel Dörfler { 331fb81684fSAxel Dörfler return PutOption(options, option, &data, 1); 332fb81684fSAxel Dörfler } 333fb81684fSAxel Dörfler 334fb81684fSAxel Dörfler 335fb81684fSAxel Dörfler uint8* 336fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint16 data) 337fb81684fSAxel Dörfler { 338fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 339fb81684fSAxel Dörfler } 340fb81684fSAxel Dörfler 341fb81684fSAxel Dörfler 342fb81684fSAxel Dörfler uint8* 343fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint32 data) 344fb81684fSAxel Dörfler { 345fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 346fb81684fSAxel Dörfler } 347fb81684fSAxel Dörfler 348fb81684fSAxel Dörfler 349fb81684fSAxel Dörfler uint8* 35015ab0bcfSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, 35115ab0bcfSAxel Dörfler const uint8* data, uint32 size) 352fb81684fSAxel Dörfler { 353fb81684fSAxel Dörfler options[0] = option; 354fb81684fSAxel Dörfler options[1] = size; 355fb81684fSAxel Dörfler memcpy(&options[2], data, size); 356fb81684fSAxel Dörfler 357fb81684fSAxel Dörfler return options + 2 + size; 358fb81684fSAxel Dörfler } 359fb81684fSAxel Dörfler 360fb81684fSAxel Dörfler 361a073ba1aSHugo Santos uint8* 36237a68cb1SAxel Dörfler dhcp_message::FinishOptions(uint8* options) 363a073ba1aSHugo Santos { 36437a68cb1SAxel Dörfler return PutOption(options, OPTION_END); 365a073ba1aSHugo Santos } 366a073ba1aSHugo Santos 367a073ba1aSHugo Santos 3684ac66051SAxel Dörfler /*static*/ const char* 3694ac66051SAxel Dörfler dhcp_message::TypeToString(message_type type) 3704ac66051SAxel Dörfler { 3714ac66051SAxel Dörfler switch (type) { 3724ac66051SAxel Dörfler #define CASE(x) case x: return #x; 3734ac66051SAxel Dörfler CASE(DHCP_NONE) 3744ac66051SAxel Dörfler CASE(DHCP_DISCOVER) 3754ac66051SAxel Dörfler CASE(DHCP_OFFER) 3764ac66051SAxel Dörfler CASE(DHCP_REQUEST) 3774ac66051SAxel Dörfler CASE(DHCP_DECLINE) 3784ac66051SAxel Dörfler CASE(DHCP_ACK) 3794ac66051SAxel Dörfler CASE(DHCP_NACK) 3804ac66051SAxel Dörfler CASE(DHCP_RELEASE) 3814ac66051SAxel Dörfler CASE(DHCP_INFORM) 3824ac66051SAxel Dörfler #undef CASE 3834ac66051SAxel Dörfler } 3844ac66051SAxel Dörfler 3854ac66051SAxel Dörfler return "<unknown>"; 3864ac66051SAxel Dörfler } 3874ac66051SAxel Dörfler 3884ac66051SAxel Dörfler 389fb81684fSAxel Dörfler // #pragma mark - 390fb81684fSAxel Dörfler 391fb81684fSAxel Dörfler 392f9af6566SAxel Dörfler DHCPClient::DHCPClient(BMessenger target, const char* device) 393af074561SAxel Dörfler : 394af074561SAxel Dörfler AutoconfigClient("dhcp", target, device), 3956cc7630fSAxel Dörfler fConfiguration(kMsgConfigureInterface), 39616e8f13aSAxel Dörfler fResolverConfiguration(kMsgConfigureResolver), 3976cc7630fSAxel Dörfler fRunner(NULL), 398af074561SAxel Dörfler fServer(AF_INET, NULL, DHCP_SERVER_PORT), 399c1264353SStephan Aßmus fLeaseTime(0) 400fb81684fSAxel Dörfler { 40146ff5400SAxel Dörfler fStartTime = system_time(); 40246ff5400SAxel Dörfler fTransactionID = (uint32)fStartTime; 403fb81684fSAxel Dörfler 404af074561SAxel Dörfler BNetworkAddress link; 405af074561SAxel Dörfler BNetworkInterface interface(device); 406af074561SAxel Dörfler fStatus = interface.GetHardwareAddress(link); 407af074561SAxel Dörfler if (fStatus != B_OK) 408fb81684fSAxel Dörfler return; 409fb81684fSAxel Dörfler 410af074561SAxel Dörfler memcpy(fMAC, link.LinkLevelAddress(), sizeof(fMAC)); 411293ed4feSAxel Dörfler 412293ed4feSAxel Dörfler openlog_thread("DHCP", 0, LOG_DAEMON); 4136cc7630fSAxel Dörfler } 4146cc7630fSAxel Dörfler 4156cc7630fSAxel Dörfler 4166cc7630fSAxel Dörfler DHCPClient::~DHCPClient() 4176cc7630fSAxel Dörfler { 4186cc7630fSAxel Dörfler if (fStatus != B_OK) 4196cc7630fSAxel Dörfler return; 4206cc7630fSAxel Dörfler 4216cc7630fSAxel Dörfler delete fRunner; 4220ce7725eSAxel Dörfler 423fb81684fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 4246cc7630fSAxel Dörfler if (socket < 0) 425fb81684fSAxel Dörfler return; 4266cc7630fSAxel Dörfler 4276cc7630fSAxel Dörfler // release lease 4286cc7630fSAxel Dörfler 4296cc7630fSAxel Dörfler dhcp_message release(DHCP_RELEASE); 43046ff5400SAxel Dörfler _PrepareMessage(release, BOUND); 4316cc7630fSAxel Dörfler 4326cc7630fSAxel Dörfler _SendMessage(socket, release, fServer); 4336cc7630fSAxel Dörfler close(socket); 434293ed4feSAxel Dörfler 435293ed4feSAxel Dörfler closelog_thread(); 436fb81684fSAxel Dörfler } 437fb81684fSAxel Dörfler 4386cc7630fSAxel Dörfler 4396cc7630fSAxel Dörfler status_t 4406cc7630fSAxel Dörfler DHCPClient::Initialize() 4416cc7630fSAxel Dörfler { 4426cc7630fSAxel Dörfler fStatus = _Negotiate(INIT); 443293ed4feSAxel Dörfler syslog(LOG_DEBUG, "DHCP for %s, status: %s\n", Device(), strerror(fStatus)); 4446cc7630fSAxel Dörfler return fStatus; 4456cc7630fSAxel Dörfler } 4466cc7630fSAxel Dörfler 4476cc7630fSAxel Dörfler 4486cc7630fSAxel Dörfler status_t 4496cc7630fSAxel Dörfler DHCPClient::_Negotiate(dhcp_state state) 4506cc7630fSAxel Dörfler { 4516cc7630fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 4526cc7630fSAxel Dörfler if (socket < 0) 4536cc7630fSAxel Dörfler return errno; 4546cc7630fSAxel Dörfler 455fb4527d2SPhilippe Houdoin BNetworkAddress local; 456fb4527d2SPhilippe Houdoin local.SetToWildcard(AF_INET, DHCP_CLIENT_PORT); 457fb81684fSAxel Dörfler 4582b829b04SBruno G. Albuquerque // Enable reusing the port . This is needed in case there is more 4592b829b04SBruno G. Albuquerque // than 1 interface that needs to be configured. Note that the only reason 4602b829b04SBruno G. Albuquerque // this works is because there is code below to bind to a specific 4612b829b04SBruno G. Albuquerque // interface. 4622b829b04SBruno G. Albuquerque int option = 1; 4632b829b04SBruno G. Albuquerque setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option)); 4642b829b04SBruno G. Albuquerque 465af074561SAxel Dörfler if (bind(socket, local, local.Length()) < 0) { 466fb81684fSAxel Dörfler close(socket); 4676cc7630fSAxel Dörfler return errno; 468fb81684fSAxel Dörfler } 469fb81684fSAxel Dörfler 470af074561SAxel Dörfler BNetworkAddress broadcast; 471af074561SAxel Dörfler broadcast.SetToBroadcast(AF_INET, DHCP_SERVER_PORT); 472fb81684fSAxel Dörfler 4732b829b04SBruno G. Albuquerque option = 1; 474fb81684fSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); 475fb81684fSAxel Dörfler 47636bde12dSAxel Dörfler if (state == INIT) { 47736bde12dSAxel Dörfler // The local interface does not have an address yet, bind the socket 47836bde12dSAxel Dörfler // to the device directly. 479af074561SAxel Dörfler BNetworkDevice device(Device()); 480af074561SAxel Dörfler int index = device.Index(); 48136bde12dSAxel Dörfler 482af074561SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, &index, sizeof(int)); 48336bde12dSAxel Dörfler } 48436bde12dSAxel Dörfler 4856cc7630fSAxel Dörfler bigtime_t previousLeaseTime = fLeaseTime; 4866cc7630fSAxel Dörfler fLeaseTime = 0; 48746ff5400SAxel Dörfler fRenewalTime = 0; 48846ff5400SAxel Dörfler fRebindingTime = 0; 489fb81684fSAxel Dörfler 4906cc7630fSAxel Dörfler status_t status = B_ERROR; 4916cc7630fSAxel Dörfler time_t timeout; 4926cc7630fSAxel Dörfler uint32 tries; 4936cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 4946cc7630fSAxel Dörfler 4956cc7630fSAxel Dörfler dhcp_message discover(DHCP_DISCOVER); 49646ff5400SAxel Dörfler _PrepareMessage(discover, state); 4976cc7630fSAxel Dörfler 4986cc7630fSAxel Dörfler dhcp_message request(DHCP_REQUEST); 49946ff5400SAxel Dörfler _PrepareMessage(request, state); 5006cc7630fSAxel Dörfler 50146ff5400SAxel Dörfler // send discover/request message 502593a0d2dSAxel Dörfler _SendMessage(socket, state == INIT ? discover : request, 50346ff5400SAxel Dörfler state != RENEWAL ? broadcast : fServer); 504593a0d2dSAxel Dörfler // no need to check the status; in case of an error we'll just send 505593a0d2dSAxel Dörfler // the message again 506fb81684fSAxel Dörfler 507f9af6566SAxel Dörfler // receive loop until we've got an offer and acknowledged it 508f9af6566SAxel Dörfler 509f9af6566SAxel Dörfler while (state != ACKNOWLEDGED) { 510f9af6566SAxel Dörfler char buffer[2048]; 511f9af6566SAxel Dörfler ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer), 512f9af6566SAxel Dörfler 0, NULL, NULL); 5134b661a95SAxel Dörfler if (bytesReceived < 0 && errno == B_TIMED_OUT) { 514f9af6566SAxel Dörfler // depending on the state, we'll just try again 5156cc7630fSAxel Dörfler if (!_TimeoutShift(socket, timeout, tries)) { 5166cc7630fSAxel Dörfler close(socket); 5176cc7630fSAxel Dörfler return B_TIMED_OUT; 518f9af6566SAxel Dörfler } 519f9af6566SAxel Dörfler 520f9af6566SAxel Dörfler if (state == INIT) 521593a0d2dSAxel Dörfler _SendMessage(socket, discover, broadcast); 52215ab0bcfSAxel Dörfler else { 523593a0d2dSAxel Dörfler _SendMessage(socket, request, 524593a0d2dSAxel Dörfler state != RENEWAL ? broadcast : fServer); 52515ab0bcfSAxel Dörfler } 526f9af6566SAxel Dörfler 527d77fe260SAxel Dörfler continue; 528593a0d2dSAxel Dörfler } else if (bytesReceived < 0) 529f9af6566SAxel Dörfler break; 530f9af6566SAxel Dörfler 531f9af6566SAxel Dörfler dhcp_message* message = (dhcp_message*)buffer; 532f9af6566SAxel Dörfler if (message->transaction_id != htonl(fTransactionID) 533f9af6566SAxel Dörfler || !message->HasOptions() 534f9af6566SAxel Dörfler || memcmp(message->mac_address, discover.mac_address, 535f9af6566SAxel Dörfler discover.hardware_address_length)) { 536f9af6566SAxel Dörfler // this message is not for us 537f9af6566SAxel Dörfler continue; 538f9af6566SAxel Dörfler } 539f9af6566SAxel Dörfler 5404ac66051SAxel Dörfler syslog(LOG_DEBUG, "DHCP received %s for %s\n", 5414ac66051SAxel Dörfler dhcp_message::TypeToString(message->Type()), Device()); 5424ac66051SAxel Dörfler 543f9af6566SAxel Dörfler switch (message->Type()) { 544f9af6566SAxel Dörfler case DHCP_NONE: 545f9af6566SAxel Dörfler default: 546f9af6566SAxel Dörfler // ignore this message 547f9af6566SAxel Dörfler break; 548f9af6566SAxel Dörfler 549f9af6566SAxel Dörfler case DHCP_OFFER: 550f9af6566SAxel Dörfler { 551f9af6566SAxel Dörfler // first offer wins 552f9af6566SAxel Dörfler if (state != INIT) 553f9af6566SAxel Dörfler break; 554f9af6566SAxel Dörfler 555f9af6566SAxel Dörfler // collect interface options 556f9af6566SAxel Dörfler 557f9af6566SAxel Dörfler fAssignedAddress = message->your_address; 558f9af6566SAxel Dörfler 55910cc12daSAxel Dörfler fConfiguration.MakeEmpty(); 560293ed4feSAxel Dörfler fConfiguration.AddString("device", Device()); 561f01106c3SAxel Dörfler fConfiguration.AddBool("auto", true); 562f9af6566SAxel Dörfler 563f9af6566SAxel Dörfler BMessage address; 564f9af6566SAxel Dörfler address.AddString("family", "inet"); 565f9af6566SAxel Dörfler address.AddString("address", _ToString(fAssignedAddress)); 56616e8f13aSAxel Dörfler fResolverConfiguration.MakeEmpty(); 56716e8f13aSAxel Dörfler _ParseOptions(*message, address, fResolverConfiguration); 568f9af6566SAxel Dörfler 56910cc12daSAxel Dörfler fConfiguration.AddMessage("address", &address); 570f9af6566SAxel Dörfler 57110cc12daSAxel Dörfler // request configuration from the server 572f9af6566SAxel Dörfler 5736cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 574f9af6566SAxel Dörfler state = REQUESTING; 57546ff5400SAxel Dörfler _PrepareMessage(request, state); 576f9af6566SAxel Dörfler 5776cc7630fSAxel Dörfler status = _SendMessage(socket, request, broadcast); 57815ab0bcfSAxel Dörfler // we're sending a broadcast so that all potential offers 57915ab0bcfSAxel Dörfler // get an answer 58010cc12daSAxel Dörfler break; 581f9af6566SAxel Dörfler } 582f9af6566SAxel Dörfler 583f9af6566SAxel Dörfler case DHCP_ACK: 58410cc12daSAxel Dörfler { 58515ab0bcfSAxel Dörfler if (state != REQUESTING && state != REBINDING 58615ab0bcfSAxel Dörfler && state != RENEWAL) 587f9af6566SAxel Dörfler continue; 588f9af6566SAxel Dörfler 5896cc7630fSAxel Dörfler // TODO: we might want to configure the stuff, don't we? 5906cc7630fSAxel Dörfler BMessage address; 59116e8f13aSAxel Dörfler fResolverConfiguration.MakeEmpty(); 59216e8f13aSAxel Dörfler _ParseOptions(*message, address, fResolverConfiguration); 5934ac66051SAxel Dörfler // TODO: currently, only lease time and DNS is updated this 5944ac66051SAxel Dörfler // way 5956cc7630fSAxel Dörfler 596f9af6566SAxel Dörfler // our address request has been acknowledged 597f9af6566SAxel Dörfler state = ACKNOWLEDGED; 59810cc12daSAxel Dörfler 59910cc12daSAxel Dörfler // configure interface 60010cc12daSAxel Dörfler BMessage reply; 601d23fdd96SOliver Tappe status = Target().SendMessage(&fConfiguration, &reply); 602d23fdd96SOliver Tappe if (status == B_OK) 603d23fdd96SOliver Tappe status = reply.FindInt32("status", &fStatus); 60416e8f13aSAxel Dörfler 60516e8f13aSAxel Dörfler // configure resolver 60616e8f13aSAxel Dörfler reply.MakeEmpty(); 60716e8f13aSAxel Dörfler status = Target().SendMessage(&fResolverConfiguration, &reply); 60816e8f13aSAxel Dörfler if (status == B_OK) 60916e8f13aSAxel Dörfler status = reply.FindInt32("status", &fStatus); 610f9af6566SAxel Dörfler break; 61110cc12daSAxel Dörfler } 612f9af6566SAxel Dörfler 613f9af6566SAxel Dörfler case DHCP_NACK: 614f9af6566SAxel Dörfler if (state != REQUESTING) 615f9af6566SAxel Dörfler continue; 616f9af6566SAxel Dörfler 61715ab0bcfSAxel Dörfler // try again (maybe we should prefer other servers if this 61815ab0bcfSAxel Dörfler // happens more than once) 6196cc7630fSAxel Dörfler status = _SendMessage(socket, discover, broadcast); 6206cc7630fSAxel Dörfler if (status == B_OK) 621f9af6566SAxel Dörfler state = INIT; 622f9af6566SAxel Dörfler break; 623f9af6566SAxel Dörfler } 624f9af6566SAxel Dörfler } 625f9af6566SAxel Dörfler 626fb81684fSAxel Dörfler close(socket); 6276cc7630fSAxel Dörfler 6286cc7630fSAxel Dörfler if (status == B_OK && fLeaseTime > 0) { 6296cc7630fSAxel Dörfler // notify early enough when the lease is 63046ff5400SAxel Dörfler if (fRenewalTime == 0) 63146ff5400SAxel Dörfler fRenewalTime = fLeaseTime * 2/3; 63246ff5400SAxel Dörfler if (fRebindingTime == 0) 63346ff5400SAxel Dörfler fRebindingTime = fLeaseTime * 5/6; 63446ff5400SAxel Dörfler 635168cc3dfSRene Gollent bigtime_t now = system_time(); 63646ff5400SAxel Dörfler _RestartLease(fRenewalTime); 63746ff5400SAxel Dörfler 63846ff5400SAxel Dörfler fLeaseTime += now; 63946ff5400SAxel Dörfler fRenewalTime += now; 64046ff5400SAxel Dörfler fRebindingTime += now; 64146ff5400SAxel Dörfler // make lease times absolute 64246ff5400SAxel Dörfler } else { 6436cc7630fSAxel Dörfler fLeaseTime = previousLeaseTime; 64446ff5400SAxel Dörfler bigtime_t now = system_time(); 64546ff5400SAxel Dörfler fRenewalTime = (fLeaseTime - now) * 2/3 + now; 64646ff5400SAxel Dörfler fRebindingTime = (fLeaseTime - now) * 5/6 + now; 64746ff5400SAxel Dörfler } 6486cc7630fSAxel Dörfler 6496cc7630fSAxel Dörfler return status; 650fb81684fSAxel Dörfler } 651fb81684fSAxel Dörfler 652fb81684fSAxel Dörfler 6536cc7630fSAxel Dörfler void 6546cc7630fSAxel Dörfler DHCPClient::_RestartLease(bigtime_t leaseTime) 655fb81684fSAxel Dörfler { 6566cc7630fSAxel Dörfler if (leaseTime == 0) 657f9af6566SAxel Dörfler return; 658f9af6566SAxel Dörfler 6596cc7630fSAxel Dörfler BMessage lease(kMsgLeaseTime); 66046ff5400SAxel Dörfler fRunner = new BMessageRunner(this, &lease, leaseTime, 1); 661f9af6566SAxel Dörfler } 662f9af6566SAxel Dörfler 663f9af6566SAxel Dörfler 664f9af6566SAxel Dörfler void 66516e8f13aSAxel Dörfler DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address, 66616e8f13aSAxel Dörfler BMessage& resolverConfiguration) 6670ce7725eSAxel Dörfler { 6680ce7725eSAxel Dörfler dhcp_option_cookie cookie; 6690ce7725eSAxel Dörfler message_option option; 6700ce7725eSAxel Dörfler const uint8* data; 6710ce7725eSAxel Dörfler size_t size; 6720ce7725eSAxel Dörfler while (message.NextOption(cookie, option, data, size)) { 6730ce7725eSAxel Dörfler // iterate through all options 6740ce7725eSAxel Dörfler switch (option) { 6750ce7725eSAxel Dörfler case OPTION_ROUTER_ADDRESS: 6760ce7725eSAxel Dörfler address.AddString("gateway", _ToString(data)); 6770ce7725eSAxel Dörfler break; 6780ce7725eSAxel Dörfler case OPTION_SUBNET_MASK: 6790ce7725eSAxel Dörfler address.AddString("mask", _ToString(data)); 6800ce7725eSAxel Dörfler break; 6815782c5a3SAxel Dörfler case OPTION_BROADCAST_ADDRESS: 6825782c5a3SAxel Dörfler address.AddString("broadcast", _ToString(data)); 6835782c5a3SAxel Dörfler break; 6840ce7725eSAxel Dörfler case OPTION_DOMAIN_NAME_SERVER: 685a552ec13SAxel Dörfler { 6860ce7725eSAxel Dörfler for (uint32 i = 0; i < size / 4; i++) { 68761729d93SAxel Dörfler syslog(LOG_INFO, "DHCP for %s got DNS: %s\n", Device(), 688293ed4feSAxel Dörfler _ToString(&data[i * 4]).String()); 68916e8f13aSAxel Dörfler resolverConfiguration.AddString("nameserver", 69015ab0bcfSAxel Dörfler _ToString(&data[i * 4]).String()); 69115ab0bcfSAxel Dörfler } 69216e8f13aSAxel Dörfler resolverConfiguration.AddInt32("nameserver_count", 69316e8f13aSAxel Dörfler size / 4); 6940ce7725eSAxel Dörfler break; 695a552ec13SAxel Dörfler } 6960ce7725eSAxel Dörfler case OPTION_SERVER_ADDRESS: 697af074561SAxel Dörfler fServer.SetAddress(*(in_addr_t*)data); 6980ce7725eSAxel Dörfler break; 69946ff5400SAxel Dörfler 7000ce7725eSAxel Dörfler case OPTION_ADDRESS_LEASE_TIME: 701293ed4feSAxel Dörfler syslog(LOG_INFO, "lease time of %lu seconds\n", 702293ed4feSAxel Dörfler htonl(*(uint32*)data)); 7036cc7630fSAxel Dörfler fLeaseTime = htonl(*(uint32*)data) * 1000000LL; 7040ce7725eSAxel Dörfler break; 7051a4e8e7bSAxel Dörfler case OPTION_RENEWAL_TIME: 706293ed4feSAxel Dörfler syslog(LOG_INFO, "renewal time of %lu seconds\n", 70746ff5400SAxel Dörfler htonl(*(uint32*)data)); 70846ff5400SAxel Dörfler fRenewalTime = htonl(*(uint32*)data) * 1000000LL; 70946ff5400SAxel Dörfler break; 7101a4e8e7bSAxel Dörfler case OPTION_REBINDING_TIME: 711293ed4feSAxel Dörfler syslog(LOG_INFO, "rebinding time of %lu seconds\n", 71246ff5400SAxel Dörfler htonl(*(uint32*)data)); 71346ff5400SAxel Dörfler fRebindingTime = htonl(*(uint32*)data) * 1000000LL; 7141a4e8e7bSAxel Dörfler break; 7151a4e8e7bSAxel Dörfler 7160ce7725eSAxel Dörfler case OPTION_HOST_NAME: 71716e8f13aSAxel Dörfler syslog(LOG_INFO, "DHCP host name: \"%.*s\"\n", (int)size, 71816e8f13aSAxel Dörfler (const char*)data); 7190ce7725eSAxel Dörfler break; 7205782c5a3SAxel Dörfler 7215782c5a3SAxel Dörfler case OPTION_DOMAIN_NAME: 7225782c5a3SAxel Dörfler { 72316e8f13aSAxel Dörfler char domain[256]; 72416e8f13aSAxel Dörfler strlcpy(domain, (const char*)data, 72516e8f13aSAxel Dörfler min_c(size + 1, sizeof(domain))); 7260f87f52fSStephan Aßmus 72716e8f13aSAxel Dörfler syslog(LOG_INFO, "DHCP domain name: \"%s\"\n", domain); 7280f87f52fSStephan Aßmus 72916e8f13aSAxel Dörfler resolverConfiguration.AddString("domain", domain); 7305782c5a3SAxel Dörfler break; 7315782c5a3SAxel Dörfler } 7320ce7725eSAxel Dörfler 7330ce7725eSAxel Dörfler case OPTION_MESSAGE_TYPE: 7340ce7725eSAxel Dörfler break; 7350ce7725eSAxel Dörfler 7360ce7725eSAxel Dörfler default: 737293ed4feSAxel Dörfler syslog(LOG_INFO, "unknown option %lu\n", (uint32)option); 7380ce7725eSAxel Dörfler break; 7390ce7725eSAxel Dörfler } 7400ce7725eSAxel Dörfler } 7410ce7725eSAxel Dörfler } 7420ce7725eSAxel Dörfler 7430ce7725eSAxel Dörfler 7440ce7725eSAxel Dörfler void 74546ff5400SAxel Dörfler DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state) 7460ce7725eSAxel Dörfler { 7470ce7725eSAxel Dörfler message.opcode = BOOT_REQUEST; 7480ce7725eSAxel Dörfler message.hardware_type = ARP_HARDWARE_TYPE_ETHER; 7490ce7725eSAxel Dörfler message.hardware_address_length = 6; 7500ce7725eSAxel Dörfler message.transaction_id = htonl(fTransactionID); 751bcc8dadaSAxel Dörfler message.seconds_since_start = htons(min_c((system_time() - fStartTime) 75215ab0bcfSAxel Dörfler / 1000000LL, 65535)); 7530ce7725eSAxel Dörfler memcpy(message.mac_address, fMAC, 6); 7540ce7725eSAxel Dörfler 75546ff5400SAxel Dörfler message_type type = message.Type(); 75646ff5400SAxel Dörfler 75746ff5400SAxel Dörfler switch (type) { 7580ce7725eSAxel Dörfler case DHCP_REQUEST: 7590ce7725eSAxel Dörfler case DHCP_RELEASE: 7600ce7725eSAxel Dörfler { 7610ce7725eSAxel Dörfler // add server identifier option 762af074561SAxel Dörfler const sockaddr_in& server = (sockaddr_in&)fServer.SockAddr(); 763a073ba1aSHugo Santos uint8* next = message.PrepareMessage(type); 7640ce7725eSAxel Dörfler next = message.PutOption(next, OPTION_SERVER_ADDRESS, 765af074561SAxel Dörfler (uint32)server.sin_addr.s_addr); 76646ff5400SAxel Dörfler 76746ff5400SAxel Dörfler // In RENEWAL or REBINDING state, we must set the client_address field, and not 76846ff5400SAxel Dörfler // use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages 7695d4d5313SHugo Santos if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING)) { 77015ab0bcfSAxel Dörfler next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, 77115ab0bcfSAxel Dörfler (uint32)fAssignedAddress); 7725d4d5313SHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 77337a68cb1SAxel Dörfler kRequestParameters, sizeof(kRequestParameters)); 7745d4d5313SHugo Santos } else 77546ff5400SAxel Dörfler message.client_address = fAssignedAddress; 77646ff5400SAxel Dörfler 777a073ba1aSHugo Santos message.FinishOptions(next); 778a073ba1aSHugo Santos break; 779a073ba1aSHugo Santos } 780a073ba1aSHugo Santos 781a073ba1aSHugo Santos case DHCP_DISCOVER: 782a073ba1aSHugo Santos { 783a073ba1aSHugo Santos uint8* next = message.PrepareMessage(type); 784a073ba1aSHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 78537a68cb1SAxel Dörfler kRequestParameters, sizeof(kRequestParameters)); 786a073ba1aSHugo Santos message.FinishOptions(next); 7870ce7725eSAxel Dörfler break; 7880ce7725eSAxel Dörfler } 7890ce7725eSAxel Dörfler 7900ce7725eSAxel Dörfler default: 7910ce7725eSAxel Dörfler // the default options are fine 7920ce7725eSAxel Dörfler break; 7930ce7725eSAxel Dörfler } 7940ce7725eSAxel Dörfler } 7950ce7725eSAxel Dörfler 7960ce7725eSAxel Dörfler 7970ce7725eSAxel Dörfler void 7986cc7630fSAxel Dörfler DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries) 799f9af6566SAxel Dörfler { 8006cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 8016cc7630fSAxel Dörfler tries = 0; 802f9af6566SAxel Dörfler 803f9af6566SAxel Dörfler struct timeval value; 8046cc7630fSAxel Dörfler value.tv_sec = timeout; 805f9af6566SAxel Dörfler value.tv_usec = 0; 806f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 807f9af6566SAxel Dörfler } 808f9af6566SAxel Dörfler 809f9af6566SAxel Dörfler 810f9af6566SAxel Dörfler bool 8116cc7630fSAxel Dörfler DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries) 812f9af6566SAxel Dörfler { 8136cc7630fSAxel Dörfler timeout += timeout; 8146cc7630fSAxel Dörfler if (timeout > MAX_TIMEOUT) { 8156cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 816f9af6566SAxel Dörfler 8176cc7630fSAxel Dörfler if (++tries > 2) 818f9af6566SAxel Dörfler return false; 819f9af6566SAxel Dörfler } 82061729d93SAxel Dörfler syslog(LOG_DEBUG, "DHCP timeout shift for %s: %lu secs (try %lu)\n", 82161729d93SAxel Dörfler Device(), timeout, tries); 822f9af6566SAxel Dörfler 823f9af6566SAxel Dörfler struct timeval value; 8246cc7630fSAxel Dörfler value.tv_sec = timeout; 825f9af6566SAxel Dörfler value.tv_usec = 0; 826f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 827f9af6566SAxel Dörfler 828f9af6566SAxel Dörfler return true; 829f9af6566SAxel Dörfler } 830f9af6566SAxel Dörfler 831f9af6566SAxel Dörfler 832f9af6566SAxel Dörfler BString 833f9af6566SAxel Dörfler DHCPClient::_ToString(const uint8* data) const 834f9af6566SAxel Dörfler { 835f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)data); 836f9af6566SAxel Dörfler return target; 837f9af6566SAxel Dörfler } 838f9af6566SAxel Dörfler 839f9af6566SAxel Dörfler 840f9af6566SAxel Dörfler BString 841f9af6566SAxel Dörfler DHCPClient::_ToString(in_addr_t address) const 842f9af6566SAxel Dörfler { 843f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)&address); 844f9af6566SAxel Dörfler return target; 845f9af6566SAxel Dörfler } 846f9af6566SAxel Dörfler 847f9af6566SAxel Dörfler 848f9af6566SAxel Dörfler status_t 8491a905a76SAxel Dörfler DHCPClient::_SendMessage(int socket, dhcp_message& message, 850af074561SAxel Dörfler const BNetworkAddress& address) const 851f9af6566SAxel Dörfler { 8524ac66051SAxel Dörfler syslog(LOG_DEBUG, "DHCP send message %s for %s\n", 8534ac66051SAxel Dörfler dhcp_message::TypeToString(message.Type()), Device()); 85461729d93SAxel Dörfler 855f9af6566SAxel Dörfler ssize_t bytesSent = sendto(socket, &message, message.Size(), 856af074561SAxel Dörfler address.IsBroadcast() ? MSG_BCAST : 0, address, address.Length()); 857f9af6566SAxel Dörfler if (bytesSent < 0) 858f9af6566SAxel Dörfler return errno; 859f9af6566SAxel Dörfler 860f9af6566SAxel Dörfler return B_OK; 861fb81684fSAxel Dörfler } 862fb81684fSAxel Dörfler 863fb81684fSAxel Dörfler 86446ff5400SAxel Dörfler dhcp_state 86546ff5400SAxel Dörfler DHCPClient::_CurrentState() const 86646ff5400SAxel Dörfler { 86746ff5400SAxel Dörfler bigtime_t now = system_time(); 86846ff5400SAxel Dörfler 86946ff5400SAxel Dörfler if (now > fLeaseTime || fStatus < B_OK) 87046ff5400SAxel Dörfler return INIT; 87146ff5400SAxel Dörfler if (now >= fRebindingTime) 87246ff5400SAxel Dörfler return REBINDING; 87346ff5400SAxel Dörfler if (now >= fRenewalTime) 87446ff5400SAxel Dörfler return RENEWAL; 87546ff5400SAxel Dörfler 87646ff5400SAxel Dörfler return BOUND; 87746ff5400SAxel Dörfler } 87846ff5400SAxel Dörfler 87946ff5400SAxel Dörfler 880fb81684fSAxel Dörfler void 881fb81684fSAxel Dörfler DHCPClient::MessageReceived(BMessage* message) 882fb81684fSAxel Dörfler { 8836cc7630fSAxel Dörfler switch (message->what) { 8846cc7630fSAxel Dörfler case kMsgLeaseTime: 88546ff5400SAxel Dörfler { 88646ff5400SAxel Dörfler dhcp_state state = _CurrentState(); 88746ff5400SAxel Dörfler 88846ff5400SAxel Dörfler bigtime_t next; 88946ff5400SAxel Dörfler if (_Negotiate(state) == B_OK) { 89046ff5400SAxel Dörfler switch (state) { 89146ff5400SAxel Dörfler case RENEWAL: 89246ff5400SAxel Dörfler next = fRebindingTime; 8936cc7630fSAxel Dörfler break; 89446ff5400SAxel Dörfler case REBINDING: 89546ff5400SAxel Dörfler default: 89646ff5400SAxel Dörfler next = fRenewalTime; 89746ff5400SAxel Dörfler break; 89846ff5400SAxel Dörfler } 89946ff5400SAxel Dörfler } else { 90046ff5400SAxel Dörfler switch (state) { 90146ff5400SAxel Dörfler case RENEWAL: 90246ff5400SAxel Dörfler next = (fLeaseTime - fRebindingTime) / 4 + system_time(); 90346ff5400SAxel Dörfler break; 90446ff5400SAxel Dörfler case REBINDING: 90546ff5400SAxel Dörfler default: 90646ff5400SAxel Dörfler next = (fLeaseTime - fRenewalTime) / 4 + system_time(); 90746ff5400SAxel Dörfler break; 90846ff5400SAxel Dörfler } 90946ff5400SAxel Dörfler } 91046ff5400SAxel Dörfler 91146ff5400SAxel Dörfler _RestartLease(next - system_time()); 91246ff5400SAxel Dörfler break; 91346ff5400SAxel Dörfler } 9146cc7630fSAxel Dörfler 9156cc7630fSAxel Dörfler default: 916fb81684fSAxel Dörfler BHandler::MessageReceived(message); 9176cc7630fSAxel Dörfler break; 9186cc7630fSAxel Dörfler } 919fb81684fSAxel Dörfler } 920