client.c 35.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
 * dhcpcd - DHCP client daemon -
 * Copyright (C) 1996 - 1997 Yoichi Hariguchi <yoichi@fore.com>
 * Copyright (C) January, 1998 Sergei Viznyuk <sv@phystech.com>
 * 
 * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_packet.h>
#include <net/route.h>
33
34
35
36
#include <arpa/inet.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <netpacket/packet.h>
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <setjmp.h>
#include <time.h>
#include "client.h"
#include "buildmsg.h"
#include "arp.h"

int DebugFlag = 1;
#define DEBUG

53
54
55
56
57
58
59
60
61
typedef struct dhcp_response_return
{
	unsigned int	server_ip_addr;
	char			server_hw_addr[ETH_ALEN];
	dhcpMessage	dhcp_msg;
} dhcp_response_return;


void debug_dump_dhcp_options (struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, dhcpOptions *options);
62
63

/*****************************************************************************/
64
int parse_dhcp_reply (struct iphdr *iphdr, struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, dhcpOptions *options)
65
66
{
	register u_char	*p = dhcp_msg->options+4;
67
	unsigned char		*end = dhcp_msg->options + sizeof (dhcp_msg->options);
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

	/* Force T1 and T2 to 0: either new values will be in message, or they
	   will need to be recalculated from lease time */
	if ( options->val[dhcpT1value] && options->len[dhcpT1value] > 0 )
		memset (options->val[dhcpT1value], 0, options->len[dhcpT1value]);
	if ( options->val[dhcpT2value] && options->len[dhcpT2value] > 0 )
		memset (options->val[dhcpT2value], 0, options->len[dhcpT2value]);

	while ( p < end )
	{
		switch ( *p )
		{
			case endOption:
				goto swend;
			case padOption:
				p++;
				break;
			default:
				if ( p[1] )
				{
					if ( options->len[*p] == p[1] )
						memcpy (options->val[*p], p+2, p[1]);
					else
					{
						options->len[*p] = p[1];
						if ( options->val[*p] )
							free (options->val[*p]);
						else
							options->num++;
						options->val[*p] = malloc (p[1]+1);
						memset (options->val[*p], 0, p[1]+1);
						memcpy (options->val[*p], p+2, p[1]);
					}
				}
				p+=p[1]+2;
		}
	}

swend:
#ifdef DEBUG
108
	debug_dump_dhcp_options (saddr, dhcp_msg, options);
109
110
111
#endif

#if 0
112
	if ( !dhcp_msg->yiaddr )
113
114
115
		dhcp_msg->yiaddr = DhcpMsgSend->ciaddr;
#endif

116
	if (!options->val[dhcpServerIdentifier]) /* did not get dhcpServerIdentifier */
117
118
	{
		/* make it the same as IP address of the sender */
119
120
		options->val[dhcpServerIdentifier] = malloc (4);
		memcpy (options->val[dhcpServerIdentifier], &(iphdr->saddr), 4);
121
122
		options->len[dhcpServerIdentifier] = 4;
		options->num++;
123
124
		if (DebugFlag)
			syslog (LOG_DEBUG, "dhcpServerIdentifier option is missing in DHCP server response. Assuming %u.%u.%u.%u\n",
125
126
127
128
129
				((unsigned char *)options->val[dhcpServerIdentifier])[0],
				((unsigned char *)options->val[dhcpServerIdentifier])[1],
				((unsigned char *)options->val[dhcpServerIdentifier])[2],
				((unsigned char *)options->val[dhcpServerIdentifier])[3]);
	}
130
	if (!options->val[dns]) /* did not get DNS */
131
132
	{
		/* make it the same as dhcpServerIdentifier */
133
		options->val[dns] = malloc (4);
134
135
136
137
		memcpy (options->val[dns], options->val[dhcpServerIdentifier], 4);
		options->len[dns] = 4;
		options->num++;
		if ( DebugFlag )
138
139
140
			syslog (LOG_DEBUG, "dns option is missing in DHCP server response. Assuming %u.%u.%u.%u\n",
				((unsigned char *)options->val[dns])[0], ((unsigned char *)options->val[dns])[1],
				((unsigned char *)options->val[dns])[2], ((unsigned char *)options->val[dns])[3]);
141
	}
142
	if (!options->val[subnetMask]) /* did not get subnetMask */
143
	{
144
		options->val[subnetMask] = malloc (4);
145
		((unsigned char *)options->val[subnetMask])[0] = 255;
146
		if (IN_CLASSA (ntohl (dhcp_msg->yiaddr)))
147
148
149
150
151
152
153
154
		{
			((unsigned char *)options->val[subnetMask])[1] = 0; /* class A */
			((unsigned char *)options->val[subnetMask])[2] = 0;
			((unsigned char *)options->val[subnetMask])[3] = 0;
		}
		else
		{
			((unsigned char *)options->val[subnetMask])[1] = 255;
155
			if (IN_CLASSB (ntohl (dhcp_msg->yiaddr)))
156
157
158
159
160
161
162
			{
				((unsigned char *)(options->val[subnetMask]))[2] = 0;/* class B */
				((unsigned char *)(options->val[subnetMask]))[3] = 0;
			}
			else
			{
				((unsigned char *)options->val[subnetMask])[2] = 255;
163
				if (IN_CLASSC (ntohl (dhcp_msg->yiaddr)))
164
165
166
167
168
169
170
					((unsigned char *)options->val[subnetMask])[3] = 0; /* class C */
				else
					((unsigned char *)options->val[subnetMask])[3] = 255;
			}
		}
		options->len[subnetMask] = 4;
		options->num++;
171
172
173
174
		if (DebugFlag)
			syslog (LOG_DEBUG, "subnetMask option is missing in DHCP server response. Assuming %u.%u.%u.%u\n",
				((unsigned char *)options->val[subnetMask])[0], ((unsigned char *)options->val[subnetMask])[1],
				((unsigned char *)options->val[subnetMask])[2], ((unsigned char *)options->val[subnetMask])[3]);
175
	}
176
	if (!options->val[broadcastAddr]) /* did not get broadcastAddr */
177
178
	{
		int br = dhcp_msg->yiaddr | ~*((int *)options->val[subnetMask]);
179
		options->val[broadcastAddr] = malloc (4);
180
181
182
		memcpy (options->val[broadcastAddr], &br, 4);
		options->len[broadcastAddr] = 4;
		options->num++;
183
		if (DebugFlag)
184
			syslog(LOG_DEBUG, "broadcastAddr option is missing in DHCP server response. Assuming %u.%u.%u.%u\n",
185
186
				((unsigned char *)options->val[broadcastAddr])[0], ((unsigned char *)options->val[broadcastAddr])[1],
				((unsigned char *)options->val[broadcastAddr])[2], ((unsigned char *)options->val[broadcastAddr])[3]);
187
	}
188
	if (!options->val[routersOnSubnet])
189
	{
190
191
192
		options->val[routersOnSubnet] = malloc (4);
		if (options->val[dhcpServerIdentifier])
			memcpy (options->val[routersOnSubnet], options->val[dhcpServerIdentifier], 4);
193
		else
194
			memcpy (options->val[routersOnSubnet], &dhcp_msg->giaddr, 4);
195
196
		options->len[routersOnSubnet] = 4;
		options->num++;
197
198
199
200
		if (DebugFlag)
			syslog (LOG_DEBUG, "routersOnSubnet option is missing in DHCP server response.  Assuming %u.%u.%u.%u (DHCP server)\n",
				((unsigned char *)options->val[routersOnSubnet])[0], ((unsigned char *)options->val[routersOnSubnet])[1],
				((unsigned char *)options->val[routersOnSubnet])[2], ((unsigned char *)options->val[routersOnSubnet])[3]);
201
	}
202
	if (options->val[dhcpIPaddrLeaseTime] && options->len[dhcpIPaddrLeaseTime] == 4)
203
204
205
206
207
	{
		if ( *(unsigned int *)options->val[dhcpIPaddrLeaseTime] == 0 )
		{
			unsigned int	lease_time = htonl (DHCP_DEFAULT_LEASETIME);
			memcpy (options->val[dhcpIPaddrLeaseTime], &lease_time, 4);
208
209
			if (DebugFlag)
				syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime=0 in DHCP server response. Assuming %u sec\n", lease_time);
210
211
212
		}
		else
		{
213
214
215
			if (DebugFlag)
				syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime = %u in DHCP server response.\n",
					ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]));
