Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 186569) +++ channels/chan_sip.c (working copy) @@ -14433,13 +14433,40 @@ } if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->pendinginvite) { - /* We already have a pending invite. Sorry. You are on hold. */ - p->glareinvite = seqno; - transmit_response_reliable(p, "491 Request Pending", req); - if (option_debug) - ast_log(LOG_DEBUG, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid); - /* Don't destroy dialog here */ - return 0; + if (!ast_test_flag(&p->flags[0], SIP_OUTGOING) && ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED)) { + /* We have received a reINVITE on an incoming call to which we have sent a 200 OK but not yet received + * an ACK. According to RFC 5407, Section 3.1.4, the proper way to handle this race condition is to accept + * the reINVITE since we have established a dialog. + * + * So what needs to be done to insure that everything goes smoothly? First, we need to clear + * the p->pendinginvite since it no longer is pending. Next, we need to cancel the retransmission + * of our 200 OK in response to the initial INVITE. When we later receive the ACK for the initial INVITE, + * we should just ignore it since the iseqno for this sip_pvt has increased beyond the CSeq in the initial + * INVITE transaction. + * + * Basically, we're rolling the ACK and reINVITE handling into one here. + */ + + /* Note that this will both clear the pendinginvite flag and cancel the + * retransmission of the 200 OK + */ + __sip_ack(p, p->lastinvite, FLAG_RESPONSE, 0); + + /* At this point, we've cleared the pendinginvite number off the sip_pvt, and stopped + * the 200 OK retransmissions. The big item now is to make sure that when we do + * receive an ACK for the initial INVITE request that we do just ignore it. + * + * The rest of the processing for the reINVITE should just work + */ + } else { + /* We already have a pending invite. Sorry. You are on hold. */ + p->glareinvite = seqno; + transmit_response_reliable(p, "491 Request Pending", req); + if (option_debug) + ast_log(LOG_DEBUG, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid); + /* Don't destroy dialog here */ + return 0; + } } p_replaces = get_header(req, "Replaces");