C语言代码分析:dhcp_start函数
本文将对以下代码进行详细的解析和解释:
/**
* @ingroup dhcp4
* Start DHCP negotiation for a network interface.
*
* If no DHCP client instance was attached to this interface,
* a new client is created first. If a DHCP client instance
* was already present, it restarts negotiation.
*
* @param netif The lwIP network interface
* @return lwIP error code
* - ERR_OK - No error
* - ERR_MEM - Out of memory
*/
err_t
dhcp_start(struct netif *netif)
{
struct dhcp *dhcp;
err_t result;
LWIP_ASSERT_CORE_LOCKED();
LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
/* check MTU of the netif */
if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
return ERR_MEM;
}
/* no DHCP client attached yet? */
if (dhcp == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): mallocing new DHCP client\n"));
dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
if (dhcp == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
return ERR_MEM;
}
/* store this dhcp client in the netif */
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
/* already has DHCP client attached */
} else {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
if (dhcp->pcb_allocated != 0) {
dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */
}
/* dhcp is cleared below, no need to reset flag*/
}
/* clear data structure */
memset(dhcp, 0, sizeof(struct dhcp));
/* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
if (dhcp_inc_pcb_refcount() != ERR_OK) {
/* ensure DHCP PCB is allocated */
return ERR_MEM;
}
dhcp->pcb_allocated = 1;
if (!netif_is_link_up(netif)) {
/* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */
dhcp_set_state(dhcp, DHCP_STATE_INIT);
return ERR_OK;
}
/* (re)start the DHCP negotiation */
result = dhcp_discover(netif);
if (result != ERR_OK) {
/* free resources allocated above */
dhcp_release_and_stop(netif);
return ERR_MEM;
}
return result;
}
1. 函数介绍
dhcp_start
函数是lwIP协议栈中的一个函数,这个函数的作用是开始一个网络接口的DHCP协商过程。
如果没有DHCP客户端实例附加到这个接口,那么首先会创建一个新的客户端。如果已经有一个DHCP客户端实例,那么就会重新开始协商。
函数的原型为:
err_t dhcp_start(struct netif *netif);
2. 参数解析
dhcp_start
函数只有一个参数,即struct netif *netif
,表示需要开始DHCP协商的网络接口。
3. 代码详解
3.1 确认核心已锁定
LWIP_ASSERT_CORE_LOCKED();
这个宏用于确保在调用dhcp_start
函数的时候,lwIP的核心已经被锁定,防止并发问题。
3.2 检查网络接口是否有效
LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
这里检查传入的网络接口是否为NULL,如果为NULL,那么就返回错误。并检查网络接口是否在运行状态,如果不在运行状态,同样返回错误。
3.3 获取DHCP客户端数据
dhcp = netif_dhcp_data(netif);
这行代码获取网络接口关联的dhcp数据。
3.4 检查网络接口MTU
if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
return ERR_MEM;
}
这段代码检查了网络接口的MTU(最大传输单元)是否小于DHCP要求的最小值,如果小于,那么返回内存错误。
3.5 分配和初始化DHCP客户端
if (dhcp == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): mallocing new DHCP client\n"));
dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
if (dhcp == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
return ERR_MEM;
}
/* store this dhcp client in the netif */
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
/* already has DHCP client attached */
} else {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
if (dhcp->pcb_allocated != 0) {
dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */
}
/* dhcp is cleared below, no need to reset flag*/
}
这段代码首先检查是否已经有DHCP客户端附加到网络接口,如果没有,那么就分配一个新的并关联到网络接口。如果已经有,那么就重启DHCP配置。同时,如果DHCP的pcb已经分配,那么就减少其引用计数。
3.6 清理DHCP客户端数据结构
/* clear data structure */
memset(dhcp, 0, sizeof(struct dhcp));
这段代码清理了DHCP客户端数据结构,为后续的操作做准备。
3.7 确保DHCP PCB已分配
if (dhcp_inc_pcb_refcount() != ERR_OK) {
/* ensure DHCP PCB is allocated */
return ERR_MEM;
}
dhcp->pcb_allocated = 1;
这段代码确保了DHCP的PCB已经被分配。
3.8 检查网络接口链路状态
if (!netif_is_link_up(netif)) {
/* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */
dhcp_set_state(dhcp, DHCP_STATE_INIT);
return ERR_OK;
}
这段代码检查了网络接口的链路状态,如果链路没有启动,那么就将DHCP的状态设置为INIT,并等待dhcp_network_changed()
函数调用dhcp_discover()
函数。
3.9 启动或重启DHCP协商
/* (re)start the DHCP negotiation */
result = dhcp_discover(netif);
if (result != ERR_OK) {
/* free resources allocated above */
dhcp_release_and_stop(netif);
return ERR_MEM;
}
return result;
这段代码试图启动或重启DHCP协商,如果失败,那么就释放之前分配的资源,并返回内存错误。
4. 总结
dhcp_start
函数是lwIP协议栈中非常重要的一个函数,它负责开始网络接口的DHCP协商过程。这个函数的实现涉及到了很多网络协议的知识,包括网络接口的状态管理、DHCP协议的状态机、网络接口的MTU检查等等。
当你在使用lwIP进行网络开发的时候,理解这个函数的实现可以帮助你更好地理解lwIP是如何管理网络接口的,以及如何进行DHCP协商的。
5. 参考资料
- lwIP协议栈源码
2.《深入理解lwIP协议栈》 - lwIP Wiki ↗
以上就是对dhcp_start
函数的分析,希望对你有所帮助。如果你有任何问题,欢迎在评论区提问,我会尽力回答。