diff --git a/mongoose.c b/mongoose.c index 000cbc58c7..3f6ef069e9 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5107,7 +5107,7 @@ static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) { return n; } -static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) { +void mg_tcpip_arp_request(struct mg_tcpip_if *ifp, uint32_t ip, uint8_t *mac) { struct eth *eth = (struct eth *) ifp->tx.buf; struct arp *arp = (struct arp *) (eth + 1); memset(eth->dst, 255, sizeof(eth->dst)); @@ -5118,6 +5118,7 @@ static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) { arp->plen = 4; arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip; memcpy(arp->sha, ifp->mac, sizeof(arp->sha)); + if (mac != NULL) memcpy(arp->tha, mac, sizeof(arp->tha)); ether_output(ifp, PDIFF(eth, arp + 1)); } @@ -5126,7 +5127,9 @@ static void onstatechange(struct mg_tcpip_if *ifp) { MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip)); MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw)); MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac)); - arp_ask(ifp, ifp->gw); // unsolicited GW ARP request + } else if (ifp->state == MG_TCPIP_STATE_IP) { + MG_ERROR(("Got IP")); + mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request } else if (ifp->state == MG_TCPIP_STATE_UP) { MG_ERROR(("Link up")); srand((unsigned int) mg_millis()); @@ -5276,8 +5279,12 @@ static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) { } else if (pkt->arp->op == mg_htons(2)) { if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return; if (pkt->arp->spa == ifp->gw) { - // Got response for the GW ARP request. Set ifp->gwmac + // Got response for the GW ARP request. Set ifp->gwmac and IP -> READY memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac)); + if (ifp->state == MG_TCPIP_STATE_IP) { + ifp->state = MG_TCPIP_STATE_READY; + onstatechange(ifp); + } } else { struct mg_connection *c = getpeer(ifp->mgr, pkt, false); if (c != NULL && c->is_arplooking) { @@ -5352,7 +5359,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { // assume DHCP server = router until ARP resolves memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; - ifp->state = MG_TCPIP_STATE_READY; // BOUND state + ifp->state = MG_TCPIP_STATE_IP; // BOUND state uint64_t rand; mg_random(&rand, sizeof(rand)); srand((unsigned int) (rand + mg_millis())); @@ -5400,7 +5407,7 @@ static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { res.magic = pkt->dhcp->magic; res.xid = pkt->dhcp->xid; if (ifp->enable_get_gateway) { - ifp->gw = res.yiaddr; + ifp->gw = res.yiaddr; // set gw IP, best-effort gwmac as DHCP server's memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); } tx_udp(ifp, pkt->eth->src, ifp->ip, mg_htons(67), @@ -5785,6 +5792,7 @@ static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) { if (pkt.eth->type == mg_htons(0x806)) { pkt.arp = (struct arp *) (pkt.eth + 1); if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated + mg_tcpip_call(ifp, MG_TCPIP_EV_ARP, &pkt.raw); rx_arp(ifp, &pkt); } else if (pkt.eth->type == mg_htons(0x86dd)) { pkt.ip6 = (struct ip6 *) (pkt.eth + 1); @@ -5816,40 +5824,53 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { #if MG_ENABLE_TCPIP_PRINT_DEBUG_STATS if (expired_1000ms) { - const char *names[] = {"down", "up", "req", "ready"}; + const char *names[] = {"down", "up", "req", "ip", "ready"}; MG_INFO(("Status: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u", names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent, ifp->ndrop, ifp->nerr)); } #endif + // Handle gw ARP request timeout, order is important + if (expired_1000ms && ifp->state == MG_TCPIP_STATE_IP) { + ifp->state = MG_TCPIP_STATE_READY; // keep best-effort MAC + onstatechange(ifp); + } // Handle physical interface up/down status if (expired_1000ms && ifp->driver->up) { bool up = ifp->driver->up(ifp); bool current = ifp->state != MG_TCPIP_STATE_DOWN; - if (up != current) { - ifp->state = up == false ? MG_TCPIP_STATE_DOWN - : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP - : MG_TCPIP_STATE_READY; - if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + if (up != current) { // link state has changed + ifp->state = up == false ? MG_TCPIP_STATE_DOWN + : ifp->enable_dhcp_client || ifp->ip == 0 + ? MG_TCPIP_STATE_UP + : MG_TCPIP_STATE_IP; + onstatechange(ifp); + } else if (!ifp->enable_dhcp_client && ifp->state == MG_TCPIP_STATE_UP && + ifp->ip) { + ifp->state = MG_TCPIP_STATE_IP; // ifp->fn has set an IP onstatechange(ifp); } if (ifp->state == MG_TCPIP_STATE_DOWN) MG_ERROR(("Network is down")); + mg_tcpip_call(ifp, MG_TCPIP_EV_TIMER_1S, NULL); } if (ifp->state == MG_TCPIP_STATE_DOWN) return; // DHCP RFC-2131 (4.4) - if (ifp->state == MG_TCPIP_STATE_UP && expired_1000ms) { - tx_dhcp_discover(ifp); // INIT (4.4.1) - } else if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY && - ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING - if (ifp->now >= ifp->lease_expire) { - ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP - onstatechange(ifp); - } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && - ((ifp->now / 1000) % 60) == 0) { - // hack: 30 min before deadline, try to rebind (4.3.6) every min - tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); - } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + if (ifp->enable_dhcp_client && expired_1000ms) { + if (ifp->state == MG_TCPIP_STATE_UP) { + tx_dhcp_discover(ifp); // INIT (4.4.1) + } else if (ifp->state == MG_TCPIP_STATE_READY && + ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING + if (ifp->now >= ifp->lease_expire) { + ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP + onstatechange(ifp); + } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && + ((ifp->now / 1000) % 60) == 0) { + // hack: 30 min before deadline, try to rebind (4.3.6) every min + tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); + } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + } } // Read data from the network @@ -5943,7 +5964,7 @@ void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) { ifp->mtu = MG_TCPIP_MTU_DEFAULT; mgr->extraconnsize = sizeof(struct connstate); if (ifp->ip == 0) ifp->enable_dhcp_client = true; - memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set to broadcast + memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set best-effort to bcast mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535 ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from // MG_EPHEMERAL_PORT_BASE to 65535 @@ -5996,7 +6017,7 @@ void mg_connect_resolved(struct mg_connection *c) { rem_ip != ifp->gw) { // skip if gw (onstatechange -> READY -> ARP) // If we're in the same LAN, fire an ARP lookup. MG_DEBUG(("%lu ARP lookup...", c->id)); - arp_ask(ifp, rem_ip); + mg_tcpip_arp_request(ifp, rem_ip, NULL); settmout(c, MIP_TTYPE_ARP); c->is_arplooking = 1; } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) { diff --git a/mongoose.h b/mongoose.h index de0982e4fa..727e5557a5 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2739,6 +2739,8 @@ 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_USER // Starting ID for user events }; @@ -2775,13 +2777,15 @@ struct mg_tcpip_if { uint8_t state; // Current 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 and has requested an IP -#define MG_TCPIP_STATE_READY 3 // Interface is up and has an IP assigned +#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 }; 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); +void mg_tcpip_arp_request(struct mg_tcpip_if *ifp, uint32_t ip, uint8_t *mac); extern struct mg_tcpip_driver mg_tcpip_driver_stm32f; extern struct mg_tcpip_driver mg_tcpip_driver_w5500; diff --git a/src/net_builtin.c b/src/net_builtin.c index 76c091ec9f..6576bde518 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -185,7 +185,7 @@ static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) { return n; } -static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) { +void mg_tcpip_arp_request(struct mg_tcpip_if *ifp, uint32_t ip, uint8_t *mac) { struct eth *eth = (struct eth *) ifp->tx.buf; struct arp *arp = (struct arp *) (eth + 1); memset(eth->dst, 255, sizeof(eth->dst)); @@ -196,6 +196,7 @@ static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) { arp->plen = 4; arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip; memcpy(arp->sha, ifp->mac, sizeof(arp->sha)); + if (mac != NULL) memcpy(arp->tha, mac, sizeof(arp->tha)); ether_output(ifp, PDIFF(eth, arp + 1)); } @@ -204,7 +205,9 @@ static void onstatechange(struct mg_tcpip_if *ifp) { MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip)); MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw)); MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac)); - arp_ask(ifp, ifp->gw); // unsolicited GW ARP request + } else if (ifp->state == MG_TCPIP_STATE_IP) { + MG_ERROR(("Got IP")); + mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request } else if (ifp->state == MG_TCPIP_STATE_UP) { MG_ERROR(("Link up")); srand((unsigned int) mg_millis()); @@ -354,8 +357,12 @@ static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) { } else if (pkt->arp->op == mg_htons(2)) { if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return; if (pkt->arp->spa == ifp->gw) { - // Got response for the GW ARP request. Set ifp->gwmac + // Got response for the GW ARP request. Set ifp->gwmac and IP -> READY memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac)); + if (ifp->state == MG_TCPIP_STATE_IP) { + ifp->state = MG_TCPIP_STATE_READY; + onstatechange(ifp); + } } else { struct mg_connection *c = getpeer(ifp->mgr, pkt, false); if (c != NULL && c->is_arplooking) { @@ -430,7 +437,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { // assume DHCP server = router until ARP resolves memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; - ifp->state = MG_TCPIP_STATE_READY; // BOUND state + ifp->state = MG_TCPIP_STATE_IP; // BOUND state uint64_t rand; mg_random(&rand, sizeof(rand)); srand((unsigned int) (rand + mg_millis())); @@ -478,7 +485,7 @@ static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { res.magic = pkt->dhcp->magic; res.xid = pkt->dhcp->xid; if (ifp->enable_get_gateway) { - ifp->gw = res.yiaddr; + ifp->gw = res.yiaddr; // set gw IP, best-effort gwmac as DHCP server's memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); } tx_udp(ifp, pkt->eth->src, ifp->ip, mg_htons(67), @@ -863,6 +870,7 @@ static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) { if (pkt.eth->type == mg_htons(0x806)) { pkt.arp = (struct arp *) (pkt.eth + 1); if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated + mg_tcpip_call(ifp, MG_TCPIP_EV_ARP, &pkt.raw); rx_arp(ifp, &pkt); } else if (pkt.eth->type == mg_htons(0x86dd)) { pkt.ip6 = (struct ip6 *) (pkt.eth + 1); @@ -894,40 +902,53 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { #if MG_ENABLE_TCPIP_PRINT_DEBUG_STATS if (expired_1000ms) { - const char *names[] = {"down", "up", "req", "ready"}; + const char *names[] = {"down", "up", "req", "ip", "ready"}; MG_INFO(("Status: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u", names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent, ifp->ndrop, ifp->nerr)); } #endif + // Handle gw ARP request timeout, order is important + if (expired_1000ms && ifp->state == MG_TCPIP_STATE_IP) { + ifp->state = MG_TCPIP_STATE_READY; // keep best-effort MAC + onstatechange(ifp); + } // Handle physical interface up/down status if (expired_1000ms && ifp->driver->up) { bool up = ifp->driver->up(ifp); bool current = ifp->state != MG_TCPIP_STATE_DOWN; - if (up != current) { - ifp->state = up == false ? MG_TCPIP_STATE_DOWN - : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP - : MG_TCPIP_STATE_READY; - if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + if (up != current) { // link state has changed + ifp->state = up == false ? MG_TCPIP_STATE_DOWN + : ifp->enable_dhcp_client || ifp->ip == 0 + ? MG_TCPIP_STATE_UP + : MG_TCPIP_STATE_IP; + onstatechange(ifp); + } else if (!ifp->enable_dhcp_client && ifp->state == MG_TCPIP_STATE_UP && + ifp->ip) { + ifp->state = MG_TCPIP_STATE_IP; // ifp->fn has set an IP onstatechange(ifp); } if (ifp->state == MG_TCPIP_STATE_DOWN) MG_ERROR(("Network is down")); + mg_tcpip_call(ifp, MG_TCPIP_EV_TIMER_1S, NULL); } if (ifp->state == MG_TCPIP_STATE_DOWN) return; // DHCP RFC-2131 (4.4) - if (ifp->state == MG_TCPIP_STATE_UP && expired_1000ms) { - tx_dhcp_discover(ifp); // INIT (4.4.1) - } else if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY && - ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING - if (ifp->now >= ifp->lease_expire) { - ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP - onstatechange(ifp); - } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && - ((ifp->now / 1000) % 60) == 0) { - // hack: 30 min before deadline, try to rebind (4.3.6) every min - tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); - } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + if (ifp->enable_dhcp_client && expired_1000ms) { + if (ifp->state == MG_TCPIP_STATE_UP) { + tx_dhcp_discover(ifp); // INIT (4.4.1) + } else if (ifp->state == MG_TCPIP_STATE_READY && + ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING + if (ifp->now >= ifp->lease_expire) { + ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP + onstatechange(ifp); + } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && + ((ifp->now / 1000) % 60) == 0) { + // hack: 30 min before deadline, try to rebind (4.3.6) every min + tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); + } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + } } // Read data from the network @@ -1021,7 +1042,7 @@ void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) { ifp->mtu = MG_TCPIP_MTU_DEFAULT; mgr->extraconnsize = sizeof(struct connstate); if (ifp->ip == 0) ifp->enable_dhcp_client = true; - memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set to broadcast + memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set best-effort to bcast mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535 ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from // MG_EPHEMERAL_PORT_BASE to 65535 @@ -1074,7 +1095,7 @@ void mg_connect_resolved(struct mg_connection *c) { rem_ip != ifp->gw) { // skip if gw (onstatechange -> READY -> ARP) // If we're in the same LAN, fire an ARP lookup. MG_DEBUG(("%lu ARP lookup...", c->id)); - arp_ask(ifp, rem_ip); + mg_tcpip_arp_request(ifp, rem_ip, NULL); settmout(c, MIP_TTYPE_ARP); c->is_arplooking = 1; } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) { diff --git a/src/net_builtin.h b/src/net_builtin.h index e6e625d757..75cad292f2 100644 --- a/src/net_builtin.h +++ b/src/net_builtin.h @@ -22,6 +22,8 @@ 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_USER // Starting ID for user events }; @@ -58,13 +60,15 @@ struct mg_tcpip_if { uint8_t state; // Current 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 and has requested an IP -#define MG_TCPIP_STATE_READY 3 // Interface is up and has an IP assigned +#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 }; 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); +void mg_tcpip_arp_request(struct mg_tcpip_if *ifp, uint32_t ip, uint8_t *mac); extern struct mg_tcpip_driver mg_tcpip_driver_stm32f; extern struct mg_tcpip_driver mg_tcpip_driver_w5500; diff --git a/tutorials/tcpip/pcap-driver/main.c b/tutorials/tcpip/pcap-driver/main.c index dea210b335..b8646c9d72 100644 --- a/tutorials/tcpip/pcap-driver/main.c +++ b/tutorials/tcpip/pcap-driver/main.c @@ -1,16 +1,16 @@ -// Copyright (c) 2022 Cesanta Software Limited +// Copyright (c) 2022-24 Cesanta Software Limited // All rights reserved // -// SNTP example using MIP and pcap driver +// example using MIP and pcap driver +// make CFLAGS_EXTRA="-DMG_TLS=MG_TLS_BUILTIN -DDISABLE_DHCP" for "auto-IP" #include #include "mongoose.h" -#define MQTT_URL "mqtt://broker.emqx.io:1883" // MQTT broker URL -#define MQTTS_URL "mqtts://mongoose.ws:8883" // HiveMQ does not TLS1.3 -#define MQTT_TOPIC "mg/rx" // Topic to subscribe to +#define MQTT_URL "mqtt://broker.emqx.io:1883" // MQTT broker URL +#define MQTTS_URL "mqtts://mongoose.ws:8883" // HiveMQ does not TLS1.3 +#define MQTT_TOPIC "mg/rx" // Topic to subscribe to -// // Taken from broker.emqx.io static const char *s_ca_cert = "-----BEGIN CERTIFICATE-----\n" "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" @@ -44,29 +44,6 @@ static const char *s_ca_cert = "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" "-----END CERTIFICATE-----\n"; -// "-----BEGIN CERTIFICATE-----\n" -// "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh" -// "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" -// "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n" -// "MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\n" -// "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" -// "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n" -// "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n" -// "2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n" -// "1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\n" -// "q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\n" -// "tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\n" -// "vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\n" -// "BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n" -// "5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n" -// "1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\n" -// "NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\n" -// "Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n" -// "8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\n" -// "pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n" -// "MrY=\n" -// "-----END CERTIFICATE-----\n"; - static const char *s_tls_cert = "-----BEGIN CERTIFICATE-----\n" "MIIBMTCB2aADAgECAgkAluqkgeuV/zUwCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwI\n" @@ -192,6 +169,55 @@ static void mqtt_ev_handler(struct mg_connection *c, int ev, void *ev_data) { } } +static void if_ev_handler(struct mg_tcpip_if *ifp, int ev, void *ev_data) { + // Trigger MQTT connection when we have an IP address + if (ifp->state == MG_TCPIP_STATE_READY && ev == MG_TCPIP_EV_ST_CHG) { + struct mg_mqtt_opts opts = {.clean = true}; + // mg_mqtt_connect(ifp->mgr, MQTT_URL, &opts, mqtt_ev_handler, NULL); + mg_mqtt_connect(ifp->mgr, MQTTS_URL, &opts, mqtt_ev_handler, "tls enabled"); + } + +#if defined(DISABLE_DHCP) + { + static uint32_t ip = 0; + static unsigned counter = 0; + // Set initial self-assigned IP + if (ip == 0) ip = MG_IPV4(169, 254, 2, 100); + + // restart process on link change + if (ev == MG_TCPIP_EV_ST_CHG && ifp->state == MG_TCPIP_STATE_DOWN) { + ifp->ip = 0; + counter = 0; + } + + if (ifp->state == MG_TCPIP_STATE_UP) { + // Catch ARP packets. Parse them yourself, that's easy. + if (ev == MG_TCPIP_EV_ARP) { + struct mg_str *frame = ev_data; + MG_INFO(("Iface %p: Got ARP frame", ifp)); + mg_hexdump(frame->buf, frame->len); + // TODO: check for conflict. On conflict, increment ip and reset counter + } + + // Catch 1 second timer events + if (ev == MG_TCPIP_EV_TIMER_1S) { + if (++counter <= 3) { + MG_INFO(("Sending ARP probe")); + mg_tcpip_arp_request(ifp, ip, NULL); + } else { + // Seems to be no conflict. Assign us an IP + MG_INFO(("Assigning %M, sending gratuitous ARP", mg_print_ip4, &ip)); + ifp->ip = ip; // state will change to MG_TCPIP_STATE_IP on next poll + mg_tcpip_arp_request(ifp, ip, ifp->mac); + } + } + } + } +#else + (void) ev_data; +#endif +} + int main(int argc, char *argv[]) { const char *iface = "lo0"; // Network iface const char *mac = "02:00:01:02:03:77"; // MAC address @@ -247,27 +273,29 @@ int main(int argc, char *argv[]) { mg_log_set(MG_LL_DEBUG); // Set log level struct mg_tcpip_driver driver = {.tx = pcap_tx, .up = pcap_up, .rx = pcap_rx}; - struct mg_tcpip_if mif = {.driver = &driver, .driver_data = ph}; + struct mg_tcpip_if mif = {.driver = &driver, + .driver_data = ph, + .enable_mac_check = true, +#if defined(DISABLE_DHCP) + .mask = MG_IPV4(255, 255, 255, 0), + .gw = MG_IPV4(169, 254, 2, 1), +#endif + .fn = if_ev_handler}; sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1], &mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]); mg_tcpip_init(&mgr, &mif); + // order is important: set after calling mg_tcpip_init() +#if defined(DISABLE_DHCP) + mif.enable_dhcp_client = false; +#endif + MG_INFO(("Init done, starting main loop")); mg_http_listen(&mgr, "http://0.0.0.0:8000", http_ev_handler, NULL); mg_http_listen(&mgr, "https://0.0.0.0:8443", http_ev_handler, "tls enabled"); - bool got_ip = false; - while (s_signo == 0) { mg_mgr_poll(&mgr, 100); - - // Trigger MQTT connection when we receive IP address - if (mif.state == MG_TCPIP_STATE_READY && got_ip == false) { - struct mg_mqtt_opts opts = {.clean = true}; - // mg_mqtt_connect(&mgr, MQTT_URL, &opts, mqtt_ev_handler, NULL); - mg_mqtt_connect(&mgr, MQTTS_URL, &opts, mqtt_ev_handler, "tls enabled"); - got_ip = true; - } } mg_mgr_free(&mgr);