Merge pull request #3282 from cesanta/mip6

Introduce IPv6, unit tests pass
This commit is contained in:
Sergio R. Caprile 2025-11-05 11:58:26 -03:00 committed by GitHub
commit b53d8439e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 2088 additions and 634 deletions

File diff suppressed because it is too large Load diff

View file

@ -1057,6 +1057,26 @@ struct timeval {
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
#endif
#if MG_ENABLE_IPV6
#ifndef MG_TCPIP_GLOBAL
#define MG_TCPIP_GLOBAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#ifndef MG_TCPIP_IPV6_LINKLOCAL
#define MG_TCPIP_IPV6_LINKLOCAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#ifndef MG_TCPIP_PREFIX_LEN
#define MG_TCPIP_PREFIX_LEN 0
#endif
#ifndef MG_TCPIP_GW6
#define MG_TCPIP_GW6 MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#endif
#ifndef MG_SET_MAC_ADDRESS
#define MG_SET_MAC_ADDRESS(mac)
#endif
@ -1368,6 +1388,16 @@ void mg_delayms(unsigned int ms);
#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
#define MG_IPV6(a, b, c, d, e, f, g ,h) \
{ (uint8_t)((a)>>8),(uint8_t)(a), \
(uint8_t)((b)>>8),(uint8_t)(b), \
(uint8_t)((c)>>8),(uint8_t)(c), \
(uint8_t)((d)>>8),(uint8_t)(d), \
(uint8_t)((e)>>8),(uint8_t)(e), \
(uint8_t)((f)>>8),(uint8_t)(f), \
(uint8_t)((g)>>8),(uint8_t)(g), \
(uint8_t)((h)>>8),(uint8_t)(h) }
// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
#define MG_U8P(ADDR) ((uint8_t *) (ADDR))
#define MG_IPADDR_PARTS(ADDR) \
@ -1382,6 +1412,14 @@ void mg_delayms(unsigned int ms);
((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
((uint32_t) MG_U8P(p)[1] << 16U) | \
((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
#define MG_LOAD_BE64(p) \
((uint64_t) (((uint64_t) MG_U8P(p)[0] << 56U) | \
((uint64_t) MG_U8P(p)[1] << 48U) | \
((uint64_t) MG_U8P(p)[2] << 40U) | \
((uint64_t) MG_U8P(p)[3] << 32U) | \
((uint64_t) MG_U8P(p)[4] << 24U) | \
((uint64_t) MG_U8P(p)[5] << 16U) | \
((uint64_t) MG_U8P(p)[6] << 8U) | MG_U8P(p)[7]))
#define MG_STORE_BE16(p, n) \
do { \
MG_U8P(p)[0] = ((n) >> 8U) & 255; \
@ -1400,11 +1438,24 @@ void mg_delayms(unsigned int ms);
MG_U8P(p)[2] = ((n) >> 8U) & 255; \
MG_U8P(p)[3] = (n) &255; \
} while (0)
#define MG_STORE_BE64(p, n) \
do { \
MG_U8P(p)[0] = ((n) >> 56U) & 255; \
MG_U8P(p)[1] = ((n) >> 48U) & 255; \
MG_U8P(p)[2] = ((n) >> 40U) & 255; \
MG_U8P(p)[3] = ((n) >> 32U) & 255; \
MG_U8P(p)[4] = ((n) >> 24U) & 255; \
MG_U8P(p)[5] = ((n) >> 16U) & 255; \
MG_U8P(p)[6] = ((n) >> 8U) & 255; \
MG_U8P(p)[7] = (n) &255; \
} while (0)
uint16_t mg_ntohs(uint16_t net);
uint32_t mg_ntohl(uint32_t net);
uint64_t mg_ntohll(uint64_t net);
#define mg_htons(x) mg_ntohs(x)
#define mg_htonl(x) mg_ntohl(x)
#define mg_htonll(x) mg_ntohll(x)
#define MG_REG(x) ((volatile uint32_t *) (x))[0]
#define MG_BIT(x) (((uint32_t) 1U) << (x))
@ -3084,18 +3135,17 @@ typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev,
void *ev_data);
enum {
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct
// mg_wifi_scan_bss_data *
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and
// chip specific
MG_TCPIP_EV_DRIVER, // Driver event driver specific
MG_TCPIP_EV_USER // Starting ID for user events
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct mg_wifi_scan_bss_data *
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and chip specific
MG_TCPIP_EV_DRIVER, // Driver event driver specific
MG_TCPIP_EV_ST6_CHG, // state6 change uint8_t * (&ifp->state6)
MG_TCPIP_EV_USER // Starting ID for user events
};
// Network interface
@ -3120,6 +3170,13 @@ struct mg_tcpip_if {
char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Name for DHCP, "mip" if unset
uint16_t mtu; // Interface MTU
#define MG_TCPIP_MTU_DEFAULT 1500
#if MG_ENABLE_IPV6
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses
uint8_t prefix_len; // Prefix length
uint64_t gw6[2]; // Default gateway
bool enable_slaac; // Enable IPv6 address autoconfiguration
bool enable_dhcp6_client; // Enable DCHPv6 client
#endif
// Internal state, user can use it but should not change it
uint8_t gwmac[6]; // Router's MAC
@ -3132,14 +3189,17 @@ struct mg_tcpip_if {
volatile uint32_t nrecv; // Number of received frames
volatile uint32_t nsent; // Number of transmitted frames
volatile uint32_t nerr; // Number of driver errors
uint8_t state; // Current state
uint8_t state; // Current link and IPv4 state
#define MG_TCPIP_STATE_DOWN 0 // Interface is down
#define MG_TCPIP_STATE_UP 1 // Interface is up
#define MG_TCPIP_STATE_REQ 2 // Interface is up, DHCP REQUESTING state
#define MG_TCPIP_STATE_IP 3 // Interface is up and has an IP assigned
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work
#if MG_ENABLE_IPV6
uint8_t gw6mac[6]; // IPv6 Router's MAC
uint8_t state6; // Current IPv6 state
#endif
};
void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
void mg_tcpip_free(struct mg_tcpip_if *);
void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp);
@ -3675,6 +3735,18 @@ struct mg_tcpip_driver_stm32h_data {
#define MG_ENABLE_ETH_IRQ()
#endif
#if MG_ENABLE_IPV6
#define MG_IPV6_INIT(mif) \
do { \
memcpy(mif.ip6ll, (uint8_t[16]) MG_TCPIP_IPV6_LINKLOCAL, 16); \
memcpy(mif.ip6, (uint8_t[16]) MG_TCPIP_GLOBAL, 16); \
memcpy(mif.gw6, (uint8_t[16]) MG_TCPIP_GW6, 16); \
mif.prefix_len = MG_TCPIP_PREFIX_LEN; \
} while(0)
#else
#define MG_IPV6_INIT(mif)
#endif
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_stm32h_data driver_data_; \
@ -3688,6 +3760,7 @@ struct mg_tcpip_driver_stm32h_data {
mif_.driver = &mg_tcpip_driver_stm32h; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
MG_IPV6_INIT(mif_); \
mg_tcpip_init(mgr, &mif_); \
MG_ENABLE_ETH_IRQ(); \
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \

View file

@ -175,6 +175,26 @@
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
#endif
#if MG_ENABLE_IPV6
#ifndef MG_TCPIP_GLOBAL
#define MG_TCPIP_GLOBAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#ifndef MG_TCPIP_IPV6_LINKLOCAL
#define MG_TCPIP_IPV6_LINKLOCAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#ifndef MG_TCPIP_PREFIX_LEN
#define MG_TCPIP_PREFIX_LEN 0
#endif
#ifndef MG_TCPIP_GW6
#define MG_TCPIP_GW6 MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#endif
#ifndef MG_SET_MAC_ADDRESS
#define MG_SET_MAC_ADDRESS(mac)
#endif

View file

@ -49,6 +49,18 @@ struct mg_tcpip_driver_stm32h_data {
#define MG_ENABLE_ETH_IRQ()
#endif
#if MG_ENABLE_IPV6
#define MG_IPV6_INIT(mif) \
do { \
memcpy(mif.ip6ll, (uint8_t[16]) MG_TCPIP_IPV6_LINKLOCAL, 16); \
memcpy(mif.ip6, (uint8_t[16]) MG_TCPIP_GLOBAL, 16); \
memcpy(mif.gw6, (uint8_t[16]) MG_TCPIP_GW6, 16); \
mif.prefix_len = MG_TCPIP_PREFIX_LEN; \
} while(0)
#else
#define MG_IPV6_INIT(mif)
#endif
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_stm32h_data driver_data_; \
@ -62,6 +74,7 @@ struct mg_tcpip_driver_stm32h_data {
mif_.driver = &mg_tcpip_driver_stm32h; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
MG_IPV6_INIT(mif_); \
mg_tcpip_init(mgr, &mif_); \
MG_ENABLE_ETH_IRQ(); \
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \

File diff suppressed because it is too large Load diff

View file

@ -20,18 +20,17 @@ typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev,
void *ev_data);
enum {
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct
// mg_wifi_scan_bss_data *
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and
// chip specific
MG_TCPIP_EV_DRIVER, // Driver event driver specific
MG_TCPIP_EV_USER // Starting ID for user events
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct mg_wifi_scan_bss_data *
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and chip specific
MG_TCPIP_EV_DRIVER, // Driver event driver specific
MG_TCPIP_EV_ST6_CHG, // state6 change uint8_t * (&ifp->state6)
MG_TCPIP_EV_USER // Starting ID for user events
};
// Network interface
@ -56,6 +55,13 @@ struct mg_tcpip_if {
char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Name for DHCP, "mip" if unset
uint16_t mtu; // Interface MTU
#define MG_TCPIP_MTU_DEFAULT 1500
#if MG_ENABLE_IPV6
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses
uint8_t prefix_len; // Prefix length
uint64_t gw6[2]; // Default gateway
bool enable_slaac; // Enable IPv6 address autoconfiguration
bool enable_dhcp6_client; // Enable DCHPv6 client
#endif
// Internal state, user can use it but should not change it
uint8_t gwmac[6]; // Router's MAC
@ -68,14 +74,17 @@ struct mg_tcpip_if {
volatile uint32_t nrecv; // Number of received frames
volatile uint32_t nsent; // Number of transmitted frames
volatile uint32_t nerr; // Number of driver errors
uint8_t state; // Current state
uint8_t state; // Current link and IPv4 state
#define MG_TCPIP_STATE_DOWN 0 // Interface is down
#define MG_TCPIP_STATE_UP 1 // Interface is up
#define MG_TCPIP_STATE_REQ 2 // Interface is up, DHCP REQUESTING state
#define MG_TCPIP_STATE_IP 3 // Interface is up and has an IP assigned
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work
#if MG_ENABLE_IPV6
uint8_t gw6mac[6]; // IPv6 Router's MAC
uint8_t state6; // Current IPv6 state
#endif
};
void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
void mg_tcpip_free(struct mg_tcpip_if *);
void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp);

View file

@ -204,6 +204,10 @@ uint32_t mg_ntohl(uint32_t net) {
return MG_LOAD_BE32(&net);
}
uint64_t mg_ntohll(uint64_t net) {
return MG_LOAD_BE64(&net);
}
void mg_delayms(unsigned int ms) {
uint64_t to = mg_millis() + ms + 1;
while (mg_millis() < to) (void) 0;

View file

@ -27,6 +27,16 @@ void mg_delayms(unsigned int ms);
#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
#define MG_IPV6(a, b, c, d, e, f, g ,h) \
{ (uint8_t)((a)>>8),(uint8_t)(a), \
(uint8_t)((b)>>8),(uint8_t)(b), \
(uint8_t)((c)>>8),(uint8_t)(c), \
(uint8_t)((d)>>8),(uint8_t)(d), \
(uint8_t)((e)>>8),(uint8_t)(e), \
(uint8_t)((f)>>8),(uint8_t)(f), \
(uint8_t)((g)>>8),(uint8_t)(g), \
(uint8_t)((h)>>8),(uint8_t)(h) }
// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
#define MG_U8P(ADDR) ((uint8_t *) (ADDR))
#define MG_IPADDR_PARTS(ADDR) \
@ -41,6 +51,14 @@ void mg_delayms(unsigned int ms);
((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
((uint32_t) MG_U8P(p)[1] << 16U) | \
((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
#define MG_LOAD_BE64(p) \
((uint64_t) (((uint64_t) MG_U8P(p)[0] << 56U) | \
((uint64_t) MG_U8P(p)[1] << 48U) | \
((uint64_t) MG_U8P(p)[2] << 40U) | \
((uint64_t) MG_U8P(p)[3] << 32U) | \
((uint64_t) MG_U8P(p)[4] << 24U) | \
((uint64_t) MG_U8P(p)[5] << 16U) | \
((uint64_t) MG_U8P(p)[6] << 8U) | MG_U8P(p)[7]))
#define MG_STORE_BE16(p, n) \
do { \
MG_U8P(p)[0] = ((n) >> 8U) & 255; \
@ -59,11 +77,24 @@ void mg_delayms(unsigned int ms);
MG_U8P(p)[2] = ((n) >> 8U) & 255; \
MG_U8P(p)[3] = (n) &255; \
} while (0)
#define MG_STORE_BE64(p, n) \
do { \
MG_U8P(p)[0] = ((n) >> 56U) & 255; \
MG_U8P(p)[1] = ((n) >> 48U) & 255; \
MG_U8P(p)[2] = ((n) >> 40U) & 255; \
MG_U8P(p)[3] = ((n) >> 32U) & 255; \
MG_U8P(p)[4] = ((n) >> 24U) & 255; \
MG_U8P(p)[5] = ((n) >> 16U) & 255; \
MG_U8P(p)[6] = ((n) >> 8U) & 255; \
MG_U8P(p)[7] = (n) &255; \
} while (0)
uint16_t mg_ntohs(uint16_t net);
uint32_t mg_ntohl(uint32_t net);
uint64_t mg_ntohll(uint64_t net);
#define mg_htons(x) mg_ntohs(x)
#define mg_htonl(x) mg_ntohl(x)
#define mg_htonll(x) mg_ntohll(x)
#define MG_REG(x) ((volatile uint32_t *) (x))[0]
#define MG_BIT(x) (((uint32_t) 1U) << (x))

File diff suppressed because it is too large Load diff

View file

@ -2617,6 +2617,8 @@ static void test_util(void) {
const char *e;
char buf[100], *s;
struct mg_addr a;
uint64_t ipv3;
uint8_t d64[8] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef};
uint32_t ipv4;
uint16_t port;
struct mg_str data;
@ -2651,6 +2653,20 @@ static void test_util(void) {
((uint8_t *) &ipv4)[2] == 0x45);
ASSERT(MG_LOAD_BE24(&ipv4) == 0xef2345);
memcpy(&ipv3, d64, sizeof(ipv3));
#if defined(_MSC_VER) && _MSC_VER < 1700
// VC98 doesn't suppport LL suffix
#else
ASSERT(ipv3 == mg_htonll(0x1234567890abcdefLL));
ASSERT(mg_ntohll(ipv3) == 0x1234567890abcdefLL);
#endif
MG_STORE_BE64(&ipv3, 0x5678abcd12349ef0);
ASSERT(((uint8_t *) &ipv3)[0] == 0x56 && ((uint8_t *) &ipv3)[1] == 0x78 &&
((uint8_t *) &ipv3)[2] == 0xab && ((uint8_t *) &ipv3)[3] == 0xcd &&
((uint8_t *) &ipv3)[4] == 0x12 && ((uint8_t *) &ipv3)[5] == 0x34 &&
((uint8_t *) &ipv3)[6] == 0x9e && ((uint8_t *) &ipv3)[7] == 0xf0);
ASSERT(MG_LOAD_BE64(&ipv3) == 0x5678abcd12349ef0);
memset(a.ip, 0xa5, sizeof(a.ip));
ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true);
ASSERT(a.is_ip6 == true);