文/告别年代 Email：byeyear@hotmail.com 基本流程 A. link up -> link down: 关闭 MAC 和 DMA； 调用 netif_set_link_down B. link down -> link up: 打开 MAC 和 DMA； 调用 netif_set_link_up C. 注意：当使用 RAW API 时，所有使用 RAW API 的代码（包括处理链路状态的代码）必须运行于同一线程环境。 代码分析 有四个函数和两个标志位和链路状态改变有关： A. netif_set_up 该函数设置 NETIF_FLAG_UP 标记，并在链路已 up 的情况下发送 arp 探测。 如果你的网络使用静态 IP，那么在 lwip 初始化时调用该函数； 如果你的网络使用 DHCP，那么 DHCP 成功后会帮你调用 netif_set_up。 B. netif_set_down 除非你需要关闭网络，否则一般不需要主动调用该函数。 C. netif_set_link_up 该函数设置 NETIF_FLAG_LINK_UP 标记，启动 DHCP 和 AutoIP，并在 NETIF_FLAG_UP 标记有效的情况下发送 arp 探测。 当链路从 down 变化为 up 时调用该函数。 注意：初始化时如果链路有效，low_level_init 将直接设置 NETIF_FLAG_LINK_UP，而不调用 netif_set_link_up 函数，避免在 lwip 没有完全初始化好时启动 DHCP。 D. netif_set_link_down 在链路从 up 变为 down 时调用该函数。 E. NETIF_FLAG_UP和NETIF_FLAG_LINK_UP 前者表示 lwip 协议栈已经就绪（已得到合法 IP 地址，且协议栈已准备好收发数据包）；后者表示链路层有效。 或者说，一个是软件（协议栈）就绪标志，一个是硬件（链路层）就绪标志。 F. 参考 lwip 代码中的 netif.h 文件对这两个标记的详细说明。 网上很多 port 代码不管是否使用 DHCP 都在 lwip 初始化时设置 NETIF_FLAG_UP，这是不正确的。 NETIF_FLAG_UP 必须在获得有效 IP 地址后才能置位，以保证顺利发送 ARP 探测。 情景分析 A. 静态 IP，初始化时链路有效 这是最简情况。驱动层会看到 Link 有效，并直接设置 NETIF_FLAG_LINK_UP。 随后 lwip 初始化过程中调用 netif_set_up，该函数设置 NETIF_FLAG_UP，并发送 arp 探测。 B. 静态 IP，初始化时链路无效 驱动层不会设置 NETIF_FLAG_LINK_UP。 lwip 初始化过程会调用 netif_set_up，该函数看到没有 link，除了设置标记外不会做任何事。 当链路变为有效后，驱动层调用 netif_set_link_up，发送 arp 探测。 C. 动态 IP，初始化时链路有效 驱动层直接设置 NETIF_FLAG_LINK_UP。 lwip 初始化过程中调用 dhcp_start，启动 DHCP 过程。 但 lwip 初始化过程不会调用 netif_set_up，因为还没有获得有效IP地址。 获得有效 IP 后，lwip 会帮我们调用 netif_set_up，发送 arp 探测。 D. 动态 IP，初始化时链路无效 驱动层不会设置 NETIF_FLAG_LINK_UP。 lwip 初始化过程中仍然会调用 dhcp_start。对 dhcp_start 的调用是必须的，因为 dhcp 过程需要的资源将在该函数中分配。 等到链路有效后驱动层调用 netif_set_link_up，该函数会启动 DHCP 过程。 获得有效 IP 后，lwip 会帮我们调用 netif_set_up，发送 arp 探测。 E. 静态 IP，链路断开后重建 链路断开时 netif_set_link_down，重建后 netif_set_link_up 发送 arp 探测。 NETIF_FLAG_UP 在设置后就一直有效。 F. 动态 IP，链路断开后重建 链路重建后 netif_set_link_up 重新启动 DHCP 过程，该过程会清除 NETIF_FLAG_UP 标记。 DHCP 完成后 lwip 自动调用 netif_set_up 重新置位该标记并发起 arp 探测。 总结 使用静态 IP low_level_init 根据当前链路状态设置或不设置 NETIF_FLAG_LINK_UP； lwip 初始化时调用 netif_set_up； 链路状态改变时调用 netif_set_link_up/netif_set_link_down。 使用动态 IP low_level_init 根据当前链路状态设置或不设置 NETIF_FLAG_LINK_UP； lwip 初始化时调用 dhcp_start； 链路状态改变时调用 netif_set_link_up/netif_set_link_down； 不要在使用动态IP时直接调用 netif_set_up，而是由lwip协议栈代码在成功获得 IP 后为你调用这个函数。