216
217
218
219
220
221
222
223
224
225
		}
	}
	else /* did not get dhcpIPaddrLeaseTime */
	{
		unsigned int	lease_time = htonl (DHCP_DEFAULT_LEASETIME);
		options->val[dhcpIPaddrLeaseTime] = malloc(4);
		memcpy (options->val[dhcpIPaddrLeaseTime], &lease_time, 4);
		options->len[dhcpIPaddrLeaseTime] = 4;
		options->num++;
		if ( DebugFlag )
226
			syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime option is missing in DHCP server response. Assuming %u sec\n", lease_time);
227
	}
228
	if (options->val[dhcpT1value] && options->len[dhcpT1value] == 4)
229
	{
230
		if (*(unsigned int *)options->val[dhcpT1value] == 0)
231
		{
232
233
			unsigned t2 = 0.5 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]);
			int t1 = htonl (t2);
234
235
			memcpy (options->val[dhcpT1value],&t1,4);
			options->len[dhcpT1value] = 4;
236
237
			if (DebugFlag)
				syslog (LOG_DEBUG, "dhcpT1value is missing in DHCP server response. Assuming %u sec\n", t2);
238
239
240
241
		}
	}
	else		/* did not get T1 */
	{
242
243
		unsigned t2 = 0.5 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]);
		int t1 = htonl (t2);
244
245
246
247
		options->val[dhcpT1value] = malloc(4);
		memcpy (options->val[dhcpT1value],&t1,4);
		options->len[dhcpT1value] = 4;
		options->num++;
248
249
		if (DebugFlag)
			syslog (LOG_DEBUG, "dhcpT1value is missing in DHCP server response. Assuming %u sec\n", t2);
250
	}
251
	if (options->val[dhcpT2value] && options->len[dhcpT2value] == 4)
252
	{
253
		if (*(unsigned int *)options->val[dhcpT2value] == 0)
254
		{
255
256
257
			unsigned t2 = 0.875 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]);
			int t1 = htonl (t2);
			memcpy (options->val[dhcpT2value],&t1,4);
258
			options->len[dhcpT2value] = 4;
259
260
			if (DebugFlag)
				syslog (LOG_DEBUG, "dhcpT2value is missing in DHCP server response. Assuming %u sec\n", t2);
261
262
263
264
		}
	}
	else		/* did not get T2 */
	{
265
266
		unsigned t2 = 0.875 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]);
		int t1 = htonl (t2);
267
		options->val[dhcpT2value] = malloc(4);
268
		memcpy (options->val[dhcpT2value],&t1,4);
