本节中W5500作为DHCP客户端,路由器作为DHCP服务器端。在DHCP请求的过程中,包括4个主要的阶段:发现阶段、提供阶段、选择阶段以及确认阶段。
下面来说一下整个DHCP请求流程。
首先W5500客户端发送DHCP DISCOVER消息(IP地址租用申请),这个消息通过广播方式发出,所有网络中的DHCP服务器都将接收到这个消息。随后,网络中的DHCP服务器会回应一个DHCPOFFER消息(IP地址租用提供),由于这个时候客户端还没有网络地址,所以DHCP OFFER也是通过广播的方式发送出去的。 后,向该服务器发送DHCP REQUEST消息。在DHCP REQUEST消息中将包含客户端然申请的IP地址。最后,DHCP服务器将回送DHCP ACK的响应消息来通知客户端可以使用该IP地址,该确认里面包含了分配的IP地址和该地址的一个稳定期限的租约(默认是8天),并同时更新DHCP数据库。
主循环代码如下:while(1) { DHCP_run(); } uint8_t DHCP_run(void) { 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 ) { 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; 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; case STATE_DHCP_REQUEST : if (type == DHCP_ACK) { #ifdef _DHCP_DEBUG_ printf("> Receive DHCP_ACK\r\n"); #endif if (check_DHCP_leasedIP()) { 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(); hcp_state = STATE_DHCP_LEASED; } else { 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; 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; 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; }DHCP的测试步骤如下