diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index de23063f96ef8701a1f6af5e789f75465dac6574..f4867aeefeb4ccd28d4bbee44a3e8d0011d741fc 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -25121,6 +25121,39 @@ static int sip_t38_abort(const void *data)
 	return 0;
 }
 
+/*! \brief Checks state of the p->refer->refer_call state: can it be picked up?
+ *
+ * It will terminate the call if it cannot be picked up; e.g. because it
+ * was gone, or because it wasn't in a ringing state.
+ *
+ * \return 1 if terminated, 0 if ok
+ */
+static int terminate_on_invalid_replaces_state(struct sip_pvt *p, struct sip_request *req, const char *replace_id)
+{
+	if (p->refer->refer_call == p) {
+		ast_log(LOG_NOTICE, "INVITE with replaces into its own call id (%s == %s)!\n", replace_id, p->callid);
+		transmit_response_reliable(p, "400 Bad request", req);	/* The best way to not not accept the transfer */
+
+	} else if (!p->refer->refer_call->owner) {
+		/* Oops, someting wrong anyway, no owner, no call */
+		ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existing call id (%s)!\n", replace_id);
+		/* Check for better return code */
+		transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replace)", req);
+
+	} else if (ast_channel_state(p->refer->refer_call->owner) != AST_STATE_RINGING &&
+			ast_channel_state(p->refer->refer_call->owner) != AST_STATE_RING &&
+			ast_channel_state(p->refer->refer_call->owner) != AST_STATE_UP) {
+		ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-ringing or active call id (%s)!\n", replace_id);
+		transmit_response_reliable(p, "603 Declined (Replaces)", req);
+
+	} else {
+		/* Ok */
+		return 0;
+	}
+	/* Terminated */
+	return 1;
+}
+
 /*!
  * \brief bare-bones support for SIP UPDATE
  *
@@ -25322,6 +25355,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 	int gotdest;
 	const char *p_replaces;
 	char *replace_id = NULL;
+	int magic_call_id = 0;
 	int refer_locked = 0;
 	const char *required;
 	unsigned int required_profile = 0;
@@ -25553,40 +25587,27 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 					ast_channel_unlock(subscription->owner);
 				}
 				subscription = dialog_unref(subscription, "unref dialog subscription");
+				magic_call_id = !ast_strlen_zero(pickup.exten);
 			}
 		}
 
-		/* This locks both refer_call pvt and refer_call pvt's owner!!!*/
-		if (!error && ast_strlen_zero(pickup.exten) && (p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) {
-			ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id);
-			transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
-			error = 1;
-		} else {
-			refer_locked = 1;
-		}
-
-		/* The matched call is the call from the transferer to Asterisk .
-			We want to bridge the bridged part of the call to the
-			incoming invite, thus taking over the refered call */
-
-		if (p->refer->refer_call == p) {
-			ast_log(LOG_NOTICE, "INVITE with replaces into it's own call id (%s == %s)!\n", replace_id, p->callid);
-			transmit_response_reliable(p, "400 Bad request", req);	/* The best way to not not accept the transfer */
-			error = 1;
-		}
-
-		if (!error && ast_strlen_zero(pickup.exten) && !p->refer->refer_call->owner) {
-			/* Oops, someting wrong anyway, no owner, no call */
-			ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existing call id (%s)!\n", replace_id);
-			/* Check for better return code */
-			transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replace)", req);
-			error = 1;
-		}
-
-		if (!error && ast_strlen_zero(pickup.exten) && ast_channel_state(p->refer->refer_call->owner) != AST_STATE_RINGING && ast_channel_state(p->refer->refer_call->owner) != AST_STATE_RING && ast_channel_state(p->refer->refer_call->owner) != AST_STATE_UP) {
-			ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-ringing or active call id (%s)!\n", replace_id);
-			transmit_response_reliable(p, "603 Declined (Replaces)", req);
-			error = 1;
+		if (!error) {
+			if (magic_call_id) {
+				;
+			/* This locks both refer_call pvt and refer_call pvt's owner!!!*/
+			} else if ((p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag))) {
+				/* The matched call is the call from the transferer to Asterisk .
+					We want to bridge the bridged part of the call to the
+					incoming invite, thus taking over the refered call */
+				refer_locked = 1;
+				if (terminate_on_invalid_replaces_state(p, req, replace_id)) {
+					error = 1;
+				}
+			} else {
+				ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id);
+				transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
+				error = 1;
+			}
 		}
 
 		if (error) {	/* Give up this dialog */
@@ -25828,11 +25849,52 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 				goto request_invite_cleanup;
 			}
 
+			/* We cannot call sip_new with any channel locks
+			 * held. Unlock the referred channel if locked. */
+			if (refer_locked) {
+				sip_pvt_unlock(p->refer->refer_call);
+				if (p->refer->refer_call->owner) {
+					ast_channel_unlock(p->refer->refer_call->owner);
+				}
+			}
+
 			/* First invitation - create the channel.  Allocation
 			 * failures are handled below. */
-
 			c = sip_new(p, AST_STATE_DOWN, S_OR(p->peername, NULL), NULL, p->logger_callid);
 
+			/* Reacquire the lock on the referred call. */
+			if (refer_locked) {
+				/* Reuse deadlock avoid pattern found in
+				 * get_sip_pvt_byid_locked. */
+				sip_pvt_lock(p->refer->refer_call);
+				while (p->refer->refer_call->owner && ast_channel_trylock(p->refer->refer_call->owner)) {
+					sip_pvt_unlock(p->refer->refer_call);
+					usleep(1);
+					sip_pvt_lock(p->refer->refer_call);
+				}
+
+				/* And now, check once more that the call is still
+				 * still available. Yuck. Bail out if it isn't. */
+				if (terminate_on_invalid_replaces_state(p, req, replace_id)) {
+					/* Free the referred call: it's not ours anymore. */
+					sip_pvt_unlock(p->refer->refer_call);
+					if (p->refer->refer_call->owner) {
+						ast_channel_unlock(p->refer->refer_call->owner);
+					}
+					p->refer->refer_call = dialog_unref(p->refer->refer_call, "unref dialog p->refer->refer_call");
+					refer_locked = 0;
+					/* Kill the channel we just created. */
+					sip_pvt_unlock(p);
+					ast_hangup(c);
+					sip_pvt_lock(p); /* pvt is expected to remain locked on return, so re-lock it */
+					/* Mark the call as failed. */
+					sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+					p->invitestate = INV_COMPLETED;
+					res = INV_REQ_ERROR;
+					goto request_invite_cleanup;
+				}
+			}
+
 			if (cc_recall_core_id != -1) {
 				ast_setup_cc_recall_datastore(c, cc_recall_core_id);
 				ast_cc_agent_set_interfaces_chanvar(c);
@@ -25891,7 +25953,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 		p->lastinvite = seqno;
 
 	if (c && replace_id) {	/* Attended transfer or call pickup - we're the target */
-		if (!ast_strlen_zero(pickup.exten)) {
+		if (magic_call_id) {
 			append_history(p, "Xfer", "INVITE/Replace received");
 
 			/* Let the caller know we're giving it a shot */
@@ -26062,7 +26124,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 
 request_invite_cleanup:
 
-	if (refer_locked && p->refer && p->refer->refer_call) {
+	if (refer_locked) {
 		sip_pvt_unlock(p->refer->refer_call);
 		if (p->refer->refer_call->owner) {
 			ast_channel_unlock(p->refer->refer_call->owner);