Merge branch 'feat/lwip_hook_dhcp_extra_opt' into 'master'

feat(lwip): Add DHCP extra option hook

Closes IDFGH-14572

See merge request espressif/esp-idf!36949
This commit is contained in:
David Čermák
2025-03-21 22:06:56 +08:00
5 changed files with 132 additions and 1 deletions

View File

@@ -1325,6 +1325,25 @@ menu "LWIP"
endchoice
choice LWIP_HOOK_DHCP_EXTRA_OPTION
prompt "DHCP extra option hook"
default LWIP_HOOK_DHCP_EXTRA_OPTION_NONE
help
Enables custom hook to receive and parse extra DHCP options.
Setting this to "default" provides weak implementation
stub that could be overwritten in application code.
Setting this to "custom" provides hook's declaration
only and expects the application to implement it.
config LWIP_HOOK_DHCP_EXTRA_OPTION_NONE
bool "No hook declared"
config LWIP_HOOK_DHCP_EXTRA_OPTION_DEFAULT
bool "Default (weak) implementation"
config LWIP_HOOK_DHCP_EXTRA_OPTION_CUSTOM
bool "Custom implementation"
endchoice
choice LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE
prompt "Netconn external resolve Hook"
default LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -189,6 +189,18 @@ int dhcp_set_vendor_class_identifier(uint8_t len, const char * str)
}
#endif /* LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS */
#if defined(CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_DEFAULT)
void __weak lwip_dhcp_on_extra_option(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset)
{
LWIP_UNUSED_ARG(dhcp);
LWIP_UNUSED_ARG(state);
LWIP_UNUSED_ARG(len);
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(offset);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("lwip_dhcp_on_extra_option(): Received DHCP option %d\n", option));
}
#endif /* CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_DEFAULT */
void dhcp_parse_extra_opts(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset)
{
LWIP_UNUSED_ARG(dhcp);
@@ -229,6 +241,10 @@ void dhcp_parse_extra_opts(struct dhcp *dhcp, uint8_t state, uint8_t option, uin
pbuf_copy_partial(p, &dhcp_option_vsi, copy_len, offset) == copy_len, return;);
} /* DHCP_OPTION_VSI */
#endif /* LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS */
#if !defined(CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_NONE)
lwip_dhcp_on_extra_option(dhcp, state, option, len, p, offset);
#endif
}
void dhcp_append_extra_opts(struct netif *netif, uint8_t state, struct dhcp_msg *msg_out, uint16_t *options_out_len)

View File

@@ -70,6 +70,10 @@ int lwip_hook_ip6_input(struct pbuf *p, struct netif *inp);
#define LWIP_HOOK_IP6_INPUT lwip_hook_ip6_input
#endif /* CONFIG_LWIP_HOOK_IP6_INPUT_CUSTIOM... */
#if defined(CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_CUSTOM) || defined(CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_DEFAULT)
void lwip_dhcp_on_extra_option(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset);
#endif /* CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_CUSTOM (or DEFAULT) */
#ifdef CONFIG_LWIP_IPV4
struct netif *
ip4_route_src_hook(const ip4_addr_t *src,const ip4_addr_t *dest);

View File

@@ -434,6 +434,52 @@ IPV4 network address port translation (NAPT) and port forwarding are supported.
- To use NAPT for forwarding packets between two interfaces, it needs to be enabled on the interface connecting to the target network. For example, to enable internet access for Ethernet traffic through the Wi-Fi interface, NAPT must be enabled on the Ethernet interface.
- Usage of NAPT is demonstrated in :example:`network/vlan_support`.
Default lwIP Hooks
++++++++++++++++++
ESP-IDF port layer provides a default hook file, which is included in the lwIP build process. This file is located at :component_file:`lwip/port/include/lwip_default_hooks.h` and defines several hooks that implement default ESP-IDF behavior of lwIP stack. These hooks could be further modified by choosing one of these options:
- *None*: No hook is declared.
- *Default*: Default IDF implementation is provided (declared as ``weak`` in most cases and can be overridden).
- *Custom*: Only the hook declaration is provided, and the application must implement it.
**DHCP Extra Option Hook**
ESP-IDF allows applications to define a hook for handling extra DHCP options. This can be useful for implementing custom DHCP-based behaviors, such as retrieving specific vendor options. To enable this feature, configure :ref:`CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION` either to **Default** (``weak`` implementation is provided which could be replaced by custom implementation) or **Custom** (you will have to implement the hook and define its link dependency to lwip)
**Example Usage**
An application can define the following function to handle a specific DHCP option (e.g., captive portal URI):
.. code-block::
#include "esp_netif.h"
#include "lwip/dhcp.h"
void lwip_dhcp_on_extra_option(struct dhcp *dhcp, uint8_t state,
uint8_t option, uint8_t len,
struct pbuf* p, uint16_t offset)
{
if (option == ESP_NETIF_CAPTIVEPORTAL_URI) {
char *uri = (char *)p->payload + offset;
ESP_LOGI(TAG, "Captive Portal URI: %s", uri);
}
}
**Other Default Hooks**
ESP-IDF provides additional lwIP hooks that can be overridden. These include:
- TCP ISN Hook (:ref:`CONFIG_LWIP_HOOK_TCP_ISN`): Allows custom randomization of TCP Initial Sequence Numbers (ESP-IDF provided implementation is the default option, set to *Custom* to provide custom implementation or *None* to use lwIP implementation).
- IPv6 Route Hook (:ref:`CONFIG_LWIP_HOOK_IP6_ROUTE`): Enables custom route selection for IPv6 packets (No hook by default, use *Default* or *Custom* to override).
- IPv6 Get Gateway Hook (:ref:`CONFIG_LWIP_HOOK_ND6_GET_GW`): Enables defining a custom gateway selection logic (No hook by default, use *Default* or *Custom* to override).
- IPv6 Source Address Selection Hook (:ref:`CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR`): Allows customization of source address selection (No hook by default, use *Default* or *Custom* to override).
- Netconn External Resolve Hook (:ref:`CONFIG_LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE`): Allows overriding the DNS resolution logic for network connections (No hook by default, use *Default* or *Custom* to override).
- DNS External Resolve Hook (:ref:`CONFIG_LWIP_HOOK_DNS_EXTERNAL_RESOLVE`): Provides a hook for custom DNS resolution logic with callbacks (No hook by default, but could be selected by an external component to prefer the custom option; use *Default* or *Custom* to override).
- IPv6 Packet Input Hook (:ref:`CONFIG_LWIP_HOOK_IP6_INPUT`): Provides filtering or modification of incoming IPv6 packets (ESP-IDF provided ``weak`` implementation is the default option; use *Custom* or provide a strong definition to override the *Default* option; choose *None* to disable IPv6 packet input filtering)
Each of these hooks can be configured in menuconfig, allowing selection of default, custom, or no implementation.
.. _lwip-custom-hooks:
Customized lwIP Hooks

