From e1f7f3d7bb68deedad7c127a380cd382bb7fce35 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 22 Aug 2024 21:19:33 +0100 Subject: [PATCH] Make ARP probe public. Add ARP event --- mongoose.c | 9 ++++--- mongoose.h | 3 +++ src/net_builtin.c | 9 ++++--- src/net_builtin.h | 3 +++ tutorials/tcpip/pcap-driver/main.c | 39 +++++++++++++++++++++++++++--- 5 files changed, 54 insertions(+), 9 deletions(-) diff --git a/mongoose.c b/mongoose.c index 000cbc58..732f8a50 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,7 @@ 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 + 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()); @@ -5785,6 +5786,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); @@ -5834,6 +5836,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { 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; @@ -5996,7 +5999,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 de0982e4..b9826139 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 }; @@ -2782,6 +2784,7 @@ struct mg_tcpip_if { 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 76c091ec..64e891f4 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,7 @@ 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 + 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()); @@ -863,6 +864,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); @@ -912,6 +914,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { 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; @@ -1074,7 +1077,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 e6e625d7..c672d989 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 }; @@ -65,6 +67,7 @@ struct mg_tcpip_if { 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 dea210b3..7e93e79f 100644 --- a/tutorials/tcpip/pcap-driver/main.c +++ b/tutorials/tcpip/pcap-driver/main.c @@ -6,9 +6,9 @@ #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 = @@ -192,6 +192,35 @@ 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) { + static uint32_t ip = 0; + static unsigned counter = 0; + + // Set initial self-assigned IP + if (ip == 0) ip = MG_IPV4(169, 254, 2, 100); + + // 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 && ifp->ip == 0) { + MG_INFO(("Sending ARP probe")); + mg_tcpip_arp_request(ifp, ip, NULL); + + // Seems to be no conflict. Assign us an IP + if (counter++ > 2) { + MG_INFO(("Assigning %M, sending ARP probe", mg_print_ip4, &ip)); + ifp->ip = ip; + mg_tcpip_arp_request(ifp, ip, ifp->mac); + } + } +} + int main(int argc, char *argv[]) { const char *iface = "lo0"; // Network iface const char *mac = "02:00:01:02:03:77"; // MAC address @@ -252,6 +281,10 @@ int main(int argc, char *argv[]) { &mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]); mg_tcpip_init(&mgr, &mif); + // Call order is important: call after mg_tcpip_init() + mif.fn = if_ev_handler; + mif.enable_dhcp_client = false; + 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");