Changing between Dhcp & Static IP

Discussion to talk about software related topics only.
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Changing between Dhcp & Static IP

Post by SeeCwriter »

I'm trying to be able to switch between DHCP and Static IP without a reboot and I'm finding a lot of success.

I used the example on pg 27 of NNDKprogman.pdf as the basis. What happens is, I boot up (NANO54415) in DHCP. All is fine. I have the board setup to send broadcast UDP datagrams twice a second. I send a command to the board to switch to static ip. It will do it, and I see the datagrams are now coming from the static ip address. Where is crashes is trying to get back to DHCP. When I command it to DHCP mode, it hangs forever somewhere. The opposite also works one time. That is, I can boot up into Static IP mode, send a command to switch to DHCP, which works, then send another command to switch back to static, and it hangs again. A reboot will always go back to the last successfully commanded mode.

In the code below, a command to switch modes generates a call to RedoEthernet(), which is supposed to do it all.
I'm using v2.7.1 IDE.

Code: Select all

void RedoEthernet()
{
	// close all tcp/ip connections.
	close(listen_fd);
	for ( int i=FIRST_TCP_LINK; i<TOTAL_PROTOCOL_LINKS; i++ )
	{
		if (mandc[i].port == -1) continue;
		close(mandc[i].port);
		mandc[i].port = -1;     
	}

	EnableDHCP(false, 0);

	KillStack();

	if ( SS->use_dhcp  ) {
		InitializeStack();
		EnableDHCP( true, 5 );
	}
	else {
		InitializeStack( SS->ip_address, SS->ip_mask, SS->ip_gateway );
	}

	// Listen for new tcp/ip connections.
	listen_fd = listen(INADDR_ANY, TCPIP_PORT, 5);    

}

void EnableDHCP(BOOL enable, int wait_seconds)
{
	static int ethernet = GetFirstInterface();
	static DhcpObject *dhcp_client = new DhcpObject(ethernet);

	if (enable) dhcp_client->StartDHCP();
	else        dhcp_client->StopDHCP();
	
	if (enable && wait_seconds)
	{
		OSSemPend(&dhcp_client->NotifySem, wait_seconds*TICKS_PER_SECOND);     // if (return==OS_TIMEOUT) then it failed.
	}
	
}

SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Re: Changing between Dhcp & Static IP

Post by SeeCwriter »

The first sentence of my original post should read:

I'm trying to be able to switch between DHCP and Static IP without a reboot and I'm NOT finding a lot of success.
sblair
Posts: 162
Joined: Mon Sep 12, 2011 1:54 pm

Re: Changing between Dhcp & Static IP

Post by sblair »

Here's what I do when I'm switching modes and it works fine on MOD54415

Code: Select all

//Reset Ethernet Link
		if(NV_Settings.IPMode == MODE_DHCP)
			InitializeEthernet();
		else
		{
			ChangeRuntimeIPSettings(CONFIG_IF_ID_ETHERNET, // Use first Config Record, 0
																	cr->ip_Addr, // New IP address
																	cr->ip_Mask, // New IP mask
																	cr->ip_GateWay, // New IP gateway
																	cr->ip_DNS_server); // New IP dns
		}


/************************************************/
/* void InitializeEthernet()        			*/
/************************************************/
/* SMB 10/4/2011                                */
/* Get an IP Address.  If non-static then DHCP  */
/* or generate an Auto-IP address           */
/************************************************/
void InitializeEthernet()
{
	unsigned char i = 0;
	unsigned char temp = 0;
	DhcpObject *pDhcpObj;
	pDhcpObj = new DhcpObject(CONFIG_IF_ID_ETHERNET);


	siprintf(DHCPname, NV_Settings.HostName);
	pDHCPOfferName = DHCPname;

	/**** NNDK bug:  Network cold boots in half duplex.  Should be fixed in 2.7.0 or later. ***/

	 // Check network connection for Full duplex
	if(EtherLink())
	{
		if( !EtherDuplex() )
		{
			// Force re-negotiate
#ifdef NNDK_2_6_7		//ToDo:  New NNDK issue.  Under NNDK 2.7.x this call no longer compiles.  But the root issue SHOULD be fixed that caused us to add this code.
#ifndef _DEBUG						//ToDo: NNDK 2.6.7 issue when compiling for Debug this isn't being declared in the debug libs.
			ManualEthernetConfig( true, true, true );
#endif
#else //NNDK 2.7.x
			enet0.ManualEthernetConfig( true, true, true );	//New method under NNDK 2.7.x
#endif //NNDK_2_6_7
			// Wait for network
			// should come up as we are connected to switch
			i = 5;
			while(!EtherLink() || !i--)
				OSTimeDly(TICKS_PER_SECOND);
		}
	}

	 if(EtherLink())
	{
		iprintf("Network up ok\n");
		if( EtherSpeed100() ) iprintf("100 Mbit  ");
		if( EtherDuplex() ) iprintf("Full duplex\n"); else iprintf("Half duplex\n");
	}
	else
		iprintf("Network is down\n");


	//If we are set to DHCP....
	if (EthernetIP == 0 || NV_Settings.IPMode == MODE_DHCP)
	{
		NV_Settings.IPMode = MODE_DHCP;
		pDhcpObj->StartDHCP();

		// Pend on semaphore to verify an address was obtained...
		if (OSSemPend(&(pDhcpObj->NotifySem),
				10 * TICKS_PER_SECOND) == OS_TIMEOUT) //Wait 10 seconds
		{
			//DHCP Failed....

			pDhcpObj->StopDHCP(); //Stop DHCP

			//Generate Auto-IP
			iprintf("DHCP Failed.  Generating Auto-IP\n");
			GetAutoIPAddress();
			NV_Settings.IPMode = MODE_AUTO_IP;

			//DEBUG display
			DisplayRuntimeIPSettings(CONFIG_IF_ID_ETHERNET);

			//Verify selected IP is not already in use.
			i = 0;
			do
			{
				temp = IsMyAddressUsedArpDetect(1 * TICKS_PER_SECOND,
						CONFIG_IF_ID_ETHERNET);
				iprintf("is my IP addy used?  %d, count %d\n\n", temp, i);
				i++;
			} while (temp && i < 10); //make 10 attempts.
		}
	} else
		NV_Settings.IPMode = MODE_STATIC_IP;

	NetbiosEnableNameService(pDHCPOfferName, TRUE);
}
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: Changing between Dhcp & Static IP

