xref: /haiku/src/servers/net/DHCPClient.cpp (revision bcc8dada2c41e4fc46430df2006cbf7ad667f380)
1fb81684fSAxel Dörfler /*
236bde12dSAxel Dörfler  * Copyright 2006-2008, 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>
2036bde12dSAxel Dörfler #include <sys/sockio.h>
21f9af6566SAxel Dörfler #include <sys/time.h>
22fb81684fSAxel Dörfler 
23fb81684fSAxel Dörfler 
24fb81684fSAxel Dörfler // See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options
25fb81684fSAxel Dörfler 
26fb81684fSAxel Dörfler #define DHCP_CLIENT_PORT	68
27fb81684fSAxel Dörfler #define DHCP_SERVER_PORT	67
28fb81684fSAxel Dörfler 
29f9af6566SAxel Dörfler #define DEFAULT_TIMEOUT		2	// secs
30f9af6566SAxel Dörfler #define MAX_TIMEOUT			15	// secs
31f9af6566SAxel Dörfler 
32fb81684fSAxel Dörfler enum message_opcode {
33fb81684fSAxel Dörfler 	BOOT_REQUEST = 1,
34fb81684fSAxel Dörfler 	BOOT_REPLY
35fb81684fSAxel Dörfler };
36fb81684fSAxel Dörfler 
37fb81684fSAxel Dörfler enum message_option {
38fb81684fSAxel Dörfler 	OPTION_MAGIC = 0x63825363,
39fb81684fSAxel Dörfler 
40fb81684fSAxel Dörfler 	// generic options
41fb81684fSAxel Dörfler 	OPTION_PAD = 0,
42f9af6566SAxel Dörfler 	OPTION_END = 255,
43f9af6566SAxel Dörfler 	OPTION_SUBNET_MASK = 1,
4465186fecSAxel Dörfler 	OPTION_TIME_OFFSET = 2,
45f9af6566SAxel Dörfler 	OPTION_ROUTER_ADDRESS = 3,
46f9af6566SAxel Dörfler 	OPTION_DOMAIN_NAME_SERVER = 6,
47f9af6566SAxel Dörfler 	OPTION_HOST_NAME = 12,
485782c5a3SAxel Dörfler 	OPTION_DOMAIN_NAME = 15,
49fb81684fSAxel Dörfler 	OPTION_DATAGRAM_SIZE = 22,
50fb81684fSAxel Dörfler 	OPTION_MTU = 26,
51fb81684fSAxel Dörfler 	OPTION_BROADCAST_ADDRESS = 28,
52fb81684fSAxel Dörfler 	OPTION_NETWORK_TIME_SERVERS = 42,
5365186fecSAxel Dörfler 	OPTION_NETBIOS_NAME_SERVER = 44,
5465186fecSAxel Dörfler 	OPTION_NETBIOS_SCOPE = 47,
55fb81684fSAxel Dörfler 
56fb81684fSAxel Dörfler 	// DHCP specific options
57fb81684fSAxel Dörfler 	OPTION_REQUEST_IP_ADDRESS = 50,
58fb81684fSAxel Dörfler 	OPTION_ADDRESS_LEASE_TIME = 51,
59fb81684fSAxel Dörfler 	OPTION_OVERLOAD = 52,
60fb81684fSAxel Dörfler 	OPTION_MESSAGE_TYPE = 53,
61fb81684fSAxel Dörfler 	OPTION_SERVER_ADDRESS = 54,
62fb81684fSAxel Dörfler 	OPTION_REQUEST_PARAMETERS = 55,
63fb81684fSAxel Dörfler 	OPTION_ERROR_MESSAGE = 56,
64fb81684fSAxel Dörfler 	OPTION_MESSAGE_SIZE = 57,
65fb81684fSAxel Dörfler 	OPTION_RENEWAL_TIME = 58,
66fb81684fSAxel Dörfler 	OPTION_REBINDING_TIME = 59,
67fb81684fSAxel Dörfler 	OPTION_CLASS_IDENTIFIER = 60,
68fb81684fSAxel Dörfler 	OPTION_CLIENT_IDENTIFIER = 61,
69fb81684fSAxel Dörfler };
70fb81684fSAxel Dörfler 
71fb81684fSAxel Dörfler enum message_type {
72f9af6566SAxel Dörfler 	DHCP_NONE = 0,
73f9af6566SAxel Dörfler 	DHCP_DISCOVER,
74fb81684fSAxel Dörfler 	DHCP_OFFER,
75fb81684fSAxel Dörfler 	DHCP_REQUEST,
76fb81684fSAxel Dörfler 	DHCP_DECLINE,
77fb81684fSAxel Dörfler 	DHCP_ACK,
78f9af6566SAxel Dörfler 	DHCP_NACK,
79fb81684fSAxel Dörfler 	DHCP_RELEASE,
80fb81684fSAxel Dörfler 	DHCP_INFORM
81fb81684fSAxel Dörfler };
82fb81684fSAxel Dörfler 
83fb81684fSAxel Dörfler struct dhcp_option_cookie {
8415ab0bcfSAxel Dörfler 	dhcp_option_cookie()
8515ab0bcfSAxel Dörfler 		:
8615ab0bcfSAxel Dörfler 		state(0),
8715ab0bcfSAxel Dörfler 		file_has_options(false),
8815ab0bcfSAxel Dörfler 		server_name_has_options(false)
8915ab0bcfSAxel Dörfler 	{
9015ab0bcfSAxel Dörfler 	}
91fb81684fSAxel Dörfler 
92fb81684fSAxel Dörfler 	const uint8* next;
93fb81684fSAxel Dörfler 	uint8	state;
94fb81684fSAxel Dörfler 	bool	file_has_options;
95fb81684fSAxel Dörfler 	bool	server_name_has_options;
96fb81684fSAxel Dörfler };
97fb81684fSAxel Dörfler 
98fb81684fSAxel Dörfler struct dhcp_message {
99fb81684fSAxel Dörfler 	dhcp_message(message_type type);
100fb81684fSAxel Dörfler 
101fb81684fSAxel Dörfler 	uint8		opcode;
102fb81684fSAxel Dörfler 	uint8		hardware_type;
103fb81684fSAxel Dörfler 	uint8		hardware_address_length;
104fb81684fSAxel Dörfler 	uint8		hop_count;
105fb81684fSAxel Dörfler 	uint32		transaction_id;
10646ff5400SAxel Dörfler 	uint16		seconds_since_start;
107fb81684fSAxel Dörfler 	uint16		flags;
108fb81684fSAxel Dörfler 	in_addr_t	client_address;
109fb81684fSAxel Dörfler 	in_addr_t	your_address;
110fb81684fSAxel Dörfler 	in_addr_t	server_address;
111fb81684fSAxel Dörfler 	in_addr_t	gateway_address;
112fb81684fSAxel Dörfler 	uint8		mac_address[16];
113fb81684fSAxel Dörfler 	uint8		server_name[64];
114fb81684fSAxel Dörfler 	uint8		file[128];
115fb81684fSAxel Dörfler 	uint32		options_magic;
116fb81684fSAxel Dörfler 	uint8		options[1260];
117fb81684fSAxel Dörfler 
118fb81684fSAxel Dörfler 	size_t MinSize() const { return 576; }
119fb81684fSAxel Dörfler 	size_t Size() const;
120fb81684fSAxel Dörfler 
121fb81684fSAxel Dörfler 	bool HasOptions() const;
122fb81684fSAxel Dörfler 	bool NextOption(dhcp_option_cookie& cookie, message_option& option,
123fb81684fSAxel Dörfler 		const uint8*& data, size_t& size) const;
124f9af6566SAxel Dörfler 	message_type Type() const;
125fb81684fSAxel Dörfler 	const uint8* LastOption() const;
126fb81684fSAxel Dörfler 
127a073ba1aSHugo Santos 	uint8* PrepareMessage(uint8 type);
128fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option);
129fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option, uint8 data);
130fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option, uint16 data);
131fb81684fSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option, uint32 data);
13215ab0bcfSAxel Dörfler 	uint8* PutOption(uint8* options, message_option option, const uint8* data,
13315ab0bcfSAxel Dörfler 		uint32 size);
134a073ba1aSHugo Santos 	uint8* FinishOptions(uint8 *);
135fb81684fSAxel Dörfler } _PACKED;
136fb81684fSAxel Dörfler 
1370cf5e6acSAxel Dörfler #define DHCP_FLAG_BROADCAST		0x8000
138fb81684fSAxel Dörfler 
139fb81684fSAxel Dörfler #define ARP_HARDWARE_TYPE_ETHER	1
140fb81684fSAxel Dörfler 
1416cc7630fSAxel Dörfler const uint32 kMsgLeaseTime = 'lstm';
1426cc7630fSAxel Dörfler 
1435d4d5313SHugo Santos static const uint8 kRequiredParameters[] = {
14465186fecSAxel Dörfler 	OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS,
14565186fecSAxel Dörfler 	OPTION_DOMAIN_NAME_SERVER, OPTION_BROADCAST_ADDRESS
1465d4d5313SHugo Santos };
1475d4d5313SHugo Santos 
148fb81684fSAxel Dörfler 
149fb81684fSAxel Dörfler dhcp_message::dhcp_message(message_type type)
150fb81684fSAxel Dörfler {
151fb81684fSAxel Dörfler 	memset(this, 0, sizeof(*this));
152fb81684fSAxel Dörfler 	options_magic = htonl(OPTION_MAGIC);
153fb81684fSAxel Dörfler 
154a073ba1aSHugo Santos 	uint8* next = PrepareMessage(type);
155a073ba1aSHugo Santos 	FinishOptions(next);
156fb81684fSAxel Dörfler }
157fb81684fSAxel Dörfler 
158fb81684fSAxel Dörfler 
159fb81684fSAxel Dörfler bool
160fb81684fSAxel Dörfler dhcp_message::HasOptions() const
161fb81684fSAxel Dörfler {
162fb81684fSAxel Dörfler 	return options_magic == htonl(OPTION_MAGIC);
163fb81684fSAxel Dörfler }
164fb81684fSAxel Dörfler 
165fb81684fSAxel Dörfler 
166fb81684fSAxel Dörfler bool
167fb81684fSAxel Dörfler dhcp_message::NextOption(dhcp_option_cookie& cookie,
168fb81684fSAxel Dörfler 	message_option& option, const uint8*& data, size_t& size) const
169fb81684fSAxel Dörfler {
170fb81684fSAxel Dörfler 	if (cookie.state == 0) {
171fb81684fSAxel Dörfler 		if (!HasOptions())
172fb81684fSAxel Dörfler 			return false;
173fb81684fSAxel Dörfler 
174fb81684fSAxel Dörfler 		cookie.state++;
175fb81684fSAxel Dörfler 		cookie.next = options;
176fb81684fSAxel Dörfler 	}
177fb81684fSAxel Dörfler 
178fb81684fSAxel Dörfler 	uint32 bytesLeft = 0;
179fb81684fSAxel Dörfler 
180fb81684fSAxel Dörfler 	switch (cookie.state) {
181fb81684fSAxel Dörfler 		case 1:
182fb81684fSAxel Dörfler 			// options from "options"
183fb81684fSAxel Dörfler 			bytesLeft = sizeof(options) + cookie.next - options;
184fb81684fSAxel Dörfler 			break;
185fb81684fSAxel Dörfler 
186fb81684fSAxel Dörfler 		case 2:
187fb81684fSAxel Dörfler 			// options from "file"
188fb81684fSAxel Dörfler 			bytesLeft = sizeof(options) + cookie.next - options;
189fb81684fSAxel Dörfler 			break;
190fb81684fSAxel Dörfler 
191fb81684fSAxel Dörfler 		case 3:
192fb81684fSAxel Dörfler 			// options from "server_name"
193fb81684fSAxel Dörfler 			bytesLeft = sizeof(options) + cookie.next - options;
194fb81684fSAxel Dörfler 			break;
195fb81684fSAxel Dörfler 	}
196fb81684fSAxel Dörfler 
197fb81684fSAxel Dörfler 	while (true) {
198fb81684fSAxel Dörfler 		if (bytesLeft == 0) {
199fb81684fSAxel Dörfler 			// TODO: suppport OPTION_OVERLOAD!
200fb81684fSAxel Dörfler 			cookie.state = 4;
201fb81684fSAxel Dörfler 			return false;
202fb81684fSAxel Dörfler 		}
203fb81684fSAxel Dörfler 
204fb81684fSAxel Dörfler 		option = (message_option)cookie.next[0];
205fb81684fSAxel Dörfler 		if (option == OPTION_END) {
206fb81684fSAxel Dörfler 			cookie.state = 4;
207fb81684fSAxel Dörfler 			return false;
208fb81684fSAxel Dörfler 		} else if (option == OPTION_PAD) {
209fb81684fSAxel Dörfler 			bytesLeft--;
210fb81684fSAxel Dörfler 			cookie.next++;
211fb81684fSAxel Dörfler 			continue;
212fb81684fSAxel Dörfler 		}
213fb81684fSAxel Dörfler 
214fb81684fSAxel Dörfler 		size = cookie.next[1];
215fb81684fSAxel Dörfler 		data = &cookie.next[2];
216fb81684fSAxel Dörfler 		cookie.next += 2 + size;
217fb81684fSAxel Dörfler 
218fb81684fSAxel Dörfler 		if (option == OPTION_OVERLOAD) {
219fb81684fSAxel Dörfler 			cookie.file_has_options = data[0] & 1;
220fb81684fSAxel Dörfler 			cookie.server_name_has_options = data[0] & 2;
221fb81684fSAxel Dörfler 			continue;
222fb81684fSAxel Dörfler 		}
223fb81684fSAxel Dörfler 
224fb81684fSAxel Dörfler 		return true;
225fb81684fSAxel Dörfler 	}
226fb81684fSAxel Dörfler }
227fb81684fSAxel Dörfler 
228fb81684fSAxel Dörfler 
229f9af6566SAxel Dörfler message_type
230f9af6566SAxel Dörfler dhcp_message::Type() const
231f9af6566SAxel Dörfler {
232f9af6566SAxel Dörfler 	dhcp_option_cookie cookie;
233f9af6566SAxel Dörfler 	message_option option;
234f9af6566SAxel Dörfler 	const uint8* data;
235f9af6566SAxel Dörfler 	size_t size;
236f9af6566SAxel Dörfler 	while (NextOption(cookie, option, data, size)) {
237f9af6566SAxel Dörfler 		// iterate through all options
238f9af6566SAxel Dörfler 		if (option == OPTION_MESSAGE_TYPE)
239f9af6566SAxel Dörfler 			return (message_type)data[0];
240f9af6566SAxel Dörfler 	}
241f9af6566SAxel Dörfler 
242f9af6566SAxel Dörfler 	return DHCP_NONE;
243f9af6566SAxel Dörfler }
244f9af6566SAxel Dörfler 
245f9af6566SAxel Dörfler 
246fb81684fSAxel Dörfler const uint8*
247fb81684fSAxel Dörfler dhcp_message::LastOption() const
248fb81684fSAxel Dörfler {
249fb81684fSAxel Dörfler 	dhcp_option_cookie cookie;
250fb81684fSAxel Dörfler 	message_option option;
251fb81684fSAxel Dörfler 	const uint8* data;
252fb81684fSAxel Dörfler 	size_t size;
253fb81684fSAxel Dörfler 	while (NextOption(cookie, option, data, size)) {
254fb81684fSAxel Dörfler 		// iterate through all options
255fb81684fSAxel Dörfler 	}
256fb81684fSAxel Dörfler 
257fb81684fSAxel Dörfler 	return cookie.next;
258fb81684fSAxel Dörfler }
259fb81684fSAxel Dörfler 
260fb81684fSAxel Dörfler 
261fb81684fSAxel Dörfler size_t
262fb81684fSAxel Dörfler dhcp_message::Size() const
263fb81684fSAxel Dörfler {
264fb81684fSAxel Dörfler 	const uint8* last = LastOption();
265fb81684fSAxel Dörfler 	return sizeof(dhcp_message) - sizeof(options) + last + 1 - options;
266fb81684fSAxel Dörfler }
267fb81684fSAxel Dörfler 
268fb81684fSAxel Dörfler 
269fb81684fSAxel Dörfler uint8*
270a073ba1aSHugo Santos dhcp_message::PrepareMessage(uint8 type)
271a073ba1aSHugo Santos {
272a073ba1aSHugo Santos 	uint8 *next = options;
273a073ba1aSHugo Santos 	next = PutOption(next, OPTION_MESSAGE_TYPE, type);
27415ab0bcfSAxel Dörfler 	next = PutOption(next, OPTION_MESSAGE_SIZE,
27515ab0bcfSAxel Dörfler 		(uint16)htons(sizeof(dhcp_message)));
276a073ba1aSHugo Santos 	return next;
277a073ba1aSHugo Santos }
278a073ba1aSHugo Santos 
27965186fecSAxel Dörfler 
280a073ba1aSHugo Santos uint8*
281fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option)
282fb81684fSAxel Dörfler {
283fb81684fSAxel Dörfler 	options[0] = option;
284fb81684fSAxel Dörfler 	return options + 1;
285fb81684fSAxel Dörfler }
286fb81684fSAxel Dörfler 
287fb81684fSAxel Dörfler 
288fb81684fSAxel Dörfler uint8*
289fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8 data)
290fb81684fSAxel Dörfler {
291fb81684fSAxel Dörfler 	return PutOption(options, option, &data, 1);
292fb81684fSAxel Dörfler }
293fb81684fSAxel Dörfler 
294fb81684fSAxel Dörfler 
295fb81684fSAxel Dörfler uint8*
296fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint16 data)
297fb81684fSAxel Dörfler {
298fb81684fSAxel Dörfler 	return PutOption(options, option, (uint8*)&data, sizeof(data));
299fb81684fSAxel Dörfler }
300fb81684fSAxel Dörfler 
301fb81684fSAxel Dörfler 
302fb81684fSAxel Dörfler uint8*
303fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint32 data)
304fb81684fSAxel Dörfler {
305fb81684fSAxel Dörfler 	return PutOption(options, option, (uint8*)&data, sizeof(data));
306fb81684fSAxel Dörfler }
307fb81684fSAxel Dörfler 
308fb81684fSAxel Dörfler 
309fb81684fSAxel Dörfler uint8*
31015ab0bcfSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option,
31115ab0bcfSAxel Dörfler 	const uint8* data, uint32 size)
312fb81684fSAxel Dörfler {
313fb81684fSAxel Dörfler 	options[0] = option;
314fb81684fSAxel Dörfler 	options[1] = size;
315fb81684fSAxel Dörfler 	memcpy(&options[2], data, size);
316fb81684fSAxel Dörfler 
317fb81684fSAxel Dörfler 	return options + 2 + size;
318fb81684fSAxel Dörfler }
319fb81684fSAxel Dörfler 
320fb81684fSAxel Dörfler 
321a073ba1aSHugo Santos uint8*
322a073ba1aSHugo Santos dhcp_message::FinishOptions(uint8 *next)
323a073ba1aSHugo Santos {
324a073ba1aSHugo Santos 	return PutOption(next, OPTION_END);
325a073ba1aSHugo Santos }
326a073ba1aSHugo Santos 
327a073ba1aSHugo Santos 
328fb81684fSAxel Dörfler //	#pragma mark -
329fb81684fSAxel Dörfler 
330fb81684fSAxel Dörfler 
331f9af6566SAxel Dörfler DHCPClient::DHCPClient(BMessenger target, const char* device)
332fb81684fSAxel Dörfler 	: BHandler("dhcp"),
3336cc7630fSAxel Dörfler 	fTarget(target),
33410cc12daSAxel Dörfler 	fDevice(device),
3356cc7630fSAxel Dörfler 	fConfiguration(kMsgConfigureInterface),
3366cc7630fSAxel Dörfler 	fRunner(NULL),
3376cc7630fSAxel Dörfler 	fLeaseTime(0)
338fb81684fSAxel Dörfler {
33946ff5400SAxel Dörfler 	fStartTime = system_time();
34046ff5400SAxel Dörfler 	fTransactionID = (uint32)fStartTime;
341fb81684fSAxel Dörfler 
3420ce7725eSAxel Dörfler 	fStatus = get_mac_address(device, fMAC);
343fb81684fSAxel Dörfler 	if (fStatus < B_OK)
344fb81684fSAxel Dörfler 		return;
345fb81684fSAxel Dörfler 
3466cc7630fSAxel Dörfler 	memset(&fServer, 0, sizeof(struct sockaddr_in));
3476cc7630fSAxel Dörfler 	fServer.sin_family = AF_INET;
3486cc7630fSAxel Dörfler 	fServer.sin_len = sizeof(struct sockaddr_in);
3496cc7630fSAxel Dörfler 	fServer.sin_port = htons(DHCP_SERVER_PORT);
3506cc7630fSAxel Dörfler }
3516cc7630fSAxel Dörfler 
3526cc7630fSAxel Dörfler 
3536cc7630fSAxel Dörfler DHCPClient::~DHCPClient()
3546cc7630fSAxel Dörfler {
3556cc7630fSAxel Dörfler 	if (fStatus != B_OK)
3566cc7630fSAxel Dörfler 		return;
3576cc7630fSAxel Dörfler 
3586cc7630fSAxel Dörfler 	delete fRunner;
3590ce7725eSAxel Dörfler 
360fb81684fSAxel Dörfler 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
3616cc7630fSAxel Dörfler 	if (socket < 0)
362fb81684fSAxel Dörfler 		return;
3636cc7630fSAxel Dörfler 
3646cc7630fSAxel Dörfler 	// release lease
3656cc7630fSAxel Dörfler 
3666cc7630fSAxel Dörfler 	dhcp_message release(DHCP_RELEASE);
36746ff5400SAxel Dörfler 	_PrepareMessage(release, BOUND);
3686cc7630fSAxel Dörfler 
3696cc7630fSAxel Dörfler 	_SendMessage(socket, release, fServer);
3706cc7630fSAxel Dörfler 	close(socket);
371fb81684fSAxel Dörfler }
372fb81684fSAxel Dörfler 
3736cc7630fSAxel Dörfler 
3746cc7630fSAxel Dörfler status_t
3756cc7630fSAxel Dörfler DHCPClient::Initialize()
3766cc7630fSAxel Dörfler {
3776cc7630fSAxel Dörfler 	fStatus = _Negotiate(INIT);
3786cc7630fSAxel Dörfler 	printf("DHCP for %s, status: %s\n", fDevice.String(), strerror(fStatus));
3796cc7630fSAxel Dörfler 	return fStatus;
3806cc7630fSAxel Dörfler }
3816cc7630fSAxel Dörfler 
3826cc7630fSAxel Dörfler 
3836cc7630fSAxel Dörfler status_t
3846cc7630fSAxel Dörfler DHCPClient::_Negotiate(dhcp_state state)
3856cc7630fSAxel Dörfler {
3866cc7630fSAxel Dörfler 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
3876cc7630fSAxel Dörfler 	if (socket < 0)
3886cc7630fSAxel Dörfler 		return errno;
3896cc7630fSAxel Dörfler 
390fb81684fSAxel Dörfler 	sockaddr_in local;
391fb81684fSAxel Dörfler 	memset(&local, 0, sizeof(struct sockaddr_in));
392fb81684fSAxel Dörfler 	local.sin_family = AF_INET;
393fb81684fSAxel Dörfler 	local.sin_len = sizeof(struct sockaddr_in);
394fb81684fSAxel Dörfler 	local.sin_port = htons(DHCP_CLIENT_PORT);
395fb81684fSAxel Dörfler 	local.sin_addr.s_addr = INADDR_ANY;
396fb81684fSAxel Dörfler 
397fb81684fSAxel Dörfler 	if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
398fb81684fSAxel Dörfler 		close(socket);
3996cc7630fSAxel Dörfler 		return errno;
400fb81684fSAxel Dörfler 	}
401fb81684fSAxel Dörfler 
402fb81684fSAxel Dörfler 	sockaddr_in broadcast;
403fb81684fSAxel Dörfler 	memset(&broadcast, 0, sizeof(struct sockaddr_in));
404fb81684fSAxel Dörfler 	broadcast.sin_family = AF_INET;
405fb81684fSAxel Dörfler 	broadcast.sin_len = sizeof(struct sockaddr_in);
406fb81684fSAxel Dörfler 	broadcast.sin_port = htons(DHCP_SERVER_PORT);
407fb81684fSAxel Dörfler 	broadcast.sin_addr.s_addr = INADDR_BROADCAST;
408fb81684fSAxel Dörfler 
409fb81684fSAxel Dörfler 	int option = 1;
410fb81684fSAxel Dörfler 	setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
411fb81684fSAxel Dörfler 
41236bde12dSAxel Dörfler 	if (state == INIT) {
41336bde12dSAxel Dörfler 		// The local interface does not have an address yet, bind the socket
41436bde12dSAxel Dörfler 		// to the device directly.
41536bde12dSAxel Dörfler 		int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0);
41636bde12dSAxel Dörfler 		if (linkSocket >= 0) {
41736bde12dSAxel Dörfler 			// we need to know the index of the device to be able to bind to it
41836bde12dSAxel Dörfler 			ifreq request;
41936bde12dSAxel Dörfler 			prepare_request(request, fDevice.String());
42036bde12dSAxel Dörfler 			if (ioctl(linkSocket, SIOCGIFINDEX, &request, sizeof(struct ifreq))
42136bde12dSAxel Dörfler 					== 0) {
42236bde12dSAxel Dörfler 				setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE,
42336bde12dSAxel Dörfler 					&request.ifr_index, sizeof(int));
42436bde12dSAxel Dörfler 			}
42536bde12dSAxel Dörfler 
42636bde12dSAxel Dörfler 			close(linkSocket);
42736bde12dSAxel Dörfler 		}
42836bde12dSAxel Dörfler 	}
42936bde12dSAxel Dörfler 
4306cc7630fSAxel Dörfler 	bigtime_t previousLeaseTime = fLeaseTime;
4316cc7630fSAxel Dörfler 	fLeaseTime = 0;
43246ff5400SAxel Dörfler 	fRenewalTime = 0;
43346ff5400SAxel Dörfler 	fRebindingTime = 0;
434fb81684fSAxel Dörfler 
4356cc7630fSAxel Dörfler 	status_t status = B_ERROR;
4366cc7630fSAxel Dörfler 	time_t timeout;
4376cc7630fSAxel Dörfler 	uint32 tries;
4386cc7630fSAxel Dörfler 	_ResetTimeout(socket, timeout, tries);
4396cc7630fSAxel Dörfler 
4406cc7630fSAxel Dörfler 	dhcp_message discover(DHCP_DISCOVER);
44146ff5400SAxel Dörfler 	_PrepareMessage(discover, state);
4426cc7630fSAxel Dörfler 
4436cc7630fSAxel Dörfler 	dhcp_message request(DHCP_REQUEST);
44446ff5400SAxel Dörfler 	_PrepareMessage(request, state);
4456cc7630fSAxel Dörfler 
44646ff5400SAxel Dörfler 	// send discover/request message
4476cc7630fSAxel Dörfler 	status = _SendMessage(socket, state == INIT ? discover : request,
44846ff5400SAxel Dörfler 		state != RENEWAL ? broadcast : fServer);
4496cc7630fSAxel Dörfler 	if (status < B_OK) {
450fb81684fSAxel Dörfler 		close(socket);
4516cc7630fSAxel Dörfler 		return status;
4526cc7630fSAxel Dörfler 	}
453fb81684fSAxel Dörfler 
454f9af6566SAxel Dörfler 	// receive loop until we've got an offer and acknowledged it
455f9af6566SAxel Dörfler 
456f9af6566SAxel Dörfler 	while (state != ACKNOWLEDGED) {
457f9af6566SAxel Dörfler 		char buffer[2048];
458f9af6566SAxel Dörfler 		ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer),
459f9af6566SAxel Dörfler 			0, NULL, NULL);
4604b661a95SAxel Dörfler 		if (bytesReceived < 0 && errno == B_TIMED_OUT) {
461f9af6566SAxel Dörfler 			// depending on the state, we'll just try again
4626cc7630fSAxel Dörfler 			if (!_TimeoutShift(socket, timeout, tries)) {
4636cc7630fSAxel Dörfler 				close(socket);
4646cc7630fSAxel Dörfler 				return B_TIMED_OUT;
465f9af6566SAxel Dörfler 			}
466f9af6566SAxel Dörfler 
467f9af6566SAxel Dörfler 			if (state == INIT)
4686cc7630fSAxel Dörfler 				status = _SendMessage(socket, discover, broadcast);
46915ab0bcfSAxel Dörfler 			else {
47046ff5400SAxel Dörfler 				status = _SendMessage(socket, request, state != RENEWAL
4716cc7630fSAxel Dörfler 					? broadcast : fServer);
47215ab0bcfSAxel Dörfler 			}
473f9af6566SAxel Dörfler 
4746cc7630fSAxel Dörfler 			if (status < B_OK)
475f9af6566SAxel Dörfler 				break;
476f9af6566SAxel Dörfler 		} else if (bytesReceived < B_OK)
477f9af6566SAxel Dörfler 			break;
478f9af6566SAxel Dörfler 
479f9af6566SAxel Dörfler 		dhcp_message *message = (dhcp_message *)buffer;
480f9af6566SAxel Dörfler 		if (message->transaction_id != htonl(fTransactionID)
481f9af6566SAxel Dörfler 			|| !message->HasOptions()
482f9af6566SAxel Dörfler 			|| memcmp(message->mac_address, discover.mac_address,
483f9af6566SAxel Dörfler 				discover.hardware_address_length)) {
484f9af6566SAxel Dörfler 			// this message is not for us
485f9af6566SAxel Dörfler 			continue;
486f9af6566SAxel Dörfler 		}
487f9af6566SAxel Dörfler 
488f9af6566SAxel Dörfler 		switch (message->Type()) {
489f9af6566SAxel Dörfler 			case DHCP_NONE:
490f9af6566SAxel Dörfler 			default:
491f9af6566SAxel Dörfler 				// ignore this message
492f9af6566SAxel Dörfler 				break;
493f9af6566SAxel Dörfler 
494f9af6566SAxel Dörfler 			case DHCP_OFFER:
495f9af6566SAxel Dörfler 			{
496f9af6566SAxel Dörfler 				// first offer wins
497f9af6566SAxel Dörfler 				if (state != INIT)
498f9af6566SAxel Dörfler 					break;
499f9af6566SAxel Dörfler 
500f9af6566SAxel Dörfler 				// collect interface options
501f9af6566SAxel Dörfler 
502f9af6566SAxel Dörfler 				fAssignedAddress = message->your_address;
503f9af6566SAxel Dörfler 
50410cc12daSAxel Dörfler 				fConfiguration.MakeEmpty();
50510cc12daSAxel Dörfler 				fConfiguration.AddString("device", fDevice.String());
506f01106c3SAxel Dörfler 				fConfiguration.AddBool("auto", true);
507f9af6566SAxel Dörfler 
508f9af6566SAxel Dörfler 				BMessage address;
509f9af6566SAxel Dörfler 				address.AddString("family", "inet");
510f9af6566SAxel Dörfler 				address.AddString("address", _ToString(fAssignedAddress));
5110ce7725eSAxel Dörfler 				_ParseOptions(*message, address);
512f9af6566SAxel Dörfler 
51310cc12daSAxel Dörfler 				fConfiguration.AddMessage("address", &address);
514f9af6566SAxel Dörfler 
51510cc12daSAxel Dörfler 				// request configuration from the server
516f9af6566SAxel Dörfler 
5176cc7630fSAxel Dörfler 				_ResetTimeout(socket, timeout, tries);
518f9af6566SAxel Dörfler 				state = REQUESTING;
51946ff5400SAxel Dörfler 				_PrepareMessage(request, state);
520f9af6566SAxel Dörfler 
5216cc7630fSAxel Dörfler 				status = _SendMessage(socket, request, broadcast);
52215ab0bcfSAxel Dörfler 					// we're sending a broadcast so that all potential offers
52315ab0bcfSAxel Dörfler 					// get an answer
52410cc12daSAxel Dörfler 				break;
525f9af6566SAxel Dörfler 			}
526f9af6566SAxel Dörfler 
527f9af6566SAxel Dörfler 			case DHCP_ACK:
52810cc12daSAxel Dörfler 			{
52915ab0bcfSAxel Dörfler 				if (state != REQUESTING && state != REBINDING
53015ab0bcfSAxel Dörfler 					&& state != RENEWAL)
531f9af6566SAxel Dörfler 					continue;
532f9af6566SAxel Dörfler 
5336cc7630fSAxel Dörfler 				// TODO: we might want to configure the stuff, don't we?
5346cc7630fSAxel Dörfler 				BMessage address;
5356cc7630fSAxel Dörfler 				_ParseOptions(*message, address);
5366cc7630fSAxel Dörfler 					// TODO: currently, only lease time and DNS is updated this way
5376cc7630fSAxel Dörfler 
538f9af6566SAxel Dörfler 				// our address request has been acknowledged
539f9af6566SAxel Dörfler 				state = ACKNOWLEDGED;
54010cc12daSAxel Dörfler 
54110cc12daSAxel Dörfler 				// configure interface
54210cc12daSAxel Dörfler 				BMessage reply;
5436cc7630fSAxel Dörfler 				fTarget.SendMessage(&fConfiguration, &reply);
54410cc12daSAxel Dörfler 
54510cc12daSAxel Dörfler 				if (reply.FindInt32("status", &fStatus) != B_OK)
5466cc7630fSAxel Dörfler 					status = B_OK;
547f9af6566SAxel Dörfler 				break;
54810cc12daSAxel Dörfler 			}
549f9af6566SAxel Dörfler 
550f9af6566SAxel Dörfler 			case DHCP_NACK:
551f9af6566SAxel Dörfler 				if (state != REQUESTING)
552f9af6566SAxel Dörfler 					continue;
553f9af6566SAxel Dörfler 
55415ab0bcfSAxel Dörfler 				// try again (maybe we should prefer other servers if this
55515ab0bcfSAxel Dörfler 				// happens more than once)
5566cc7630fSAxel Dörfler 				status = _SendMessage(socket, discover, broadcast);
5576cc7630fSAxel Dörfler 				if (status == B_OK)
558f9af6566SAxel Dörfler 					state = INIT;
559f9af6566SAxel Dörfler 				break;
560f9af6566SAxel Dörfler 		}
561f9af6566SAxel Dörfler 	}
562f9af6566SAxel Dörfler 
563fb81684fSAxel Dörfler 	close(socket);
5646cc7630fSAxel Dörfler 
5656cc7630fSAxel Dörfler 	if (status == B_OK && fLeaseTime > 0) {
5666cc7630fSAxel Dörfler 		// notify early enough when the lease is
56746ff5400SAxel Dörfler 		if (fRenewalTime == 0)
56846ff5400SAxel Dörfler 			fRenewalTime = fLeaseTime * 2/3;
56946ff5400SAxel Dörfler 		if (fRebindingTime == 0)
57046ff5400SAxel Dörfler 			fRebindingTime = fLeaseTime * 5/6;
57146ff5400SAxel Dörfler 
57246ff5400SAxel Dörfler 		_RestartLease(fRenewalTime);
57346ff5400SAxel Dörfler 
57446ff5400SAxel Dörfler 		bigtime_t now = system_time();
57546ff5400SAxel Dörfler 		fLeaseTime += now;
57646ff5400SAxel Dörfler 		fRenewalTime += now;
57746ff5400SAxel Dörfler 		fRebindingTime += now;
57846ff5400SAxel Dörfler 			// make lease times absolute
57946ff5400SAxel Dörfler 	} else {
5806cc7630fSAxel Dörfler 		fLeaseTime = previousLeaseTime;
58146ff5400SAxel Dörfler 		bigtime_t now = system_time();
58246ff5400SAxel Dörfler 		fRenewalTime = (fLeaseTime - now) * 2/3 + now;
58346ff5400SAxel Dörfler 		fRebindingTime = (fLeaseTime - now) * 5/6 + now;
58446ff5400SAxel Dörfler 	}
5856cc7630fSAxel Dörfler 
5866cc7630fSAxel Dörfler 	return status;
587fb81684fSAxel Dörfler }
588fb81684fSAxel Dörfler 
589fb81684fSAxel Dörfler 
5906cc7630fSAxel Dörfler void
5916cc7630fSAxel Dörfler DHCPClient::_RestartLease(bigtime_t leaseTime)
592fb81684fSAxel Dörfler {
5936cc7630fSAxel Dörfler 	if (leaseTime == 0)
594f9af6566SAxel Dörfler 		return;
595f9af6566SAxel Dörfler 
5966cc7630fSAxel Dörfler 	BMessage lease(kMsgLeaseTime);
59746ff5400SAxel Dörfler 	fRunner = new BMessageRunner(this, &lease, leaseTime, 1);
598f9af6566SAxel Dörfler }
599f9af6566SAxel Dörfler 
600f9af6566SAxel Dörfler 
601f9af6566SAxel Dörfler void
6020ce7725eSAxel Dörfler DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address)
6030ce7725eSAxel Dörfler {
6040ce7725eSAxel Dörfler 	dhcp_option_cookie cookie;
6050ce7725eSAxel Dörfler 	message_option option;
6060ce7725eSAxel Dörfler 	const uint8* data;
6070ce7725eSAxel Dörfler 	size_t size;
6080ce7725eSAxel Dörfler 	while (message.NextOption(cookie, option, data, size)) {
6090ce7725eSAxel Dörfler 		// iterate through all options
6100ce7725eSAxel Dörfler 		switch (option) {
6110ce7725eSAxel Dörfler 			case OPTION_ROUTER_ADDRESS:
6120ce7725eSAxel Dörfler 				address.AddString("gateway", _ToString(data));
6130ce7725eSAxel Dörfler 				break;
6140ce7725eSAxel Dörfler 			case OPTION_SUBNET_MASK:
6150ce7725eSAxel Dörfler 				address.AddString("mask", _ToString(data));
6160ce7725eSAxel Dörfler 				break;
6175782c5a3SAxel Dörfler 			case OPTION_BROADCAST_ADDRESS:
6185782c5a3SAxel Dörfler 				address.AddString("broadcast", _ToString(data));
6195782c5a3SAxel Dörfler 				break;
6200ce7725eSAxel Dörfler 			case OPTION_DOMAIN_NAME_SERVER:
621a552ec13SAxel Dörfler 			{
622a552ec13SAxel Dörfler 				// TODO: for now, we write it just out to /etc/resolv.conf
623a552ec13SAxel Dörfler 				FILE* file = fopen("/etc/resolv.conf", "w");
6240ce7725eSAxel Dörfler 				for (uint32 i = 0; i < size / 4; i++) {
6250ce7725eSAxel Dörfler 					printf("DNS: %s\n", _ToString(&data[i*4]).String());
62615ab0bcfSAxel Dörfler 					if (file != NULL) {
62715ab0bcfSAxel Dörfler 						fprintf(file, "nameserver %s\n",
62815ab0bcfSAxel Dörfler 							_ToString(&data[i*4]).String());
62915ab0bcfSAxel Dörfler 					}
6300ce7725eSAxel Dörfler 				}
631a552ec13SAxel Dörfler 				fclose(file);
6320ce7725eSAxel Dörfler 				break;
633a552ec13SAxel Dörfler 			}
6340ce7725eSAxel Dörfler 			case OPTION_SERVER_ADDRESS:
6350ce7725eSAxel Dörfler 				fServer.sin_addr.s_addr = *(in_addr_t*)data;
6360ce7725eSAxel Dörfler 				break;
63746ff5400SAxel Dörfler 
6380ce7725eSAxel Dörfler 			case OPTION_ADDRESS_LEASE_TIME:
6390ce7725eSAxel Dörfler 				printf("lease time of %lu seconds\n", htonl(*(uint32*)data));
6406cc7630fSAxel Dörfler 				fLeaseTime = htonl(*(uint32*)data) * 1000000LL;
6410ce7725eSAxel Dörfler 				break;
6421a4e8e7bSAxel Dörfler 			case OPTION_RENEWAL_TIME:
64346ff5400SAxel Dörfler 				printf("renewal time of %lu seconds\n",
64446ff5400SAxel Dörfler 					htonl(*(uint32*)data));
64546ff5400SAxel Dörfler 				fRenewalTime = htonl(*(uint32*)data) * 1000000LL;
64646ff5400SAxel Dörfler 				break;
6471a4e8e7bSAxel Dörfler 			case OPTION_REBINDING_TIME:
64846ff5400SAxel Dörfler 				printf("rebinding time of %lu seconds\n",
64946ff5400SAxel Dörfler 					htonl(*(uint32*)data));
65046ff5400SAxel Dörfler 				fRebindingTime = htonl(*(uint32*)data) * 1000000LL;
6511a4e8e7bSAxel Dörfler 				break;
6521a4e8e7bSAxel Dörfler 
6530ce7725eSAxel Dörfler 			case OPTION_HOST_NAME:
6545782c5a3SAxel Dörfler 			{
6550ce7725eSAxel Dörfler 				char name[256];
6560ce7725eSAxel Dörfler 				memcpy(name, data, size);
6570ce7725eSAxel Dörfler 				name[size] = '\0';
6580ce7725eSAxel Dörfler 				printf("DHCP host name: \"%s\"\n", name);
6590ce7725eSAxel Dörfler 				break;
6605782c5a3SAxel Dörfler 			}
6615782c5a3SAxel Dörfler 
6625782c5a3SAxel Dörfler 			case OPTION_DOMAIN_NAME:
6635782c5a3SAxel Dörfler 			{
6645782c5a3SAxel Dörfler 				char name[256];
6655782c5a3SAxel Dörfler 				memcpy(name, data, size);
6665782c5a3SAxel Dörfler 				name[size] = '\0';
6675782c5a3SAxel Dörfler 				printf("DHCP domain name: \"%s\"\n", name);
6685782c5a3SAxel Dörfler 				break;
6695782c5a3SAxel Dörfler 			}
6700ce7725eSAxel Dörfler 
6710ce7725eSAxel Dörfler 			case OPTION_MESSAGE_TYPE:
6720ce7725eSAxel Dörfler 				break;
6730ce7725eSAxel Dörfler 
6740ce7725eSAxel Dörfler 			default:
6750ce7725eSAxel Dörfler 				printf("unknown option %lu\n", (uint32)option);
6760ce7725eSAxel Dörfler 				break;
6770ce7725eSAxel Dörfler 		}
6780ce7725eSAxel Dörfler 	}
6790ce7725eSAxel Dörfler }
6800ce7725eSAxel Dörfler 
6810ce7725eSAxel Dörfler 
6820ce7725eSAxel Dörfler void
68346ff5400SAxel Dörfler DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state)
6840ce7725eSAxel Dörfler {
6850ce7725eSAxel Dörfler 	message.opcode = BOOT_REQUEST;
6860ce7725eSAxel Dörfler 	message.hardware_type = ARP_HARDWARE_TYPE_ETHER;
6870ce7725eSAxel Dörfler 	message.hardware_address_length = 6;
6880ce7725eSAxel Dörfler 	message.transaction_id = htonl(fTransactionID);
689*bcc8dadaSAxel Dörfler 	message.seconds_since_start = htons(min_c((system_time() - fStartTime)
69015ab0bcfSAxel Dörfler 		/ 1000000LL, 65535));
6910ce7725eSAxel Dörfler 	memcpy(message.mac_address, fMAC, 6);
6920ce7725eSAxel Dörfler 
69346ff5400SAxel Dörfler 	message_type type = message.Type();
69446ff5400SAxel Dörfler 
69546ff5400SAxel Dörfler 	switch (type) {
6960ce7725eSAxel Dörfler 		case DHCP_REQUEST:
6970ce7725eSAxel Dörfler 		case DHCP_RELEASE:
6980ce7725eSAxel Dörfler 		{
6990ce7725eSAxel Dörfler 			// add server identifier option
700a073ba1aSHugo Santos 			uint8* next = message.PrepareMessage(type);
7010ce7725eSAxel Dörfler 			next = message.PutOption(next, OPTION_SERVER_ADDRESS,
7020ce7725eSAxel Dörfler 				(uint32)fServer.sin_addr.s_addr);
70346ff5400SAxel Dörfler 
70446ff5400SAxel Dörfler 			// In RENEWAL or REBINDING state, we must set the client_address field, and not
70546ff5400SAxel Dörfler 			// use OPTION_REQUEST_IP_ADDRESS for DHCP_REQUEST messages
7065d4d5313SHugo Santos 			if (type == DHCP_REQUEST && (state == INIT || state == REQUESTING)) {
70715ab0bcfSAxel Dörfler 				next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS,
70815ab0bcfSAxel Dörfler 					(uint32)fAssignedAddress);
7095d4d5313SHugo Santos 				next = message.PutOption(next, OPTION_REQUEST_PARAMETERS,
7105d4d5313SHugo Santos 					kRequiredParameters, sizeof(kRequiredParameters));
7115d4d5313SHugo Santos 			} else
71246ff5400SAxel Dörfler 				message.client_address = fAssignedAddress;
71346ff5400SAxel Dörfler 
714a073ba1aSHugo Santos 			message.FinishOptions(next);
715a073ba1aSHugo Santos 			break;
716a073ba1aSHugo Santos 		}
717a073ba1aSHugo Santos 
718a073ba1aSHugo Santos 		case DHCP_DISCOVER:
719a073ba1aSHugo Santos 		{
720a073ba1aSHugo Santos 			uint8 *next = message.PrepareMessage(type);
721a073ba1aSHugo Santos 			next = message.PutOption(next, OPTION_REQUEST_PARAMETERS,
722a073ba1aSHugo Santos 				kRequiredParameters, sizeof(kRequiredParameters));
723a073ba1aSHugo Santos 			message.FinishOptions(next);
7240ce7725eSAxel Dörfler 			break;
7250ce7725eSAxel Dörfler 		}
7260ce7725eSAxel Dörfler 
7270ce7725eSAxel Dörfler 		default:
7280ce7725eSAxel Dörfler 			// the default options are fine
7290ce7725eSAxel Dörfler 			break;
7300ce7725eSAxel Dörfler 	}
7310ce7725eSAxel Dörfler }
7320ce7725eSAxel Dörfler 
7330ce7725eSAxel Dörfler 
7340ce7725eSAxel Dörfler void
7356cc7630fSAxel Dörfler DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries)
736f9af6566SAxel Dörfler {
7376cc7630fSAxel Dörfler 	timeout = DEFAULT_TIMEOUT;
7386cc7630fSAxel Dörfler 	tries = 0;
739f9af6566SAxel Dörfler 
740f9af6566SAxel Dörfler 	struct timeval value;
7416cc7630fSAxel Dörfler 	value.tv_sec = timeout;
742f9af6566SAxel Dörfler 	value.tv_usec = 0;
743f9af6566SAxel Dörfler 	setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value));
744f9af6566SAxel Dörfler }
745f9af6566SAxel Dörfler 
746f9af6566SAxel Dörfler 
747f9af6566SAxel Dörfler bool
7486cc7630fSAxel Dörfler DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries)
749f9af6566SAxel Dörfler {
7506cc7630fSAxel Dörfler 	timeout += timeout;
7516cc7630fSAxel Dörfler 	if (timeout > MAX_TIMEOUT) {
7526cc7630fSAxel Dörfler 		timeout = DEFAULT_TIMEOUT;
753f9af6566SAxel Dörfler 
7546cc7630fSAxel Dörfler 		if (++tries > 2)
755f9af6566SAxel Dörfler 			return false;
756f9af6566SAxel Dörfler 	}
7576cc7630fSAxel Dörfler 	printf("DHCP timeout shift: %lu secs (try %lu)\n", timeout, tries);
758f9af6566SAxel Dörfler 
759f9af6566SAxel Dörfler 	struct timeval value;
7606cc7630fSAxel Dörfler 	value.tv_sec = timeout;
761f9af6566SAxel Dörfler 	value.tv_usec = 0;
762f9af6566SAxel Dörfler 	setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value));
763f9af6566SAxel Dörfler 
764f9af6566SAxel Dörfler 	return true;
765f9af6566SAxel Dörfler }
766f9af6566SAxel Dörfler 
767f9af6566SAxel Dörfler 
768f9af6566SAxel Dörfler BString
769f9af6566SAxel Dörfler DHCPClient::_ToString(const uint8* data) const
770f9af6566SAxel Dörfler {
771f9af6566SAxel Dörfler 	BString target = inet_ntoa(*(in_addr*)data);
772f9af6566SAxel Dörfler 	return target;
773f9af6566SAxel Dörfler }
774f9af6566SAxel Dörfler 
775f9af6566SAxel Dörfler 
776f9af6566SAxel Dörfler BString
777f9af6566SAxel Dörfler DHCPClient::_ToString(in_addr_t address) const
778f9af6566SAxel Dörfler {
779f9af6566SAxel Dörfler 	BString target = inet_ntoa(*(in_addr*)&address);
780f9af6566SAxel Dörfler 	return target;
781f9af6566SAxel Dörfler }
782f9af6566SAxel Dörfler 
783f9af6566SAxel Dörfler 
784f9af6566SAxel Dörfler status_t
785f9af6566SAxel Dörfler DHCPClient::_SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const
786f9af6566SAxel Dörfler {
787f9af6566SAxel Dörfler 	ssize_t bytesSent = sendto(socket, &message, message.Size(),
788f9af6566SAxel Dörfler 		address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0,
789f9af6566SAxel Dörfler 		(struct sockaddr*)&address, sizeof(sockaddr_in));
790f9af6566SAxel Dörfler 	if (bytesSent < 0)
791f9af6566SAxel Dörfler 		return errno;
792f9af6566SAxel Dörfler 
793f9af6566SAxel Dörfler 	return B_OK;
794fb81684fSAxel Dörfler }
795fb81684fSAxel Dörfler 
796fb81684fSAxel Dörfler 
79746ff5400SAxel Dörfler dhcp_state
79846ff5400SAxel Dörfler DHCPClient::_CurrentState() const
79946ff5400SAxel Dörfler {
80046ff5400SAxel Dörfler 	bigtime_t now = system_time();
80146ff5400SAxel Dörfler 
80246ff5400SAxel Dörfler 	if (now > fLeaseTime || fStatus < B_OK)
80346ff5400SAxel Dörfler 		return INIT;
80446ff5400SAxel Dörfler 	if (now >= fRebindingTime)
80546ff5400SAxel Dörfler 		return REBINDING;
80646ff5400SAxel Dörfler 	if (now >= fRenewalTime)
80746ff5400SAxel Dörfler 		return RENEWAL;
80846ff5400SAxel Dörfler 
80946ff5400SAxel Dörfler 	return BOUND;
81046ff5400SAxel Dörfler }
81146ff5400SAxel Dörfler 
81246ff5400SAxel Dörfler 
813fb81684fSAxel Dörfler void
814fb81684fSAxel Dörfler DHCPClient::MessageReceived(BMessage* message)
815fb81684fSAxel Dörfler {
8166cc7630fSAxel Dörfler 	switch (message->what) {
8176cc7630fSAxel Dörfler 		case kMsgLeaseTime:
81846ff5400SAxel Dörfler 		{
81946ff5400SAxel Dörfler 			dhcp_state state = _CurrentState();
82046ff5400SAxel Dörfler 
82146ff5400SAxel Dörfler 			bigtime_t next;
82246ff5400SAxel Dörfler 			if (_Negotiate(state) == B_OK) {
82346ff5400SAxel Dörfler 				switch (state) {
82446ff5400SAxel Dörfler 					case RENEWAL:
82546ff5400SAxel Dörfler 						next = fRebindingTime;
8266cc7630fSAxel Dörfler 						break;
82746ff5400SAxel Dörfler 					case REBINDING:
82846ff5400SAxel Dörfler 					default:
82946ff5400SAxel Dörfler 						next = fRenewalTime;
83046ff5400SAxel Dörfler 						break;
83146ff5400SAxel Dörfler 				}
83246ff5400SAxel Dörfler 			} else {
83346ff5400SAxel Dörfler 				switch (state) {
83446ff5400SAxel Dörfler 					case RENEWAL:
83546ff5400SAxel Dörfler 						next = (fLeaseTime - fRebindingTime) / 4 + system_time();
83646ff5400SAxel Dörfler 						break;
83746ff5400SAxel Dörfler 					case REBINDING:
83846ff5400SAxel Dörfler 					default:
83946ff5400SAxel Dörfler 						next = (fLeaseTime - fRenewalTime) / 4 + system_time();
84046ff5400SAxel Dörfler 						break;
84146ff5400SAxel Dörfler 				}
84246ff5400SAxel Dörfler 			}
84346ff5400SAxel Dörfler 
84446ff5400SAxel Dörfler 			_RestartLease(next - system_time());
84546ff5400SAxel Dörfler 			break;
84646ff5400SAxel Dörfler 		}
8476cc7630fSAxel Dörfler 
8486cc7630fSAxel Dörfler 		default:
849fb81684fSAxel Dörfler 			BHandler::MessageReceived(message);
8506cc7630fSAxel Dörfler 			break;
8516cc7630fSAxel Dörfler 	}
852fb81684fSAxel Dörfler }
853fb81684fSAxel Dörfler 
854