
* dhcpcd/client.c - Clean up some of the debug messages git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@386 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
1123 lines
36 KiB
C
1123 lines
36 KiB
C
/*
|
|
* 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>
|
|
#include <arpa/inet.h>
|
|
#include <netinet/udp.h>
|
|
#include <netinet/ip.h>
|
|
#include <netpacket/packet.h>
|
|
#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"
|
|
#include "udpipgen.h"
|
|
|
|
#ifdef DEBUG
|
|
int DebugFlag = 1;
|
|
#else
|
|
int DebugFlag = 0;
|
|
#endif
|
|
|
|
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);
|
|
|
|
/*****************************************************************************/
|
|
int parse_dhcp_reply (struct iphdr *iphdr, struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, dhcpOptions *options)
|
|
{
|
|
register u_char *p = dhcp_msg->options+4;
|
|
unsigned char *end = dhcp_msg->options + sizeof (dhcp_msg->options);
|
|
|
|
/* 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
|
|
debug_dump_dhcp_options (saddr, dhcp_msg, options);
|
|
#endif
|
|
|
|
#if 0
|
|
if ( !dhcp_msg->yiaddr )
|
|
dhcp_msg->yiaddr = DhcpMsgSend->ciaddr;
|
|
#endif
|
|
|
|
if (!options->val[dhcpServerIdentifier]) /* did not get dhcpServerIdentifier */
|
|
{
|
|
/* make it the same as IP address of the sender */
|
|
options->val[dhcpServerIdentifier] = malloc (4);
|
|
memcpy (options->val[dhcpServerIdentifier], &(iphdr->saddr), 4);
|
|
options->len[dhcpServerIdentifier] = 4;
|
|
options->num++;
|
|
if (DebugFlag)
|
|
syslog (LOG_DEBUG, "dhcpServerIdentifier option is missing in DHCP server response. Assuming %u.%u.%u.%u\n",
|
|
((unsigned char *)options->val[dhcpServerIdentifier])[0],
|
|
((unsigned char *)options->val[dhcpServerIdentifier])[1],
|
|
((unsigned char *)options->val[dhcpServerIdentifier])[2],
|
|
((unsigned char *)options->val[dhcpServerIdentifier])[3]);
|
|
}
|
|
if (!options->val[dns]) /* did not get DNS */
|
|
{
|
|
/* make it the same as dhcpServerIdentifier */
|
|
options->val[dns] = malloc (4);
|
|
memcpy (options->val[dns], options->val[dhcpServerIdentifier], 4);
|
|
options->len[dns] = 4;
|
|
options->num++;
|
|
if ( DebugFlag )
|
|
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]);
|
|
}
|
|
if (!options->val[subnetMask]) /* did not get subnetMask */
|
|
{
|
|
options->val[subnetMask] = malloc (4);
|
|
((unsigned char *)options->val[subnetMask])[0] = 255;
|
|
if (IN_CLASSA (ntohl (dhcp_msg->yiaddr)))
|
|
{
|
|
((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;
|
|
if (IN_CLASSB (ntohl (dhcp_msg->yiaddr)))
|
|
{
|
|
((unsigned char *)(options->val[subnetMask]))[2] = 0;/* class B */
|
|
((unsigned char *)(options->val[subnetMask]))[3] = 0;
|
|
}
|
|
else
|
|
{
|
|
((unsigned char *)options->val[subnetMask])[2] = 255;
|
|
if (IN_CLASSC (ntohl (dhcp_msg->yiaddr)))
|
|
((unsigned char *)options->val[subnetMask])[3] = 0; /* class C */
|
|
else
|
|
((unsigned char *)options->val[subnetMask])[3] = 255;
|
|
}
|
|
}
|
|
options->len[subnetMask] = 4;
|
|
options->num++;
|
|
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]);
|
|
}
|
|
if (!options->val[broadcastAddr]) /* did not get broadcastAddr */
|
|
{
|
|
int br = dhcp_msg->yiaddr | ~*((int *)options->val[subnetMask]);
|
|
options->val[broadcastAddr] = malloc (4);
|
|
memcpy (options->val[broadcastAddr], &br, 4);
|
|
options->len[broadcastAddr] = 4;
|
|
options->num++;
|
|
if (DebugFlag)
|
|
syslog(LOG_DEBUG, "broadcastAddr option is missing in DHCP server response. Assuming %u.%u.%u.%u\n",
|
|
((unsigned char *)options->val[broadcastAddr])[0], ((unsigned char *)options->val[broadcastAddr])[1],
|
|
((unsigned char *)options->val[broadcastAddr])[2], ((unsigned char *)options->val[broadcastAddr])[3]);
|
|
}
|
|
if (!options->val[routersOnSubnet])
|
|
{
|
|
options->val[routersOnSubnet] = malloc (4);
|
|
if (options->val[dhcpServerIdentifier])
|
|
memcpy (options->val[routersOnSubnet], options->val[dhcpServerIdentifier], 4);
|
|
else
|
|
memcpy (options->val[routersOnSubnet], &dhcp_msg->giaddr, 4);
|
|
options->len[routersOnSubnet] = 4;
|
|
options->num++;
|
|
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]);
|
|
}
|
|
if (options->val[dhcpIPaddrLeaseTime] && options->len[dhcpIPaddrLeaseTime] == 4)
|
|
{
|
|
if ( *(unsigned int *)options->val[dhcpIPaddrLeaseTime] == 0 )
|
|
{
|
|
unsigned int lease_time = htonl (DHCP_DEFAULT_LEASETIME);
|
|
memcpy (options->val[dhcpIPaddrLeaseTime], &lease_time, 4);
|
|
if (DebugFlag)
|
|
syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime=0 in DHCP server response. Assuming %u sec\n", lease_time);
|
|
}
|
|
else
|
|
{
|
|
if (DebugFlag)
|
|
syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime = %u in DHCP server response.\n",
|
|
ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]));
|
|
}
|
|
}
|
|
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 )
|
|
syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime option is missing in DHCP server response. Assuming %u sec\n", lease_time);
|
|
}
|
|
if (options->val[dhcpT1value] && options->len[dhcpT1value] == 4)
|
|
{
|
|
if (*(unsigned int *)options->val[dhcpT1value] == 0)
|
|
{
|
|
unsigned t2 = 0.5 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]);
|
|
int t1 = htonl (t2);
|
|
memcpy (options->val[dhcpT1value],&t1,4);
|
|
options->len[dhcpT1value] = 4;
|
|
if (DebugFlag)
|
|
syslog (LOG_DEBUG, "dhcpT1value is missing in DHCP server response. Assuming %u sec\n", t2);
|
|
}
|
|
}
|
|
else /* did not get T1 */
|
|
{
|
|
unsigned t2 = 0.5 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]);
|
|
int t1 = htonl (t2);
|
|
options->val[dhcpT1value] = malloc(4);
|
|
memcpy (options->val[dhcpT1value],&t1,4);
|
|
options->len[dhcpT1value] = 4;
|
|
options->num++;
|
|
if (DebugFlag)
|
|
syslog (LOG_DEBUG, "dhcpT1value is missing in DHCP server response. Assuming %u sec\n", t2);
|
|
}
|
|
if (options->val[dhcpT2value] && options->len[dhcpT2value] == 4)
|
|
{
|
|
if (*(unsigned int *)options->val[dhcpT2value] == 0)
|
|
{
|
|
unsigned t2 = 0.875 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]);
|
|
int t1 = htonl (t2);
|
|
memcpy (options->val[dhcpT2value],&t1,4);
|
|
options->len[dhcpT2value] = 4;
|
|
if (DebugFlag)
|
|
syslog (LOG_DEBUG, "dhcpT2value is missing in DHCP server response. Assuming %u sec\n", t2);
|
|
}
|
|
}
|
|
else /* did not get T2 */
|
|
{
|
|
unsigned t2 = 0.875 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]);
|
|
int t1 = htonl (t2);
|
|
options->val[dhcpT2value] = malloc(4);
|
|
memcpy (options->val[dhcpT2value],&t1,4);
|
|
options->len[dhcpT2value] = 4;
|
|
options->num++;
|
|
if (DebugFlag)
|
|
syslog (LOG_DEBUG, "dhcpT2value is missing in DHCP server response. Assuming %u sec\n", t2);
|
|
}
|
|
if (options->val[dhcpMessageType])
|
|
return *(unsigned char *)options->val[dhcpMessageType];
|
|
return -1;
|
|
}
|
|
/*****************************************************************************/
|
|
void class_id_setup (dhcp_interface *iface, const char *g_cls_id)
|
|
{
|
|
unsigned int g_cls_id_len = 0;
|
|
|
|
if (!iface) return;
|
|
|
|
memset (iface->cls_id, 0, DHCP_CLASS_ID_MAX_LEN);
|
|
|
|
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) )
|
|
syslog (LOG_ERR,"classIDsetup: uname: %m\n");
|
|
snprintf (iface->cls_id, DHCP_CLASS_ID_MAX_LEN, "%s %s %s",
|
|
sname.sysname, sname.release, sname.machine);
|
|
iface->cls_id_len = strlen (iface->cls_id);
|
|
}
|
|
}
|
|
/*****************************************************************************/
|
|
void client_id_setup (dhcp_interface *iface, const char *g_cli_id)
|
|
{
|
|
unsigned int g_cli_id_len = 0;
|
|
char *c;
|
|
|
|
if (!iface) return;
|
|
|
|
memset (iface->cli_id, 0, DHCP_CLIENT_ID_MAX_LEN);
|
|
c = iface->cli_id;
|
|
|
|
if (g_cli_id)
|
|
g_cli_id_len = strlen (g_cli_id);
|
|
|
|
if ( g_cli_id_len )
|
|
{
|
|
*c++ = 0; /* type: string */
|
|
memcpy (c, g_cli_id, g_cli_id_len);
|
|
iface->cli_id_len = g_cli_id_len + 1;
|
|
}
|
|
else
|
|
{
|
|
*c++ = ARPHRD_ETHER; /* type: Ethernet address */
|
|
memcpy (c, iface->chaddr, ETH_ALEN);
|
|
iface->cli_id_len = ETH_ALEN + 1;
|
|
}
|
|
}
|
|
/*****************************************************************************/
|
|
void release_dhcp_options (dhcp_interface *iface)
|
|
{
|
|
register int i;
|
|
for ( i = 1; i < 256; i++ )
|
|
{
|
|
if ( iface->dhcp_options.val[i] )
|
|
free(iface->dhcp_options.val[i]);
|
|
}
|
|
|
|
memset (&(iface->dhcp_options), 0, sizeof (dhcpOptions));
|
|
}
|
|
/*****************************************************************************/
|
|
/* Subtract the `struct timeval' values X and Y,
|
|
storing the result in RESULT.
|
|
Return 1 if the difference is negative, otherwise 0. */
|
|
static int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y)
|
|
{
|
|
/* 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;
|
|
}
|
|
/*****************************************************************************/
|
|
/* Ripped from pump.
|
|
*/
|
|
int verify_checksum(void * buf, int length, void * buf2, int length2)
|
|
{
|
|
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;
|
|
|
|
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, int min_data, struct timeval *end_time)
|
|
{
|
|
struct timeval diff;
|
|
struct timeval now;
|
|
int recv_data_len = 0;
|
|
char ethPacket[ETH_FRAME_LEN];
|
|
|
|
if (min_data < 1)
|
|
return RET_DHCP_ERROR;
|
|
|
|
/* Wake up each second to check whether or not we've been told
|
|
* to stop with iface->cease and check our end time.
|
|
*/
|
|
gettimeofday (&now, NULL);
|
|
/* syslog (LOG_INFO, "DHCP waiting for data, overall end_time = {%ds, %dus}\n", (int)end_time->tv_sec, (int)end_time->tv_usec);*/
|
|
while ((timeval_subtract (&diff, end_time, &now) == 0) && !iface->cease && (recv_data_len < min_data))
|
|
{
|
|
fd_set fs;
|
|
struct timeval wait = {1, 0};
|
|
/* syslog (LOG_INFO, "DHCP waiting for data of minimum size %d, remaining timeout = {%ds, %dus}\n", min_data, (int)diff.tv_sec, (int)diff.tv_usec);*/
|
|
|
|
FD_ZERO (&fs);
|
|
FD_SET (sk, &fs);
|
|
|
|
if (select (sk+1, &fs, NULL, NULL, &wait) == -1)
|
|
return RET_DHCP_ERROR;
|
|
if (FD_ISSET(sk, &fs))
|
|
{
|
|
/* Get length of data waiting on the socket */
|
|
recv_data_len = recvfrom (sk, ethPacket, sizeof (ethPacket), MSG_DONTWAIT | MSG_PEEK, 0, NULL);
|
|
if ((recv_data_len == -1) && (errno != EAGAIN))
|
|
return RET_DHCP_ERROR; /* Return on fatal errors */
|
|
}
|
|
gettimeofday (&now, NULL);
|
|
};
|
|
|
|
if (iface->cease)
|
|
return RET_DHCP_CEASED;
|
|
else if (recv_data_len >= min_data)
|
|
return RET_DHCP_SUCCESS;
|
|
|
|
return RET_DHCP_TIMEOUT;
|
|
}
|
|
/*****************************************************************************/
|
|
int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_type,
|
|
dhcp_msg_build_proc build_dhcp_msg, dhcp_response_return *dhcp_return)
|
|
{
|
|
char *pkt_recv = NULL;
|
|
int recv_sk = -1;
|
|
struct sockaddr_in addr;
|
|
int tries = 0;
|
|
int err = RET_DHCP_TIMEOUT;
|
|
struct timeval recv_end, overall_end, diff, current;
|
|
udpipMessage *udp_send = NULL;
|
|
|
|
if (!dhcp_return)
|
|
return RET_DHCP_ERROR;
|
|
memset (dhcp_return, 0, sizeof (dhcp_response_return));
|
|
|
|
pkt_recv = malloc (sizeof (char) * ETH_FRAME_LEN);
|
|
if (!pkt_recv)
|
|
return RET_DHCP_ERROR;
|
|
|
|
recv_sk = socket (AF_PACKET, SOCK_DGRAM, ntohs (ETH_P_IP));
|
|
if (recv_sk < 0)
|
|
{
|
|
err = RET_DHCP_ERROR;
|
|
goto out;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
/* 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.
|
|
*/
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Starting request loop");
|
|
#endif
|
|
do
|
|
{
|
|
udpipMessage *udp_msg_recv = NULL;
|
|
struct iphdr *ip_hdr = NULL;
|
|
struct udphdr *udp_hdr;
|
|
char *tmp_ip;
|
|
dhcpMessage *dhcp_msg_recv = NULL;
|
|
int reply_type = -1;
|
|
char foobuf[512];
|
|
struct sockaddr_ll server_hw_addr;
|
|
int data_good = 0;
|
|
int min_data_len = (sizeof (struct iphdr) + sizeof (struct udphdr));
|
|
|
|
|
|
if (iface->cease)
|
|
goto out;
|
|
|
|
/* Send the DHCP request */
|
|
do
|
|
{
|
|
int udp_send_len = 0;
|
|
struct sockaddr addr;
|
|
|
|
/* Call the specific DHCP message building routine for this request */
|
|
if (!(udp_send = build_dhcp_msg (iface, &udp_send_len)))
|
|
{
|
|
err = RET_DHCP_ERROR;
|
|
goto out;
|
|
}
|
|
|
|
memset (&addr, 0, sizeof (struct sockaddr));
|
|
memcpy (addr.sa_data, iface->iface, strlen (iface->iface));
|
|
err = sendto (iface->sk, udp_send, udp_send_len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof (struct sockaddr));
|
|
if (iface->cease || ((err == -1) && (errno != EAGAIN)))
|
|
{
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: error sending, cease = %d, err = %d, errno = %d", iface->cease, err, errno);
|
|
#endif
|
|
err = iface->cease ? RET_DHCP_CEASED : RET_DHCP_ERROR;
|
|
goto out;
|
|
}
|
|
|
|
/* Return if we've exceeded our timeout */
|
|
gettimeofday (¤t, NULL);
|
|
if (timeval_subtract (&diff, &overall_end, ¤t) != 0)
|
|
{
|
|
err = RET_DHCP_TIMEOUT;
|
|
goto out;
|
|
}
|
|
} while ((err == -1) && (errno == EAGAIN));
|
|
|
|
/* 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.
|
|
*/
|
|
tries++;
|
|
gettimeofday (&recv_end, NULL);
|
|
recv_end.tv_sec += (tries * DHCP_INITIAL_RTO);
|
|
recv_end.tv_usec += (random () % 200000);
|
|
/* Clamp recv_end to overall_end if its greater than overall_end */
|
|
if (timeval_subtract (&diff, &overall_end, &recv_end) != 0)
|
|
memcpy (&recv_end, &overall_end, sizeof (struct timeval));
|
|
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Request sent, waiting for reply...");
|
|
#endif
|
|
|
|
/* Packet receive loop */
|
|
data_good = 0;
|
|
gettimeofday (¤t, NULL);
|
|
while ((timeval_subtract (&diff, &recv_end, ¤t) == 0) && !data_good)
|
|
{
|
|
int len;
|
|
int o;
|
|
char ethPacket[ETH_FRAME_LEN];
|
|
|
|
/* Wait for some kind of data to appear on the socket */
|
|
if ((err = peekfd (iface, recv_sk, min_data_len, &recv_end)) != RET_DHCP_SUCCESS)
|
|
{
|
|
if (err == RET_DHCP_TIMEOUT)
|
|
break;
|
|
goto out;
|
|
}
|
|
|
|
gettimeofday (¤t, NULL);
|
|
|
|
/* 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);
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Got some data of length %d.", len);
|
|
#endif
|
|
if (len < (sizeof (struct iphdr) + sizeof (struct udphdr)))
|
|
{
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Data length failed minimum length check (should be %d, got %d)", (sizeof (struct iphdr) + sizeof (struct udphdr)), len);
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
ip_hdr = (struct iphdr *) pkt_recv;
|
|
if (!verify_checksum (NULL, 0, ip_hdr, sizeof (struct iphdr)))
|
|
{
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Reply message had bad IP checksum, won't use it.");
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (ntohs (ip_hdr->tot_len) > len)
|
|
{
|
|
#ifdef DEBUG
|
|
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);
|
|
#endif
|
|
continue;
|
|
}
|
|
len = ntohs (ip_hdr->tot_len);
|
|
|
|
if (ip_hdr->protocol != IPPROTO_UDP)
|
|
{
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Reply message was not UDP (ip_hdr->protocol = %d, IPPROTO_UDP = %d), won't use it.", ip_hdr->protocol, IPPROTO_UDP);
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
udp_hdr = (struct udphdr *) (pkt_recv + sizeof (struct iphdr));
|
|
if (ntohs (udp_hdr->source) != DHCP_SERVER_PORT)
|
|
{
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Reply message's source port was not the DHCP server port number, won't use it.");
|
|
#endif
|
|
continue;
|
|
}
|
|
if (ntohs (udp_hdr->dest) != DHCP_CLIENT_PORT)
|
|
{
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Reply message's destination port was not the DHCP client port number, won't use it.");
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
#ifdef DEBUG
|
|
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);
|
|
#endif
|
|
free (dhcp_msg_recv);
|
|
continue;
|
|
}
|
|
|
|
if (dhcp_msg_recv->htype != ARPHRD_ETHER)
|
|
{
|
|
#ifdef DEBUG
|
|
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);
|
|
#endif
|
|
free (dhcp_msg_recv);
|
|
continue;
|
|
}
|
|
|
|
if (dhcp_msg_recv->op != DHCP_BOOTREPLY)
|
|
{
|
|
#ifdef DEBUG
|
|
syslog (LOG_INFO, "DHCP: Reply message was not a bootp/DHCP reply, won't use it.");
|
|
#endif
|
|
free (dhcp_msg_recv);
|
|
continue;
|
|
}
|
|
|
|
data_good = 1;
|
|
}
|
|
|
|
if (!data_good)
|
|
continue;
|
|
|
|
/* 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);
|
|
|
|
/* Copy DHCP response options from received packet into local options list */
|
|
reply_type = parse_dhcp_reply (ip_hdr, &server_hw_addr, dhcp_msg_recv, &(iface->dhcp_options));
|
|
if (expected_reply_type == reply_type)
|
|
{
|
|
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;
|
|
}
|
|
free (dhcp_msg_recv);
|
|
|
|
if (reply_type == DHCP_NAK)
|
|
{
|
|
#ifdef DEBUG
|
|
if (iface->dhcp_options.val[dhcpMsg])
|
|
syslog (LOG_ERR, "DHCP: DHCP_NAK response received: %s.", (char *)iface->dhcp_options.val[dhcpMsg]);
|
|
else
|
|
syslog (LOG_ERR, "DHCP: DHCP_NAK response received.");
|
|
#endif
|
|
err = RET_DHCP_NAK;
|
|
goto out;
|
|
}
|
|
gettimeofday (¤t, NULL);
|
|
} while (timeval_subtract (&diff, &overall_end, ¤t) == 0);
|
|
|
|
out:
|
|
free (udp_send);
|
|
if (err != RET_DHCP_SUCCESS)
|
|
free (pkt_recv);
|
|
if (recv_sk >= 0)
|
|
close (recv_sk);
|
|
return err;
|
|
}
|
|
/*****************************************************************************/
|
|
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;
|
|
|
|
release_dhcp_options (iface);
|
|
return dhcp_request (iface, &build_dhcp_reboot);
|
|
}
|
|
/*****************************************************************************/
|
|
int dhcp_init (dhcp_interface *iface)
|
|
{
|
|
dhcp_response_return dhcp_resp;
|
|
int err;
|
|
|
|
if (!iface) return RET_DHCP_ERROR;
|
|
|
|
release_dhcp_options (iface);
|
|
|
|
#ifdef DEBUG
|
|
syslog (LOG_DEBUG, "ClassID = \"%s\"", iface->cls_id);
|
|
syslog (LOG_DEBUG, "ClientID = \"%u.%u.%u.%02X.%02X.%02X.%02X.%02X.%02X\"\n",
|
|
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 )
|
|
syslog (LOG_INFO, "Broadcasting DHCP_DISCOVER\n");
|
|
iface->xid = random ();
|
|
err = dhcp_handle_transaction (iface, DHCP_OFFER, &build_dhcp_discover, &dhcp_resp);
|
|
if (err != RET_DHCP_SUCCESS)
|
|
return err;
|
|
|
|
if (iface->client_options->send_second_discover)
|
|
{
|
|
dhcp_response_return dhcp_resp2;
|
|
|
|
if (DebugFlag)
|
|
syslog (LOG_INFO, "Broadcasting second DHCP_DISCOVER\n");
|
|
|
|
iface->xid = dhcp_resp.dhcp_msg.xid;
|
|
err = dhcp_handle_transaction (iface, DHCP_OFFER, &build_dhcp_discover, &dhcp_resp2);
|
|
if (err == RET_DHCP_SUCCESS)
|
|
memcpy (&dhcp_resp, &dhcp_resp2, sizeof (dhcp_response_return));
|
|
}
|
|
|
|
iface->ciaddr = dhcp_resp.dhcp_msg.yiaddr;
|
|
memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4);
|
|
memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN);
|
|
iface->xid = dhcp_resp.dhcp_msg.xid;
|
|
|
|
/* DHCP_OFFER received */
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "DHCP_OFFER received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
|
|
((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 dhcp_request (iface, &build_dhcp_request);
|
|
}
|
|
/*****************************************************************************/
|
|
int dhcp_request(dhcp_interface *iface, dhcp_msg_build_proc buildDhcpMsg)
|
|
{
|
|
dhcp_response_return dhcp_resp;
|
|
int err;
|
|
|
|
/* DHCP state REQUEST: request an address from a _particular_ DHCP server */
|
|
|
|
if (!iface) return RET_DHCP_ERROR;
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "Broadcasting DHCP_REQUEST for %u.%u.%u.%u\n",
|
|
((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
|
|
((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
|
|
}
|
|
|
|
err = dhcp_handle_transaction (iface, DHCP_ACK, buildDhcpMsg, &dhcp_resp);
|
|
if (err != RET_DHCP_SUCCESS)
|
|
return err;
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
|
|
((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 */
|
|
if (arpCheck(iface))
|
|
{
|
|
if (DebugFlag)
|
|
syslog (LOG_INFO, "requested %u.%u.%u.%u address is in use\n",
|
|
((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
|
|
((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
|
|
dhcpDecline ();
|
|
iface->ciaddr = 0;
|
|
return RET_DHCP_ADDRESS_IN_USE;
|
|
}
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "verified %u.%u.%u.%u address is not in use\n",
|
|
((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);
|
|
memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN);
|
|
|
|
return RET_DHCP_BOUND;
|
|
}
|
|
/*****************************************************************************/
|
|
int dhcp_renew(dhcp_interface *iface)
|
|
{
|
|
dhcp_response_return dhcp_resp;
|
|
int err;
|
|
|
|
/* DHCP state RENEW: request renewal of our lease from the original DHCP server */
|
|
if (!iface) return RET_DHCP_ERROR;
|
|
|
|
if ( DebugFlag )
|
|
{
|
|
syslog (LOG_INFO,"Sending DHCP_REQUEST for %u.%u.%u.%u to %u.%u.%u.%u\n",
|
|
((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();
|
|
err = dhcp_handle_transaction (iface, DHCP_ACK, &build_dhcp_renew, &dhcp_resp);
|
|
if (err != RET_DHCP_SUCCESS);
|
|
return err;
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
|
|
((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)
|
|
{
|
|
dhcp_response_return dhcp_resp;
|
|
int err;
|
|
|
|
/* DHCP state REBIND: request renewal of our lease from _any_ DHCP server */
|
|
if (!iface) return RET_DHCP_ERROR;
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO,"Broadcasting DHCP_REQUEST for %u.%u.%u.%u\n",
|
|
((unsigned char *)&(iface->ciaddr))[0],
|
|
((unsigned char *)&(iface->ciaddr))[1],
|
|
((unsigned char *)&(iface->ciaddr))[2],
|
|
((unsigned char *)&(iface->ciaddr))[3]);
|
|
}
|
|
|
|
iface->xid = random ();
|
|
err = dhcp_handle_transaction(iface, DHCP_ACK, &build_dhcp_rebind, &dhcp_resp);
|
|
if (err != RET_DHCP_SUCCESS)
|
|
return err;
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
|
|
((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);
|
|
memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN);
|
|
|
|
return RET_DHCP_BOUND;
|
|
}
|
|
/*****************************************************************************/
|
|
int dhcp_release(dhcp_interface *iface)
|
|
{
|
|
udpipMessage *msg;
|
|
struct sockaddr addr;
|
|
socklen_t addr_len = sizeof (struct sockaddr);
|
|
int len;
|
|
|
|
if ( iface->ciaddr == 0 )
|
|
return RET_DHCP_ERROR;
|
|
|
|
iface->xid = random();
|
|
if (!(msg = build_dhcp_release (iface, &len)))
|
|
return RET_DHCP_ERROR;
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "Sending DHCP_RELEASE for %u.%u.%u.%u to %u.%u.%u.%u\n",
|
|
((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]);
|
|
}
|
|
|
|
memset (&addr, 0, sizeof (struct sockaddr));
|
|
memcpy (addr.sa_data, iface->iface, strlen (iface->iface));
|
|
if (sendto (iface->sk, msg, len, 0, (struct sockaddr *)&addr, addr_len))
|
|
syslog (LOG_ERR, "dhcpRelease: sendto: %m\n");
|
|
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)
|
|
{
|
|
udpipMessage *msg;
|
|
struct sockaddr addr;
|
|
socklen_t addr_len = sizeof (struct sockaddr);
|
|
int len;
|
|
|
|
iface->xid = random ();
|
|
if (!(msg = build_dhcp_decline (iface, &len)))
|
|
return RET_DHCP_ERROR;
|
|
|
|
if (DebugFlag)
|
|
syslog (LOG_INFO, "Broadcasting DHCP_DECLINE\n");
|
|
|
|
memset (&addr, 0, sizeof (struct sockaddr));
|
|
memcpy (addr.sa_data, iface->iface, strlen (iface->iface));
|
|
if (sendto (iface->sk, msg, len, 0, &addr, addr_len))
|
|
syslog (LOG_ERR,"dhcpDecline: sendto: %m\n");
|
|
free (msg);
|
|
|
|
return RET_DHCP_SUCCESS;
|
|
}
|
|
#endif
|
|
/*****************************************************************************/
|
|
int dhcp_inform(dhcp_interface *iface)
|
|
{
|
|
dhcp_response_return dhcp_resp;
|
|
int err;
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "Broadcasting DHCP_INFORM for %u.%u.%u.%u\n",
|
|
((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1],
|
|
((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]);
|
|
}
|
|
|
|
iface->xid = random ();
|
|
err = dhcp_handle_transaction (iface, DHCP_ACK, build_dhcp_inform, &dhcp_resp);
|
|
if (err != RET_DHCP_SUCCESS)
|
|
return err;
|
|
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname,
|
|
((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 */
|
|
if (arpCheck(iface))
|
|
{
|
|
if (DebugFlag)
|
|
syslog (LOG_INFO, "Requested %u.%u.%u.%u address is in use\n",
|
|
((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;
|
|
}
|
|
if (DebugFlag)
|
|
{
|
|
syslog (LOG_INFO, "Verified %u.%u.%u.%u address is not in use\n",
|
|
((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;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
/*****************************************************************************/
|
|
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;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void debug_dump_dhcp_options (struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, dhcpOptions *options)
|
|
{
|
|
int i,j;
|
|
|
|
syslog (LOG_INFO, "Server replied with %d DHCP options:\n", options->num);
|
|
for (i = 1; i < 255; i++)
|
|
{
|
|
if (options->val[i])
|
|
{
|
|
switch (i)
|
|
{
|
|
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);
|
|
syslog (LOG_INFO, "\ti=%-2d (%s) len=%-2d option = %u.%u.%u.%u\n",
|
|
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);
|
|
syslog (LOG_INFO, "\ti=%-2d (%s) len=%-2d option = %d\n", i, opt_name,
|
|
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);
|
|
syslog (LOG_INFO, "\ti=%-2d (%s) len=%-2d option = %u\n", i, opt_name,
|
|
options->len[i],*(unsigned char *)options->val[i]);
|
|
free (opt_name);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
char *opt_name = get_dhcp_option_name (i);
|
|
syslog (LOG_INFO, "\ti=%-2d (%s) len=%-2d option = \"%s\"\n",
|
|
i, opt_name, options->len[i], (char *)options->val[i]);
|
|
free (opt_name);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
syslog (LOG_INFO, "\tdhcp_msg->yiaddr = %u.%u.%u.%u",
|
|
((unsigned char *)&dhcp_msg->yiaddr)[0], ((unsigned char *)&dhcp_msg->yiaddr)[1],
|
|
((unsigned char *)&dhcp_msg->yiaddr)[2], ((unsigned char *)&dhcp_msg->yiaddr)[3]);
|
|
syslog (LOG_INFO, "\tdhcp_msg->siaddr = %u.%u.%u.%u",
|
|
((unsigned char *)&dhcp_msg->siaddr)[0], ((unsigned char *)&dhcp_msg->siaddr)[1],
|
|
((unsigned char *)&dhcp_msg->siaddr)[2], ((unsigned char *)&dhcp_msg->siaddr)[3]);
|
|
syslog (LOG_INFO, "\tdhcp_msg->giaddr = %u.%u.%u.%u",
|
|
((unsigned char *)&dhcp_msg->giaddr)[0], ((unsigned char *)&dhcp_msg->giaddr)[1],
|
|
((unsigned char *)&dhcp_msg->giaddr)[2], ((unsigned char *)&dhcp_msg->giaddr)[3]);
|
|
syslog (LOG_INFO, "\tdhcp_msg->sname = \"%s\"", dhcp_msg->sname);
|
|
syslog (LOG_INFO, "\tServer 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]);
|
|
}
|
|
|
|
#endif
|