Post by dciliske »

You probably want to actually use the DHCPObject pointer that's part of the InterfaceBlock instead of your own stand alone one. Now that I think about this, you're probably doing this because of the DHCP example... Anyways, here's the relevant snippet from GetDHCPAddress

Code: Select all

   dhcpIntf = GetInterFaceBlock(intf);
   pobj = dhcpIntf->dhcpClient;

   // If the interface didn't have an associated DHCP object, create it
   if (pobj == NULL)
   {
      pobj = new  DhcpObject( intf );
   }
   int state = pobj->GetDHCPState();
   if ( state != SDHCP_NOTSTARTED )
   {
       if ( state == SBOOTP_TRANSMITTING || state == SBOOTP_DONE )
       {
           pobj->StopBOOTP();
       }
       else
       {
           pobj->StopDHCP();
       }
   }
   pobj->StartDHCP(); //Start DHCP
When a DHCPObject is created, it's registered to it's interface's InterfaceBlock. I'm not entirely certain what will happen if you replace the DHCPObject on the IFB with a different one if the first still exists...

-Dan
Dan Ciliske
Project Engineer
Netburner, Inc
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Re: Changing between Dhcp & Static IP

Post by SeeCwriter »

I tried using function GetInterfaceBlock(), but I get compiler "Not declared in this scope."

I've included all the header files in the example program in NNDKProgman.pdf, page 23,24.

I've searched (grep) all the NB system files and include files, all the Nano system files and include files, and that function doesn't appear anywhere. Did the name change since the manual was written?
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Re: Changing between Dhcp & Static IP

Post by SeeCwriter »

Never mind. I misspelled the function. I missed the uppercase 'F'.
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: Changing between Dhcp & Static IP

Post by dciliske »

That would be because someone who shall remain nameless :roll: has spelling and capitalization problems... The 'F' is capitalized. It's located in 'netinterface.h'. Unfortunately, it's used in too many things for us to correct the spelling and not break something or somebody else's code.

-Dan
Dan Ciliske
Project Engineer
Netburner, Inc
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Re: Changing between Dhcp & Static IP

Post by SeeCwriter »

I think I changed my program to match the logic flow of sample program in section 7.3 of NNKProgman.pdf.
The Nano is booting up in Static IP mode. I can't AutoUpdate and I can't connect via TCP/IP. But the Nano is
sending UDP broadcast datagrams with the correct IP address.

Code: Select all

int FirstInterface;		// First Ethernet Interface.
InterfaceBlock *ib;		// Interface data of first interface.
DhcpObject *dhcp_client;

void UserMain()
{
  iprintf("\r\nApplication started\r\n");
	OSTimeDly(TICKS_PER_SECOND/10);
  
  LoadSystemParameters();
  
  StartEthernet();
  
  while( 1 )
  {
    SendUDPDataGram();
    OSTimeDly(TICKS_PER_SECOND/2);
  }  
}

