idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
netif.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
22#include <idfxx/chrono>
23#include <idfxx/error>
24#include <idfxx/event>
25#include <idfxx/flags>
26#include <idfxx/mac>
27#include <idfxx/net>
28
29#include <array>
30#include <cstdint>
31#include <optional>
32#include <string>
33#include <string_view>
34#include <utility>
35#include <vector>
36
37typedef struct esp_netif_obj esp_netif_t;
38
39namespace idfxx::netif {
40
41// =============================================================================
42// Forward declarations
43// =============================================================================
44
45class interface;
46
47// =============================================================================
48// Enumerations
49// =============================================================================
50
55enum class dhcp_option_id : int {
56 // clang-format off
57 subnet_mask = 1,
65 captiveportal_uri = 114,
66 // clang-format on
67};
68
73enum class dns_type : int {
74 // clang-format off
75 main = 0,
76 backup = 1,
77 fallback = 2,
78 // clang-format on
79};
80
87enum class flag : uint32_t {
88 // clang-format off
89 dhcp_client = 1u << 0,
90 dhcp_server = 1u << 1,
91 autoup = 1u << 2,
92 garp = 1u << 3,
93 event_ip_modified = 1u << 4,
94 is_ppp = 1u << 5,
95 is_bridge = 1u << 6,
96 mldv6_report = 1u << 7,
97 ipv6_autoconfig_enabled = 1u << 8,
98 // clang-format on
99};
100
114enum class ip_event_id : int32_t {
115 // clang-format off
116 sta_got_ip4 = 0,
117 sta_lost_ip4 = 1,
119 got_ip6 = 3,
120 eth_got_ip4 = 4,
121 eth_lost_ip4 = 5,
122 ppp_got_ip4 = 6,
123 ppp_lost_ip4 = 7,
124 // clang-format on
125};
126
127} // namespace idfxx::netif
128
130template<>
131inline constexpr bool idfxx::enable_flags_operators<idfxx::netif::flag> = true;
133
134namespace idfxx::netif {
135
136// =============================================================================
137// Error handling
138// =============================================================================
139
144enum class errc : esp_err_t {
145 // clang-format off
146 invalid_params = 0x5001,
147 if_not_ready = 0x5002,
148 dhcpc_start_failed = 0x5003,
149 dhcp_already_started = 0x5004,
150 dhcp_already_stopped = 0x5005,
151 no_mem = 0x5006,
152 dhcp_not_stopped = 0x5007,
153 driver_attach_failed = 0x5008,
154 init_failed = 0x5009,
155 dns_not_configured = 0x500A,
156 mld6_failed = 0x500B,
157 ip6_addr_failed = 0x500C,
158 dhcps_start_failed = 0x500D,
159 tx_failed = 0x500E,
160 // clang-format on
161};
162
167class error_category : public std::error_category {
168public:
171
173 [[nodiscard]] std::string message(int ec) const override final;
174};
175
176} // namespace idfxx::netif
177
179
187
199
200} // namespace idfxx
201
202namespace idfxx::netif {
203
211[[nodiscard]] inline std::error_code make_error_code(errc e) noexcept {
212 return {std::to_underlying(e), netif_category()};
213}
214
215} // namespace idfxx::netif
216
218namespace std {
219template<>
220struct is_error_code_enum<idfxx::netif::errc> : std::true_type {};
221} // namespace std
223
224namespace idfxx::netif {
225
226// =============================================================================
227// IP events
228// =============================================================================
229
237extern const event_base<ip_event_id> ip_events;
238
240inline event_base<ip_event_id> idfxx_get_event_base(ip_event_id*) {
241 return ip_events;
242}
245// =============================================================================
246// Event data wrappers
247// =============================================================================
248
263
278
293
294// =============================================================================
295// Typed event constants
296// =============================================================================
297
299inline constexpr idfxx::event<ip_event_id, ip4_event_data> sta_got_ip4{ip_event_id::sta_got_ip4};
301inline constexpr idfxx::event<ip_event_id> sta_lost_ip4{ip_event_id::sta_lost_ip4};
304 ip_event_id::ap_sta_ip4_assigned
305};
307inline constexpr idfxx::event<ip_event_id, ip6_event_data> got_ip6{ip_event_id::got_ip6};
309inline constexpr idfxx::event<ip_event_id, ip4_event_data> eth_got_ip4{ip_event_id::eth_got_ip4};
311inline constexpr idfxx::event<ip_event_id> eth_lost_ip4{ip_event_id::eth_lost_ip4};
313inline constexpr idfxx::event<ip_event_id, ip4_event_data> ppp_got_ip4{ip_event_id::ppp_got_ip4};
315inline constexpr idfxx::event<ip_event_id> ppp_lost_ip4{ip_event_id::ppp_lost_ip4};
316
317// =============================================================================
318// DNS info
319// =============================================================================
320
330
331// =============================================================================
332// interface
333// =============================================================================
334
355public:
364 static interface take(esp_netif_t* handle);
365
374 static interface wrap(esp_netif_t* handle);
375
377
378 interface(const interface&) = delete;
379 interface& operator=(const interface&) = delete;
380
387 : _handle(std::exchange(other._handle, nullptr))
388 , _owning(other._owning) {}
389
396 interface& operator=(interface&& other) noexcept;
397
403 [[nodiscard]] esp_netif_t* idf_handle() const noexcept { return _handle; }
404
405 // =========================================================================
406 // Interface status
407 // =========================================================================
408
414 [[nodiscard]] bool is_up() const;
415
421 [[nodiscard]] const char* key() const;
422
428 [[nodiscard]] const char* description() const;
429
436
442 void set_route_priority(int priority);
443
450
460
470
471 // =========================================================================
472 // MAC address
473 // =========================================================================
474
475#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
478 [[nodiscard]] mac_address get_mac() const { return unwrap(try_get_mac()); }
479
482 void set_mac(const mac_address& mac) { unwrap(try_set_mac(mac)); }
483#endif
484
493
503
504 // =========================================================================
505 // Hostname
506 // =========================================================================
507
508#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
511 [[nodiscard]] std::string get_hostname() const { return unwrap(try_get_hostname()); }
512
515 void set_hostname(std::string_view hostname) { unwrap(try_set_hostname(hostname)); }
516#endif
517
524
532
533 // =========================================================================
534 // IPv4
535 // =========================================================================
536
543
544#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
547 void set_ip4_info(const net::ip4_info& info) { unwrap(try_set_ip4_info(info)); }
548#endif
549
559
560 // =========================================================================
561 // IPv6
562 // =========================================================================
563
564#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
567 void create_ip6_linklocal() { unwrap(try_create_ip6_linklocal()); }
568
571 [[nodiscard]] net::ip6_addr get_ip6_linklocal() const { return unwrap(try_get_ip6_linklocal()); }
572
575 [[nodiscard]] net::ip6_addr get_ip6_global() const { return unwrap(try_get_ip6_global()); }
576#endif
577
584
591
598
604 [[nodiscard]] std::vector<net::ip6_addr> get_all_ip6() const;
605
611 [[nodiscard]] std::vector<net::ip6_addr> get_all_preferred_ip6() const;
612
613 // =========================================================================
614 // DHCP client
615 // =========================================================================
616
617#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
620 void dhcp_client_start() { unwrap(try_dhcp_client_start()); }
621
624 void dhcp_client_stop() { unwrap(try_dhcp_client_stop()); }
625#endif
626
634
642
649
650 // =========================================================================
651 // DHCP server
652 // =========================================================================
653
654#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
657 void dhcp_server_start() { unwrap(try_dhcp_server_start()); }
658
661 void dhcp_server_stop() { unwrap(try_dhcp_server_stop()); }
662#endif
663
672
680
687
688 // =========================================================================
689 // DNS
690 // =========================================================================
691
692#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
695 void set_dns(dns_type type, const dns_info& info) { unwrap(try_set_dns(type, info)); }
696
699 [[nodiscard]] dns_info get_dns(dns_type type) const { return unwrap(try_get_dns(type)); }
700#endif
701
710
718
719 // =========================================================================
720 // NAPT
721 // =========================================================================
722
723#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
726 void napt_enable(bool enable = true) { unwrap(try_napt_enable(enable)); }
727#endif
728
736
737private:
738 interface(esp_netif_t* handle, bool owning) noexcept
739 : _handle(handle)
740 , _owning(owning) {}
741
742 esp_netif_t* _handle = nullptr;
743 bool _owning = true;
744};
745
746// =============================================================================
747// Subsystem lifecycle
748// =============================================================================
749
750#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
753void init();
754
757void deinit();
758#endif
759
767result<void> try_init();
768
774result<void> try_deinit();
775
776#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
777inline void init() {
778 unwrap(try_init());
779}
780inline void deinit() {
781 unwrap(try_deinit());
782}
783#endif
784
785// =============================================================================
786// Discovery
787// =============================================================================
788
795
801[[nodiscard]] std::optional<interface> get_default();
802
809
816[[nodiscard]] std::optional<interface> find_by_key(const char* key);
817
818// =============================================================================
819// SNTP sub-namespace
820// =============================================================================
821
828namespace sntp {
829
834struct config {
835 bool smooth_sync = false;
836 bool server_from_dhcp = false;
837 bool wait_for_sync = true;
838 bool start = true;
839 bool renew_servers_after_new_ip = false;
840 ip_event_id renew_event_id = ip_event_id::sta_got_ip4;
841 std::vector<std::string> servers;
842};
843
844#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
847void init(const config& cfg);
848
851void start();
852#endif
853
860result<void> try_init(const config& cfg);
861
867result<void> try_start();
868
869#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
870inline void init(const config& cfg) {
871 unwrap(try_init(cfg));
872}
873inline void start() {
874 unwrap(try_start());
875}
876#endif
877
881void deinit();
882
884namespace detail {
885[[nodiscard]] bool sync_wait_ms(std::chrono::milliseconds timeout);
886} // namespace detail
897template<typename Rep, typename Period>
898[[nodiscard]] bool sync_wait(const std::chrono::duration<Rep, Period>& timeout) {
899 return detail::sync_wait_ms(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
900}
901
902} // namespace sntp
// end of idfxx_netif_sntp
904
905} // namespace idfxx::netif
906
907// =============================================================================
908// String conversions (in idfxx namespace)
909// =============================================================================
910
911namespace idfxx {
912
921
922} // namespace idfxx
923
924#include "sdkconfig.h"
925#ifdef CONFIG_IDFXX_STD_FORMAT
927#include <algorithm>
928#include <format>
929namespace std {
930
931template<>
932struct formatter<idfxx::netif::dns_type> {
933 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
934
935 template<typename FormatContext>
936 auto format(idfxx::netif::dns_type t, FormatContext& ctx) const {
937 auto str = idfxx::to_string(t);
938 return std::copy(str.begin(), str.end(), ctx.out());
939 }
940};
941
942} // namespace std
944#endif // CONFIG_IDFXX_STD_FORMAT
945
// end of idfxx_netif
A MAC-48 (6-byte) hardware address.
Definition mac.hpp:62
IPv4 address value type.
Definition net.hpp:40
IPv6 address value type.
Definition net.hpp:121
Error category for network interface errors.
Definition netif.hpp:167
std::string message(int ec) const override final
Returns a human-readable message for the given error code.
const char * name() const noexcept override final
Returns the name of the error category.
Network interface handle.
Definition netif.hpp:354
std::vector< net::ip6_addr > get_all_ip6() const
Returns all IPv6 addresses of this interface.
void set_mac(const mac_address &mac)
Sets the MAC address.
Definition netif.hpp:482
interface & operator=(const interface &)=delete
result< net::ip6_addr > try_get_ip6_global() const
Returns the IPv6 global address of this interface.
net::ip6_addr get_ip6_global() const
Returns the IPv6 global address.
Definition netif.hpp:575
void create_ip6_linklocal()
Creates an IPv6 link-local address for this interface.
Definition netif.hpp:567
result< void > try_create_ip6_linklocal()
Creates an IPv6 link-local address for this interface.
bool is_up() const
Checks if the network interface is up.
void dhcp_client_stop()
Stops the DHCP client on this interface.
Definition netif.hpp:624
void set_ip4_info(const net::ip4_info &info)
Sets the IPv4 information.
Definition netif.hpp:547
bool is_dhcp_server_running() const
Checks if the DHCP server is running on this interface.
std::vector< net::ip6_addr > get_all_preferred_ip6() const
Returns all preferred IPv6 addresses of this interface.
result< void > try_dhcp_client_stop()
Stops the DHCP client on this interface.
result< void > try_set_ip4_info(const net::ip4_info &info)
Sets the IPv4 information of this interface.
void napt_enable(bool enable=true)
Enables or disables NAPT on this interface.
Definition netif.hpp:726
void dhcp_server_start()
Starts the DHCP server on this interface.
Definition netif.hpp:657
result< std::string > try_get_hostname() const
Returns the hostname of this interface.
void set_hostname(std::string_view hostname)
Sets the hostname.
Definition netif.hpp:515
flags< flag > get_flags() const
Returns the flags set on this interface.
interface(interface &&other) noexcept
Move constructs an interface, transferring ownership state.
Definition netif.hpp:386
void dhcp_client_start()
Starts the DHCP client on this interface.
Definition netif.hpp:620
interface(const interface &)=delete
result< void > try_set_mac(const mac_address &mac)
Sets the MAC address of this interface.
idfxx::event< ip_event_id, ip4_event_data > got_ip4_event() const
Returns the typed "got IP" event for this interface.
result< net::ip6_addr > try_get_ip6_linklocal() const
Returns the IPv6 link-local address of this interface.
result< void > try_dhcp_server_start()
Starts the DHCP server on this interface.
const char * key() const
Returns the interface key string.
bool is_dhcp_client_running() const
Checks if the DHCP client is running on this interface.
idfxx::event< ip_event_id > lost_ip4_event() const
Returns the typed "lost IP" event for this interface.
mac_address get_mac() const
Returns the MAC address.
Definition netif.hpp:478
const char * description() const
Returns the interface description string.
void set_dns(dns_type type, const dns_info &info)
Sets the DNS server information.
Definition netif.hpp:695
net::ip6_addr get_ip6_linklocal() const
Returns the IPv6 link-local address.
Definition netif.hpp:571
void dhcp_server_stop()
Stops the DHCP server on this interface.
Definition netif.hpp:661
result< void > try_set_dns(dns_type type, const dns_info &info)
Sets the DNS server information for this interface.
net::ip4_info get_ip4_info() const
Returns the current IPv4 information of this interface.
esp_netif_t * idf_handle() const noexcept
Returns the underlying ESP-NETIF handle.
Definition netif.hpp:403
result< void > try_set_hostname(std::string_view hostname)
Sets the hostname of this interface.
result< void > try_dhcp_server_stop()
Stops the DHCP server on this interface.
interface & operator=(interface &&other) noexcept
Move assigns an interface, transferring ownership state.
result< void > try_dhcp_client_start()
Starts the DHCP client on this interface.
dns_info get_dns(dns_type type) const
Returns the DNS server information.
Definition netif.hpp:699
result< mac_address > try_get_mac() const
Returns the MAC address of this interface.
result< dns_info > try_get_dns(dns_type type) const
Returns the DNS server information for this interface.
void set_route_priority(int priority)
Sets the route priority of this interface.
int get_route_priority() const
Returns the route priority of this interface.
std::string get_hostname() const
Returns the hostname.
Definition netif.hpp:511
result< void > try_napt_enable(bool enable=true)
Enables or disables NAPT (Network Address Port Translation) on this interface.
Concept for types that can be both received and posted as event data.
Definition event.hpp:164
int esp_err_t
Definition error.hpp:35
std::string to_string(core_id c)
Returns a string representation of a CPU core identifier.
Definition cpu.hpp:52
struct esp_netif_obj esp_netif_t
Definition netif.hpp:37
constexpr idfxx::event< ip_event_id, ip4_event_data > eth_got_ip4
Ethernet received IPv4 address event with IP details.
Definition netif.hpp:309
const event_base< ip_event_id > ip_events
IP event base.
std::error_code make_error_code(errc e) noexcept
Creates an error code from an idfxx::netif::errc value.
Definition netif.hpp:211
dns_type
DNS server type.
Definition netif.hpp:73
constexpr idfxx::event< ip_event_id, ip6_event_data > got_ip6
Received IPv6 address event.
Definition netif.hpp:307
errc
Network interface error codes.
Definition netif.hpp:144
std::optional< interface > get_default()
Returns a non-owning handle to the default network interface.
constexpr idfxx::event< ip_event_id, ap_sta_ip4_assigned_event_data > ap_sta_ip4_assigned
Soft-AP assigned IP to a connected station event.
Definition netif.hpp:303
flag
Network interface flags.
Definition netif.hpp:87
size_t get_nr_of_ifs()
Returns the number of registered network interfaces.
constexpr idfxx::event< ip_event_id > sta_lost_ip4
Station lost IPv4 address event.
Definition netif.hpp:301
constexpr idfxx::event< ip_event_id > eth_lost_ip4
Ethernet lost IPv4 address event.
Definition netif.hpp:311
dhcp_option_id
DHCP option identifiers.
Definition netif.hpp:55
constexpr idfxx::event< ip_event_id, ip4_event_data > ppp_got_ip4
PPP interface received IPv4 address event with IP details.
Definition netif.hpp:313
void set_default(interface &iface)
Sets the given interface as the default network interface.
ip_event_id
IP event IDs.
Definition netif.hpp:114
std::optional< interface > find_by_key(const char *key)
Finds a network interface by its key string.
constexpr idfxx::event< ip_event_id > ppp_lost_ip4
PPP interface lost IPv4 address event.
Definition netif.hpp:315
constexpr idfxx::event< ip_event_id, ip4_event_data > sta_got_ip4
Station received IPv4 address event with IP details.
Definition netif.hpp:299
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
Definition error.hpp:307
@ timeout
Operation timed out.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:120
result< void > wrap(esp_err_t e)
Wraps an esp_err_t into a result<void>.
Definition error.hpp:286
const netif::error_category & netif_category() noexcept
Returns a reference to the netif error category singleton.
std::unexpected< std::error_code > netif_error(esp_err_t e)
Creates an unexpected error from an ESP-IDF error code, mapping to netif error codes where possible.
IPv4 network interface information.
Definition net.hpp:197
Information about an IP assigned to a station connected to an AP.
Definition netif.hpp:285
DNS server information.
Definition netif.hpp:327
net::ip4_addr ip
Definition netif.hpp:328
Information about an acquired IPv4 address.
Definition netif.hpp:255
Information about an acquired IPv6 address.
Definition netif.hpp:270