269
270
		options->len[dhcpT2value] = 4;
		options->num++;
271
272
		if (DebugFlag)
			syslog (LOG_DEBUG, "dhcpT2value is missing in DHCP server response. Assuming %u sec\n", t2);
273
	}
274
	if (options->val[dhcpMessageType])
275
276
277
278
		return *(unsigned char *)options->val[dhcpMessageType];
	return -1;
}
/*****************************************************************************/
279
void class_id_setup (dhcp_interface *iface, const char *g_cls_id)
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
{
	unsigned int	 g_cls_id_len = 0;

	if (!iface) return;

	if (g_cls_id)
		g_cls_id_len = strlen (g_cls_id);

	if (g_cls_id_len)
	{
		memcpy (iface->cls_id, g_cls_id, g_cls_id_len);
		iface->cls_id_len = g_cls_id_len;
	}
	else
	{
		struct utsname sname;
		if ( uname(&sname) )
297
			syslog (LOG_ERR,"classIDsetup: uname: %m\n");
298
299
300
301
302
		snprintf (iface->cls_id, DHCP_CLASS_ID_MAX_LEN, "%s %s %s",
				sname.sysname, sname.release, sname.machine);
	}
}
/*****************************************************************************/
303
void client_id_setup (dhcp_interface *iface, const char *g_cli_id)
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
{
	unsigned int	 g_cli_id_len = 0;
	unsigned char	*c = iface->cli_id;

	if (!iface) return;

	if (g_cli_id)
		g_cli_id_len = strlen (g_cli_id);

	*c++ = dhcpClientIdentifier;
	if ( g_cli_id_len )
	{
		*c++ = g_cli_id_len + 1;	/* 1 for the field below */
		*c++ = 0;			/* type: string */
		memcpy (c, g_cli_id, g_cli_id_len);
		iface->cli_id_len = g_cli_id_len + 3;
	}
	else
	{
		*c++ = ETH_ALEN + 1;	        /* length: 6 (MAC Addr) + 1 (# field) */
324
		*c++ = ARPHRD_ETHER;	/* type: Ethernet address */
325
326
327
328
329
		memcpy (c, iface->chaddr, ETH_ALEN);
		iface->cli_id_len = ETH_ALEN + 3;
	}
}
/*****************************************************************************/
330
void release_dhcp_options (dhcp_interface *iface)
331
332
333
334
335
336
337
338
{
	register int i;
	for ( i = 1; i < 256; i++ )
	{
		if ( iface->dhcp_options.val[i] )
			free(iface->dhcp_options.val[i]);
	}

339
	memset (&(iface->dhcp_options), 0, sizeof (dhcpOptions));
340
341
342
343
344
}
/*****************************************************************************/
/* Subtract the `struct timeval' values X and Y,
   storing the result in RESULT.
   Return 1 if the difference is negative, otherwise 0.  */
345
static int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y)
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
{
	/* Perform the carry for the later subtraction by updating Y. */
	if (x->tv_usec < y->tv_usec)
	{
		int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
		y->tv_usec -= 1000000 * nsec;
		y->tv_sec += nsec;
	}
	if (x->tv_usec - y->tv_usec > 1000000)
	{
		int nsec = (x->tv_usec - y->tv_usec) / 1000000;
		y->tv_usec += 1000000 * nsec;
		y->tv_sec -= nsec;
	}

	/* Compute the time remaining to wait.
	`tv_usec' is certainly positive. */
	result->tv_sec = x->tv_sec - y->tv_sec;
	result->tv_usec = x->tv_usec - y->tv_usec;

	/* Return 1 if result is negative. */
	return x->tv_sec < y->tv_sec;
}
/*****************************************************************************/
370
371
372
/* Ripped from pump.
 */
int verify_checksum(void * buf, int length, void * buf2, int length2)
373
{
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
	unsigned int csum;
	unsigned short * sp;

	csum = 0;
	for (sp = (unsigned short *) buf; length > 0; (length -= 2), sp++)
		csum += *sp;

	/* this matches rfc 1071, but not Steven's */
	if (length)
		csum += *((unsigned char *) sp);

	for (sp = (unsigned short *) buf2; length2 > 0; (length2 -= 2), sp++)
		csum += *sp;

	/* this matches rfc 1071, but not Steven's */
	if (length)
		csum += *((unsigned char *) sp);

	while (csum >> 16)
		csum = (csum & 0xffff) + (csum >> 16);

	if (csum!=0x0000 && csum != 0xffff)
		return 0;
397

398
399
400
401
402
403
404
405
406
407
	return 1;
}
/*****************************************************************************/
/* "timeout" should be the future point in time when we wish to stop
 * checking for data on the socket.
 */
int peekfd (dhcp_interface *iface, int sk, struct timeval *timeout)
{
	struct timeval diff;
	struct timeval now;
408
409

	/* Wake up each second to check whether or not we've been told
410
	 * to stop with iface->cease and check our timeout.
411
	 */
412
413
414
	gettimeofday (&now, NULL);
	syslog (LOG_INFO, "DHCP waiting for data, overall timeout = {%ds, %dus}\n", (int)timeout->tv_sec, (int)timeout->tv_usec);
	while (timeval_subtract (&diff, timeout, &now) == 0)
415
	{
416
		fd_set fs;
417
		struct timeval wait = {1, 0};
418
419
420
421
		syslog (LOG_INFO, "DHCP waiting for data, remaining timeout = {%ds, %dus}\n", (int)diff.tv_sec, (int)diff.tv_usec);

		FD_ZERO (&fs);
		FD_SET (sk, &fs);
422

423
		if (select (sk+1, &fs, NULL, NULL, &wait) == -1)
424
			return RET_DHCP_ERROR;
425
		if (FD_ISSET(sk, &fs))
426
427
428
			return RET_DHCP_SUCCESS;
		if (iface->cease)
			return RET_DHCP_CEASED;
429
430
		gettimeofday (&now, NULL);
	};
431
432
433
	return RET_DHCP_TIMEOUT;
}
/*****************************************************************************/
434
435
int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_type,
				dhcp_msg_build_proc build_dhcp_msg, dhcp_response_return *dhcp_return)
