+static void send_mtu_probe_handler(event_loop_t *loop, void *data) {
+ meshlink_handle_t *mesh = loop->data;
+ node_t *n = data;
+ int timeout = 1;
+
+ n->mtuprobes++;
+
+ if(!n->status.reachable || !n->status.validkey) {
+ logger(mesh, MESHLINK_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
+ n->mtuprobes = 0;
+ return;
+ }
+
+ if(n->mtuprobes > 32) {
+ if(!n->minmtu) {
+ n->mtuprobes = 31;
+ timeout = mesh->pinginterval;
+ goto end;
+ }
+
+ logger(mesh, MESHLINK_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
+ n->status.udp_confirmed = false;
+ n->mtuprobes = 1;
+ n->minmtu = 0;
+ n->maxmtu = MTU;
+ }
+
+ if(n->mtuprobes >= 10 && n->mtuprobes < 32 && !n->minmtu) {
+ logger(mesh, MESHLINK_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
+ n->mtuprobes = 31;
+ }
+
+ if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) {
+ if(n->minmtu > n->maxmtu)
+ n->minmtu = n->maxmtu;
+ else
+ n->maxmtu = n->minmtu;
+ n->mtu = n->minmtu;
+ logger(mesh, MESHLINK_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
+ n->mtuprobes = 31;
+ }
+
+ if(n->mtuprobes == 31) {
+ timeout = mesh->pinginterval;
+ goto end;
+ } else if(n->mtuprobes == 32) {
+ timeout = mesh->pingtimeout;
+ }
+
+ for(int i = 0; i < 4 + mesh->localdiscovery; i++) {
+ int len;
+
+ if(i == 0) {
+ if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU)
+ continue;
+ len = n->maxmtu + 8;
+ } else if(n->maxmtu <= n->minmtu) {
+ len = n->maxmtu;
+ } else {
+ len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
+ }
+
+ if(len < 64)
+ len = 64;
+
+ vpn_packet_t packet;
+ packet.probe = true;
+ memset(packet.data, 0, 14);
+ randomize(packet.data + 14, len - 14);
+ packet.len = len;
+ n->status.broadcast = i >= 4 && n->mtuprobes <= 10 && n->prevedge;
+
+ logger(mesh, MESHLINK_DEBUG, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
+
+ send_udppacket(mesh, n, &packet);
+ }
+
+ n->status.broadcast = false;
+ n->probe_counter = 0;
+ gettimeofday(&n->probe_time, NULL);
+
+ /* Calculate the packet loss of incoming traffic by comparing the rate of
+ packets received to the rate with which the sequence number has increased.
+ */
+
+ if(n->received > n->prev_received)
+ n->packetloss = 1.0 - (n->received - n->prev_received) / (float)(n->received_seqno - n->prev_received_seqno);
+ else
+ n->packetloss = n->received_seqno <= n->prev_received_seqno;
+
+ n->prev_received_seqno = n->received_seqno;
+ n->prev_received = n->received;
+
+end:
+ timeout_set(&mesh->loop, &n->mtutimeout, &(struct timeval){timeout, rand() % 100000});
+}