Xilinx代码分析: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. 参考资料

  1. lwIP协议栈源码
    2.《深入理解lwIP协议栈》
  2. lwIP Wiki ↗

以上就是对dhcp_start函数的分析,希望对你有所帮助。如果你有任何问题,欢迎在评论区提问,我会尽力回答。

猜你喜欢

转载自blog.csdn.net/qq_24951479/article/details/131688769