436
{
437
438
439
	char				*pkt_recv = NULL;
	int				recv_sk = -1;
	struct sockaddr_in	addr;
440
	int				tries = 0;
441
442
443
444
445
446
447
	int				dhcp_send_len, err = RET_DHCP_TIMEOUT;
	dhcpMessage		*dhcp_send = NULL;
	struct timeval		recv_timeout, overall_end, diff, current;

	if (!dhcp_return)
		return RET_DHCP_ERROR;
	memset (dhcp_return, 0, sizeof (dhcp_response_return));
448

449
450
451
	pkt_recv = malloc (sizeof (char) * ETH_FRAME_LEN);
	if (!pkt_recv)
		return RET_DHCP_ERROR;
452

453
454
	/* Call the specific DHCP message building routine for this request */
	if (!(dhcp_send = build_dhcp_msg (iface, &dhcp_send_len, &addr)))
455
	{
456
457
458
		err = RET_DHCP_ERROR;
		goto out;
	}
459

460
461
462
463
464
465
	recv_sk = socket (AF_PACKET, SOCK_DGRAM, ntohs (ETH_P_IP));
	if (recv_sk < 0)
	{
		err = RET_DHCP_ERROR;
		goto out;
	}
466

467
468
469
470
471
	/* Setup the time in the future to quit doing DHCP stuff.  If we reach this time,
	 * we return RET_DHCP_TIMEOUT.
	 */
	gettimeofday (&overall_end, NULL);
	overall_end.tv_sec += iface->client_options->base_timeout;
472

473
474
475
476
	/* Send the request, then wait for the reply for a certain period of time
	 * that increases with each failed request.  Quit when we reach our end time though.
	 */
	syslog (LOG_INFO, "DHCP: Starting request loop");
477
478
	do
	{
479
480
		struct iphdr		*ip_hdr;
		struct udphdr		*udp_hdr;
481
		char				*tmp_ip;
482
		dhcpMessage		*dhcp_msg_recv = NULL;
483
484
		int				 reply_type = -1;
		char				 foobuf[512];
485
486
487
488
		struct sockaddr_ll	 server_hw_addr;
		int				 o;
		char				 ethPacket[ETH_FRAME_LEN];
		int				 len;
489

490
491
492
		if (iface->cease)
			goto out;

493
494
		/* Send the DHCP request */
		syslog (LOG_INFO, "DHCP: Sending request packet...");
495
		do
496
		{
497
498
			err = sendto (iface->sk, dhcp_send, dhcp_send_len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof (struct sockaddr));
			if (iface->cease || ((err == -1) && (errno != EAGAIN)))
499
			{
500
501
502
				syslog (LOG_INFO, "DHCP: error sending, cease = %d, err = %d, errno = %d", iface->cease, err, errno);
				err = iface->cease ? RET_DHCP_CEASED : RET_DHCP_ERROR;
				goto out;
503
			}
504

505
506
507
			/* Return if we've exceeded our timeout */
			gettimeofday (&current, NULL);
			if (timeval_subtract (&diff, &overall_end, &current) != 0)
508
			{
509
510
511
				err = RET_DHCP_TIMEOUT;
				syslog (LOG_INFO, "DHCP: Send timeout");
				goto out;
512
			}
513
514
		} while ((err == -1) && (errno == EAGAIN));
		syslog (LOG_INFO, "DHCP: Sent request packet.");
515

516
517
518
519
		/* Set up the future time at which point to stop waiting for data
		 * on our socket and try the request again.  If that future point is
		 * later than our overall DHCP operation timeout (overall_end) then
		 * clamp the receive timeout to overall_end.
520
		 */
521
522
523
		tries++;
		gettimeofday (&recv_timeout, NULL);
		recv_timeout.tv_sec += (tries * DHCP_INITIAL_RTO);
524
		recv_timeout.tv_usec += (random () % 200000);
525
526
527
528
529
		if (timeval_subtract (&diff, &overall_end, &recv_timeout) != 0)
			memcpy (&recv_timeout, &overall_end, sizeof (struct timeval));

		/* Wait for some kind of data to appear on the socket */
		syslog (LOG_INFO, "DHCP: Waiting for reply...");
530
		if ((err = peekfd (iface, recv_sk, &recv_timeout)) != RET_DHCP_SUCCESS)
531
		{
532
533
534
			if (err == RET_DHCP_TIMEOUT)
				continue;
			goto out;
535
		}
536
		syslog (LOG_INFO, "DHCP: Got some data to check for reply packet.");
537

538
539
540
541
		/* Peek from the data until we get a full amount or a timeout has occurred */
		memset (pkt_recv, 0, ETH_FRAME_LEN);
		o = sizeof (struct sockaddr_ll);
		do
542
		{
543
544
545
546
547
548
549
			o = sizeof (server_hw_addr);
			len = recvfrom (recv_sk, ethPacket, sizeof (ethPacket), MSG_DONTWAIT | MSG_PEEK, (struct sockaddr *)&server_hw_addr, &o);
			if (iface->cease || ((len == -1) && (errno != EAGAIN)) || (len == 0))
			{
				err = iface->cease ? RET_DHCP_CEASED : RET_DHCP_ERROR;
				goto out;
			}
550

551
552
553
			/* Return if we've exceeded our timeout */
			gettimeofday (&current, NULL);
			if (timeval_subtract (&diff, &overall_end, &current) != 0)
554
			{
555
556
				err = RET_DHCP_TIMEOUT;
				goto out;
557
			}
558
559
560
561
562
563
564
565
566
567
568
			syslog (LOG_INFO, "DHCP: Received data of len %d, looking for at least %d", len, (sizeof (struct iphdr) + sizeof (struct udphdr)));
		} while (len < (sizeof (struct iphdr) + sizeof (struct udphdr)));

		/* Ok, we allegedly have the data we need, so grab it from the queue */
		o = sizeof (struct sockaddr_ll);
		len = recvfrom (recv_sk, pkt_recv, ETH_FRAME_LEN, 0, (struct sockaddr *)&server_hw_addr, &o);
		syslog (LOG_INFO, "DHCP: actual data length was %d", len);
		if (len < (sizeof (struct iphdr) + sizeof (struct udphdr)))
		{
			syslog (LOG_INFO, "DHCP: Data length failed minimum length check (should be %d, got %d)", (sizeof (struct iphdr) + sizeof (struct udphdr)), len);
			continue;
569
570
		}

571
572
		ip_hdr = (struct iphdr *) pkt_recv;
		if (!verify_checksum (NULL, 0, ip_hdr, sizeof (struct iphdr)))
573
		{
574
			syslog (LOG_INFO, "DHCP: Reply message had bad IP checksum, won't use it.");
575
576
577
			continue;
		}

578
		if (ntohs (ip_hdr->tot_len) > len)
579
		{
580
			syslog (LOG_INFO, "DHCP: Reply message had mismatch in length (IP header said %d, packet was really %d), won't use it.", ntohs (ip_hdr->tot_len), len);
581
582
			continue;
		}
583
		len = ntohs (ip_hdr->tot_len);
584

585
		if (ip_hdr->protocol != IPPROTO_UDP)
586
		{
587
			syslog (LOG_INFO, "DHCP: Reply message was not not UDP (ip_hdr->protocol = %d, IPPROTO_UDP = %d), won't use it.", ip_hdr->protocol, IPPROTO_UDP);
588
589
590
			continue;
		}

591
592
		udp_hdr = (struct udphdr *) (pkt_recv + sizeof (struct iphdr));
		if (ntohs (udp_hdr->source) != DHCP_SERVER_PORT)
593
		{
594
			syslog (LOG_INFO, "DHCP: Reply message's source port was not the DHCP server port number, won't use it.");
595
596
			continue;
		}
597
		if (ntohs (udp_hdr->dest) != DHCP_CLIENT_PORT) 
598
		{
599
			syslog (LOG_INFO, "DHCP: Reply message's destination port was not the DHCP client port number, won't use it.");
600
601
602
			continue;
		}

603
604
605
606
607
608
609
		/* Ok, packet appears to be OK */
		/* Ensure DHCP packet is 0xFF terminated, which isn't the case on Cisco 800 series ISDN router */
		dhcp_msg_recv = malloc (sizeof (dhcpMessage));
		memset (dhcp_msg_recv, 0xFF, sizeof (dhcpMessage));
		memcpy (dhcp_msg_recv, (char *) udp_hdr + sizeof (struct udphdr), len - sizeof (struct iphdr) - sizeof (struct udphdr));

		if (dhcp_msg_recv->xid != iface->xid)
610
		{
611
612
			syslog (LOG_INFO, "DHCP: Reply message's XID does not match expected XID (message %d, expected %d), won't use it.", dhcp_msg_recv->xid, iface->xid);
			free (dhcp_msg_recv);
613
614
615
			continue;
		}

616
		if (dhcp_msg_recv->htype != ARPHRD_ETHER)
617
		{
618
619
620
			if (DebugFlag)
				syslog (LOG_DEBUG, "DHCP: Reply message's header type was not ARPHRD_ETHER (messgae %d, expected %d), won't use it.", dhcp_msg_recv->htype, ARPHRD_ETHER);
			free (dhcp_msg_recv);
621
622
623
			continue;
		}

624
		if (dhcp_msg_recv->op != DHCP_BOOTREPLY)
625
		{
626
627
			syslog (LOG_INFO, "DHCP: Reply message was not a bootp/DHCP reply, won't use it.");
			free (dhcp_msg_recv);
628
629
630
			continue;
		}

631
632
		/* Clear out all data remaining on the interface in preparation for another broadcast if needed */
		while ((iface->foo_sk > 0) && recvfrom (iface->foo_sk, (void *)foobuf, sizeof (foobuf), 0, NULL, NULL) != -1);
633
634

		/* Copy DHCP response options from received packet into local options list */
635
636
		reply_type = parse_dhcp_reply (ip_hdr, &server_hw_addr, dhcp_msg_recv, &(iface->dhcp_options));
		if (expected_reply_type == reply_type)
637
		{
638
639
640
641
642
643
			memcpy (&dhcp_return->server_ip_addr, &(ip_hdr->saddr), 4);
			memcpy (&dhcp_return->server_hw_addr, &server_hw_addr, ETH_ALEN);
			memcpy (&dhcp_return->dhcp_msg, dhcp_msg_recv, sizeof (dhcpMessage));
			free (dhcp_msg_recv);
			err = RET_DHCP_SUCCESS;
			goto out;
644
		}
645
		free (dhcp_msg_recv);
646
647
648

		if (reply_type == DHCP_NAK)
		{
649
650
			if (iface->dhcp_options.val[dhcpMsg])
				syslog (LOG_ERR, "DHCP: DHCP_NAK response received: %s.", (char *)iface->dhcp_options.val[dhcpMsg]);
651
			else
652
653
654
				syslog (LOG_ERR, "DHCP: DHCP_NAK response received.");
			err = RET_DHCP_NAK;
			goto out;
655
		}
656
657
		gettimeofday (&current, NULL);
	} while (timeval_subtract (&diff, &overall_end, &current) == 0);
658

659
660
661
662
663
664
665
out:
	free (dhcp_send);
	if (err != RET_DHCP_SUCCESS)
		free (pkt_recv);
	if (recv_sk >= 0)
		close (recv_sk);
	return err;
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
}
/*****************************************************************************/
int dhcp_reboot (dhcp_interface *iface)
{
	/* Client has a cached IP and wants to request it again from the server
	 * if possible.  DHCP state INIT-REBOOT.
	 *
 	 * If no response from the server is received, we assume that we can still
	 * use the cached IP address.
	 */

	/* FIXME: get the IP address to renew from somewhere */

	if (!iface) return RET_DHCP_ERROR;

681
682
	release_dhcp_options (iface);
	return dhcp_request (iface, &build_dhcp_reboot);
683
684
685
686
}
/*****************************************************************************/
int dhcp_init (dhcp_interface *iface)
{
687
688
	dhcp_response_return	dhcp_resp;
	int					err;
689
690
691

	if (!iface) return RET_DHCP_ERROR;

692
	release_dhcp_options (iface);
693
694

#ifdef DEBUG
695
	syslog (LOG_DEBUG, "ClassID  = \"%s\"\n"
696
697
698
699
700
701
702
		"ClientID = \"%u.%u.%u.%02X.%02X.%02X.%02X.%02X.%02X\"\n", iface->cls_id,
		iface->cli_id[0], iface->cli_id[1], iface->cli_id[2],
		iface->cli_id[3], iface->cli_id[4], iface->cli_id[5],
		iface->cli_id[6], iface->cli_id[7], iface->cli_id[8]);
#endif

	if ( DebugFlag )
703
		syslog (LOG_INFO, "Broadcasting DHCP_DISCOVER\n");
704
	iface->xid = random ();
705
	err = dhcp_handle_transaction (iface, DHCP_OFFER, &build_dhcp_discover, &dhcp_resp);
706
707
708
	if (err != RET_DHCP_SUCCESS)
		return err;

709
	if (iface->client_options->send_second_discover)
710
	{
711
		dhcp_response_return	dhcp_resp2;
712
713

		if (DebugFlag)
714
			syslog (LOG_INFO, "Broadcasting second DHCP_DISCOVER\n");
715

716
717
		iface->xid = dhcp_resp.dhcp_msg.xid;
		err = dhcp_handle_transaction (iface, DHCP_OFFER, &build_dhcp_discover, &dhcp_resp2);
718
		if (err == RET_DHCP_SUCCESS)
719
			memcpy (&dhcp_resp, &dhcp_resp2, sizeof (dhcp_response_return));
720
721
	}

722
	iface->ciaddr = dhcp_resp.dhcp_msg.yiaddr;
723
	memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4);
