Commit 89db6d0f authored by Jon Grimm's avatar Jon Grimm

[SCTP] Overlapping INIT check not right for case 'B'.

Auditing code I see that case 'B' is checking against tie-tag fields.
This is not right, should be checking against peer_vtag == 0, per the
RFC. 
parent 416c322a
...@@ -966,7 +966,7 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc, ...@@ -966,7 +966,7 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
new_addr = list_entry(pos, struct sctp_transport, transports); new_addr = list_entry(pos, struct sctp_transport, transports);
found = 0; found = 0;
list_for_each(pos2, &asoc->peer.transport_addr_list) { list_for_each(pos2, &asoc->peer.transport_addr_list) {
addr = list_entry(pos2, struct sctp_transport, addr = list_entry(pos2, struct sctp_transport,
transports); transports);
if (sctp_cmp_addr_exact(&new_addr->ipaddr, if (sctp_cmp_addr_exact(&new_addr->ipaddr,
&addr->ipaddr)) { &addr->ipaddr)) {
...@@ -1049,20 +1049,17 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc, ...@@ -1049,20 +1049,17 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc,
(asoc->c.peer_vtag == new_asoc->c.peer_ttag)) (asoc->c.peer_vtag == new_asoc->c.peer_ttag))
return 'A'; return 'A';
/* Collision case D.
* Note: Test case D first, otherwise it may be incorrectly
* identified as second case of B if the value of the Tie_tag is
* not filled into the state cookie.
*/
if ((asoc->c.my_vtag == new_asoc->c.my_vtag) &&
(asoc->c.peer_vtag == new_asoc->c.peer_vtag))
return 'D';
/* Collision case B. */ /* Collision case B. */
if ((asoc->c.my_vtag == new_asoc->c.my_vtag) && if ((asoc->c.my_vtag == new_asoc->c.my_vtag) &&
((asoc->c.peer_vtag != new_asoc->c.peer_vtag) || ((asoc->c.peer_vtag != new_asoc->c.peer_vtag) ||
(!new_asoc->c.my_ttag && !new_asoc->c.peer_ttag))) (0 == asoc->c.peer_vtag))) {
return 'B'; return 'B';
}
/* Collision case D. */
if ((asoc->c.my_vtag == new_asoc->c.my_vtag) &&
(asoc->c.peer_vtag == new_asoc->c.peer_vtag))
return 'D';
/* Collision case C. */ /* Collision case C. */
if ((asoc->c.my_vtag != new_asoc->c.my_vtag) && if ((asoc->c.my_vtag != new_asoc->c.my_vtag) &&
...@@ -1071,7 +1068,8 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc, ...@@ -1071,7 +1068,8 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc,
(0 == new_asoc->c.peer_ttag)) (0 == new_asoc->c.peer_ttag))
return 'C'; return 'C';
return 'E'; /* No such case available. */ /* No match to any of the special cases; discard this packet. */
return 'E';
} }
/* Common helper routine for both duplicate and simulataneous INIT /* Common helper routine for both duplicate and simulataneous INIT
...@@ -1501,11 +1499,17 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, ...@@ -1501,11 +1499,17 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
sctp_ulpevent_t *ev = NULL; sctp_ulpevent_t *ev = NULL;
sctp_chunk_t *repl; sctp_chunk_t *repl;
/* The local endpoint cannot use any value from the received /* Clarification from Implementor's Guide:
* state cookie and need to immediately resend a COOKIE-ACK * D) When both local and remote tags match the endpoint should
* and move into ESTABLISHED if it hasn't done so. * enter the ESTABLISHED state, if it is in the COOKIE-ECHOED state.
* It should stop any cookie timer that may be running and send
* a COOKIE ACK.
*/ */
if (SCTP_STATE_ESTABLISHED != asoc->state) {
/* Don't accidentally move back into established state. */
if (asoc->state < SCTP_STATE_ESTABLISHED) {
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_ESTABLISHED)); SCTP_STATE(SCTP_STATE_ESTABLISHED));
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START,
...@@ -1529,13 +1533,14 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, ...@@ -1529,13 +1533,14 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
SCTP_ULPEVENT(ev)); SCTP_ULPEVENT(ev));
} }
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
repl = sctp_make_cookie_ack(new_asoc, chunk); repl = sctp_make_cookie_ack(new_asoc, chunk);
if (!repl) if (!repl)
goto nomem; goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
nomem: nomem:
...@@ -1606,8 +1611,6 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, ...@@ -1606,8 +1611,6 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
sctp_send_stale_cookie_err(ep, asoc, chunk, commands, sctp_send_stale_cookie_err(ep, asoc, chunk, commands,
err_chk_p); err_chk_p);
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
break;
case -SCTP_IERROR_BAD_SIG: case -SCTP_IERROR_BAD_SIG:
default: default:
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
...@@ -1640,9 +1643,8 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, ...@@ -1640,9 +1643,8 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
new_asoc); new_asoc);
break; break;
default: /* No such case, discard it. */ default: /* Discard packet for all others. */
printk(KERN_WARNING "%s:unknown case\n", __FUNCTION__); retval = sctp_sf_pdiscard(ep, asoc, type, arg, commands);
retval = SCTP_DISPOSITION_DISCARD;
break; break;
}; };
...@@ -1849,8 +1851,8 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep, ...@@ -1849,8 +1851,8 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_INC, sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_INC,
SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR));
/* If we've sent any data bundled with COOKIE-ECHO we need to /* If we've sent any data bundled with COOKIE-ECHO we need to
* resend. * resend.
*/ */
list_for_each(pos, &asoc->peer.transport_addr_list) { list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, struct sctp_transport, transports); t = list_entry(pos, struct sctp_transport, transports);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment