1fb81684fSAxel Dörfler /* 25d4d5313SHugo Santos * Copyright 2006-2007, 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> 20f9af6566SAxel Dörfler #include <sys/time.h> 21fb81684fSAxel Dörfler 22fb81684fSAxel Dörfler 23fb81684fSAxel Dörfler // See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options 24fb81684fSAxel Dörfler 25fb81684fSAxel Dörfler #define DHCP_CLIENT_PORT 68 26fb81684fSAxel Dörfler #define DHCP_SERVER_PORT 67 27fb81684fSAxel Dörfler 28f9af6566SAxel Dörfler #define DEFAULT_TIMEOUT 2 // secs 29f9af6566SAxel Dörfler #define MAX_TIMEOUT 15 // secs 30f9af6566SAxel Dörfler 31fb81684fSAxel Dörfler enum message_opcode { 32fb81684fSAxel Dörfler BOOT_REQUEST = 1, 33fb81684fSAxel Dörfler BOOT_REPLY 34fb81684fSAxel Dörfler }; 35fb81684fSAxel Dörfler 36fb81684fSAxel Dörfler enum message_option { 37fb81684fSAxel Dörfler OPTION_MAGIC = 0x63825363, 38fb81684fSAxel Dörfler 39fb81684fSAxel Dörfler // generic options 40fb81684fSAxel Dörfler OPTION_PAD = 0, 41f9af6566SAxel Dörfler OPTION_END = 255, 42f9af6566SAxel Dörfler OPTION_SUBNET_MASK = 1, 4365186fecSAxel Dörfler OPTION_TIME_OFFSET = 2, 44f9af6566SAxel Dörfler OPTION_ROUTER_ADDRESS = 3, 45f9af6566SAxel Dörfler OPTION_DOMAIN_NAME_SERVER = 6, 46f9af6566SAxel Dörfler OPTION_HOST_NAME = 12, 475782c5a3SAxel Dörfler OPTION_DOMAIN_NAME = 15, 48fb81684fSAxel Dörfler OPTION_DATAGRAM_SIZE = 22, 49fb81684fSAxel Dörfler OPTION_MTU = 26, 50fb81684fSAxel Dörfler OPTION_BROADCAST_ADDRESS = 28, 51fb81684fSAxel Dörfler OPTION_NETWORK_TIME_SERVERS = 42, 5265186fecSAxel Dörfler OPTION_NETBIOS_NAME_SERVER = 44, 5365186fecSAxel Dörfler OPTION_NETBIOS_SCOPE = 47, 54fb81684fSAxel Dörfler 55fb81684fSAxel Dörfler // DHCP specific options 56fb81684fSAxel Dörfler OPTION_REQUEST_IP_ADDRESS = 50, 57fb81684fSAxel Dörfler OPTION_ADDRESS_LEASE_TIME = 51, 58fb81684fSAxel Dörfler OPTION_OVERLOAD = 52, 59fb81684fSAxel Dörfler OPTION_MESSAGE_TYPE = 53, 60fb81684fSAxel Dörfler OPTION_SERVER_ADDRESS = 54, 61fb81684fSAxel Dörfler OPTION_REQUEST_PARAMETERS = 55, 62fb81684fSAxel Dörfler OPTION_ERROR_MESSAGE = 56, 63fb81684fSAxel Dörfler OPTION_MESSAGE_SIZE = 57, 64fb81684fSAxel Dörfler OPTION_RENEWAL_TIME = 58, 65fb81684fSAxel Dörfler OPTION_REBINDING_TIME = 59, 66fb81684fSAxel Dörfler OPTION_CLASS_IDENTIFIER = 60, 67fb81684fSAxel Dörfler OPTION_CLIENT_IDENTIFIER = 61, 68fb81684fSAxel Dörfler }; 69fb81684fSAxel Dörfler 70fb81684fSAxel Dörfler enum message_type { 71f9af6566SAxel Dörfler DHCP_NONE = 0, 72f9af6566SAxel Dörfler DHCP_DISCOVER, 73fb81684fSAxel Dörfler DHCP_OFFER, 74fb81684fSAxel Dörfler DHCP_REQUEST, 75fb81684fSAxel Dörfler DHCP_DECLINE, 76fb81684fSAxel Dörfler DHCP_ACK, 77f9af6566SAxel Dörfler DHCP_NACK, 78fb81684fSAxel Dörfler DHCP_RELEASE, 79fb81684fSAxel Dörfler DHCP_INFORM 80fb81684fSAxel Dörfler }; 81fb81684fSAxel Dörfler 82fb81684fSAxel Dörfler struct dhcp_option_cookie { 83fb81684fSAxel Dörfler dhcp_option_cookie() : state(0), file_has_options(false), server_name_has_options(false) {} 84fb81684fSAxel Dörfler 85fb81684fSAxel Dörfler const uint8* next; 86fb81684fSAxel Dörfler uint8 state; 87fb81684fSAxel Dörfler bool file_has_options; 88fb81684fSAxel Dörfler bool server_name_has_options; 89fb81684fSAxel Dörfler }; 90fb81684fSAxel Dörfler 91fb81684fSAxel Dörfler struct dhcp_message { 92fb81684fSAxel Dörfler dhcp_message(message_type type); 93fb81684fSAxel Dörfler 94fb81684fSAxel Dörfler uint8 opcode; 95fb81684fSAxel Dörfler uint8 hardware_type; 96fb81684fSAxel Dörfler uint8 hardware_address_length; 97fb81684fSAxel Dörfler uint8 hop_count; 98fb81684fSAxel Dörfler uint32 transaction_id; 9946ff5400SAxel Dörfler uint16 seconds_since_start; 100fb81684fSAxel Dörfler uint16 flags; 101fb81684fSAxel Dörfler in_addr_t client_address; 102fb81684fSAxel Dörfler in_addr_t your_address; 103fb81684fSAxel Dörfler in_addr_t server_address; 104fb81684fSAxel Dörfler in_addr_t gateway_address; 105fb81684fSAxel Dörfler uint8 mac_address[16]; 106fb81684fSAxel Dörfler uint8 server_name[64]; 107fb81684fSAxel Dörfler uint8 file[128]; 108fb81684fSAxel Dörfler uint32 options_magic; 109fb81684fSAxel Dörfler uint8 options[1260]; 110fb81684fSAxel Dörfler 111fb81684fSAxel Dörfler size_t MinSize() const { return 576; } 112fb81684fSAxel Dörfler size_t Size() const; 113fb81684fSAxel Dörfler 114fb81684fSAxel Dörfler bool HasOptions() const; 115fb81684fSAxel Dörfler bool NextOption(dhcp_option_cookie& cookie, message_option& option, 116fb81684fSAxel Dörfler const uint8*& data, size_t& size) const; 117f9af6566SAxel Dörfler message_type Type() const; 118fb81684fSAxel Dörfler const uint8* LastOption() const; 119fb81684fSAxel Dörfler 120a073ba1aSHugo Santos uint8* PrepareMessage(uint8 type); 121fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option); 122fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint8 data); 123fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint16 data); 124fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint32 data); 1255d4d5313SHugo Santos uint8* PutOption(uint8* options, message_option option, const uint8* data, uint32 size); 126a073ba1aSHugo Santos uint8* FinishOptions(uint8 *); 127fb81684fSAxel Dörfler } _PACKED; 128fb81684fSAxel Dörfler 1290cf5e6acSAxel Dörfler #define DHCP_FLAG_BROADCAST 0x8000 130fb81684fSAxel Dörfler 131fb81684fSAxel Dörfler #define ARP_HARDWARE_TYPE_ETHER 1 132fb81684fSAxel Dörfler 1336cc7630fSAxel Dörfler const uint32 kMsgLeaseTime = 'lstm'; 1346cc7630fSAxel Dörfler 1355d4d5313SHugo Santos static const uint8 kRequiredParameters[] = { 13665186fecSAxel Dörfler OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS, 13765186fecSAxel Dörfler OPTION_DOMAIN_NAME_SERVER, OPTION_BROADCAST_ADDRESS 1385d4d5313SHugo Santos }; 1395d4d5313SHugo Santos 140fb81684fSAxel Dörfler 141fb81684fSAxel Dörfler dhcp_message::dhcp_message(message_type type) 142fb81684fSAxel Dörfler { 143fb81684fSAxel Dörfler memset(this, 0, sizeof(*this)); 144fb81684fSAxel Dörfler options_magic = htonl(OPTION_MAGIC); 145fb81684fSAxel Dörfler 146a073ba1aSHugo Santos uint8* next = PrepareMessage(type); 147a073ba1aSHugo Santos FinishOptions(next); 148fb81684fSAxel Dörfler } 149fb81684fSAxel Dörfler 150fb81684fSAxel Dörfler 151fb81684fSAxel Dörfler bool 152fb81684fSAxel Dörfler dhcp_message::HasOptions() const 153fb81684fSAxel Dörfler { 154fb81684fSAxel Dörfler return options_magic == htonl(OPTION_MAGIC); 155fb81684fSAxel Dörfler } 156fb81684fSAxel Dörfler 157fb81684fSAxel Dörfler 158fb81684fSAxel Dörfler bool 159fb81684fSAxel Dörfler dhcp_message::NextOption(dhcp_option_cookie& cookie, 160fb81684fSAxel Dörfler message_option& option, const uint8*& data, size_t& size) const 161fb81684fSAxel Dörfler { 162fb81684fSAxel Dörfler if (cookie.state == 0) { 163fb81684fSAxel Dörfler if (!HasOptions()) 164fb81684fSAxel Dörfler return false; 165fb81684fSAxel Dörfler 166fb81684fSAxel Dörfler cookie.state++; 167fb81684fSAxel Dörfler cookie.next = options; 168fb81684fSAxel Dörfler } 169fb81684fSAxel Dörfler 170fb81684fSAxel Dörfler uint32 bytesLeft = 0; 171fb81684fSAxel Dörfler 172fb81684fSAxel Dörfler switch (cookie.state) { 173fb81684fSAxel Dörfler case 1: 174fb81684fSAxel Dörfler // options from "options" 175fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 176fb81684fSAxel Dörfler break; 177fb81684fSAxel Dörfler 178fb81684fSAxel Dörfler case 2: 179fb81684fSAxel Dörfler // options from "file" 180fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 181fb81684fSAxel Dörfler break; 182fb81684fSAxel Dörfler 183fb81684fSAxel Dörfler case 3: 184fb81684fSAxel Dörfler // options from "server_name" 185fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 186fb81684fSAxel Dörfler break; 187fb81684fSAxel Dörfler } 188fb81684fSAxel Dörfler 189fb81684fSAxel Dörfler while (true) { 190fb81684fSAxel Dörfler if (bytesLeft == 0) { 191fb81684fSAxel Dörfler // TODO: suppport OPTION_OVERLOAD! 192fb81684fSAxel Dörfler cookie.state = 4; 193fb81684fSAxel Dörfler return false; 194fb81684fSAxel Dörfler } 195fb81684fSAxel Dörfler 196fb81684fSAxel Dörfler option = (message_option)cookie.next[0]; 197fb81684fSAxel Dörfler if (option == OPTION_END) { 198fb81684fSAxel Dörfler cookie.state = 4; 199fb81684fSAxel Dörfler return false; 200fb81684fSAxel Dörfler } else if (option == OPTION_PAD) { 201fb81684fSAxel Dörfler bytesLeft--; 202fb81684fSAxel Dörfler cookie.next++; 203fb81684fSAxel Dörfler continue; 204fb81684fSAxel Dörfler } 205fb81684fSAxel Dörfler 206fb81684fSAxel Dörfler size = cookie.next[1]; 207fb81684fSAxel Dörfler data = &cookie.next[2]; 208fb81684fSAxel Dörfler cookie.next += 2 + size; 209fb81684fSAxel Dörfler 210fb81684fSAxel Dörfler if (option == OPTION_OVERLOAD) { 211fb81684fSAxel Dörfler cookie.file_has_options = data[0] & 1; 212fb81684fSAxel Dörfler cookie.server_name_has_options = data[0] & 2; 213fb81684fSAxel Dörfler continue; 214fb81684fSAxel Dörfler } 215fb81684fSAxel Dörfler 216fb81684fSAxel Dörfler return true; 217fb81684fSAxel Dörfler } 218fb81684fSAxel Dörfler } 219fb81684fSAxel Dörfler 220fb81684fSAxel Dörfler 221f9af6566SAxel Dörfler message_type 222f9af6566SAxel Dörfler dhcp_message::Type() const 223f9af6566SAxel Dörfler { 224f9af6566SAxel Dörfler dhcp_option_cookie cookie; 225f9af6566SAxel Dörfler message_option option; 226f9af6566SAxel Dörfler const uint8* data; 227f9af6566SAxel Dörfler size_t size; 228f9af6566SAxel Dörfler while (NextOption(cookie, option, data, size)) { 229f9af6566SAxel Dörfler // iterate through all options 230f9af6566SAxel Dörfler if (option == OPTION_MESSAGE_TYPE) 231f9af6566SAxel Dörfler return (message_type)data[0]; 232f9af6566SAxel Dörfler } 233f9af6566SAxel Dörfler 234f9af6566SAxel Dörfler return DHCP_NONE; 235f9af6566SAxel Dörfler } 236f9af6566SAxel Dörfler 237f9af6566SAxel Dörfler 238fb81684fSAxel Dörfler const uint8* 239fb81684fSAxel Dörfler dhcp_message::LastOption() const 240fb81684fSAxel Dörfler { 241fb81684fSAxel Dörfler dhcp_option_cookie cookie; 242fb81684fSAxel Dörfler message_option option; 243fb81684fSAxel Dörfler const uint8* data; 244fb81684fSAxel Dörfler size_t size; 245fb81684fSAxel Dörfler while (NextOption(cookie, option, data, size)) { 246fb81684fSAxel Dörfler // iterate through all options 247fb81684fSAxel Dörfler } 248fb81684fSAxel Dörfler 249fb81684fSAxel Dörfler return cookie.next; 250fb81684fSAxel Dörfler } 251fb81684fSAxel Dörfler 252fb81684fSAxel Dörfler 253fb81684fSAxel Dörfler size_t 254fb81684fSAxel Dörfler dhcp_message::Size() const 255fb81684fSAxel Dörfler { 256fb81684fSAxel Dörfler const uint8* last = LastOption(); 257fb81684fSAxel Dörfler return sizeof(dhcp_message) - sizeof(options) + last + 1 - options; 258fb81684fSAxel Dörfler } 259fb81684fSAxel Dörfler 260fb81684fSAxel Dörfler 261fb81684fSAxel Dörfler uint8* 262a073ba1aSHugo Santos dhcp_message::PrepareMessage(uint8 type) 263a073ba1aSHugo Santos { 264a073ba1aSHugo Santos uint8 *next = options; 265a073ba1aSHugo Santos next = PutOption(next, OPTION_MESSAGE_TYPE, type); 266a073ba1aSHugo Santos next = PutOption(next, OPTION_MESSAGE_SIZE, (uint16)htons(sizeof(dhcp_message))); 267a073ba1aSHugo Santos return next; 268a073ba1aSHugo Santos } 269a073ba1aSHugo Santos 27065186fecSAxel Dörfler 271a073ba1aSHugo Santos uint8* 272fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option) 273fb81684fSAxel Dörfler { 274fb81684fSAxel Dörfler options[0] = option; 275fb81684fSAxel Dörfler return options + 1; 276fb81684fSAxel Dörfler } 277fb81684fSAxel Dörfler 278fb81684fSAxel Dörfler 279fb81684fSAxel Dörfler uint8* 280fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8 data) 281fb81684fSAxel Dörfler { 282fb81684fSAxel Dörfler return PutOption(options, option, &data, 1); 283fb81684fSAxel Dörfler } 284fb81684fSAxel Dörfler 285fb81684fSAxel Dörfler 286fb81684fSAxel Dörfler uint8* 287fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint16 data) 288fb81684fSAxel Dörfler { 289fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 290fb81684fSAxel Dörfler } 291fb81684fSAxel Dörfler 292fb81684fSAxel Dörfler 293fb81684fSAxel Dörfler uint8* 294fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint32 data) 295fb81684fSAxel Dörfler { 296fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 297fb81684fSAxel Dörfler } 298fb81684fSAxel Dörfler 299fb81684fSAxel Dörfler 300fb81684fSAxel Dörfler uint8* 3015d4d5313SHugo Santos dhcp_message::PutOption(uint8* options, message_option option, const uint8* data, uint32 size) 302fb81684fSAxel Dörfler { 303fb81684fSAxel Dörfler options[0] = option; 304fb81684fSAxel Dörfler options[1] = size; 305fb81684fSAxel Dörfler memcpy(&options[2], data, size); 306fb81684fSAxel Dörfler 307fb81684fSAxel Dörfler return options + 2 + size; 308fb81684fSAxel Dörfler } 309fb81684fSAxel Dörfler 310fb81684fSAxel Dörfler 311a073ba1aSHugo Santos uint8* 312a073ba1aSHugo Santos dhcp_message::FinishOptions(uint8 *next) 313a073ba1aSHugo Santos { 314a073ba1aSHugo Santos return PutOption(next, OPTION_END); 315a073ba1aSHugo Santos } 316a073ba1aSHugo Santos 317a073ba1aSHugo Santos 318fb81684fSAxel Dörfler // #pragma mark - 319fb81684fSAxel Dörfler 320fb81684fSAxel Dörfler 321f9af6566SAxel Dörfler DHCPClient::DHCPClient(BMessenger target, const char* device) 322fb81684fSAxel Dörfler : BHandler("dhcp"), 3236cc7630fSAxel Dörfler fTarget(target), 32410cc12daSAxel Dörfler fDevice(device), 3256cc7630fSAxel Dörfler fConfiguration(kMsgConfigureInterface), 3266cc7630fSAxel Dörfler fRunner(NULL), 3276cc7630fSAxel Dörfler fLeaseTime(0) 328fb81684fSAxel Dörfler { 32946ff5400SAxel Dörfler fStartTime = system_time(); 33046ff5400SAxel Dörfler fTransactionID = (uint32)fStartTime; 331fb81684fSAxel Dörfler 3320ce7725eSAxel Dörfler fStatus = get_mac_address(device, fMAC); 333fb81684fSAxel Dörfler if (fStatus < B_OK) 334fb81684fSAxel Dörfler return; 335fb81684fSAxel Dörfler 3366cc7630fSAxel Dörfler memset(&fServer, 0, sizeof(struct sockaddr_in)); 3376cc7630fSAxel Dörfler fServer.sin_family = AF_INET; 3386cc7630fSAxel Dörfler fServer.sin_len = sizeof(struct sockaddr_in); 3396cc7630fSAxel Dörfler fServer.sin_port = htons(DHCP_SERVER_PORT); 3406cc7630fSAxel Dörfler } 3416cc7630fSAxel Dörfler 3426cc7630fSAxel Dörfler 3436cc7630fSAxel Dörfler DHCPClient::~DHCPClient() 3446cc7630fSAxel Dörfler { 3456cc7630fSAxel Dörfler if (fStatus != B_OK) 3466cc7630fSAxel Dörfler return; 3476cc7630fSAxel Dörfler 3486cc7630fSAxel Dörfler delete fRunner; 3490ce7725eSAxel Dörfler 350fb81684fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 3516cc7630fSAxel Dörfler if (socket < 0) 352fb81684fSAxel Dörfler return; 3536cc7630fSAxel Dörfler 3546cc7630fSAxel Dörfler // release lease 3556cc7630fSAxel Dörfler 3566cc7630fSAxel Dörfler dhcp_message release(DHCP_RELEASE); 35746ff5400SAxel Dörfler _PrepareMessage(release, BOUND); 3586cc7630fSAxel Dörfler 3596cc7630fSAxel Dörfler _SendMessage(socket, release, fServer); 3606cc7630fSAxel Dörfler close(socket); 361fb81684fSAxel Dörfler } 362fb81684fSAxel Dörfler 3636cc7630fSAxel Dörfler 3646cc7630fSAxel Dörfler status_t 3656cc7630fSAxel Dörfler DHCPClient::Initialize() 3666cc7630fSAxel Dörfler { 3676cc7630fSAxel Dörfler fStatus = _Negotiate(INIT); 3686cc7630fSAxel Dörfler printf("DHCP for %s, status: %s\n", fDevice.String(), strerror(fStatus)); 3696cc7630fSAxel Dörfler return fStatus; 3706cc7630fSAxel Dörfler } 3716cc7630fSAxel Dörfler 3726cc7630fSAxel Dörfler 3736cc7630fSAxel Dörfler status_t 3746cc7630fSAxel Dörfler DHCPClient::_Negotiate(dhcp_state state) 3756cc7630fSAxel Dörfler { 3766cc7630fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 3776cc7630fSAxel Dörfler if (socket < 0) 3786cc7630fSAxel Dörfler return errno; 3796cc7630fSAxel Dörfler 380fb81684fSAxel Dörfler sockaddr_in local; 381fb81684fSAxel Dörfler memset(&local, 0, sizeof(struct sockaddr_in)); 382fb81684fSAxel Dörfler local.sin_family = AF_INET; 383fb81684fSAxel Dörfler local.sin_len = sizeof(struct sockaddr_in); 384fb81684fSAxel Dörfler local.sin_port = htons(DHCP_CLIENT_PORT); 385fb81684fSAxel Dörfler local.sin_addr.s_addr = INADDR_ANY; 386fb81684fSAxel Dörfler 387fb81684fSAxel Dörfler if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) { 388fb81684fSAxel Dörfler close(socket); 3896cc7630fSAxel Dörfler return errno; 390fb81684fSAxel Dörfler } 391fb81684fSAxel Dörfler 392fb81684fSAxel Dörfler sockaddr_in broadcast; 393fb81684fSAxel Dörfler memset(&broadcast, 0, sizeof(struct sockaddr_in)); 394fb81684fSAxel Dörfler broadcast.sin_family = AF_INET; 395fb81684fSAxel Dörfler broadcast.sin_len = sizeof(struct sockaddr_in); 396fb81684fSAxel Dörfler broadcast.sin_port = htons(DHCP_SERVER_PORT); 397fb81684fSAxel Dörfler broadcast.sin_addr.s_addr = INADDR_BROADCAST; 398fb81684fSAxel Dörfler 399fb81684fSAxel Dörfler int option = 1; 400fb81684fSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); 401fb81684fSAxel Dörfler 4026cc7630fSAxel Dörfler bigtime_t previousLeaseTime = fLeaseTime; 4036cc7630fSAxel Dörfler fLeaseTime = 0; 40446ff5400SAxel Dörfler fRenewalTime = 0; 40546ff5400SAxel Dörfler fRebindingTime = 0; 406fb81684fSAxel Dörfler 4076cc7630fSAxel Dörfler status_t status = B_ERROR; 4086cc7630fSAxel Dörfler time_t timeout; 4096cc7630fSAxel Dörfler uint32 tries; 4106cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 4116cc7630fSAxel Dörfler 4126cc7630fSAxel Dörfler dhcp_message discover(DHCP_DISCOVER); 41346ff5400SAxel Dörfler _PrepareMessage(discover, state); 4146cc7630fSAxel Dörfler 4156cc7630fSAxel Dörfler dhcp_message request(DHCP_REQUEST); 41646ff5400SAxel Dörfler _PrepareMessage(request, state); 4176cc7630fSAxel Dörfler 41846ff5400SAxel Dörfler // send discover/request message 4196cc7630fSAxel Dörfler status = _SendMessage(socket, state == INIT ? discover : request, 42046ff5400SAxel Dörfler state != RENEWAL ? broadcast : fServer); 4216cc7630fSAxel Dörfler if (status < B_OK) { 422fb81684fSAxel Dörfler close(socket); 4236cc7630fSAxel Dörfler return status; 4246cc7630fSAxel Dörfler } 425fb81684fSAxel Dörfler 426f9af6566SAxel Dörfler // receive loop until we've got an offer and acknowledged it 427f9af6566SAxel Dörfler 428f9af6566SAxel Dörfler while (state != ACKNOWLEDGED) { 429f9af6566SAxel Dörfler char buffer[2048]; 430f9af6566SAxel Dörfler ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer), 431f9af6566SAxel Dörfler 0, NULL, NULL); 4324b661a95SAxel Dörfler if (bytesReceived < 0 && errno == B_TIMED_OUT) { 433f9af6566SAxel Dörfler // depending on the state, we'll just try again 4346cc7630fSAxel Dörfler if (!_TimeoutShift(socket, timeout, tries)) { 4356cc7630fSAxel Dörfler close(socket); 4366cc7630fSAxel Dörfler return B_TIMED_OUT; 437f9af6566SAxel Dörfler } 438f9af6566SAxel Dörfler 439f9af6566SAxel Dörfler if (state == INIT) 4406cc7630fSAxel Dörfler status = _SendMessage(socket, discover, broadcast); 44146ff5400SAxel Dörfler else 44246ff5400SAxel Dörfler status = _SendMessage(socket, request, state != RENEWAL 4436cc7630fSAxel Dörfler ? broadcast : fServer); 444f9af6566SAxel Dörfler 4456cc7630fSAxel Dörfler if (status < B_OK) 446f9af6566SAxel Dörfler break; 447f9af6566SAxel Dörfler } else if (bytesReceived < B_OK) 448f9af6566SAxel Dörfler break; 449f9af6566SAxel Dörfler 450f9af6566SAxel Dörfler dhcp_message *message = (dhcp_message *)buffer; 451f9af6566SAxel Dörfler if (message->transaction_id != htonl(fTransactionID) 452f9af6566SAxel Dörfler || !message->HasOptions() 453f9af6566SAxel Dörfler || memcmp(message->mac_address, discover.mac_address, 454f9af6566SAxel Dörfler discover.hardware_address_length)) { 455f9af6566SAxel Dörfler // this message is not for us 456f9af6566SAxel Dörfler continue; 457f9af6566SAxel Dörfler } 458f9af6566SAxel Dörfler 459f9af6566SAxel Dörfler switch (message->Type()) { 460f9af6566SAxel Dörfler case DHCP_NONE: 461f9af6566SAxel Dörfler default: 462f9af6566SAxel Dörfler // ignore this message 463f9af6566SAxel Dörfler break; 464f9af6566SAxel Dörfler 465f9af6566SAxel Dörfler case DHCP_OFFER: 466f9af6566SAxel Dörfler { 467f9af6566SAxel Dörfler // first offer wins 468f9af6566SAxel Dörfler if (state != INIT) 469f9af6566SAxel Dörfler break; 470f9af6566SAxel Dörfler 471f9af6566SAxel Dörfler // collect interface options 472f9af6566SAxel Dörfler 473f9af6566SAxel Dörfler fAssignedAddress = message->your_address; 474f9af6566SAxel Dörfler 47510cc12daSAxel Dörfler fConfiguration.MakeEmpty(); 47610cc12daSAxel Dörfler fConfiguration.AddString("device", fDevice.String()); 477*f01106c3SAxel Dörfler fConfiguration.AddBool("auto", true); 478f9af6566SAxel Dörfler 479f9af6566SAxel Dörfler BMessage address; 480f9af6566SAxel Dörfler address.AddString("family", "inet"); 481f9af6566SAxel Dörfler address.AddString("address", _ToString(fAssignedAddress)); 4820ce7725eSAxel Dörfler _ParseOptions(*message, address); 483f9af6566SAxel Dörfler 48410cc12daSAxel Dörfler fConfiguration.AddMessage("address", &address); 485f9af6566SAxel Dörfler 48610cc12daSAxel Dörfler // request configuration from the server 487f9af6566SAxel Dörfler 4886cc7630fSAxel Dörfler _ResetTimeout(socket, timeout, tries); 489f9af6566SAxel Dörfler state = REQUESTING; 49046ff5400SAxel Dörfler _PrepareMessage(request, state); 491f9af6566SAxel Dörfler 4926cc7630fSAxel Dörfler status = _SendMessage(socket, request, broadcast); 49310cc12daSAxel Dörfler // we're sending a broadcast so that all potential offers get an answer 49410cc12daSAxel Dörfler break; 495f9af6566SAxel Dörfler } 496f9af6566SAxel Dörfler 497f9af6566SAxel Dörfler case DHCP_ACK: 49810cc12daSAxel Dörfler { 49946ff5400SAxel Dörfler if (state != REQUESTING && state != REBINDING && state != RENEWAL) 500f9af6566SAxel Dörfler continue; 501f9af6566SAxel Dörfler 5026cc7630fSAxel Dörfler // TODO: we might want to configure the stuff, don't we? 5036cc7630fSAxel Dörfler BMessage address; 5046cc7630fSAxel Dörfler _ParseOptions(*message, address); 5056cc7630fSAxel Dörfler // TODO: currently, only lease time and DNS is updated this way 5066cc7630fSAxel Dörfler 507f9af6566SAxel Dörfler // our address request has been acknowledged 508f9af6566SAxel Dörfler state = ACKNOWLEDGED; 50910cc12daSAxel Dörfler 51010cc12daSAxel Dörfler // configure interface 51110cc12daSAxel Dörfler BMessage reply; 5126cc7630fSAxel Dörfler fTarget.SendMessage(&fConfiguration, &reply); 51310cc12daSAxel Dörfler 51410cc12daSAxel Dörfler if (reply.FindInt32("status", &fStatus) != B_OK) 5156cc7630fSAxel Dörfler status = B_OK; 516f9af6566SAxel Dörfler break; 51710cc12daSAxel Dörfler } 518f9af6566SAxel Dörfler 519f9af6566SAxel Dörfler case DHCP_NACK: 520f9af6566SAxel Dörfler if (state != REQUESTING) 521f9af6566SAxel Dörfler continue; 522f9af6566SAxel Dörfler 523a552ec13SAxel Dörfler // try again (maybe we should prefer other servers if this happens more than once) 5246cc7630fSAxel Dörfler status = _SendMessage(socket, discover, broadcast); 5256cc7630fSAxel Dörfler if (status == B_OK) 526f9af6566SAxel Dörfler state = INIT; 527f9af6566SAxel Dörfler break; 528f9af6566SAxel Dörfler } 529f9af6566SAxel Dörfler } 530f9af6566SAxel Dörfler 531fb81684fSAxel Dörfler close(socket); 5326cc7630fSAxel Dörfler 5336cc7630fSAxel Dörfler if (status == B_OK && fLeaseTime > 0) { 5346cc7630fSAxel Dörfler // notify early enough when the lease is 53546ff5400SAxel Dörfler if (fRenewalTime == 0) 53646ff5400SAxel Dörfler fRenewalTime = fLeaseTime * 2/3; 53746ff5400SAxel Dörfler if (fRebindingTime == 0) 53846ff5400SAxel Dörfler fRebindingTime = fLeaseTime * 5/6; 53946ff5400SAxel Dörfler 54046ff5400SAxel Dörfler _RestartLease(fRenewalTime); 54146ff5400SAxel Dörfler 54246ff5400SAxel Dörfler bigtime_t now = system_time(); 54346ff5400SAxel Dörfler fLeaseTime += now; 54446ff5400SAxel Dörfler fRenewalTime += now; 54546ff5400SAxel Dörfler fRebindingTime += now; 54646ff5400SAxel Dörfler // make lease times absolute 54746ff5400SAxel Dörfler } else { 5486cc7630fSAxel Dörfler fLeaseTime = previousLeaseTime; 54946ff5400SAxel Dörfler bigtime_t now = system_time(); 55046ff5400SAxel Dörfler fRenewalTime = (fLeaseTime - now) * 2/3 + now; 55146ff5400SAxel Dörfler fRebindingTime = (fLeaseTime - now) * 5/6 + now; 55246ff5400SAxel Dörfler } 5536cc7630fSAxel Dörfler 5546cc7630fSAxel Dörfler return status; 555fb81684fSAxel Dörfler } 556fb81684fSAxel Dörfler 557fb81684fSAxel Dörfler 5586cc7630fSAxel Dörfler void 5596cc7630fSAxel Dörfler DHCPClient::_RestartLease(bigtime_t leaseTime) 560fb81684fSAxel Dörfler { 5616cc7630fSAxel Dörfler if (leaseTime == 0) 562f9af6566SAxel Dörfler return; 563f9af6566SAxel Dörfler 5646cc7630fSAxel Dörfler BMessage lease(kMsgLeaseTime); 56546ff5400SAxel Dörfler fRunner = new BMessageRunner(this, &lease, leaseTime, 1); 566f9af6566SAxel Dörfler } 567f9af6566SAxel Dörfler 568f9af6566SAxel Dörfler 569f9af6566SAxel Dörfler void 5700ce7725eSAxel Dörfler DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address) 5710ce7725eSAxel Dörfler { 5720ce7725eSAxel Dörfler dhcp_option_cookie cookie; 5730ce7725eSAxel Dörfler message_option option; 5740ce7725eSAxel Dörfler const uint8* data; 5750ce7725eSAxel Dörfler size_t size; 5760ce7725eSAxel Dörfler while (message.NextOption(cookie, option, data, size)) { 5770ce7725eSAxel Dörfler // iterate through all options 5780ce7725eSAxel Dörfler switch (option) { 5790ce7725eSAxel Dörfler case OPTION_ROUTER_ADDRESS: 5800ce7725eSAxel Dörfler address.AddString("gateway", _ToString(data)); 5810ce7725eSAxel Dörfler break; 5820ce7725eSAxel Dörfler case OPTION_SUBNET_MASK: 5830ce7725eSAxel Dörfler address.AddString("mask", _ToString(data)); 5840ce7725eSAxel Dörfler break; 5855782c5a3SAxel Dörfler case OPTION_BROADCAST_ADDRESS: 5865782c5a3SAxel Dörfler address.AddString("broadcast", _ToString(data)); 5875782c5a3SAxel Dörfler break; 5880ce7725eSAxel Dörfler case OPTION_DOMAIN_NAME_SERVER: 589a552ec13SAxel Dörfler { 590a552ec13SAxel Dörfler // TODO: for now, we write it just out to /etc/resolv.conf 591a552ec13SAxel Dörfler FILE* file = fopen("/etc/resolv.conf", "w"); 5920ce7725eSAxel Dörfler for (uint32 i = 0; i < size / 4; i++) { 5930ce7725eSAxel Dörfler printf("DNS: %s\n", _ToString(&data[i*4]).String()); 594a552ec13SAxel Dörfler if (file != NULL) 595a552ec13SAxel Dörfler fprintf(file, "nameserver %s\n", _ToString(&data[i*4]).String()); 5960ce7725eSAxel Dörfler } 597a552ec13SAxel Dörfler fclose(file); 5980ce7725eSAxel Dörfler break; 599a552ec13SAxel Dörfler } 6000ce7725eSAxel Dörfler case OPTION_SERVER_ADDRESS: 6010ce7725eSAxel Dörfler fServer.sin_addr.s_addr = *(in_addr_t*)data; 6020ce7725eSAxel Dörfler break; 60346ff5400SAxel Dörfler 6040ce7725eSAxel Dörfler case OPTION_ADDRESS_LEASE_TIME: 6050ce7725eSAxel Dörfler printf("lease time of %lu seconds\n", htonl(*(uint32*)data)); 6066cc7630fSAxel Dörfler fLeaseTime = htonl(*(uint32*)data) * 1000000LL; 6070ce7725eSAxel Dörfler break; 6081a4e8e7bSAxel Dörfler case OPTION_RENEWAL_TIME: 60946ff5400SAxel Dörfler printf("renewal time of %lu seconds\n", 61046ff5400SAxel Dörfler htonl(*(uint32*)data)); 61146ff5400SAxel Dörfler fRenewalTime = htonl(*(uint32*)data) * 1000000LL; 61246ff5400SAxel Dörfler break; 6131a4e8e7bSAxel Dörfler case OPTION_REBINDING_TIME: 61446ff5400SAxel Dörfler printf("rebinding time of %lu seconds\n", 61546ff5400SAxel Dörfler htonl(*(uint32*)data)); 61646ff5400SAxel Dörfler fRebindingTime = htonl(*(uint32*)data) * 1000000LL; 6171a4e8e7bSAxel Dörfler break; 6181a4e8e7bSAxel Dörfler 6190ce7725eSAxel Dörfler case OPTION_HOST_NAME: 6205782c5a3SAxel Dörfler { 6210ce7725eSAxel Dörfler char name[256]; 6220ce7725eSAxel Dörfler memcpy(name, data, size); 6230ce7725eSAxel Dörfler name[size] = '\0'; 6240ce7725eSAxel Dörfler printf("DHCP host name: \"%s\"\n", name); 6250ce7725eSAxel Dörfler break; 6265782c5a3SAxel Dörfler } 6275782c5a3SAxel Dörfler 6285782c5a3SAxel Dörfler case OPTION_DOMAIN_NAME: 6295782c5a3SAxel Dörfler { 6305782c5a3SAxel Dörfler char name[256]; 6315782c5a3SAxel Dörfler memcpy(name, data, size); 6325782c5a3SAxel Dörfler name[size] = '\0'; 6335782c5a3SAxel Dörfler printf("DHCP domain name: \"%s\"\n", name); 6345782c5a3SAxel Dörfler break; 6355782c5a3SAxel Dörfler } 6360ce7725eSAxel Dörfler 6370ce7725eSAxel Dörfler case OPTION_MESSAGE_TYPE: 6380ce7725eSAxel Dörfler break; 6390ce7725eSAxel Dörfler 6400ce7725eSAxel Dörfler default: 6410ce7725eSAxel Dörfler printf("unknown option %lu\n", (uint32)option); 6420ce7725eSAxel Dörfler break; 6430ce7725eSAxel Dörfler } 6440ce7725eSAxel Dörfler } 6450ce7725eSAxel Dörfler } 6460ce7725eSAxel Dörfler 6470ce7725eSAxel Dörfler 6480ce7725eSAxel Dörfler void 64946ff5400SAxel Dörfler DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state) 6500ce7725eSAxel Dörfler { 6510ce7725eSAxel Dörfler message.opcode = BOOT_REQUEST; 6520ce7725eSAxel Dörfler message.hardware_type = ARP_HARDWARE_TYPE_ETHER; 6530ce7725eSAxel Dörfler message.hardware_address_length = 6; 6540ce7725eSAxel Dörfler message.transaction_id = htonl(fTransactionID); 65546ff5400SAxel Dörfler message.seconds_since_start = htons(min_c((fStartTime - system_time()) / 1000000LL, 65535)); 6560ce7725eSAxel Dörfler memcpy(message.mac_address, fMAC, 6); 6570ce7725eSAxel Dörfler 65846ff5400SAxel Dörfler message_type type = message.Type(); 65946ff5400SAxel Dörfler 66046ff5400SAxel Dörfler switch (type) { 6610ce7725eSAxel Dörfler case DHCP_REQUEST: 6620ce7725eSAxel Dörfler case DHCP_RELEASE: 6630ce7725eSAxel Dörfler { 6640ce7725eSAxel Dörfler // add server identifier option 665a073ba1aSHugo Santos uint8* next = message.PrepareMessage(type); 6660ce7725eSAxel Dörfler next = message.PutOption(next, OPTION_SERVER_ADDRESS, 6670ce7725eSAxel Dörfler (uint32)fServer.sin_addr.s_addr); 66846ff5400SAxel Dörfler 66946ff5400SAxel Dörfler // In RENEWAL or REBINDING state, we must set the client_address field, and not 67046ff5400SAxel Dörfler // use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages 6715d4d5313SHugo Santos if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING)) { 6720ce7725eSAxel Dörfler next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, fAssignedAddress); 6735d4d5313SHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 6745d4d5313SHugo Santos kRequiredParameters, sizeof(kRequiredParameters)); 6755d4d5313SHugo Santos } else 67646ff5400SAxel Dörfler message.client_address = fAssignedAddress; 67746ff5400SAxel Dörfler 678a073ba1aSHugo Santos message.FinishOptions(next); 679a073ba1aSHugo Santos break; 680a073ba1aSHugo Santos } 681a073ba1aSHugo Santos 682a073ba1aSHugo Santos case DHCP_DISCOVER: 683a073ba1aSHugo Santos { 684a073ba1aSHugo Santos uint8 *next = message.PrepareMessage(type); 685a073ba1aSHugo Santos next = message.PutOption(next, OPTION_REQUEST_PARAMETERS, 686a073ba1aSHugo Santos kRequiredParameters, sizeof(kRequiredParameters)); 687a073ba1aSHugo Santos message.FinishOptions(next); 6880ce7725eSAxel Dörfler break; 6890ce7725eSAxel Dörfler } 6900ce7725eSAxel Dörfler 6910ce7725eSAxel Dörfler default: 6920ce7725eSAxel Dörfler // the default options are fine 6930ce7725eSAxel Dörfler break; 6940ce7725eSAxel Dörfler } 6950ce7725eSAxel Dörfler } 6960ce7725eSAxel Dörfler 6970ce7725eSAxel Dörfler 6980ce7725eSAxel Dörfler void 6996cc7630fSAxel Dörfler DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries) 700f9af6566SAxel Dörfler { 7016cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 7026cc7630fSAxel Dörfler tries = 0; 703f9af6566SAxel Dörfler 704f9af6566SAxel Dörfler struct timeval value; 7056cc7630fSAxel Dörfler value.tv_sec = timeout; 706f9af6566SAxel Dörfler value.tv_usec = 0; 707f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 708f9af6566SAxel Dörfler } 709f9af6566SAxel Dörfler 710f9af6566SAxel Dörfler 711f9af6566SAxel Dörfler bool 7126cc7630fSAxel Dörfler DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries) 713f9af6566SAxel Dörfler { 7146cc7630fSAxel Dörfler timeout += timeout; 7156cc7630fSAxel Dörfler if (timeout > MAX_TIMEOUT) { 7166cc7630fSAxel Dörfler timeout = DEFAULT_TIMEOUT; 717f9af6566SAxel Dörfler 7186cc7630fSAxel Dörfler if (++tries > 2) 719f9af6566SAxel Dörfler return false; 720f9af6566SAxel Dörfler } 7216cc7630fSAxel Dörfler printf("DHCP timeout shift: %lu secs (try %lu)\n", timeout, tries); 722f9af6566SAxel Dörfler 723f9af6566SAxel Dörfler struct timeval value; 7246cc7630fSAxel Dörfler value.tv_sec = timeout; 725f9af6566SAxel Dörfler value.tv_usec = 0; 726f9af6566SAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); 727f9af6566SAxel Dörfler 728f9af6566SAxel Dörfler return true; 729f9af6566SAxel Dörfler } 730f9af6566SAxel Dörfler 731f9af6566SAxel Dörfler 732f9af6566SAxel Dörfler BString 733f9af6566SAxel Dörfler DHCPClient::_ToString(const uint8* data) const 734f9af6566SAxel Dörfler { 735f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)data); 736f9af6566SAxel Dörfler return target; 737f9af6566SAxel Dörfler } 738f9af6566SAxel Dörfler 739f9af6566SAxel Dörfler 740f9af6566SAxel Dörfler BString 741f9af6566SAxel Dörfler DHCPClient::_ToString(in_addr_t address) const 742f9af6566SAxel Dörfler { 743f9af6566SAxel Dörfler BString target = inet_ntoa(*(in_addr*)&address); 744f9af6566SAxel Dörfler return target; 745f9af6566SAxel Dörfler } 746f9af6566SAxel Dörfler 747f9af6566SAxel Dörfler 748f9af6566SAxel Dörfler status_t 749f9af6566SAxel Dörfler DHCPClient::_SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const 750f9af6566SAxel Dörfler { 751f9af6566SAxel Dörfler ssize_t bytesSent = sendto(socket, &message, message.Size(), 752f9af6566SAxel Dörfler address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0, 753f9af6566SAxel Dörfler (struct sockaddr*)&address, sizeof(sockaddr_in)); 754f9af6566SAxel Dörfler if (bytesSent < 0) 755f9af6566SAxel Dörfler return errno; 756f9af6566SAxel Dörfler 757f9af6566SAxel Dörfler return B_OK; 758fb81684fSAxel Dörfler } 759fb81684fSAxel Dörfler 760fb81684fSAxel Dörfler 76146ff5400SAxel Dörfler dhcp_state 76246ff5400SAxel Dörfler DHCPClient::_CurrentState() const 76346ff5400SAxel Dörfler { 76446ff5400SAxel Dörfler bigtime_t now = system_time(); 76546ff5400SAxel Dörfler 76646ff5400SAxel Dörfler if (now > fLeaseTime || fStatus < B_OK) 76746ff5400SAxel Dörfler return INIT; 76846ff5400SAxel Dörfler if (now >= fRebindingTime) 76946ff5400SAxel Dörfler return REBINDING; 77046ff5400SAxel Dörfler if (now >= fRenewalTime) 77146ff5400SAxel Dörfler return RENEWAL; 77246ff5400SAxel Dörfler 77346ff5400SAxel Dörfler return BOUND; 77446ff5400SAxel Dörfler } 77546ff5400SAxel Dörfler 77646ff5400SAxel Dörfler 777fb81684fSAxel Dörfler void 778fb81684fSAxel Dörfler DHCPClient::MessageReceived(BMessage* message) 779fb81684fSAxel Dörfler { 7806cc7630fSAxel Dörfler switch (message->what) { 7816cc7630fSAxel Dörfler case kMsgLeaseTime: 78246ff5400SAxel Dörfler { 78346ff5400SAxel Dörfler dhcp_state state = _CurrentState(); 78446ff5400SAxel Dörfler 78546ff5400SAxel Dörfler bigtime_t next; 78646ff5400SAxel Dörfler if (_Negotiate(state) == B_OK) { 78746ff5400SAxel Dörfler switch (state) { 78846ff5400SAxel Dörfler case RENEWAL: 78946ff5400SAxel Dörfler next = fRebindingTime; 7906cc7630fSAxel Dörfler break; 79146ff5400SAxel Dörfler case REBINDING: 79246ff5400SAxel Dörfler default: 79346ff5400SAxel Dörfler next = fRenewalTime; 79446ff5400SAxel Dörfler break; 79546ff5400SAxel Dörfler } 79646ff5400SAxel Dörfler } else { 79746ff5400SAxel Dörfler switch (state) { 79846ff5400SAxel Dörfler case RENEWAL: 79946ff5400SAxel Dörfler next = (fLeaseTime - fRebindingTime) / 4 + system_time(); 80046ff5400SAxel Dörfler break; 80146ff5400SAxel Dörfler case REBINDING: 80246ff5400SAxel Dörfler default: 80346ff5400SAxel Dörfler next = (fLeaseTime - fRenewalTime) / 4 + system_time(); 80446ff5400SAxel Dörfler break; 80546ff5400SAxel Dörfler } 80646ff5400SAxel Dörfler } 80746ff5400SAxel Dörfler 80846ff5400SAxel Dörfler _RestartLease(next - system_time()); 80946ff5400SAxel Dörfler break; 81046ff5400SAxel Dörfler } 8116cc7630fSAxel Dörfler 8126cc7630fSAxel Dörfler default: 813fb81684fSAxel Dörfler BHandler::MessageReceived(message); 8146cc7630fSAxel Dörfler break; 8156cc7630fSAxel Dörfler } 816fb81684fSAxel Dörfler } 817fb81684fSAxel Dörfler 818