void StartEthernet()
{
	InitializeStack();

	FirstInterface = GetFirstInterface();
	ib = GetInterFaceBlock( FirstInterface );
	dhcp_client = new DhcpObject( FirstInterface );

	if ( SS->use_dhcp  ) {
		EnableDHCP( true, 5 );
	}
	else {
		ChangeRuntimeIPSettings( ib, SS->ip_address, SS->ip_mask, SS->ip_gateway, SS->ip_dns );
	}

	// Only change Priority after Ethernet initialization.
	OSChangePrio(MAIN_PRIO);
	
	EnableAutoUpdate();
	StartHTTP();
	EnableSmartTraps();
	EnableTaskMonitor();
}

void EnableDHCP(BOOL enable, int wait_seconds)
{
	if (enable) dhcp_client->StartDHCP();
	else        dhcp_client->StopDHCP();
	
	if (enable && wait_seconds)
	{
		if ( OSSemPend(&dhcp_client->NotifySem, wait_seconds*TICKS_PER_SECOND) == OS_TIMEOUT ) { 
			iprintf( "DHCP Server Not Found!\r\n");
		}
	}
}

void ChangeRuntimeIPSettings( InterfaceBlock *ib_, IPADDR IpAddr, IPADDR IpMask, IPADDR IpGate, IPADDR IpDNS )
{
	iprintf("Old Settings:\r\n");
	iprintf("   IP:    "); ShowIP(ib->netIP); 		iprintf("\r\n");
	iprintf("   Mask:  "); ShowIP(ib->netIpMask); iprintf("\r\n");
	iprintf("   Gway:  "); ShowIP(ib->netIpGate); iprintf("\r\n");
	iprintf("   DNS:   "); ShowIP(ib->netDNS); 		iprintf("\r\n");
	iprintf("-------------------------------\r\n");
	ib_->netIP			= IpAddr;
	ib_->netIpMask	= IpMask;
	ib_->netIpGate	= IpGate;
	ib_->netDNS			= IpDNS;
	iprintf("New Settings:\r\n");
	iprintf("   IP:    "); ShowIP(ib->netIP); 		iprintf("\r\n");
	iprintf("   Mask:  "); ShowIP(ib->netIpMask); iprintf("\r\n");
	iprintf("   Gway:  "); ShowIP(ib->netIpGate); iprintf("\r\n");
	iprintf("   DNS:   "); ShowIP(ib->netDNS); 		iprintf("\r\n");
	iprintf("-------------------------------\r\n");
}

Here is the printout at bootup:
Old Settings:
IP: 0.0.0.0
Mask: 0.0.0.0
Gway: 0.0.0.0
DNS: 0.0.0.0
-------------------------------
New Settings:
IP: 10.250.5.127
Mask: 255.255.255.0
Gway: 0.0.0.0
DNS: 0.0.0.0
-------------------------------
Starting UDP Read Task

Application started
------------------------------------------

I haven't even gotten back to trying to switch modes yet. What am I missing?
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Re: Changing between Dhcp & Static IP

Post by SeeCwriter »

I tested switching between Static and DHCP, and it appears to work. When in DHCP mode, I can connect via TCP/IP and communicate, but not in Static IP mode.

I can use UDP in both modes, which is how I do most of my communication.

I noticed when in DHCP mode, printing the value of EthernetIpGate shows a valid ip address. But when in
Static IP, the value is always 0.0.0.0. Yet, printing out ib->netIpGate shows a valid ip when in Static.

Is that a clue to what may be happening?
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: Changing between Dhcp & Static IP

Post by dciliske »

Yup. It says you have the wrong interface block. Something is horribly wrong here and I don't know what. So, if you look at ip.h, you'll see that all the EthernetIP vars are the dereferenced FirstInterFace vars. And the FirstInterFace vars are pointers to the first InterfaceBlock that is registered, which is the Ethernet. The specific code that registers an interface is this:

Code: Select all

int RegisterInterface( InterfaceBlock *pIfBlock )
{
for ( int i = 1; i < MAX_INTERFACES; i++ )
   {
      if ( pblocks[i] == NULL )
      {
         pblocks[i] = pIfBlock;
#if defined MULTIHOME || defined AUTOIP
	     pIfBlock->bMultiHome=FALSE;
#endif

         if ( i == 1 )
         {
            FirstInterFaceIP = &( pIfBlock->netIP );
            FirstInterFaceMask = &( pIfBlock->netIpMask );
            FirstInterFaceGate = &( pIfBlock->netIpGate );
            FirstInterFaceDNS = &( pIfBlock->netDNS );
         }
         return i;
      }
   }
   return 0;
}
So, if EthernetIPGate is reporting 0.0.0.0, but your InterfaceBlock is reporting a valid address, you have the wrong block. If I had to guess, you actually got a handle to the AutoIP block by mistake, somehow, and you're modifying that one, but the base block is not set and things are breaking. That's my theory at least...

Take a look at the address where ib is pointing versus where EthernetIPGate is located, if they don't seem to be within a InterfaceBlock size, there's your answer.

-Dan
Dan Ciliske
Project Engineer
Netburner, Inc
Post Reply