Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plpmtud icmp #241

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Prev Previous commit
React to ICMP messages when probing
Irene Ruengeler authored and Irene Ruengeler committed Jun 14, 2018
commit 1e184b4a092bef1f346ef3f422e692a732c9ad4e
6 changes: 6 additions & 0 deletions usrsctplib/netinet/sctp_output.c
Original file line number Diff line number Diff line change
@@ -4491,6 +4491,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
if (!stcb->sctp_ep->plpmtud_supported) {
net->mtu = mtu;
sctp_pathmtu_adjustment(stcb, net->mtu, net);
} else {
net->max_mtu = mtu;
}
}
#else
@@ -4973,6 +4975,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_pathmtu_adjustment(stcb, net->mtu, net);
}
} else {
if (!net->got_max) {
net->max_mtu = mtu;
net->got_max = 1;
}
if (net->port) {
net->mtu -= sizeof(struct udphdr);
}
219 changes: 179 additions & 40 deletions usrsctplib/netinet/sctp_usrreq.c
Original file line number Diff line number Diff line change
@@ -397,49 +397,188 @@ sctp_notify(struct sctp_inpcb *inp,
#endif
/* no need to unlock here, since the TCB is gone */
} else if (icmp_code == ICMP_UNREACH_NEEDFRAG) {
if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
SCTP_TCB_UNLOCK(stcb);
return;
}
/* Find the next (smaller) MTU */
if (next_mtu == 0) {
/*
* Old type router that does not tell us what the next
* MTU is.
* Rats we will have to guess (in a educated fashion
* of course).
*/
next_mtu = sctp_get_prev_mtu(ip_len);
}
/* Stop the PMTU timer. */
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
timer_stopped = 1;
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
if (inp->plpmtud_supported) {
uint32_t base;
#ifdef INET
if (stcb->asoc.scope.ipv4_addr_legal) {
base = SCTP_PROBE_MTU_V4_BASE;
}
#endif
net->probe_counts = 0;
if (net->probing_state == SCTP_PROBE_DONE) {
sctp_pathmtu_timer(inp, stcb, net);
}
if (net->probing_state > SCTP_PROBE_NONE && net->probing_state < SCTP_PROBE_DONE) {
if (next_mtu == 0) {
switch (net->probing_state) {
case SCTP_PROBE_BASE:
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
break;
case SCTP_PROBE_SEARCH_UP:
net->mtu_probing = 0;
net->mtu = net->probed_mtu;
net->probing_state = SCTP_PROBE_DONE;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4);
}
sctp_pathmtu_adjustment(stcb, net->mtu, net);
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
break;
case SCTP_PROBE_SEARCH_DOWN:
net->max_mtu = sctp_get_prev_mtu(net->max_mtu);
net->probe_mtu = net->max_mtu;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
break;
}
} else if (net->probed_mtu <= next_mtu && next_mtu < net->probe_mtu) {
switch (net->probing_state) {
case SCTP_PROBE_BASE:
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
break;
case SCTP_PROBE_SEARCH_UP:
net->mtu_probing = 0;
//net->mtu = net->probed_mtu;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probe_mtu = net->max_mtu;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
break;
case SCTP_PROBE_SEARCH_DOWN:
net->max_mtu = min(net->max_mtu, next_mtu);
net->probe_mtu = net->max_mtu;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
break;
}
} else if (next_mtu < net->probed_mtu) {
switch (net->probing_state) {
case SCTP_PROBE_BASE:
case SCTP_PROBE_SEARCH_DOWN:
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
break;
case SCTP_PROBE_SEARCH_UP:
if (next_mtu < base) {
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
} else {
net->probe_mtu = base;
net->probed_mtu = base;
net->mtu = min(net->probed_mtu, next_mtu);
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_BASE;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
}
break;
}
} else if (next_mtu == base) {
switch (net->probing_state) {
case SCTP_PROBE_BASE:
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
break;
case SCTP_PROBE_SEARCH_DOWN:
net->mtu_probing = 0;
net->mtu = next_mtu;
net->probed_mtu = next_mtu;
net->max_mtu = next_mtu;
net->probing_state = SCTP_PROBE_DONE;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
}
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
break;
case SCTP_PROBE_SEARCH_UP:
net->mtu = min(net->probed_mtu, next_mtu);
net->max_mtu = min(net->max_mtu, next_mtu);
if (net->probed_mtu > base) {
net->probe_mtu = base;
net->probing_state = SCTP_PROBE_BASE;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
} else {
net->probing_state = SCTP_PROBE_DONE;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
}
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
}
break;
}
}
}
} else {
timer_stopped = 0;
}
/* Update the path MTU. */
if (net->port) {
next_mtu -= sizeof(struct udphdr);
}
if (net->mtu > next_mtu) {
net->mtu = next_mtu;
#if defined(__FreeBSD__)
if (net->port) {
sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr));
if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
SCTP_TCB_UNLOCK(stcb);
return;
}
/* Find the next (smaller) MTU */
if (next_mtu == 0) {
/*
* Old type router that does not tell us what the next
* MTU is.
* Rats we will have to guess (in a educated fashion
* of course).
*/
next_mtu = sctp_get_prev_mtu(ip_len);
}
/* Stop the PMTU timer. */
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
timer_stopped = 1;
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
} else {
sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu);
timer_stopped = 0;
}
/* Update the path MTU. */
if (net->port) {
next_mtu -= sizeof(struct udphdr);
}
if (net->mtu > next_mtu) {
net->mtu = next_mtu;
#if defined(__FreeBSD__)
if (net->port) {
sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr));
} else {
sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu);
}
#endif
}
/* Update the association MTU */
if (stcb->asoc.smallest_mtu > next_mtu) {
sctp_pathmtu_adjustment(stcb, next_mtu, net);
}
/* Finally, start the PMTU timer if it was running before. */
if (timer_stopped) {
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
}
#endif
}
/* Update the association MTU */
if (stcb->asoc.smallest_mtu > next_mtu) {
sctp_pathmtu_adjustment(stcb, next_mtu, net);
}
/* Finally, start the PMTU timer if it was running before. */
if (timer_stopped) {
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
}
SCTP_TCB_UNLOCK(stcb);
} else {
189 changes: 164 additions & 25 deletions usrsctplib/netinet6/sctp6_usrreq.c
Original file line number Diff line number Diff line change
@@ -351,7 +351,7 @@ sctp6_notify(struct sctp_inpcb *inp,
struct socket *so;
#endif
int timer_stopped;
printf("sctp6_notify\n");

switch (icmp6_type) {
case ICMP6_DST_UNREACH:
if ((icmp6_code == ICMP6_DST_UNREACH_NOROUTE) ||
@@ -392,31 +392,170 @@ printf("sctp6_notify\n");
break;
case ICMP6_PACKET_TOO_BIG:
printf("ICMP6_PACKET_TOO_BIG\n");
if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
SCTP_TCB_UNLOCK(stcb);
break;
}
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
timer_stopped = 1;
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
if (inp->plpmtud_supported) {
uint32_t base;
#ifdef INET6
if (stcb->asoc.scope.ipv6_addr_legal) {
base = SCTP_PROBE_MTU_V6_BASE;
}
#endif
net->probe_counts = 0;
if (net->probing_state == SCTP_PROBE_DONE) {
sctp_pathmtu_timer(inp, stcb, net);
}
if (net->probing_state > SCTP_PROBE_NONE && net->probing_state < SCTP_PROBE_DONE) {
if (next_mtu == 0) {
switch (net->probing_state) {
case SCTP_PROBE_BASE:
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
break;
case SCTP_PROBE_SEARCH_UP:
net->mtu_probing = 0;
net->mtu = net->probed_mtu;
net->probing_state = SCTP_PROBE_DONE;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4);
}
sctp_pathmtu_adjustment(stcb, net->mtu, net);
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
break;
case SCTP_PROBE_SEARCH_DOWN:
net->max_mtu = sctp_get_prev_mtu(net->max_mtu);
net->probe_mtu = net->max_mtu;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
break;
}
} else if (net->probed_mtu <= next_mtu && next_mtu < net->probe_mtu) {
switch (net->probing_state) {
case SCTP_PROBE_BASE:
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
break;
case SCTP_PROBE_SEARCH_UP:
net->mtu_probing = 0;
//net->mtu = net->probed_mtu;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probe_mtu = net->max_mtu;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
break;
case SCTP_PROBE_SEARCH_DOWN:
net->max_mtu = min(net->max_mtu, next_mtu);
net->probe_mtu = net->max_mtu;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
break;
}
} else if (next_mtu < net->probed_mtu) {
switch (net->probing_state) {
case SCTP_PROBE_BASE:
case SCTP_PROBE_SEARCH_DOWN:
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
break;
case SCTP_PROBE_SEARCH_UP:
if (next_mtu < base) {
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
} else {
net->probe_mtu = base;
net->probed_mtu = base;
net->mtu = min(net->probed_mtu, next_mtu);
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_BASE;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
}
break;
}
} else if (next_mtu == base) {
switch (net->probing_state) {
case SCTP_PROBE_BASE:
net->probed_mtu = SCTP_PROBE_MIN;
net->mtu_probing = 0;
net->max_mtu = min(net->max_mtu, next_mtu);
net->probing_state = SCTP_PROBE_ERROR;
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
break;
case SCTP_PROBE_SEARCH_DOWN:
net->mtu_probing = 0;
net->mtu = next_mtu;
net->probed_mtu = next_mtu;
net->max_mtu = next_mtu;
net->probing_state = SCTP_PROBE_DONE;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
}
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
break;
case SCTP_PROBE_SEARCH_UP:
net->mtu = min(net->probed_mtu, next_mtu);
net->max_mtu = min(net->max_mtu, next_mtu);
if (net->probed_mtu > base) {
net->probe_mtu = base;
net->probing_state = SCTP_PROBE_BASE;
net->probe_counts = 0;
sctp_send_a_probe(stcb->sctp_ep, stcb, net);
} else {
net->probing_state = SCTP_PROBE_DONE;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
}
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
}
break;
}
}
}
} else {
timer_stopped = 0;
}
/* Update the path MTU. */
if (net->port) {
next_mtu -= sizeof(struct udphdr);
}
if (net->mtu > next_mtu) {
net->mtu = next_mtu;
}
/* Update the association MTU */
if (stcb->asoc.smallest_mtu > next_mtu) {
sctp_pathmtu_adjustment(stcb, next_mtu, net);
}
/* Finally, start the PMTU timer if it was running before. */
if (timer_stopped) {
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
SCTP_TCB_UNLOCK(stcb);
break;
}
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
timer_stopped = 1;
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
} else {
timer_stopped = 0;
}
/* Update the path MTU. */
if (net->port) {
next_mtu -= sizeof(struct udphdr);
}
if (net->mtu > next_mtu) {
net->mtu = next_mtu;
}
/* Update the association MTU */
if (stcb->asoc.smallest_mtu > next_mtu) {
sctp_pathmtu_adjustment(stcb, next_mtu, net);
}
/* Finally, start the PMTU timer if it was running before. */
if (timer_stopped) {
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
}
}
SCTP_TCB_UNLOCK(stcb);
break;