Getting IP address from DHCP server(router)

This is a sample code for getting IP addresses from the DHCP Server nearby. DHCP is commonly applied in many different environments. It allows users to initialize the network configuration of their devices even if they do not have knowledge about the Internet. 

Normally the process would be divided into four parts: send a broadcast packet to search for a DHCP server around; wait until a response (packet from DHCP server) is received, which includes several sets of IP address as leases if there are more than one DHCP server around; send another broadcast packet to confirm using the IP address; wait for a packet from the respective DHCP server as acknowledgement and confirmation of the lease. Please look up DHCP for more details.


Before burning the bin file into your EVB:

      1. Connect W5500 EVB to the router/NAT that you are using, or any other device that allows you to connect to the internet

      2. Manually change the Network configuration:
          • Go to the definition of function “set_default()” (Should be inside device.c), make sure the subnet mask, local IP address, gateway and DNS are set according to the internet setting you are using with your router/NAT
      3. Rebuild the sample code and burn it into W5500EVB


Code Explanation


After boot or reboot W5500EVB, all necessary configurations are initialized.

int main()
{
  RCC_Configuration();
  NVIC_Configuration();
  Systick_Init(72);
  GPIO_Configuration();
  Timer_Configuration();
  USART1_Init();
  at24c16_init();
  printf("W5500 EVB initialization over.\r\n");
  
  Reset_W5500();
  WIZ_SPI_Init();
  printf("W5500 initialized!\r\n");  
  
  set_default(); 	
  init_dhcp_client();

  while(1)
  {
    DHCP_run();
  }
}               
                                             
/******************


These are all the necessary
 initialization


********************/






/******************


These are messages shown in 
serial window for debugging
 

********************/

DHCP_run() is divided into five states: Ready, Discover, Request, Leased and Re-request. Before going into switch statement, the function checks:

  • If ‘dhcp_state ==STATE_DHCP_STOP’ the loop would stop forever
  • If the state of socket is UDP so that W5500EVB can run as a DHCP client. 

After assuring the above, it parses the packet if there is any, and gets the details. The parsing process would be kept looping. Then it goes into switch statement

