Good to hear it's working!
I added some more stuff today. Like I expected, behaviour would be the same if the physical link is OK but no DHCP server is present. I added some code to automatically restart DHCP if the DHCP client is not in the BOUND state. This is done every minute.
First, we need a way to read the DHCP state from outside DHCPCLNT.C. I added a function to do this in DHCPCLNT.C:
/* FUNCTION: dhc_get_state()
*
* dhc_get_state() : Get the actual state for the interface
*
*
* PARAM1: int iface
*
* RETURNS: unsigned int state
*/
unsigned int dhc_get_state(int iface)
{
return (unsigned int) dhc_states[iface].state; /* Return the actual state */
}
#endif /* DHCP_CLIENT - ifdef out whole file */
The rest of the modifications are done in timeouts.c.
We need to know the definitions of the DHCP states in timeouts.c:
#ifdef DHCP_CLIENT
#include "dhcpclnt.h"
extern int dhc_discover(int iface);
extern int dhc_second(void);
#endif
Then, we need to define the timeout time for restarting the DHCP sequence, and a variable to keep track of time:
#ifdef DHCP_CLIENT
#define DHCP_AUTO_RESTART_TIME (60*TPS) //auto restart DHCP 60 seconds after timeout
static char link_down_detect;
static u_long dhcp_timeout_timer = 0;
void set_link_down_detect(char link_status)
{
link_down_detect = link_status;
}
char read_link_down_detect(void)
{
return link_down_detect;
}
#endif And last, the code to restart DHCP:
#ifdef DHCP_CLIENT
if (dhc_get_state(0 /*iface*/) != DHCS_BOUND) // (there's only one interface!)
{
if ((cticks - dhcp_timeout_timer) > DHCP_AUTO_RESTART_TIME)
{
link_down_detect = TRUE; // this will restart DHCP
dhcp_timeout_timer = cticks;
}
}
else
dhcp_timeout_timer = cticks;
while(!(fec_mii_read(FEC_PHY0, PHY_REG_SR, &mymrdata))) // read status register
;
if ((mymrdata & PHY_R1_LS) == 0)
link_down_detect = TRUE; // detect if link is down
else
{
if (link_down_detect == TRUE)
{
if( POWERUP_CONFIG_DHCP_ENABLED )
{
//for (iface = 0; iface < STATIC_NETS; iface++)
//{
dprintf("\nRestarting DHCP...\n");
dhc_set_callback_dhc_main_ipset(0 /*iface*/); // (there's only one interface!)
dhc_state_init(0 /*iface*/, TRUE);
//}
}
}
link_down_detect = FALSE;
}
dhc_second();
#endif
Because the DTRAPs that appear after the initial 5 minutes timeout make working with the console a little problematic, I removed that DTRAP from the code, which is located in
DNSCLNT.C:
static int
dnc_sendreq(struct dns_querys * dns_entry)
{
PACKET pkt;
struct dns_hdr * dns; /* outgoing dns header */
char * cp; /* scratch pointer for building question field */
int server; /* index of server to use */
/* figure out which server to try */
for (server = 0; server < MAXDNSSERVERS; server++)
{
if (dns_servers[server] == 0L)
break;
}
if (server == 0) /* no servers set? */
{
//dtrap();
return ENP_LOGIC;
}
server = dns_entry->tries % server;
At least, that was the DTRAP that did it for me...
For convenience, I once again added the modified source code in the attached ZIP file.
It is possible to reduce those initial 5 minutes to ease testing somewhat. 5 Minutes is a long time to wait! But don't make the time shorter than 2 minutes as you will then start seeing some severe errors!
The time is defined in dhcsetup.c:
if(dhcnets == 0) /* no nets doing DHCP? */
return;
/* wait for DHCP activity to conclude */
// while (((cticks - dhcp_started) < (30*TPS*10)) && // 5 minutes
while (((cticks - dhcp_started) < (120*TPS)) && // 2 minutes
(dhc_alldone() == FALSE))
{
/* let other tasks spin. This is required, since some systems
* increment cticks in tasks, or use a polling task to receive
* packets. Without this activity this loop will never exit.
*/
tk_yield();
#ifndef SUPERLOOP
/* In non-superloop systems the pktdemux task won;t be running
* yet since the network has not been marked as UP. Force processing
* of received packets here.
*/
if (rcvdq.q_len)
pktdemux();
#endif
}