View File

@@ -434,6 +434,52 @@ NAPT 和端口转发
- 要在两个接口之间使用 NAPT 转发数据包,必须在连接到目标网络的接口上启用 NAPT。例如为了通过 Wi-Fi 接口为以太网流量启用互联网访问,必须在以太网接口上启用 NAPT。
- NAPT 的使用示例可参考 :example:`network/vlan_support`
默认 lwIP 钩子
++++++++++++++++++
IDF 移植层提供了默认的钩子文件lwIP 构建过程中会包含此文件。此文件位于 :component_file:`lwip/port/include/lwip_default_hooks.h`,并定义了多个钩子,用于实现 lwIP 协议栈的默认 ESP-IDF 行为。这些钩子可以通过以下选项进行进一步修改:
- *None*:不声明任何钩子。
- *Default*:提供默认的 IDF 实现(多数情况下被声明为可被覆盖的弱实现)。
- *Custom*:仅提供钩子声明,应用程序必须自行实现钩子。
**DHCP 额外选项钩子**
ESP-IDF 允许应用程序通过定义钩子来处理额外的 DHCP 选项,可以帮助实现基于 DHCP 的自定义行为(例如获取特定的供应商选项)。若想启用此功能,可以将 :ref:`CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION` 配置为 **Default** (提供弱实现,可替换为自定义实现)或 **Custom** (需要自行实现该钩子,并定义其对 lwIP 的链接依赖)。
**示例用法**
应用程序可以定义以下函数来处理特定的 DHCP 选项(例如强制门户 URI
.. code-block::
#include "esp_netif.h"
#include "lwip/dhcp.h"
void lwip_dhcp_on_extra_option(struct dhcp *dhcp, uint8_t state,
uint8_t option, uint8_t len,
struct pbuf* p, uint16_t offset)
{
if (option == ESP_NETIF_CAPTIVEPORTAL_URI) {
char *uri = (char *)p->payload + offset;
ESP_LOGI(TAG, "Captive Portal URI: %s", uri);
}
}
**其他默认钩子**
ESP-IDF 提供了其他可覆盖的 lwIP 钩子,例如:
- TCP ISN 钩子 (:ref:`CONFIG_LWIP_HOOK_TCP_ISN`):允许自定义 TCP 初始序列号 (ISN) 的随机化逻辑。ESP-IDF 提供的实现是默认选项,设置为 *Custom* 可使用自定义实现,设置为 *None* 可使用 lwIP 实现。
- IPv6 路由钩子 (:ref:`CONFIG_LWIP_HOOK_IP6_ROUTE`):支持自定义 IPv6 数据包的路由选择。默认无钩子,可使用 *Default**Custom* 进行覆盖。
- IPv6 获取网关钩子 (:ref:`CONFIG_LWIP_HOOK_ND6_GET_GW`):支持自定义网关选择逻辑。默认无钩子,可使用 *Default**Custom* 进行覆盖。
- IPv6 源地址选择钩子 (:ref:`CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR`):允许自定义源地址的选择逻辑。默认无钩子,可使用 Default 或 Custom 进行覆盖
- Netconn 外部解析钩子 (:ref:`CONFIG_LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE`):允许覆盖网络连接的 DNS 解析逻辑默认无钩子,可使用 *Default**Custom* 进行覆盖。
- DNS 外部解析钩子 (:ref:`CONFIG_LWIP_HOOK_DNS_EXTERNAL_RESOLVE`):提供用于自定义 DNS 解析逻辑的回调钩子。默认无钩子,但外部组件可以选择优先使用自定义选项;可使用 *Default**Custom* 进行覆盖。
- IPv6 数据包输入钩子 (:ref:`CONFIG_LWIP_HOOK_IP6_INPUT`):能够过滤或修改传入的 IPv6 数据包。ESP-IDF 提供的弱实现是默认选项;可使用 *Custom* 或强定义来覆盖 *Default* 选项,或选择 *None* 以禁用 IPv6 数据包输入过滤。
这些钩子均可在 menuconfig 中进行配置,可选择默认实现、自定义实现或不启用。
.. _lwip-custom-hooks:
自定义 lwIP 钩子