xref: /haiku/src/servers/net/DHCPClient.cpp (revision 46ff54007d71698788ded180c50f8867ab2df815)
1fb81684fSAxel Dörfler /*
2fb81684fSAxel Dörfler  * Copyright 2006, 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,
43f9af6566SAxel Dörfler 	OPTION_ROUTER_ADDRESS = 3,
44f9af6566SAxel Dörfler 	OPTION_DOMAIN_NAME_SERVER = 6,
45f9af6566SAxel Dörfler 	OPTION_HOST_NAME = 12,
465782c5a3SAxel Dörfler 	OPTION_DOMAIN_NAME = 15,
47fb81684fSAxel Dörfler 	OPTION_DATAGRAM_SIZE = 22,
48fb81684fSAxel Dörfler 	OPTION_MTU = 26,
49fb81684fSAxel Dörfler 	OPTION_BROADCAST_ADDRESS = 28,
50fb81684fSAxel Dörfler 	OPTION_NETWORK_TIME_SERVERS = 42,
51fb81684fSAxel Dörfler 
52fb81684fSAxel Dörfler 	// DHCP specific options
53fb81684fSAxel Dörfler 	OPTION_REQUEST_IP_ADDRESS = 50,
54fb81684fSAxel Dörfler 	OPTION_ADDRESS_LEASE_TIME = 51,
55fb81684fSAxel Dörfler 	OPTION_OVERLOAD = 52,
56fb81684fSAxel Dörfler 	OPTION_MESSAGE_TYPE = 53,
57fb81684fSAxel Dörfler 	OPTION_SERVER_ADDRESS = 54,
58fb81684fSAxel Dörfler 	OPTION_REQUEST_PARAMETERS = 55,
59fb81684fSAxel Dörfler 	OPTION_ERROR_MESSAGE = 56,
60fb81684fSAxel Dörfler 	OPTION_MESSAGE_SIZE = 57,
61fb81684fSAxel Dörfler 	OPTION_RENEWAL_TIME = 58,
62fb81684fSAxel Dörfler 	OPTION_REBINDING_TIME = 59,
63fb81684fSAxel Dörfler 	OPTION_CLASS_IDENTIFIER = 60,
64fb81684fSAxel Dörfler 	OPTION_CLIENT_IDENTIFIER = 61,
65fb81684fSAxel Dörfler };
66fb81684fSAxel Dörfler 
67fb81684fSAxel Dörfler enum message_type {
68f9af6566SAxel Dörfler 	DHCP_NONE = 0,
69f9af6566SAxel Dörfler 	DHCP_DISCOVER,
70fb81684fSAxel Dörfler 	DHCP_OFFER,
71fb81684fSAxel Dörfler 	DHCP_REQUEST,
72fb81684fSAxel Dörfler 	DHCP_DECLINE,
73fb81684fSAxel Dörfler 	DHCP_ACK,
74f9af6566SAxel Dörfler 	DHCP_NACK,
75fb81684fSAxel Dörfler 	DHCP_RELEASE,
76fb81684fSAxel Dörfler 	DHCP_INFORM
77fb81684fSAxel Dörfler };
78fb81684fSAxel Dörfler 
79fb81684fSAxel Dörfler struct dhcp_option_cookie {
80fb81684fSAxel Dörfler 	dhcp_option_cookie() : state(0), file_has_options(false), server_name_has_options(false) {}
81fb81684fSAxel Dörfler 
82fb81684fSAxel Dörfler 	const uint8* next;
83fb81684fSAxel Dörfler 	uint8	state;
84fb81684fSAxel Dörfler 	bool	file_has_options;
85fb81684fSAxel Dörfler 	bool	server_name_has_options;
86fb81684fSAxel Dörfler };
87fb81684fSAxel Dörfler 
88fb81684fSAxel Dörfler struct dhcp_message {
89fb81684fSAxel Dörfler 	dhcp_message(message_type type);
90fb81684fSAxel Dörfler 
91fb81684fSAxel Dörfler 	uint8		opcode;
92fb81684fSAxel Dörfler 	uint8		hardware_type;
93fb81684fSAxel Dörfler 	uint8		hardware_address_length;
94fb81684fSAxel Dörfler 	uint8		hop_count;
95fb81684fSAxel Dörfler 	uint32		transaction_id;
96*46ff5400SAxel Dörfler 	uint16		seconds_since_start;
97fb81684fSAxel Dörfler 	uint16		flags;
98fb81684fSAxel Dörfler 	in_addr_t	client_address;
99fb81684fSAxel Dörfler 	in_addr_t	your_address;
100fb81684fSAxel Dörfler 	in_addr_t	server_address;
101fb81684fSAxel Dörfler 	in_addr_t	gateway_address;
102fb81684fSAxel Dörfler 	uint8		mac_address[16];
103fb81684fSAxel Dörfler 	uint8		server_name[64];
104fb81684fSAxel Dörfler 	uint8		file[128];
105fb81684fSAxel Dörfler 	uint32		options_magic;
106fb81684fSAxel Dörfler 	uint8		options[1260];
107fb81684fSAxel Dörfler 
108fb81684fSAxel Dörfler 	size_t MinSize() const { return 576; }
109fb81684fSAxel Dörfler 	size_t Size() const;
110fb81684fSAxel Dörfler 
111fb81684fSAxel Dörfler 	bool HasOptions() const;
112fb81684fSAxel Dörfler 	bool NextOption(dhcp_option_cookie& cookie, message_option& option,
113fb81684fSAxel Dörfler 		const uint8*& data, size_t& size) const;
114f9af6566SAxel Dörfler 	message_type Type() const;
115fb81684fSAxel Dörfler 	const uint8* LastOption() const;
116fb81684fSAxel Dörfler 
117fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option);
118fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option, uint8 data);
119fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option, uint16 data);
120fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option, uint32 data);
121fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option, uint8* data, uint32 size);
122fb81684fSAxel Dörfler } _PACKED;
123fb81684fSAxel Dörfler 
1240cf5e6acSAxel Dörfler #define DHCP_FLAG_BROADCAST		0x8000
125fb81684fSAxel Dörfler 
126fb81684fSAxel Dörfler #define ARP_HARDWARE_TYPE_ETHER	1
127fb81684fSAxel Dörfler 
1286cc7630fSAxel Dörfler const uint32 kMsgLeaseTime = 'lstm';
1296cc7630fSAxel Dörfler 
130fb81684fSAxel Dörfler 
131fb81684fSAxel Dörfler dhcp_message::dhcp_message(message_type type)
132fb81684fSAxel Dörfler {
133fb81684fSAxel Dörfler 	memset(this, 0, sizeof(*this));
134fb81684fSAxel Dörfler 	options_magic = htonl(OPTION_MAGIC);
135fb81684fSAxel Dörfler 
136fb81684fSAxel Dörfler 	uint8* next = options;
137fb81684fSAxel Dörfler 	next = PutOption(next, OPTION_MESSAGE_TYPE, (uint8)type);
1380cf5e6acSAxel Dörfler 	next = PutOption(next, OPTION_MESSAGE_SIZE, (uint16)htons(sizeof(dhcp_message)));
139fb81684fSAxel Dörfler 	next = PutOption(next, OPTION_END);
140fb81684fSAxel Dörfler }
141fb81684fSAxel Dörfler 
142fb81684fSAxel Dörfler 
143fb81684fSAxel Dörfler bool
144fb81684fSAxel Dörfler dhcp_message::HasOptions() const
145fb81684fSAxel Dörfler {
146fb81684fSAxel Dörfler 	return options_magic == htonl(OPTION_MAGIC);
147fb81684fSAxel Dörfler }
148fb81684fSAxel Dörfler 
149fb81684fSAxel Dörfler 
150fb81684fSAxel Dörfler bool
151fb81684fSAxel Dörfler dhcp_message::NextOption(dhcp_option_cookie& cookie,
152fb81684fSAxel Dörfler 	message_option& option, const uint8*& data, size_t& size) const
153fb81684fSAxel Dörfler {
154fb81684fSAxel Dörfler 	if (cookie.state == 0) {
155fb81684fSAxel Dörfler 		if (!HasOptions())
156fb81684fSAxel Dörfler 			return false;
157fb81684fSAxel Dörfler 
158fb81684fSAxel Dörfler 		cookie.state++;
159fb81684fSAxel Dörfler 		cookie.next = options;
160fb81684fSAxel Dörfler 	}
161fb81684fSAxel Dörfler 
162fb81684fSAxel Dörfler 	uint32 bytesLeft = 0;
163fb81684fSAxel Dörfler 
164fb81684fSAxel Dörfler 	switch (cookie.state) {
165fb81684fSAxel Dörfler 		case 1:
166fb81684fSAxel Dörfler 			// options from "options"
167fb81684fSAxel Dörfler 			bytesLeft = sizeof(options) + cookie.next - options;
168fb81684fSAxel Dörfler 			break;
169fb81684fSAxel Dörfler 
170fb81684fSAxel Dörfler 		case 2:
171fb81684fSAxel Dörfler 			// options from "file"
172fb81684fSAxel Dörfler 			bytesLeft = sizeof(options) + cookie.next - options;
173fb81684fSAxel Dörfler 			break;
174fb81684fSAxel Dörfler 
175fb81684fSAxel Dörfler 		case 3:
176fb81684fSAxel Dörfler 			// options from "server_name"
177fb81684fSAxel Dörfler 			bytesLeft = sizeof(options) + cookie.next - options;
178fb81684fSAxel Dörfler 			break;
179fb81684fSAxel Dörfler 	}
180fb81684fSAxel Dörfler 
181fb81684fSAxel Dörfler 	while (true) {
182fb81684fSAxel Dörfler 		if (bytesLeft == 0) {
183fb81684fSAxel Dörfler 			// TODO: suppport OPTION_OVERLOAD!
184fb81684fSAxel Dörfler 			cookie.state = 4;
185fb81684fSAxel Dörfler 			return false;
186fb81684fSAxel Dörfler 		}
187fb81684fSAxel Dörfler 
188fb81684fSAxel Dörfler 		option = (message_option)cookie.next[0];
189fb81684fSAxel Dörfler 		if (option == OPTION_END) {
190fb81684fSAxel Dörfler 			cookie.state = 4;
191fb81684fSAxel Dörfler 			return false;
192fb81684fSAxel Dörfler 		} else if (option == OPTION_PAD) {
193fb81684fSAxel Dörfler 			bytesLeft--;
194fb81684fSAxel Dörfler 			cookie.next++;
195fb81684fSAxel Dörfler 			continue;
196fb81684fSAxel Dörfler 		}
197fb81684fSAxel Dörfler 
198fb81684fSAxel Dörfler 		size = cookie.next[1];
199fb81684fSAxel Dörfler 		data = &cookie.next[2];
200fb81684fSAxel Dörfler 		cookie.next += 2 + size;
201fb81684fSAxel Dörfler 
202fb81684fSAxel Dörfler 		if (option == OPTION_OVERLOAD) {
203fb81684fSAxel Dörfler 			cookie.file_has_options = data[0] & 1;
204fb81684fSAxel Dörfler 			cookie.server_name_has_options = data[0] & 2;
205fb81684fSAxel Dörfler 			continue;
206fb81684fSAxel Dörfler 		}
207fb81684fSAxel Dörfler 
208fb81684fSAxel Dörfler 		return true;
209fb81684fSAxel Dörfler 	}
210fb81684fSAxel Dörfler }
211fb81684fSAxel Dörfler 
212fb81684fSAxel Dörfler 
213f9af6566SAxel Dörfler message_type
214f9af6566SAxel Dörfler dhcp_message::Type() const
215f9af6566SAxel Dörfler {
216f9af6566SAxel Dörfler 	dhcp_option_cookie cookie;
217f9af6566SAxel Dörfler 	message_option option;
218f9af6566SAxel Dörfler 	const uint8* data;
219f9af6566SAxel Dörfler 	size_t size;
220f9af6566SAxel Dörfler 	while (NextOption(cookie, option, data, size)) {
221f9af6566SAxel Dörfler 		// iterate through all options
222f9af6566SAxel Dörfler 		if (option == OPTION_MESSAGE_TYPE)
223f9af6566SAxel Dörfler 			return (message_type)data[0];
224f9af6566SAxel Dörfler 	}
225f9af6566SAxel Dörfler 
226f9af6566SAxel Dörfler 	return DHCP_NONE;
227f9af6566SAxel Dörfler }
228f9af6566SAxel Dörfler 
229f9af6566SAxel Dörfler 
230fb81684fSAxel Dörfler const uint8*
231fb81684fSAxel Dörfler dhcp_message::LastOption() const
232fb81684fSAxel Dörfler {
233fb81684fSAxel Dörfler 	dhcp_option_cookie cookie;
234fb81684fSAxel Dörfler 	message_option option;
235fb81684fSAxel Dörfler 	const uint8* data;
236fb81684fSAxel Dörfler 	size_t size;
237fb81684fSAxel Dörfler 	while (NextOption(cookie, option, data, size)) {
238fb81684fSAxel Dörfler 		// iterate through all options
239fb81684fSAxel Dörfler 	}
240fb81684fSAxel Dörfler 
241fb81684fSAxel Dörfler 	return cookie.next;
242fb81684fSAxel Dörfler }
243fb81684fSAxel Dörfler 
244fb81684fSAxel Dörfler 
245fb81684fSAxel Dörfler size_t
246fb81684fSAxel Dörfler dhcp_message::Size() const
247fb81684fSAxel Dörfler {
248fb81684fSAxel Dörfler 	const uint8* last = LastOption();
249fb81684fSAxel Dörfler 	return sizeof(dhcp_message) - sizeof(options) + last + 1 - options;
250fb81684fSAxel Dörfler }
251fb81684fSAxel Dörfler 
252fb81684fSAxel Dörfler 
253fb81684fSAxel Dörfler uint8*
254fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option)
255fb81684fSAxel Dörfler {
256fb81684fSAxel Dörfler 	options[0] = option;
257fb81684fSAxel Dörfler 	return options + 1;
258fb81684fSAxel Dörfler }
259fb81684fSAxel Dörfler 
260fb81684fSAxel Dörfler 
261fb81684fSAxel Dörfler uint8*
262fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8 data)
263fb81684fSAxel Dörfler {
264fb81684fSAxel Dörfler 	return PutOption(options, option, &data, 1);
265fb81684fSAxel Dörfler }
266fb81684fSAxel Dörfler 
267fb81684fSAxel Dörfler 
268fb81684fSAxel Dörfler uint8*
269fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint16 data)
270fb81684fSAxel Dörfler {
271fb81684fSAxel Dörfler 	return PutOption(options, option, (uint8*)&data, sizeof(data));
272fb81684fSAxel Dörfler }
273fb81684fSAxel Dörfler 
274fb81684fSAxel Dörfler 
275fb81684fSAxel Dörfler uint8*
276fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint32 data)
277fb81684fSAxel Dörfler {
278fb81684fSAxel Dörfler 	return PutOption(options, option, (uint8*)&data, sizeof(data));
279fb81684fSAxel Dörfler }
280fb81684fSAxel Dörfler 
281fb81684fSAxel Dörfler 
282fb81684fSAxel Dörfler uint8*
283fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8* data, uint32 size)
284fb81684fSAxel Dörfler {
285fb81684fSAxel Dörfler 	options[0] = option;
286fb81684fSAxel Dörfler 	options[1] = size;
287fb81684fSAxel Dörfler 	memcpy(&options[2], data, size);
288fb81684fSAxel Dörfler 
289fb81684fSAxel Dörfler 	return options + 2 + size;
290fb81684fSAxel Dörfler }
291fb81684fSAxel Dörfler 
292fb81684fSAxel Dörfler 
293fb81684fSAxel Dörfler //	#pragma mark -
294fb81684fSAxel Dörfler 
295fb81684fSAxel Dörfler 
296f9af6566SAxel Dörfler DHCPClient::DHCPClient(BMessenger target, const char* device)
297fb81684fSAxel Dörfler 	: BHandler("dhcp"),
2986cc7630fSAxel Dörfler 	fTarget(target),
29910cc12daSAxel Dörfler 	fDevice(device),
3006cc7630fSAxel Dörfler 	fConfiguration(kMsgConfigureInterface),
3016cc7630fSAxel Dörfler 	fRunner(NULL),
3026cc7630fSAxel Dörfler 	fLeaseTime(0)
303fb81684fSAxel Dörfler {
304*46ff5400SAxel Dörfler 	fStartTime = system_time();
305*46ff5400SAxel Dörfler 	fTransactionID = (uint32)fStartTime;
306fb81684fSAxel Dörfler 
3070ce7725eSAxel Dörfler 	fStatus = get_mac_address(device, fMAC);
308fb81684fSAxel Dörfler 	if (fStatus < B_OK)
309fb81684fSAxel Dörfler 		return;
310fb81684fSAxel Dörfler 
3116cc7630fSAxel Dörfler 	memset(&fServer, 0, sizeof(struct sockaddr_in));
3126cc7630fSAxel Dörfler 	fServer.sin_family = AF_INET;
3136cc7630fSAxel Dörfler 	fServer.sin_len = sizeof(struct sockaddr_in);
3146cc7630fSAxel Dörfler 	fServer.sin_port = htons(DHCP_SERVER_PORT);
3156cc7630fSAxel Dörfler }
3166cc7630fSAxel Dörfler 
3176cc7630fSAxel Dörfler 
3186cc7630fSAxel Dörfler DHCPClient::~DHCPClient()
3196cc7630fSAxel Dörfler {
3206cc7630fSAxel Dörfler 	if (fStatus != B_OK)
3216cc7630fSAxel Dörfler 		return;
3226cc7630fSAxel Dörfler 
3236cc7630fSAxel Dörfler 	delete fRunner;
3240ce7725eSAxel Dörfler 
325fb81684fSAxel Dörfler 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
3266cc7630fSAxel Dörfler 	if (socket < 0)
327fb81684fSAxel Dörfler 		return;
3286cc7630fSAxel Dörfler 
3296cc7630fSAxel Dörfler 	// release lease
3306cc7630fSAxel Dörfler 
3316cc7630fSAxel Dörfler 	dhcp_message release(DHCP_RELEASE);
332*46ff5400SAxel Dörfler 	_PrepareMessage(release, BOUND);
3336cc7630fSAxel Dörfler 
3346cc7630fSAxel Dörfler 	_SendMessage(socket, release, fServer);
3356cc7630fSAxel Dörfler 	close(socket);
336fb81684fSAxel Dörfler }
337fb81684fSAxel Dörfler 
3386cc7630fSAxel Dörfler 
3396cc7630fSAxel Dörfler status_t
3406cc7630fSAxel Dörfler DHCPClient::Initialize()
3416cc7630fSAxel Dörfler {
3426cc7630fSAxel Dörfler 	fStatus = _Negotiate(INIT);
3436cc7630fSAxel Dörfler 	printf("DHCP for %s, status: %s\n", fDevice.String(), strerror(fStatus));
3446cc7630fSAxel Dörfler 	return fStatus;
3456cc7630fSAxel Dörfler }
3466cc7630fSAxel Dörfler 
3476cc7630fSAxel Dörfler 
3486cc7630fSAxel Dörfler status_t
3496cc7630fSAxel Dörfler DHCPClient::_Negotiate(dhcp_state state)
3506cc7630fSAxel Dörfler {
3516cc7630fSAxel Dörfler 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
3526cc7630fSAxel Dörfler 	if (socket < 0)
3536cc7630fSAxel Dörfler 		return errno;
3546cc7630fSAxel Dörfler 
355fb81684fSAxel Dörfler 	sockaddr_in local;
356fb81684fSAxel Dörfler 	memset(&local, 0, sizeof(struct sockaddr_in));
357fb81684fSAxel Dörfler 	local.sin_family = AF_INET;
358fb81684fSAxel Dörfler 	local.sin_len = sizeof(struct sockaddr_in);
359fb81684fSAxel Dörfler 	local.sin_port = htons(DHCP_CLIENT_PORT);
360fb81684fSAxel Dörfler 	local.sin_addr.s_addr = INADDR_ANY;
361fb81684fSAxel Dörfler 
362fb81684fSAxel Dörfler 	if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
363fb81684fSAxel Dörfler 		close(socket);
3646cc7630fSAxel Dörfler 		return errno;
365fb81684fSAxel Dörfler 	}
366fb81684fSAxel Dörfler 
367fb81684fSAxel Dörfler 	sockaddr_in broadcast;
368fb81684fSAxel Dörfler 	memset(&broadcast, 0, sizeof(struct sockaddr_in));
369fb81684fSAxel Dörfler 	broadcast.sin_family = AF_INET;
370fb81684fSAxel Dörfler 	broadcast.sin_len = sizeof(struct sockaddr_in);
371fb81684fSAxel Dörfler 	broadcast.sin_port = htons(DHCP_SERVER_PORT);
372fb81684fSAxel Dörfler 	broadcast.sin_addr.s_addr = INADDR_BROADCAST;
373fb81684fSAxel Dörfler 
374fb81684fSAxel Dörfler 	int option = 1;
375fb81684fSAxel Dörfler 	setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
376fb81684fSAxel Dörfler 
3776cc7630fSAxel Dörfler 	bigtime_t previousLeaseTime = fLeaseTime;
3786cc7630fSAxel Dörfler 	fLeaseTime = 0;
379*46ff5400SAxel Dörfler 	fRenewalTime = 0;
380*46ff5400SAxel Dörfler 	fRebindingTime = 0;
381fb81684fSAxel Dörfler 
3826cc7630fSAxel Dörfler 	status_t status = B_ERROR;
3836cc7630fSAxel Dörfler 	time_t timeout;
3846cc7630fSAxel Dörfler 	uint32 tries;
3856cc7630fSAxel Dörfler 	_ResetTimeout(socket, timeout, tries);
3866cc7630fSAxel Dörfler 
3876cc7630fSAxel Dörfler 	dhcp_message discover(DHCP_DISCOVER);
388*46ff5400SAxel Dörfler 	_PrepareMessage(discover, state);
3896cc7630fSAxel Dörfler 
3906cc7630fSAxel Dörfler 	dhcp_message request(DHCP_REQUEST);
391*46ff5400SAxel Dörfler 	_PrepareMessage(request, state);
3926cc7630fSAxel Dörfler 
393*46ff5400SAxel Dörfler 	// send discover/request message
3946cc7630fSAxel Dörfler 	status = _SendMessage(socket, state == INIT ? discover : request,
395*46ff5400SAxel Dörfler 		state != RENEWAL ? broadcast : fServer);
3966cc7630fSAxel Dörfler 	if (status < B_OK) {
397fb81684fSAxel Dörfler 		close(socket);
3986cc7630fSAxel Dörfler 		return status;
3996cc7630fSAxel Dörfler 	}
400fb81684fSAxel Dörfler 
401f9af6566SAxel Dörfler 	// receive loop until we've got an offer and acknowledged it
402f9af6566SAxel Dörfler 
403f9af6566SAxel Dörfler 	while (state != ACKNOWLEDGED) {
404f9af6566SAxel Dörfler 		char buffer[2048];
405f9af6566SAxel Dörfler 		ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer),
406f9af6566SAxel Dörfler 			0, NULL, NULL);
4076cc7630fSAxel Dörfler printf("recvfrom returned: %ld, %s\n", bytesReceived, strerror(errno));
408f9af6566SAxel Dörfler 		if (bytesReceived == B_TIMED_OUT) {
409f9af6566SAxel Dörfler 			// depending on the state, we'll just try again
4106cc7630fSAxel Dörfler 			if (!_TimeoutShift(socket, timeout, tries)) {
4116cc7630fSAxel Dörfler 				close(socket);
4126cc7630fSAxel Dörfler 				return B_TIMED_OUT;
413f9af6566SAxel Dörfler 			}
414f9af6566SAxel Dörfler 
415f9af6566SAxel Dörfler 			if (state == INIT)
4166cc7630fSAxel Dörfler 				status = _SendMessage(socket, discover, broadcast);
417*46ff5400SAxel Dörfler 			else
418*46ff5400SAxel Dörfler 				status = _SendMessage(socket, request, state != RENEWAL
4196cc7630fSAxel Dörfler 					? broadcast : fServer);
420f9af6566SAxel Dörfler 
4216cc7630fSAxel Dörfler 			if (status < B_OK)
422f9af6566SAxel Dörfler 				break;
423f9af6566SAxel Dörfler 		} else if (bytesReceived < B_OK)
424f9af6566SAxel Dörfler 			break;
425f9af6566SAxel Dörfler 
426f9af6566SAxel Dörfler 		dhcp_message *message = (dhcp_message *)buffer;
427f9af6566SAxel Dörfler 		if (message->transaction_id != htonl(fTransactionID)
428f9af6566SAxel Dörfler 			|| !message->HasOptions()
429f9af6566SAxel Dörfler 			|| memcmp(message->mac_address, discover.mac_address,
430f9af6566SAxel Dörfler 				discover.hardware_address_length)) {
431f9af6566SAxel Dörfler 			// this message is not for us
432f9af6566SAxel Dörfler 			continue;
433f9af6566SAxel Dörfler 		}
434f9af6566SAxel Dörfler 
435f9af6566SAxel Dörfler 		switch (message->Type()) {
436f9af6566SAxel Dörfler 			case DHCP_NONE:
437f9af6566SAxel Dörfler 			default:
438f9af6566SAxel Dörfler 				// ignore this message
439f9af6566SAxel Dörfler 				break;
440f9af6566SAxel Dörfler 
441f9af6566SAxel Dörfler 			case DHCP_OFFER:
442f9af6566SAxel Dörfler 			{
443f9af6566SAxel Dörfler 				// first offer wins
444f9af6566SAxel Dörfler 				if (state != INIT)
445f9af6566SAxel Dörfler 					break;
446f9af6566SAxel Dörfler 
447f9af6566SAxel Dörfler 				// collect interface options
448f9af6566SAxel Dörfler 
449f9af6566SAxel Dörfler 				fAssignedAddress = message->your_address;
450f9af6566SAxel Dörfler 
45110cc12daSAxel Dörfler 				fConfiguration.MakeEmpty();
45210cc12daSAxel Dörfler 				fConfiguration.AddString("device", fDevice.String());
453f9af6566SAxel Dörfler 
454f9af6566SAxel Dörfler 				BMessage address;
455f9af6566SAxel Dörfler 				address.AddString("family", "inet");
456f9af6566SAxel Dörfler 				address.AddString("address", _ToString(fAssignedAddress));
4570ce7725eSAxel Dörfler 				_ParseOptions(*message, address);
458f9af6566SAxel Dörfler 
45910cc12daSAxel Dörfler 				fConfiguration.AddMessage("address", &address);
460f9af6566SAxel Dörfler 
46110cc12daSAxel Dörfler 				// request configuration from the server
462f9af6566SAxel Dörfler 
4636cc7630fSAxel Dörfler 				_ResetTimeout(socket, timeout, tries);
464f9af6566SAxel Dörfler 				state = REQUESTING;
465*46ff5400SAxel Dörfler 				_PrepareMessage(request, state);
466f9af6566SAxel Dörfler 
4676cc7630fSAxel Dörfler 				status = _SendMessage(socket, request, broadcast);
46810cc12daSAxel Dörfler 					// we're sending a broadcast so that all potential offers get an answer
46910cc12daSAxel Dörfler 				break;
470f9af6566SAxel Dörfler 			}
471f9af6566SAxel Dörfler 
472f9af6566SAxel Dörfler 			case DHCP_ACK:
47310cc12daSAxel Dörfler 			{
474*46ff5400SAxel Dörfler 				if (state != REQUESTING && state != REBINDING && state != RENEWAL)
475f9af6566SAxel Dörfler 					continue;
476f9af6566SAxel Dörfler 
4776cc7630fSAxel Dörfler 				// TODO: we might want to configure the stuff, don't we?
4786cc7630fSAxel Dörfler 				BMessage address;
4796cc7630fSAxel Dörfler 				_ParseOptions(*message, address);
4806cc7630fSAxel Dörfler 					// TODO: currently, only lease time and DNS is updated this way
4816cc7630fSAxel Dörfler 
482f9af6566SAxel Dörfler 				// our address request has been acknowledged
483f9af6566SAxel Dörfler 				state = ACKNOWLEDGED;
48410cc12daSAxel Dörfler 
48510cc12daSAxel Dörfler 				// configure interface
48610cc12daSAxel Dörfler 				BMessage reply;
4876cc7630fSAxel Dörfler 				fTarget.SendMessage(&fConfiguration, &reply);
48810cc12daSAxel Dörfler 
48910cc12daSAxel Dörfler 				if (reply.FindInt32("status", &fStatus) != B_OK)
4906cc7630fSAxel Dörfler 					status = B_OK;
491f9af6566SAxel Dörfler 				break;
49210cc12daSAxel Dörfler 			}
493f9af6566SAxel Dörfler 
494f9af6566SAxel Dörfler 			case DHCP_NACK:
495f9af6566SAxel Dörfler 				if (state != REQUESTING)
496f9af6566SAxel Dörfler 					continue;
497f9af6566SAxel Dörfler 
498a552ec13SAxel Dörfler 				// try again (maybe we should prefer other servers if this happens more than once)
4996cc7630fSAxel Dörfler 				status = _SendMessage(socket, discover, broadcast);
5006cc7630fSAxel Dörfler 				if (status == B_OK)
501f9af6566SAxel Dörfler 					state = INIT;
502f9af6566SAxel Dörfler 				break;
503f9af6566SAxel Dörfler 		}
504f9af6566SAxel Dörfler 	}
505f9af6566SAxel Dörfler 
506fb81684fSAxel Dörfler 	close(socket);
5076cc7630fSAxel Dörfler 
5086cc7630fSAxel Dörfler 	if (status == B_OK && fLeaseTime > 0) {
5096cc7630fSAxel Dörfler 		// notify early enough when the lease is
510*46ff5400SAxel Dörfler 		if (fRenewalTime == 0)
511*46ff5400SAxel Dörfler 			fRenewalTime = fLeaseTime * 2/3;
512*46ff5400SAxel Dörfler 		if (fRebindingTime == 0)
513*46ff5400SAxel Dörfler 			fRebindingTime = fLeaseTime * 5/6;
514*46ff5400SAxel Dörfler 
515*46ff5400SAxel Dörfler 		_RestartLease(fRenewalTime);
516*46ff5400SAxel Dörfler 
517*46ff5400SAxel Dörfler 		bigtime_t now = system_time();
518*46ff5400SAxel Dörfler 		fLeaseTime += now;
519*46ff5400SAxel Dörfler 		fRenewalTime += now;
520*46ff5400SAxel Dörfler 		fRebindingTime += now;
521*46ff5400SAxel Dörfler 			// make lease times absolute
522*46ff5400SAxel Dörfler 	} else {
5236cc7630fSAxel Dörfler 		fLeaseTime = previousLeaseTime;
524*46ff5400SAxel Dörfler 		bigtime_t now = system_time();
525*46ff5400SAxel Dörfler 		fRenewalTime = (fLeaseTime - now) * 2/3 + now;
526*46ff5400SAxel Dörfler 		fRebindingTime = (fLeaseTime - now) * 5/6 + now;
527*46ff5400SAxel Dörfler 	}
5286cc7630fSAxel Dörfler 
5296cc7630fSAxel Dörfler 	return status;
530fb81684fSAxel Dörfler }
531fb81684fSAxel Dörfler 
532fb81684fSAxel Dörfler 
5336cc7630fSAxel Dörfler void
5346cc7630fSAxel Dörfler DHCPClient::_RestartLease(bigtime_t leaseTime)
535fb81684fSAxel Dörfler {
5366cc7630fSAxel Dörfler 	if (leaseTime == 0)
537f9af6566SAxel Dörfler 		return;
538f9af6566SAxel Dörfler 
5396cc7630fSAxel Dörfler 	BMessage lease(kMsgLeaseTime);
540*46ff5400SAxel Dörfler 	fRunner = new BMessageRunner(this, &lease, leaseTime, 1);
541f9af6566SAxel Dörfler }
542f9af6566SAxel Dörfler 
543f9af6566SAxel Dörfler 
544f9af6566SAxel Dörfler void
5450ce7725eSAxel Dörfler DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address)
5460ce7725eSAxel Dörfler {
5470ce7725eSAxel Dörfler 	dhcp_option_cookie cookie;
5480ce7725eSAxel Dörfler 	message_option option;
5490ce7725eSAxel Dörfler 	const uint8* data;
5500ce7725eSAxel Dörfler 	size_t size;
5510ce7725eSAxel Dörfler 	while (message.NextOption(cookie, option, data, size)) {
5520ce7725eSAxel Dörfler 		// iterate through all options
5530ce7725eSAxel Dörfler 		switch (option) {
5540ce7725eSAxel Dörfler 			case OPTION_ROUTER_ADDRESS:
5550ce7725eSAxel Dörfler 				address.AddString("gateway", _ToString(data));
5560ce7725eSAxel Dörfler 				break;
5570ce7725eSAxel Dörfler 			case OPTION_SUBNET_MASK:
5580ce7725eSAxel Dörfler 				address.AddString("mask", _ToString(data));
5590ce7725eSAxel Dörfler 				break;
5605782c5a3SAxel Dörfler 			case OPTION_BROADCAST_ADDRESS:
5615782c5a3SAxel Dörfler 				address.AddString("broadcast", _ToString(data));
5625782c5a3SAxel Dörfler 				break;
5630ce7725eSAxel Dörfler 			case OPTION_DOMAIN_NAME_SERVER:
564a552ec13SAxel Dörfler 			{
565a552ec13SAxel Dörfler 				// TODO: for now, we write it just out to /etc/resolv.conf
566a552ec13SAxel Dörfler 				FILE* file = fopen("/etc/resolv.conf", "w");
5670ce7725eSAxel Dörfler 				for (uint32 i = 0; i < size / 4; i++) {
5680ce7725eSAxel Dörfler 					printf("DNS: %s\n", _ToString(&data[i*4]).String());
569a552ec13SAxel Dörfler 					if (file != NULL)
570a552ec13SAxel Dörfler 						fprintf(file, "nameserver %s\n", _ToString(&data[i*4]).String());
5710ce7725eSAxel Dörfler 				}
572a552ec13SAxel Dörfler 				fclose(file);
5730ce7725eSAxel Dörfler 				break;
574a552ec13SAxel Dörfler 			}
5750ce7725eSAxel Dörfler 			case OPTION_SERVER_ADDRESS:
5760ce7725eSAxel Dörfler 				fServer.sin_addr.s_addr = *(in_addr_t*)data;
5770ce7725eSAxel Dörfler 				break;
578*46ff5400SAxel Dörfler 
5790ce7725eSAxel Dörfler 			case OPTION_ADDRESS_LEASE_TIME:
5800ce7725eSAxel Dörfler 				printf("lease time of %lu seconds\n", htonl(*(uint32*)data));
5816cc7630fSAxel Dörfler 				fLeaseTime = htonl(*(uint32*)data) * 1000000LL;
5820ce7725eSAxel Dörfler 				break;
5831a4e8e7bSAxel Dörfler 			case OPTION_RENEWAL_TIME:
584*46ff5400SAxel Dörfler 				printf("renewal time of %lu seconds\n",
585*46ff5400SAxel Dörfler 					htonl(*(uint32*)data));
586*46ff5400SAxel Dörfler 				fRenewalTime = htonl(*(uint32*)data) * 1000000LL;
587*46ff5400SAxel Dörfler 				break;
5881a4e8e7bSAxel Dörfler 			case OPTION_REBINDING_TIME:
589*46ff5400SAxel Dörfler 				printf("rebinding time of %lu seconds\n",
590*46ff5400SAxel Dörfler 					htonl(*(uint32*)data));
591*46ff5400SAxel Dörfler 				fRebindingTime = htonl(*(uint32*)data) * 1000000LL;
5921a4e8e7bSAxel Dörfler 				break;
5931a4e8e7bSAxel Dörfler 
5940ce7725eSAxel Dörfler 			case OPTION_HOST_NAME:
5955782c5a3SAxel Dörfler 			{
5960ce7725eSAxel Dörfler 				char name[256];
5970ce7725eSAxel Dörfler 				memcpy(name, data, size);
5980ce7725eSAxel Dörfler 				name[size] = '\0';
5990ce7725eSAxel Dörfler 				printf("DHCP host name: \"%s\"\n", name);
6000ce7725eSAxel Dörfler 				break;
6015782c5a3SAxel Dörfler 			}
6025782c5a3SAxel Dörfler 
6035782c5a3SAxel Dörfler 			case OPTION_DOMAIN_NAME:
6045782c5a3SAxel Dörfler 			{
6055782c5a3SAxel Dörfler 				char name[256];
6065782c5a3SAxel Dörfler 				memcpy(name, data, size);
6075782c5a3SAxel Dörfler 				name[size] = '\0';
6085782c5a3SAxel Dörfler 				printf("DHCP domain name: \"%s\"\n", name);
6095782c5a3SAxel Dörfler 				break;
6105782c5a3SAxel Dörfler 			}
6110ce7725eSAxel Dörfler 
6120ce7725eSAxel Dörfler 			case OPTION_MESSAGE_TYPE:
6130ce7725eSAxel Dörfler 				break;
6140ce7725eSAxel Dörfler 
6150ce7725eSAxel Dörfler 			default:
6160ce7725eSAxel Dörfler 				printf("unknown option %lu\n", (uint32)option);
6170ce7725eSAxel Dörfler 				break;
6180ce7725eSAxel Dörfler 		}
6190ce7725eSAxel Dörfler 	}
6200ce7725eSAxel Dörfler }
6210ce7725eSAxel Dörfler 
6220ce7725eSAxel Dörfler 
6230ce7725eSAxel Dörfler void
624*46ff5400SAxel Dörfler DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state)
6250ce7725eSAxel Dörfler {
6260ce7725eSAxel Dörfler 	message.opcode = BOOT_REQUEST;
6270ce7725eSAxel Dörfler 	message.hardware_type = ARP_HARDWARE_TYPE_ETHER;
6280ce7725eSAxel Dörfler 	message.hardware_address_length = 6;
6290ce7725eSAxel Dörfler 	message.transaction_id = htonl(fTransactionID);
630*46ff5400SAxel Dörfler 	message.seconds_since_start = htons(min_c((fStartTime - system_time()) / 1000000LL, 65535));
6310ce7725eSAxel Dörfler 	memcpy(message.mac_address, fMAC, 6);
6320ce7725eSAxel Dörfler 
633*46ff5400SAxel Dörfler 	message_type type = message.Type();
634*46ff5400SAxel Dörfler 
635*46ff5400SAxel Dörfler 	switch (type) {
6360ce7725eSAxel Dörfler 		case DHCP_REQUEST:
6370ce7725eSAxel Dörfler 		case DHCP_RELEASE:
6380ce7725eSAxel Dörfler 		{
6390ce7725eSAxel Dörfler 			// add server identifier option
6400ce7725eSAxel Dörfler 			uint8* next = message.options;
6410ce7725eSAxel Dörfler 			next = message.PutOption(next, OPTION_MESSAGE_TYPE, (uint8)DHCP_REQUEST);
6420ce7725eSAxel Dörfler 			next = message.PutOption(next, OPTION_MESSAGE_SIZE,
6430cf5e6acSAxel Dörfler 				(uint16)htons(sizeof(dhcp_message)));
6440ce7725eSAxel Dörfler 			next = message.PutOption(next, OPTION_SERVER_ADDRESS,
6450ce7725eSAxel Dörfler 				(uint32)fServer.sin_addr.s_addr);
646*46ff5400SAxel Dörfler 
647*46ff5400SAxel Dörfler 			// In RENEWAL or REBINDING state, we must set the client_address field, and not
648*46ff5400SAxel Dörfler 			// use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages
649*46ff5400SAxel Dörfler 			if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING))
6500ce7725eSAxel Dörfler 				next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, fAssignedAddress);
651*46ff5400SAxel Dörfler 			else
652*46ff5400SAxel Dörfler 				message.client_address = fAssignedAddress;
653*46ff5400SAxel Dörfler 
6540ce7725eSAxel Dörfler 			next = message.PutOption(next, OPTION_END);
6550ce7725eSAxel Dörfler 			break;
6560ce7725eSAxel Dörfler 		}
6570ce7725eSAxel Dörfler 
6580ce7725eSAxel Dörfler 		default:
6590ce7725eSAxel Dörfler 			// the default options are fine
6600ce7725eSAxel Dörfler 			break;
6610ce7725eSAxel Dörfler 	}
6620ce7725eSAxel Dörfler }
6630ce7725eSAxel Dörfler 
6640ce7725eSAxel Dörfler 
6650ce7725eSAxel Dörfler void
6666cc7630fSAxel Dörfler DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries)
667f9af6566SAxel Dörfler {
6686cc7630fSAxel Dörfler 	timeout = DEFAULT_TIMEOUT;
6696cc7630fSAxel Dörfler 	tries = 0;
670f9af6566SAxel Dörfler 
671f9af6566SAxel Dörfler 	struct timeval value;
6726cc7630fSAxel Dörfler 	value.tv_sec = timeout;
673f9af6566SAxel Dörfler 	value.tv_usec = 0;
674f9af6566SAxel Dörfler 	setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value));
675f9af6566SAxel Dörfler }
676f9af6566SAxel Dörfler 
677f9af6566SAxel Dörfler 
678f9af6566SAxel Dörfler bool
6796cc7630fSAxel Dörfler DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries)
680f9af6566SAxel Dörfler {
6816cc7630fSAxel Dörfler 	timeout += timeout;
6826cc7630fSAxel Dörfler 	if (timeout > MAX_TIMEOUT) {
6836cc7630fSAxel Dörfler 		timeout = DEFAULT_TIMEOUT;
684f9af6566SAxel Dörfler 
6856cc7630fSAxel Dörfler 		if (++tries > 2)
686f9af6566SAxel Dörfler 			return false;
687f9af6566SAxel Dörfler 	}
6886cc7630fSAxel Dörfler 	printf("DHCP timeout shift: %lu secs (try %lu)\n", timeout, tries);
689f9af6566SAxel Dörfler 
690f9af6566SAxel Dörfler 	struct timeval value;
6916cc7630fSAxel Dörfler 	value.tv_sec = timeout;
692f9af6566SAxel Dörfler 	value.tv_usec = 0;
693f9af6566SAxel Dörfler 	setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value));
694f9af6566SAxel Dörfler 
695f9af6566SAxel Dörfler 	return true;
696f9af6566SAxel Dörfler }
697f9af6566SAxel Dörfler 
698f9af6566SAxel Dörfler 
699f9af6566SAxel Dörfler BString
700f9af6566SAxel Dörfler DHCPClient::_ToString(const uint8* data) const
701f9af6566SAxel Dörfler {
702f9af6566SAxel Dörfler 	BString target = inet_ntoa(*(in_addr*)data);
703f9af6566SAxel Dörfler 	return target;
704f9af6566SAxel Dörfler }
705f9af6566SAxel Dörfler 
706f9af6566SAxel Dörfler 
707f9af6566SAxel Dörfler BString
708f9af6566SAxel Dörfler DHCPClient::_ToString(in_addr_t address) const
709f9af6566SAxel Dörfler {
710f9af6566SAxel Dörfler 	BString target = inet_ntoa(*(in_addr*)&address);
711f9af6566SAxel Dörfler 	return target;
712f9af6566SAxel Dörfler }
713f9af6566SAxel Dörfler 
714f9af6566SAxel Dörfler 
715f9af6566SAxel Dörfler status_t
716f9af6566SAxel Dörfler DHCPClient::_SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const
717f9af6566SAxel Dörfler {
718f9af6566SAxel Dörfler 	ssize_t bytesSent = sendto(socket, &message, message.Size(),
719f9af6566SAxel Dörfler 		address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0,
720f9af6566SAxel Dörfler 		(struct sockaddr*)&address, sizeof(sockaddr_in));
721f9af6566SAxel Dörfler 	if (bytesSent < 0)
722f9af6566SAxel Dörfler 		return errno;
723f9af6566SAxel Dörfler 
724f9af6566SAxel Dörfler 	return B_OK;
725fb81684fSAxel Dörfler }
726fb81684fSAxel Dörfler 
727fb81684fSAxel Dörfler 
728*46ff5400SAxel Dörfler dhcp_state
729*46ff5400SAxel Dörfler DHCPClient::_CurrentState() const
730*46ff5400SAxel Dörfler {
731*46ff5400SAxel Dörfler 	bigtime_t now = system_time();
732*46ff5400SAxel Dörfler 
733*46ff5400SAxel Dörfler 	if (now > fLeaseTime || fStatus < B_OK)
734*46ff5400SAxel Dörfler 		return INIT;
735*46ff5400SAxel Dörfler 	if (now >= fRebindingTime)
736*46ff5400SAxel Dörfler 		return REBINDING;
737*46ff5400SAxel Dörfler 	if (now >= fRenewalTime)
738*46ff5400SAxel Dörfler 		return RENEWAL;
739*46ff5400SAxel Dörfler 
740*46ff5400SAxel Dörfler 	return BOUND;
741*46ff5400SAxel Dörfler }
742*46ff5400SAxel Dörfler 
743*46ff5400SAxel Dörfler 
744fb81684fSAxel Dörfler void
745fb81684fSAxel Dörfler DHCPClient::MessageReceived(BMessage* message)
746fb81684fSAxel Dörfler {
7476cc7630fSAxel Dörfler 	switch (message->what) {
7486cc7630fSAxel Dörfler 		case kMsgLeaseTime:
749*46ff5400SAxel Dörfler 		{
750*46ff5400SAxel Dörfler 			dhcp_state state = _CurrentState();
751*46ff5400SAxel Dörfler 
752*46ff5400SAxel Dörfler 			bigtime_t next;
753*46ff5400SAxel Dörfler 			if (_Negotiate(state) == B_OK) {
754*46ff5400SAxel Dörfler 				switch (state) {
755*46ff5400SAxel Dörfler 					case RENEWAL:
756*46ff5400SAxel Dörfler 						next = fRebindingTime;
7576cc7630fSAxel Dörfler 						break;
758*46ff5400SAxel Dörfler 					case REBINDING:
759*46ff5400SAxel Dörfler 					default:
760*46ff5400SAxel Dörfler 						next = fRenewalTime;
761*46ff5400SAxel Dörfler 						break;
762*46ff5400SAxel Dörfler 				}
763*46ff5400SAxel Dörfler 			} else {
764*46ff5400SAxel Dörfler 				switch (state) {
765*46ff5400SAxel Dörfler 					case RENEWAL:
766*46ff5400SAxel Dörfler 						next = (fLeaseTime - fRebindingTime) / 4 + system_time();
767*46ff5400SAxel Dörfler 						break;
768*46ff5400SAxel Dörfler 					case REBINDING:
769*46ff5400SAxel Dörfler 					default:
770*46ff5400SAxel Dörfler 						next = (fLeaseTime - fRenewalTime) / 4 + system_time();
771*46ff5400SAxel Dörfler 						break;
772*46ff5400SAxel Dörfler 				}
773*46ff5400SAxel Dörfler 			}
774*46ff5400SAxel Dörfler 
775*46ff5400SAxel Dörfler 			_RestartLease(next - system_time());
776*46ff5400SAxel Dörfler 			break;
777*46ff5400SAxel Dörfler 		}
7786cc7630fSAxel Dörfler 
7796cc7630fSAxel Dörfler 		default:
780fb81684fSAxel Dörfler 			BHandler::MessageReceived(message);
7816cc7630fSAxel Dörfler 			break;
7826cc7630fSAxel Dörfler 	}
783fb81684fSAxel Dörfler }
784fb81684fSAxel Dörfler 
785