uint8_t DHCP_run(void)//20180625
{
  uint8_t  type;
  uint8_t  ret;

  if(dhcp_state == STATE_DHCP_STOP) return DHCP_STOPPED;

  if(getSn_SR(SOCK_DHCP) != SOCK_UDP)
  socket(SOCK_DHCP, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00);

  ret = DHCP_RUNNING;	
  type = parseDHCPMSG();
	
  switch ( dhcp_state ) {

State_DHCP_Ready

This is the Initial state after all necessary initialization(Refer to function init_dhcp_client()). It clears the buffer for IP address being allocated by DHCP server, send a broadcast packet to search for DHCP server around, and turn into State_Discover.

case STATE_DHCP_READY :

  DHCP_allocated_ip[0] = 0;
  DHCP_allocated_ip[1] = 0;
  DHCP_allocated_ip[2] = 0;
  DHCP_allocated_ip[3] = 0;

  send_DHCP_DISCOVER();
  dhcp_time = 0;
  dhcp_state = 
  STATE_DHCP_DISCOVER;
  break;
/***************


Clear buffer



send a broadcast packet to 
search for DHCP server around,


****************/

State_DCHP_Discover

Detect whether there is a lease offer from any DHCP Server

If there is, get the IP from RX register and store it into our own buffer for IP address being allocated. Then a broadcast ‘Request’ packet would be sent to DHCP server to confirm accepting the offer. Then it turns into State_Request.

case STATE_DHCP_DISCOVER :
  if (type == DHCP_OFFER)
  {

#ifdef _DHCP_DEBUG_
  printf("> Receive DHCP_OFFER\r\n");
#endif

    DHCP_allocated_ip[0] = pDHCPMSG->yiaddr[0];
    DHCP_allocated_ip[1] = pDHCPMSG->yiaddr[1];
    DHCP_allocated_ip[2] = pDHCPMSG->yiaddr[2];
    DHCP_allocated_ip[3] = pDHCPMSG->yiaddr[3];
    send_DHCP_REQUEST();
    dhcp_time = 0;
    dhcp_state = STATE_DHCP_REQUEST;
  } 
  else 
    ret = check_DHCP_timeout();
  break;
/*************




printf() for debug


Get the IP from RX register 
and store it into our own 
buffer for IP address 
being allocated


Send request to DHCP Server



****************/

State_DHCP_Request

To check whether there is an acknowledgement packet from DHCP server about us accepting the offer.

If there is, check to see if the leased IP address from server is valid, and assign it to be W5500EVB’s own IP address in the subnet. It then turns into State_Leased. While if the IP allocated is invalid, it turns back into State_Ready and repeat the above states.

If there is no such packet received, it turns back into State_Discover and send the acceptance packet to the server again.

case STATE_DHCP_REQUEST :
  if (type == DHCP_ACK) 
  {

#ifdef _DHCP_DEBUG_
  printf("> Receive DHCP_ACK\r\n");
#endif

    if (check_DHCP_leasedIP()) 
    {
      // Network info assignment from DHCP
      printf("ip:%d.%d.%d.%d\r\n",DHCP_allocated_ip[0],DHCP_allocated_ip[1],DHCP_allocated_ip[2],DHCP_allocated_ip[3]);
      printf("sn:%d.%d.%d.%d\r\n",DHCP_allocated_sn[0],DHCP_allocated_sn[1],DHCP_allocated_sn[2],DHCP_allocated_sn[3]);
      printf("gw:%d.%d.%d.%d\r\n",DHCP_allocated_gw[0],DHCP_allocated_gw[1],DHCP_allocated_gw[2],DHCP_allocated_gw[3]);
      dhcp_ip_assign();
      reset_DHCP_timeout();
      dhcp_state = STATE_DHCP_LEASED;
    }

    else 
    {
      // IP address conflict occurred
      reset_DHCP_timeout();
      dhcp_ip_conflict();
      dhcp_state = STATE_DHCP_READY;
    }
  }
 
  else if (type == DHCP_NAK) 
  {

#ifdef _DHCP_DEBUG_
  printf("> Receive DHCP_NACK\r\n");
#endif

    reset_DHCP_timeout();
    dhcp_state = STATE_DHCP_DISCOVER;
  }

  else 
    ret = check_DHCP_timeout();
  break;
/****************







Check if the IP allocated is valid













IP allocated is invalid, 
start the process again









No packet is received from server,
it turns back into State_Discover and 
send the acceptance packet to the server again.





****************/

State_DHCP_Leased

For State_DHCP_Leased, it means W5500EVB has an IP address from the server already. During this state, W5500EVB would keep checking whether the lease time is over and a new request has to be sent, and move into State_Re-request. Or it would remain in this state until the lease time is over.

case STATE_DHCP_LEASED :
  ret = DHCP_IP_LEASED;	
	  
  if ((dhcp_lease_time != DEFAULT_LEASETIME) && ((dhcp_lease_time/2) < dhcp_time)) {

#ifdef _DHCP_DEBUG_
 printf("> Maintains the IP address \r\n");
#endif

    type = 0;
    OLD_allocated_ip[0] = DHCP_allocated_ip[0];
    OLD_allocated_ip[1] = DHCP_allocated_ip[1];
    OLD_allocated_ip[2] = DHCP_allocated_ip[2];
    OLD_allocated_ip[3] = DHCP_allocated_ip[3];
				
    DHCP_XID++;
    send_DHCP_REQUEST();				
    reset_DHCP_timeout();
    dhcp_state = STATE_DHCP_REREQUEST;
  }
  break;
/****************



checking whether the lease time is over 
and a new request has to be sent





Replace old allocated IP by
new allocated IP







****************/

State_DHCP_Re-request

W5500EVB turns into this state only when it runs continuously till the lease-time ends. A request was sent before going into this state. During this state, once an acknowledge packet is received, EVB checks whether the new allocated IP address remains the same as the old one. It it is, it turns back into State_Leased, else it updates the IP address.

case STATE_DHCP_REREQUEST :
  ret = DHCP_IP_LEASED;

  if (type == DHCP_ACK) {
    dhcp_retry_count = 0;
    if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] || 
	    OLD_allocated_ip[1] != DHCP_allocated_ip[1] ||
	    OLD_allocated_ip[2] != DHCP_allocated_ip[2] ||
	    OLD_allocated_ip[3] != DHCP_allocated_ip[3]) {
      ret = DHCP_IP_CHANGED;
      dhcp_ip_update();

#ifdef _DHCP_DEBUG_
  printf(">IP changed.\r\n");
#endif					
    }

#ifdef _DHCP_DEBUG_
  else printf(">IP is continued.\r\n");
#endif   

    reset_DHCP_timeout();
    dhcp_state = STATE_DHCP_LEASED;
  } 

  else if (type == DHCP_NAK) 
  {

#ifdef _DHCP_DEBUG_
  printf("> Receive DHCP_NACK, Failed to maintain ip\r\n");
#endif

    reset_DHCP_timeout();
    dhcp_state = STATE_DHCP_DISCOVER;
  } 

  else ret = check_DHCP_timeout();
  break;

  default :
    break;
  }
  return ret;
}

Remarks

In order to know entirely how DHCP client works, please look up the details of DHCP (Dynamic Host Configuration Protocol), especially the part of the structure of packets being sent and received. Self studying about the function parseDHCPMSG() may also help.