aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/sctp_timer.c85
1 files changed, 49 insertions, 36 deletions
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index bce1f5cd166d..582abd8e8854 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -164,8 +164,8 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
/*
- * sctp_find_alternate_net() returns a non-NULL pointer as long
- * the argument net is non-NULL.
+ * sctp_find_alternate_net() returns a non-NULL pointer as long as there
+ * exists nets, which are not being deleted.
*/
struct sctp_nets *
sctp_find_alternate_net(struct sctp_tcb *stcb,
@@ -174,14 +174,14 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
{
/* Find and return an alternate network if possible */
struct sctp_nets *alt, *mnet, *min_errors_net = NULL, *max_cwnd_net = NULL;
- int once;
+ bool looped;
/* JRS 5/14/07 - Initialize min_errors to an impossible value. */
int min_errors = -1;
uint32_t max_cwnd = 0;
if (stcb->asoc.numnets == 1) {
- /* No others but net */
+ /* No selection can be made. */
return (TAILQ_FIRST(&stcb->asoc.nets));
}
/*
@@ -328,25 +328,22 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
return (max_cwnd_net);
}
}
- mnet = net;
- once = 0;
-
- if (mnet == NULL) {
- mnet = TAILQ_FIRST(&stcb->asoc.nets);
- if (mnet == NULL) {
- return (NULL);
- }
+ /* Look for an alternate net, which is active. */
+ if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) {
+ alt = TAILQ_NEXT(net, sctp_next);;
+ } else {
+ alt = TAILQ_FIRST(&stcb->asoc.nets);
}
+ looped = false;
for (;;) {
- alt = TAILQ_NEXT(mnet, sctp_next);
if (alt == NULL) {
- once++;
- if (once > 1) {
- break;
+ if (!looped) {
+ alt = TAILQ_FIRST(&stcb->asoc.nets);
+ looped = true;
}
- alt = TAILQ_FIRST(&stcb->asoc.nets);
+ /* Definitely out of candidates. */
if (alt == NULL) {
- return (NULL);
+ break;
}
}
if (alt->ro.ro_nh == NULL) {
@@ -358,43 +355,59 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
}
if (((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) &&
(alt->ro.ro_nh != NULL) &&
- (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))) {
- /* Found a reachable address */
+ (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) &&
+ (alt != net)) {
+ /* Found an alternate net, which is reachable. */
break;
}
- mnet = alt;
+ alt = TAILQ_NEXT(alt, sctp_next);
}
if (alt == NULL) {
- /* Case where NO insv network exists (dormant state) */
- /* we rotate destinations */
- once = 0;
- mnet = net;
+ /*
+ * In case no active alternate net has been found, look for
+ * an alternate net, which is confirmed.
+ */
+ if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) {
+ alt = TAILQ_NEXT(net, sctp_next);;
+ } else {
+ alt = TAILQ_FIRST(&stcb->asoc.nets);
+ }
+ looped = false;
for (;;) {
- if (mnet == NULL) {
- return (TAILQ_FIRST(&stcb->asoc.nets));
- }
- alt = TAILQ_NEXT(mnet, sctp_next);
if (alt == NULL) {
- once++;
- if (once > 1) {
- break;
+ if (!looped) {
+ alt = TAILQ_FIRST(&stcb->asoc.nets);
+ looped = true;
}
- alt = TAILQ_FIRST(&stcb->asoc.nets);
+ /* Definitely out of candidates. */
if (alt == NULL) {
break;
}
}
if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) &&
(alt != net)) {
- /* Found an alternate address */
+ /*
+ * Found an alternate net, which is
+ * confirmed.
+ */
break;
}
- mnet = alt;
+ alt = TAILQ_NEXT(alt, sctp_next);
}
}
if (alt == NULL) {
- return (net);
+ /*
+ * In case no confirmed alternate net has been found, just
+ * return net, if it is not being deleted. In the other case
+ * just return the first net.
+ */
+ if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) {
+ alt = net;
+ }
+ if (alt == NULL) {
+ alt = TAILQ_FIRST(&stcb->asoc.nets);
+ }
}
return (alt);
}