#include <assert.h>
#include "dhcp.h"
#include "global.h"
#include "utils.h"
net_config netconfig = { 0x00 };
char *IfName = DEFAULT_IFNAME;
int IfName_len = DEFAULT_IFNAME_LEN;
//void *(*currState)() = &dhcpReboot;
int DebugFlag = 1;
unsigned int lease_time;
unsigned LeaseTime = DEFAULT_LEASETIME;
time_t TimeOut = DEFAULT_TIMEOUT;
int magic_cookie = 0;
unsigned short dhcpMsgSize = 0;
unsigned nleaseTime = 0;
int error_l = 0; // contain error_l number accur in state machine
static int dhcpSocket = -1;
unsigned short ip_id;
static short int narpCheck = 0;
dhcpOptions DhcpOptions;
dhcpInterface DhcpIface;
udpipMessage UdpIpMsgSend, UdpIpMsgRecv;
unsigned char ClientHwAddr[ETH_ALEN];
struct ip *ipSend = (struct ip *)((struct udpiphdr *)UdpIpMsgSend.udpipmsg)->ip;
struct ip *ipRecv = (struct ip *)((struct udpiphdr *)UdpIpMsgRecv.udpipmsg)->ip;
dhcpMessage *DhcpMsgSend = (dhcpMessage *)&UdpIpMsgSend.udpipmsg[sizeof(udpiphdr)];
dhcpMessage *DhcpMsgRecv = (dhcpMessage *)&UdpIpMsgRecv.udpipmsg[sizeof(udpiphdr)];
struct timeval stStart,stCurtime;
unsigned char dhcp_success = 0;
pthread_t g_timeoutcheck_thread = 0;
static void *dhcptimeoutcheck_thread(void)
{
unsigned int diff = 0;
prctl(PR_SET_NAME, "#DHCP_LEASE", 0,0,0);
pthread_detach(pthread_self());
while(1)
{
usleep(100000);
if (dhcp_success == 1)
{
gettimeofday(&stCurtime,NULL);
diff = (unsigned int)(stCurtime.tv_sec - stStart.tv_sec);
if (diff > lease_time-lease_time/2)
{
dhcp_success = 0;
dhcpReBound();
}
}
}
g_timeoutcheck_thread = 0;
return NULL;
}
int dhcp_run(int iWiFi )
{
// Reset status
dhcp_success = 0;
memset(&netconfig, 0x00, sizeof(netconfig));
// End
if(iWiFi == 1)
{
IfName = WIFI_IFNAME;
IfName_len = WIFI_IFNAME_LEN;
}
else
{
IfName = DEFAULT_IFNAME;
IfName_len = DEFAULT_IFNAME_LEN;
}
void *(*currState)(void) = &dhcpReboot;
if (getuid())
{
zPrintf(DEBUG_eErr,"%s(%d):not a superuser\n", __FILE__, __LINE__);
return ERR_NOROOT;
}
memset(&DhcpOptions, 0, sizeof(dhcpOptions));
magic_cookie = htonl(MAGIC_COOKIE);
dhcpMsgSize = htons(sizeof(dhcpMessage));
nleaseTime = htonl(LeaseTime);
do {
if ((currState=(void *(*)(void))currState()) == NULL)
{
zPrintf(DEBUG_eWrn,"dhcp run return error!\n");
return error_l;
}
} while (currState != &dhcpBound);
dhcpBound();
dhcpStop();
return 0; // success
}
void *dhcpStart()
{
int o = 1, i=0;
struct ifreq ifr;
struct sockaddr_pkt sap;
short int saved_if_flags;
memset(&ifr,0,sizeof(struct ifreq));
memcpy(ifr.ifr_name,IfName,IfName_len);
if (dhcpSocket != -1)
{
close(dhcpSocket);
dhcpSocket = -1;
}
dhcpSocket = socket(AF_PACKET,SOCK_PACKET,htons(ETH_P_ALL));
if (dhcpSocket == -1)
{
zPrintf(DEBUG_eErr,"%s(%d):dhcpStart:socket:%s\n", __FILE__, __LINE__, strerror(errno));
error_l = ERR_SOCKET;
return NULL;
}
do {
i++;
if ( i>1 )
zPrintf(DEBUG_eMsg,"dhcpStart: retrying MAC address request "
"(returned %02x:%02x:%02x:%02x:%02x:%02x)",
ClientHwAddr[0],ClientHwAddr[1],ClientHwAddr[2],
ClientHwAddr[3],ClientHwAddr[4],ClientHwAddr[5]);
if (ioctl(dhcpSocket,SIOCGIFHWADDR,&ifr) < 0)
{
zPrintf(DEBUG_eErr,"%s(%d):dhcpStart:ioctl:%s\n", __FILE__, __LINE__, strerror(errno));
error_l = ERR_SOCKET;
close(dhcpSocket);
dhcpSocket = -1;
return NULL;
}
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER && ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE802)
{
zPrintf(DEBUG_eErr,"%s(%d):dhcpStart: interface %s is not Ethernet or 802.2 Token Ring\n",
__FILE__, __LINE__, ifr.ifr_name);
error_l = ERR_SOCKET;
close(dhcpSocket);
dhcpSocket = -1;
return NULL;
}
//added by Snoopy 2006-1-16, hold timeout
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;//100000;//20ms
if (setsockopt(dhcpSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout) < 0)
{
close(dhcpSocket);
dhcpSocket = -1;
return NULL;
}
if (setsockopt(dhcpSocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof timeout) < 0)
{
close(dhcpSocket);
dhcpSocket = -1;
return NULL;
}
//end
if (setsockopt(dhcpSocket,SOL_SOCKET,SO_BROADCAST,&o,sizeof(o)) < -1)
{
zPrintf(DEBUG_eErr,"%s(%d):dhcpStart:setsockopt:%s\n", __FILE__, __LINE__, strerror(errno));
error_l = ERR_SOCKET;
close(dhcpSocket);
dhcpSocket = -1;
return NULL;
}
if (ioctl(dhcpSocket,SIOCGIFFLAGS,&ifr) < 0)
{
zPrintf(DEBUG_eErr,"%s(%d):dhcpStart:ioctl:%s\n", __FILE__, __LINE__, strerror(errno));
error_l = ERR_SOCKET;
close(dhcpSocket);
dhcpSocket = -1;
return NULL;
}
saved_if_flags = ifr.ifr_flags;
ifr.ifr_flags = saved_if_flags | IFF_UP | IFF_BROADCAST | IFF_NOTRAILERS | IFF_RUNNING;
if (ioctl(dhcpSocket,SIOCSIFFLAGS,&ifr))
{
zPrintf(DEBUG_eErr,"%s(%d):dhcpStart:ioctl:%s\n", __FILE__, __LINE__, strerror(errno));
error_l = ERR_SOCKET;
close(dhcpSocket);
dhcpSocket = -1;
return NULL;
}
memset(&sap,0,sizeof(sap));
sap.spkt_protocol = htons(ETH_P_ALL);
memcpy(sap.spkt_device,IfName,IfName_len);
sap.spkt_family = AF_PACKET;
if (bind(dhcpSocket,(struct sockaddr*)&sap,sizeof(struct sockaddr)) == -1)
zPrintf(DEBUG_eErr,"%s(%d):dhcpStart:bind:%s\n", __FILE__, __LINE__, strerror(errno));
memcpy(ClientHwAddr,ifr.ifr_hwaddr.sa_data,ETH_ALEN);
if (DebugFlag)
zPrintf(DEBUG_eMsg,"dhcpcd: MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n",
ClientHwAddr[0], ClientHwAddr[1], ClientHwAddr[2],
ClientHwAddr[3], ClientHwAddr[4], ClientHwAddr[5]);
} while (!ClientHwAddr[0] &&
!ClientHwAddr[1] &&
!ClientHwAddr[2] &&
!ClientHwAddr[3] &&
!ClientHwAddr[4] &&
!ClientHwAddr[5] &&
i<HWADDR_TRIES );
ip_id = time(NULL)&0xffff;
srandom(ip_id); // seed for random()
return (void*)&dhcpInit;
}
void *dhcpReboot()
{
struct ifreq ifr;
struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr);
if (dhcpStart() == NULL)
return NULL;
memset(&DhcpOptions,0,sizeof(DhcpOptions));
memset(&DhcpIface,0,sizeof(dhcpInterface));
memset(&DhcpIface,0,sizeof(dhcpInterface));
memset(&ifr,0,sizeof(struct ifreq));
memcpy(ifr.ifr_name,IfName,IfName_len);
p->sin_family = AF_INET;
if (ioctl(dhcpSocket,SIOCGIFADDR,&ifr) == 0)
DhcpIface.ciaddr=p->sin_addr.s_addr;
classIDsetup();
clientIDsetup();
return (void*)&dhcpInit;
}
void *dhcpInit()
{
releaseDhcpOptions();
#ifdef DEBUG
zPrintf(DEBUG_eErr,"ClassID = \"%s\"\n", DhcpIface.class_id);
zPrintf(DEBUG_eErr,"ClientID = \"%u.%u.%u.%02X.%02X.%02X.%02X.%02X.%02X\"\n",
DhcpIface.client_id[0],DhcpIface.client_id[1],DhcpIface.client_id[2],
DhcpIface.client_id[3],DhcpIface.client_id[4],DhcpIface.client_id[5],
DhcpIface.client_id[6],DhcpIface.client_id[7],DhcpIface.client_id[8]);
#endif
if (DebugFlag)
zPrint