xref: /haiku/src/servers/net/DHCPClient.cpp (revision f01106c3cfc01f5706583d75c6d75d3b7cd98b77)
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