lwIp源码解析--DHCPv4

lwIp源码解析–DHCPv4

一、简介
   1.1 lwip版本
   lwip 2.1.2

   1.2 代码范围
   在lwip中包含了DHCPv4客户端的实现,文件路径:

    lwip-2.1.2\src\core\ipv4\dhcp.c   
    lwip-2.1.2\src\include\lwip\dhcp.h

   文件代码两千行左右,阅读难度不大。

二、DHCPv4流程和状态机
   没有找到电子版,所以在TCP/IP详解卷一中拍了对应照片。
   dhcpv4交互流程如下:
在这里插入图片描述
   dhcp消息头格式如下:
在这里插入图片描述
   dhcp客户端状态变化图:
在这里插入图片描述

三、DHCPv4源码
   3.1 启动客户端

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;
}

   解析如下:
   ①入参struct netif *netif 为lwip网卡对应接口;

   ②NETIF_FLAG_UP未置起,退出,正常情况下netif只要初始化,就要置NETIF_FLAG_UP标志;

    LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);

   ③获取netif中的dhcp客户端成员,dhcp的一个指针。存在netif的client_data[]中;

     dhcp = netif_dhcp_data(netif); 

   ④ 若netif的MTU小于 DHCP_MAX_MSG_LEN_MIN_REQUIRED(576)字节,认为不支持DHCP协议,返回错误;

   ⑤如果dhcp == NULL,说明之前并没有申请过DHCP客户端成员,则重新为其mem_malloc() 申请结构体,并且根据索引LWIP_NETIF_CLIENT_DATA_INDEX_DHCP放在NETIF的client_data中;

   ⑥ 如果dhcp != NULL,说明已经申请过DHCP结构体了,再看下是否申请过UDP的PCB结构体,如果已经申请过了dhcp->pcb_allocated != 0, 则调用函数dhcp_dec_pcb_refcount() ,释放掉原来的udp_pcb;

static void
dhcp_dec_pcb_refcount(void)
{
   
  LWIP_ASSERT("dhcp_pcb_refcount(): refcount error", (dhcp_pcb_refcount > 0));
  dhcp_pcb_refcount--;

  if (dhcp_pcb_refcount == 0) {
   
    udp_remove(dhcp_pcb);
    dhcp_pcb = NULL;
  }
}

   ⑦调用dhcp_inc_pcb_refcount() 重新申请udp_pcb, 发送方式为广播,绑定本地客户端端口68, connect服务器端口67。

static err_t
dhcp_inc_pcb_refcount(void)
{
   
  if (dhcp_pcb_refcount == 0) {
   
    LWIP_ASSERT("dhcp_inc_pcb_refcount(): memory leak", dhcp_pcb == NULL);

    /* allocate UDP PCB */
    dhcp_pcb = udp_new();

    if (dhcp_pcb == NULL) {
   
      return ERR_MEM;
    }

    ip_set_option(dhcp_pcb, SOF_BROADCAST);

    /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */
    udp_bind(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_CLIENT);
    udp_connect(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER);
    udp_recv(dhcp_pcb, dhcp_recv, NULL);
  }

  dhcp_pcb_refcount++;

  return ERR_OK;
}

   ⑧ dhcp_

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

同人与野

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值