724
725
	memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN);
	iface->xid = dhcp_resp.dhcp_msg.xid;
726
727

	/* DHCP_OFFER received */
728
	if (DebugFlag)
729
	{
730
		syslog (LOG_INFO, "DHCP_OFFER received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
731
732
733
734
735
736
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]);
	}

737
	return dhcp_request (iface, &build_dhcp_request);
738
739
740
741
}
/*****************************************************************************/
int dhcp_request(dhcp_interface *iface, dhcp_msg_build_proc buildDhcpMsg)
{
742
743
	dhcp_response_return	dhcp_resp;
	int					err;
744
745
746
747
748

	/* DHCP state REQUEST: request an address from a _particular_ DHCP server */

	if (!iface) return RET_DHCP_ERROR;

749
	if (DebugFlag)
750
	{
751
		syslog (LOG_INFO, "Broadcasting DHCP_REQUEST for %u.%u.%u.%u\n",
752
753
754
755
			((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
			((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
	}

756
	err = dhcp_handle_transaction (iface, DHCP_ACK, buildDhcpMsg, &dhcp_resp);
757
758
759
	if (err != RET_DHCP_SUCCESS)
		return err;

760
	if (DebugFlag)
761
	{
762
		syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
763
764
765
766
767
768
769
770
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]);
	}

#ifdef ARPCHECK
	/* check if the offered IP address already in use */
771
	if (arpCheck(iface))
772
	{
773
		if (DebugFlag)
774
			syslog (LOG_INFO, "requested %u.%u.%u.%u address is in use\n",
775
776
				((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
				((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
777
		dhcpDecline ();
778
779
780
781
		iface->ciaddr = 0;
		return RET_DHCP_ADDRESS_IN_USE;
	}

782
	if (DebugFlag)
783
	{
784
		syslog (LOG_INFO, "verified %u.%u.%u.%u address is not in use\n",
785
786
787
788
789
790
791
			((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
			((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
	}
#endif

	/* Successfull ACK: Use the fields obtained for future requests */
	memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4);
792
	memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN);
793
794
795
796
797
798

	return RET_DHCP_BOUND;
}
/*****************************************************************************/
int dhcp_renew(dhcp_interface *iface)
{
799
800
	dhcp_response_return	dhcp_resp;
	int					err;
801
802
803
804
805
806

	/* DHCP state RENEW: request renewal of our lease from the original DHCP server */
	if (!iface) return RET_DHCP_ERROR;

	if ( DebugFlag )
	{
807
		syslog (LOG_INFO,"Sending DHCP_REQUEST for %u.%u.%u.%u to %u.%u.%u.%u\n",
808
809
810
811
812
813
814
			((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
			((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3],
			((unsigned char *)&(iface->siaddr))[0], ((unsigned char *)&(iface->siaddr))[1],
			((unsigned char *)&(iface->siaddr))[2], ((unsigned char *)&(iface->siaddr))[3]);
	}

	iface->xid = random();
815
	err = dhcp_handle_transaction (iface, DHCP_ACK, &build_dhcp_renew, &dhcp_resp);
816
817
818
	if (err != RET_DHCP_SUCCESS);
		return err;

819
	if (DebugFlag)
820
	{
821
		syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
822
823
824
825
826
827
828
829
830
831
832
				((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0],
				((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1],
				((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2],
				((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]);
	}

	return RET_DHCP_BOUND;
}
/*****************************************************************************/
int dhcp_rebind(dhcp_interface *iface)
{
833
834
	dhcp_response_return	dhcp_resp;
	int					err;
835
836
837
838

	/* DHCP state REBIND: request renewal of our lease from _any_ DHCP server */
	if (!iface) return RET_DHCP_ERROR;

839
	if (DebugFlag)
840
	{
841
		syslog (LOG_INFO,"Broadcasting DHCP_REQUEST for %u.%u.%u.%u\n",
842
843
844
845
846
847
848
			((unsigned char *)&(iface->ciaddr))[0],
			((unsigned char *)&(iface->ciaddr))[1],
			((unsigned char *)&(iface->ciaddr))[2],
			((unsigned char *)&(iface->ciaddr))[3]);
	}

	iface->xid = random ();
849
	err = dhcp_handle_transaction(iface, DHCP_ACK, &build_dhcp_rebind, &dhcp_resp);
850
851
852
	if (err != RET_DHCP_SUCCESS)
		return err;

853
	if (DebugFlag)
854
	{
855
		syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
856
857
858
859
860
861
862
863
				((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0],
				((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1],
				((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2],
				((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]);
	}

	/* Successfull ACK: Use the fields obtained for future requests */
	memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4);
864
	memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN);
865
866
867
868
869
870

	return RET_DHCP_BOUND;
}
/*****************************************************************************/
int dhcp_release(dhcp_interface *iface)
{
871
872
873
874
	struct sockaddr_in	addr;
	socklen_t			addr_len = sizeof (struct sockaddr_in);
	int				len;
	dhcpMessage		*msg;
875
876
877
878
879

	if ( iface->ciaddr == 0 )
		return RET_DHCP_ERROR;

	iface->xid = random();
880
	if (!(msg = build_dhcp_release (iface, &len, &addr)))
881
882
883
884
		return RET_DHCP_ERROR;

	if (DebugFlag)
	{
885
		syslog (LOG_INFO, "Sending DHCP_RELEASE for %u.%u.%u.%u to %u.%u.%u.%u\n",
886
887
888
889
890
891
			((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
			((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3],
			((unsigned char *)&(iface->siaddr))[0], ((unsigned char *)&(iface->siaddr))[1],
			((unsigned char *)&(iface->siaddr))[2], ((unsigned char *)&(iface->siaddr))[3]);
	}

892
	if (sendto (iface->sk, msg, sizeof (dhcpMessage), 0, (struct sockaddr *)&addr, addr_len))
893
		syslog (LOG_ERR, "dhcpRelease: sendto: %m\n");
894
895
896
897
898
899
900
901
902
903
904
	free (msg);

	arpRelease (iface); /* clear ARP cache entries for client IP addr */
	iface->ciaddr = 0;

	return RET_DHCP_SUCCESS;
}
/*****************************************************************************/
#ifdef ARPCHECK
int dhcp_decline(dhcp_interface *iface)
{
905
906
907
908
	struct sockaddr_in	addr;
	socklen_t			addr_len = sizeof (struct sockaddr_in);
	int				len;
	dhcpMessage		*msg;
909
910

	iface->xid = random ();
911
	if (!(msg = build_dhcp_decline (iface, &len, &addr)))
912
913
		return  RET_DHCP_ERROR;

914
	if (DebugFlag)
915
		syslog (LOG_INFO, "Broadcasting DHCP_DECLINE\n");
916

917
	if (sendto (iface->sk, msg, sizeof (dhcpMessage), 0, &addr, addr_len))
918
919
920
921
922
923
924
925
926
		syslog (LOG_ERR,"dhcpDecline: sendto: %m\n");
	free (msg);

	return RET_DHCP_SUCCESS;
}
#endif
/*****************************************************************************/
int dhcp_inform(dhcp_interface *iface)
{
927
928
	dhcp_response_return	dhcp_resp;
	int					err;
929

930
	if (DebugFlag)
931
	{
932
		syslog (LOG_INFO, "Broadcasting DHCP_INFORM for %u.%u.%u.%u\n",
933
934
			((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
			((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
935
936
937
	}

	iface->xid = random ();
938
	err = dhcp_handle_transaction (iface, DHCP_ACK, build_dhcp_inform, &dhcp_resp);
939
940
941
	if (err != RET_DHCP_SUCCESS)
		return err;

942
	if (DebugFlag)
943
	{
944
		syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
945
946
947
948
949
950
951
952
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2],
			((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]);
	}

#ifdef ARPCHECK
	/* check if the offered IP address already in use */
953
	if (arpCheck(iface))
954
	{
955
		if (DebugFlag)
956
			syslog (LOG_INFO, "Requested %u.%u.%u.%u address is in use\n",
957
958
959
960
961
				((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
				((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
		dhcpDecline (iface);
		return RET_DHCP_SUCCESS;
	}
962
	if (DebugFlag)
963
	{
964
		syslog (LOG_INFO, "Verified %u.%u.%u.%u address is not in use\n",
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
			((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
			((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
	}
#endif

	return RET_DHCP_SUCCESS;
}

/*****************************************************************************/
char *get_dhcp_option_name (int i)
{
	char *buf = NULL;
	if (i <= dhcpClientIdentifier)
		buf = strdup (dhcp_opt_table [i].name);
	else	
		buf = strdup ("unknown");
	return buf;
}

/*****************************************************************************/
985
void debug_dump_dhcp_options (struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, dhcpOptions *options)
986
987
988
{
	int i,j;

989
	syslog (LOG_INFO, "debug_dump_dhcp_options: %d options received:\n", options->num);
990
991
	for (i = 1; i < 255; i++)
	{
992
		if (options->val[i])
993
		{
994
			switch (i)
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
			{
				case 1: /* subnet mask */
				case 3: /* routers on subnet */
				case 4: /* time servers */
				case 5: /* name servers */
				case 6: /* dns servers */
				case 28:/* broadcast addr */
				case 33:/* staticRoute */
				case 41:/* NIS servers */
				case 42:/* NTP servers */
				case 50:/* dhcpRequestdIPaddr */
				case 54:/* dhcpServerIdentifier */
					for (j = 0; j < options->len[i]; j += 4)
					{
						char *opt_name = get_dhcp_option_name (i);
1010
						syslog (LOG_INFO, "i=%-2d (%s)  len=%-2d  option = %u.%u.%u.%u\n",
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
								i, opt_name, options->len[i],
								((unsigned char *)options->val[i])[0+j],
								((unsigned char *)options->val[i])[1+j],
								((unsigned char *)options->val[i])[2+j],
								((unsigned char *)options->val[i])[3+j]);
						free (opt_name);
					}
					break;
				case 2: /* time offset */
				case 51:/* dhcpAddrLeaseTime */
				case 57:/* dhcpMaxMsgSize */
				case 58:/* dhcpT1value */
				case 59:/* dhcpT2value */
					{
						char *opt_name = get_dhcp_option_name (i);
1026
						syslog (LOG_INFO, "i=%-2d (%s)  len=%-2d  option = %d\n", i, opt_name,
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
							options->len[i], ntohl(*(int *)options->val[i]));
						free (opt_name);
					}
					break;
				case 23:/* defaultIPTTL */
				case 29:/* performMaskdiscovery */
				case 31:/* performRouterdiscovery */
				case 53:/* dhcpMessageType */
					{
						char *opt_name = get_dhcp_option_name (i);
1037
						syslog (LOG_INFO, "i=%-2d (%s)  len=%-2d  option = %u\n", i, opt_name,
1038
1039
1040
1041
1042
1043
1044
							options->len[i],*(unsigned char *)options->val[i]);
						free (opt_name);
					}
					break;
				default:
					{
						char *opt_name = get_dhcp_option_name (i);
1045
						syslog (LOG_INFO, "i=%-2d (%s)  len=%-2d  option = \"%s\"\n",
1046
1047
1048
1049
1050
1051
1052
1053
							i, opt_name, options->len[i], (char *)options->val[i]);
						free (opt_name);
					}
					break;
			}
		}
	}

1054
	syslog (LOG_INFO, "dhcp_msg->yiaddr  = %u.%u.%u.%u",
1055
				((unsigned char *)&dhcp_msg->yiaddr)[0], ((unsigned char *)&dhcp_msg->yiaddr)[1],
1056
1057
				((unsigned char *)&dhcp_msg->yiaddr)[2], ((unsigned char *)&dhcp_msg->yiaddr)[3]);
	syslog (LOG_INFO, "dhcp_msg->siaddr  = %u.%u.%u.%u",
1058
				((unsigned char *)&dhcp_msg->siaddr)[0], ((unsigned char *)&dhcp_msg->siaddr)[1],
1059
1060
				((unsigned char *)&dhcp_msg->siaddr)[2], ((unsigned char *)&dhcp_msg->siaddr)[3]);
	syslog (LOG_INFO, "dhcp_msg->giaddr  = %u.%u.%u.%u",
1061
				((unsigned char *)&dhcp_msg->giaddr)[0], ((unsigned char *)&dhcp_msg->giaddr)[1],
1062
1063
1064
1065
1066
				((unsigned char *)&dhcp_msg->giaddr)[2], ((unsigned char *)&dhcp_msg->giaddr)[3]);
	syslog (LOG_INFO, "dhcp_msg->sname   = \"%s\"", dhcp_msg->sname);
	syslog (LOG_INFO, "Server Hardware Address   = %02X.%02X.%02X.%02X.%02X.%02X\n",
				saddr->sll_addr[0], saddr->sll_addr[1], saddr->sll_addr[2], saddr->sll_addr[3],
				saddr->sll_addr[4], saddr->sll_addr[5]);
1067
1068
}