diff options
author | rrs <rrs@FreeBSD.org> | 2006-11-10 13:34:55 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2006-11-10 13:34:55 +0000 |
commit | 463be3f37d7d4500581c6562d9d9c39984e4e0f4 (patch) | |
tree | 4170e79a6fb36430770a7d8e40bcc1d85cd50261 /sys | |
parent | 50bb724108b7417b0df3bbf7029c43dbd734df49 (diff) | |
download | FreeBSD-src-463be3f37d7d4500581c6562d9d9c39984e4e0f4.zip FreeBSD-src-463be3f37d7d4500581c6562d9d9c39984e4e0f4.tar.gz |
This patch fixes a LOR that happens during INIT-ACK collision.
We were calling select_a_tag() inside sctp_send_initate_ack().
During collision cases we have a stcb and thus a SCTP_LOCK. When
we call select_a_tag it (below it) locks the INFO lock. We now
1) pre-select the nonce-tie-tags in sctputil.c during setup of
a tcb.
2) In the other case where we have to select tags, we unlock after
incr the ref cnt (so assoc won't go away0 and then do the
tag selection followed by a relock and decr the refcnt.
Approved by: gnn
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/sctp_output.c | 22 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 4 |
2 files changed, 17 insertions, 9 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 76c2d61..d8dd145 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3371,14 +3371,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* populate any tie tags */ if (asoc != NULL) { /* unlock before tag selections */ - if (asoc->my_vtag_nonce == 0) - asoc->my_vtag_nonce = sctp_select_a_tag(inp); stc.tie_tag_my_vtag = asoc->my_vtag_nonce; - - if (asoc->peer_vtag_nonce == 0) - asoc->peer_vtag_nonce = sctp_select_a_tag(inp); stc.tie_tag_peer_vtag = asoc->peer_vtag_nonce; - stc.cookie_life = asoc->cookie_life; net = asoc->primary_destination; } else { @@ -3628,9 +3622,19 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag); initackm_out->msg.init.initial_tsn = htonl(asoc->init_seq_number); } else { - initackm_out->msg.init.initiate_tag = htonl(sctp_select_a_tag(inp)); - /* get a TSN to use too */ - initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); + if (asoc) { + atomic_add_int(&asoc->refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + initackm_out->msg.init.initiate_tag = htonl(sctp_select_a_tag(inp)); + /* get a TSN to use too */ + initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); + SCTP_TCB_LOCK(stcb); + atomic_add_int(&asoc->refcnt, -1); + } else { + initackm_out->msg.init.initiate_tag = htonl(sctp_select_a_tag(inp)); + /* get a TSN to use too */ + initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); + } } /* save away my tag to */ stc.my_vtag = initackm_out->msg.init.initiate_tag; diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 927e444..c0d6742 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1020,6 +1020,10 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc, } else { asoc->my_vtag = sctp_select_a_tag(m); } + /* Get the nonce tags */ + asoc->my_vtag_nonce = sctp_select_a_tag(m); + asoc->peer_vtag_nonce = sctp_select_a_tag(m); + if (sctp_is_feature_on(m, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) asoc->hb_is_disabled = 1; else |