diff --git a/mongoose.c b/mongoose.c index 69d99789..c28921d7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -7702,6 +7702,13 @@ static void onstatechange(struct mg_tcpip_if *ifp) { MG_INFO((" MAC: %M", mg_print_mac, ifp->mac)); if (ifp->l2type == MG_TCPIP_L2_ETH) mg_tcpip_arp_request(ifp, ifp->ip, ifp->mac); // gratuitous ARP annc + if (ifp->is_ip_changed) { + struct mg_connection *c; + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (!c->is_listening && !c->is_udp) c->is_closing = 1; + } + ifp->is_ip_changed = false; + } } else if (ifp->state == MG_TCPIP_STATE_IP) { if (ifp->gw != 0 && ifp->l2type == MG_TCPIP_L2_ETH) mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request @@ -8011,6 +8018,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { // assume DHCP server = router until ARP resolves memcpy(ifp->gwmac, mg_l2_getaddr(ifp, pkt->l2), sizeof(ifp->gwmac)); ifp->gw_ready = true; // NOTE(): actual gw ARP won't retry now + if (ifp->ip != ip) ifp->is_ip_changed = true; ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; ifp->state = MG_TCPIP_STATE_IP; // BOUND state mg_random(&rand, sizeof(rand)); @@ -8266,7 +8274,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { struct ndp_ra *ra = (struct ndp_ra *) (pkt->icmp6 + 1); uint8_t *opts = (uint8_t *) (ra + 1); size_t opt_left = pkt->pay.len - 12; - bool gotl2addr = false, gotprefix = false; + bool gotl2addr = false, gotprefix = false, changed = false; uint8_t l2[sizeof(struct mg_l2addr)]; uint32_t mtu = 0; uint8_t *prefix, prefix_len; @@ -8299,6 +8307,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { (void) pref_lifetime; gotprefix = true; + if (prefix_len != ifp->prefix || !match_prefix(prefix, ifp->prefix, ifp->prefix_len)) + changed = true; } opts += length; opt_left -= length; @@ -8306,6 +8316,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { // fill prefix and global if (gotprefix && !fill_global(ifp, prefix, prefix_len)) return; + if (changed) ifp->is_ip6_changed = true; ifp->gw6[0] = pkt->ip6->src[0], ifp->gw6[1] = pkt->ip6->src[1]; if (gotl2addr) memcpy(ifp->gw6mac, l2, sizeof(ifp->gw6mac)); if (gotl2addr || ifp->l2type == MG_TCPIP_L2_PPP || ifp->l2type == MG_TCPIP_L2_PPPoE) { @@ -8384,6 +8395,12 @@ static void onstate6change(struct mg_tcpip_if *ifp) { (struct mg_addr *) &ip6_allrouters), ifp->ip6, (uint64_t *) ip6_allrouters.addr.ip6, false, ifp->mac); + if (ifp->is_ip6_changed) { + struct mg_connection *c; + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (!c->is_listening && !c->is_udp) c->is_closing = 1; + } + ifp->is_ip6_changed = false; } } else if (ifp->state6 == MG_TCPIP_STATE_IP) { if ((ifp->gw6[0] != 0 || ifp->gw6[1] != 0) && (ifp->l2type != MG_TCPIP_L2_PPP && ifp->l2type != MG_TCPIP_L2_PPPoE)) diff --git a/mongoose.h b/mongoose.h index e72f68a0..a61d76a4 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3644,6 +3644,7 @@ struct mg_tcpip_if { bool enable_fcs_check; // Do a FCS check on RX frames and strip it bool enable_mac_check; // Do a hw addr check on RX frames bool update_mac_hash_table; // Signal drivers to update MAC controller + bool is_ip_changed; // IP address changed, close/restart conns struct mg_tcpip_driver *driver; // Low level driver void *driver_data; // Driver-specific data mg_tcpip_event_handler_t pfn; // Driver-specific event handler function @@ -3660,6 +3661,7 @@ struct mg_tcpip_if { uint64_t gw6[2]; // default gateway. bool enable_slaac; // Enable IPv6 address autoconfiguration bool enable_dhcp6_client; // Enable DCHPv6 client TODO() + bool is_ip6_changed; // IPv6 address changed, close/restart conns #endif // Internal state, user can use it but should not change it diff --git a/src/net_builtin.c b/src/net_builtin.c index add95827..340bd2d0 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -393,6 +393,13 @@ static void onstatechange(struct mg_tcpip_if *ifp) { MG_INFO((" MAC: %M", mg_print_mac, ifp->mac)); if (ifp->l2type == MG_TCPIP_L2_ETH) mg_tcpip_arp_request(ifp, ifp->ip, ifp->mac); // gratuitous ARP annc + if (ifp->is_ip_changed) { + struct mg_connection *c; + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (!c->is_listening && !c->is_udp) c->is_closing = 1; + } + ifp->is_ip_changed = false; + } } else if (ifp->state == MG_TCPIP_STATE_IP) { if (ifp->gw != 0 && ifp->l2type == MG_TCPIP_L2_ETH) mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request @@ -702,6 +709,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { // assume DHCP server = router until ARP resolves memcpy(ifp->gwmac, mg_l2_getaddr(ifp, pkt->l2), sizeof(ifp->gwmac)); ifp->gw_ready = true; // NOTE(): actual gw ARP won't retry now + if (ifp->ip != ip) ifp->is_ip_changed = true; ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; ifp->state = MG_TCPIP_STATE_IP; // BOUND state mg_random(&rand, sizeof(rand)); @@ -957,7 +965,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { struct ndp_ra *ra = (struct ndp_ra *) (pkt->icmp6 + 1); uint8_t *opts = (uint8_t *) (ra + 1); size_t opt_left = pkt->pay.len - 12; - bool gotl2addr = false, gotprefix = false; + bool gotl2addr = false, gotprefix = false, changed = false; uint8_t l2[sizeof(struct mg_l2addr)]; uint32_t mtu = 0; uint8_t *prefix, prefix_len; @@ -990,6 +998,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { (void) pref_lifetime; gotprefix = true; + if (prefix_len != ifp->prefix || !match_prefix(prefix, ifp->prefix, ifp->prefix_len)) + changed = true; } opts += length; opt_left -= length; @@ -997,6 +1007,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { // fill prefix and global if (gotprefix && !fill_global(ifp, prefix, prefix_len)) return; + if (changed) ifp->is_ip6_changed = true; ifp->gw6[0] = pkt->ip6->src[0], ifp->gw6[1] = pkt->ip6->src[1]; if (gotl2addr) memcpy(ifp->gw6mac, l2, sizeof(ifp->gw6mac)); if (gotl2addr || ifp->l2type == MG_TCPIP_L2_PPP || ifp->l2type == MG_TCPIP_L2_PPPoE) { @@ -1075,6 +1086,12 @@ static void onstate6change(struct mg_tcpip_if *ifp) { (struct mg_addr *) &ip6_allrouters), ifp->ip6, (uint64_t *) ip6_allrouters.addr.ip6, false, ifp->mac); + if (ifp->is_ip6_changed) { + struct mg_connection *c; + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (!c->is_listening && !c->is_udp) c->is_closing = 1; + } + ifp->is_ip6_changed = false; } } else if (ifp->state6 == MG_TCPIP_STATE_IP) { if ((ifp->gw6[0] != 0 || ifp->gw6[1] != 0) && (ifp->l2type != MG_TCPIP_L2_PPP && ifp->l2type != MG_TCPIP_L2_PPPoE)) diff --git a/src/net_builtin.h b/src/net_builtin.h index 3c7145e8..71d15b24 100644 --- a/src/net_builtin.h +++ b/src/net_builtin.h @@ -49,6 +49,7 @@ struct mg_tcpip_if { bool enable_fcs_check; // Do a FCS check on RX frames and strip it bool enable_mac_check; // Do a hw addr check on RX frames bool update_mac_hash_table; // Signal drivers to update MAC controller + bool is_ip_changed; // IP address changed, close/restart conns struct mg_tcpip_driver *driver; // Low level driver void *driver_data; // Driver-specific data mg_tcpip_event_handler_t pfn; // Driver-specific event handler function @@ -65,6 +66,7 @@ struct mg_tcpip_if { uint64_t gw6[2]; // default gateway. bool enable_slaac; // Enable IPv6 address autoconfiguration bool enable_dhcp6_client; // Enable DCHPv6 client TODO() + bool is_ip6_changed; // IPv6 address changed, close/restart conns #endif // Internal state, user can use it but should not change it