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 ipv6_addr_failed = 0x500C,
158 dhcps_start_failed = 0x500D,
159 tx_failed = 0x500E,
162 // Backward-compatibility alias for the original spelling.
163 ip6_addr_failed [[deprecated("use ipv6_addr_failed")]] = ipv6_addr_failed,
165 // clang-format on
166};
167
172class error_category : public std::error_category {
173public:
176
178 [[nodiscard]] std::string message(int ec) const override final;
179};
180
181} // namespace idfxx::netif
182
184
192
204
205} // namespace idfxx
206
207namespace idfxx::netif {
208
216[[nodiscard]] inline std::error_code make_error_code(errc e) noexcept {
217 return {std::to_underlying(e), netif_category()};
218}
219
220} // namespace idfxx::netif
221
223namespace std {
224template<>
225struct is_error_code_enum<idfxx::netif::errc> : std::true_type {};
226} // namespace std
228
229namespace idfxx::netif {
230
231// =============================================================================
232// IP events
233// =============================================================================
234
242extern const event_base<ip_event_id> ip_events;
243
245inline event_base<ip_event_id> idfxx_get_event_base(ip_event_id*) {
246 return ip_events;
247}
250// =============================================================================
251// Event data wrappers
252// =============================================================================
253
268
283
298
299// =============================================================================
300// Typed event constants
301// =============================================================================
302
304inline constexpr idfxx::event<ip_event_id, ip4_event_data> sta_got_ip4{ip_event_id::sta_got_ip4};
306inline constexpr idfxx::event<ip_event_id> sta_lost_ip4{ip_event_id::sta_lost_ip4};
309 ip_event_id::ap_sta_ip4_assigned
310};
312inline constexpr idfxx::event<ip_event_id, ip6_event_data> got_ip6{ip_event_id::got_ip6};
314inline constexpr idfxx::event<ip_event_id, ip4_event_data> eth_got_ip4{ip_event_id::eth_got_ip4};
316inline constexpr idfxx::event<ip_event_id> eth_lost_ip4{ip_event_id::eth_lost_ip4};
318inline constexpr idfxx::event<ip_event_id, ip4_event_data> ppp_got_ip4{ip_event_id::ppp_got_ip4};
320inline constexpr idfxx::event<ip_event_id> ppp_lost_ip4{ip_event_id::ppp_lost_ip4};
321
322// =============================================================================
323// DNS info
324// =============================================================================
325
335
336// =============================================================================
337// interface
338// =============================================================================
339
360public:
369 static interface take(esp_netif_t* handle);
370
379 static interface wrap(esp_netif_t* handle);
380
382
383 interface(const interface&) = delete;
384 interface& operator=(const interface&) = delete;
385
392 : _handle(std::exchange(other._handle, nullptr))
393 , _owning(other._owning) {}
394
401 interface& operator=(interface&& other) noexcept;
402
408 [[nodiscard]] esp_netif_t* idf_handle() const noexcept { return _handle; }
409
410 // =========================================================================
411 // Interface status
412 // =========================================================================
413
419 [[nodiscard]] bool is_up() const;
420
426 [[nodiscard]] const char* key() const;
427
433 [[nodiscard]] const char* description() const;
434
441
447 void set_route_priority(int priority);
448
455
465
475
476 // =========================================================================
477 // MAC address
478 // =========================================================================
479
480#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
483 [[nodiscard]] mac_address get_mac() const { return unwrap(try_get_mac()); }
484
487 void set_mac(const mac_address& mac) { unwrap(try_set_mac(mac)); }
488#endif
489
498
508
509 // =========================================================================
510 // Hostname
511 // =========================================================================
512
513#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
516 [[nodiscard]] std::string get_hostname() const { return unwrap(try_get_hostname()); }
517
520 void set_hostname(std::string_view hostname) { unwrap(try_set_hostname(hostname)); }
521#endif
522
529
537
538 // =========================================================================
539 // IPv4
540 // =========================================================================
541
548
549#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
552 void set_ipv4_info(const net::ipv4_info& info) { unwrap(try_set_ipv4_info(info)); }
553#endif
554
564
566 // Backward-compatibility forwarders for the original spellings.
567 [[nodiscard, deprecated("use get_ipv4_info")]] net::ipv4_info get_ip4_info() const { return get_ipv4_info(); }
568#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
569 [[deprecated("use set_ipv4_info")]] void set_ip4_info(const net::ipv4_info& info) { set_ipv4_info(info); }
570#endif
571 [[deprecated("use try_set_ipv4_info")]] result<void> try_set_ip4_info(const net::ipv4_info& info) {
572 return try_set_ipv4_info(info);
573 }
575
576 // =========================================================================
577 // IPv6
578 // =========================================================================
579
580#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
583 void create_ipv6_linklocal() { unwrap(try_create_ipv6_linklocal()); }
584
587 [[nodiscard]] net::ipv6_addr get_ipv6_linklocal() const { return unwrap(try_get_ipv6_linklocal()); }
588
591 [[nodiscard]] net::ipv6_addr get_ipv6_global() const { return unwrap(try_get_ipv6_global()); }
592#endif
593
600
607
614
620 [[nodiscard]] std::vector<net::ipv6_addr> get_all_ipv6() const;
621
627 [[nodiscard]] std::vector<net::ipv6_addr> get_all_preferred_ipv6() const;
628
630 // Backward-compatibility forwarders for the original spellings.
631#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
632 [[deprecated("use create_ipv6_linklocal")]] void create_ip6_linklocal() { create_ipv6_linklocal(); }
633 [[nodiscard, deprecated("use get_ipv6_linklocal")]] net::ipv6_addr get_ip6_linklocal() const {
634 return get_ipv6_linklocal();
635 }
636 [[nodiscard, deprecated("use get_ipv6_global")]] net::ipv6_addr get_ip6_global() const { return get_ipv6_global(); }
637#endif
638 [[deprecated("use try_create_ipv6_linklocal")]] result<void> try_create_ip6_linklocal() {
639 return try_create_ipv6_linklocal();
640 }
641 [[nodiscard, deprecated("use try_get_ipv6_linklocal")]] result<net::ipv6_addr> try_get_ip6_linklocal() const {
642 return try_get_ipv6_linklocal();
643 }
644 [[nodiscard, deprecated("use try_get_ipv6_global")]] result<net::ipv6_addr> try_get_ip6_global() const {
645 return try_get_ipv6_global();
646 }
647 [[nodiscard, deprecated("use get_all_ipv6")]] std::vector<net::ipv6_addr> get_all_ip6() const {
648 return get_all_ipv6();
649 }
650 [[nodiscard, deprecated("use get_all_preferred_ipv6")]] std::vector<net::ipv6_addr> get_all_preferred_ip6() const {
651 return get_all_preferred_ipv6();
652 }
654
655 // =========================================================================
656 // DHCP client
657 // =========================================================================
658
659#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
662 void dhcp_client_start() { unwrap(try_dhcp_client_start()); }
663
666 void dhcp_client_stop() { unwrap(try_dhcp_client_stop()); }
667#endif
668
676
684
691
692 // =========================================================================
693 // DHCP server
694 // =========================================================================
695
696#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
699 void dhcp_server_start() { unwrap(try_dhcp_server_start()); }
700
703 void dhcp_server_stop() { unwrap(try_dhcp_server_stop()); }
704#endif
705
714
722
729
730 // =========================================================================
731 // DNS
732 // =========================================================================
733
734#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
737 void set_dns(dns_type type, const dns_info& info) { unwrap(try_set_dns(type, info)); }
738
741 [[nodiscard]] dns_info get_dns(dns_type type) const { return unwrap(try_get_dns(type)); }
742#endif
743
752
760
761 // =========================================================================
762 // NAPT
763 // =========================================================================
764
765#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
768 void napt_enable(bool enable = true) { unwrap(try_napt_enable(enable)); }
769#endif
770
778
779private:
780 interface(esp_netif_t* handle, bool owning) noexcept
781 : _handle(handle)
782 , _owning(owning) {}
783
784 esp_netif_t* _handle = nullptr;
785 bool _owning = true;
786};
787
788// =============================================================================
789// Subsystem lifecycle
790// =============================================================================
791
792#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
795void init();
796
799void deinit();
800#endif
801
809result<void> try_init();
810
816result<void> try_deinit();
817
818#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
819inline void init() {
820 unwrap(try_init());
821}
822inline void deinit() {
823 unwrap(try_deinit());
824}
825#endif
826
827// =============================================================================
828// Discovery
829// =============================================================================
830
837
843[[nodiscard]] std::optional<interface> get_default();
844
851
858[[nodiscard]] std::optional<interface> find_by_key(const char* key);
859
860// =============================================================================
861// SNTP sub-namespace
862// =============================================================================
863
870namespace sntp {
871
876struct config {
877 bool smooth_sync = false;
878 bool server_from_dhcp = false;
879 bool wait_for_sync = true;
880 bool start = true;
881 bool renew_servers_after_new_ip = false;
882 ip_event_id renew_event_id = ip_event_id::sta_got_ip4;
883 std::vector<std::string> servers;
884};
885
886#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
889void init(const config& cfg);
890
893void start();
894#endif
895
902result<void> try_init(const config& cfg);
903
909result<void> try_start();
910
911#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
912inline void init(const config& cfg) {
913 unwrap(try_init(cfg));
914}
915inline void start() {
916 unwrap(try_start());
917}
918#endif
919
923void deinit();
924
926namespace detail {
927[[nodiscard]] bool sync_wait_ms(std::chrono::milliseconds timeout);
928} // namespace detail
939template<typename Rep, typename Period>
940[[nodiscard]] bool sync_wait(const std::chrono::duration<Rep, Period>& timeout) {
941 return detail::sync_wait_ms(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
942}
943
944} // namespace sntp
// end of idfxx_netif_sntp
946
947} // namespace idfxx::netif
948
949// =============================================================================
950// String conversions (in idfxx namespace)
951// =============================================================================
952
953namespace idfxx {
954
963
964} // namespace idfxx
965
966#include "sdkconfig.h"
967#ifdef CONFIG_IDFXX_STD_FORMAT
969#include <algorithm>
970#include <format>
971namespace std {
972
973template<>
974struct formatter<idfxx::netif::dns_type> {
975 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
976
977 template<typename FormatContext>
978 auto format(idfxx::netif::dns_type t, FormatContext& ctx) const {
979 auto str = idfxx::to_string(t);
980 return std::copy(str.begin(), str.end(), ctx.out());
981 }
982};
983
984} // namespace std
986#endif // CONFIG_IDFXX_STD_FORMAT
987
// end of idfxx_netif
A MAC-48 (6-byte) hardware address.
Definition mac.hpp:62
IPv4 address value type.
Definition net.hpp:41
IPv6 address value type.
Definition net.hpp:132
Error category for network interface errors.
Definition netif.hpp:172
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:359
void set_mac(const mac_address &mac)
Sets the MAC address.
Definition netif.hpp:487
std::vector< net::ipv6_addr > get_all_ipv6() const
Returns all IPv6 addresses of this interface.
interface & operator=(const interface &)=delete
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:666
bool is_dhcp_server_running() const
Checks if the DHCP server is running on this interface.
result< net::ipv6_addr > try_get_ipv6_global() const
Returns the IPv6 global address of this interface.
result< void > try_dhcp_client_stop()
Stops the DHCP client on this interface.
void napt_enable(bool enable=true)
Enables or disables NAPT on this interface.
Definition netif.hpp:768
void dhcp_server_start()
Starts the DHCP server on this interface.
Definition netif.hpp:699
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:520
flags< flag > get_flags() const
Returns the flags set on this interface.
net::ipv6_addr get_ipv6_linklocal() const
Returns the IPv6 link-local address.
Definition netif.hpp:587
interface(interface &&other) noexcept
Move constructs an interface, transferring ownership state.
Definition netif.hpp:391
void dhcp_client_start()
Starts the DHCP client on this interface.
Definition netif.hpp:662
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.
void set_ipv4_info(const net::ipv4_info &info)
Sets the IPv4 information.
Definition netif.hpp:552
std::vector< net::ipv6_addr > get_all_preferred_ipv6() const
Returns all preferred IPv6 addresses of this interface.
void create_ipv6_linklocal()
Creates an IPv6 link-local address for this interface.
Definition netif.hpp:583
result< void > try_create_ipv6_linklocal()
Creates an IPv6 link-local address for this interface.
net::ipv4_info get_ipv4_info() const
Returns the current IPv4 information 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.
net::ipv6_addr get_ipv6_global() const
Returns the IPv6 global address.
Definition netif.hpp:591
mac_address get_mac() const
Returns the MAC address.
Definition netif.hpp:483
result< void > try_set_ipv4_info(const net::ipv4_info &info)
Sets the IPv4 information of this interface.
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:737
void dhcp_server_stop()
Stops the DHCP server on this interface.
Definition netif.hpp:703
result< void > try_set_dns(dns_type type, const dns_info &info)
Sets the DNS server information for this interface.
esp_netif_t * idf_handle() const noexcept
Returns the underlying ESP-NETIF handle.
Definition netif.hpp:408
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:741
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.
result< net::ipv6_addr > try_get_ipv6_linklocal() const
Returns the IPv6 link-local address of this interface.
std::string get_hostname() const
Returns the hostname.
Definition netif.hpp:516
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:314
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:216
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:312
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:308
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:306
constexpr idfxx::event< ip_event_id > eth_lost_ip4
Ethernet lost IPv4 address event.
Definition netif.hpp:316
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:318
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:320
constexpr idfxx::event< ip_event_id, ip4_event_data > sta_got_ip4
Station received IPv4 address event with IP details.
Definition netif.hpp:304
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:227
Information about an IP assigned to a station connected to an AP.
Definition netif.hpp:290
DNS server information.
Definition netif.hpp:332
net::ipv4_addr ip
Definition netif.hpp:333
Information about an acquired IPv4 address.
Definition netif.hpp:260
Information about an acquired IPv6 address.
Definition netif.hpp:275